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