红外NEC通信协议

这篇具有很好参考价值的文章主要介绍了红外NEC通信协议。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、NEC简介

        红外(Infrared,IR)遥控是一种无线、非接触控制技术,常用于遥控器、无线键盘、鼠标等设备之间的通信。IR协议的工作原理是,发送方通过红外线发送一个特定的编码,接收方通过识别该编码来执行相应的操作。

        IR协议是指红外线通信协议的总称,而NEC协议是IR协议中的一种具体实现。红外遥控系统分为发射和接收两部分,发射部分的发射元件为红外发光二极管,它发出的是红外线而不是可见光;接收电路的红外接收管是一种光敏二极管。

nec协议,一般人学不会的FPGA,协议,NEC,红外IR,FPGA

二、NEC传输格式

        NEC协议采用PPM(Pulse Position Modulation,脉冲位置调制)的形式进行编码,数据的每一位(Bit)脉冲长度为560us,由38KHz的载波脉冲 (carrier burst) 进行调制,推荐的载波占空比为 1/3至 1/4。有载波脉冲的地方,其宽度都为 560us,而载波脉冲的间隔时间是不同的。

        逻辑“1”的载波脉冲+载波脉冲间隔时间为2.25ms;逻辑“0”的载波脉冲+载波脉冲间隔时间为逻辑“1”的一半,即1.125ms. 

nec协议,一般人学不会的FPGA,协议,NEC,红外IR,FPGA

        每次信息都是按照引导码 (9ms载波脉冲+4.5ms 空闲信号)地址码、地址反码、控制码和控制反码的格式进行传输,因此,单次信息传输的时间是固定不变的

nec协议,一般人学不会的FPGA,协议,NEC,红外IR,FPGA

        当红外遥控器上的按键被一直按下时,红外遥控器只会发送一次完整的信息,其后会每隔 110ms 发送一次重复码(连发码)。重复码的数据格式比较简单,同样是由 9ms的载波脉冲开始,紧接着是2.25ms的空闲信号,随后是560us的载波脉冲。

nec协议,一般人学不会的FPGA,协议,NEC,红外IR,FPGA

nec协议,一般人学不会的FPGA,协议,NEC,红外IR,FPGA

        红外接收头通常被厂家集成在一个元件中,成为一体化红外接收头。红外接收头内部的三极管电路具有信号反向的功能,也就是将1变为0,0变为1,即数据0是0.56ms的低电平和0.56ms的高电平,数据1是0.5ms的低电平和1.69ms的高电平,9ms是高电平变为低电平。

nec协议,一般人学不会的FPGA,协议,NEC,红外IR,FPGA

三、FPGA实现

通过三段式状态机实现红外驱动模块

nec协议,一般人学不会的FPGA,协议,NEC,红外IR,FPGA文章来源地址https://www.toymoban.com/news/detail-718996.html

module ir_rcv(
    input                  clk   ,      //系统时钟
    input                  rst_n ,      //系统复位信号,低电平有效
    input                  remote_in ,  //红外接收信号
	 
    output    reg          repeat_en ,  //重复码有效信号
    output    reg          data_en   ,  //数据有效信号
    output    reg  [7:0]   data         //红外控制码
    );

//parameter define
parameter  idle           = 5'b0_0001;  //空闲状态
parameter  start_low_9ms  = 5'b0_0010;  //监测同步码低电平
parameter  start_judge    = 5'b0_0100;  //判断重复码和同步码高电平(空闲信号)
parameter  rec_data       = 5'b0_1000;  //接收数据
parameter  repeat_code    = 5'b1_0000;  //重复码

//reg define
reg    [4:0]    cur_state      ;  //当前状态
reg    [4:0]    next_state     ;  //下一状态

reg    [11:0]   div_cnt        ;  //分频计数器
reg             div_clk        ;  //分频时钟
reg             remote_in_d0   ;  //对输入的红外信号延时打拍
reg             remote_in_d1   ;
reg    [7:0]    time_cnt       ;  //对红外的各个状态进行计数

reg             time_cnt_clr   ;  //计数器清零信号
reg             time_done      ;  //计时完成信号
reg             error_en       ;  //错误信号
reg             judge_flag     ;  //检测出的标志信号 0:同步码高电平(空闲信号)  1:重复码
reg    [15:0]   data_temp      ;  //暂存收到的控制码和控制反码
reg    [5:0]    data_cnt       ;  //对接收的数据进行计数       

//wire define
wire            ir_pos  ;  //输入红外信号的上升沿
wire            ir_neg  ;  //输入红外信号的下降沿

//*****************************************************
//**                    main code
//*****************************************************

assign  ir_pos = (~remote_in_d1) & remote_in_d0;
assign  ir_neg = remote_in_d1 & (~remote_in_d0);

//对50MHz时钟进行分频,50Mhz/(2*(3124+1))=8khz,T=0.125ms,得到一个周期为0.125ms(8KHz)的时钟
//对时钟进行分频,是因为红外信号接收的过程用时较长,如果使用50Mhz的时钟采样,内部定义的计数器位宽会比较大,也可以分频成其它频率的时钟
always @(posedge clk or negedge rst_n  ) begin
    if (!rst_n) begin
        div_cnt <= 12'd0;
        div_clk <= 1'b0;
    end    
    else if(div_cnt == 12'd3124) begin
        div_cnt <= 12'd0;
        div_clk <= ~div_clk;
    end    
    else
        div_cnt <= div_cnt + 12'b1;
end

//对红外的各个状态进行计数,例如监测同步码低电平、判断重复码和同步码高电平等
always @(posedge div_clk or negedge rst_n) begin
    if(!rst_n)
        time_cnt <= 8'b0;
    else if(time_cnt_clr)
        time_cnt <= 8'b0;
    else 
        time_cnt <= time_cnt + 8'b1;
end 

//对输入的remote_in信号延时打拍,即在一个时钟周期内,获取两个不同的红外信号采样值,以便后续的上升沿和下降沿检测
always @(posedge div_clk or negedge rst_n) begin
    if(!rst_n) begin
        remote_in_d0 <= 1'b0;
        remote_in_d1 <= 1'b0;
    end
    else begin
        remote_in_d0 <= remote_in;
        remote_in_d1 <= remote_in_d0;
    end
end

//采用三段式状态机对红外信号进行解析
always @ (posedge div_clk or negedge rst_n) begin
    if(!rst_n)
        cur_state <= idle;
    else
        cur_state <= next_state ;
end

always @(*) begin
    next_state = idle;                          
    case(cur_state)
        idle : begin                           //默认在空闲状态,time_cnt_clr的值置为1,time_cnt也就为0
            if(remote_in_d0 == 1'b0)           //在空闲状态中检测到下降沿,则进入9ms低电平判断
                next_state = start_low_9ms;    //此时time_cnt_clr的值置为0,time_cnt开始计数
            else
                next_state = idle;             //否则一直保持空闲状态
        end
        start_low_9ms : begin                  //监测同步码低电平
            if(time_done)                      //计数达到9ms,跳转判断重复码和同步码高电平
                next_state = start_judge;
            else if(error_en)                  //计数不在9ms范围,发生错误,跳转到空闲状态
                next_state = idle;
            else
                next_state = start_low_9ms;    //否则一直保持在start_low_9ms
        end
        start_judge : begin                    //判断重复码和同步码高电平(空闲信号)
            if(time_done) begin
                if(judge_flag == 1'b0)         //如果是同步码,则跳转到接收数据状态
                    next_state = rec_data;
                else 
                    next_state = repeat_code;  //否则跳转到重复码状态
            end
            else if(error_en)
                next_state = idle;
            else
                next_state = start_judge;
        end
        rec_data : begin                       //接收数据,当数据传输完成,跳转到空闲状态
            if(ir_pos && data_cnt == 6'd32) 
                next_state = idle;
            else
                next_state = rec_data;                
        end
        repeat_code : begin                    //重复码
            if(ir_pos)
                next_state = idle;             //进入空闲状态
            else
                next_state = repeat_code;    
        end    
        default : next_state = idle;
    endcase
end

always @(posedge div_clk or negedge rst_n ) begin 
    if (!rst_n) begin  
        time_cnt_clr <= 1'b0;
        time_done <= 1'b0;
        error_en <= 1'b0;
        judge_flag <= 1'b0;
        data_en <= 1'b0;
        data <= 8'd0;
        repeat_en <= 1'b0;
        data_cnt <= 6'd0;
        data_temp <= 32'd0;
    end
    else begin
        time_cnt_clr <= 1'b0;
        time_done <= 1'b0;
        error_en <= 1'b0;
        repeat_en <= 1'b0;
        data_en <= 1'b0;
        case(cur_state)
            idle           : begin
                time_cnt_clr <= 1'b1;
                if(remote_in_d0 == 1'b0)
                    time_cnt_clr <= 1'b0;
            end   
            start_low_9ms  : begin                             //9ms/0.125ms = 72
                if(ir_pos) begin                               //当检测到ir_pos(红外信号上升沿)为高电平时,说明此时红外信号拉高,即同步码低电平结束
                    time_cnt_clr <= 1'b1;                      //停止计数            
                    if(time_cnt >= 69 && time_cnt <= 75)       //判断time_cnt的值是否接近9ms,如果接近9ms,跳转到start_judee状态
                        time_done <= 1'b1;  
                    else                                       //如果time_cnt的值不接近9ms,则发生了错误,跳转到空闲状态
                        error_en <= 1'b1;
                end   
            end
            start_judge : begin
                if(ir_neg) begin   
                    time_cnt_clr <= 1'b1;   
                    if(time_cnt >= 15 && time_cnt <= 20) begin          //重复码高电平2.25ms 2.25/0.125 = 18
                        time_done <= 1'b1;
                        judge_flag <= 1'b1;                             //检测出是重复码,跳转到repeat_code重复码状态
                    end    
                    else if(time_cnt >= 33 && time_cnt <= 38) begin     //同步码高电平4.5ms  4.5/0.125 = 36
                        time_done <= 1'b1;
                        judge_flag <= 1'b0;                             //检测出是同步码,跳转到rec_data接收数据状态   
                    end
                    else
                        error_en <= 1'b1;
                end                       
            end
            rec_data : begin                                  
                if(ir_pos) begin                                  //当有红外信号上升沿
                    time_cnt_clr <= 1'b1;
                    if(data_cnt == 6'd32) begin                   //有32个数据即32个上升沿或下降沿,分别为16位地址码以及16位数据
                        data_en <= 1'b1;                          //当计数到32即数据传输完成
                        data_cnt <= 6'd0;
                        data_temp <= 16'd0;
                        if(data_temp[7:0] == ~data_temp[15:8])    //校验控制码和控制反码
                            data <= data_temp[7:0];
                    end
                end
                else if(ir_neg) begin                             //当有红外信号下降沿
                    time_cnt_clr <= 1'b1;
                    data_cnt <= data_cnt + 1'b1;                  //每当1bit数据到来时也就是一个下降沿到来时,数据位数计数器加1
                    //解析控制码和控制反码,判断是560us还是1690us计数完成,进而得到这个数据位是0还是1        
                    if(data_cnt >= 6'd16 && data_cnt <= 6'd31) begin 
                        if(time_cnt >= 2 && time_cnt <= 6) begin  //0.565/0.125 = 4.52
                            data_temp <= {1'b0,data_temp[15:1]};  //逻辑“0”
                        end
                        else if(time_cnt >= 10 && time_cnt <= 15) //1.69/0.125 = 13.52
                            data_temp <= {1'b1,data_temp[15:1]};  //逻辑“1”
                    end
                end
            end
            repeat_code : begin                                
                if(ir_pos) begin                           
                    time_cnt_clr <= 1'b1;
                    repeat_en <= 1'b1;
                end
            end
            default : ;
        endcase
    end
end

endmodule

到了这里,关于红外NEC通信协议的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【FPGA开发】HDMI通信协议解析及FPGA实现

      笔者在这里使用的开发板是正点原子的达芬奇开发板,FPGA型号为XC7A35TFGG484-2。参考的课程是正点原子的课程手把手教你学达芬奇达芬奇Pro之FPGA开发篇。   HDMI,全称为High Definition Multimedia Interface,即高清多媒体接口。它不仅可以传输视频信号,还可以传输音频信号。上

    2024年02月21日
    浏览(48)
  • 详解UART通信协议以及FPGA实现

      从《浅谈UART,TTL,RS-232,RS-485的区别》这篇文章,我们知道了UART是一种串行、异步、全双工的通信协议,属于协议层;传输过程一般采用RS-232,RS-485电平标准,将所需传输的数据一位接一位地传输;整体传输框架如下:   串口通信由发送端和接收端构成,两根信号线

    2024年04月28日
    浏览(39)
  • 【LabVIEW FPGA入门】LabVIEW FPGA 实现SPI通信协议

            该实现由两个组件组成:在 LabVIEW FPGA 中实现的 SPI 协议以及用于从主机 PC 或实时控制器与 FPGA 进行通信的 LabVIEW 主机接口。该架构允许从单个主机程序控制多个 SPI 端口,同时仍然允许定制 FPGA VI 以进行其他数据采集和处理。该实现不使用任何DMA(直接内存访问

    2024年01月17日
    浏览(58)
  • 【一般人不会告诉你】比肩chatgtp的5款AI网站

    1. Dall-E: https://labs.openai.com/ 2. Codeformer: https://shangchenzhou.com/projects/Co... 3. Playground AI: https://playgroundai.com/ 4. Clip Drop: https://clipdrop.co/relight 5. Astria: https://www.strmr.com/examples 6. ChatGPT: https://chat.openai.com/chat 第一个,DALL-E,这个网站是一个图片生成网站,它对每一个图片设置了

    2024年02月02日
    浏览(32)
  • IIC通信协议详解 & PCF8591应用(Verilog实现FPGA)

    该文章结合PCF8591 8-bit AD/DA 模数/数模转换器来详细介绍IIC通信协议,尽量做到条理清晰,通俗易懂。该文图片均从PCF8591手册中截取,一定程度上引导读者学习阅读data sheet。 之后可能会更新 如何将IIC的Verilog实现变为一个IP核,并在pynq-Z2板子上使用 。 2.1 地址位 在I2C总线系统

    2024年02月04日
    浏览(65)
  • 【FPGA】 xilinx vivado中AXI4通信协议详解

    AXI是ARM 1996年提出的微控制器总线家族AMBA中的一部分。AXI的第一个版本出现在AMBA3.0,发布于2003年。当前的最新的版本发布于2010年。AXI 4总线和别的总线一样,都用来传输bits信息 (包含了数据或者地址) 。AXI4总线有三种类型,分别是AXI4、AXI4-Lite、AXI4-Stream AXI4:主要面向高性能

    2024年04月28日
    浏览(44)
  • FPGA 20个例程篇:13.千兆网口实现ARP通信协议(下)

            完成了RGMII接口和GMII接口转换的代码设计,接下来我们来设计以太网帧的报文解析模块,为了兼顾下一个例程中ICMP和UDP报文的解析,我们把ARP报文解析分成以太网首部解析和ARP数据解析两部分,这样以太网首部解析模块还可以再用到下一个例程当中提高了代码的复用

    2024年02月13日
    浏览(49)
  • FPGA 20个例程篇:14.千兆网口实现ICMP、UDP通信协议(上)

           UDP是一种面向无连接的传输层协议,属于TCP/IP协议族的一种,UDP具有消耗资源少、通信效率高等优点,一般性地用来传输音频或者视频等对实时性要求高的场合。         ICMP是TCP/IP协议族的一个IP层子协议,包含在IP数据报里,主要用于IP主机、路由器之间传递控制消

    2024年02月03日
    浏览(45)
  • 【FPGA协议篇】UART通信及其verilog实现(代码采用传参实现模块通用性,适用于快速开发)

    ​ 即通用异步收发器(Universal Asynchronous Receiver/Transmitter),是一种 串行、异步、全双工 的通信协议。特点是通信线路简单,适用于远距离通信,但传输速度慢。 数据传输速率:波特率(单位:baud,波特) 常见波特率有:1200、2400、4800、19200、38400、57600等,最常用的是9600和11520

    2024年02月05日
    浏览(50)
  • FPGA协议篇:UART通信及Verilog最易懂实现方式/通用于任何工程/带握手信号 ----UART_TX

            UART(Universal Asynchronous Receiver/Transmitter)是一种通用的 异步收发传输协议 ,用于在计算机系统和外部设备之间进行串行数据传输。UART 协议定义了数据的传输格式和通信规则,使得不同设备之间能够进行可靠的数据交换。 首先先把设计代码放到这里: UART_TX完整代

    2024年03月27日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包