stm32使用(无线串口)实现收发、判断数据+DMA(HAL库)

news/2025/2/26 9:03:54

目录

前言:

1.    用CubeMX配置串口+DMA所需要的环境

(1)打开CubeMAX,点击红框

stm32F103C8T6%E7%9A%84%E8%8A%AF%E7%89%87-toc" style="margin-left:40px"> (2)查找stm32F103C8T6的芯片

(3)配置SYS

 (4)配置RCC时钟

(5)配置主频

(6)配置串口

(7)配置DMA

(8)生成工程

2.串口中断与DMA相关重要函数介绍

(1)串口相关 

接收完成回调函数:

 接收串口的函数:

 发送串口的函数:

空闲中断打开函数:

在每次进入中断后,判断是否为空闲中断:

清除空闲标志位

终止当前的接收(会把RxferCount清零)

终止接收回调函数

发送完成回调函数

(2)DMA相关

串口DMA接收函数:

串口DMA发送函数:

3.编写相关代码

(1)项目要求

(2)相关代码编写

1.全局变量

2.main.c

stm32f1xx_it.c-toc" style="margin-left:80px">3.stm32f1xx_it.c

4.ATK-LORA-01无线串口的使用

1.使用该无线串口前,需要通过软件调整该串口的参数配置。

2.步骤如下:

总结:


前言:

      本文章使用stm32f103c8t6进行HAL库串口程序的使用,可以解决串口接收发送数据问题,也使用了DMA转运,但没有实现无线数据传输(脑子笨了点),此外,本章也会初步的介绍关于ATK-LORA-01无线串口模块的使用,当然,这也指的是透明传输这一方面。

      STM32的串口收发信息,标准库的代码b站上江协科技我认为已经讲的非常清楚了,但可惜没有hal库的,其他的博主,还有网络上的一些视频,貌似距离如接收“stop”然后发送“”stop”,接着接收“start”然后发送“start”都有些困难,他们通过只接受一个字节然后进入中断,所以我实际用CUbeMX来带领大家来操作一遍,无脑掌握。

     备注:关于串口无限数据传输的方法我认为下面这一篇博客讲的非常厉害,使用串口的空闲中断,而且也给出了解决方法,给了我很大启发,链接如下:超子物联网HAL库笔记:串口篇

1.    用CubeMX配置串口+DMA所需要的环境

(1)打开CubeMAX,点击红框

stm32F103C8T6%E7%9A%84%E8%8A%AF%E7%89%87"> (2)查找stm32F103C8T6的芯片

C8T6和C8T6TR都可以,双击。

 

(3)配置SYS

 (4)配置RCC时钟

注意如果这个没有配置好的话,就不能配置72MHz的主频。

(5)配置主频

直接双击改写为72,之后敲下Enter,自动配置完毕。

(6)配置串口

一定要使能串口中断!!接收不到信号。

(7)配置DMA

由于要使用DMA,我们先在这里吧DAM配置好。

配置中等速度其他的不用改。

(8)生成工程

 以上就是CubeMX所有的准备操作啦,下面是实现的代码。

2.串口中断与DMA相关重要函数介绍

(1)串口相关 

HAL库为串口中断提供了很多回调函数。 比如 错误回调、半完成回调、Rx、Tx完成回调。你需要用什么回调,就声明什么回调~

接收完成回调函数:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

其中“RxCpltCallback” 可以分解为以下部分:

  • “Rx” 通常代表 “Receive”,即接收。
  • “Cplt” 通常代表 “Complete”,即完成。
  • “Callback” 即回调,指的是当某个特定事件发生时被调用的函数。

 接收串口的函数:

HAL_UART_Receive_IT(&Uart1,Buff,Rx_Size,200)

他的参数分别为:串口配置结构体地址、接收缓冲区(我们自己定义的数组)、预计接收的字节个数(我们自己定义)、超时时间(单位为ms)

接收串口的函数会有四个返回值:

HAL_OK、 代表此次在200ms内接受到了 200 字节。 (也就是与预计相等)
HAL_ERROR 、代表传参错误、 比如超时时间为0、或者数据缓冲区地址为空
HAL_TIMEOUT 、代表未能在规定时间内接收到 200 个字节
往往分为两种情况: 1、接收了但没接收完、2、一点没接收
HAL_BUSY、代表已经在接受了。在忙

注意!!!当接受完size(预计接受的字节)后就会触发串口中断,但如果没有接收完size个字节,而是少接受了字节,就不会触发串口中断,但是数组缓冲区中仍然有数据,这也就是为什么很多博主喜欢把size设置为1,因为一接触到数据就进一次中断。

 发送串口的函数:

HAL_UART_Transmit_IT(&huart1,txBuff,200);

 他的参数分别为:串口配置结构体地址、发送缓冲区(我们自己定义的数组)、预计发送的字节个数(我们自己定义)。

空闲中断打开函数:

__HAL_UART_ENABLE_IT(&uart1.uart,UART_IT_IDLE);

在每次进入中断后,判断是否为空闲中断:

if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE))

清除空闲标志位

__HAL_UART_CLEAR_FLAG(&uart1.uart, UART_FLAG_IDLE);

终止当前的接收(会把RxferCount清零)

HAL_UART_AbortReceive_IT(&uart1.uart);

终止接收回调函数

void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)

发送完成回调函数

HAL_UART_TxCpltCallback

(2)DMA相关

DMA(Direct Memory Access)是一种直接内存访问技术,

可以在不经过CPU的情况下实现外设与内存之间的数据传输,提高数据传输效率

同时,DMA同样可以触发串口中断,进入串口中断函数处理任务。

串口DMA接收函数:

HAL_UART_Receive_DMA(&huart1, (uint8_t *)&ReBuff,5);

他的参数分别为:串口配置结构体地址、接收缓冲区(我们自己定义的数组)、预计接收的字节个数(我们自己定义)。

其效果和串口接收函数是一样的,注意的要点也一样,这里就不多描述。

串口DMA发送函数:

HAL_UART_Transmit_DMA(&huart1,(uint8_t *)"stop",5);

他的参数分别为:串口配置结构体地址、发送缓冲区(我们自己定义的数组或字符串)、预计发送的字节个数(我们自己定义)。

3.编写相关代码

(1)项目要求

stm32使用(无线串口)实现收发、判断数据+DMA(HAL库),现象如下:

项目开始:单片机通过串口发送: Hello windows! ,后PC端通过串口助手发送stop,单片机接收到后停止Hello windows!发送,PC端再通过串口助手发送start,单片机接收到后同样发送start,并且开始Hello windows!发送。如下图

(2)相关代码编写

1.全局变量

char ReBuff[5];//接收缓冲区
int flag=1;//对于stop和start的判断标志
uint8_t SendBuff[]="Hello windows! ";//字符串"Hello windows! "封装
const char *str1="start";//字符串"start! "封装
const char *str2="stop";//字符串"stop "封装
char *result1 ;//strstr比较结果
char *result2 ;

2.main.c

在while函数上加上HAL_UART_Receive_DMA(&huart1, (uint8_t *)&ReBuff,5);

接收串口信息,当达到5个数组时触发中断。

下面是while里面的函数

/* USER CODE BEGIN 3 */
        result1 = strstr(ReBuff, str1);
    result2 = strstr(ReBuff, str2);
        if(result1)
        {
            flag=1;
        HAL_UART_Transmit_DMA(&huart1,(uint8_t *)"start",5);
            memset(ReBuff, 0, sizeof(ReBuff));   
            result1 =0;
            
        }
        else if(result2)
        {
          flag=0;
            HAL_UART_Transmit_DMA(&huart1,(uint8_t *)"stop",5);
            memset(ReBuff, 0, sizeof(ReBuff));
      result2 =0;            
        }
        if(flag==1)
     {
          HAL_UART_Transmit_DMA(&huart1,(uint8_t *)SendBuff,17);
            HAL_Delay(1000);
     }
  }
  /* USER CODE END 3 */

这里使用的strstr函数,用于查找子字符串在另一个字符串中的第一次出现,使用此函数时要添加下面的头文件才可以使用。

#include "string.h"
#include "stdio.h"

 这里使用的memset函数,用于清零数组。同样要加上述头文件。

下面是,HAL_UART_RxCpltCallback里触发中断后的操作

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance==USART1)//判断是串口1中断被触发
	{
		HAL_UART_Receive_DMA(&huart1, (uint8_t *)&ReBuff,5); //用于再次开启串口中断等待
	}
}

stm32f1xx_it.c">3.stm32f1xx_it.c

主要修改void USART1_IRQHandler(void),其他不需要修改。

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
  /* 在每次进入中断后,判断是否为空闲中断 */
    if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)){
        /* 清除空闲标志位 */
        //__HAL_UART_CLEAR_FLAG(&uart1.uart, UART_FLAG_IDLE);
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);
        /* 终止当前的接收(会把RxferCount清零) */
        HAL_UART_AbortReceive_IT(&huart1);//放弃串口1中断
        HAL_UART_Receive_DMA(&huart1, (uint8_t *)&ReBuff,5);//开启串口1中断
    }
  /* USER CODE END USART1_IRQn 1 */
}

      这里最后放弃串口1中断,是因为不放弃的话,比如串口1接收到长度为4的信号stop,这时候主函数中判断已经发生,且已经将接收缓冲数组中的值清零,但由于没有放弃串口1中断,导致继续接收的数据没有从缓冲数组的首位开始写,使得数据紊乱。所以需要重新关闭再开启接收中断。

      至此,软件部分编写完毕。

4.ATK-LORA-01无线串口的使用

1.使用该无线串口前,需要通过软件调整该串口的参数配置。

2.步骤如下:

(1)用UBS-TTL串口连接无线串口进行参数配置

连接MD0引脚后,在上位机按下

等待出现框中回复时,可进行配置,再按下“保存配置”时,配置成功!

注意!!!通讯中的两个ATK-LORA-01模块都要配置相同信道、波特率、地址、功率。

上位机软件如下:

通过网盘分享的文件:上位机软件.rar
链接: https://pan.baidu.com/s/1qQxlQT5BfZvN-iksfvM45g 提取码: ua25

总结:

       我们学习知识,要理解运用,将所用到的知识化为自己的知识才是重点。此外,串口通常只是单对单的通信,这一点上我认为不如IIC,希望这篇文章能够帮助到大家,谢谢!

       文章程序源码我发在下面了,需要自取。

通过网盘分享的文件:DMA-test1
链接: https://pan.baidu.com/s/1HVK7Me02YbYHvHsmysKrFA 提取码: ike8


http://www.niftyadmin.cn/n/5868441.html

相关文章

2025年第16届蓝桥杯嵌入式竞赛学习笔记(十):ADC测量电压

1.原理图 VDD的最大值为3.3V,所以PB15测量电压值的范围为0~3.3V,然后它读取到的AD值为0~4096,所以电压测量公式为 为什么是4096,因为ADC是一个12比特的 2.CubeMX配置 将PB15引脚配置为ADC2_IN15,PB12配置为ADC1_IN11 …

【LeetCode Hot100】旋转图像|原地旋转 vs 转置+反转,Java实现,图解+代码

💻 [LeetCode Hot100] 旋转图像|原地旋转 vs 转置反转,Java实现,图解代码 ✏️本文对应题目链接:旋转图像 📌 题目描述 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 …

[杂学笔记]OSI七层模型作用、HTTP协议中的各种方法、HTTP的头部字段、TLS握手、指针与引用的使用场景、零拷贝技术

1.OSI七层模型作用 物理层:负责光电信号的传输,以及将光电信号转化为二进制数据数据链路层:主要负责将收到的二进制数据进一步的封装为数据帧报文。同时因为数据在网络中传递的时候,每一个主机都能够收到报文数据,该层…

安宝特科技 | Vuzix Z100智能眼镜+AugmentOS:重新定义AI可穿戴设备的未来——从操作系统到硬件生态,如何掀起无感智能革命?

一、AugmentOS:AI可穿戴的“操作系统革命” 2025年2月3日,Vuzix与AI人机交互团队Mentra联合推出的AugmentOS,被业内视为智能眼镜领域的“iOS时刻”。这款全球首个专为智能眼镜设计的通用操作系统,通过三大突破重新定义了AI可穿戴…

使用内置命令查看笔记本电池健康状态

如何使用powercfg /batteryreport命令查看笔记本电池健康状态 在Windows系统中,了解笔记本电池的健康状态对于维护电脑性能和预测电池寿命至关重要。Windows 10和Windows 11系统提供了一个内置命令powercfg /batteryreport,可以生成一份详细的电池使用情…

计算机网络:应用层 —— 电子邮件

文章目录 电子邮件的起源与发展电子邮件的组成电子邮件协议邮件发送和接收过程邮件发送协议SMTP协议多用途因特网邮件扩展MIME 电子邮件的信息格式 邮件读取协议邮局协议POP因特网邮件访问协议IMAP 基于万维网的电子邮件 电子邮件(E-mail)是因特网上最早…

SSL/TLS 协议、SSL证书 和 SSH协议 的区别和联系

下面是 SSL/TLS 协议、SSL证书 和 SSH协议 的区别和联系,包含它们的英文全称和中文全称: 属性SSL/TLS 协议SSL证书SSH 协议英文全称Secure Sockets Layer / Transport Layer SecuritySecure Sockets Layer CertificateSecure Shell Protocol中文全称安全…

UE5 Computer Shader学习笔记

首先这里是绑定.usf文件的路径,并声明是用声明着色器 上面就是对应的usf文件路径,在第一张图进行链接 Shader Frequency 的作用 Shader Frequency 是 Unreal Engine 中用于描述着色器类型和其执行阶段的分类。常见的 Shader Frequency 包括&#xff1a…