51单片机——红外通讯
实物与键码对应图示
红外接收的电路图:
NEC协议
数据格式: 发射端的方波图,接收端的正好与之相反,数据传输从最低位开始
NEC 标准下的编码表示
其中:引导码高电平约9000us 左右,低电平约4500us 左右;
用户码16 位,数据码16 位,共32位;
数据0 是用“高电平约560us +低电平约560us”表示。
数据1 可用“高电平约560us+低电平约1680us”表示。
通讯流程:(部分顺序可改变)
1.定义头文件。
2.定义要使用的变量。
3.始化定时器0,外部中断0,串口。
4.写定时器0的中断函数。
5.写外部中断0,中断处理函数函数(外部中断0,存储脉宽33次)。
6.写把提取的33次脉宽进行解码 NEC协议 的函数(对比脉宽,看是0还是1)
7.主函数(写出自己的要求(将串口发送的数据显示出来))
程序实现:
#include <reg52.h>
//自定义类型名
typedef unsigned char INT8U;
typedef unsigned char uchar;
typedef unsigned int INT16U;
typedef unsigned int uint;
uchar IRtime; //储存检测红外高低电平持续时间
uchar IRcord[4]; //储存解码后的4个字节数据
uchar IRdata[33]; //包含起始码在内的33位数据
bit IRpro_ok; //解码后四个字节数据接收完成标志位
bit IRok; //33位数据接收完成标志位
//初始化定时器0,外部中断0,串口
void init()
{
TMOD |=0x02; //设置定时器0工作模式2,8位自动重装
TL0 = TH0 = 0; //初始化定时器0寄存器,定时器0溢出一次,时间为256个机器周期
EA = 1; //开总中断
ET0 = 1; //开定时器0中断
TR0 = 1; //启动定时器0
IT0 = 1; //设置外部中断0跳变沿触发方式
EX0 = 1; //开外部中断0中断
TMOD |=0x20; //设置定时器1,工作模式2,8位自动重装(串口的定时器)
TL1 = TH1 = 0xfd;//比特率9600
SM1 = 1; //将串口设置为工作模式1,10位异步收发
TR1 = 1; //启动定时器1
}
/中断函数/ //定时器中断,没中断一次需要256*1.085us=277.76us
void time0() interrupt 1 //定时器0的中断
{
IRtime++;//277.76us
}
/外部中断0,存储脉宽33次/
//外部中断0,中断处理函数
void int0() interrupt 0 //c储存33次的计数
{
static uchar i;//(静态)变量用于存入33次数据计数,退出函数时,数值会保留
static bit startflag; //开始储存脉宽标志位
if(startflag) //判断是否为1
{
if((IRtime < 53)&&(IRtime >= 32)) i = 0; //53277.72,32277.72 判断引导码,如果是引导码则从起始码开始存
IRdata[i]=IRtime; //以T0溢出的次数来计算脉宽把这个时间存放在数组中
IRtime = 0; //计数清零
i++; //计数脉宽存入次数自加
if(i==33) //i等于33那么表示已经存入了33次脉宽
{
IRok = 1; // 脉宽检查完成
i = 0; //把脉宽计数清零准备下次存入
}
}
else //(startflag=0时)
{
IRtime = 0; //定时器0计数清零
startflag = 1;//开始处理标志位置1
}
}
//把提取的33次脉宽进行解码 NEC协议
void IRcordpro()//对比脉宽,看是0还是1
{
uchar i; //i是用于计数处理4个字节
uchar j; //j用于计数处理1个字节的8位数据
uchar k; //k用于计数处理33次脉宽
k = 1; //从第一位脉宽开始处理,丢掉起始码
for(i = 0;i < 4;i++) //把四个字节循环完
{
for(j=0;j<8;j++)
{
/如果脉宽大于数据0标准的1125us那么就判定为数据1/
if(IRdata[k]>5) IRcord[i] |=0x80; //最高位写1
//只能右移七次,如果右移八次则会把第一位数据移出去
if(j<7) IRcord[i] >>=1;
k++; //处理下一次脉宽
}
}
IRpro_ok = 1;
}
void main()
{
uchar i; //计数串口发送字节数
init(); //初始化-
while(1)
{
if(IRok) //判断33次脉宽是否提取完成
{
IRcordpro(); //根据脉宽解码出4个字节的数据
IRok = 0; //解码完成后,清零脉宽检查完成标志位等待下一次脉宽检查
if(IRpro_ok ) //判断解码是否完成
{
for(i=0;i<4;i++) //串口发送4个字节数据
{
SBUF = IRcord[i]; //串口发送数据
while(!TI) //等待发送完成标志
TI = 0; //清零发送完成标志为
}
IRpro_ok = 0; //清零解码标志位,以便下次使用
}
}
}
}