【项目1:uart_fsm_led】- 第一部分-tx
最近学了状态机、串口通信,于是想要使用串口通信去控制LED翻转
主要需要3个模块去实现,于是我考虑分步骤去依次实现每个模块,并且对其仿真验证
这一篇先对数据发送模块进行测试验证
设计的框图如下:

一、设计文件
module uart_tx #( parameter CLK_FRE = 50, //clock frequency(Mhz) parameter BAUD_RATE = 115200 //serial baud rate ) ( input clk, //clock input input rst_n, //asynchronous reset input, low active input[7:0] tx_8bit, //data to send input tx_en, //data to be sent is valid output reg tx_done, //send ready output tx_1bit //serial data output ); //calculates the clock cycle for baud rate localparam CYCLE = CLK_FRE * 1000000 / BAUD_RATE; //state machine code localparam S_IDLE = 1; localparam S_START = 2;//start bit localparam S_SEND_BYTE = 3;//data bits localparam S_STOP = 4;//stop bit reg[2:0] state; reg[2:0] next_state; reg[15:0] cycle_cnt; //baud counter reg[2:0] bit_cnt;//bit counter reg[7:0] tx_data_latch; //latch data to send reg tx_reg; //serial data output assign tx_1bit = tx_reg; //第一段:同步时序,描述状态转移 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) state <= S_IDLE; else state <= next_state; end //(*)第二段:组合逻辑判断状态转移条件、描述状态转移规律 always@(*) begin case(state) S_IDLE: if(tx_en == 1'b1) next_state <= S_START; else next_state <= S_IDLE; S_START: if(cycle_cnt == CYCLE - 1) next_state <= S_SEND_BYTE; else next_state <= S_START; S_SEND_BYTE: if(cycle_cnt == CYCLE - 1 && bit_cnt == 3'd7) next_state <= S_STOP; else next_state <= S_SEND_BYTE; S_STOP: if(cycle_cnt == CYCLE - 1) next_state <= S_IDLE; else next_state <= S_STOP; default: next_state <= S_IDLE; endcase end // 发送完成标志位 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin tx_done <= 1'b0; end else if(state == S_IDLE) if(tx_en == 1'b1) tx_done <= 1'b0; else tx_done <= 1'b1; else if(state == S_STOP && cycle_cnt == CYCLE - 1) tx_done <= 1'b1; end // 输入数据锁存,方便后面并转串 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin tx_data_latch <= 8'd0; end else if(state == S_IDLE && tx_en == 1'b1) tx_data_latch <= tx_8bit; // 将输入数据锁存 end // 位计数器 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin bit_cnt <= 3'd0; end else if(state == S_SEND_BYTE) if(cycle_cnt == CYCLE - 1) bit_cnt <= bit_cnt + 3'd1; else bit_cnt <= bit_cnt; else bit_cnt <= 3'd0; end // 波特率计数器 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) cycle_cnt <= 16'd0; else if((state == S_SEND_BYTE && cycle_cnt == CYCLE - 1) || next_state != state) cycle_cnt <= 16'd0; else cycle_cnt <= cycle_cnt + 16'd1; end //第三段:同步时序,描述每个状态的输出 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) tx_reg <= 1'b1; else case(state) S_IDLE,S_STOP: tx_reg <= 1'b1; S_START: tx_reg <= 1'b0; S_SEND_BYTE: tx_reg <= tx_data_latch[bit_cnt]; default: tx_reg <= 1'b1; endcase end endmodule
二、测试文件
`timescale 1ns/1ns // 第一步:测试发送模块能否将并行数据转成串行数据 module tb_step_01; reg clk; reg rst_n; reg [7:0]tx_8bit; reg tx_en ; wire tx_1bit; wire tx_done; initial begin clk = 1'b0; rst_n = 1'b0; #12; rst_n = 1'b1; begin tx_8bit = 8'd0; tx_en = 1'b0; // 产生输入数据 # 1000;//延迟50个时钟周期 tx_8bit = 8'b0100_1111; tx_en = 1'b1;//tx_en拉高,发送端开始接收数据,当tx_en拉高1000ns后将其拉低,等数据传完后,等着tx_done拉高,就完成一个H的发送 #1000; tx_en = 1'b0; @(posedge tx_done) tx_8bit = 8'b0110_0101; tx_en = 1'b1; # 100000; tx_en = 1'b0; end end always #10 clk = ~ clk; // 调用发送模块 uart_tx uart_tx_inst ( .clk(clk), //clock input .rst_n(rst_n), //asynchronous reset input, low active .tx_8bit(tx_8bit), //data to send .tx_en(tx_en), //data to be sent is valid .tx_done(tx_done), //send ready .tx_1bit(tx_1bit) //serial data output ); endmodule
三、波形图


浙公网安备 33010602011771号