使用STM32的定时器如何为PPM解码

2019-07-21 06:10发布

大家好,工作中要求使用将设备上输出的PPM解码。我使用了正点原子的MINI板做的实验。实验了很多次,都解不出来。得到的数据都不正确,我不知道问题出在什么地方了,我把我的测试思路写出来,把解码的那部分代码贴出来,大家帮忙看看,谢谢。
测试思路:(1)使用定时器1的channel 1进行输入捕获,定时器 采用下降沿触发输入捕获中断。
                  (2)第一次输入捕获中断,设置定时器上升沿触发中断同时计数器清零,中断标志清除
                  (3)第二次输入捕获中断,设置定时器下降沿触发中断同时保存计数器值,清除中断标志,并判断是否是PPM的head部分,是head部分则计数器清零,否则重复第一次输入捕获中断的功能继续检测PPM的head部分。
                  (4)第三次输入捕获中断,如果第二次没能检测到PPM的head部分,则重复第一次输入捕获中断的功能继续检测PPM的head部分。如果检测到head,则该次中断则捕获PPM中第一组有效值;
                 (5)继续捕获PPM中的有效值,知道完全将PPM中的有效值都捕获完成再跳出中断。
定时器初始化:
void time_iCPPM_init(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStruct;
  NVIC_InitTypeDef NVIC_InitStructure;
  TIM_ICInitTypeDef  TIM_ICInitStruct;
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //使能TIM1时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIOA时钟

  //gpio初始化:
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //浮空输入
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  //中断初始化:
  NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn; //设TIM1输入捕获中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //配置优先级组
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //允许TIM1全局中断
  NVIC_Init(&NVIC_InitStructure);
  //时基初始化:
  TIM_DeInit(TIM1);
  TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
  TIM_TimeBaseInitStruct.TIM_Prescaler = 72;
  TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInitStruct.TIM_Period = 0xFFFF;
  TIM_TimeBaseInitStruct.TIM_ClockDivision = 0;
  TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct );
  //输入捕获初始化:
  TIM_ICStructInit(&TIM_ICInitStruct);
  TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
  TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Falling; //由于先检测低电平的同步头,所以这里下降沿触发
  //下降沿触发
  TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStruct.TIM_ICFilter = 0x5;
  TIM_ICInit(TIM1, &TIM_ICInitStruct );
  //开始捕获:
  TIM_Cmd(TIM1, ENABLE);
  TIM_ClearFlag(TIM1,TIM_FLAG_CC1 );
  TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE); 
  TIM_ITConfig(TIM1, TIM_IT_Update, DISABLE);
}
//解码PPM部分:
//中断处理函数:
void TIM1_CC_IRQHandler(void)
{
  
  if (i == 0)     //变量i用于调整中断处理的任务:分为每通道第一次进入计数清零,第二次计入保存计数
   {              //当然要先检测同步头,即上面图中比较长的一段低电平
      TIM1->CCER &= 0XFFFD;//改为上升沿触发并且清零清中断标志,定时器在初始化的时候是下降沿触发
      TIM1->CNT = 0;
      TIM1->SR &= 0XFFFC;//清除中断标志 
      i = 1;
   }
   else if (i == 1)
   {  
      TIM1->CCER |= 0X02; //改为下降沿触发
      buffer = TIM1->CNT; //保存计数
      TIM1->SR &= 0XFFFC; //清除中断标志
 if (buffer < 3000)  //如果低电平时间太短,即不是同步头
      {
        i = 0;            //则继续检测同步头
      }
      else
      { 
        i = 2;            //否则
        TIM1->CNT = 0;    //计数清零,准备读取高电平时间
TIM1->SR &= 0XFFFC;//清除中断标志
      }
    }
    else if (i == 2)      //到这里已经开始读取各通道数据了
    { 
       TIM1->CCER &= 0XFFFD;    //改为上升沿触发
       channel[c] = TIM1->CNT;  //保存通道c的数据
       TIM1->SR &= 0XFFFC;      //清中断标志
       i = 3;                   //i=3里面做的事是为各通道清零并准备下降沿时读数
       c++;                     //通道数加1
       if(c == 6)               //如果已经读了6个通道
       {
        c = 0;                  //回归第1个通道(6个通道对应0~5)
        goto end;               //退出中断
       }
     }
     else if (i == 3)
     { 
       TIM1->CCER |= 0X02; //改为下降沿触发
       TIM1->CNT = 0;   //计数清零
       TIM1->SR &= 0XFFFC; //清除中断标志
       i = 2;
     }
end: ;     //一个空语句 
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
3条回答
正点原子
1楼-- · 2019-07-21 10:35
 精彩回答 2  元偷偷看……
阳heaven阳
2楼-- · 2019-07-21 16:28
最后结果出来没有啊
阳heaven阳
3楼-- · 2019-07-21 20:56
ppm解码最后成功了没啊

一周热门 更多>