小灰的51单片机学习之让单片机数个数(7)定时器以及定时器中断的理解

写在之前

大家还记之前小灰写小灰的51单片机学习之渐入佳境(4)的时候有这样一个东西嘛

这里有一个程序的空跑,那什么是程序的空跑呢?其实小灰最近在教别人的时候讲了很久都不怎么能理解程序的空跑那么我们来探讨一下这个吧!

时钟周期和机器周期

说到单片机的时间,就不得不提到一件事情。大家都知道单片机的运行速度很快,但是我一句话运行完了再运行下一句话,我是多久之后运行呢?有的同学可能就会说立刻执行下一句话,那么这个立刻是1ms之后还是1us之后甚至1ns之后呢?大家这就无从得知了吧,而且运行一句话需要多长时间呢?这就得益于我们单片机上的一个器件,晶振!
在这里插入图片描述
然后就长这个样子了,在我们的原理图上面是长这个样子
在这里插入图片描述
这个晶振有什么用呢?晶振分为有源晶振和无源晶振,大家不用管晶振类型,只需要我们这里用的是无源晶振,然后无源晶振会来回震荡,震荡就会输出波形,产生正弦波。(正弦波都不晓得长什么样子的直接狗带)
那么这个正弦波有什么用呢?他会给我们的单片机提供时钟信号。比如说这个图晶振是11.0592M的,当然我们也会用12M具体俩种晶振分别有什么好处感兴趣的同学自行了解我这里就不介绍了。为了方便计算为我后面都用12M的晶振举例。而单片机输出的那个正弦波的频率的值刚好就是这个12M。而这个频率对应的周期就是1/12000000,然而如果是x的晶振就1/x这么多秒,这个时间叫时钟周期,而时钟周期的含义就是晶振振动频率的倒数。
机器周期,其实就是时钟周期*12,对于晶振是12M的单片机,机器周期就是1/12000000x12 = 1us,机器周期能干啥呢?CPU完成一项基本操作(取指令、存储器读写等)所消耗的最短时间。其实可能大家还是不懂这些,emmm听不懂没关系,问题不大嘛接着往后看。

定时器与计时器

而我们的单片机也有计算时间的功能,大家可能就觉得这个东西是叫计时器,但是不要搞错了哈,我们的计时器和定时器是俩个东西。所以接下来先给大家介绍一下定时器是什么。
顾名思义,定时器定时器,就是用来定时用的,定时结束之后我们肯定要干点什么对吧,不然定时干啥呢?这里先保留悬念。那么我们知道定时器肯定要通过什么东西来计算时间然后才能定时嘛,其实定时器计算时间和我们前面说的晶振分不开关系。还记得前面我们说晶振会震荡吧,晶振震荡之后会产生一定的信号,而我们就有时钟周期,时钟周期的12倍就是机器周期,没错,定时器每隔一个机器周期就会加一,然后加一 加一,加到什么时候呢?加满了就会溢出也就是我们所理解的定时的时间到了,而一般加满了我们会进入一个叫定时器中断的东西,和前面的外部中断有点类似,前面是按键按下进入中断,而这里是定时器溢出了进入中断,问题不大。对于这个定时,可能对大家不是很好理解,我认为是这样,我们对于手机上一个定时一小时,大家可以看到时间慢慢减少,减到0就代表我们定时结束了,对于单片机来说呢 最多可以及时到65535,到65536就结束了,如果我们想定时10个机器周期,那么我们只能更改起始时间也就是设定为65525,如果想定时10000个机器周期呢,那么就是55535,对于手机的定时来说是减,那么对于单片机的定时就是累加,而我们控制定时时间就是控制起始的单位,也就是不是从0开始,最多加到65535结束。为什么说最多加到65535呢?
因为2^16是65536,而这就要涉及到定时器的工作原理了。
以16位手动重装模式为例,他会有两个8位的用来计数的东西,其实也只能数到256,是从00000001~11111111,大家不要以为11111111是一个很大的数,其实这里只是一个2进制的数,转化到十进制也就是255,而我们俩个8位来计数的,分为高8位和低8位,这样我们就会256*256 - 1= 65535(65536已结溢出了,所以计数不到),最大65535定时器已经计数计满了,计满了之后就会溢出,然后俩个计数的东西就会清0。所以我们最大也就是65535。对于定时器大家可以这么去理解,就是俩个可以计数的东西,低级(TL0)一点的数到256 就让高级(TH0)的一个加一,直到低级高级全满了,整个定时器就定时到了终点就是数满了。(以上说的只是定时器的工作方式1,定时器一共有四个工作方式,但是都是大同小异,大家可以先这么了解16位的手动重装模式也就是工作方式1,等有一定理解之后再去了解其他工作模式)。
刚刚上面说的是从0开始数,如果我在一开始给TL0,和TH0填充一个数字,如果填充的数字比较大,那么我们定时的时间就比较短,如果填充的数字比较小那么我们定时的时间就比较长,这也是我们定时器的工作方式,计数器无非就是从外部引脚接收脉冲然后计数,和定时器区别不是很大,这里就不详细介绍了。

定时中断

大家在前面接触过了外部中断,也知道了中断大概是什么个东西,我们对定时器进行定时,我们在生活中也会设定一个定时,定时结束之后我们也许会去起床,也许我们会去学习,那么单片机能干啥呢?他啥都能干啥都不能干,定时器在定时满溢出之后会有一个溢出信号,而这个溢出信号也能进入中断,而这个中断就叫定时器中断,那么我们该怎么操作呢?不要慌在这之前我得先给大家讲一下中断优先级

中断优先级

有一天我们兴奋的在房间里打着游戏,突然自己的外卖到了,我们只能停下我们的游戏走向门口。这是我们之前说过的中断的概念,但是我们走到了门口发现门是关的,我们只能停下走路再去开门,这就是中断里头再中断了,也许这个很好理解,但是大家有没有发现有个优先级的事情,我们在走路的过程中能停下来去开门,但是在开门的过程中不能停下去走路吧,这就是一个优先级的问题,优先级高的能打断优先级低的中断,但是优先级低的不能打断优先级高的,正如优先俩个字。那么51单片机的优先级是什么呢?
在这里插入图片描述
大家不需要看懂这个表的每一个字,只需要知道这个顺序就足够,从上往下优先级依次降低。可能大家在一开始不会用到这个,但是希望大家能知道有这样一个东西。
不过再说一嘴,大家还记得我们中断服务函数后面有一个数字吗,其实那个数字就是这个相同优先级内的查询次序这个数字,大家一开始没必要管那个 你需要用什么中断然后去看一下是哪个数字然后使用就行。

来看代码

#include <reg52.h>

sbit LED = P2^0
void main()
{
   TMOD = 0x01;	//这个是设置定时器模式,这么弄是设置为手动重装模式
   TH0 = (65535-922) /256;	//高八位和第八位预装值 时间是1ms
   TL0 = (65535-922) %256;
   TR0 = 1;	//打开定时器
   ET0 = 1;	//打开定时器中断
   EA = 1;	//打开总中断
   while(1)	//主函数什么都不干
   {
      ;
   }
}

void TIME0() interrupt 1
{
   static int cnt = 0;	//定义一个变量
   TH0 = (65535-1085) /256;	//再一次重装
   TL0 = (65535-1085) %256;
   cnt++;	//变量加一
   if(cnt == 500)	//到500就反转一下灯的状态 这样会看到灯每隔0.5s改变一下状态
   {
   	  LED = ~LED;
      cnt = 0;
   }
      
}

大家肯定对这个有很多的疑惑吧,不要慌我们接下来就慢慢讲解

还记得我们说对TH0和TL0这个设定一个初值吗,我们这里给TH0和TL0赋值就是给他弄一个初值开始计数,那这个初值是怎么算来的呢?
我们在前面说过,我们会有一个机器周期也就是12个时钟周期=12 x 1/12 us =1 us ,这是晶振为12M的如果是11.0592的就是12/11.0592 x 1us,然后我们65536 - 需要时间×12/11.0592 就是我们得到的设定时间,那我对这个数除以256和对256取余是干啥呢,其实就是取出高八位和第八位,没有特别的意思 你可以自己算出来转换这个数也可以,比如说1ms 就是1000 x11.0592 /12 =1085 然后拿65535 - 1085 = 64450 ,然后就拿这个数字取余和除就行,其实如果不好理解的话,可以直接吧这个数字装换成二进制你会发现结果是一样的

TMOD是一个寄存器 控制定时器的模式,0x01的模式就是16位手动重装

下面的那个函数叫中断服务函数,前面也介绍过了重点是我在中断服务函数函数里头重新赋值了TH0和TL0,这是因为溢出之后就会清零,我们需要手动给他重新装载一下值,最后是哪个static,这样写说明这句话只会被定义一次,不然每次进入中断cnt都是0了

写在最后

我太难了,大家要加油我也要加油,觉得自己写的有点不好,希望各位给我提一下意见然后改进吧,后面也会更难!
我是小灰,一个努力用平实的语言写出困难内容的探索者!^ _ ^!

发布了15 篇原创文章 · 获赞 35 · 访问量 3402

猜你喜欢

转载自blog.csdn.net/weixin_44065323/article/details/102648872