DMA案例 外设到内存搬运

DMA案例 外设到内存搬运

需求
使用DMA的方式将串口接收缓存寄存器的值搬运到内存中,同时闪烁LED1。

CubeMX配置

串口配置
在这里插入图片描述
DMA配置
在这里插入图片描述
串口中断配置
在这里插入图片描述

用到的库函数

  1. __HAL_UART_ENABLE
#define __HAL_UART_ENABLE_IT(
	__HANDLE__,   // 参数一
	__INTERRUPT__ // 参数二
)   ((((__INTERRUPT__) >> 28U) == UART_CR1_REG_INDEX)? 
((__HANDLE__)->Instance->CR1 |= ((__INTERRUPT__) & UART_IT_MASK)): \
(((__INTERRUPT__) >> 28U) == UART_CR2_REG_INDEX)? 
((__HANDLE__)->Instance->CR2 |= ((__INTERRUPT__) & UART_IT_MASK)): \
((__HANDLE__)->Instance->CR3 |= ((__INTERRUPT__) & UART_IT_MASK)))

参数一:HANDLE, 串口句柄
参数二:INTERRUPT 需要使能的中断
返回值: 无

  1. HAL_UART_Receive_DMA
HAL_StatusTypeDef HAL_UART_Receive_DMA(
	UART_HandleTypeDef *huart,  // 参数一
	uint8_t *pData,   // 参数二
	uint16_t Size   // 参数三
)

参数一:UART_HandleTypeDef *huart 串口句柄
参数二:uint8_t *pData 接收缓存首地址
参数三:uint16_t Size 接收缓存长度
返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)

  1. __HAL_UART_GET_FLAG
#define __HAL_UART_GET_FLAG(
	__HANDLE__,   // 参数一
	__FLAG__   // 参数二
) (((__HANDLE__)->Instance->SR  & (__FLAG__)) == (__FLAG__))

参数一:HANDLE 串口句柄
参数二:FLAG 需要查看的FLAG
返回值:FLAG的值

  1. __HAL_UART_CLEAR_IDLEFLAG
#define __HAL_UART_CLEAR_IDLEFLAG(
	__HANDLE__   // 参数一
) __HAL_UART_CLEAR_PEFLAG(__HANDLE__)

参数一:HANDLE 串口句柄
返回值:无

  1. HAL_UART_DMAStop
HAL_StatusTypeDef HAL_UART_DMAStop(
	UART_HandleTypeDef *huart
)

参数一:UART_HandleTypeDef *huart 串口句柄
返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)

  1. __HAL_DMA_GET_COUNTER
#define __HAL_DMA_GET_COUNTER(
	__HANDLE__    // 参数一
) ((__HANDLE__)->Instance->CNDTR)

参数一:HANDLE 串口句柄
返回值:未传输数据的大小

代码实现

如何判断串口接收是否完成?如何知道串口收到数据的长度?

使用串口空闲中断(IDLE)!

  • 串口空闲时,触发空闲中断;
  • 空闲中断标志位由硬件置1,软件清零

利用串口空闲中断,可以用如下流程实现DMA控制的任意长数据接收;
1. 使能IDLE空闲中断;
2. 使能DMA接收中断;
3. 收到串口接收中断,DMA不断传输数据到缓冲区;
4. 一帧数据接收完毕,串口暂时空闲,触发串口空闲中断;
5. 在中断服务函数中,清除中断标志位,关闭DMA传输(防止干扰);
6. 计算刚才收到了多少个字节的数据。
7. 处理缓冲区数据,开启DMA传输,开始下一帧接收。

// main.c
#define BUF_SIZE 100
// 使能IDLE空闲中断
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); 

// 使能DMA接收中断
HAL_UART_Receive_DMA(&huart1, rcvBuf, BUF_SIZE); 

while (1)
{
  /* USER CODE END WHILE */
	HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
	HAL_Delay(300);
  /* USER CODE BEGIN 3 */
}

// main.h 
/* USER CODE BEGIN EM */

#define BUF_SIZE 100

/* USER CODE END EM */

// stm32f1xx_it.c

extern uint8_t rcvBuf[BUF_SIZE];
extern uint8_t rcvLen;
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) == SET){ // 判断IDLE标志位是否被置位
		// 清除标志位
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);
		
		// 停止DMA传输,防止干扰
		HAL_UART_DMAStop(&huart1);
		uint8_t temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
		
		// 计算数据长度
		rcvLen = BUF_SIZE - temp;
		
		//发送数据
		HAL_UART_Transmit_DMA(&huart1, rcvBuf, rcvLen);
		
		//开启DMA
		HAL_UART_Receive_DMA(&huart1, rcvBuf, BUF_SIZE);
	}
	
  /* USER CODE END USART1_IRQn 1 */
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值