|
本帖最后由 wzqwxx 于 2021-10-8 11:48 编辑
今天谈的是NEC 协议的。关于此协议请上百度。
放假在家集中学习了51单片机,“苦读”了一些书箱和视频教程。谈不上谈论什么 ,其实就向大家汇报这段时间的学习情况,欢迎交流,提出宝贵意见。
本人是第一次在贵坛发贴,定有很多不到的地方,也请大家批评指正。
今天就NEC 协议,仿照教材编写了三种红外解码方案,并都在开发板调试通过,完整源码会在附件提供。
第一种方案是参照教程的源码(在此称第四方案)改写的,解码部分代码比第四方案精减了,而且不失第四方案性能,只用了几行代码,占用内存也少。而第四方案正好相反。这两种方案都是利用中断,对前后信号两个下降沿之间时间长短、判定二进制数据0/1位的。优点:利用了两个中断,分别是定时器0和外部中断0,程序执行很快,占用CPU时间很少。缺点:占用了两个中断,能正确解码NEC协议的遥控器信号,也能解码别的协议遥控器的信号,当然是乱码。
第二种方案,与第四种方案解码方式不同,只利用一个外部中断0,对信号高低电平分别测量延续时长,来判定二进制数据0/1位的。优点:代码少,占用内存少,只利用了一个外部中断。能正确解码NEC协议的遥控器信号,禁止解码别的协议遥控器的信号,不会出现乱码。缺点:占用CPU时间多,整个解码期间不能产生别的中断。
第三种方案,综合了一二两种方案,扬长避短,优势互补,自认为是很好的方案。相对第四方案,优点:代码少,占用内存少,程序执行较快,占用CPU时间较少,只利用了一个外部中断0,能正确解码NEC协议的遥控器信号,禁止解码别的协议遥控器的信号。缺点:解码头部要延时9+4.5=13.5ms时间,有点长,CPU不能做其它任务。
下面将前三种方案核心代码贴出,欢迎大家评论交流,并指出错误和不足 。
/*-----------------------------------------------
* 【实验平台】: QX-单片机开发板
* 【外部晶振】: 11.0592mhz
* 【主控芯片】: STC89C52
* 【编译环境】: Keil μVisio4
名称:遥控器红外解码数码管显示
使用:按遥控器会在数码管上对应显示十六进制键值
NEC 协议下的编码表示
其中:引导码高电平约9000us 左右,低电平约4500us 左右;
接收端:引导码低电平约9000us 左右,高电平约4500us 左右;
用户码16 位,数据码16 位,共32位;
发送端: 数据0 是用“高电平约560us +低电平约560us”表示。
数据1 可用“高电平约560us+低电平约1680us”表示
接收端反转:数据0 是用“低电平约560us +高电平约560us”表示。
数据1 可用“低电平约560us+高电平约1680us”表示
------------------------------------------------*/

单片机源程序如下:
- #include<reg52.h> //包含头文件,头文件包含特殊功能寄存器的定义
- sbit IR=P3^2; //红外接口
- sbit beep = P2^3;//蜂鸣器接口
- #define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P0 替换
- sbit LATCH1=P2^6; //定义锁存使能端口 段锁存
- sbit LATCH2=P2^7; // 位锁存
- unsigned char code dofly_DuanMa[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
- 0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
- //0-F的码表
- unsigned char irtime; //红外用全局变量 计数延时,识别比特位电平高低
- unsigned char IRcord[4];//存储键码
- void delay(unsigned int i)
- {
- unsigned int m,n;
- for(m=i;m>0;m--)
- for(n=114;n>0;n--);
- }
- void tim0_isr (void) interrupt 1 using 1 //STC89C52 11.0592M
- {
- irtime++; //用于计数2个下降沿之间的时间 每个溢出中断时长256*1.085us=277.7us
- }
- void EX0_ISR (void) interrupt 0 //外部中断0服务函数
- {
- static unsigned char i; //接收红外信号处理
- if( irtime <3 || irtime >54) goto end; //两个下降沿延时过短(少于833us)或过长不解码 滤除干扰波
- if(irtime > 45 && irtime < 54)//跳过引导码 头码,9ms+4.5ms
- {
- irtime=0;
- i=0;
- }
- else{
- IRcord[i/8] >>= 1; //i/8每处理8位换下一个元素,总的处理4个字节共32位的数据
- if(irtime > 6) IRcord[i/8] |= 0x80; //位0电平时长计数上限4,位1高电平计数上限8
- irtime = 0; //这里取6为0/1 的识别分界
- i++;
- if(i > 31){ i=0; beep = 0; delay(100); beep = 1; }
- } //beep 鸣叫一声 解码成功
- end: irtime=0;
- }
- void TIM0init(void)//定时器0初始化
- {
- TMOD=0x02;//定时器0工作方式2,TH0是重装值,TL0是初值
- TH0=0x00; //重载值
- TL0=0x00; //初始化值
- ET0=1; //开中断
- TR0=1;
- }
- void EX0init(void)
- {
- IT0 = 1; //指定外部中断0下降沿触发,INT0 (P3.2)
- EX0 = 1; //使能外部中断
- EA = 1; //开总中断
- }
- void SMG_show(unsigned char num) //两位数码管显示十六进制键码
- {
- P0=dofly_DuanMa[num/16];
- LATCH1=1;
- LATCH1=0;
- P0=0xdf; //选中第一个数码管
- LATCH2=1;
- LATCH2=0;
- delay(2);
- P0=dofly_DuanMa[num%16];
- LATCH1=1;
- LATCH1=0;
- P0=0xbf; //选中第二个数码管
- LATCH2=1;
- LATCH2=0;
- delay(2);
- }
- void main(void)
- {
- EX0init(); //初始化外部中断
- TIM0init();//初始化定时器
- while(1)//主循环
- {
- SMG_show(IRcord[2]);//两位数码管显示十六进制键码
- }
- }
-
-
复制代码
例程副本.rar
(12.69 KB, 下载次数: 66)
|
评分
-
查看全部评分
|