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) begin
	if(!sys_rst_n)begin
		uart_done_prev1 <= 0;
		uart_done_prev2 <= 0;
	end
	else begin
		uart_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) begin
	if(!sys_rst_n) 
		c_status <= 4'd0;
	else
		c_status <= n_status;
end

//组合逻辑状态切换
always @(*) begin
	case(c_status)
		IDLE : begin 					//起始状态
			if(uart_done_rise) begin
				if(uart_data == SOF)
					n_status = DATA_RX;	//如果接收到AA,则进入DATA_RX状态
				else
					n_status = IDLE;
				end
			else 
				n_status = IDLE;
		end
		DATA_RX: begin					//接收有效数据状态
			if(uart_done_rise) begin
				if(r_bytecnt >= 3'd3)
					n_status = DATA_EOF;
				else
					n_status = DATA_RX;
			end
			else n_status = DATA_RX;
		end
		DATA_EOF: begin					//接收帧尾状态
			if(uart_done_rise) begin
				if(uart_data == EOF)
					n_status = DONE;
				else
					n_status = IDLE;
			end
			else n_status = DATA_EOF;
		end
		DONE: begin 					//解帧完成
			n_status = IDLE;
			end
		default: begin
			n_status = IDLE;
		end
	endcase
end
//接收4个有效数据的计数器
always @(posedge sys_clk) begin
	if(c_status == DATA_RX) begin
		if(uart_done_rise) 
			r_bytecnt <= r_bytecnt+1;
		else ;
	end
	else 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) begin
	if((c_status == DATA_RX) && uart_done_rise) begin
		case(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: ;
		endcase
	end
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) begin
	if((c_status == DONE)) begin
		rx_data <= reg_rx_data;
		rx_vaild <= 1'b1;
		rx_error <= 1'b0;
	end
	else if((c_status == DATA_EOF) && (uart_data != EOF)) begin
		rx_data <= rx_data;
		rx_error <= 1'b1;
		rx_vaild <= 1'b0;
	end
	else begin
		rx_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。


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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

梯度上升和随机梯度上升

目录 梯度上升算法&#xff1a; 代码&#xff1a; 随机梯度上升算法&#xff1a; 代码&#xff1a; 实验&#xff1a; 做图代码&#xff1a; 疑问&#xff1a; 1.梯度上升算法不适应大的数据集&#xff0c;改用随机梯度上升更合适。 2.改进过的随机梯度算法&#xff0…

边缘计算网关构建智慧楼宇新生态,打造未来建筑管理

边缘计算网关在无人值守环境中的应用十分广泛&#xff0c;尤其在智慧楼宇管理方面发挥着重要作用。它能够实现多个地点多楼宇之间的数据实时互通&#xff0c;通过边缘计算网关物联网应用构建智慧楼宇生态系统&#xff0c;解决传统楼宇管理网络布线、人员巡检以及后期运维等问题…

IoT DC3 是一个基于 Spring Cloud 全开源物联网平台 linux docker部署傻瓜化步骤

如有不了解可先参考我的另一篇文章本地部署:IoT DC3 是一个基于 Spring Cloud 的开源的、分布式的物联网(IoT)平台本地部署步骤 如有不了解可先参考我的另一篇文章本地部署: 1 环境准备: JDK 8 以上 docker 安装好 下载docker-compose-dev.yml 文件 执行基础环境docker安装 …

c++--运算符重载

1.重载的运算符 (1).重载运算符函数的参数数量与该运算符作用的运算对象数量一样多。 (2).除了重载的函数调用运算符operator()之外&#xff0c;其他重载运算符不能含有默认实参。 (3).对一个重载的运算符&#xff0c;其优先级和结合律与对应的内置运算符保持一致。 (4).当一个…

STM32通用定时器

本文实践&#xff1a;实现通过TIM14_CH1输出PWM&#xff0c;外部显示为呼吸灯。 通用定时器简介 拥有TIM2~TIM5、TIM9~TIM14 一共10个定时器&#xff0c;具有4路独立通道&#xff0c;可用于输入捕获、输出比 较&#xff0c;同时包含了基本定时去的所有功能。 通用定时器的结…

音视频技术开发周刊 | 322

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 超级AI不会主宰人类&#xff0c;但人工智能必须开源&#xff01;LeCun最新采访引全网300万人围观 LeCun最新访谈视频中&#xff0c;再次坦露了自己对开源AI的看法。超级AI…

[MySQL--基础]多表查询

前言 ⭐Hello!这里是欧_aita的博客。 ⭐今日语录&#xff1a;生活中最大的挑战就是发现自己是谁。然后&#xff0c;坚定不移地成为那个人。 ⭐个人主页&#xff1a;欧_aita ψ(._. )>⭐个人专栏&#xff1a; 数据结构与算法 MySQL数据库 多表查询 前言多表关系概述&#x1f…

怎么翻译英文医学文献资料

文献翻译是一项要求严谨、精确且地道的工作&#xff0c;对于医学文献翻译更是如此。那么&#xff0c;怎么翻译英文医学文献资料&#xff0c;医学英文文献翻译公司哪个好&#xff1f; 专业人士指出&#xff0c;在翻译医学文献时&#xff0c;理解原文的语境是至关重要的。这不仅需…

Vue JAVA开发常用模板

1.VsCode添加模板 左下角设置》用户代码片段 新建全局代码片段》将模板粘贴仅文件&#xff08;prefix用于指定触发关键字&#xff09; 添加成功过后输入配置的关键字即可使用 1.1 vue2模板 {// Example:"Print to console": {"prefix": "vue2",…

创建conan包-Understanding Packaging

创建conan包-Understanding Packaging 1 Understanding Packaging1.1 Creating and Testing Packages Manually1.2 Package Creation Process 本文是基于对conan官方文档Understanding Packaging翻译而来&#xff0c; 更详细的信息可以去查阅conan官方文档。 1 Understanding …

Leetcode刷题详解——等差数列划分

1. 题目链接&#xff1a;413. 等差数列划分 2. 题目描述&#xff1a; 如果一个数列 至少有三个元素 &#xff0c;并且任意两个相邻元素之差相同&#xff0c;则称该数列为等差数列。 例如&#xff0c;[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。 给你一个整数数组 …

24、到底什么是感受野?

在之前的文章中介绍卷积算法时,一直在强调一个地方,那就是卷积算法是——卷积核在输入图像上滑动扫描的过程。 在每一次扫描时,可以把卷积核的在长宽方向的大小看做一个窗口,透过窗口可以看到的输入图像的范围,就称为感受野。 也就是神经网络(卷积)在每一次扫描过程中…

RHEL8.9 静默安装Oracle19C

RHEL8.9 静默安装Oracle19C 甘肃圆角网络科技开发有限公司 说明(GUI)&#xff1a;  1.实际业务场景中&#xff0c;Linux环境一般情况下是没有GUI的。没有GUI并不意味着没有安装图形界面。可能在部署Linux操作系统环境的时候安装了桌面环境&#xff0c;只是启动的时候设置了启动…

龙迅LT2611UX 四端口LVDS转HDMI(2.0)

1.描述&#xff1a; LT2611UX 四端口LVDS TO HDMI2.0。 LT2611UX是一款高性能得LVDS到HDMI2.0转换器得STB&#xff0c;DVD应用程序&#xff0c;LVDS输入可以配置单端口&#xff0c;双端口或者四端口&#xff0c;带有一个高速时钟通道&#xff0c;最多可运行三到四个高速数据…

FacetWP Relevanssi Integration相关性集成插件

点击阅读FacetWP Relevanssi Integration相关性集成插件原文 FacetWP Relevanssi Integration相关性集成插件是FacetWP与用于高级搜索的 Relevanssi 插件的集成显着增强了您网站的搜索功能。这个强大的工具使您的用户能够轻松找到他们寻求的特定内容&#xff0c;无论他们的查询…

【分布式算法】Raft算法详解

目录 一、什么是分布式一致性 二、Raft算法概述 三、Raft 算法的实现原理 3.1、Leader 选举 3.1.1、背景 3.1.2、有哪些成员身份 ​编辑 3.1.3、节点的状态转换 3.1.4、选举领导者的过程 3.1.5、节点间如何通讯&#xff1f; 3.1.6、什么是任期&#xff1f; 3.1.7、选…

SQL数据库知识点总结归纳

前后顺序可以任意颠倒,不影响库中的数据关系 关系数据库的逻辑性强而物理性弱,因此关系数据库中的各条记录前后顺序可以任意颠倒,不影响库中的数据关系 一名员工可以使用多台计算机(1:m),而一台计算机只能被一名员工使用(1:1),所以员工和计算机两个实体之间是一对多…

如何写出一个性能优化的单例模式

总结/朱季谦 单例模型是面试当中最常见的一种设计模式&#xff0c;它是一种对象创建模式&#xff0c;用于产生一个对象的具体实例&#xff0c;可以确保系统中一个类只产生一个实例。 简而言之&#xff0c;单例模式可以带来两个好处&#xff1a; 1、对于频繁使用到的对象&…

Linux--网络编程-ftp(TCP)网络通信-文件交互

项目要求&#xff1a;实现以下内容 远程控制&#xff1a; 1、查看服务器当前路径文件 ls 3、进入、退出服务器文件夹 cd 4、上传文件到服务器 put xxx 本地控制&#xff1a; 1、查看本地&#xff08;客户端&#xff09;文件 lls 2、进入客户端文件夹 lcd 3、获取服务器的文件…

MySQL笔记-第01章_数据库概述

视频链接&#xff1a;【MySQL数据库入门到大牛&#xff0c;mysql安装到优化&#xff0c;百科全书级&#xff0c;全网天花板】 文章目录 第01章_数据库概述1. 为什么要使用数据库2. 数据库与数据库管理系统2.1 数据库的相关概念2.2 数据库与数据库管理系统的关系2.3 常见的数据库…