打印

编码器的问题,求助!!!

[复制链接]
楼主: DownCloud
手机看帖
扫描二维码
随时随地手机跟帖
21
DownCloud|  楼主 | 2011-8-19 14:47 | 只看该作者 回帖奖励 |倒序浏览
8# 王奉瑾
谢谢你了,这倍频的方法太容易想到了,我的最大问题是抖动的问题!!!!!!还有对我来说不是小问题,而是非常大非常大的问题。再给点提示吧!

使用特权

评论回复
22
Cortex-M0| | 2011-8-19 14:48 | 只看该作者

RE: STM32学习笔记之正交编码器接口

最近做一个项目,主控芯片用STM32RBT6,要用到光栅尺,本来带一个控制器的,通过控制器的232可以读取光栅尺的数据,但这个控制器太大,设备中放不下,于是,考虑自己做一个,网上看到很多有用CPLD的方案,后来无意间发现stm32的定时器可以配置成编码器,甚喜

高兴之余,突然发现stm32的定时器是16位的,我的光栅尺的计数会超过65535,于是在21ic论坛上和几位高手请教,最终确定的方案

工作过程是配置TIM3为正交编码器模式,并定一个10ms的中断,每10ms读取一次计数值,10ms的前提是在10ms内计数器不溢出(这个思想要感谢21ic的lxyppc)

以下是部分代码:(这些代码修改于ST官方的例程,但我的工程用的是V3的固件库,他们的例程貌似是0.3的,所以有些地方有改动)

下面是初始化TIM3为正交编码器模式

void ENC_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;

/* Encoder unit connected to TIM3, 4X mode */   
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

/* TIM3 clock source enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* Enable GPIOA, clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

GPIO_StructInit(&GPIO_InitStructure);
/* Configure PA.06,07 as encoder input */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Enable the TIM3 Update Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = TIMx_PRE_EMPTION_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = TIMx_SUB_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

/* Timer configuration in Encoder mode */
TIM_DeInit(ENCODER_TIMER);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // No prescaling
TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   
TIM_TimeBaseInit(ENCODER_TIMER, &TIM_TimeBaseStructure);

TIM_EncoderInterfaceConfig(ENCODER_TIMER, TIM_EncoderMode_TI12,
                             TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = ICx_FILTER;
TIM_ICInit(ENCODER_TIMER, &TIM_ICInitStructure);

// Clear all pending interrupts
TIM_ClearFlag(ENCODER_TIMER, TIM_FLAG_Update);
TIM_ITConfig(ENCODER_TIMER, TIM_IT_Update, ENABLE);
//Reset counter
TIM2->CNT = COUNTER_RESET;

// ENC_Clear_Speed_Buffer();

TIM_Cmd(ENCODER_TIMER, ENABLE);
}

以下为获取一次计数值,此算法来自lxyppc,可以规避超过16位的情况,具体细节见https://bbs.21ic.com/viewthread.php?tid=110623的讨论

s16 ENC_Get_Electrical_Angle(void)
{
static u16   lastCount = 0;
u16 curCount = ENCODER_TIMER->CNT;
s32 dAngle = curCount - lastCount;
if(dAngle >= MAX_COUNT){
    dAngle -= ENCODER_TIM_PERIOD;
}else if(dAngle < -MAX_COUNT){
    dAngle += ENCODER_TIM_PERIOD;
}
lastCount = curCount;
return (s16)dAngle;
}

以下为系统滴答的初始化和中断函数

void TB_Init(void)
{   
/* Setup SysTick Timer for 10 msec interrupts */
if (SysTick_Config(SystemFrequency / 100))
{
    /* Capture error */
    while (1);
}
}

void SysTick_Handler(void)
{   
/*if (hTimebase_display_500us != 0)
{
    hTimebase_display_500us --;
}
   */
if (hSpeedMeas_Timebase_500us !=0)
{
    hSpeedMeas_Timebase_500us--;
}
else
{
    hSpeedMeas_Timebase_500us = SPEED_SAMPLING_TIME;

    CurrentCount += ENC_Get_Electrical_Angle();
        
    //ENC_Calc_Average_Speed must be called ONLY every SPEED_MEAS_TIMEBASE ms
    //ENC_Calc_Average_Speed();   
}
}

以上代码已通过测试,固件库版本为:V3.1.2
ST官方例程和中文说明文档:http://www.st.com/internet/com/home/home.jsp

http://images.stmicroelectronics ... 32F10xxx_Encoder_AN(CH).zip

最后抱怨一句,st为啥不把定时器做成32位的呢,能增加1分钱成本吗?

转自:http://www.52solution.com/bbs/redirect.php?tid=1092&goto=lastpost

使用特权

评论回复
23
DownCloud|  楼主 | 2011-8-19 14:48 | 只看该作者
本帖最后由 DownCloud 于 2011-8-19 15:06 编辑

12# Cortex-M0
大侠,就不要嘲笑我了,我已经道歉了。真心望你帮忙解决此问题。
已经看到了,谢谢

使用特权

评论回复
24
DownCloud|  楼主 | 2011-8-19 14:52 | 只看该作者
9# Cortex-M0
谢谢。哪里事半功倍啊,对我一点提示都木有。

使用特权

评论回复
25
dengm| | 2011-8-19 14:59 | 只看该作者
如速度高可用
gal16v8做的硬件解码
把2位的格雷码扩大到8位的格雷码接入 单片机的 8 位端口
用软件定时采样, 再查表变为 Binary

使用特权

评论回复
26
沈老| | 2011-8-19 15:00 | 只看该作者
一般现在做单片机板时都加一个CPLD,如果你有就叫CPLD来完成计数。
包括方向识别,2,4倍频,窄脉冲抑制。

使用特权

评论回复
27
DownCloud|  楼主 | 2011-8-19 15:05 | 只看该作者
24# Cortex-M0
大虾不愧是大虾,非常感谢你的硬件的方法,现在坐等软件解决方案!

使用特权

评论回复
28
Cortex-M0| | 2011-8-19 15:06 | 只看该作者
9# Cortex-M0  
谢谢。哪里事半功倍啊,对我一点提示都木有。
DownCloud 发表于 2011-8-19 14:52


汗~~~  :L

二姨家大名顶顶的老王,前来指点,对您一点帮助都没有吗?

使用特权

评论回复
29
DownCloud|  楼主 | 2011-8-19 15:08 | 只看该作者
30# Cortex-M0
透露的太不明显了啊!!!:P

使用特权

评论回复
30
DownCloud|  楼主 | 2011-8-19 15:10 | 只看该作者
28# 沈老
嗯,非常感谢,硬件方法通过你们已经有所了解,收获不少。会自己再去查资料学习的!

使用特权

评论回复
31
dengm| | 2011-8-19 15:11 | 只看该作者
前端加cd40106 or 74hc14

   ---->-----10k-----+-----40106---->---- P3.2/P3.3
                             |
                          =+=  102
                          =+=
                             |
                            地

使用特权

评论回复
32
DownCloud|  楼主 | 2011-8-19 15:12 | 只看该作者
27# dengm
嗯,非常感谢,硬件方法通过你们已经有所了解,收获不少。会自己再去查资料学习的!

使用特权

评论回复
33
Cortex-M0| | 2011-8-19 15:20 | 只看该作者
12# Cortex-M0  
大侠,就不要嘲笑我了,我已经道歉了。真心望你帮忙解决此问题。
DownCloud 发表于 2011-8-19 14:48


俺一个小虾米,哪敢嘲笑您啊,事实上,你的贴子哪是请教啊,分明是考试,把二姨家的大虾们都吓跑了~~~

没有一个大虾能帮您解这世界级难题,什么原因呢?作为命题,总有一大堆前提条件,如编码器分辨率,最高运转速度(折合最高计数频率),硬件接口,所用单片机型号,等等等等啦。。。。。。

这样的命题才有解啊~~~

现在您出的题目,除了神仙,能知道您在想些什么,否则哪个大虾能解?

除了沉默,就是打酱油,请朋友的朋友(循环N遍),来帮您解决不是问题的问题~~~

使用特权

评论回复
34
dqyubsh| | 2011-8-19 15:32 | 只看该作者
既然你说一定要有抖动(凭什么啊,我 日),OK,那就按有抖动的说。如果就按你说的用软件处理,一个接中断,一个接IO,而且在抖动时中断一直发生,快到让你都来不及处理,即,进了中断,没等处理完,下次中断又重入了。抖着抖着计数就不准了。如果情况确实是这样,说明一个道理——你的单片机根本完成不了这种事。

你可以数一下你的中断多少条指令,占用多少个机器周期,这个周期就是你的死结。你不可能处理比这个周期还快的事件。而且,处理完的计数,最后会求取长度、速度,还要显示,要交换,要处理键盘,这些你都想过没有?

事实上,在生产过程中,我们用过每米720和1280个脉冲的编码器,如果移动速度500米/小时,很慢,这时候也许单片机能行;如果操作员把速度提到20000米/小时以上,估计你的单片机就OVER了。

做项目,不仅要满足常规条件下使用,更要应付这些不按常规操作的操作。即,你的设计要有足够的余量,应付不时之需。这种情况下,最可靠的方式就是——不用单片机干这事,用硬件实现。

20年前,8031的年代,这事这样干:用逻辑芯片、GAL(或CPLD)等把A/B处理成两个信号,一个脉冲,一个方向,然后用8253数计数,单片机判断方向。

前几年,我用国外的正交编码的计数器芯片,直接数出脉冲个数。它自动处理脉冲和方向,存入32位计数器,最高支持40Mhz的脉冲输入。可以说这个速度已经完全足够了。我用单片机访问这个计数器就可以了,它做完了一切。

目前,个别单片机已经有了可以直接处理正交编码的功能,包括楼上说的ST,以及TI的28xx。

可以说,单纯地使用软件处理的方案,我不会采用。我一直认为,单片机仅仅是个玩具,完成项目最大的障碍就是单片机的资源永远贫乏,受制于速度、接口能力、稳定性。任何在这个位置节省钱财的设计,我都不会推崇。

说这么多,就是强调一点,硬件、模拟电路会解决你用软件很难解决的问题,用软件防抖,说说就算了,没有硬件来的靠谱。如果在学校,老师一定让你这么干,你可以弄一个糊弄一下老师,在现场,拉倒吧,踏踏实实做自己的认为最正确的。

使用特权

评论回复
评分
参与人数 2威望 +2 收起 理由
触觉的爱 + 1
Cortex-M0 + 1
35
DownCloud|  楼主 | 2011-8-19 15:42 | 只看该作者
35# Cortex-M0
考试?您言重了。你前面说这是小号都排不上的问题。现在又这样说,我不知为何。当然你的解决方案我觉得应该是没问题的。我用的是51或者avr,当然还处在初学阶段(被您这样的高手打击我也觉得很习惯),我不大懂arm见识也少所以你的方法还是让我学到了很多东西。

使用特权

评论回复
36
dqyubsh| | 2011-8-19 15:44 | 只看该作者
33楼前端加CD40xx的方法比较靠谱,用上拉电阻将A/B信号拉到电源,这对提高输入阻抗大有好处。而且,CD系列可以适应不同供电电压的编码器,如5V,国外常见的10V/12V。

使用特权

评论回复
37
t.jm| | 2011-8-19 15:56 | 只看该作者
编码器应该是抗干扰能力最强的,LZ出现风吹都会计数的本质原因是:正常的编码器变化1个CLICK会产生4个事件(A,B各产生1个下降沿,1个上升沿),而LZ只用其中的1个事件来判断当然容易产生误判啦。

使用特权

评论回复
38
Cortex-M0| | 2011-8-19 16:01 | 只看该作者
35# Cortex-M0  
考试?您言重了。你前面说这是小号都排不上的问题。现在又这样说,我不知为何。当然你的解决方案我觉得应该是没问题的。我用的是51或者avr,当然还处在初学阶段(被您这样的高手打击我也觉得很习惯) ...
DownCloud 发表于 2011-8-19 15:42


呵呵!

俺的意思是您出题不清,不打不相识,给个dengm大虾的经典A/B相计数程序。

EX_INT0:
    Push acc
    DB 0,0,0,0
    MOV A, P3
    ANL A, #00001100B
    JZ L_INT_10
       XRL A, #00000100B
       JNZ L_INT_8
          CLR  F_DIR
L_INT_8:
          POP ACC
          RETI
L_INT_10:
   SETB F_DIR
   POP ACC
   RETI

使用特权

评论回复
39
DownCloud|  楼主 | 2011-8-19 16:01 | 只看该作者
38# dqyubsh
遇到高手,我也觉得硬件确实比较靠谱。不过抖动确实是真实的存在的,这是真实发生过的事,测量长度,设备静止不动,然后计数值一直增加或者一直减小。

使用特权

评论回复
40
dengm| | 2011-8-19 16:03 | 只看该作者
软件:    用p3.2 门控, Timer0 , 上/下边缘都中断

$MOD51
   c_Delay equ 10 ; 延时采样
   f_DIR BIT 20H.0
   CntL   data 30h
   CntH   data 31h
   
   ORG 0000H
     NOP
     AJMP START

   ORG 0003H ; INT 0
     MOV TL0, #(256-c_Delay)
     SETB TR0     
     RETI
     
   ORG 000BH ; TIMER 0
     CLR TR0
     JB P3.3, L_up  
       SJMP L_DN

   ORG 0050H
L_UP:
     SETB F_DIR
     INC CntL
     XCH A, CntL
     JNZ $+4
       INC CntH
     SJMP L_UP_DN_EX

L_DN:
    CLR F_DIR
    XCH A, CntL
    JNZ $+4
      DEC CntH
    DEC A

L_UP_DN_EX:
    XCH A, CntL

    RETI


START:
; Configure Timer 0
;    - Mode     = 2 ; - Interrupt= ENABLED
;    - Clock Source = INTERNAL
;    - Enable Gating Control  = ENABLED
      anl   TMOD, #0F0H                  ;clear Timer 0
      orl   TMOD, #0Ah  ;
      mov   TL0,  #(256-c_Delay) ;value set by user
      mov   TH0,  #0 ;value set by user
      SETB ET0
        
      SETB IT0 ;边缘
      SETB EX0
      
      SETB EA
;-------------------------------
MainLoop:
     nop
     nop
     sjmp MainLoop  
                    
            
      end

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则