源码系列:基于FPGA的红外线遥控系统设计(附源工程)

原创 FPGA技术江湖 2025-04-20 08:36

大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。


今天给大侠带来基于FPGA的红外线遥控系统设计,附源码,获取源码,请在“FPGA技术江湖”公众号内回复“红外线遥控系统设计源码”,可获取源码文件。话不多说,上货。


前言


红外线(Infrared)是波长介乎微波与可见光之间的电磁波,波长在760纳米(nm)至1毫米(mm)之间,比红光长的非可见光 红外线遥控是目前使用最广泛的一种通信和遥控手段。由于红外线遥控装置具有体积小、功耗低、功能强、成本低等特点,因而,继彩电、录像机之后,在录音机、音响设备、空凋机以及玩具等其它小型电器装置上也纷纷采用红外线遥控。现在工业设备中,也已经广泛在使用。


设计原理


红外遥控系统主要由红外的发送装置和接收装置组成,发送装置可由按键,编码模块,发射电路等组成,接收装置由红外接收电路,遥控,解码模块等组成,此次设计我们用到的硬件平台式是Altera的DE1_SOC,晶振为50MHZ。

在红外的编码中,我们对1 和 0 的编码是通过38KHZ的脉冲来定义的,在红外的的编码中每个脉冲的为256.25us长的38KHZ载波频率(26.3us),对0,1的脉冲的定义的时间如下图:


红外的数据格式为包括引导码,用户码,数据码和数据纠错码,停止位编码总为32位。数据反码是数据码反相后的编码,可用于对数据的纠错。此外第二段的用户码可以在遥控应用电路中设置为第一段用户码的反码。

数据格式如下图:



一帧数据在发送时先发送9MS的高电平,然后发送4.5MS的低电平的起始位,然后发送用户码,数据码,数据反码。然后再发送一位的停止位。不发送数据时数据线一直为低。

发送的时序图如下:


接受的时,接收到的时序和发送的时序恰恰相反,如发送时先发送9ms的高,4.5ms的低,接收为接收9ms的低电平,4.5ms低电平。

接收的控制器我们用的时红外遥控装置,按键发送的数据如下图所示:

设计框架


设计的总框架如下图


在设计中分频模块提供所需要的38KHZ的时钟,当按键按下时发送我们的发送模块发送一个给定的数值,我用户码为8'b0,第二段用户码为8'hff,然后发送给定的数据码,和数据反码。上电后我们的设计会发一次我们给定的数据码,然后在接受模块会接受到其发送的数据并在数码管上显示出来,之后我们可以用我们我的遥控键盘来发送数据,接收模块接收显示出来,通过验证我们接收和发送的正确。


设计代码


顶层模块infrared代码:

module infrared(clk, rst_n, key, tx, seg1, seg2, rx);
input clk, rst_n; input key; output tx; input rx; wire [7:0] show_data; output [7:0] seg1,seg2; wire [31:0] data_n; wire clk_38khz; clk_frep clk_frep_dut( .clk(clk), .rst_n(rst_n), .clk_38khz(clk_38khz) ); encode encode_dut( .clk(clk_38khz), .rst_n(rst_n), .d_out(data_n), .key(key)  ); tttxxx tx_dut( .clk(clk_38khz), .rst_n(rst_n), .data_n(data_n), .tx(tx), .key(key) ); seg seg01( .clk(clk), .rst_n(rst_n), .seg7(seg1), .data_in(show_data[3:0]) ); seg seg02( .clk(clk), .rst_n(rst_n), .seg7(seg2), .data_in(show_data[7:4]) ); rx_led led_dut( .clk(clk_38khz), .rst_n(rst_n), .rx(rx), .show_data(show_data) ); endmodule 


发送模块tttxxx代码:

module tttxxx(clk, rst_n, data_n, tx, key);
input clk, rst_n; input key; input [31:0] data_n; output reg tx; reg [31:0] temp; reg [8:0] count; reg [2:0] state; reg data; reg [13:0] num; reg [31:0] d_data; parameter T9ms = 342; //9000/26.3; parameter T4500us = 171; //4500/26.3; parameter T0 = 21; //(1125-562.25)/26.3; parameter T1 = 63; //(2250-562.25)/26.3; parameter T562us = 21; //562.25/26.3; parameter T = 2666; reg T9_flag; reg T45_flag; reg T0_flag; reg T1_flag; reg T9_down; reg T45_down; reg T0_down; reg T1_down; reg [9:0] cnt9; reg [9:0] cnt45; reg [9:0] cnt0; reg [9:0] cnt1; reg [9:0] cnt562; reg t0_clk, t1_clk; always @ (posedge clk) if(!rst_n) begin count <= 0; state <= 0; tx <= 0; data <= 0; num <= 0; temp <= 0; d_data <= {8'b0,8'hff, 8'b10100010, 8'b01011101}; end else case (state) 0 : if(count < 10) begin tx <= 0; count <= count + 1; end else if(!key) begin count <= 0; state <= 1; T9_flag <= 1; tx <= 1; end 1 : if(T9_down) begin state <= 2; T45_flag <= 1; tx <= 0; T9_flag <= 0; end else begin tx <= 1; state <= 1; end 2 : if(T45_down) begin state <= 3; tx <= 0; T45_flag <= 0; end else tx <= 0; 3 : if(count < 32) begin count <= count + 1; if(!d_data[31 - count]) begin T0_flag <= 1; state <= 4; T1_flag <= 0; end else begin T1_flag <= 1; state <= 5; T0_flag <= 0; end end else begin count <= 0; state <= 6; T0_flag <= 0; T1_flag <= 0; end 4 : if(T0_down) begin state <= 3; tx <= 0; end else begin tx <= t0_clk; end 5 : if(T1_down) begin state <= 3; tx <= 0; end else tx <= t1_clk; 6 : if(count < T562us - 1) begin count <= count + 1; tx <= 1; end else begin tx <= 0; end default: state <= 0; endcase
always @ (posedge clk) if(!rst_n) begin T9_down <= 0; cnt9 <= 0; end else if (T9_flag) begin if(cnt9 < T9ms - 1) begin T9_down <= 0; cnt9 <= cnt9 + 1; end else begin T9_down <= 1; cnt9 <= 0; end end always @ (posedge clk) if(!rst_n) begin T45_down <= 0; cnt45 <= 0; end else if (T45_flag) begin if(cnt45 < T4500us - 1) begin T45_down <= 0; cnt45 <= cnt45 + 1; end else begin T45_down <= 1; cnt45 <= 0; end end reg [9:0] cnt00; always @ (posedge clk) if(!rst_n) begin t0_clk <= 0; T0_down <= 0; cnt0 <= 0; cnt00 <= 0; end else if (T0_flag) begin if(cnt0 < T562us - 1) begin t0_clk <= 1; cnt0 <= cnt0 + 1; T0_down <= 0; end else begin if(cnt00 < T0 - 1) begin cnt00 <= cnt00 + 1; t0_clk <= 0; T0_down <= 0; end else begin T0_down <= 1; cnt0 <= 0; cnt00 <= 0; end end end reg [9:0] cnt11; always @ (posedge clk) if(!rst_n) begin t1_clk <= 0; T1_down <= 0; cnt1 <= 0; cnt11 <= 0; end else if (T1_flag) begin if(cnt1 < T562us - 1) begin t1_clk <= 1; cnt1 <= cnt1 + 1; T1_down <= 0; end else begin if(cnt11 < T1 - 1) begin cnt11 <= cnt11 + 1; t1_clk <= 0; T1_down <= 0; end else begin T1_down <= 1; cnt1 <= 0; cnt11 <= 0; end end end endmodule 

接收模块rx_led代码:

0    module rx_led(clk, rst_n, rx, show_data);1    2    input clk, rst_n;3    input rx;4    output reg [7:0] show_data;5    6    reg [1:0] state;7    reg [7:0] cnt;8    reg temp;9    reg [9:0] num;10   reg flag;11   reg [31:0] data; 12   reg [1:0] state_s;13   reg flag_x;14   reg [12:0] count;15   16   parameter T = 2566;   // 一帧数据的时间17   18   //这个模块是中因为接受的32位编码数据中,不管是位0还是位1,接受的低电平都是相同的,19   //我们可以通过来判断高电平的时间来确定为位1 还是位0,位’1‘ 1.68MS,位0 562.25us20   always @ (posedge clk)21     if(!rst_n)22       begin23         num <= 0;24         data <= 0;25         state_s <= 0;26         flag_x <= 0;27         count <= 0;28       end29     else30       begin31         case (state_s)32           0  :   if(!rx)            //判断起始位,是否接受=收数据33                 begin34                   state_s <= 1;35                   flag_x <= 0;36                   count <= count + 1;37                 end38               else39                 begin40                   flag_x <= 0;41                   state_s <= 0;42                   count <= count + 1;43                 end44           45           1  :  if(num < (342 + 171 - 1))  //延迟9ms + 4.5ms的起始时间46                 begin47                   num <= num + 1;48                   state_s <= 1;49                   count <= count + 1;50                 end51               else52                 begin53                   num <= 0;54                   state_s <= 2;55                   count <= count + 1;56                 end57           58           2  :   if(flag && num < 32)    //flag来的时候表示接到了位1 ,或者位0,59                             //通过移位寄存器来获取32位数据60                 begin61                   data <= {data[30:0],temp};62                   state_s <= 2;63                   num <= num + 1;64                   count <= count + 1;65                 end66               else if(num == 32)67                 begin68                   state_s <= 3;69                   num <= 0;70                   count <= count + 1;71                 end72               else73                 state_s <= 2;74           75           3  :  if(num < 21 - 1)    //延迟结束位的时间76                 begin77                   num <= num + 1;78                   count <= count + 1;79                 end80               else81                 begin82                   if(count == T - 1)    //延迟一帧数据的时间后,发送一个标志位83                     begin84                       num <= 0;85                       state_s <= 0;86                       flag_x <= 1;87                       count <= 0;88                       count <= count + 1;89                     end90                   else91                     count <= count + 1;92                 end93           default: state_s <= 0;94         endcase95       end96       97   always @ (posedge clk)98     if(!rst_n)99       begin100        cnt <= 0;101        state <= 0;102        temp <= 0;103        flag <= 0;104      end105    else106      if(state_s > 1 && state_s < 3)107      case (state)108        0  :   if(rx)    109              begin110                cnt <= cnt + 1;111                state <= 1;112                flag <= 0;113              end114            else115              begin116                state <= 0;117                flag <= 0;118              end119              120        1  :  if(!rx) 121              begin122                cnt <= cnt;123                state <= 2;124              end125            else126              cnt <= cnt + 1;127        128        2  :  if(400 < cnt * 26 &&  cnt * 26 < 600)    //判断高电平的时间129              begin130                temp <= 0;131                flag <= 1;132                state <= 0;133                cnt <= 0;134              end135            else if (1400 < cnt * 26 && cnt * 26 < 1700)  //判断高电平的时间136              begin137                temp <= 1;138                flag <= 1;139                state <= 0;140                cnt <= 0;141              end142            else143              begin144                state <= 0;145                cnt <= 0;146              end147        default: state <= 0;148      endcase149  150  always @ (*)      //接收完一帧数据后,当标志位来的时候通过对数据的纠错来捕获数据151              //我们接收的数据用的是左移,而发送的时候先发的是低位152    if(!rst_n)153      show_data <= 0;154    else if((data[7:0] == ~data[15:8]) && (data[31:24] == ~data[23:16]) && flag_x)155      begin156        show_data[0] <= data[15];157        show_data[1] <= data[14];158        show_data[2] <= data[13];159        show_data[3] <= data[12];160        show_data[4] <= data[11];161        show_data[5] <= data[10];162        show_data[6] <= data[9];163        show_data[7] <= data[8];164      165      end166    else167      show_data <= show_data;168      169 endmodule


数码管seg模块:

0   module seg(clk, rst_n, seg7, data_in);1 2   input clk;3   input rst_n;4   input [3:0] data_in;5   6   output reg [7:0] seg7;7   8   9   `define T1ms  50_000 //分频出1k的时钟10  //`define T1ms  511  reg [15:0] count;12  reg flag;13  always @ (posedge clk or negedge rst_n) 14    if(!rst_n)15      begin16        count <= 15'b0;17        flag <= 1;18      end19    else20      if(count == `T1ms /2 - 1)21        begin22          count <= 15'b0;23          flag <= ~flag;24        end25      else26        begin27          count <= count + 1'b1;28        end29  30  always @ (posedge flag)31    if(!rst_n)32      seg7 <= 8'b1010_0100;33    else34      begin35        case (data_in)36          0:seg7 <= 8'b1100_0000;37          1:seg7 <= 8'b1111_1001;38          2:seg7 <= 8'b1010_0100;39          3:seg7 <= 8'b1011_0000;40          4:seg7 <= 8'b1001_1001;41          5:seg7 <= 8'b1001_0010;42          6:seg7 <= 8'b1000_0010;43          7:seg7 <= 8'b1111_1000;44          8:seg7 <= 8'b1000_0000;45          9:seg7 <= 8'b1001_0000;46          10:seg7 <= 8'b1000_1000;47          11:seg7 <= 8'b1000_0011;48          12:seg7 <= 8'b1100_0110;49          13:seg7 <= 8'b1010_0001;50          14:seg7 <= 8'b1000_0110;51          15:seg7 <= 8'b1000_1110;52          default:;53        endcase54      end5556 endmodule


分频模块clk_frep代码:
0   module clk_frep(clk, rst_n, clk_38khz);1 2   input clk, rst_n;3   output reg  clk_38khz;4   5   reg [9:0] count;6   7   //分频出红外模块所用的38Khz的时钟8   //也可以用占空比为1:3的38khz的时钟9   10  always @ (posedge clk or negedge rst_n)11    if(!rst_n)12      begin13        count <= 0;14        clk_38khz <= 1;15      end16    else if(count == (50_000_000 / 38000 / 2 - 1))17      begin18        clk_38khz <= ~clk_38khz;19        count <= 0;20      end21    else22      count <= count + 1'd1;2324  endmodule

仿真测试



测试模块infrared_tb代码
0   `timescale 1ns/1ps1 2 module infrared_tb();3 4   reg clk, rst_n;5   reg key;6   wire tx;7   wire [7:0] show_data;8   9   //因为我们代码中只发送一次数据,所以可以把key一直拉低10  11  initial begin12    clk = 1;13    rst_n = 0;14    key = 1;15    16    #100.1 rst_n = 1;17    18    #200  key = 0;    1920  end21  22  always # 10 clk = ~clk;2324  infrared dut(25    .clk(clk), 26    .rst_n(rst_n), 27    .key(key), 28    .tx(tx),29    .rx(rx),30    .seg1(seg1),31    .seg2(seg2)32  );3334 endmodule

仿真图: 

仿真中我们可以把数码管模块的计数器的值改小一点,便于仿真。

如图中所示的我们发的是32’h00ffa25d,那么数据为是8’b1010_0010,那么先发送时就时就按下面的序列开始0100_0101接收到的为45,所以工程正确。

- THE END -

🍁


往期精选 

 
 

【免费】FPGA工程师人才招聘平台

FPGA人才招聘,企业HR,看过来!

系统设计精选 | 基于FPGA的实时图像边缘检测系统设计(附代码)

基于原语的千兆以太网RGMII接口设计

时序分析理论和timequest使用_中文电子版

求职面试 | FPGA或IC面试题最新汇总篇

FPGA技术江湖广发江湖帖

无广告纯净模式,给技术交流一片净土,从初学小白到行业精英业界大佬等,从军工领域到民用企业等,从通信、图像处理到人工智能等各个方向应有尽有,QQ微信双选,FPGA技术江湖打造最纯净最专业的技术交流学习平台。


FPGA技术江湖微信交流群

加群主微信,备注姓名+学校/公司+专业/岗位进群


FPGA技术江湖QQ交流群

备注姓名+学校/公司+专业/岗位进群

FPGA技术江湖 任何技术的学习就好比一个江湖,对于每一位侠客都需要不断的历练,从初入江湖的小白到归隐山林的隐世高人,需要不断的自我感悟自己修炼,让我们一起仗剑闯FPGA乃至更大的江湖。
评论 (0)
  • 浪潮之上:智能时代的觉醒    近日参加了一场课题的答辩,这是医疗人工智能揭榜挂帅的国家项目的地区考场,参与者众多,围绕着医疗健康的主题,八仙过海各显神通,百花齐放。   中国大地正在发生着激动人心的场景:深圳前海深港人工智能算力中心高速运转的液冷服务器,武汉马路上自动驾驶出租车穿行的智慧道路,机器人参与北京的马拉松竞赛。从中央到地方,人工智能相关政策和消息如雨后春笋般不断出台,数字中国的建设图景正在智能浪潮中徐徐展开,战略布局如同围棋
    广州铁金刚 2025-04-30 15:24 187浏览
  • 在CAN总线分析软件领域,当CANoe不再是唯一选择时,虹科PCAN-Explorer 6软件成为了一个有竞争力的解决方案。在现代工业控制和汽车领域,CAN总线分析软件的重要性不言而喻。随着技术的进步和市场需求的多样化,单一的解决方案已无法满足所有用户的需求。正是在这样的背景下,虹科PCAN-Explorer 6软件以其独特的模块化设计和灵活的功能扩展,为CAN总线分析领域带来了新的选择和可能性。本文将深入探讨虹科PCAN-Explorer 6软件如何以其创新的模块化插件策略,提供定制化的功能选
    虹科汽车智能互联 2025-04-28 16:00 184浏览
  • 随着电子元器件的快速发展,导致各种常见的贴片电阻元器件也越来越小,给我们分辨也就变得越来越难,下面就由smt贴片加工厂_安徽英特丽就来告诉大家如何分辨的SMT贴片元器件。先来看看贴片电感和贴片电容的区分:(1)看颜色(黑色)——一般黑色都是贴片电感。贴片电容只有勇于精密设备中的贴片钽电容才是黑色的,其他普通贴片电容基本都不是黑色的。(2)看型号标码——贴片电感以L开头,贴片电容以C开头。从外形是圆形初步判断应为电感,测量两端电阻为零点几欧,则为电感。(3)检测——贴片电感一般阻值小,更没有“充放
    贴片加工小安 2025-04-29 14:59 223浏览
  • 文/郭楚妤编辑/cc孙聪颖‍越来越多的企业开始蚕食动力电池市场,行业“去宁王化”态势逐渐明显。随着这种趋势的加强,打开新的市场对于宁德时代而言至关重要。“我们不希望被定义为电池的制造者,而是希望把自己称作新能源产业的开拓者。”4月21日,在宁德时代举行的“超级科技日”发布会上,宁德时代掌门人曾毓群如是说。随着宁德时代核心新品骁遥双核电池的发布,其搭载的“电电增程”技术也走进业界视野。除此之外,经过近3年试水,宁德时代在换电业务上重资加码。曾毓群认为换电是一个重资产、高投入、长周期的产业,涉及的利
    华尔街科技眼 2025-04-28 21:55 163浏览
  • 你是不是也有在公共场合被偷看手机或笔电的经验呢?科技时代下,不少现代人的各式机密数据都在手机、平板或是笔电等可携式的3C产品上处理,若是经常性地需要在公共场合使用,不管是工作上的机密文件,或是重要的个人信息等,民众都有防窃防盗意识,为了避免他人窥探内容,都会选择使用「防窥保护贴片」,以防止数据外泄。现今市面上「防窥保护贴」、「防窥片」、「屏幕防窥膜」等产品就是这种目的下产物 (以下简称防窥片)!防窥片功能与常见问题解析首先,防窥片最主要的功能就是用来防止他人窥视屏幕上的隐私信息,它是利用百叶窗的
    百佳泰测试实验室 2025-04-30 13:28 324浏览
  • 文/Leon编辑/cc孙聪颖‍2023年,厨电行业在相对平稳的市场环境中迎来温和复苏,看似为行业增长积蓄势能。带着对市场向好的预期,2024 年初,老板电器副董事长兼总经理任富佳为企业定下双位数增长目标。然而现实与预期相悖,过去一年,这家老牌厨电企业不仅未能达成业绩目标,曾提出的“三年再造一个老板电器”愿景,也因市场下行压力面临落空风险。作为“企二代”管理者,任富佳在掌舵企业穿越市场周期的过程中,正面临着前所未有的挑战。4月29日,老板电器(002508.SZ)发布了2024年年度报告及2025
    华尔街科技眼 2025-04-30 12:40 206浏览
  • 贞光科技代理品牌紫光国芯的车规级LPDDR4内存正成为智能驾驶舱的核心选择。在汽车电子国产化浪潮中,其产品以宽温域稳定工作能力、优异电磁兼容性和超长使用寿命赢得市场认可。紫光国芯不仅确保供应链安全可控,还提供专业本地技术支持。面向未来,紫光国芯正研发LPDDR5车规级产品,将以更高带宽、更低功耗支持汽车智能化发展。随着智能网联汽车的迅猛发展,智能驾驶舱作为人机交互的核心载体,对处理器和存储器的性能与可靠性提出了更高要求。在汽车电子国产化浪潮中,贞光科技代理品牌紫光国芯的车规级LPDDR4内存凭借
    贞光科技 2025-04-28 16:52 256浏览
  • 一、gao效冷却与控温机制‌1、‌冷媒流动设计‌采用低压液氮(或液氦)通过毛细管路导入蒸发器,蒸汽喷射至样品腔实现快速冷却,冷却效率高(室温至80K约20分钟,至4.2K约30分钟)。通过控温仪动态调节蒸发器加热功率,结合温度传感器(如PT100铂电阻或Cernox磁场不敏感传感器),实现±0.01K的高精度温度稳定性。2、‌宽温区覆盖与扩展性‌标准温区为80K-325K,通过降压选件可将下限延伸至65K(液氮模式)或4K(液氦模式)。可选配475K高温模块,满足材料在ji端温度下的性能测试需求
    锦正茂科技 2025-04-30 13:08 251浏览
  • 网约车,真的“饱和”了?近日,网约车市场的 “饱和” 话题再度引发热议。多地陆续发布网约车风险预警,提醒从业者谨慎入局,这背后究竟隐藏着怎样的市场现状呢?从数据来看,网约车市场的“过剩”现象已愈发明显。以东莞为例,截至2024年12月底,全市网约车数量超过5.77万辆,考取网约车驾驶员证的人数更是超过13.48万人。随着司机数量的不断攀升,订单量却未能同步增长,导致单车日均接单量和营收双双下降。2024年下半年,东莞网约出租车单车日均订单量约10.5单,而单车日均营收也不容乐
    用户1742991715177 2025-04-29 18:28 221浏览
  • 在智能硬件设备趋向微型化的背景下,语音芯片方案厂商针对小体积设备开发了多款超小型语音芯片方案,其中WTV系列和WT2003H系列凭借其QFN封装设计、高性能与高集成度,成为微型设备语音方案的理想选择。以下从封装特性、功能优势及典型应用场景三个方面进行详细介绍。一、超小体积封装:QFN技术的核心优势WTV系列与WT2003H系列均提供QFN封装(如QFN32,尺寸为4×4mm),这种封装形式具有以下特点:体积紧凑:QFN封装通过减少引脚间距和优化内部结构,显著缩小芯片体积,适用于智能门铃、穿戴设备
    广州唯创电子 2025-04-30 09:02 236浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦