串口中断结合定时器实现稳定可靠的串口接收

来源:互联网 发布:windows iscsitarget 编辑:程序博客网 时间:2024/06/06 06:38

    串口的接收方式可以有很多种,之前也提到过使用延时判断串口接收指正的值是否改变来进行接收完成的判断。也介绍过使用DMA的空闲中断触发以判断串口接收完成。以上两种方式,在一定情况下可以使用效果也还可以。延时判断的方式,对于不跑操作系统的工程里影响不大,但是到了一个跑实时系统的工程里,这种方式就显得不稳定了。而DMA方式接收,效率很高而且不占用处理器时间,但是这样接收就是太快了,在数据频繁发送的情况下,经常会把两条应该是分开的数据合为了一条。

    结合定时器的使用,以10ms为数据包间的最大间隔,如果超过10ms没有接收到新的数据,那么这一次数据就可以认为已经发送完成了。如果在10ms内接收到了新的数据,则把定时器的值重装并开始计时。

    具体代码如下。

    //定义接收缓冲区

unsigned char RX3_Temp[RX3_Recv_Len] = {0};     /* 临时缓冲 */unsigned char RX3_Point = 0;          /* 缓冲区指针 */

    //初始化串口3

void USART3_Init_JAVE( u32 bound ){GPIO_InitTypeDef  GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef  NVIC_InitStructure;USART_DeInit(USART3);//使能串口3的时钟 和对应GPIO时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//配置TX引脚GPIOGPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_Init(GPIOB,&GPIO_InitStructure);//配置RX引脚GPIOGPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOB,&GPIO_InitStructure);//配置串口3USART_InitStructure.USART_BaudRate = bound;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(USART3, &USART_InitStructure);//使能串口3USART_Cmd(USART3,ENABLE);//使能串口接收中断USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//配置串口3接收中断NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);USART_ClearFlag(USART3, USART_FLAG_RXNE);USART_GetFlagStatus(USART3,USART_FLAG_TC);     /* 先读SR,再写DR */TIM7_Int_Init(99,7199);//10ms中断RX3_Point=0;//清零TIM_Cmd(TIM7,DISABLE);//关闭定时器7}

    //初始化定时器7 及中断

//定时器7初始化和中断处理void TIM7_Int_Init(u16 arr,u16 psc){TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); //时钟使能//定时器TIM7初始化TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位 TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断//中断优先级NVIC设置NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;  //TIM7中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  //先占优先级0级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级3级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器TIM_Cmd(TIM7, ENABLE);  //使能TIMx }void TIM7_IRQHandler(void)   //TIM7中断{if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)  //检查TIM7更新中断{RX3_Point|=0x80;//最高位置1,标记接收完成TIM_ClearITPendingBit(TIM7, TIM_IT_Update  );  //清除TIMx更新中断标志 TIM_Cmd(TIM7, DISABLE);  //关闭TIM7 }}

    //串口3中断

void USART3_IRQHandler( void ){char temp = 0;if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET){           temp = USART_ReceiveData( USART3 );     /* 读取USART3数据,自动清零标志位 RXNE */if((RX3_Point&0x80) == 0){if(RX3_Point < RX3_Recv_Len)//还可以接收数据{TIM_SetCounter(TIM7,0);//计数器清空   if(RX3_Point==0) //使能定时器7的中断 {TIM_Cmd(TIM7,ENABLE);//使能定时器7}RX3_Buff[RX3_Point++]=temp;//记录接收到的值 }else{RX3_Point|=0x80; //长度超出限制了}}}}

在应用程序中,只需要一直扫描判断RX3_Point的最高位是否为1就可以判断是否接收完成了。

if(RX3_Point & 0x80)

{

     printf("接收完成\r\n");

    RX3_Point =0;

}

使用时需要注意的是,扫描到一次结果后,对其进行处理,最后必须要对RX3_Point 进行清零操作,否则将不再接收新的数据。




0 0
原创粉丝点击