uart


 最近學習了解了一些常用的通信協議,整理了一下,分享出來。另外,歡迎各位關注個人公

眾號——FPGAer的自我修養,正在更新一些FPGA、Verilog相關的基礎知識,期待和同樣愛

好FPGA的你相遇。

 

1.UART

UART是異步串行通信口的總稱。它所包含的RS232\RS449\RS423等等是對應各種異步串行

通信口的接口標准和總線標准。他們規定了通信口的電氣特性、傳輸速率、連接特性和機械特

性等一系列內容,實際上屬於通信網絡的底層概念,與通信協議沒有直接關系。

幾個相關名詞的解釋:

·波特率:每秒鍾傳送的bit的個數。

·起始位:先發出一個邏輯0的信號,表示傳輸數據的開始。

·數據位:衡量通信中實際數據位的參數,標准數據位可以是5、7、8位,從最低位開始傳

輸。

·奇偶校驗位:UART發送時,檢查發送數據中“1”的個數,自動在奇偶校驗位添加1/0,

用於發送數據的校驗。

·停止位:一個數據的結束標志,可以為1位、1.5位、2位的高電平。

·空閑位:處於邏輯1狀態,表示當前線路上無數據傳輸。

·時序圖:

·發送數據過程:空閑狀態,線路處於高電平,當收到發送數據指令后,拉低電平一個數

據位的時間,接着數據按從低位到高位依次發送,數據發送完畢,接着發送奇偶校驗位和停止

位(停止位為高電平),一幀數據發送結束。

·接收數據過程:空閑狀態,線路處於高電平,當檢測到線路的下降沿,說明線路有數據

傳輸,按照約定的波特率從低位到高位接收數據,數據接收完畢,接着接收並比較奇偶校驗位

是否正確,如果正確則通知接收端設備准備接收數據或存入緩存。

由於UART是異步傳輸,沒有同步傳輸時鍾。為保證數據傳輸的正確性,每個數據有16個

時鍾采樣,取中間的采樣值,以保證不會誤碼或滑碼。

·設計實例:

下面是一個UART的回環實例代碼設計:

接收模塊uart_rx:

module uart_rx(
    input rxd,
    input clk,
    output receive_ack,
    output reg [7:0] data_i
    );
    
    parameter IDLE = 0;
    parameter RECEIVE = 1;
    parameter RECEIVE_END = 2;
    
    reg [3:0] CS,NS;
    reg [4:0] count;
    reg [7:0] data_o_tmp;
    
    always@(posedge clk)
        CS <= NS;
    
    always@(*) begin
        NS <= CS;
        case(CS)
            IDLE:       if(!rxd) NS = RECEIVE;
            RECEIVE:    if(count == 7) NS = RECEIVE_END;else NS = NS;
            RECEIVE_END:NS = IDLE;
            default:    NS = IDLE;
        endcase
    end
    
    always@(posedge clk)
        if(CS == RECEIVE)
            count <= count + 1;
        else if(CS == IDLE | CS == RECEIVE_END)
            count <= 0;
    
    always @(posedge clk)
        if(CS == RECEIVE)begin
            data_i[6:0] <= data_i[7:1];
            data_i[7] <= rxd;
        end
        
    assign receive_ack = (CS == RECEIVE_END) ? 1 : 0;
             
endmodule

發送模塊uart_tx:

module uart_tx(
    input [7:0] data_o,
    input       clk,
    input       receive_ack,
    output reg  txd
    );
    parameter IDLE          = 0;
    parameter SEND_START    = 1;
    parameter SEND_DATA     = 2;
    parameter SEND_END      = 3;
    
    reg [3:0] CS,NS;
    reg [4:0] count;
    reg [7:0] data_o_tmp;
    
    always @ (posedge clk)
        CS <= NS;
    
    always @ (*) begin
        NS <= CS;
        case(CS)
            IDLE:       begin if(receive_ack) NS = SEND_START;  end
            SEND_START: begin NS = SEND_DATA;                   end
            SEND_DATA:  begin if(count == 7) NS = SEND_END;     end
            SEND_END:   begin if(receive_ack) NS = SEND_START;  end
            default:    NS = IDLE;
        endcase
    end
    
    always @(posedge clk)
        if(CS == SEND_START)
            count <= count + 1;
        else if(CS == IDLE | CS == SEND_END)
            count <= 0;
        else
            count <= count;
    
    always @(posedge clk)
        if(CS == SEND_START)
            data_o_tmp <= data_o;
        else if(CS == SEND_DATA)
            data_o_tmp[6:0] <= data_o_tmp[7:1];
    
    always @(posedge clk)
        if(CS == SEND_START)
            txd <= 0;
        else if(CS == SEND_DATA)
            txd <= data_o_tmp;
        else if(CS == SEND_END)
            txd <= 1;        
    
endmodule

特定波特率產生模塊clk_div:

module clk_div(
    input clk,
    output reg clk_out
    );
​
    parameter baud_rata = 9600;
    parameter div_num = 'd125_000_000 /baud_rata;  //分頻數等於時鍾頻率除以想要得到的波特率
    reg [15:0] num;
​
    always @(posedge clk) begin
        if(num == div_num) begin
            num <= 0;
            clk_out <= 1;
        end
        else begin
            num <= num + 1;
            clk_out <= 0;
        end
    end
​
endmodule

頂層文件uart_top:

module uart_top(
    input clk,
    input rxd,
    output txd
    );
​
    wire clk_9600;
    wire receive_ack;
    wire [7:0] data;
​
    uart_tx uart_tx
    (
        .clk        (clk_9600),
        .txd        (txd),
        .data_o     (data),
        .receive_ack(receive_ack)
    );
​
    uart_rx uart_rx
    (
        .clk        (clk_9600),
        .rxd        (rxd),
        .data_i     (data),
        .receive_ack(receive_ack)
    );
​
    clk_div clk_div
    (
        .clk        (clk),
        .clk_out    (clk_9600)
    );
​
endmodule

 

2.PS/2

PS/2是一種雙向同步串行通信協議。接口是一種6針的連接口,但只有四個引腳是有意義

的,分別是Clock(時鍾)、Data(數據)、VCC和GND。其中時鍾和數據引腳是雙向的。PS/2常

用於連接某些輸入設備,例如鼠標、鍵盤等。通信的兩端通過時鍾來同步,通過數據引腳來交

換數據。任何一方想要抑制另外一方的通信,只需要將時鍾引腳拉低即可。

如果是PC和PS/2鍵盤之間通信,PC必須做主機,即PC可以抑制鍵盤發送數據,而鍵盤不能

抑制PC發送數據。

PS/2的每一位數據幀包含11-12位,具體含義如下:

數據位名稱 說明
1個起始位 總是邏輯0
8個數據位 低位在前
1個奇偶校驗位 奇校驗
1個停止位 總是邏輯1
1個應答位 僅用在主機對設備的通信中

·PS/2的時序圖:

由設備產生時鍾和數據,主機根據時鍾來讀取數據。以FPGA和PS/2鍵盤為例,鍵盤產生時

鍾和數據,FPGA只需要讀數據。當時鍾下降沿時,FPGA記錄數據信號。

·設計實例:

主機為FPGA,根據PS/2的時序,得到鍵盤的按鍵值。雖然在時序圖中,主機是在時鍾下降

沿讀取數據,但實際上要為了排除噪聲干擾,需要在FPGA端對信號進行濾波。下面給出設計

代碼。

module ps2_keyboard(
    input clk,
    input clr,
    input PS2C,       //ps2 clk in
    input PS2D,       //ps2 data in
    
    output [15:0] xkey
);
reg         PS2CF;
reg         PS2DF;
reg [7:0]   ps2c_filter;
reg [7:0]   ps2d_filter;
reg [10:0]  shift1;
reg [10:0]  shift2;
​
assign xkey = { shift2[8:1], shift1[8:1] };
always @(posedge clk or posedge clr) begin
    if (clr) begin
        ps2c_filter <= 11'b0;
        ps2d_filter <= 11'b0;
        PS2CF <= 1;
        PS2DF <= 1;
    end
    else begin
        ps2c_filter[7] <= PS2C;
        ps2c_filter[6:0] <= ps2c_filter[7:1];
        ps2d_filter[7] <= PS2D;
        ps2d_filter[6:0] <= ps2d_filter[7:1];
        if(ps2c_filter == 8'b1111_1111)
            PS2CF <= 1;                         //去時鍾毛刺
        else if(ps2c_filter == 8'b0000_0000)
            PS2CF <= 0;
        if(ps2d_filter == 8'b1111_1111)
            PS2DF <= 1;                         //去數據毛刺
        else if(ps2d_filter == 8'b0000_0000)
            PS2DF <= 0;
    end
end
​
always @(negedge PS2CF or posedge clr) begin
    if (clr) begin
        shift1 <= 11'b0;
        shift2 <= 11'b0;
    end
    else begin
        shift1 <= {PS2DF, shift1[10:1]};
        shift2 <= {shift1[0], shift2[10:1]}; 
    end
end
​
endmodule

參考文獻:

[1]湯勇明,張聖清,陸佳華.搭建你的數字積木-數字電路與邏輯設計[M].北京:清華大學出版

社,2017.

 


免責聲明!

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



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