基于STEP FPGA的UART串口通信模塊驅(qū)動(dòng)
硬件說(shuō)明
通用異步收發(fā)傳輸器(Universal Asynchronous Receiver/Transmitter),通常稱作UART,是一種通用串行數(shù)據(jù)總線,用于異步通信。該總線雙向通信,可以實(shí)現(xiàn)全雙工傳輸和接收。
異步通信以一個(gè)字符為傳輸單位,通信中兩個(gè)字符間的時(shí)間間隔多少是不固定的,然而在同一個(gè)字符中的兩個(gè)相鄰位間的時(shí)間間隔是固定的。兩個(gè)相鄰位間的時(shí)間間隔與UART通信的波特率有關(guān),波特率用來(lái)表征UART通信中數(shù)據(jù)傳輸?shù)乃俾剩疵棵腌妭魉偷亩M(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波特。
我們這里使用的時(shí)序?yàn)槿サ粜r?yàn)位的時(shí)序
本設(shè)計(jì)共有四個(gè)模塊,一個(gè)top模塊,一個(gè)baud模塊,一個(gè)接收模塊和一個(gè)發(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í)鐘時(shí)波特率參數(shù)選擇1250對(duì)應(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_Rx Uart_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_Tx Uart_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
// -------------------------------------------------------------------- // >>>>>>>>>>>>>>>>>>>>>>>>> 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í)鐘時(shí)波特率參數(shù)選擇1250對(duì)應(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 @ (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)時(shí)鐘信號(hào)不使能(bps_en為低電平)時(shí),計(jì)數(shù)器清零并停止計(jì)數(shù) cnt <= 1'b0; //當(dāng)時(shí)鐘信號(hào)使能時(shí),計(jì)數(shù)器對(duì)系統(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 @ (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,因計(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
// -------------------------------------------------------------------- // >>>>>>>>>>>>>>>>>>>>>>>>> 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)時(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; //多級(jí)延時(shí)鎖存去除亞穩(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 //檢測(cè)UART接收輸入信號(hào)的下降沿 wire neg_rs232_rx = rs232_rx2 & rs232_rx1 & (~rs232_rx0) & (~rs232_rx); reg [3:0] num; //接收時(shí)鐘使能信號(hào)的控制 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為低電平)時(shí)檢測(cè)到UART接收信號(hào)下降沿,進(jìn)入工作狀態(tài)(bps_en為高電平),控制時(shí)鐘模塊產(chǎn)生接收時(shí)鐘 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)中時(shí),按照接收時(shí)鐘的節(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)時(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í)鐘使能信號(hào) 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 //檢測(cè)接收時(shí)鐘使能信號(hào)的下降沿,因?yàn)橄陆笛卮斫邮諗?shù)據(jù)的完成,以此作為發(fā)送信號(hào)的激勵(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ū)動(dòng)發(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)檢測(cè)到接收時(shí)鐘使能信號(hào)的下降沿,表明接收完成,需要發(fā)送數(shù)據(jù),使能發(fā)送時(shí)鐘使能信號(hào) tx_data_r <= {1'b1,tx_data,1'b0}; end else if(num==4'd10) begin bps_en <= 1'b0; //一次UART發(fā)送需要10個(gè)時(shí)鐘信號(hào),然后結(jié)束 endend //當(dāng)處于工作狀態(tài)中時(shí),按照發(fā)送時(shí)鐘的節(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è)計(jì),需要大家掌握的同時(shí)自己創(chuàng)建工程,通過(guò)整個(gè)設(shè)計(jì)流程,生成FPGA配置文件加載測(cè)試。
評(píng)論