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

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

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

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

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

直接程序吧

u8  Usart1_RX_Cop[]={};   //串口2备用接收缓冲,最大 1024 个字节.
u8  Usart1_RX_BUF[]={};   //串口1接收缓冲,最大 1024 个字节.
u16 Usart1_REC_Cnt = ;        //串口1接收的数据个数
u16 Usart1_Current_Cnt = ;    //串口1当前接收的数据个数
u16 Usart1_Current_cnt = ;    //串口1当前接收的数据个数
u8  Usart1_AT_flage = ;       //串口1接收完成标志位

u8  Usart2_RX_Cop[]={};   //串口2备用接收缓冲,最大 1024 个字节.
u8  Usart2_RX_BUF[]={};   //串口2接收缓冲,最大 1024 个字节.
u16 Usart2_REC_Cnt = ;        //串口2接收的数据个数
u16 Usart2_Current_Cnt = ;    //串口2当前接收的数据个数
u16 Usart2_Current_cnt = ;    //串口2当前接收的数据个数
u8  Usart2_AT_flage = ;       //串口2接收完成标志位

u8  Usart3_RX_BUF[]={};   //串口3接收缓冲,最大 1024 个字节.
u16 Usart3_REC_Cnt = ;        //串口3接收的数据个数
u8  Usart3_AT_flage = ;       //串口3接收完成标志位

u8 Free_Read_Rst = ;//读DR清除空闲中断
void USART123_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  PA9
    GPIO_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  PA10
   GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING ;
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
   GPIO_Init(GPIOA, &GPIO_InitStructure);

    //USART2_TX   GPIOA.2
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
  GPIO_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;//PA3
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);

    //USART3_TX   GPIOB.10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
  GPIO_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;//PB11
  GPIO_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 中断服务程序**********************/
void USART1_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++;
  }
  else if(USART_GetITStatus(USART1,USART_IT_IDLE) == SET)//传输完一条完整的数据就会进入这个
    {
        Free_Read_Rst = USART1->DR; //清USART_IT_IDLE标志
        Usart1_AT_flage = ;//接收到一条完整的数据
        Usart1_Current_Cnt = Usart1_REC_Cnt;//复制接收到的数据个数
        Usart1_REC_Cnt = ;//清零接收的个数
   }
}

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

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

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

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

其实思路都知道

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

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

直接上程序

/********************串口 1 中断服务程序**********************/
void USART1_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 = ;//清零计数
  }
}
void timer_config(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    /* Resets the TIM2 */
    TIM_DeInit(TIM2);
    //设置了时钟分割。
    TIM_TimeBaseStructure.TIM_ClockDivision = ;
    // 选择了计数器模式。
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    //初值
    TIM_TimeBaseStructure.TIM_Period = ;//定时时间1ms进一次
    //设置了用来作为 TIMx 时钟频率除数的预分频值。72M / 7099+1 = 0.01M
    TIM_TimeBaseStructure.TIM_Prescaler = ;

    //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 );
}
void TIM2_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
    {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
        )//防止累加循环过去
        {
          Time2_cnt ++ ;
        }
        )//空闲时间大于约3毫秒
        {
            TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE );//关闭定时器---注意千万不要放到主函数里面关,,,,大家可以试一试会出现什么问题.....
            Usart1_AT_flage = ;//接收完成标志位置一
            Usart1_Current_Cnt = Usart1_REC_Cnt;//赋值接收的数据个数
            Usart1_REC_Cnt = ;//清零接收的数据个数
       }
}

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

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

u8  Usart2_RX_Cop[]={};   //串口2备用接收缓冲,最大 1024 个字节.
u8  Usart2_RX_BUF[]={};   //串口2接收缓冲,最大 1024 个字节.
u16 Usart2_REC_Cnt = ;        //串口2接收的数据个数
u16 Usart2_Current_Cnt = ;    //串口2当前接收的数据个数
u16 Usart2_Current_cnt = ;    //串口2当前接收的数据个数
u8  Usart2_AT_flage = ;       //串口2接收完成标志位

u8  Usart3_RX_Cop[]={};   //串口2备用接收缓冲,最大 1024 个字节.
u8  Usart3_RX_BUF[]={};   //串口2接收缓冲,最大 1024 个字节.
u16 Usart3_REC_Cnt = ;        //串口2接收的数据个数
u16 Usart3_Current_Cnt = ;    //串口2当前接收的数据个数
u16 Usart3_Current_cnt = ;    //串口2当前接收的数据个数
u8  Usart3_AT_flage = ;       //串口2接收完成标志位

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

    //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 );
}
void TIM3_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

        )//开始累加空闲变量
        {
          )//防止累加过去,造成循环
          {
            Usart1_IdealTime++;//空闲变量累加
          }
       }

       )//调节这个值以适应不同的接收速率
       {
            Usart1_TimeFlage = ;//停止空闲变量累加
            Usart1_IdealTime = ;//清零空闲累加变量
            Usart1_AT_flage = ; //接收标志位置一
            Usart1_Current_Cnt = Usart1_REC_Cnt;//拷贝接收的数据个数
            Usart1_REC_Cnt =;//清零接收的数据个数
      }

      )//开始累加空闲变量
      {
        )//防止累加过去,造成循环
        {
          Usart3_IdealTime++;//空闲变量累加
        }
      }

      )//调节这个值以适应不停的接收速率
      {
          Usart3_TimeFlage = ;//停止空闲变量累加
          Usart3_IdealTime = ;//清零空闲累加变量
          Usart3_AT_flage = ; //接收标志位置一
          Usart3_Current_Cnt = Usart3_REC_Cnt;//拷贝接收的数据个数
          Usart3_REC_Cnt =;//清零接收的数据个数
      }
    }
}

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

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

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

关于STM32空闲中断的更多相关文章

  1. STM32空闲中断

    收发共存的思路没有经过验证!!! 空闲中断:既可以用来作为不定长接收数据帧的断帧判断/特别是DMA数据的接收,也可以用来指示中断发送的结束. 在需要发送的地方USART_ITConfig(UART5, ...

  2. STM32 HAL 库实现乒乓缓存加空闲中断的串口 DMA 收发机制,轻松跑上 2M 波特率

    前言 直接储存器访问(Direct Memory Access,DMA),允许一些设备独立地访问数据,而不需要经过 CPU 介入处理.因此在访问大量数据时,使用 DMA 可以节约可观的 CPU 处理时 ...

  3. Stm32使用串口空闲中断,基于队列来接收不定长、不定时数据

    串口持续地接收不定长.不定时的数据,把每一帧数据缓存下来且灵活地利用内存空间,下面提供一种方式供参考.原理是利用串口空闲中断和DMA,每当对方发来一帧完整的数据后,串口接收开始空闲,触发中断,在中断处 ...

  4. (二)stm32之中断配置

    一.stm32的中断和异常 Cortex拥有强大的异常响应系统,它能够打断当前代码执行流程事件分为异常和中断,它们用一个表管理起来,编号为0~15为内核异常,16以上的为外部中断,这个表就是中断向量表 ...

  5. 转载:STM32之中断与事件---中断与事件的区别

    这张图是一条外部中断线或外部事件线的示意图,图中信号线上划有一条斜线,旁边标志19字样的注释,表示这样的线路共有19套.图中的蓝色虚线箭头,标出了外部中断信号的传输路径,首先外部信号从编号1的芯片管脚 ...

  6. STM32外部中断具体解释

      一.基本概念 ARM Coetex-M3内核共支持256个中断,当中16个内部中断,240个外部中断和可编程的256级中断优先级的设置.STM32眼下支持的中断共84个(16个内部+68个外部), ...

  7. STM32之中断与事件---中断与事件的区别

    STM32之中断与事件---中断与事件的区别  http://blog.csdn.net/flydream0/article/details/8208463 这张图是一条外部中断线或外部事件线的示意图 ...

  8. stm32之中断配置

    一.stm32的中断和异常 Cortex拥有强大的异常响应系统,它能够打断当前代码执行流程事件分为异常和中断,它们用一个表管理起来,编号为0~15为内核异常,16以上的为外部中断,这个表就是中断向量表 ...

  9. 2-关于单片机通信数据传输(中断接收,大小端,IEEE754浮点型格式,共用体,空闲中断,环形队列)

    上一篇链接 http://www.cnblogs.com/yangfengwu/p/8628219.html 先说明一点这种方式,不光对于单片机类的,,对于上位机接收数据同样适用----不骗人的,自己 ...

随机推荐

  1. Python练习册 第 0013 题: 用 Python 写一个爬图片的程序,爬 这个链接里的日本妹子图片 :-),(http://tieba.baidu.com/p/2166231880)

    这道题是一道爬虫练习题,需要爬链接http://tieba.baidu.com/p/2166231880里的所有妹子图片,点进链接看一下,这位妹子是日本著名性感女演员--杉本由美,^_^好漂亮啊,赶紧 ...

  2. Html 经典布局(三)

    经典布局案例(三): <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  3. AngularJs 4大核心

    放弃了IE8, 4大核心: MVC: 数据模型,视图层,业务逻辑和控制模式(控制器), 为何MVC不是设计模式呢?(23种设计模式里没有MVC,MVC模式的目的就是实现Web系统的职能分工,超越了设计 ...

  4. wow.js中各种特效对应的类名

    一.(页面在向下滚动的时候,有些元素会产生细小的动画效果.虽然动画比较小,但却能吸引你的注意.) 刚知道wow.js这个插件,之前访问别的网站下拉滚动条会出现各种效果感觉特别神奇,现在自己依葫芦画瓢也 ...

  5. git的使用及常用命令

    一,GIT是什么? git是目前世界上最先进的分布式版本控制系统 Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在 ...

  6. html、css、js实现简易计算器

    学习HTML,CSS,JS一个月后,想着能自己是否能写出一个简单的东西,故编写了简易的计算器,之前也写过一个坦克大战,坦克大战的有些基本功能没有实现, 故也没有记录下来,想来,对这行初来咋到的,还是需 ...

  7. mybatis插入List集合数据

    处女帖 今天做完一个定时任务将一个表中的数据每天统计到另外一个表中,开始是用循环的方式向数据库添加,觉得数据库可能访问压力过大,所以就使用了mybatis的foreach标签来稍微的减少压力. 首先封 ...

  8. 防止微信浏览器video标签全屏的问题

    在微信浏览器里面使用video标签,会自动变成全屏,改成下面就好了,起码可以在video标签之上加入其他元素. <video id="videoID" webkit-play ...

  9. bzoj4514 [Sdoi2016]数字配对

    Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对 ...

  10. Linux环境下用户空间与内核空间数据的交换方式

    在linux环境开发过程中,经常会需要在用户空间和内核空间之间进行数据交换. 介绍了 Linux 系统下用户空间与内核空间数据交换的几种方式 第一节:使用procfs实现内核交互简明教程(1) 第二节 ...