热度 20
2016-4-20 19:07
909 次阅读|
0 个评论
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 data_byte; //发送字节 input send_en;//发送控制 input baud_set;//波特率选择 output reg rs232_tx;//数据发送 output reg tx_done;//发送完成 output reg uart_state;//是否处于空闲状态 //查找表--比特率选择 reg 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 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 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 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 ; 3 : rs232_tx = r_data_byte ; 4 : rs232_tx = r_data_byte ; 5 : rs232_tx = r_data_byte ; 6 : rs232_tx = r_data_byte ; 7 : rs232_tx = r_data_byte ; 8 : rs232_tx = r_data_byte ; 9 : rs232_tx = r_data_byte ; 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 data_byte; reg send_en; reg 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 更多资料请参考: 发烧友小梅哥视频教程