当前位置:   article > 正文

红外NEC通信协议_nec协议

nec协议

一、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实现

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

  1. module ir_rcv(
  2. input clk , //系统时钟
  3. input rst_n , //系统复位信号,低电平有效
  4. input remote_in , //红外接收信号
  5. output reg repeat_en , //重复码有效信号
  6. output reg data_en , //数据有效信号
  7. output reg [7:0] data //红外控制码
  8. );
  9. //parameter define
  10. parameter idle = 5'b0_0001; //空闲状态
  11. parameter start_low_9ms = 5'b0_0010; //监测同步码低电平
  12. parameter start_judge = 5'b0_0100; //判断重复码和同步码高电平(空闲信号)
  13. parameter rec_data = 5'b0_1000; //接收数据
  14. parameter repeat_code = 5'b1_0000; //重复码
  15. //reg define
  16. reg [4:0] cur_state ; //当前状态
  17. reg [4:0] next_state ; //下一状态
  18. reg [11:0] div_cnt ; //分频计数器
  19. reg div_clk ; //分频时钟
  20. reg remote_in_d0 ; //对输入的红外信号延时打拍
  21. reg remote_in_d1 ;
  22. reg [7:0] time_cnt ; //对红外的各个状态进行计数
  23. reg time_cnt_clr ; //计数器清零信号
  24. reg time_done ; //计时完成信号
  25. reg error_en ; //错误信号
  26. reg judge_flag ; //检测出的标志信号 0:同步码高电平(空闲信号) 1:重复码
  27. reg [15:0] data_temp ; //暂存收到的控制码和控制反码
  28. reg [5:0] data_cnt ; //对接收的数据进行计数
  29. //wire define
  30. wire ir_pos ; //输入红外信号的上升沿
  31. wire ir_neg ; //输入红外信号的下降沿
  32. //*****************************************************
  33. //** main code
  34. //*****************************************************
  35. assign ir_pos = (~remote_in_d1) & remote_in_d0;
  36. assign ir_neg = remote_in_d1 & (~remote_in_d0);
  37. //对50MHz时钟进行分频,50Mhz/(2*(3124+1))=8khz,T=0.125ms,得到一个周期为0.125ms(8KHz)的时钟
  38. //对时钟进行分频,是因为红外信号接收的过程用时较长,如果使用50Mhz的时钟采样,内部定义的计数器位宽会比较大,也可以分频成其它频率的时钟
  39. always @(posedge clk or negedge rst_n ) begin
  40. if (!rst_n) begin
  41. div_cnt <= 12'd0;
  42. div_clk <= 1'b0;
  43. end
  44. else if(div_cnt == 12'd3124) begin
  45. div_cnt <= 12'd0;
  46. div_clk <= ~div_clk;
  47. end
  48. else
  49. div_cnt <= div_cnt + 12'b1;
  50. end
  51. //对红外的各个状态进行计数,例如监测同步码低电平、判断重复码和同步码高电平等
  52. always @(posedge div_clk or negedge rst_n) begin
  53. if(!rst_n)
  54. time_cnt <= 8'b0;
  55. else if(time_cnt_clr)
  56. time_cnt <= 8'b0;
  57. else
  58. time_cnt <= time_cnt + 8'b1;
  59. end
  60. //对输入的remote_in信号延时打拍,即在一个时钟周期内,获取两个不同的红外信号采样值,以便后续的上升沿和下降沿检测
  61. always @(posedge div_clk or negedge rst_n) begin
  62. if(!rst_n) begin
  63. remote_in_d0 <= 1'b0;
  64. remote_in_d1 <= 1'b0;
  65. end
  66. else begin
  67. remote_in_d0 <= remote_in;
  68. remote_in_d1 <= remote_in_d0;
  69. end
  70. end
  71. //采用三段式状态机对红外信号进行解析
  72. always @ (posedge div_clk or negedge rst_n) begin
  73. if(!rst_n)
  74. cur_state <= idle;
  75. else
  76. cur_state <= next_state ;
  77. end
  78. always @(*) begin
  79. next_state = idle;
  80. case(cur_state)
  81. idle : begin //默认在空闲状态,time_cnt_clr的值置为1,time_cnt也就为0
  82. if(remote_in_d0 == 1'b0) //在空闲状态中检测到下降沿,则进入9ms低电平判断
  83. next_state = start_low_9ms; //此时time_cnt_clr的值置为0,time_cnt开始计数
  84. else
  85. next_state = idle; //否则一直保持空闲状态
  86. end
  87. start_low_9ms : begin //监测同步码低电平
  88. if(time_done) //计数达到9ms,跳转判断重复码和同步码高电平
  89. next_state = start_judge;
  90. else if(error_en) //计数不在9ms范围,发生错误,跳转到空闲状态
  91. next_state = idle;
  92. else
  93. next_state = start_low_9ms; //否则一直保持在start_low_9ms
  94. end
  95. start_judge : begin //判断重复码和同步码高电平(空闲信号)
  96. if(time_done) begin
  97. if(judge_flag == 1'b0) //如果是同步码,则跳转到接收数据状态
  98. next_state = rec_data;
  99. else
  100. next_state = repeat_code; //否则跳转到重复码状态
  101. end
  102. else if(error_en)
  103. next_state = idle;
  104. else
  105. next_state = start_judge;
  106. end
  107. rec_data : begin //接收数据,当数据传输完成,跳转到空闲状态
  108. if(ir_pos && data_cnt == 6'd32)
  109. next_state = idle;
  110. else
  111. next_state = rec_data;
  112. end
  113. repeat_code : begin //重复码
  114. if(ir_pos)
  115. next_state = idle; //进入空闲状态
  116. else
  117. next_state = repeat_code;
  118. end
  119. default : next_state = idle;
  120. endcase
  121. end
  122. always @(posedge div_clk or negedge rst_n ) begin
  123. if (!rst_n) begin
  124. time_cnt_clr <= 1'b0;
  125. time_done <= 1'b0;
  126. error_en <= 1'b0;
  127. judge_flag <= 1'b0;
  128. data_en <= 1'b0;
  129. data <= 8'd0;
  130. repeat_en <= 1'b0;
  131. data_cnt <= 6'd0;
  132. data_temp <= 32'd0;
  133. end
  134. else begin
  135. time_cnt_clr <= 1'b0;
  136. time_done <= 1'b0;
  137. error_en <= 1'b0;
  138. repeat_en <= 1'b0;
  139. data_en <= 1'b0;
  140. case(cur_state)
  141. idle : begin
  142. time_cnt_clr <= 1'b1;
  143. if(remote_in_d0 == 1'b0)
  144. time_cnt_clr <= 1'b0;
  145. end
  146. start_low_9ms : begin //9ms/0.125ms = 72
  147. if(ir_pos) begin //当检测到ir_pos(红外信号上升沿)为高电平时,说明此时红外信号拉高,即同步码低电平结束
  148. time_cnt_clr <= 1'b1; //停止计数
  149. if(time_cnt >= 69 && time_cnt <= 75) //判断time_cnt的值是否接近9ms,如果接近9ms,跳转到start_judee状态
  150. time_done <= 1'b1;
  151. else //如果time_cnt的值不接近9ms,则发生了错误,跳转到空闲状态
  152. error_en <= 1'b1;
  153. end
  154. end
  155. start_judge : begin
  156. if(ir_neg) begin
  157. time_cnt_clr <= 1'b1;
  158. if(time_cnt >= 15 && time_cnt <= 20) begin //重复码高电平2.25ms 2.25/0.125 = 18
  159. time_done <= 1'b1;
  160. judge_flag <= 1'b1; //检测出是重复码,跳转到repeat_code重复码状态
  161. end
  162. else if(time_cnt >= 33 && time_cnt <= 38) begin //同步码高电平4.5ms 4.5/0.125 = 36
  163. time_done <= 1'b1;
  164. judge_flag <= 1'b0; //检测出是同步码,跳转到rec_data接收数据状态
  165. end
  166. else
  167. error_en <= 1'b1;
  168. end
  169. end
  170. rec_data : begin
  171. if(ir_pos) begin //当有红外信号上升沿
  172. time_cnt_clr <= 1'b1;
  173. if(data_cnt == 6'd32) begin //有32个数据即32个上升沿或下降沿,分别为16位地址码以及16位数据
  174. data_en <= 1'b1; //当计数到32即数据传输完成
  175. data_cnt <= 6'd0;
  176. data_temp <= 16'd0;
  177. if(data_temp[7:0] == ~data_temp[15:8]) //校验控制码和控制反码
  178. data <= data_temp[7:0];
  179. end
  180. end
  181. else if(ir_neg) begin //当有红外信号下降沿
  182. time_cnt_clr <= 1'b1;
  183. data_cnt <= data_cnt + 1'b1; //每当1bit数据到来时也就是一个下降沿到来时,数据位数计数器加1
  184. //解析控制码和控制反码,判断是560us还是1690us计数完成,进而得到这个数据位是0还是1
  185. if(data_cnt >= 6'd16 && data_cnt <= 6'd31) begin
  186. if(time_cnt >= 2 && time_cnt <= 6) begin //0.565/0.125 = 4.52
  187. data_temp <= {1'b0,data_temp[15:1]}; //逻辑“0”
  188. end
  189. else if(time_cnt >= 10 && time_cnt <= 15) //1.69/0.125 = 13.52
  190. data_temp <= {1'b1,data_temp[15:1]}; //逻辑“1”
  191. end
  192. end
  193. end
  194. repeat_code : begin
  195. if(ir_pos) begin
  196. time_cnt_clr <= 1'b1;
  197. repeat_en <= 1'b1;
  198. end
  199. end
  200. default : ;
  201. endcase
  202. end
  203. end
  204. endmodule

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/246608
推荐阅读
相关标签
  

闽ICP备14008679号