21ic电子技术开发论坛 单片机与嵌入式系统 ST MCU STM8的C语言编程(5)--8位定时器应用
发新帖我要提问
返回列表
打印
[STM8]

STM8的C语言编程(5)--8位定时器应用

[复制链接]
837|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
vigous1|  楼主 | 2015-2-27 15:31 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在STM8单片机中,有多种定时器资源,既有8位的定时器,也有普通的16位定时器,还有高级的定时器。今天的实验是用最简单的8位定时器TIM4来进行延时,然后驱动LED闪烁。为了简单起见,这里是通过程序查询定时器是否产生更新事件,来判断定时器的延时是否结束。
同样还是利用ST的开发工具,生成一个C程序的框架,然后修改其中的main.c,修改后的代码如下。
编译通过后,下载到开发板,运行程序,可以看到LED在闪烁,或者用示波器可以在LED引脚上看到方波。
在这里要特别提醒的是,从ST给的手册上看,这个定时器中的计数器是一个加1计数器,但本人在实验过程中感觉不太对,经过反复的实验,我认为应该是一个减1计数器(也许是我拿的手册不对,或许是理解上有误)。例如,当给定时器中的自动装载寄存器装入255时,产生的方波频率最小,就象下面代码中计算的那样,产生的方波频率为30HZ左右。若初始化时给自动装载寄存器装入1,则产生的方波频率最大,大约为3.9K左右。也就是说实际的分频数为ARR寄存器的值+1。
// 程序描述:通过初始化定时器4,进行延时,驱动LED闪烁
//           LED接在MCU的GPIO的PD3上
#include"STM8S207C_S.h"
main()
{
// 首先初始化GPIO
PD_DDR = 0x08;
PD_CR1 =0x08;             // 将PD3设置成推挽输出
PD_CR2 = 0x00;
// 然后初始化定时器4                              
TIM4_IER =0x00;            // 禁止中断
TIM4_EGR =0x01;            // 允许产生更新事件
TIM4_PSCR = 0x07;          // 计数器时钟=主时钟/128=2MHZ/128
                                                          // 相当于计数器周期为64uS
             TIM4_ARR =255;             //设定重装载时的寄存器值,255是最大值
TIM4_CNTR =255;            // 设定计数器的初值
                             //定时周期=(ARR+1)*64=16320uS
TIM4_CR1 =0x01;            // b0 =1,允许计数器工作
                             // b1 = 0,允许更新
                             // 设置控制器,启动定时器
while(1)                   // 进入无限循环
{
   while((TIM4_SR1 & 0x81) == 0x00);      // 等待更新标志
   TIM4_SR1 =0x00;                      // 清除更新标志
   PD_ODR = PD_ODR ^0x08;               // LED驱动信号取反
                                          // LED闪烁频率=2MHZ/128/255/2=30.63
}                             
}

沙发
vigous1|  楼主 | 2015-2-27 15:32 | 只看该作者
今天进行的实验依然是用定时器4,只不过改成了用中断方式来实现,由定时器4的中断服务程序来驱动LED的闪烁。
实现中断方式的关键点有几个,第一个关键点就是要打开定时器4的中断允许位,在定时器4的IER寄存器中有定义。第二个关键点,就是打开CPU的全局中断允许位,在汇编语言中,就是执行RIM指令,在C语言中,用下列语句实现:
_asm("rim");
第3个关键点就是中断服务程序的框架或写法,中断服务程序的写法如下:
@far@interrupt void TIM4_UPD_OVF_IRQHandler (void)
{
   // 下面是中断服务程序的实体
}                           
第4个关键点就是要设置中断向量,即将中断服务程序的入口填写到中断向量表中,如下所示,将IRQ23对应的中断服务程序的入口填写成TIM4_UPD_OVF_IRQHandler
structinterrupt_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, NonHandledInterrupt}, /* irq13 */
     {0x82, NonHandledInterrupt}, /* irq14 */
     {0x82, NonHandledInterrupt}, /* irq15 */
     {0x82, NonHandledInterrupt}, /* irq16 */
     {0x82, NonHandledInterrupt}, /* irq17 */
     {0x82, NonHandledInterrupt}, /* irq18 */
     {0x82, NonHandledInterrupt}, /* irq19 */
     {0x82, NonHandledInterrupt}, /* irq20 */
     {0x82, NonHandledInterrupt}, /* irq21 */
     {0x82, NonHandledInterrupt}, /* irq22 */
  {0x82, TIM4_UPD_OVF_IRQHandler},/* irq23 */
     {0x82, NonHandledInterrupt}, /* irq24 */
     {0x82, NonHandledInterrupt}, /* irq25 */
     {0x82, NonHandledInterrupt}, /* irq26 */
     {0x82, NonHandledInterrupt}, /* irq27 */
     {0x82, NonHandledInterrupt}, /* irq28 */
     {0x82, NonHandledInterrupt}, /* irq29 */
};
解决了以上4个关键点,我们就能很轻松地用C语言实现中断服务了。

使用特权

评论回复
板凳
vigous1|  楼主 | 2015-2-27 15:34 | 只看该作者
同样还是利用ST的开发工具,生成一个C程序的框架,然后修改其中的main.c,修改后的代码如下。另外还要修改stm8_interrupt_vector.c。
编译通过后,下载到开发板,运行程序,可以看到LED在闪烁,或者用示波器可以在LED引脚上看到方波。
修改后的main.c如下:
// 程序描述:通过初始化定时器4,以中断方式驱动LED闪烁
//           LED接在MCU的GPIO的PD3上
#include"STM8S207C_S.h"
main()
{
// 首先初始化GPIO
PD_DDR = 0x08;
PD_CR1 =0x08;             // 将PD3设置成推挽输出
PD_CR2 = 0x00;
// 然后初始化定时器4                              
TIM4_IER =0x00;            // 禁止中断
TIM4_EGR =0x01;            // 允许产生更新事件
TIM4_PSCR = 0x07;          // 计数器时钟=主时钟/128=2MHZ/128
                                                          // 相当于计数器周期为64uS
             TIM4_ARR =255;             //设定重装载时的寄存器值,255是最大值
TIM4_CNTR =255;            // 设定计数器的初值
                             // 定时周期=(ARR+1)*64=16320uS
TIM4_CR1 =0x01;            // b0 =1,允许计数器工作
                             // b1 = 0,允许更新
                             // 设置控制器,启动定时器
TIM4_IER =0x01;            // 允许更新中断
_asm("rim");               // 允许CPU全局中断
while(1)                   // 进入无限循环
{
}                             
}

使用特权

评论回复
地板
vigous1|  楼主 | 2015-2-27 15:35 | 只看该作者
//函数功能:定时器4的更新中断服务程序
//输入参数:无
//输出参数:无
//返 回 值:无
@far@interrupt void TIM4_UPD_OVF_IRQHandler (void)
{
   TIM4_SR1 = 0x00;          // 清除更新标志
   PD_ODR = PD_ODR ^ 0x08;   // LED驱动信号取反
                             //LED闪烁频率=2MHZ/128/255/2=30.63
}                                         
修改后的stm8_interrupt_vector.c如下:
/*   BASIC INTERRUPT VECTOR TABLE FOR STM8 devices
*  Copyright (c) 2007 STMicroelectronics
*/
typedefvoid @far (*interrupt_handler_t)(void);
structinterrupt_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;
}
externvoid _stext();     /* startup routine */
extern@far @interrupt void TIM4_UPD_OVF_IRQHandler (void);
structinterrupt_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, NonHandledInterrupt}, /* irq13 */
      {0x82, NonHandledInterrupt}, /* irq14 */
      {0x82, NonHandledInterrupt}, /* irq15 */
      {0x82, NonHandledInterrupt}, /* irq16 */
      {0x82, NonHandledInterrupt}, /* irq17 */
      {0x82, NonHandledInterrupt}, /* irq18 */
      {0x82, NonHandledInterrupt}, /* irq19 */
      {0x82, NonHandledInterrupt}, /* irq20 */
      {0x82, NonHandledInterrupt}, /* irq21 */
      {0x82, NonHandledInterrupt}, /* irq22 */
   {0x82, TIM4_UPD_OVF_IRQHandler},/* irq23 */
      {0x82, NonHandledInterrupt}, /* irq24 */
      {0x82, NonHandledInterrupt}, /* irq25 */
      {0x82, NonHandledInterrupt}, /* irq26 */
      {0x82, NonHandledInterrupt}, /* irq27 */
      {0x82, NonHandledInterrupt}, /* irq28 */
      {0x82, NonHandledInterrupt}, /* irq29 */
};

使用特权

评论回复
5
搞IT的| | 2015-2-28 16:51 | 只看该作者
从ST给的手册上看,这个定时器中的计数器是一个加1计数器吧。。。

使用特权

评论回复
6
spiriter3| | 2015-2-28 17:05 | 只看该作者
支持一下,很好的教程了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

88

主题

427

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部