1.串口空闲中断的理解

 

其实发送的两个字符之间间隔非常短,所以在两个字符之间不叫空闲。空闲的定义是总线上在一个字节的时间内没有再接收到数据,空闲中断是检测到有数据被接收后,总线上在一个字节的时间内没有再接收到数据的时候发生的。

而总线在什么情况时,会有一个字节时间内没有接收到数据呢?一般就只有一个数据帧发送完成的情况,所以串口的空闲中断也叫帧中断。

2. 代码实现

相关变量声明

#define USART1_EN 1//串口使能标志
#if USART1_EN == 1
uint8_t RxBuffer1[24];//串口数据接收缓冲区
__IO uint8_t RxCounter1; //串口接收数据长度记录
bool RX1_flag = false;//串口接收完成标志
#endif

 

串口IO口初始化

static void InitHardUart()//串口IO口初始化
{
    GPIO_InitType GPIO_InitStructure;
#if USART1_EN == 1
    
    /* Connect PXx to USART1_Tx
  GPIO_PinAFConfig(GPIOB, GPIO_PinsSource6, GPIO_AF_0); */
  /* Connect PXx to USART1_Rx 
  GPIO_PinAFConfig(GPIOB, GPIO_PinsSource7, GPIO_AF_0);*/

    
  /* Configure USART1 Tx/Rx amd USART2 Tx/Rx */
   /*GPIO_InitStructure.GPIO_Pins = GPIO_Pins_6 | GPIO_Pins_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
  GPIO_InitStructure.GPIO_OutType = GPIO_OutType_PP;
  GPIO_InitStructure.GPIO_Pull = GPIO_Pull_NOPULL;
  GPIO_Init(GPIOB, &GPIO_InitStructure); */
    //=====================寄存器代码===start========
    //设置复用输出类型
    GPIOB->AFR[0] &= ~(0xff000000);
    GPIOB->AFR[0] |= (0x00000000);
    GPIOB->MODER &= ~(0XF000);
    GPIOB->MODER |= (0XA000);//设置复用输出
    GPIOB->OTYPER &= ~(0xC0);
    GPIOB->OTYPER |= (0x00);//设置推挽输出
    //设置输出速度
    GPIOB->HDRV &= ~(0x00C0);
    GPIOB->HDRV |= (0x00C0);//设置速度为高
    GPIOB->ODRVR &= ~(0XF000);
    GPIOB->PUPDR &= ~(0XF000);//设置上拉/下拉
    GPIOB->PUPDR |= (0X0000);
    //=====GPIOB->ot================寄存器代码===end========
#endif
#if USART2_EN == 1
    
#endif
}

 

 串口时钟初始化

//时钟初始化
static void UART_RCC_Config(void)
{ 

  /* Enable GPIO clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_GPIOB, ENABLE);//串口IO口时钟使能
#if USART1_EN == 1  
  /* Enable USART1 Clock 
  RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_USART1, ENABLE); */
    RCC->APB2EN &= ~(0X4000);
    RCC->APB2EN |= (0X4000);//串口时钟使能
#endif
}

 

串口中断优先级设置

//串口中断优先级初始化
static void UART_NVIC_Config(void)
{ 
#if USART1_EN == 1
    NVIC_InitType NVIC_InitStructure;

  /* Configure the NVIC Preemption Priority Bits */  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
  
  /* Enable the USART2 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
#endif
}

串口参数设置

cubemx 串口空闲中断 加dma接受例程 串口空闲状态_#if

cubemx 串口空闲中断 加dma接受例程 串口空闲状态_初始化_02

//串口参数初始化
/*    函 数 名: SetBaudrate
*    功能说明: 配置串口波特率
*    形    参: USARTx.串口 Value.波特率*/
static void SetBaudrate(USART_Type *USARTx, uint32_t Value)
{
/*    USART_InitType USART_InitStructure;        
     USART_InitStructure.USART_BaudRate = UART1_BAUD;                //设置波特率
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;//设置数据位为8位
  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;//工作模式:发送和接收
  Configure USART1 
  USART_Init(USARTx, &USART_InitStructure);*/
    //=====================寄存器代码===start========
    //设置波特率 USART_BaudRate
    float temp;
    float fraction;     //小数部分
    u16 mantissa;//整数部分
    //计算出USARTDIV 
    temp = UART1_BAUD;//不能直接将UART1_BAUD代入计算 USARTDIV 的公式
    temp = (120*1000*1000)/(temp*16);//at32的时钟频率为120M 
    //取波特率整数部分
    mantissa = temp;
    //计算波特率小数部分
    fraction = (temp - mantissa)*16+1;
    //计算波特率的值
    mantissa=(mantissa<<4)+fraction;
    USARTx->BAUDR = mantissa;//波特率赋值
    //设置数据形式 USART_WordLength
    USARTx->CTRL1 &= ~(0x1000);
    USARTx->CTRL1 |= (0x0000);//一个起始位,8 个数据位,n 个停止位
    //设置停止位 USART_StopBits
    USARTx->CTRL2 &= ~(0x3000);
    USARTx->CTRL2 |= (0x0000);//1 个停止位
    //设置校验位 USART_Parity
    USARTx->CTRL1 &= ~(0x0400);
    USARTx->CTRL1 |= (0x0000);//禁止校验控制;
    //设置硬件流控制 USART_HardwareFlowControl
    USARTx->CTRL3 &= ~(0x0030);
    USARTx->CTRL3 |= (0x0000);//禁止 RTS 硬件流控制,0:禁止 CTS 硬件流控制;
    //设置传输模式 USART_Mode
    USARTx->CTRL1 &= ~(0x000C);
    USARTx->CTRL1 |= (0x000C);//使能接收,并开始搜寻 RX 引脚上的起始位。使能发送。
    //=====================寄存器代码===end========
    
    /* Clear USART1 Interrupt Flag 
    USART_ClearFlag(USART1, USART_FLAG_RDNE);*/
    //清除接收标志
    USARTx->STS = ~(USART_FLAG_RDNE);
  /* 串口接收中断和串口空闲中断使能 */
  USART_INTConfig(USARTx, USART_INT_RDNE, ENABLE);//接收中断
  USART_INTConfig(USARTx, USART_INT_IDLEF, ENABLE);//空闲中断
    //接收中断使能
//    USARTx->CTRL1 |= (1<<5);
    //空闲中断使能
//    USARTx->CTRL1 |= (1<<4);
    
  /* Enable the USART1
  USART_Cmd(USART1, ENABLE); */
    //串口使能
    USARTx->CTRL1 |= 0x2000;
}

View Code

 

串口初始化

//功能说明: 串口初始化
void bsp_InitUsart(void)
{
    UART_RCC_Config();//串口时钟使能
    UART_NVIC_Config();//中断优先级初始化
    InitHardUart();//IO口初始化
#if USART1_EN == 1
    SetBaudrate(USART1, UART1_BAUD);
#endif
}

 

串口中断函数编写

/**
  * @brief  This function handles USART1 global interrupt request.
  * @param  None
  * @retval None
  */
void USART1_IRQHandler(void)
{   
  if(USART_GetITStatus(USART1, USART_INT_RDNE) != RESET)//触发串口接收中断
  {
    /* Read one byte from the receive data register */
//        if(RxCounter1 < DATA_SIZE)
            RxBuffer1[RxCounter1++] = USART_ReceiveData(USART1);//串口数据存储
    }
    else if(USART_GetITStatus(USART1, USART_INT_IDLEF) != RESET)//触发串口空闲中断
    {
        uint8_t DR_text = USART1->DT;//读取串口数据寄存器(只有读取了串口数据寄存器,串口空闲中断才会清除)
        RxCounter1 = 0;//串口接收数据字节数清零
        RX1_flag = true;//串口接收完成标志置位
    }
}

所有代码

cubemx 串口空闲中断 加dma接受例程 串口空闲状态_#if

cubemx 串口空闲中断 加dma接受例程 串口空闲状态_初始化_02

#define USART1_EN 1
#if USART1_EN == 1
uint8_t RxBuffer1test[12];
uint8_t RxBuffer1[24];
__IO uint8_t RxCounter1; 
bool RX1_flag = false;//串口接收完成标志
#endif

#if USART2_EN == 1

#endif
static void InitHardUart()//串口IO口初始化
{
    GPIO_InitType GPIO_InitStructure;
#if USART1_EN == 1
    
    /* Connect PXx to USART1_Tx
  GPIO_PinAFConfig(GPIOB, GPIO_PinsSource6, GPIO_AF_0); */
  /* Connect PXx to USART1_Rx 
  GPIO_PinAFConfig(GPIOB, GPIO_PinsSource7, GPIO_AF_0);*/

    
  /* Configure USART1 Tx/Rx amd USART2 Tx/Rx */
   /*GPIO_InitStructure.GPIO_Pins = GPIO_Pins_6 | GPIO_Pins_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
  GPIO_InitStructure.GPIO_OutType = GPIO_OutType_PP;
  GPIO_InitStructure.GPIO_Pull = GPIO_Pull_NOPULL;
  GPIO_Init(GPIOB, &GPIO_InitStructure); */
    //=====================寄存器代码===start========
    //设置复用输出类型
    GPIOB->AFR[0] &= ~(0xff000000);
    GPIOB->AFR[0] |= (0x00000000);
    GPIOB->MODER &= ~(0XF000);
    GPIOB->MODER |= (0XA000);//设置复用输出
    GPIOB->OTYPER &= ~(0xC0);
    GPIOB->OTYPER |= (0x00);//设置推挽输出
    //设置输出速度
    GPIOB->HDRV &= ~(0x00C0);
    GPIOB->HDRV |= (0x00C0);//设置速度为高
    GPIOB->ODRVR &= ~(0XF000);
    GPIOB->PUPDR &= ~(0XF000);//设置上拉/下拉
    GPIOB->PUPDR |= (0X0000);
    //=====GPIOB->ot================寄存器代码===end========
#endif
#if USART2_EN == 1
    
#endif
}
//时钟初始化
static void UART_RCC_Config(void)
{ 

  /* Enable GPIO clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_GPIOB, ENABLE);//串口IO口时钟使能
#if USART1_EN == 1  
  /* Enable USART1 Clock 
  RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_USART1, ENABLE); */
    RCC->APB2EN &= ~(0X4000);
    RCC->APB2EN |= (0X4000);//串口时钟使能
#endif
}

//串口中断优先级初始化
static void UART_NVIC_Config(void)
{ 
#if USART1_EN == 1
    NVIC_InitType NVIC_InitStructure;

  /* Configure the NVIC Preemption Priority Bits */  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
  
  /* Enable the USART2 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
#endif
}

//串口参数初始化
/*    函 数 名: SetBaudrate
*    功能说明: 配置串口波特率
*    形    参: USARTx.串口 Value.波特率*/
static void SetBaudrate(USART_Type *USARTx, uint32_t Value)
{
/*    USART_InitType USART_InitStructure;        
     USART_InitStructure.USART_BaudRate = UART1_BAUD;                //设置波特率
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;//设置数据位为8位
  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;//工作模式:发送和接收
  Configure USART1 
  USART_Init(USARTx, &USART_InitStructure);*/
    //=====================寄存器代码===start========
    //设置波特率 USART_BaudRate
    float temp;
    float fraction;     //小数部分
    u16 mantissa;//整数部分
    //计算出USARTDIV 
    temp = UART1_BAUD;//不能直接将UART1_BAUD代入计算 USARTDIV 的公式
    temp = (120*1000*1000)/(temp*16);//at32的时钟频率为120M 
    //取波特率整数部分
    mantissa = temp;
    //计算波特率小数部分
    fraction = (temp - mantissa)*16+1;
    //计算波特率的值
    mantissa=(mantissa<<4)+fraction;
    USARTx->BAUDR = mantissa;//波特率赋值
    //设置数据形式 USART_WordLength
    USARTx->CTRL1 &= ~(0x1000);
    USARTx->CTRL1 |= (0x0000);//一个起始位,8 个数据位,n 个停止位
    //设置停止位 USART_StopBits
    USARTx->CTRL2 &= ~(0x3000);
    USARTx->CTRL2 |= (0x0000);//1 个停止位
    //设置校验位 USART_Parity
    USARTx->CTRL1 &= ~(0x0400);
    USARTx->CTRL1 |= (0x0000);//禁止校验控制;
    //设置硬件流控制 USART_HardwareFlowControl
    USARTx->CTRL3 &= ~(0x0030);
    USARTx->CTRL3 |= (0x0000);//禁止 RTS 硬件流控制,0:禁止 CTS 硬件流控制;
    //设置传输模式 USART_Mode
    USARTx->CTRL1 &= ~(0x000C);
    USARTx->CTRL1 |= (0x000C);//使能接收,并开始搜寻 RX 引脚上的起始位。使能发送。
    //=====================寄存器代码===end========
    
    /* Clear USART1 Interrupt Flag 
    USART_ClearFlag(USART1, USART_FLAG_RDNE);*/
    //清除接收标志
    USARTx->STS = ~(USART_FLAG_RDNE);
  /* 串口接收中断和串口空闲中断使能 */
  USART_INTConfig(USARTx, USART_INT_RDNE, ENABLE);//接收中断
  USART_INTConfig(USARTx, USART_INT_IDLEF, ENABLE);//空闲中断
    //接收中断使能
//    USARTx->CTRL1 |= (1<<5);
    //空闲中断使能
//    USARTx->CTRL1 |= (1<<4);
    
  /* Enable the USART1
  USART_Cmd(USART1, ENABLE); */
    //串口使能
    USARTx->CTRL1 |= 0x2000;
}
//功能说明: 串口初始化
void bsp_InitUsart(void)
{
    UART_RCC_Config();//串口时钟使能
    UART_NVIC_Config();//中断优先级初始化
    InitHardUart();//IO口初始化
#if USART1_EN == 1
    SetBaudrate(USART1, UART1_BAUD);
#endif
}
/**
  * @brief  This function handles USART1 global interrupt request.
  * @param  None
  * @retval None
  */
void USART1_IRQHandler(void)
{   
  if(USART_GetITStatus(USART1, USART_INT_RDNE) != RESET)//触发串口接收中断
  {
    /* Read one byte from the receive data register */
//        if(RxCounter1 < DATA_SIZE)
            RxBuffer1[RxCounter1++] = USART_ReceiveData(USART1);
    }
    else if(USART_GetITStatus(USART1, USART_INT_IDLEF) != RESET)//触发串口空闲中断
    {
        uint8_t DR_text = USART1->DT;//读取串口数据寄存器(只有读取了串口数据寄存器,串口空闲中断才会清除)
        RxCounter1 = 0;
        RX1_flag = true;
    }
}

View Code

 

3.程序运行效果

每次接收完成一帧数据(不定长度)之后,就会触发串口空闲中断;串口接收完成标志置位;

 4.串口空闲中断DMA接收不定长度

参考:

串口参数配置修改

修改函数:SetBaudrate();

修改内容:取消串口接收中断

cubemx 串口空闲中断 加dma接受例程 串口空闲状态_#if

cubemx 串口空闲中断 加dma接受例程 串口空闲状态_初始化_02

//串口参数初始化
/*    函 数 名: SetBaudrate
*    功能说明: 配置串口波特率
*    形    参: USARTx.串口 Value.波特率*/
static void SetBaudrate(USART_Type *USARTx, uint32_t Value)
{
/*    USART_InitType USART_InitStructure;        
     USART_InitStructure.USART_BaudRate = UART1_BAUD;                //设置波特率
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;//设置数据位为8位
  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;//工作模式:发送和接收
  Configure USART1 
  USART_Init(USARTx, &USART_InitStructure);*/
    //=====================寄存器代码===start========
    //设置波特率 USART_BaudRate
    float temp;
    float fraction;     //小数部分
    u16 mantissa;//整数部分
    //计算出USARTDIV 
    temp = UART1_BAUD;//不能直接将UART1_BAUD代入计算 USARTDIV 的公式
    temp = (120*1000*1000)/(temp*16);//at32的时钟频率为120M 
    //取波特率整数部分
    mantissa = temp;
    //计算波特率小数部分
    fraction = (temp - mantissa)*16+1;
    //计算波特率的值
    mantissa=(mantissa<<4)+fraction;
    USARTx->BAUDR = mantissa;//波特率赋值
    //设置数据形式 USART_WordLength
    USARTx->CTRL1 &= ~(0x1000);
    USARTx->CTRL1 |= (0x0000);//一个起始位,8 个数据位,n 个停止位
    //设置停止位 USART_StopBits
    USARTx->CTRL2 &= ~(0x3000);
    USARTx->CTRL2 |= (0x0000);//1 个停止位
    //设置校验位 USART_Parity
    USARTx->CTRL1 &= ~(0x0400);
    USARTx->CTRL1 |= (0x0000);//禁止校验控制;
    //设置硬件流控制 USART_HardwareFlowControl
    USARTx->CTRL3 &= ~(0x0030);
    USARTx->CTRL3 |= (0x0000);//禁止 RTS 硬件流控制,0:禁止 CTS 硬件流控制;
    //设置传输模式 USART_Mode
    USARTx->CTRL1 &= ~(0x000C);
    USARTx->CTRL1 |= (0x000C);//使能接收,并开始搜寻 RX 引脚上的起始位。使能发送。
    //=====================寄存器代码===end========
    
    /* Clear USART1 Interrupt Flag 
    USART_ClearFlag(USART1, USART_FLAG_RDNE);*/
    //清除接收标志
    USARTx->STS = ~(USART_FLAG_RDNE);
  /* 串口接收中断和串口空闲中断使能 */
  //USART_INTConfig(USARTx, USART_INT_RDNE, ENABLE);//接收中断  DMA模式下不使用
  USART_INTConfig(USARTx, USART_INT_IDLEF, ENABLE);//空闲中断
    //接收中断使能
//    USARTx->CTRL1 |= (1<<5);
    //空闲中断使能
//    USARTx->CTRL1 |= (1<<4);
    
  /* Enable the USART1
  USART_Cmd(USART1, ENABLE); */
    //串口使能
    USARTx->CTRL1 |= 0x2000;
}

View Code

 

DMA配置添加

添加函数:UsartRX_DmaConfigure();DMA_Channel_ON_OFF();

添加内容:串口接收DMA配置,串口接收DMA配置使能/关闭

DMA通道设置说明:

cubemx 串口空闲中断 加dma接受例程 串口空闲状态_串口_07

 

 由图可知,我们需要配置的外设串口1RX的DMA通道为通道3;

DMA设置代码:

//功能说明: 配置串口DMA
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量  
//On_Off:0x01:开启DMA,0x02:关闭DMA
static void UsartRX_DmaConfigure(DMA_Channel_Type* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr, u8 On_Off)
{
    DMA_InitType DMA_InitStructure;
    NVIC_InitType NVIC_InitStructure;
    /* DMA clock enable */
    RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_DMA1, ENABLE);

#if USART1_EN == 1
    /* USART1_Tx_DMA_Channel (triggered by USART1 Tx event) Config */
    DMA_Reset(DMA_CHx);
    DMA_DefaultInitParaConfig(&DMA_InitStructure);
    DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;         /* DMA外设基地址 */
    DMA_InitStructure.DMA_MemoryBaseAddr = cmar;                           /* DMA内存基地址 */
    DMA_InitStructure.DMA_Direction = DMA_DIR_PERIPHERALSRC;                  /* 传输方向,外设->内存*/
    DMA_InitStructure.DMA_BufferSize = cndtr;                             /* 数据大小 */
    DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE;          /* 外设地址寄存器不变 */
    DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE;                   /* 内存地址寄存器递增 */
    DMA_InitStructure.DMA_PeripheralDataWidth = DMA_PERIPHERALDATAWIDTH_BYTE; /* 外设数据宽度为8位 */
    DMA_InitStructure.DMA_MemoryDataWidth = DMA_MEMORYDATAWIDTH_BYTE;         /* 存储器数据宽度为8位 */
    DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL;                             /* 非循环模式 */
    DMA_InitStructure.DMA_Priority = DMA_PRIORITY_VERYHIGH;                   /* 非常高优先级 */
    DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE;                        /* 非内存到内存 */
    DMA_Init(DMA_CHx, &DMA_InitStructure);

    /* Enable USART1 DMA TX Channel */
    DMA_ChannelEnable(DMA_CHx, ENABLE);
    /* Enable USART1 DMA RX request */
    USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
#endif

}

 

//功能说明: DMA通道开关
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量  
//On_Off:0x01:开启DMA,0x02:关闭DMA
void DMA_Channel_ON_OFF(DMA_Channel_Type* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr, u8 On_Off)
{
    if(On_Off == 0X01)//开启DMA
    {
        DMA_CHx->TCNT = 24;//设置数据长度
        DMA_ChannelEnable(DMA_CHx, ENABLE);//开启DMA通道
    }
    else if(On_Off == 0x02)
    {
        DMA_ChannelEnable(DMA_CHx, DISABLE);//关闭DMA通道
    }
}

 

串口初始化函数修改

修改函数:bsp_InitUsart();

修改内容:添加DMA配置;

//功能说明: 串口初始化
void bsp_InitUsart(void)
{
    UART_RCC_Config();//串口时钟使能
    UART_NVIC_Config();//中断优先级初始化
    InitHardUart();//IO口初始化
#if USART1_EN == 1
    SetBaudrate(USART1, UART1_BAUD);
#endif
    UsartRX_DmaConfigure(DMA1_Channel3, (uint32_t)&USART1->DT, (uint32_t)RxBuffer1, DATA_SIZE, 0X01);//配置串口DMA
}

 外设配置所有代码:

cubemx 串口空闲中断 加dma接受例程 串口空闲状态_#if

cubemx 串口空闲中断 加dma接受例程 串口空闲状态_初始化_02

#if USART1_EN == 1
uint8_t RxBuffer1test[12];
uint8_t RxBuffer1[24];
__IO uint8_t RxCounter1; 
bool RX1_flag = false;//串口接收完成标志
#endif

#if USART2_EN == 1

#endif
static void InitHardUart()//串口IO口初始化
{
    GPIO_InitType GPIO_InitStructure;
#if USART1_EN == 1
    
    /* Connect PXx to USART1_Tx
  GPIO_PinAFConfig(GPIOB, GPIO_PinsSource6, GPIO_AF_0); */
  /* Connect PXx to USART1_Rx 
  GPIO_PinAFConfig(GPIOB, GPIO_PinsSource7, GPIO_AF_0);*/

    
  /* Configure USART1 Tx/Rx amd USART2 Tx/Rx */
   /*GPIO_InitStructure.GPIO_Pins = GPIO_Pins_6 | GPIO_Pins_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
  GPIO_InitStructure.GPIO_OutType = GPIO_OutType_PP;
  GPIO_InitStructure.GPIO_Pull = GPIO_Pull_NOPULL;
  GPIO_Init(GPIOB, &GPIO_InitStructure); */
    //=====================寄存器代码===start========
    //设置复用输出类型
    GPIOB->AFR[0] &= ~(0xff000000);
    GPIOB->AFR[0] |= (0x00000000);
    GPIOB->MODER &= ~(0XF000);
    GPIOB->MODER |= (0XA000);//设置复用输出
    GPIOB->OTYPER &= ~(0xC0);
    GPIOB->OTYPER |= (0x00);//设置推挽输出
    //设置输出速度
    GPIOB->HDRV &= ~(0x00C0);
    GPIOB->HDRV |= (0x00C0);//设置速度为高
    GPIOB->ODRVR &= ~(0XF000);
    GPIOB->PUPDR &= ~(0XF000);//设置上拉/下拉
    GPIOB->PUPDR |= (0X0000);
    //=====GPIOB->ot================寄存器代码===end========
#endif
#if USART2_EN == 1
    
#endif
}
//时钟初始化
static void UART_RCC_Config(void)
{ 

  /* Enable GPIO clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_GPIOB, ENABLE);//串口IO口时钟使能
#if USART1_EN == 1  
  /* Enable USART1 Clock 
  RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_USART1, ENABLE); */
    RCC->APB2EN &= ~(0X4000);
    RCC->APB2EN |= (0X4000);//串口时钟使能
#endif
}

//串口中断优先级初始化
static void UART_NVIC_Config(void)
{ 
#if USART1_EN == 1
    NVIC_InitType NVIC_InitStructure;

  /* Configure the NVIC Preemption Priority Bits */  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
  
  /* Enable the USART2 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
#endif
}

//串口参数初始化
/*    函 数 名: SetBaudrate
*    功能说明: 配置串口波特率
*    形    参: USARTx.串口 Value.波特率*/
static void SetBaudrate(USART_Type *USARTx, uint32_t Value)
{
/*    USART_InitType USART_InitStructure;        
     USART_InitStructure.USART_BaudRate = UART1_BAUD;                //设置波特率
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;//设置数据位为8位
  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;//工作模式:发送和接收
  Configure USART1 
  USART_Init(USARTx, &USART_InitStructure);*/
    //=====================寄存器代码===start========
    //设置波特率 USART_BaudRate
    float temp;
    float fraction;     //小数部分
    u16 mantissa;//整数部分
    //计算出USARTDIV 
    temp = UART1_BAUD;//不能直接将UART1_BAUD代入计算 USARTDIV 的公式
    temp = (120*1000*1000)/(temp*16);//at32的时钟频率为120M 
    //取波特率整数部分
    mantissa = temp;
    //计算波特率小数部分
    fraction = (temp - mantissa)*16+1;
    //计算波特率的值
    mantissa=(mantissa<<4)+fraction;
    USARTx->BAUDR = mantissa;//波特率赋值
    //设置数据形式 USART_WordLength
    USARTx->CTRL1 &= ~(0x1000);
    USARTx->CTRL1 |= (0x0000);//一个起始位,8 个数据位,n 个停止位
    //设置停止位 USART_StopBits
    USARTx->CTRL2 &= ~(0x3000);
    USARTx->CTRL2 |= (0x0000);//1 个停止位
    //设置校验位 USART_Parity
    USARTx->CTRL1 &= ~(0x0400);
    USARTx->CTRL1 |= (0x0000);//禁止校验控制;
    //设置硬件流控制 USART_HardwareFlowControl
    USARTx->CTRL3 &= ~(0x0030);
    USARTx->CTRL3 |= (0x0000);//禁止 RTS 硬件流控制,0:禁止 CTS 硬件流控制;
    //设置传输模式 USART_Mode
    USARTx->CTRL1 &= ~(0x000C);
    USARTx->CTRL1 |= (0x000C);//使能接收,并开始搜寻 RX 引脚上的起始位。使能发送。
    //=====================寄存器代码===end========
    
    /* Clear USART1 Interrupt Flag 
    USART_ClearFlag(USART1, USART_FLAG_RDNE);*/
    //清除接收标志
    USARTx->STS = ~(USART_FLAG_RDNE);
  /* 串口接收中断和串口空闲中断使能 */
  //USART_INTConfig(USARTx, USART_INT_RDNE, ENABLE);//接收中断  DMA模式下不使用
  USART_INTConfig(USARTx, USART_INT_IDLEF, ENABLE);//空闲中断
    //接收中断使能
//    USARTx->CTRL1 |= (1<<5);
    //空闲中断使能
//    USARTx->CTRL1 |= (1<<4);
    
  /* Enable the USART1
  USART_Cmd(USART1, ENABLE); */
    //串口使能
    USARTx->CTRL1 |= 0x2000;
}
//功能说明: 配置串口DMA
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量  
//On_Off:0x01:开启DMA,0x02:关闭DMA
static void UsartRX_DmaConfigure(DMA_Channel_Type* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr, u8 On_Off)
{
    DMA_InitType DMA_InitStructure;
    NVIC_InitType NVIC_InitStructure;
    /* DMA clock enable */
    RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_DMA1, ENABLE);

#if USART1_EN == 1
    /* USART1_Tx_DMA_Channel (triggered by USART1 Tx event) Config */
    DMA_Reset(DMA_CHx);
    DMA_DefaultInitParaConfig(&DMA_InitStructure);
    DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;         /* DMA外设基地址 */
    DMA_InitStructure.DMA_MemoryBaseAddr = cmar;                           /* DMA内存基地址 */
    DMA_InitStructure.DMA_Direction = DMA_DIR_PERIPHERALSRC;                  /* 传输方向,外设->内存*/
    DMA_InitStructure.DMA_BufferSize = cndtr;                             /* 数据大小 */
    DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE;          /* 外设地址寄存器不变 */
    DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE;                   /* 内存地址寄存器递增 */
    DMA_InitStructure.DMA_PeripheralDataWidth = DMA_PERIPHERALDATAWIDTH_BYTE; /* 外设数据宽度为8位 */
    DMA_InitStructure.DMA_MemoryDataWidth = DMA_MEMORYDATAWIDTH_BYTE;         /* 存储器数据宽度为8位 */
    DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL;                             /* 非循环模式 */
    DMA_InitStructure.DMA_Priority = DMA_PRIORITY_VERYHIGH;                   /* 非常高优先级 */
    DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE;                        /* 非内存到内存 */
    DMA_Init(DMA_CHx, &DMA_InitStructure);

    /* Enable USART1 DMA TX Channel */
    DMA_ChannelEnable(DMA_CHx, ENABLE);
    /* Enable USART1 DMA RX request */
    USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
#endif

}
//功能说明: DMA通道开关
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量  
//On_Off:0x01:开启DMA,0x02:关闭DMA
void DMA_Channel_ON_OFF(DMA_Channel_Type* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr, u8 On_Off)
{
    if(On_Off == 0X01)//开启DMA
    {
        DMA_CHx->TCNT = 24;//设置数据长度
        DMA_ChannelEnable(DMA_CHx, ENABLE);//开启DMA通道
    }
    else if(On_Off == 0x02)
    {
        DMA_ChannelEnable(DMA_CHx, DISABLE);//关闭DMA通道
    }
}
//功能说明: 串口初始化
void bsp_InitUsart(void)
{
    UART_RCC_Config();//串口时钟使能
    UART_NVIC_Config();//中断优先级初始化
    InitHardUart();//IO口初始化
#if USART1_EN == 1
    SetBaudrate(USART1, UART1_BAUD);
#endif
    UsartRX_DmaConfigure(DMA1_Channel3, (uint32_t)&USART1->DT, (uint32_t)RxBuffer1, DATA_SIZE, 0X01);//配置串口DMA
}

View Code

 

串口中断函数修改

/**
  * @brief  This function handles USART1 global interrupt request.
  * @param  None
  * @retval None
  */
void USART1_IRQHandler(void)
{  
    if(USART_GetITStatus(USART1, USART_INT_IDLEF) != RESET)//触发串口空闲中断
    {
        uint8_t DR_text = USART1->DT;//读取串口数据寄存器(只有读取了串口数据寄存器,串口空闲中断才会清除)
        DR_text = USART1->STS;//清除IDLE标记位
        DMA_ChannelEnable(DMA1_Channel3, DISABLE);//关闭DMA通道
        RxCounter1 = 0;//串口接收数据字节数清零
        RX1_flag = true;//串口接收完成标志置位
    }
}

 

注意:在每次接收完成之后都需要经过关闭DMA通道->处理串口数据->再次开启DMA通道的过程,如下图:

cubemx 串口空闲中断 加dma接受例程 串口空闲状态_#if_10

cubemx 串口空闲中断 加dma接受例程 串口空闲状态_初始化_11

在接收完成之后的代码:

if(BLE_Massage_Buffer_Refresh == true&&Con_State_get() == true)//一帧数据接收完成
        {
            BLE_Massage_Buffer_Refresh = false;
            BLE_Command_Handler(BLE_Massage_Buffer);        //串口命令处理
            DMA_Channel_ON_OFF(DMA1_Channel3, (uint32_t)&USART1->DT, (uint32_t)BLE_Massage_Buffer, 12, 0x01);//开启DMA通道
        }

 

 

运行效果和串口空闲中断一样,只是串口空闲中断需要我们自己手动将串口数据存储到数组。