ESP32 读取编码器数字

关于ESP32系列芯片对旋转编码器硬件加速支持的概述。以下是针对您所提及的各款芯片的具体分析:

ESP32

  • 支持情况:ESP32支持旋转编码器的硬件加速功能,通过其内置的PCNT(Pulse Counter)模块实现。
  • 特点:ESP32的PCNT模块拥有8个可编程的计数器通道,每个通道都可以独立配置和管理,支持多种编码器模式,如全正交、半正交和单边计数模式。
  • 应用:适用于需要处理多个编码器信号的应用场景。

ESP32-C2

  • 支持情况:ESP32-C2同样支持旋转编码器的硬件加速功能。
  • 特点:虽然ESP32-C2在性能和功能上可能与ESP32有所不同,但它也集成了PCNT模块,支持旋转编码器的读取。
  • 应用:适合用于对成本敏感且需要简单无线连接功能的物联网设备,如无线控制器等。

ESP32-C3

  • 支持情况:ESP32-C3不支持旋转编码器的硬件加速功能,因为它没有PCNT模块。
  • 替代方案:如果需要使用旋转编码器,ESP32-C3可能需要依赖软件计数方法,这可能会增加CPU的负担并降低计数的精度和效率。
  • 应用:尽管不支持硬件加速的编码器读取,但ESP32-C3的低功耗和低成本特性使其在其他物联网应用场景中仍然具有吸引力。

ESP32-S3

  • 支持情况:ESP32-S3支持旋转编码器的硬件加速功能,但仅有两个PCNT模块。
  • 特点:这意味着ESP32-S3可以同时硬件加速两个编码器的读取,但无法支持更多数量的编码器。
  • 应用:适合需要处理少量编码器信号且对功耗和性能有要求的物联网设备。

总结

  • ESP32和ESP32-C2:支持旋转编码器的硬件加速功能,适用于需要处理多个编码器信号的应用场景。
  • ESP32-C3:不支持旋转编码器的硬件加速功能,可能需要依赖软件计数方法。
  • ESP32-S3:支持两个旋转编码器的硬件加速功能,适用于需要处理少量编码器信号的应用场景。

在选择芯片时,需要根据具体的应用需求来决定。如果需要处理多个编码器信号,ESP32或ESP32-C2可能是更好的选择;如果仅需要处理少量编码器信号且对功耗和成本有较高要求,ESP32-S3可能是一个不错的选择;而如果无法接受软件计数的精度和效率损失,则应避免选择ESP32-C3。

 

 

ESP32-C3:不支持旋转编码器的硬件加速功能,可能需要依赖软件计数方法。

 

复制代码
#include <Arduino.h>

// 定义编码器的A相和B相引脚
const int pinA = 2;
const int pinB = 4;

// 变量用于存储上一个状态
volatile int lastA = HIGH;
volatile int lastB = HIGH;
volatile int encoderPos = 0; // 编码器位置

// 中断服务函数
void readEncoder() {
    int newA = digitalRead(pinA);
    int newB = digitalRead(pinB);

    int encoded = (newA << 1) | newB; // 将A和B的状态组合成一个二进制值
    int sum = (lastA << 2) | encoded; // 将前一个状态和当前状态组合

    // 判断旋转方向
    if (sum == 0b1101 || sum == 0b0110 || sum == 0b1011 || sum == 0b0100) {
        int temp = encoderPos;
        temp += 1;
        encoderPos = temp; // 顺时针旋转
        Serial.println("顺时针旋转");
    } else if (sum == 0b1110 || sum == 0b0001 || sum == 0b1000 || sum == 0b0111) {
        int temp = encoderPos;
        temp -= 1;
        encoderPos = temp; // 逆时针旋转
        Serial.println("逆时针旋转");
    }

    lastA = newA; // 更新上一个A相状态
    lastB = newB; // 更新上一个B相状态
}

void setup() {
    Serial.begin(115200);
    pinMode(pinA, INPUT_PULLUP); // 设置A相引脚为上拉输入
    pinMode(pinB, INPUT_PULLUP); // 设置B相引脚为上拉输入

    // 启用中断
    attachInterrupt(digitalPinToInterrupt(pinA), readEncoder, CHANGE);
    attachInterrupt(digitalPinToInterrupt(pinB), readEncoder, CHANGE);
}

void loop() {
    // 在这里可以添加其他代码,例如处理编码器位置
    Serial.print("编码器位置: ");
    Serial.println(encoderPos);
    delay(100); // 延时,减少串口输出频率
}
复制代码

 

支持旋转编码器的硬件加速功能

复制代码
#include <ESP32Encoder.h> // https://github.com/madhephaestus/ESP32Encoder.git 
 
#define CLK 13 // CLK ENCODER 
#define DT 15 // DT ENCODER 
 
ESP32Encoder encoder;
 
void setup () { 
  encoder.attachHalfQuad ( DT, CLK );
  encoder.setCount ( 0 );
  Serial.begin ( 115200 );
}
 
void loop () {    
  long newPosition = encoder.getCount() / 2;
  Serial.println(newPosition);
} 
复制代码

 

LEDC控制电机,PIN中断读取ENCODER

复制代码
#include <Arduino.h>
// #include <driver/rtc_clk.h>
#include <stdio.h>
#include "driver/ledc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
// 定义TB6600控制角
#define TB_DIR 10
#define TB_PUL 3
#define TB_EN 2
// 定义 LED 连接的 GPIO 引脚
#define LEDC_PIN TB_PUL
// 定义 LEDC 通道和定时器
#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE  // ESP32-C3 仅支持低速模式
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_DUTY_RES LEDC_TIMER_10_BIT // 设置占空比 
void ledc_init(void)
{
      //ESP32-C3 不支持 LEDC 模块的高速模式。
    // 配置 LEDC 定时器
    ledc_timer_config_t ledc_timer = {
        .speed_mode = LEDC_MODE,
        .duty_resolution = LEDC_DUTY_RES,
        .timer_num = LEDC_TIMER,
        .freq_hz = 1000,  // 初始频率 1kHz
        .clk_cfg = LEDC_AUTO_CLK
    };
    ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));

    // 配置 LEDC 通道
    ledc_channel_config_t ledc_channel = {
        .gpio_num = LEDC_PIN,
        .speed_mode = LEDC_MODE,
        .channel = LEDC_CHANNEL,
        .timer_sel = LEDC_TIMER,
        .duty = 0,  // 初始占空比为 0%
        .hpoint = 0
    };
    ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
}
// 设置PWM波占空比
int ledc_duty(int duty)
{
  int ret;
  ret  = ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty);
  ret  = ledc_update_duty(LEDC_MODE, LEDC_CHANNEL);
  return ret;
}
//设置PWM波频率
int ledc_freq(int freq)
{
  int ret;
  ret  =  ledc_set_freq(LEDC_MODE, LEDC_TIMER, freq);
  return ret;
}

void led_control_task(void *arg)
{
    // 逐渐增加占空比到 50%
    for (int duty = 0; duty <= 511; duty += 10) {
        // ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty);
        // ledc_update_duty(LEDC_MODE, LEDC_CHANNEL);
        ledc_duty(duty);
        vTaskDelay(100 / portTICK_PERIOD_MS);  // 延迟 100ms
    }

    // 保持 50% 占空比一段时间
    vTaskDelay(2000 / portTICK_PERIOD_MS);  // 延迟 2s

    // 逐渐降低占空比到 0%
    for (int duty = 511; duty >= 0; duty -= 10) {
        // ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty);
        // ledc_update_duty(LEDC_MODE, LEDC_CHANNEL);
        ledc_duty(duty);
        vTaskDelay(100 / portTICK_PERIOD_MS);  // 延迟 100ms
    }
    ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 255);
    ledc_update_duty(LEDC_MODE, LEDC_CHANNEL);
    // 动态修改频率
    for (int freq = 1000; freq <= 50000; freq += 1000) {
        //ledc_set_freq(LEDC_MODE, LEDC_TIMER, freq);
        ledc_freq(freq);
        printf("Frequency changed to %d Hz\n", freq);
        vTaskDelay(2000 / portTICK_PERIOD_MS);  // 延迟 2s
    }
 
    // 也可以从高频逐渐降低频率
    for (int freq = 50000; freq >= 1000; freq -= 1000) {
        //ledc_set_freq(LEDC_MODE, LEDC_TIMER, freq);
        ledc_freq(freq);
        printf("Frequency changed to %d Hz\n", freq);
        vTaskDelay(2000 / portTICK_PERIOD_MS);  // 延迟 2s
    }
    // 任务完成后删除任务
    vTaskDelete(NULL);
}
//////////////////////////////////////////////////////////////////////
// 定义编码器的A相和B相引脚
const int pinA = 4;
const int pinB = 6;

// 变量用于存储上一个状态
volatile int lastA = HIGH;
volatile int lastB = HIGH;
volatile int encoderPos = 0; // 编码器位置

// 中断服务函数
void readEncoder() {
    int newA = digitalRead(pinA);
    int newB = digitalRead(pinB);

    int encoded = (newA << 1) | newB; // 将A和B的状态组合成一个二进制值
    int sum = (lastA << 2) | encoded; // 将前一个状态和当前状态组合

    // 判断旋转方向
    if (sum == 0b1101 || sum == 0b0110 || sum == 0b1011 || sum == 0b0100) {
        int temp = encoderPos;
        temp += 1;
        encoderPos = temp; // 顺时针旋转
        //Serial.println("顺时针旋转");
    } else if (sum == 0b1110 || sum == 0b0001 || sum == 0b1000 || sum == 0b0111) {
        int temp = encoderPos;
        temp -= 1;
        encoderPos = temp; // 逆时针旋转
        //Serial.println("逆时针旋转");
    }

    lastA = newA; // 更新上一个A相状态
    lastB = newB; // 更新上一个B相状态
    
}
// encoder的引脚与中断的初始化 
void initEncoder(void) {
    // 引脚初始化
    pinMode(pinA, INPUT_PULLUP); // 设置A相引脚为上拉输入
    pinMode(pinB, INPUT_PULLUP); // 设置B相引脚为上拉输入
    // 启用中断
    attachInterrupt(digitalPinToInterrupt(pinA), readEncoder, CHANGE);
    attachInterrupt(digitalPinToInterrupt(pinB), readEncoder, CHANGE);
}
/////////////////////////////////////////////////////////////////////
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  // Encoder
  initEncoder();
  // 将TB6600的控制引脚设置为输出模式
  pinMode(TB_DIR, OUTPUT);
  pinMode(TB_EN, OUTPUT);
  pinMode(TB_PUL, OUTPUT); 
  // 设置转动方向
  digitalWrite(TB_DIR, HIGH); 
  digitalWrite(TB_EN, LOW); 
  //ESP32-C3 不支持 LEDC 模块的高速模式。
  ledc_init();
  ledc_duty(255);
  ledc_freq(6400);
  // 启动一个任务来控制 PWM 信号
  //xTaskCreate(led_control_task, "led_control_task", 2048, NULL, 5, NULL);
}
int encoderPos_last =0;
void loop() {
  // put your main code here, to run repeatedly:
  // 在这里可以添加其他代码,例如处理编码器位置
  if(encoderPos_last !=encoderPos){
    //Serial.print("编码器位置: ");
    Serial.println(encoderPos);
    encoderPos_last =encoderPos;
  }
  delay(100); // 延时,减少串口输出频率
}
复制代码

 

posted @   辛河  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示