用状态机实现串口多字节数据发送
这次设计一个多字节(8-256位)且波特率可更改(通过修改例化模块的参数)的串口发送模块。
1、状态机的设定
- 状态机的设定有空闲、发送、和数据移位三个状态,其中空闲状态为等待多字节发送的信号;
- 发送状态为给8位串口发送模块传输待发送的8位数据,同时判断是否发送完数据回到空闲状态;
- 数据移位状态为等到前面8位字节数据发送完后,将接下来待发送的8位数据移动到数据寄存器的低8位中。若数据在发送中则会进行等待;
2、需要的模块
(1)8位串口发送模块
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Engineer: Lclone // // Create Date: 2022/12/10 00:21:40 // Design Name: uart_byte_tx // Module Name: uart_byte_tx // Project Name: uart_byte_tx // Description: 8位串口发送模块,波特率可通过参数设置。 // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module uart_byte_tx #( parameter TX_BAUD = 9600, parameter CLK_FQC = 50_000_000, parameter BAUD_CNT = CLK_FQC/TX_BAUD) ( input [7:0] Data, input Send_en, input Clk, input Rst_n, output reg Uart_Tx, output reg Tx_done ); reg [15:0] baud_cnt; reg [ 3:0] bit_cnt; reg Send_en_r; reg Send_en_rr; reg Tx_flag; always @(posedge Clk) begin Send_en_r <= Send_en; Send_en_rr <= Send_en_r; end always @(posedge Clk or negedge Rst_n) begin if(Rst_n == 0) Tx_flag <= 0; else if(~Send_en_rr & Send_en_r) Tx_flag <= 1'b1; else if(bit_cnt == 10 - 1 & baud_cnt == BAUD_CNT - 1) Tx_flag <= 1'b0; end always @(posedge Clk or negedge Rst_n) begin if(Rst_n == 0) baud_cnt <= 0; else if(baud_cnt == BAUD_CNT - 1) baud_cnt <= 0; else if(Tx_flag) baud_cnt <= baud_cnt + 1'b1; end always @(posedge Clk or negedge Rst_n) begin if(Rst_n == 0) bit_cnt <= 0; else if(bit_cnt == 10 - 1 & baud_cnt == BAUD_CNT - 1) bit_cnt <= 0; else if(baud_cnt == BAUD_CNT - 1) bit_cnt <= bit_cnt + 1'b1; end always @(posedge Clk or negedge Rst_n) begin if(Rst_n == 0) Uart_Tx <= 1'b1; else if(Tx_flag == 0) Uart_Tx <= 1'b1; else case(bit_cnt) 0: Uart_Tx <= 1'b0; 1: Uart_Tx <= Data[0]; 2: Uart_Tx <= Data[1]; 3: Uart_Tx <= Data[2]; 4: Uart_Tx <= Data[3]; 5: Uart_Tx <= Data[4]; 6: Uart_Tx <= Data[5]; 7: Uart_Tx <= Data[6]; 8: Uart_Tx <= Data[7]; 9: Uart_Tx <= 1'b1; default: Uart_Tx <= 1'b1; endcase end always @(posedge Clk or negedge Rst_n) begin if(Rst_n == 0) Tx_done <= 1'b0; else if(bit_cnt == 9 & baud_cnt == BAUD_CNT - 1) Tx_done <= 1'b1; else Tx_done <= 1'b0; end endmodule
3、设计的模块代码
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 2022/12/12 19:14:03 // Design Name: uart_bytes_tx // Module Name: uart_bytes_tx_3 // Project Name: uart_bytes_tx // Target Devices: xc7z020clg400-1 // Tool Versions: 2018.3 // Description: 多字节(8-256位)且波特率可更改(通过修改例化模块的参数)的串口发送模块。 // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module uart_bytes_tx_3 #( parameter DATA_WIDTH = 40, //待发送的数据位宽 parameter ROUNDS = DATA_WIDTH/8) //数据发送的次数(例化时不需要设置) ( input Clk, //时钟信号 input Rst_n, //复位信号 input [DATA_WIDTH-1:0] Bytes_data, //多字节数据端口 input Send_bytes_en, //多字节发送使能 output reg Tx_bytes_done, //多字节发送结束 output wire Uart_Tx //串口发送端口 ); reg [ 2:0] state; //状态寄存器 reg [DATA_WIDTH-1:0] bytes_data_reg; //多字节数据寄存器 reg [ 7:0] data_reg; //待发送的8位数据寄存器 reg send_en; //8位数据的发送使能 wire tx_done; //8位数据的发送结束 reg [ 4:0] rounds; //需要发送的次数 uart_byte_tx //串口8位发送模块 # ( .TX_BAUD (9600), //波特率 .CLK_FQC (50_000_000)) //模块的时钟频率 uart_byte_tx_inst ( .Data (data_reg), .Send_en (send_en), .Clk (Clk), .Rst_n (Rst_n), .Uart_Tx (Uart_Tx), .Tx_done (tx_done) ); always @(posedge Clk or negedge Rst_n) begin //数据寄存 if(Rst_n == 0) bytes_data_reg <= 0; else if(Send_bytes_en) bytes_data_reg <= Bytes_data; else bytes_data_reg <= bytes_data_reg; end always @(posedge Clk or negedge Rst_n) begin //状态机 if(Rst_n == 0) begin state <= 0; data_reg <= 0; send_en <= 0; Tx_bytes_done <= 0; end else case(state) 0: begin if(Send_bytes_en) state <= 3'b1; else begin state <= 0; data_reg <= 0; send_en <= 0; Tx_bytes_done <= 0; end end 1: begin if(rounds == ROUNDS) begin Tx_bytes_done <= 1'b1; state <= 0; end else begin data_reg <= bytes_data_reg[7:0]; send_en <= 1'b1; state <= 3'd2; end end 2: begin send_en <= 0; if(tx_done) begin bytes_data_reg <= bytes_data_reg >> 8; state <= 3'd1; end else state <= 3'd2; end endcase end always @(posedge Clk or negedge Rst_n) begin //发送次数计数 if(Rst_n == 0) rounds <= 0; else if(rounds == ROUNDS & state == 1) rounds <= 0; else if(tx_done) rounds <= rounds + 1'b1; end endmodule
4、仿真验证
(1)仿真激励
`timescale 1ns / 1ps module uart_bytes_tx_tb(); reg Clk; reg Rst_n; reg Send_bytes_en; reg [63:0]Bytes_data; wire Tx_bytes_done; wire Uart_Tx; uart_bytes_tx_3 # ( .DATA_WIDTH (64)) uart_bytes_tx_inst ( .Clk (Clk), .Rst_n (Rst_n), .Bytes_data (Bytes_data), .Send_bytes_en (Send_bytes_en), .Tx_bytes_done (Tx_bytes_done), .Uart_Tx (Uart_Tx) ); defparam uart_bytes_tx_inst.uart_byte_tx_inst.BAUD_CNT = 10; initial Clk <= 1'b1; always #10 Clk <= ~Clk; initial begin Rst_n <= 0; Bytes_data <= 0; Send_bytes_en <= 0; #200 Rst_n <= 1'b1; #20 Bytes_data <= 64'h0123456789abcdef; Send_bytes_en <= 1'b1; #20 Send_bytes_en <= 0; #20000 Bytes_data <= 64'hfedcba9876543210; Send_bytes_en <= 1'b1; #20 Send_bytes_en <= 0; @(posedge Tx_bytes_done) #100 $stop; end endmodule
(2)仿真波形
第一轮发送:
两轮发送:
本文作者:FPGA与ZYNQ的学习笔记
本文链接:https://www.cnblogs.com/Lclone/p/16980903.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步