本办法使用定时器定时查询DMA接收到的数据,如果超过设定的周期则认为本次数据包结束,将数据拷贝到缓冲区,交由其他程序处理。可以接收任意大小的数据包,尤其适用于MODBUS等协议,曾经用于GPS、GPRS等接收,很实用。本方法占用CPU时间极少,尤其是波特率很高时,效果更加明显。
当某一个串口的数据接收超时以后,定时器中断中将数据拷贝到缓冲区,在主程序中可以判断数据标志UART1_Flag,大于0的时候即代表有数据接收到,可以处理,处理完后将此变量清零即可。
两个数据包间隔较小时,可以将定时器的周期调短些。

//超时时间定义 

#define        UART1_TimeoutComp 2  //20ms 

#define        UART2_TimeoutComp 10  //100ms 

#define        UART3_TimeoutComp 10  //100ms 


#define SRC_USART1_DR (&(USART1->DR)) //串口接收寄存器作为源头 

#define SRC_USART2_DR (&(USART2->DR)) //串口接收寄存器作为源头 

#define SRC_USART3_DR (&(USART3->DR)) //串口接收寄存器作为源头 



extern u16 UART1_Flag,UART2_Flag,UART3_Flag; 

extern u8 uart1_data[200],uart3_data[500],uart2_data[500]; 


u8 UART1_Timeout,UART2_Timeout,UART3_Timeout; 

u16 UART1_FlagTemp,UART2_FlagTemp,UART3_FlagTemp; 

u8 uart1_data_temp[200],uart2_data_temp[500],uart3_data_temp[500]; 


u16 uart1_Flag_last=0,uart2_Flag_last=0,uart3_Flag_last=0; 


//定时器初始化 

void TimerInit(void) 

{ 

   //定时器初始化数据结构定义 

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 

   //初始化定时器,用于超时接收,20ms 


        //复位计数器 

        TIM_DeInit(TIM2);                                                         


        TIM_TimeBaseStructure.TIM_Period           = 100;                //计数上限,100*100us = 10000us = 10ms 

        TIM_TimeBaseStructure.TIM_Prescaler        = 4799;        //预分频4800,48MHz主频,分频后时钟周期100us 

        TIM_TimeBaseStructure.TIM_ClockDivision    = TIM_CKD_DIV1;  //不分频 

        TIM_TimeBaseStructure.TIM_CounterMode      = TIM_CounterMode_Up;  //向上计数 

        TIM_TimeBaseStructure.TIM_RepetitionCounter=0; 

        //初始化 

        TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); 


        //清中断 

    TIM_ClearFlag(TIM2, TIM_FLAG_Update); 



        //使能定时器中断 

        TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); 

       TIM_UpdateDisableConfig(TIM2,DISABLE);  

        //定时器清零 

        TIM_SetCounter(TIM2,0); 

        //定时器启动         

      TIM_Cmd(TIM2,ENABLE);         

} 



//DMA初始化,只列出一个通道,其他两个通道相同 

void DMA5_Init(void) 

{ 

  DMA_InitTypeDef DMA_InitStructure; 


  DMA_DeInit(DMA1_Channel5); //将DMA的通道1寄存器重设为缺省值 

  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_USART1_DR; //源头BUF既是 (&(USART1->DR)) 

  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)uart1_data_temp; //目标BUF 既是要写在哪个个数组之中  

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外设作源头//外设是作为数据传输的目的地还是来源  

  DMA_InitStructure.DMA_BufferSize = 200; //DMA缓存的大小 单位在下边设定 

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不递增 

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址递增 

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设字节为单位 

  DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //内存字节为单位 

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式 

  DMA_InitStructure.DMA_Priority = DMA_Priority_High; //4优先级之一的(高优先)VeryHigh/High/Medium/Low 

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //非内存到内存  

  DMA_Init(DMA1_Channel5, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道1寄存器  

  DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE); //DMA5传输完成中断  

  USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能USART1的接收DMA请求 


  DMA_Cmd(DMA1_Channel5, ENABLE); //正式允许DMA          

} 


//串口初始化,只列出一个通道,其他两个通道相同         

void USART1_Configuration(void) 

{ 

    //串口初始化数据结构定义 

        USART_InitTypeDef USART_InitStructure;  


        //初始化串口为38400,n,8,1 

        USART_InitStructure.USART_BaudRate            = 38400  ; 

        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_Init(USART1, &USART_InitStructure); 

         

        //启动串口,不需要接收中断 

        USART_Cmd(USART1, ENABLE); 

         

        //默认设置为输入状态    

        DMA5_Init(); 

} 


//定时器中断服务程序 

void TIM2_IRQHandler(void) 

{ 

  u16 i;    

  //清定时器中断 

  TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);  


  UART1_Timeout++; 

  UART2_Timeout++; 

  UART3_Timeout++; 

//------------------------------------------------------------------ 

  i=DMA_GetCurrDataCounter(DMA1_Channel5); 

  DMA_ClearITPendingBit(DMA1_IT_GL5); //清除全部中断标志 


  if(i!=uart1_Flag_last)  //未完成传输 

  { 

          UART1_Timeout=0; 

        uart1_Flag_last=i; 

  } 

  else 

  { 

    if(UART1_Timeout>UART1_TimeoutComp)  //产生超时 

        { 

           if(i<200) //有数据接收到 

           { 

                  UART1_FlagTemp=200-i;      //得到接收到的字节数 

               

                for(i=0;i<UART1_FlagTemp;i++)  //将数据拷贝到缓冲区 

                 uart1_data[i]=uart1_data_temp[i]; 

                UART1_Flag=UART1_FlagTemp; 

                 

                DMA_ClearFlag(DMA1_FLAG_TC5); 

                DMA_Cmd(DMA1_Channel5, DISABLE); //正式允许DMA                  

                DMA5_Init();                   

           } 

           UART1_Timeout=0; 

        } 

  } 

  //------------------------------------------------------------------ 

  i=DMA_GetCurrDataCounter(DMA1_Channel6); 

  DMA_ClearITPendingBit(DMA1_IT_GL6); //清除全部中断标志 


  if(i!=uart2_Flag_last)  //未完成传输 

  { 

          UART2_Timeout=0; 

        uart2_Flag_last=i; 

  } 

  else 

  { 

    if(UART2_Timeout>UART2_TimeoutComp)  //产生超时 

        { 

           if(i<500) //有数据接收到 

           { 

                  UART2_FlagTemp=500-i;  //得到接收到的字节数 


                for(i=0;i<UART2_FlagTemp;i++)  //将数据拷贝到缓冲区 

                 uart2_data[i]=uart2_data_temp[i]; 

                UART2_Flag=UART2_FlagTemp; 

                 

                DMA_ClearFlag(DMA1_FLAG_TC6); 

                DMA_Cmd(DMA1_Channel6, DISABLE); //正式允许DMA                  

                DMA6_Init(); 

                                 

           } 

           UART2_Timeout=0; 

        } 

  } 

  //------------------------------------------------------------------ 

  i=DMA_GetCurrDataCounter(DMA1_Channel3); 

  DMA_ClearITPendingBit(DMA1_IT_GL3); //清除全部中断标志 


  if(i!=uart3_Flag_last)  //未完成传输 

  { 

          UART3_Timeout=0; 

        uart3_Flag_last=i; 

  } 

  else 

  { 

    if(UART3_Timeout>UART3_TimeoutComp)  //产生超时 

        { 

           if(i<500) //有数据接收到 

           { 

                  UART3_FlagTemp=500-i;  //得到接收到的字节数 


                for(i=0;i<UART3_FlagTemp;i++)  //将数据拷贝到缓冲区 

                 uart3_data[i]=uart3_data_temp[i]; 

                UART3_Flag=UART3_FlagTemp; 

                 

                DMA_ClearFlag(DMA1_FLAG_TC3); 

                DMA_Cmd(DMA1_Channel3, DISABLE); //正式允许DMA                  

                DMA3_Init();   

                 

           } 

           UART3_Timeout=0; 

        } 

  }   

}