DMA,全称为: Direct Memory Access,即直接存储器访问。 DMA 传输方式无需 CPU 直接
控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备
开辟一条直接传送数据的通路, 能使 CPU 的效率大为提高。
普通usart中断接收数据利用的是频繁的发生中断,影响CPU效率。
DMA接收 + 串口空闲中断 可以高效解决这个问题
下面是STM32CbueMX USART1 DMA 配置设置
通过DMA打印,使用方法和printf一样。
#define UART_BUFFER_SIZE 200
static unsigned char txbuf[UART_BUFFER_SIZE] = {0};
//===DMA打印函数=============================
void dma_printf(const char *format, ...)
{
va_list args;
uint32_t length;
//---等待上一帧数据发送完成------------------------
while(__HAL_DMA_GET_FLAG(huart1.hdmatx, DMA_FLAG_TCIF3_7) != RESET);
__HAL_DMA_CLEAR_FLAG(huart1.hdmatx, DMA_FLAG_TCIF3_7);
va_start(args, format);
length = vsnprintf((char *)txbuf, sizeof(txbuf), (char *)format, args);
va_end(args);
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)txbuf, length);
}
//===DMA发送完成,关闭DMA,清除发送缓存区=======
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
__HAL_DMA_DISABLE(&hdma_usart1_tx);
memset(txbuf, 0, 200);
}
DMA接收,高效原理是利用了串口空闲中断
static unsigned int rxlen = 0;
static unsigned char rxbuf[UART_BUFFER_SIZE] = {0};
static unsigned char rxtemp[UART_BUFFER_SIZE] = {0};
//===串口中断==============================
void USART1_IRQHandler(void)
{
static unsigned char mode = 0;
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_IDLE) != RESET)
{
//---清除串口中断标志位-----------------------
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
//===串口空闲中断状态机,确保数据接收完成=============
switch(mode)
{
case 0:
mode ++;
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
break;
case 1:
//---停止DMA----------------------------------
HAL_UART_DMAStop(&huart1);
//---获取接收长度,拷贝-----------------------
rxlen = UART_BUFFER_SIZE - (__HAL_DMA_GET_COUNTER(huart1.hdmarx));
memcpy(rxbuf, rxtemp, rxlen);
//---重新开启串口空闲中断,DMA接收-----------------------
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, rxtemp, UART_BUFFER_SIZE);
mode = 0;
break;
default:
break;
}
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
主函数
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
//---开启串口空闲中断,DMA接收-----------------------
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, rxtemp, UART_BUFFER_SIZE);
//dma_printf("sudaroot\r\n");
while (1)
{
if(rxlen != 0)
{
rxlen = 0;
dma_printf("%s", rxbuf);
memset(rxbuf, 0, UART_BUFFER_SIZE);
}
}
}
附上源码下载:https://download.csdn.net/download/sudaroot/10845922
测试效果:定时1ms循环发送,连续发30W+字节数据不丢失。
全篇完。
本人博客仅仅代表我个人见解方便记录成长笔记。
若有与 看官老爷见解有冲突,我坚信看官老爷见解是对的,我的是错的。
感谢~!