學習筆記:FPGA之多終端點歌系統設計一:UART通信協議

一,UART是什麼?

來自百度百科:https://baike.baidu.com/item/UART/4429746

二,UART通信協議

(1)UART傳輸速度    

    UART作爲異步串行通信接口,也就是說,它的數據傳輸不需要時鐘,只要兩條信號線分別進行數據收發。收發雙方只需要約定好數據傳輸的速度和幀格式,就能保證數據收發的準確性。簡單的講就是約定好一個數據位傳輸的時間和一個數據的長短。

    UART的數據傳輸速度是用波特率來描述的,即每秒鐘傳輸的數據位,例如1000波特率表示每秒鐘傳輸1000比特的數據,或者說每個數據位持續1毫秒。波特率不是隨意的,必須服從一定的標準,如果希望設計123456波特率的RS-232接口,是不行的。常用的串行傳輸速率值包括以下幾種:1200bps,9600bps,38400bps,115200bps等、在115200bps下,每位數據持續(1/114200)=8.68us.如果傳輸8位數據,共持續8*8.68us=69.44us。但是每個字節的傳輸又要求額外的“開始位”和“停止位”,所以實際上需要10*8.68us=86.8us的時間。因此最大的有效數據傳輸率只有達到11.5KBytes每秒。

(2)UART的幀格式

 通過該圖,我們可以看出, 它是由1個起始位(必須爲0),8個數據位(用戶數據),1個奇偶校驗位(用於簡單地糾錯保證傳輸可靠性)和1或2個停止位(必須爲1)組成。除了奇偶校驗位,其他3個部分都是必須的。通過這個UART幀格式圖我們可以知道,UART的通信是十分簡單的,它是以低電平作爲起始位,高電平作爲停止位,中間可傳輸5~8比特數據和1比特奇偶校驗位,奇偶校驗位的有無和數據比特的長度由通信雙方約定。發送端發送數據時先發一低電平,然後發送8比特數據,之後馬上把信號拉高,從而完成一幀數據傳送。接收端收到低電平開始計數,然後接受8比特信息位後如果檢測到高電平即認爲已接受完一幀數據,繼續等待下一幀起始信號低電平的到來,若接受完8比特數據後沒有檢測到高電平則認爲這不是一幀有效數據,將其丟棄,繼續等待起始信號。收發可同時進行,互不干擾。一幀數據傳輸完畢後可以繼續傳輸下一幀數據,也可以繼續保持爲高電平。兩幀之間保持高電平,持續時間可以任意長。

(3)UART協議使用。

發送0-9這十個數字來控制蜂鳴器的發聲。

1,功能模塊圖

(2)verilog代碼:

//波特率產生採樣信號模塊
module Uart_Bps_Module
(
    //輸入端口
    CLK_50M,RST_N,bps_start,
    //輸出端口
    bps_flag
);


input    CLK_50M;
input    RST_N;
input    bps_start;    //接受和發送端口的波特率時鐘啓動信號    
output   bps_flag;    //接受數據位的中間採樣點,發送數據的數據改變點


reg    [12:0]    time_cnt;
reg    [12:0]    time_cnt_n;
reg    bps_flag;
reg    bps_flag_n;

//波特率爲115200,一位週期爲1/115200=8.69us,8.68/(1/50)=434
parameter    BPS_PARA=9'd434;
parameter    BPS_PARA_2=8'd217;//中間採樣

always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        time_cnt<=13'b0;
    else
        time_cnt<=time_cnt_n;
end

always @ (*)
begin
    if((time_cnt==BPS_PARA)||(!bps_start))
        time_cnt_n=1'b0;
    else
        time_cnt_n=time_cnt+1'b1;
end

alwways @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        bps_flag<=1'b0;
    else
        bps_flag<=bps_flag_n;
end

always @ (*)
begin
    if(time_cnt==BPS_PARA_2)
        bps_flag_n=1'b1;//採樣標誌
    else
        bps_flag_n=1'b0;
end
endmodule

//UART解析模塊
module Uart_Rx_Module
(
    //input
    CLK_50M,RST_N,UART_RX,rx_bps_flag,
    //output
    out_rx_data,rx_bps_start
);



input    CLK_50M;
input    RST_N;
input    UART_RX;//FPGA的接受端口,串口cp2102的發送端口
input    rx_bps_flag;
output    rx_bps_start; //接受端口的波特率時鐘啓動信號
output    [7:0]    out_rx_data;//解析完成的數據



reg    [1:0]    detect_edge;//下降沿
wire    [1:0]    detect_edge_n;
reg    negedge_reg;//下降沿標誌
wire    negedge_reg_n;
reg    rx_bps_start;
reg    rx_bps_start_n;
reg    [3:0]    bit_cnt;//記錄接受數據位
reg    [3:0]    bit_cnt_n;
reg    [7:0]    shift_data;//接受串行數據流中用到的移位寄存器
reg    [7:0]    shift_data_n;
reg    [7:0]    out_rx_data;//從UART_RX數據線中解析完後的數據
reg    [7:0]    out_rx_data_n;



always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        detect_edge<=2'b11;
    else
        detect_edge<=detect_edge_n;
end
//接受uart_rx信號
assign detect_edge_n={detect_edge[0],UART_RX};



always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        negedge_reg<=1'b0;
    else
        negedge_reg<=negedge_reg_n;
end

//判斷下降沿
assign negedge_reg_n=(detect_edge==2'b10)?1'b1:1'b0;

always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        rx_bps_start<=1'b0;
    else
        rx_bps_start<=rx_bps_start_n;
end

//下降沿到來,就啓動波特率計數器
always @(*)
begin
    if(negedge_reg)
        rx_bps_start_n=1'b1;
    else if(bit_cnt==4'd9)
        rx_bps_start_n=1'b0;
    else
        rx_bps_start_n=rx_bps_start;
end

always @(posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        bit_cnt<=4'b0;
    else
        bit_cnt<=bit_cnt_n;
end

//判斷是否中間採樣點採樣
always @(*)
begin
    if(rx_bos_flag)
        bit_cnt_n=bit_cnt+1'b1;
    else if(bit_cnt==4'd9)
        bit_cnt_n=1'b0;
    else
        bit_cnt_n=bit_cnt;
end

always @(posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        shift_data<=8'b0;
    else
        shift_data<=shift_data_n;
end

//中間點採樣,每採樣一個便開始啓動移位寄存器記錄數據
always @(*)
begin
    if(rx_bps_flag)
        shift_data_n={UART_RX,shift_data[7:1]};
    else
        shift_data_n=shift_data;
end

always @(posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        out_rx_data<=8'b0;
    else
        out_rx_data<=out_rx_data_n;
end

//數據是否接受完成
always @(*)
begin
    if(bit_cnt==4'd9)
        out_rx_data_n=shift_data;
    else
        out_rx_data_n=out_rx_data;
end


endmodule


//蜂鳴器模塊
module Bepp_Module
(
    //input
    CLK_50M,RST_N,KEY,
    //output
    BEEP
);


input     CKL_50M;
input     RST_N;
intput    [7:0]    KEY;
output    BEEP;




reg    [15:0]    time_cnt;
reg    [15:0]    time_cnt_n;
reg    [15:0]    freq;
reg    [15:0]    freq_n;
reg    beep_reg;
reg    beep_reg_n;



always @(posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        time_cnt<=16'b0;
     else
        time_cnt<=time_cnt_n;
end

always @(*)
begin
    if(time_cnt==freq)
        time_cnt_n=16'b0;
    else
        time_cnt_n=time_cnt+1'b1;
end

always @(posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        beep_reg<=1'b0;
    else
        beep_reg<=beep_reg_n;
end

always @(*)
begin
    if(time_cnt==freq)
        beep_reg_n=~beep_reg;
    else
        beep_reg_n=beep_reg;
end

always @(posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        freq<=16'b0;
    else
        freq<=freq_n;
end

always @(*)
begin
    case(KEY)
        8'h30:freq_n=16'd0;
        8'h31:freq_n=16'd47774;
        8'h32:freq_n=16'd42568;
        8'h33:freq_n=16'd37919;
        8'h34:freq_n=16'd35791;
        8'h35:freq_n=16'd31888;
        8'h36:freq_n=16'd28409;
        8'h37:freq_n=16'd25309;
        8'h38:freq_n=16'd23889;
        8'h39:freq_n=16'd21276;
    default:feq_n=freq;
endcase
end

assign BEEP=beep_reg;

endmodule




 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章