STM32 USART1 DMA打印和接收

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+字节数据不丢失。

全篇完。

本人博客仅仅代表我个人见解方便记录成长笔记。

若有与 看官老爷见解有冲突,我坚信看官老爷见解是对的,我的是错的。

感谢~!

猜你喜欢

转载自blog.csdn.net/sudaroot/article/details/84955751