目录
前言
本篇是51单片机系列的最后一节——外部中断,通俗的讲外部中断就是以单片机引脚的电平高低变化触发的中断。本篇分别以按键和红外遥控为例介绍外部中断。
一、EXTI
外部中断(EXTI)和其他中断的实质是一样的,即在程序运行过程中处理突发事件,只是触发方式有所不同。
STC89C52有2个外部中断:外部中断0和外部中断1,分别接在P3^2和P3^3引脚上,它们有两种触发方式:下降沿触发和低电平触发,它们在中断服务程序中分别对应了不同的中断号,如下:
51单片机的外部中断资源与stm32相比还是差很多的,首先stm32几乎所有的引脚都可以触发外部中断,而51的外部中断除了P3^2和P3^3引脚其他都不可以,其次stm32的外部中断还可以捕获上升沿和高电平,最后stm32不会对中断服务程序限制特定的中断号。
上两图就是51单片机外部中断的相关寄存器和内部框图,可以对照这两张图来写程序(可谓寻址)。
二、按键触发
普中51单片机开发板的K3和K4按键刚好接在外部中断上,我们可以用它来实现一个简单的外部中断测试。
unsigned char Num;
void main()
{
LCD_Init(); //初始化显示屏
LCD_ShowString(1,1,"Num");
//配置外部中断,位寻址
IT0=1;
IE0=0;
EX0=1;
EA=1;
PX0=1;
while(1)
{
LCD_ShowNum(2,1,Num,3);
}
}
void Int0_Routine(void) interrupt 0 //中断服务程序
{
Num++; //中断事件
}
三、红外遥控
红外遥控是利用红外光进行通信的设备,由红外LED将调制后的信号发出,由专用的红外接收头进行解调输出,为异步单工通信方式。红外接收头接在了单片机的P3^2引脚上,可以出发外部中断0,根据不同频率的波形解析出不同的数据,具体原则遵循红外NEC协议:
遥控器的不同按键对应不同的键码值,如上如图所示,红外NEC协议编码说明:在一个13.5ms的起始信号后,560us低电平560us高电平方波为逻辑0,560us低电平1690us高电平为逻辑1,绿色的那段方波信号代表长按连发。可以通过外部中断来捕获这些跳变从而解析出数据,组成各个键码值。
定时器:
#include <REGX52.H>
void Timer0_Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0; //设置定时初值
TH0 = 0; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 0; //定时器0不计时
}
void Timer0_SetCounter(unsigned int Value)
{
TH0=Value/256;
TL0=Value%256;
}
unsigned int Timer0_GetCounter(void)
{
return (TH0<<8)|TL0;
}
void Timer0_Run(unsigned char Flag)
{
TR0=Flag;
}
外部中断0配置:
#include <REGX52.H>
void Int0_Init(void)
{
IT0=1;
IE0=0;
EX0=1;
EA=1;
PX0=1;
}
红外遥控解码:
#include <REGX52.H>
#include "Timer0.h"
#include "Int0.h"
unsigned int IR_Time;
unsigned char IR_State;
unsigned char IR_Data[4];
unsigned char IR_pData;
unsigned char IR_DataFlag;
unsigned char IR_RepeatFlag;
unsigned char IR_Address;
unsigned char IR_Command;
void IR_Init(void)
{
Timer0_Init();
Int0_Init();
}
unsigned char IR_GetDataFlag(void)
{
if(IR_DataFlag)
{
IR_DataFlag=0;
return 1;
}
return 0;
}
unsigned char IR_GetRepeatFlag(void)
{
if(IR_RepeatFlag)
{
IR_RepeatFlag=0;
return 1;
}
return 0;
}
unsigned char IR_GetAddress(void)
{
return IR_Address;
}
unsigned char IR_GetCommand(void)
{
return IR_Command;
}
//外部中断0中断函数,下降沿触发执行
void Int0_Routine(void) interrupt 0
{
if(IR_State==0) //状态0,空闲状态
{
Timer0_SetCounter(0); //定时计数器清0
Timer0_Run(1); //定时器启动
IR_State=1; //置状态为1
}
else if(IR_State==1) //状态1,等待Start信号或Repeat信号
{
IR_Time=Timer0_GetCounter(); //获取上一次中断到此次中断的时间
Timer0_SetCounter(0); //定时计数器清0
//如果计时为13.5ms,则接收到了Start信号(判定值在12MHz晶振下为13500,在11.0592MHz晶振下为12442)
if(IR_Time>12442-500 && IR_Time<12442+500)
{
IR_State=2; //置状态为2
}
//如果计时为11.25ms,则接收到了Repeat信号(判定值在12MHz晶振下为11250,在11.0592MHz晶振下为10368)
else if(IR_Time>10368-500 && IR_Time<10368+500)
{
IR_RepeatFlag=1; //置收到连发帧标志位为1
Timer0_Run(0); //定时器停止
IR_State=0; //置状态为0
}
else //接收出错
{
IR_State=1; //置状态为1
}
}
else if(IR_State==2) //状态2,接收数据
{
IR_Time=Timer0_GetCounter(); //获取上一次中断到此次中断的时间
Timer0_SetCounter(0); //定时计数器清0
//如果计时为1120us,则接收到了数据0(判定值在12MHz晶振下为1120,在11.0592MHz晶振下为1032)
if(IR_Time>1032-500 && IR_Time<1032+500)
{
IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8)); //数据对应位清0
IR_pData++; //数据位置指针自增
}
//如果计时为2250us,则接收到了数据1(判定值在12MHz晶振下为2250,在11.0592MHz晶振下为2074)
else if(IR_Time>2074-500 && IR_Time<2074+500)
{
IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8)); //数据对应位置1
IR_pData++; //数据位置指针自增
}
else //接收出错
{
IR_pData=0; //数据位置指针清0
IR_State=1; //置状态为1
}
if(IR_pData>=32) //如果接收到了32位数据
{
IR_pData=0; //数据位置指针清0
if((IR_Data[0]==~IR_Data[1]) && (IR_Data[2]==~IR_Data[3])) //数据验证
{
IR_Address=IR_Data[0]; //转存数据
IR_Command=IR_Data[2];
IR_DataFlag=1; //置收到连发帧标志位为1
}
Timer0_Run(0); //定时器停止
IR_State=0; //置状态为0
}
}
}
主程序:
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "IR.h"
unsigned char Num;
unsigned char Address;
unsigned char Command;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"ADDR CMD NUM");
LCD_ShowString(2,1,"00 00 000");
IR_Init();
while(1)
{
if(IR_GetDataFlag() || IR_GetRepeatFlag()) //如果收到数据帧或者收到连发帧
{
Address=IR_GetAddress(); //获取遥控器地址码
Command=IR_GetCommand(); //获取遥控器命令码
LCD_ShowHexNum(2,1,Address,2); //显示遥控器地址码
LCD_ShowHexNum(2,7,Command,2); //显示遥控器命令码
if(Command==IR_VOL_MINUS) //如果遥控器VOL-按键按下
{
Num--; //Num自减
}
if(Command==IR_VOL_ADD) //如果遥控器VOL+按键按下
{
Num++; //Num自增
}
LCD_ShowNum(2,12,Num,3); //显示Num
}
}
}
总结
51单片机外部中断 红外遥控
博主棒棒!