51单片机中断和定时器学习

1.中断系统

什么是中断系统?

计算机执行某程序时,发生了紧急事件或有特殊请求,CPU暂停某程序的执行, 转而去处理上述事件或请求,处理完毕后再重新执行某程序的过程叫做中断。

简而言之:就是计算机做一下突发程序,而这种突发就需要某种条件来触发。

数据的输入/输出传送方式:

无条件传送方式:       一方对另一方来说总是准备好的。

查询传送方式(LOOK UP):      传送前一方先查询另一方的状态,若已经准备好就传送,否则就继

续查询/等待。 中断传送方式(IRQ):      一方通过申请中断的方式与另一方进行数据传送。 直接存

储器存取方式(DMA):      双方直接通过总线传送数据, 不经CPU中转。适用于数据量大高速通讯的设备不占用CPU时间。

中断系统结构

 引起CPU中断的根源,称为中断源。中断源向CPU提出的中断请求。CPU暂时中断原来的事务A,转去处理事件B。对事件B处理完毕后,再回到原来被中断的地方(即断点),称为中断返回。实现上述中断功能的部件称为中断系统(中断机构)----->可以理解为整套流程为中断系统

如何去使用单片机的中断系统?

1.51单片机的基础知识

51子系列允许5个中断源:----->(看触发中断的条件)

外部中断源(2个):    

INT0——由P3.2端口线引入,低电平或下降沿引起。    

INT1——由P3.3端口线引入,低电平或下降沿引起。    

这两个外部中断源标志和它们的触发方式控制位由特殊功能寄存器TCON的低4位控制。

内部中断源(3个):    

T0——定时器/计数器0中断,由T0回零溢出引起。    

T1——定时器/计数器1中断,由T1回零溢出引起。    

TI/RI——串行I/O中断,串行端口完成一帧字符发送/接收后引起。    

这3个内部中断源的控制位分别锁存在特殊功能寄存器TCON和SCON中。

2.允许中断

理解:EA是总开关;ET0、ET1、ET2是各定时器中断的小开关;EX0、EX1是外部中断的开关;

 

3.中断配置

解释:IT0、IT1是外部中断触发选择类型,TF0、TF1是定时器溢出标志

4.编写中断处理函数

中断是处理紧急任务的,那么就需要中断处理函数

void int1() interrupt 2  //中断处理函数,加关键字interrupt和入口号

{

中断处理语句

}

interrupt 入口号

实例:

/*********************************************************************************
* 【作    者】:	清翔电子:向量
* 【版    本】:	V1.0
* 【网    站】:	http://www.qxmcu.com/ 
* 【淘宝店铺】:	http://qxmcu.taobao.com/
* 【实验平台】:	清翔 QX-MCS51 单片机开发板
* 【外部晶振】: 	11.0592mhz	
* 【主控芯片】: 	STC89C52
* 【编译环境】: 	Keil μVisio4	
* 【程序功能】: 	外部中断0低电平触发方式,每按下一次S2按键就会进入一次中断,
					LED灯会发生状态变化。		   			            			    
* 【使用说明】: 	用1根杜邦线把P32和P37相接,每按下一次S2按键就会进入一次中断。
**********************************************************************************/
#include <reg52.h>

#define uint unsigned int
#define uchar unsigned char

sbit key_s2 = P3^0;//独立按键S2
sbit flag = P3^7; //外部中断信号产生脚

/*====================================
函数	: delay(uint z)
参数	:z 延时毫秒设定,取值范围0-65535
返回值	:无
描述	:12T/Fosc11.0592M毫秒级延时
====================================*/
void delay(uint z)
{
	uint x,y;
	for(x = z; x > 0; x--)
		for(y = 114; y > 0 ; y--); 		
} 
//外部中断0初始化
void int0Init()
{
	EA = 1;	//开总中断
	EX0 = 1;//开外部中断0
	IT0 = 0;//外部中断0低电平触发	
}

void main()//main函数自身会循环
{
	int0Init();//外部中断0初始化	
	while(1)
	{
		if(key_s2 == 0)//判断S2是否被按下
		{
			delay(20);//按键消抖
			if(key_s2 == 0)
			{
				flag = 0;
				flag = 0;//产生低电平,CPU会采样2次P3.2的状态,两次都为低才触发
				flag = 1;//结束低电平
				while(!key_s2);//松手检测
			}	
		}

	}	
}

//外部中断1中断服务程序
void int0() interrupt 0
{
	P1 = ~P1;//P1的状态按位取反
}  

 

代码解释

p3.4、p3.5是两个外部中断,p3.2,、p3.3是两个内部定时中断,现在我们用外部中断0,

也就是p3.4,初始化选择低电平触发,那这个触发源从哪来?

需要我们人为制造一个发生高低电平变化的信号,也就是按键按下信号发生变化,将这个信号给p3.7引脚,然后将p3.4和p3.7相接,让p3.4引脚读取信号

flag = 0;
flag = 0;

用了两次是为了避免机器周期太快形成的干扰,可以改成为

flag = 0;
delay(5);

好了,我们现在试试用外部中断1试试

/*********************************************************************************
* 【作    者】:	清翔电子:向量
* 【版    本】:	V1.0
* 【网    站】:	http://www.qxmcu.com/ 
* 【淘宝店铺】:	http://qxmcu.taobao.com/
* 【实验平台】:	清翔 QX-MCS51 单片机开发板
* 【外部晶振】: 	11.0592mhz	
* 【主控芯片】: 	STC89C52
* 【编译环境】: 	Keil μVisio4	
* 【程序功能】: 	外部中断1下降沿触发方式,每按下一次S2按键就会进入一次中断,LED
					灯会发生状态变化。		   			            			    
* 【使用说明】: 	用1根杜邦线把P33和P37相接,每按下一次S2按键就会进入一次中断。
**********************************************************************************/
#include <reg52.h>

#define uint unsigned int
#define uchar unsigned char

sbit key_s2 = P3^0;//独立按键S2
sbit flag = P3^7; //外部中断信号产生脚

/*====================================
函数	: delay(uint z)
参数	:z 延时毫秒设定,取值范围0-65535
返回值	:无
描述	:12T/Fosc11.0592M毫秒级延时
====================================*/
void delay(uint z)
{
	uint x,y;
	for(x = z; x > 0; x--)
		for(y = 114; y > 0 ; y--); 		
} 
//外部中断1初始化
void int1Init()
{
	EA = 1;	//开总中断
	EX1 = 1;//开外部中断1
	IT1 = 1;//外部中断1下降沿触发	
}

void main()//main函数自身会循环
{
	int1Init();//外部中断1初始化	
	while(1)
	{
		if(key_s2 == 0)//判断S2是否被按下
		{
			delay(20);//按键消抖
			if(key_s2 == 0)
			{
				flag = 1;
				flag = 0;//产生下降沿
				while(!key_s2);//松手检测
			}	
		}

	}	
}

//外部中断1中断服务程序
void int1() interrupt 2
{
	P1 = ~P1;
}  

 2.定时器

什么是定时/计数器以及用处?

就是一个寄存器,会有机器自动按时产生一个信号,然后该寄存器+1,直到溢出为止,

我们可以通过改变计数的起始值从而改变溢出的时间,完成不同时间的定时

1.51单片机定时器基础

51单片机有2个16位定时器/计数器:定时器0(T0为P3.4)和定时器1(T1为P3.5)

这里所说的16位是指定时/计数器内部分别有16位的计数寄存器。 当工作在定时模式时,每经过一个机器周期内部的16位计数寄存器的值就会加1,当这个寄存器装满时溢出。 我们可以算出工作在定时模式时最高单次定时时间为65535*1.085us=时间(单位us) 当工作在计数器模式时,T0(P3.4引脚),T1(P3.5引脚)每来一个脉冲计数寄存器加1

定时器作用:定时计数器可以用于精确事件定时,PWM脉宽调制,波形发生,信号时序测量的方面。

2.启动定时器(打开开关)

 3.设置定时器

现在不好理解很正常,直接看代码就非常容易理解了

/*********************************************************************************
* 【作    者】:	清翔电子:向量
* 【版    本】:	V1.0
* 【网    站】:	http://www.qxmcu.com/ 
* 【淘宝店铺】:	http://qxmcu.taobao.com/
* 【实验平台】:	清翔 QX-MCS51 单片机开发板
* 【外部晶振】: 	11.0592mhz	
* 【主控芯片】: 	STC89C52
* 【编译环境】: 	Keil μVisio4	
* 【程序功能】: 	定时器0工作模式1 16位定时模式,数码管动态显示0-10,秒表。		   			            			    
* 【使用说明】: 
**********************************************************************************/
#include <reg52.h>
#include <intrins.h>

#define uint unsigned int
#define uchar unsigned char

sbit DU = P2^6;//数码管段选
sbit WE = P2^7;//数码管段选

//共阴数码管段选表0-9
uchar  code tabel[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};

/*====================================
函数	: delay(uint z)
参数	:z 延时毫秒设定,取值范围0-65535
返回值	:无
描述	:12T/Fosc11.0592M毫秒级延时
====================================*/
void delay(uint z)
{
	uint x,y;
	for(x = z; x > 0; x--)
		for(y = 114; y > 0 ; y--); 		
} 

/*====================================
函数	:display(uchar i)
参数	:i 显示数值,取值范围0-255
返回值	:无
描述	:三位共阴数码管动态显示
====================================*/
void display(uchar i)
{
	uchar bai, shi, ge;
	bai = i / 100; //236 / 100  = 2
	shi = i % 100 / 10;	//236 % 100 / 10 = 3
	ge  = i % 10;//236 % 10 =6
	
	//第一位数码管  		
	P0 = 0XFF;//清除断码
	WE = 1;//打开位选锁存器
	P0 = 0XFE; //1111 1110
	WE = 0;//锁存位选数据
	
	DU = 1;//打开段选锁存器
	P0 = tabel[bai];//
	DU = 0;//锁存段选数据
	delay(5);

	//第二位数码管
	P0 = 0XFF;//清除断码
	WE = 1;//打开位选锁存器
	P0 = 0XFD; //1111 1101
	WE = 0;//锁存位选数据
	
	DU = 1;//打开段选锁存器
	P0 = tabel[shi];//
	DU = 0;//锁存段选数据
	delay(5);

	//第三位数码管
	P0 = 0XFF;//清除断码
	WE = 1;//打开位选锁存器
	P0 = 0XFB; //1111 1011
	WE = 0;//锁存位选数据
	
	DU = 1;//打开段选锁存器
	P0 = tabel[ge];//
	DU = 0;//锁存段选数据
	delay(5);
}
//定时器0初始化
void timer0Init()
{
	TR0 = 1;	 //启动定时器0
	TMOD = 0X01; //定时器工作模式1,16位定时器计数模式
	TH0 = 0x4b;
	TL0 = 0xfd; //定时50ms
}

void main()//main函数自身会循环
{	
	uchar mSec, Sec;//毫秒和秒储存变量
	timer0Init();//定时器0初始化
	while(1)
	{
		if(TF0 == 1)//判断是否溢出
		{
			TF0 = 0;//软件清零溢出标志位
			TH0 = 0x4b;
			TL0 = 0xfd; //定时50ms
			mSec++;//50ms到
			if(mSec == 20)
			{
				mSec = 0;
				Sec++;//1秒时间到
			}					
		}
		display(Sec); //数码管显示函数
		if(Sec > 10)
			Sec = 0;//秒清零 
	}	
}  

主要的步骤

初始化: void timer0Init()
{
    TR0 = 1;     //启动定时器0
    TMOD = 0X01; //定时器工作模式1,16位定时器计数模式
    TH0 = 0x4b;
    TL0 = 0xfc; //定时50ms
}

TMOD 是怎么来的?

0000 0001

TH0 和TL0是前后8位

也就是说要计数46083次溢出

那就要从65535-46083 = 19452开始计数

19452的16进制是4B FC

4.定时器计数

/*********************************************************************************
* 【作    者】:	清翔电子:向量
* 【版    本】:	V1.0
* 【网    站】:	http://www.qxmcu.com/ 
* 【淘宝店铺】:	http://qxmcu.taobao.com/
* 【实验平台】:	清翔 QX-MCS51 单片机开发板
* 【外部晶振】: 	11.0592mhz	
* 【主控芯片】: 	STC89C52
* 【编译环境】: 	Keil μVisio4	
* 【程序功能】: 	定时器0工作模式1,16位计数模式,//定时器1工作模式1,16位定时模式		   			            			    
* 【使用说明】: 	用一根杜邦线把P34引脚对应排针与P10引脚对应的排针链接到一起
					P10产生方波 数码管显示方波次数
**********************************************************************************/
#include <reg52.h>
#include <intrins.h>

#define uint unsigned int
#define uchar unsigned char

sbit DU = P2^6;//数码管段选
sbit WE = P2^7;//数码管段选
sbit LED1 = P1^0;//LED1
//共阴数码管段选表0-9
uchar  code tabel[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};

/*====================================
函数	: delay(uint z)
参数	:z 延时毫秒设定,取值范围0-65535
返回值	:无
描述	:12T/Fosc11.0592M毫秒级延时
====================================*/
void delay(uint z)
{
	uint x,y;
	for(x = z; x > 0; x--)
		for(y = 114; y > 0 ; y--); 		
} 

/*====================================
函数	:display(uchar i)
参数	:i 显示数值,取值范围0-255
返回值	:无
描述	:三位共阴数码管动态显示
====================================*/
void display(uchar i)
{
	uchar bai, shi, ge;
	bai = i / 100; //236 / 100  = 2
	shi = i % 100 / 10;	//236 % 100 / 10 = 3
	ge  = i % 10;//236 % 10 =6
	
	//第一位数码管  		
	P0 = 0XFF;//清除断码
	WE = 1;//打开位选锁存器
	P0 = 0XFE; //1111 1110
	WE = 0;//锁存位选数据
	
	DU = 1;//打开段选锁存器
	P0 = tabel[bai];//
	DU = 0;//锁存段选数据
	delay(5);

	//第二位数码管
	P0 = 0XFF;//清除断码
	WE = 1;//打开位选锁存器
	P0 = 0XFD; //1111 1101
	WE = 0;//锁存位选数据
	
	DU = 1;//打开段选锁存器
	P0 = tabel[shi];//
	DU = 0;//锁存段选数据
	delay(5);

	//第三位数码管
	P0 = 0XFF;//清除断码
	WE = 1;//打开位选锁存器
	P0 = 0XFB; //1111 1011
	WE = 0;//锁存位选数据
	
	DU = 1;//打开段选锁存器
	P0 = tabel[ge];//
	DU = 0;//锁存段选数据
	delay(5);
}
//定时器0初始化
void timer0Init()
{
	TR0 = 1;	 //启动定时器0
	TMOD |= 0X05; //定时器0工作模式1,16位计数模式
	TH0 = 0;
	TL0 = 0; 
}

//定时器1初始化
void timer1Init()
{
	TR1 = 1;	 //启动定时器1
	TMOD |= 0X10; //定时器1工作模式1,16位定时模式
	TH1 = 0x4b;
	TL1 = 0xfd; //定时50ms

}

void main()//main函数自身会循环
{	
	uchar mSec, Sec;//毫秒和秒储存变量
	timer0Init();//定时器0初始化
	timer1Init();//定时器1初始化
	while(1)
	{
		if(TF1 == 1)//判断是否溢出
		{
			TF1 = 0;//软件清零溢出标志位
			TH1 = 0x4b;
			TL1 = 0xfd; //定时50ms
			mSec++;//50ms到
			if(mSec == 10) //定时50毫秒到
			{
				mSec = 0;
				LED1 = ~LED1;//产生方波
			}					
		}
		display(TL0); //数码管显示函数
	}	
}  

解释:计数器就是读取电平变化来计数,将p3.4和p1相接

                TMOD |= 0X05;TMOD |= 0X10;防止取代原本位置,等同于TM0D = 0X15;

5.定时器中断

/*
定时器0工作模式1 16位定时计数
数码管动态显示0-10,每隔1秒显示一次
*/
/*********************************************************************************
* 【作    者】:	清翔电子:向量
* 【版    本】:	V1.0
* 【网    站】:	http://www.qxmcu.com/ 
* 【淘宝店铺】:	http://qxmcu.taobao.com/
* 【实验平台】:	清翔 QX-MCS51 单片机开发板
* 【外部晶振】: 	11.0592mhz	
* 【主控芯片】: 	STC89C52
* 【编译环境】: 	Keil μVisio4	
* 【程序功能】: 	定时器0工作模式1 16位定时计数,中断方式响应。
					三位数码管动态扫描,定时器0中断方式扫描。		   			            			    
* 【使用说明】: 	按下S2按键数码管值加一,最大加到120.
					按下S3数码管值减一,最小减到0.
**********************************************************************************/
#include <reg52.h>
#include <intrins.h>

#define uint unsigned int
#define uchar unsigned char

sbit DU = P2^6;//数码管段选
sbit WE = P2^7;//数码管段选
sbit key_s2 = P3^0;//独立按键S2
sbit key_s3 = P3^1;//独立按键S3
uchar num;//数码管显示的值
uchar mSec, Sec;//毫秒和秒储存变量

//共阴数码管段选表0-9
uchar code SMGduan[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};
//数码管位选码
uchar code SMGwei[] = {0xfe, 0xfd, 0xfb};

/*====================================
函数	: delay(uint z)
参数	:z 延时毫秒设定,取值范围0-65535
返回值	:无
描述	:12T/Fosc11.0592M毫秒级延时
====================================*/
void delay(uint z)
{
	uint x,y;
	for(x = z; x > 0; x--)
		for(y = 114; y > 0 ; y--); 		
} 

/*====================================
函数	:display(uchar i)
参数	:i 显示数值,取值范围0-255
返回值	:无
描述	:三位共阴数码管动态显示
====================================*/
void display(uchar i)
{
	static uchar wei; 		
	P0 = 0XFF;//清除断码
	WE = 1;//打开位选锁存器
	P0 = SMGwei[wei];
	WE = 0;//锁存位选数据
	switch(wei)
	{
		case 0: DU = 1; P0 = SMGduan[i / 100]; DU = 0; break;
		case 1: DU = 1; P0 = SMGduan[i % 100 / 10]; DU = 0; break;	
		case 2: DU = 1; P0 = SMGduan[i % 10]; DU = 0; break;		
	}
	wei++;
	if(wei == 3)
		wei = 0;
}
//定时器0初始化
void timer0Init()
{
	EA = 1;	//打开总中断
	ET0 = 1;//打开定时器0中断
	TR0 = 1;	 //启动定时器0
	TMOD = 0X01; //定时器工作模式1,16位定时模式
	TH0 = 0xED;
	TL0 = 0xFF; //定时5ms
}

void main()//main函数自身会循环
{	
	timer0Init();//定时器0初始化
	while(1)
	{
		if(key_s2 == 0)//判断S2是否被按下
		{
			delay(20);//按键消抖
			if(key_s2 == 0)
			{
				if(num != 120)
				num++;
				while(!key_s2);//松手检测
			}	
		}
		if(key_s3 == 0)//判断S3是否被按下
		{
			delay(20);//按键消抖
			if(key_s3 == 0)
			{
				if(num > 0)
					num--;
				while(!key_s3);//松手检测
			}	
		}
	}	
} 

//定时器0中断函数
void timer0() interrupt 1
{
	TH0 = 0xED;
	TL0 = 0xFF; //定时5ms
	display(num); //数码管显示函数	
} 
  • 18
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值