1. 程式人生 > >FPGA-串列埠通訊的接收模組(傳送接收模組)

FPGA-串列埠通訊的接收模組(傳送接收模組)

接收模組和傳送模組類似:

       在接收的過程中為了保證接收資料的準確性對單個時鐘波特率進行分頻,單個時鐘訊號下分頻16次,進行資料採集保證了資料的準確性,這裡的程式碼思想借鑑了小梅哥的程式碼的編寫思想。

傳送接收模組的驗證:

      這裡傳送接收的驗證是通過PC端進行傳送,由開發板先接收到資料,然後進行傳送,這裡如果要是驗證些字串或者是一些特殊的指令,用狀態機或者類似狀態機的思想進行設計。

這裡只貼出任務要求的接收模組的驗證基本任務和程式碼

任務要求:

由PC埠進行傳送指令檢測單個字元和字串

      如果傳送I Like FPGA led 全亮,如果錯誤led閃爍,當傳送單個字元時,利用LED燈指示該字元的ASCII碼。

串列埠接收模組:

module uart_rxd(clk,rst_n,bps_set,rxd,data_byte,rxd_finish,uart_state
    );
	input           clk       ;//輸入時鐘
	input           rst_n     ;//復位訊號
	input     [1:0] bps_set   ;//波特率選擇
	input           rxd       ;//接收模組
	output    [7:0] data_byte ;//接收資料
	output          rxd_finish;//傳送完成標誌
	output          uart_state;//串列埠通訊狀態
	reg       [7:0] data_byte ;
	reg             rxd_finish;
	reg             uart_state;
	parameter       BPS_4800    =16'd324,
                    BPS_9600    =16'd162,
					BPS_19200   =16'd80 ,
                    BPS_115200  =16'd13 ;
	
	//消除亞穩態
	reg rxd_s0,rxd_s1;  //同步暫存器
	
[email protected]
(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rxd_s0<=1'b0; rxd_s1<=1'b0; end else begin rxd_s0<=rxd; rxd_s1<=rxd_s0; end end reg rxd_temp0,rxd_temp1;//資料暫存器 [email protected](posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rxd_temp0<=1'b0; rxd_temp1<=1'b0; end else begin rxd_temp0<=rxd_s1; rxd_temp1<=rxd_temp0; end end wire rxd_negedge =~rxd_temp0&rxd_temp1; reg [15:0] div_cnt; reg [15:0] time_div; //波特率選擇模組
[email protected]
(*)begin if(rst_n==1'b0)begin time_div=BPS_9600; end else begin case(bps_set) 2'b00: time_div = BPS_4800; 2'b01: time_div = BPS_9600; 2'b10: time_div = BPS_19200; 2'b11: time_div = BPS_115200; default:time_div = BPS_9600; endcase end end //波特率計數模組 [email protected](posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin div_cnt<=1'b0; end else if(uart_state==1'b1)begin if(div_cnt==time_div)begin div_cnt<=1'b0; end else begin div_cnt<=div_cnt+1'b1; end end else begin div_cnt<=1'b0; end end //波特率時鐘模組 reg bps_clk; [email protected](posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin bps_clk<=1'b0; end else if(div_cnt==time_div)begin bps_clk<=1'b1; end else begin bps_clk<=1'b0; end end //bps計數模組 reg [7:0] bps_cnt; [email protected](posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin bps_cnt<=8'd0; end else if(rxd_finish==1'b1||(bps_cnt==8'd12 && (Start>3'd3)))begin bps_cnt<=8'd0; end else if(bps_clk==1'b1)begin bps_cnt<=bps_cnt+1'b1; end else begin bps_cnt<=bps_cnt; end end [email protected](posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rxd_finish=1'b0; end else if(bps_cnt==8'd159)begin rxd_finish=1'b1; end else begin rxd_finish=1'b0; end end //資料緩衝區模組 reg [2:0] r_data_byte[7:0]; reg [2:0]Start,Stop; [email protected](posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin Start<=3'd0; r_data_byte[0]<=3'd0; r_data_byte[1]<=3'd0; r_data_byte[2]<=3'd0; r_data_byte[3]<=3'd0; r_data_byte[4]<=3'd0; r_data_byte[5]<=3'd0; r_data_byte[6]<=3'd0; r_data_byte[7]<=3'd0; Stop<=3'd0; end else if(bps_clk==1'b1)begin if(bps_cnt==1'b0)begin Start<=3'd0; r_data_byte[0]<=3'd0; r_data_byte[1]<=3'd0; r_data_byte[2]<=3'd0; r_data_byte[3]<=3'd0; r_data_byte[4]<=3'd0; r_data_byte[5]<=3'd0; r_data_byte[6]<=3'd0; r_data_byte[7]<=3'd0; Stop<=3'd0; end if(16'd6<=bps_cnt&&bps_cnt<=16'd12)begin Start<=Start+rxd_s1; end else if(16'd22<=bps_cnt&&bps_cnt<=16'd28)begin r_data_byte[0]<=r_data_byte[0]+rxd_s1; end else if(16'd38<=bps_cnt&&bps_cnt<=16'd44)begin r_data_byte[1]<=r_data_byte[1]+rxd_s1; end else if(16'd54<=bps_cnt&&bps_cnt<=16'd60)begin r_data_byte[2]<=r_data_byte[2]+rxd_s1; end else if(16'd70<=bps_cnt&&bps_cnt<=16'd76)begin r_data_byte[3]<=r_data_byte[3]+rxd_s1; end else if(16'd86<=bps_cnt&&bps_cnt<=16'd92)begin r_data_byte[4]<=r_data_byte[4]+rxd_s1; end else if(16'd102<=bps_cnt&&bps_cnt<=16'd108)begin r_data_byte[5]<=r_data_byte[5]+rxd_s1; end else if(16'd118<=bps_cnt&&bps_cnt<=16'd124)begin r_data_byte[6]<=r_data_byte[6]+rxd_s1; end else if(16'd134<=bps_cnt&&bps_cnt<=16'd140)begin r_data_byte[7]<=r_data_byte[7]+rxd_s1; end else if(16'd150<=bps_cnt&&bps_cnt<=16'd156)begin Stop<=Stop+rxd_s1; end end else; end [email protected](posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin data_byte<=8'd0; end else if(bps_cnt==8'd159)begin data_byte[0]<=(r_data_byte[0]>3'd3)?1'b1:1'b0; data_byte[1]<=(r_data_byte[1]>3'd3)?1'b1:1'b0; data_byte[2]<=(r_data_byte[2]>3'd3)?1'b1:1'b0; data_byte[3]<=(r_data_byte[3]>3'd3)?1'b1:1'b0; data_byte[4]<=(r_data_byte[4]>3'd3)?1'b1:1'b0; data_byte[5]<=(r_data_byte[5]>3'd3)?1'b1:1'b0; data_byte[6]<=(r_data_byte[6]>3'd3)?1'b1:1'b0; data_byte[7]<=(r_data_byte[7]>3'd3)?1'b1:1'b0; end else begin data_byte<=data_byte; end end [email protected](posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin uart_state<=1'b0; end else if(rxd_negedge==1'b1)begin uart_state<=1'b1; end else if(rxd_finish==1'b1||(bps_cnt==8'd12 && (Start>3'd3)))begin uart_state<=1'b0; end else begin uart_state<=uart_state; end end endmodule

 

字元緩衝模組:

module uart_dat_buf(clk,rst_n,rxd_sel,rxd_finish,rxd_state,data_byte,led
    );
	input           clk       ;//輸入時鐘
	input           rst_n     ;//復位訊號
	input           rxd_sel   ;//指令選擇
	input           rxd_finish;//一位資料傳送完成標誌
	input           rxd_state ;//傳送狀態標誌
	input     [7:0] data_byte ;
	
	output reg[7:0] led       ;
	
	parameter       TIME = 25'd2500_0000,
					S0 =4'd0,
					S1 =4'd1,
					S2 =4'd2,
					S3 =4'd3,
					S4 =4'd4,
					S5 =4'd5,
					S6 =4'd6,
					S7 =4'd7,
					S8 =4'd8,
					S9 =4'd9,
					S10=4'd10,
					ERROR =4'd15;
	//資料接收模組
	reg       [7:0] data_byte_temp;
	[email protected](*)begin
		if(rst_n==1'b0)begin
			data_byte_temp=8'd0;
		end
		else if(rxd_state==1'b1)begin
			data_byte_temp=data_byte;
		end
		else begin
			data_byte_temp=data_byte_temp;
		end
	end
	//狀態轉換
	reg [3:0] state_c;
	reg [3:0] state_n;
	[email protected](posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			state_c<=S0;
		end
		else if(rxd_state==1'b1)begin
			state_c<=state_c;
		end
		else begin
			state_c<=state_n;
		end
	end
	//狀態判斷
	[email protected](*)begin
		if(rst_n==1'b0)begin
			state_n=S0;
		end
		else if(rxd_sel==1'b0&&rxd_state==1'b1)begin
			case(state_c)
				S0 :
					if(data_byte_temp=="I")begin
						state_n=S1;
					end
					else begin
						state_n=ERROR;
					end
				S1 :
					if(data_byte_temp==" ")begin
						state_n=S2;
					end
					else begin
						state_n=ERROR;
					end
				S2 :
					if(data_byte_temp=="L")begin
						state_n=S3;
					end
					else begin
						state_n=ERROR;
					end
				S3 :
					if(data_byte_temp=="i")begin
						state_n=S4;
					end
					else begin
						state_n=ERROR;
					end
				S4 :
					if(data_byte_temp=="k")begin
						state_n=S5;
					end
					else begin
						state_n=ERROR;
					end
				S5 :
					if(data_byte_temp=="e")begin
						state_n=S6;
					end
					else begin
						state_n=ERROR;
					end
				S6 :
					if(data_byte_temp==" ")begin
						state_n=S7;
					end
					else begin
						state_n=ERROR;
					end
				S7 :
					if(data_byte_temp=="F")begin
						state_n=S8;
					end
					else begin
						state_n=ERROR;
					end
				S8 :
					if(data_byte_temp=="P")begin
						state_n=S9;
					end
					else begin
						state_n=ERROR;
					end
				S9 :
					if(data_byte_temp=="G")begin
						state_n=S10;
					end
					else begin
						state_n=ERROR;
					end
				S10:
					if(data_byte_temp=="A")begin
						state_n=S0;
					end
					else begin
						state_n=ERROR;
					end
				ERROR:if(data_byte_temp=="I")begin
						state_n=S1;
					end
					else begin
						state_n=ERROR;
					end
				default:state_n=S0;
			endcase
		end
		else begin
			state_n=state_n;
		end
	end
	
	reg [1:0] flag_led;
	//輸出模組
	[email protected](posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			flag_led<=2'd3;
		end
		else if(rxd_sel==1'b1)begin
			flag_led<=2'b10;
		end
		else if(rxd_sel==1'b0)begin
			if(state_c==ERROR)begin
				flag_led<=2'b01;
			end
			else if(state_c==S10)begin
				flag_led<=2'b00;
			end
			else begin
				flag_led<=flag_led;
			end
		end
		else begin
			flag_led<=2'b11;
		end
	end
	//閃爍led設計
	reg  [24:0] cnt;//存放計數器的值
	//數碼管特殊狀態閃爍計數器模組
	[email protected](posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			cnt <=25'd0;
		end
		else if(cnt ==TIME-1'b1)begin
			cnt <=1'b0;
		end
		else if(flag_led==2'b01)begin
			cnt <=cnt + 1'b1;
		end
		else begin
			cnt <=25'd0;
		end
	end
	
	//led燈指示
	[email protected](posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			led<=8'b1111_1111;
		end
		else if(flag_led==2'b10)begin
			led<=data_byte_temp;
		end
		else if(flag_led==2'b00)begin
			led<=8'b0000_0000;
		end
		else if(flag_led==2'b01)begin
			if(cnt<(TIME/2-1'b1))begin
				led<=8'b1111_1111;
			end
			else begin
				led<=8'b0000_0000;
			end
		end
		else if(flag_led==2'b11)begin
			led<=8'b1111_1111;
		end
		else begin
			led<=led;
		end
	end

endmodule

 

頂層檔案:

module uart_rxd_top(ext_clk_25m,ext_rst_n,uart_rx,led,switch0
    );
	input ext_clk_25m	;//系統時鐘
	input ext_rst_n		;//復位訊號
	input uart_rx		;//串列埠通訊接收
	input switch0		;//指令切換
	
	output [7:0]led		;//led顯示
	
	wire [7:0]data_byte;
	wire uart_state;
	wire rxd_finish;
	
	uart_rxd u_r1(
	.clk(ext_clk_25m),
	.rst_n(ext_rst_n),
	.bps_set(1), 
	.rxd(uart_rx),
	.data_byte(data_byte),
	.rxd_finish(rxd_finish),
	.uart_state(uart_state)
    );
	
	uart_dat_buf u_dat1(
	.clk(ext_clk_25m),
	.rst_n(ext_rst_n),
	.rxd_sel(switch0),
	.rxd_finish(rxd_finish),
	.rxd_state(uart_state),
	.data_byte(data_byte),
	.led(led)
    );

endmodule