基于STEP FPGA的UART串口通信模塊驅(qū)動
硬件說明
通用異步收發(fā)傳輸器(Universal Asynchronous Receiver/Transmitter),通常稱作UART,是一種通用串行數(shù)據(jù)總線,用于異步通信。該總線雙向通信,可以實現(xiàn)全雙工傳輸和接收。
異步通信以一個字符為傳輸單位,通信中兩個字符間的時間間隔多少是不固定的,然而在同一個字符中的兩個相鄰位間的時間間隔是固定的。兩個相鄰位間的時間間隔與UART通信的波特率有關(guān),波特率用來表征UART通信中數(shù)據(jù)傳輸?shù)乃俾?,即每秒鐘傳送的二進(jìn)制位數(shù)。例如數(shù)據(jù)傳送速率為120字符/秒,而每一個字符為10位(1個起始位,7個數(shù)據(jù)位,1個校驗位,1個結(jié)束位),則其傳送的波特率為10×120=1200字符/秒=1200波特。
我們這里使用的時序為去掉校驗位的時序
本設(shè)計共有四個模塊,一個top模塊,一個baud模塊,一個接收模塊和一個發(fā)送模塊,大家可以根據(jù)自己的需求進(jìn)行調(diào)整。
Verilog代碼
// -------------------------------------------------------------------- // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< // -------------------------------------------------------------------- // Module: Uart_bus // // Author: Step // // Description: The module for uart communication // // // -------------------------------------------------------------------- // Code Revision History : // -------------------------------------------------------------------- // Version: |Mod. Date: |Changes Made: // V1.0 |2016/04/20 |Initial ver // -------------------------------------------------------------------- module Uart_Bus # ( parameter BPS_PARA = 1250 //當(dāng)使用12MHz時鐘時波特率參數(shù)選擇1250對應(yīng)9600的波特率 ) ( input clk_in, //系統(tǒng)時鐘 input rst_n_in, //系統(tǒng)復(fù)位,低有效 input rs232_rx, //FPGA中UART接收端,分配給UART模塊中的發(fā)送端TXD output rs232_tx //FPGA中UART發(fā)送端,分配給UART模塊中的接收端RXD ); /////////////////////////////////UART接收功能模塊例化//////////////////////////////////// wire bps_en_rx,bps_clk_rx; wire [7:0] rx_data; //UART接收波特率時鐘控制模塊 例化 Baud # ( .BPS_PARA (BPS_PARA ) ) Baud_rx ( .clk_in (clk_in ), //系統(tǒng)時鐘 .rst_n_in (rst_n_in ), //系統(tǒng)復(fù)位,低有效 .bps_en (bps_en_rx ), //接收時鐘使能 .bps_clk (bps_clk_rx ) //接收時鐘輸出 ); //UART接收數(shù)據(jù)模塊 例化 Uart_Rx Uart_Rx_uut ( .clk_in (clk_in ), //系統(tǒng)時鐘 .rst_n_in (rst_n_in ), //系統(tǒng)復(fù)位,低有效 .bps_en (bps_en_rx ), //接收時鐘使能 .bps_clk (bps_clk_rx ), //接收時鐘輸入 .rs232_rx (rs232_rx ), //UART接收輸入 .rx_data (rx_data ) //接收到的數(shù)據(jù) ); /////////////////////////////////UART發(fā)送功能模塊例化//////////////////////////////////// wire bps_en_tx,bps_clk_tx; //UART發(fā)送波特率時鐘控制模塊 例化 Baud # ( .BPS_PARA (BPS_PARA ) ) Baud_tx ( .clk_in (clk_in ), //系統(tǒng)時鐘 .rst_n_in (rst_n_in ), //系統(tǒng)復(fù)位,低有效 .bps_en (bps_en_tx ), //發(fā)送時鐘使能 .bps_clk (bps_clk_tx ) //發(fā)送時鐘輸出 ); //UART發(fā)送數(shù)據(jù)模塊 例化 Uart_Tx Uart_Tx_uut(.clk_in (clk_in ), //系統(tǒng)時鐘 .rst_n_in (rst_n_in ), //系統(tǒng)復(fù)位,低有效 .bps_en (bps_en_tx ), //發(fā)送時鐘使能 .bps_clk (bps_clk_tx ), //發(fā)送時鐘輸入 .rx_bps_en (bps_en_rx ), //因需要自收自發(fā),使用接收時鐘使能判定:接收到新的數(shù)據(jù),需要發(fā)送 .tx_data (rx_data ), //需要發(fā)出的數(shù)據(jù) .rs232_tx (rs232_tx ) //UART發(fā)送輸出 ); endmodule
// -------------------------------------------------------------------- // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< // -------------------------------------------------------------------- // Module: Baud // // Author: Step // // Description: Beat for uart transfer and receive baud rate // // -------------------------------------------------------------------- // Code Revision History : // -------------------------------------------------------------------- // Version: |Mod. Date: |Changes Made: // V1.0 |2016/04/20 |Initial ver // -------------------------------------------------------------------- module Baud # ( parameter BPS_PARA = 1250 //當(dāng)使用12MHz時鐘時波特率參數(shù)選擇1250對應(yīng)9600的波特率 ) ( input clk_in, //系統(tǒng)時鐘 input rst_n_in, //系統(tǒng)復(fù)位,低有效 input bps_en, //接收或發(fā)送時鐘使能 output reg bps_clk //接收或發(fā)送時鐘輸出 ); reg [12:0] cnt;//計數(shù)器計數(shù)滿足波特率時鐘要求 always @ (posedge clk_in or negedge rst_n_in) begin if(!rst_n_in) cnt <= 1'b0; else if((cnt >= BPS_PARA-1)||(!bps_en)) //當(dāng)時鐘信號不使能(bps_en為低電平)時,計數(shù)器清零并停止計數(shù) cnt <= 1'b0; //當(dāng)時鐘信號使能時,計數(shù)器對系統(tǒng)時鐘計數(shù),周期為BPS_PARA個系統(tǒng)時鐘周期 else cnt <= cnt + 1'b1;end //產(chǎn)生相應(yīng)波特率的時鐘節(jié)拍,接收模塊將以此節(jié)拍進(jìn)行UART數(shù)據(jù)接收 always @ (posedge clk_in or negedge rst_n_in) begin if(!rst_n_in) bps_clk <= 1'b0; else if(cnt == (BPS_PARA>>1)) //BPS_PARA右移一位等于除2,因計數(shù)器終值BPS_PARA為數(shù)據(jù)更替時間點,所以計數(shù)器中值時為數(shù)據(jù)最穩(wěn)定時間點 bps_clk <= 1'b1; else bps_clk <= 1'b0; end endmodule
// -------------------------------------------------------------------- // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< // -------------------------------------------------------------------- // Module: Uart_Rx // // Author: Step // // Description: The receive module of uart interface // // -------------------------------------------------------------------- // Code Revision History : // -------------------------------------------------------------------- // Version: |Mod. Date: |Changes Made: // V1.0 |2016/04/20 |Initial ver // -------------------------------------------------------------------- module Uart_Rx(input clk_in, //系統(tǒng)時鐘 input rst_n_in, //系統(tǒng)復(fù)位,低有效 output reg bps_en, //接收時鐘使能 input bps_clk, //接收時鐘輸入 input rs232_rx, //UART接收輸入 output reg [7:0] rx_data //接收到的數(shù)據(jù) ); reg rs232_rx0,rs232_rx1,rs232_rx2; //多級延時鎖存去除亞穩(wěn)態(tài) always @ (posedge clk_in or negedge rst_n_in) begin if(!rst_n_in) begin rs232_rx0 <= 1'b0; rs232_rx1 <= 1'b0; rs232_rx2 <= 1'b0; end else begin rs232_rx0 <= rs232_rx; rs232_rx1 <= rs232_rx0; rs232_rx2 <= rs232_rx1; endend //檢測UART接收輸入信號的下降沿 wire neg_rs232_rx = rs232_rx2 & rs232_rx1 & (~rs232_rx0) & (~rs232_rx); reg [3:0] num; //接收時鐘使能信號的控制 always @ (posedge clk_in or negedge rst_n_in) begin if(!rst_n_in) bps_en <= 1'b0; else if(neg_rs232_rx && (!bps_en)) //當(dāng)空閑狀態(tài)(bps_en為低電平)時檢測到UART接收信號下降沿,進(jìn)入工作狀態(tài)(bps_en為高電平),控制時鐘模塊產(chǎn)生接收時鐘 bps_en <= 1'b1; else if(num==4'd9) //當(dāng)完成一次UART接收操作后,退出工作狀態(tài),恢復(fù)空閑狀態(tài) bps_en <= 1'b0; end reg [7:0] rx_data_r;//當(dāng)處于工作狀態(tài)中時,按照接收時鐘的節(jié)拍獲取數(shù)據(jù) always @ (posedge clk_in or negedge rst_n_in) begin if(!rst_n_in) begin num <= 4'd0; rx_data <= 8'd0; rx_data_r <= 8'd0; end else if(bps_en) begin if(bps_clk) begin num <= num+1'b1; if(num<=4'd8) rx_data_r[num-1]<=rs232_rx; //先接受低位再接收高位,8位有效數(shù)據(jù) end else if(num == 4'd9) begin //完成一次UART接收操作后,將獲取的數(shù)據(jù)輸出 num <= 4'd0; rx_data <= rx_data_r; end end end endmodule
// -------------------------------------------------------------------- // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< // -------------------------------------------------------------------- // Module: Uart_Tx // // Author: Step // // Description: The transfer module of uart interface // // -------------------------------------------------------------------- // Code Revision History : // -------------------------------------------------------------------- // Version: |Mod. Date: |Changes Made: // V1.0 |2016/04/20 |Initial ver // -------------------------------------------------------------------- module Uart_Tx ( input clk_in, //系統(tǒng)時鐘 input rst_n_in, //系統(tǒng)復(fù)位,低有效 output reg bps_en, //發(fā)送時鐘使能 input bps_clk, //發(fā)送時鐘輸入 input rx_bps_en, //因需要自收自發(fā),使用接收時鐘使能判定:接收到新的數(shù)據(jù),需要發(fā)送 input [7:0] tx_data, //需要發(fā)出的數(shù)據(jù) output reg rs232_tx //UART發(fā)送輸出 ); reg rx_bps_en_r;//延時鎖存接收時鐘使能信號 always @ (posedge clk_in or negedge rst_n_in) begin if(!rst_n_in) rx_bps_en_r <= 1'b0; else rx_bps_en_r <= rx_bps_en;end //檢測接收時鐘使能信號的下降沿,因為下降沿代表接收數(shù)據(jù)的完成,以此作為發(fā)送信號的激勵 wire neg_rx_bps_en = rx_bps_en_r & (~rx_bps_en); reg [3:0] num; reg [9:0] tx_data_r; //根據(jù)接收數(shù)據(jù)的完成,驅(qū)動發(fā)送數(shù)據(jù)操作 always @ (posedge clk_in or negedge rst_n_in) begin if(!rst_n_in) begin bps_en <= 1'b0; tx_data_r <= 8'd0; end else if(neg_rx_bps_en)begin bps_en <= 1'b1; //當(dāng)檢測到接收時鐘使能信號的下降沿,表明接收完成,需要發(fā)送數(shù)據(jù),使能發(fā)送時鐘使能信號 tx_data_r <= {1'b1,tx_data,1'b0}; end else if(num==4'd10) begin bps_en <= 1'b0; //一次UART發(fā)送需要10個時鐘信號,然后結(jié)束 endend //當(dāng)處于工作狀態(tài)中時,按照發(fā)送時鐘的節(jié)拍發(fā)送數(shù)據(jù) always @ (posedge clk_in or negedge rst_n_in) begin if(!rst_n_in) begin num <= 1'b0; rs232_tx <= 1'b1; end else if(bps_en) begin if(bps_clk) begin num <= num + 1'b1; rs232_tx <= tx_data_r[num]; end else if(num>=4'd10) num <= 4'd0; end end endmodule
小結(jié)
本節(jié)主要為大家講解了UART通信的原理及軟件設(shè)計,需要大家掌握的同時自己創(chuàng)建工程,通過整個設(shè)計流程,生成FPGA配置文件加載測試。
評論