串口通信主要包括三个模块:波特率产生模块、发射模块和接收模块。
本节以波特率为115200bps为例来说明波特率模块设计方法,其余波特率可以以此类推。由于我的开发板上的时钟为50MHz,周期T=20ns,而波特率为115200bps,所以1个bit持续的时间是8.7us,那么每个bit占用的周期数N=(8.7us / 20ns) = 434,所以可以定义一个计数器,每当计数器从0计数到433的时候就把计数器清零,然后在计数值为1的情况下产生一个高脉冲。发射模块只要检测到这个高脉冲的到来就发送一个bit,这样就实现了波特率为115200bps的串口数据发送。
而接收模块的波特率时钟产生逻辑与发送的波特率时钟相比稍有不同。不同之处在于当接收模块检测到I_rs232_rxd的下降沿以后,表示有数据过来,准备开始接收数据了,由于一个bit持续的时间为434个时钟周期,所以为了保证接收模块接收数据的准确性,我们需要在434/2=217个周期,也就是数据的正中间位置的时候把输入的数据接收并存起来。也就是说接收模块的波特率时钟要比发射模块的波特率时钟滞后数个周期。
I_clk是系统时钟;
I_rst_n是系统复位;
I_tx_bps_en是发射模块波特率使能信号,当I_tx_bps_en为1时O_bps_tx_clk才有时钟信号输出;
I_rx_bps_en是接收模块波特率使能信号,当I_rx_bps_en为1时O_bps_rx_clk才有时钟信号输出。
波特率模块的完整代码如下:
module baudrate_gen
(
input I_clk , // 系统50MHz时钟
input I_rst_n , // 系统全局复位
input I_bps_tx_clk_en , // 串口发送模块波特率时钟使能信号
input I_bps_rx_clk_en , // 串口接收模块波特率时钟使能信号
output O_bps_tx_clk , // 发送模块波特率产生时钟
output O_bps_rx_clk // 接收模块波特率产生时钟
);
parameter C_BPS9600 = 5207 , //波特率为9600bps
C_BPS19200 = 2603 , //波特率为19200bps
C_BPS38400 = 1301 , //波特率为38400bps
C_BPS57600 = 867 , //波特率为57600bps
C_BPS115200 = 433 ; //波特率为115200bps
parameter C_BPS_SELECT = C_BPS115200 ; //波特率选择
reg [12:0] R_bps_tx_cnt ;
reg [12:0] R_bps_rx_cnt ;
///
// 功能:串口发送模块的波特率时钟产生逻辑
///
always @(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
R_bps_tx_cnt <= 13'd0 ;
else if(I_bps_tx_clk_en == 1'b1)
begin
if(R_bps_tx_cnt == C_BPS_SELECT)
R_bps_tx_cnt <= 13'd0 ;
else
R_bps_tx_cnt <= R_bps_tx_cnt + 1'b1 ;
end
else
R_bps_tx_cnt <= 13'd0 ;
end
assign O_bps_tx_clk = (R_bps_tx_cnt == 13'd1) ? 1'b1 : 1'b0 ;
///
// 功能:串口接收模块的波特率时钟产生逻辑
///
always @(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
R_bps_rx_cnt <= 13'd0 ;
else if(I_bps_rx_clk_en == 1'b1)
begin
if(R_bps_rx_cnt == C_BPS_SELECT)
R_bps_rx_cnt <= 13'd0 ;
else
R_bps_rx_cnt <= R_bps_rx_cnt + 1'b1 ;
end
else
R_bps_rx_cnt <= 13'd0 ;
end
assign O_bps_rx_clk = (R_bps_rx_cnt == C_BPS_SELECT >> 1'b1) ? 1'b1 : 1'b0 ;
endmodule
testbench文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2019/07/03 14:40:14
// Design Name:
// Module Name: test_mealy
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_baudrate();
reg I_clk,I_rst_n;
reg I_bps_tx_clk_en;
reg I_bps_rx_clk_en;
wire O_bps_tx_clk;
wire O_bps_rx_clk;
initial begin
I_clk =0;
I_rst_n=0;
I_bps_tx_clk_en=0;
I_bps_rx_clk_en=0;
#100 I_rst_n=1;
#200;
I_bps_tx_clk_en=1;
I_bps_rx_clk_en=1;
end
always #10 I_clk <= ~I_clk;
baudrate_gen tb_baudrate_gen_inst(
.I_clk (I_clk),
.I_rst_n (I_rst_n),
.I_bps_tx_clk_en (I_bps_tx_clk_en),
.I_bps_rx_clk_en (I_bps_rx_clk_en),
.O_bps_tx_clk (O_bps_tx_clk),
.O_bps_rx_clk (O_bps_rx_clk)
);
endmodule