FPGA串口接收解帧、并逐帧发送有效数据——1

FPGA串口接收解帧、并逐帧发送有效数据

工程实现的功能:FPGA串口接收到串口调试助手发来的数据,将其数据解帧。判断到正确的帧头和帧尾之后,将有效数据存入rx_data中;另一方面发送端将有效数据逐帧发送出去。

参考:正点原子官方FPGA串口通信实验

模块构成:

在这里插入图片描述

在原子哥的基础上改的代码。添加了接收状态机模块:rx_state_machine修改了串口发送模块:uart_send。其余部分代码基本不变(只加了例化,修改数据位宽)

接收状态机模块rx_state_machine——进行解帧处理,接收有效数据

假设:帧头为AA,帧尾为55,有效数据为32bit

思路:使用三段式状态机

接收状态机标志位是什么?

module uart_recv(input			  sys_clk,                  //系统时钟input             sys_rst_n,                //系统复位,低电平有效input             uart_rxd,                 //UART接收端口output  reg       uart_done,                //接收一帧数据完成标志output  reg       rx_flag,                  //接收过程标志信号output  reg [ 3:0] rx_cnt,                  //接收数据计数器output  reg [ 7:0] rxdata,output  reg [7:0] uart_data,                 //接收的数据output  reg [31:0] rx_data);

在uart_recv中,有一个uart_done信号,是接收一帧数据完成标志,当uart_done拉高,表明接收了一帧数据(8bit),并存到了 uart_data 中。

我们可以用uart_done的上升沿作为状态机跳转的使能信号。

边沿检测如下:

//边沿检测 uart_done 信号
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n)beginuart_done_prev1 <= 0;uart_done_prev2 <= 0;endelse beginuart_done_prev1 <= uart_done;	uart_done_prev2 <= uart_done_prev1;  //延迟两拍end
end
//上升沿检测
assign uart_done_rise = uart_done_prev1 & ~uart_done_prev2;

检测到uart_done的上升沿时,uart_done_rise拉高一个时钟周期。当uart_done_rise拉高时(表明接收了一帧数据,并存到了 uart_data 中),状态机进入跳转判断。

状态机设计

在上面的假设中,帧头为AA,帧尾为55,有效数据为4帧(32bit)。

所以状态机的状态有:

  • 起始状态IDLE

  • 如果接收到AA,则进入DATA_RX状态

  • 如果接收的数据>=4帧 ,进入下一个状态,即帧尾检测状态

  • 如果检测到了帧尾,则进入DONE状态,表明解帧完成

在接收帧头或帧尾的状态中,只要不是AA或55,则重新进入起始状态。

localparam 	SOF		= 8'haa;	//帧头
localparam 	EOF		= 8'h55;	//帧尾localparam	IDLE		= 4'd0;	
localparam	DATA_SOF	= 4'd1;
localparam	DATA_RX		= 4'd2;
localparam 	DATA_EOF	= 4'd3;
localparam 	DONE		= 4'd4;//时序逻辑状态切换
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) c_status <= 4'd0;elsec_status <= n_status;
end//组合逻辑状态切换
always @(*) begincase(c_status)IDLE : begin 					//起始状态if(uart_done_rise) beginif(uart_data == SOF)n_status = DATA_RX;	//如果接收到AA,则进入DATA_RX状态elsen_status = IDLE;endelse n_status = IDLE;endDATA_RX: begin					//接收有效数据状态if(uart_done_rise) beginif(r_bytecnt >= 3'd3)n_status = DATA_EOF;elsen_status = DATA_RX;endelse n_status = DATA_RX;endDATA_EOF: begin					//接收帧尾状态if(uart_done_rise) beginif(uart_data == EOF)n_status = DONE;elsen_status = IDLE;endelse n_status = DATA_EOF;endDONE: begin 					//解帧完成n_status = IDLE;enddefault: beginn_status = IDLE;endendcase
end
//接收4个有效数据的计数器
always @(posedge sys_clk) beginif(c_status == DATA_RX) beginif(uart_done_rise) r_bytecnt <= r_bytecnt+1;else ;endelse r_bytecnt <= 3'b0;
end

代码解释:首先定义帧头SOF= 8’haa;(start of flag),帧尾EOF= 8’h55;(end of flag),以及5个状态(在后面设计状态机时发现DATA_SOF状态用不到)

  • 第一个always语句块,时序逻辑状态切换,保证了当前状态c_status和下个状态n_status的切换。

  • 第二个always语句块,4个状态所执行的操作。

    • c_status为IDLE,uart_done_rise拉高时,状态机进入跳转判断。

      如果此时uart_data中的数据是帧头SOF,则准备进入下一个状态,进行有效数据的接收DATA_RX状态;

      否则继续停留在IDLE状态。

    • c_status为DATA_RX,uart_done_rise拉高时,状态机进入跳转判断。

      在DATA_RX状态中,如果接收的字节数r_bytecnt>= 3'd3,说明已经完整地接收了4帧的有效数据,准备进入下个状态,进行帧尾检测DATA_EOF;

      否则,说明数据还没有接收完,继续停留在DATA_RX状态接收数据。

    • c_status为DATA_EOF,uart_done_rise拉高时,状态机进入跳转判断。

      如果此时uart_data中的数据是帧尾EOF,则进入解帧完成状态DONE;

      否则,说明帧尾不正确,该组数据无效,状态进入IDLE,重新解帧新的数据

  • 第三个always语句中,是接收4个有效数据的计数器。c_status处于有效数据的接收状态时,每次uart_done_rise拉高(表明接收了一帧数据),计数器r_bytecnt加1;


上面的三个always语句块,实现了状态的跳转和判断。接下来需要计算数据,并判断什么情况下进行输出。

//将所有接收到的值赋给寄存器 reg_rx_data
always @(posedge sys_clk) beginif((c_status == DATA_RX) && uart_done_rise) begincase(r_bytecnt)3'd0: reg_rx_data[31:24] <= uart_data;3'd1: reg_rx_data[23:16] <= uart_data;3'd2: reg_rx_data[15:8] <= uart_data;3'd3: reg_rx_data[7:0] <= uart_data;		default: ;endcaseend
end

首先,将有效数据存入寄存器reg_rx_data中。

c_status = DATA_RX状态下,一共接收了4帧的数据,现在把这4帧数据组合成一个32bit的数据。

当r_bytecnt为0时,这时候接收的是最高位,存入reg_rx_data[31:24],

当r_bytecnt为1时,将此时刻接收的数据存入reg_rx_data[23:16],

依此类推。

//判断数据是否有效
always @(posedge sys_clk) beginif((c_status == DONE)) beginrx_data <= reg_rx_data;rx_vaild <= 1'b1;rx_error <= 1'b0;endelse if((c_status == DATA_EOF) && (uart_data != EOF)) beginrx_data <= rx_data;rx_error <= 1'b1;rx_vaild <= 1'b0;endelse beginrx_data <= rx_data;rx_vaild <= 1'b0;rx_error <= 1'b1;end	
end

接下来,判断什么情况下进行输出 / 判断该组数据是否有效

  • c_status == DONE时,表明完整地解帧完了一组数据,rx_data <= reg_rx_data;将寄存器reg_rx_data的值赋给输出rx_data;同时给两个标志位rx_vaild、rx_error赋值。
  • 当解帧的帧尾不等于EOF时,接收数据无效,rx_data保持不变。

注释:至于为什么这里只判断了帧尾,没有判断帧头,是因为帧头的判断在状态机里就实现了:如果帧头不正确,则直接回到起始状态,进行不到接收有效数据的状态。但是帧尾还需要再判断,是因为进行到帧尾的状态时,就已经接收完有效数据了,并已经存入了reg_rx_data中。所以,还要再对帧尾进行判断,如果不符合,则rx_data不更新,认为这个数据无效。

接收解帧结果

ila_0 ila_rx (.clk(sys_clk), // input wire clk.probe0(uart_done), // input wire [0:0]  probe0  .probe1(uart_data), // input wire [7:0]  probe1 .probe2(rx_vaild), // input wire [0:0]  probe2 .probe3(rx_data), // input wire [31:0]  probe3 .probe4(uart_done_rise), // input wire [0:0]  probe4 .probe5(c_status), // input wire [2:0]  probe5 .probe6(r_bytecnt) // input wire [2:0]  probe6
);

在这里插入图片描述

在串口调试助手中,我发送的是aa1234567855,结果如上图,有效数据12345678存入了rx_data。


在下一节继续写逐帧发送部分

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

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

相关文章

RAG落地实践、AI游戏开发、上海·深圳·广州线下工坊启动!星河社区重磅周

飞桨星河社区在成立的5年以来&#xff0c;已汇集660万AI开发者&#xff0c;覆盖深度学习初学者、在职开发者、企业开发者、高校教师、创业者等&#xff0c;已成为AI领域最具影响力的社区之一&#xff0c;无论是AI爱好者还是AI开发者&#xff0c;都能在这里探索AI的无限可能。飞…

城市分站建站系统源码 全新版本SEO推广优化排名高 附带完整的搭建教程

在过去的几年中&#xff0c;许多企业在建立网站时面临一些共同的问题&#xff1a;缺乏技术支持、不懂SEO、预算有限等。这些问题导致他们的网站无法充分发挥作用&#xff0c;无法在搜索引擎中获得良好的排名&#xff0c;进而影响到企业的业务发展。小编来给大家分享一款城市分站…

编译原理词法分析:NFA转DFA(原理+完整代码+可视化实现)

NFA转换为DFA 【本文内容摘要】 什么是DFA通过子集构造法将NFA转换为DFA生成DFA的dot文件并且形成可视化。 如果本文对各位看官有用的话&#xff0c;请记得给一个免费的赞哦&#xff08;收藏也不错&#xff09;&#xff01; 文章目录 NFA转换为DFA一、什么是DFA二、NFA转换为…

k8s引用环境变量

一 定义环境变量 ① 如何在k8s中定义环境变量 env、configmap、secret补充&#xff1a; k8s 创建Service自带的环境变量 ② 从pod属性中获取 kubectl explain deploy.spec.template.spec.containers.env.valueFrom关注&#xff1a; configMapKeyRef、fieldRef 和 resour…

初探Maven

文章目录 一、Maven概述二、安装配置Maven&#xff08;一&#xff09;下载Maven&#xff08;二&#xff09;安装Maven&#xff08;三&#xff09;配置Maven 三、IDEA里配置Maven&#xff08;一&#xff09;版本情况说明&#xff08;二&#xff09;配置构建工具Maven 一、Maven概…

如何批量修改ppt中的字体?

ppt制作已经属于是复杂的操作了&#xff0c;当我们想要更换ppt中的字体&#xff0c;有没有什么快捷的方法呢&#xff1f;今天分享两个方法&#xff0c;一键修改ppt文件字体。 方法一&#xff1a; 找到功能栏中的编辑选项卡&#xff0c;点击替换 – 替换字体&#xff0c;在里面…

python加速方法:纯CPU多进程加速(joblib库)

我写C 代码喜欢用OpenMP进行加速&#xff0c;在不更改源代码情况下只做稍稍修改即可实现CPU利用率最大化&#xff0c;跨平台移植也没有问题。 python是个好东西&#xff0c;苦恼于密级计算的时候只能使用单核&#xff0c;使用多线程不奏效&#xff0c;因为毕竟它受限于语言本身…

【Go】Go语言基础内容

变量声明&#xff1a; 变量声明&#xff1a;在Go中&#xff0c;变量必须先声明然后再使用。声明变量使用 var 关键字&#xff0c;后面跟着变量名和类型&#xff0c;如下所示&#xff1a; var age int这行代码声明了一个名为 age 的整数变量。 变量初始化&#xff1a;您可以在声…

二叉树遍历 LeetCode 1038. 从二叉搜索树到更大和树

1038. 从二叉搜索树到更大和树 给定一个二叉搜索树 root (BST)&#xff0c;请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。 从图中可以看出&#xff0c;每个节点是BST右中左遍历时&#xff0c;遍历到的节点的值加上之前所有节点的值。 在遍历时可以使…

全球与中国木质颗粒燃料市场:增长趋势、竞争格局与前景展望

木质颗粒汽油的主要优点之一是环境永续性。木质颗粒被认为是碳中立的&#xff0c;因为燃烧过程中释放的二氧化碳量大约等于木材生长过程中吸收的二氧化碳量。这种封闭的碳循环减少了温室气体净排放并减轻了气候变迁的影响。作为一种可再生资源&#xff0c;木屑颗粒还可以透过促…

Python必备神器揭秘:15个最热门库全解析

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com Python生态系统中拥有大量优秀的库&#xff0c;为开发者提供了广泛且强大的工具。本文将介绍15个最受欢迎的Python库&#xff0c;包括它们的功能、优点以及示例代码&#xff0c;帮助读者更全面地了解和使用这些库…

spring boot mybatis TypeHandler 源码如何初始化及调用

目录 概述使用TypeHandler使用方式在 select | update | insert 中加入 配置文件中指定 源码分析配置文件指定Mapper 执行query如何转换 结束 概述 阅读此文 可以达到 spring boot mybatis TypeHandler 源码如何初始化及如何调用的。 spring boot 版本为 2.7.17&#xff0c;my…

深入理解Go语言GC机制

1、Go 1.3之前的标记-清除&#xff08;mark and sweep&#xff09;算法 Go 1.3之前的时候主要用的是普通的标记-清除算法&#xff0c;此算法主要由两个主要的步骤&#xff1a; 标记&#xff08;Mark phase&#xff09;清除&#xff08;Sweep phase&#xff09; 1&#xff09…

7.Vue UI库

7.Vue UI库 7.1移动端常用的UI库 &#xff08;1&#xff09; Vant&#xff1a;Vant 4 - A lightweight, customizable Vue UI library for mobile web apps.A lightweight, customizable Vue UI library for mobile web apps.https://vant-ui.github.io/vant/#/zh-CN &#xf…

提升--22---ReentrantReadWriteLock读写锁

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 ReadWriteLock----读写锁1.读写锁介绍线程进入读锁的前提条件&#xff1a;线程进入写锁的前提条件&#xff1a;而读写锁有以下三个重要的特性&#xff1a; Reentran…

个体诊所电子处方系统哪个好用,推荐一款可以自由设置配方模板能够填写病历可以查询历史病历的门诊处方笺软件

一、前言 1、功能实用&#xff0c;操作简单&#xff0c;不会电脑也会操作&#xff0c;软件免安装&#xff0c;已内置数据库。 2、中医西医均可用此软件开电子处方&#xff0c;支持病历记录查询&#xff0c;药品进出库管理&#xff0c;支持配方模板一键导入电子处方。 二、电子…

Amazon CodeWhisperer 正式可用, 并面向个人开发者免费开放

文章作者&#xff1a;深度-围观 北京——2023年4月18日&#xff0c;亚马逊云科技宣布&#xff0c;实时 AI 编程助手 Amazon CodeWhisperer 正式可用&#xff0c;同时推出的还有供所有开发人员免费使用的个人版&#xff08;CodeWhisperer Individual&#xff09;。CodeWhisperer…

SAP ABAP Tree Control 对象与ALV Grid 对象关联

Tree Control 对象与ALV Grid 对象关联 在双击 Tree 对象时&#xff0c;变更ALV Trid 对象的显示&#xff0c;实现界面如图9-11 所示。 Screen 设计界面如图9-12 所示。 主程序&#xff1a; REPORT ytest36. DATA: ok_code TYPE sy-ucomm,save_ok TYPE sy-ucomm. DATA: wa_co…

【C++】map和set的使用及注意事项

map和set的使用及注意事项 1.关联式容器2. 键值对3.set3.1接口介绍3.1.1构造3.1.2迭代器3.1.3容量3.1.4修改 3.2set使用及注意事项 4.multiset5.map6.multimap349. 两个数组的交集 1.关联式容器 在初阶阶段&#xff0c;我们已经接触过STL中的部分容器&#xff0c;比如&#xf…

vue项目解决计算后浮点数精度问题

1.1 问题描述 计算出的结果本来应该为13.8386&#xff0c;但是这里因为js精度问题&#xff0c;导致后边多了一串的0000001。 1.2 使用场景 求和&#xff0c;每个物品的单价*数量 1.3 解决办法 引入第三方库Decimal 1.4 vue项目中Decimal安装步骤 1.4.1 安装Decimal np…