关于STM32的编码器计数及溢出处理调试总结

举报
kobesdu 发表于 2022/02/08 09:49:56 2022/02/08
【摘要】 错误1、pc6 pc7被用作其他用途,GPIO模式配置错误。导致计数不准确;错误2、引脚模式设置错误,应该设置为GPIO_Mode_IPD;//GPIO_Mode_IPU GPIO_Mode_IN_FLOATING 都可以;错误3 引脚重映射没有开启AFIO时钟; 总结 关于编码器的溢出处理: 网上的检测数值突变的方法不可靠,会有漏检的情况。在滴答定时器中检测encoder的值突变void ...


错误1、

pc6 pc7被用作其他用途,GPIO模式配置错误。导致计数不准确;

错误2、引脚模式设置错误,应该设置为GPIO_Mode_IPD;//GPIO_Mode_IPU GPIO_Mode_IN_FLOATING 都可以;

错误3 引脚重映射没有开启AFIO时钟; 总结 关于编码器的溢出处理: 网上的检测数值突变的方法不可靠,会有漏检的情况。在滴答定时器中检测encoder的值突变

void SysTick_Handler(void) {// systick中断,1ms一次

static int encoder[2] = {0 , 0};// 两次编码器读值,用以计算溢出方向

static int N = 0;// 圈数

encoder[1] = TIM3->CNT;

if((encoder[1] - encoder[0] ) > 0x7FFF)

{ N--; }

else if( (encoder[0] - encoder[1] ) > 0x7FFF)

{ N++; }

EncCnt = N * 0xFFFF + encoder[1];

encoder[0] = encoder[1]; }

我采用了两种方法处理:一种是采用另一个定时器实时的检测溢出标志及方向标志,这种方法是可行的。即使速度很快的时候依然计数准确。但是出现了新的问题,用作定时器的时钟,当定时周期设置的很小的时候才可以计数准确,但是由于中断的优先级高,导致无法进入主循环程序。附上检测代码。这样的处理方法,在速度慢的时候可以检测正确。但是定时周期要设置足够小。CR1的bit4代表计数方向标志,1代表减二代表加;SR的bit0代表溢出中断标志,1代表溢出。该位是硬件置1软件清零。另一种是使用编码器溢出中断。中断的时候对编码器溢出方向进行判断,然后根据方向进行累加。


void TIM2_IRQHandler(void)

{

if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET )

{ TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);         
 encoder= TIM3->CNT;

      if((TIM3->CR1&0x10) == 0x10)//向下计数

      {          

           if(TIM3->SR&0x01 == 0x01)//tim3计数溢出

             {

                        TIM3->SR= TIM3->SR&0xFE;//sr的bit0清零

                        N--;
                 }                    
      }
      else if((TIM3->CR1&0x10) == 0x00)//向上计数
      {
           if(TIM3->SR&0x01 == 0x01)//tim3计数溢出
             {
                        TIM3->SR= TIM3->SR&0xFE;//sr的bit0清零
                        N++;
                 }                   
      }
          EncCnt= N * 65536 + TIM3->CNT;  
      //        encoder[0] = encoder[1];
   }                
复制代码

}


最后,我找到了更简单的检测编码器溢出中断并进行累计的方法。

其实当编码器的定时器溢出的时候,会导致进入中断。这样直接用编码器的中断函数即可。但是需要注意的是,需要在编码器的定时器配置的时候,配置中断。如果不配置,就会导致程序一运行就死机。一直停在DMA2_Channel4_5_IRQHandler这一句。

附上最终测试验证完成的代码

编码器初始化配置 ( 注意。如果不适用中断溢出的方法,无需配置

NVIC_InitStructure.NVIC_IRQChannel =TIM3_IRQn;

   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

这部分。。。)

并且我适用的是tim3重定义到pc7  pc6的。也可以使用部分重映射和默认引脚。

void EncoderTimInit()

{

//     对TIM_ICInitStructure的配置和对TIM_EncoderInterfaceConfig函数的使用实际上是冲突的,两个语句中的极性的设置是重复的

       //--------------1

       GPIO_InitTypeDefGPIO_InitStructure;

   TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

   TIM_ICInitTypeDef TIM_ICInitStructure;

   NVIC_InitTypeDef NVIC_InitStructure;

      

      

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能TIM3时钟

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//使能GPIOC时钟

       RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);  //AFIO时钟

      

       GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);       //TIM选择全复用功能使能

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;//PC6 PC7浮空输入

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//GPIO_Mode_IPU  GPIO_Mode_IN_FLOATING

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   GPIO_Init(GPIOC,&GPIO_InitStructure);

      

      

       TIM_DeInit(TIM3);       //TIM3初始化

   /* Timer configuration in Encoder mode */

   TIM_TimeBaseStructure.TIM_Prescaler = 0; // 不分频

   TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM3_PERIOD-1;  //计数40000  定时 T = 1/72000000 *40000 S=  1/1.8ms

   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//设置时钟分频系数:不分频

   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式

   TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

      

//     //编码配置                        编码模式   

   TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); //TIM_ICPolarity_Rising上升沿捕获

   TIM_ICStructInit(&TIM_ICInitStructure);       //输入捕获模式配置为硬件默认值

   TIM_ICInitStructure.TIM_ICFilter = 0x06;//ICx_FILTER;  //比较滤波器

   TIM_ICInit(TIM3, &TIM_ICInitStructure);//调用库函数把配置信息填充进去

 

   NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;

   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

   NVIC_Init(&NVIC_InitStructure);

 

//     TIM_ARRPreloadConfig(TIM3,ENABLE);

//     TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Disable);

 

       //Clear all pending interrupts

//     TIM_SetAutoreload(TIM3,0xffff);

       TIM_ClearFlag(TIM3,TIM_FLAG_Update);//清除TIM3的更新标志位

       TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//使能中断                                                                                                    

 

   //Reset counter  计数初始值

   TIM3->CNT = 0;

   TIM_Cmd(TIM3, ENABLE);

}

 

编码器计数模块

void TIM3_IRQHandler(void)

{     

       if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET)

   {

    TIM_ClearITPendingBit(TIM3 , TIM_FLAG_Update);

          if((TIM3->CR1&0x10) == 0x10)//向下计数

          {          

                     N--;               

          }

          else if((TIM3->CR1&0x10) == 0x00)//向上计数

          {

                     N++;            

          }

              EncCnt= N * 65536 + TIM3->CNT;        

   }           

}

注: N 和EncCnt变量最好定义为volatile

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。