UART串口verilog hdl实现(1)波特率产生模块

串口通信主要包括三个模块:波特率产生模块、发射模块和接收模块。
本节以波特率为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
        

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 8
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
下面是一个简单的Verilog HDL代码,可以实现串口通信: ```verilog module uart ( input clk, // 时钟信号 input reset_n, // 复位信号 input rx, // 接收数据信号 output reg tx, // 发送数据信号 output reg tx_busy // 发送忙信号 ); // 定义常量 parameter CLK_FREQ = 50_000_000; // 时钟频率 parameter BAUD_RATE = 115200; // 波特率 parameter DATA_BITS = 8; // 数据位数 parameter STOP_BITS = 1; // 停止位数 parameter PARITY = 0; // 校验位 // 定义变量 reg [DATA_BITS + 2:0] tx_reg; // 发送寄存器 reg [3:0] tx_cnt; // 发送计数器 reg [DATA_BITS + 2:0] rx_reg; // 接收寄存器 reg [3:0] rx_cnt; // 接收计数器 // 时钟分频 reg [31:0] clk_div; reg [31:0] baud_div; assign clk_div = CLK_FREQ / (BAUD_RATE * (DATA_BITS + STOP_BITS + PARITY + 1)); assign baud_div = clk_div / 2; // 发送模块 always @(posedge clk or negedge reset_n) begin if (~reset_n) begin tx <= 1'b1; tx_busy <= 1'b0; tx_reg <= {DATA_BITS + 2{1'b1}}; tx_cnt <= 4'd0; end else if (tx_cnt == 4'd0) begin if (tx_reg[0]) begin tx <= 1'b0; tx_reg <= {tx_reg[DATA_BITS + 2:1], 1'b0}; tx_cnt <= tx_cnt + 1; end else begin tx <= 1'b1; tx_busy <= 1'b0; end end else begin tx <= 1'b1; tx_cnt <= tx_cnt + 1; end end // 接收模块 always @(posedge clk or negedge reset_n) begin if (~reset_n) begin rx_reg <= {DATA_BITS + 2{1'b1}}; rx_cnt <= 4'd0; end else if (rx_cnt == 4'd0) begin rx_reg <= {rx, rx_reg[DATA_BITS + 2:1]}; rx_cnt <= rx_cnt + 1; end else if (rx_cnt == baud_div) begin rx_cnt <= 4'd0; end else begin rx_cnt <= rx_cnt + 1; end end endmodule ``` 这个代码实现了一个基本的UART串口,可以通过FPGA的IO口与外部设备进行串口通信。需要注意的是,这个代码只是一个示例,实际应用中可能需要根据具体需求进行适当修改和优化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值