大二下學期做的期末設計,使用verilog編寫,對車載MP3紅外遙控器(NEC協議)進行解碼,解碼完整,並通過有趣的流水燈控制和七段數碼管控制來體現解碼效果,貼出來供大家參考。
這裏有這個作品視頻的鏈接:鏈接: http://pan.baidu.com/s/1nvRNRol 密碼: 8dmm
功能框架:
使用器件:
①basys3開發板(Artix-7 xc7a357);
②紅外接收模塊(一體化紅外接收頭、1.2K電阻),小器件,自己焊接就可以了
③車載MP3紅外遙控器(NEC協議)。
代碼挺多,這裏給出紅外解碼的部分,其餘LED和數碼管的控制模塊,在這裏就不放出來了
module JieMa(clk,rst,ir_in,ir_data_out);
input clk,rst,ir_in;
output reg [7:0] ir_data_out;
/********************邊沿檢測******************/
wire pos_edge; //ir_in信號的上升沿
wire neg_edge; //ir_in信號的下降沿
wire ir_change; //ir_in信號發生變化
reg reg0,reg1,reg2; //預防亞穩態
always @ (posedge clk or posedge rst)
begin
if(rst)
begin
reg0<=1'b0;
reg1<=1'b0;
reg2<=1'b0;
end
else
begin
reg0<= ir_in;
reg1<= reg0;
reg2<= reg1;
end
end
assign pos_edge = reg1 & ~reg2;
assign neg_edge = ~reg1 & reg2;
assign ir_change = neg_edge | pos_edge;
/*********************************************/
/********************分頻計時******************/
reg [11:0] count1;
reg [8:0] count2;
wiredelay_9ms,delay_4_5ms,delay_0_56ms,delay_1_68ms;
always @ (posedge clk or posedge rst)
begin
if(rst)
count1<= 12'd0;
elseif(ir_change) //ir信號發生跳變就重新計數
count1<= 12'd0;
elseif(count1 == 12'd3000) //成功計數15對應300ns 1500對應30us
count1<= 12'd0;
else
count1<= count1 + 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if(rst)
count2<= 9'd0;
elseif(ir_change) //ir信號發生跳變就重新計數
count2<= 9'd0;
elseif(count1 == 12'd3000) //count1成功計數30us,則count2+1
count2<= count2 + 1'b1;
else
count2<= count2;
end
assign delay_9ms =(count2>250)&(count2<350); //300,取範圍值,增加穩定性
assign delay_4_5ms =(count2>120)&(count2<180); //150
assign delay_0_56ms =(count2>7)&(count2<27); //17
assign delay_1_68ms =(count2>46)&(count2<66); //56
//delay_9ms=1,表示從第一次ir_in信號發生跳變開始,到下一次ir_in發生跳變爲止,此過程大概經歷了9ms
/*********************************************/
/******************三段式狀態機****************/
parameter start = 3'b000,
begin_9ms =3'b001,
begin_4_5ms= 3'b010,
data_recive= 3'b011;
reg error;
reg [5:0] data_count;
reg [31:0] get_data;
reg [2:0] state,next_state;
always @ (posedge clk or posedge rst) //時序邏輯
if(rst)
state<= start;
else
state<= next_state;
always @ (*) //必須全部電平敏感,狀態轉移,組合邏輯,阻塞式賦值
case(state)
start:
if(neg_edge)//IR信號發生跳變,由1變0
next_state= begin_9ms;
else
next_state= start;
begin_9ms:
if(pos_edge)
begin
if(delay_9ms)//在上升沿到來時,是否經過了9ms,即低電平是否持續了9ms
next_state= begin_4_5ms;
else
next_state= start;
end
else
next_state= begin_9ms;
begin_4_5ms:
if(neg_edge)
begin
if(delay_4_5ms)//高電平是否持續了4.5ms
next_state= data_recive;
else
next_state= start;
end
else
next_state= begin_4_5ms;
data_recive://開始接收數據
if((data_count== 6'd32) & reg1 & reg2) //接受了32位數據與一位終止位
next_state= start;
elseif (error) //接受數據過程中出錯
next_state= start;
else
next_state= data_recive;
default:
next_state= start;
endcase
always @ (posedge clk or posedge rst) //狀態中的輸出,時序邏輯
begin
if(rst)
begin
data_count <= 6'd0;
error <= 1'b0;
get_data <= 32'd0;
end
elseif(state == start) //一開始沒獲得任何數據
begin
data_count <= 6'd0;
error <= 1'b0;
get_data <= 32'd0;
end
elseif(state == data_recive)
begin
if(pos_edge)
begin
if(!delay_0_56ms)
//上升沿到來,之前的低電平的持續時間不足0.56ms,說明出錯
error<= 1'b1;
else
error<= 1'b0;
end
elseif(neg_edge)
begin
if(delay_0_56ms)
//下降沿到來,之前的高電平的持續時間0.56ms,說明收到的是0
get_data[0]<= 1'b0;
elseif (delay_1_68ms)
//下降沿到來,之前的高電平的持續時間1.68ms,說明收到的是1
get_data[0]<= 1'b1;
else //收到的數據非0非1,說明出錯
error<= 1'b1;
//上述各語句接收完1個位的數據,get_data[0]保存了最新接收到的數據
get_data[31:1]<= get_data[30:0];
//數據左移
data_count<= data_count+1'b1;
end
end
end
/*********************************************/
/*************將接收到的數據輸出****************/
always @ (posedge clk or posedge rst)
if(rst)
ir_data_out <= 8'd0;
elseif( (data_count == 6'd32) & reg1 & reg2)
//接受完32位數據,並且接受到最後的停止位
ir_data_out<=get_data[15:8];
//輸出數據碼,與實際紅外發送出來的數據是倒序相等的
else
ir_data_out<= ir_data_out;
/*********************************************/
endmodule