红外解码芯片IRM3638的verilog实现
0赞最近关注奥运是大事,我的开发板进展放缓,主要原因是在红外编解码这一块卡壳了,没法继续。上来肯定是要先看看电路的:
一个是发一个是收,似乎很简单。所以我就想当然的以为它们之间的通信无非就是发1收1发0收0了,然后就有我苦日子了。随送的pdf里是介绍PT2222的通信协议(看后感觉和以前用过的PT2262/2276这对红外编解码芯片通信协议类似),问题也出在看资料不够认真,有些关键的字句没有好好揣摩,导致了理解错误,参考代码也是研究了(还是有些细节没有研究透),当然自己的verilog也没能成功,郁闷了好几天。Download了这个电路里的红外解码芯片的IRM-3638的datasheet,其实给的也很简单,没有详细的介绍。最后在原来的pdf里发现了一句话,然后重新对红外的编解码有一个了解,这才搞定。学了一个教训,任何看似简单的东西越是要细心揣摩(不知哪位高人说过:细节决定成败),绝不能想当然,磨刀不误砍柴功啊,基本通信原理要先弄懂,别急着下手,一步到位是不可能的,但是少走弯路是可以做到的。
又感悟了一大堆,说说这个红外吧。具体什么叫红外也没什么好说,网上一搜一大堆,相信也没有人没听说过,这里就来讨论基于红外解码芯片IRM-3638的通信。硬件电路上面给了,一发一收,貌似很简单,其实确实不难,复杂问题都在IRM-3638里给你解决了。先说说我开始学习时的认识误区,前面也谈到了,这对芯片是不是发1收1发0收0呢?答案显然不对,这样的协议明显抗干扰效果不佳。实际上,IRM-3638是一个红外解码芯片,内部有晶振。发送端持续发0时,接收端输出的是1,但是发送端持续发1时,接收端可不是输出0,这就用到了晶振。发送时必须用33kHz的载波,也就是约26.3us的时钟周期(高电平持续约8.77us,低电平持续约16.53us的方波),当持续发出这样的载波信号时,接收端经过IRM-3638处理后,最后输出的信号是0。明白了吧,呵呵,实践一下吧!
以下的Verilog代码是要实现sw1,sw2,sw3三个按键任意键按下时原理不亮的三个LED灯(led_d2,led_d3,led_d4)同时点亮,键值是通过前面介绍的红外对射电路实现传输的。
Verilog代码:
module topirda(clk,rst_n,irda_receive,irda_send,sw1,sw2,sw3,led_d2,led_d3,led_d4);
input clk; //50M主时钟
input rst_n; //复位信号
input irda_receive; //红外数据接收端口
output irda_send; //红外数据发送端口
input sw1; //按键1
input sw2; //按键2
input sw3; //按键3
output led_d2; //发光二极管2
output led_d3; //发光二极管3
output led_d4; //发光二极管4
//------------------------------------------------
//按键检测部分
reg[19:0] cnt_20ms; //20ms计数寄存器
reg key_value; //每20ms检测一次键值,低电平表示按下
always @ (posedge clk or negedge rst_n)
if(!rst_n) cnt_20ms <= 20'd0;
else cnt_20ms <= cnt_20ms+'b1;
always @ (posedge clk or negedge rst_n)
if(!rst_n) key_value <= 1'b1;
else if(cnt_20ms == 20'hfffff) key_value <= sw1 & sw2 & sw3;
//------------------------------------------------
//红外编码发送部分
reg[10:0] cnt_1315; //26.3us计数寄存器,载波周期
always @ (posedge clk or negedge rst_n)
if(!rst_n) cnt_1315 <= 11'd0;
else if(cnt_1315 < 11'd1315) cnt_1315 <= cnt_1315+1'b1;
else cnt_1315 <= 11'd0;
reg irda_send_r; //发送数据寄存器
always @ (posedge clk or negedge rst_n)
if(!rst_n) irda_send_r <= 1'b0;
else if(!key_value)//有键按下时发送载波信号
if((cnt_1315 >= 11'd0) && (cnt_1315 <= 11'd438)) irda_send_r <= 1'b1;
else irda_send_r <= 1'b0;
else irda_send_r <= 1'b0; //无键按下时持续发送0
assign irda_send = irda_send_r;
//------------------------------------------------
//红外接收部分
assign {led_d2,led_d3,led_d4} = irda_receive ? 3'b111:3'b000;
endmodule