美文网首页STM32我爱编程
关于STM32空闲中断

关于STM32空闲中断

作者: 杨奉武 | 来源:发表于2017-10-14 19:12 被阅读54次

有一次做一个东西,为了尽量不占用CPU的处理数据时间,所以就使用DMA接收串口的数据,但是呢问题来了.,,,,,怎么样才能确定接收到了一条完整的数据了,,我们都知道只要打开DMA

那家伙就不停的把接收的数据放到我们指定的地方.

只要接收到一条完整的数据我就该去处理了

关于空闲中断,,,就是说每接收到一条完整的数据就会置位空闲标志位,我们只需要判断空闲标志位是否置一,,就能知道是不是接收到了一条完整的数据

用空闲中断的好处就是,,对于以前我写程序通信都会在数据的后面加上尾,,然后另一个接收的单片机通过判断数据的尾来确定是不是一条完整的数据,,,有了空闲中断就不需要在给数据加上尾了,,,,,

直接程序吧

u8  Usart1_RX_Cop[1024]={0};//串口2备用接收缓冲,最大 1024 个字节.u8  Usart1_RX_BUF[1024]={0};//串口1接收缓冲,最大 1024 个字节.u16 Usart1_REC_Cnt =0;//串口1接收的数据个数u16 Usart1_Current_Cnt =0;//串口1当前接收的数据个数u16 Usart1_Current_cnt =0;//串口1当前接收的数据个数u8  Usart1_AT_flage =0;//串口1接收完成标志位u8  Usart2_RX_Cop[1024]={0};//串口2备用接收缓冲,最大 1024 个字节.u8  Usart2_RX_BUF[1024]={0};//串口2接收缓冲,最大 1024 个字节.u16 Usart2_REC_Cnt =0;//串口2接收的数据个数u16 Usart2_Current_Cnt =0;//串口2当前接收的数据个数u16 Usart2_Current_cnt =0;//串口2当前接收的数据个数u8  Usart2_AT_flage =0;//串口2接收完成标志位u8  Usart3_RX_BUF[1024]={0};//串口3接收缓冲,最大 1024 个字节.u16 Usart3_REC_Cnt =0;//串口3接收的数据个数u8  Usart3_AT_flage =0;//串口3接收完成标志位u8 Free_Read_Rst=0;//读DR清除空闲中断

voidUSART123_Init(uint32_t bound_1,uint32_t bound_2,uint32_t bound_3)

{

USART_InitTypeDef USART_InitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2|RCC_APB1Periph_USART3, ENABLE);//使能USART2,USART3时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO , ENABLE);//USART1_TX  PA9GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;;

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure);//USART1_RX  PA10GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING ;

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;

GPIO_Init(GPIOA,&GPIO_InitStructure);//USART2_TX  GPIOA.2GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//PA.2GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP;//复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure);//USART2_RX      GPIOA.3初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);//USART3_TX  GPIOB.10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PB10GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP;//复用推挽输出GPIO_Init(GPIOB, &GPIO_InitStructure);//USART3_RX      GPIOB.11初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PB11GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOB, &GPIO_InitStructure);

USART_InitStructure.USART_BaudRate=bound_1;

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_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启串口接受中断USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口1总线空闲中断USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);//开启串口2总线空闲中断USART_InitStructure.USART_BaudRate=bound_2;

USART_Init(USART2,&USART_InitStructure);

USART_InitStructure.USART_BaudRate=bound_3;

USART_Init(USART3,&USART_InitStructure);

USART_Cmd(USART1, ENABLE);

USART_Cmd(USART2, ENABLE);

USART_Cmd(USART3, ENABLE);

}

/********************串口 1 中断服务程序**********************/voidUSART1_IRQHandler(void)

{if(USART_GetITStatus(USART1, USART_IT_RXNE) !=RESET) //正常情况下进入这个接收

{

USART_ClearITPendingBit(USART1, USART_FLAG_ORE);

USART_ClearITPendingBit(USART1,USART_IT_ORE);//清除中断标志Usart1_RX_BUF[Usart1_REC_Cnt] =USART_ReceiveData(USART1);//读取接收到的数据Usart1_REC_Cnt++;

}elseif(USART_GetITStatus(USART1,USART_IT_IDLE) ==SET)//传输完一条完整的数据就会进入这个

{

Free_Read_Rst= USART1->DR;//清USART_IT_IDLE标志Usart1_AT_flage =1;//接收到一条完整的数据Usart1_Current_Cnt = Usart1_REC_Cnt;//复制接收到的数据个数Usart1_REC_Cnt =0;//清零接收的个数}

}

主函数循环里只需要......

先说一点:单片机的串口可以接收任意波特率的数据,你所写的9600意思是以这个波特率发送....

其实昨天才发现这家伙真的太准确了,,准确到如果碰见通信中速率如果不是设置的波特率,就是说通信的速率慢了不是(我上面设置的波特率是9600)1/9600(S)发过来一位数据了,低于了这个值假设是2400吧!接受到一位数据后如果1/9600(s)后没有接收到数据,那么这家伙也会进空闲中断.......因为你是设置的9600,,,,那么在1/9600(s)后理应接收到下一位数据....而其实是在1/2400(S)后才会接收到另一位数据.....如果能把空闲中断的检测时间降到满足的要求就好了....

所以嘛,,,,,自己写个别这么苛刻的,昨天写好了,不过呢今天主要是把自己遇到的问题说一下

其实思路都知道

串口接收的时候打开一个定时器,并且只要接收到数据就清零一个变量,这个变量是在定时器里面执行自加一操作,,

如果串口一段时间(空闲中断的检测时间)不接收数据了这个变量就能自加到我们设置的数,然后关掉定时器,置位接收完成标志位,...

直接上程序

/********************串口 1 中断服务程序**********************/voidUSART1_IRQHandler(void)

{if(USART_GetITStatus(USART1, USART_IT_RXNE) !=RESET)

{

USART_ClearITPendingBit(USART1, USART_FLAG_ORE);

USART_ClearITPendingBit(USART1,USART_IT_ORE);//清除中断标志Usart1_RX_BUF[Usart1_REC_Cnt] =USART_ReceiveData(USART1);//读取接收到的数据Usart1_REC_Cnt++;

TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE );//打开定时器开始计时Time2_cnt =0;//清零计数}

}

voidtimer_config(void)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);/*Resets the TIM2*/TIM_DeInit(TIM2);//设置了时钟分割。TIM_TimeBaseStructure.TIM_ClockDivision =0;//选择了计数器模式。TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//初值TIM_TimeBaseStructure.TIM_Period =10;//定时时间1ms进一次//设置了用来作为 TIMx 时钟频率除数的预分频值。72M / 7099+1 = 0.01MTIM_TimeBaseStructure.TIM_Prescaler =7199;//TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);

TIM_ClearITPendingBit(TIM2, TIM_IT_Update);/*Enables the TIM2 counter*/TIM_Cmd(TIM2, ENABLE);/*Enables the TIM2 Capture Compare channel 1 Interrupt source*/TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE );

}

voidTIM2_IRQHandler(void)

{if(TIM_GetITStatus(TIM2, TIM_IT_Update) ==SET)

{

TIM_ClearITPendingBit(TIM2, TIM_IT_Update);if(Time2_cnt<100)//防止累加循环过去

{

Time2_cnt++;

}if(Time2_cnt>3)//空闲时间大于约3毫秒

{

TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE );//关闭定时器---注意千万不要放到主函数里面关,,,,大家可以试一试会出现什么问题.....Usart1_AT_flage =1;//接收完成标志位置一

Usart1_Current_Cnt=Usart1_REC_Cnt;//赋值接收的数据个数

Usart1_REC_Cnt=0;//清零接收的数据个数      }

}

然后昨天又写了一个两个串口的,因为用了两个串口做数据转换(用的串口1和串口3),,,,其实其中一个也可以用空闲中断,,但是担心数据传输过程中万一速率有所变化,,,,,,,,完蛋啦

uint8_t  Usart1_TimeFlage =0;//串口1空闲变量允许累加标志uint16_t Usart1_IdealTime =0;//串口1空闲累加变量uint8_t  Usart3_TimeFlage =0;//串口3空闲变量允许累加标志uint16_t Usart3_IdealTime =0;//串口3空闲累加变量u8  Usart1_RX_Cop[1024]={0};//串口2备用接收缓冲,最大 1024 个字节.u8  Usart1_RX_BUF[1024]={0};//串口1接收缓冲,最大 1024 个字节.u16 Usart1_REC_Cnt =0;//串口1接收的数据个数u16 Usart1_Current_Cnt =0;//串口2当前接收的数据个数u16 Usart1_Current_cnt =0;//串口2当前接收的数据个数u8  Usart1_AT_flage =0;//串口1接收完成标志位u8  Usart2_RX_Cop[1024]={0};//串口2备用接收缓冲,最大 1024 个字节.u8  Usart2_RX_BUF[1024]={0};//串口2接收缓冲,最大 1024 个字节.u16 Usart2_REC_Cnt =0;//串口2接收的数据个数u16 Usart2_Current_Cnt =0;//串口2当前接收的数据个数u16 Usart2_Current_cnt =0;//串口2当前接收的数据个数u8  Usart2_AT_flage =0;//串口2接收完成标志位u8  Usart3_RX_Cop[1024]={0};//串口2备用接收缓冲,最大 1024 个字节.u8  Usart3_RX_BUF[1024]={0};//串口2接收缓冲,最大 1024 个字节.u16 Usart3_REC_Cnt =0;//串口2接收的数据个数u16 Usart3_Current_Cnt =0;//串口2当前接收的数据个数u16 Usart3_Current_cnt =0;//串口2当前接收的数据个数u8  Usart3_AT_flage =0;//串口2接收完成标志位

voidtimer3_config(void)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);/*Resets the TIM2*/TIM_DeInit(TIM3);//设置了时钟分割。TIM_TimeBaseStructure.TIM_ClockDivision =0;//选择了计数器模式。TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//初值TIM_TimeBaseStructure.TIM_Period =10;//定时时间1Ms进一次//设置了用来作为 TIMx 时钟频率除数的预分频值。72M / 7099+1 = 0.01MTIM_TimeBaseStructure.TIM_Prescaler =7199;//TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);

TIM_ClearITPendingBit(TIM3, TIM_IT_Update);/*Enables the TIM2 counter*/TIM_Cmd(TIM3, ENABLE);/*Enables the TIM2 Capture Compare channel 1 Interrupt source*/TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE );

}

voidTIM3_IRQHandler(void)

{if(TIM_GetITStatus(TIM3, TIM_IT_Update) ==SET)

{

TIM_ClearITPendingBit(TIM3, TIM_IT_Update);if(Usart1_TimeFlage ==1)//开始累加空闲变量{if(Usart1_IdealTime<400)//防止累加过去,造成循环{

Usart1_IdealTime++;//空闲变量累加}

}if(Usart1_IdealTime>=100)//调节这个值以适应不同的接收速率{

Usart1_TimeFlage=0;//停止空闲变量累加Usart1_IdealTime =0;//清零空闲累加变量Usart1_AT_flage =1;//接收标志位置一Usart1_Current_Cnt = Usart1_REC_Cnt;//拷贝接收的数据个数Usart1_REC_Cnt =0;//清零接收的数据个数}if(Usart3_TimeFlage ==1)//开始累加空闲变量{if(Usart3_IdealTime<400)//防止累加过去,造成循环{

Usart3_IdealTime++;//空闲变量累加}

}if(Usart3_IdealTime>=100)//调节这个值以适应不停的接收速率{

Usart3_TimeFlage=0;//停止空闲变量累加Usart3_IdealTime =0;//清零空闲累加变量Usart3_AT_flage =1;//接收标志位置一Usart3_Current_Cnt = Usart3_REC_Cnt;//拷贝接收的数据个数Usart3_REC_Cnt =0;//清零接收的数据个数}

}

}

那么主循环里---具体的处理函数,改为自己的就行

源码,,这个是用的板子的空闲中断,,,,板子的其余文件删掉便可,,,,

链接:http://pan.baidu.com/s/1c228q6c密码:pl3k

相关文章

  • 关于STM32空闲中断

    有一次做一个东西,为了尽量不占用CPU的处理数据时间,所以就使用DMA接收串口的数据,但是呢问题来了.,,,,,怎...

  • 4.STM32之中断式按键

    1.STM32中断概述 中断优先级 在使用中断式按键之前,我们先去了解一下STM32的中断。关于这方面可以参考《S...

  • STM32之外部中断

    关于stm32 的外部引脚中断的简单应用;用来添加一个外部引脚中断;更改IRQ_Handler函数可以实现不同的中...

  • STM32外部中断

    STM32 的每个 IO 都可以作为外部中断的中断输入口,这点也是 STM32 的强大之处。GPIO 的管脚 GP...

  • 4.4每日站报

    DONE STM32定时器中断部分的学习 学习数电译码器部分 写了关于定时器中断的学习笔记 TODO 完成STM3...

  • STM32 利用Hal库实现UART中断处理

    实验室项目需要使用STM32开发,Hal库的资料相对较少,关于UART中断与之前使用飞思卡尔芯片的中断不同。首先在...

  • 按键与中断处理

    NVIC中断工作原理 cortex-m3支持256个中断,其中包含了16个内核中断,240个外部中断。stm32中...

  • STM32一文通(5) 中断概览

    STM32 中断非常强大,每个外设都可以产生中断 中断优先级数值越小级别越高 中断的类型分两类: 1. 系统异常(...

  • 4. 关于DMA问题

    1. 问题: 1、空闲中断和别的接收完成(一个字节)中断,发送完成(发送寄存器控)中断的一样是串口中断; 2、空闲...

  • stm32 外部中断

    首先,要理清楚,什么是中断。 中断的意思是,比如CPU是主角,他正在工作,忽然间GPIO口跟他讲,这件事需要他来做...

网友评论

    本文标题:关于STM32空闲中断

    本文链接:https://www.haomeiwen.com/subject/zijfuxtx.html