46053|95

1412

帖子

15

TA的资源

版主

楼主
 

【新年首发】利用STM32编码器进行任意位置确定 [复制链接]

 
本帖最后由 youki12345 于 2015-2-19 23:20 编辑

       车轮位置的确定是在制作小车的过程中必不可少的部件,好在STM32中包含了硬件的编码器。但使用的过程中却存在诸多不方便。下面由我一一道来:
      1。编码器原理
       什么是正交?如果两个信号相位相差90度,则这两个信号称为正交。由于两个信号相差90度,因此可以根据两个信号哪个先哪个后来判断方向、根据每个信号脉冲数量的多少及整个编码轮的周长就可以算出当前行走的距离、如果再加上定时器的话还可以计算出速度。
       2。为什么要用编码器
      
       从上图可以看出,由于TI,T2一前一后有个90度的相位差,所以当出现这个相位差时就表示轮子旋转了一个角度。但有人会问了:既然都是脉冲,为什么不用普通IO中断?实际上如果是轮子一直正常旋转当然没有问题。仔细观察上图,如果出现了毛刺呢?这就是需要我们在软件中编写算法进行改正。于是,我们就会想到如果有个硬件能够处理这种情况那不是挺好吗?
    3. STM32编码器
   
     还是刚才那张图,但这时候我们看到STM32的硬件编码器还是很智能的,当T1,T2脉冲是连续产生的时候计数器加一或减一一次,而当某个接口产生了毛刺或抖动,则计数器计数不变,也就是说该接口能够容许抖动。在STM32中,编码器使用的是定时器接口,通过数据手册可知,定时器1,2,3,4,5和8有编码器的功能,而其他没有。编码器输入信号TI1,TI2经过输入滤波,边沿检测产生TI1FP1TI2FP2接到编码器模块,通过配置编码器的工作模式,即可以对编码器进行正向/反向计数。如果用的是定时器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,这个返回值用于本次里程的计算,给总里程用
}
         每次把中断的次数记录下来,然后再把距离上次中断共走了多少个脉冲,再把两者相加即可。







此帖出自stm32/stm8论坛

最新回复

楼主,想问一下,如果STM32配置成了编码器接口,如何可靠的测试低转速的速度呢?一般是用周期法测低转速,这需要精确测试两个编码器脉冲之间的时间来计算转速。这时候又不能使用触发中断了   详情 回复 发表于 2020-6-1 23:24

赞赏

3

查看全部赞赏

点赞 关注(17)
个人签名https://bbs.eeworld.com.cn/thread-471646-1-1.html
欢迎加入我的团队
 

回复
举报

4008

帖子

0

TA的资源

版主

推荐
 
本帖最后由 huo_hu 于 2015-2-22 15:52 编辑

好的,我来补充一下,
1.编码器有个转速上限,超过这个上限是不能正常工作的,这个是硬件的限制,原则上线数越多转速就越低,这点在选型时要注意,编码器的输出一般是开漏的,所以单片机的io一定要上拉输入状态.
2.定时器初始化好以后,任何时候CNT寄存器的值就是编码器的位置信息,正转他会加反转他会减这部分是不需要软件干预的,初始化时给的TIM_Period 值应该是码盘整圈的刻度值,在减溢出会自动修正为这个数.加超过此数值就回0.
3.如果要扩展成多圈计数需要溢出中断像楼主说的,程序上圈计数加减方向位就行了.
4.每个定时器的输入脚可以通过软件设定滤波
5.应用中如果没有绝对位置信号或者初始化完成后还没有收到绝对位置信号前的计数只能是相对计数.收到绝对位置信号后重新修改一次CNT的值就行了.码盘一般都有零位置信号,结合到定时器捕获输入就行.上电以后要往返运动一下找到这个位置.
6.即便有滤波计数值偶尔也会有出错误的情况,一圈多计一个或少计一个数都是很正常的特别是转速比较高的时候尤其明显,有个绝对位置信号做修正是很有必要的.绝对位置信号不需要一定在零位置点,收到这个信号就将CNT修正为一个固定的数值即可.
7.开启定时器的输入中断可以达到每个步计数都作处理的效果,但是高速运转的时候你可能处理不过来.



此帖出自stm32/stm8论坛

点评

有几个细节麻烦解答下: 1、编码器所谓一圈x个脉冲,是指的上下脉冲数,还是只是上升沿或下降沿的个数? 2、stm32设为上下脉冲计数,按他的表格,不是一会儿(上升)加数一会儿(下降)减数,最终为0了吗? 3、那  详情 回复 发表于 2017-9-12 12:02
请教版主:“开启定时器的输入中断可以达到每个步计数都作处理的效果” 定时器的输入中断如何设置?  详情 回复 发表于 2017-1-20 13:24
关于第6点,如果转速不高,STM32的硬件完全能应付过来,这种情况下是不是就不会多计数或者少计数了?  详情 回复 发表于 2016-1-6 09:32
 
 

回复

360

帖子

0

TA的资源

纯净的硅(初级)

沙发
 
謝謝你的詳細解說
此帖出自stm32/stm8论坛
 
 

回复

1080

帖子

2

TA的资源

五彩晶圆(中级)

板凳
 
LZ总结的不错~~~~~~~~~~~~~~~
此帖出自stm32/stm8论坛
 
 
 

回复

110

帖子

0

TA的资源

一粒金砂(中级)

4
 
顶LZ,写的真好
此帖出自stm32/stm8论坛
 
 
 

回复

165

帖子

0

TA的资源

一粒金砂(中级)

5
 
虽然看不懂,但还是看完了。
此帖出自stm32/stm8论坛

点评

哪个地方看不懂?估计没写好。。。  详情 回复 发表于 2015-2-20 13:15
 
 
 

回复

1412

帖子

15

TA的资源

版主

6
 
哪个地方看不懂?估计没写好。。。
此帖出自stm32/stm8论坛

点评

是我的问题,对这个没什么概念,没接触过。  详情 回复 发表于 2015-2-20 13:18
 
 
 

回复

165

帖子

0

TA的资源

一粒金砂(中级)

7
 
youki12345 发表于 2015-2-20 13:15
哪个地方看不懂?估计没写好。。。



是我的问题,对这个没什么概念,没接触过。
此帖出自stm32/stm8论坛
 
 
 

回复

1万

帖子

25

TA的资源

裸片初长成(高级)

8
 
写得很不错的。

STM32的正交解码使用TIM同样可以达到专用解码器的功能。
此帖出自stm32/stm8论坛
 
 
 

回复

2886

帖子

0

TA的资源

五彩晶圆(初级)

9
 
讲解的很详细
此帖出自stm32/stm8论坛
 
 
 

回复

793

帖子

8

TA的资源

纯净的硅(中级)

10
 
顶楼主,谢谢分享。
此帖出自stm32/stm8论坛
 
 
 

回复

1412

帖子

15

TA的资源

版主

11
 
过讲了,嘿嘿!
此帖出自stm32/stm8论坛
 
 
 

回复

1453

帖子

18

TA的资源

纯净的硅(高级)

12
 
楼主写的很详细,抽空坐下来慢慢学习
此帖出自stm32/stm8论坛

点评

谢谢哈!!?  详情 回复 发表于 2015-2-25 18:54
 
 
 

回复

1412

帖子

15

TA的资源

版主

14
 
1.编码器有个转速上限,

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
请教这个上限如何看,是哪个参数?以前还真没注意这个。

另外,现在越来越多的编码器不是开漏的啦。
此帖出自stm32/stm8论坛
 
个人签名https://bbs.eeworld.com.cn/thread-471646-1-1.html
欢迎加入我的团队
 
 

回复

1412

帖子

15

TA的资源

版主

15
 
谢谢哈!!?
此帖出自stm32/stm8论坛
 
 
 

回复

6

帖子

0

TA的资源

一粒金砂(初级)

16
 
如果不用中断能够达到这样的效果吗?我直接用的是另一个定时器做为定时中断来检测移动的位移可以吗?
此帖出自stm32/stm8论坛

点评

可以,但是精度会差一点  详情 回复 发表于 2015-5-14 22:02
 
 
 

回复

1412

帖子

15

TA的资源

版主

17
 
zouyanrong 发表于 2015-5-12 14:07
如果不用中断能够达到这样的效果吗?我直接用的是另一个定时器做为定时中断来检测移动的位移可以吗?

可以,但是精度会差一点

此帖出自stm32/stm8论坛
 
个人签名https://bbs.eeworld.com.cn/thread-471646-1-1.html
欢迎加入我的团队
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

18
 
正好需要需要哈,谢谢了
此帖出自stm32/stm8论坛
 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

19
 
顶楼主,写的真好
此帖出自stm32/stm8论坛
 
 
 

回复

15

帖子

1

TA的资源

一粒金砂(中级)

20
 
楼主我用的是F4 开发板中 使用TIM4 I/0口 PB6、PB7,设置 都跟你一样为什么 CNT值一直未0 不变化呢?
此帖出自stm32/stm8论坛

点评

首先确保外部电路连接正常了,你用示波器看看编码器转的时候是否有高低电平输出。然后再考虑代码。 代码的话用网上的就行,转转编码器就会变化。  详情 回复 发表于 2015-10-24 12:20
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表