目录
1、简述
2、设计
3、实现
4、测试
1、简述
上一节描述了 Verilog 的 UART RX 过程,相对于 RX,传送数据就稍微简单一些,不需要进行线上数据的采样;
发送数据需要考虑的几点:
1、内部数据位并行,发送的时候为 tx 串行,那么就需要考虑到传送的时候的 busy 信号,并进行数据的并行转串行;
2、同样需要根据串口的配置来进行发送数据的计数
3、需要根据波特率来进行发送有效的计数
2、设计
那么根据需求进行设计如下:
1、来自 PLL 的时钟和 Locked 为模块提供 Clock 和复位信号;
2、波特率发生器根据配置的波特率来进行计数的控制;
3、当 tx_en 信号来的时候,进行来自 FIFO 的并行数据锁定,并拉高 busy;
4、根据传送的配置(数据位、校验位、停止位)来进行发送数据的计数;
5、状态机根据发送数据的计数和波特率有效信号,来进行状态转换,并将数据发送出去;
3、实现
Verilog 代码设计为(此处的波特率发生器仅仅为了仿真需要,counter 设置成为了 10,实际情况需计算,同时为了简化,数据位为8,没有校验位,停止位为1):
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 17:49:03 12/08/2019
// Design Name:
// Module Name: uart_tx
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module uart_tx(input clk,input rst_n,input tx_en,input [7:0] data,output reg busy,output reg tx);parameter BAUD_MAX = 20;parameter START_VALUE = 1'b0;parameter STOP_VALUE = 1'b1;parameter START_BIT = 1;parameter DATA_BIT = 8;parameter STOP_BIT = 1;// State Machine Definationparameter IDLE = 3'b001;parameter SAMP = 3'b010;parameter TRAS = 3'b100;reg [2:0] current_state, next_state;always @ (posedge clk or negedge rst_n)if(!rst_n)current_state <= IDLE;elsecurrent_state <= next_state;// Statereg sent_finished;always @ (current_state or tx_en or sent_finished)beginnext_state = 3'bx;case(current_state)IDLE : beginif (tx_en) next_state = SAMP;else next_state = IDLE;endSAMP : beginif (tx_en) next_state = TRAS;else next_state = IDLE;endTRAS : beginif (!tx_en) next_state = IDLE;else if (sent_finished) next_state = IDLE;else next_state = TRAS;enddefault : next_state = IDLE;endcaseendreg [9:0] data_samp;reg [4:0] baud_cnt;reg [3:0] sent_cnt;always @ (posedge clk or negedge rst_n)if (!rst_n) begindata_samp <= 10'bx;busy <= 1'b0;tx <= 1'b1;baud_cnt <= 5'b0;sent_finished <= 1'b0;sent_cnt <= 1'b0;endelse begincase (next_state)IDLE : begindata_samp <= 10'bx;busy <= 1'b0;tx <= 1'b1;baud_cnt <= 5'b0;sent_finished <= 1'b0;sent_cnt <= 1'b0;endSAMP : begin//data_samp <= {1'b1, data[0],data[1],data[2],data[3],data[4],data[5],data[6], data[7], 1'b0};data_samp <= {1'b1, data[7:0], 1'b0};busy <= 1'b1;tx <= 1'b1;baud_cnt <= 5'b0;sent_finished <= 1'b0;sent_cnt <= 1'b0;endTRAS : beginif (baud_cnt == BAUD_MAX) beginbaud_cnt <= 5'b0;if (sent_cnt == 4'd10) begindata_samp <= 10'bx;busy <= 1'b0;tx <= 1'b1;sent_finished <= 1'b1;sent_cnt <= 1'b0;endelse begindata_samp <= data_samp;busy <= 1'b1;tx <= data_samp[sent_cnt];sent_finished <= 1'b0;sent_cnt <= sent_cnt + 1'b1;endendelse beginbaud_cnt <= baud_cnt + 1'b1;endendendcaseend
endmodule
4、测试
testbench:
`timescale 1ns / 1ps// Company:
// Engineer:
//
// Create Date: 19:28:59 12/08/2019
// Design Name: uart_tx
// Module Name: G:/FPGA/Spartan_6/ise_project/sp6_stephen/sp6_stephen_pro/source_code/uart_tx_tb.v
// Project Name: sp6_stephen_pro
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: uart_tx
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// module uart_tx_tb;// Inputsreg clk;reg rst_n;reg tx_en;reg [7:0] data;// Outputswire busy;wire tx;// Instantiate the Unit Under Test (UUT)uart_tx uut (.clk(clk), .rst_n(rst_n), .tx_en(tx_en), .data(data), .busy(busy), .tx(tx));
always #1 clk = ~clk;initial begin// Initialize Inputsclk = 0;rst_n = 0;tx_en = 0;data = 0;// Wait 100 ns for global reset to finish#100;// Add stimulus hererst_n = 1;data = 8'b1010_1010;#100 tx_en = 1'b1;#500 data = 8'b0101_0101;endendmodule