[STM32F103]基于HAL库用DMA实现不定长串口数据收发(手把手一起做)

目录

        前言

1.基础知识

        1.1DMA简介

        1.2 串口简介

2.STM32CUBEMX配置(工程创建)

        2.1 基础配置

        2.2 串口配置

        2.3 DMA配置

        2.4 工程创建

3. 库函数简介

4.DMA空闲中断收发串口数据

5.实验现象


前言

        本文主要讲述了利用STM32Cubemx来配置DMA串口收发,会手把手一步一步的进行教学,量大管饱,放心食用。

        本文使用的芯片为STM32F103C8T6(经典老演员了),使用的工具为STM32Cubemx。

        本文主要面向初学者,详细讲述了配置过程。如果你有任何疑问,都可以在文章后面留言(虽然我也不一定回答就是了doge)。

1.基础知识

1.1DMA简介

        在正式配置之前,我们先来一起简单了解一下DMA。

        DMA(Direct Memory Access,直接内存访问)是一种用于处理器和外设之间传输数据的技术,通过DMA,外设可以直接访问内存中的数据,而不需要处理器的干预,从而提高数据传输的效率。

        举个例子:

        我是元始天尊,我把灵珠给太乙真人,然后通过太乙真人把灵珠给殷夫人,这是常规情况的数据传输,太乙真人就是CPU,灵珠就是数据,这样做会占用太乙真人的精力(消耗CPU的资源)。

        然而实际上,太乙真人在这中间仅仅只是充当了一个大自然的搬运工,这样太大材小用了,像太乙真人这样的十二金仙,有捍卫人间正道,斩妖除魔的大事儿要处理,哪儿能天天当快递员呀。

        于是,伟大的元始天尊(也就是我),想了一个办法,我直接用法术,把灵珠传送到殷夫人肚子里面,这就是DMA了。灵珠就是数据,法术就相当于是DMA通道,这样不但太乙真人可以去干大事儿了,灵珠也能更快到达殷夫人肚子里面了,两全其美,皆大欢喜。

        这张图就是我上面描述的过程,有细心的小伙伴可能发现了,我这里用的是双向箭头,因为这里的数据传输,也是双向的,殷夫人收到灵珠了,但是她不会用呀,那她也可以通过DMA通道,找我要使用说明书;太乙真人那边同理啊,太乙真人就相当于一个客服,他可以把殷夫人的问题转述给我。所以这里数据传输是双向的,因为他只是一个通道,这个通道双方都可以使用。

        看懂了上面那张图,那我们接下来看看STM32参考手册的图:

           乍一看是不是感觉好复杂?不要害怕,我们一起来仔细看一下:

        红色的部分,就是元始天尊,我把数据通过DMA通道(蓝色部分),直接传递给殷夫人(绿色部分),这就是DMA传输,很好理解,对吧?是不是和上面那张哪吒的图一摸一样呀?

1.2 串口简介

这里就不再赘述啦,不清楚的同学可以看看我这篇文章:

https://blog.csdn.net/Jin_Apple/article/details/142100390?spm=1001.2014.3001.5502

2.STM32CUBEMX配置(工程创建)

2.1 基础配置

首先打开STM32CUBEMX,选择我们的芯片(我这里用的是STM32F103C8T6)

然后是时钟配置,这里选择外部高速时钟,然后配置时钟频率72Mhz(这里输入完成之后直接按回车就可以了)

然后是系统配置

2.2 串口配置

接下来我们来配置串口:

选择USART1,将模式设置为异步通信,下面的波特率、传输长度等,我们用默认的就可以了。

2.3 DMA配置

为串口添加DMA,选择normal模式(正常模式)

2.4 工程创建

给你的工程起个名字,然后选择你的保存路径,选择MDK-ARM

然后点击右上角的GEAERATE CODE就可以了。

3. 库函数简介

接下来我们来介绍一下相关的函数:

HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)

这个是HAL库利用DMA发送数据的函数,我们先来看看官方对他的注释:

@brief就是简单介绍了一下这个函数的功能,以DMA模式发送数据。

@note 进行了一些补充说明,当UART奇偶校验没有启用,且字长为9位时,发送的数据被视作uint16的数据,在这种情况下,size必须通过pdata提供uint16。是不是看着花里胡哨的?其实就这一大坨英文就表达了一个意思,如果UART配置为9位数据长度,就应该以uint16为单位进行处理,而不是uint8。(多啰嗦一句,uint8指的是无符号的8位整型,由8个二进制位组成,其最大值是1111 1111 ,也就是255,uint16是和它类似,不过是16位的)。

接下来我们来看参数:

huart:这是一个指向UART_HandleTypeDef结构体的指针。

pData:这是一个指向数据缓冲区的指针,可以是uint8或uint16类型的数据元素。根据UART配置,这个缓冲区可能包含8位或16位的数据。

Size:这是一个无符号整数,表示要发送的数据元素的数量。如果UART配置为9位数据长度,则这个参数应该表示uint16的数量。

我们用更简单的话来说明一下,pData,就是你要发送的数据,Size,就是你要发送的数据长度。

接下来我们再来看看接收函数:

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

可以看到这个其实和发送函数类似,简单来说,pData就是数据,Size就是接收的长度。

4.DMA空闲中断收发串口数据

接下来就到了改写代码的环节了,我们例程的功能是:收到1,则回复2。

在usart.c文件夹中添加如上代码,分别用于表示接受数据的长度、数据、以及接受完成的标志。

uint8_t Gu8RxLen = 0;
uint8_t Gu8RxDataBuf[16];
uint8_t Gu8RxEndFlag = 0;

这里开启空闲中断,并且用到了我们上面提到的接收函数。

	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能空闲中断
	HAL_UART_Receive_DMA(&huart1,Gu8RxDataBuf,16);

之后我们在usart.h文件里面,将我们上面定义的三个整型加上extern 关键字,这样只要其他文件里面引用了usart.h这个头文件,就可以使用这三个整型。

接下来我们来改一下中断部分:

先引用头文件,因为我们这里需要用到上面的整型

然后我们改写一下USART1_IRQHandler(void)这个函数

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
	uint32_t Lu32Itflag = 0;
	uint32_t Lu32Num = 0;
	Lu32Itflag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取空闲中断标志位
	if((Lu32Itflag != RESET))
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
		HAL_UART_DMAStop(&huart1); // 停止DMA传输
		Lu32Num =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数   
		Gu8RxLen =  16 - Lu32Num; //总计数减去未传输的数据个数,得到已经接收的数据个数
		Gu8RxEndFlag = 1;	// 接受完成标志位置1	
	 }
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

这下该准备的都准备好了,我们可以来实现我们上面需要的功能了。

在main.c里面定义一个数组,用来发送数据:

uint8_t Gu8TxBuf[16];
Gu8TxBuf[0] = 0x02;

此后在循环里面,加入如下代码:

while (1)
  {
    if(Gu8RxEndFlag == 1)//如果接收完成
    {
      if(Gu8RxDataBuf[0] == 0x01)//收到1
      {
       HAL_UART_Transmit_DMA(&huart1,Gu8TxBuf,1);//发送2
      }
    	Gu8RxEndFlag = 0;//清除接收完成标志位
    }
    /* USER CODE END WHILE */
    
    /* USER CODE BEGIN 3 */
  }

最后我们选择自己的烧录器,编译下载即可。

5.实验现象

可以看到我们这边已经成功了,当我发送1的时候,自动回复2。

本文参考了如下文章:

https://blog.csdn.net/as480133937/article/details/105013368

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值