1.再遇多文件编程

因为定时器经常在后面的教程中使用到,所以我们也把这部分功能代码单独使用文件封装起来。

在第六章的教程中已经教过大家多文件创建,这里点到为止。

创建好“timer.c”和“timer.h”

定时器12


添加进工程中

定时器13


2.timer.c的代码

#include <reg52.h> 
#include <function.h> //详见第六章第8讲
  
u8 T0RH,T0RL,T1RH,T1RL;
  
void TIM0_Init(u32 us,int trim)//trim:微调
{
    u32 tmp;  //临时变量
    
    tmp = 11059200 / 12;            //定时器计数频率
    tmp = ( tmp * (us/100) )/10000; //计算所需的计数值
    tmp = 65536 - tmp;              //计算定时器重载值
    tmp = tmp+trim;                 //微调计数值使其定时更精确到我们想要的定时时间
    T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节  
    T0RL = (unsigned char)tmp;
    TMOD &= 0xF0; //清0低四位 
    TMOD |= 0x01; //设置定时器0为工作模式1   
    TH0 = T0RH;   //加载T0重载值   
    TL0 = T0RL;
    ET0 = 1;      //闭合定时器0中断的开关        
    TR0 = 1;      //启动定时器0         
}  
 
void TIM1_Init(u32 us,int trim)//trim:微调
{
    u32 tmp;  //临时变量
    
    tmp = 11059200 / 12;            //定时器计数频率
    tmp = ( tmp * (us/100) )/10000; //计算所需的计数值
    tmp = 65536 - tmp;              //计算定时器重载值
    tmp = tmp+trim;                 //微调计数值使其定时更精确到我们想要的定时时间
    T1RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节    
    T1RL = (unsigned char)tmp;
    TMOD&=0x0F;//清0高四位
    TMOD|=0x10;//设置定时器1为工作模式1 
    TH1 = T1RH;//加载T1重载值     
    TL1 = T1RL;
    ET1 = 1;   //闭合定时器1中断的开关        
    TR1 = 1;   //启动定时器1         
}

“TMOD&=0xF0;”的作用跟数码管显示小数点的代码技巧一样,保持前面4位的值不变,清0后四位,然后“TMOD|=0x01;”就是不改变原来高四位的值,然后把低四位设成 0001。

如果在TIM0_Init()函数中只写“TMOD=0x01;”

在TIM1_Init()函数中只写“TMOD=0x10;”

然后初始化时像这样按顺序来写

TIM0_Init(20000,20);//定时20ms,20微调使定时精度更高

TIM1_Init(50000,20);//定时50ms,20微调使定时精度更高

那么执行TIM1_Init()的函数内容时就会执行“TMOD=0x10;”把人家低四位给清0了,原本想让定时器0工作在模式1,现在低2位的值变了也就不是工作在模式1了。

所以“TMOD&=0x0F; TMOD|=0x10;”的写法是不干涉互相的位。

我们定义了“T0RH,T0RL,T1RH,T1RL”四个8位的全局变量(R:reload)用来在中断函数里重新赋值。

因为工作模式1都是需要在中断函数中重新赋初值,所以这四个变量是存取初始化时给THx和TLx的初值。


3.timer.h的代码

#ifndef __TIMER_H__
#define __TIMER_H__
  
extern u8 T0RH,T0RL,T1RH,T1RL;
 
void TIM0_Init(u32 us,int trim);//trim:微调 
void TIM1_Init(u32 us,int trim);//trim:微调 

#endif


4.main.c的代码

这样,实现间隔50ms的流水灯在书写上就相当简洁了

#include <reg52.h> 
#include <function.h> //详见第六章第8讲
#include <timer.h>

void main()
{
    LED_Init();         //初始化LED硬件模块
    EA = 1;             //闭合总中断开关
    TIM0_Init(50000,20);//用定时器0定时50ms,20是微调使中断函数里的i均匀地50.00ms后自加,精度更高
    while(1);
}

void TIM0_IRQHandler() interrupt 1
{
    static u8 i; 
    TH0 = T0RH;  //重新加载重载值
    TL0 = T0RL;

    P0=~(0x01<<i);
    i++;
    if(i>=8)i=0; 
}
点赞(0)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)