赞
踩
uart :异步、串行、全双工
一般描述某种通信的特点为:同步/异步 , 串行/并行 , 半双工/全双工
同步:要求一个芯片控制另一芯片的时序,一般,两者之间至少采用一个总线连接以控制时钟(“时钟线”), 其中主机主动控制时钟线(通过时钟线输出),从机被动接受时钟线(通过时钟线输入)。
异步:双方不会通过总线连接时钟,异步通信要求双方使用独立的时钟生成装置(波特率发生器),生成相 同的通信速度。
串行:在每个数据方向上仅有一根数据线。每次仅传输一位数据。
并行:在每个数据方向上有多根数据线。每次可以传输数据的多个位(一般是8/16位)
半双工:数据线仅有一组,同一时刻,只有一方控制数据线的发送,另一方接收数据(即双方不能同时发送 数据)
全双工:数据线有两组或以上,同一时刻,通信双方都可以给对方发送数据。
uart:通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),是一种通用串行数据总线,用于异步通信。uart能实现双向通信,在嵌入式设计中,它常用于主机与辅助设备通信。uart包括RS232、RS449、RS432、RS422和RS485等接口标准规范和总线标准规范,既uart是异步串行通信口的的总称。而RS232、RS449、RS432、RS422和RS485等是对应各种异步串行通信口的接口标准和总线标准,它规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容,实际上属于通信网络中的物理层(最底层)的概念,与通信协议没有直接关系。(内容来源于《搭建你的数字积木-数字电路与逻辑设计》)
参数的意义如下:
波特率 | 波特率周期 | 波特率分频计数值 |
---|---|---|
9600 | 104167ns | 104164 / sys_clk_period |
19200 | 52083ns | 52083 / sys_clk_period |
38400 | 26041ns | 26041 / sys_clk_period |
57600 | 17361ns | 17361 / sys_clk_period |
115200 | 8680ns | 8680 / sys_clk_period |
说明:sys_clk_period 为系统时钟周期 |
使用工具:ISE Design Suite 14.7
FPGA开发板: Basys2
波特率:9600 bit/s
实现的功能:
指令一:PC端发送I like FPGA,开发板回应 I like FPGA, too. 在PC端显示。
指令二:PC端发送I like Verilog,开发板回应 I like Verilog, too. 在PC端显示。
RTL视图如下:
module top_uart_tx_rx( input clk, input rst_n, input rs232_rx, output rs232_tx ); //uart_rx wire [7:0] rx_data; wire rx_done; //uart_tx wire tx_finish; wire send_en; wire [7:0] data_tx; //rx_datadeal wire tx_en1; wire tx_en2; //tx_datadeal uart_rx uart_rx( .clk (clk) , .rst_n (rst_n) , .rs232_rx(rs232_rx) , .rx_data (rx_data) , .rx_done (rx_done) ); uart_tx uart_tx( .clk (clk), .rst_n (rst_n), .send_en (send_en), .data_tx (data_tx), .rs232_tx (rs232_tx), .tx_finish (tx_finish) ); tx_datadeal tx_datadeal( .clk (clk ), .rst_n (rst_n ), .tx_en1 (tx_en1), .tx_en2 (tx_en2), .tx_finish (tx_finish), .send_en (send_en), .data_tx (data_tx) ); rx_datadeal rx_datadeal( .clk (clk) , .rst_n (rst_n) , .rx_data (rx_data), .rx_done (rx_done), .tx_en1 (tx_en1), .tx_en2 (tx_en2) ); endmodule
module rx_datadeal( input clk , input rst_n , input [7:0] rx_data , input rx_done , output reg tx_en1 , output reg tx_en2 ); reg [3:0] data_cnt; reg [3:0] flag1; reg [3:0] flag2; always@(posedge clk or negedge rst_n) begin if(!rst_n) data_cnt <= 4'd0; else if(flag1 == 4'd11 || flag2 == 4'd14 ) data_cnt <= 4'd0; else if(rx_done) data_cnt <= data_cnt + 1'b1; end //给tx的使能信号 always@(posedge clk or negedge rst_n) begin if(!rst_n) begin tx_en1 <= 1'b0; tx_en2 <= 1'b0; end else if(flag1 == 4'd11) tx_en1 <= 1'b1; else if(flag2 == 4'd14) tx_en2 <= 1'b1; else begin tx_en1 <= 1'b0; tx_en2 <= 1'b0; end end always@(posedge clk or negedge rst_n) begin if(!rst_n) begin flag1 <= 4'd0; flag2 <= 4'd0; end else if(flag1 == 4'd11) flag1 <= 4'd0; else if(flag2 == 4'd14) flag2 <= 4'd0; else begin case(data_cnt) 4'd0 : begin if(rx_data == "I") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd1 : begin if(rx_data == " ") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd2 : begin if(rx_data == "L") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd3 : begin if(rx_data == "i") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd4 : begin if(rx_data == "k") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd5 : begin if(rx_data == "e") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd6 : begin if(rx_data == " ") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd7 : begin if(rx_data == "F") begin flag1 <= flag1 + 1'b1; flag2 <= 4'd0; end else if(rx_data == "V") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd8 : begin if(rx_data == "P") begin flag1 <= flag1 + 1'b1; flag2 <= 4'd0; end else if(rx_data == "e") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd9 : begin if(rx_data == "G") begin flag1 <= flag1 + 1'b1; flag2 <= 4'd0; end else if(rx_data == "r") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd10 : begin if(rx_data == "A") begin flag1 <= flag1 + 1'b1; flag2 <= 4'd0; end else if(rx_data == "i") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd11 : begin if(rx_data == "l") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd12 : begin if(rx_data == "o") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd13 : begin if(rx_data == "g") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end default : begin flag1 <= 4'd0; flag2 <= 4'd0; end endcase end end endmodule
module uart_rx(clk,rst_n,rs232_rx,rx_data,rx_done); input clk; input rst_n; input rs232_rx; output reg [7:0] rx_data; output reg rx_done; reg [1:0]s_rs232_rx;//消除亚稳态 reg [1:0]tmp_rs232_rx;//数据寄存器 wire nedge; reg [15:0]div_cnt;//分频计数器 reg bps_clk; reg uart_state; reg [7:0]bps_cnt; reg [2:0]start_bit; reg [2:0]stop_bit; reg [2:0]rx_data_t [7:0]; // 地址宽度 always@(posedge clk or negedge rst_n) if(!rst_n) s_rs232_rx <= 0; else begin s_rs232_rx[0] <= rs232_rx; s_rs232_rx[1] <= s_rs232_rx[0]; end always@(posedge clk or negedge rst_n) if(!rst_n) tmp_rs232_rx <= 0; else begin tmp_rs232_rx[0] <= s_rs232_rx[1]; tmp_rs232_rx[1] <= tmp_rs232_rx[0]; end assign nedge = tmp_rs232_rx[1] & ~tmp_rs232_rx[0]; always@(posedge clk or negedge rst_n) if(!rst_n) div_cnt <= 16'd0; else if(uart_state == 1) begin if(div_cnt == 325) div_cnt <= 16'd0; else div_cnt <= div_cnt + 1; end else div_cnt <= 0; always@(posedge clk or negedge rst_n) if(!rst_n) bps_clk <= 1'b0; else if(div_cnt == 16'b1) bps_clk <= 1'b1; else bps_clk <= 1'b0; always@(posedge clk or negedge rst_n) if(!rst_n) uart_state <= 1'b0; else if(nedge) uart_state <= 1'b1; else if(rx_done || (bps_cnt == 8'd12 && start_bit > 2)) uart_state <= 1'b0; else uart_state <= uart_state; always@(posedge clk or negedge rst_n) if(!rst_n) bps_cnt <= 0; else if(bps_cnt == 8'd159 | (bps_cnt == 8'd12 && start_bit > 2)) bps_cnt <= 0; else if(bps_clk == 1) bps_cnt <= bps_cnt + 1; else bps_cnt <= bps_cnt; always@(posedge clk or negedge rst_n) if(!rst_n) begin rx_done <= 1'b0; end else if(bps_cnt == 8'd159) begin rx_done <= 1'b1; end else begin rx_done <= 1'b0; end always@(posedge clk or negedge rst_n) if(!rst_n) begin start_bit <= 3'd0; rx_data_t[0] <= 3'd0; rx_data_t[1] <= 3'd0; rx_data_t[2] <= 3'd0; rx_data_t[3] <= 3'd0; rx_data_t[4] <= 3'd0; rx_data_t[5] <= 3'd0; rx_data_t[6] <= 3'd0; rx_data_t[7] <= 3'd0; stop_bit <= 3'd0; end else if(bps_clk == 1) begin case(bps_cnt) 0:begin start_bit <= 3'd0; rx_data_t[0] <= 3'd0; rx_data_t[1] <= 3'd0; rx_data_t[2] <= 3'd0; rx_data_t[3] <= 3'd0; rx_data_t[4] <= 3'd0; rx_data_t[5] <= 3'd0; rx_data_t[6] <= 3'd0; rx_data_t[7] <= 3'd0; stop_bit <= 3'd0; end 5,6,7,8,9,10: start_bit <= start_bit + s_rs232_rx[1]; 21,22,23,24,25,26: rx_data_t[0] <= rx_data_t[0] + s_rs232_rx[1]; 37,38,39,40,41,42: rx_data_t[1] <= rx_data_t[1] + s_rs232_rx[1]; 53,54,55,56,57,58: rx_data_t[2] <= rx_data_t[2] + s_rs232_rx[1]; 69,70,71,72,73,74: rx_data_t[3] <= rx_data_t[3] + s_rs232_rx[1]; 85,86,87,88,89,90: rx_data_t[4] <= rx_data_t[4] + s_rs232_rx[1]; 101,102,103,104,105,106: rx_data_t[5] <= rx_data_t[5] + s_rs232_rx[1]; 117,119,120,121,122,123: rx_data_t[6] <= rx_data_t[6] + s_rs232_rx[1]; 133,135,136,137,138,139: rx_data_t[7] <= rx_data_t[7] + s_rs232_rx[1]; 149,151,152,153,154,155: stop_bit <= stop_bit + s_rs232_rx[1]; endcase end always@(posedge clk or negedge rst_n) if(!rst_n) rx_data <= 8'd0; else if(bps_cnt == 159) begin rx_data[0] <= rx_data_t[0][2]; rx_data[1] <= rx_data_t[1][2]; rx_data[2] <= rx_data_t[2][2]; rx_data[3] <= rx_data_t[3][2]; rx_data[4] <= rx_data_t[4][2]; rx_data[5] <= rx_data_t[5][2]; rx_data[6] <= rx_data_t[6][2]; rx_data[7] <= rx_data_t[7][2]; end endmodule
module tx_datadeal( input clk, input rst_n, input tx_finish, input tx_en1, input tx_en2, output reg send_en, output reg [7:0] data_tx ); //define reg [4:0] data_cnt; reg tx_state1; reg tx_state2; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin tx_state1 <= 1'b0; tx_state2 <= 1'b0; end else if(tx_en1) tx_state1 <= 1'b1; else if(tx_en2) tx_state2 <= 1'b1; else if(data_cnt == 5'd15) tx_state1 <= 1'b0; else if(data_cnt == 5'd18) tx_state2 <= 1'b0; else begin tx_state1 <= tx_state1; tx_state2 <= tx_state2; end end //data_cnt always@(posedge clk or negedge rst_n) begin if(!rst_n) data_cnt <= 5'd0; else if(tx_state1 == 1'b1 && data_cnt == 5'd15) data_cnt <= 5'd0; else if(tx_state2 == 1'b1 && data_cnt == 5'd18) data_cnt <= 5'd0; else if(tx_finish) data_cnt <= data_cnt + 1'b1; else data_cnt <= data_cnt; end //send_en always@(posedge clk or negedge rst_n) begin if(!rst_n) send_en <= 1'b0; else if(tx_en1 || tx_en2) send_en <= 1'b1; else if(tx_finish) begin if(tx_state1) begin if(data_cnt < 5'd14) send_en <= 1'b1; else send_en <= 1'b0; end else if(tx_state2) begin if(data_cnt < 5'd17) send_en <= 1'b1; else send_en <= 1'b0; end end else send_en <= 1'b0; end always@(posedge clk or negedge rst_n) begin if(!rst_n) data_tx <= 8'd0; else if(tx_state1) begin case(data_cnt) 5'd0 : data_tx <= "I"; 5'd1 : data_tx <= " "; 5'd2 : data_tx <= "L"; 5'd3 : data_tx <= "i"; 5'd4 : data_tx <= "k"; 5'd5 : data_tx <= "e"; 5'd6 : data_tx <= " "; 5'd7 : data_tx <= "F"; 5'd8 : data_tx <= "P"; 5'd9 : data_tx <= "G"; 5'd10 : data_tx <= "A"; 5'd11 : data_tx <= ","; 5'd12 : data_tx <= "t"; 5'd13 : data_tx <= "o"; 5'd14 : data_tx <= "o"; default : data_tx <= 8'd0; endcase end else if(tx_state2) begin case(data_cnt) 5'd0 : data_tx <= "I"; 5'd1 : data_tx <= " "; 5'd2 : data_tx <= "L"; 5'd3 : data_tx <= "i"; 5'd4 : data_tx <= "k"; 5'd5 : data_tx <= "e"; 5'd6 : data_tx <= " "; 5'd7 : data_tx <= "V"; 5'd8 : data_tx <= "e"; 5'd9 : data_tx <= "r"; 5'd10 : data_tx <= "i"; 5'd11 : data_tx <= "l"; 5'd12 : data_tx <= "o"; 5'd13 : data_tx <= "g"; 5'd14 : data_tx <= ","; 5'd15 : data_tx <= "t"; 5'd16 : data_tx <= "o"; 5'd17 : data_tx <= "o"; default : data_tx <= 8'd0; endcase end else data_tx <= 8'd0; end endmodule
module uart_tx(clk,rst_n,tx_finish,send_en,rs232_tx,uart_state,data_tx); input clk ; input rst_n ; input send_en ;//发送使能信号 input [ 7:0] data_tx ;//发送字节 output reg rs232_tx ; output reg tx_finish ; output reg uart_state ; reg bps_clk ;//波特率时钟 reg [ 15:0] div_cnt ;//分频计数器 reg [ 15:0] bps_DR = 5207 ;//分频计数最大值 reg [ 3:0] bps_cnt ;//波特率计数时钟 reg [ 7:0] r_data_tx ; localparam START_BYTE = 1'b0 ; localparam STOP_BYTE = 1'b1 ; //控制信号 always@(posedge clk or negedge rst_n) if(!rst_n) uart_state <= 1'b0; else if(send_en) uart_state <= 1'b1; else if(bps_cnt == 4'd11) uart_state <= 1'b0; else uart_state <= uart_state; //寄存器存储发送信息 always@(posedge clk or negedge rst_n) if(!rst_n) r_data_tx <= 1'b0; else if(uart_state) r_data_tx <= data_tx; else r_data_tx <= r_data_tx; //counter always@(posedge clk or negedge rst_n) if(!rst_n) div_cnt <= 16'd0; else if(uart_state) begin if(div_cnt == bps_DR) div_cnt <= 16'd0; else div_cnt <= div_cnt + 1'b1; end else div_cnt <= 16'd0; //产生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'd1; else bps_clk <= 1'b0; always@(posedge clk or negedge rst_n) if(!rst_n) bps_cnt <= 4'd0; else if(bps_cnt == 4'd11) bps_cnt <= 4'd0; else if(bps_clk) bps_cnt <= bps_cnt + 1'b1; else bps_cnt <= bps_cnt; //产生发送完成信号 always@(posedge clk or negedge rst_n) if(!rst_n) tx_finish <= 1'b0; else if(bps_cnt == 4'd11) tx_finish <= 1'b1; else tx_finish <= 1'b0; //发送模块 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_BYTE; //0 2:rs232_tx <= r_data_tx[0]; 3:rs232_tx <= r_data_tx[1]; 4:rs232_tx <= r_data_tx[2]; 5:rs232_tx <= r_data_tx[3]; 6:rs232_tx <= r_data_tx[4]; 7:rs232_tx <= r_data_tx[5]; 8:rs232_tx <= r_data_tx[6]; 9:rs232_tx <= r_data_tx[7]; 10:rs232_tx <= STOP_BYTE; //1 default:rs232_tx <= 1'b1; endcase end endmodule
module tb_uart_tx_rx; // Inputs reg clk; reg rst_n; reg rs232_rx; // Outputs wire rs232_tx; // Instantiate the Unit Under Test (UUT) top_uart_tx_rx uut ( .clk(clk), .rst_n(rst_n), .rs232_rx(rs232_rx), .rs232_tx(rs232_tx) ); parameter period=20, RST_ING=1'b0, BPS_9600=32'd104_167; initial begin // Initialize Inputs clk = 0; forever #(period/2)clk=~clk; end reg [4:0] cnt; reg [7:0] data_tx; initial begin rst_n = RST_ING; #5000; rst_n = ~RST_ING; rs232_rx = 1'b1; //I Like FPGA #1000_000; data_tx = "I"; tx_task(data_tx); #1000_000; data_tx = " "; tx_task(data_tx); #1000_000; data_tx = "L"; tx_task(data_tx); #1000_000; data_tx = "i"; tx_task(data_tx); #1000_000; data_tx = "k"; tx_task(data_tx); #1000_000; data_tx = "e"; tx_task(data_tx); #1000_000; data_tx = " "; tx_task(data_tx); #1000_000; data_tx = "F"; tx_task(data_tx); #1000_000; data_tx = "P"; tx_task(data_tx); #1000_000; data_tx = "G"; tx_task(data_tx); #1000_000; data_tx = "A"; tx_task(data_tx); //I Like Verilog #100_000_000; data_tx = "I"; tx_task(data_tx); #1000_000; data_tx = " "; tx_task(data_tx); #1000_000; data_tx = "L"; tx_task(data_tx); #1000_000; data_tx = "i"; tx_task(data_tx); #1000_000; data_tx = "k"; tx_task(data_tx); #1000_000; data_tx = "e"; tx_task(data_tx); #1000_000; data_tx = " "; tx_task(data_tx); #1000_000; data_tx = "V"; tx_task(data_tx); #1000_000; data_tx = "e"; tx_task(data_tx); #1000_000; data_tx = "r"; tx_task(data_tx); #1000_000; data_tx = "i"; tx_task(data_tx); #1000_000; data_tx = "l"; tx_task(data_tx); #1000_000; data_tx = "o"; tx_task(data_tx); #1000_000; data_tx = "g"; tx_task(data_tx); //I Like FPGA #100_000_000; data_tx = "I"; tx_task(data_tx); #1000_000; data_tx = " "; tx_task(data_tx); #1000_000; data_tx = "L"; tx_task(data_tx); #1000_000; data_tx = "i"; tx_task(data_tx); #1000_000; data_tx = "k"; tx_task(data_tx); #1000_000; data_tx = "e"; tx_task(data_tx); #1000_000; data_tx = " "; tx_task(data_tx); #1000_000; data_tx = "F"; tx_task(data_tx); #1000_000; data_tx = "P"; tx_task(data_tx); #1000_000; data_tx = "G"; tx_task(data_tx); #1000_000; data_tx = "A"; tx_task(data_tx); end task tx_task; input [7:0] rs232_tx; integer i; begin rs232_rx = 0; #BPS_9600; for(i = 0;i < 8;i = i+1) begin rs232_rx = data_tx[i]; #BPS_9600; end rs232_rx = 1; #BPS_9600; end endtask endmodule
仿真图如下:
本篇博文为记录学习所用,如有错误,请各位指正批评,如有转载请注明出处。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。