学习笔记|定时器|STC中断|定时器时间计算|STC32G单片机视频开发教程(冲哥)|第十一集:定时器的作用和意义

1.定时器的作用和意义

什么是定时器:定时器-与非网
上节课的一段代码:

while(1)

{
    TimeCount++;
    delay_ms(1);
}

TimeCount++然后一个延时1毫秒,每运行1ms,变量就会加一。
系统已经运行了多少个毫秒。
实际使用时的代码如下,

while(1)
{
    TimeCount++;
    delay_ms(1);
    if (KEY1 == 0)
		{
			delay_ms(10);
			if (KEY1 == 0)
			{
				while(KEY1 == 0);
            }
        }
}

判断按键有沿有按下的时候,我们等待按键松开,还有一个while循环。
如果没有松开,会一直死在这一行。所以,按下的时间段内,TimeCount++没有在执行,变量不会动。
那么像这样while函数在不断循环执行的时候,能不能有办法让这个变量每隔1ms能自动加一,并且不受while循环的影响呢?
引入:中断的概念
如果中断不发生,就会一直执行主程序(主函数)。但是,如果中断发生了,先会进行这个中断的处理函数
处理完后,从中断返回,再继续执行主程序(之前没有完成的一个人任务)。
在这里插入图片描述

定时器中断

定时一定时间之后产生的中断,也就是定时器中断。
主程序:你在背书
中断:妈妈让你五分钟以后看一下锅里的汤有没有烧干,一个定时器中断的一个例子。

定时器是定时器和计数器的统称。

1)设置为定时器时,可实现硬件计时,或者使程序每隔一固定时间完成一项操作;
2)设置为计数器时候能够对脉冲进行计数;
3)替代长时间的delay,提高CPU的运行效率和处理速度,能及时的响应某个事件。

2.STC32G单片机定时器使用原理

T0实现1ms中断
手册原文:
在这里插入图片描述

定时器/计数器(24位定时器,8位预分频14+16位自动重装载)
STC32G系列单片机内部设置了5个24位定时器/计数器(8位预分频+16位计数)。5个16位定时器T0、T1、T2、T3和T4都具有计数方式和定时方式两种工作方式。对定时器/计数器TO和T1,用它们在特殊功能寄存器TMOD中相对应的控制位CT来选择TO或T1为定时器还是计数器。对定时器/计数器T2,用特殊功能寄存器AUXR中的控制位T2_C/T来选择T2为定时器还是计数器。对定时器/计数器T3,用特殊功能寄存器T4T3M中的控制位T3_C/T来选择T3为定时器还是计数器。对定时器/计数器
T4,用特殊功能寄存器T4T3M中的控制位T4_C/T来选择T4为定时器还是计数器。定时器/计数器的核心部件是一个加法计数器,其本质是对脉冲进行计数。只是计数脉冲来源不同:如果计数脉冲来自系统
时钟,则为定时方式,此时定时器/计数器每12个时钟或者每1个时钟得到一个计数脉冲,计数值加1;如果计数脉冲来自单片机外部引脚,则为计数方式,每来一个脉冲加1。
当定时器/计数器TO、T1及T2工作在定时模式时,特殊功能寄存器AUXR中的TOx12、T1x12和T2x12分别决定是系统时钟/12还是系统时钟/1(不分频〉后让TO、T1和T2进行计数。当定时器/计数器T3和T4工作在定时模式时,特殊功能寄存器T4T3M中的T3x12和T4x12分别决定是系统时钟/12还是系统时钟/1(不分频〉后让T3和T4进行计数。当定时器/计数器工作在计数模式时,对外部脉冲计数不分频。
定时器/计数器0有4种工作模式:模式0(16位自动重装载模式)﹐模式1(16位不可重装载模式),模式2(8位自动重装模式),模式3(不可屏蔽中断的16位自动重装载模式)。定时器/计数器1除模式3外,其他工作模式与定时器/计数器О相同。T1在模式3时无效,停止计数。定时器T2的工作模式固定为16位自动重装载模式。T2可以当定时器使用,也可以当串口的波特率发生器和可编程时钟输出。定时器3、定时器4与定时器T2一样,它们的工作模式固定为16位自动重装载模式。T3/T4可以当定时器使用,也可以当串口的波特率发生器和可编程时钟输出。

2.1 先设置功能为定时器/计数器(本质都是加法计数器)

STC32G系列单片机内部设置了5个24位定时器/计数器(8位预分频+16位计数)。5个16位定时器T0、T1、T2、T3和T4都具有计数方式和定时方式两种工作方式。对定时器/计数器TO和T1,用它们在特殊功能寄存器TMOD中相对应的控制位CT来选择TO或T1为定时器还是计数器。对定时器/计数器T2,用特殊功能寄存器AUXR中的控制位T2_C/T来选择T2为定时器还是计数器。对定时器/计数器T3,用特殊功能寄存器T4T3M中的控制位T3_C/T来选择T3为定时器还是计数器。对定时器/计数器T4,用特殊功能寄存器T4T3M中的控制位T4_C/T来选择T4为定时器还是计数器。定时器/计数器的核心部件是一个加法计数器,其本质是对脉冲进行计数。只是计数脉冲来源不同:如果计数脉冲来自系统时钟,则为定时方式,此时定时器/计数器每12个时钟或者每1个时钟得到一个计数脉冲,计数值加1;如果计数脉冲来自单片机外部引脚,则为计数方式,每来一个脉冲加1。
本节课主要用T0即timer 0也就是定时器0来实现功能。这个T就是一个定时的一个简称。
以定时器0/1模式寄存器(TMOD)为例:
T0 C/T:控制定时器0用作定时器或计数器,清0则用作定时器(对内部系统时钟进行计数),置1用作
计数器(对引脚TO/P3.4外部脉冲进行计数)。
在这里插入图片描述

2.2、在定时器模式下,设置不分频或者12分频∶

在这里插入图片描述

当定时器/计数器TO、T1及T2工作在定时模式时,特殊功能寄存器AUXR中的TOx12、T1x12和T2x12分别决定是系统时钟/12还是系统时钟/1(不分频)后让TO、T1和T2进行计数。当定时器/计数器T3和T4工作在定时模式时,特殊功能寄存器T4T3M中的T3x12和T4x12分别决定是系统时钟/12还是系统时钟/1(不分频)后让T3和T4进行计数。当定时器/计数器工作在计数模式时,对外部脉冲计数不分频。
定时方式,此时定时器/计数器每12个时钟或者每1个时钟得到一个计数脉冲,计数值加1; 计数差了12倍。
看一下辅助寄存器(AUXR)
在这里插入图片描述
在这里插入图片描述

用特殊功能寄存器AUXR中的控制位T2_C/T来选择T2为定时器还是计数器。
默认最高位为0:
在这里插入图片描述

所以默认的频率是除以12的。

Tips:选择不分频还是12分频

看具体的定时时间,如果定时时间够,那就用12分频。如果不分频,相当于定时的时间短一些,但是精度会更好。

2.3、定时器的工作模式

在这里插入图片描述

16位自动重载模式:计数可以从0计数到65535,16位就是65535,2^16-1=65535。
定时时间到了,系统会把你写入的定时时间重新给他自已装进去。不自动重载模式,需要自己手动给定定时时间。
8位自动重载:从0计数到255,这就是他的最大值,
不可屏蔽中断的16位自动重载:与模式0相同,不可屏蔽中断,中断优先级最高,高于其他所有中断的优先级,并且不可关闭,可用作操作系统的系统节拍定时器,或者系统监控定时器。
这个中断只要一旦开启,他就是最高优先级,别的任何的中断都是不能打断它的。后期还有串口中断,外部中断等等。
今天主要做16位自动重载模式的设置及测试。
在这里插入图片描述

2.4 TCON寄存器设置

TF0和TR0
TF0:T0溢出中断标志,一定要手动给它写1,不写1则不能开启,即不能计数。T0被允许计数以后,从初值开始加1计数,当产生溢出时,由硬件置“1”TFO,
向CPU请求中断,一直保持CPU响应该中断时,才由硬件清0(也可由查询软件清0)。
TR0:定时器T0的运行控制位。该位由软件置位和清零,当然不清0也没关系。当GATE (TMOD.3)=0,TRO=1时就允许TO开
始计数,TRO=0时禁止TO计数。当GATE(TMOD.3)=1,TRO=1且INTO输入高电平时,才允许TO计数,TRO=0时禁止TO计数。

2.5中断使能寄存器(中断允许位)

在这里插入图片描述
在这里插入图片描述

回顾一下我们之前的课我们想要P60输出一个低电平,我们可以这样写:
方法1:P60 = 0;
方法2:P6 = 0XFE; //当然最好要写 P6 &= 0XFE;
在这里插入图片描述

比如说我们要设置ET0等于1:可以直接写ET0等于1(这样子更方便而且不会影响到别的位)
也可以写IE=0X02

3.定时器的简单应用

在这里插入图片描述
当c/T=0时,多路开关连接到系统时钟的分频输出,TO0对内部系统时钟计数,TO工作在定时方式。当
C/T=1时,多路开关连接到外部脉冲输入P3.4/T0,即TO工作在计数方式。
STC单片机的定时器0有两种计数速率:一种是12T模式,每12个时钟加1,与传统8051单片机相同;另外一种是1T模式,每个时钟加1,速度是传统8051单片机的12倍。TO 的速率由特殊功能寄存器AUXR中的TOx12决定,如果TOx12=0,TO则工作在12T模式;如果TOx12=1,T0则工作在1T模式
定时器0有两个隐藏的寄存器RL_THO和RL_TLO。RL_THO与THO共有同一个地址,RL_TLO与TLO共有同一个地址。当TRO=0即定时器/计数器О被禁止工作时,对TLO写入的内容会同时写入RL_TLO,对THO写入的内容也会同时写入RL_THO。当TRO=1即定时器/计数器О被允许工作时,对TLO写入内容,实际上不是写入当前寄存器TLO0中,而是写入隐藏的寄存器RL_TLO中,对THO写入内容,实际上也不是写入当前寄存器TH0中,而是写入隐藏的寄存器RL_THO,这样可以巧妙地实现16位重装载定时器。当读THO和TLO的内容时,所读的内容就是THO和TLO的内容,而不是RL_THO和RL_TLO的内容。
当定时器О工作在模式0(TMOD[1:0][M1.MO]=00B)时,[THO,TLO]的溢出不仅置位TFO,而且会自动将[RL_THO,RL_TLO]的内容重新装入[THO,TLO]。
当TOCLKO/INT_CLKO.0=1时,P3.5/T1管脚配置为定时器0的时钟输出TOCLKO。输出时钟频率为TO溢出率/2。
如果C/T=0,定时器/计数器TO对内部系统时钟计数,则:
TO工作在1T模式(AUXR.7/TOx12=1)时的输出时钟频率 =(SYsclk)(TMOPS+1)(65536-[RL_THO, RL_TLO])2To工作在12T模式(AUXR.7/TOx12=0)时的输出时钟频率-(SYsck)(TMOPS+1)/12/(65536-[RL_THO,RL_TLO])2如果C/T=1,定时器/计数器TO是对外部脉冲输入(P3.4/TO)计数,则:
输出时钟频率=(To_Pin_CLK)/(65536-[RL_THO,RL_TLO])/2
根据手册 14.5范例程序
14.5.1 定时器0(模式0一16位自动重载),用作定时

TMOD = 0x00;//模式0,16位自动重载模式
TL0=0x66;//65536-11.0592M/12/1000
TH0 = 0xfe;
TR0= 1;//启动定时器
ET0= 1;//使能定时器中断
EA=1;

TMOD = 0x00 查询手册,可知,执行设置:
1、16位自动重载模式;
2、T0_C/T:控制定时器0用作定时器或计数器,清0则用作定时器(对内部系统时钟进行计数)
3、TO_GATE:控制定时器0,当GATE=0(TMOD.3)时,如TRO=1,则定时器计数。

定时时间:

相关公式:
在这里插入图片描述

TL0 = 0x66;//65536-11.0592M/12/1000
TH0 = 0xfc;
0XFC66对应64614,65536-64614=922,92212(0+1)/(11.0592*1000000)=0.0010004340277778s
约为1ms。

本节目标:T0实现1毫秒的一个中断

用上节课的代码做模板,编译运行,会发现有一个小bug,每次按key的时候,数码管会闪一下。
用定时器就可以把这个闪的这个问题给修复掉。
首先打开stc手册,14.5节例程:
在这里插入图片描述

右键跳转到sys_init()的定义,可以看到,TMOD以前的定义均已有。
直接看到我们最重要的这个TMOD,一般初始化的代码放在EA之前.
手册中给到是11.0592MHZ时间,需要改成24MHZ:
在这里插入图片描述

根据前述公式:24000000*0.001/12/(0+1)=2000,改成程序员模式:65536-2000=0XF830,则:
TL0 = 0X30; //计算出24MB时钟下的1ms定时时间
TH0 = 0XF8;
在这里插入图片描述

打开定时器,使能定时器中断。

STC中断列表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
增加定时器中断函数,函数名按规定写,可以自定,但是关键词interrupt不能少,表示中断号:
void TM0_Isr() interrupt 1 //定时器0对应中断号1,自动找到中断号,并去执行。
把需要的函数移植到中断中去,这里只需将数码管刷新函数SEG_Fre()加入到其中,并禁用SEG_Fre()中的延时语句,将数码管刷新代码也加入:

void TM0_Isr() interrupt 1 //1ms进来执行一次,无需其他延时,重复赋值
{
	SEG_Fre();		//数码管刷新1ms执行一次

	if( RUN_State==1 ) //开始运行后,每隔1ms加1,需要移进来
		{
			TimCount++; //每ms加1,按键操作均不影响数码管刷新
			Show_Tab[4] = TimCount/10000%10;
			Show_Tab[5] = TimCount/1000%10+10;
			Show_Tab[6] = TimCount/100%10;
			Show_Tab[7] = TimCount/10%10;		//取10位
		}
}

编译下载,发现一个bug,按键一直按住不松开时,数码管显示有问题,肯定是按键函数有问题,找一下按键部分代码:
将按键部分的刷新代码删除,该部分刷新由中断函数每ms自动执行,无需重复刷新。
再运行,数码管无闪烁,实验成功。

4.定时器的快速使用方法

STC-ISP有专用的定时器时间计算选项卡:
在这里插入图片描述

输入参数后,生产C代码:

void Timer0_Isr(void) interrupt 1
{
}

void Timer0_Init(void)		//1000微秒@24.000MHz
{
	AUXR &= 0x7F;			//定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TL0 = 0x30;				//设置定时初始值
	TH0 = 0xF8;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0 = 1;				//使能定时器0中断
}

将初始化函数 Timer0_Init()放在主程序前,并将中断名称修改一致:

中断频率越低越好!!

总结

1.了解定时器和定时器中断
2.学会分析什么时候该用定时器
3.熟悉工具并能快速使用定时器

课后练习:

一、第十课的课后作业做一个简易时钟,在此基础上将时钟改成定时器驱动。
二、在上述基础上是增加一个按钮,按下一次就可以让时间暂停,在按一下时间又能继续走,在按一下再暂停!

猜你喜欢

转载自blog.csdn.net/Medlar_CN/article/details/132712561