3.EP4CE10F17的串口设计
前記:師夷長技以自強。
1.基本概念
UART:Universal Asynchronous Receiver/Transmitter,通用異步收發傳輸器,它是一種電子器件,可以在數據發送時將并行數據轉換成串行數據來傳輸,在數據接收時將接收到的串行數據轉換成并行數據。UART是異步串行通信的總稱,包含了RS232,RS449,RS423,RS422和RS485等協議標準。
RS-232:美國電子工業聯盟(EIA)制定的串行數據通信的接口標準,被廣泛用于計算機串行接口外設連接。
2.UART設計
2.1關鍵參數
我們已經知道UART是一種串行傳輸協議,那么一次傳多少個數據呢?應該傳多快呢?怎么區分一次傳輸?還有既然是通信,難免會有干擾,如何降低數據傳輸錯誤率呢?這些都是一個通信設計者應該考慮的事情。
數據位:定義單個UART數據傳輸從開始到停止期間發送的數據位數。可以為5,6,7,8(默認)。
波特率:每秒可以通信的數據比特個數,典型波特率有300,1200,2400,9600,19200,115200。
奇偶校驗類型:可選參數,分為奇校驗(各數位和校驗位中“1”的個數為奇數)和偶校驗(各數位和校驗位中“1”的個數為偶數)。
停止位:每次傳輸完成后就要發送停止位,可選1,1.5,2位。
2.2時序
需要注意的是,UART作為一種古老的傳輸協議,是先傳低位數據的。
2.3電路設計
早起采用的方案是RS232轉TTL
但由于DB9的RS232接口占用PCB太大,多數系統采用USB轉TTL
在windows下裝CH340G的驅動程序就能夠仿真標準串口了。
3.UART模塊設計
3.1模塊框圖
為了啟動UART發送數據,需要一個Send_En信號;發送完成應該輸出Tx_Done信號;待發送的數據data_byte[7:0];波特率設置baud_Set[2:0];輸出的信號有RS232_Tx;還有基本的時序信號Clk和Rst_n,uart_state。
3.2 代碼文件
module UART(
?? ?input Clk,
?? ?input Rst_n,
?? ?input Send_En,
?? ?input [7:0]data_byte,
?? ?input [2:0]baud_set,
?? ?output uart_state,
?? ?output reg Tx_done,
?? ?output reg Rs232_Tx
);
?? ?reg en;
?? ?reg [7:0]r_data_byte;
?? ?reg [12:0]Clk_CNT;
?? ?reg [3:0]BPS_CNT;
?? ?reg [12:0]Clk_CNT_SHR;
?? ?
?? ?always@(posedge Clk,negedge Rst_n)
?? ?if(!Rst_n)
?? ??? ?en <= 0;
?? ?else if(Send_En)
?? ??? ?en <= 1;
?? ?else if(Tx_done)
?? ??? ?en <= 0;
?? ?else?? ?
?? ??? ?en <= en;
?? ??? ?
?? ?always@(posedge Clk,negedge Rst_n)
?? ?if(!Rst_n)
?? ??? ?r_data_byte <= 0;
?? ?else if(Send_En)
?? ??? ?r_data_byte <= data_byte;
?? ?else
?? ??? ?r_data_byte <= r_data_byte;
?? ??? ?
?? ?always@(posedge Clk,negedge Rst_n)
?? ?if(!Rst_n)
?? ??? ?Clk_CNT_SHR <= 0;
?? ?else if(Send_En)begin
?? ??? ?case(baud_set)
?? ??? ??? ?0:
?? ??? ??? ??? ?Clk_CNT_SHR <= 5208; ?//9600
?? ??? ??? ?1:
?? ??? ??? ??? ?Clk_CNT_SHR <= 3472; ?//14400
?? ??? ??? ?2:
?? ??? ??? ??? ?Clk_CNT_SHR <= 2604; ?//19200
?? ??? ??? ?3:
?? ??? ??? ??? ?Clk_CNT_SHR <= 1736; ?//28800
?? ??? ??? ?4:
?? ??? ??? ??? ?Clk_CNT_SHR <= 1302; ?//38400
?? ??? ??? ?5:
?? ??? ??? ??? ?Clk_CNT_SHR <= 892; ? //56000
?? ??? ??? ?6:
?? ??? ??? ??? ?Clk_CNT_SHR <= 868; ? //57600
?? ??? ??? ?7:
?? ??? ??? ??? ?Clk_CNT_SHR <= 434; ? //115200
?? ??? ??? ?default:;
?? ??? ?endcase
?? ?end
?? ?else
?? ??? ?Clk_CNT_SHR <= Clk_CNT_SHR;
?? ?
?? ?always@(posedge Clk,negedge Rst_n)
?? ?if(!Rst_n)
?? ??? ?Clk_CNT <= 0;
?? ?else if(en)
?? ??? ?if(Clk_CNT == Clk_CNT_SHR)
?? ??? ??? ?Clk_CNT <= 0;
?? ??? ?else
?? ??? ??? ?Clk_CNT <= Clk_CNT + 13'b1;
?? ?else?
?? ??? ?Clk_CNT <= 0;
?? ?
?? ?always@(posedge Clk,negedge Rst_n)
?? ?if(!Rst_n)
?? ??? ?BPS_CNT <= 0;
?? ?else if(en&&Clk_CNT == Clk_CNT_SHR)begin
?? ??? ?if(BPS_CNT == 10)
?? ??? ??? ?BPS_CNT <= 0;
?? ??? ?else
?? ??? ??? ?BPS_CNT <= BPS_CNT + 4'b1;
?? ?end
?? ?else if(Tx_done)?? ?
?? ??? ?BPS_CNT <= 0;
?? ?else
?? ??? ?BPS_CNT <= BPS_CNT;
?? ??? ?
?? ?always@(posedge Clk,negedge Rst_n)
?? ?if(!Rst_n)
?? ??? ?Rs232_Tx <= 1;
?? ?else if(en)
?? ??? ?case(BPS_CNT)
?? ??? ??? ?0:
?? ??? ??? ??? ?Rs232_Tx <= 0;
?? ??? ??? ?1:
?? ??? ??? ??? ?Rs232_Tx <= r_data_byte[0];
?? ??? ??? ?2:
?? ??? ??? ??? ?Rs232_Tx <= r_data_byte[1];
?? ??? ??? ?3:
?? ??? ??? ??? ?Rs232_Tx <= r_data_byte[2];
?? ??? ??? ?4:
?? ??? ??? ??? ?Rs232_Tx <= r_data_byte[3];
?? ??? ??? ?5:
?? ??? ??? ??? ?Rs232_Tx <= r_data_byte[4];
?? ??? ??? ?6:
?? ??? ??? ??? ?Rs232_Tx <= r_data_byte[5];
?? ??? ??? ?7:
?? ??? ??? ??? ?Rs232_Tx <= r_data_byte[6];
?? ??? ??? ?8:
?? ??? ??? ??? ?Rs232_Tx <= r_data_byte[7];
?? ??? ??? ?9:
?? ??? ??? ??? ?Rs232_Tx <= 1;
?? ??? ?endcase
?? ?else
?? ??? ?Rs232_Tx <= 1;
?? ??? ?
?? ?always@(posedge Clk,negedge Rst_n)
?? ?if(!Rst_n)
?? ??? ?Tx_done <= 1;
?? ?else if(en&&BPS_CNT==10)
?? ??? ?Tx_done <= 1;
?? ?else
?? ??? ?Tx_done <= 0;
?? ??? ?
?? ?assign uart_state = en;
?? ??? ?
?? ?
endmodule
?
3.3 仿真
3.3.1 仿真文件
為了測試UART的時序是否正確,需要進行RTL仿真,代碼如下
`timescale 1ns/1ns
`define clock_period 20
module UART_tb();
?? ?reg Clk;
?? ?reg Rst_n;
?? ?reg Send_En;
?? ?reg [7:0]data_byte;
?? ?reg [2:0]baud_set;
?? ?wire uart_state;
?? ?wire Tx_done;
?? ?wire Rs232_Tx;
?? ?UART UART1(
?? ??? ?.Clk(Clk),
?? ??? ?.Rst_n(Rst_n),
?? ??? ?.Send_En(Send_En),
?? ??? ?.data_byte(data_byte),
?? ??? ?.baud_set(baud_set),
?? ??? ?.uart_state(uart_state),
?? ??? ?.Tx_done(Tx_done),
?? ??? ?.Rs232_Tx(Rs232_Tx)
?? ?);
?? ?initial Clk = 0;
?? ?always #10 Clk = ~Clk;
?? ?initial begin
?? ?Rst_n = 0;
?? ?Send_En = 0;
?? ?#`clock_period;
?? ?Rst_n = 1;
?? ?data_byte = 8'h53;
?? ?baud_set = 0;
?? ?Send_En = 1;
?? ?#`clock_period;
?? ?Send_En =0;
?? ?wait(Tx_done);
?? ?#20000;
?? ?data_byte = 8'h73;
?? ?Send_En = 1;
?? ?#`clock_period;
?? ?Send_En =0;
?? ?wait(Tx_done);
?? ?#20000;
?? ?$stop;
?? ?end
?? ?
endmodule
仿真的結果為
3.3.2 板上測試
為了在開發板上能跑起來,需要在寫一個UART_top模塊,主要的測試思路是固定波特率為9600,要發送的數據是0x54,復位后就不斷的發送數據,添加的代碼文件如下
module UART_top(
?? ?input Clk,
?? ?input Rst_n,
?? ?output Rs232_Tx
);
?? ?reg Send_En;
?? ?wire [7:0]data_byte;
?? ?wire [2:0]baud_set;
?? ?wire Tx_done;
?? ?UART UART1(
?? ??? ?.Clk(Clk),
?? ??? ?.Rst_n(Rst_n),
?? ??? ?.Send_En(Send_En),
?? ??? ?.data_byte(data_byte),
?? ??? ?.baud_set(baud_set),
?? ??? ?.uart_state(),
?? ??? ?.Tx_done(Tx_done),
?? ??? ?.Rs232_Tx(Rs232_Tx)
?? ?);
?? ?assign data_byte = 8'h54;
?? ?assign baud_set = 8'b0;
?? ?always@(posedge Clk,negedge Rst_n)
?? ?if(!Rst_n)
?? ??? ?Send_En <= 0;
?? ?else if(Tx_done)
?? ??? ?Send_En <= 1;
?? ?else?
?? ??? ?Send_En <= 0;
endmodule
為了確保設計的時序沒問題,可以先在軟件上仿真,所以需要添加的測試文件UART_top_tb如下
`timescale 1ns/1ns
module UART_top_tb();
?? ?reg Clk;
?? ?reg Rst_n;
?? ?wire Rs232_Tx;
?? ?UART_top UART_top1(
?? ??? ?.Clk(Clk),
?? ??? ?.Rst_n(Rst_n),
?? ??? ?.Rs232_Tx(Rs232_Tx)
?? ?);
?? ?
?? ?initial Clk = 0;
?? ?always #10 Clk = ~Clk;
?? ?
?? ?initial begin
?? ??? ?Rst_n = 0;
?? ??? ?#20;
?? ??? ?Rst_n = 1;
?? ??? ?#10000000;
?? ?end
?? ?
endmodule
仿真后可以得到如下的波形
下載到開發板上,用在PC端用串口調試助手接收也可以看到收到的數據
?
總結
以上是生活随笔為你收集整理的3.EP4CE10F17的串口设计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript运筹帷幄,掌控全局
- 下一篇: go语言基础-----06-----匿名