首页 > 其他分享 >用状态机实现串口多字节数据发送

用状态机实现串口多字节数据发送

时间:2022-12-13 22:55:19浏览次数:39  
标签:发送 字节 tx uart bytes 状态机 Tx 串口 reg

这次设计一个多字节(8-256位)且波特率可更改(通过修改例化模块的参数)的串口发送模块。

1、状态机的设定

image

  • 状态机的设定有空闲、发送、和数据移位三个状态,其中空闲状态为等待多字节发送的信号;
  • 发送状态为给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)仿真波形

第一轮发送:
image
两轮发送:
image

标签:发送,字节,tx,uart,bytes,状态机,Tx,串口,reg
From: https://www.cnblogs.com/Lclone/p/16980903.html

相关文章

  • 整型变量(int)与字节数组(byte[])的相互转换
    //int2byte.cpp:定义控制台应用程序的入口点。//#include"stdafx.h"#include<Windows.h>/*#defineMAKEWORD(a,b)((WORD)(((BYTE)(((DWORD_PTR)(a))&0xff))|((W......
  • 清晰讲解LSB、MSB和大小端模式及网络字节序
    时隔一个月又回到了写文章,很开心O(∩_∩)O~~今天在做需求的涉及到一个固件版本的概念,其中固件组的人谈到了版本号从​​MSB​​​到​​LSB​​排列,检索查阅后将所得整理如......
  • js字符串转字节stringToByte
    functionstringToByte(str){varlen,c;len=str.length;varbytes=[];for(vari=0;i<len;i++){c=str.charCodeAt(i);......
  • 14 HotSpot将字节码变为机器码的过程
    目录1广义理解:解释执行与编译执行1HotSpot虚拟机基本介绍1为何HotSpot虚拟机要使用解释器与即时编译器并存的架构?2为何HotSpot虚拟机要实现两个(或三个)不同的即时编译器......
  • [记] rust获取windows虚拟串口
    comportlist="0.1.2"  usecomportlist::available_ports;foridxinavailable_ports(vec!["CNCPorts","Ports"]){ifletSome(ss)=idx.serial_number......
  • 字节流简述
    字节简述字节概述字节(byte)是计算机用于计量存储容量的一中计量单位。B(字节)KB(千字节)无论网络上两个终端需要传输什么数据,都需要传输二进制bit的数据。既然传输的都是b......
  • 0停机迁移Nacos?Java字节码技术来帮忙
    摘要:本文介绍如何将SpringCloud应用从开源Consul无缝迁移至华为云Nacos。本文分享自华为云社区《0停机迁移Nacos?Java字节码技术来帮忙》,作者:华为云PaaS服务小智。1.市场......
  • 浅谈字节码增强技术系列1-字节码增强概览
    作者:董子龙前言前段时间一直想参照lombok的实现原理写一篇可以生成业务单据修改记录插件的专利,再查阅资料的过程中,偶然了解到了字节码增强工具-byteBuddy。但是由于当时时间......
  • Java 字节码增强技术小记
    总结是什么:字节码增强技术用于对静态字节码文件进行修改或动态修改运行中的程序。使用场景有【动态代理、AOP、ORM框架】、【热部署、Mock测试、性能诊断工具】等,例如动......
  • 2021 届 字节跳动 校招提前批开始啦~~~
    又是一年校招季~~字节跳动的2021届校招提前批已经开始了~~因为疫情,今年各家公司的大规模校园宣讲多多少少都会受到影响。所以大家一定要特别关注校招的线上宣传活动,公众号......