任务:使用定时器的编码器功能,采集旋转编码器的信号并处理,使用LL库
网上似乎没查到关于LL库配置定时器编码器模式,这篇博客用于分享我解决问题的过程,以及提出一种实现方案。
作者只是大四学生一枚,水平有限,如有错误,还请您指出,不胜感激。
核心思路是:不管是什么库,最终都是操作单片机寄存器,先了解清楚HAL库的配置方法,再依照其核心实现去匹配LL库相关函数。KEIL左侧的function中可以快速查到文件内函数,如图所示。
根据经验,一般c文件内的函数接口是需要一系列操作的函数(如初始化),h文件中的函数一般是宏函数,可以快速操作某一寄存器(比如使能,获取数据)。
目录
一、硬件介绍
二、cubeMX配置
三、代码实现
一、硬件介绍
开发板采用的正点原子stm32F1RCT6 mini板,20线AB相旋转编码器模块如图,
这个模块有五根线,正负电源线(用于上拉),CLK和DT(也就是AB输出线),KEY(按下旋钮与gnd接通)
二、cubeMX配置
参考资料:http://www.eemaker.com/stm32cubemx-encoder.html
我这里没有分频,但实际上选择的encoderMode是 TI1和TI2这种模式下,AB两相的上升沿和下降沿都会计数,所以计数值是采集到脉冲个数的4倍。
配置为LL库,为了高效。配置完成、生成代码后会产生初始化函数:
void MX_TIM2_Init(void)
{
LL_TIM_InitTypeDef TIM_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
/**TIM2 GPIO Configuration GPIO口信息
PA0-WKUP ------> TIM2_CH1
PA1 ------> TIM2_CH2
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_0|LL_GPIO_PIN_1;
GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//配置模式
LL_TIM_SetEncoderMode(TIM2, LL_TIM_ENCODERMODE_X4_TI12);
LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI);
LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1);
LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV2_N8);
LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING);
LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_DIRECTTI);
LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1);
LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV2_N8);
LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING);
TIM_InitStruct.Prescaler = 0;
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct.Autoreload = 65535;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
LL_TIM_Init(TIM2, &TIM_InitStruct);
LL_TIM_DisableARRPreload(TIM2);
LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET);
LL_TIM_DisableMasterSlaveMode(TIM2);
}
三、代码实现
已知HAL库实现定时器编码器需要几个核心步骤
- 初始化外设(上面已讲)
- 使能(一层一层剥开,追其根本就是操作CCER 、 CR1)
HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL) ;
具体内容:即使能两个通道,以及使能定时器
HAL_StatusTypeDef HAL_TIM_Encoder_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
{
/* Check the parameters */
assert_param(IS_TIM_CC2_INSTANCE(htim->Instance));
/* Enable the encoder interface channels */
switch (Channel)
{
case TIM_CHANNEL_1:
{
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
break;
}
case TIM_CHANNEL_2:
{
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_2, TIM_CCx_ENABLE);
break;
}
default :
{
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_2, TIM_CCx_ENABLE);
break;
}
}
/* Enable the Peripheral */
__HAL_TIM_ENABLE(htim);
/* Return function status */
return HAL_OK;
}
//使能操作,追其根本就是操作CCER
void TIM_CCxChannelCmd(TIM_TypeDef* TIMx, uint32_t Channel, uint32_t ChannelState)
{
uint32_t tmp = 0U;
/* Check the parameters */
assert_param(IS_TIM_CC1_INSTANCE(TIMx));
assert_param(IS_TIM_CHANNELS(Channel));
tmp = TIM_CCER_CC1E << Channel;
/* Reset the CCxE Bit */
TIMx->CCER &= ~tmp;
/* Set or reset the CCxE Bit */
TIMx->CCER |= (uint32_t)(ChannelState << Channel);
}
//定时器使能实际是操作CR1
#define __HAL_TIM_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->CR1|=(TIM_CR1_CEN))
- 获取数据(获取CNT)
i= __HAL_TIM_GET_COUNTER(&htim2);
//也就是获得CNT
#define __HAL_TIM_GET_COUNTER(__HANDLE__) \
((__HANDLE__)->Instance->CNT)
根据这个流程,筛选LL库中相关函数:
- 初始化(cubemx已自动生成)
- 使能通道(操作CCER)
LL_TIM_CC_EnableChannel(TIM2,LL_TIM_CHANNEL_CH1);
LL_TIM_CC_EnableChannel(TIM2,LL_TIM_CHANNEL_CH2);
//可以看到也是操作CCER
__STATIC_INLINE void LL_TIM_CC_EnableChannel(TIM_TypeDef *TIMx, uint32_t Channels)
{
SET_BIT(TIMx->CCER, Channels);
}
使能计数(操作CR1)
LL_TIM_EnableCounter(TIM2);
__STATIC_INLINE void LL_TIM_EnableCounter(TIM_TypeDef *TIMx)
{
SET_BIT(TIMx->CR1, TIM_CR1_CEN);
}
- 获取数据(获取CNT)
i= LL_TIM_GetCounter(TIM2);
//获取CNT
__STATIC_INLINE uint32_t LL_TIM_GetCounter(TIM_TypeDef *TIMx)
{
return (uint32_t)(READ_REG(TIMx->CNT));
}
- 然后功能就能实现了(可以看到我编码器转过一个刻度,数值增加了4(因为没分频),顺时针转增加,逆时针转减少)
具体代码就不上传了,时间用来写博客了,抓紧做毕设了。
如果有错误请您支出。如果觉得有帮助,打赏一下我这个穷学生吧,啊哈哈,开玩笑的。