完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
通过通过红外二极管发射红外光,三极管的状态来控制。 红外模块一般都是三个引脚,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< 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; } } |
|
|
|
只有小组成员才能发言,加入小组>>
3278 浏览 9 评论
2955 浏览 16 评论
3455 浏览 1 评论
8987 浏览 16 评论
4050 浏览 18 评论
1102浏览 3评论
570浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
568浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2301浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1857浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 01:01 , Processed in 1.173381 second(s), Total 80, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号