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端用串口调试助手接收也可以看到收到的数据

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值