当前位置: 首页 > news >正文

旋转编码器模块(软件消抖)

目录

旋转编码器简介

模块接线

正交编码器控制原理 

模块代码

Encoder.h

Encoder.c 

main.c 

消抖代码 

Encoder.c


旋转编码器简介

旋转编码器是一种将旋转角位移转换为一连串数字脉冲信号的旋转式电位器。当编码器的旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的正交方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度,位置,旋转方向

正交信号为两个一样的波形但相位差为90°,这提高输出信号的质量和稳定性,从而消除了干扰。

本博客使用的是EC11型号360度旋转编码器,旋转编码器一圈为20格,一格一完整脉冲,在静止的时候,AB两线输出都是高电平 

旋转编码器旋转的输出动作,由于编码器的不同,A、B端输出脉冲不同,我这一种就是转一格,A、B对C端输出一个完整脉冲。 

更多详细见:

EC11旋转编码器 | 立创开发板技术文档中心 (lckfb.com)

我的旋转编码器不能使用按键,本博客就不涉及按键检测了


模块接线

                                   旋转编码器电路

按键电路内部没接,C相内部已经已接入GND  

旋转编码器STM32F103C8T6
VCC3.3V
GNDGND
APB0
BPB1

正交编码器控制原理 

正交编码器正反转由自己定义

 A、B两相空闲状态都为高电平,编码器旋转时都输出方波,但两个信号有90°相位差

注:下面图形中的波形不是从空闲状态开始的

正转

当是顺时针旋转时,B相超前A相90度,即A相为下降沿时,B相为高电平;A相为上升沿时,B相为低电平  

反转

当是逆时针旋转时,A相超前B相90度,即A相为下降沿时,B相为低电平;A相为上升沿时,B相为高电平。  

编码器正交波形动态展示视频时间段为00:50至1:57 旋转编码器|从零开始认识各种传感器_哔哩哔哩_bilibili

模块代码

思路一:A相下降沿进入中断函数,判断B相的高低电平确定编码器旋转方向。

思路二:A相和B相下降沿都进入中断函数,判断另一相的高低电平确定编码器旋转方向。

思路三:A相的上升沿和下降沿都进入中断函数,在A相下降沿时记录B相电平,A相上升沿时再记录B相电平,判断B相电平在这期间是上升沿还是下降沿以确定编码器旋转方向。(推荐此法

Encoder.h

#ifndef __ENCODER_H
#define __ENCODER_Hvoid Encoder_Init(void);
int16_t Encoder_Get(void);#endif

Encoder.c 

该代码实现思路二,消抖效果不佳,请见思路三消抖代码

#include "stm32f10x.h"                  // Device headerint16_t Encoder_Count;void Encoder_Init(void)
{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_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);
}int16_t Encoder_Get(void)
{int16_t Temp = Encoder_Count;Encoder_Count = 0;return Temp;
}void EXTI0_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line0) == SET){/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0){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_1) == 0){if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0){Encoder_Count ++;}}EXTI_ClearITPendingBit(EXTI_Line1);}
}

main.c 

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Encoder.h"int16_t Num;int main(void)
{OLED_Init();Encoder_Init();OLED_ShowString(1, 1, "Num:");while (1){Num += Encoder_Get();OLED_ShowSignedNum(1, 5, Num, 5);}
}

消抖代码 

A相下降沿消抖:A相和B相默认输出高电平,先检测A相下降沿,若发生抖动,不断进入上升沿和下降沿的if判断,但是这时(A相下降沿时),B相电平不会发生变化,不会执行下面的代码。这样A相下降沿时A相电平的抖动就过滤了。

		//判断A相低电平时,B相边沿变化则确定编码器转向,若不变化则过滤计数,用来消除A相和B相边沿变化的抖动if(B_level==1 && BOUT == 0) //B相为下降沿{Encoder_Count++;//顺时针转}if(B_level==0 && BOUT == 1)//B相为上升沿{Encoder_Count--;//逆时针转}	

B相电平变化的抖动:检测到A下降沿后,若B相下降沿则正转,上升沿则反转。 B相电平变化也会有抖动。但并不影响程序对B相电平检测,也不阻塞程序。A相下降沿时,if判断会将A相下降沿时最后的B相电平存储,A相上升沿时,if会检查B相电平并判断B相电平变化确定编码器计数方向。

A相上升沿抖动A相下降沿消抖类似。A相上升沿时,B相电平不会发生变化,不会执行上面的if语句,不计数

Encoder.c

该代码实现思路三,消抖效果好

#include "stm32f10x.h"int16_t Encoder_Count;//计数次数#define AOUT GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0)//编码器A相输出
#define BOUT GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)//编码器B相输出void Encoder_Init(void)
{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_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);	EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line0;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_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);
}int16_t Encoder_Get(void)
{int16_t Temp = Encoder_Count;Encoder_Count = 0;return Temp;
}//检测到A相信号上升沿和下降沿进入中断函数
void EXTI0_IRQHandler(void)
{static uint8_t B_level;//B_level:A相下降沿时B相电平,范围0~1;//A相下降沿判断下面逻辑if(AOUT == 0)//A相下降沿触发中断{                                                          B_level=0;//默认读取B相电平为0,记录A相下降沿时B相电平if(BOUT == 1)//若为B相高电平则B_level置1{B_level=1;}}//A相上升沿时判断下面逻辑if(AOUT == 1){//判断A相低电平时,B相边沿变化则确定编码器转向,若不变化则视为抖动,过滤计数if(B_level==1 && BOUT == 0) //B相为下降沿{Encoder_Count++;//顺时针转}if(B_level==0 && BOUT == 1)//B相为上升沿{Encoder_Count--;//逆时针转}	 }	EXTI_ClearITPendingBit(EXTI_Line0);	
}

参考博客

江协科技STM32——旋转编码器计次(软件消抖)_旋转编码器消抖-CSDN博客

相关文章:

  • LVGL | VisualStuio PC模拟器
  • 【机器学习】集成学习------迅速了解什么是集成学习!!!
  • 子组件和父组件的挂载顺序
  • 微信小程序认证和备案
  • c++ 编译器的不同处理阶段详解
  • Open3D 点云添加均匀分布的随机噪声
  • Spring Cloud各个微服务之间为什么要用http交互?难道不慢吗?
  • camtasia studio字幕位置怎么移动 camtasia studio字幕有黑框怎么删除黑框
  • oracle 数据库安装与配置 全新教程
  • nestjs目录命名导致的循环引用
  • 2024嵌入式面试:比亚迪嵌入式面试题及参考答案(BYD面试)
  • 数据安全与个人信息保护的辨析
  • 数据结构---五大排序---哈希表---二分查找法
  • 9,sql 约束
  • 面试题总结(一) -- 基础语法篇
  • AHK 中 = 和 == 等比较运算符的用法
  • Android交互
  • C学习-枚举(九)
  • C语言笔记(第一章:C语言编程)
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • JavaScript/HTML5图表开发工具JavaScript Charts v3.19.6发布【附下载】
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • sessionStorage和localStorage
  • XML已死 ?
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 基于web的全景—— Pannellum小试
  • 每天一个设计模式之命令模式
  • 我与Jetbrains的这些年
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 异步
  • 用简单代码看卷积组块发展
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • 从如何停掉 Promise 链说起
  • # Maven错误Error executing Maven
  • #mysql 8.0 踩坑日记
  • #php的pecl工具#
  • $GOPATH/go.mod exists but should not goland
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第6节 (嵌套的Finally代码块)
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (二十九)STL map容器(映射)与STL pair容器(值对)
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (四)React组件、useState、组件样式
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (转)LINQ之路
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • (转)为C# Windows服务添加安装程序
  • (转载)利用webkit抓取动态网页和链接
  • ..thread“main“ com.fasterxml.jackson.databind.JsonMappingException: Jackson version is too old 2.3.1
  • .apk 成为历史!
  • .bat批处理(一):@echo off
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .NET文档生成工具ADB使用图文教程
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • .vimrc php,修改home目录下的.vimrc文件,vim配置php高亮显示