4. 编码器的使用

您所在的位置:网站首页 编码器检测设备 4. 编码器的使用

4. 编码器的使用

2024-07-10 15:23:12| 来源: 网络整理| 查看: 265

4.5.2.2. 软件分析¶

宏定义

bsp_encoder.h-宏定义¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 /* 定时器选择 */ #define ENCODER_TIM TIM3 #define ENCODER_TIM_CLK_ENABLE() __HAL_RCC_TIM3_CLK_ENABLE() /* 定时器溢出值 */ #define ENCODER_TIM_PERIOD 65535 /* 定时器预分频值 */ #define ENCODER_TIM_PRESCALER 0 /* 定时器中断 */ #define ENCODER_TIM_IRQn TIM3_IRQn #define ENCODER_TIM_IRQHandler TIM3_IRQHandler /* 编码器接口引脚 */ #define ENCODER_TIM_CH1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() #define ENCODER_TIM_CH1_GPIO_PORT GPIOC #define ENCODER_TIM_CH1_PIN GPIO_PIN_6 #define ENCODER_TIM_CH1_GPIO_AF GPIO_AF2_TIM3 #define ENCODER_TIM_CH2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() #define ENCODER_TIM_CH2_GPIO_PORT GPIOC #define ENCODER_TIM_CH2_PIN GPIO_PIN_7 #define ENCODER_TIM_CH2_GPIO_AF GPIO_AF2_TIM3 /* 编码器接口倍频数 */ #define ENCODER_MODE TIM_ENCODERMODE_TI12 /* 编码器接口输入捕获通道相位设置 */ #define ENCODER_IC1_POLARITY TIM_ICPOLARITY_RISING #define ENCODER_IC2_POLARITY TIM_ICPOLARITY_RISING /* 编码器物理分辨率 */ #define ENCODER_RESOLUTION 15 /* 经过倍频之后的总分辨率 */ #if ((ENCODER_MODE == TIM_ENCODERMODE_TI1) || (ENCODER_MODE == TIM_ENCODERMODE_TI2)) #define ENCODER_TOTAL_RESOLUTION (ENCODER_RESOLUTION * 2) /* 2倍频后的总分辨率 */ #else #define ENCODER_TOTAL_RESOLUTION (ENCODER_RESOLUTION * 4) /* 4倍频后的总分辨率 */ #endif /* 减速电机减速比 */ #define REDUCTION_RATIO 34

使用宏定义非常方便程序升级、移植。如果使用不同的定时器、编码器倍频数、编码器分辨率等,修改这些宏即可。 开发板使用的是TIM3的CH1和CH2,分别连接到编码器的通道A和通道B,对应的引脚为PC6、PC7。

定时器复用功能引脚初始化

bsp_encoder.c-定时器复用功能引脚初始化¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 /** * @brief 编码器接口引脚初始化 * @param 无 * @retval 无 */ static void Encoder_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* 定时器通道引脚端口时钟使能 */ ENCODER_TIM_CH1_GPIO_CLK_ENABLE(); ENCODER_TIM_CH2_GPIO_CLK_ENABLE(); /**TIM3 GPIO Configuration PC6 ------> TIM3_CH1 PC7 ------> TIM3_CH2 */ /* 设置输入类型 */ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; /* 设置上拉 */ GPIO_InitStruct.Pull = GPIO_PULLUP; /* 设置引脚速率 */ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; /* 选择要控制的GPIO引脚 */ GPIO_InitStruct.Pin = ENCODER_TIM_CH1_PIN; /* 设置复用 */ GPIO_InitStruct.Alternate = ENCODER_TIM_CH1_GPIO_AF; /* 调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO */ HAL_GPIO_Init(ENCODER_TIM_CH1_GPIO_PORT, &GPIO_InitStruct); /* 选择要控制的GPIO引脚 */ GPIO_InitStruct.Pin = ENCODER_TIM_CH2_PIN; /* 设置复用 */ GPIO_InitStruct.Alternate = ENCODER_TIM_CH2_GPIO_AF; /* 调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO */ HAL_GPIO_Init(ENCODER_TIM_CH2_GPIO_PORT, &GPIO_InitStruct); }

定时器通道引脚使用之前必须设定相关参数,这里选择复用功能,并指定到对应的定时器。使用GPIO之前都必须开启相应端口时钟,这个没什么好说的。 唯一要注意的一点,有些编码器的输出电路是不带上拉电阻的,需要在板子上或者芯片GPIO设置中加上上拉电阻。

编码器接口配置

bsp_encoder.c-编码器接口配置¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 /** * @brief 配置TIMx编码器模式 * @param 无 * @retval 无 */ static void TIM_Encoder_Init(void) { TIM_Encoder_InitTypeDef Encoder_ConfigStructure; /* 使能编码器接口时钟 */ ENCODER_TIM_CLK_ENABLE(); /* 定时器初始化设置 */ TIM_EncoderHandle.Instance = ENCODER_TIM; TIM_EncoderHandle.Init.Prescaler = ENCODER_TIM_PRESCALER; TIM_EncoderHandle.Init.CounterMode = TIM_COUNTERMODE_UP; TIM_EncoderHandle.Init.Period = ENCODER_TIM_PERIOD; TIM_EncoderHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; TIM_EncoderHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; /* 设置编码器倍频数 */ Encoder_ConfigStructure.EncoderMode = ENCODER_MODE; /* 编码器接口通道1设置 */ Encoder_ConfigStructure.IC1Polarity = ENCODER_IC1_POLARITY; Encoder_ConfigStructure.IC1Selection = TIM_ICSELECTION_DIRECTTI; Encoder_ConfigStructure.IC1Prescaler = TIM_ICPSC_DIV1; Encoder_ConfigStructure.IC1Filter = 0; /* 编码器接口通道2设置 */ Encoder_ConfigStructure.IC2Polarity = ENCODER_IC2_POLARITY; Encoder_ConfigStructure.IC2Selection = TIM_ICSELECTION_DIRECTTI; Encoder_ConfigStructure.IC2Prescaler = TIM_ICPSC_DIV1; Encoder_ConfigStructure.IC2Filter = 0; /* 初始化编码器接口 */ HAL_TIM_Encoder_Init(&TIM_EncoderHandle, &Encoder_ConfigStructure); /* 清零计数器 */ __HAL_TIM_SET_COUNTER(&TIM_EncoderHandle, 0); /* 清零中断标志位 */ __HAL_TIM_CLEAR_IT(&TIM_EncoderHandle,TIM_IT_UPDATE); /* 使能定时器的更新事件中断 */ __HAL_TIM_ENABLE_IT(&TIM_EncoderHandle,TIM_IT_UPDATE); /* 设置更新事件请求源为:定时器溢出 */ __HAL_TIM_URS_ENABLE(&TIM_EncoderHandle); /* 设置中断优先级 */ HAL_NVIC_SetPriority(ENCODER_TIM_IRQn, 5, 1); /* 使能定时器中断 */ HAL_NVIC_EnableIRQ(ENCODER_TIM_IRQn); /* 使能编码器接口 */ HAL_TIM_Encoder_Start(&TIM_EncoderHandle, TIM_CHANNEL_ALL); }

编码器接口配置中,主要初始化两个结构体,其中时基初始化结构体TIM_HandleTypeDef很简单,而且在其他应用中都用涉及到,直接看注释理解即可。

重点是编码器接口结构体TIM_Encoder_InitTypeDef的初始化。对于STM32定时器的编码器接口,我们首先需要设置编码器的倍频数,即成员EncoderMode, 它可把编码器接口设置为2倍频或4倍频,根据bsp_encoder.h的宏定义我们将其设置为4倍频,倍频原理在上面已有讲解这里不再赘述。

对于编码器接口输入通道的配置,我们只讲解通道1的配置情况,通道2是一样的。首先是输入信号极性,成员IC1Polarity在输入捕获模式中是用来设置触发边沿的, 但在编码器模式中是用来设置输入信号是否反相的。设置为RISING表示不反相,FALLING表示反相。此成员与编码器的计数触发边沿无关, 只用来匹配编码器和电机的方向,当设定的电机正方向与编码器正方向不一致时不必更改硬件连接,直接在程序中修改IC1Polarity即可。

接下来是成员IC1Selection,这个成员用于选择输入通道,IC1可以是TI1输入的TI1FP1,也可以是从TI2输入的TI2FP1,我们这里选择直连(DIRECTTI),即TI1FP1映射到IC1, 在编码器模式下这个成员只能设置为DIRECTTI,其他可选值都是不起作用的。

最后是成员IC1Prescaler和成员IC1Filter,我们需要对编码器的每个脉冲信号都进行捕获,所以设置成不分频。根据STM32编码器接口2倍频或4倍频的原理, 接口在倍频采样的过程中也会对信号抖动进行补偿,所以输入滤波器也很少会用到。

配置完编码器接口结构体后清零计数器,然后开启定时器的更新事件中断,并把更新事件中断源配置为定时器溢出,也就是仅当定时器溢出时才触发更新事件中断。 然后配置定时器的中断优先级并开启中断,最后启动编码器接口。

定时器溢出次数记录

bsp_encoder.c-定时器溢出次数记录¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /** * @brief 定时器更新事件回调函数 * @param 无 * @retval 无 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { /* 判断当前计数器计数方向 */ if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&TIM_EncoderHandle)) /* 下溢 */ Encoder_Overflow_Count--; else /* 上溢 */ Encoder_Overflow_Count++; }

在TIM_Encoder_Init函数中我们配置了仅当定时器计数溢出时才触发更新事件中断,然后在中断回调函数中记录定时器溢出了多少次。首先定义一个全局变量Encoder_Overflow_Count, 用来记录计数器的溢出次数。在定时器更新事件中断回调函数中,使用__HAL_TIM_IS_TIM_COUNTING_DOWN函数判断当前的计数方向,是向上计数还是向下计数, 如果向下计数,Encoder_Overflow_Count减1,反之则加1。这样在计算电机转速和位置的时候就可以把溢出次数也参与在内。

主函数

main.c-主函数¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 /** * @brief 主函数 * @param 无 * @retval 无 */ int main(void) { __IO uint16_t ChannelPulse = 0; uint8_t i = 0; /* HAL库初始化*/ HAL_Init(); /* 初始化系统时钟为168MHz */ SystemClock_Config(); /* 配置1ms时基为SysTick */ HAL_InitTick(5); /* 初始化按键GPIO */ Key_GPIO_Config(); /* 初始化USART */ DEBUG_USART_Config(); printf("\r\n——————————野火减速电机编码器测速演示程序——————————\r\n"); /* 通用定时器初始化并配置PWM输出功能 */ TIMx_Configuration(); TIM1_SetPWM_pulse(PWM_CHANNEL_1,0); TIM1_SetPWM_pulse(PWM_CHANNEL_2,0); /* 编码器接口初始化 */ Encoder_Init(); while(1) { /* 扫描KEY1 */ if( Key_Scan(KEY1_GPIO_PORT, KEY1_PIN) == KEY_ON) { /* 增大占空比 */ ChannelPulse += 50; if(ChannelPulse > PWM_PERIOD_COUNT) ChannelPulse = PWM_PERIOD_COUNT; set_motor_speed(ChannelPulse); } /* 扫描KEY2 */ if( Key_Scan(KEY2_GPIO_PORT, KEY2_PIN) == KEY_ON) { if(ChannelPulse


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭