基于ARM的万历系统.doc
目录1 引言11.1STM32F103系列性能特点:21.2 电子万年历的发展状况22 总体设计框图32.1设计任务和要求32.1.1 课程设计目的32.1.2 课程设计要求32.2设计思路42.3设计中所用到的库文件42.4 RTC(实时时钟)简介43 万年历硬件系统53.1 内部时钟电路53.2 内部串口电路54 程序运行结果65 程序代码分析66 调试过程97 总结与体会9参考文献10附录一11附录二20附录三21万年历系统摘要:在当代繁忙的工作与生活中,时间与我们每个人都有非常密切的关系,每个人都被时间影响着,我们必须对时间有一个度量。因此本设计主要就是设计一款电子万年历系统,本次嵌入式系统课程设计以STM32F103RB芯片为核心,主要能够实现时钟的运行,调整,显示阳历的年、月、日、星期、时、分、秒以及十二生肖等信息。显示部分通过电脑上的超级终端进行显示,当程序编译无误后,将其下载至开发板中,然后通过超级终端进行显示,开始时用户需要自行设置时间和日期,然后万年历系统才会按照用户设计的功能开始工作。由于单片机具有灵活性强、成本低、功耗低、保密性好等特点,所以电子日历时钟一般都以单片机为核心,外加一些外围设备来实现,可以显示年月日时分秒和温度信息,具有可调整日期和时间功能。输出设备显示器可以用液晶显示技术和数码管显示技术。关键字:电子万年历 STM32F103RB 时间日期显示 超级终端 十二生肖显示 1 引言STM32系列基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex-M3内核。按性能有不同的系列:STM32F103“增强型”系列和STM32F101“基本型”系列。此次我们所使用的STM32F103RB芯片就是增强型系列,增强型系列时钟频率达到72MHz,是同类产品中性能最高的产品;基本型时钟频率为36MHz,以16位产品的价格得到比16位产品大幅提升的性能,是16位产品用户的最佳选择。两个系列都内置32K到128K的闪存,不同的是SRAM的最大容量和外设接口的组合。时钟频率72MHz时,从闪存执行代码,STM32功耗36mA,是32位市场上功耗最低的产品,相当于0.5mA/MHz。 ARM Cortex-M系列主要用于微控制器单片机(MCU)领域,是为了那些对功耗和成本非常敏感,同时对性能要求不断增加的嵌入式应用(如微控制器系统、汽车电子与车身控制系统、各种家电、工业控制、医疗器械、玩具和无线网络等)所设计与实现的。随着在各种不同领域应用需求的增加,微处理器市场也在趋于多样化。Cortex-M3是一个32位的单片机核,在传统的单片机领域中,有一些不同于通用32位CPU应用的要求,结合了多种创新性突破技术,使得芯片供应商可以提供超低费用的芯片。M3处理器还集成了许多紧耦合系统外设,合理利用了芯片空间,使系统能满足下一代产品的控制需求。Cortex的优势在于低功耗、低成本、高性能的结合,凭借缩小的内核尺寸、出色的中断延迟、集成的系统部件、灵活的硬件配置、快速的系统调试和简易的软件编程,Cortex-M3处理器将成为广大嵌入式系统(从复杂的片上系统到低端微控制器)的理想解决方案。1.1STM32F103系列性能特点:1、DMA:12通道DMA控制器。支持的外设:定时器,ADC,DAC,SPI,IIC和USART。2、内核:ARM32位Cortex-M3 CPU,最高工作频率72MHz,1.25DMIPS/MHz。单周期乘法和硬件除法。3、低功耗:3种低功耗模式:休眠,停止,待机模式。为RTC和备份寄存器供电的VBAT。4、调试模式:串行调试(SWD)和JTAG接口。 5、存储器:片上集成32-512KB的Flash存储器。6-64KB的SRAM存储器。6、时钟、复位和电源管理:2.0-3.6V的电源供电和I/O接口的驱动电压。POR、PDR和可编程的电压探测器(PVD)。4-16MHz的晶振。内嵌出厂前调校的8MHz RC振荡电路。内部40 kHz的RC振荡电路。用于CPU时钟的PLL。带校准用于RTC的32kHz的晶振。7、2个12位的us级的A/D转换器(16通道):A/D测量范围:0-3.6 V。双采样和保持能力。片上集成一个温度传感器。8、2通道12位D/A转换器:STM32F103xC,STM32F103xD,STM32F103xE独有。9、ECOPACK封装:STM32F103xx系列微控制器采用ECOPACK封装形式。 10、最多多达11个定时器:4个16位定时器,每个定时器有4个IC/OC/PWM或者脉冲计数器。2个16位的6通道高级控制定时器:最多6个通道可用于PWM输出。2个看门狗定时器(独立看门狗和窗口看门狗)。Systick定时器:24位倒计数器。2个16位基本定时器用于驱动DAC。 11、最多多达13个通信接口:2个IIC接口(SMBus/PMBus)。5个USART接口(ISO7816接口,LIN,IrDA兼容,调试控制)。3个SPI接口(18 Mbit/s),两个和IIS复用。CAN接口(2.0B)。USB 2.0全速接口。SDIO接口。1.2 电子万年历的发展状况随着人们生活水平的提高和生活节奏的加快,对时间的要求越来越高,精准数字计时的消费需求也是越来越多。二十一世纪的今天,最具代表性的计时产品就是电子万年历,它是近代世界钟表业界的第三次革命。第一次是摆和摆轮游丝的发明,相对稳定的机械振荡频率源使钟表的走时差从分级缩小到秒级,代表性的产品就是带有摆或摆轮游丝的机械钟或表。第二次革命是石英晶体振荡器的应用,发明了走时精度更高的石英电子钟表,使钟表的走时月差从分级缩小到秒级。第三次革命就是单片机数码计时技术的应用(电子万年历),使计时产品的走时日差从分级缩小到1/600万秒,从原有传统指针计时的方式发展为人们日常更为熟悉的夜光数字显示方式,直观明了,并增加了全自动日期、星期、温度以及其他日常附属信息的显示功能,它更符合消费者的生活需求!因此,电子万年历的出现带来了钟表计时业界跨跃性的进步!2 总体设计框图 本电路主要由3大部分电路组成:ARM最小系统电路、时钟显示电路和闹钟警报电路(本设计用LED灯指示)。其中ATM最小系统主要由复位电路和时钟电路组成。在该设计中,闹钟提醒由LED灯代替,当闹钟时间到的话,LED灯亮,延时设定的时间后自动关闭。总体设计方框图,如图3所示。STM32 复位电路串口显示 输入时间 时钟电路图一 总体设计方框图2.1设计任务和要求 2.1.1 课程设计目的(1) 了解嵌入式芯片的工作原理,从而学会制作相关的东西。 (2) 进一步了解嵌入式系统以及嵌入式在实际生活中的应用 2.1.2 课程设计要求 (1) 本次设计要包含ARM板上的几个模块 (2) 本次设计要有一定有实际意义(有应用价值)2.2设计思路STM32 的RTC 实现一个简易的电子万年历。RTC实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期,当用户设置好时间日期后,在超级终端中显示我们所要求的电子万年历的功能。当时间 计数为:23:59:59 时将刷新为:00:00:00。2.3设计中所用到的库文件 start_stm32f10x_hd.c core_cm3.c system_stm32f10x.c stm32f10x_gpio.c stm32f10x_rcc.c stm32f10x_usart.c stm32f10x_pwr.c stm32f10x_bkp.c stm32f10x_rtc.c stm32f10x_misc.c 用户编写的文件 main.c stm32f10x_it.c usart.c rtc.c 2.4 RTC(实时时钟)简介 实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。 RTC模块和时钟配置系统(RCC_BDCR寄存器)是在后备区域,即在系统复位或从待机模式唤醒后RTC的设置和时间维持不变。 系统复位后,禁止访问后备寄存器和RTC,防止对后备区域(BKP)的意外写操作。执行以下操作使能对后备寄存器和RTC的访问: 设置寄存器PWR_CR的DBP位使能对后备寄存器和RTC的访问。当我们需要在掉电之后,又需要RTC时钟正常运行的话,单片机的VBAT脚需外接3.3V的锂电池。当我们重新上电的时候,主电源给VBAT供电,当系统掉电之后VBAT给RTC时钟工作,RTC中的数据都会保持在后备寄存器当中。 3 万年历硬件系统3.1 内部时钟电路 图二 内部时钟电路3.2 内部串口电路图三 内部串口电路4 程序运行结果程序通过宏定义来设置当前时间,对开发板进行初始化后,进行设置和串口初始化,并打开中断,当设置时间到时,程序读取可编程计数器的值以或许信息,通过串口发送数据显示时钟。5 程序代码分析 首先在 stm32f10x_conf.g 中将相应库文件的头文件的注释去掉,这样才能够真正使用这些库,否则将会编译错误。 1. /* Uncomment the line below to enable peripheral header file inclusion */ 2. /* #include "stm32f10x_adc.h" */ 3. #include "stm32f10x_bkp.h" 4. /* #include "stm32f10x_can.h" */ 5. /* #include "stm32f10x_crc.h" */ 6. /* #include "stm32f10x_dac.h" */ 7. /* #include "stm32f10x_dbgmcu.h" */ 8. /* #include "stm32f10x_dma.h" */ 9. /* #include "stm32f10x_exti.h" */ 10. /*#include "stm32f10x_flash.h"*/ 11. /* #include "stm32f10x_fsmc.h" */ 12. #include "stm32f10x_gpio.h" 13. /* #include "stm32f10x_i2c.h" */ 14. #include "stm32f10x_iwdg.h" 15. #include "stm32f10x_pwr.h" 16. #include "stm32f10x_rcc.h" 17. #include "stm32f10x_rtc.h" 18. /* #include "stm32f10x_sdio.h" */ 19. /* #include "stm32f10x_spi.h" */ 20. /* #include "stm32f10x_tim.h" */ 21. #include "stm32f10x_usart.h" 22. /* #include "stm32f10x_wwdg.h" */ 23. #include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */ 配置好库的环境之后,我们就从main函数开始分析。 int main(void) /* config the sysclock to 72M */ SystemInit(); /* USART1 config */ USART1_Config(); /* 配置RTC秒中断优先级 */ NVIC_Configuration(); printf( "rn This is a RTC demo. rn" ); if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) /* Backup data register value is not correct or not yet programmed (when the first time the program is executed) */ . printf("rnThis is a RTC demo!rn"); printf("rnn RTC not yet configured."); /* RTC Configuration */ RTC_Configuration(); printf("rn RTC configured."); /* Adjust time by values entred by the user on the hyperterminal */ Time_Adjust(); BKP_WriteBackupRegister(BKP_DR1, 0xA5A5); else /* Check if the Power On Reset flag is set */ if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET) printf("rnn Power On Reset occurred."); /* Check if the Pin Reset flag is set */ else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET) . printf("rnn External Reset occurred."); printf("rn No need to configure RTC."); . /* Wait for RTC registers synchronization */ RTC_WaitForSynchro(); /* Enable the RTC Second */ RTC_ITConfig(RTC_IT_SEC, ENABLE); /* Wait until last write operation on RTC registers has finished */ RTC_WaitForLastTask(); #ifdef RTCClockOutput_Enable /* Enable PWR and BKP clocks */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); /* Allow access to BKP Domain */ PWR_BackupAccessCmd(ENABLE); /* Disable the Tamper Pin */ BKP_TamperPinCmd(DISABLE); /* To output RTCCLK/64 on Tamper pin, the tamper functionality must be disabled */ /* Enable RTC Clock Output on Tamper Pin */ BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock); #endif /* Clear reset flags */ RCC_ClearFlag(); /* Display time in infinite loop */ Time_Show(); while (1) 6 调试过程整个设计的调试过程是分步进行的。 1)、 60秒倒计时的调试:对深入浅出ARM课本中的万年历源程序进行实现倒计时功能。倒计时功能实现后再添加LED的提示,同样将添加好的程序进行编译并下载到芯片,然后运行,观察开发板现象看看是否能实现所需功能。 2)、 校时、校分的调试:在能够实现倒计时功能的程序中添加校时校分的程序。KEY1按下计数器停止计数小时(HOUR)加1,KEY3按下计数器停止计数分钟(MIN)加1。程序添加完之后编译,编译无错之后下载到芯片,然后运行。按下KEY1或KEY3,观察是否能实现所需功能。7 总结与体会当今社会是数字化技术高速发展的社会。电子万年历的开发与研究在信息化时代的今天亦是当务之急,因为它遍及人们生活的每一个角落。所以说万年历的开发是国家之所需,社会之所需,人民之所需。由于社会对信息交换不断提高的要求以及高新技术的逐步发展,促进了万年历发展并且投入市场得到了广泛的应用。本次ARM嵌入式系统设计主要以STM32F103RB芯片为核心,主要能够实现显示时间、日期、节日、以及24节气和12生肖等功能。其中时间显示包括时、分、秒,日期显示包括年、月、日,显示部分通过电脑上的超级终端进行显示。通过这两周的实习,感觉自己好多东西都不会,特别是自己的动手能力还有待提高。当然,在这次实习期间,我也学到了以前没有学会的知识和操作能力,培养了我独立思考和团队协作的能力。以前摸棱两可的知识变得更加清晰了。对ARM感觉也慢慢熟悉了,没有以前那么生疏了。当然这期间更多是是同学的帮助和老师的指导。经过这次实习,让我找到了自己的不足,在以后的学习中,我会更加的努力刻苦,获得更大更广的知识面。当今社会是数字化技术高速发展的社会。电子万年历的开发与研究在信息化时代的今天亦是当务之急,因为它遍及人们生活的每一个角落。所以说万年历的开发是国家之所需,社会之所需,人民之所需。由于社会对信息交换不断提高的要求以及高新技术的逐步发展,促进了万年历发展并且投入市场得到了广泛的应用。参考文献1.彭刚,秦志强.基于ARM Cortes-M3的STM32系列嵌入式微控制器应用实践M.北京:电子工业出版社.2011.1 2.吴明晖, 徐睿. 基于ARM的嵌入式系统开发与应用. 人民邮电出版社,2004.3.赖于树. ARM微处理器与应用开发. 电子工业出版社,2007.4.张绮文,谢建雄,谢劲心.ARM嵌入式常用模块与中和系统设计实例精讲. 电子工业出版社, 2007.5.刘岚 尹勇 李京蔚. 基于ARM的嵌入式系统开发. 电子工业出版社, 2008.6.李佳. ARM系列处理器应用技术完全手册. 人民邮电出版社,2006. 附录附录一:源程序#include "stm32f10x.h"#include "stdio.h" #include "calendar.h"#include "date.h"#include "tamper.h"_IO uint32_t TimeDisplay = 0;void RCC_Configuration(void);void NVIC_RTC_Configuration(void);void GPIO_Configuration(void);void USART_Configuration(void);int fputc(int ch, FILE *f);void RTC_Configuration(void);void Time_Regulate(struct rtc_time *tm);void Time_Adjust(void);void Time_Display(uint32_t TimeVar);void Time_Show(void);u8 USART_Scanf(u32 value);#define RTCClockSource_LSEu8 const *WEEK_STR = "日", "一", "二", "三", "四", "五", "六"u8 const *zodiac_sign = "猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗"struct rtc_time systmtime;int main() RCC_Configuration(); NVIC_RTC_Configuration(); NVIC_TAMPER_Configuration(); GPIO_Configuration(); USART_Configuration(); RCC_APB1PeriphClockCmd(RCC_APB2Periph_ALL | RCC_APB1Periph_ALL, ENABLE); BKP_DeInit(); PWR_BackupAccessCmd(ENABLE); BKP_ClearFlag(); BKP_TamperPinLevelConfig(BKP_TamperPinLevel_Low); BKP_TamperPinCmd(ENABLE); BKP_ITConfig(ENABLE); BKP_WriteBackupRegister(BKP_DR1, 0xA1A2); if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) printf("rnn RTC not yet configured."); RTC_Configuration();printf("rn RTC configured."); Time_Adjust();BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);elseif (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET) printf("rnn Power On Reset occurred.");else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET) printf("rnn External Reset occurred."); printf("rn No need to configure RTC.");RTC_WaitForSynchro();RTC_ITConfig(RTC_IT_SEC, ENABLE);RTC_WaitForLastTask(); #ifdef RTCClockOutput_Enable RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); BKP_TamperPinCmd(DISABLE); BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);#endif RCC_ClearFlag(); Time_Show();void RCC_Configuration()SystemInit();RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);void NVIC_RTC_Configuration() NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);void GPIO_Configuration() GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure);void USART_Configuration() USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 115200;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No ;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE);int fputc(int ch, FILE *f) USART_SendData(USART1, (unsigned char) ch); while (!(USART1->SR & USART_FLAG_TXE); return (ch);void RTC_Configuration() RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); BKP_DeInit(); #ifdef RTCClockSource_LSI RCC_LSICmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)=RESET) RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); #elif defined RTCClockSource_LSE RCC_LSEConfig(RCC_LSE_ON); while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)=RESET) RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); #endif RCC_RTCCLKCmd(ENABLE); #ifdef RTCClockOutput_Enable BKP_TamperPinCmd(DISABLE); BKP_RTCCalibrationClockOutputCmd(ENABLE); #endif RTC_WaitForSynchro(); RTC_WaitForLastTask(); RTC_ITConfig(RTC_IT_SEC, ENABLE); RTC_WaitForLastTask(); #ifdef RTCClockSource_LSI RTC_SetPrescaler(31999); #elif defined RTCClockSource_LSE RTC_SetPrescaler(32767); #endif RTC_WaitForLastTask();void Time_Regulate(struct rtc_time *tm) u32 Tmp_YY = 0xFF, Tmp_MM = 0xFF, Tmp_DD = 0xFF, Tmp_HH = 0xFF, Tmp_MI = 0xFF, Tmp_SS = 0xFF; printf("rn=Time Settings="); printf("rn 请输入年份(Please Set Years): 20"); while (Tmp_YY = 0xFF) Tmp_YY = USART_Scanf(99); printf("nr 年份被设置为: 20%0.2dnr", Tmp_YY); tm->tm_year = Tmp_YY+2000; Tmp_MM = 0xFF; printf("rn 请输入月份(Please Set Months): "); while (Tmp_MM = 0xFF) Tmp_MM = USART_Scanf(12); printf("nr 月份被设置为: %dnr", Tmp_MM); tm->tm_mon= Tmp_MM; Tmp_DD = 0xFF; printf("rn 请输入日期(Please Set Dates): "); while (Tmp_DD = 0xFF) Tmp_DD = USART_Scanf(31); printf("nr 日期被设置为: %dnr", Tmp_DD); tm->tm_mday= Tmp_DD; Tmp_HH = 0xFF; printf("rn 请输入时钟(Please Set Hours): "); while (Tmp_HH = 0xFF) Tmp_HH = USART_Scanf(23); printf("nr 时钟被设置为: %dnr", Tmp_HH ); tm->tm_hour= Tmp_HH; Tmp_MI = 0xFF; printf("rn 请输入分钟(Please Set Minutes): "); while (Tmp_MI = 0xFF) Tmp_MI = USART_Scanf(59); printf("nr 分钟被设置为: %dnr", Tmp_MI); tm->tm_min= Tmp_MI; Tmp_SS = 0xFF; printf("rn 请输入秒钟(Please Set Seconds): ");