11 串口发送应用之使用状态机实现多字节数据发送

news2024/9/25 2:32:39

1. 使用串口发送5个字节数据到电脑

uart协议规定,发送的数据位只能是6,7,8位,如果数据位不符合,接收者接收不到数据。所以我们需要将40位数据data分为5个字节数据分别发送,那么接收者就能通过uart协议接收到数据了。

2. 第一次使用状态机写设计代码(不够简洁的版本)

为什么要使用状态机:由于在always语句块中,语句是并行执行的,当我想要处理有先后顺序的问题时,就需要用状态机来解决。

针对发送五个字节数据到电脑的目的按,可将状态机的使用分为以下三种情况:

1. 没有开始发送(数据请求trans_go信号没有出现)

2. 数据请求trans_go信号出现

3. 数据请求trans_go信号出现

2.1 设计代码

module uart_tx_data(
    clk,
    rstn,
    trans_go,
    data40,
    uart_tx,
    trans_done
);

    input clk;
    input rstn;
    input trans_go;
    input [39:0] data40;
    output uart_tx;
    output reg trans_done;
    
    reg [7:0] data;
    reg send_go;
    wire tx_done;
    
    uart_byte_tx uart_byte_tx(
        .clk(clk),
        .rstn(rstn),
        .blaud_set(3'd4),
        .data(data),
        .send_go(send_go),
        .uart_tx(uart_tx),
        .tx_done(tx_done)
    );
    
    reg [2:0]state;
    always@(posedge clk or negedge rstn)
    if(!rstn) begin
        state <= 0;
        send_go <= 0;
        data <= 0;
        trans_done <= 0;
    end    
    else 
        case(state)
        0:  begin
                if(trans_go)begin
                    trans_done <= 0;
                    data <= data40[7:0];
                    send_go <= 1;
                    state <= 1;
                end
                else begin
                    data <= data;
                    send_go <= 0;
                    state <= 0;
                end
            end
            
        1:begin
              if(tx_done)begin
                  data <= data40[15:8];
                  send_go <= 1;
                  state <= 2;
              end
              else 
                  send_go <= 0;
          end

       2:begin
              if(tx_done)begin
                  data <= data40[23:16];
                  send_go <= 1;
                  state <= 3;
              end
              else
                  send_go <= 0;
         end
            
       3:begin
              if(tx_done)begin
                  data <= data40[31:24];
                  send_go <= 1;
                  state <= 4;
              end
              else
                  send_go <= 0;
         end

       4:begin
              if(tx_done)begin
                  data <= data40[39:32];
                  send_go <= 1;
                  state <= 5;
              end
              else
                  send_go <= 0;
          end
        
        5:begin
              if(tx_done)begin
                  trans_done <= 1;
                  state <= 0;
              end
              else
                  send_go <= 0;
           end
        default: begin
                data <= data;
                send_go <= 0;
                state <= 0;
        end
     endcase

endmodule
module uart_byte_tx(
    clk,
    rstn,
    blaud_set,
    data,
    send_go,
    uart_tx,
    tx_done
);
    
    input clk;
    input rstn;
    input [2:0]blaud_set;
    input [7:0]data;
    input send_go;
    output reg uart_tx;
    output tx_done;
    
    //Blaud_set = 0时,波特率 = 9600;
    //Blaud_set = 1时,波特率 = 19200;
    //Blaud_set = 2时,波特率 = 38400;
    //Blaud_set = 3时,波特率 = 57600;
    //Blaud_set = 4时,波特率 = 115200;
    
    reg[17:0] bps_dr;
    always@(*)
        case(blaud_set)
            0: bps_dr = 1000000000/9600/20;
            1: bps_dr = 1000000000/19200/20;
            2: bps_dr = 1000000000/38400/20;
            3: bps_dr = 1000000000/57600/20;
            4: bps_dr = 1000000000/115200/20;
        endcase
        
    reg [7:0] r_data;
    always@(posedge clk)
    if(send_go)
        r_data <= data;
    else
        r_data <= r_data;
        
    reg send_en;  
    always@(posedge clk or negedge rstn)
    if(!rstn)
        send_en <= 0;
    else if(send_go)
        send_en <= 1;
    else if(tx_done)
        send_en <= 0;
        
    
    wire bps_clk;
    assign bps_clk = (div_cnt == 1);
    reg[17:0] div_cnt;
    always@(posedge clk or negedge rstn)
    if(!rstn)
        div_cnt <= 0;
    else if(send_en)begin
        if(div_cnt == (bps_dr - 1))
            div_cnt <= 0;
        else
            div_cnt <= div_cnt + 1'd1;
    end
    else
        div_cnt <= 0;    
    
    reg[3:0] bps_cnt;    
    always@(posedge clk or negedge rstn)
    if(!rstn)
        bps_cnt <= 0;
    else if(send_en)begin
        if(bps_cnt == 11)
            bps_cnt <= 0;
        else if(div_cnt == 1)
            bps_cnt <= bps_cnt + 4'd1;
    end
    else
        bps_cnt <= 0;
    
    reg tx_done;
    always@(posedge clk or negedge rstn)
    if(!rstn)
        uart_tx <= 1'd1;
    else 
        case(bps_cnt)
            0: tx_done <= 0;
            1: uart_tx <= 1'd0;
            2: uart_tx <= r_data[0];
            3: uart_tx <= r_data[1];
            4: uart_tx <= r_data[2];
            5: uart_tx <= r_data[3];
            6: uart_tx <= r_data[4];
            7: uart_tx <= r_data[5];
            8: uart_tx <= r_data[6];
            9: uart_tx <= r_data[7];
            10: uart_tx <= 1'd1;
            11: begin uart_tx <= 1'd1; tx_done <= 1; end
            default: uart_tx <= 1'd1;
        endcase
 
endmodule

2.2 仿真代码(学习trans_go脉冲信号以及数据发送完成信号)

以下两点需要学习:

  1. 通过控制trans_go信号的产生与结束,来模拟一个周期的脉冲信号
  2. 通过增加一个输出端口tx_done,来通知我输出何时完成
`timescale 1ns / 1ps

module uart_tx_data_tb();
    
    reg clk;
    reg rstn;
    reg trans_go;
    reg [39:0]data40;
    wire trans_done;
    wire uart_tx;

    uart_tx_data uart_tx_data_inst(
        .clk(clk),
        .rstn(rstn),
        .trans_go(trans_go),
        .data40(data40),
        .trans_done(trans_done),
        .uart_tx(uart_tx)
    );

    initial clk = 1;
    always #10 clk = ~clk;
    
    initial begin
        rstn = 0;
        trans_go = 0;
        data40 = 0;
        #201;
        rstn = 1;
        #200;
        data40 = 40'h123456789a;
        trans_go = 1; //trans_go脉冲信号的模拟
        #20;
        trans_go = 0; //trans_go脉冲信号的模拟
        @(posedge trans_done) //数据发送完成信号的标识
        #200000;
        
        data40 = 40'ha987654321;
        trans_go = 1;
        #20;
        trans_go = 0;
        @(posedge trans_done)
        #200000;
        $stop;
    end

endmodule

仿真波形

3. 优化状态机代码

1. 任务:优化状态机,实现只要个或3个状态实现发送的功能,并且易于修改为发送任意个字节的数据

2. 征集不使用状态机的思想来实现本任务的方案

任务1完成如下,对于任务2,我的思路是:由于fpga是并行发送数据的,如果我们想要多字节发送数据的话,肯定需要将多字节串起来发送,所以我们可以将五个字节的数据串起来,每个字节之间相隔起始位和结束位,以此来达到在遵循协议的情况下实现多字节的输出。

3.1 设计代码(三个状态):

三个状态:

状态1.等待发送请求

状态2.等待单字节数据发送完成

状态3.检查所有数据是否发送完成

module uart_tx_data1(
    clk,
    rstn,
    trans_go,
    data40,
    uart_tx,
    trans_done
);

    input clk;
    input rstn;
    input trans_go;
    input [39:0] data40;
    output uart_tx;
    output reg trans_done;
    
    reg [7:0] data;
    reg send_go;
    wire tx_done;
    
    uart_byte_tx uart_byte_tx(
        .clk(clk),
        .rstn(rstn),
        .blaud_set(3'd4),
        .data(data),
        .send_go(send_go),
        .uart_tx(uart_tx),
        .tx_done(tx_done)
    );
    
    reg [2:0]state;
    reg [2:0]counter;
    always@(posedge clk or negedge rstn)
    if(!rstn) begin
        state <= 0;
        send_go <= 0;
        data <= 0;
        trans_done <= 0;
        counter <= 0;
    end    
    else 
        case(state)
        0:begin //等待发送请求
              if(trans_go)begin 
                  trans_done <= 0;
                  send_go <= 1;
                  data <= (data40>>8*counter);
                  state <= 1;
              end
              else begin 
                  data <= data;
                  send_go <= 0;
                  state <= 0;
              end
            end
            
        1:begin //等待单字节数据发送完成
                if(tx_done)begin
                    counter <= counter + 1'd1;
                    state <= 2;
                end
                else 
                    send_go <= 0;
          end
        
        2:begin //检查所有数据是否发送完成
            if(counter == 5) begin
                  trans_done <= 1;
                  state <= 0;
                  counter <= 0;
            end
            else begin
                  send_go <= 1;
                  data <= (data40>>(8*counter));
                  state <= 1;
             end
           end
           
        default: begin
                data <= data;
                send_go <= 0;
                state <= 0;
        end
     endcase

endmodule

 

module uart_byte_tx(
    clk,
    rstn,
    blaud_set,
    data,
    send_go,
    uart_tx,
    tx_done
);
    
    input clk;
    input rstn;
    input [2:0]blaud_set;
    input [7:0]data;
    input send_go;
    output reg uart_tx;
    output tx_done;
    
    //Blaud_set = 0时,波特率 = 9600;
    //Blaud_set = 1时,波特率 = 19200;
    //Blaud_set = 2时,波特率 = 38400;
    //Blaud_set = 3时,波特率 = 57600;
    //Blaud_set = 4时,波特率 = 115200;
    
    reg[17:0] bps_dr;
    always@(*)
        case(blaud_set)
            0: bps_dr = 1000000000/9600/20;
            1: bps_dr = 1000000000/19200/20;
            2: bps_dr = 1000000000/38400/20;
            3: bps_dr = 1000000000/57600/20;
            4: bps_dr = 1000000000/115200/20;
        endcase
        
    reg [7:0] r_data;
    always@(posedge clk)
    if(send_go)
        r_data <= data;
    else
        r_data <= r_data;
        
    reg send_en;  
    always@(posedge clk or negedge rstn)
    if(!rstn)
        send_en <= 0;
    else if(send_go)
        send_en <= 1;
    else if(tx_done)
        send_en <= 0;
        
    
    wire bps_clk;
    assign bps_clk = (div_cnt == 1);
    reg[17:0] div_cnt;
    always@(posedge clk or negedge rstn)
    if(!rstn)
        div_cnt <= 0;
    else if(send_en)begin
        if(div_cnt == (bps_dr - 1))
            div_cnt <= 0;
        else
            div_cnt <= div_cnt + 1'd1;
    end
    else
        div_cnt <= 0;    
    
    reg[3:0] bps_cnt;    
    always@(posedge clk or negedge rstn)
    if(!rstn)
        bps_cnt <= 0;
    else if(send_en)begin
        if(bps_cnt == 11)
            bps_cnt <= 0;
        else if(div_cnt == 1)
            bps_cnt <= bps_cnt + 4'd1;
    end
    else
        bps_cnt <= 0;
    
    reg tx_done;
    always@(posedge clk or negedge rstn)
    if(!rstn)
        uart_tx <= 1'd1;
    else 
        case(bps_cnt)
            0: tx_done <= 0;
            1: uart_tx <= 1'd0;
            2: uart_tx <= r_data[0];
            3: uart_tx <= r_data[1];
            4: uart_tx <= r_data[2];
            5: uart_tx <= r_data[3];
            6: uart_tx <= r_data[4];
            7: uart_tx <= r_data[5];
            8: uart_tx <= r_data[6];
            9: uart_tx <= r_data[7];
            10: uart_tx <= 1'd1;
            11: begin uart_tx <= 1'd1; tx_done <= 1; end
            default: uart_tx <= 1'd1;
        endcase
 
endmodule

 

仿真代码

`timescale 1ns / 1ps

module uart_tx_data1_tb();
    
    reg clk;
    reg rstn;
    reg trans_go;
    reg [39:0]data40;
    wire trans_done;
    wire uart_tx;

    uart_tx_data1 uart_tx_data_inst1(
        .clk(clk),
        .rstn(rstn),
        .trans_go(trans_go),
        .data40(data40),
        .trans_done(trans_done),
        .uart_tx(uart_tx)
    );

    initial clk = 1;
    always #10 clk = ~clk;
    
    initial begin
        rstn = 0;
        trans_go = 0;
        data40 = 0;
        #201;
        rstn = 1;
        #200;
        data40 = 40'h123456789a;
        trans_go = 1;
        #20;
        trans_go = 0;
        @(posedge trans_done);
        #200000;
        
        data40 = 40'ha987654321;
        trans_go = 1;
        #20;
        trans_go = 0;
        @(posedge trans_done);
        #200000;
        $stop;
    end

endmodule

仿真波形

3.2 调试

调试1:counter位宽给错了,counter要记到5,但是只给了[1:0]两位:

调试2:counter记到5后未清零,导致数据多发了三次,且由于data = data40>>8*counter,导致数据为00:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1440033.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mobile ALOHA 2: An Enhanced Low-Cost Hardware for Bimanual Teleoperation

文章目录 1. Mobile ALOHA 11.1 项目地址 2. Mobile ALOHA 22.1 相关链接2.2 Whats upgraded in II ? Reference Stanford 最新家务机器人 1. Mobile ALOHA 1 Mobile ALOHA: Learning Bimanual Mobile Manipulation with Low-Cost Whole-Body Teleoperation 1.1 项目地址 htt…

CoreSight学习笔记

文章目录 1 Components1.1 ROM Table 2 使用场景2.1 Debug Monitor中断2.1.1 参考资料 2.2 Programming the cross halt2.2.1 编程实现2.2.2 参考资料 2.3 CTI中断2.3.1 编程实现2.3.1.1 准备工作2.3.1.2 触发中断2.3.1.3 中断响应 2.3.2 参考资料 1 Components 1.1 ROM Table…

力扣热门100题 - 4.寻找两个正序数组的中位数

力扣热门100题 - 4.寻找两个正序数组的中位数 题目描述&#xff1a;示例&#xff1a;提示&#xff1a;解题思路&#xff1a;代码&#xff1a; 题目链接&#xff1a;4.寻找两个正序数组的中位数 题目描述&#xff1a; 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&a…

【golang】23、gorilla websocket 源码:examples、数据结构、流程

文章目录 一、examples1.1 echo1.1.1 server.go1.1.2 client.go 1.2 command1.2.1 功能和启动方式1.2.2 home.html1.2.3 main.go 1.3 filewatch1.3.1 html1.3.2 serveHome 渲染模板1.3.3 serveWs1.3.4 writer() 1.4 buffer pool1.4.1 server1.4.2 client 1.5 chat1.5.1 server1…

掌握虚拟化与网络配置之道:深入浅出VMware及远程管理技巧

目录 虚拟机介绍 虚拟机的关键字 服务器架构的发展 为什么用虚拟机VMware 虚拟机和阿里云的区别 功能角度 价格因素 应用场景 优势方面 找到windows的服务管理 配置VMware 关于VMware安装的几个服务 vmware如何修改各种网络配置 关于NAT的详细信息(了解) NAT(网…

【芯片设计- RTL 数字逻辑设计入门 11 -- 移位运算与乘法】

请阅读【嵌入式开发学习必备专栏 】 文章目录 移位运算与乘法Verilog Codeverilog 拼接运算符&#xff08;{}&#xff09;Testbench CodeVCS 波形仿真 问题小结 移位运算与乘法 已知d为一个8位数&#xff0c;请在每个时钟周期分别输出该数乘1/3/7/8,并输出一个信号通知此时刻输…

LLaMA 入门指南

LLaMA 入门指南 LLaMA 入门指南LLaMA的简介LLaMA模型的主要结构Transformer架构多层自注意力层前馈神经网络Layer Normalization和残差连接 LLaMA模型的变体Base版本Large版本Extra-Large版本 LLaMA模型的特点大规模数据训练 LLaMA模型常用数据集介绍公共数据来源已知的数据集案…

物理信息神经网络(PINN): 将物理知识融合到深度学习中

物理信息神经网络&#xff08;PINN&#xff09;: 将物理知识融合到深度学习中 物理信息神经网络&#xff08;PINN&#xff09;简介PINN的工作原理PINN模型如何利用物理法则指导模型训练1. 定义物理问题和相应的物理定律2. 构建神经网络3. 定义损失函数数据误差项 (Data-fidelit…

Docker-Learn(三)创建镜像Docker(换源)

根据之前的内容基础&#xff0c;本小点的内容主要涉及到的内容是比较重要的文本Dockerfile 1. 编辑Dockerfile 启动命令行终端&#xff08;在自己的工作空间当中&#xff09;,创建和编辑Dockerfile。 vim Dockerfile然后写入以下内容 # 使用一个基础镜像 FROM ubuntu:late…

Mysql为什么使用B+Tree作为索引结构

B树和B树 一般来说&#xff0c;数据库的存储引擎都是采用B树或者B树来实现索引的存储。首先来看B树&#xff0c;如图所示&#xff1a; B树是一种多路平衡树&#xff0c;用这种存储结构来存储大量数据&#xff0c;它的整个高度会相比二叉树来说&#xff0c;会矮很多。 而对于数…

苹果推出新型开源AI图像编辑模型“MGIE”;可汗学院辅助学习的GPT,Prompt 质量非常高

&#x1f989; AI新闻 &#x1f680; 苹果推出新型开源AI图像编辑模型“MGIE” 摘要&#xff1a;苹果公司最近发布了一个名为“MGIE”的开源人工智能模型&#xff0c;旨在通过自然语言指令对图片进行编辑。MGIE&#xff0c;全称MLLM-Guided Image Editing&#xff0c;依赖于多…

文献速递:肿瘤分割---- 弱监督教师-学生网络用于非增强图像的肝脏肿瘤分割

文献速递&#xff1a;肿瘤分割---- 弱监督教师-学生网络用于非增强图像的肝脏肿瘤分割 01 文献速递介绍 准确的肝脏肿瘤分割对放射科医师来说是必不可少的&#xff0c;以诊断和治疗肝脏肿瘤并提高患者的生存率&#xff08;Radtke 等人&#xff0c;2007年&#xff09;。特别是…

代码随想录算法训练营29期|day44 任务以及具体任务

动态规划&#xff1a;完全背包理论基础 本题力扣上没有原题&#xff0c;大家可以去卡码网第52题 (opens new window)去练习&#xff0c;题意是一样的。 #算法公开课 《代码随想录》算法视频公开课 (opens new window)&#xff1a;带你学透完全背包问题&#xff01; (opens …

HTML 标签

HTML&#xff1a;超文本标记语言 HTML骨架结构&#xff1a; html标签&#xff1a;网页的整体 head标签&#xff1a;网页的头部 body标签&#xff1a;网页的身体 HTML的注释 VS code中&#xff1a;ctrl/ 浏览器不会执行注释 HTML标签的构成&#xff1a; 双标签&#xff1a…

Kubernetes基础(十四)-Cluster Autoscaler

Kubernetes 给出的解决方案就是&#xff1a;自动伸缩&#xff08;auto-scaling&#xff09;&#xff0c;通过自动伸缩组件之间的配合&#xff0c;可以 7*24 小时的监控着k8s集群&#xff0c;动态变化负载&#xff0c;以适应用户需求。 1 自动伸缩组件 1.1 自动伸缩类型 1.1.…

VsCode中常用的正则表达式操作

在vscode中可以使用正则表达式来进行搜索内容&#xff0c;极大的方便了我们对大量数据中需要查看的信息进行筛选&#xff0c;使用正则搜索时点击 .* 此文章会持续补充常用的正则操作 1.光标选中搜索到的内容 将搜索的内容进行全选&#xff0c;举例&#xff1a;在如下文件中我需…

基于Linux的HTTP代理服务器搭建与配置实战

在数字化世界中&#xff0c;HTTP代理服务器扮演着至关重要的角色&#xff0c;它们能够帮助我们管理网络请求、提高访问速度&#xff0c;甚至在某些情况下还能保护我们的隐私。而Linux系统&#xff0c;凭借其强大的功能和灵活性&#xff0c;成为了搭建HTTP代理服务器的理想选择。…

Android Camera2 API 后台服务

最近在搞CameraAPP需要将Camera2弄成一个后台服务&#xff0c;发现跟预览的Activity没多大变动只是加了Service&#xff0c;和一些简单的修改。之前的公司也用到Camera2&#xff0c;发现用到的时候还是蛮多的所以记录一下&#xff0c;代码在文章末尾 camera2的结构如下&#x…

常用的前端模块化标准总结

1、模块化标准出现以前使用的模块化方案&#xff1a; 1&#xff09;文件划分&#xff1a; 将不同的模块定义在不同的文件中&#xff0c;然后使用时通过script标签引入这些文件 缺点&#xff1a; 模块变量相当于是定义在全局的&#xff0c;容易造成变量名冲突&#xff08;即不…

代码随想录算法训练营第25天 | 216.组合总和III ,17.电话号码的字母组合

回溯章节理论基础&#xff1a; https://programmercarl.com/%E5%9B%9E%E6%BA%AF%E7%AE%97%E6%B3%95%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 216.组合总和III 题目链接&#xff1a;https://leetcode.cn/problems/combination-sum-iii/ 思路: 本题就是在[1,2,3,4,5,6,7,…