1.通过外部寄存器编写代码,实现按下独立按键num数字++展示在LCD1602上的功能
STC89C52的外部中断有两种触发方式: 下降沿触发和低电平触发
此例中选择下降沿触发模式
此时mian.c编码
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
unsigned char num;
void main()
{
IT0=1; //下降沿触发
IE0=0; //中断请求标志位清0
EX0=1; //外部中断打开
EA=1; //所有中断打开
PX0=1; //高优先级,确保其不会被其他中断打断
LCD_Init();
while(1)
{
LCD_ShowNum(2,1,num,3);
}
}
void T1_time() interrupt 0
{
num++;
}
2.模块化中断部分
以下部分我参照这位老哥的笔记进行编写
江科大自化协51单片机学习笔记(红外遥控部分)_单片机红外遥控器寄存器怎么设置-CSDN博客https://blog.csdn.net/lonelypasserby/article/details/128837798江科大笔记的思路是IR.C里面集成Int0.c和Time0.c,然后通过IR.C解码
Int0.c主要负责中断部分
#include <REGX52.H>
/**
* @brief 外部中断初始化
* @param 无
* @retval 无
*/
void Int0_Init(void)
{
IT0=1; //下降沿触发
IE0=0; //中断请求标志位清0
EX0=1; //外部中断打开
EA=1; //所有中断打开
PX0=1; //高优先级,确保其不会被其他中断打断
}
/*外部中断0中断函数模板
void Int0_Routine(void) interrupt 0
{
}
*/
Time0.c赋负责计时
#include <REGX52.H>
//用于计时,不需要中断
void Timer0_Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0; //设置定时初始值为0用于计时
TH0 = 0; //设置定时初始值为0用于计时
TF0 = 0; //清除TF0标志
TR0 = 0; //外部控制
}
/**
* @brief 参数为标志位Flag,通过标志位控制计时器的启动与停止
* @param
* @retval
*/
void Timer0_Run(unsigned char Flag)
{
TR0=Flag;
}
/**
* @brief 定时器0设置计数器值
* @param
* @retval
*/
void Timer0_SetCounter(unsigned int Value)
{
TH0=Value/256;
TL0=Value%256;
}
/**
* @brief 定时器0取到计数器值
* @param
* @retval
*/
unsigned int Timer0_GetCounter(void)
{
return (TH0<<8)|TL0;
}
根据上图编写IR.C代码,IR.C负责解码,注意要在IR.h中引入宏定义
#include <REGX52.H>
#include "Int0.h"
#include "time0.h"
unsigned int IR_Time; //用于存储每次计时器取出的时间值,便于判断信号类型
unsigned char IR_State; /*0为空闲状态、1为等待信号状态(等待Start和Repeat信号)、
2为读取数据状态*/
unsigned char IR_Data[4]; //数据共有4个字节共32位
unsigned char IR_pData; //指向数据位数的指针
unsigned char IR_DataFlag; //为0表示数据解码未完成,为1表示数据解码已完成
unsigned char IR_RepeatFlag; //为0表示数据不重写,为1表示数据重写
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;
}
/**
* @brief 红外遥控获取收到的地址数据
* @param 无
* @retval 收到的地址数据
*/
unsigned char IR_GetAddress(void)
{
return IR_Address;
}
/**
* @brief 红外遥控获取收到的命令数据
* @param 无
* @retval 收到的命令数据
*/
unsigned char IR_GetCommand(void)
{
return IR_Command;
}
void Int0_Routine(void) interrupt 0
{
//IR_State==0空闲状态,红外LED不亮,接收头输出高电平
if(IR_State==0)
{
Timer0_SetCounter(0); //定时计数器清0
Timer0_Run(1); //定时器启动
IR_State=1; //置状态为1
}
/*等待信号状态1:取出计时器数据后清0,
判断信号为Start信号还是Repeat信号,
若为Start信号,则进入读取数据状态;若为Repeat信号,则将IR_RepeatFlag置1,
停止计时,回到空闲状态;*/
else if(IR_State==1)
{
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
}
}
}
4.IR.h代码
#ifndef __IR_H__
#define __IR_H__
#define IR_POWER 0x45
#define IR_MODE 0x46
#define IR_MUTE 0x47
#define IR_START_STOP 0x44
#define IR_PREVIOUS 0x40
#define IR_NEXT 0x43
#define IR_EQ 0x07
#define IR_VOL_MINUS 0x15
#define IR_VOL_ADD 0x09
#define IR_0 0x16
#define IR_RPT 0x19
#define IR_USD 0x0D
#define IR_1 0x0C
#define IR_2 0x18
#define IR_3 0x5E
#define IR_4 0x08
#define IR_5 0x1C
#define IR_6 0x5A
#define IR_7 0x42
#define IR_8 0x52
#define IR_9 0x4A
void IR_Init(void);
unsigned char IR_GetDataFlag(void);
unsigned char IR_GetRepeatFlag(void);
unsigned char IR_GetAddress(void);
unsigned char IR_GetCommand(void);
#endif
5.mian.c代码
#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_ADD)
{
num++;
}
if(command==IR_VOL_MINUS)
{
num--;
}
LCD_ShowNum(2,12,num,3);
}
}
}
6.结果展示
红外遥控