51单片机复习002

http://blog.csdn.net/dragon12345666/article/details/22315025  对应程序例程文件地址

1、AT89S52的6个中断源

2个外部中断:INT0 (对应引脚 P3^2) , INT1 (对应引脚 P3^3)

3个片内定时器/计数器中断:T0 (P3^4) , T1(P3^5)  [TF0,TF1,(TF2)]

1个串行口中断:TI/RI


2、AT89S52外部中断:INT0 , INT1

配置1:定时器/中断控制寄存器 TCON  (88H)

TCON : 

TF1TR1TF0TR0IE1IT1IE0IT0
---------------------------------------------------------------------------------------------------------

TF1 、TF0 : 定时器0、1溢出中断申请标志位

                  = 0 没溢出 , = 1 溢出-->申请中断-->进入中断后标志位自动清零

IR1 、 IR0 : 定时器运行的启动/停止控制位

                  = 0 停止运行 , = 1 启动定时器

---------------------------------------------------------------------------------------------------------

IE0 、IE1 : 外部中断的中断请求标志位

                 = 0 无外部中断申请 , =1有外部中断INT0 或 INT1中断申请

IT0 , IT1 : 外部中断请求的触发方式的设置位

                 = 0 低电平触发 , = 1 负跳变触发(下降沿触发)

---------------------------------------------------------------------------------------------------------


配置2:中断允许寄存器 IE  (0A8H)

IE :

EAET2ESET1EX1ET0EX0
EA : 总中断开关

       = 1 时,允许有中断产生 , = 0 时,禁止全部中断

各具体中断开关 :ET2 ES ET1 EX1 ET0 EX0

       = 1 , 开对应中断 , =0时,禁止对应中断


配置3:中断优先级控制寄存器 IP  (0B8H)

IP : 

PT2PSPT1PX1PT0PX0
          = 1 设置为高优先级

          = 0 设置为低优先级

  不设置:默认为低优先级




外部中断INT0 、INT1初始化函数如下:

/******************************************************************************
 *	名称:INT_0_1_Init()
 *	功能:初始化外部中断 INT0 和 INT1
 *	参数:无
 *	返回:无
 ******************************************************************************/
 void INT_0_1_Init(void)
 {
 	/*------------------初始化中断-------------------*/

	 //1、配置定时器中断控制寄存器 TCON :
		// TCON: TF1, TR1, TF0, TR0,| IE1, IT1, IE0, IT0
		IT0 = 0 ; //低电平触发
		IT1 = 0 ;
	
	//2、配置中断允许寄存器 IE :
		// IE: EA, - , ET2, ES, ET1, EX1, ET0, EX0
		EA = 1 ;
		EX0 = 1 ;
		EX1 = 1 ;
	
	//3、配置优先级控制寄存器 IP :(可不配置,默认按低优先级列表顺序排优先级)
		// IP: - , - , PT2, PS, PT1, PX1, PT0, PX0
		IP = 0x00 ;
 }

中断服务程序如下:

/******************************************************************************
 *	名称:	void SMG_NUM_int1(void)
 *	功能:	中断服务程序,实现数码管上的数值增加
 *	修饰符 1:interrupt 2 :将该函数转化成中断INT1的中断服务程序
 *	修饰符 2:using 1 :本函数内使用工作寄存器组1 ,最好省略不写,系统自动分配
 ******************************************************************************/
void SMG_NUM_int1(void) interrupt 2 
{
//1、判断是否中断源有按键按下,对按键进行软件消抖 (单片机INT1引脚接了独立按键)
	if(INT1_KEY == 0)
	{
		delay1ms(15) ;
		if(INT1_KEY == 0)
		{	
		//2、等待按键释放
			while(!INT1_KEY)
			{ ; }
		//3、按键释放后,key_num 减 1		
			if(key_num > 0)
			{
				key_num -- ;
			}
			else
			{
				key_num = 0 ;
			}
			display_num(key_num);

		}
	}

}

完整外部中断程序:

参照 http://blog.csdn.net/dragon12345666/article/details/22315025  中的程序示例 1、2




3、AT89S52的定时器和计数器


注意:1、16位计数器,计数的最大范围:0 ----> 65536 ( 2 的 16 次方 )

           2、定时器是通过对机器周期脉冲的计数来实现定时的。

                 机器频率 = 晶振频率 f晶振/12 ;  (12分频)

                 机器周期 = (1 / f晶振)* 12 ;

如:12M的晶振,一个机器周期就是1us 。



4、AT89S52的3个定时器 T0 T1 T2 ,2中模式:查询模式、中断模式 , 4种工作方式。

定时器方式寄存器 TMOD  (89H)

TMOD : (T1----T0)

GATEC/T~M1M0GATEC/T~M1M0
------------------------------------------------------------------------------------------------------

       M1  ,M0 

    =  0    0  工作方式0:13位定时器(主要和老单片机8048、8748等兼容);

    =  0    1 工作方式1:16位定时器;  

    =  1    0 工作方式2: 可自动重装的8位定时器; 

    =  1   1 工作方式3: 将T0分为2个8位的定时器,但此时T1不能工作。

------------------------------------------------------------------------------------------------------

C/T~ : 定时器/计数器 选择位   (参照下图分析)

= 1 : 外部事件计数器 (对T0/T1对应管脚的负脉冲进行计数)

= 0 : 片时钟定时器 (对机器周期脉冲计数来实现定时

------------------------------------------------------------------------------------------------------

GATE : 门控置位    (参照下图分析)

= 0 : Timer的启动/停止由软件对 TR0/TR1 写 1 或 0 来控制

= 1 : Timer的启动/停止由外部中断INTx 和 软件对TRx写 1 或 0 共同控制

(INTx 和 TRx 同时为1时,Tx运行,否则不运行)

------------------------------------------------------------------------------------------------------


定时器T0 -- 查询模式 -- 工作方式1 初始化程序段如下:

/******************************************************************************
 *	名称:ScanMode_T0_Init()
 *	功能:定时器T0 查询模式 工作方式1 , 定时50ms
 *	参数:无
 *	返回:无
 ******************************************************************************/
 void ScanMode_T0_Init(void)
 {
 	/*------------------初始化定时器T0 查询模式 工作方式1-------------------*/

	 //1、配置定时器方式寄存器 TMOD :
		// TMOD: GATE, C/T~, M1, M0,| GATE, C/T~, M1, M0  (T1 | T0)
		TMOD = 0x01 ; //0000 0010 :T0 定时器 , 工作方式1 16位定时器
	
	//2、给定时器赋初值 :
		TH0 = (65536 - 50000) / 256 ;	//定时时长50,000us 
		TL0 = (65536 - 50000) % 256 ;	//定时器初值为 65536 - 50000
	
	//3、配置定时器中断控制寄存器 TCON :
		// TCON: TF1, TR1, TF0, TR0,| IE1, IT1, IE0, IT0 
		TF0 = 0 ;  //清零定时器T0溢出标志位
		TR0 = 1 ;  //运行定时器T0
 }


完整程序参考我的文档  http://blog.csdn.net/dragon12345666/article/details/22315025#t2  程序例程 3

定时器T0 -- 中断模式 -- 工作方式1 初始化程序段如下:

/******************************************************************************
 *	名称:InterruptMode_T0_Init()
 *	功能:定时器T0 中断模式 工作方式1 , 定时50ms
 *	参数:无
 *	返回:无
 ******************************************************************************/
 void InterruptMode_T0_Init(void)
 {
 	/*------------------初始化定时器T0 中断模式 工作方式1-------------------*/

	 //1、配置中断允许寄存器 IE :
	 	// IE: EA, - , ET2, ES, ET1, EX1, ET0, EX0
		EA = 1 ;   //开总中断
		ET0 = 1 ;  //允许定时器ET0产生中断
	 
	 //2、配置定时器方式寄存器 TMOD :
		// TMOD: GATE, C/T~, M1, M0,| GATE, C/T~, M1, M0  (T1 | T0)
		TMOD = 0x01 ; //0000 0010 :T0 定时器 , 工作方式1 16位定时器
	
	//2、给定时器赋初值 :
		TH0 = (65536 - 50000) / 256 ;	//定时时长50,000us 
		TL0 = (65536 - 50000) % 256 ;	//定时器初值为 65536 - 50000
	
	//3、配置定时器(中断)控制寄存器 TCON :
		// TCON: TF1, TR1, TF0, TR0,| IE1, IT1, IE0, IT0 
		TR0 = 1 ;  //运行定时器T0
 }
写定时器 T0 的中断服务程序

/******************************************************************************
 *	名称:	void LED_InterruptMode_T0(void)
 *	功能:	定时器T0中断服务程序,实现P0口的8位LED按2Hz频率闪烁
 *	修饰符 1:interrupt 1 :将该函数转化成定时器中断T0的中断服务程序
 *	修饰符 2:using 1 :本函数内使用工作寄存器组 1 , 可省略不写,系统自动分配
 ******************************************************************************/
void LED_InterruptMode_T0(void) interrupt 1
{
	int i ;
	i++ ;
	//定时器工作在中断方式,溢出申请中断,进入中断后溢出位自动清零(硬件实现)
	TH0 = (65536 - 50000) / 256 ;
	TL0 = (65536 - 50000) % 256 ;

	if(i % 5 == 0)
	{
		P0 = ~P0 ;
		i = 0 ;
	}
}


完整程序参考我的文档 http://blog.csdn.net/dragon12345666/article/details/22315025#t2  程序例程 4


定时器T0 --> 工作方式2 --> 查询模式       8位自动重装定时器    初始化函数

/******************************************************************************
 *	名称:ScanMode_T0_Init()
 *	功能:定时器T0 查询模式 工作方式1 , 定时50ms
 *	参数:无
 *	返回:无
 ******************************************************************************/
 void ScanMode_T0_Init(void)
 {
 	/*------------------初始化定时器T0 查询模式 工作方式1-------------------*/

	 //1、配置定时器方式寄存器 TMOD :
		// TMOD: GATE, C/T~, M1, M0,| GATE, C/T~, M1, M0  (T1 | T0)
		TMOD = 0x02 ; //0000 0010 :T0 定时器 , 工作方式2 8位自动重装定时器
	
	//2、给定时器赋初值 :
		TL0 = 256 - 200 ;	//定时时长200us 
		TH0 = TL0 ;
	
	//3、配置定时器中断控制寄存器 TCON :
		// TCON: TF1, TR1, TF0, TR0,| IE1, IT1, IE0, IT0 
		TF0 = 0 ;  //清零定时器T0溢出标志位
		TR0 = 1 ;  //运行定时器T0
 }



定时器T0 --> 工作方式2 --> 中断模式       8位自动重装定时器    初始化函数

/******************************************************************************
 *	名称:ScanMode_T0_Init()
 *	功能:定时器T0 中断模式 工作方式2 , 定时0.5ms
 *	参数:无
 *	返回:无
 ******************************************************************************/
 void InterruptMode_T0_Init(void)
 {
 	/*------------------初始化定时器T0 中断模式 工作方式1-------------------*/

	 //1、配置中断允许寄存器 IE :
	 	// IE: EA, - , ET2, ES, ET1, EX1, ET0, EX0
		EA = 1 ;   //开总中断
		ET0 = 1 ;  //允许定时器ET0产生中断
	 
	 //2、配置定时器方式寄存器 TMOD :
		// TMOD: GATE, C/T~, M1, M0,| GATE, C/T~, M1, M0  (T1 | T0)
		TMOD = 0x02 ; //0000 0010 :T0 定时器 , 工作方式2 8位自动重装定时器
	
	//2、给定时器赋初值 :
		TL0 = 256 - 200 ;	//定时时长200us 
		TH0 = TL0 ;
	
	//3、配置定时器(中断)控制寄存器 TCON :
		// TCON: TF1, TR1, TF0, TR0,| IE1, IT1, IE0, IT0 
		TR0 = 1 ;  //运行定时器T0
 }



5、while(1) { ... }  和  while(变量 != 某值) { ... } 的区别。(昨晚犯了一个很二的错误)

单片机、嵌入式的程序必须都是嵌套在一个死循环里执行,因为不可能让芯片没执行一次程序都再给芯片重烧一次程序吧。

while(1) { ... } 是一个死循环;但是 while(变量 != 某值) { ... } 却不一定是一个死循环,因为当“变量 == 某值 ”的时候,while的判断条件将不再满足,跳出循环。

所以在基于芯片写程序时,如果while的判断条件是一个表达式,则最好不要用其作为程序执行的死循环的外壳,解决办法:在其外侧再加一个while(1) { ... } 这样的死循环。

比如我想让AT89S52单片机的P0端口的8个LED灯按照1Hz的频率闪烁,下面一段程序却无法实现:


/******************************************************************************
 *	说明:AT89S52芯片,12M晶振
 *	初始化定时器T0 --> 查询模式 --> 工作方式1
 *	给定时器赋初值前,必须清零溢出标志位 , 
 *  通过定义变量 和 定时器 配合增加延时时长
 *	本程序:通过定时器工作在查询模式,实现P0口LED灯的状态每隔0.5s翻转一次
 ******************************************************************************/

#include<reg52.h>


/******************************************************************************
 *	名称:ScanMode_T0_Init()
 *	功能:定时器T0 查询模式 工作方式1 , 定时50ms
 *	参数:无
 *	返回:无
 ******************************************************************************/
 void ScanMode_T0_Init(void)
 {
 	/*------------------初始化定时器T0 查询模式 工作方式1-------------------*/

	 //1、配置定时器方式寄存器 TMOD :
		// TMOD: GATE, C/T~, M1, M0,| GATE, C/T~, M1, M0  (T1 | T0)
		TMOD = 0x01 ; //0000 0010 :T0 定时器 , 工作方式1 16位定时器
	
	//2、给定时器赋初值 :
		TH0 = (65536 - 50000) / 256 ;	//定时时长50,000us 
		TL0 = (65536 - 50000) % 256 ;	//定时器初值为 65536 - 50000
	
	//3、配置定时器中断控制寄存器 TCON :
		// TCON: TF1, TR1, TF0, TR0,| IE1, IT1, IE0, IT0 
		TF0 = 0 ;  //清零定时器T0溢出标志位
		TR0 = 1 ;  //运行定时器T0
 }


void main(void)
{
	int i = 0 ;
	ScanMode_T0_Init() ;	//初始化定时器T0 , 查询模式,工作方式1,16位定时器
	P0 = 0x00 ;	//点亮P0口的LED灯

	while(TF0 == 1)
	{
		TF0 = 0 ; //定时器,查询模式,定时器赋初值前必须清零溢出标志位
		TH0 = (65536 - 50000) / 256 ;
		TL0 = (65536 - 50000) % 256 ;
		TR0 = 1;  //赋初值后,运行定时器
		
		i++ ;
		if(i%10 == 0) //每个10*50,000us = 0.5s , P0口状态翻转一次
		{
			P0 = ~P0 ;			
		}


	}	

		
}

原因:只有当定时器T0溢出时,while(TF0 == 1)的判断条件才满足,执行循环内程序,否则main()函数内部的程序顺序执行一遍,整个工程的程序执行结束,不再循环!
解决方法:在 while(TF0 == 1){ ... }  外侧加死循环 while(1){ } ,程序运行后输出结果正常。程序段如下:
void main(void)
{
	int i = 0 ;
	ScanMode_T0_Init() ;	//初始化定时器T0 , 查询模式,工作方式1,16位定时器
	P0 = 0x00 ;	//点亮P0口的LED灯

	while(1)
	{
	while(TF0 == 1)
	{
		TF0 = 0 ; //定时器,查询模式,定时器赋初值前必须清零溢出标志位
		TH0 = (65536 - 50000) / 256 ;
		TL0 = (65536 - 50000) % 256 ;
		TR0 = 1;  //赋初值后,运行定时器
		
		i++ ;
		if(i%10 == 0) //每个10*50,000us = 0.5s , P0口状态翻转一次
		{
			P0 = ~P0 ;			
		}


	}	
	}

		
}


定时器T0 --> 工作方式2 --> 中断模式       8位自动重装定时器    初始化函数


6、有关中断优先级的一个问题:

问题:在AT89S52单片机上同时允许INT0和INT1两个中断时,有时候会出现以下情况:INT0正常,INT1却一直用不了,即使INT0和INT1配置完全相同。
疑惑:在外部中断INT0未发生的时候,外部中断INT1是应该能够申请到中断的,但是却没有反应。
解决方法:我通过设置中断优先级寄存器IP,设置PX1=1,让其处在高级优先级顺序表中执行,结果中断INT0/INT1都能正常工作了。
	//5、配置优先级控制寄存器 IP :(可不配置,默认按低优先级列表顺序排优先级)
		// IP: - , - , PT2, PS, PT1, PX1, PT0, PX0
		IP = 0x04 ;
完整程序参照: http://blog.csdn.net/dragon12345666/article/details/22315025#t7
(程序示例8)












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值