STM8S应用笔记—中断里的万年历

  • 格式:docx
  • 大小:100.81 KB
  • 文档页数:17

Reap=Time.Year; while(Reap-4>=0) Reap=Reap-4; if(Reap!=0) Row=0; else
Day++
是 Day=0
Month==12?
Day++
… …
应该可以说,至此,一个万年历功能模块就通过 STM8S 的中断子 函数实现了。但仍有一些注意事项:首先,计数器的更新中断需要通 过软件对计数器状态寄存器的更新中断位的清零退出, 否则将成为死 循环;其次,万年历作为一个背景式的程序不应影响到其它主要中断 程序的进行,故应将其中断优先级降低。STM8S 的软件中断共 3 级, 降低到多少,视需求而定。 很高兴能与大家分享一点我自己的小成果,敬请多多指教。 最后,是我编写的程序。有一些需要特加说明:
struct Time { int Year; char Month; char Day; char Hour; char Minute; char Second; };
struct Time Time={YEAR,MONTH,DAY,HOUR,MINUTE,SECOND}; int Reap; char Row; charLastDay[2][13]= {{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;
UART2_BRR2 = 0x0B; UART2_BRR1 = 0x08; UART2_CR2 = 0x2C;
_asm("rim");
while(1); } 2、 中断向量表
#include<STM8S105C_S.h>
#define YEAR 2010 #define MONTH 9 #define DAY 1 #define HOUR 0 #define MINUTE 0 #define SECOND 0
遇到刚才提到的第二个问题;然而一旦更新中断子程序过长,超过了 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; 2、 fMASTER = fHSE, fCPU = fMASTER;
typedef void @far (*interrupt_handler_t)(void);
struct interrupt_vector { unsigned char interrupt_instruction; interrupt_handler_t interrupt_handler; };
通过各级 MCU 中内置的计数器(我使用的是 TIM3)对主 时钟频率进行分频,从而获得 1Hz 的时钟信号,初始化程 序段及必要注释如下: TIM3_CCMR1 |= 0x78; 选择 PWM2 模式;
TIM3_CCER1 |= 0x03; TIM3_ARRH TIM3_ARRL TIM3_CCR1H TIM3_CCR1L = 0x01; = 0xff; = 0x00; = 0xff;
}Time; 变量类型根据需求选定以节约空间。 也可以选择压缩存储,但会使读写程序较为复杂。 我选择牺牲较小空间节省时间的做法, 后面有针对性解释。 4、 以计数器 TIM3 的更新中断执行条件循环, 使各变量成为一 串级联的“计数器” ;令循环条件按照日历进制选定便可实 现电子万年历功能。下面详细阐述循环条件的选定。 时、分、秒、日、年的进制都容易实现。以时、分、秒间 的进制为例,只需使用分支语句,使 MCU 在进入 TIM3 更 新中断后,进行如下判断:
@far @interrupt void NonHandledInterrupt (void) { /* in order to detect unexpected events during
development, it is recommended to set a breakpoint on the following instruction
试想一下只使用分支语句进行判断的判定逻辑, 相信大多数人都 不会喜欢这种做法。当然,解决方法多种多样,大家尽情想象。我仍 以牺牲空间节省时间为准则, 采用预置一个存放每个月最大天数的二 维数组 LastDay,通过查表的方法,完成判定。数组如下列表: 0 0 0 1 31 31 2 28 29 3 31 31 4 30 30 5 31 31 6 30 30 7 31 31 8 31 31 9 30 30 10 31 31 11 30 30 12 31 31
1、
该程序中除万年历部分外,还含有 UART 送显部分。本人 只做了秒的显示,用来检验程序执行效果。用 RS232 将 开发板与 PC 相连,再将本程序下载到板子上运行,然后 打开超级终端就可以看到显示。 UART 设置如下 COM7 波特率:115200 数据位:8 位 停止位:1 位 奇偶校验:无 流量限制:无
注:数组中加入 LastDay[x][0]是为了在查表取纵坐标时少进行一次减 法运算(若无此二数,则求取纵坐标时需要执行 Time.Month-1) 。 判定流程图如下(接上一流程图) :
… …
Hour==23?
是 Row=(Time.Year%4==0)?1:0 退出更新中断
Day==LastDay[Row][Month]?
更新中断
退出中断程序
Second==59?


Second++
Second=0

Munite==59?


Munite++
Munite=0

Hour==23?


Hour++
Hour=0
… …
年、日同理,依次嵌套即可。下面重点讨论月的进制,一个月的 天数分为三类: 中国老话说得好,一三五七八十腊,四六九冬满三十: 前半句都是 31 天的月,后半句是 30 天的 4 个月份,这便是两类 了。 最后一类就是二月, 闰年 29 天, 平年 28 天 (闰年能被 4 整除) 。
*/ 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;
2、
我所使用的这块 STM8S 开发办无法使用标准 C 的‘/’和 ‘%’ ,因此只好用 while 循环加以代替,目前原因尚不 明了。
3、
万年历初始值设定在#: 1、 主函数
#include<STM8S105C_S.h>
main() {
STM8S 应用笔记—中断里的万年历
沈 京
由意法半导体推出的 MCU—STM8S, 自上市以来就凭借着其优异 的性能、较低的功耗以及相对全面的拓展功能备受青睐。本人是在跟 随王铁流教授进行课题初步研究的过程中接触到该 MCU 的,课题的 内容可以简述为应用 STM8 系列芯片实现雷击时刻记录功能。我使用 的是 STM8S105S4 三合一体验套件。 既然是要记录时刻, 自然就需要在 MCU 中嵌入一个万年历模块, 而 STM8S 本身没有现成的类似模块。本篇着重讲述的正是如何应用 STM8S 实现电子万年历功能。 欲实现这一功能,最简单也是最直接的想法及其实现步骤如下: 1、 通过预分频器及 MCU 中内置的计数器对主时钟频率进行 分频,从而获得 1Hz 的时钟信号; 2、 级联 6 个计数器,并依照年、月、日、时、分、秒的进制 规则设置各级计数器的计数周期。 该法若能实施, 其优点是显而易见的。 因为它完全依靠硬件, 故而使得万年历与 CPU 中执行的程序互不干扰, 保证了计时的精 确度,且不占用 CPU 的时间资源。然而事实是,任何人在查看了 STM8S 的硬件资源后,都会遇到下面这个尴尬的问题。 STM8S 共有 6 个计数器, 而其中只有 3 个计数器可以通过寄存器 设置进行级联。而欲实现上述想法,至少需要 7 个计数器,且其中须
_asm("sim");
CLK_CKDIVR = 0x00;
ITC_SPR6&=~0x0c;
TIM3_CCMR1 |= 0x78; TIM3_CCER1 |= 0x03; TIM3_ARRH TIM3_ARRL = 0x03; = 0xff;
TIM3_CCR1H = 0x00; TIM3_CCR1L = 0xff; TIM3_PSCR |= 0x0e; TIM3_CR1 TIM3_IER |= 0x81; |= 0x01;
使能捕获/比较 1 通道; 设置自动装载寄存器, 即计数周期; 设置比较寄存器, 即电平翻转条件; fPSCR = fMASTER / 215 ; 使能计数器及预装载器; 使能更新中断。