STM32学习 旋转编码器计次(显示在OLED)

1.1旋转编码器

旋转编码器概述:

1.光栅编码器

光栅编码器是一种利用光栅的光学特性来精确测量位移的装置。它由主光栅和指示光栅组成,物体移动使透过光栅的光发生变化,经光电探测器转换为电信号,通过计数脉冲确定位移量。具有高精度、高可靠性和快速响应等特点,广泛应用于工业和仪器仪表领域。然而,光栅编码器存在一些不足。它只能计算位置和速度,不能判断方向。在某些应用中,这可能会限制其使用。为了弥补这一缺陷,可以结合其他能够判断方向的旋转编码器,以提高测量的准确性和全面性。

2.旋转编码器

旋转编码器是一种用于测量旋转角度或位置的传感器。它通常由一个旋转轴和一个固定的外壳组成,内部包含了光学或磁性的编码元件。

旋转编码器可以产生正交波形,也称为 A 相和 B 相波形。这两个波形具有以下特点:

一、波形特征
  1. 相位差:

    1. A 相和 B 相波形之间存在 90 度的相位差。这意味着当旋转编码器的轴旋转时,A 相和 B 相波形的上升沿和下降沿会交替出现,且相位相差四分之一周期。(见图2)

    2. 例如,当 A 相波形处于高电平时,B 相波形可能处于上升沿、下降沿或低电平状态,具体取决于旋转方向和编码器的分辨率。

  2. 脉冲数:

    1. 旋转编码器每旋转一圈,会产生一定数量的脉冲。这个脉冲数通常与编码器的分辨率有关。例如,一个分辨率为 1024 线的编码器,每旋转一圈会产生 1024 个脉冲。

    2. A 相和 B 相波形的脉冲数是相同的,它们可以用来确定旋转的角度或位置。通过计数 A 相或 B 相波形的脉冲数,并结合相位差信息,可以确定旋转的方向。

3.霍尔传感器编码器

一、工作原理霍尔传感器编码器通常由一个磁体和多个霍尔元件组成。当磁体与霍尔元件之间发生相对运动时,霍尔元件会检测到磁场的变化,并产生相应的电信号。这些电信号可以被处理和解读,以确定旋转角度、线性位移或速度等参数。二、特点

  1. 非接触式测量:霍尔传感器编码器采用非接触式测量方式,不会对被测物体产生磨损,具有较高的可靠性和寿命。

  2. 高精度:能够提供高精度的测量结果,适用于对测量精度要求较高的场合。

  3. 快速响应:对运动的响应速度快,能够实时监测被测物体的运动状态。

4.独立编码器元件

独立编码器元件是一种可以独立工作的用于测量角度、位置、速度等物理量的电子元件。

一、结构组成

通常包括码盘(可以是光学码盘、磁性码盘等)、检测元件(如光电二极管、霍尔元件等)以及信号处理电路等部分。

输入轴转动,输出轴就会有波形。

旋转编码器硬件电路

编码器控制数值 代码实现

硬件电路接线

初始化代码

#include "stm32f10x.h"                  // Device header


int16_t Encoder_Count;
void Encoder_Init(void ){
  
  //因为这里会产生90°的相位差,所以在A相低电平,B相下降沿的时候为正转
  //在A相下降沿,B相低电平的时候才判断为反转
  
  //第一步配置GPIO 跟 APIO 这里参考手册或是函数说明选择APBX 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
  
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU;
  GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0 | GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
  GPIO_Init(GPIOB,&GPIO_InitStructure);
  
  //指定外部中断线,以及端口,想要哪个端口触发中断,根据信号线初始化端口选择GPIO_PinSourcex的参数
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
  
  EXTI_InitTypeDef EXTI_InitStructure;
  EXTI_InitStructure.EXTI_Line=EXTI_Line0 | EXTI_Line1;
  EXTI_InitStructure.EXTI_LineCmd=ENABLE;
  EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
  EXTI_Init(&EXTI_InitStructure);
  
  //这里是两个端口,所以要分别进行优先级的设置
  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
  NVIC_Init(&NVIC_InitStructure);
        
  NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
  NVIC_Init(&NVIC_InitStructure);
        
}
uint16_t Encoder_Get(void)
{
                int16_t Key;
         Key=Encoder_Count;
        Encoder_Count = 0;
        return Key;
}


//中断函数编写
void EXTI0_IRQHandler(void )
        {
  if(EXTI_GetITStatus(EXTI_Line0) == SET)
  {
    if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) ==0)
    {
      Encoder_Count--;
    }
                  EXTI_ClearITPendingBit(EXTI_Line0);//清除中断标志位
  }
}

void EXTI1_IRQHandler(void )
        {
  if(EXTI_GetITStatus(EXTI_Line1) == SET)
  {
    if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0) ==0)
    {
      Encoder_Count++;
    }
                  EXTI_ClearITPendingBit(EXTI_Line1);//清除中断标志位
  }
}

主程序

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Encoder.h"


int16_t Num;
int main(void)
        {
  OLED_Init();
  OLED_ShowString(1,1,"Num:");
  Encoder_Init();
                
  while(1)
                {
    Num += Encoder_Get();
    OLED_ShowSignedNum(1,5,Num,5);
  }
}

实现效果

旋转编码器正转的时候数值增大,反之减小,另外这款编码器的sw 口(switch)还可以在按下的时候作为按键使用,有兴趣可以自行研究

STM32中处理旋转编码器计数时,计数可能会因为编码器抖动而产生混乱。为了消除这种现象,通常需要对输入信号进行消抖处理。以下是一个使用Keil STM32Cube HAL库进行消抖的基本示例,这里假设我们有一个中断服务函数`ENCODER_IRQHandler()`来处理编码器的变化: ```c #include "stm32f10x_hal.h" #include "stm32f1xx_hal_tim.h" // 编码器相关的全局变量 TIM_HandleTypeDef htim_encoder; uint16_t last_count = 0; // 上一次计数值 uint8_t debounce_counter = 0; // 中断处理函数 void ENCODER_IRQHandler(void) { static uint8_t new_direction = 0; // 新方向标志 if (htim_encoder.Instance->SR & TIM_FLAG_UPDATE) { uint16_t current_count = htim_encoder.Instance->CNT; // 获取当前计数值 if (current_count != last_count) { // 如果有变化 last_count = current_count; // 消抖处理 if (debounce_counter > 0) { debounce_counter--; } else { // 更新计数,只有当debounce_counter为0时才确认新的方向 // 这里假设编码器每转一圈计数加一 if (new_direction) { encoder_steps++; } debounce_counter = DEBOUNCE_TIMEOUT; // 设置默认的消抖时间 new_direction ^= 1; // 切换新旧方向标记 } } } } int main(void) { // 初始化HAL库和其他硬件资源 // ... // 初始化编码器定时器 htim_encoder.Instance = htim4; // 需要替换为实际的TIM实例 htim_encoder.Init.Prescaler = ...; // 根据你的编码器配置设置预分频器 htim_encoder.Init.CounterMode = TIM_COUNTERMODE_UP; htim_encoder.Init.Period = ...; // 设置周期 HAL_TIM_Base_Init(&htim_encoder); // 配置并启用编码器中断 HAL_NVIC_EnableIRQ(TIM4_IRQn); HAL_TIM_Base_Start_IT(&htim_encoder); while (1) { // 主循环 } } ``` 在这个例子中,我们添加了一个`debounce_counter`变量用于记录消抖持续的时间,超过设定阈值后才确认计数。消抖时间(`DEBOUNCE_TIMEOUT`)可以根据实际情况调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值