FPGA强化(5):红外遥控"/>
FPGA强化(5):红外遥控
文章目录
- 第37讲:红外遥控
- infrared_rcv
- led_ctrl
- top_infrared_rcv
- tb_top_infrared_rcv
第37讲:红外遥控
红外遥控是利用近红外光传送遥控指令的,波长为0.76um~1.5um。
红外发射器件(红外发光管)与红外接收器件(光敏二极管、三极管及光电池)的发光与受光峰值波长一般为0.8um~0.94um,在近红外光波段内,二者的光谱整好重合,能够很好地匹配,可以获得较高的传输效率及较高的可靠性。
系统框图绘制
解码模块状态转移图
infrared_rcv
`timescale 1ns/1nsmodule infrared_rcv
(input wire sys_clk , //系统时钟,频率50MHzinput wire sys_rst_n , //复位信号,低有效input wire infrared_in , //红外接受信号output reg repeat_en , //重复码使能信号output reg [19:0] data //接收的控制码
);//parameter define
parameter CNT_0_56MS_L = 20000 , //0.56ms计数为0-27999CNT_0_56MS_H = 35000 ,CNT_1_69MS_L = 80000 , //1.69ms计数为0-84499CNT_1_69MS_H = 90000 ,CNT_2_25MS_L = 100000, //2.25ms计数为0-112499CNT_2_25MS_H = 125000,CNT_4_5MS_L = 175000, //4.5ms计数为0-224999CNT_4_5MS_H = 275000,CNT_9MS_L = 400000, //9ms计数为0-449999CNT_9MS_H = 490000;
//state
parameter IDLE = 5'b0_0001, //空闲状态S_T9 = 5'b0_0010, //监测同步码低电平S_JUDGE = 5'b0_0100, //判断重复码和同步码高电平S_IFR_DATA = 5'b0_1000, //接收数据S_REPEAT = 5'b1_0000; //重复码//wire define
wire ifr_in_rise ; //检测红外信号的上升沿
wire ifr_in_fall ; //检测红外信号的下降沿//reg define
reg infrared_in_d1 ; //对infrared_in信号打一拍
reg infrared_in_d2 ; //对infrared_in信号打两拍
reg [18:0] cnt ; //计数器
reg flag_0_56ms ; //0.56ms计数完成标志信号
reg flag_1_69ms ; //1.69ms计数完成标志信号
reg flag_2_25ms ; //2.25ms计数完成标志信号
reg flag_4_5ms ; //4.5ms计数完成标志信号
reg flag_9ms ; //0.56ms计数完成标志信号
reg [4:0] state ; //状态机状态
reg [5:0] data_cnt ; //数据计数器
reg [31:0] data_tmp ; //数据寄存器//检测红外信号的上升沿和下降沿
assign ifr_in_rise = (~infrared_in_d2) & (infrared_in_d1) ;
assign ifr_in_fall = (infrared_in_d2) & (~infrared_in_d1) ;//对infrared_in信号打拍
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)begininfrared_in_d1 <= 1'b0;infrared_in_d2 <= 1'b0;endelsebegininfrared_in_d1 <= infrared_in;infrared_in_d2 <= infrared_in_d1;end//cnt
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt <= 19'd0;elsecase(state)IDLE: cnt <= 19'd0;S_T9: if((ifr_in_rise==1'b1) && (flag_9ms==1'b1))cnt <= 19'd0;elsecnt <= cnt + 1;S_JUDGE:if((ifr_in_fall==1'b1) && (flag_2_25ms==1'b1 || flag_4_5ms==1'b1))cnt <= 19'd0;elsecnt <= cnt + 1;S_IFR_DATA: if((flag_0_56ms == 1'b1) && (ifr_in_rise==1'b1))cnt <= 19'd0;else if(((flag_0_56ms==1'b1) || (flag_1_69ms==1'b1)) && (ifr_in_fall==1'b1))cnt <= 19'd0;elsecnt <= cnt + 1;default:cnt <= 19'd0;endcase//flag_0_56ms:计数到0.56ms范围拉高标志信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)flag_0_56ms <= 1'b0;else if((state == S_IFR_DATA) && (cnt >= CNT_0_56MS_L) && (cnt <= CNT_0_56MS_H))flag_0_56ms <= 1'b1;elseflag_0_56ms <= 1'b0;//flag_1_69ms:计数到1.69ms范围拉高标志信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)flag_1_69ms <= 1'b0;else if((state == S_IFR_DATA) && (cnt >= CNT_1_69MS_L) && (cnt <= CNT_1_69MS_H))flag_1_69ms <= 1'b1;elseflag_1_69ms <= 1'b0;//flag_2_25ms:计数到2.25ms范围拉高标志信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)flag_2_25ms <= 1'b0;else if((state == S_JUDGE) && (cnt >= CNT_2_25MS_L) && (cnt <= CNT_2_25MS_H))flag_2_25ms <= 1'b1;elseflag_2_25ms <= 1'b0;//flag_4_5ms:计数到4.5ms范围拉高标志信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)flag_4_5ms <= 1'b0;else if((state == S_JUDGE) && (cnt >= CNT_4_5MS_L) && (cnt <= CNT_4_5MS_H))flag_4_5ms <= 1'b1;elseflag_4_5ms <= 1'b0;//flag_9ms:计数到9ms范围拉高标志信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)flag_9ms <= 1'b0;else if((state == S_T9) && (cnt >= CNT_9MS_L) && (cnt <= CNT_9MS_H))flag_9ms <= 1'b1;elseflag_9ms <= 1'b0;//状态机:状态跳转
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)state <= IDLE;else case(state)//若检测到红外信号下降沿到来跳转到S_T9状态IDLE:if(ifr_in_fall == 1'b1)state <= S_T9;else //若没检测到红外信号的下降沿,则让其保持在IDLE状态state <= IDLE;S_T9: //若检测到红外信号上升沿到来,则判断flag_9ms是否为1//若检测到时间接近9ms,则跳转到S_judje状态if((ifr_in_rise == 1'b1) && (flag_9ms == 1'b1))state <= S_JUDGE;else if((ifr_in_rise == 1'b1) && (flag_9ms == 1'b0))state <= IDLE;elsestate <= S_T9;S_JUDGE: //若检测到红外信号下降沿到来,则判断flag_2_25ms是否为1//若检测到时间接近2.25ms,则跳转重复码状态if((ifr_in_fall == 1'b1) && (flag_2_25ms == 1'b1))state <= S_REPEAT;else if((ifr_in_fall == 1'b1) && (flag_4_5ms == 1'b1))state <= S_IFR_DATA;else if((ifr_in_fall == 1'b1) && (flag_2_25ms == 1'b0) && (flag_4_5ms == 1'b0))state <= IDLE;elsestate <= S_JUDGE;S_IFR_DATA://若上升沿到来,低电平保持时间不满足编码协议,则回到空闲状态if(ifr_in_rise == 1'b1 && flag_0_56ms == 1'b0)state <= IDLE;//若下降沿到来,高电平保持时间不满足编码0或1,则回到空闲状态else if(ifr_in_fall == 1'b1 && (flag_0_56ms == 1'b0 &&flag_1_69ms == 1'b0))state <= IDLE;//数据接收完毕之后回到空闲状态,等待下一个指令的到来else if(ifr_in_rise == 1'b1 && data_cnt == 6'd32)state <= IDLE;S_REPEAT:/*若上升沿到来,无论时间是否到了0.56ms,状态机都跳回IDLE状态等待下一数据码或重复码的到来*/if(ifr_in_rise == 1'b1)state <= IDLE;elsestate <= S_REPEAT;default:state <= IDLE;endcase//data_tmp
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)data_tmp <= 32'b0;else if(state == S_IFR_DATA && ifr_in_fall == 1'b1 &&flag_0_56ms == 1'b1)data_tmp[data_cnt] <= 1'b0;else if(state == S_IFR_DATA && ifr_in_fall == 1'b1 &&flag_1_69ms == 1'b1)data_tmp[data_cnt] <= 1'b1;elsedata_tmp <= data_tmp;//data_cnt
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)data_cnt <= 1'b0;else if(ifr_in_rise == 1'b1 && data_cnt == 6'd32)data_cnt <= 1'b0;else if(ifr_in_fall == 1'b1 && state == S_IFR_DATA)data_cnt <= data_cnt + 1'b1;elsedata_cnt <= data_cnt;//repeat_en
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)repeat_en <= 1'b0;else if(state == S_REPEAT && (data_tmp[23:16] == ~data_tmp[31:24]))repeat_en <= 1'b1;elserepeat_en <= 1'b0;always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)data <= 20'b0;//数据接收完之后若数据校验正确,则输出数据码的数据else if(data_tmp[23:16] == ~data_tmp[31:24] && data_tmp[7:0] ==~data_tmp [15:8] && data_cnt==6'd32)data <= {12'b0,data_tmp[23:16]};endmodule
led_ctrl
`timescale 1ns/1nsmodule led_ctrl
(input wire sys_clk , //系统时钟,频率50MHzinput wire sys_rst_n , //复位信号,低有效input wire repeat_en , //重复码使能信号output reg led //输出led灯信号
);//parameter define
parameter CNT_MAX = 2500_000;//wire define
wire repeat_en_rise ; //重复码使能信号上升沿//reg define
reg repeat_en_d1; //重复码使能信号打一拍
reg repeat_en_d2; //重复码使能信号打两拍
reg cnt_en ; //计数器使能信号
reg [21:0] cnt ; //计数器//获得repeat_en上升沿信号
assign repeat_en_rise = repeat_en_d1 & ~repeat_en_d2;//对reeat_en打两拍
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)beginrepeat_en_d1 <= 1'b0;repeat_en_d2 <= 1'b0;endelsebeginrepeat_en_d1 <= repeat_en;repeat_en_d2 <= repeat_en_d1;end//当重复码使能信号上升沿来到,拉高计数器使能信号,计到50ms后拉低
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_en <= 1'b0;else if(cnt == CNT_MAX - 1)cnt_en <= 1'b0;else if(repeat_en_rise == 1'b1)cnt_en <= 1'b1;//当计数器使能信号为高时让计数器开始计数,为低时计数器清零
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt <= 22'b0;else if(cnt_en == 1'b1)cnt <= cnt + 1;elsecnt <= 22'b0;//当计数器大于0时,点亮led灯,也就是当使能信号到来,led灯会亮50ms
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)led <= 1'b1;else if(cnt > 0)led <= 1'b0;elseled <= 1'b1;endmodule
top_infrared_rcv
`timescale 1ns/1nsmodule top_infrared_rcv
(input wire sys_clk , //系统时钟,频率50MHzinput wire sys_rst_n , //复位信号,低电平有效input wire infrared_in , //红外接收信号output wire stcp , //输出数据存储寄时钟output wire shcp , //移位寄存器的时钟输入output wire ds , //串行数据输入output wire oe , //输出使能信号output wire led //led灯控制信号
);//wire define
wire repeat_en ; //重复码使能信号
wire [19:0] data ; //接收的控制码//-------------infrared_rcv_inst--------------
infrared_rcv infrared_rcv_inst
(.sys_clk (sys_clk ), //系统时钟,频率50MHz.sys_rst_n (sys_rst_n ), //复位信号,低有效.infrared_in (infrared_in), //红外接受信号.repeat_en (repeat_en ), //重复码使能信号.data (data ) //接收的控制码
);//-------------led_ctrl_inst--------------
led_ctrl led_ctrl_inst
(.sys_clk (sys_clk ) , //系统时钟,频率50MHz.sys_rst_n (sys_rst_n) , //复位信号,低有效.repeat_en (repeat_en) , //重复码使能信号.led (led )
);//-------------seg_595_dynamic_inst--------------
seg_595_dynamic seg_595_dynamic_inst
(.sys_clk (sys_clk ), //系统时钟,频率50MHz.sys_rst_n (sys_rst_n), //复位信号,低有效.data (data ), //数码管要显示的值.point (6'd0 ), //小数点显示,高电平有效.seg_en (1'b1 ), //数码管使能信号,高电平有效.sign (1'b0 ), //符号位,高电平显示负号.stcp (stcp ), //输出数据存储寄时钟.shcp (shcp ), //移位寄存器的时钟输入.ds (ds ), //串行数据输入.oe (oe ) //输出使能信号
);endmodule
tb_top_infrared_rcv
`timescale 1ns/1ns
module tb_top_infrared_rcv();//wire define
wire led ;
wire stcp ;
wire shcp ;
wire ds ;
wire oe ;//reg define
reg sys_clk ;
reg sys_rst_n ;
reg infrared_in ;//对sys_clk,sys_rst_n,infrared_in赋值
initialbeginsys_clk = 1'b1;sys_rst_n <= 1'b0;infrared_in <= 1'b1;#100sys_rst_n <= 1'b1;
//引导码#1000infrared_in <= 1'b0; #9000000infrared_in <= 1'b1; #4500000
//地址码(发送地址码8’h99)
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//地址反码(地址反码为8’h66)
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据码(发送数据码8’h22)
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据反码(数据反码为8’hdd)
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据0infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #560000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//数据1infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #1690000
//重复码infrared_in <= 1'b0; #560000infrared_in <= 1'b1; #42000000infrared_in <= 1'b0; #9000000infrared_in <= 1'b1; #2250000infrared_in <= 1'b0; #560000infrared_in <= 1'b1;end//clk:产生时钟
always #10 sys_clk <= ~sys_clk;top_infrared_rcv top_infrared_rcv_inst
(.sys_clk (sys_clk ), //系统时钟,频率50MHz.sys_rst_n (sys_rst_n ), //复位信号,低电平有效.infrared_in (infrared_in), //红外接收信号.stcp (stcp ), //输出数据存储寄时钟.shcp (shcp ), //移位寄存器的时钟输入.ds (ds ), //串行数据输入.oe (oe ), //输出使能信号.led (led ) //led灯控制信号);endmodule
更多推荐
FPGA强化(5):红外遥控
发布评论