理論基礎
可見光中紅光的波長范圍為620nm ~ 720nm,波長比紅光波長還長的的光叫紅外線。紅外線按波長范圍可分為近紅外、中紅外、遠紅外、極紅外。紅外線遙控是利用近紅外光傳送遙控指令的,波長為0.76um~1 .5um。
紅外遙控發射部分由遙控按鍵、編碼以及調制電路、紅外發光二極管等組成。紅外遙控接收部分由光敏二極管、解調電路等組成。最后將解調的信號輸入FPGA內進行解碼輸出。接收信號是板載的HS0038B,該接收頭收到信號后輸出的波形剛好與發送的波形相反。發射信號是遙控器,鍵碼如下:
編碼協議NEC
紅外遙控的編碼協議有NEC、Philips RC-5、Philips RC-6、Sony SIRC等,而使用最多的是 NEC協議 。NEC協議采用的是PPM(Pulse Position Modulation,脈沖位置調制)進行編碼。當我們按下遙控器的一個按鍵時,會發送一幀的數據。這一幀數據由 引導碼、地址碼、地址反碼、數據碼、數據反碼以及一位結束位 (可忽略)組成。
9ms的高電平+4.5ms的低電平組成了引導碼。后面是 地址碼和地址反碼 ,0和1是由時間間隔區分的(邏輯“1”由560us的高脈沖加上1.69ms的低電平組成,而邏輯“0”由560us的高脈沖加上560us的低電平組成)。如圖分別是0000_0000和1111_1111,再后面是 數據碼和數據反碼 ,如圖是1010_1101(注意低位和高位順序)和0101_0010。由于是正碼和反碼,因此總共0和1的數量一定都是8個,那么它們的總時長是不變的。最后是562.5um脈沖突發以表示消息傳輸的結束。
長按時,當發送完數據后,每隔110ms會發送一個重復碼,重復碼由9ms的高脈沖和2.25ms的低電平以及560us的高脈沖(結束標志)組成。們使用的一體化接收頭接收到信號后輸出到FPGA的波形剛好與發送的波形 相反 。即發送的高脈沖,接收后輸出就為低電平;發送的低電平,接收后輸出就為高電平。
設計規劃
使用紅外遙控器發送紅外信號,FPGA開發板上的接收頭接收到紅外信號后傳入FPGA芯片內,FPGA芯片接收到信號后進行解碼,將解碼后的按鍵碼顯示在數碼管上。若檢測到發送了重復碼,則讓led閃爍顯示,一個重復碼閃爍一次。
一共包括四個模塊,紅外模塊,led模塊,數碼管動態顯示模塊和頂層模塊。其中數碼管動態顯示模塊可以直接調用以前的,而led模塊比較簡單,因此重心放在紅外模塊上。
紅外模塊
輸入是時鐘,復位和紅外輸入信號,輸出是數據和重復使能信號。其中data是27位,我們的協議是8位,這里用27位是因為數碼管動態顯示模塊是27位的(顯示最大值9999_9999),所以在這里也定義成20位的位寬與之相匹配,防止出現未知的錯誤。我們收到數據后首先要判斷是否按照NEC協議發送的,只有是才能輸出相應的數據和重復使能信號。我們知道接收的數據與紅外發送的數據是相反的,發送的引導碼是9ms的高電平+4.5ms的低電平,那么只要判斷接收的引導碼是不是9ms的低電平和4.5ms的高電平,接下來的地址碼,數據碼和重復碼也是同理。
用狀態圖的跳轉來展示整個過程:
IDEL狀態:初始狀態,等待紅外信號的到來。當檢測到下降沿來臨時,表示9ms的低電平已經開始發送,這時我們從IDLE跳轉到S_T9狀態。
S_T9:檢測9ms低電平狀態。檢測到上升沿時,這中間的低電平如果保持了9ms,跳轉到下一個狀態,如果不是說明信息有誤,回到IDEL狀態重新開始。
S_JUDGE:由于9ms低電平后可能是4.5ms高電平(引導碼)也可能是2.25ms高電平(重復碼),如果是前者,說明后面是地址碼、地址反碼、數據碼和數據反碼,跳轉到S_IFR_DATA;如果是后者,說明這一段是重復碼,跳轉到S_REPEAT;若都不是,說明發送錯誤,回到IDEL。
S_IFR_DATA:地址碼、地址反碼和數據碼、數據反碼的接收與發送的電平相反,檢測到560us的低電平后,如果接的是1.69ms高電平說明邏輯1,560us高電平說明邏輯0。當接受完32位數據后回到IDEL,如果都不滿足說明發送錯誤,回到IDEL。
S_REPEAT:重復碼狀態。當上升沿到來的時直接回到IDEL。
通過判斷高低電平的持續時間去判斷狀態,一共涉及到9ms(449_999)、4.5ms(224_999)、2.25ms(112_499)、1.69ms(84_499)、0.56ms(27_999)的時間間隔,因此需要5個計數器去產生fag信號。flag信號在以前章節都是持續一個時鐘周期的高電平,這里由于晶振可能不會剛好控制在9ms整,因此需要讓它在較大的時間范圍保持高電平。
時間信號產生波形圖
接下來要對紅外信號進行 采沿 ,采沿的代碼在工程上非常常見!!!對需要采沿的信號打拍后經過取反、相與操作即可獲得上升沿或下降沿標志信號。用always能檢測到信號狀態的改變,但是占用資源和時間。
上升沿下降沿信號產生波形圖
ifr_in_rise=infrared_in_d1&&(~infrared_in_d2)
ifr_in_fall=infrared_in_d2&&(~infrared_in_d1)
引導碼狀態跳轉波形圖
代碼編寫
module infrared_rcv
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire infrared_in ,
output reg repeat_en , //重復碼使能信號
output reg [19:0] data //接收的控制碼
);
//parameter define
parameter CNT_0_56MS_L = 20000 , //0.56ms計數為0-27999
CNT_0_56MS_H = 35000 ,
CNT_1_69MS_L = 80000 , //1.69ms計數為0-84499
CNT_1_69MS_H = 90000 ,
CNT_2_25MS_L = 100000, //2.25ms計數為0-112499
CNT_2_25MS_H = 125000,
CNT_4_5MS_L = 175000, //4.5ms計數為0-224999
CNT_4_5MS_H = 275000,
CNT_9MS_L = 400000, //9ms計數為0-449999
CNT_9MS_H = 490000;
//state
parameter IDLE = 5'b0_0001, //空閑狀態
S_T9 = 5'b0_0010, //監測同步碼低電平
S_JUDGE = 5'b0_0100, //判斷重復碼和同步碼高電平
S_IFR_DATA = 5'b0_1000, //接收數據
S_REPEAT = 5'b1_0000; //重復碼
//wire define
wire ifr_in_rise ; //檢測紅外信號的上升沿
wire ifr_in_fall ; //檢測紅外信號的下降沿
//reg define
reg infrared_in_d1 ; //對infrared_in信號打一拍
reg infrared_in_d2 ; //對infrared_in信號打兩拍
reg [18:0] cnt ; //計數器
reg flag_0_56ms ; //0.56ms計數完成標志信號
reg flag_1_69ms ; //1.69ms計數完成標志信號
reg flag_2_25ms ; //2.25ms計數完成標志信號
reg flag_4_5ms ; //4.5ms計數完成標志信號
reg flag_9ms ; //0.56ms計數完成標志信號
reg [4:0] state ; //狀態機狀態
reg [5:0] data_cnt ; //數據計數器
reg [31:0] data_tmp ; //數據寄存器
//檢測紅外信號的上升沿和下降沿
assign ifr_in_rise = (~infrared_in_d2) & (infrared_in_d1);
assign ifr_in_fall = (infrared_in_d2) & (~infrared_in_d1);
//對infrared_in信號打拍
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
infrared_in_d1 <= 1'b0;
infrared_in_d2 <= 1'b0;
end
else
begin
infrared_in_d1 <= infrared_in;
infrared_in_d2 <= infrared_in_d1;
end
//cnt
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 19'd0;
else
case(state)
IDLE: cnt <= 19'd0;
S_T9: if((ifr_in_rise==1'b1) && (flag_9ms==1'b1))
cnt <= 19'd0;
else
cnt <= cnt + 1;
S_JUDGE:if((ifr_in_fall==1'b1) && (flag_2_25ms==1'b1 ||
flag_4_5ms==1'b1))
cnt <= 19'd0;
else
cnt <= cnt + 1;
S_IFR_DATA: if((flag_0_56ms == 1'b1) && (ifr_in_rise==1'b1))
cnt <= 19'd0;
else if(((flag_0_56ms==1'b1) ||
(flag_1_69ms==1'b1)) && (ifr_in_fall==1'b1))
cnt <= 19'd0;
else
cnt <= cnt + 1;
default:cnt <= 19'd0;
endcase
//flag_0_56ms:計數到0.56ms范圍拉高標志信號
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_0_56ms <= 1'b0;
else if((state == S_IFR_DATA) && (cnt >= CNT_0_56MS_L) &&
(cnt <= CNT_0_56MS_H))
flag_0_56ms <= 1'b1;
else
flag_0_56ms <= 1'b0;
//flag_1_69ms:計數到1.69ms范圍拉高標志信號
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_1_69ms <= 1'b0;
else if((state == S_IFR_DATA) && (cnt >= CNT_1_69MS_L) &&
(cnt <= CNT_1_69MS_H))
flag_1_69ms <= 1'b1;
else
flag_1_69ms <= 1'b0;
//flag_2_25ms:計數到2.25ms范圍拉高標志信號
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_2_25ms <= 1'b0;
else if((state == S_JUDGE) && (cnt >= CNT_2_25MS_L) &&
(cnt <= CNT_2_25MS_H))
flag_2_25ms <= 1'b1;
else
flag_2_25ms <= 1'b0;
//flag_4_5ms:計數到4.5ms范圍拉高標志信號
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_4_5ms <= 1'b0;
else if((state == S_JUDGE) && (cnt >= CNT_4_5MS_L) &&
(cnt <= CNT_4_5MS_H))
flag_4_5ms <= 1'b1;
else
flag_4_5ms <= 1'b0;
//flag_9ms:計數到9ms范圍拉高標志信號
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_9ms <= 1'b0;
else if((state == S_T9) && (cnt >= CNT_9MS_L) &&
(cnt <= CNT_9MS_H))
flag_9ms <= 1'b1;
else
flag_9ms <= 1'b0;
//狀態機:狀態跳轉
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= IDLE;
else
case(state)
IDLE:
if(ifr_in_fall == 1'b1)
state <= S_T9;
else
state <= IDLE;
S_T9:
if((ifr_in_rise == 1'b1) && (flag_9ms == 1'b1))
state <= S_JUDGE;
else if((ifr_in_rise == 1'b1) && (flag_9ms == 1'b0))
state <= IDLE;
else
state <= S_T9;
S_JUDGE:
if((ifr_in_fall == 1'b1) && (flag_2_25ms == 1'b1))
state <= S_REPEAT;
else if((ifr_in_fall == 1'b1) && (flag_4_5ms == 1'b1))
state <= S_IFR_DATA;
else if((ifr_in_fall == 1'b1) && (flag_2_25ms == 1'b0) &&
(flag_4_5ms == 1'b0))
state <= IDLE;
else
state <= S_JUDGE;
S_IFR_DATA:
if(ifr_in_rise == 1'b1 && flag_0_56ms == 1'b0)
state <= IDLE;
else if(ifr_in_fall == 1'b1 && (flag_0_56ms == 1'b0 &&
flag_1_69ms == 1'b0))
state <= IDLE;
else if(ifr_in_rise == 1'b1 && data_cnt == 6'd32)
state <= IDLE;
S_REPEAT:
if(ifr_in_rise == 1'b1)
state <= IDLE;
else
state <= S_REPEAT;
default:
state <= IDLE;
endcase
//data_tmp
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_tmp <= 32'b0;
else if(state == S_IFR_DATA && ifr_in_fall == 1'b1 &&
flag_0_56ms == 1'b1)
data_tmp[data_cnt] <= 1'b0;
else if(state == S_IFR_DATA && ifr_in_fall == 1'b1 &&
flag_1_69ms == 1'b1)
data_tmp[data_cnt] <= 1'b1;
else
data_tmp <= data_tmp;
//data_cnt
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_cnt <= 1'b0;
else if(ifr_in_rise == 1'b1 && data_cnt == 6'd32)
data_cnt <= 1'b0;
else if(ifr_in_fall == 1'b1 && state == S_IFR_DATA)
data_cnt <= data_cnt + 1'b1;
else
data_cnt <= data_cnt;
//repeat_en
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
repeat_en <= 1'b0;
else if(state == S_REPEAT && (data_tmp[23:16] ==
~data_tmp[31:24]))
repeat_en <= 1'b1;
else
repeat_en <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 20'b0;
else if(data_tmp[23:16] == ~data_tmp[31:24] && data_tmp[7:0] ==
~data_tmp [15:8] && data_cnt==6'd32)
data <= {12'b0,data_tmp[23:16]};
endmodule
參數定義:我們需要規定flag信號拉起時的計數值,由于要保持一個時間段,5個計數值都要定義低值和高值
狀態定義:5個狀態用5位數值表示,每個狀態都有一個不同位為1。對于大型狀態機而言,如果上一個狀態到下一個狀態只改變一位會比這種定義好
檢測上升沿和下降沿:檢測方式是打拍之后取反求與,如果檢測到,對應的信號拉高
打拍:在第四節中介紹了阻塞賦值和非阻塞賦值,非阻塞賦值是并行的,always塊結束之后再完成賦值行為。所以在波形上看一條非阻塞賦值是有一個時鐘周期的延時。這個打拍可以理解為一次延時。
always塊中a=din;b=a;c=b; always塊中a=| | Q1 | Q2 | Q3 | Q4 | | Q1 | Q2 | Q3 | Q4 |
| ----- | ---- | ---- | ---- | ---- | ----- | ---- | ---- | ---- | ---- |
| din | 0 | 1 | 1 | 0 | din | 1 | 0 | 0 | 0 |
| a | 0 | 1 | 1 | 0 | a | 1 | 0 | 0 | 0 |
| b | 0 | 1 | 1 | 0 | b | 1 | 1 | 0 | 0 |
| c | 0 | 1 | 1 | 0 | c | 1 | 1 | 1 | 0 |
cnt計數:非復位狀態時要看狀態,IDEL狀態cnt一直保持0,S_T9狀態要判斷是否低電平持續9ms,條件是如果有上升沿的同時9ms的flag拉起,就要歸0重新準備計數,否則+1。其他狀態也是同理。
flag信號:以1.69ms為例,若復位有效,flag為低電平;如果狀態位于S_IFR_DATA且滿足1.69ms計數值的低值到高值之間,就拉高,否則維持低電平,其他的flag信號也是同理
狀態跳轉:復位有效是IDEL狀態;當狀態處于IDEL時,如果檢測到下降沿則跳轉到S_T9,否則說明發送錯誤,維持在IDEL;當狀態處于S_T9時,如果檢測到上升沿且低電平維持了9ms左右則跳轉到S_JUDGE,如果不是維持9ms說明發送錯誤則跳轉到IDEL;當狀態處于S_JUDGE時,如果檢測到下降沿且高電平維持了2.25ms左右,說明是重復碼跳轉到S_REPEAT左右,如果維持4.5ms說明后面要接地址碼等跳轉到S_IFR_DATA狀態,如果都不是說明發送錯誤回到IDEL狀態;當狀態處于S_IFR_DATA時,如果檢測到上升沿但不是維持56ms說明發送錯誤回到IDEL狀態,如果檢測到下降沿但是高電平時間不滿足邏輯0或1說明發送錯誤回到IDEL狀態,如果檢測到上升沿且數據計數器滿足32位則接收完畢回到IDEL狀態;當狀態處于S_REPEAT狀態時,如果檢測到上升沿直接回到IDEL狀態,否則維持原態。case語句需要default。
數據緩存:在S_IFR_DATA狀態時接收的32位數據需要區分邏輯0和1,先緩存到data_tmp中。當狀態是S_IFR_DATA時,復位有效時32位緩存都為0;當檢測到下降沿且高電平維持0.56ms說明是邏輯0,將其寫入到對應位的緩存中;維持1.69ms說明是邏輯1,也寫入。
data_cnt:數據計數器,因此有32位數據,每計數一次都要寫入一位。復位有效時為低電平;檢測到上升沿且data_cnt=32說明計滿且寫滿了,歸0;檢測到下降沿且處于S_IFR_DATA狀態,+1;其他情況維持不變
repeat_en:重復使能信號,要傳遞給Led作為亮燈的控制信號。重復的判斷條件是1、處于重復S_REPEAT狀態2、確實檢測到了重復的數據。復位有效時歸0;狀態處于重復狀態且緩存中高8位和次8位相同時拉高;其他情況歸0
數據輸出:復位有效時數據所有位都歸0;32位數據校驗方式是地址碼和地址反碼是位反的,數據碼和數據反碼是位反的,數據計數器計滿32個數值,如果檢驗成功,就將數據碼進行輸出。由于data和之前數碼管動態顯示中的位數一致是27位,這里輸出數據只有8位,因此高位都賦0。數碼管只需要顯示低8位表示的數值即可
LED燈控制模塊
當有一次重復碼時,重復使能有效,led閃爍一次。如果讓燈在使能有效時亮,使能信號持續時間很短,led亮的時間也短,效果不明顯。長按紅外遙控按鍵那么每110ms會發送一次重復碼,那么如果讓led燈在110ms中亮50ms,led的顯示效果比較好。需要一個50ms的計數器,在repeat_en信號檢測出上升沿時開始計數,此時led低電平點亮,計數完畢后led熄滅。
編寫代碼
module led_ctrl
(
input wire sys_clk , //系統時鐘,頻率50MHz
input wire sys_rst_n , //復位信號,低有效
input wire repeat_en , //重復碼使能信號
output reg led //輸出led燈信號
);
//parameter define
parameter CNT_MAX = 2500_000;
//wire define
wire repeat_en_rise ; //重復碼使能信號上升沿
//reg define
reg repeat_en_d1; //重復碼使能信號打一拍
reg repeat_en_d2; //重復碼使能信號打兩拍
reg cnt_en ; //計數器使能信號
reg [21:0] cnt ; //計數器
//獲得repeat_en上升沿信號
assign repeat_en_rise = repeat_en_d1 & ~repeat_en_d2;
//對repeat_en打兩拍
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
repeat_en_d1 <= 1'b0;
repeat_en_d2 <= 1'b0;
end
else
begin
repeat_en_d1 <= repeat_en;
repeat_en_d2 <= repeat_en_d1;
end
//當重復碼使能信號上升沿來到,拉高計數器使能信號,計到50ms后拉低
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_en <= 1'b0;
else if(cnt == CNT_MAX - 1)
cnt_en <= 1'b0;
else if(repeat_en_rise == 1'b1)
cnt_en <= 1'b1;
//當計數器使能信號為高時讓計數器開始計數,為低時計數器清零
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 22'b0;
else if(cnt_en == 1'b1)
cnt <= cnt + 1;
else
cnt <= 22'b0;
//當計數器大于0時,點亮led燈,也就是當使能信號到來,led燈會亮50ms
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
led <= 1'b1;
else if(cnt > 0)
led <= 1'b0;
else
led <= 1'b1;
endmodule
參數定義,獲取上升沿,打拍
使能信號cnt_en:復位時歸0;cnt計數到CNT_MAX-1時歸0,上升沿信號repeat_en_rise拉高時拉高
計數器cnt:復位時歸0;cnt_en為高電平時計數+1,其他情況歸0
led:復位時拉高表示熄滅,當cnt>0(1-250000)時led拉低表示點亮,否則熄滅
頂層模塊
module top_infrared_rcv
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire infrared_in ,
output wire stcp ,
output wire shcp ,
output wire ds ,
output wire oe ,
output wire led
);
//wire define
wire repeat_en ; //重復碼使能信號
wire [19:0] data ; //接收的控制碼
infrared_rcv infrared_rcv_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.infrared_in (infrared_in),
.repeat_en (repeat_en ),
.data (data )
);
led_ctrl led_ctrl_inst
(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n) ,
.repeat_en (repeat_en) ,
.led (led )
);
seg_595_dynamic seg_595_dynamic_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.data (data ),
.point (6'd0 ),
.seg_en (1'b1 ),
.sign (1'b0 ),
.stcp (stcp ),
.shcp (shcp ),
.ds (ds ),
.oe (oe )
);
endmodule
testbench
`timescale 1ns/1ns
module tb_top_infrared_rcv();
//wire define
wire led ;
wire stcp ;
wire shcp ;
wire ds ;
//reg define
reg sys_clk ;
reg sys_rst_n ;
reg infrared_in ;
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
infrared_in <= 1'b1;
#100
sys_rst_n <= 1'b1;
//引導碼
#1000
infrared_in <= 1'b0; #9000000
infrared_in <= 1'b1; #4500000
//地址碼(發送地址碼8’h99)
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//地址反碼(地址反碼為8’h66)
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據碼(發送數據碼8’h22)
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據反碼(數據反碼為8’hdd)
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據0
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #560000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//數據1
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #1690000
//重復碼
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1; #42000000
infrared_in <= 1'b0; #9000000
infrared_in <= 1'b1; #2250000
infrared_in <= 1'b0; #560000
infrared_in <= 1'b1;
end
//clk:產生時鐘
always #10 sys_clk <= ~sys_clk;
top_infrared_rcv top_infrared_rcv_inst
(
.sys_clk (sys_clk ), //系統時鐘,頻率50MHz
.sys_rst_n (sys_rst_n ), //復位信號,低電平有效
.infrared_in (infrared_in), //紅外接收信號
.stcp (stcp ), //輸出數據存儲寄時鐘
.shcp (shcp ), //移位寄存器的時鐘輸入
.ds (ds ), //串行數據輸入
.led (led ) //led燈控制信號
);
endmodule
初始化
引導碼:低電平9ms,高電平4.5ms
地址碼1001_1001:邏輯1是低電平延遲0.56ms后高電平延遲0.56ms,邏輯0是低電平延遲0.56ms后高電平延遲1.69ms
地址反碼0110_0110
數據碼0010_0010
數據反碼1101_1101,數據反碼后要以0.56ms的低電平作為結束標志
重復碼:維持一段時間高電平后再發送重復碼,低電平延遲9ms再高電平延遲2.25ms,以0.56ms的低電平作為重復碼的結束標志
產生時鐘,實例化
對比波形
data是27h'0000022與我們發送的數據一致,重復使能也按照預期實現。
管腳分配
紅外模塊的管腳圖,其他管腳之前都用過不重復
全編譯后上板驗證
長按才亮燈,按鍵對應的值顯示在數碼管上,視頻中我可能按的比較重。
-
FPGA
+關注
關注
1630文章
21794瀏覽量
605129 -
發光二極管
+關注
關注
13文章
1203瀏覽量
66438 -
NEC
+關注
關注
0文章
238瀏覽量
99157 -
時鐘
+關注
關注
11文章
1746瀏覽量
131673 -
紅外遙控
+關注
關注
22文章
347瀏覽量
45683
發布評論請先 登錄
相關推薦
評論