本帖最后由 江弘源 于 2022-2-6 19:19 编辑
【“保姆级”指南】郭天祥51单片机STC89C52外设--HX1838红外接收头使用方法 这是我接触的第一款没有在郭天祥新概念书里讲解的芯片,我觉得红外线接收协议的探究难度和DS18B20旗鼓相当,大幅低于郭天祥配套的时钟芯片(反正Intel和Motorola协议看得我晕晕的,时钟芯片的功能也比常见的万年历+时钟复杂很多),建议(像我的)初学者如果有意强化自己使用陌生芯片的能力,可以使用这款红外芯片或者温度探头DS18B20先挑战一把,再用时钟芯片进阶研究。 前言:所有代码在郭天祥51开发板TX-1C普通开发板测试成功。 建议《郭天祥新概念51单片机C语言教程》先攻克定时器,串口打印部分再阅读本文。 1.红外通讯--NEC标准协议及其拓展NEC协议(extended-NEC,下称extNEC) NEC通信协议是常见红外遥控器的通讯协议。其他的通信协议还有飞利浦(Philips RC5/RC6),松下等厂家的协议等。下面重点介绍NEC标准协议及其拓展态。 如何表示0,1信号: 0信号:0.56ms低电平,之后跟着0.56ms高电平,共1.125ms 1信号:0.56ms低电平,之后跟着1.68ms高电平,共2.25ms (ext)NEC一次发送的内容由三部分(及其反码组成)组成 引导码:触发低电平条件,进入外来中断程序处理红外信号。先有9ms低电平再跟着4.5ms高电平。 8位地址码(又称“客户码”):一般一个遥控一码,以标识遥控器身份,硬件固定和软件编程兼有(方便配对),防止遥控器的数据被错误的接收器接收导致遥控器不小心遥控到非目标设备的情况(串码)。 extNEC会连续出现16位地址码,标准NEC8位地址码出现之后紧跟着地址码的反码。 8位数据码:和遥控器的按键一一对应,一般由硬件固定(学习遥控器可以软件编程,学习目标遥控器的地址码和数据码),以标识键位。 数据码的反码:用于取反之后与前面的数据码匹配,用于检查传输数据过程是否有问题。 结束码:最后有0.56ms低电平,表示传输代码结束。 连续信号引导码:与引导码类似,不过高电平时间变短,只有2.25ms。 我网上找到的大多数资料把NEC和extNEC混为一谈,两个协议之间的区别便是extNEC将原有标准协议的基础上放弃了8位用于数据校验的地址码反码,转而将地址码由8位(256种排列组合)拓展到16位(65536种),接收和发送端的组合可以变得更多,降低串码的可能性。 单次传输:引导码-【地址码-地址码反码】(16位地址码)-数据码-数据码反码-结束码 连续传输:引导码-【地址码-地址码反码】(16位地址码)-数据码-数据码反码-结束码-连续信号引导码-结束码-连续信号引导码-结束码-...... 【方括号是标准NEC的内容】(圆括号是拓展NEC的内容)
我们使用的红外接收模块是HX1838。负责将红外载波信号直接解码成pwm信号,方便软件读取。 -参考参数 模块含有一颗接收灯,通断电不亮,通电并接收到载波红外信号时闪亮。 接收原理 发射极调解载波频率38khz的红外信号—— 接收器将红外信号转化为TTL电平的(ext)NEC协议信号—— 由单片机软件解码(ext)NEC协议信号 (由软件判断软件编程的地址码是不是和遥控器预设的地址码匹配,不是则本次接收的数据丢弃,是则说明接收端和发射端匹配,进行下一步处理) (软件记录接下来的数据码及其紧跟着的反码,判断反码的“反码”是不是和数据码相匹配(数据校验),不是则数据传输出现差错,本次接收的数据丢弃,是则存入其他负责存储数据码的变量) (软件将数据码与预设的编码表匹配,判断出按下的是哪个按键,执行按键对应的操作) 使用方法 其接口非常简单,接收器5V供电,只有三个接口: VCC,GND和数据端口 直接把VCC和GND杜邦线怼上延伸出来的供电插针(暂时不知道有没有反接保护),数据端口接上P3.2(外界中断0输入)即可。 P3是“准双向端口”,记得开始读取之前先写1。
2.研究用器材 £ 郭天祥TX-1C 51开发板(或者有空余的外界中断输入端的51最小系统板) £ HX1838红外线接收头和配套遥控 网上上买到的,不到5块钱 £ 5个遥控器(从左到右分别是科沃斯扫地机器人遥控器,老式松下空调遥控器,模块配套的遥控器,DVD遥控器,天猫魔盒遥控器) £ 其中,左两个遥控器有接收到信号(接收灯闪亮)但似乎是协议不同,串口打印不出数据;第三四个遥控使用的是标准NEC协议,地址码好像都是0(改都不改,不怕串码么),第五个使用的是拓展NEC协议(而且遥控硬件地址码可以编程修改) 鄙人才疏学浅,这次只能先探究接收单次信号的情况,也就是按下一次按键就操作一次代码(长按无动作)的情况。 3.功能实现(for延时版本) 实现思路: a.引导码输入端口,触发外部中断0,进入中断函数,关闭外来中断0开关防止后来的低电平使得CPU重复进入中断程序 b.使用while等待电平变化,同时用计时器或者for延时计算引导码高/低电平延时时间,检查是否为硬件抖动(过很小一段时间后端口会恢复到高电平),是抖动的话自动“退出”(重新打开外来中断0开关并return)防止函数卡死。不是的话说明使用while等待引导码通过。 c.分四组采集数据,一次八位,存储在数组里 (d.01信号唯一区别是高电平时间长短,用两个while等待电平低变高再变低,数据位右移默认为0,当高电平时间超出某值时认为接收到1信号,用 或 运算将最高位变为1) (e.采集过程中也要设置防卡死“退出”口,使用while等待电平变化,同时用计时器或者for延时计算引导码高/低电平延时时间,超过正常数据接受时间自动“退出”) f.数据码反码取反和数据码比对,决定是数据无效并丢弃(“退出”)还是存储- g.根据地址码的格式判定是哪种类型NEC协议 h.正常“退出” i.标志位置1,启动printf串口打印。 有一个要点是防卡死“退出”口要贯穿采集数据的整个过程,防止程序死掉。 第二个要点是相比判断高电平时间来判断是0还是1,通过判断1节代码整体所用时间(0为1.125ms,1为2.25ms)来判断是0是1也是可以的(好像写出来的程序不是很稳定)。 简介: 启动串口打印功能,使用中断法读取红外线接收头接收的数据码,接收后立即用十进制打印出来。同时判断发射器使用的是标准还是拓展NEC协议,打印信号类型和对应类型地址码。 要点一:串口打印参数:波特率9600,方式1,其他保持默认。 要点二:定时器1采用八位自动重装模式(产生波特率),红外信号对接外界中断0输入口(P3^2) 标志位: signal_input:红外线接收头有输入 signal_extNEC:为1表示遥控器是拓展NEC,0为标准NEC
单片机源程序如下:
- #include<reg52.h>
- #include<intrins.h>
- #include<stdio.h>
- #define unchar unsigned char
- #define unint unsigned int
- sbit IRIN=P3^2;
- unchar IRCOM[7];
- unchar receive_data,custom_address,extra_address;
- unchar signal_input,signal_extNEC;
- void delay(unchar x);
- void init(unint bps_setting);
- void main()
- {
-
- IRIN=1; //I/O口初始化
- IE=0x81; //允许总中断中断,使能 INT0 外部中断
-
- init(0xFD); //波特率9600
-
- while(1)
- {
- if(signal_input==1)
- {
- signal_input=0;
- receive_data=IRCOM[2];
- custom_address=IRCOM[0];
- extra_address=IRCOM[1];
- ES=0;
- TI=1;
- printf("The IR code you receive is %bu!\n",receive_data);
- while(!TI);
-
- if (signal_extNEC==0)
- {
- printf("The corresponding custom address is %bu!,using standard NEC protocol.\n",custom_address);
- while(!TI);
- }
- else if(signal_extNEC==1)
- {
- printf("The full extent of its custom address is %bu",custom_address);
- while(!TI);
- printf(" %bu!,using extra NEC protocol.\n",extra_address);
- while(!TI);
- }
-
- printf("\n");
- while(!TI);
- TI=0;
- ES=1;
- }
- }
- }
- void IR_IN() interrupt 0 using 0//步骤a
- {
- unchar j,k,N=0;
- EX0 = 0;
- delay(15);
- if (IRIN==1)
- {
- EX0 =1;
- return;
- } //软件防抖动
-
- while (!IRIN) //等IR变为高电平,跳过9ms的前导低电平信号。
- delay(1);
-
- while (IRIN) //等IR变为低电平,跳过4.5ms的前导高电平信号。
- delay(1);
-
- //步骤b结束,c开始
-
- for (j=0;j<4;j++) //收集四组数据
- {
- for (k=0;k<8;k++) //每组数据有8位
- {
-
- while (!IRIN) //等 IR 变为高电平
- delay(1);
- while (IRIN) //计算IR高电平时长
- {
- delay(1);
- N++; //计数器叠加
- if (N>=30)
- {
- EX0=1;
- return;
- } //步骤e,0.14ms计数过长自动离开。
- } //高电平时间记录判定,即为步骤d
- IRCOM[j]=IRCOM[j] >> 1; //数据最高位补“0”
- if(N>=8)
- {
- IRCOM[j] = IRCOM[j] | 0x80; //数据最高位补“1”
- }
- N=0; //步骤d结束,计数器清零,准备下一位计数
- }
- }
-
- if(IRCOM[2]!=~IRCOM[3])
- {
- EX0=1;
- return;
- }
- //步骤f,数据校验
-
- if (IRCOM[0]==~IRCOM[1])
- {
- signal_extNEC=0;
- }
- else
- {
- signal_extNEC=1;
- }//步骤g,格式判定
-
- signal_input=1;
- EX0 = 1; //退出并启动步骤i
- }
- void init(unint bps_setting)
- {
- TH1=bps_setting;
- TL1=bps_setting;
- TMOD=0x20;
- TR1=1;
-
- SM0=0;
- SM1=1; //串口方式1
- REN=1;
-
- EA=1;
- ET0=1;
- ES=1;
-
- }
- /***************延时函数*****************************/
- void delay(unchar x) //x*0.14MS
- {
- unchar i;
- while(x--)
- {
- for (i = 0; i<13; i++) {}
- }
- }
复制代码
实验效果: 使用前三四个遥控的情况 使用天猫魔盒遥控器的情况
4.后记 鄙人不常登录论坛,可能会不定期回复问题,或者以后会考虑在这个项目下延伸一些内容(stm32版本......)。 这是菜鸟的第一篇技术文章,欢迎在下面指出问题,也欢迎引用我的内容,记得在下面吱一声哈。
appendix: 0.引用资料 (这位老哥用的是定时器0进行延时计数,不过有个小问题就是没有设置防卡死) 1.研究中发现的问题 我去查阅了淘宝给的资料,和论坛上的代码对比了一下, 这一部分代码竟然出奇的相似! 不过这段代码好像没什么卵用(单纯是把接收到的数据不知道做什么算术运算),删掉也不影响串口打印,如果有大佬知道它的作用,欢迎在下面指出。 2.抛砖引玉 ① 既然接收编码会了,那么用软件编程发射如何? 店家在邮寄红外芯片和遥控器的同时,还送了一颗红外发射二极管。理论上使用51单片机调制pwm也能实现电子信号到红外信号的调制。 使用单片机收发红外线信号实现机器间通讯是另一个值得深挖的好问题,先按下不表。 ②关于连续信号的接收问题 在网上只找到了stm32/树莓派版本的带连续信号判定的代码,如果我的文章能够引出哪位大佬写代码实现51单片机连续信号的接收,我将感激不尽。 |