STM8S应用笔记—中断里的万年历.docx_第1页
STM8S应用笔记—中断里的万年历.docx_第2页
STM8S应用笔记—中断里的万年历.docx_第3页
STM8S应用笔记—中断里的万年历.docx_第4页
STM8S应用笔记—中断里的万年历.docx_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

STM8S应用笔记中断里的万年历沈 京由意法半导体推出的MCUSTM8S,自上市以来就凭借着其优异的性能、较低的功耗以及相对全面的拓展功能备受青睐。本人是在跟随王铁流教授进行课题初步研究的过程中接触到该MCU的,课题的内容可以简述为应用STM8系列芯片实现雷击时刻记录功能。我使用的是STM8S105S4三合一体验套件。既然是要记录时刻,自然就需要在MCU中嵌入一个万年历模块,而STM8S本身没有现成的类似模块。本篇着重讲述的正是如何应用STM8S实现电子万年历功能。欲实现这一功能,最简单也是最直接的想法及其实现步骤如下:1、 通过预分频器及MCU中内置的计数器对主时钟频率进行分频,从而获得1Hz的时钟信号;2、 级联6个计数器,并依照年、月、日、时、分、秒的进制规则设置各级计数器的计数周期。 该法若能实施,其优点是显而易见的。因为它完全依靠硬件,故而使得万年历与CPU中执行的程序互不干扰,保证了计时的精确度,且不占用CPU的时间资源。然而事实是,任何人在查看了STM8S的硬件资源后,都会遇到下面这个尴尬的问题。STM8S共有6个计数器,而其中只有3个计数器可以通过寄存器设置进行级联。而欲实现上述想法,至少需要7个计数器,且其中须有6个相互级联。因此,该途径不可行,Pass。排除掉完全通过硬件解决问题的方法,我们便自然而然地将目光转向了软件途径。首先应当排除使用主函数中的while循环,其弊病至少有以下几点:首先,若将万年历放在主函数中,计数靠的就是不停的while循环,而在遇到中断时,CPU将暂停主函数程序执行而跳转到中断子程序,这就意味着计数被停止了,必然会产生误差。其次, CPU执行不同的指令所需的时间不同。由于用软件编写万年历时会遇到进制判别的问题,故不可能避开分支语句,而不同的分支执行的指令也不尽相同,因此很难保证每次循环所用时间相等。而循环与循环之间是紧挨着进行的,这就会导致误差的累积,最后积少成多,谬之千里。另外,主函数不得不一直运行这些程序,故会增加一定的功耗。弃用了纯软件模式,也就只剩软硬件结合的路可走了。既然硬件没有那么多符合要求的计数器,我们就可以考虑结合硬件所得的1Hz时钟信号,通过软件计数器的更新中断子函数,做出一些符合要求的“计数器”,以实现万年历功能。 同主函数解决方案一样,使用更新中断子函数也不可避免地会遇到程序执行时间的问题。如果在一个1Hz时钟更新中断的子函数执行时间小于1秒,那么中断子程序的发动间隔就被限定为1秒,故使用更新中断子程序不会遇到刚才提到的第二个问题;然而一旦更新中断子程序过长,超过了1秒,则意味着下一秒的中断将会被延迟,且该延迟会递推下去,最终导致万年历计时的重大误差,方案就是不可行的了。我们不妨估算一下,若设置主时钟频率及CPU频率预分频器均为1:1分频,则万年历中断间隔时间:CPU时钟周期= 1/1/fCPU = fCPU = 16M换算成十进制数就是224,即16777216,假设子程序有100条C语句,也就是大概300条汇编指令,以一条汇编指令需要20个时钟周期估算可知,子程序执行所需时间约为1/2796秒,即不足毫秒级。故,软件解决方案可行。此外,即使执行时间未超过1秒而只是较大,效果也将是不理想的。因为中断与中断之间相对少的剩余时间会限制未来其它功能的发展。因此,欲使用软件解决方案,就必须注意提高CPU处理速度,精简语句,尽量少的使用定次循环,必要时须以牺牲空间的方式来节省时间。思路及步骤如下:1、 选用默认的内部高速RC振荡器(16MHz)为主时钟,主时钟频率及CPU频率预分频器选择1:1分频,以保证分频结果的准确度和程序执行速度,初始化程序及必要注释如下:CLK_CKDIVR = 0x00; fMASTER = fHSE, fCPU = fMASTER;2、 通过各级MCU中内置的计数器(我使用的是TIM3)对主时钟频率进行分频,从而获得1Hz的时钟信号,初始化程序段及必要注释如下: TIM3_CCMR1 |= 0x78; 选择PWM2模式; TIM3_CCER1 |= 0x03; 使能捕获/比较1通道; TIM3_ARRH = 0x01; 设置自动装载寄存器, TIM3_ARRL = 0xff; 即计数周期; TIM3_CCR1H = 0x00; 设置比较寄存器, TIM3_CCR1L = 0xff; 即电平翻转条件; TIM3_PSCR |= 0x0f; fPSCR = fMASTER / 215; TIM3_CR1 |= 0x81; 使能计数器及预装载器;TIM3_IER |= 0x01; 使能更新中断。各分频系数的选定、计算方法及过程如下:fMASTER = fHSE = 16MHz = 224Hz;fPSCR = fMASTER / 215 = 29Hz;TIM3_ARR = 29 1 = 511 = 0x01ff.3、 设置六个变量分别代表年、月、日、时、分、秒,鉴于这六个变量相互间的联系,我将其整个设置成了一个结构体Time,详细如下: struct Time int Year;char Month;char Day;char Hour;char Minute;char Second;Time;变量类型根据需求选定以节约空间。也可以选择压缩存储,但会使读写程序较为复杂。我选择牺牲较小空间节省时间的做法,后面有针对性解释。4、 以计数器TIM3的更新中断执行条件循环,使各变量成为一串级联的“计数器”;令循环条件按照日历进制选定便可实现电子万年历功能。下面详细阐述循环条件的选定。时、分、秒、日、年的进制都容易实现。以时、分、秒间的进制为例,只需使用分支语句,使MCU在进入TIM3更新中断后,进行如下判断: 年、日同理,依次嵌套即可。下面重点讨论月的进制,一个月的天数分为三类:中国老话说得好,一三五七八十腊,四六九冬满三十:前半句都是31天的月,后半句是30天的4个月份,这便是两类了。最后一类就是二月,闰年29天,平年28天(闰年能被4整除)。试想一下只使用分支语句进行判断的判定逻辑,相信大多数人都不会喜欢这种做法。当然,解决方法多种多样,大家尽情想象。我仍以牺牲空间节省时间为准则,采用预置一个存放每个月最大天数的二维数组LastDay,通过查表的方法,完成判定。数组如下列表:012345678910111203128313031303131303130310312931303130313130313031注:数组中加入LastDayx0是为了在查表取纵坐标时少进行一次减法运算(若无此二数,则求取纵坐标时需要执行Time.Month-1)。判定流程图如下(接上一流程图):应该可以说,至此,一个万年历功能模块就通过STM8S的中断子函数实现了。但仍有一些注意事项:首先,计数器的更新中断需要通过软件对计数器状态寄存器的更新中断位的清零退出,否则将成为死循环;其次,万年历作为一个背景式的程序不应影响到其它主要中断程序的进行,故应将其中断优先级降低。STM8S的软件中断共3级,降低到多少,视需求而定。很高兴能与大家分享一点我自己的小成果,敬请多多指教。最后,是我编写的程序。有一些需要特加说明:1、 该程序中除万年历部分外,还含有UART送显部分。本人只做了秒的显示,用来检验程序执行效果。用RS232将开发板与PC相连,再将本程序下载到板子上运行,然后打开超级终端就可以看到显示。UART设置如下COM7波特率:115200数据位:8位停止位:1位奇偶校验:无流量限制:无2、 我所使用的这块STM8S开发办无法使用标准C的/和%,因此只好用while循环加以代替,目前原因尚不明了。3、 万年历初始值设定在#define部分为2010.9.1 00:00:00程序如下:1、 主函数#includemain() _asm(sim); CLK_CKDIVR = 0x00; ITC_SPR6&=0x0c; TIM3_CCMR1 |= 0x78; TIM3_CCER1 |= 0x03; TIM3_ARRH = 0x03; TIM3_ARRL = 0xff; TIM3_CCR1H = 0x00; TIM3_CCR1L = 0xff; TIM3_PSCR |= 0x0e; TIM3_CR1 |= 0x81; TIM3_IER |= 0x01; UART2_BRR2 = 0x0B; UART2_BRR1 = 0x08; UART2_CR2 = 0x2C; _asm(rim); while(1);2、 中断向量表#include#define YEAR 2010#define MONTH 9#define DAY 1#define HOUR 0#define MINUTE 0#define SECOND 0struct Timeint Year;char Month;char Day;char Hour;char Minute;char Second;struct Time Time=YEAR,MONTH,DAY,HOUR,MINUTE,SECOND;int Reap;char Row;charLastDay213=0,31,28,31,30,31,30,31,31,30,31,30,31,0,31,29,31,30,31,30,31,31,30,31,30,31;unsigned char Ten,Unit;typedef void far (*interrupt_handler_t)(void);struct interrupt_vector unsigned char interrupt_instruction;interrupt_handler_t interrupt_handler;far interrupt void NonHandledInterrupt (void)/* in order to detect unexpected events during development, it is recommended to set a breakpoint on the following instruction*/return;far interrupt void Clock (void) if(Time.Second=59) Time.Second=0; if(Time.Minute=59) Time.Minute=0; if(Time.Hour=23) Time.Hour=0; Reap=Time.Year; while(Reap-4=0) Reap=Reap-4; if(Reap!=0) Row=0; else Row=1; if(Time.Day=LastDayRowTime.Month) Time.Day=1; if(Time.Month=12) Time.Month=1; Time.Year+; else Time.Month+; else Time.Day+; else Time.Hour+; else Time.Minute+; else Time.Second+;/*Sent Second Via UART*/ while (!(UART2_SR & 0x80); UART2_DR = r; Unit = Time.Second; Ten = 0; while(Unit - 10 = 0) Unit = Unit - 10; Ten+; while (!(UART2_SR & 0x80); UART2_DR = Ten + 48; while (!(UART2_SR & 0x80); UART2_DR = Unit + 48; TIM3_SR1 &=0x01; return;extern void _stext(); /* startup routine */struct interrupt_vector const _vectab = 0x82, (interrupt_handler_t)_stext, /* reset */0x82, NonHandledInterrupt, /* trap */0x82, NonHandledInterrupt , /* irq0 */0x82, NonHandledInterrupt, /* irq1 */0x82, NonHandledInterrupt, /* irq2 */0x82, NonHandledInterrupt, /* irq3 */0x82, NonHandledInterrupt, /* irq4 */0x82, NonHandledInterrupt, /* irq5 */0x82, NonHandledInterrupt, /* irq6 */0x82, NonHandledInterrupt, /* irq7 */0x82, NonHandledInterrupt, /* irq8 */0x82, NonHandledInterrupt, /* irq9 */0x82, NonHandledInterrupt, /* irq10 */0x82, NonHandledInterrupt, /* irq11 */0x82, NonHandledInterrupt, /* irq12 */0x82, NonHandledInt

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论