FPGA之串口收發字符串之(一)——發送模塊

1、總體概述

串口通信是一種常見的通信方式。在FPGA中也是比不可少,本專題實現FPGA的串口收發字符串,屬於Uart通信,通信方式:串行、異步、全雙工的。用verilog實現,包括以下幾個模塊:串口發送模塊、串口接收模塊、波特率發生器模塊、字符串接收與發送調度模塊(可以獨立於串口接收模塊,這裏的輸入數據位並行的,主要是爲了將要待發送字符串(來自其他模塊)進行數據重組(本次的通信外部設備爲HMI,其字符串控制指令具有特定的字符串格式))、按鍵發送字符模塊(包含按鍵消抖模塊),以下從各模塊及書寫和調試中遇到的問題進行詳細說明。本次實例實現FPGA控制HMI屏(串口屏),在屏幕上顯示相應的字符串數據。

NOTE:異步通信指的是通信的發送與接收方使用各自的時鐘控制數據的發送和接收過程,具體就是:以字符(一幀數據)爲單位進行傳輸,字符與字符見的間隙是任意的,但字符內部各bit位是一固定時間傳送的(即在固定波特率的控制下進行)。通信的傳輸方向爲全雙工,指的時數據可以同時雙向傳輸(實際上感覺這一點的作用並不是太大,因爲很多時候不需要同時雙向,一般是當接收到某個特定數據時,再向外發送某個數據,這已經暗含了非同時的特點,但它一定有特殊的應用場合)。

2 USART_Send模塊

本次收發模塊採用的是10bit爲一幀數據的傳輸方式,串口發送模塊的數據輸入爲8位並行數據(數據收入一個時鐘週期就完成,速度很快),故需要將接收到的數據進行重組(即加上起始位0和停止位1),隨後在波特率的控制下調度數據移位串行輸出。發送模塊的輸入需要一個發送請求脈衝,用於作爲啓動波特率發生器的標誌(控制移位輸出)。

代碼如下:
主要包括:請求信號到來寫入數據、數據移位操作和數據位數計數模塊
<請求信號到來寫入數據>

/*************請求信號到來寫入數據****************/
//請求信號到來,寫入數據並置位波特率啓動位
always @ (posedge clk, negedge rst_n)
begin
	if (!rst_n)
		tx_bps_start <= 1'b0;
	else if (req_send) 	 	 		  	  	 	    	  	 	 //請求信號有效,將輸入寫入到datain_buf1中
		tx_bps_start <= 1'b1;                      	 	 //波特率啓動標誌,直到停止位變爲0
	else if (bit_cnt == 4'd10)
		tx_bps_start <= 1'b0;
end

always @ (posedge clk, negedge rst_n)
begin
	if (!rst_n)
		datain_buf1 <= {(PORT_WID + 1){1'b0}};
	else if (req_send)
		datain_buf1 <= {1'b1, datain[7 : 0], 1'b0}; 	 	 //10位數據幀格式,0位起始位,9位停止位;
end

<數據移位操作>

reg 	 	 	 	 	 	 	 dat_flag;
/*************數據移位操作****************/
always @ (posedge clk, negedge rst_n)
begin
	if (!rst_n)
	begin
		datain_buf2 <= {(PORT_WID + 1){1'b0}};
		dat_flag <= 1'b0;
	end
	else if (tx_bps_flag)
	begin
		datain_buf2 <= datain_buf1 >> bit_cnt;
		dat_flag <= 1'b1; 	 	 	 	  	 	 	 	  	 	
	end
	else
		dat_flag <= 1'b0;
end

assign TXD = tx_buf; 
 
assign TI = ti_buf;
always @ (posedge clk, negedge rst_n)
begin
	if (!rst_n)
		ti_buf <= 1'b0;
	else if (bit_cnt == 4'd10)
		ti_buf <= 1'b1;
	else
		ti_buf <= 1'b0;
end

always @ (posedge clk, negedge rst_n)
begin
	if (!rst_n)
		tx_buf <= 1'b1;
	else if (dat_flag) 	  	   	 	 	 		 	 //不是tx_bps_flag一到就賦值給tx_buf,順延一個週期
		tx_buf <= datain_buf2[0]; 	 		 	 	    //爲了避免datain_buf2初始賦值的影響
	else if (!tx_bps_start)
		tx_buf <= 1'b1;
end

<數據位數計數>

/*************數據位數計數****************/
always @ (posedge clk, negedge rst_n)
begin
	if (!rst_n)
		bit_cnt <= {DATA_WID{1'b0}};
	else if (tx_bps_flag)
		bit_cnt <= bit_cnt + 1'b1;
	else if (bit_cnt >= 4'd10)
		bit_cnt <= {DATA_WID{1'b0}};
end

在這裏,先附上整個串口和發送程序的時序圖,以方便理解。

串口收發時序圖
這一節先寫到這,主要是串口的發送模塊,下一節更新接收模塊。
NOTE:完整代碼連接
https://download.csdn.net/download/huigeyu/11156523 如有需要,請自行下載!