目錄
一:串口通信簡(jiǎn)介
二:三種常見的數(shù)據(jù)通信方式—RS232串口通信
2.1 實(shí)驗(yàn)任務(wù)
2.2 串口接收模塊的設(shè)計(jì)
2.2.1 代碼設(shè)計(jì)
2.3?串口發(fā)送模塊的設(shè)計(jì)
2.3.1 代碼設(shè)計(jì)
2.4 頂層模塊編寫
2.4.1 代碼設(shè)計(jì)
2.4.2?仿真驗(yàn)證代碼
2.4.3 仿真結(jié)果
2.4.4 板上驗(yàn)證文章來源:http://www.zghlxwxcb.cn/news/detail-774915.html
一:串口通信簡(jiǎn)介
?????? 通信方式一般分為串行通信和并行通信。并行通信是指多比特?cái)?shù)據(jù)同時(shí)通過并行線進(jìn)行傳送。這種傳輸方式通信線多、成本高,故不宜進(jìn)行遠(yuǎn)距離通信,通常傳輸距離小于 30 米。串行通信是指數(shù)據(jù)在一條數(shù)據(jù)線上,一比特接一比特地按順序傳送的方式。這種運(yùn)輸方式通常節(jié)省傳輸線,大大降低使用成本,但數(shù)據(jù)傳送速度慢。綜上可知,串行通信主要應(yīng)用于長(zhǎng)距離、低速率的通信場(chǎng)合。本次實(shí)驗(yàn)我們主要講解下串行通信。文章來源地址http://www.zghlxwxcb.cn/news/detail-774915.html


二:三種常見的數(shù)據(jù)通信方式—RS232串口通信



2.1 實(shí)驗(yàn)任務(wù)

2.2 串口接收模塊的設(shè)計(jì)



2.2.1 代碼設(shè)計(jì)
//串轉(zhuǎn)并
module zdyz_rs232_rx(
input sys_clk , //系統(tǒng)時(shí)鐘
input sys_rst_n , //系統(tǒng)復(fù)位,低有效
input uart_rxd , //UART 接收端口
output reg uart_rx_done, //UART 接收完成信號(hào)
output reg [7:0] uart_rx_data //UART 接收到的數(shù)據(jù)
);
parameter CLK_FREQ = 5000_0000; //系統(tǒng)時(shí)鐘頻率
parameter UART_BPS = 115200 ; //串口波特率
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS; //為得到指定波特率,對(duì)系統(tǒng)時(shí)鐘計(jì)數(shù) BPS_CNT 次
reg uart_rxd_d0;
reg uart_rxd_d1;//定義兩個(gè)D觸發(fā)器進(jìn)行異步打拍處理
reg rx_flag ; //接收過程標(biāo)志信號(hào)
reg [3:0] rx_cnt ; //接收數(shù)據(jù)位計(jì)數(shù)器
reg [15:0] baud_cnt ; //波特率計(jì)數(shù)器(位寬為16,防止溢出)
reg [7:0 ] rx_data_t ; //接收數(shù)據(jù)寄存器
wire start_flag;//開始接收的標(biāo)志,下降沿到來。
//打兩拍:波特率時(shí)鐘和系統(tǒng)時(shí)鐘不同步,為異步信號(hào),所以要進(jìn)行打拍處理,防止產(chǎn)生亞穩(wěn)態(tài)
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
uart_rxd_d0 <= 1'b0;
uart_rxd_d1 <= 1'b0;
end
else begin
uart_rxd_d0 <= uart_rxd;
uart_rxd_d1 <= uart_rxd_d0;
end
end
assign start_flag = (uart_rxd_d0 == 0)&&(uart_rxd_d1 == 1);//下降沿到來的表示方法
// rx_flag接收信號(hào)的拉高與拉低
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
rx_flag <= 1'b0;
else if(start_flag) //檢測(cè)到起始位
rx_flag <= 1'b1; //接收過程中,標(biāo)志信號(hào) rx_flag 拉高
//在停止位一半的時(shí)候,即接收過程結(jié)束,標(biāo)志信號(hào) rx_flag 拉低
else if((rx_cnt == 4'd9) && (baud_cnt == BAUD_CNT_MAX/2 - 1))//rx_flag 要提前拉低,防止其影響下一幀數(shù)據(jù)的接收
rx_flag <= 1'b0;
else
rx_flag <= rx_flag;
end
//波特率的計(jì)數(shù)器計(jì)數(shù)邏輯
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
baud_cnt <= 0;
else if(rx_flag)begin
if(baud_cnt == BAUD_CNT_MAX - 1)
baud_cnt <= 0;
else
baud_cnt <= baud_cnt + 1;
end
else
baud_cnt <= 0;
end
//位計(jì)數(shù)實(shí)現(xiàn)邏輯
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
rx_cnt <= 0;
else if(rx_flag)begin
if(baud_cnt == BAUD_CNT_MAX - 1)
rx_cnt <= rx_cnt + 1;
else
rx_cnt <= rx_cnt;
end
else
rx_cnt <= 0;//其他情況下都為0,所以不用擔(dān)心計(jì)數(shù)超過9,且其計(jì)數(shù)也不會(huì)超過9,當(dāng)rx_flag為0時(shí)就不計(jì)數(shù)了
end
//根據(jù) rx_cnt 來寄存 rxd 端口的數(shù)據(jù)
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
rx_data_t <= 0;
else if(rx_flag)begin //系統(tǒng)處于接收過程時(shí)
if(baud_cnt == BAUD_CNT_MAX/2 - 1)begin//判斷 baud_cnt 是否計(jì)數(shù)到數(shù)據(jù)位的中間
case(rx_cnt)
1:rx_data_t[0] <= uart_rxd_d1; //寄存數(shù)據(jù)的最低位
2:rx_data_t[1] <= uart_rxd_d1;
3:rx_data_t[2] <= uart_rxd_d1;
4:rx_data_t[3] <= uart_rxd_d1;
5:rx_data_t[4] <= uart_rxd_d1;
6:rx_data_t[5] <= uart_rxd_d1;
7:rx_data_t[6] <= uart_rxd_d1;
8:rx_data_t[7] <= uart_rxd_d1;//寄存數(shù)據(jù)的高低位
default:rx_data_t <= rx_data_t;
endcase
end
else
rx_data_t <= rx_data_t;
end
else
rx_data_t <= 0;
end
//給接收完成信號(hào)和接收到的數(shù)據(jù)賦值
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
uart_rx_done <= 0;
uart_rx_data <= 0;
end
//當(dāng)接收數(shù)據(jù)計(jì)數(shù)器計(jì)數(shù)到停止位,且 baud_cnt 計(jì)數(shù)到停止位的中間時(shí)
else if((rx_cnt == 4'd9) && (baud_cnt == BAUD_CNT_MAX/2 - 1))begin
uart_rx_done <= 1; //拉高接收完成信號(hào)
uart_rx_data <= rx_data_t;//并對(duì) UART 接收到的數(shù)據(jù)進(jìn)行賦值
end
else begin
uart_rx_done <= 0;
uart_rx_data <= uart_rx_data;
end
end
endmodule
2.3?串口發(fā)送模塊的設(shè)計(jì)


2.3.1 代碼設(shè)計(jì)
module zdyz_rs232_tx(
input sys_clk , //系統(tǒng)時(shí)鐘
input sys_rst_n , //系統(tǒng)復(fù)位,低有效
input uart_tx_en , //UART 的發(fā)送使能(發(fā)送是有標(biāo)志起始時(shí)間的,接收是根據(jù)下降沿到來就開始進(jìn)入起始位)
input [7:0] uart_tx_data, //UART 要發(fā)送的數(shù)據(jù)
output reg uart_txd , //UART 發(fā)送端口
output reg uart_tx_busy //發(fā)送忙狀態(tài)信號(hào)
);
//parameter define
parameter CLK_FREQ = 50000000; //系統(tǒng)時(shí)鐘頻率
parameter UART_BPS = 115200 ; //串口波特率
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS; //為得到指定波特率,對(duì)系統(tǒng)時(shí)鐘計(jì)數(shù) BPS_CNT 次
reg [7:0] tx_data_t; //發(fā)送數(shù)據(jù)寄存器
reg [3:0] tx_cnt ; //發(fā)送數(shù)據(jù)位計(jì)數(shù)器
reg [15:0] baud_cnt ; //波特率計(jì)數(shù)器
//當(dāng) uart_tx_en 為高時(shí),寄存輸入的并行數(shù)據(jù)(防止發(fā)生變化影響發(fā)送),并拉高 BUSY 信號(hào)
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
tx_data_t <= 0;
uart_tx_busy <= 0;
end
else if(uart_tx_en)begin
tx_data_t <= uart_tx_data;
uart_tx_busy <= 1;
end
/*為了確保環(huán)回實(shí)驗(yàn)的成功,在程序的 36 行我們將 uart_tx_busy 提前 1/16 個(gè)停止位拉低。盡管串口發(fā)送數(shù)據(jù)只是接收數(shù)據(jù)的反過程,
理論上在傳輸?shù)臅r(shí)間上是一致的,但是考慮到我們模塊里計(jì)算波特率會(huì)有較小的偏差,并且串口對(duì)端的通信設(shè)備(如電腦等)收發(fā)數(shù)據(jù)的波特率
同樣可能會(huì)出現(xiàn)較小的偏差,因此為了確保環(huán)回實(shí)驗(yàn)的成功,這里將發(fā)送模塊的停止位略微提前結(jié)束。需要說明的是,較小偏差的波特率在
串口通信時(shí)是允許的,同樣可以保證數(shù)據(jù)可靠穩(wěn)定的傳輸*/
else if((tx_cnt == 4'd9) && (baud_cnt == BAUD_CNT_MAX - BAUD_CNT_MAX/16))begin
uart_tx_busy <= 0;
tx_data_t <= 0;
end
else begin
uart_tx_busy <= uart_tx_busy;
tx_data_t <= tx_data_t;
end
end
//波特率的計(jì)數(shù)器計(jì)數(shù)邏輯
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
baud_cnt <= 0;
else if(uart_tx_busy)begin //當(dāng)處于發(fā)送過程時(shí),波特率計(jì)數(shù)器(baud_cnt)進(jìn)行循環(huán)計(jì)數(shù)
if(baud_cnt == BAUD_CNT_MAX - 1)
baud_cnt <= 0; //計(jì)數(shù)達(dá)到一個(gè)波特率周期后清零
else
baud_cnt <= baud_cnt + 1;
end
else
baud_cnt <= 0;//發(fā)送過程結(jié)束時(shí)計(jì)數(shù)器清零
end
//位計(jì)數(shù)實(shí)現(xiàn)邏輯
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
tx_cnt <= 0;
else if(uart_tx_busy)begin//處于發(fā)送過程時(shí) tx_cnt 才進(jìn)行計(jì)數(shù)
if(baud_cnt == BAUD_CNT_MAX - 1)//當(dāng)波特率計(jì)數(shù)器計(jì)數(shù)到一個(gè)波特率周期時(shí)
tx_cnt <= tx_cnt + 1; //發(fā)送數(shù)據(jù)計(jì)數(shù)器加 1
else
tx_cnt <= tx_cnt;
end
else
tx_cnt <= 0;//其他情況下都為0,所以不用擔(dān)心計(jì)數(shù)超過9,且其計(jì)數(shù)也不會(huì)超過9,當(dāng)rx_flag為0時(shí)就不計(jì)數(shù)了
end
//根據(jù) tx_cnt 來給 uart 發(fā)送端口賦值
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
uart_txd <= 1 ;//空閑態(tài)為1
else if(uart_tx_busy)begin
case(tx_cnt)
4'd0 : uart_txd <= 1'b0 ; //起始位
4'd1 : uart_txd <= tx_data_t[0]; //數(shù)據(jù)位最低位
4'd2 : uart_txd <= tx_data_t[1];
4'd3 : uart_txd <= tx_data_t[2];
4'd4 : uart_txd <= tx_data_t[3];
4'd5 : uart_txd <= tx_data_t[4];
4'd6 : uart_txd <= tx_data_t[5];
4'd7 : uart_txd <= tx_data_t[6];
4'd8 : uart_txd <= tx_data_t[7]; //數(shù)據(jù)位最高位
4'd9 : uart_txd <= 1'b1 ; //停止位
default:uart_txd <= 1'b1 ;
endcase
end
else
uart_txd <= 1 ; //空閑時(shí)發(fā)送端口為高電平
end
endmodule
2.4 頂層模塊編寫
2.4.1 代碼設(shè)計(jì)
module top_uart(
input sys_clk , //外部 50MHz 時(shí)鐘
input sys_rst_n, //系外部復(fù)位信號(hào),低有效
//UART 端口
input uart_rxd , //UART 接收端口(串行數(shù)據(jù))
output uart_txd //UART 發(fā)送端口
);
parameter CLK_FREQ = 50000000; //定義系統(tǒng)時(shí)鐘頻率
parameter UART_BPS = 115200 ; //定義串口波特率
//wire define
wire uart_rx_done; //UART 接收完成信號(hào)
wire [7:0] uart_rx_data; //UART 接收數(shù)據(jù)(并行數(shù)據(jù))
wire uart_tx_busy;
//*****************************************************
//** main code
//*****************************************************
//串口接收
zdyz_rs232_rx #(
.CLK_FREQ (CLK_FREQ),
.UART_BPS (UART_BPS)
)zdyz_rs232_rx(
.sys_clk(sys_clk) , //系統(tǒng)時(shí)鐘
.sys_rst_n(sys_rst_n) , //系統(tǒng)復(fù)位,低有效
.uart_rxd(uart_rxd) , //UART 接收端口
.uart_rx_done(uart_rx_done), //UART 接收完成信號(hào)
.uart_rx_data(uart_rx_data)//UART 接收到的數(shù)據(jù)
);
zdyz_rs232_tx #(
.CLK_FREQ (CLK_FREQ),
.UART_BPS (UART_BPS)
)zdyz_rs232_tx(
.sys_clk(sys_clk) , //系統(tǒng)時(shí)鐘
.sys_rst_n(sys_rst_n) , //系統(tǒng)復(fù)位,低有效
.uart_tx_en(uart_rx_done) , //UART 的發(fā)送使能
.uart_tx_data(uart_rx_data), //UART 要發(fā)送的數(shù)據(jù)
.uart_txd(uart_txd) , //UART 發(fā)送端口
.uart_tx_busy(uart_tx_busy) //發(fā)送忙狀態(tài)信號(hào)
);
endmodule
2.4.2?仿真驗(yàn)證代碼
`timescale 1ns/1ns //仿真的單位/仿真的精度
module tb_uart_loopback();
//parameter define
parameter CLK_PERIOD = 20;//時(shí)鐘周期為 20ns
//reg define
reg sys_clk ; //時(shí)鐘信號(hào)
reg sys_rst_n; //復(fù)位信號(hào)
reg uart_rxd ; //UART 接收端口
//wire define
wire uart_txd ; //UART 發(fā)送端口
//*****************************************************
//** main code
//*****************************************************
//發(fā)送 8'h55 8'b0101_0101
initial begin
sys_clk <= 1'b0;
sys_rst_n <= 1'b0;
uart_rxd <= 1'b1;
#200
sys_rst_n <= 1'b1;
#1000
uart_rxd <= 1'b0; //起始位
#8680
uart_rxd <= 1'b1; //D0
#8680
uart_rxd <= 1'b0; //D1
#8680
uart_rxd <= 1'b1; //D2
#8680
uart_rxd <= 1'b0; //D3
#8680
uart_rxd <= 1'b1; //D4
#8680
uart_rxd <= 1'b0; //D5
#8680
uart_rxd <= 1'b1; //D6
#8680
uart_rxd <= 1'b0; //D7
#8680
uart_rxd <= 1'b1; //停止位
#8680
uart_rxd <= 1'b1; //空閑狀態(tài)
end
//50Mhz 的時(shí)鐘,周期則為 1/50Mhz=20ns,所以每 10ns,電平取反一次
always #(CLK_PERIOD/2) sys_clk = ~sys_clk;
//例化頂層模塊
top_uart top_uart(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.uart_rxd (uart_rxd ),
.uart_txd (uart_txd )
);
endmodule
2.4.3 仿真結(jié)果

2.4.4 板上驗(yàn)證
到了這里,關(guān)于ZYNQ 7020 之 FPGA知識(shí)點(diǎn)重塑筆記一——串口通信的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!