STM32F103VET6基于STM32CubeMX创建串口中断+ DMA 不定长数据接收

STM32F103VET6基于STM32CubeMX创建串口中断+ DMA 不定长数据接收


📓DMA参数介绍

  • 🎉DMA传输方式
    在这里插入图片描述
  • 🌿传输方向; 外设到内存;内存到外设;内存到内存; 外设到外设
  • 🌿DMA_Mode_Normal,正常模式,

🍁当一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次

  • 🌿DMA_Mode_Circular ,循环传输模式

🍁当传输结束时,硬件自动会将传输数据量寄存器进行重装,进行下一轮的数据传输。 也就是多次传输模式.

  • 🌿Data Width :DMA内存地址自增,每次增加一个Byte(字节)

⛳注意事项

  • 🚩本例程的串口1中断服务函数不是由STM32CubeMX自动配置生成的,而是定义在main.c文件中,默认是勾选上的,如果没有取消勾选,生成代码后,会与stm32f1xx_it.c中生成相关的中断服务函数会与main.c中的USART1_IRQHandler函数重复冲突,导致编译报错。
    在这里插入图片描述

🌼主程序main.c代码完善

  • 📜在main.c中添加下面的代码
#define UART_RX_LEN 1024           // 一次最大接收的数据量
uint8_t UART_RX_BUF[UART_RX_LEN];  // DMA数据接收缓存
__IO uint16_t UART_RX_STA = 0;     // 第15bit表示一帧数据接收完成,第14~0位表示接收到的数据量

void USART1_IRQHandler(void)
{//串口中断函数
	if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET)  // 空闲中断标记被置位
	{
	    __HAL_UART_CLEAR_IDLEFLAG(&huart1);  // 清除中断标记
	    HAL_UART_DMAStop(&huart1);           // 停止DMA接收
	    UART_RX_STA = UART_RX_LEN - __HAL_DMA_GET_COUNTER(huart1.hdmarx);  // 总数据量减去未接收到的数据量为已经接收到的数据量
	    UART_RX_BUF[UART_RX_STA] = 0;  // 添加结束符
	    UART_RX_STA |= 0X8000;         // 标记接收结束
	    HAL_UART_Receive_DMA(&huart1, UART_RX_BUF, UART_RX_LEN);  // 重新启动DMA接收
	}
}
  • 🔖在while(1)中添加下面的代码:
		if(UART_RX_STA & 0X8000)
{
	HAL_UART_Transmit(&huart1, UART_RX_BUF, UART_RX_STA & 0X7FFF, 100);    // 将接收到的数据发送回去
	UART_RX_STA = 0;  // 清除标记
}
 printf("STM32F103CET6");
	HAL_Delay(1000);
  }

📝printf重定向相关代码

  • 📑在usart.c文件中添加下面的代码,并在target设置中勾选Use Micro Lib选项,,并在调用printf函数的地方包含stdio.h头文件。
#include <stdio.h>
int fputc(int ch,FILE *f)
{
    uint32_t temp = ch;
 
    HAL_UART_Transmit(&huart1,(uint8_t *)&temp,1,0xFFFF);        //huart1是串口的句柄
    HAL_Delay(2);
 
    return ch;
}

📒其他打印封装函数参考:

#include <stdio.h>
#include "usart.h"
#include <string.h>
#include <stdarg.h>
//使用printf()发送数据,需要对printf函数进行重定向,且只能使用USART1。
// 重定向fputc函数,使用printf()发送数据
int fputc(int ch, FILE *f)
{
	// 参数1:串口句柄,参数2:要发送的数据;参数3:要发生数据的长度;参数4:超时等待时间
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100);
	return ch;
}
//DMA发送:本项目中使用的方法
// DMA模式
void log_DMA(const char *format, ...)
{
	va_list args;			// 定义参数列表变量
	va_start(args, format); // 从format位置开始接收参数表,放在arg里面

	char strBuf[256];				// 定义输出的字符串
	vsprintf(strBuf, format, args); // 使用vsprintf将格式化的数据写入缓冲区
	va_end(args);					// 结束可变参数的使用

	// 等待上次的数据发送完成,避免新的数据覆盖正在传输的数据,导致混乱
	while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)
	{
		// Wait for DMA transfer to complete
	}

	HAL_UART_Transmit_DMA(&huart1, (uint8_t *)strBuf, strlen(strBuf));
}


//中断式发送:
// 中断模式
void log_IT(const char *format, ...)
{
	va_list args;			// 定义参数列表变量
	va_start(args, format); // 从format位置开始接收参数表,放在arg里面

	char strBuf[256];				// 定义输出的字符串
	vsprintf(strBuf, format, args); // 使用vsprintf将格式化的数据写入缓冲区
	va_end(args);					// 结束可变参数的使用

	// 等待上次的数据发送完成,避免新的数据覆盖正在传输的数据,导致混乱
	while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)
	{
		// Wait for transfer to complete
	}

	HAL_UART_Transmit_IT(&huart1, (uint8_t *)strBuf, strlen(strBuf));
}

//使用sprintf()函数,阻塞式发送:
// 堵塞模式
void log(const char *format, ...)
{
	va_list args;			// 定义参数列表变量
	va_start(args, format); // 从format位置开始接收参数表,放在arg里面

	char strBuf[256];				// 定义输出的字符串
	vsprintf(strBuf, format, args); // 使用vsprintf将格式化的数据写入缓冲区
	va_end(args);					// 结束可变参数的使用
	HAL_UART_Transmit(&huart1, (uint8_t *)strBuf, strlen(strBuf), HAL_MAX_DELAY);
}

📚工程源码

链接:https://pan.baidu.com/s/1O1CnA0eMttLLXWZPpUWJEQ 
提取码:ud7l
  • 🌿DMA接收+空闲中断例程
链接:https://pan.baidu.com/s/1qOtfw21j0pQmAhJoVUe-cw?pwd=pb23 
提取码:pb23
  • 🌿DMA接收+空闲中断+DMA发送例程
链接:https://pan.baidu.com/s/1TaeL2FCV-uqDv6xbXrnvhw?pwd=vtrk 
提取码:vtrk
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值