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

这篇具有很好参考价值的文章主要介绍了FPGA串口接收解帧、并逐帧发送有效数据——1。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

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

模块构成:

FPGA串口接收解帧、并逐帧发送有效数据——1,ZYNQ&FPGA实例,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
);

FPGA串口接收解帧、并逐帧发送有效数据——1,ZYNQ&amp;FPGA实例,fpga开发,信息与通信

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


在下一节继续写逐帧发送部分文章来源地址https://www.toymoban.com/news/detail-755024.html

到了这里,关于FPGA串口接收解帧、并逐帧发送有效数据——1的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 串口发送数据,只接收到00的原因之一

    1、环境: STM32F103RCT6 KEIL 5 2、现象: 不管我发送任何类型的数据,在串口助手上显示接收到的都是00, 我头很大,去网上找了别人的代码对比检查。 终于,细心的我发现,原来粗心的我少了一行代码。 3、解决方案1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); 好了,加上这一行

    2024年02月12日
    浏览(86)
  • 最详细STM32,cubeMX串口发送,接收数据

    这篇文章将详细介绍 串口 发送数据,接受数据。 实验开发板:STM32F103C8T6。 所需软件:keil5 , cubeMX 。 实验目的:了解 串口的基础知识,掌握串口如何发送,接收数据 。 实验:串口发送数据点亮 led。 如果想了解串口的基础知识可以参考我之前的文章: STM32Cube串口USART发送

    2024年02月04日
    浏览(67)
  • C#与松下PLC串口通讯发送,接收数据

    记录与学习 第一次跟PLC打交道,C#与松下plc交互读写功能,很多东西都是自己在网上找的,整理了下做个记录  引入“Panasonic.dll”文件 下载地址 百度盘百度网盘 请输入提取码  提取码:8vnm  public Panasonic.PLC Sp_PLC;   Sp_PLC.WCS(\\\"R\\\", \\\"1\\\", true);//提示PLC软件初始化完成,可以正常工

    2023年04月12日
    浏览(50)
  • STM32实现三个串口同时开启发送接收数据

            实现STM32开通三个串口,每个串口都可以实现接收和发送数据。          编程时,严禁在中断函数中写入发送串口数据代码,否则会出错,具体原因不清楚(有大佬知道的话帮我指出),可能原因是DR寄存器冲突导致。         RX,TX连接到A9,A10使用串口1,使

    2024年04月13日
    浏览(72)
  • C#串口通信从入门到精通(26)——多个串口多个线程发送数据和接收数据

    我们在开发串口程序的过程中有时候会遇到多个串口,并且多个串口也需要在多个线程进行操作,本文就来讲解如何实现多个串口在多线程下的安全发送与接收。 我们首先使用虚拟串口助手虚拟COM1、COM2这一对串口;COM3、COM4这一对串口,然后使用代码操作COM1,然后打开一个

    2024年02月11日
    浏览(56)
  • Qt+C++串口调试接收发送数据曲线图

    程序示例精选 Qt+C++串口调试接收发送数据曲线图 如需安装运行环境或远程调试,见文章底部个人 QQ 名片,由专业技术人员远程协助! 这篇博客针对Qt+C++串口调试接收发送数据曲线图编写代码,代码整洁,规则,易读。 学习与应用推荐首选。 一、所需工具软件 二、使用步骤

    2024年02月11日
    浏览(46)
  • 串口通信——发送和接收数据(8位和16位数据之间的转换)

    1.发送两个字节数据,就是16位的数据,每一次发送8位,发送两次,这里要进行数据的拆分,如发送一个0XFF56,接收得到的也是FF56(16进制显示); 2.接收两个字节的数据(这里通过串口助手以16进制发送一个数据),将拼接的数据(只能一个字节一个字节接收)除以100展示出来

    2024年01月17日
    浏览(98)
  • QT三驾马车(一)——实现上位机(串口数据发送和接收)

    以后同学们做项目一定会用到QT的三驾马车,QT的三驾马车即QT的串口编程,QT的网络编程和QT的GPIO,今天我们通过一个项目来介绍第一部分,QT的串口编程。 之前看过很多相关的文章,但是按照顺序来编译总是会出错,可是我自己还找不到原因,对于我这种新手小白来说极其

    2024年02月15日
    浏览(43)
  • 【PHP】PHP实现与硬件串口交互,接收硬件发送的实时数据

    目的:借助虚拟串口软件(VSPD)模拟硬件串口发送数据,使用PHP语言实现接收硬件发送的数据。 我这里的需求是连接天平,把天平的称量数据实时的传送到PHP使用。 使用工具:vspd+串口调试工具 使用语言:PHP 使用到的工具有VSPD和串口调试工具,其中VSPD是模拟硬件串口,串

    2024年02月02日
    浏览(34)
  • FPGA接收串口数据并通过LCD1602显示

    一、前言 在学习《FPGA设计与Verilog HDL实现》第九章内容Verilog驱动常用I/O外设时,书中有一个驱动LCD1602的例程,但其是通过状态机显示固定的几个字符。本着动手实践的原则,决定利用手头的硬件实现FPGA接收串口数据并在LCD1602上显示,下面记录项目开始的过程。因为刚接触

    2024年02月06日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包