选择编码器接口模式的方法是:如果计数器只在TI2的边沿计数,则置TIMx_SMCR寄存器中的
SMS=001;如果只在TI1边沿计数,则置SMS=010;如果计数器同时在TI1和TI2边沿计数,则
置SMS=011
TI1FP1和TI2FP2
是TI1和TI2在通过输入滤波器和极性控制后的信号;如果没有滤波和变相,则TI1FP1=TI1,
TI2FP2=TI2。根据两个输入信号的跳变顺序,产生了计数脉冲和方向信号。依据两个输入信号
的跳变顺序,计数器向上或向下计数,同时硬件对TIMx_CR1寄存器的DIR位进行相应的设置。
不管计数器是依靠TI1计数、依靠TI2计数或者同时依靠TI1和TI2计数,在任一输入端(TI1或者
TI2)的跳变都会重新计算DIR位。
编码器接口模式基本上相当于使用了一个带有方向选择的外部时钟。这意味着计数器只在0到
TIMx_ARR寄存器的自动装载值之间连续计数(根据方向,或是0到ARR计数,或是ARR到0计
数)。所以在开始计数之前必须配置TIMx_ARR;同样,捕获器、比较器、预分频器、重复计数
器、触发输出特性等仍工作如常。编码器模式和外部时钟模式2不兼容,因此不能同时操作。
在这个模式下,计数器依照增量编码器的速度和方向被自动的修改,因此计数器的内容始终指
示着编码器的位置。计数方向与相连的传感器旋转的方向对应。下表列出了所有可能的组合,
假设TI1和TI2不同时变换
表73 计数方向与编码器信号的关系
226/754
相对信号的电平 (TI1FP1对应TI2, TI2FP2对应TI1) |
TI1FP1信号 |
TI2FP2信号 |
有效边沿 |
上升 |
下降 |
上升 |
下降 |
高 |
向下计数 |
向上计数 |
不计数 |
不计数 |
仅在TI1计数 |
低 |
向上计数 |
向下计数 |
不计数 |
不计数 |
高 |
不计数 |
不计数 |
向上计数 |
向下计数 |
仅在TI2计数 |
低 |
不计数 |
不计数 |
向下计数 |
向上计数 |
高 |
向下计数 |
向上计数 |
向上计数 |
向下计数 |
在TI1和TI2上计数 |
低 |
向上计数 |
向下计数 |
向下计数 |
向上计数 |
一个外部的增量编码器可以直接与
MCU
连接而不需要外部接口逻辑。但是,一般会使用比较器
将编码器的差动输出转换到数字信号,这大大增加了抗噪声干扰能力。编码器输出的第三个信
号表示机械零点,可以把它连接到一个外部中断输入并触发一个计数器复位。
下图是一个计数器操作的实例,显示了计数信号的产生和方向控制。它还显示了当选择了双边
沿时,输入抖动是如何被抑制的;抖动可能会在传感器的位置靠近一个转换点时产生。在这个
例子中,我们假定配置如下:
●
CC1S=’01’ (TIMx_CCMR1
寄存器,
IC1FP1
映射到
TI1)
●
CC2S=’01’ (TIMx_CCMR2
寄存器,
IC2FP2
映射到
TI2)
●
CC1P=’0’ (TIMx_CCER
寄存器,
IC1FP1
不反相,
IC1FP1=TI1)
●
CC2P=’0’ (TIMx_CCER
寄存器,
IC2FP2
不反相,
IC2FP2=TI2)
●
SMS=’011’ (TIMx_SMCR
寄存器,所有的输入均在上升沿和下降沿有效
).
●
CEN=’1’ (TIMx_CR1
寄存器,计数器使能
)
图
91
编码器模式下的计数器操作实例
下图为当IC1FP1极性反相时计数器的操作实例(CC1P=’1’,其他配置与上例相同)
图92 IC1FP1反相的编码器接口模式实例
当定时器配置成编码器接口模式时,提供传感器当前位置的信息。使用第二个配置在捕获模式
的定时器,可以测量两个编码器事件的间隔,获得动态的信息(速度,加速度,减速度)。指示机
械零点的编码器输出可被用做此目的。根据两个事件间的间隔,可以按照固定的时间读出计数
器。如果可能的话,你可以把计数器的值锁存到第三个输入捕获寄存器(捕获信号必须是周期的
并且可以由另一个定时器产生);也可以通过一个由实时时钟产生的DMA请求来读取它的值。
eg:
编码器A相接PB6,B相接PB7
#define ENCODENU 65536
void time4IOInit()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //①使能 GPIOB 时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //PB6 7 设置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void time4CountInit()
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //使能 TIM4 时钟
TIM4->ARR = ENCODENU-1; //设定计数器重装值(因为没有使用更新中断所以将计数器设最大值,保证1s延时不会溢出)
TIM4->PSC = 0; //预分频器
TIM4->CR1 &=~(3<<8); // 选择时钟分频:不分频
TIM4->CR1 &=~(3<<5); //边沿对齐(根据dir位向上或者向下计数)
//定时器4配置成编码器模式,双边沿触发
TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);
TIM_SetCounter(TIM4, 0);
//计数器清零
}
void encoderConfig()
{
time4IOInit();
time4CountInit();
TIM_Cmd(TIM4, ENABLE); //计数器使能,开始工作
}
void main ()
{
int dir=0;
u16 nu=0;
encoderConfig();
for (;;)
{
dir=(TIM4->CR1 & 0x0010)>4; //取方向标志位
if(dir > 0){ //向下计数
nu = (ENCODENU-TIM_GetCounter(TIM4))/4; //除以4是因为一对脉冲计数器计数4次
FG_Print("down ; TIM_GetCounter=%d \r\n",nu*60/1000);//(*60是因为延时1s转换成一分钟,/1000是因为编码器转一圈是1000个脉冲)
}else{ //向上计数
nu = TIM_GetCounter(TIM4)/4;
FG_Print("up ; TIM_GetCounter=%d \r\n",nu*60/1000);
}
TIM_SetCounter(TIM4, 0);
osDelay(1000);
}
}