直接存储器访问 (DMA) : 用于在外设与存储器之间以及存储器与存储器之间进行高速数据传输。DMA传输过程的初始化和启动由CPU完成,传输过程由DMA控制器来执行,无需CPU参与,从而节省CPU资源,提高利用率。
DMA数据传输的四个要素:
STM32的DMA控制器特点
DMA数据传输方式
串口DMA方式发送函数:HAL_UART_Transmit_DMA
函数原型 | HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_Handle TypeDef *huart, uint 8_t *pData, uint 16_t Size) |
---|---|
功能描述 | 在DMA方式下发送一定数量的数据 |
入口参数1 | huart:串口句柄的地址 |
入口参数 | pData:待发送数据的首地址 |
入口参数3 | Size:待发送数据的个数 |
返回值 | HAL状态值:HAL_OK表示发送成功;HAL_ERROR表示参数错误;HAL_BUSY表示串口被占用; |
注意事项 | 1. 该函数将启动DMA方式的串口数据发送2. 完成指定数量的数据发送后,可以触发DMA中断,在中断中将调用发送中断回调函数HAL_UART_TxCpltCallback进行后续处理3. 该函数由用户调用户调用 |
串口DMA方式接收函数:HAL_UART_Receive_DMA
函数原型 | HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_Handle TypeDef *huart, uint 8_t *pData, uint 16_t Size) |
---|---|
功能描述 | 在DMA方式下接收一定数量的数据 |
入口参数1 | huart:串口句柄的地址 |
入口参数 | pData:待接收数据的首地址 |
入口参数3 | Size:待接收数据的个数 |
返回值 | HAL状态值:HAL_OK表示发送成功;HAL_ERROR表示参数错误;HAL_BUSY表示串口被占用; |
注意事项 | 1. 该函数将启动DMA方式的串口数据接收2. 完成指定数量的数据接收后,可以触发DMA中断,在中断中将调用接收中断回调函数HAL_UART_ExCpltCallback进行后续处理3. 该函数由用户调用户调用 |
获取未传输数据个数函数:__HAL_DMA_GET_COUNTER
函数原型 | __HAL_DMA_GET_COUNTER |
---|---|
功能描述 | 获取DMA数据流中未传输数据的个数 |
参数 | HANDLE :串口句柄的地址 |
返回值 | NDTR寄存器的内容,即DMA数据流中无传输数据的个数 |
注意事项 | 1. 该函数是宏函数,进行宏替换,不发生函数调用2. 该函数需要由用户调用,用于获取未传输数据的个数 |
关闭DMA数据流:__HAL_DMA_DISABLE
函数原型 | __HAL_DMA_DISABLE(__HANDLE__) |
---|---|
功能描述 | 关闭指定的DMA数据流 |
参数 | HANDLE :串口句柄的地址 |
返回值 | 无 |
注意事项 | 1. 该函数是宏函数,进行宏替换,不发生函数调用2. 该函数需要由用户调用,用于关闭指定的DMA数据流3. 关闭DMA数据流后触发DMA中断,最终调用串口收发的回调函数 |
不定长数据的收发:利用串口调试助手,从PC上发送任意长度的字符到开发板,开发板收到后原样发回到PC。
空闲中断的特点:
设计思路:
使能IDLE中断,在串口2的中断服务程序USART2_IRQHandler中添加对IDLE中断的判断,该函数位于stm32f4xx_it.c文件;
设置传输模式为普通模式,启动DMA传输。串口一旦接收到数据,则触发DMA操作,将数据存放到用户定义的接收缓冲区;
当一帧数据发送完成后,线路处于IDLE状态,将触发IDLE中断,调用IDLE中断回调函数,设置数据接收完成标志;
主程序检测到接收完成标志置位后,将接收的一帧数据原样发回到PC,并禁能DMA,以触发DMA中断。DMA中断将调用接收中断回调函数,在回调函数中重新启动DMA传输。
串口1的DMA配置
DMA数据流的中断使能由CubeMX自动勾选,手动使能串口2中断
编写程序
在stm32f1xx_it.c
中添加空闲中断的处理
/**
* @brief This function handles USART1 global interrupt.
*/
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 */
// Add handling of idle interrupts
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1); // Clear the IDLE interrupt flag
HAL_UART_IdleCpltCallback(&huart1); // User-written IDLE interrupt callback function
}
/* USER CODE END USART1_IRQn 1 */
}
在main.c
中
添加用户宏变量、变量定义
/* USER CODE BEGIN PM */
#define LENGTH 100 // Receive buffer size
/* USER CODE END PM */
/* USER CODE BEGIN PV */
uint8_t RxBuffer[LENGTH];
uint8_t RecCount = 0;
uint8_t RxFlag = 0;
/* USER CODE END PV */
声明和定义空闲中断回调函数,定义DMA接收中断回调函数
/* USER CODE BEGIN PFP */
void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
/* USER CODE END PFP */
/* USER CODE BEGIN 4 */
int fputc (int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart- >Instance == USART1)
{
HAL_UART_Receive_DMA(&huart1, (uint8_t*)RxBuffer, LENGTH);
}
}
void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
{
RxFlag = 1;
}
/* USER CODE END 4 */
编写用户应用代码
/* USER CODE BEGIN 2 */
printf("*** UART coummunication using IDLE IT + DMAn");
pringf("PLease enter arbitrary length characters:n");
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, (uint8_t*)RxBuffer, LENGTH);
/* USER CODE END 2 */
/* USER CODE BEGIN 3 */
if (RxFlag == 1)
{
RxFlag = 0;
RecCount = LENGTH - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
HAL_UART_Transmit_DMA(&huart1, (uint8_t*)RxBuffer, RecCount);
RecCount = 0;
__HAL_DMA_DISABLE(&hdma_uasrt1_rx);
}
}
/* USER CODE END 3 */
全部0条评论
快来发表一下你的评论吧 !