单片机学习小组
登录
直播中
宜家
8年用户
1110经验值
私信
关注
怎样去编写基于38khz的NEC协议红外接收编码与解码的程序
开启该帖子的消息推送
NEC
红外接收
编码
基于38khz的NEC协议红外接收与发射控制的原理是什么?
怎样去编写基于38khz的NEC协议红外接收编码与解码的程序?
回帖
(1)
邹昀
2022-2-15 10:21:56
红外发射
通过通过红外二极管发射红外光,三极管的状态来控制。
红外模块一般都是三个引脚,vcc,gnd,dat,通过控制dat口的来控制发射红外光。
简易电路图
将数据口连接到单片机的引脚为上,控制io口的电平状态,来控制三极管的导通状态,从而发射红外光。
NEC协议
NEC协议特点:8位地址和8位命令为提高可靠性,地址和命令都传输2次,脉冲间隔调制38kHz载波频率。
包含引导码,地址码,地址码反码,命令码,命令码反码,结束码。
产生红外光
1.38khz频率,就是1s/38khz = 26.3us/(周期) pwm波的占空比是1/3,即8.77us发射红外光,17.53us不发射红外光。
2.一个时钟周期时产生高电平的时间为8.77us(导通,发射红外光),低电平的时间为17.53us(不导通,不发射红外光)。
数据编码 0 1
对数据的编码就是通过多个周期发送指定格式的高低电平,控制红外二极管亮灭。
发送一个二进制 0
一.0.56ms内发送载波信号,一个周期26.3us 就需要 560us/26.3us = 21.29 个周期。 也就是需要发送8.77us高电平,17.53低电平,需要21个周期 。
二.0.56ms不发送载波信号,也是21个周期 就是26.53us的低电平需要21个周期。
结合程序
从最下面往上面看,下面是底层函数
#include
#include
void Delay9us();
void Delay18us();
void Delay26us();
void Send_IR(unsigned int i);
void NoSend_IR(unsigned int i);
void Send_NEC_0();
void Send_NEC_1();
void Send_ENC_Message(unsigned int user_code,unsigned char Cmd);
void GetByte_And_SendByte(unsigned int user_code,unsigned char Cmd);
//红外控制引脚
***it IR_EN = P2^0;
void main()
{
Send_ENC_Message(100,20); //地址码和命令码
}
/*
*发送一帧数据
*/
void Send_ENC_Message(unsigned int user_code,unsigned char Cmd)
{
//先发送引导码
Send_IR(342); //9ms发送载波信号 周期 = 9000us/26.3us = 342
NoSend_IR(171); //4.5ms不发送载波信号,周期 = 4500us/26.3us = 171
GetByte_And_SendByte(user_code,Cmd); //取出每一位并发送
}
//取出数据中的每一位并发送
void GetByte_And_SendByte(unsigned int user_code,unsigned char Cmd)
{
unsigned int temp,i; //定义中间变量
//发送数据码(地址码和地址码的反码)
temp = user_code&0x0001; //通过与运算取出数据最低位
for(i = 0;i<16;i++){ //循环16位数据中的每一位
if(temp){ //如果是1执行
Send_NEC_1();
}else{ //是0执行
Send_NEC_0();
}
temp = temp>>1; //左移一位,取出下一位数据
}
//数据赋值给中间变量,取出最低位
//发送命令码
temp = Cmd & 0x01;
for(i = 0;i<8;i++){ //循环8位命令中的每一位
if(temp){ //如果是1执行
Send_NEC_1();
}else{ //是0执行
Send_NEC_0();
}
temp = temp>>1; //左移一位,取出下一位命令
}
//发送命令码的反码
temp = (~Cmd) & 0x01;
for(i = 0;i<8;i++){ //循环8位命令中的每一位
if(temp){ //如果是1执行
Send_NEC_1();
}else{ //是0执行
Send_NEC_0();
}
temp = temp>>1; //左移一位,取出下一位命令
}
//发送结束码
Send_NEC_0();
}
/*
发送二进制数据 0
*/
void Send_NEC_0()
{
Send_IR(21); //发送载波信号0.56ms, 也就是发送红外光21个周期
NoSend_IR(21); //不发送载波信号0.56ms,也是个周期
}
/*
发送二进制数据 1
*/
void Send_NEC_1()
{
Send_IR(21); //发送载波信号也是21个周期
NoSend_IR(64); //不发送载波信号为1.68ms 发送周期 = 1680us/26.3us = 63.87
}
//发送红外光, 26.3us这个周期内8.77us发送红外光,17.53us不发送红外光
void Send_IR(unsigned int i)
{
while(i--) //产生i个周期的信号 ,一个周期是26.3us
{
IR_EN = 1;
Delay9us();
IR_EN = 0;
Delay18us();
}
}
//不发送红外 26.3us这个周期内都不不发送红外光
void NoSend_IR(unsigned int i)
{
while(i--)
{
IR_EN = 0;
Delay26us();
}
}
//延时9us函数,用于控制输出高电平的时间 标准为8.77us,允许有误差
void Delay9us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 1;
while (--i);
}
//延时18us函数,控制输出低电平时间,标准为17.53us
void Delay18us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 5;
while (--i);
}
//26.3us,用于控制周期内不发射红外光
void Delay26us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 9;
while (--i);
}
红外接收
与发送相反,当有载波信号是,io口为低电平。
接收电路
解码过程
最前面接收的9ms的引导码:
就是9ms的低电平, 也就是IR端口会输出9ms的低电平,然后是4.5ms的高电平。
数据位;
解码代码
#include "ir.h"
//数据接收缓冲区
unsigned char ircode[4];
//标志位,用于判断是否成功接收数据
char ir_flag =0;
//等待10us
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void Delay600us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
i = 2;
j = 15;
do
{
while (--j);
} while (--i);
}
//接收初始化
void IR_Init()
{
IR_INPUT = 1; //初始化引脚转态
IT0 = 1; //外部中断0 设置为下降沿触发
EA = 1; //开中断
EX0 = 1; //中断总允许
}
//中断服务函数
//处理接收的红外信息,进行解码
void EX0_ISR() interrupt 0
{
ir_flag = ir_read(ircode); //对接收标志位进行判断,将接受到的数据保存到数组中
if(!ir_flag)
{
return; //返回值为零直接退出
}
}
//接收红外数据解码
char ir_read(unsigned char * readBuff)
{
unsigned char count ,i,j,temp = 0;
//判断是不是低电平,即接收引导码为低电平
if(!IR_INPUT){
//检测低电平的有效性,是否为引导码 低电平的时间只有9ms
count = 0;
//等待低电平(引导码)结束,接收为低电平时一直等待
while(!IR_INPUT){
count++; //为低电平是加加技术
//实时检测是否为低电平
Delay10us();
if(count>1000){ //9ms/10us = 900次 如果超过9ms还是低电平,低电平不合法(允许误差,稍微大一点,1000)
return 0; //不是有效引导码,退出
}
}
//IR_INPUT = 1,引导码低电平结束,进入4.5ms的高电平
count = 0; //清零
//检测高电平的有效性
while(IR_INPUT){
count++;
Delay10us(); //高电平超过4.5ms,超时判断
if(count>500){ //4500us/10us = 450 ,允许误差,设置为 500
return 0;
}
}
//高电平结束,引导码结束,接收数据
//接收四个字节的数据 用号码,用户码反码 ,命令码,命令码反码
for(i = 0;i<4;i++){
//接收每个字节的比特位Byte
for(j=0;j<8;j++){
count = 0;
while(!IR_INPUT){ //等待第一个位的低电平结束0.56ms,也就是载波有红外时。
count++;
Delay10us();
if(count>60){ //0.54ms/10us = 56 ,允许误差
return 0; //超时退出,正常自动在while循环判断就退出了
}
}
//判断是0还是1,高电平时间为560us,是0,如果高电平时间为1.685ms,是1
//延时600us,超过0的时间,判断IR_INPUT是0还是1,如果是1,则表示前面状态还未结束,说明是1
Delay600us();
if(IR_INPUT){ //高电平,表示数据为比特位 1
temp |= 1<
count = 0;
while(IR_INPUT){ //等待高电平结束
count++;
Delay10us();
if(count>100){
return 0;
}
}
} //不是 1,为0时开始已经赋值为0了
}
readBuff
= temp; //保存数据
temp = 0;
}
Delay600us();
//通过反码判断数据是否正确 >>互为反码相加等于255
if((readBuff[0]+readBuff[1]) == 255 ){
if((readBuff[2]+readBuff[3]) == 255 ){
return 1; //数据正确,返回1
}
}
}
return 0;
}
调用
//采用判断标志位标志位,为1表示接收到数据
if(ir_flag){
switch(ircode[2]){ //取出命令码
case 0xff :method1();break; //相应的命令执行函数
case 0x0f :method2();break;
case 0x7f :method3();break;
}
}
红外发射
通过通过红外二极管发射红外光,三极管的状态来控制。
红外模块一般都是三个引脚,vcc,gnd,dat,通过控制dat口的来控制发射红外光。
简易电路图
将数据口连接到单片机的引脚为上,控制io口的电平状态,来控制三极管的导通状态,从而发射红外光。
NEC协议
NEC协议特点:8位地址和8位命令为提高可靠性,地址和命令都传输2次,脉冲间隔调制38kHz载波频率。
包含引导码,地址码,地址码反码,命令码,命令码反码,结束码。
产生红外光
1.38khz频率,就是1s/38khz = 26.3us/(周期) pwm波的占空比是1/3,即8.77us发射红外光,17.53us不发射红外光。
2.一个时钟周期时产生高电平的时间为8.77us(导通,发射红外光),低电平的时间为17.53us(不导通,不发射红外光)。
数据编码 0 1
对数据的编码就是通过多个周期发送指定格式的高低电平,控制红外二极管亮灭。
发送一个二进制 0
一.0.56ms内发送载波信号,一个周期26.3us 就需要 560us/26.3us = 21.29 个周期。 也就是需要发送8.77us高电平,17.53低电平,需要21个周期 。
二.0.56ms不发送载波信号,也是21个周期 就是26.53us的低电平需要21个周期。
结合程序
从最下面往上面看,下面是底层函数
#include
#include
void Delay9us();
void Delay18us();
void Delay26us();
void Send_IR(unsigned int i);
void NoSend_IR(unsigned int i);
void Send_NEC_0();
void Send_NEC_1();
void Send_ENC_Message(unsigned int user_code,unsigned char Cmd);
void GetByte_And_SendByte(unsigned int user_code,unsigned char Cmd);
//红外控制引脚
***it IR_EN = P2^0;
void main()
{
Send_ENC_Message(100,20); //地址码和命令码
}
/*
*发送一帧数据
*/
void Send_ENC_Message(unsigned int user_code,unsigned char Cmd)
{
//先发送引导码
Send_IR(342); //9ms发送载波信号 周期 = 9000us/26.3us = 342
NoSend_IR(171); //4.5ms不发送载波信号,周期 = 4500us/26.3us = 171
GetByte_And_SendByte(user_code,Cmd); //取出每一位并发送
}
//取出数据中的每一位并发送
void GetByte_And_SendByte(unsigned int user_code,unsigned char Cmd)
{
unsigned int temp,i; //定义中间变量
//发送数据码(地址码和地址码的反码)
temp = user_code&0x0001; //通过与运算取出数据最低位
for(i = 0;i<16;i++){ //循环16位数据中的每一位
if(temp){ //如果是1执行
Send_NEC_1();
}else{ //是0执行
Send_NEC_0();
}
temp = temp>>1; //左移一位,取出下一位数据
}
//数据赋值给中间变量,取出最低位
//发送命令码
temp = Cmd & 0x01;
for(i = 0;i<8;i++){ //循环8位命令中的每一位
if(temp){ //如果是1执行
Send_NEC_1();
}else{ //是0执行
Send_NEC_0();
}
temp = temp>>1; //左移一位,取出下一位命令
}
//发送命令码的反码
temp = (~Cmd) & 0x01;
for(i = 0;i<8;i++){ //循环8位命令中的每一位
if(temp){ //如果是1执行
Send_NEC_1();
}else{ //是0执行
Send_NEC_0();
}
temp = temp>>1; //左移一位,取出下一位命令
}
//发送结束码
Send_NEC_0();
}
/*
发送二进制数据 0
*/
void Send_NEC_0()
{
Send_IR(21); //发送载波信号0.56ms, 也就是发送红外光21个周期
NoSend_IR(21); //不发送载波信号0.56ms,也是个周期
}
/*
发送二进制数据 1
*/
void Send_NEC_1()
{
Send_IR(21); //发送载波信号也是21个周期
NoSend_IR(64); //不发送载波信号为1.68ms 发送周期 = 1680us/26.3us = 63.87
}
//发送红外光, 26.3us这个周期内8.77us发送红外光,17.53us不发送红外光
void Send_IR(unsigned int i)
{
while(i--) //产生i个周期的信号 ,一个周期是26.3us
{
IR_EN = 1;
Delay9us();
IR_EN = 0;
Delay18us();
}
}
//不发送红外 26.3us这个周期内都不不发送红外光
void NoSend_IR(unsigned int i)
{
while(i--)
{
IR_EN = 0;
Delay26us();
}
}
//延时9us函数,用于控制输出高电平的时间 标准为8.77us,允许有误差
void Delay9us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 1;
while (--i);
}
//延时18us函数,控制输出低电平时间,标准为17.53us
void Delay18us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 5;
while (--i);
}
//26.3us,用于控制周期内不发射红外光
void Delay26us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 9;
while (--i);
}
红外接收
与发送相反,当有载波信号是,io口为低电平。
接收电路
解码过程
最前面接收的9ms的引导码:
就是9ms的低电平, 也就是IR端口会输出9ms的低电平,然后是4.5ms的高电平。
数据位;
解码代码
#include "ir.h"
//数据接收缓冲区
unsigned char ircode[4];
//标志位,用于判断是否成功接收数据
char ir_flag =0;
//等待10us
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void Delay600us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
i = 2;
j = 15;
do
{
while (--j);
} while (--i);
}
//接收初始化
void IR_Init()
{
IR_INPUT = 1; //初始化引脚转态
IT0 = 1; //外部中断0 设置为下降沿触发
EA = 1; //开中断
EX0 = 1; //中断总允许
}
//中断服务函数
//处理接收的红外信息,进行解码
void EX0_ISR() interrupt 0
{
ir_flag = ir_read(ircode); //对接收标志位进行判断,将接受到的数据保存到数组中
if(!ir_flag)
{
return; //返回值为零直接退出
}
}
//接收红外数据解码
char ir_read(unsigned char * readBuff)
{
unsigned char count ,i,j,temp = 0;
//判断是不是低电平,即接收引导码为低电平
if(!IR_INPUT){
//检测低电平的有效性,是否为引导码 低电平的时间只有9ms
count = 0;
//等待低电平(引导码)结束,接收为低电平时一直等待
while(!IR_INPUT){
count++; //为低电平是加加技术
//实时检测是否为低电平
Delay10us();
if(count>1000){ //9ms/10us = 900次 如果超过9ms还是低电平,低电平不合法(允许误差,稍微大一点,1000)
return 0; //不是有效引导码,退出
}
}
//IR_INPUT = 1,引导码低电平结束,进入4.5ms的高电平
count = 0; //清零
//检测高电平的有效性
while(IR_INPUT){
count++;
Delay10us(); //高电平超过4.5ms,超时判断
if(count>500){ //4500us/10us = 450 ,允许误差,设置为 500
return 0;
}
}
//高电平结束,引导码结束,接收数据
//接收四个字节的数据 用号码,用户码反码 ,命令码,命令码反码
for(i = 0;i<4;i++){
//接收每个字节的比特位Byte
for(j=0;j<8;j++){
count = 0;
while(!IR_INPUT){ //等待第一个位的低电平结束0.56ms,也就是载波有红外时。
count++;
Delay10us();
if(count>60){ //0.54ms/10us = 56 ,允许误差
return 0; //超时退出,正常自动在while循环判断就退出了
}
}
//判断是0还是1,高电平时间为560us,是0,如果高电平时间为1.685ms,是1
//延时600us,超过0的时间,判断IR_INPUT是0还是1,如果是1,则表示前面状态还未结束,说明是1
Delay600us();
if(IR_INPUT){ //高电平,表示数据为比特位 1
temp |= 1<
count = 0;
while(IR_INPUT){ //等待高电平结束
count++;
Delay10us();
if(count>100){
return 0;
}
}
} //不是 1,为0时开始已经赋值为0了
}
readBuff
= temp; //保存数据
temp = 0;
}
Delay600us();
//通过反码判断数据是否正确 >>互为反码相加等于255
if((readBuff[0]+readBuff[1]) == 255 ){
if((readBuff[2]+readBuff[3]) == 255 ){
return 1; //数据正确,返回1
}
}
}
return 0;
}
调用
//采用判断标志位标志位,为1表示接收到数据
if(ir_flag){
switch(ircode[2]){ //取出命令码
case 0xff :method1();break; //相应的命令执行函数
case 0x0f :method2();break;
case 0x7f :method3();break;
}
}
举报
更多回帖
rotate(-90deg);
回复
相关问答
NEC
红外接收
编码
如何实现4路
红外
的
38KHz
载波
编码
发送?
2022-02-15
1286
怎样
去
编写
IR
NEC
协议
的驱动
程序
呢
2022-02-14
937
如何
去
编写
并完成
红外
遥控测试代码呢
2021-12-01
1284
如何用
NEC
协议
模拟家电遥控器对设备进行遥控操作呢
2021-11-25
1590
如何用R05D与
红外接收
管对遥控器
红外接收
进行波形分析呢
2022-02-15
2666
用非IR的普通PT2262究竟能不能做成
红外
遥控?
2012-04-30
3058
NEC
解码
协议
的代码
程序
该
怎样
去
实现呢
2022-01-24
1185
怎么使用psoc 4
解码
IR
NEC
协议
代码
2019-01-09
1704
如何利用
NEC
协议
实现
红外
遥控?
2021-04-19
1791
求单片机模拟
38KHz
红外
发射
程序
!
2019-07-23
2494
发帖
登录/注册
20万+
工程师都在用,
免费
PCB检查工具
无需安装、支持浏览器和手机在线查看、实时共享
查看
点击登录
登录更多精彩功能!
首页
论坛版块
小组
免费开发板试用
ebook
直播
搜索
登录
×
20
完善资料,
赚取积分