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