返回> 网站首页 

STM32F207串口DMA模式(串口中断bug稳定性)

yoours2015-09-15 14:20:26 阅读 4491

简介一边听听音乐,一边写写文章。

使用DMA操作UART4:

一、DMA映射表
见下表:

STM32F207串口DMA模式(串口中断bug稳定性) - happyboy200032 - happyboy200032的博客

UART4的发送 UART4_TX 在Stream4。
UART4的接收 UART4_RX在Stream2。
他们在Channel_4。

二、程序代码
unsigned char btDMARecbuf[255];// DMA接收数据地址
unsigned char btDMASendbuf[255];//DMA发送数据地址

// 初始化
void UartDMA()
{
    //定义中断结构体
    NVIC_InitTypeDef NVIC_InitStructure ;
    //定义IO初始化结构体
    GPIO_InitTypeDef GPIO_InitStructure;
    //定义串口结构体
    USART_InitTypeDef USART_InitStructure;
    //定义DMA结构体
    DMA_InitTypeDef DMA_InitStructure;

    USART_DeInit(UART4); // 串口4
    DMA_DeInit(DMA1_Stream2); // 接收
    DMA_DeInit(DMA1_Stream4); // 发送

    //设置IO口时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_UART4);
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_UART4);

    //管脚模式:输出口
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    //类型:推挽模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    //上拉下拉设置
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    //IO口速度
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    //管脚指定
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    //初始化
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    //管脚模式:输入口
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    //上拉下拉设置
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    //管脚指定
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    //初始化
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    //打开串口对应的外设时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);

    //串口发 - DMA配置
    //启动DMA时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
    //DMA发送中断设置
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    //DMA通道配置
    DMA_InitStructure.DMA_Channel = DMA_Channel_4;
    //外设地址
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&UART4->DR);
    //内存地址
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)btDMASendbuf;
    //dma传输方向
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    //设置DMA在传输时缓冲区的长度
    DMA_InitStructure.DMA_BufferSize = 255;
    //设置DMA的外设递增模式,一个外设
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    //设置DMA的内存递增模式
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    //外设数据字长
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    //内存数据字长
    DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
    //设置DMA的传输模式
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    //设置DMA的优先级别
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;

    //指定如果FIFO模式或直接模式将用于指定的流 : 不使能FIFO模式
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    //指定了FIFO阈值水平
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    //指定的Burst转移配置内存传输
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    //指定的Burst转移配置外围转移 */
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    //配置DMA1的通道
    DMA_Init(DMA1_Stream4, &DMA_InitStructure);
    //使能中断
    DMA_ITConfig(DMA1_Stream4, DMA_IT_TC, ENABLE);

    //串口收 - DMA配置
    DMA_InitStructure.DMA_Channel = DMA_Channel_4;
    //外设地址
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&UART4->DR);
    //内存地址
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)btDMARecbuf;
    //dma传输方向
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    //设置DMA在传输时缓冲区的长度
    DMA_InitStructure.DMA_BufferSize = 255;
    //设置DMA的外设递增模式,一个外设
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    //设置DMA的内存递增模式
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    //外设数据字长
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    //内存数据字长
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    //设置DMA的传输模式
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    //设置DMA的优先级别
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

    //指定如果FIFO模式或直接模式将用于指定的流 : 不使能FIFO模式
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    //指定了FIFO阈值水平
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    //指定的Burst转移配置内存传输
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    //指定的Burst转移配置外围转移 */
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    //配置DMA1的通道
    DMA_Init(DMA1_Stream2, &DMA_InitStructure);
    //使能通道
    DMA_Cmd(DMA1_Stream2, ENABLE);

    //初始化串口参数
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStructure.USART_BaudRate = 115200;
    //初始化串口
    USART_Init(UART4, &USART_InitStructure);

    //配置中断
    NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;               //通道设置为串口中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;       //中断占先等级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;              //中断响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //打开中断
    NVIC_Init(&NVIC_InitStructure);

    //采用DMA方式发送
    USART_DMACmd(UART4, USART_DMAReq_Tx, ENABLE);
    //采用DMA方式接收
    USART_DMACmd(UART4, USART_DMAReq_Rx, ENABLE);

    //中断配置
    USART_ITConfig(UART4, USART_IT_TC, DISABLE);
    USART_ITConfig(UART4, USART_IT_RXNE, DISABLE);
    USART_ITConfig(UART4, USART_IT_TXE, DISABLE);
    USART_ITConfig(UART4, USART_IT_IDLE, ENABLE);

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    USART_ITConfig(UART4, USART_IT_PE, ENABLE);    //开启PE错误接收中断Bit 8PEIE: PE interrupt enable
    USART_ITConfig(UART4, USART_IT_ERR, ENABLE);//CR2 开启ERR中断

    //启动串口
    USART_Cmd(UART4, ENABLE);

    while(!DMA_GetCmdStatus(DMA1_Stream4))
   {
      DMA_Cmd(DMA1_Stream4, ENABLE);
   }

   while(!DMA_GetCmdStatus(DMA1_Stream2))
   {
      DMA_Cmd(DMA1_Stream2, ENABLE);
   }
}

// 发送
void UartSend(uint8_t *data, uint8_t size)
{
    unsigned char i;
    //复制数据
    for (i=0; i<size; i++)
    {
        btDMASendbuf[i] = data[i];
    }
    //设置传输数据长度
    DMA_SetCurrDataCounter(DMA1_Stream4, size);
    //打开DMA, 开始发送
    DMA_Cmd(DMA1_Stream4, ENABLE);
}

// DMA发送中断处理函数
void DMA1_Stream4_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4) != RESET)
    {
        //清除标志位
        DMA_ClearFlag(DMA1_Stream4, DMA_FLAG_TCIF4);
        //关闭DMA
        DMA_Cmd(DMA1_Stream4, DISABLE);
        //打开发送完成中断, 发送最后两个字节
        USART_ITConfig(UART4, USART_IT_TC, ENABLE);
    }
}

// 串口中断处理函数
void UART4_IRQHandler(void)
{
    unsigned char i;
    unsigned char len = 0;
    //发送完成中断处理
    if(USART_GetITStatus(UART4, USART_IT_TC) != RESET)
    {
        //关闭发送完成中断
        USART_ITConfig(UART4, USART_IT_TC, DISABLE);
    }

    //接收完成中断
    if(USART_GetITStatus(UART4, USART_IT_IDLE) != RESET)
    {
// 非常重要!!! 用于串口中断接收稳定性
        UART4->SR;
        UART4->DR; //清USART_IT_IDLE标志

        //关闭DMA
        DMA_Cmd(DMA1_Stream2, DISABLE);
        //清除标志位
        DMA_ClearFlag(DMA1_Stream2, DMA_FLAG_TCIF2);

        //获得接收帧帧长
        len = 255 - DMA_GetCurrDataCounter(DMA1_Stream2);
        for (i=0;i<len;i++)
        {
                DPbuf[DPbufEnd++] = btDMARecbuf[i];
        }

        //设置传输数据长度
        DMA_SetCurrDataCounter(DMA1_Stream2, 255);
        //打开DMA
        DMA_Cmd(DMA1_Stream2, ENABLE);
    }

    // 非常重要!!! 用于串口中断接收稳定性
    if(USART_GetFlagStatus(UART4, USART_FLAG_ORE) == SET)
    {
        USART_ReceiveData(UART4); //必须取出来扔掉
        USART_ClearFlag(UART4, USART_FLAG_ORE);
    }

    if(USART_GetFlagStatus(UART4, USART_FLAG_NE) != RESET)
    {
        USART_ClearFlag(UART4, USART_FLAG_NE);
    }

    if(USART_GetFlagStatus(UART4, USART_FLAG_FE) != RESET)
    {
        USART_ClearFlag(UART4, USART_FLAG_FE);
    }

    if(USART_GetFlagStatus(UART4, USART_FLAG_PE) != RESET)
    {
        USART_ClearFlag(UART4, USART_FLAG_PE);
    }

    if(USART_GetITStatus(UART4, USART_IT_ERR) != RESET)
    {
        USART_ClearITPendingBit(UART4, USART_IT_ERR);
    }

    if(USART_GetITStatus(UART4, USART_IT_ORE) != RESET)
    {
        USART_ClearITPendingBit(USART1, USART_IT_ORE);
    }
}

微信小程序扫码登陆

文章评论

4491人参与,0条评论