stm32-hal库(5)--usart串口通信三种模式(主从通信)(关于通信失败和串口不断发送数据问题的解决)

问题:

最近发现,stm32cubemx最新版本f1系列的hal库(1.85版本)生成的hal库,其中stm32f1xx_hal_uart.c的库文件中,其串口发送接收存在一些问题:

1.没有使用 __HAL_LOCK__HAL_UNLOCK 宏,锁机制。

2.pdata8bitspdata16bits 未初始化为 NULL,可能会导致未定义行为。

3.在遇到超时错误时,没有恢复 huart->RxState 状态。

这样子会出现什么问题呢?

1.串口中断进不去,主机发送消息,从机无回应

2.轮询模式下,打开串口,其会不断给电脑串口发信息,直到几千几万条后溢出。

(也有可能是我没理解到位,如果知道原因的大佬,可以在评论区给点意见)

解决方法:

我将stm32cubemx的hal库版本进行了修改,改成了1.81版本,进行通信,实验成功。

步骤如下:

1.点击库管理

2.找到自己芯片库

如果你是1.85版本,如果前面框为绿色,选中然后下面点击移除就行。

点击1.81版本,进行安装。下图2框取消勾选,3框选择1.81。

其他配置和上篇文章一致:

STM32-hal库学习(4)--usart/uart通信 (单向通信)(同时显示在oled)-CSDN博客

1.轮询模式

什么是轮询模式?

轮询模式利用阻塞模式收发数据

        HAL_UART_Transmit():串口发送数据,使用超时管理机制
        HAL_UART_Receive(): 串口接收数据,使用超时管理机制

        其用于在没有中断机制或DMA机制的情况下,主动等待并处理外设的状态变化。在轮询模式下,CPU不断地检查外设的状态寄存器,以确定是否有数据可供处理。这种方式简单易用,但效率较低,因为CPU在等待期间不能处理其他任务。

程序:

main.c中加入

#include "stdio.h"
uint8_t RxDate[256];

因为oled函数里面没有显示hex类型函数,所以编写oled.c的hex显示函数:

void OLED_ShowHexArray(uint8_t x, uint8_t y, uint8_t *numArray, uint8_t Length, uint8_t size2, uint8_t Color_Turn)
{uint8_t i;uint8_t highNibble, lowNibble;for (i = 0; i < Length; i++){highNibble = (numArray[i] >> 4) & 0x0F;lowNibble = numArray[i] & 0x0F;// 显示高半字节if (highNibble < 10){OLED_ShowChar(x + (size2 / 2) * (2 * i), y, highNibble + '0', size2, Color_Turn);}else{OLED_ShowChar(x + (size2 / 2) * (2 * i), y, highNibble - 10 + 'A', size2, Color_Turn);}// 显示低半字节if (lowNibble < 10){OLED_ShowChar(x + (size2 / 2) * (2 * i + 1), y, lowNibble + '0', size2, Color_Turn);}else{OLED_ShowChar(x + (size2 / 2) * (2 * i + 1), y, lowNibble - 10 + 'A', size2, Color_Turn);}}
}

在oled.h加入:

void OLED_ShowHexArray(uint8_t x, uint8_t y, uint8_t *numArray, uint8_t Length, uint8_t size2, uint8_t Color_Turn);

在main.c实现轮询,

#include "string.h"
#include "stdio.h"
uint8_t RxDate[256];
unsigned int num = 0;

while(1)加入

switch(HAL_UART_Receive(&huart1, RxDate, 200, 1)){case HAL_OK:HAL_Delay(1);HAL_UART_Transmit(&huart1, RxDate, 200, 1);break;case HAL_TIMEOUT:if (huart1.RxXferCount != 200-1){HAL_UART_Transmit(&huart1, RxDate, 200-1 - huart1.RxXferCount, 1);}else{HAL_Delay(1);}break;case HAL_ERROR:// 错误处理逻辑,可以根据需要添加// 例如,重置 UART 或重新初始化huart1.RxState = HAL_UART_STATE_READY;__HAL_UNLOCK(&huart1);break;case HAL_BUSY:// 处理 UART 忙碌状态的逻辑// 可以选择等待一段时间再重试HAL_Delay(1);break;default:break;}OLED_ShowHexArray(48, 4, RxDate,1, 16, 0); // len 设置为 8,具体根据显示需求调整}

代码解释:HAL_UART_Receive接收huart1句柄的数据,RxDate,长度为200,等待时间为0xffff(也就是1)。若接收完毕,返回HAL_OK,则发送数据回电脑。

测试:

2.中断模式:

        USART的中断模式是一种数据传输方式,在这种模式下,当特定事件(如接收到一个字符或发送完一个字符)发生时,会触发中断请求,中断服务程序(ISR)负责处理这些事件。使用中断模式可以提高系统效率,因为在等待数据的过程中,CPU可以执行其他任务,而不需要不断轮询USART状态。

.中断模式收发数据
        HAL_UART_Transmit_IT():串口中断模式发送
        HAL_UART_Receive_IT(): 串口中断模式接收

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

这个函数的目的是启动UART传输并以非阻塞的方式发送一定数量的数据。

参数说明:中断方式的收发函数只有三个参数
      第一个参数是要使用的串口句柄地址
      第二个参数是发送缓冲区的首地址,用于存放要发送的数据
      第三个参数是发送缓冲区长度

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

参数说明与发送函数类似,只是把第二个和第三个参数变为了接收缓冲区

程序:

main.c加入

uint8_t  TxDate[64], RxDate[64];
uint8_t  rxstate;

int main加入

HAL_UART_Receive_IT(&huart1,RxDate,1);

接收中断函数,我这里将长度设为了1,表示接收到一个字节,便接收完毕,返回一个字节,比如0x11 是一个十六进制数,表示的是一个字节(8位)数据。在计算机系统中,十六进制数 0x11 对应的二进制数是 00010001,占用一个字节的存储空间。因此,0x11 占用1个字节。

while(1)加入

if(rxstate == 1)
{rxstate = 0;HAL_UART_Transmit_IT(&huart1,TxDate,1);
}			

当接收标志位为1,则表示接收完成,如果标志位为1,便发送数据

最下面加上

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART1){memcpy(TxDate,RxDate,1);rxstate = 1;HAL_UART_Receive_IT(&huart1,RxDate,1);}
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART1){}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART1){}
  • memcpy(TxDate, RxDate, 1);:将接收到的一个字节的数据从 RxDate 复制到 TxDate。这里假设 RxDate 是接收缓冲区,TxDate 是发送缓冲区。
  • memcpy 函数用于内存拷贝,将 RxDate 中的一个字节数据复制到 TxDate 中。
  • 拷贝完成,标志位变成1

测试:

3.DMA模式:

什么是dma模式?

        DMA(Direct Memory Access,直接内存访问)是一种计算机系统中用于数据传输的机制。它允许数据在外设和内存之间直接传输,而不需要CPU的介入,从而减轻了CPU的负担,提高了数据传输的效率。

举个例子:

        想象一下我们搬家的场景:你要把家里的一些东西从旧房子搬到新房子。在传统的情况下,你可能要亲自搬每一箱东西,把它们从旧房子搬到新房子。这就相当于CPU传统地处理数据传输的方式。

      现在,有一支搬家队,他们专门负责搬家。你只需要告诉他们从哪里搬,搬到哪里,然后他们就会自己完成这项任务。而你可以利用这段时间去做其他事情,不需要亲自动手。这就有点类似于DMA的工作原理。

        在计算机中,CPU通常会处理数据的传输工作,就像你亲自搬家一样。但有了DMA,就好比有了一支专门负责数据传输的队伍。CPU只需要告诉DMA从哪里搬,搬到哪里,然后就可以去处理其他任务了。DMA负责在外设和内存之间直接传输数据,而不需要CPU一直参与。

        简而言之,DMA就像是一支搬家队伍,负责在不需要CPU亲自操劳的情况下完成数据传输任务,从而提高了系统的效率。

DMA模式的优势

  1. 效率高:DMA能够以较高的效率传输数据,因为传输过程不需要经过CPU。
  2. 释放CPU资源:在数据传输过程中,CPU可以执行其他任务,避免了CPU因数据传输而被阻塞。
  3. 传输速度快:由于DMA控制器专门用于数据传输,其速度通常比通过CPU进行传输要快。

DMA模式的工作原理

  1. 配置DMA控制器:在使用DMA模式之前,需要配置DMA控制器,包括源地址、目的地址、传输数据的大小等。
  2. 启动DMA传输:配置完成后,启动DMA传输。DMA控制器将接管数据传输任务。
  3. 传输完成中断:在传输完成后,DMA控制器会生成一个中断,通知CPU传输已经完成。

DMA发送函数

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

参数类型和中断模式发送函数相同

DMA接收函数

HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

参数类型和中断模式接收函数相同 

HAL_UART_Transmit_DMA();串口DMA模式发送

HAL_UART_Transmit_DMA();串口DMA模式接收

HAL_UART_DMAPause() 暂停串口DMA

HAL_UART_DMAResume();恢复串口DMA

HAL_UART_DMAStop(); 结束串口DMA

因为比较多,关于代码部分,在日后文章中将具体写一下

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

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

相关文章

开源大模型RAG企业本地知识库问答机器人-ChatWiki

ChatWiki ChatWiki是一款开源的知识库 AI 问答系统。系统基于大语言模型&#xff08;LLM &#xff09;和检索增强生成&#xff08;RAG&#xff09;技术构建&#xff0c;提供开箱即用的数据处理、模型调用等能力&#xff0c;可以帮助企业快速搭建自己的知识库 AI 问答系统。 开…

vue使用glide.js实现轮播图(可直接复制使用)

效果图 可以实现自动轮播&#xff0c;3种切换方式&#xff1a;直接滑动图片、点击两侧按钮、点击底部按钮 体验链接:http://website.livequeen.top 实现 一、引入依赖 1、控制台引入依赖 npm install glidejs/glide 2、在css中引用 <style scoped> import glidejs/g…

.net 项目中配置 Swagger

一、前言 二、Swagger 三、.net 项目中添加Swagger 1、准备工作 &#xff08;1&#xff09;.net项目 &#xff08;2&#xff09;SwaggerController &#xff08;3&#xff09;XML文档注释 2、安装Swagger包 3、 添加配置swagger中间件 &#xff08;1&#xff09;添加S…

uniapp, ‍[⁠TypeError⁠]‍ “Failed to fetch dynamically imported module“ 报错解决思路

文章目录 1. 背景2. 报错3. 解决思路4. 思考参考1. 背景 最近基于uniapp开发一款设备参数调试的APP软件,在使用第三方插件的过程中,出现下面的报错。 2. 报错 [plugin:vite:import-analysis] Cannot find module ‘D:/leaning/uniapp/demo/jk-uts-udp示例/uni_modules/uts-…

对于CDA一级考试该咋准备??!

一、了解考试内容和结构 CDA一级考试主要涉及的内容包括&#xff1a;数据分析概述与职业操守、数据结构、数据库基础与数据模型、数据可视化分析与报表制作、Power BI应用、业务数据分析与报告编写等。 CDA Level Ⅰ 认证考试大纲:https://edu.cda.cn/group/4/thread/174335 …

C++精解【9】

文章目录 大整数GMP概述GMP安装 [cygwin](https://cygwin.com/install.html)安装 gmpexample Eigen基本属性和运算 大整数GMP 概述 GMP GMP是一个用于任意精度算术的免费库&#xff0c;可对有符号整数、有理数和浮点数进行操作。除了运行GMP的机器的可用内存所暗示的精度外&…

expandtabs()方法——tab符号转为空格

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 expandtabs()方法把字符串中的tab&#xff08;\t&#xff09;符号转为空格&#xff0c;tab&#xff08;\t&#xff09;符号默认的空格数是…

简单科普-GPT到底是什么?

1.ChatGPT ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Transformer&#xff09;&#xff0c;是OpenAI研发的一款聊天机器人程序 &#xff0c;于2022年11月30日发布 。ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c;它能够基于在预训练阶段所见…

MATLAB2024a下的神经网络聚类工具箱聚类

1 打开神经网络聚类工具箱GUI界面 图1-1 2 导入训练数据 图2-1 导入训练集如图2-2&#xff0c;图2-3、图2-4所示 图2-2 图2-3 图2-4 如图2-4&#xff0c;确认无误点击确定 3 模型训练 如图3-1&#xff0c;调整验证集与测试集比例及映射大小后点击”训练“&#xff0c;开始训练…

uview文本框组件计数count报错u--textarea

报错内容&#xff1a; [Vue warn]: Error in render: “TypeError: Cannot read property ‘length’ of null” found in —> at uni_modules/uview-ui/components/u-textarea/u-textarea.vue at uni_modules/uview-ui/components/u–textarea/u–textarea.vue mp.runtime.…

浪潮信息AIStation与毕昇:让AI大模型开发变得更易用

在数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;技术正以前所未有的速度改变着世界。近日&#xff0c;毕昇大模型应用开发平台和浪潮信息AIStation智能业务生产创新平台完成兼容性互认证。二者的融合&#xff0c;不仅简化了大模型定制开发的流程&#xff…

【进阶篇-Day6:JAVA中Arrays工具类、排序算法、正则表达式的介绍】

目录 1、Arrays工具类2、排序算法2.1 冒泡排序2.2 选择排序2.3 二分查找&#xff08;折半查找&#xff09;&#xff08;1&#xff09;概念&#xff1a;&#xff08;2&#xff09;步骤&#xff1a; 3、正则表达式3.1 正则表达式的概念&#xff1a;3.2 正则表达式的格式&#xff…

Unidbg调用-补环境V3-Hook

结合IDA和unidbg,可以在so的执行过程进行Hook,这样可以让我们了解并分析具体的执行步骤。 应用场景:基于unidbg调试执行步骤 或 还原算法(以Hookzz为例)。 1.大姨妈 1.1 0x1DA0 public void hook1() {

【项目日记(二)】搜索引擎-索引制作

❣博主主页: 33的博客❣ ▶️文章专栏分类:项目日记◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多项目内容 目录 1.前言2.索引结构2.1创捷索引2.2根据索引查询2.3新增文档2.4内存索引保存到磁盘2.5把…

U-Net for text-to-image

1. Unet for text-to-image 笔记来源&#xff1a; 1.hkproj/pytorch-stable-diffusion 2.understanding u-net a comprehensive tutorial 3.Deep Dive into Self-Attention by Hand 4.Towards Understanding Cross and Self-Attention in Stable Diffusion for Text-Guided Im…

java大型医院绩效考核系统源码(医院为什么需要绩效机制?)医院绩效考核系统源码 医院管理绩效考核系统源码

java大型医院绩效考核系统源码&#xff08;医院为什么需要绩效机制&#xff1f;&#xff09;医院绩效考核系统源码 医院管理绩效考核系统源码 医院作为提供医疗服务的核心机构&#xff0c;其运营和管理效率直接影响到患者的就医体验、治疗效果以及医院的长期发展。因此&#xf…

构造函数的小白理解

一、实例 using System; using System.Collections; using System.Collections.Generic; using UnityEngine;//定义一个名为Question的类&#xff0c;用于存储问题及相关信息 [Serializable] public class Question {public string questionText;//存储题目文本字段public str…

Unix/Linux shell实用小程序1:生字本

前言 在日常工作学习中&#xff0c;我们会经常遇到一些不认识的英语单词&#xff0c;于时我们会打开翻译网站或者翻译软件进行查询&#xff0c;但是大部分工具没有生词本的功能&#xff0c;而有生字本的软件又需要注册登陆&#xff0c;免不了很麻烦&#xff0c;而且自己的数据…

风控图算法之中心性算法(小数据集Python版)

风控图算法之中心性算法&#xff08;小数据集Python版&#xff09; 图算法在金融风控领域的应用已经超越了传统的社区发现技术&#xff0c;这些技术曾被主要用于识别和分析欺诈性行为模式&#xff0c;例如黑产团伙。当前&#xff0c;一系列图统计算法&#xff0c;包括介数中心…

Hive SQL:实现炸列(列转行)以及逆操作(行转列)

目录 列转行行转列 列转行 函数&#xff1a; EXPLODE(ARRAY)&#xff1a;将ARRAY中的每一元素转换为每一行 EXPLODE(MAP)&#xff1a;将MAP中的每个键值对转换为两行&#xff0c;其中一行数据包含键&#xff0c;另一行数据包含值 数据样例&#xff1a; 1、将每天的课程&#…