fpga的学习:红外遥控(代码片段)

石小舟 石小舟     2022-12-13     546

关键词:

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



来看红外接收模块:






`timescale  1ns/1ns
module  infrared_rcv
(
    input   wire        sys_clk     ,   //系统时钟,频率50MHz
    input   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-27999
            CNT_0_56MS_H  =   35000 ,
            CNT_1_69MS_L  =   80000 ,    //1.69ms计数为0-84499
            CNT_1_69MS_H  =   90000 ,
            CNT_2_25MS_L  =   100000,    //2.25ms计数为0-112499
            CNT_2_25MS_H  =   125000,
            CNT_4_5MS_L   =   175000,   //4.5ms计数为0-224999
            CNT_4_5MS_H   =   275000,
            CNT_9MS_L     =   400000,   //9ms计数为0-449999
            CNT_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)
        begin
            infrared_in_d1  <=  1'b0;
            infrared_in_d2  <=  1'b0;
        end
    else
        begin
            infrared_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;
    else
        case(state)
            IDLE:   cnt <=  19'd0;
            S_T9:   if((ifr_in_rise==1'b1) && (flag_9ms==1'b1))
                        cnt <=  19'd0;
                    else
                        cnt <=  cnt + 1;
            S_JUDGE:if((ifr_in_fall==1'b1) && (flag_2_25ms==1'b1 || flag_4_5ms==1'b1))
                        cnt <=  19'd0;
                    else
                        cnt <=  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;
                        else
                            cnt <=  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;
    else
        flag_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;
    else
        flag_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;
    else
        flag_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;
    else
        flag_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;
    else
        flag_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;
            else
                state   <=  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;
            else
                state   <=  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;
            else
                state   <=  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;
    else
        data_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;
    else
        data_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;
    else
        repeat_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     ,   //系统时钟,频率50MHz
    input   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)
        begin
            repeat_en_d1    <=  1'b0;
            repeat_en_d2    <=  1'b0;
        end
    else
        begin
            repeat_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;
    else
            cnt <=  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;
    else
        led <=  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赋值
initial
    begin
        sys_clk     =   1'b1;
        sys_rst_n   <=  1'b0;
        infrared_in <=  1'b1;
        #100
        sys_rst_n   <=  1'b1;
//引导码
        #1000
        infrared_in <=  1'b0; #9000000
        infrared_in <=  1'b1; #4500000
//地址码(发送地址码8’h99)
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//地址反码(地址反码为8’h66)
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据码(发送数据码8’h22)
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据反码(数据反码为8’hdd)
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//重复码
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #42000000
        infrared_in <=  1'b0; #9000000
        infrared_in <=  1'b1; #2250000
        infrared_in <=  1'b0; #560000
        infrared_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

红外遥控学习,万能遥控解决方案(代码片段)

红外遥控学习,万能遥控解决方案1.原理2.思路3.红外遥控接收3.1初始化定时器3.2定时器输入捕获3.3获取数据3.4红外接收测试3.5测试过程4.发送程序4.1初始化定时器和定时器的通道4.1发送函数1.原理目前电视机、空调等家电大部... 查看详情

51单片机学习笔记_14红外遥控(代码片段)

红外传感器遥控器通过红外LED发送调制后的信号,开发板上的红外接收模块接收遥控器的红外线。单工异步,940nm波长(还有一种250nm的N,可见光),EC通信标准。38KHz:红外线频率。IN:发送的方波... 查看详情

esp8266+红外模块制作万能网路遥控器(代码片段)

ESP8266+红外模块制作万能网路遥控器通过红外模块模拟遥控发射指令接入blinker平台,通过手机可以远程控制。前提是先读取出你要操控设备遥控的发射码出来。参考《Arduino红外接收码获取程序》手机APP:点灯blinker在APP应用里面... 查看详情

基于点灯blinker——esp8266红外遥控空调(代码片段)

基于点灯blinker——ESP8266红外遥控格力空调提醒:本篇内容的通用性不强,因为没有采用获取红外遥控编码的指令来模拟遥控发送,非标准设备编码可能不一样,可能控制失效。程序中所用到的库有Blinker和IRremoteESP8266都可以在Ard... 查看详情

树梅派硬件编程_红外遥控器(代码片段)

红外遥控器红外遥控原理用户码或数据码中的每一个位可以是位‘1’,也可以是位‘0’。区分‘0’和‘1’是利用脉冲的时间间隔来区分,这种编码方式称为脉冲位置调制方式,英文简写PPM。红外接收头的型号有很... 查看详情

androidstb遥控器适配(代码片段)

文章目录一、常用命令介绍二、红外遥控器适配2.1海思红外遥控器适配2.2Amlogic红外遥控器适配2.3Mstar红外遥控器适配三、蓝牙遥控器适配3.1蓝牙键值3.2kl3.3Android键值一、常用命令介绍在目前的机顶盒市场中,海思和Amlogic࿰... 查看详情

乐鑫esp8266的基于nonos移植红外线1883,实现遥控器控制(代码片段)

...阶博文有那么一段时间了,那么本文带来的是基于Nonos的红外线H1838的NEC协议的移植小案例,浏览博文前,需要知道以下常识:1、红外遥控的原理是什么?2、红外遥控的协议有哪些?NEC?3、红外遥控的电路组成?8266的最小系统... 查看详情

4.451单片机-nec红外线遥控器解码(代码片段)

4.4 NEC红外线遥控器解码4.4.1接收头原理图介绍图4-4-1实验板上的红外线接收头是接在单片机的P3.2IO口上,要使用红外线接收功能,需要将红外线接收头的跳线帽接上。图4-4-24.4.2NEC红外线协议介绍红外线遥控是目前使用最... 查看详情

基于arduino的红外遥控(代码片段)

1、红外接收头介绍 一、什么是红外接收头? 红外遥控器发出的信号是一连串的二进制脉冲码。为了使其在无线传输过程中免受其他红外信号的干扰,通常都是先将其调制在特定的载波频率上,然后再经红外发射二极管发射... 查看详情

基于arduino智能控制(时钟模块,光敏,红外遥控)(代码片段)

...。)一、接线说明(时钟模块示例图)(红外模块)二、代码部分功能简介此次模块最终实现的功能是通过红外遥控器上对应的按钮,进入各个按钮所对应的不同模式。1.单个按钮控制(1)按下“... 查看详情

用米思齐(mixly)或者arduino制作红外线遥控灯(代码片段)

----用米思齐(mixly)或者Arduino制作红外线遥控灯一、先设置红外线遥控和LED灯的端口二、在面包板上把LED灯的电路接好,注意要接电阻!三、Arduino代码#include<IRremote.h>longir_item;IRrecvirrecv_5(5);decode_resultsresults_5;... 查看详情

红外通信(代码片段)

红外线系统一般由红外发射装置和红外接收设备两大部分组成。红外发射装置又可由键盘电路、红外编码芯片、电源和红外发射电路组成。红外接收设备可由红外接收电路、红外解码芯片、电源和应用电路组成。常为了使信号更... 查看详情

和12岁小同志搞创客开发:如何驱动红外遥控器?(代码片段)

目录1、红外遥控器通信原理2、NEC协议3、实践机缘巧合在网上认识一位12岁小同志,从零开始系统辅导其创客开发思维和技巧。项目专栏:https://blog.csdn.net/m0_38106923/category_11097422.html 红外遥控器是我们常用的一种遥控设... 查看详情

和12岁小同志搞创客开发:如何驱动红外遥控器?(代码片段)

目录1、红外遥控器通信原理2、NEC协议3、实践机缘巧合在网上认识一位12岁小同志,从零开始系统辅导其创客开发思维和技巧。项目专栏:https://blog.csdn.net/m0_38106923/category_11097422.html 红外遥控器是我们常用的一种遥控设... 查看详情

androidframework工作日志---atv9遥控器红外模式下,机顶盒在假待机阶段会响应遥控器语音键(代码片段)

【问题描述】测试部反馈,红外模式下,按power键进入假待机,按红外语音键会唤醒。背景交代:红外语言键是我们自定义的按键,键值225。在红外模式下按会弹提示框“没连蓝牙,请连蓝牙使用语音键【问题结论】不是问题,... 查看详情

51单片机_红外线(代码片段)

...*************************************************************************2*红外通信实验*3实现现象:下载程序后,数码管显示红外遥控键值数据4注意事项:红外遥控器内的电池绝缘片一定要抽掉5****************************************************** 查看详情

proteus仿真+c8051源码(100例)+红外线遥控仿真(代码片段)

从百度网盘下载,提取码:di7r目录结构├─Proteus仿真+C8051源码(100例)││源码解释.doc│││└─基于8051+Proteus仿真││案例压缩包相关说明.txt│││├─第01篇基础部分││├─01闪烁的LED││││LastLoaded闪烁的LED.DBK││││... 查看详情

基于arduino检测红外遥控编码(调用第三方库教程)(代码片段)

Arduino板子红外遥控模块1.接线5V----------+(红外接收头正极)GND--------(红外接收头负极)OUT--------11(11号引脚)2.调用第三方库1.通过项目----->加载库---->管理库2.打开库管理器3.搜索红外遥控模块对... 查看详情