你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

使用定时器2的CH1输入捕获和CH2输出比较来对UART断帧检测

[复制链接]
suebillt 提问时间:2015-12-24 16:10 /
本帖最后由 suebillt 于 2015-12-24 17:11 编辑

接收大量不定长的串口数据(或是SPI等),常规的方法不太适用,串口的空闲中断如果可以自己设置空闲时长的话可能会好点,但是丢帧率略高。
我现在用STM32F407来接收GPS数据(1秒大概发送五六百字节),不定长,一开始调试的时候用串口的空闲中断配合DMA倒是不错,但是我加上了DMA
双通道缓冲之后发现数据丢失了或者说一大段数据被误认为空闲了,所以打算用定时器来做一个可以自由控制空闲时长的断帧检测(参考ST官方的资料,
《UART断帧检测》)

代码思路:当TIM2_CH1捕获到上升沿的时候清零计数器的值,开启CH2输出捕获,因为TIM2设置为Slave Reset模式,上升沿自动清零,这样如果有
高电平保持时间长于设定值(计数器分频84,即每次计数器加一为1us,输出比较值10ms即0x2710)即TIM2_CH2的CC2中断产生即检测到空闲帧了
测试需要我打开了CC1和CC2中断并在中断中输出,发现CC1中断后CC2 立即也中断了(读出CNT的值也就500以下(us)不可能与0x2710匹配啊),
一直搞不明白错在哪里额,即是在CCA中断中手动清楚CNT也不能阻止CC2中断


  1. static        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  2. static        NVIC_InitTypeDef NVIC_InitStructure;
  3. static        GPIO_InitTypeDef GPIO_InitStructure;
  4. static  TIM_ICInitTypeDef  TIM2_ICInitStructure;
  5. static  TIM_OCInitTypeDef  TIM2_OCInitStructure;
  6. //通用定时器2中断初始化
  7. //这里时钟选择为APB1的2倍,而APB1为42M
  8. //arr:自动重装值。
  9. //psc:时钟预分频数
  10. //这里使用的是定时器2!
  11. void TIM2_Int_Init(void)
  12. {        
  13.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);  ///使能TIM2时钟
  14.         RCC_APB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
  15.         
  16.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIOA0,1
  17.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
  18.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;        //IO速率100MHz
  19.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推免复用输出
  20.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //下拉
  21.         GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0

  22.         GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM2); //PA0¸PA1复用定时器2
  23.         
  24.   TIM_TimeBaseInitStructure.TIM_Period =0xffffffff;         //定时器分频 计数器加1为1ms
  25.         TIM_TimeBaseInitStructure.TIM_Prescaler=83;  //自动重装载值
  26.         TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //先上计数
  27.         TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //时钟分频1(84MHz)
  28.         
  29.         TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//
  30.         
  31.         
  32.         //输入捕获配置
  33.         TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端IC1映射到TI1上
  34.   TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;        //上升沿捕获
  35.   TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1
  36.   TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;         //配置输入分频,不分频
  37.   TIM2_ICInitStructure.TIM_ICFilter = 0x0;//IC1F=0000 不配置滤波器,提高捕获响应速度
  38.   TIM_ICInit(TIM2, &TIM2_ICInitStructure);
  39.         

  40. //输出比较设置        
  41.   TIM2_OCInitStructure.TIM_OCMode=TIM_OCMode_Timing;
  42.         TIM2_OCInitStructure.TIM_Pulse=0x2710;
  43.         //TIM2_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
  44.         //TIM2_OCInitStructure.OCFastMode=
  45.         TIM_OC2Init(TIM2,&TIM2_OCInitStructure);

  46.         TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset);//TIM2配置成SLAVE RESET,模式
  47.         TIM_SelectInputTrigger(TIM2,TIM_TS_TI1FP1);//TIM2触发模式为ED
  48.   TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);
  49.         
  50.         TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE); //开启更新中断和CC1IE捕获中断
  51.         TIM_Cmd(TIM2,ENABLE); //使能定时器2
  52.         
  53.         NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn; //
  54.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=4; //抢占优先级4
  55.         NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; //子优先级0
  56.         NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  57.         NVIC_Init(&NVIC_InitStructure);

  58. }
  59. //捕获状态
  60. //[7]:0,没有成功捕获(溢出),1成功捕获
  61. //[6]:0,还没有捕获到低电平;1已经捕获到低电平了.
  62. //[5:0]:捕获低电平后溢出的次数(对于32位处理器来说,1us计数加1,溢出时间4294秒:)
  63. //u8  TIM2CH1_CAPTURE_STA=0;        //输入捕获状态                                                   
  64. //u32        TIM2CH1_CAPTURE_VAL;        //输入捕获值(TIM2/TIM5是32位)

  65. u8 TIM2CH1_Rising=0;
  66. u8 TIM2CH1_Falling=1;
  67. u32 TIM2CH1_Counter;
  68. //定时器2中断服务程序         
  69. void TIM2_IRQHandler(void)
  70. {                 
  71.                 if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//溢出
  72.                 {                     
  73.                         if(TIM2CH1_Rising)//已经捕获到高电平
  74.                         {
  75.                                 TIM2CH1_Rising++;
  76.                         }         
  77.                 }
  78.                 if(TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
  79.                 {        printf("#####CC1&&&&&");
  80. //                        if(TIM2CH1_Rising)                //捕获到一个下降沿                 
  81. //                        {                                 
  82. //                                TIM2CH1_Falling=1;                //标记成功捕获到一次高电平脉宽
  83. //                                TIM2CH1_Rising=0;
  84. //                          TIM2CH1_Counter=TIM_GetCapture1(TIM2);//获取当前的捕获值.
  85.                                 //printf("\r\n%d",TIM2CH1_Rising*4294);
  86. //                                if(TIM2CH1_Counter>1000)
  87. //                                  printf(" %d",TIM2CH1_Counter);
  88. //                                 TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
  89. //                        }
  90. //      if(TIM2CH1_Falling)                        //第一次捕获上升沿
  91. //                        {
  92. //                                TIM2CH1_Counter=0;                        //清空
  93. //                                TIM2CH1_Falling=0;
  94. //                                TIM2CH1_Rising=1;                //标记捕获到上升沿
  95. //                                TIM_Cmd(TIM2,ENABLE );         //使能定时器
  96.                                  TIM_SetCounter(TIM2,0);
  97.                         TIM_ITConfig(TIM2,TIM_IT_CC1,DISABLE);
  98.                         TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE);
  99. //                                 TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling);                //CC1P=1 设置为下降沿捕获
  100. //                                TIM_Cmd(TIM2,ENABLE );         //使能定时器
  101. //                        }                    
  102.                 }        
  103.     if(TIM_GetITStatus(TIM2,TIM_IT_CC2)!=RESET)
  104.     {
  105.                         printf(" CC2");
  106.                         printf(" %d",TIM_GetCapture1(TIM2));
  107.                         TIM_ITConfig(TIM2,TIM_IT_CC1,ENABLE);
  108.                         TIM_ITConfig(TIM2,TIM_IT_CC2,DISABLE);
  109.                 }                        
  110.         TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位         
  111. }
复制代码


收藏 2 评论8 发布时间:2015-12-24 16:10

举报

8个回答
disheng4688 回答时间:2015-12-24 17:08:11
学习了,谢谢分享。
suebillt 回答时间:2015-12-24 17:10:43
disheng4688 发表于 2015-12-24 17:08
学习了,谢谢分享。

不好意思,这个问题没有解决
disheng4688 回答时间:2015-12-24 17:12:45
suebillt 发表于 2015-12-24 17:10
不好意思,这个问题没有解决

以前到不知道能这么用。
suebillt 回答时间:2015-12-24 17:15:27
disheng4688 发表于 2015-12-24 17:12
以前到不知道能这么用。

单纯的打开通道1输入捕获的话倒是能触发update中断,加上通道2输出比较厚就不能update了,而且一直触发比较的匹配中断
suebillt 回答时间:2015-12-24 18:26:16
结帖结贴,忘记清除CC2的中断标志位了,草!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
xmshao 回答时间:2015-12-25 10:14:51
小细节被无视而折腾,正常得很。

TIM2工作在slave reset,TIM2-CH1 输入触发,TIM2_CH2 工作在OC模式。
当CC2产生OC中断时表面出现空闲帧了。平常数传时,TIM2会被不停的RESET。
是这个意思吧。
suebillt 回答时间:2015-12-25 10:53:40
xmshao 发表于 2015-12-25 10:14
小细节被无视而折腾,正常得很。

TIM2工作在slave reset,TIM2-CH1 输入触发,TIM2_CH2 工作在OC模式。

是的,没用过定时器的这两个功能,被里面的一些触发方式搞晕了折腾挺久的
xmshao 回答时间:2015-12-25 14:02:18
STM32定时器东西多,理解。用多了就好。

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版