极海F103定时器支持编码器接口,适合应用于对于电机位置要求较为严格的应用场景。对于客户采样控制十分便利。
编码器接口(Encoder Interface),可以接收正交编码器(又称为增量编码器)的信号,根据编码器旋转产生的正交信号脉冲,自动由硬件电路控制定时器时基单元中的计数器CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度。从原理上看,编码器接口输出的信号相当于一个带方向控制的外部事件,同事控制CNT的计数时钟和计数方向。这时,CNT的值就代表了编码器的位置。如果每隔一段时间将CNT的值取出并清0,我们就能得到编码器在这一段时间内的旋转速度(注意,不是旋转速率,这里的速度只与这段时间的长短和始末位置有关),思路与测频法测正交脉冲的频率相似,只不过这里的计数器的计数方向由编码器接口决定。
编码器接口借用了定时器的CH1和CH2通道,与CH3和CH4无关。且输入捕获前端的输入滤波和极性选择部分也有使用。编码器接口的输出部分,相当于一个从模式控制器,控制CNT的自增和自减。此时72MHz内部时钟和时基单元初始化时设置的计数方向都处于失效的状态,因为此时的计数时钟和计数方向都处于编码器接口托管的状态。 所以当一个定时器被配置为编码器接口模式,这个定时器就很难完成其他工作了,因为编码器接口直接控制时基单元的时钟来源。
如下为编码器基于APM32F103的应用代码,仅供参考
/** Enable GPIOA Periph Clock */
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOD);
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_AFIO);
配置编码器A/B/Z项 输入管脚
/** Config GPIO */
gpioConfig.pin = GPIO_PIN_12 | GPIO_PIN_13|GPIO_PIN_14;
gpioConfig.mode = GPIO_MODE_IN_PU;
gpioConfig.speed = GPIO_SPEED_50MHz;
GPIO_Config(GPIOA,&gpioConfig);
/** Config GPIOA Alernate Function for TMR1 */
GPIO_ConfigPinRemap(GPIO_REMAP_TMR4);
RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR4);
/** Config TMR1 */
baseConfig.clockDivision = TMR_CLOCK_DIV_1;
baseConfig.countMode = TMR_COUNTER_MODE_UP;
baseConfig.division = 0;
baseConfig.period = (4 * 1024) - 1; //根据编码器线数配置计数值
baseConfig.repetitionCounter = 0;
TMR_ConfigTimeBase(TMR4, &baseConfig);
/** Encoder */ 配置编码器边沿计数模式
TMR_ConfigEncodeInterface(TMR4,TMR_ENCODER_MODE_TI12,TMR_IC_POLARITY_BOTHEDGE,TMR_IC_POLARITY_BOTHEDGE);
/** Input Capture */
ICConfig.channel = TMR_CHANNEL_1;
ICConfig.polarity = TMR_IC_POLARITY_BOTHEDGE;
ICConfig.selection = TMR_IC_SELECTION_DIRECT_TI;
ICConfig.prescaler = TMR_IC_PSC_1;
ICConfig.filter = 0;
TMR_ConfigIC(TMR4,&ICConfig);
ICConfig.channel = TMR_CHANNEL_2;
TMR_ConfigIC(TMR4,&ICConfig);
ICConfig.channel = TMR_CHANNEL_3;
ICConfig.polarity = TMR_IC_POLARITY_RISING;
ICConfig.selection = TMR_IC_SELECTION_DIRECT_TI;
ICConfig.prescaler = TMR_IC_PSC_1;
ICConfig.filter = 0;
TMR_ConfigIC(TMR4,&ICConfig);
TMR_ReadIntFlag(TMR4, TMR_INT_CC3);
/** Counter */
TMR_ConfigCounter(TMR4,0x0000);
TMR_ClearStatusFlag(TMR4,TMR_FLAG_UPDATE);
TMR_ClearStatusFlag(TMR4,TMR_FLAG_CC3);
TMR_EnableInterrupt(TMR4, TMR_INT_UPDATE);
NVIC_EnableIRQRequest(TMR4_IRQn, 0, 0);
TMR_Enable(TMR4);
//中断处理,当计数值触发定时器更新中断时,通过判断计数方向,来判断正反转;同时,若Z相有电平触发则判断已经转过一圈了,重新对定时器计数清0,进行零点校准后技术,这里也可以用外部中断方式来对Z相进行判断。
void TMR4_IRQHandler(void)
{
if(TMR_ReadIntFlag(TMR4,TMR_INT_UPDATE)==1)
{if((TMR4->CTRL1_B.CNTDIR)!=0)
{
circle_count--;
}
else
{
circle_count++;
}
printf("circle_count: %08x\r\n", encoderNum);
TMR_ConfigCounter(TMR4,0x0000);
TMR_ClearIntFlag(TMR4,TMR_FLAG_UPDATE);
}
if (TMR_ReadIntFlag(TMR4,TMR_INT_CC3)==1)
{
TMR4->CNT=0;
TMR_Enable(TMR4);
TMR_ClearIntFlag(TMR4,TMR_FLAG_CC3);
}
}
|