干货 | 一文让你通晓STM32编码器

车轮位置的确定是在制作小车的过程中必不可少的部件,好在STM32中包含了硬件的编码器。但使用的过程中却存在诸多不方便。下面由我一一道来:

1、编码器原理

什么是正交?如果两个信号相位相差90度,则这两个信号称为正交。由于两个信号相差90度,因此可以根据两个信号哪个先哪个后来判断方向、根据每个信号脉冲数量的多少及整个编码轮的周长就可以算出当前行走的距离、如果再加上定时器的话还可以计算出速度。

2、为什么要用编码器

从上图可以看出,由于TI,T2一前一后有个90度的相位差,所以当出现这个相位差时就表示轮子旋转了一个角度。但有人会问了:既然都是脉冲,为什么不用普通IO中断?实际上如果是轮子一直正常旋转当然没有问题。仔细观察上图,如果出现了毛刺呢?这就是需要我们在软件中编写算法进行改正。于是,我们就会想到如果有个硬件能够处理这种情况那不是挺好吗?

3、STM32编码器

还是刚才那张图,但这时候我们看到STM32的硬件编码器还是很智能的,当T1,T2脉冲是连续产生的时候计数器加一或减一一次,而当某个接口产生了毛刺或抖动,则计数器计数不变,也就是说该接口能够容许抖动。在STM32中,编码器使用的是定时器接口,通过数据手册可知,定时器1,2,3,4,5和8有编码器的功能,而其他没有。编码器输入信号TI1,TI2经过输入滤波,边沿检测产生TI1FP1,TI2FP2接到编码器模块,通过配置编码器的工作模式,即可以对编码器进行正向/反向计数。如果用的是定时器3,则对应的引脚是在PA6和PA7上。根据stmn32手册上编码器模式的说明,有6中组合计数方式,见下表。

由此可知,通过选择可以确定使用定时器的哪种方式来得到我们所要的结果。STM32编码器的使用也非常简单,其基本步骤和开发STM32其他部件的操作一致,都是打开时钟,配置接口,配置模式,如果要用中断则打开中断。具体可以参考以下代码(这里使用的是TIM4,引脚采用GPIOA 11和GPIOA12):

bool EncodeInit(u8 none1,u32 period)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
  TIM_ICInitTypeDef TIM_ICInitStructure;  
  GPIO_InitTypeDef GPIO_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  EXTI_InitTypeDef   EXTI_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//??TIM3??
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);//??GPIOA??
    
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
    
   GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_10);
  GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_10);
    
   TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // No prescaling 
  TIM_TimeBaseStructure.TIM_Period = 1333; 
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   
  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
  
    TIM_ICStructInit(&TIM_ICInitStructure);
    TIM_ICInitStructure.TIM_ICFilter = 10;
     TIM_ICInit(TIM4, &TIM_ICInitStructure);
  
  // Clear all pending interrupts
  TIM_ClearFlag(TIM4, TIM_FLAG_Update);
  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);

//Reset counter
  TIM_SetCounter(TIM4,0);
  TIM_Cmd(TIM4, ENABLE); 
    
     return 0;
}

4、编码器的中断

由于编码器是基于定时器的,所以编码器的中断实际上就是定时器的中断啦。也就是说定时器是每隔一定时间加一个数(或减一个数 ),当数到达预设值时就产生中断,而编码器是每一个有效脉冲就加一个数(或减一个数 ),当数到达预设值时就产生中断。若预设值为1000则编码器与定时器中断不同的是,当编码器反转时值到达999产生一次中断,而当编码器正转到达0时同样产生一次中断。在硬件上这两个中断是没法区分的,这也就造成了有种情况的误判。

5、STM32编码器没有考虑的情况

想象一下,如果编码器的预设值为1000,当某次我们使得编码器正转产生中断后,立即反转则又该怎么办呢?根据上面的说法,这时候会产生两次一样的中断。如果在算法上没有处理的话,极有可能认为是行走了两次正向。但实际上并没有。所以这个时候必须结合方向来判断行走的情况(判断方向使用的是DIR寄存器位)或者在产生中断后读一次count寄存器位(看看是999还是0,以此来判断当前的方向)。只有上一次为正且这一次同样为正,距离才是相加的。
具体中断处理函数代码如下:

void TIM4_IRQHandler(void)
{
    temp=(TIM_GetCounter(TIM4)&0xffff);    
if(TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
  {    
        if(temp==9999)
            {    
              count--;
                if(predir==0)//只有当前一次是负向走,这一次还是负向走才上传数据
                {
                    upcount--;
                
                }else{
                    predir=0;//表示往负向走      
              }
            }else if(temp==0)
            {
              count++;
                if(predir==1)//只有当前一次是正向走,这次又是正向走才上传数据
                {
                    upcount++;
                }else{
                    predir=1;//表示往正向走
                }
            }
      
        }    
         
        
            TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
  }else{
        #ifdef DEBUG
         printf("ENCODE TIMER INTERRUP ERROR! \n");
    #endif
        while(1)
        {
            ;
        }
  }

6、最后一个问题

那么如果当前并没有到一个中断怎么办?难道这个时候就不能得到编码器的精确位置了吗?

其实只是个非常简单的算法:

u32 EncodeGetMileage(u8 none1,u8 none2)
{  
      u8 i=0;
      temp=(TIM_GetCounter(TIM4)&0xffff);
                if(count<0)
                {
                     temp_mileage=(abs(count)-1)*1000 +(1000-temp);

}else{
                    temp_mileage=count*1000 +temp;
                }
        } 
     
        return temp_mileage; //返回编码器的脉冲个数,一个脉冲相当于125/1333 mm,这个返回值用于本次里程的计算,给总里程用
}

每次把中断的次数记录下来,然后再把距离上次中断共走了多少个脉冲,再把两者相加即可。

(0)

相关推荐

  • HC-SR04超声波测距原理及实现

    HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可达3mm: 模块包括超声波发射器.接收器与控制电路. 在智能小车的测距.避障,盲人拐杖,视力保护器(坐姿矫正),倒 ...

  • 早读 | 珍藏版:超清动图演示肩关节的体格检查(全),满分干货好文!

    尽管各式各样的诊断设备不断应用于临床,但体格检查始终是疾病诊断的关键,而解剖是体格检查的基础!对于肩关节而言,我们不但要熟知肩峰前后角.锁骨远端.喙突等重要的骨性标志,还要熟悉肩袖及肱二头肌等肌肉肌腱 ...

  • 干货 | 一文看懂中华兵器史

    Cold Arms 石兵器时代 1.旧石器时代的石兵 原始人类工兵不分,石器就是石兵,用作生产生活就是石器,用作格斗就是石兵.下图是周口店"北京人"使用的石器. 2.新石器时代的石 ...

  • 干货 | 一文整理所有常考的中国能源问题!

    能源问题 1.我国能源利用的现状:以煤炭为主,利用石油.天然气,积极发展水电,稳妥发展核电,因地制宜发展太阳能.风能.沼气.地热能.海洋能等. 2.我国能源消费利用变化特点:煤炭比例下降,石油.天然气 ...

  • 精选干货 | 一文看懂文献综述的写作结构、方法、步骤与常见问题

    文献综述也称研究综述,是指在全面掌握.分析某一学术问题(或研究领域)相关文献的基础上,对该学术问题(或研究领域)在一定时期内已有研究成果.存在问题进行分析.归纳.整理和评述而形成的论文. 文献综述一般 ...

  • 纯干货!一文搞懂申请解除保全如何操作|保全与执行

    原创声明 今日推送文章,为文章作者授权本公众号原创文章,转载请在公众号醒目位置注明作者及出处.我们将不断创新文章内容,努力提供更多更好的保全与执行实务干货.转载请直接联系责任编辑. 财产保全的解除及注 ...

  • 珍藏版:超清动图演示肩关节的体格检查(全),满分干货好文!

    尽管各式各样的诊断设备不断应用于临床,但体格检查始终是疾病诊断的关键,而解剖是体格检查的基础!对于肩关节而言,我们不但要熟知肩峰前后角.锁骨远端.喙突等重要的骨性标志,还要熟悉肩袖及肱二头肌等肌肉肌腱 ...

  • 干货 | 一文搞懂文件系统

     1.概述        文件系统是操作系统用于明确存储设备(常见的是磁盘,也有基于NAND Flash的固态硬盘)或分区上的文件的方法和数据结构:即在存储设备上组织文件的方法.操作系统中负责管理和存 ...

  • 干货好文!区域曝光法原来这么简单!

    安塞尔·亚当斯 美国著名摄影家安塞尔·亚当斯的区域曝光理论,是半个多世纪以来摄影科学的基本理论之一. 区域曝光系统是一个极其有用的摄影方法,一旦掌握了这种方法,甚至是初学摄影者也能像经验丰富的老手一样 ...

  • 干货 | 一文轻松搞定MSA

    最新课程 测量系统分析(Measurement Systems Analysis,MSA) 数据是通过测量获得的,对测量定义是:测量是赋值给具体事物以表示他们之间关于特殊特性的关系.这个定义由C.Ei ...