DMA,全称为: Direct Memory Access,即直接存储器访问。 DMA 传输方式无需 CPU 直接
控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备
开辟一条直接传送数据的通路, 能使 CPU 的效率大为提高。
普通usart中断接收数据利用的是频繁的发生中断,影响CPU效率。
DMA接收 + 串口空闲中断 可以高效解决这个问题
下载https://download.youkuaiyun.com/download/sudaroot/12100167
下面是STM32CbueMX USART1 DMA 配置设置
下面是2020-01-13文章更新
变量定义,用法含义如其名:
#define UART_BUFFER_SIZE 1024
uint32_t ReceiveError = 0;
uint32_t ReceiveLength = 0;
uint32_t TransmitLength = 0;
uint32_t ReceiveComplete = 0;
uint32_t TransmitComplete = 1;
uint8_t aRxBuffer[UART_BUFFER_SIZE] = {0};
uint8_t aTxBuffer[UART_BUFFER_SIZE] = {0};
通过DMA打印,使用方法和printf一样。
void UART_Printf_DMA(char *format, ...)
{
va_list args;
uint32_t length;
//---等待上一帧数据发送完成------------------------
while(TransmitComplete != 1);
TransmitComplete = 0;
va_start(args, format);
length = vsnprintf((char *)aTxBuffer, UART_BUFFER_SIZE, format, args);
va_end(args);
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)aTxBuffer, length);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
memset(aTxBuffer, 0, TransmitLength);
__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TC);
TransmitComplete = 1; // UART_DMA 发送完成标志
}
}
UART_DMA接收数据,高效原理是利用了串口空闲中断(UART_IT_IDLE)及空闲标志位(UART_FLAG_IDLE)
void UART1_IT_IDLE_ReceiveDMA(void)
{
if (__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_IDLE) != RESET \
&& __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) == SET)
{
__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
HAL_UART_DMAStop(&huart1);
ReceiveLength = UART_BUFFER_SIZE - (__HAL_DMA_GET_COUNTER(huart1.hdmarx));
if (ReceiveLength < 3 || aRxBuffer[ReceiveLength - 2] != 0x0D \
|| aRxBuffer[ReceiveLength - 1] != 0x0A)
HAL_UART_Receive_DMA(&huart1, aRxBuffer, UART_BUFFER_SIZE);
else ReceiveComplete = 1; //接收完成
}
}
中断函数:
void USART1_IRQHandler(void)
{
UART1_IT_IDLE_ReceiveDMA();
HAL_UART_IRQHandler(&huart1);
}
接收错误,接收的数据长度超过缓存区的最大长度
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
ReceiveError = 1; // 接收超过最大缓存区,ERROR
}
}
主函数:
int main(void)
{
HAL_Init();
SystemClock_Config();
__HAL_RCC_DMA2_CLK_ENABLE();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
__HAL_UART_DISABLE_IT(&huart1, UART_IT_IDLE);
__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TC);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, aRxBuffer, UART_BUFFER_SIZE);
while (1)
{
if(ReceiveComplete == 1)
{
while(TransmitComplete != 1);
TransmitComplete = 0;
ReceiveComplete = 0;
TransmitLength = ReceiveLength;
memcpy(aTxBuffer, aRxBuffer, TransmitLength);
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)aTxBuffer, TransmitLength);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_UART_Receive_DMA(&huart1, aRxBuffer, UART_BUFFER_SIZE);
}
if(ReceiveError == 1) Error_Handler();
}
}
效果图:1ms定时发送回显测试,发送173036字节,回显173036字节。
全篇完。
本人博客仅仅代表我个人见解方便记录成长笔记。
若有与 看官老爷见解有冲突,我坚信看官老爷见解是对的,我的是错的。
感谢~!