有一次做一个东西,为了尽量不占用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清除空闲中断

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  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 中断服务程序**********************/
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 = 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 中断服务程序**********************/
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 = 0;//清零计数}
}

void timer_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 );
}

void TIM2_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接收完成标志位

void timer3_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 );
}

void TIM3_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空闲中断相关推荐

  1. 关于STM32空闲中断极限时间

    今天空了专门做了关于STM32空闲中断极限时间的实验,结果如下: 115200,8,N,1, 1个位理论用时:1/115200=8.68us,实测发送一帧数据的字节间延时超过大约173us时,则出现空 ...

  2. stm32: 串口空闲中断的实现(HAL库)

    STM32利用串口空闲中断来分包(HAL库) 文章目录 STM32利用串口空闲中断来分包(HAL库) 1. 开发环境 2. 串口中断接收的问题和解决办法 3. 串口空闲中断分包的原理 4. STM32 ...

  3. stm32 USART接收总线空闲中断--USART_IT_IDLE

    stm32 USART接收总线空闲中断--USART_IT_IDLE 版权声明:转载请注明作者和链接 https://blog.csdn.net/Hola_ya/article/details/815 ...

  4. STM32 利用空闲中断接收数据

    STM32 利用串口空闲中断接收不定长数据 利用cubeMX打开DMA串口接收中断 利用CubeMX打开串口中断 HAL_NVIC_SetPriority(USART2_IRQn, 0, 0); HA ...

  5. STM32 HAL CubeMX 串口IDLE接收空闲中断+DMA

    关于DMA原理部分讲解,及CubeMx配置部分,请参考该文章 [STM32]HAL库 STM32CubeMX教程十一-DMA (串口DMA发送接收) 本篇文章我们仅针对例程进行详解剖析 历程详解 详解 ...

  6. stm32的rxne和idle中断_STM32 HAL CubeMX 串口IDLE接收空闲中断+DMA

    历程详解 详解包括: 中断原理讲解 例程流程详解 库函数分析详解 对应寄存器介绍 对应函数介绍 对应注释详解 本篇文章提供两种方法: 一种是 :IDLE 接收空闲中断+DMA 一种是: IDLE 接收 ...

  7. stm32的串口DMA空闲中断接收不等长数据,stm32F1的usart1-DMA-IDLE收发

    stm32的DMA收发原理,和stm32F4 + USART2 +DMA +IDLE使用,见另一篇:https://blog.csdn.net/Mark_md/article/details/1072 ...

  8. stm32的串口DMA空闲中断接收不等长数据,stm32F4的usart2-DMA-IDLE收发

    1. 串口为什么要使用DMA?好处? 提高系统实时性:stm32单片机的串口没有FIFO,使用字节中断的方式去接收,会频繁进入中断,影响系统实时性.好在stm32的串口可以级联DMA使用,在大数据量连 ...

  9. STM32应用(七)JY901九轴姿态模块(串口DMA空闲中断和I2C通信)

    文章目录 0.相关基础知识介绍 0.1六轴.九轴传感器有什么区别? 1.JY901模块简介 1.1 产品概述 1.2 性能参数 1.3 实物图和接线 2.软件和使用说明书 3.串口通信JY901 3. ...

最新文章

  1. Vim----ma6174
  2. TensorFlow AI 新品更易用!联手NVIDIA,支持Swift和JavaScript
  3. js弹框带传值父窗口给子框_JavaScript实现弹出子窗口并传值给父窗口
  4. 老男孩python全栈开发视频教程_老男孩Python全栈开发(92天全)视频教程 自学笔记16...
  5. iPhone应用程序编程指南(窗口和视图)
  6. SAP Leonardo 机器学习插件的安装
  7. HTML5 基础知识
  8. 003之MFCSocket异步编程(指针机制)
  9. PHP中的++和--
  10. IMUGPS融合定位::IMU姿态解算
  11. 【数据仓库】6.数据质量监控
  12. openwrt 中 WiFi探针的三种实现办法
  13. A1.0.2 离线瓦片用ol3显示多功能地图
  14. 从四大造字法看文字所承载的文化_举例说明汉语汉字所承载的文化信息?
  15. 忽如一夜春风来,千树万树梨花开
  16. 幼儿园教师计算机心得,幼儿园教师信息技术应用心得体会
  17. eva新世纪福音战士_【新世纪福音战士EVA合集】新世纪福音战士EVA游戏大全-ZOL游戏库...
  18. 贝叶斯垃圾邮件分类问题中联合概率的推导
  19. 关键词SEO排名优化的对策与流程
  20. iwebshop的WAMP环境部署

热门文章

  1. 绿色节能环保 开启低碳生活
  2. Ant Design Pro 企业级后台实战(73 个视频)
  3. 我记得你往日的样子----聂鲁达
  4. 做自媒体怎样开始起步?
  5. Android个人信息页面
  6. RITnet: Real-time Semantic Segmentation of the Eye for Gaze Tracking
  7. 开源的免费听音乐程序
  8. 异硫氰酸荧光素(FITC)标记的抗人IL-1ra单克隆抗体,FITC-IL-1ra
  9. 江苏联亚国际展览中心跨境展批发产品B2B门户线上展会平台matchup expo SEO工作日志
  10. 【字节跳动2019年】算法岗笔试题