【前言】
红外遥控器常用的调制制式主要分为两种,这里主要讲解以NEC调制方式的遥控器解码过程。
-----1、 使用定时器计算高低电平的时间
-----2、 使用数组存放一组完整的电平时间编码
-----3、 计算电平的时长
-----4、 组合数据,获得编码值,存放于数组
-----5、 LCD1602管显示
红外遥控器常用的调制制式主要分为两种,这里主要讲解以NEC调制方式的遥控器解码过程。
废话不多说,直接上时序图!( 更多详细资料自行查询)
总时序图:
前导码:
-----1、 使用定时器计算高低电平的时间
-----2、 使用数组存放一组完整的电平时间编码
-----3、 计算电平的时长
-----4、 组合数据,获得编码值,存放于数组
-----5、 LCD1602管显示
【编写程序】
/*--------------------------------------------------------
程序功能: 51红外遥控器解码程序
功能详情: 遥控解码后送数码管依次显示,共4字节 .( 12MHz晶振 )
编写时间: 2017/9/7
编写人: 吴**
--------------------------------------------------------*/
#include<reg52.h>
#include<string.h>
#define uchar unsigned char
#define uint unsigned int
#define display_data P0
sbit LCD_RS=P1^0;
sbit LCD_RW=P1^1;
sbit LCD_EN=P1^2;
uchar irtime = 0;
uchar startflag = 0; // 起始标志位
uchar ir_rc_ok = 0; // 红外高/低电平时间接收完成标志位
uchar bitnum = 0;
uchar ir_change_ok = 0; // 转码完成标志位
uchar irdata[33]; // 电平时间数组
uchar ircode[4]; // 遥控解码数组
// 字符编码
uchar str[17]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F',' '};
/********* 延时函数 **********/
void delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
/********** 系统初始化 ********/
void sysinit()
{
// 初始化定时器
TMOD = 0x02; // 设置定时器0为工作方式2 (0~255)
TH0 = 0x00; // 赋初值
TL0 = 0x00;
TR0 = 1; // 启动定时器0
ET0 = 1; // 使能定时器0
// 初始换外部中断1
IT1 = 1; // 下降沿触发
EX1 = 1; // 开外部中断0
EA = 1; // 开总中断
}
/************ 转换编码 *************/
void changecode()
{
uchar k = 1;
uchar i,j;
uchar value;
if(ir_rc_ok ==1) // 如果ir接收完成就进行转码
{
for(i=0;i<4;i++) // 获取前导码后的4个字节数据
{
for(j=0;j<8;j++)
{
value = value>>1; // 因低位在前,所以需右移
if(irdata[k]>6&&irdata[k]<10) // 判断数据是否为" 1 ",从第2位开始接收
{
value |= 0x80;
}
k++;
}
ircode[i] = value; // 存储1个字节数据
}
ir_change_ok = 1; // 编码转换完成标志位
ir_rc_ok = 0; // ir接收标志复位
}
}
/********** 1602写指令 ***********/
void write_com(uchar com)
{
LCD_RS=0; //RS =‘low’为写指令
LCD_RW=0;
display_data=com;
delayms(5);
LCD_EN=1;
delayms(5);
LCD_EN=0;
}
/*********** 1602写数据 ***********/
void write_data(uchar wdata)
{
LCD_RS=1; //RS ='high'为写数据
LCD_RW=0;
display_data=wdata;
delayms(3);
LCD_EN=1;
delayms(5);
LCD_EN=0;
}
/*********** 1602显示屏初始化 ***********/
void disinit()
{
LCD_EN=0; //初始化使能
write_com(0x38); //设置显示模式
write_com(0x0f); //设置显示开/关及光标
write_com(0x06); //设置指针位置及移屏
write_com(0x80); //数据指针初始化( +0x10 指针移至显示区外)
}
/************* 1602显示解码结果 *****************/
void display()
{
uchar num,high,low;
if(ir_change_ok == 1) // 判断编码是否转换完毕
{
ir_change_ok = 0;
write_com(0x80); // 重复调用时,显示指针复位
for(num=0;num<4;num++)
{
high = ircode[num]/16;
low = ircode[num]%16;
write_data(str[high]);
write_data(str[low]);
write_data(str[16]); // 显示空格
}
}
}
/********** 主函数 *************/
void main()
{
sysinit(); // 初始化
disinit(); // 显示屏初始化
while(1)
{
changecode(); // 获取编码
display(); // 显示解码后的编码
}
}
/********* 定时器0中断服务函数 ***********/
void t0()interrupt 1
{
irtime++;
}
/********* 外部中断1服务函数 ***********/
void exint1() interrupt 2
{
if(startflag)
{
if(irtime>32) // 检测前导码
{
bitnum=0;
}
irdata[bitnum]=irtime; // 从前导码开始接收数据
irtime=0;
bitnum++;
if(bitnum==33) // 前导码+4字节数据,共 33 比特
{
bitnum=0;
ir_rc_ok = 1;
}
}
else
{
startflag = 1;
irtime = 0;
}
}