基于STEP FPGA的UART串口通信模塊驅(qū)動

 行業(yè)動態(tài)     |      2023-11-30 10:33:39    |      作者

硬件說明

通用異步收發(fā)傳輸器(Universal Asynchronous Receiver/Transmitter),通常稱作UART,是一種通用串行數(shù)據(jù)總線,用于異步通信。該總線雙向通信,可以實(shí)現(xiàn)全雙工傳輸和接收。異步通信以一個(gè)字符為傳輸單位,通信中兩個(gè)字符間的時(shí)間間隔多少是不固定的,然而在同一個(gè)字符中的兩個(gè)相鄰位間的時(shí)間間隔是固定的。兩個(gè)相鄰位間的時(shí)間間隔與UART通信的波特率有關(guān),波特率用來表征UART通信中數(shù)據(jù)傳輸?shù)乃俾?,即每秒鐘傳送的二進(jìn)制位數(shù)。例如數(shù)據(jù)傳送速率為120字符/秒,而每一個(gè)字符為10位(1個(gè)起始位,7個(gè)數(shù)據(jù)位,1個(gè)校驗(yàn)位,1個(gè)結(jié)束位),則其傳送的波特率為10×120=1200字符/秒=1200波特。

  • 起始位:先發(fā)出一個(gè)邏輯”0”信號,表示傳輸字符的開始。
  • 數(shù)據(jù)位:可以是5~8位邏輯”0”或”1”。如ASCII碼(7位),擴(kuò)展BCD碼(8位)。小端傳輸
  • 校驗(yàn)位:數(shù)據(jù)位加上這一位后,使得“1”的位數(shù)應(yīng)為偶數(shù)(偶校驗(yàn))或奇數(shù)(奇校驗(yàn))
  • 停止位:它是一個(gè)字符數(shù)據(jù)的結(jié)束標(biāo)志??梢允?位、1.5位、2位的高電平。
  • 空閑位:處于邏輯“1”狀態(tài),表示當(dāng)前線路上沒有資料傳送。

我們這里使用的時(shí)序?yàn)槿サ粜r?yàn)位的時(shí)序

本設(shè)計(jì)共有四個(gè)模塊,一個(gè)top模塊,一個(gè)baud模塊,一個(gè)接收模塊和一個(gè)發(fā)送模塊,大家可以根據(jù)自己的需求進(jìn)行調(diào)整。


Verilog代碼

//-------------------------------------------------------------------- //>>>>>>>>>>>>>>>>>>>>>>>>>COPYRIGHTNOTICE<<<<<<<<<<<<<<<<<<<<<<<<< //-------------------------------------------------------------------- //Module:Uart_bus // //Author:Step // //Description:Themoduleforuartcommunication // // //-------------------------------------------------------------------- //CodeRevisionHistory: //-------------------------------------------------------------------- //Version:|Mod.Date:|ChangesMade: //V1.0|2016/04/20|Initialver //-------------------------------------------------------------------- moduleUart_Bus# ( parameter BPS_PARA=1250//當(dāng)使用12MHz時(shí)鐘時(shí)波特率參數(shù)選擇1250對應(yīng)9600的波特率 ) ( input clk_in, //系統(tǒng)時(shí)鐘 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接收波特率時(shí)鐘控制模塊例化 Baud# ( .BPS_PARA (BPS_PARA ) ) Baud_rx ( .clk_in (clk_in ), //系統(tǒng)時(shí)鐘 .rst_n_in (rst_n_in ), //系統(tǒng)復(fù)位,低有效 .bps_en (bps_en_rx ), //接收時(shí)鐘使能 .bps_clk (bps_clk_rx ) //接收時(shí)鐘輸出 ); //UART接收數(shù)據(jù)模塊例化 Uart_RxUart_Rx_uut ( .clk_in (clk_in ), //系統(tǒng)時(shí)鐘 .rst_n_in (rst_n_in ), //系統(tǒng)復(fù)位,低有效 .bps_en (bps_en_rx ), //接收時(shí)鐘使能 .bps_clk (bps_clk_rx ), //接收時(shí)鐘輸入 .rs232_rx (rs232_rx ), //UART接收輸入 .rx_data (rx_data ) //接收到的數(shù)據(jù) ); /////////////////////////////////UART發(fā)送功能模塊例化//////////////////////////////////// wire bps_en_tx,bps_clk_tx; //UART發(fā)送波特率時(shí)鐘控制模塊例化 Baud# ( .BPS_PARA (BPS_PARA ) ) Baud_tx ( .clk_in (clk_in ), //系統(tǒng)時(shí)鐘 .rst_n_in (rst_n_in ), //系統(tǒng)復(fù)位,低有效 .bps_en (bps_en_tx ), //發(fā)送時(shí)鐘使能 .bps_clk (bps_clk_tx ) //發(fā)送時(shí)鐘輸出 ); //UART發(fā)送數(shù)據(jù)模塊例化 Uart_TxUart_Tx_uut(.clk_in (clk_in ), //系統(tǒng)時(shí)鐘 .rst_n_in (rst_n_in ), //系統(tǒng)復(fù)位,低有效 .bps_en (bps_en_tx ), //發(fā)送時(shí)鐘使能 .bps_clk (bps_clk_tx ), //發(fā)送時(shí)鐘輸入 .rx_bps_en (bps_en_rx ), //因需要自收自發(fā),使用接收時(shí)鐘使能判定:接收到新的數(shù)據(jù),需要發(fā)送 .tx_data (rx_data ), //需要發(fā)出的數(shù)據(jù) .rs232_tx (rs232_tx ) //UART發(fā)送輸出 ); endmodule

//-------------------------------------------------------------------- //>>>>>>>>>>>>>>>>>>>>>>>>>COPYRIGHTNOTICE<<<<<<<<<<<<<<<<<<<<<<<<< //-------------------------------------------------------------------- //Module:Baud // //Author:Step // //Description:Beatforuarttransferandreceivebaudrate // //-------------------------------------------------------------------- //CodeRevisionHistory: //-------------------------------------------------------------------- //Version:|Mod.Date:|ChangesMade: //V1.0|2016/04/20|Initialver //-------------------------------------------------------------------- moduleBaud# ( parameter BPS_PARA=1250//當(dāng)使用12MHz時(shí)鐘時(shí)波特率參數(shù)選擇1250對應(yīng)9600的波特率 ) ( input clk_in, //系統(tǒng)時(shí)鐘 input rst_n_in, //系統(tǒng)復(fù)位,低有效 input bps_en, //接收或發(fā)送時(shí)鐘使能 output reg bps_clk //接收或發(fā)送時(shí)鐘輸出 ); reg [12:0] cnt;//計(jì)數(shù)器計(jì)數(shù)滿足波特率時(shí)鐘要求 always@(posedgeclk_inornegedgerst_n_in)begin if(!rst_n_in) cnt<=1'b0; elseif((cnt>=BPS_PARA-1)||(!bps_en))//當(dāng)時(shí)鐘信號不使能(bps_en為低電平)時(shí),計(jì)數(shù)器清零并停止計(jì)數(shù) cnt<=1'b0; //當(dāng)時(shí)鐘信號使能時(shí),計(jì)數(shù)器對系統(tǒng)時(shí)鐘計(jì)數(shù),周期為BPS_PARA個(gè)系統(tǒng)時(shí)鐘周期 else cnt<=cnt+1'b1;end//產(chǎn)生相應(yīng)波特率的時(shí)鐘節(jié)拍,接收模塊將以此節(jié)拍進(jìn)行UART數(shù)據(jù)接收 always@(posedgeclk_inornegedgerst_n_in) begin if(!rst_n_in) bps_clk<=1'b0; elseif(cnt==(BPS_PARA>>1)) //BPS_PARA右移一位等于除2,因計(jì)數(shù)器終值BPS_PARA為數(shù)據(jù)更替時(shí)間點(diǎn),所以計(jì)數(shù)器中值時(shí)為數(shù)據(jù)最穩(wěn)定時(shí)間點(diǎn) bps_clk<=1'b1; else bps_clk<=1'b0; end endmodule

//-------------------------------------------------------------------- //>>>>>>>>>>>>>>>>>>>>>>>>>COPYRIGHTNOTICE<<<<<<<<<<<<<<<<<<<<<<<<< //-------------------------------------------------------------------- //Module:Uart_Rx // //Author:Step // //Description:Thereceivemoduleofuartinterface // //-------------------------------------------------------------------- //CodeRevisionHistory: //-------------------------------------------------------------------- //Version:|Mod.Date:|ChangesMade: //V1.0|2016/04/20|Initialver //-------------------------------------------------------------------- moduleUart_Rx(input clk_in, //系統(tǒng)時(shí)鐘 input rst_n_in, //系統(tǒng)復(fù)位,低有效 output reg bps_en, //接收時(shí)鐘使能 input bps_clk, //接收時(shí)鐘輸入 input rs232_rx, //UART接收輸入 output reg [7:0] rx_data //接收到的數(shù)據(jù) ); reg rs232_rx0,rs232_rx1,rs232_rx2; //多級延時(shí)鎖存去除亞穩(wěn)態(tài) always@(posedgeclk_inornegedgerst_n_in)begin if(!rst_n_in)begin rs232_rx0<=1'b0; rs232_rx1<=1'b0; rs232_rx2<=1'b0; endelsebegin 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; //接收時(shí)鐘使能信號的控制 always@(posedgeclk_inornegedgerst_n_in)begin if(!rst_n_in) bps_en<=1'b0; elseif(neg_rs232_rx&&(!bps_en)) //當(dāng)空閑狀態(tài)(bps_en為低電平)時(shí)檢測到UART接收信號下降沿,進(jìn)入工作狀態(tài)(bps_en為高電平),控制時(shí)鐘模塊產(chǎn)生接收時(shí)鐘 bps_en<=1'b1; elseif(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)中時(shí),按照接收時(shí)鐘的節(jié)拍獲取數(shù)據(jù) always@(posedgeclk_inornegedgerst_n_in)begin if(!rst_n_in)begin num<=4'd0; rx_data<=8'd0; rx_data_r<=8'd0; endelseif(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ù) endelseif(num==4'd9)begin //完成一次UART接收操作后,將獲取的數(shù)據(jù)輸出 num<=4'd0; rx_data<=rx_data_r; end end end endmodule

//-------------------------------------------------------------------- //>>>>>>>>>>>>>>>>>>>>>>>>>COPYRIGHTNOTICE<<<<<<<<<<<<<<<<<<<<<<<<< //-------------------------------------------------------------------- //Module:Uart_Tx // //Author:Step // //Description:Thetransfermoduleofuartinterface // //-------------------------------------------------------------------- //CodeRevisionHistory: //-------------------------------------------------------------------- //Version:|Mod.Date:|ChangesMade: //V1.0|2016/04/20|Initialver //-------------------------------------------------------------------- moduleUart_Tx ( input clk_in, //系統(tǒng)時(shí)鐘 input rst_n_in, //系統(tǒng)復(fù)位,低有效 output reg bps_en, //發(fā)送時(shí)鐘使能 input bps_clk, //發(fā)送時(shí)鐘輸入 input rx_bps_en, //因需要自收自發(fā),使用接收時(shí)鐘使能判定:接收到新的數(shù)據(jù),需要發(fā)送 input [7:0] tx_data, //需要發(fā)出的數(shù)據(jù) output reg rs232_tx //UART發(fā)送輸出 ); reg rx_bps_en_r;//延時(shí)鎖存接收時(shí)鐘使能信號 always@(posedgeclk_inornegedgerst_n_in)begin if(!rst_n_in)rx_bps_en_r<=1'b0; elserx_bps_en_r<=rx_bps_en;end//檢測接收時(shí)鐘使能信號的下降沿,因?yàn)橄陆笛卮斫邮諗?shù)據(jù)的完成,以此作為發(fā)送信號的激勵(lì) 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@(posedgeclk_inornegedgerst_n_in)begin if(!rst_n_in)begin bps_en<=1'b0; tx_data_r<=8'd0; endelseif(neg_rx_bps_en)begin bps_en<=1'b1; //當(dāng)檢測到接收時(shí)鐘使能信號的下降沿,表明接收完成,需要發(fā)送數(shù)據(jù),使能發(fā)送時(shí)鐘使能信號 tx_data_r<={1'b1,tx_data,1'b0}; endelseif(num==4'd10)begin bps_en<=1'b0; //一次UART發(fā)送需要10個(gè)時(shí)鐘信號,然后結(jié)束 endend//當(dāng)處于工作狀態(tài)中時(shí),按照發(fā)送時(shí)鐘的節(jié)拍發(fā)送數(shù)據(jù) always@(posedgeclk_inornegedgerst_n_in)begin if(!rst_n_in)begin num<=1'b0; rs232_tx<=1'b1; endelseif(bps_en)begin if(bps_clk)begin num<=num+1'b1; rs232_tx<=tx_data_r[num]; endelseif(num>=4'd10) num<=4'd0; end end endmodule


小結(jié)

本節(jié)主要為大家講解了UART通信的原理及軟件設(shè)計(jì),需要大家掌握的同時(shí)自己創(chuàng)建工程,通過整個(gè)設(shè)計(jì)流程,生成FPGA配置文件加載測試。