高云FPGA系列教程(8):ARM串口数据接收(中断和轮询方式)

news2025/6/16 23:41:24

文章目录

    • @[toc]
      • 1. GW1NSR-4C串口外设简介
      • 2. FPGA配置
      • 3. 常用函数
      • 4. 轮询方式接收数据
      • 5. 中断方式接收数据

本文是高云FPGA系列教程的第8篇文章。

本篇文章介绍片上ARM Cortex-M3硬核处理器串口外设的使用,演示轮询方式和中断方式接收串口数据,并进行回环测试,基于TangNano 4K开发板。

参考文档:Gowin_EMPU(GW1NS-4C)软件编程 参考手册

1. GW1NSR-4C串口外设简介

GW1NSR-4C ARM部分共有2个串口外设,都挂载在APB1总线上,最高支持波特率921.6Kbit/s,无奇偶校验位,8位数据位,1位停止位,支持高速测试模式 HSTM(High Speed Test Mode),即每个时钟周期输出1位数据,可以在短时间内传输大量数据。

官方手册上没有描述发送和接收缓存FIFO的深度,所以不确定是否支持缓存。

2. FPGA配置

FPGA部分需要在云源软件中手动使能EMPU串口外设,如下图所示。


不需要其他配置,使用起来非常简单。

3. 常用函数

高云串口驱动函数常用的有以下几个:

//串口初始化,指定波特率和中断使能,高速测试模式等
ErrorStatus UART_Init(UART_TypeDef* UARTx, UART_InitTypeDef* UART_InitStruct)
//获取接收缓存区状态,当接收到数据时,返回SET
FlagStatus UART_GetRxBufferFull(UART_TypeDef* UARTx)
//获取发送缓存区状态
FlagStatus UART_GetTxBufferFull(UART_TypeDef* UARTx)
//发送一个字节
void UART_SendChar(UART_TypeDef* UARTx,char txchar)
//发送字符串
void UART_SendString(UART_TypeDef* pUARTx, char *str)
//接收一个字节,轮询或接收中断时调用,自动
char UART_ReceiveChar(UART_TypeDef* UARTx)
//获取接收中断的状态,当被触发时返回SET
ITStatus UART_GetRxIRQStatus(UART_TypeDef* UARTx)
//获取发送中断的状态
ITStatus UART_GetTxIRQStatus(UART_TypeDef* UARTx)
//清除接收中断
void UART_ClearRxIRQ(UART_TypeDef* UARTx)
//清除发送中断
void UART_ClearTxIRQ(UART_TypeDef* UARTx)

下面来介绍串口接收数据的两种方式:轮询方式和中断方式。

4. 轮询方式接收数据

初始化时不使能接收中断:

void uart0_init(uint32_t BaudRate)
{
	UART_InitTypeDef UART_InitStruct;

	UART_InitStruct.UART_Mode.UARTMode_Tx = ENABLE;
	UART_InitStruct.UART_Mode.UARTMode_Rx = ENABLE;
	UART_InitStruct.UART_Int.UARTInt_Tx = DISABLE;
	UART_InitStruct.UART_Int.UARTInt_Rx = DISABLE;
	UART_InitStruct.UART_Ovr.UARTOvr_Tx = DISABLE;
	UART_InitStruct.UART_Ovr.UARTOvr_Rx = DISABLE;
	UART_InitStruct.UART_Hstm = DISABLE;
	UART_InitStruct.UART_BaudRate = BaudRate;//Baud Rate

	UART_Init(UART0, &UART_InitStruct);
}

主循环中直接把收到的数据通过串口发送出去:

while(1)
{
    if(UART_GetRxBufferFull(UART0))
    {
        cnt_idle = 0;
        rx = UART_ReceiveChar(UART0);
        printf("rec data: %c\r\n", rx);
    }
}

这种简单粗暴的方式,会导致数据丢失,可能是串口接收部分没有FIFO导致:

我们可以采用缓冲区配合超时空闲的方式来处理,首先定义一个缓冲数组用来存储收到的数据,并通过一个计时器来判断当前是否空闲,若空闲则把数据返回:

uint8_t rx = 0;
uint8_t buf[256];
uint16_t buf_idx = 0;
uint32_t cnt_idle = 0;

//空闲超时方式接收不丢失数据
while(1)
{
    //空闲时间计数器
    if(buf_idx != 0)
    {
        cnt_idle++;
    }
    else 
    {
        cnt_idle = 0;
    }
    //数据缓存到数组中
    if(UART_GetRxBufferFull(UART0))
    {
        cnt_idle = 0;
        buf[buf_idx] = UART_ReceiveChar(UART0);
        buf_idx++;
    }
    //长时间没有接收到串口数据,把缓冲区数据返回
    if(cnt_idle > 5000)   //明显感觉=500000
    {
        UART_SendString(UART0, buf);
        cnt_idle = 0;
        buf_idx = 0;
        memset(buf, 0, sizeof(buf)/sizeof(buf[0]));
    }
}

实际测试效果很不错,数据没有任何丢失:

下面来介绍通过串口接收中断的方式来缓存数据。

5. 中断方式接收数据

初始化时使能串口接收中断,并通过NVIC开启串口中断请求。

void uart0_init(uint32_t BaudRate)
{
	UART_InitTypeDef UART_InitStruct;
	NVIC_InitTypeDef InitTypeDef_NVIC;

	UART_InitStruct.UART_Mode.UARTMode_Tx = ENABLE;
	UART_InitStruct.UART_Mode.UARTMode_Rx = ENABLE;
	UART_InitStruct.UART_Int.UARTInt_Tx = DISABLE;
	UART_InitStruct.UART_Int.UARTInt_Rx = ENABLE;   //开启接收中断
	UART_InitStruct.UART_Ovr.UARTOvr_Tx = DISABLE;
	UART_InitStruct.UART_Ovr.UARTOvr_Rx = DISABLE;
	UART_InitStruct.UART_Hstm = DISABLE;
	UART_InitStruct.UART_BaudRate = BaudRate;//Baud Rate

	UART_Init(UART0, &UART_InitStruct);

    //Enable UART0 interrupt handler
    InitTypeDef_NVIC.NVIC_IRQChannel = UART0_IRQn;
    InitTypeDef_NVIC.NVIC_IRQChannelPreemptionPriority = 1;
    InitTypeDef_NVIC.NVIC_IRQChannelSubPriority = 1;
    InitTypeDef_NVIC.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&InitTypeDef_NVIC);
}

串口中断服务函数,数据缓存到数组中,并清零空闲计数器:

void UART0_Handler(void)
{
	char rx = 0;
	
	if(UART_GetRxIRQStatus(UART0) == SET)
	{
		rx = UART_ReceiveChar(UART0);
        buf[buf_idx] = rx;
        buf_idx++;
        cnt_idle = 0;
	}
	
	UART_ClearRxIRQ(UART0);
}

需要注释掉系统默认提供的串口中断服务函数,否则编译会报错。

主循环中通过一个计数器来判断串口是否空闲,当超时没有收到新的数据时,认为串口空闲,把缓冲区的数据返回:

uint8_t rx = 0;
uint8_t buf[256];
uint16_t buf_idx = 0;
uint32_t cnt_idle = 0;

while(1)
{
    //长时间没有接收到串口数据
    if(buf_idx != 0)
        cnt_idle++;
    else 
        cnt_idle = 0;

    if(cnt_idle > 5000)   //明显感觉=500000
    {
        printf("rx: %s", buf);
        cnt_idle = 0;
        buf_idx = 0;
        memset(buf, 0, sizeof(buf)/sizeof(buf[0]));
    }
}

下载,运行,数据完整:


本文是高云FPGA系列教程的第8篇文章。

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

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

相关文章

【Java 基础篇】Executors工厂类详解

在多线程编程中,线程池是一项重要的工具,它可以有效地管理和控制线程的生命周期,提高程序的性能和可维护性。Java提供了java.util.concurrent包来支持线程池的创建和管理,而Executors工厂类是其中的一部分,它提供了一些…

MySQL数据库笔记

文章目录 一、初识MySQL1.1、什么是数据库1.2、数据库分类1.3、MySQL简介 二、操作数据库2.1、操作数据库(了解)2.2、数据库的列类型2.3、数据库的字段属性(重点)2.4、创建数据库表(重点)2.5、数据表的类型…

【PHPCUSTOM】打包PHP程序为EXE

目录 一、下载PHPCUSTOM 二、PHP网站打包 1、打开PHPCUSTOM 2、配置参数 3、生成exe文件 网上很多PHP程序打包成EXE的文章,但是都不能用,最后找到了PHPCUSTOM,使用PHPCUSTOM可以把PHP程序打包成exe。我们都知道PHP是服务端语言&#xff…

CCG超级标记

1. 定义 组合范畴语法(Combinatory Categorial Grammar,CCG)是一种用于自然语言语法分析的语言学理论和计算模型。它是一种形式文法,旨在描述句子的结构和语法规则(通过简练的描述形式表现出句子中各成分的句法语义关…

用VS Code运行C语言(安装VS Code,mingw的下载和安装)

下载并安装VS code。 安装扩展包: 此时,写完代码右键之后并没有运行代码的选项,如图: 接下来安装编译器mingw。 下载链接: https://sourceforge.net/projects/mingw-w64/ 得到压缩包: 解压: …

车载通信架构 —— SOME/IP 协议概述

车载通信架构 —— SOME/IP 协议概述 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 对学习而言,学习之后的思考、思考之后的行动、行动之后的改变更重要,如果不盯住内层的改变量,那么在表层投…

浅谈DBT的一些不足之处

DBT的好处是显而易见的,它支持连接多达41种数据库。而且不需要你写DDL语句,只要写select语句,DBT会自动帮你推断schema结构,将数据写入到数据库中: 但是使用了一段时间之后,发现DBT也存在着如下这些不足之处…

YOLOv5、YOLOv8改进:HorNet完全替换backone

1.简介 论文地址:https://arxiv.org/abs/2207.14284 代码地址:https://github.com/raoyongming/HorNet 视觉Transformer的最新进展表明,在基于点积自注意力的新空间建模机制驱动的各种任务中取得了巨大成功。在本文中,作者证明了…

pcl--第七节 点云配准

点云配准原理概述 点云配准需求场景 ​ 随着计算机辅助设计技术的发展,通过实物模型产生数字模型的逆向工程技术获得了越来越广泛的应用,与此同时,硬件设备的日趋完善也为数字模型操作提供了足够的技术支持。 ​ 由于三维扫描仪设备受到测…

win系统环境搭建(九)——Windows安装chatGPT

windows环境搭建专栏🔗点击跳转 win系统环境搭建(九)——Windows安装chatGPT 本系列windows环境搭建开始讲解如何给win系统搭建环境,本人所用系统是腾讯云服务器的Windows Server 2022,你可以理解成就是你用的windows…

FFmpeg5.1.3编译动态库详细教程(基于Linux虚拟机)

FFmpeg编译详细教程 FFmpeg编译详细教程 本文原创:猿视野 ( 一家分享技术架构思路,扩展程序员视野的网站,遇到技术问题,可以加联系方式相互交流) 转载请注明出处和相关链接,否则追究其法律责任! 原文地址:https://dev…

MyBatis之增删查改功能

文章目录 一、创建各种类二、MyBatis的各种功能 1、查询<select>2、增加<insert>3、修改<update>4、删除<delete>三、总结 前言 在MyBatis项目中编写代码实现对MySql数据库的增删查改 一、创建各种类 1、在Java包的mapper文件下创建一个接口 我创建…

“毛细血管”的进化:华为分销业务如何让伙伴也有“高能级”

作者 | 曾响铃 文 | 响铃说 数字化蓬勃发展的大时代&#xff0c;除了那些中、大型企业&#xff0c;数量更为庞大的小微企业同样有借助数字化产品、服务来提升企业经营的需求&#xff0c;由此也带来了广袤的数字化分销市场。 这里处在聚光灯之外&#xff0c;很少被数字化时代…

PyCharm安装教程,新手详细

首先进入官网&#xff1a;https://www.jetbrains.com/pycharm/download/?sectionwindows#sectionwindows 然后选择版本&#xff0c;我下载的是社区版&#xff0c;一般学习是够了 然后点击Download进行下载。 双击exe运行 然后选择安装路径&#xff0c;建议放在D盘 然后这…

找不到msvcp140.dll的解决方法,以及msvcp140.dll丢失的原因

在计算机使用过程中&#xff0c;我们可能会遇到无法启动程序的问题&#xff0c;提示找不到 msvcp140.dll。这使得许多用户感到困扰&#xff0c;因为 msvcp140.dll 是 Microsoft Visual C Redistributable 的一个组件&#xff0c;它包含了 C 运行时库。这个库对于许多应用程序和…

SpringCLoud——RabbitMQ的消息模型

Work Queue工作队列 他的主要作用就是增加消费者的个数&#xff0c;可以提高消息处理速度&#xff0c;避免队列消息堆积。 案例 实现一个队列绑定多个消费者 首先修改一下之前的发送消息的代码&#xff0c;让他循环发送50次&#xff0c;但是不要一次性发完&#xff1a; Tes…

React(react18)中组件通信04——redux入门

React&#xff08;react18&#xff09;中组件通信04——redux入门 1. 前言1.1 React中组件通信的其他方式1.2 介绍redux1.2.1 参考官网1.2.2 redux原理图1.2.3 redux基础介绍1.2.3.1 action1.2.3.2 store1.2.3.3 reducer 1.3 安装redux 2. redux入门例子3. redux入门例子——优…

【算法】二分答案

文章目录 相关链接什么时候使用二分答案&#xff1f;题目列表最大化最小化相关题目列表&#x1f4d5;2439. 最小化数组中的最大值解法1——二分答案解法2——分类讨论O(n) 2513. 最小化两个数组中的最大值&#xff08;二分答案lcm容斥原理&#xff09;&#x1f402;好题&#x…

每日练习-8

目录 一、选择题 二、算法题 1.另类加法 2、走方格的方案数 一、选择题 1、 解析&#xff1a;当使用new运算符创建一个类的对象数组时&#xff0c;会调用该类的构造函数来初始化每个对象。因此&#xff0c;如果创建了5个对象&#xff0c;那么构造函数会被调用5次。 当使用delet…

[2023.09.20]:Yew的前端开发经历小结

今天基本上完成了一个操作闭环&#xff0c;即能够保存&#xff0c;拉取和删除数据。截个图 这个过程的前端和后端都是用Rust写的&#xff0c;前端使用的是Yew。 Yew是一种用于构建现代Web应用程序的Rust框架&#xff0c;其计目标是提供一种安全、高效、易用的方式来构建Web应…