ESP32驱动编码器--SIQ-02FVS3 (Vscode + IDF)
提示:本博客作为学习笔记,有错误的地方希望指正
文章目录
- 一、编码器简介
- 二、硬件设计
- 三、实现代码
- 四、显示结果
一、编码器简介
编码器一般分为霍尔式的和光栅式的编码器,我这里使用的式SIQ-02FVS3这种迷你编码器,和EC11的驱动方法差不多,但是这种编码器体积比较小,但是价格比价贵。下面是编码器的实物图。SIQ-02FVS3还带有按压按键,实现多功能。
那么我们该怎样去使用这个编码器呢,从给出的数据手册上面我们看到一个波形,我们就是通过这个波形去判断编码器是否转动以及编码器转动的方向,可以从图中可以看出当从CW方向转动的时候,A的波形上升沿比B波形的上升沿快,具体快多少,这里数据手册给出24±3°,当从CCW方向转动的这个时候恰好相反,B的相位上升沿快于A的上升沿。这样可以通过捕获上升沿的顺序来判断编码器的方向。
了解编码器的工作机制以后我们就可以有以下几种方法实现编码器的状态捕获,以CW方向为例。
- 1、当检测到A项上升沿的时候,检测B项的状态,可以A上升沿中断,在中断中检测B的电平状态。
- 2、同时检测A、B项的上升沿,然后根据上升沿的顺序判断方向。
- 3、可以捕获一个项(例如A项)的边沿,然后判断A项第一个边沿中断时候获取B和A项的电平,再第二个边沿触发中断的时候捕获B和A项的电平,根据两次捕获B和A项的值就可以知道旋转的方向。
二、硬件设计
硬件设计值得注意的是使用中断的方式检测的话,硬件上最好使用0.1uF的滤波电容滤波,不然转动的时候就会出现一些毛刺出发中断,要么就使用软件滤波,但是比较麻烦,检测两次上升沿的间隔时间来判断时候接收处理中断信号的有效值。
以下两张图片是通过逻辑分析仪捕捉到转转时候的电平,第一张看起来不错有中断比较明显,但是通过放大以后发现第二张图中就有毛刺,这个是没有硬件滤波的电路。
原理图
三、实现代码
我这里使用的是第三种方法实现对编码器状态的捕获的,加上硬件的滤波,目前用起来是比较准确的,使用队列在中断中将数据发送出去。从第三种情况来看捕获边缘有两种情况,以A边缘中断,然后在A中断中捕获A、B的状态。两种情况。
CW方向为例,第一次捕获A项的的边缘位上升沿,此时A = 1,B = 0;那么第二次就必须捕获下降沿,A = 0,B = 1。假如A第一次没有在边沿捕获到上升沿的时候,捕获的是下降沿,第二次就一定捕获到上升沿。CCW方向也是如此的,这样我们就判断这四种情况,其他的都不用管,这样可以过滤掉干扰,从而实现更准确的控制。
Encoder.c文件
#include "Encoder.h"
#define ESP_INTR_FLAG_DEFAULT 0xQueueHandle encoder_gpio_event_queue = NULL; //编码器队列
static unsigned int Value_count = 0; //状态计数
static int Encoder_A_Last_Value = 0; //第一次A项的值
static int Encoder_B_Last_Value = 0; //第一次B项的值
static int Encoder_A_Value = 0; //第二次A项的值
static int Encoder_B_Value = 0; //第二次B项的值
#define TAG "Encoder"
/****************************************** @brief GPIO中断处理* @author wsp* @date 2022-2-21* ***************************************/
static void IRAM_ATTR encoder_gpio_isr_handler(void * arg)
{uint32_t GPIO_Queue_Data = 0; //发送队列变量if(Value_count == 0){ //边缘计数值,计数两次边缘值Encoder_A_Last_Value = gpio_get_level(Encoder_A); //捕获A项的值Encoder_B_Last_Value = gpio_get_level(Encoder_B); //捕获B项的值Value_count = 1; //开始第一次计数}else if(Value_count == 1){ //完成一个边缘捕获Encoder_A_Value = gpio_get_level(Encoder_A); //捕获A项的值Encoder_B_Value = gpio_get_level(Encoder_B); //捕获B项的值//状态判断处理if(((Encoder_A_Last_Value == 0 && Encoder_A_Value == 1) && (Encoder_B_Last_Value == 1 && Encoder_B_Value == 0)) || ((Encoder_A_Last_Value == 1 && Encoder_A_Value == 0) && (Encoder_B_Last_Value == 0 && Encoder_B_Value == 1))){ //顺时针旋转GPIO_Queue_Data = 1; //右一}else if(((Encoder_A_Last_Value == 0 && Encoder_A_Value == 1) && (Encoder_B_Last_Value == 0 && Encoder_B_Value == 1)) || ((Encoder_A_Last_Value == 1 && Encoder_A_Value == 0) && (Encoder_B_Last_Value == 1 && Encoder_B_Value == 0))){ //逆时针旋转GPIO_Queue_Data = 2; //左二}Encoder_B_Last_Value = 2; //清除状态值,不初始化0原因是在全局第一次初始化就是0,为了区别Encoder_A_Last_Value = 2; //清除状态值Value_count = 0; //清除状态值}if(GPIO_Queue_Data != 0) //状态改变的时候 发送队列xQueueSendFromISR(encoder_gpio_event_queue, &GPIO_Queue_Data, NULL);
}
/****************************************** @brief 编码器初始化* @author wsp* @date 2022-2-21* ***************************************/
void Encoder_init(void)
{gpio_config_t io_conf; //配置GPIO结构体io_conf.intr_type = GPIO_INTR_DISABLE; //不使能GPIO中断io_conf.mode = GPIO_MODE_INPUT; //GPIO输入模式io_conf.pull_down_en = 0; //下拉使能io_conf.pull_up_en = 1; //上拉不使能io_conf.pin_bit_mask = Encoder_CHB_GPIO_INPUT_PIN_SEL; //GPIO输入引脚选择gpio_config(&io_conf); //配置IO参数io_conf.intr_type = GPIO_INTR_ANYEDGE; //边沿触发中断io_conf.pin_bit_mask = Encoder_CHA_GPIO_INPUT_PIN_SEL; //GPIO输入引脚选择gpio_config(&io_conf); //配置IO参数io_conf.intr_type = GPIO_INTR_DISABLE; //不使能GPIO中断io_conf.pin_bit_mask = Encoder_KEY_GPIO_INPUT_PIN_SEL; //GPIO输入引脚选择gpio_config(&io_conf); //配置IO参数gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); //安装GPIO中断服务gpio_isr_handler_add(Encoder_A,encoder_gpio_isr_handler,(void * )Encoder_A);//添加中断服务 encoder_gpio_event_queue = xQueueCreate(1,sizeof(uint32_t)); //创建队列
}
void Encoder_Test(void)
{char Capure_Enconder_State = 0;while(1){//获取队列信息if (pdTRUE == xQueueReceive(encoder_gpio_event_queue, & Capure_Enconder_State, (portTickType)portMAX_DELAY)){printf("Capure_Enconder_State:%d\n\r",Capure_Enconder_State);}}
}
Encoder.h文件
#ifndef _Encoder_H_
#define _Encoder_H_
#include "lvgl/lvgl.h"
#include <stdio.h>
#include "lv_port_indev_Key.h"
#include "lvgl_function.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/ledc.h"
#include "esp_err.h"
#include "sdkconfig.h"#define Encoder_A 34 //编码器通道一
#define Encoder_B 35 //编码器通道二
#define Encoder_K 13 //编码器按键通道#define Encoder_CHA_GPIO_INPUT_PIN_SEL ((1ULL<<Encoder_A))
#define Encoder_CHB_GPIO_INPUT_PIN_SEL ((1ULL<<Encoder_B))
#define Encoder_KEY_GPIO_INPUT_PIN_SEL ((1ULL<<Encoder_K))extern xQueueHandle encoder_gpio_event_queue;
void Encoder_init(void);
void Encoder_Test(void);
#endif
main函数
void app_main(void)
{Encoder_init();Encoder_Test();
}
四、显示结果
最后的显示结果是相当的准确的,不会出现快速转动的时候出问题。
ESP32驱动编码器--SIQ-02FVS3 (Vscode + IDF)相关推荐
- 使用ESP32驱动QMA7981读取三轴加速度(带例程)
使用ESP32驱动QMA7981读取三轴加速度(带例程) 1.简介 ESP32是国产乐鑫公司生产的32位单片机,双核240MHz,带有蓝牙和wifi功能,本例中使用的是ESP32-S模组.QMA798 ...
- esp32驱动ws2815出现的频闪问题
问题现象 最近在使用esp32驱动多个ws2815灯珠时,使用官方的rmt库,偶尔的情况下出现频闪,灯珠颜色不对的问题. 使用的idf版本为4.2.1 查找原因 1.首先初步认为是时序问题,先单独使用 ...
- ESP32驱动WS2812
ESP32驱动WS2812 开发环境:VSCODE+platformio,框架:Arduino 直接贴代码,注释都在代码里 #include <Arduino.h> #include &l ...
- WT32-SC01是ESP32驱动3.5彩屏开发板方案适合用arduino方式开发吗?因为需要彩屏和电容触摸的驱动的
ESP32驱动3.5寸彩屏开发板方案因为带有彩屏和电容触摸的驱动,能否用arduino方式开发,这是很多熟悉arduino开发的技术人员关心的问题. 目前启明云端推出的http://esp32.8ms ...
- 使用ESP32驱动ST7789,效果很好的IPS显示屏
前言 在平台上面购买了这一种模块,然后这种模块是IPS液晶屏,显示效果会比早期那种好一些.显示屏的控制芯片是ST7789 我准备使用ESP32进行驱动,测试上使用简单的Arduino IDE,那么具体 ...
- 解决ESP32 驱动 28BYJ-48 步进电机反向不转之震动的问题
解决ESP32 驱动 28BYJ-48 步进电机反向不转之震动的问题 date: 2021-09-19 lastmod: 2021-09-19 问题描述 Esp 32 在 mqtt 消息下通过 Ste ...
- ESP32驱动震动传感器、MAX4466(感知层)
ESP32驱动震动传感器.MAX4466(感知层) 文章目录 ESP32驱动震动传感器.MAX4466(感知层) 前言 一.物联网概述 1.物联网: 2.物联网的三层结构 二.开发环境的搭建 三.硬件 ...
- Micropython ESP32驱动CH455控制4位数码管
Micropython ESP32驱动CH455控制4位数码管 1.硬件 CH455驱动4位共阴数码管的原理图如下所示. ESP32-S模块,用GPIO4作为SCL和GPIO16作为SDA. 2.软件 ...
- ESP32驱动喇叭(syn6288),UTF-8转Unicode,包含中文驱动
本文讲讲ESP32驱动喇叭,说实话,我当初为了驱动好这个喇叭,整了三天都没整出来,而且还是我在公司实习的时候,组长一直问,这么简单还没整出来,到底是不是你人的问题,挺离谱的,但是真的挺坑的,本来SYN ...
最新文章
- 3行代码,Python数据预处理提速6倍!(附链接)
- mysql5.6,基于GTID的主从同步与延迟复制
- linux修改jdk环境变量6,Linux CentOS 6.5 使用自带jdk修改环境变量(示例代码)
- 本地Git关联远程Git时遇到的一些问题
- hadoop等的下载地址
- Mini-Batch 、Momentum、Adam算法的实现
- Java加密知识体系
- 2353410-06-5,TCO-PEG8-TFP ester单分散交联剂,含有TCO部分和PFP酯
- 如何表格合并快速简单?
- Java面试题总结-2022版
- 全国计算机等级考试二级公共,全国计算机等级考试二级公共基础知识.
- 什么是低电压处理器 笔记本CPU标准与低电压区别对比
- 如何用快慢指针在链表找到中间点
- 更改chrome主页_为什么我的Chrome主页更改了?
- 使用裁切技巧,去除视频上下黑边,保持视频画面不变形播放
- IOS m3u8格式视频流截图
- win7使用U盘重装系统
- iptables流量中转
- 数据库T-SQL语句
- Thymeleaf3.0简易教程
热门文章
- android获取drawable路径,从资源文件中获取drawable
- 在ROS(indigo)中读取手机GPS用于机器人定位~GPS2BT在ubuntu和window系统下的使用方法~
- MT8KTF51264HZ-1G9E5内存条MTA16ATF2G64HZ-2G6E1
- 专利申请流程分别从三种类型进行说明:发明专利、外观设计专利和实用新型专利
- 关于AI识别物体坐标点与追踪逻辑
- 外贸邮箱用什么好?如何绑定随心邮?
- python UserBasedCF
- 利用POST重启路由器,一直无法实现,求帮助
- mybatis SqlSessionFactory . openSession()方法执行过程
- 【Unity游戏开发教程】零基础带你从小白到超神16——四种方法控制人物移动之角色控制器