C8051F020 定时器中断


C8051F020 定时器中断

概述

C8051DF020内部有5个计数器/定时器,具体功能如下图,其中定时器0、1可以用来作为通用定时器使用,来产生周期性的中断请求。

五个定时器的功能

时钟滴答周期

CKCON: 时钟控制寄存器

位4: T1M:定时器1 时钟选择。该位控制提供给定时器1 的系统时钟的分频数。
0:定时器1 使用系统时钟的12 分频
1:定时器1 使用系统时钟
位3: T0M:定时器0 时钟选择。该位控制提供给定时器0 的系统时钟的分频数。
0:计数器/定时器使用系统时钟的12 分频
1:计数器/定时器使用系统时钟

如果设置此为控制器的系统时钟为24MHz,则默认12分频后,时钟频率为2MHz

此时若对定时器1设置:

TL0=(256-200);    // when 24MHz & SYSCLK/12, 10kHz timeout 
TH0=(256-200);    // reload

则定时器溢出的频率为:

即周期为$100μs$

如果设置T0M(T1M)位为1,此时使用的是系统时钟,即如果控制器的系统时钟为24MHz,则定时器时钟频率也为24MHz。

定时器0和定时器1

因为这两个定时器是可以产生通用定时器中断的,所以重点介绍一下这两个定时器的一些功能。

相关寄存器

定时器0和定时器1都是一个16位的寄存器,在被访问时以两个字节出现:低字节(TL0或TL1)和一个高字节(TH0或TH1)。定时器控制寄存器(TCON)用于允许定时器0和1以及指示它们的状态。。这两个定时器都有四种工作方式,通过设置定时器方式寄存器(TMOD)中的方式选择位M1-M0 来选择工作方式。相关寄存器说明如下

THX和TLX

X=0 or 1

TL0: 定时器0低字节

TL1:定时器1低字节

TH0:定时器0高字节

TH1:定时器1高字节

简单理解:定时器0和定时器1都是一个16位的寄存器,THX和TLX是装寄存器的数的“盒子”;H是”High”的意思,代表着THX装的是16位中的高8位数;L是”Low”的意思,代表着TLX装的是16位中的低8位数。

TCON:定时器控制寄存器

TCON:定时器控制寄存器

此寄存器中位$0\sim 3$控制的是外部中断,暂且忽略。控制定时器0、1的是$4\sim 7$。

以定时器0为例,TCON中位4、5控制的是定时器0,位4是控制定时器0是否运行控制,默认0禁止运行,当设置为1时为允许定时器0控制。

TF0是定时器0的溢出标志位,在使用定时器0中断时该为可自动被清零,不需要手动控制,所以在此不必深究。

位6、7对应定时器1控制位,功能同定时器0。

所以关于此寄存器的定时器中断相关编程只有控制TR0或TR1来控制允许定时器0或1:

TR0=1; //允许定时器0运行控制:即打开定时器0,开始工作
TR1=1; //允许定时器1运行控制

TMOD: 定时器方式寄存器

TMOD: 定时器方式寄存器

TMOD寄存器低四位是控制定时器0的方式,高四位控制定时器1的方式,下面以定时器0为例进行介绍。

位0-1控制的是定时器0的工作方式选择,其四种工作方式会在下面详细介绍。在这四种方式里在使用定时器中断时用的最多的是方式2,即T0M0=0,T0M1=1。

位2为选择功能为计数器还是定时器,在使用定时器中断毫无疑问设置为0。

位3为定时器0门控位,此位的功能是可以将定时器的运作和外部中断联系起来,多用于脉冲宽度的测量,在本项目中应该用不到,故设置为0即可。

定时器1同定时器0。

TMOD=0X02; //设置定时器的工作方式为自动重装载的8位定时器,其是否允许控制与外部中断无关

定时器0、1工作方式

方式2:8位自动重装载的定时器

此方式在定时器中断中使用的最多。

在此方式下,TL0保持计数值,TH0保持重载值。当TL0 中的计数值发生溢出(从全‘1’到0x00)时,定时器溢出标志TF0(TCON.5)被置位,TH0 中的重载值被重新装入到TL0。如果中断被允许,在TF0 被置位时将产生一个中断。TH0 中的重载值保持不变。

TMOD=0X02;        //设置定时器的工作方式为自动重装载的8位定时器
TL0=(256-200);    // when 24MHz & SYSCLK/12, 10kHz timeout 
TH0=(256-200);    // reload
TR0=1;            // 为保证第一次计数正确,必须在允许定时器之前将TL0初始化为希望的数值

方式0,1,3

方式0:13位计数器/定时器。简单来说,本来应该是THX、TLX两个字节,但是现在只用了13位,所以这里TLX的高三位没用使用,予以忽略。

方式1:16位计数器/定时器。很明显,和方式0的区别在于两个字节所有位都使用上了。

方式3:两个8位计数器/定时器(仅定时器0)。定时器0的高、低8位作为两个独立的定时器/计数器来运作,它们的功能不同。使用此方式时,定时器1停止运行,因为TH0用的占用了定时器1的运行控制位TR1,此时定时器1只可以用于产生串口的波特率时钟。

关于定时器的中断

相关寄存器

IE:中断允许寄存器

IE:中断允许寄存器

对于定时器中断来说,我们只需要关注位1、位3、位7

位1:ET0:定时器0中断允许位。此为设置为1,即可允许TF0溢出标志位的中断请求。注意和TR0的区别:ET0是定时器0的中断允许位,TR0是允许定时器0工作,所以在使用定时器0中断时,这两位都应该置为1。

位3:ET1:定时器1中断允许位。原理同定时器0。

位7:EA:允许所有中断。相当于一个中断的“总开关”,在使用任何中断时此位都必须置1。

EA=1; //打开总中断
ET0=1; //允许定时器0中断
ET1=1; //允许定时器1中断

IP:中断优先级寄存器

IP:中断优先级寄存器

此寄存器是为了设置中断的优先级,默认中断优先级为

中断源 优先级
复位 最高
外部中断0(INT0) 0
定时器0溢出 1
外部中断1(INT1) 2
定时器1溢出 3
UART0 4
定时器2溢出 5

如果需要调整中断源的优先级,即可通过控制IP寄存器来实现,比如设置定时器0中断为高优先级:

IP=0X02; 设置定时器0中断为高优先级

这个如果不是特别复杂的项目,一般用的也不多

软件实现

实现定时器中断的软件程序一般较为固定,假设使用定时器0工作方式2(8位自动重载),溢出周期为100μs,程序实现如下:

// 初始化设置
TL0=(256-200); // 24MHz/(12×200)=10KHz,100μs
TH0=(256-200); // 重载值
TMOD=0x02;       // 设置定时器0工作方式2
EA=1;           // 开总中断
ET0=1;           // 允许定时器0中断
TR0=1;           // 启动定时器0

// 定时器0中断服务程序
void t0_isr(void) __interrupt (1)    
{
    t0_isr_callback();

}

// 定时器0中断服务
void t0_isr_callback(void)    
{
    //用户设置相关程序,即进入了定时器中断之后要干什么事
}

中断服务程序中“__interrupt (x)”是编译器规定的固定语法,x 代表这个函数是作为第几号中断的服务程序。

其实在定时器0中断服务程序中直接写相关程序也可,这里老师是为了程序结构清晰且利于维护,加了一个函数t0_isr_callback(void)

老师原话:“这个中断服务程序里什么都没做,只是调用了函数t0_isr_callback()。为什么这样做?这可是我的精心设计啊!有了这个函数,你不必关心事情何时发生,你只需要关心事情发生了要怎么处理,即由你来写回调函数里的内容。因为是人家调用你,所以叫“回调(callback)”。在很多已经做好框架(Framework)的软件项目里,回调经常被使用,它为框架搭建者和内容填充者提供了清晰的分工。”


文章作者: Mat Jenin
文章链接: http://matjenin.xyz
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mat Jenin !
  目录