(一) UART 介紹
略……(后續會補上)
(二) UART 軟件
PC 端使用的軟件為“串口調試助手 ComAssistant”
(三) UART 模塊介紹
下面先介紹 UART 關鍵的3個模塊,可以先不理解其中的工作原理,先了解這幾個模塊的作用與效果。
1. Uart_ClkDiv
/* Uart時鍾信號 */
module Uart_ClkDiv(
input Sys_CLK, //50Mhz系統時鍾
output Uart_CLK //9600bps
);
- 上述 Uart_ClkDiv 用來生成 Uart 傳輸所需要的時鍾信號,輸入 50Mhz 系統時鍾,輸出 Uart 時鍾
2. Uart_Rx
/* Uart_Rx 用於接收數據 */
module Uart_Rx(
input Uart_CLK,//采樣時鍾
input RST,//復位信號
input Signal_Rx,//UART數據輸入
output reg [7:0] Data_Rx,//接收數據輸出
output reg Rdsig,//置1時表示上層模塊已經可以讀8位數據了
output reg DataError_Flag,//數據出錯指示
output reg FrameError_Flag//幀出錯指示
);
- 上述 Uart_Rx 用於接收數據,輸入的 Uart_CLK 為模塊 Uart_ClkDiv 生成的 Uart 時鍾信號,RST 為復位鍵信號(低電平有效),Signal_Rx 為 Uart 數據輸入信號
- 8bit 輸出 Data_Rx 為一次接收獲取的數據,Rdsig 為低電平表示正在接收數據,當一次數據接收完畢后會置成一段時間的高電平
- DataError_Flag 和 FrameError_Flag 都是出錯提示,當接收數據過程發送錯誤會被置成高電平,需要注意此處的校驗位為偶校驗位(Even)
3. Uart_Tx
/* Uart_Tx發送數據 */
module Uart_Tx(
input Uart_CLK,
input RST,
input [7:0] Data_Tx,//8位待發送數據
input Wrsig,
output reg Idle,//空閑狀態,0表示空閑,1表示忙碌
output reg Signal_Tx//並轉串,1位輸出
);
- 上述 Uart_Tx 用於發送數據,輸入的 Uart_CLK 為模塊 Uart_ClkDiv 生成的 Uart 時鍾信號,RST 為復位鍵信號(低電平有效)
- Data_Tx 為 8bit 待發送數據,Wrsig 上升沿時開始發送
- Idle 是 Uart_Tx 發送器的狀態,0表示空閑,1表示忙碌, Signal_Tx 是數據輸出信號
上述三個模塊是 UART 發送的核心,但要實現超過 8 位的數據傳輸,單靠上面還不夠
(四) 實現多比特數據傳輸
- 由於 UART 的資料位(數據位)一般是8位,但實際應用中需要傳輸多位數據。
- 根據 Uart_Rx 和 Uart_Tx 各接口的效果,使用時鍾周期進行循環接收與發送
- 此處以接收 64bit 數據,並將接收到的數據發送為例,演示多位數據傳輸的原理
注意:圖中的校驗位為EVEN,應該為偶校驗,猜測軟件將EVEN(偶)錯誤標記成EVEN(奇)
1. 頂層模塊
/* 頂層模塊 */
module uart_top(
input sys_clk,//系統時鍾
input sys_rst,//復位鍵
input signal_rx,//接收信號rx
input enable,//使能信號
output isEnable,//是否能夠運行
output Err,//錯誤信號
output busy,//忙碌信號
output finish,//完成信號
output signal_tx//tx發送信號
);
- 上述為頂層模塊的接口,由於代碼實現的原因,在每次發送數據至 FPGA 板子前需要按下復位鍵,否則將無法正常接收
- 運行中信號,錯誤信號,忙碌信號,完成信號分別綁在 FPGA 的 4 個 LED 燈中,作為 FPGA 傳輸數據時的反饋
- 使能信號 enable 綁於一個撥碼開關上,高電平運行
2. 循環接收模塊
2.1 接口定義
/* 循環接收模塊 */
module Uart_Receive_Top(
input sys_clk,//系統時鍾
input sys_rst,//系統復位鍵
input signal_rx,//接收信號rx
input enable,//使能信號
output reg[63:0] data_input,//數據輸入
output reg Err,//報錯,高電平出錯
output reg finish,//接收完成信號
output reg busy//高電平忙碌
);
- 上述是接收模塊的接口定義,在此模塊中實現循環接收數據,接收完畢后會將 finish 信號置1,表示接收完成
如果接收未完成,busy 信號為1,如果接收出錯,Err信號為1
2.2 核心代碼
/* 循環接收模塊 */
case(state)
4'd00 : begin
if(Rdsig && !DataError && !FrameError) begin
data_input[64-0*8-1:64-(0+1)*8] <= data_rx;
busy <= 1'b1;
state <= state + 1;
end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
4'd01 : begin
if(!Rdsig)state <= state + 1;
end
4'd02 : begin
if(Rdsig && !DataError && !FrameError) begin
data_input[64-1*8-1:64-(1+1)*8] <= data_rx;
busy <= 1'b1;
state <= state + 1;
end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
4'd03 : begin
if(!Rdsig)state <= state + 1;
end
...
4'd14 : begin
if(Rdsig && !DataError && !FrameError) begin
data_input[64-7*8-1:64-(7+1)*8] <= data_rx;
finish <= 1;
busy <= 0;
state <= state;
end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
//報錯
4'b1111:Err<=1;
default:;
endcase
- 上述是接收過程的其中幾個狀態,每兩個狀態完成一次接收操作
- 第一個狀態進行接收,當 Rwsig 為 1 時表示接收完畢,DataError 和 FrameError 都不為 0 表示未發生錯誤
故一次接收完成,進行 data_input 的賦值,並讓 state + 1 跳轉至下一個狀態;如果發生錯誤,將狀態跳轉到報錯狀態 - 第二個狀態等待下一次接收的開始,當 Rwsig 為 0 后表明接收開始,跳轉到下一個狀態等待接收完畢
- 當最后一個數據接收完畢后,將 finish 置 1,busy 置 0,表明接收完畢
3. 發送模塊
3.1 接口定義
module Uart_Send_Top(
input sys_clk,//系統時鍾50MHz
input sys_rst,//重置鍵rst
input [63:0] data_output,//待發送數據
input enable,//發送使能,1為可以發送
output wire signal_tx,//uart發送信號tx
output reg Err,//報錯,高電平出錯
output reg finish,//完成信號
output reg busy//高電平時表示忙碌
);
- 上述是循環發送模塊的接口定義,與接收接口類似
3.2 核心代碼
/* 循環發送模塊 */
case(state)
4'd00 : begin
if(!Busy_Tx) begin
Data_Tx <= data_output[64-0*8-1:64-(0+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_cnt <= 12'd0;
wait_finished <= 1'b0;
end
end
4'd01 : begin
if(Busy_Tx) begin
Wrsig <= 0;
end
else begin
wait_cnt <= wait_cnt + 1;
if(wait_cnt == 12'hA00) begin
wait_cnt <= 12'd0;
wait_finished <= 1'b1;
end
else if(wait_cnt == 12'd0 && wait_finished) state <= state + 1;
end
end
4'd02 : begin
if(!Busy_Tx) begin
Data_Tx <= data_output[64-1*8-1:64-(1+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_cnt <= 12'd0;
wait_finished <= 1'b0;
end
end
4'd03 : begin
if(Busy_Tx) begin
Wrsig <= 0;
end
else begin
wait_cnt <= wait_cnt + 1;
if(wait_cnt == 12'hA00) begin
wait_cnt <= 12'd0;
wait_finished <= 1'b1;
end
else if(wait_cnt == 12'd0 && wait_finished) state <= state + 1;
end
...
4'd14 : begin
if(!Busy_Tx) begin
Data_Tx <= data_output[64-7*8-1:64-(7+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_cnt <= 12'd0;
wait_finished <= 1'b0;
end
end
4'd15 : begin
if(Busy_Tx) begin
Wrsig <= 0;
end
else begin
wait_cnt <= wait_cnt + 1;
if(wait_cnt == 12'hA00) begin
wait_cnt <= 12'd0;
wait_finished <= 1'b1;
end
else if(wait_cnt == 12'd0 && wait_finished) begin//發送完成
finish <= 1;
busy <= 0;
end
end
end
default:;
endcase
- 上述是發送過程的幾個狀態,同接收類似,每兩個狀態完成一次發送
- 第一個狀態是發送數據,當 Busy_Tx 為 0,即發送器空閑時,傳入發送數據,並產生 Wrsig 高電平啟動信號
設置 wait_cnt 的原因是兩次發送最好有一個碼元的間隔(具體原因我也不知道QWQ,我助教說的)
當傳輸發送數據后,wait_cnt 和 wait_finished 都置 0,開始計數,並跳轉到下一個狀態 - 第二個狀態等待將 Wrsig 置回 0,完成一次啟動信號的發生;當傳輸完畢,發送器變回空閑狀態(Busy_Tx=0)時,開始計數
計數完畢后,跳轉至下一個狀態 - 最后一個狀態結束后不再跳轉,將 finish 置成 1,busy 置成 0,其他保持不變
通過上述兩個循環,完成對數據的接收與發送
(五) ISE綜合
- 綜合過程中可能會出現如下 warning,這是由於我們使用了 Uart_CLK 代替了系統時鍾,會產生警告(可忽略)
Route:455 - CLK Net:Uart_Send_Top/module_ClkDiv/Uart_CLK may have excessive skew
- 選用的 FPGA 板子信息如下
- 引腳定義如下
(六) 完整代碼
1. 頂層模塊 uart_top.v 代碼
module uart_top(
input sys_clk,//系統時鍾
input sys_rst,//復位鍵
input signal_rx,//接收信號rx
input enable,//使能信號
output isEnable,//是否能夠運行
output Err,//錯誤信號
output busy,//忙碌信號
output finish,//完成信號
output signal_tx//tx發送信號
);
wire [63:0] data;
wire finish_receive;
/* uart接收 */
wire err_rx;
wire busy_rx;
Uart_Receive_Top Uart_Receive_Top(
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.signal_rx(signal_rx),
.enable(enable),
.data_input(data),
.Err(err_rx),
.busy(busy_rx),
.finish(finish_receive)
);
/* uart發送 */
wire err_tx;
wire busy_tx;
Uart_Send_Top Uart_Send_Top(
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.data_output(data),
.enable(finish_receive),
.signal_tx(signal_tx),
.Err(err_tx),
.finish(finish),
.busy(busy_tx)
);
assign busy = busy_rx | busy_tx ;
assign Err = err_rx | err_tx;
assign isEnable = enable;
endmodule
2. Uart循環接收模塊 Uart_Receive_Top.v 代碼
module Uart_Receive_Top(
input sys_clk,//系統時鍾
input sys_rst,//系統復位鍵
input signal_rx,//接收信號rx
input enable,//使能信號
output reg[63:0] data_input,//加解密文輸入
output reg Err,//報錯,高電平出錯
output reg finish,//接收完成信號
output reg busy//高電平忙碌
);
/* uart時鍾信號產生 */
wire uart_clk;
Uart_ClkDiv module_ClkDiv(
.Sys_CLK(sys_clk),
.Uart_CLK(uart_clk)
);
/* 接收模塊 */
wire[7:0] data_rx;//接收數據緩存
wire Rdsig;//讀使能,高電平時可以從8位緩存中讀取數據
wire DataError;//數據錯誤信號,高電平時出錯
wire FrameError;//幀錯誤信號,高電平時出錯
Uart_Rx module_Rx(
.Uart_CLK(uart_clk),
.RST(sys_rst),
.Signal_Rx(signal_rx),
.Data_Rx(data_rx),
.Rdsig(Rdsig),
.DataError_Flag(DataError),
.FrameError_Flag(FrameError)
);
/* 狀態機 */
reg [3:0] state;
always@(posedge sys_clk or negedge sys_rst) begin
if(~sys_rst) begin
Err <= 0;
finish <= 0;
busy <= 0;
data_input <= 64'b0;
state <= 4'b0;
end
else if(~enable) begin
Err <= 0;
finish <= 0;
busy <= 0;
data_input <= 64'b0;
state <= 4'b0;
end
else begin
case(state)
//讀取64bit 的data_input
4'd00 : begin
if(Rdsig && !DataError && !FrameError)begin
data_input[64-0*8-1:64-(0+1)*8] <= data_rx;
busy <= 1'b1;
state <= state + 1; end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
4'd01 : begin
if(!Rdsig)state <= state + 1;
end
4'd02 : begin
if(Rdsig && !DataError && !FrameError)begin
data_input[64-1*8-1:64-(1+1)*8] <= data_rx;
busy <= 1'b1;
state <= state + 1; end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
4'd03 : begin
if(!Rdsig)state <= state + 1;
end
4'd04 : begin
if(Rdsig && !DataError && !FrameError)begin
data_input[64-2*8-1:64-(2+1)*8] <= data_rx;
busy <= 1'b1;
state <= state + 1; end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
4'd05 : begin
if(!Rdsig)state <= state + 1;
end
4'd06 : begin
if(Rdsig && !DataError && !FrameError)begin
data_input[64-3*8-1:64-(3+1)*8] <= data_rx;
busy <= 1'b1;
state <= state + 1; end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
4'd07 : begin
if(!Rdsig)state <= state + 1;
end
4'd08 : begin
if(Rdsig && !DataError && !FrameError)begin
data_input[64-4*8-1:64-(4+1)*8] <= data_rx;
busy <= 1'b1;
state <= state + 1; end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
4'd09 : begin
if(!Rdsig)state <= state + 1;
end
4'd10 : begin
if(Rdsig && !DataError && !FrameError)begin
data_input[64-5*8-1:64-(5+1)*8] <= data_rx;
busy <= 1'b1;
state <= state + 1; end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
4'd11 : begin
if(!Rdsig)state <= state + 1;
end
4'd12 : begin
if(Rdsig && !DataError && !FrameError)begin
data_input[64-6*8-1:64-(6+1)*8] <= data_rx;
busy <= 1'b1;
state <= state + 1; end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
4'd13 : begin
if(!Rdsig)state <= state + 1;
end
4'd14 : begin
if(Rdsig && !DataError && !FrameError)begin
data_input[64-7*8-1:64-(7+1)*8] <= data_rx;
finish <= 1;
busy <= 0;
state <= state;
end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
//報錯
4'b1111:Err<=1;
default:;
endcase
end
end
endmodule
3. Uart循環發送模塊 Uart_Send_Top.v 代碼
module Uart_Send_Top(
input sys_clk,//系統時鍾50MHz
input sys_rst,//重置鍵rst
input [63:0] data_output,//待發送數據
input enable,//發送使能,1為可以發送
output wire signal_tx,//uart發送信號tx
output reg Err,//報錯,高電平出錯
output reg finish,//完成信號
output reg busy//高電平時表示忙碌
);
/* uart時鍾信號產生 */
wire uart_clk;
Uart_ClkDiv module_ClkDiv(
.Sys_CLK(sys_clk),
.Uart_CLK(uart_clk)
);
/* 發送模塊 */
reg [7:0] Data_Tx;//待發送8位數據
reg Wrsig;//寫使能,上升沿有效
wire Busy_Tx;//1時忙碌,0時空閑
Uart_Tx module_Tx(
.Uart_CLK(uart_clk),
.RST(sys_rst),
.Data_Tx(Data_Tx),
.Wrsig(Wrsig),
.Idle(Busy_Tx),
.Signal_Tx(signal_tx)
);
/* 狀態機 */
reg [3:0] state;
reg[11:0] wait_cnt;//等待時使用的計數器
reg wait_finished;//1表示完成等待
always@(posedge sys_clk or negedge sys_rst) begin
if(~sys_rst) begin
Err <= 0;
finish <= 0;
busy <= 0;
state <= 4'b0;
wait_cnt <= 12'b0;
wait_finished <= 0;
Data_Tx <= 8'b0;
Wrsig <= 0;
end
else if(~enable) begin
Err <= 0;
finish <= 0;
busy <= 0;
state <= 4'b0;
wait_cnt <= 12'b0;
wait_finished <= 0;
Data_Tx <= 8'b0;
Wrsig <= 0;
end
else begin
case(state)
4'd00 : begin
busy <= 1;
if(!Busy_Tx) begin
Data_Tx <= data_output[64-0*8-1:64-(0+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_cnt <= 12'd0;
wait_finished <= 1'b0;
end
end
4'd01 : begin
if(Busy_Tx) begin
Wrsig <= 0;
end
else begin
wait_cnt <= wait_cnt + 1;
if(wait_cnt == 12'hA00) begin
wait_cnt <= 12'd0;
wait_finished <= 1'b1;
end
else if(wait_cnt == 12'd0 && wait_finished) state <= state + 1;
end
end
4'd02 : begin
if(!Busy_Tx) begin
Data_Tx <= data_output[64-1*8-1:64-(1+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_cnt <= 12'd0;
wait_finished <= 1'b0;
end
end
4'd03 : begin
if(Busy_Tx) begin
Wrsig <= 0;
end
else begin
wait_cnt <= wait_cnt + 1;
if(wait_cnt == 12'hA00) begin
wait_cnt <= 12'd0;
wait_finished <= 1'b1;
end
else if(wait_cnt == 12'd0 && wait_finished) state <= state + 1;
end
end
4'd04 : begin
if(!Busy_Tx) begin
Data_Tx <= data_output[64-2*8-1:64-(2+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_cnt <= 12'd0;
wait_finished <= 1'b0;
end
end
4'd05 : begin
if(Busy_Tx) begin
Wrsig <= 0;
end
else begin
wait_cnt <= wait_cnt + 1;
if(wait_cnt == 12'hA00) begin
wait_cnt <= 12'd0;
wait_finished <= 1'b1;
end
else if(wait_cnt == 12'd0 && wait_finished) state <= state + 1;
end
end
4'd06 : begin
if(!Busy_Tx) begin
Data_Tx <= data_output[64-3*8-1:64-(3+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_cnt <= 12'd0;
wait_finished <= 1'b0;
end
end
4'd07 : begin
if(Busy_Tx) begin
Wrsig <= 0;
end
else begin
wait_cnt <= wait_cnt + 1;
if(wait_cnt == 12'hA00) begin
wait_cnt <= 12'd0;
wait_finished <= 1'b1;
end
else if(wait_cnt == 12'd0 && wait_finished) state <= state + 1;
end
end
4'd08 : begin
if(!Busy_Tx) begin
Data_Tx <= data_output[64-4*8-1:64-(4+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_cnt <= 12'd0;
wait_finished <= 1'b0;
end
end
4'd09 : begin
if(Busy_Tx) begin
Wrsig <= 0;
end
else begin
wait_cnt <= wait_cnt + 1;
if(wait_cnt == 12'hA00) begin
wait_cnt <= 12'd0;
wait_finished <= 1'b1;
end
else if(wait_cnt == 12'd0 && wait_finished) state <= state + 1;
end
end
4'd10 : begin
if(!Busy_Tx) begin
Data_Tx <= data_output[64-5*8-1:64-(5+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_cnt <= 12'd0;
wait_finished <= 1'b0;
end
end
4'd11 : begin
if(Busy_Tx) begin
Wrsig <= 0;
end
else begin
wait_cnt <= wait_cnt + 1;
if(wait_cnt == 12'hA00) begin
wait_cnt <= 12'd0;
wait_finished <= 1'b1;
end
else if(wait_cnt == 12'd0 && wait_finished) state <= state + 1;
end
end
4'd12 : begin
if(!Busy_Tx) begin
Data_Tx <= data_output[64-6*8-1:64-(6+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_cnt <= 12'd0;
wait_finished <= 1'b0;
end
end
4'd13 : begin
if(Busy_Tx) begin
Wrsig <= 0;
end
else begin
wait_cnt <= wait_cnt + 1;
if(wait_cnt == 12'hA00) begin
wait_cnt <= 12'd0;
wait_finished <= 1'b1;
end
else if(wait_cnt == 12'd0 && wait_finished) state <= state + 1;
end
end
4'd14 : begin
if(!Busy_Tx) begin
Data_Tx <= data_output[64-7*8-1:64-(7+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_cnt <= 12'd0;
wait_finished <= 1'b0;
end
end
4'd15 : begin
if(Busy_Tx) begin
Wrsig <= 0;
end
else begin
wait_cnt <= wait_cnt + 1;
if(wait_cnt == 12'hA00) begin
wait_cnt <= 12'd0;
wait_finished <= 1'b1;
end
else if(wait_cnt == 12'd0 && wait_finished) begin//發送完成
finish <= 1;
busy <= 0;
end
end
end
default:;
endcase
end
end
endmodule
4. Uart 時鍾生成模塊 Uart_ClkDiv.v 代碼
/* Uart時鍾信號 */
module Uart_ClkDiv(
input Sys_CLK, //50Mhz系統時鍾
output reg Uart_CLK //9600bps
);
reg [7:0]Uart_CLK_Cnt;
initial
begin
Uart_CLK <= 1'b0;
Uart_CLK_Cnt <= 8'd0;
end
always@(posedge Sys_CLK)
begin
if(Uart_CLK_Cnt <= 8'd160)
Uart_CLK_Cnt = Uart_CLK_Cnt + 1;
else
begin
Uart_CLK = ~Uart_CLK;
Uart_CLK_Cnt = 8'd0;
end
end
endmodule
5. Uart發送模塊 Uart_Tx.v 代碼
/* Uart_Tx發送數據 */
module Uart_Tx(
input Uart_CLK,
input RST,
input [7:0] Data_Tx,//8位待發送數據
input Wrsig,
output reg Idle,//空閑狀態,0表示空閑,1表示忙碌
output reg Signal_Tx//並轉串,1位輸出
);
//16個時鍾周期發送1bit數據
reg Send;
reg WrsigBuf;
reg WrsigRise;
reg Presult;
reg [7:0]Tx_Cnt;
parameter paritymode = 1'b0;
always@(posedge Uart_CLK) //檢測寫入信號的上升沿
begin
WrsigBuf <= Wrsig;
WrsigRise <= (~WrsigBuf) & Wrsig;
end
always@(posedge Uart_CLK)
begin
if(WrsigRise && (~Idle)) //當發送命令有效且線路為空閑時,啟動新的數據發送進程
Send <= 1'b1; //正在發送
else if(Tx_Cnt == 8'd168) //除非一幀資料發送結束,否則Send信號保持高電平
Send <= 1'b0; //正在空閑
end
always@(posedge Uart_CLK or negedge RST)
begin
if(!RST)Signal_Tx<=1'b1;
else begin
if(Send == 1'b1)
begin
case(Tx_Cnt) //產生起始位
8'd0:
begin
Signal_Tx <= 1'b0;
Idle <= 1'b1;
Tx_Cnt <= Tx_Cnt + 8'd1;
end
8'd16:
begin
Signal_Tx <= Data_Tx[0]; //發送數據0位
Presult <= Data_Tx[0]^paritymode;
Idle <= 1'b1;
Tx_Cnt <= Tx_Cnt + 8'd1;
end
8'd32:
begin
Signal_Tx <= Data_Tx[1]; //發送數據1位
Presult <= Data_Tx[1]^Presult;
Idle <= 1'b1;
Tx_Cnt <= Tx_Cnt + 8'd1;
end
8'd48:
begin
Signal_Tx <= Data_Tx[2]; //發送數據2位
Presult <= Data_Tx[2]^Presult;
Idle <= 1'b1;
Tx_Cnt <= Tx_Cnt + 8'd1;
end
8'd64:
begin
Signal_Tx <= Data_Tx[3]; //發送數據3位
Presult <= Data_Tx[3]^Presult;
Idle <= 1'b1;
Tx_Cnt <= Tx_Cnt + 8'd1;
end
8'd80:
begin
Signal_Tx <= Data_Tx[4]; //發送數據4位
Presult <= Data_Tx[4]^Presult;
Idle <= 1'b1;
Tx_Cnt <= Tx_Cnt + 8'd1;
end
8'd96:
begin
Signal_Tx <= Data_Tx[5]; //發送數據5位
Presult <= Data_Tx[5]^Presult;
Idle <= 1'b1;
Tx_Cnt <= Tx_Cnt + 8'd1;
end
8'd112:
begin
Signal_Tx <= Data_Tx[6]; //發送數據6位
Presult <= Data_Tx[6]^Presult;
Idle <= 1'b1;
Tx_Cnt <= Tx_Cnt + 8'd1;
end
8'd128:
begin
Signal_Tx <= Data_Tx[7]; //發送數據7位
Presult <= Data_Tx[7]^Presult;
Idle <= 1'b1;
Tx_Cnt <= Tx_Cnt + 8'd1;
end
8'd144:
begin
Signal_Tx <= Presult; //發送奇偶校驗位
Presult <= Data_Tx[0]^paritymode;
Idle <= 1'b1;
Tx_Cnt <= Tx_Cnt + 8'd1;
end
8'd160:
begin
Signal_Tx <= 1'b1; //發送停止位
Idle <= 1'b1;
Tx_Cnt <= Tx_Cnt + 8'd1;
end
8'd168:
begin
Signal_Tx <= 1'b1;
Idle <= 1'b0; //一幀資料發送結束
Tx_Cnt <= Tx_Cnt + 8'd1;
end
default:
Tx_Cnt <= Tx_Cnt + 8'd1;
endcase
end
else
begin
Signal_Tx <= 1'b1;
Tx_Cnt <= 8'd0;
Idle <= 1'b0;
end
end
end
endmodule
6. Uart接收模塊 Uart_Rx.v 代碼
/* Uart_Rx 用於接收數據 */
module Uart_Rx(
input Uart_CLK,//采樣時鍾
input RST,//復位信號
input Signal_Rx,//UART數據輸入
output reg [7:0] Data_Rx,//接收數據輸出
output reg Rdsig,//置1時表示上層模塊已經可以讀8位數據了
output reg DataError_Flag,//數據出錯指示
output reg FrameError_Flag//幀出錯指示
);
reg [7:0]cnt;
reg RxBuf;
reg RxFall;
reg Recieve;
reg Presult;
reg Idle;
parameter paritymode = 1'b0;
always@(posedge Uart_CLK) //檢測線路的下降沿
begin
RxBuf <= Signal_Rx;
RxFall <= RxBuf & (~Signal_Rx);
end
////////////////////////////////////////////////////////////////
//啟動串口接收程序
////////////////////////////////////////////////////////////////
always@(posedge Uart_CLK)
begin
if (RxFall && (~Idle)) //檢測到線路的下降沿並且原先線路為空閑,啟動接收數據進程
Recieve <= 1'b1; //正在接收
else if(cnt == 8'd170) //除非接收數據完成,否則接收狀態保持
Recieve <= 1'b0;
end
////////////////////////////////////////////////////////////////
//串口接收程序, 16個時鍾接收一個bit
////////////////////////////////////////////////////////////////
always@(posedge Uart_CLK or negedge RST)
begin
if (!RST)
begin
Idle<=1'b0;
cnt<=8'd0;
Rdsig <= 1'b0;
FrameError_Flag <= 1'b0;
DataError_Flag <= 1'b0;
Presult<=1'b0;
Data_Rx <= 8'b0;
end
else if(Recieve == 1'b1)
begin
case(cnt)
8'd0:begin
Idle <= 1'b1;
cnt <= cnt + 8'd1;
Rdsig <= 1'b0;
end
8'd24:begin //接收第0位數據
Idle <= 1'b1;
Data_Rx[0] <= Signal_Rx;
Presult <= paritymode^Signal_Rx;
cnt <= cnt + 8'd1;
Rdsig <= 1'b0;
end
8'd40:begin //接收第1位數據
Idle <= 1'b1;
Data_Rx[1] <= Signal_Rx;
Presult <= Presult^Signal_Rx;
cnt <= cnt + 8'd1;
Rdsig <= 1'b0;
end
8'd56:begin //接收第2位數據
Idle <= 1'b1;
Data_Rx[2] <= Signal_Rx;
Presult <= Presult^Signal_Rx;
cnt <= cnt + 8'd1;
Rdsig <= 1'b0;
end
8'd72:begin //接收第3位數據
Idle <= 1'b1;
Data_Rx[3] <= Signal_Rx;
Presult <= Presult^Signal_Rx;
cnt <= cnt + 8'd1;
Rdsig <= 1'b0;
end
8'd88:begin //接收第4位數據
Idle <= 1'b1;
Data_Rx[4] <= Signal_Rx;
Presult <= Presult^Signal_Rx;
cnt <= cnt + 8'd1;
Rdsig <= 1'b0;
end
8'd104:begin //接收第5位數據
Idle <= 1'b1;
Data_Rx[5] <= Signal_Rx;
Presult <= Presult^Signal_Rx;
cnt <= cnt + 8'd1;
Rdsig <= 1'b0;
end
8'd120:begin //接收第6位數據
Idle <= 1'b1;
Data_Rx[6] <= Signal_Rx;
Presult <= Presult^Signal_Rx;
cnt <= cnt + 8'd1;
Rdsig <= 1'b0;
end
8'd136:begin //接收第7位數據
Idle <= 1'b1;
Data_Rx[7] <= Signal_Rx;
Presult <= Presult^Signal_Rx;
cnt <= cnt + 8'd1;
Rdsig <= 1'b0;
end
8'd152:begin //接收奇偶校驗位
Idle <= 1'b1;
if(Presult == Signal_Rx)
DataError_Flag <= 1'b0;
else
DataError_Flag <= 1'b1; //如果奇偶校驗位不對,表示數據出錯
cnt <= cnt + 8'd1;
Rdsig <= 1'b0;
end
8'd168:begin
Idle <= 1'b1;
if(1'b1 == Signal_Rx)
FrameError_Flag <= 1'b0;
else
FrameError_Flag <= 1'b1; //如果沒有接收到停止位,表示幀出錯
cnt <= cnt + 8'd1;
Rdsig <= 1'b0;
end
8'd169:begin
Rdsig <= 1'b1;
cnt <= cnt + 8'd1;
end
default:
cnt <= cnt + 8'd1;
endcase
end
else
begin
cnt <= 8'd0;
Idle <= 1'b0;
Rdsig <= 1'b0;
end
end
endmodule