【STM32】CUBEMX之串口:串口三种模式(轮询模式、中断模式、DMA模式)的配置与使用示例 + 串口重定向 + 使用HAL扩展函数实现不定长数据接收

这篇具有很好参考价值的文章主要介绍了【STM32】CUBEMX之串口:串口三种模式(轮询模式、中断模式、DMA模式)的配置与使用示例 + 串口重定向 + 使用HAL扩展函数实现不定长数据接收。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

 文章来源地址https://www.toymoban.com/news/detail-846269.html

总览

使用CUBEMX创建工程的基本配置

CUBEMX中的配置

Keil中的配置

实物连接

串口轮询模式

轮询模式HAL库函数

特点

实验一:发送数据给单片机并让其返回相同值

串口重定向

串口中断模式

在CUBEMX中打开串口中断

中断模式HAL库函数

特点

实验二:使用中断回调完成实验一

串口DMA模式

CUBEMX中添加DMA路径

DMA模式HAL库函数

特点

实验三:使用DMA模式完成实验一

串口不定长数据接收

串口空闲中断

串口接受HAL库扩展函数

特点

实验四:使用扩展函数完成实验一并实现不定长数据接收


 

总览

串口是常用的设备与设备之间发送和接受信息的工具,下面我们将使用STM32F103C8T6和CUBEMX, Keil 讲解如何使用CUBEMX配置串口异步通信下的三种模式(轮询模式、中断模式、DMA模式)以及相关HAL库函数。以及使用HAL库拓展函数实现串口不定长数据的接收

使用CUBEMX创建工程的基本配置

CUBEMX中的配置

打开软件,选择芯片类型,可以在左上角搜索芯片型号,选择好后点击Start Project创建一个新工程

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

首先在左栏找到System Core->SYS->Debug中,将其更改为Serial Wire

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

再来到RCC中修改高速外部时钟为外部晶振

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

接下来点击Clock Configuation配置时钟树,使用PLLCLK并将其时钟源修改为HSE,最后在HCLK中修改频率为72MHz,点击键盘上回车,Cubemx就会帮你将剩下的参数自己配置好

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

接下来来到Project Manager配置工程路径以及生成工程类型,这里由于我们使用的是Keil,所有在IDE选项中选择MDK-ARM即可

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

点击Code Generator,将第一项修改为只复制必要的文件,可以节省项目所占空间,接着在第二个选项中勾选生成独立的.c/.h代码,方变我们进行修改

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

最后一步,配置一个串口:回到Pinout&Configuration,在Connectivity中找到USART1,将其Mode修改为Asynchronous即异步通信模式

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

完成后我们就可以看到串口输出输入管脚分辨对应单片机上PA9以及PA10,RX为输入(即接受Receive)TX为输出(即发送Transmit)

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

配置好一个串口就是这样了,如果还需要中断、DMA模式可以返回继续配置

接下来点击右上角Generate Code就可以生成keil工程了,点击弹出的Open Project就可以打开新建的工程了

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

Keil中的配置

首先选择烧录器,我使用的是ST-link,点击魔术棒,在USE中修改其为St Link Debugger

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

接着点击Unilities选项,点击Settings,在弹出的选项卡中勾选Reset and Run

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

接着在Pack选项卡中取消勾选Enable,这样我们在烧录过后就可以不用手动复位了

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

keil的基本配置到此也结束了

实物连接

这里需要一些必要的驱动还需要USB转TTL模块:

CH340串口驱动,下载地址:

CH340 Drivers for Windows, Mac and Linux (gogo.co.nz)

ST-Link驱动,下载地址:

https://www.st.com/en/development-tools/stsw-link009.html

我用的串口软件是逐飞助手,下载地址:https://gitee.com/seekfree/seekfree_assistant/blob/master/%E3%80%90%E8%BD%AF%E4%BB%B6%E3%80%91%E9%80%90%E9%A3%9E%E5%8A%A9%E6%89%8B%E4%B8%8A%E4%BD%8D%E6%9C%BA/%E9%80%90%E9%A3%9E%E5%8A%A9%E6%89%8BV1.0.4.exe

具体的下载安装就不阐述了,基本都是跟着步骤来就好

连接的时候:将USB-TTL模块上的,A9->RX;A10->TX,如下图

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

串口轮询模式

轮询模式HAL库函数

//串口发送函数
HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
//参数分别为串口句柄,发送数据地址,发送数据大小,超时时间,举例
uint8_t TxBuffer[5]={1,2,3,4,5};
HAL_UART_Transmit(&huart1,TxBuffer,sizeof(TxBuffer),50);
//串口接收函数
HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
//参数分别为串口句柄,发送数据地址,发送数据大小,超时时间,举例
uint8_t RxBuffer[5]={0};
HAL_UART_Receive(&huart1,RxBuffer,sizeof(RxBuffer),50);

特点

只能接受或发送指定长度,或者在超时时间内接受或者发送,该等待时间内CPU阻塞

实验一:发送数据给单片机并让其返回相同值

打开刚刚创建的keil工程

1. 打开Application/User文件夹中的main.c文件

2. 下滑找到main函数,将代码写进主函数,代码在图片后面(将代码写在begin和end块之中可以防止再次生成时所写代码不被覆盖)

3. 点击③所示按钮进行编译,下方无error即可

4. 点击load将编译后生成的hex文件下载进单片机

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

uint8_t RxBuffer[5] = {0};

if(HAL_UART_Receive(&huart1,RxBuffer,sizeof(RxBuffer),1000)==HAL_OK)
	HAL_UART_Transmit(&huart1,RxBuffer,sizeof(RxBuffer),50);

接着打开串口调试助手,按照如图所示连接好串口,选择带有CH340的即可

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

接着给单片机发送数据,由于RxBuffer大小仅有5字节,所以一次只给单片机发送5字节数据,观察是否会返回。可以看到,在接收到数据后,单片机又将发送的数据返回

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

串口重定向

有c语言基础的同学都知道,我们常用接收和发送信息的函数是scanf和printf,进行串口重定向后,我们也可以在工程中使用该函数,步骤如下

首先,打开魔术棒,勾选微库

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

下拉main.c找位置重新改写fputc和fgetc函数

在上面引用函数库

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

接着添加改写后的函数

int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
    return ch;
}
int fgetc(FILE *f)
{
    uint8_t ch;
    HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
    return ch;
}

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

接着回到主函数while()中修改原来的代码

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

编译、下载后打开逐飞助手,就可以得到以下结果

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

串口中断模式

在CUBEMX中打开串口中断

回到cubemx界面,在刚刚的USART1界面找到NVIC Settings 勾选中断选项后点击生成代码

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

中断模式HAL库函数

//串口中断发送函数
HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
//参数与轮询模式差不多,但比轮询模式少了超时时间,中断情况下不需要使程序阻塞在此等待,使用例子如下
uint8_t TxBuffer[10] = {0};
HAL_UART_Transmit_IT(&huart1, TxBuffer, sizeof(TxBuffer));
//串口中断接收函数
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
//使用和上面的大致相同,这里不做过多阐述

这里需要注意的是:串口中断接收函数尽量不要放到while循环里,以免上一次接受还没完成就开启了下一次接受,出现BUG

串口中断接收函数在接收完成后会产生一次中断,我们可以在对应的中断回调函数中处理接收到的数据以及开启下一次接收,该中断回调函数需要我们自己重定义,模板如下

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
     if(huart == &huart1){                 //若有多个串口,接收完成后依然调用该中断回调函数,所以在书写中断回调函数时养成加判断的习惯
        //用户书写处理接收数据函数
     }
HAL_UART_Receive_IT(huart, pData, Size);   //再次启动串口接受中断用于接受下一次的数据
}

发送完成只有一样有其对应的中断回调函数,该函数为:

HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);

由于不经常使用,所以这里就不过多阐述,大致使用方式与接受完成回调函数相似

特点

解决了CPU阻塞问题,但仍然无法实现不定长数据接受

实验二:使用中断回调完成实验一

按照上述方法配置完CUBEMX后,接下来进行keil代码的编写,首先将上个实验中自己添加的代码删除。

由于需要在多个函数中调用RxBuffer,将其提升为全局变量,可以写在自带的PV(Private Varibles)注释对中

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

接下来在主函数中打开串口接收中断,注意,不要放在While()中

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

接下来在USER CODE BEGIN 4注释对中编写中断回调函数,代码及其功能详解在图片下方代码块中

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){        //接收中断回调函数
	if(huart == &huart1){                                       //判断返回串口
		HAL_UART_Transmit_IT(huart, RxBuffer, sizeof(RxBuffer));    //开启发送中断打印接收到的信息
	}
HAL_UART_Receive_IT(huart, RxBuffer, sizeof(RxBuffer));    //启用接收中断准备下一次数据的接收
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){    //发送中断回调函数
	if(huart == &huart1)
	{
		uint8_t SucMsg[11] = "\nsuccessful";
		HAL_UART_Transmit(huart, SucMsg, sizeof(SucMsg), HAL_MAX_DELAY);    //发送发送成功的信息,注意不要使用中断的形式,否则会反复调用该中断
	}
}

注:代码块successful中增加了一个"\n"是为了换行好观察数据

接下来重复编译烧录的过程,然后打开串口助手,发送一个10字的消息,得到结果如下

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

中断模式下的使用就到此为止了

串口DMA模式

Direct Memory Access-直接内存访问,在创建完DMA通道后,它会在合适的时机自动将数据转移,不占用CPU进行转移,且在转移完成后触发一次中断表明转移完成

CUBEMX中添加DMA路径

点击DMA settings->Add中添加如图所示两条路径,配置默认即可

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

设置好后点击generator code重新更新代码,(注意之前的NVIC中的中断也要打开)

DMA模式HAL库函数

//串口DMA发送函数
HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
//格式与使用方法与中断模式
uint8_t TxBuffer[10] = {0};
HAL_UART_Transmit_DMA(&huart1, TxBuffer, sizeof(TxBuffer));
//串口DMA接收函数
HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
//使用和上面的大致相同,这里不做过多阐述

特点

进一步减少了对CPU的占用,仍无法实现不定长数据接受

实验三:使用DMA模式完成实验一

DMA传输完成后也是调用TxCpltCallback与RxCpltCallback函数

故我们只需要在原keil代码中把IT换成DMA即可

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

编译下载后打开串口助手,调试结果如下

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

串口不定长数据接收

串口空闲中断

空闲中断发生时,表明一帧数据包接受完成,在此时对数据进行分析处理即可

串口接受HAL库扩展函数

HAL_UARTEx_ReceiveToIdle(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint16_t *RxLen, uint32_t Timeout);//阻塞轮询
HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);//中断
HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);//DMA

注意:由于接受的是不定长数据,可以把用于接收的数组长度写大一点 Size不表示期望接受的数据长度,而是一次可接受的数据的最大长度,一般填写接受数组的长度

串口中断空闲回调函数

HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size);
//一般需要用户重定义,且完整书写用户自定义回调函数格式应为:
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
     if(huart == &huart2){
        //用户书写处理接收数据函数
     }
HAL_UARTEx_ReceiveToIdle_DMA(huart, pData, Size);   //再次启动串口接受中断用于接受下一次的数据,此处采用DMA,采用中断模式也可以
__HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT); //关闭DMA传输过半中断,如果上面采用中断模式则不需要
}

注意:比RxCpltCallback函数多出参数Size,该参数表示接收到的数据长度 使用ReceiveToIdle函数后,不再调用RxCpltCallback回调 使用DMA模式的ReceiceToIdle会触发传输过半中断(接收到Size一半的数据),如果想接受完整数据,则需要将其关闭

特点

结合DMA模式后,实现了对CPU的最小占用程度和对不定长数据的接收和处理

实验四:使用扩展函数完成实验一并实现不定长数据接收

由于我们在CUBEMX中已经打开DMA以及中断,所以CUBEMX中可以不用再做配置

打开keil,删除上次实验写的代码

首先添加一个比较大的接受数组,然后添加一个了来自外部文件usart.c的句柄

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

然后在主函数中开启一次接受,跟上面一样,不要放在while()中

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

最后在注释对中添加中断回调函数

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

所有添加的代码及注释都在这里啦

uint8_t RxBuffer[50] = {0};


extern DMA_HandleTypeDef hdma_usart1_rx;


HAL_UARTEx_ReceiveToIdle_DMA(&huart1,RxBuffer,50);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT); //关闭过半中断


void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
     if(huart == &huart1){
			 HAL_UART_Transmit(huart, RxBuffer, sizeof(RxBuffer),HAL_MAX_DELAY);//传输回接受的数据
			 for(uint8_t i = 0;i < sizeof(RxBuffer); i++)	RxBuffer[i] = 0;//将上一次的数据清零,若不清零,下一次的数据若小于上一次,则会保留上一次多出来的数据
     }
HAL_UARTEx_ReceiveToIdle_DMA(huart, RxBuffer, 50); //再次打开接受
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT); //关闭过半中断,以获得完整数据
}

编译下载后打开串口助手,最后的结果就是这样啦

cubemx stm32f1 dma 中断,STM32,stm32,单片机,嵌入式硬件

以上就是串口的基本常用用法以及其实践了,欢迎大家讨论

 

 

 

 

 

 

 

到了这里,关于【STM32】CUBEMX之串口:串口三种模式(轮询模式、中断模式、DMA模式)的配置与使用示例 + 串口重定向 + 使用HAL扩展函数实现不定长数据接收的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • STM32 CubeMX ADC采集 单通道,多通道,内部温度(轮询,DMA,中断)(HAL库)

    12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部 信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右 对齐方式存储在16位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定

    2024年02月06日
    浏览(25)
  • 【STM32 CubeMX】串口编程DMA+IDLE中断

    在嵌入式系统中,串口通信是一项关键的任务,而使用DMA(直接内存访问)结合IDLE中断进行串口编程,尤其是在STM32 CubeMX环境中,能够提高系统的效率和性能。STM32 CubeMX为STM32微控制器提供了图形化的配置工具,可以简化初始化代码的生成过程,使得串口编程变得更加容易。

    2024年02月20日
    浏览(27)
  • STM32 cubemx+串口空闲中断+DMA双缓冲

            写这篇文章是为了记录下之前做过的项目中用到的一部分关键技术,之前做过的项目中涉及到 采用最小开销来实时接收遥控器数据、能够准确验证传输过来数据的准确性 ,减小误差率,要求能稳定适用于不同的环境。 目录 1、为什么要用到串口空闲中断? 2、为

    2024年02月09日
    浏览(18)
  • STM32F4_HAL库_串口阻塞/中断/DMA三种方式发送数据的配置

    串口阻塞发送的意思就是,发送一段数据,在没有发送完所有数据之前,一直停留在此发送函数(可设定阻塞时间),这个过程中会阻塞别的程序运行; HAL库的配置分为两个层次,一个是HAL库内部调用的、与MCU硬件相关的初始化xxx_MspInit,一个是我们外部调用的初始化xxx_In

    2023年04月25日
    浏览(15)
  • HAL库学习05---串口通信(三种方式轮询、中断、DMA)

    串行通信的通讯方式可以分为两类: 1、同步通信 ,带时钟信号的传输,如SPI、IIC、USART 2、异步传输 ,不带时钟信号的传输,如UART、USART UART通用异步收发器 :UART口指的是一种物理接口形式(硬件) UART是异步,全双工串口总线。它比同步串口复杂很多。有两根线,一根TXD用于

    2024年02月11日
    浏览(13)
  • STM32使用三种方式(阻塞、中断、DMA)实现串口发送和接收数据

    记录下学习STM32开发板的心得的和遇见的问题。 板卡型号:STM32F405RGT6 软件:STM32CubeMX、IAR STM32串口外设提供了3种接收和发送方式:阻塞、中断、DMA,主要给大家分享中断方式接收不定长数据和DMA使用空闲中断接收不定长数据。 阻塞发送: 阻塞接收: 两个函数需要注意的就

    2024年02月03日
    浏览(23)
  • STM32 cubemx配置DMA+空闲中断接收不定长数据

    本篇文章给大家讲解一下DMA+串口空闲中断接收串口不定长数据,之前我们也是讲解过串口接收不定长数据的,那么本篇文章的话将使用DMA来接收不定长数据。 串口空闲中断是指在串口接收到数据后,在数据的传输结束之后,在一段连续的空闲时间内没有接收到新数据时触发

    2024年02月19日
    浏览(25)
  • STM32串口通信——DMA中断 (简单配置即可直接使用)

    目录 各函数的功能及使用方法 1.串口调试输出 2. 串口调试输出 接口设置    3. 串口格式化输出 4.用户串口DMA中断初始化函数 使用方法 1.找到系统的串口初始化函数 2.在结束位置添加我们的串口初始化函数  5.用户中断回调函数 使用方法 1.找到系统的中断服务.c文件 打开  

    2024年02月09日
    浏览(17)
  • (stm32之HAL库)UART工作在DMA模式要打开串口中断吗?

    最近学习了stm32(F4xx)的串口在DMA模式下的使用,期间以ST官方提供的例程进行参考学习,发现其初始化过程中是打开了UART的中断的,而且HAL库中stm32f4xx_hal_uart.c文件中的DMA模式使用说明里也有这么一句话: 即在非循环模式下(也就是发完一次数据就停止的常用模式)需要配置

    2024年02月12日
    浏览(17)
  • 【STM32 CubeMX】串口编程DMA

    在嵌入式系统中,串口通信是一项至关重要的功能,它允许单片机与外部设备进行数据交换,如传感器、显示器或其他设备。然而,在高速数据传输的场景下,传统的串口通信方式可能会使CPU过于繁忙,从而影响系统的性能。为了解决这一问题,STM32系列微控制器提供了DMA(

    2024年02月20日
    浏览(18)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包