使用UART實現FPGA板與PC通信


(一) 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM