×
单片机 > 单片机程序设计 > 详情

单片机红外通信(红外编码发射和红外接收解码代码)

发布时间:2023-02-27 发布时间:
|

关于红外通信,网上有很多关于解码的单片机代码和视频,发射编码部分并不好找。写发射部分代码花费了不少时间,拿出来与大家分享一下。下面是我在网上找到的资料:

一、NEC协议特征:
1.8位地址和8位命令长度
2.每次传输两遍地址(用户码)和命令(按键值)
3.通过脉冲串之间的时间间隔来实现信号的调制(PPM)
4.38Khz载波
5.每位的周期为1.12ms(低电平)或者2.25ms(高电平)



二、NEC协议的典型脉冲链:

用户码和数据码中的‘0’和‘1’是利用脉冲的时间间隔来区分,这种编码方式称为脉冲位置调制方式(PPM)。
其中位0首先为0.56ms的高电平,然后是0.565ms的低电平;位1首先是0.56ms的高电平,然后是1.69ms的低电平。


五、编程注意事项
1.红外接收头引脚信号是相反的电平。以上电平是从发射头角度来看,红外接收头引脚输出的是相反的电平。如图,即没有数据传输时,P3.2引脚保持为高电平,当接收到数据时,首先是引导 码,9ms的低电平和4.5ms的高电平,然后是32位数据和1位停止位。一般来说,P3.2 与单片机的某中断引脚相连,当接收数据时,低电平会触发中断。

2.数据从LSB(低位)开始发送,所以选择右移方式接收数据。四个字节的数据都是先发送D0,最后发送D7。所以接收到1位数据后,给变量的 最高位赋值,右移。或者先右移,再给变量的最高位赋值。

3.可以用一个数组保存32个数据的持续时间,用于后面判断高低电平。用定时器对两个数据(中断)之间的时间计时,并保存这个持续时间用于以后判断是位1还是位0。

4.可以用2字节,4字节变量存储32个数据,以节省代码空间。

可以用两个16位的int型变量存储数据,第一个int变量存储用户码,第二个存储数据码和数据反码。也可以用一个32位long型的变量存储所有数据。

5.判断停止位。接收到停止位后可以屏蔽红外引脚的中断,防止后面数据的干扰,解码成功后在开启中断。

发射编码部分核心代码:

#include

typedef unsigned char uchar;

typedef unsigned int uint;

sbit irsend = P7^5; // 红外发送

sbit K = P0^7; // 按键总开关

sbit key1 = P0^0; // 按键1

sbit key2 = P0^1; // 按键2

uint hwcount, count; // 要进中断的总次数、用于记录进入中断次数

uchar irsys[2]= {0x00,0xff}; // 16位用户码

bit hsflag = 0; // 发送38KHz载波标志位

uchar ircode; // 发送的红外数据


void Timer1Init(void) // 13微秒@12.000MHz

{

AUXR &= 0xBF; // 定时器时钟12T模式

TMOD &= 0x0F; // 设置定时器模式

TMOD |= 0x20; // 设置定时器模式

TL1 = 0xF3; // 设置定时初值

TH1 = 0xF3; // 设置定时重载值

TF1 = 0; // 清除TF1标志

TR1 = 0; // 定时器1关闭计时

ET1 = 1; // 开定时器1中断

EA = 1; // 开总中断

}


void Timer1_isr() interrupt 3

{

count++;

if(hsflag) // 有发射标志,则发射38khz

{

irsend = ~irsend;

}

else // 否则不发射,即相当于发射编码中的低电平

irsend = 1;

}


void ir_SendByte() // 红外发送一字节数据

{

uchar i;

for(i=0;i<8;i++) // 一字节八位,循环八次

{

hwcount = 43; // 0.56ms高电平,需要进43次定时器1中断(560/13=43)

hsflag = 1; // 发射38KHz载波标志

count = 0; // count置0,从这时起记录进入定时器1中断的次数

TR1 = 1; // 定时器1开启计时

while(count < hwcount); // 在此等待,直到进入中断次数达到43次

TR1 = 0; // 定时器1关闭计时

if(ircode&0x01) // 数据是从最低位开始发送的,最低位是1则要进130次中断

{

hwcount = 130; // 1.69ms低电平,进中断总次数130(1690/13=130)

}

else // 最低位是0,则要进43次定时器1中断

{

hwcount = 43; // 0.565ms低电平,进中断总次数43(565/13=43)

}

hsflag = 0; // 低电平,不需要38kHz载波

count = 0;

TR1 = 1;

while(count < hwcount);

TR1 = 0;

ircode = ircode >> 1; // 将数据右移一位,即从低位到高位发送

}

}

void ir_Send(uchar date)

{

hwcount = 692; // (引导码中的)9ms高电平,9000/13=692

hsflag = 1; // 高电平需要38kHz载波

count = 0;

TR1 = 1;

while(count < hwcount);

TR1 = 0;

hwcount = 346; // (引导码中)4.5ms低电平,4500/13=346

hsflag = 0; // 低电平不需要38kHz载波

count = 0;

TR1 = 1;

while(count < hwcount);

TR1 = 0;

ircode = irsys[0]; // 发送用户码的前8位

ir_SendByte();

ircode = irsys[1]; // 发送用户码的后8位

ir_SendByte();

ircode = date; // 发送键值

ir_SendByte();

ircode = ~date; // 发送



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
AVR单片机为何要写1作为清0中断标志位