STM32-UART 空闲中断+DMA发送接收

STM32-UART 空闲中断+DMA发送接收

cubemx配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


这里DMA的初始化一定要在串口初始化前面,否则会有问题
在这里插入图片描述


代码


main.c中加入这个,创建缓冲区,标志位等

//用于DMA接收
uint8_t u1_rec_buf[MAX_BUF];
uint8_t receive_num;
//用于DMA发送
uint8_t sendbuf[8000]={0};//创建一个发送缓冲区
uint8_t Tx_busy=0;//等于0表示dma-tx空闲中,可以发送,等于1说明发送中,需要等待

main.h中加入这个

#define MAX_BUF 200
extern uint8_t u1_rec_buf[];
extern uint8_t receive_num;

main()函数中,加入
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能空闲中断
HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);//使能串口接收DMA

加入位置为初始化完成后如下

HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能空闲中断
HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);//使能串口接收DMA
/* USER CODE END 2 */



DMA发送示例


初始化时同时把发送数组填充满

for(uint16_t i=0;i<8000;i++)
{
	sendbuf[i]='g';
}

while(1)里

while(1)
{
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);//点亮LED
	while(Tx_busy==1)//等待标志位归零,即发送完成
	{
	}
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,0);//关闭LED
	HAL_Delay(2000);
	HAL_UART_Transmit_DMA(&huart1,sendbuf,8000);//使能DMA发送
	Tx_busy=1;//发送标志位置1
}

重定义串口发送完成回调函数,我们在这里清空标志位

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance==USART1)
	{
		Tx_busy=0;//释放总线
	}
}

试验现象:DMA发送时led会点亮,发送完成后led会熄灭,两秒一次循环
如果修改发送数组个数,现在是8000,改成4000,led亮的时间会缩短一半,不可以太小,要不观察不到了就
为什么一定要用led?而不用printf等,如果说printf也是用的串口1,那么会出现printf打印不出来的现象,因为dma已经占据了串口发送的位置,cpu不暂停dma的时候去抢发送的位置是抢不到了,也只有等到dma发送完成了端口被释放了才可以再printf出去,如果printf用的其它串口,那么是可以正常使用的
用到的API:
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)串口DMA发送函数,正常会返回HAL_OK,不过在本例中没有使用返回值
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)原来是个弱定义,我们自己重新写,函数会在TX完成时被调用,我们用它清除标志位就可以了。
中断中建议使用标志位代替复杂操作,在主循环中去检测标志位进行相应措施就可以了,养成好习惯。


DMA空闲中断接收示例


在原有的串口1中断服务函数添加新代码

void USART1_IRQHandler(void)
{
	/* USER CODE BEGIN USART1_IRQn 0 */
	if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)==SET)   //判断是否是空闲中断
	{
	__HAL_UART_CLEAR_IDLEFLAG(&huart1);                     //清楚空闲中断标志
	HAL_UART_DMAStop(&huart1); //  停止DMA传输
	receive_num=MAX_BUF-__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
	HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);//重新打开DMA接收
	}
	/* USER CODE END USART1_IRQn 0 */
	HAL_UART_IRQHandler(&huart1);
	/* USER CODE BEGIN USART1_IRQn 1 */
	
	/* USER CODE END USART1_IRQn 1 */
}

mian()主循环中

 while (1)
  {
		if(receive_num!=0)//有了接收
		{
			printf("\nreceive_num=%d\n",receive_num);//打印接收个数
			HAL_UART_Transmit_DMA(&huart1,u1_rec_buf,receive_num);//将接收内容原封不动返还回去
			receive_num=0;//清空标志位
		}
  }

实验现象
在这里插入图片描述


版权声明:本文为CSDN博主「gxt_kt」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/my_id_kt/article/details/122412078

STM32-UART 空闲中断+DMA发送接收

cubemx配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


这里DMA的初始化一定要在串口初始化前面,否则会有问题
在这里插入图片描述


代码


main.c中加入这个,创建缓冲区,标志位等

//用于DMA接收
uint8_t u1_rec_buf[MAX_BUF];
uint8_t receive_num;
//用于DMA发送
uint8_t sendbuf[8000]={0};//创建一个发送缓冲区
uint8_t Tx_busy=0;//等于0表示dma-tx空闲中,可以发送,等于1说明发送中,需要等待

main.h中加入这个

#define MAX_BUF 200
extern uint8_t u1_rec_buf[];
extern uint8_t receive_num;

main()函数中,加入
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能空闲中断
HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);//使能串口接收DMA

加入位置为初始化完成后如下

HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能空闲中断
HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);//使能串口接收DMA
/* USER CODE END 2 */



DMA发送示例


初始化时同时把发送数组填充满

for(uint16_t i=0;i<8000;i++)
{
	sendbuf[i]='g';
}

while(1)里

while(1)
{
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);//点亮LED
	while(Tx_busy==1)//等待标志位归零,即发送完成
	{
	}
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,0);//关闭LED
	HAL_Delay(2000);
	HAL_UART_Transmit_DMA(&huart1,sendbuf,8000);//使能DMA发送
	Tx_busy=1;//发送标志位置1
}

重定义串口发送完成回调函数,我们在这里清空标志位

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance==USART1)
	{
		Tx_busy=0;//释放总线
	}
}

试验现象:DMA发送时led会点亮,发送完成后led会熄灭,两秒一次循环
如果修改发送数组个数,现在是8000,改成4000,led亮的时间会缩短一半,不可以太小,要不观察不到了就
为什么一定要用led?而不用printf等,如果说printf也是用的串口1,那么会出现printf打印不出来的现象,因为dma已经占据了串口发送的位置,cpu不暂停dma的时候去抢发送的位置是抢不到了,也只有等到dma发送完成了端口被释放了才可以再printf出去,如果printf用的其它串口,那么是可以正常使用的
用到的API:
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)串口DMA发送函数,正常会返回HAL_OK,不过在本例中没有使用返回值
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)原来是个弱定义,我们自己重新写,函数会在TX完成时被调用,我们用它清除标志位就可以了。
中断中建议使用标志位代替复杂操作,在主循环中去检测标志位进行相应措施就可以了,养成好习惯。


DMA空闲中断接收示例


在原有的串口1中断服务函数添加新代码

void USART1_IRQHandler(void)
{
	/* USER CODE BEGIN USART1_IRQn 0 */
	if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)==SET)   //判断是否是空闲中断
	{
	__HAL_UART_CLEAR_IDLEFLAG(&huart1);                     //清楚空闲中断标志
	HAL_UART_DMAStop(&huart1); //  停止DMA传输
	receive_num=MAX_BUF-__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
	HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);//重新打开DMA接收
	}
	/* USER CODE END USART1_IRQn 0 */
	HAL_UART_IRQHandler(&huart1);
	/* USER CODE BEGIN USART1_IRQn 1 */
	
	/* USER CODE END USART1_IRQn 1 */
}

mian()主循环中

 while (1)
  {
		if(receive_num!=0)//有了接收
		{
			printf("\nreceive_num=%d\n",receive_num);//打印接收个数
			HAL_UART_Transmit_DMA(&huart1,u1_rec_buf,receive_num);//将接收内容原封不动返还回去
			receive_num=0;//清空标志位
		}
  }

实验现象
在这里插入图片描述


版权声明:本文为CSDN博主「gxt_kt」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/my_id_kt/article/details/122412078

生成海报
点赞 0

gxt_kt

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

STM32-UART 空闲中断+DMA发送接收

STM32-UART 空闲中断DMA发送接收 cubemx配置 这里DMA的初始化一定要在串口初始化前面,否则会有问题 代码 main.c中加入这个,创建缓冲区,标志位等 //用于DMA接收 ui

驱动led --GPIO控制

GPIO引脚操作方法概述 硬件知识_LED原理图不同主芯片控制GPIO引脚的方法概述具体单板控制GPIO引脚的方法详解具体单板LED程序的编写与实验汇编与机器码编程知识_进制编程知识_字节序_位操作编写C程序控制LED解析C程序的内部机制完善

自制 RTOS

目录 0. 配置 1. 体系架构 2. 内存管理 3. 任务/调度器 3. IPC 3.1 信号量 3.2 互斥锁 3.3 消息队列 4. 临界区保护 4.1. 全局中断 4.2. 挂起调度器 4.3. 互斥锁 5.