参考文档:野火STM32F103
网友资料整理
1. Direct Memory Access-直接内存访问
DMA控制器独立于内核
是一个单独的外设
- DMA1有7个通道
- DMA2有5个通道
- DMA有四个等级,非常高,高,中,低四个优先级
- 如果优先等级相同,通道编号越小优先级越高
- 数据流向: 存储器到存储器,存储器到外设,外设到存储器
- 单次传输或循环传输
- 传输过半中断,传输完成中断,传输错误中断
2. 串口示例
- 初始化
// 定义一个GPIO初始化结构体,并初始化为0
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 检查当前USART实例是否为USART1
if(uartHandle->Instance==USART1)
{
// 用户自定义代码区域开始(USART1_MspInit 0)
/* USER CODE BEGIN USART1_MspInit 0 */
// 用户自定义代码区域结束(USART1_MspInit 0)
/* USER CODE END USART1_MspInit 0 */
// 使能USART1时钟
__HAL_RCC_USART1_CLK_ENABLE();
// 使能GPIOA时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
// USART1 GPIO配置说明
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
// 配置GPIO引脚
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; // 选择PA9和PA10引脚
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 设置为复用推挽输出模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 不使用上拉或下拉电阻
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; // 设置最高频率
GPIO_InitStruct.Alternate = GPIO_AF4_USART1; // 选择USART1复用功能
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化GPIO
// USART1 DMA初始化
// USART1_TX DMA通道初始化
hdma_usart1_tx.Instance = DMA1_Channel2; // 选择DMA1通道2
hdma_usart1_tx.Init.Request = DMA_REQUEST_3; // 选择DMA请求3
hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; // 数据传输方向:内存到外设
hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE; // 禁用外设地址递增
hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE; // 启用内存地址递增
hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; // 外设数据对齐方式:字节
hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; // 内存数据对齐方式:字节
hdma_usart1_tx.Init.Mode = DMA_NORMAL; // 设置为普通模式
hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW; // 设置优先级为低
if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK) // 初始化DMA
{
Error_Handler(); // 如果初始化失败,调用错误处理函数
}
// 将DMA与USART1_TX关联
__HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);
// USART1中断初始化
HAL_NVIC_SetPriority(USART1_IRQn, 2, 0); // 设置USART1中断优先级
HAL_NVIC_EnableIRQ(USART1_IRQn); // 使能USART1中断
// 用户自定义代码区域开始(USART1_MspInit 1)
/* USER CODE BEGIN USART1_MspInit 1 */
// 用户自定义代码区域结束(USART1_MspInit 1)
/* USER CODE END USART1_MspInit 1 */
}
- DMA发送
/* USART1 向 DMA发出TX请求 */
HAL_UART_Transmit_DMA(&UartHandle, (uint8_t *)SendBuff ,SENDBUFF_SIZE);
- 使用DMA传输完成中断
//初始化
void MX_DMA_Init(void)
{
// 使能DMA控制器时钟
__HAL_RCC_DMA1_CLK_ENABLE();
// DMA中断初始化
// 配置DMA1通道2和3的中断
HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 2, 0); // 设置DMA1通道2和3中断的优先级为2,子优先级为0
HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); // 使能DMA1通道2和3的中断
}
//中断服务函数
/**
* @brief This function handles DMA1 channel 2 and channel 3 interrupts.
*/
void DMA1_Channel2_3_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel2_3_IRQn 0 */
/* USER CODE END DMA1_Channel2_3_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart1_tx);
/* USER CODE BEGIN DMA1_Channel2_3_IRQn 1 */
/* USER CODE END DMA1_Channel2_3_IRQn 1 */
}
//中断回调函数-打印传输完成结果
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
printf(" dma_ok\r\n");
}
}
//主函数
while (1)
{
HAL_UART_Transmit_DMA(&huart1, Tx_buff, 10);
HAL_Delay(1000);
}
结果:传输完数据到中断回调函数中打印 : dma ok
3. 库函数备注
串口发送/接收函数
HAL_UART_Transmit():串口发送数据,使用超时管理机制
HAL_UART_Receive():串口接收数据,使用超时管理机制
HAL_UART_Transmit_IT():串口中断模式发送
HAL_UART_Receive_IT():串口中断模式接收
HAL_UART_Transmit_DMA():串口DMA模式发送
HAL_UART_Transmit_DMA():串口DMA模式接收
串口中断函数
HAL_UART_IRQHandler(UART_HandleTypeDef *huart); //串口中断处理函数
HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //串口发送中断回调函数
HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart); //串口发送一半中断回调函数(用的较少)
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //串口接收中断回调函数
HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//串口接收一半回调函数(用的较少)
HAL_UART_ErrorCallback();串口接收错误函数