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

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) beginstate <= 0;send_go <= 0;data <= 0;trans_done <= 0;end    else case(state)0:  beginif(trans_go)begintrans_done <= 0;data <= data40[7:0];send_go <= 1;state <= 1;endelse begindata <= data;send_go <= 0;state <= 0;endend1:beginif(tx_done)begindata <= data40[15:8];send_go <= 1;state <= 2;endelse send_go <= 0;end2:beginif(tx_done)begindata <= data40[23:16];send_go <= 1;state <= 3;endelsesend_go <= 0;end3:beginif(tx_done)begindata <= data40[31:24];send_go <= 1;state <= 4;endelsesend_go <= 0;end4:beginif(tx_done)begindata <= data40[39:32];send_go <= 1;state <= 5;endelsesend_go <= 0;end5:beginif(tx_done)begintrans_done <= 1;state <= 0;endelsesend_go <= 0;enddefault: begindata <= data;send_go <= 0;state <= 0;endendcaseendmodule
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;endcasereg [7:0] r_data;always@(posedge clk)if(send_go)r_data <= data;elser_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)beginif(div_cnt == (bps_dr - 1))div_cnt <= 0;elsediv_cnt <= div_cnt + 1'd1;endelsediv_cnt <= 0;    reg[3:0] bps_cnt;    always@(posedge clk or negedge rstn)if(!rstn)bps_cnt <= 0;else if(send_en)beginif(bps_cnt == 11)bps_cnt <= 0;else if(div_cnt == 1)bps_cnt <= bps_cnt + 4'd1;endelsebps_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; enddefault: uart_tx <= 1'd1;endcaseendmodule

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

以下两点需要学习:

  1. 通过控制trans_go信号的产生与结束,来模拟一个周期的脉冲信号
  2. 通过增加一个输出端口tx_done,来通知我输出何时完成
`timescale 1ns / 1psmodule 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 beginrstn = 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;endendmodule

仿真波形

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) beginstate <= 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;endelse begin data <= data;send_go <= 0;state <= 0;endend1:begin //等待单字节数据发送完成if(tx_done)begincounter <= counter + 1'd1;state <= 2;endelse send_go <= 0;end2:begin //检查所有数据是否发送完成if(counter == 5) begintrans_done <= 1;state <= 0;counter <= 0;endelse beginsend_go <= 1;data <= (data40>>(8*counter));state <= 1;endenddefault: begindata <= data;send_go <= 0;state <= 0;endendcaseendmodule

 

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;endcasereg [7:0] r_data;always@(posedge clk)if(send_go)r_data <= data;elser_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)beginif(div_cnt == (bps_dr - 1))div_cnt <= 0;elsediv_cnt <= div_cnt + 1'd1;endelsediv_cnt <= 0;    reg[3:0] bps_cnt;    always@(posedge clk or negedge rstn)if(!rstn)bps_cnt <= 0;else if(send_en)beginif(bps_cnt == 11)bps_cnt <= 0;else if(div_cnt == 1)bps_cnt <= bps_cnt + 4'd1;endelsebps_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; enddefault: uart_tx <= 1'd1;endcaseendmodule

 

仿真代码

`timescale 1ns / 1psmodule 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 beginrstn = 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;endendmodule

仿真波形

3.2 调试

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

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

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

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

相关文章

第一章:从3D到2D

本文是《从0开始图形学》的第一章内容。讲解如何将3D的模型“画”到2D的图形山。 概念解说 图形学渲染&#xff0c;就是将3D的东西“画”到2D的屏幕上&#xff0c;和拍照的效果是一样的&#xff0c;这也是为什么很多3D渲染引擎会有“相机”这个概念&#xff0c;这一节我们来看…

CleanMyMac4.14.7破解版安装包下载

CleanMyMac识别并清理垃圾文件的过程主要依赖于其强大的扫描功能和智能算法。以下是具体的步骤&#xff1a; CleanMyMac X2024全新版下载如下: https://wm.makeding.com/iclk/?zoneid49983 扫描垃圾文件&#xff1a;首先&#xff0c;用户需要打开CleanMyMac软件&#xff0c…

黄金交易策略(Nerve Nnife):大K线对技术指标的影响

我们使用heiken ashi smoothed来做敏感指标&#xff08;大趋势借助其转向趋势预判&#xff0c;但不是马上转变&#xff09;&#xff0c;has默认使用6根k线的移动平均值来做计算的。若在6根k线规范内有一个突变的行情&#xff08;k线很长&#xff09;&#xff0c;那么整个行情的…

【见微知著】OpenCV中C++11 lambda方式急速像素遍历

学习《OpenCV应用开发&#xff1a;入门、进阶与工程化实践》一书 做真正的OpenCV开发者&#xff0c;从入门到入职&#xff0c;一步到位&#xff01; C11 lambda语法 C11中引入了lambda表达式&#xff0c;它支持定义一个内联(inline)的函数&#xff0c;作为一个本地的对象或者…

JAVA毕业设计126—基于Java+Springboot+Vue的二手交易商城管理系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootVue的二手交易商城管理系统(源代码数据库)126 一、系统介绍 本项目前后端分离&#xff0c;本系统分为管理员、用户两种角色 1、用户&#xff1a; 注册、登录、…

VBA技术资料MF117:测试显示器大小

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

使用Launch4j将jar包转成.exe可执行文件

Launch4j官网:Launch4j - Cross-platform Java executable wrapper 然后点击上面按钮 随便写个文件名

C++入门学习(二十六)for循环

for (初始化; 条件; 递增/递减) { // 代码块 } 打印1~10&#xff1a; #include <iostream> using namespace std; int main() { for (int i 1; i < 10; i) { cout <<i<<endl; } return 0; } 打印九九乘法表&#xff1a; #include <iostream…

修改SpringBoot中默认依赖版本

例如SpringBoot2.7.2中ElasticSearch版本是7.17.4 我希望把它变成7.6.1

基于图像掩膜和深度学习的花生豆分拣(附源码)

目录 项目介绍 图像分类网络构建 处理花生豆图片完成预测 项目介绍 这是一个使用图像掩膜技术和深度学习技术实现的一个花生豆分拣系统 我们有大量的花生豆图片&#xff0c;并以及打好了标签&#xff0c;可以看一下目录结构和几张具体的图片 同时我们也有几张大的图片&…

第五章:变换矩阵

本文是《从0开始图形学》笔记的第五章&#xff0c;初步介绍变换矩阵的作用和求解方式&#xff0c;通过本章内容&#xff0c;我们将掌握模型的旋转和移动。 矩阵的初认识 图形学自然避不开矩阵&#xff0c;矩阵为点坐标的变换提供了一个优雅简洁的处理方案。简单来说&#xff0…

kubernetes镜像仓库harbor

一、镜像仓库的种类 GitHub GitHub有付费版和免费版,目前默认的docker镜像拉取策略是从GitHub上进行拉取gitee 国内harbor私有仓库二、harbor仓库规划设计 私有镜像仓库 Harbor 安装和配置 新创建一台虚拟机安装harbor, 配置如下: 主机名ip配置网络harbor192.168.1.204VCPU/…

【数据库】索引的使用

【数据库】索引的使用 前言出发示例创建表Explain 查看sql执行计划where 查询解析无索引有索引 where oderBy 查询解析无索引有索引 总结 前言 在数据库设计过程中&#xff0c;常需要考虑性能&#xff0c;好的设计可以大大提高sql 语句的增删改查速度。在表的创建过程中&…

【linux温故】CFS调度

写在前面 网上关于CFS 调度器的文章多如牛毛&#xff0c;没必要自己写。很多文章写的都非常好。 很多文章里&#xff0c;关键的技术点&#xff0c;都是一样的&#xff0c;只是各个文章说法不一样。 掌握了核心的&#xff0c;关键的&#xff0c;其他的&#xff0c;如果工作中…

【5G NR】【一文读懂系列】移动通讯中使用的信道编解码技术-卷积码原理

目录 一、引言 二、卷积编码的发展历史 2.1 卷积码的起源 2.2 主要发展阶段 2.3 重要里程碑 三、卷积编码的基本概念 3.1 基本定义 3.2 编码器框图 3.3 编码多项式 3.4 网格图(Trellis)描述 四、MATLAB示例 一、引言 卷积编码&#xff0c;作为数字通信领域中的一项…

C++,stl,栈stack和队列queue详解

1.栈stack 1.stack基本概念 2.stack常用接口 代码示例&#xff1a; #include<bits/stdc.h> using namespace std;int main() {stack<int> stk;stk.push(7);stk.push(9);stk.push(5);cout << "栈的size为&#xff1a;" << stk.size() <…

机器学习系列——(十九)层次聚类

引言 在机器学习和数据挖掘领域&#xff0c;聚类算法是一种重要的无监督学习方法&#xff0c;它试图将数据集中的样本分组&#xff0c;使得同一组内的样本相似度高&#xff0c;不同组间的样本相似度低。层次聚类&#xff08;Hierarchical Clustering&#xff09;是聚类算法中的…

2.7日学习打卡----初学RabbitMQ(二)

2.7日学习打卡 JMS 由于MQ产品很多&#xff0c;操作方式各有不同&#xff0c;于是JAVA提供了一套规则 ——JMS&#xff0c;用于操作消息中间件。JMS即Java消息服务 &#xff08;JavaMessage Service&#xff09;应用程序接口&#xff0c;是一个Java平台中关于面 向消息中间件的…

Spring Boot整合MyBatis Plus实现基本CRUD与高级功能

文章目录 1. 引言2. 项目搭建与依赖配置2.1 添加MyBatis Plus依赖2.2 配置数据源与MyBatis Plus 3. 实现基本CRUD功能3.1 创建实体类3.2 创建Mapper接口3.3 实现Service层3.4 控制器实现 4. 高级功能实现4.1 自动填充功能4.2 乐观锁功能4.3 逻辑删除功能 5. 拓展&#xff1a;My…

EasyExcel操作Excel表格

一、EasyExcel介绍 1.1 介绍 EasyExcel 是一个基于 Java 的简单易用的 Excel 文件读写工具&#xff0c;它提供了一种简单而又高效的方式来读取、写入和操作 Excel 文件。EasyExcel 是阿里巴巴开源的项目&#xff0c;它旨在简化开发人员处理 Excel 文件的流程&#xff0c;使得…