一、读取摇杆数值
为了使用ESP32读取XY摇杆的值,可以按照以下步骤操作。这里使用Arduino IDE进行编程。
所需材料
- ESP32开发板
- 摇杆模块
- 面包板和跳线
接线
- 将摇杆模块的VCC连接到ESP32的3.3V,GND连接到ESP32的GND。
- 将摇杆模块的VRx连接到ESP32的GPIO 34(可以选择任意ADC引脚),VRy连接到GPIO 35。!!!!注意注意,35、34、36、39只能输入,别踩坑
- 如果需要读取摇杆按键状态,可以将SW引脚连接到ESP32的一个数字输入引脚。
代码
int VRx = 34; // X轴引脚
int VRy = 35; // Y轴引脚
int SW = 32; // 按键引脚
void setup() {
Serial.begin(115200);
pinMode(VRx, INPUT);
pinMode(VRy, INPUT);
pinMode(SW, INPUT_PULLUP); // 如果使用按键引脚
}
void loop() {
int xValue = analogRead(VRx); // 读取X轴的值
int yValue = analogRead(VRy); // 读取Y轴的值
int swState = digitalRead(SW); // 读取按键状态(如果有)
// 打印读取的值
Serial.print("X-axis: ");
Serial.print(xValue);
Serial.print(" | Y-axis: ");
Serial.print(yValue);
Serial.print(" | Switch: ");
Serial.println(swState);
delay(500); // 延迟0.5秒
}
解释
int VRx = 34;
和int VRy = 35;
分别定义了摇杆的X轴和Y轴引脚。int SW = 32;
定义了摇杆按键引脚(如果使用)。- 在
setup()
中初始化串口通信,并设置引脚模式。 - 在
loop()
中,使用analogRead()
读取摇杆的X轴和Y轴的模拟值,并使用digitalRead()
读取按键状态。 - 打印读取的值到串口监视器。
调试与调整
- 检查接线是否正确。
- 确保摇杆模块的VCC和GND正确连接。
- 如果读取的值不正确或有噪声,可以尝试增加电源滤波电容。
这样,通过读取摇杆模块的X轴和Y轴的值,你可以在ESP32上实现各种与摇杆相关的控制和互动功能。
二、控制舵机
这里使用别人封装好的库,因为用pwm脉冲信号周期控制太麻烦了(不过可以控制LED做呼吸灯)
下一步试一下吧
使用ESP32Servo.h
库来控制舵机,可以简化控制舵机的代码,并与读取摇杆的值结合起来实现更方便的控制。以下是如何实现这一功能的详细步骤和示例代码。
安装ESP32Servo
库
- 打开Arduino IDE。
- 选择
工具
>库管理器
。 - 搜索
ESP32Servo
,然后点击安装
。
所需材料
- ESP32开发板
- 摇杆模块
- 舵机
- 面包板和跳线
接线
- 将摇杆模块的VCC连接到ESP32的3.3V,GND连接到ESP32的GND。
- 将摇杆模块的VRx连接到ESP32的GPIO 34(可以选择任意ADC引脚),VRy连接到GPIO 35。
- 将舵机的VCC连接到ESP32的5V,GND连接到ESP32的GND,信号线连接到ESP32的GPIO 13(可以选择任意PWM引脚)。
代码
#include <ESP32Servo.h>
Servo myservo; // 创建舵机对象
int VRx = 34; // X轴引脚
int VRy = 35; // Y轴引脚
int SW = 32; // 按键引脚
int servoPin = 13; // 舵机控制引脚
void setup() {
Serial.begin(115200);
myservo.attach(servoPin); // 将舵机附加到指定的引脚上
pinMode(VRx, INPUT);
pinMode(VRy, INPUT);
pinMode(SW, INPUT_PULLUP); // 如果使用按键引脚
}
void loop() {
int xValue = analogRead(VRx); // 读取X轴的值
int yValue = analogRead(VRy); // 读取Y轴的值
int swState = digitalRead(SW); // 读取按键状态(如果有)
// 将X轴和Y轴的值映射到0-180度范围内
int angleX = map(xValue, 0, 4095, 0, 180);
int angleY = map(yValue, 0, 4095, 0, 180);
// 控制舵机
myservo.write(angleX);
// 打印读取的值和映射后的角度值
Serial.print("X-axis value: ");
Serial.print(xValue);
Serial.print(" | Mapped X-axis angle: ");
Serial.print(angleX);
Serial.print(" | Y-axis value: ");
Serial.print(yValue);
Serial.print(" | Mapped Y-axis angle: ");
Serial.print(angleY);
Serial.print(" | Switch: ");
Serial.println(swState);
delay(500); // 延迟0.5秒
}
解释
#include <ESP32Servo.h>
引入了ESP32Servo
库。Servo myservo;
创建了一个舵机对象。myservo.attach(servoPin);
将舵机附加到指定的引脚上。- 在
loop()
中,读取摇杆的X轴和Y轴的模拟值,并将这些值映射到舵机的角度范围内。 - 使用
myservo.write(angleX);
控制舵机。
调试与调整
- 检查接线是否正确。
- 如果舵机抖动或反应不灵敏,可以调整代码中的映射范围和延迟时间。
- 确保舵机使用的电源足够稳定,避免电源不足导致的抖动问题。
通过这种方式,你可以使用ESP32和ESP32Servo
库通过摇杆来控制舵机,实现各种有趣的项目。
选择引脚的考虑因素
有4个引脚只能输入
- PWM功能: ESP32的几乎所有GPIO引脚都支持PWM输出功能,这是控制舵机所必需的。常用的PWM引脚有GPIO 12、GPIO 13、GPIO 14、GPIO 15等。
- 引脚冲突: 避免使用已经占用或有特殊功能的引脚。例如,GPIO 0、GPIO 2、GPIO 15在启动时有特定功能,可能会导致冲突。
- 硬件布局: 根据你的硬件布局和方便程度选择引脚。选择一个方便连接和调试的引脚。
三、XY摇杆控制两个舵机
引脚都可以自己定义,记得对照引脚图
视频
ESP32摇杆控制两个舵机
代码
里面有控制LED灯和点灯科技的物联网相关东西,可以忽略
#include "OneButton.h" //引用库函数 按钮
#include <WiFi.h>
#include <DNSServer.h>
#include <WebServer.h>
#include <WiFiManager.h>
#define BLINKER_MIOT_LIGHT
#define BLINKER_WIFI
#include <Blinker.h>
#define SERVO_PIN_1 32 //舵机接GPIO33(需要ADC引脚)
#define SERVO_PIN_2 33 //舵机接GPIO25(需要ADC引脚)
#define YJOY_PIN 35 //从双轴读取的 Y 轴将接入模拟引脚 (需要ADC引脚)
#define XJOY_PIN 34 //从双轴读取的 X 轴将接入模拟引脚 (需要ADC引脚)
#define RedLed 14 // esp32开发版的引脚号 要对照开发板引脚图 GPIO来
#define GreeLed 12
#define BlueLed 13
#include <ESP32Servo.h>
Servo myservo1;
Servo myservo2;
// 建立WiFiManager对象
WiFiManager wifiManager;
int isWifi = 1;
int isOk = 0;
volatile int a = 1000, b = 3000;
int statemachine = 0;
BlinkerButton Button1("btn1"); //这里需要根据自己在BLINKER里面设置的名字进行更改
void setup() {
// 初始化串口
Serial.begin(115200);
// rgb红色 定义输出引脚
pinMode(RedLed, OUTPUT);
// rgb绿色 定义输出引脚
pinMode(GreeLed, OUTPUT);
// rgb蓝色 定义输出引脚
pinMode(BlueLed, OUTPUT);
pinMode(XJOY_PIN, INPUT);
pinMode(YJOY_PIN, INPUT);
// pinMode(SERVO_PIN_1, OUTPUT);
// pinMode(SERVO_PIN_2, OUTPUT);
// 初始LED关闭
digitalWrite(RedLed, LOW);
digitalWrite(GreeLed, LOW);
digitalWrite(BlueLed, LOW);
myservo1.attach(SERVO_PIN_1);
myservo2.attach(SERVO_PIN_2);
// ledcSetup(1, 50, 8); // 设置通道1
// ledcAttachPin(SERVO_PIN_1, 1); // 将通道与对应的引脚连接
// ledcSetup(2, 50, 8); // 设置通道2
// ledcAttachPin(SERVO_PIN_2, 2); // 将通道与对应的引脚连接
initWifi();
initBlinker();
}
// int calculatePWM(int degree) { //0-180度
// //20ms周期,高电平0.5-2.5ms,对应0-180度角度
// const float deadZone = 6.4; //对应0.5ms(0.5ms/(20ms/256)) 舵机转动角度与占空比的关系:(角度/90+0.5)*1023/20
// const float max = 32; //对应2.5ms
// if (degree < 0)
// degree = 0;
// if (degree > 180)
// degree = 180;
// return (int)(((max - deadZone) / 180) * degree + deadZone);
// }
void initBlinker() {
BLINKER_DEBUG.stream(Serial);
String ssid = WiFi.SSID();
const char* ssid_char = ssid.c_str();
String psk = WiFi.psk();
const char* psk_char = psk.c_str();
Blinker.begin("c14dba82695f", ssid_char, psk_char);
Serial.print("要链接的wifi账号:");
Serial.println(ssid_char);
Serial.print("wifi密码:");
Serial.println(psk_char);
Button1.attach(button1_callback);
}
void loop() {
int XVal = analogRead(XJOY_PIN); //读取引脚 XJOY_PIN 上的双轴输入
int YVal = analogRead(YJOY_PIN); //读取引脚 YJOY_PIN 上的双轴输入
// // 打印读取的值
// Serial.print("X-axis: ");
// Serial.print(XVal);
// Serial.print(" | Y-axis: ");
// Serial.println(YVal);
// 在串口监视器进行串口绘图
Serial.print("X:");
Serial.println(XVal);
Serial.print("Y:");
Serial.println(YVal);
// Serial.print(" | Switch: ");
// Serial.println(swState);
// Serial.print(" 输出1舵机=");
// XVal = map(XVal, 0, 1023, 0, 179); // 转换读取数值到角度 ,1023约等于180° 179约等于0°
// Serial.println(YVal);
// Serial.print(" 输出2舵机=");
// YVal = map(YVal, 0, 1023, 0, 179);
// Serial.println(YVal);
// 将X轴和Y轴的值映射到0-180度范围内
int angleX = map(XVal, 0, 4095, 0, 180);
int angleY = map(YVal, 0, 4095, 0, 180);
myservo1.write(angleX);
myservo2.write(angleY);
Serial.print("angleX:");
Serial.println(angleX);
Serial.print("angleY:");
Serial.println(angleY);
// ledcWrite(1, calculatePWM(XVal)); // 输出PWM,设置 LEDC 通道的占空比。
// ledcWrite(2, calculatePWM(YVal)); // 输出PWM,设置 LEDC 通道的占空比。
if (isOk == 1) {
RedLedFun();
GreeLedFun();
BuleLedFun();
}
delay(30);
// 一直循环点灯科技的东西
Blinker.run();
}
void RedLedFun() {
digitalWrite(RedLed, 1);
delay(500);
digitalWrite(RedLed, 0);
}
void GreeLedFun() {
digitalWrite(GreeLed, 1);
delay(500);
digitalWrite(GreeLed, 0);
}
void BuleLedFun() {
digitalWrite(BlueLed, 1);
delay(500);
digitalWrite(BlueLed, 0);
}
void button1_callback(const String& state) {
BLINKER_LOG("get button state: ", state);
Blinker.vibrate();
if (state == "on" && isWifi == 1) {
isOk = 1;
// 给app反馈开关状态
Button1.print("on");
// 给app按钮变成绿色
Button1.color("#00cc00");
} else if (state == "off" && isWifi == 1) {
isOk = 0;
Button1.print("off");
// 给app按钮变灰色
Button1.color("#00EE00");
}
}
void initWifi() {
// wifiManager.resetSettings();
// 自动连接WiFi。以下语句的参数是连接ESP8266时的WiFi名称
wifiManager.autoConnect("33的热水壶");
// 如果您希望该WiFi添加密码,可以使用以下语句:
// wifiManager.autoConnect("AutoConnectAP", "12345678");
// 以上语句中的12345678是连接AutoConnectAP的密码
// WiFi连接成功后将通过串口监视器输出连接成功信息
Serial.println("");
Serial.print("ESP8266 Connected to ");
Serial.println(WiFi.SSID()); // WiFi名称
Serial.print("IP address:\t");
Serial.println(WiFi.localIP()); // IP
}