基于FPGA的UART发送模块设计

    

   通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UATR,是一种异步收发传输器。将数据由串行通信与并行通信间做传输转换,作为并行输入称为串行输出的芯片。UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。

  异步串行通信数据格式  

  UART作为异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输。其中各位的意义如下:

   1、起始位:先发出一个逻辑”0”的信号,表示传输字符的开始。
   2、数据位:起始位之后。资料位的个数可以是4、5、6、7、8等,构成一个字符。通常采用ASCII码。从最低位开始传送,靠时钟定位。
   3、奇偶校验位:资料位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验资料传送的正确性。
   4、停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。 由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。
   5、空闲位:处于逻辑“1”状态,表示当前线路上没有数据传输。

 发送一个字节数据的时序图

   波特率(Baud):是指从一设备发到另一设备的波特率,即每秒钟可以通信的数据比特个数。典型的波特率有300, 1200, 2400, 9600, 19200, 115200等。一般通信两端设备都要设为相同的波特率,但有些设备也可设置为自动检测波特率。

   假设需要的波特率为9600bps,那么波特率时钟周期约为 104167ns,板载时钟频率为50MHz,周期为20ns,要计数到104167ns,需要5208个板载时钟周期。

发送模块的代码:

 1 module UART_TX(
 2   clk,
 3   rst_n,
 4   
 5   send_en,
 6   tx_done,
 7   
 8   data_in,
 9   
10   uart_tx
11 );
12 
13 input clk;
14 input rst_n;
15 input[7:0] data_in;  // 输入数据
16 input send_en;       // 发送使能
17 
18 output reg tx_done;  // 发送完成标志信号
19 output reg uart_tx;  // 目标信号输出
20 
21 reg[15:0] bps_cnt;   // 波特率计数寄存器
22 reg[3:0] lsm_cnt;    // 序列机计数
23 reg flag;            // 发送标志信号
24 
25 always@(posedge clk or negedge rst_n)  // flag 信号设计
26   if(!rst_n)
27     flag <= 1'b0;
28   else if(send_en)  // 检测到 发送使能信号,则flag信号拉高
29     flag <= 1'b1;
30   else if(lsm_cnt == 10)  // 发送完一个字节后,flag信号拉低
31     flag <= 1'b0;
32      
33 always@(posedge clk or negedge rst_n)  // bps_cnt 信号设计
34   if(!rst_n)
35     bps_cnt <= 16'd0;
36   else if(flag) begin
37     if(bps_cnt == 5207)   //从0开始计数,计数到5207后停止计数,则计数5208次
38        bps_cnt <= 16'd0;
39      else
40        bps_cnt <= bps_cnt + 1'b1;
41   end
42   else
43     bps_cnt <= 16'd0;
44      
45 always@(posedge clk or negedge rst_n)  // lsm_cnt 信号设计
46   if(!rst_n)
47     lsm_cnt <= 4'd0;
48   else if(bps_cnt == 5207)  // 在 bps_cnt == 5207 时,则刚好计数满9600bps的一个周期
49     lsm_cnt <= lsm_cnt + 1'b1;
50   else if(lsm_cnt == 10)
51     lsm_cnt <= 4'd0;
52      
53 always@(posedge clk or negedge rst_n)  // 信号转换
54   if(!rst_n)
55     uart_tx <= 1'b1;
56   else if(flag) begin
57     case(lsm_cnt)
58        0 : uart_tx <= 1'b0;  //起始位
59         1 : uart_tx <= data_in[0];
60         2 : uart_tx <= data_in[1];
61         3 : uart_tx <= data_in[2];
62         4 : uart_tx <= data_in[3];
63         5 : uart_tx <= data_in[4];
64         6 : uart_tx <= data_in[5];
65         7 : uart_tx <= data_in[6];
66         8 : uart_tx <= data_in[7];
67         9 : uart_tx <= 1'b1;  //停止位
68         default: uart_tx <= 1'b1;
69      endcase 
70   end
71   else
72     uart_tx <= 1'b1;
73      
74 always@(posedge clk or negedge rst_n)  // tx_done 信号设计
75   if(!rst_n)
76     tx_done <= 1'b0;
77   else if(flag && lsm_cnt == 10)  // 发送完一个字节数据后拉高tx_done信号
78     tx_done <= 1'b1;
79   else
80     tx_done <= 1'b0;
81      
82 endmodule
View Code

testbench代码:

 1 `timescale 1ns/1ps
 2 module UART_TX_tb;
 3   reg clk;
 4   reg rst_n;
 5   reg send_en;  
 6 
 7   reg[7:0] data_in;
 8   
 9   wire uart_tx;
10   wire tx_done;  
11 
12 UART_TX_TEST u0(
13   .clk(clk),
14   .rst_n(rst_n),
15   .send_en(send_en),
16   .tx_done(tx_done),
17   
18   .data_in(data_in),
19   .uart_tx(uart_tx)
20 );
21 
22 initial
23   clk = 0;
24   always #10 clk = ~clk;
25   
26 initial
27   begin
28     rst_n = 1'b0;
29      data_in = 8'd0;
30      send_en = 1'b0;
31      #21;
32      
33      rst_n = 1'b1;
34      #1000;
35      data_in = 8'haa;
36      send_en = 1'b1;
37      #20;
38      send_en = 1'b0;
39      @(posedge tx_done)
40      
41      #1000000;
42      data_in = 8'h55;
43      send_en = 1'b1;
44      #20;
45      send_en = 1'b0;
46      @(posedge tx_done)
47      
48      #1000000;
49      $stop;
50   end
51 endmodule
View Code

猜你喜欢

转载自www.cnblogs.com/571328401-/p/12500763.html