1 基础只是
1.1红外遥控简介
红外遥控是利用近红外光传送遥控指令的,波长为0.76um ~ 1.5um。红外发射器件(红外发光管)与红外接收器件(光敏二极管、三极管及光电池)的发光与受光峰值波长一般为0.8um~0.94um,在近红外光波段内,二者的光谱正好重合,能够很好的匹配,可以获得较高的传输效率及较高的可靠性。
红外遥控发射部分由遥控按键,编码与调制电路、红外发光二极管等构成;红外遥控接收部分由光敏二极管,光电放大电路,解调电路等组成;最后将解调的信号输入 FPGA内部及逆行解码输出。
1.2 红外遥控编码协议
NEC协议采用的是PPM(Pulse Position Modulation,脉冲位置调制)进行编码。当我们按下遥控器的一个按键时,会发送一帧的数据。这一帧的数据由引导码、地址码、地址反码、数据码、数据反码以及一位结束位(可忽略)组成。注:都是低位在前。
逻辑0和1的表示方法:
当按键一直按着不放:会发送重复码
接收波形:(与发送波形图相对应)
2 实际工程
将按键按下的数字显示在数码管上,检测到重复码的话就闪烁LED灯;
2.1 模块框图
2.1.1 总体框图
2.1.2 解码模块
2.1.3 LED灯模块
2.1.4 动态数码管模块
2.1.5 内部接线框图
2.2 状态机转换
空闲、引导码、仲裁、数据、重复
2.3 波形图
2.4 代码部分
2.4.1 inf_rcv.v
module inf_rcv
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire inf_in ,
output reg [19:0] data ,
output reg reapeat_en
);
parameter IDLE = 5'b0_0001,
TIME_9MS = 5'b0_0010,
ARBIT = 5'b0_0100,
DATA = 5'b0_1000,
REAPEAT = 5'b1_0000;
//just like:560us = 560_000ns and sys_clk = 20ns, so 0~27999
parameter CNT_560US_MIN = 19'd20_000 ,
CNT_560US_MAX = 19'd35_000 ,
CNT_1_69MS_MIN = 19'd80_000 ,
CNT_1_69MS_MAX = 19'd90_000 ,
CNT_2_25MS_MIN = 19'd100_000 ,
CNT_2_25MS_MAX = 19'd125_000 ,
CNT_4_5MS_MIN = 19'd175_000 ,
CNT_4_5MS_MAX = 19'd275_000 ,
CNT_9MS_MIN = 19'd400_000 ,
CNT_9MS_MAX = 19'd490_000 ;
reg [4:0] state ;
reg inf_in_dly1 ;
reg inf_in_dly2 ;
wire inf_in_fall ;
wire inf_in_rise ;
reg [18:0] cnt ;
reg flag_9ms ;
reg flag_4_5ms ;
reg [5:0] cnt_data ;
reg flag_560us ;
reg flag_1_69ms ;
reg [31:0] data_reg ;
reg flag_2_25ms ;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= IDLE;
else case(state)
IDLE: if(inf_in_fall == 1'b1)
state <= TIME_9MS;
else
state <= IDLE;
//if over 9ms,just wait the inf_rise
TIME_9MS: if((inf_in_rise == 1'b1) && (flag_9ms == 1'b1))
state <= ARBIT;
else if((inf_in_rise == 1'b1) && (flag_9ms == 1'b0))
state <= IDLE;
else
state <= TIME_9MS;
ARBIT: if((inf_in_fall == 1'b1) && (flag_2_25ms == 1'b1))
state <= REAPEAT;
else if((inf_in_fall == 1'b1) && (flag_4_5ms == 1'b1))
state <= DATA;
else if((inf_in_fall == 1'b1) && (flag_2_25ms == 1'b0) && (flag_4_5ms == 1'b0))
state <= IDLE;
else
state <= ARBIT;
DATA: if((inf_in_rise == 1'b1) && (flag_560us == 1'b0))
state <= IDLE;
else if((inf_in_fall == 1'b1) && (flag_560us == 1'b0) && (flag_1_69ms == 1'b0))
state <= IDLE;
else if((inf_in_rise == 1'b1) && (cnt_data == 6'd32))
state <= IDLE;
REAPEAT: if(inf_in_rise == 1'b1)
state <= IDLE;
else
state <= REAPEAT;
default: state <= IDLE;
endcase
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
inf_in_dly1 <= 1'b0;
inf_in_dly2 <= 1'b0;
end
else
begin
inf_in_dly1 <= inf_in;
inf_in_dly2 <= inf_in_dly1;
end
assign inf_in_fall = (inf_in_dly1 == 1'b0) && (inf_in_dly2 == 1'b1);
assign inf_in_rise = (inf_in_dly1 == 1'b1) && (inf_in_dly2 == 1'b0);
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 19'd0;
else
case(state)
IDLE: cnt <= 19'd0;
TIME_9MS: if((inf_in_rise == 1'b1) && (flag_9ms == 1'b1))
cnt <= 19'd0;
else
cnt <= cnt + 1'b1;
ARBIT: if((inf_in_fall == 1'b1) && ((flag_4_5ms == 1'b1) || (flag_2_25ms == 1'b1)))
cnt <= 19'd0;
else
cnt <= cnt + 1'b1;
DATA: if((inf_in_rise == 1'b1) && (flag_560us == 1'b1))
cnt <= 19'd0;
else if((inf_in_fall == 1'b1) && ((flag_560us == 1'b0) || (flag_1_69ms == 1'b0)))
cnt <= 19'd0;
else
cnt <= cnt + 1'b1;
default: cnt <= 19'd0;
endcase
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_9ms <= 1'b0;
else if((state == TIME_9MS) && (cnt >= CNT_9MS_MIN) && (cnt <= CNT_9MS_MAX))
flag_9ms <= 1'b1;
else
flag_9ms <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_4_5ms <= 1'b0;
else if((state == ARBIT) && (cnt >= CNT_4_5MS_MIN) && (cnt <= CNT_4_5MS_MAX))
flag_4_5ms <= 1'b1;
else
flag_4_5ms <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_560us <= 1'b0;
else if((state == DATA) && (cnt >= CNT_560US_MIN) && (cnt <= CNT_560US_MAX))
flag_560us <= 1'b1;
else
flag_560us <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_1_69ms <= 1'b0;
else if((state == DATA) && (cnt >= CNT_1_69MS_MIN) && (cnt <= CNT_1_69MS_MAX))
flag_1_69ms <= 1'b1;
else
flag_1_69ms <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_2_25ms <= 1'b0;
else if((state == ARBIT) && (cnt >= CNT_2_25MS_MIN) && (cnt <= CNT_2_25MS_MAX))
flag_2_25ms <= 1'b1;
else
flag_2_25ms <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_data <= 6'd0;
else if((inf_in_rise == 1'b1) && (cnt_data == 6'd32))
cnt_data <= 6'd0;
else if((state == DATA) && (inf_in_fall == 1'b1))
cnt_data <= cnt_data + 1'b1;
else
cnt_data <= cnt_data;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_reg <= 32'b0;
else if((state == DATA) && (inf_in_fall == 1'b1) && (flag_560us == 1'b1))
data_reg[cnt_data] <= 1'b0;
else if((state == DATA) && (inf_in_fall == 1'b1) && (flag_1_69ms == 1'b1))
data_reg[cnt_data] <= 1'b0;
else
data_reg <= data_reg;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 20'd0;
else if((cnt_data == 6'd32) && (~data_reg[23:16] == data_reg[31:24]) && (~data_reg[15:8] == data_reg[7:0]))
data <= {12'b0,data_reg[23:16]};
else
data <= data;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
reapeat_en <= 1'b0;
else if((state == REAPEAT) && (~data_reg[23:16] == data_reg[31:24]))
reapeat_en <= 1'b1;
else
reapeat_en <= 1'b0;
endmodule
2.4.2 tb_inf_rcv.v
`timescale 1ns/1ns
module tb_inf_rcv();
reg sys_clk;
reg sys_rst_n;
reg inf_in;
wire [19:0] data;
wire reapeat_en;
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
inf_in <= 1'b1;
#30
sys_rst_n <= 1'b1;
#1000
//引导码
inf_in <= 1'b0;
#9000_000
inf_in <= 1'b1;
#4500_000
//地址码(8'h57 0101_0111 因为低位在前:1110_1010)
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
//地址反码(0001_0101)
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
//数据码:(8'h22 0010_0010 低位在前:0100_0100)
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
//数据反码(1011_1011)
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //至此实现了逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //至此实现了逻辑1
//结束位
inf_in <= 1'b0;
#560_0000
//高电平保持
inf_in <= 1'b1;
#4200_0000
//重复码
inf_in <= 1'b0;
#9000_000
inf_in <= 1'b1;
#2250_000
//结束位
inf_in <= 1'b0;
#560_0000
inf_in <= 1'b1;
inf_in <= 1'b1;
end
always #10 sys_clk = ~sys_clk;
inf_rcv inf_rcv_inst
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.inf_in (inf_in),
.data (data),
.reapeat_en (reapeat_en)
);
endmodule
2.5 仿真波形
注:其他模块可根据具体开发板书写