【项目1:uart_fsm_led】- 完结篇-tx-rx-fsm
经过调试,以及通过大佬的指点,终于实现这个小项目的功能:
使用上位机给FPGA发送数据,当FPGA检测到 led 字符串后就将灯反转
一、设计文件
模块一:tx发送模块
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
模块二:rx接收模块
module uart_rx #( 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 output reg[7:0] rx_8bit, //received serial data output reg rx_done, //received serial data is valid input rx_en, //data receiver module ready input rx_1bit //serial data input ); //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_REC_BYTE = 3; //data bits localparam S_STOP = 4; //stop bit localparam S_DATA = 5; reg[2:0] state; reg[2:0] next_state; reg rx_d0; //delay 1 clock for rx_1bit reg rx_d1; //delay 1 clock for rx_d0 wire rx_negedge; //negedge of rx_1bit reg[7:0] rx_bits; //temporary storage of received data reg[15:0] cycle_cnt; //baud counter reg[2:0] bit_cnt; //bit counter // 边沿检测 assign rx_negedge = rx_d1 && ~rx_d0; // 异步串口通信:这里需要将输入信号打2拍 // 目的:将输入信号与系统时钟同步,防止出现亚稳态 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin rx_d0 <= 1'b0; rx_d1 <= 1'b0; end else begin rx_d0 <= rx_1bit; rx_d1 <= rx_d0; end end //第一段:同步时序,描述状态转移 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(rx_negedge) next_state <= S_START; else next_state <= S_IDLE; S_START: if(cycle_cnt == CYCLE - 1)//one data cycle next_state <= S_REC_BYTE; else next_state <= S_START; S_REC_BYTE: if(cycle_cnt == CYCLE - 1 && bit_cnt == 3'd7) //receive 8bit data next_state <= S_STOP; else next_state <= S_REC_BYTE; S_STOP: if(cycle_cnt == CYCLE/2 - 1)//half bit cycle,to avoid missing the next byte receiver next_state <= S_DATA; else next_state <= S_STOP; S_DATA: if(rx_en) //data receive complete next_state <= S_IDLE; else next_state <= S_DATA; default: next_state <= S_IDLE; endcase end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) rx_done <= 1'b0; else if(state == S_STOP && next_state != state) rx_done <= 1'b1; else if(state == S_DATA && rx_en) rx_done <= 1'b0; end //第三段:同步时序,描述每个状态的输出 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) rx_8bit <= 8'd0; else if(state == S_STOP && next_state != state) rx_8bit <= rx_bits;//latch received data end // 接收的数据计数位 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin bit_cnt <= 3'd0; end else if(state == S_REC_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_REC_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)//next_state != state:状态发生跳转 cycle_cnt <= 16'd0; else cycle_cnt <= cycle_cnt + 16'd1; end //receive serial data bit data always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) rx_bits <= 8'd0; else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1) rx_bits[bit_cnt] <= rx_1bit;//串并转换 else rx_bits <= rx_bits; end endmodule
模块三:状态机模块
module fsm_led ( input clk , input rst_n , input [7:0]fsm_8bit , input fsm_en , output reg led ); // 定义状态位宽 reg [2:0] state ; reg [2:0] next_state ; // 状态编码 parameter l = 3'd1, e = 3'd2, d = 3'd3 ,IDLE = 3'd0; //第一段:固定格式得到状态 always @(posedge clk or negedge rst_n)begin if(rst_n == 1'b0) state <= IDLE; else state <= next_state; end //第二段:组合逻辑,描述状态转移 always @(posedge clk or negedge rst_n)begin if(rst_n == 1'b0) next_state <= IDLE; else if(fsm_en == 1'b1)begin//输入使能信号拉高 //else begin case(state) IDLE: if(fsm_8bit == "l") next_state <= l; else next_state <= IDLE; l: if(fsm_8bit == "e") next_state <= e; else next_state <= IDLE; e: if(fsm_8bit == "d") next_state <= d; else next_state <= IDLE; d: if(fsm_8bit == "l") next_state <= l; else next_state <= IDLE; default: next_state <= IDLE; endcase end end //第三段:输出信号 always @(posedge clk or negedge rst_n)begin if(rst_n == 1'b0) led <= 1'b0; else if(state == e && next_state == d)begin led <= ~led; end else begin led <= led; end end endmodule
顶层模块
module top_final ( input clk, input rst_n, input rx_1bit, output led , output tx_1bit ); wire [7:0]rx_8bit,rx_done; uart_tx uart_tx_inst ( .clk(clk), //clock input .rst_n(rst_n), //asynchronous reset input, low active .tx_8bit(rx_8bit), //data to send .tx_en(rx_done), //data to be sent is valid .tx_done(), //send ready .tx_1bit(tx_1bit) //serial data output ); uart_rx uart_rx_inst ( .clk(clk), //clock input .rst_n(rst_n), //asynchronous reset input, low active .rx_8bit(rx_8bit), //received serial data .rx_done(rx_done), //received serial data is valid .rx_en(1'b1), //data receiver module ready .rx_1bit(rx_1bit) //serial data input ); fsm_led ( .clk(clk) , .rst_n(rst_n) , .fsm_8bit(rx_8bit) , .fsm_en(rx_done) , .led(led) ); endmodule
二、测试文件
`timescale 1ns/1ns // 第三步:甲状态机 module tb_step_03; reg clk; reg rst_n; // tx输入 reg [7:0] tx_8bit ; reg tx_en ; // tx输出 wire tx_1bit; wire tx_done; //// rx输入 reg rx_1bit; reg rx_en; // rx输出 wire [7:0]rx_8bit; wire rx_done; // led 输出 wire led; //assign fsm_en = 1'b1; initial begin clk = 1'b0; rst_n = 1'b0; #12; rst_n = 1'b1; begin tx_8bit = 8'd0; tx_en = 1'b0; // 产生输入数据 # 1000; tx_8bit = 8'b0100_1111;//O tx_en = 1'b1; rx_en = 1'b1; @(posedge tx_done) tx_8bit = 8'b0110_1100;//l @(posedge tx_done)// 发送数据的过程中 tx_8bit = 8'b0110_0101;//e @(posedge tx_done) tx_8bit = 8'b0110_0100;//d @(posedge tx_done) tx_8bit = 8'b0110_1100;//l @(posedge tx_done) tx_8bit = 8'b0100_1111;//O @(posedge tx_done) tx_8bit = 8'b0110_0100;//d @(posedge tx_done) tx_8bit = 8'b0110_1100;//l @(posedge tx_done) tx_8bit = 8'b0110_0101;//e @(posedge tx_done) tx_8bit = 8'b0110_0100;//d @(posedge tx_done) tx_8bit = 8'b0110_1100;//l @(posedge tx_done) 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 ); uart_rx uart_rx_inst ( .clk(clk), //clock input .rst_n(rst_n), //asynchronous reset input, low active .rx_8bit(rx_8bit), //received serial data .rx_done(rx_done), //received serial data is valid .rx_en(rx_en), //data receiver module ready .rx_1bit(tx_1bit) //serial data input ); fsm_led fsm_led_inst ( .clk(clk) , .rst_n(rst_n) , .fsm_8bit(rx_8bit) , .fsm_en(rx_done) , .led(led) ); endmodule
三、波形图
四、上板验证
使用上位机发送led,每检测到一次led,就将灯反转一次