目录
在做平衡小车时候,因为板子的缘故(STM32F103ZET6)最小系统,有一些引脚没有引出来,网上大部分的平衡小车的代码是基于STM32F103C8T6的,移植代码的时候遇到几个坑。 对于F103系列来说,可以用作编码器模式的有高级定时器TIM1和TIM8,通用定时器有TIM2 TIM3 TIM4 TIM5,且每个定时器只有通道1和通道2能作为正交解码,还要注意一下定时器5和定时器2是32位定时器,装载数值时注意要装载0xffffffff。这是踩坑的主要地方,学的不够深入不了解这一部分的知识。
1、编码器的原理
如果俩个相位差为90度,这俩个信号称为正交。由于俩个信号相差90度,可以根据俩个信号那个先那个后判断方向,根据编码器的脉冲数量及编码轮的周长可以算出行驶的距离。加上一个定时器去计数单位时间内采集到的编码脉冲数量就可以算出电机的速度。
2、编码器接口模式
选择编码器接口模式的方法是:如果计数器只在
TI2
的边沿计数,则置
TIMx_SMCR
寄存器中的
SMS=001
;如果只在
TI1
边沿计数,则置
SMS=010
;如果计数器同时在
TI1
和
TI2
边沿计数,则
置
SMS=011
。
通过设置
TIMx_CCER
寄存器中的
CC1P
和
CC2P
位,可以选择
TI1
和
TI2极性;如果需要,还可以对输入滤波器编程。
两个输入
TI1
和
TI2
被用来作为增量编码器的接口。参看表
73
,假定计数器已经启动
(TIMx_CR1
寄存器中的
CEN=1)
,则计数器由每次在
TI1FP1
或
TI2FP2
上的有效跳变驱动。
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
不同时变换。
计数方向与编码器信号的关系
一个外部的增量编码器可以直接与MCU连接而不需要外部接口逻辑。但是,一般会使用比较器
将编码器的差动输出转换到数字信号,这大大增加了抗噪声干扰能力。编码器输出的第三个信号
表示机械零点,可以把它连接到一个外部中断输入并触发一个计数器复位。
检测方式一共有三种:
TIM_EncoderInterfaceConfig(TIMX, TIM_EncoderMode_TI1, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式1
TIM_EncoderInterfaceConfig(TIMX, TIM_EncoderMode_TI2, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式2
TIM_EncoderInterfaceConfig(TIMX, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
3、示例代码
1. 定时器2配置为编码器模式:
void Encoder_Init_TIM2(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器4的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOB
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器
TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//根据TIM_TimeBaseInitStruct的参数初始化定时
器TIM2
TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising,
TIM_ICPolarity_Rising);//使用编码器模式3
TIM_ICStructInit(&TIM_ICInitStructure);//把TIM_ICInitStruct 中的每一个参数按缺省值填入
TIM_ICInitStructure.TIM_ICFilter = 10; //设置滤波器长度
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_SetCounter(TIM2,0);
TIM_Cmd(TIM2, ENABLE);
}
void TIM2_IRQHandler(void)
{
if(TIM2->SR&0X0001)//溢出中断
{
}
TIM2->SR&=~(1<<0);//清除中断标志位
}
在配置编码器中设置了中断,在中断服务函数里面需要清楚中断标准位,不然可能编码器工作不正常,其他编码器配置同理,需注意只有CH1与CH2才能配置成编码器模式。
2. 单位时间读取编码器的计数
int Read_Encoder(u8 TIMX)
{
int Encoder_TIM;
switch(TIMX)
{
case 2: Encoder_TIM= (short)TIM2 -> CNT; TIM2 -> CNT=0;break;
case 3: Encoder_TIM= (short)TIM3 -> CNT; TIM3 -> CNT=0;break;
case 4: Encoder_TIM= (short)TIM4 -> CNT; TIM4 -> CNT=0;break;
default: Encoder_TIM=0;
}
return Encoder_TIM;
}
4、完整工程代码
(1条消息) STM32定时器编码器计数功能资源-CSDN文库
说的不对的地方,各位大佬指出。