红外NEC通信协议

news2025/1/16 17:14:53

一、NEC简介

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

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

二、NEC传输格式

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

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

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

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

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

三、FPGA实现

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/829531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JDK, JRE和JVM之间的区别和联系

JDK, JRE和JVM是与Java编程语言相关的三个重要的概念&#xff0c;它们分别代表Java Development Kit&#xff08;Java开发工具包&#xff09;、Java Runtime Environment&#xff08;Java运行时环境&#xff09;和Java虚拟机&#xff08;Java Virtual Machine&#xff09;。它们…

PHP8的运算符-PHP8知识详解

运算符是可以通过给出的一或多个值&#xff08;用编程行话来说&#xff0c;表达式&#xff09;来产生另一个值&#xff08;因而整个结构成为一个表达式&#xff09;的东西。 PHP8的运算符有很多&#xff0c;按类型分有一元运算符、二元运算符、三元运算符。 一元运算符只对一…

Java类与对象详解(2)

this引用 为什么要有this引用 先来看一个日期类的例子&#xff1a; ​ public class Date {public int year;public int month;public int day;//设置日期方法public void setDay(int y, int m, int d){//这里隐藏了一个Date this参数year y;month m;day d;}public void …

广州银行信用卡中心:强化数字引擎安全,实现业务稳步增长

广州银行信用卡中心是全国城商行中仅有的两家信用卡专营机构之一&#xff0c;拥有从金融产品研发至销售及后期风险控制、客户服务完整业务链条&#xff0c;曾获“2016年度最佳创新信用卡银行”。 数字引擎驱动业务增长 安全左移降低开发风险 近年来&#xff0c;广州银行信用卡…

fetch的使用和实现跨域及与axios的区别

一、作用 和axios作用类似&#xff0c;用于请求接口。它是XMLHttpRequest的一种替代方案。 二、安装 因为fetch有兼容性问题&#xff0c;所以我们安装升级版 whatwg-fetch cnpm i whatwg-fetch -S 三、使用 四、fetch和axios的区别 1&#xff0c;fetch返回的是一个未处理…

华为OD机试真题 Java 实现【TLV格式】【2023 B卷 200分】,附详细解题思路

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#…

聚焦 TimescaleDB VS TDengine 性能对比报告,IoT 场景下全面分析写入与查询

基于第三方基准性能测试平台 TSBS&#xff08;Time Series Benchmark Suite&#xff09; 标准数据集&#xff0c;TDengine 团队在 TSBS 的 IoT 场景中&#xff0c;预设了五种规模的卡车车队基础数据集&#xff0c;在相同的 AWS 云环境下对时序数据库&#xff08;Time Series Da…

【NLP概念源和流】 01-稀疏文档表示(第 1/20 部分)

一、介绍 自然语言处理(NLP)是计算方法的应用,不仅可以从文本中提取信息,还可以在其上对不同的应用程序进行建模。所有基于语言的文本都有系统的结构或规则,通常被称为形态学,例如“跳跃”的过去时总是“跳跃”。对于人类来说,这种形态学的理解是显而易见的。 在这篇介…

【FAQ】在Linux中使用curl访问EasyCVR,返回报错Unauthorized的原因排查

EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力&#xff0c;比如&#xff1a;视…

【C++刷题】经典简单题第一辑

数字在升序数组中出现的次数 class Solution { public:int GetNumberOfK(vector<int>& nums, int k){size_t left 0;size_t right nums.size();size_t mid1 -1;/** 用二分法的思想寻找 k 的边界*/// 寻找 k 的左边界下标while(left < right){mid1 left (ri…

yolov3-spp 训练结果分析:网络结果可解释性、漏检误检分析

1. valid漏检误检分析 ①为了探查第二层反向找出来的目标特征在最后一层detector上的意义&#xff01;——为什么最后依然可以框出来目标&#xff0c;且mAP还不错的&#xff1f; ②如何进一步提升和改进这个数据的效果&#xff1f;可以有哪些优化数据和改进的地方&#xff1f;让…

5分钟学会你创建搜狗百科

搜狗百科属于微信生态里的平台&#xff0c;搜狗百科不仅在搜狗搜索中展示&#xff0c;且可以在微信搜索中展示。那么搜狗百科该怎么创建呢&#xff1f;下面小马识途营销顾问分享下搜狗百科词条创建的流程。 1、要创建搜狗百科词条&#xff0c;首先需要在搜狗百科官网上注册一个…

【前端入门之旅】HTML中元素和标签有什么区别?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 标签&#xff08;Tag&#xff09;⭐元素&#xff08;Element&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&a…

实例028 为触摸屏程序添加虚拟键盘

实例说明 由于触摸屏没有键盘&#xff0c;只能利用屏幕操作。如果要输入数据或查找数据&#xff0c;需要制作一个虚拟键盘&#xff0c;以方便用户输入。本例介绍如何实现虚拟键盘的程序设计。运行本例&#xff0c;效果如图1.28所示。 技术要点 本例中用到了Lable控件的透明属…

【HarmonyOS】性能优化之低代码开发加载多张轮播图

【关键字】 HarmonyOS、低代码开发、Swiper组件、性能优化、分页加载 写在前面 目前使用DevEco Studio的低代码工具开发元服务时&#xff0c;通过实际测试发现&#xff0c;Swiper组件加载多张轮播图时加载显示耗时较长&#xff08;实际测试网络状态一般的情况下显示耗时达到8…

好的CRM有哪些优点及功能?

市面上有很多CRM品牌&#xff0c;很多初次选型的企业没有深入的了解&#xff0c;不知道如何选择适合自己的CRM软件。小编认为&#xff0c;CRM选型无非就是靠谱和适合。这里有一款值得信赖的CRM软件推荐——Zoho CRM。 一、什么是Zoho CRM&#xff1f; Zoho CRM是一款SaaS云端…

只需十四步,从零开始掌握Python机器学习

推荐阅读&#xff08;点击标题查看&#xff09; 1、Python 数据挖掘与机器学习实践技术应用 2、R-Meta分析与【文献计量分析、贝叶斯、机器学习等】多技术融合实践与拓展 3、最新基于MATLAB 2023a的机器学习、深度学习 4、【八天】“全面助力AI科研、教学与实践技能”夏令营…

计算机视觉与图形学-神经渲染专题-第一个基于NeRF的自动驾驶仿真平台

如今&#xff0c;自动驾驶汽车可以在普通情况下平稳行驶&#xff0c;人们普遍认识到&#xff0c;真实的传感器模拟将在通过模拟解决剩余的极端情况方面发挥关键作用。为此&#xff0c;我们提出了一种基于神经辐射场&#xff08;NeRF&#xff09;的自动驾驶模拟器。与现有作品相…

无人机自动返航的关键技术有哪些

无人机的广泛应用使得无人机自动返航技术变得至关重要。在各种应对意外情况的背景下&#xff0c;无人机自动返航技术的发展对确保无人机的安全&#xff0c;以及提高其应用范围具有重要意义。接下来&#xff0c;便为大家详细介绍无人机自动返航所运用到的关键技术。 一、定位与导…

Mysql on duplicate key update用法及优缺点

在实际应用中&#xff0c;经常碰到导入数据的功能&#xff0c;当导入的数据不存在时则进行添加&#xff0c;有修改时则进行更新&#xff0c; 在刚碰到的时候&#xff0c;一般思路是将其实现分为两块&#xff0c;分别是判断增加&#xff0c;判断更新&#xff0c;后来发现在mysql…