【STC单片机学习】第十课:单片机的定时器和计数器

【朱老师课程总结 侵删】

本节课重点:寄存器

第一部分、章节目录

1.10.1.定时器(timer)介绍

1.10.2.软件控制硬件的关键-寄存器

1.10.3.51单片机的定时器简介

1.10.4.定时器的主要寄存器介绍

1.10.5.定时器编程实践1

1.10.6.定时时间设置错误纠正



第二部分、章节介绍


1.10.1.定时器介绍
    本节从大的方面介绍定时器,主要是定时器的工作原理、作用和意义。
1.10.2.软件控制硬件的关键-寄存器
    本节介绍寄存器的概念,通过学习寄存器了解用软件来控制硬件的原理。
1.10.3.51单片机的定时器简介
    本节带大家读51单片机的数据手册中定时器介绍的章节,通过带读数据手册让大家学会定时器的同时学会自己读数据手册。
1.10.4.定时器的主要寄存器介绍1
    本节开始讲解51单片机的定时器相关的寄存器,本节主要是TCON中的TF和TR位、TMOD中的GATE位。
1.10.5.定时器的主要寄存器介绍2
    本节开始讲解51单片机的定时器相关的寄存器,本节主要是TCON中的TF和TR位、TMOD中的GATE位。
1.10.6.定时器的主要寄存器介绍3
    本节讲解剩下的寄存器位。
1.10.7.定时器编程实践1
    本节进行定时器编程实践,参考数据手册中的示例代码进行改写得到自己的代码并且下载进去进行测试验证。
1.10.8.定时器编程实践2
    本节进行定时器编程实践,参考数据手册中的示例代码进行改写得到自己的代码并且下载进去进行测试验证。
1.10.9.定时时间设置错误纠正
    本节补充讲解了51单片机定时器定时时间设置问题,之前的课程中讲错了这个细节的。

    
第三部分、随堂记录

1.10.1.定时器(timer)介绍

1.10.1.1、什么是定时器
(1)SoC(片上系统,可以理解成就是单片机)的一种内部外设
(2)定时器就是CPU的“闹钟”
定时器相对于SoC来说,就好像闹钟相对于人来说意义一样。单核的CPU是单线程的,只能干一件事情,干完这件事情完去干另一件事情需要定时器来提醒。

1.10.1.2、什么是计数器
计数器和定时器其实是一回事
(1)计数器也是soc当中的一个内部外设
(2)计数器顾名思义是用来计数的
例如秒表(指针表)实际上就是一个计数器,每隔一个单位走一个格(就是计一个数),因为秒表的计数时间周期是固定的,因此到了一定时间只要用计数值*计数时间周期,就能得到一个时间段,这个时间段就是我们定的时间(这就是定时器了)。

(3)计数器可以计算外部脉冲个数(脉冲其实就是电平信号通过引脚流进单片机)
查看源图像
每隔多长时间会有一个脉冲,通过计数器得到脉冲个数,就知道时间了!
也就是说:对内部脉冲计数,就叫作定时器;对外部脉冲计数,就叫作计数器。
内部脉冲,是稳定的,每个脉冲相隔时间固定,所以可以定时;
外部脉冲,是很不稳定的,无法得知两个脉冲之间的像个时间,只能计数!

(4)是定时器还是计数器,是通过寄存器来控制的

1.10.1.3、定时器如何工作
(1)第1步:先设置好定时器的时钟源(如果需要的话)
                 时钟源:石英晶体振荡器(晶振)
(2)第2步:初始化时钟相关寄存器
(3)第3步:设置定时时间(计数脉冲个数+每个脉冲时间)
(4)第4步:设置中断处理程序(外部输入优先级高于定时)
例如:主任务看电视,定时器中断程序是烧水!
(5)第5步:打开定时器
(6)运行时:定时器计数到后产生中断,然后执行中断isr

后面看代码会更明白!


1.10.2.软件控制硬件的关键-寄存器

有些硬件怎么被软件控制的呢?靠的就是寄存器!

1.10.2.1、什么是寄存器
(1)register  [reg]  
(2)寄存器

  •    寄存,内容可变,一般按位定义
  •    就相当于一个变量,只不过这个变量在固定的地址,有一个特殊的名称。
  •    寄存器分为通用寄存器(P0...)和特殊功能寄存器(IE...)

(3)寄存器使用地址访问,编程上像内存一样
reg51.h定义的那样!

1.10.2.2、寄存器的工作原理
(1)寄存器和硬件之间有双向影响
说白了,就是寄存器也有IO,和硬件属于输入/输出设备有关!
(2)软件可以读写寄存器
程序可以把值写进寄存器,也可以读取寄存器的值,就比如我们往GPIO的引脚的值,其实我们读的是引脚里面的寄存器。
(3)总结:寄存器是软件能够控制硬件的关键

1.10.2.3、单片机学习的关键就是各种寄存器
寄存器之于单片机就像单词之于英语学习!

(1)单片机的学习主要包括2个:CPU和各种内部外设
(2)各种内部外设的编程接口就是寄存器
(3)熟悉一款单片机其实就是熟悉他的寄存器
(4)寄存器会随着单片机的复杂化而变复杂(STM32和单片机的虽然有差异,但是你去学习的时候,会发现很简单!)
(5)学会用C语言操作寄存器的技巧--关键点
要学会C语言操纵单片机的技巧!


1.10.3.51单片机的定时器简介

参考数据手册P136  定时器/计数器

如果单片机工作在12T模式下!
外部12MHz晶振,则内部时钟频率是1MHz,则时钟脉冲宽度为1us(1/1MHz = 1us)。
 
如果单片机工作在6T模式下
外部12MHz晶振,则内部时钟频率是2MHz,则时钟脉冲宽度为0.5us(1/2MHz = 0.5us)。
 

51的模式和工作方式和繁琐,我们不用记住,过一遍就行,等到学嵌入式STM32的时候,会简单很多!
后几小节,我们重点通过手册来讲一下定时器的主要寄存器


1.10.4.定时器的主要寄存器介绍

MSB大端,LSB小端 P136

1.10.4.1、TCON(Timer Control) 定时器/计数器控制寄存器

0b11000011就是从B7-B0
(1)8个位,但是有4个名字:TF、TR、IE、IT,每个名字的符号都有2个,后面分别带0和1,对应T0和T1.
(2)TF: timer flag,定时器(溢出)标志位

  • 是只读(软件只是通过读取TF1来知道硬件的状态,而不用去写这一位来设置硬件的状态)的。
  • timer定时时间到了后会做2件事情:第一个是把TF标志改为1,第二个是产生中断让CPU去中断处理;当CPU响应之后,TF是硬件清零的(由1变0是自动的,不需要软件来干预。)
  • 有一些CPU的设计是需要软件去清零的(主流单片机),这时候用户的程序就一定要记得给标志位清零,不然反复不停的重复进入中断。
  • =1 溢出,=0 溢出清零

(3)TR:timer run,就是定时器的启动计数的开关。

  • 当我们把整个定时器初始化好了之后,我们给TR位写1就可以开启计数了。但是呢!
  • TR位和GATE位有一定关联性。GATE是TMOD寄存器中的寄存器位,先看一下!

(4)IE: interrupt enable ,外部中断(INTx)请求源标志位

  • 作用就是用来展示硬件的状态改变的。
  • 当INT1发生中断时,硬件自动IE1=1
  • 当CPU处理了INT1中断时硬件会自动给IE1=0(硬件自动清零)。

(5)IT:interrput trigger,外部中断触发方式控制位

  •   是用来设置外部中断的中断触发方式的。
  •    所谓中断的触发方式,就是指硬件在某种条件下才会被判定为要产生中断,所以其实就是中断产生的条件。
  • 中断触发方式一般就是:边沿触发和电平触发2种。边沿触发又分为:上升沿触发、下降沿触发、双边沿触发;电平触发方式分为:高电平触发、低电平触发2种。
  • =0  外部中断1为低电平触发方式,当INTx输入低电平时,IE=1
  • =1  外部中断( INTx )端口由“1”→“0”下降沿跳变时,IE=1

1.10.4.2、TMOD(Timer Mode) 定时器 / 计数器工作模式寄存器

(1)GATE:中文名叫门控位

  • 是TMOD寄存器中的,也有2个分别对应T0和T1。

    工作方式:

  • 当GATE=0时    timer处于定时器工作模式。此时定时器开关就只受TR位影响。具体就是TR=1开启计数,TR=0结束计数。
  • 当GATE=1时,timer处于计数器工作模式。当timer用来计数时,很关键的就是什么条件下计数,什么条件下不计数。所以当GATE=1时是否计数不仅取决于TR1还取决于INT1引脚(P3.3),实际规则是:当TR1=1并且INT1引脚也为高电平时才会计数。

(2)C/T位

  • 设置T0/T1工作在定时器模式还是计数器模式。
  • =1 表示计数器模式
  • =0 表示定时器模式。

(3)M1 + M0
       2个位一起来表示T0/T1处于哪种工作模式下,一般有4种:13位、16位、8位自动重载、双8位。   


1.10.4.3、TLx、THx
TL0+TH0:定时器0的16位寄存器
TL1+TH1:定时器1的16为寄存器
假如说,我们的脉冲宽度是0.5us,我们要定定时0.5ms和4.444ms,则计数分别为:
1000 = 0x3E8 = 高0x3  低0xE8   => TL0 = 0xE8   TH0 = 0x3
8888 = 0x22B8 = 高0x22 低0xB8  => TL0 = 0xB8   TH0 = 0x22

纠正之前的一个错误,溢出就是指的超出定时器的最大位数!

1.10.5.定时器编程实践1

1.10.5.1、实验任务
原来实现闪烁时中间的延迟是用delay函数实现的,在delay的过程中CPU要一直耗在这里不能去做别的事情。这是之前的缺点

中断+定时:
CPU可以去做主任务(静态数码管显示0-F),定时器定时500ms,到了定时的时间就产生中断,在中断处理程序isr中让LED闪烁!!

1.10.5.2、如何编程
1.思路:

(1)定时(timer初始化)

  • 对TMOD赋值,以确定T0的工作模式。
  • 计算定时器计数初值,并将其写入TH0、TL0
  • 开放定时器中断,对ET0和EA赋值
  • 使TR0置位,启动定时器定时。

(2)主程序该干嘛干嘛
(3)中断处理程序

可以在上节课按键中断程序中直接修改!【单片机学习】第九课:按键

2.问题思考:0.5s如何计算出来呢?
     机器周期也就是CPU完成一个基本操作所需要的时间。机器周期=1/单片机的时钟频率。

  • 咱们的单片机外部晶振是12MHz、工作在12T模式下,所以内部时钟频率是1MHz,机器周期是1us。最多能定65535(16位定时器工作模式下)个脉冲,也就是说最大定时时间为65535*1us=65535us=65.535ms
  • 如果要定比较长的时间(譬如500ms),定时器直接是不能满足的,解决办法是多次定时后加起来构成一个长时间

    定时办法:先用定时器定50ms,然后*10
    
而我们定时50ms的初值是多少呢?

  • 12T模式,外部晶振12MHz,内部时钟频率1MHz,内部机器周期:1us
  • 定时个数就是:50ms/1us=50000
  • 初值:要从65535-50000+1(因为实际上计数器计数到65536才溢出)=15536 =0x3CB0开始计数,初值等于0x3CB0
  • TL0 = 0xB0,   TH0 = 0x3C    (也可以这样理解:TH0 = 15536/256,TL0 = 15536%256)

大家一块看这两个图来分析我们需要如何编程!

  • MCU工作在12T,没得选
  • 咱们选用定时器0

工作模式配置

  • 因为是内部时钟计数,相当于定时器模式,GATE = 0
  • 因为是定时器模式,所以C/T = 0
  • 因为选用16位定时器模式,M1 = 0、M0 = 1
  • 综合以上三点:TMOD = 0x01

设置定时器初值(注意看手册,16位定时器模式,TH0和TL0需要重装载)

  • TH0 = 0x3C
  • TL0 = 0xB0

中断使能

  • ET0 = 1
  • EA = 1

定时器/计数器控制配置

  • 允许计数,TR0 = 1
  • 不涉及外部中断,IT、IE不用管
  • IF在计数溢出时,会自动变化,不用管

定时器中断处理程序 参考手册P141

最后程序如下

#include <reg51.h>
 
/**************代码说明**************************
			本程序采用定时器中断方式,实现了静态数码管显示0-F并且每隔0.5s时,LED1闪一次
				P0--静态数码管
				P1.0 LED1
*************************************************/
 
sbit led = P1^0;//LED接在P1.0

unsigned char  CNT = 10;   //每次计数50ms,重复10次
unsigned char  count;
 
// 独立数码管的段码表
unsigned char val[16] = 
{
	0xc0, 0xf9, 0xa4, 0xb0, 
	0x99, 0x92, 0x82, 0xf8, 
	0x80, 0x90, 0x88, 0x83,
	0xc6, 0xa1, 0x86, 0x8e
};

/*************延时函数*************/
void delay()
{
	unsigned char i = 200,j = 100;
	while(i--)
		while(j--);
}
 
/******************************定时器中断服务程序*************************/
void tm0_isr() interrupt 1 using 1
{
		TH0 = 0x3C;
		TL0 = 0xB0;   //手工重载
	
		if (count--== 0)
		{
			// 说明已经中断了10次了,0.5s已经到了
			led = !led;				// LED取反
			count = CNT;
		}
}
 
/***************************主函数*********************************/
void main(void)
{
		unsigned char i = 0;
		/************定时器初始化*************/
		TMOD = 0x01;
		TH0 = 0x3C;
		TL0 = 0xB0;
		ET0 = 1;
		EA = 1;
		TR0 = 1;
	
		led = 1;
		count = CNT; 
	
		while (1)
		{
			//主线任务
			for (i=0; i<16; i++)
			{
				P0 = val[i];
				delay();
			}
		}
}

1.10.6.3、51定时器小工具使用

下载地址:51定时器计算

本节程序下载链接:定时器
本节课结束!

猜你喜欢

转载自blog.csdn.net/qq_27148893/article/details/109690947