FPGA的学习:红外遥控

编程入门 行业动态 更新时间:2024-10-08 02:24:45

<a href=https://www.elefans.com/category/jswz/34/1769628.html style=FPGA的学习:红外遥控"/>

FPGA的学习:红外遥控

使用 FPGA 开发板配套的红外遥控器发送红外信号, FPGA 开发板上的一
体化接收头接收到红外信号后传入 FPGA 芯片内, FPGA 芯片接收到信号后进行解码,将解码后的按键码显示在数码管上。若检测到发送了重复码,则让 led 闪烁显示,一个重复码闪烁一次。



来看红外接收模块:






`timescale  1ns/1ns
module  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;elsecase(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控制模块

`timescale  1ns/1ns
module  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

最后得到RTL视图。

然后进行仿真验证。

`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的学习:红外遥控

本文发布于:2024-03-12 10:57:41,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1731348.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:FPGA

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!