前言
紅外線(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.25us
20 always @ (posedge clk)
21 if(!rst_n)
22 begin
23 num <= 0;
24 data <= 0;
25 state_s <= 0;
26 flag_x <= 0;
27 count <= 0;
28 end
29 else
30 begin
31 case (state_s)
32 0 : if(!rx) //判斷起始位,是否接受=收數據
33 begin
34 state_s <= 1;
35 flag_x <= 0;
36 count <= count + 1;
37 end
38 else
39 begin
40 flag_x <= 0;
41 state_s <= 0;
42 count <= count + 1;
43 end
44
45 1 : if(num < (342 + 171 - 1)) //延遲9ms + 4.5ms的起始時間
46 begin
47 num <= num + 1;
48 state_s <= 1;
49 count <= count + 1;
50 end
51 else
52 begin
53 num <= 0;
54 state_s <= 2;
55 count <= count + 1;
56 end
57
58 2 : if(flag && num < 32) //flag來的時候表示接到了位1 ,或者位0,
59 //通過移位寄存器來獲取32位數據
60 begin
61 data <= {data[30:0],temp};
62 state_s <= 2;
63 num <= num + 1;
64 count <= count + 1;
65 end
66 else if(num == 32)
67 begin
68 state_s <= 3;
69 num <= 0;
70 count <= count + 1;
71 end
72 else
73 state_s <= 2;
74
75 3 : if(num < 21 - 1) //延遲結束位的時間
76 begin
77 num <= num + 1;
78 count <= count + 1;
79 end
80 else
81 begin
82 if(count == T - 1) //延遲一幀數據的時間后,發送一個標志位
83 begin
84 num <= 0;
85 state_s <= 0;
86 flag_x <= 1;
87 count <= 0;
88 count <= count + 1;
89 end
90 else
91 count <= count + 1;
92 end
93 default: state_s <= 0;
94 endcase
95 end
96
97 always @ (posedge clk)
98 if(!rst_n)
99 begin
100 cnt <= 0;
101 state <= 0;
102 temp <= 0;
103 flag <= 0;
104 end
105 else
106 if(state_s > 1 && state_s < 3)
107 case (state)
108 0 : if(rx)
109 begin
110 cnt <= cnt + 1;
111 state <= 1;
112 flag <= 0;
113 end
114 else
115 begin
116 state <= 0;
117 flag <= 0;
118 end
119
120 1 : if(!rx)
121 begin
122 cnt <= cnt;
123 state <= 2;
124 end
125 else
126 cnt <= cnt + 1;
127
128 2 : if(400 < cnt * 26 && cnt * 26 < 600) //判斷高電平的時間
129 begin
130 temp <= 0;
131 flag <= 1;
132 state <= 0;
133 cnt <= 0;
134 end
135 else if (1400 < cnt * 26 && cnt * 26 < 1700) //判斷高電平的時間
136 begin
137 temp <= 1;
138 flag <= 1;
139 state <= 0;
140 cnt <= 0;
141 end
142 else
143 begin
144 state <= 0;
145 cnt <= 0;
146 end
147 default: state <= 0;
148 endcase
149
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 begin
156 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 end
166 else
167 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 5 11 reg [15:0] count; 12 reg flag; 13 always @ (posedge clk or negedge rst_n) 14 if(!rst_n) 15 begin 16 count <= 15'b0; 17 flag <= 1; 18 end 19 else 20 if(count == `T1ms /2 - 1) 21 begin 22 count <= 15'b0; 23 flag <= ~flag; 24 end 25 else 26 begin 27 count <= count + 1'b1; 28 end 29 30 always @ (posedge flag) 31 if(!rst_n) 32 seg7 <= 8'b1010_0100; 33 else 34 begin 35 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 endcase 54 end 55 56 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 begin 13 count <= 0; 14 clk_38khz <= 1; 15 end 16 else if(count == (50_000_000 / 38000 / 2 - 1)) 17 begin 18 clk_38khz <= ~clk_38khz; 19 count <= 0; 20 end 21 else 22 count <= count + 1'd1; 23 24??endmodule仿真測試
測試模塊infrared_tb代碼:
0 `timescale 1ns/1ps 1 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 begin 12 clk = 1; 13 rst_n = 0; 14 key = 1; 15 16 #100.1 rst_n = 1; 17 18 #200 key = 0; 19 20 end 21 22 always # 10 clk = ~clk; 23 24 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 ); 33 34 endmodule
仿真圖:
仿真中我們可以把數碼管模塊的計數器的值改小一點,便于仿真。

如圖中所示的我們發的是32’h00ffa25d,那么數據為是8’b1010_0010,那么先發送時就時就按下面的序列開始0100_0101接收到的為45,所以工程正確。
審核編輯:劉清
-
FPGA
+關注
關注
1660文章
22408瀏覽量
636248 -
控制器
+關注
關注
114文章
17787瀏覽量
193105 -
數碼管
+關注
關注
32文章
1894瀏覽量
94133 -
電磁波
+關注
關注
21文章
1503瀏覽量
55707 -
紅外遙控系統
+關注
關注
0文章
9瀏覽量
7746
原文標題:源碼系列:基于FPGA的紅外線遙控系統設計(附源工程)
文章出處:【微信號:HXSLH1010101010,微信公眾號:FPGA技術江湖】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
源碼系列:基于FPGA的紅外線遙控系統設計(附源工程)
紅外線是什么,紅外線簡介
基于單片機的紅外線遙控系統
工業控制計算機紅外線遙控鍵盤的設計
《 紅外線遙控系統 》設計原理、架構圖及代碼
如何實現一種基于FPGA的紅外線遙控系統設計呢?
評論