大俠好,歡迎來(lái)到FPGA技術(shù)江湖,江湖偌大,相見(jiàn)即是緣分。大俠可以關(guān)注FPGA技術(shù)江湖,在“闖蕩江湖”、"行俠仗義"欄里獲取其他感興趣的資源,或者一起煮酒言歡。
今天給大俠帶來(lái)基于FPGA的紅外線(xiàn)遙控系統(tǒng)設(shè)計(jì),附源碼,獲取源碼,請(qǐng)?jiān)凇癋PGA技術(shù)江湖”公眾號(hào)內(nèi)回復(fù)“紅外線(xiàn)遙控系統(tǒng)設(shè)計(jì)源碼”,可獲取源碼文件。話(huà)不多說(shuō),上貨。
前言
紅外線(xiàn)(Infrared)是波長(zhǎng)介乎微波與可見(jiàn)光之間的電磁波,波長(zhǎng)在760納米(nm)至1毫米(mm)之間,比紅光長(zhǎng)的非可見(jiàn)光。?紅外線(xiàn)遙控是目前使用最廣泛的一種通信和遙控手段。由于紅外線(xiàn)遙控裝置具有體積小、功耗低、功能強(qiáng)、成本低等特點(diǎn),因而,繼彩電、錄像機(jī)之后,在錄音機(jī)、音響設(shè)備、空凋機(jī)以及玩具等其它小型電器裝置上也紛紛采用紅外線(xiàn)遙控?,F(xiàn)在工業(yè)設(shè)備中,也已經(jīng)廣泛在使用。
設(shè)計(jì)原理
紅外遙控系統(tǒng)主要由紅外的發(fā)送裝置和接收裝置組成,發(fā)送裝置可由按鍵,編碼模塊,發(fā)射電路等組成,接收裝置由紅外接收電路,遙控,解碼模塊等組成,此次設(shè)計(jì)我們用到的硬件平臺(tái)式是Altera的DE1_SOC,晶振為50MHZ。
在紅外的編碼中,我們對(duì)1 和 0 的編碼是通過(guò)38KHZ的脈沖來(lái)定義的,在紅外的的編碼中每個(gè)脈沖的為256.25us長(zhǎng)的38KHZ載波頻率(26.3us),對(duì)0,1的脈沖的定義的時(shí)間如下圖:
紅外的數(shù)據(jù)格式為包括引導(dǎo)碼,用戶(hù)碼,數(shù)據(jù)碼和數(shù)據(jù)糾錯(cuò)碼,停止位編碼總為32位。數(shù)據(jù)反碼是數(shù)據(jù)碼反相后的編碼,可用于對(duì)數(shù)據(jù)的糾錯(cuò)。此外第二段的用戶(hù)碼可以在遙控應(yīng)用電路中設(shè)置為第一段用戶(hù)碼的反碼。
數(shù)據(jù)格式如下圖:
一幀數(shù)據(jù)在發(fā)送時(shí)先發(fā)送9MS的高電平,然后發(fā)送4.5MS的低電平的起始位,然后發(fā)送用戶(hù)碼,數(shù)據(jù)碼,數(shù)據(jù)反碼。然后再發(fā)送一位的停止位。不發(fā)送數(shù)據(jù)時(shí)數(shù)據(jù)線(xiàn)一直為低。
發(fā)送的時(shí)序圖如下:
接受的時(shí),接收到的時(shí)序和發(fā)送的時(shí)序恰恰相反,如發(fā)送時(shí)先發(fā)送9ms的高,4.5ms的低,接收為接收9ms的低電平,4.5ms低電平。
接收的控制器我們用的時(shí)紅外遙控裝置,按鍵發(fā)送的數(shù)據(jù)如下圖所示:
設(shè)計(jì)框架
設(shè)計(jì)的總框架如下圖:
在設(shè)計(jì)中分頻模塊提供所需要的38KHZ的時(shí)鐘,當(dāng)按鍵按下時(shí)發(fā)送我們的發(fā)送模塊發(fā)送一個(gè)給定的數(shù)值,我用戶(hù)碼為8'b0,第二段用戶(hù)碼為8'hff,然后發(fā)送給定的數(shù)據(jù)碼,和數(shù)據(jù)反碼。上電后我們的設(shè)計(jì)會(huì)發(fā)一次我們給定的數(shù)據(jù)碼,然后在接受模塊會(huì)接受到其發(fā)送的數(shù)據(jù)并在數(shù)碼管上顯示出來(lái),之后我們可以用我們我的遙控鍵盤(pán)來(lái)發(fā)送數(shù)據(jù),接收模塊接收顯示出來(lái),通過(guò)驗(yàn)證我們接收和發(fā)送的正確。
設(shè)計(jì)代碼
頂層模塊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?
發(fā)送模塊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; // 一幀數(shù)據(jù)的時(shí)間
17
18 //這個(gè)模塊是中因?yàn)榻邮艿?2位編碼數(shù)據(jù)中,不管是位0還是位1,接受的低電平都是相同的,
19 //我們可以通過(guò)來(lái)判斷高電平的時(shí)間來(lái)確定為位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) //判斷起始位,是否接受=收數(shù)據(jù)
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的起始時(shí)間
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來(lái)的時(shí)候表示接到了位1 ,或者位0,
59 //通過(guò)移位寄存器來(lái)獲取32位數(shù)據(jù)
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) //延遲結(jié)束位的時(shí)間
76 begin
77 num <= num + 1;
78 count <= count + 1;
79 end
80 else
81 begin
82 if(count == T - 1) //延遲一幀數(shù)據(jù)的時(shí)間后,發(fā)送一個(gè)標(biāo)志位
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) //判斷高電平的時(shí)間
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) //判斷高電平的時(shí)間
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 @ (*) //接收完一幀數(shù)據(jù)后,當(dāng)標(biāo)志位來(lái)的時(shí)候通過(guò)對(duì)數(shù)據(jù)的糾錯(cuò)來(lái)捕獲數(shù)據(jù)
151 //我們接收的數(shù)據(jù)用的是左移,而發(fā)送的時(shí)候先發(fā)的是低位
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
數(shù)碼管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的時(shí)鐘
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的時(shí)鐘
8 //也可以用占空比為1:3的38khz的時(shí)鐘
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
仿真測(cè)試
測(cè)試模塊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 //因?yàn)槲覀兇a中只發(fā)送一次數(shù)據(jù),所以可以把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
仿真圖:?
仿真中我們可以把數(shù)碼管模塊的計(jì)數(shù)器的值改小一點(diǎn),便于仿真。
如圖中所示的我們發(fā)的是32’h00ffa25d,那么數(shù)據(jù)為是8’b1010_0010,那么先發(fā)送時(shí)就時(shí)就按下面的序列開(kāi)始0100_0101接收到的為45,所以工程正確。