51单片机定时器和中断(六)

目录

一、定时器和中断介绍

1、定时器

(1)定时器介绍

(2)定时器作用

(3)STC89C52定时器资源

(4)定时器框图

(5)定时器的工作模式

2、中断系统

(1)关于中断系统的几个概念

(2)中断程序流程

(3)STC89C52中断资源

(4)定时器和中断系统

3、定时器和中断相关寄存器

(1)定时/计数器0和1的相关寄存器

(3)中断寄存器

二、按键控制LED流水灯模式

1、对定时/计数器赋初值

2、编写程序每隔1s,使LED1闪烁

3、编写程序按键控制LED流水灯模式

4、成果展示

三、定时器时钟

1、编写程序

2、成果展示


一、定时器和中断介绍

1、定时器

(1)定时器介绍

51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成。

(2)定时器作用

:用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作

:替代长时间的Delay函数,提高CPU的运行效率和处理速度

(3)STC89C52定时器资源

:定时器个数:3个(T0、T1、T2),T0和T1与传统的51单片机操作方式一样,T2是此型号单片机增加的资源。

:注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式是所有51单片机所共有的

(4)定时器框图

定时器在单片机内部就像一个小闹钟一样,根据时钟的输出信号,每隔“一个时间段”,计数单元的数值就增加1,当计数单元数值增加到“设定的闹钟题型时间”时,计数单元就会向中断系统发出中断申请,产生“响铃提醒”,使程序跳转到中断服务函数中执行。

(5)定时器的工作模式

STC89C52的T0和T1均有四种工作模式:

模式0:13位定时器/计数器

模式1:16位定时器/计数器(常用)

模式2:8位自动重装模式

模式3:两个8位计数器

定时器时钟SYSclk:系统时钟,即晶振周期,本开发板上的晶振为12MHZ。经第一条线路12分频后,1MHZ的倒数就是1us,这1us也就是单片机的机器周期,也是计数器自动加1的时间。

时钟中的是模式选择位,=0时为定时模式,=1为计数模式。

 左上角时钟电路提供脉冲信号,由TH0和TL0组成的16位计数器,每收到一个脉冲周期,就会自动加1,当计数器达到最大值65535时,会产生计数溢出,会立刻将溢出标志位TF0置1,向中断系统申请中断,然后计数器重新从0开始计数

当门控位GATE=0时,只要软件使运行控制位TR0为1,就可启动定时/计数器开始工作;当门控位GATE=1时,只要软件使运行控制位TR0为1,同时引脚为高电平时,才能启动定时/计数器工作。

2、中断系统

(1)关于中断系统的几个概念

当中央处理器CPU正在处理某件事的时候,外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断

实现这种功能的部件称为中断系统。中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的。

请示CPU中断的请求源称为中断源。单片机的中断系统一般允许有多个中断源,当几个中断源同时向CPU请求中断,要求为它服务的时候,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急的中断请求源,即规定每一个中断源有一个优先级别。CPU总是先响应优先级别最高的中断请求。

当CPU正在处理一个中断源请求的时候(正在执行相应的中断服务程序),发生了另外一个优先级比它还高的中断源请求。如果CPU能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低级中断服务程序,这样的过程称为中断嵌套。                   (即在执行一个中断时,里面还有一个优先级更高的中断)

这样的中断系统称为多级中断系统,没有中断嵌套功能的中断系统称为单级中断系统

(2)中断程序流程

(3)STC89C52中断资源

中断源个数8个外部中断0、定时器中断0,外部中断1、定时器中断1、串行口中断、                定时器中断2、外部中断2、外部中断3。(传统51单片机只有前面5个中断源)

中断优先级个数:4个优先级(传统51单片机只有两个,高优先级和低优先级)

中断号

 注意:中断的资源和单片机型号是关联在一起的,不同的型号可能会有不同的中断资源,例如中断源个数不同、中断优先级个数不同等等。

(4)定时器和中断系统

 Ⅰ:外部中断请求有两种信号形式

负跳脉冲触发方式(下降沿触发):电平有下降的趋势就会触发中断;

低电平触发:电平保持一段时间,检测到电平上升,才会触发中断。

ITx(这里的x包括0和1)是外部中断请求触发方式控制位:

ITx=0时,采用低电平触发方式;

ITx=1时,采用下降沿触发方式。

IEx是外部中断请求标志:

当CPU采集到端有效的中断请求后,IEx由硬件置1,在中断响应期间,由硬件自动清零。

(硬件置1指单片机自动操作,软件置1指需要人为在程序中设置)

EX0和EX1是外部中断允许控制位:

为0时,禁止外部中断,为1时,允许外部中断。

EA是中断允许总控制位:

EA=0时,中断总禁止,禁止所有中断,即不响应任何中断请求;

EA=1时,中断总允许,总允许后中断的禁止或允许由各中断源的中断允许控制位进行设置。

PX0和PX1是外部中断优先级设定位:

为1时,相应外部中断为高优先级中断;为0时,相应外部中断为低优先级中断。

Ⅱ:定时器中断T0和T1

TFx为溢出标志位:

当定时/计数器发生溢出时,TFx硬件置1,并向CPU申请中断,响应中断后,TFx由硬件自动清零。

ETx是定时/计数器Tx中断允许控制位:

为0时,禁止中断,为1时,允许中断。

PTx是定时/计数器Tx中断优先级设定位:

为1时,相应中断为高优先级中断;为0时,相应中断为低优先级中断。

Ⅲ:串行口中断

TI:串行发送中断

RI:串行接收中断

ES:串行中断允许控制位

PS:串行中断优先级设定位

3、定时器和中断相关寄存器

寄存器是连接软硬件的媒介,相当于复杂机器的“操作按钮”。

在单片机中寄存器就是一段特殊的数据存储器,一方面寄存器可以存储和读取数据,另一方面,每一个寄存器背后都连接了一根导线,控制着电路的连接方式。

(1)定时/计数器0和1的相关寄存器

TMOD不可位寻址寄存器,所以在C语言中,只能整体赋值;

TCON可位寻址寄存器,在C语言中,可以直接对具体位赋值

THx:放入定时/计数器的高八位;

TLx:放入定时/计数器的低八位;

(3)中断寄存器

二、按键控制LED流水灯模式

1、对定时/计数器赋初值

处于工作方式1的定时/计数器共16位,计数值范围为0~65535,由于89C52RC单片机晶振为11.0592MHZ,12分频后为频率为1M,频率1M的倒数就是机器周期1us,因此每隔1us,定时/计数器就计数加1,要想定时/计数器每隔1ms就申请中断,则需要将64535赋值给THx和TLx,溢出差值正好是1000,所以计数时间为1ms。

TH0=64535/256;    //将高8位放入TH0
TL0=64535%256;    //将低8位放入TL0

也可通过STC-ISP烧录程序软件,自带工具设置初值

 89C52RC单片机中,设置系统频率为12MHZ,定时器模式一般选择16位,定时器时钟一般选择12T,选择好定时器,以及设置好定时长度后,点击生成C代码。

其中AUXR是新版本的单片机才使用的,这里我使用的单片机不需要这行设定,所以把初始化函数中第一行删除。

这里还漏了中断的初始化操作,所以也需要在后面加上中断初始化。

void Timer0Init(void)		//定时器T0,1ms计数溢出,申请中断
{
	TMOD &= 0xF0;		//设置定时器模式
                    //这里是将定时器的初值直接计算出来后,换成16进制赋值
	TL0 = 0x20;		//设置定时初值
	TH0 = 0xD1;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时

    EA=1;            //中断允许总控制位
    ET0=1;			//T0中断允许控制位
	PT0=0;			//T0中断优先级设定位
}

2、编写程序每隔1s,使LED1闪烁

#include <REGX52.H>

void Timer0_Init()	//定时器T0初始化,Init一般用于初始化
{
	TMOD=0x01;		//0000 0001,不可位寻址
					//前面4位数控制T0,后面四位数T1
					//第一位GATA默认为0,第二位0为定时器模式,1为计数器模式
					//第3和第4位为01,则表示用第1种工作方式,也就是16位定时/计数器
					//TCON可位寻址,直接对“位赋值”
	TF0=0;			//溢出标志位
	TR0=1;			//定时/计数器0开始工作
	TH0=64535/256;	//对定时器0赋初值,使T0每隔1ms就计数溢出
	TL0=64535%256;	//TH0放高8位,TL0放低8位
	EA=1; 			//中断允许总控制位
	ET0=1;			//T0中断允许控制位
	PT0=0;			//T0中断优先级设定位
}

void main()
{
	Timer0_Init();
	while(1)
	{
	
	}
}

unsigned int T0Count;    //在函数外面,为全局变量,在函数里面,为局部变量,只有函数内有效
	
void Timer0_Routine() interrupt 1	//定时器T0的中断函数,当T0计数1ms溢出,就会跳到中断函数
{
 	TH0=64535/256;		//每次中断后,都要重新赋初值,不然中断响应后,定时/计数器会从0开始计数
	TL0=64535%256;
	T0Count++;
	if(T0Count>=1000)	//当计数超过1000次,也就是1s时,使P2_0取反
	{
		T0Count=0;
		P2_0=~P2_0;
	}
}

3、编写程序按键控制LED流水灯模式

main.c主函数

#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>	//函数库

unsigned char KeyNum,LEDMode;

void main()
{
	P2=0xFE;				//1111 1110赋值给P2
	Timer0Init();
	while(1)
	{
		KeyNum=Key();		//获取独立按键键码
		if(KeyNum)			//如果按键按下
		{
			if(KeyNum==1)	//如果K1按键按下
			{
				LEDMode++;		//每次按键D1,会使LEDMode在0和1之间循环
				if(LEDMode>=2)LEDMode=0;	
			}
		}
	}
}

void Timer0_Routine() interrupt 1	//定时器T0的中断函数,当T0计数1ms溢出,就会跳到中断函数
{
	static unsigned int T0Count;	//如果没有static,在函数内定义T0Count是局部变量
									//在函数结束之后,会销毁,再申请的局部变量,就不是上次继续的值
									//static是使T0Count为静态变量,使得退出程序以后,变量还能保留
									//与全局变量区别在于,这个变量只能本函数使用

	TL0 = 0x18;						//每次中断响应后,都要重新赋初值
	TH0 = 0xFC;		
	T0Count++;						//每次中断响应后,T0Count会自动加1
	if(T0Count>=500)				//当计数溢出超过500次,也就是0.5s时,执行下面操作
	{
		T0Count=0;
		if(LEDMode==0)				//模式判断
			P2=_crol_(P2,1);		//_crol_(A,x)函数,使A里面的二进制数向左移x位
		if(LEDMode==1)
			P2=_cror_(P2,1);		//_cror_(A,x)函数,使A里面的二进制数向右移x位
	}
}

定时器Timer0模块

#include <REGX52.H>

/**
  * @brief  定时器0初始化,定时1ms计数溢出
  * @param  无
  * @retval 无
  */
void Timer0Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//使TMOD低四位为0001,高四位保持不变
	TL0 = 0x18;			//计算出定时器初值,转化成16进制,再赋值给TLx和THx
	TH0 = 0xFC;		
	
	TF0 = 0;			//清除TF0计数溢出标志位
	TR0 = 1;			//定时器0开始计时
	
	ET0=1;				//中断允许总控制位
	EA=1;				//T0中断允许控制位
	PT0=0;				//T0中断优先级设定位
}

/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		
	}
}
*/

独立按键Key模块

#include <REGX52.H>
#include "Delay.h"

/**
  * @brief  获取独立按键键码
  * @param  无
  * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0
  */
unsigned char Key()
{
	unsigned char KeyNumber=0;
	
	if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
	if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
	if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
	if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
	
	return KeyNumber;
}

延迟函数Delay模块


void Delay(unsigned int xms)
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}

4、成果展示

按键控制LED流水灯模式


三、定时器时钟

1、编写程序

主函数main、Delay模块、LCD1602模块、TImer0模块,后面三个模块之前有写,就不重复了。

#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer0.h"

unsigned char Second=55,Minute=59,Hour=23;	//秒,分钟,小时

void main()
{
	LCD_Init();
	Timer0_Init();
	LCD_ShowString(1,1,"Clock:");
	LCD_ShowString(2,3,":");
	LCD_ShowString(2,6,":");

	while(1)
	{
		LCD_ShowNum(2,1,Hour,2);
		LCD_ShowNum(2,4,Minute,2);
		LCD_ShowNum(2,7,Second,2);
	}
}

void Timer0_Routine() interrupt 1	//定时器T0的中断函数,当T0计数1ms溢出,就会跳到中断函数
{
	static unsigned int T0Count;
	TL0 = 0x18;						//每次溢出都要重新赋初值
	TH0 = 0xFC;		
	T0Count++;
	if(T0Count>=1000)				//定时器溢出1000次时,也就是每秒会执行下面功能
	{
		T0Count=0;
		Second++;
		if(Second>=60)
		{
			Second=0;
			Minute++;
				if(Minute>=60)
				{
					Minute=0;
					Hour++;
					if(Hour>=24)
						Hour=0;
				}
		}
	}
}

2、成果展示

定时器时钟

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

剑鞘的流苏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值