17.菜鸟初入FPGA之Uart发送数据
0赞UART
(
Universal
Asynchronous
Receiver/Transmitter
)即
通用异
步收发传输器
,
工作于数据链路层
(协议层之一)
。
包含了
RS
-
232
、
RS
-
422
、
RS
-
485
串口通信和红外
(IrDA)
等等。
UART
协议作为一
种低速通信协议,
广泛应用于通信领域等各种场合。
UART
基本可分
为并口通信及串口通信两种
UART使用的是 异步,串行通信。
串行通信是指利用一条传输线将资料一位位地顺序传送。特点是通信线路简单,利用简单的线缆就可实现通信,降低成本,适用于远距离通信,但传输速度慢的应用场合。
异步通信以一个字符为传输单位,通信中两个字符间的时间间隔多少是不固定的,然而在同一个字符中的两个相邻位间的时间间隔是固定的。
数据传送速率用波特率来表示,即每秒钟传送的二进制位数。例如数据传送速率为120字符/秒,而每一个字符为10位(1个起始位,7个数据位,1个校验位,1个结束位),则其传送的波特率为10×120=1200字符/秒=1200波特。
UART发送一个字节时序图:
串口发送模块包含两个主要组件:
1、发送波特率生成模块
2、数据发送模块
串口发送模块整体结构体
串口发送模块详细结构图
波特率计算:
系统时钟周期为System_clk_period
baud_set |
波特率 |
波特率周期 |
波特率分频计数值 |
System_clk_period = 20计数值 |
0 |
9600 |
104167ns |
104167/ System_clk_period |
5208-1 |
1 |
19200 |
52083ns |
52083/ System_clk_period |
2604-1 |
2 |
38400 |
26041ns |
26041/ System_clk_period |
1302-1 |
3 |
57600 |
17361ns |
17361/ System_clk_period |
868-1 |
4 |
115200 |
8680ns |
8680/ System_clk_period |
434-1 |
代码:
module uart_tx( clk, rst_n, data_byte, send_en, baud_set, rs232_tx, tx_done, uart_state ); input clk,rst_n; input [7:0]data_byte; //发送字节 input send_en;//发送控制 input [3:0]baud_set;//波特率选择 output reg rs232_tx;//数据发送 output reg tx_done;//发送完成 output reg uart_state;//是否处于空闲状态 //查找表--比特率选择 reg [15:0]bps_max;//分频计数最大值 always @(posedge clk or negedge rst_n) if(!rst_n) bps_max <= 16'd5207; else begin case (baud_set) 0: bps_max <= 16'd5207; 1: bps_max <= 16'd2603; 2: bps_max <= 16'd1301; 3: bps_max <= 16'd867; 4: bps_max <= 16'd433; default:bps_max <= 16'd5207; endcase end reg [15:0]div_cnt; always @(posedge clk or negedge rst_n) if(!rst_n) div_cnt <= 16'd0; else if(uart_state)begin if(div_cnt == bps_max) div_cnt <= 16'd0; else div_cnt <= div_cnt +1'b1; end else div_cnt <= 16'd0; reg bps_clk;//波特率时钟 always @(posedge clk or negedge rst_n) if(!rst_n) bps_clk <= 1'b0; else if(div_cnt == 16'd1) bps_clk <= 1'b1; else bps_clk <= 1'b0; reg [3:0]bps_cnt; //计数到11,波特率时钟计数器 always @(posedge clk or negedge rst_n) if(!rst_n) bps_cnt <= 4'd0; else if(bps_clk) bps_cnt <= bps_cnt + 1'b1; else if(tx_done) bps_cnt <= 4'd0; else bps_cnt <= bps_cnt; always@(posedge clk or negedge rst_n) if(!rst_n) tx_done <= 1'b0; else if(bps_cnt == 4'd11) tx_done <= 1'b1; else tx_done <= 1'b0; always @(posedge clk or negedge rst_n) if(!rst_n) uart_state <= 1'b0; else if(send_en) uart_state <= 1'b1; else if(tx_done) uart_state <= 1'b0; else uart_state <= uart_state; reg [7:0]r_data_byte; always @(posedge clk or negedge rst_n) if(!rst_n) r_data_byte <= 8'd0; else if(send_en) r_data_byte <= data_byte; else r_data_byte <= r_data_byte; localparam START_BIT = 1'b0; localparam STOP_BIT = 1'b1; always@(posedge clk or negedge rst_n) if(!rst_n) rs232_tx <= 1'b1; else begin case(bps_cnt) 0 : rs232_tx <= 1'b1; 1 : rs232_tx <= START_BIT; 2 : rs232_tx <= r_data_byte[0]; 3 : rs232_tx <= r_data_byte[1]; 4 : rs232_tx <= r_data_byte[2]; 5 : rs232_tx <= r_data_byte[3]; 6 : rs232_tx <= r_data_byte[4]; 7 : rs232_tx <= r_data_byte[5]; 8 : rs232_tx <= r_data_byte[6]; 9 : rs232_tx <= r_data_byte[7]; 10 : rs232_tx <= STOP_BIT; default:rs232_tx <= 1'b1; endcase end endmodule `timescale 1ns/1ns `define clk_period 20 module uart_tx_tb; reg clk; reg rst_n; reg [7:0]data_byte; reg send_en; reg [3:0]baud_set; wire rs232_tx; wire tx_done; wire uart_state; uart_tx uart_tx( .clk(clk), .rst_n(rst_n), .data_byte(data_byte), .send_en(send_en), .baud_set(baud_set), .rs232_tx(rs232_tx), .tx_done(tx_done), .uart_state(uart_state) ); initial clk = 1; always#(`clk_period/2)clk = ~clk; initial begin rst_n = 1'b0; data_byte = 8'd0; send_en = 1'd0; baud_set = 3'd4; #(`clk_period*20 + 1 ) rst_n = 1'b1; #(`clk_period*50); data_byte = 8'haa; send_en = 1'd1; #`clk_period; send_en = 1'd0; @(posedge tx_done) #(`clk_period*5000); data_byte = 8'h55; send_en = 1'd1; #`clk_period; send_en = 1'd0; @(posedge tx_done) #(`clk_period*5000); $stop; end endmodule
更多资料请参考:
发烧友小梅哥视频教程