之前买了许多国产单片机esp32c3一直在吃灰,没有发挥它的真实价值。非常感谢硬禾组织的Fastbond2活动,刚好两者经过微妙的碰撞。恰可以用于FastBond2活动主题4 - 测量仪器(单片机开发测试领域),或者用于国产ESP32C3单片机简单应用开发教育等领域。回顾立项过程,且听我娓娓道来!
1.1 立项目标
设计用户操作界面,该设备具备简单易用的操作界面,外加显示屏SSD1306和旋转编码器进行显示和控制,用户后期可进行二次开发WiFi或蓝牙连接电脑或手机监控。
1.2 立项指标
- 多种数字和模拟信号的输入输出:用户可以选择不同的输入输出模式,并通过设备的操作界面进行设置。例如,用户可以选择某个GPIO口作为模拟输入引脚,然后通过设备的操作界面设置输入的电压值,以模拟外部信号的输入,达到调试简易传感器读取和执行器输出功能。
- 支持PWM输出、舵机控制特性:用户可以选择某个GPIO口作为PWM输出引脚,并通过设备的操作界面设置PWM输出的频率和占空比。用户还可以选择某个GPIO口作为舵机控制引脚,并通过设备的操作界面设置舵机的角度。
- 因此系统具有一定的电流输出能力、信号辨识能力和显示交互功能。
《FastBond2阶段2——基于ESP32C3开发的简易IO调试设备》是一种基于ESP32C3芯片开发的简易IO调试设备。它具有小巧、便携、功能强大等特点,可广泛应用于各个领域的电子设备调试和开发过程中。
市场应用介绍如下:
- 电子产品调试:该设备可以作为一种便携式的IO调试工具,用于电子产品的调试和测试。它支持多种接口,如GPIO、I2C、SPI、UART等,可以方便地与各种电子设备进行连接和通信,帮助工程师快速调试和验证电路功能。
- 物联网设备开发:随着物联网技术的发展,越来越多的设备需要与互联网进行连接和通信。该设备可以作为物联网设备开发过程中的工具,帮助开发者快速连接和通信,实现设备与云平台的数据传输和控制。
- 教育培训:该设备具有简单易用的特点,适合在教育培训领域使用。学生可以通过该设备学习和实践各种电子接口和通信协议的使用,提高他们的电子技术能力和创新能力。
- 嵌入式系统开发:对于嵌入式系统开发者来说,该设备可以作为一种基础工具,用于快速原型设计和验证。通过该设备,开发者可以快速连接和测试各种外设,并进行相关的软硬件开发工作。
- DIY爱好者:该设备适合DIY爱好者使用,他们可以利用该设备进行各种创意项目的开发。无论是控制LED灯的亮灭,还是与其他传感器进行数据交互,都可以通过该设备实现,并为DIY爱好者们带来更多的乐趣和创造力。
综上所述,《FastBond2阶段2——基于ESP32C3开发的简易IO调试设备》具有广泛的市场应用前景。它可以满足不同领域的需求,为电子产品调试、物联网设备开发、教育培训、嵌入式系统开发和DIY爱好者等提供了简单、便捷、高效的解决方案。
项目地址:Scheme-it | 嵌入式快速调试设备 | DigiKey
得捷电子的Scheme-it工具融合了原理图、框图和流程图绘制等功能,支持多种格式导出。并且,得捷电子提供原理图kicad格式导出的功能,同步导出对应器件的封装,减少查找封装的麻烦。Scheme-it无需专门下载安装,在浏览器在线运行,上手速度很快。这里我非常迅速画了系统的方案框图:
这里面的外设驱动详细内容见:【Arduino环境下驱动合宙esp32c3单片机基本外设】
4.1 系统设计流程图
接下来就是一步一个脚印把模块调通,最后进行解耦实验,有机会就用3D打印机打印一个外壳。如系统设计流程图所示
系统设计流程图是一个用于描述系统设计过程的流程图。在这个流程中,首先进行的是项目立项,然后进入系统设计阶段,包括结构设计和硬件模块设计。在硬件模块设计中,又包括硬件模块设计和软件模块设计。然后进行联合调试,如果调试成功,就进行系统设计修改,如果调试失败,就回到硬件模块设计进行更改,直到调试成功。最后,进行是总结并记录归档。
4.2 电路原理图
这里采用kicad绘制的原理图,这里面的蜂鸣器电路设计有缺陷,因此我加250Ω电阻直接飞线绕过三极管驱动蜂鸣器,我之前画过电路图(设计有诸多不合理,欢迎大家批评指正),但从来都没有打板子,这是我第一次打板子验证项目,非常感谢硬禾给机会,太感动了!
设计用户操作界面,该设备具备简单易用的操作界面,外加显示屏SSD1306和旋转编码器进行显示和控制,用户后期可进行二次开发WiFi或蓝牙连接电脑或手机监控。
多种数字和模拟信号的输入输出:用户可以选择不同的输入输出模式,并通过设备的操作界面进行设置。 引出了开发板全部可用端口,其中包括GPIO、ADC、UART、IIC、SPI端口。
这里面的外设驱动详细内容见:【Arduino环境下驱动合宙esp32c3单片机基本外设】
这里采用了 乐鑫科技(Espressif)的ESP32-C3-MINI-1-N4,由于之前合宙esp32c3可以等效替代,对此采用这款合宙esp32c3开发板代替,是采用ESP32-C3-MINI-1-N4模组设计的。
由于项目需要达到300元包邮,所以我选购了Pi400键盘系统
期待后期有发光发热的地方叫上鹏鹏哦!
6.1 PCB板图
工程整体采用两层板结构;
底层覆铜设计,右边是覆铜效果,左边没有覆铜效果;
采用esp32c3单片机放在中间,底部板载USB供电,靠上设计SSD1306屏幕显示,基本外设左右排开,左边有SPI、舵机端口、ADC和WS2812。右边设计有蜂鸣器和旋转编码器,中间开发板的端口全部引出。
设计的尺寸非常小宽7.37*长8.64,四周设计了立柱。
6.2 3D封装效果图
所选封装比较杂乱,偏向传统与现代工业融合
第一次下单 嘉立创返回说我没有阻焊层,修改ganber文件导出后,第二次下单工艺信息,大约5天左右就到啦!国产雄起
6.3 实物图
打板图
实物图
6.4 遇到的问题
1. 蜂鸣器驱动设计错误,解决办法:直接连接IO口,不过pwm控制效果区别不明显
2. WS2812封装对应错误,解决办法:选择引出的GPIO驱动,完美!
总共迭代了四个版本
7.1 版本1.0
是通过ChatGPT生成的,然后结合自己开发的外设调试,搭建了基本框架,可以屏幕显示,有舵机、ws2812和ADC交互控制显示,需要安装以下5个库
- #include <U8g2lib.h>
- #include <Encoder.h>
- #include <ESP32Servo.h>
- #include <FastLED.h>
- #include <WS2812FX.h>
// #define ENCODER_DO_NOT_USE_INTERRUPTS #include <U8g2lib.h> #include <Encoder.h> #include <ESP32Servo.h> #include <FastLED.h> #include <WS2812FX.h> #define OLED_CLOCK 5 #define OLED_DATA 4 #define OLED_RESET U8X8_PIN_NONE #define ENCODER_CLK 7 #define ENCODER_DT 6 #define ENCODER_SW 8 #define SERVO_PIN 19 #define LED_PIN 18 #define NUM_LEDS 4 #define SENSOR_PIN 0 U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/OLED_CLOCK, /* data=*/OLED_DATA, /* reset=*/OLED_RESET); // ESP32 Thing, pure SW emulated I2C Encoder encoder(ENCODER_CLK, ENCODER_DT); // ESP32PWM pwm; Servo myservo; // create servo object to control a servo CRGB leds[NUM_LEDS]; int currentMenu = 0; int servoAngle = 0; int ledColorIndex = 0; int sensorValue = 0; int encoderButtonState = 0; long position = 0; long newPos = 0; void setup() { ESP32PWM::allocateTimer(0); ESP32PWM::allocateTimer(1); ESP32PWM::allocateTimer(2); ESP32PWM::allocateTimer(3); myservo.setPeriodHertz(50); // standard 50 hz servo myservo.attach(SERVO_PIN, 1000, 2000); // attaches the servo on pin 18 to the servo object Serial.begin(9600); u8g2.begin(); u8g2.setFont(u8g2_font_ncenB14_tr); pinMode(ENCODER_SW, INPUT_PULLUP); FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS); // pwm.setPeriodHertz(50); // pwm.attachServo(SERVO_PIN); } void loop() { u8g2.clearBuffer(); switch (currentMenu) { case 0: // Main menu u8g2.setCursor(0, 20); u8g2.print("1. Servo"); u8g2.setCursor(0, 40); u8g2.print("2. WS2812"); u8g2.setCursor(0, 60); u8g2.print("3. Sensor"); break; case 1: // Servo menu // int servoencoderValue = 0; u8g2.setCursor(0, 20); u8g2.print("Servo Angle: "); u8g2.setCursor(30, 40); u8g2.print(servoAngle); // Handle servo control servoAngle = servoAngle + checkencoder(); if (servoAngle > 180) { servoAngle = 180; } else if (servoAngle < 0) { servoAngle = 0; } myservo.write(servoAngle); break; case 2: // WS2812 menu // int LEDencoderValue = 0; u8g2.setCursor(0, 20); u8g2.print("LED Color: "); u8g2.setCursor(30, 40); u8g2.print(ledColorIndex); // Handle LED color control ledColorIndex = ledColorIndex + checkencoder(); if (ledColorIndex < 0) { ledColorIndex = 0; } else if (ledColorIndex > 2) { ledColorIndex = 2; } setLedColor(); break; case 3: // Sensor menu u8g2.setCursor(0, 20); u8g2.print("Sensor Value: "); u8g2.setCursor(30, 40); u8g2.print(sensorValue); // Read sensor value sensorValue = analogRead(SENSOR_PIN); break; } u8g2.sendBuffer(); // Handle menu navigation encoderButtonState = digitalRead(ENCODER_SW); if (encoderButtonState == LOW) { delay(50); // Debounce delay encoderButtonState = digitalRead(ENCODER_SW); if (encoderButtonState == LOW) { currentMenu++; if (currentMenu > 3) { currentMenu = 0; } delay(200); // Debounce delay } } } int checkencoder() { newPos = encoder.read(); Serial.println("newPos:" + String(newPos) + "position:" + String(position)); delay(1); if (newPos > position) { position = newPos; return 1; } else if (newPos < position) { position = newPos; return -1; } return 0; } void setLedColor() { switch (ledColorIndex) { case 0: leds[0] = CRGB::Red; leds[1] = CRGB::Red; leds[2] = CRGB::Red; leds[3] = CRGB::Red; break; case 1: leds[0] = CRGB::Green; leds[1] = CRGB::Green; leds[2] = CRGB::Green; leds[3] = CRGB::Green; break; case 2: leds[0] = CRGB::Blue; leds[1] = CRGB::Blue; leds[2] = CRGB::Blue; leds[3] = CRGB::Blue; break; } FastLED.show(); }
7.2 版本1.1
增加了蜂鸣器控制,设计四级菜单,WS2812由三种颜色怎加到10种,解决旋转编码器无法减法控制,添加按键返回功能
// #define ENCODER_DO_NOT_USE_INTERRUPTS #include <U8g2lib.h> #include <Encoder.h> #include <ESP32Servo.h> #include <FastLED.h> #include <WS2812FX.h> #define OLED_CLOCK 5 #define OLED_DATA 4 #define OLED_RESET U8X8_PIN_NONE #define ENCODER_CLK 7 #define ENCODER_DT 6 #define ENCODER_SW 8 #define SERVO_PIN 19 #define LED_PIN 18 #define NUM_LEDS 4 #define SENSOR_PIN 0 #define SENSOR_PIN2 1 #define BUZZER 13 U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/OLED_CLOCK, /* data=*/OLED_DATA, /* reset=*/OLED_RESET); // ESP32 Thing, pure SW emulated I2C // 创建Encoder对象 Encoder myEncoder(ENCODER_CLK, ENCODER_DT); // ESP32PWM pwm; Servo myservo; // create servo object to control a servo CRGB leds[NUM_LEDS]; int currentMenu = 0; int servoAngle = 0; int ledColorIndex = 0; int sensorValue = 0; int sensorValue2 = 0; int BuzzerValue = 128; int encoderButtonState = 0; long position = 0; long newPos = 0; long oldPosition = 0; int increment = 0; int ws = 0; void setup() { myservo.setPeriodHertz(50); // standard 50 hz servo myservo.attach(SERVO_PIN, 1000, 2000); // attaches the servo on pin 18 to the servo object Serial.begin(9600); u8g2.begin(); u8g2.setFont(u8g2_font_ncenB14_tr); pinMode(ENCODER_SW, INPUT_PULLUP); pinMode(ENCODER_CLK, INPUT_PULLUP); pinMode(ENCODER_DT, INPUT_PULLUP); pinMode(BUZZER, OUTPUT); FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS); for (int i = 0; i < NUM_LEDS; i++) { leds[i] = getColor(-1); } FastLED.show(); // pwm.setPeriodHertz(50); // pwm.attachServo(SERVO_PIN); } void loop() { u8g2.clearBuffer(); switch (currentMenu) { case 0: // Main menu u8g2.setCursor(30, 20); u8g2.print("Main menu"); u8g2.setFont(u8g2_font_ncenB08_tr); u8g2.setCursor(0, 40); u8g2.print("1. Servo"); u8g2.setCursor(0, 60); u8g2.print("2. WS2812"); u8g2.setCursor(64, 40); u8g2.print("3. Sensor"); u8g2.setCursor(64, 60); u8g2.print("4. Buzzer"); break; case 1: // Servo menu // int servoencoderValue = 0; u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 20); u8g2.print("Servo Angle: "); u8g2.setCursor(30, 40); u8g2.print(servoAngle); u8g2.sendBuffer(); while (1) { if (checkencoder() == true) { setservo(); increment = 0; } if (checkswitch() == true) { break; } } break; case 2: // WS2812 menu // int LEDencoderValue = 0; u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 20); u8g2.print("LED Color: "); u8g2.setCursor(30, 40); u8g2.print(ledColorIndex); u8g2.sendBuffer(); // Handle LED color control while (1) { if (checkencoder() == true) { setLedColor(); increment = 0; } if (checkswitch() == true) { break; } } break; case 3: // Sensor menu u8g2.setFont(u8g2_font_ncenB08_tr); u8g2.setCursor(10, 30); u8g2.print("Sensor1: "); u8g2.setCursor(64, 30); u8g2.print(sensorValue); u8g2.setCursor(10, 60); u8g2.print("Sensor2: "); u8g2.setCursor(64, 60); u8g2.print(sensorValue2); // Read sensor value sensorValue = analogRead(SENSOR_PIN); sensorValue2 = analogRead(SENSOR_PIN2); break; case 4: // Buzzer menu u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 20); u8g2.print("Buzzer Value: "); u8g2.setCursor(30, 40); u8g2.print(BuzzerValue); // Handle Buzzer control while (1) { if (checkencoder() == true) { setbuzzer(); increment = 0; } if (checkswitch() == true) { break; } } break; } increment = 0; u8g2.sendBuffer(); // Handle menu navigation if (checkswitch() == true) { currentMenu++; if (currentMenu > 4) { currentMenu = 0; } delay(200); // Debounce delay } } bool checkencoder() { long newPosition = myEncoder.read(); if (newPosition != oldPosition) { // Serial.println(newPosition + String(";") + oldPosition); increment = newPosition - oldPosition; oldPosition = newPosition; return true; } return false; } bool checkswitch() { encoderButtonState = digitalRead(ENCODER_SW); if (encoderButtonState == LOW) { delay(50); // Debounce delay encoderButtonState = digitalRead(ENCODER_SW); if (encoderButtonState == LOW) { return true; } else { return false; } } else { return false; } } void setLedColor() { ledColorIndex = ledColorIndex + increment; if (ledColorIndex < 0) { ledColorIndex = 0; } else if (ledColorIndex > 10) { ledColorIndex = 10; } u8g2.setCursor(30, 40); u8g2.print(ledColorIndex); u8g2.sendBuffer(); for (int i = 0; i < NUM_LEDS; i++) { leds[i] = getColor(ledColorIndex); } FastLED.show(); delay(1); } void setservo() { servoAngle = servoAngle + increment*3; if (servoAngle > 180) { servoAngle = 180; } else if (servoAngle < 0) { servoAngle = 0; } u8g2.setCursor(30, 40); u8g2.print(servoAngle); u8g2.sendBuffer(); myservo.write(servoAngle); } void setbuzzer() { BuzzerValue = BuzzerValue + increment*8; if (BuzzerValue > 255) { BuzzerValue = 255; } else if (BuzzerValue < 0) { BuzzerValue = 0; } u8g2.setCursor(30, 40); u8g2.print(BuzzerValue); u8g2.sendBuffer(); analogWrite(BUZZER, BuzzerValue); } CRGB getColor(int index) { switch (index) { case 0: return CRGB::Red; case 1: return CRGB::Green; case 2: return CRGB::Blue; case 3: return CRGB::Yellow; case 4: return CRGB::Magenta; case 5: return CRGB::Cyan; case 6: return CRGB::White; case 7: return CRGB::Purple; case 8: return CRGB::Orange; case 9: return CRGB::Pink; default: return CRGB::Black; } }
7.3 版本1.2
增加了蓝牙交互,设计五级菜单,通过蓝牙上传设备状态信息,并且可接收手机端数据,但未完成控制设备。值得注意这个版本最稳定
// #define ENCODER_DO_NOT_USE_INTERRUPTS #include <U8g2lib.h> #include <Encoder.h> #include <ESP32Servo.h> #include <FastLED.h> #include <WS2812FX.h> #include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h> #define OLED_CLOCK 5 #define OLED_DATA 4 #define OLED_RESET U8X8_PIN_NONE #define ENCODER_CLK 7 #define ENCODER_DT 6 #define ENCODER_SW 8 #define SERVO_PIN 19 #define LED_PIN 18 #define NUM_LEDS 4 #define SENSOR_PIN 0 #define SENSOR_PIN2 1 #define BUZZER 13 #define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID #define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" #define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" //创建Bluetooth对象 BLECharacteristic *pCharacteristic; //创建SSD1306屏幕对象 U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/OLED_CLOCK, /* data=*/OLED_DATA, /* reset=*/OLED_RESET); // ESP32 Thing, pure SW emulated I2C // 创建Encoder对象 Encoder myEncoder(ENCODER_CLK, ENCODER_DT); // ESP32PWM pwm; Servo myservo; // create servo object to control a servo CRGB leds[NUM_LEDS]; int currentMenu = 0; int servoAngle = 0; int ledColorIndex = 0; int sensorValue = 0; int sensorValue2 = 0; int BuzzerValue = 128; int encoderButtonState = 0; long position = 0; long newPos = 0; long oldPosition = 0; int increment = 0; bool deviceConnected = false; char BLEbuf[256] = { 0 }; uint32_t cnt = 0; String message_c; char *message; // const char *message1; class MyServerCallbacks : public BLEServerCallbacks { void onConnect(BLEServer *pServer) { deviceConnected = true; }; void onDisconnect(BLEServer *pServer) { deviceConnected = false; } }; class MyCallbacks : public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string rxValue = pCharacteristic->getValue(); if (rxValue.length() > 0) { Serial.print("------>Received Value: "); for (int i = 0; i < rxValue.length(); i++) { Serial.print(rxValue[i]); } Serial.println(); } } }; void setup() { myservo.setPeriodHertz(50); // standard 50 hz servo myservo.attach(SERVO_PIN, 1000, 2000); // attaches the servo on pin 18 to the servo object Serial.begin(115200); u8g2.begin(); u8g2.clearDisplay(); pinMode(ENCODER_SW, INPUT_PULLUP); pinMode(ENCODER_CLK, INPUT_PULLUP); pinMode(ENCODER_DT, INPUT_PULLUP); pinMode(BUZZER, OUTPUT); FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS); for (int i = 0; i < NUM_LEDS; i++) { leds[i] = getColor(-1); } FastLED.show(); // Create the BLE Device BLEDevice::init("ESP32 BLE vor"); // 创建蓝牙服务器 BLEServer *pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); // // 创建广播服务的UUID BLEService *pService = pServer->createService(SERVICE_UUID); // 创建广播服务的UUID pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY); pCharacteristic->addDescriptor(new BLE2902()); BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE); pCharacteristic->setCallbacks(new MyCallbacks()); // 开始蓝牙服务 pService->start(); // 开始广播 pServer->getAdvertising()->start(); Serial.println("Waiting a client connection to notify..."); } void loop() { u8g2.clearBuffer(); switch (currentMenu) { case 0: // Main menu u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(7, 22); u8g2.print("Main menu"); u8g2.setFont(u8g2_font_ncenB08_tr); u8g2.setCursor(0, 40); u8g2.print("1. Servo"); u8g2.setCursor(0, 60); u8g2.print("2. WS2812"); u8g2.setCursor(64, 40); u8g2.print("3. Sensor"); u8g2.setCursor(64, 60); u8g2.print("4. Buzzer"); break; case 1: // Servo menu // int servoencoderValue = 0; u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 20); u8g2.print("Servo Angle: "); u8g2.setCursor(30, 40); u8g2.print(servoAngle); u8g2.sendBuffer(); while (1) { if (checkencoder() == true) { setservo(); increment = 0; } if (checkswitch() == true) { break; } } break; case 2: // WS2812 menu // int LEDencoderValue = 0; u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 20); u8g2.print("LED Color: "); u8g2.setCursor(30, 40); u8g2.print(ledColorIndex); u8g2.sendBuffer(); // Handle LED color control while (1) { if (checkencoder() == true) { setLedColor(); increment = 0; } if (checkswitch() == true) { break; } } break; case 3: // Sensor menu u8g2.setFont(u8g2_font_ncenB08_tr); u8g2.setCursor(10, 30); u8g2.print("Sensor1: "); u8g2.setCursor(64, 30); u8g2.print(sensorValue); u8g2.setCursor(10, 60); u8g2.print("Sensor2: "); u8g2.setCursor(64, 60); u8g2.print(sensorValue2); // Read sensor value sensorValue = analogRead(SENSOR_PIN); sensorValue2 = analogRead(SENSOR_PIN2); break; case 4: // Buzzer menu u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 20); u8g2.print("Buzzer Value: "); u8g2.setCursor(30, 40); u8g2.print(BuzzerValue); // Handle Buzzer control while (1) { if (checkencoder() == true) { setbuzzer(); increment = 0; } if (checkswitch() == true) { break; } } break; case 5: // Blue uart u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 20); u8g2.print("Blue uart : "); u8g2.setFont(u8g2_font_ncenB08_tr); u8g2.setCursor(0, 40); u8g2.print(BuzzerValue); // Handle Buzzer control while (1) { setbluetooth(); if (checkswitch() == true) { break; } } break; default: break; } increment = 0; u8g2.sendBuffer(); // Handle menu navigation if (checkswitch() == true) { currentMenu++; if (currentMenu > 5) { currentMenu = 0; } delay(200); // Debounce delay } } bool checkencoder() { long newPosition = myEncoder.read(); if (newPosition != oldPosition) { // Serial.println(newPosition + String(";") + oldPosition); increment = newPosition - oldPosition; oldPosition = newPosition; return true; } return false; } bool checkswitch() { encoderButtonState = digitalRead(ENCODER_SW); if (encoderButtonState == LOW) { delay(50); // Debounce delay encoderButtonState = digitalRead(ENCODER_SW); if (encoderButtonState == LOW) { return true; } else { return false; } } else { return false; } } void setLedColor() { ledColorIndex = ledColorIndex + increment; if (ledColorIndex < 0) { ledColorIndex = 0; } else if (ledColorIndex > 10) { ledColorIndex = 10; } u8g2.setCursor(30, 40); u8g2.print(ledColorIndex); u8g2.sendBuffer(); for (int i = 0; i < NUM_LEDS; i++) { leds[i] = getColor(ledColorIndex); } FastLED.show(); delay(1); } void setservo() { servoAngle = servoAngle + increment * 3; if (servoAngle > 180) { servoAngle = 180; } else if (servoAngle < 0) { servoAngle = 0; } u8g2.setCursor(30, 40); u8g2.print(servoAngle); u8g2.sendBuffer(); myservo.write(servoAngle); } void setbuzzer() { BuzzerValue = BuzzerValue + increment * 8; if (BuzzerValue > 255) { BuzzerValue = 255; } else if (BuzzerValue < 0) { BuzzerValue = 0; } u8g2.setCursor(30, 40); u8g2.print(BuzzerValue); u8g2.sendBuffer(); analogWrite(BUZZER, BuzzerValue); } void setbluetooth() { if (deviceConnected) { //设备连接后,每秒钟发送txValue。 memset(BLEbuf, 0, 32); message_c = "s "+String(servoAngle)+" w"+String(ledColorIndex)+" s"+String(analogRead(SENSOR_PIN))+"s"+String(analogRead(SENSOR_PIN2))+"b"+String(BuzzerValue)+"\n"; char* p = const_cast<char*>(message_c.c_str()); memcpy(BLEbuf, p, 32); pCharacteristic->setValue(BLEbuf); pCharacteristic->notify(); // Send the value to the app! Serial.print("*** Sent Value: "); Serial.print(BLEbuf); Serial.println(" ***"); // sensorValue = analogRead(SENSOR_PIN); // sensorValue2 = analogRead(SENSOR_PIN2); // memset(BLEbuf, 0, 256); // // sprintf(message, "S%dW%dS%dS%dB%d", servoAngle, ledColorIndex, sensorValue, sensorValue2, BuzzerValue); // sprintf(message, "S%dW%d", servoAngle, ledColorIndex); // // message_c = message; // // char* p = const_cast<char*>(message.c_str()); // // message1 = message; // memcpy(BLEbuf, message, 256); // // memcpy(BLEbuf, message_c, 32); // pCharacteristic->setValue(BLEbuf); // pCharacteristic->notify(); // Send the value to the app! // delay(10); u8g2.setCursor(0, 40); u8g2.print(BLEbuf); // // u8g2.setCursor(0, 60); // // u8g2.print(message_c.substring(15, 32)); u8g2.sendBuffer(); // Serial.println("Sent Value:" + String(BLEbuf)); delay(100); } } CRGB getColor(int index) { switch (index) { case 0: return CRGB::Red; case 1: return CRGB::Green; case 2: return CRGB::Blue; case 3: return CRGB::Yellow; case 4: return CRGB::Magenta; case 5: return CRGB::Cyan; case 6: return CRGB::White; case 7: return CRGB::Purple; case 8: return CRGB::Orange; case 9: return CRGB::Pink; default: return CRGB::Black; } }
7.4 版本1.3
设计了两个线程,完成了实时的蓝牙交互,不过ws2812控制不稳定。推荐版本1.2
// #define ENCODER_DO_NOT_USE_INTERRUPTS #include <U8g2lib.h> #include <Encoder.h> #include <ESP32Servo.h> #include <FastLED.h> #include <WS2812FX.h> #include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h> #define OLED_CLOCK 5 #define OLED_DATA 4 #define OLED_RESET U8X8_PIN_NONE #define ENCODER_CLK 7 #define ENCODER_DT 6 #define ENCODER_SW 8 #define SERVO_PIN 19 #define LED_PIN 18 #define NUM_LEDS 4 #define SENSOR_PIN 0 #define SENSOR_PIN2 1 #define BUZZER 13 #define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID #define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" #define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" //创建Bluetooth对象 BLECharacteristic *pCharacteristic; //创建SSD1306屏幕对象 U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/OLED_CLOCK, /* data=*/OLED_DATA, /* reset=*/OLED_RESET); // ESP32 Thing, pure SW emulated I2C // 创建Encoder对象 Encoder myEncoder(ENCODER_CLK, ENCODER_DT); // ESP32PWM pwm; Servo myservo; // create servo object to control a servo CRGB leds[NUM_LEDS]; int currentMenu = 0; int servoAngle = 0; int ledColorIndex = 0; int sensorValue = 0; int sensorValue2 = 0; int BuzzerValue = 128; int encoderButtonState = 0; long position = 0; long newPos = 0; long oldPosition = 0; int increment = 0; bool deviceConnected = false; char BLEbuf[256] = { 0 }; uint32_t cnt = 0; String message_c; char *message; // const char *message1; class MyServerCallbacks : public BLEServerCallbacks { void onConnect(BLEServer *pServer) { deviceConnected = true; }; void onDisconnect(BLEServer *pServer) { deviceConnected = false; } }; class MyCallbacks : public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string rxValue = pCharacteristic->getValue(); if (rxValue.length() > 0) { Serial.print("------>Received Value: "); for (int i = 0; i < rxValue.length(); i++) { Serial.print(rxValue[i]); } Serial.println(); } } }; void appCpuLoop(void *pvParameters) { while (true) { if (currentMenu != 5) { memset(BLEbuf, 0, 32); message_c = "s " + String(servoAngle) + "w" + String(ledColorIndex) + " s" + String(analogRead(SENSOR_PIN)) + "s" + String(analogRead(SENSOR_PIN2)) + "b" + String(BuzzerValue) + "\r\n"; char *p = const_cast<char *>(message_c.c_str()); memcpy(BLEbuf, p, 32); pCharacteristic->setValue(BLEbuf); pCharacteristic->notify(); // Send the value to the app! Serial.print("*** Sent Value: "); Serial.print(BLEbuf); Serial.println(" ***"); delay(700); } delay(300); } vTaskDelete(NULL); } void setup() { myservo.setPeriodHertz(50); // standard 50 hz servo myservo.attach(SERVO_PIN, 1000, 2000); // attaches the servo on pin 18 to the servo object Serial.begin(115200); u8g2.begin(); u8g2.clearDisplay(); pinMode(ENCODER_SW, INPUT_PULLUP); pinMode(ENCODER_CLK, INPUT_PULLUP); pinMode(ENCODER_DT, INPUT_PULLUP); pinMode(BUZZER, OUTPUT); FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS); for (int i = 0; i < NUM_LEDS; i++) { leds[i] = getColor(-1); } FastLED.show(); // Create the BLE Device BLEDevice::init("ESP32 BLE vor"); // 创建蓝牙服务器 BLEServer *pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); // // 创建广播服务的UUID BLEService *pService = pServer->createService(SERVICE_UUID); // 创建广播服务的UUID pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY); pCharacteristic->addDescriptor(new BLE2902()); BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE); pCharacteristic->setCallbacks(new MyCallbacks()); // 开始蓝牙服务 pService->start(); // 开始广播 pServer->getAdvertising()->start(); Serial.println("Waiting a client connection to notify..."); xTaskCreatePinnedToCore(appCpuLoop, //具体实现的函数 "APP_CPU_LOOP", //任务名称 8192, //堆栈大小 NULL, //输入参数 1, //任务优先级 NULL, // 1 //核心 0\1 ); } void loop() { u8g2.clearBuffer(); switch (currentMenu) { case 0: // Main menu u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(7, 22); u8g2.print("Main menu"); u8g2.setFont(u8g2_font_ncenB08_tr); u8g2.setCursor(0, 40); u8g2.print("1. Servo"); u8g2.setCursor(0, 60); u8g2.print("2. WS2812"); u8g2.setCursor(64, 40); u8g2.print("3. Sensor"); u8g2.setCursor(64, 60); u8g2.print("4. Buzzer"); break; case 1: // Servo menu // int servoencoderValue = 0; u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 20); u8g2.print("Servo Angle: "); u8g2.setCursor(30, 40); u8g2.print(servoAngle); u8g2.sendBuffer(); while (1) { if (checkencoder() == true) { setservo(); increment = 0; } if (checkswitch() == true) { break; } } break; case 2: // WS2812 menu // int LEDencoderValue = 0; u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 20); u8g2.print("LED Color: "); u8g2.setCursor(30, 40); u8g2.print(ledColorIndex); u8g2.sendBuffer(); // Handle LED color control while (1) { if (checkencoder() == true) { setLedColor(); increment = 0; } if (checkswitch() == true) { break; } } break; case 3: // Sensor menu u8g2.setFont(u8g2_font_ncenB08_tr); u8g2.setCursor(10, 30); u8g2.print("Sensor1: "); u8g2.setCursor(64, 30); u8g2.print(sensorValue); u8g2.setCursor(10, 60); u8g2.print("Sensor2: "); u8g2.setCursor(64, 60); u8g2.print(sensorValue2); // Read sensor value sensorValue = analogRead(SENSOR_PIN); sensorValue2 = analogRead(SENSOR_PIN2); break; case 4: // Buzzer menu u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 20); u8g2.print("Buzzer Value: "); u8g2.setCursor(30, 40); u8g2.print(BuzzerValue); // Handle Buzzer control while (1) { if (checkencoder() == true) { setbuzzer(); increment = 0; } if (checkswitch() == true) { break; } } break; case 5: // Blue uart u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 20); u8g2.print("Blue uart : "); u8g2.setFont(u8g2_font_ncenB08_tr); u8g2.setCursor(0, 40); u8g2.print(BuzzerValue); // Handle Buzzer control while (1) { setbluetooth(); if (checkswitch() == true) { break; } } break; default: break; } increment = 0; u8g2.sendBuffer(); // Handle menu navigation if (checkswitch() == true) { currentMenu++; if (currentMenu > 5) { currentMenu = 0; } delay(200); // Debounce delay } } bool checkencoder() { long newPosition = myEncoder.read(); if (newPosition != oldPosition) { // Serial.println(newPosition + String(";") + oldPosition); increment = newPosition - oldPosition; oldPosition = newPosition; return true; } return false; } bool checkswitch() { encoderButtonState = digitalRead(ENCODER_SW); if (encoderButtonState == LOW) { delay(50); // Debounce delay encoderButtonState = digitalRead(ENCODER_SW); if (encoderButtonState == LOW) { return true; } else { return false; } } else { return false; } } void setLedColor() { ledColorIndex = ledColorIndex + increment; if (ledColorIndex < 0) { ledColorIndex = 0; } else if (ledColorIndex > 10) { ledColorIndex = 10; } u8g2.setCursor(30, 40); u8g2.print(ledColorIndex); u8g2.sendBuffer(); for (int i = 0; i < NUM_LEDS; i++) { leds[i] = getColor(ledColorIndex); } FastLED.show(); delay(1); } void setservo() { servoAngle = servoAngle + increment * 3; if (servoAngle > 180) { servoAngle = 180; } else if (servoAngle < 0) { servoAngle = 0; } u8g2.setCursor(30, 40); u8g2.print(servoAngle); u8g2.sendBuffer(); myservo.write(servoAngle); } void setbuzzer() { BuzzerValue = BuzzerValue + increment * 8; if (BuzzerValue > 255) { BuzzerValue = 255; } else if (BuzzerValue < 0) { BuzzerValue = 0; } u8g2.setCursor(30, 40); u8g2.print(BuzzerValue); u8g2.sendBuffer(); analogWrite(BUZZER, BuzzerValue); } void setbluetooth() { if (deviceConnected) { //设备连接后,每秒钟发送txValue。 memset(BLEbuf, 0, 32); message_c = "s " + String(servoAngle) + "w" + String(ledColorIndex) + " s" + String(analogRead(SENSOR_PIN)) + "s" + String(analogRead(SENSOR_PIN2)) + "b" + String(BuzzerValue) + "\r\n"; char *p = const_cast<char *>(message_c.c_str()); memcpy(BLEbuf, p, 32); pCharacteristic->setValue(BLEbuf); pCharacteristic->notify(); // Send the value to the app! Serial.print("*** Sent Value: "); Serial.print(BLEbuf); Serial.println(" ***"); // sensorValue = analogRead(SENSOR_PIN); // sensorValue2 = analogRead(SENSOR_PIN2); // memset(BLEbuf, 0, 256); // // sprintf(message, "S%dW%dS%dS%dB%d", servoAngle, ledColorIndex, sensorValue, sensorValue2, BuzzerValue); // sprintf(message, "S%dW%d", servoAngle, ledColorIndex); // // message_c = message; // // char* p = const_cast<char*>(message.c_str()); // // message1 = message; // memcpy(BLEbuf, message, 256); // // memcpy(BLEbuf, message_c, 32); // pCharacteristic->setValue(BLEbuf); // pCharacteristic->notify(); // Send the value to the app! // delay(10); u8g2.setCursor(0, 40); u8g2.print(BLEbuf); // // u8g2.setCursor(0, 60); // // u8g2.print(message_c.substring(15, 32)); u8g2.sendBuffer(); // Serial.println("Sent Value:" + String(BLEbuf)); delay(100); } } CRGB getColor(int index) { switch (index) { case 0: return CRGB::Red; case 1: return CRGB::Green; case 2: return CRGB::Blue; case 3: return CRGB::Yellow; case 4: return CRGB::Magenta; case 5: return CRGB::Cyan; case 6: return CRGB::White; case 7: return CRGB::Purple; case 8: return CRGB::Orange; case 9: return CRGB::Pink; default: return CRGB::Black; } }
8.1 主菜单显示
主菜单显示,所有设备初始化,舵机归位,灯灭,蜂鸣器静音
8.2 舵机控制
舵机显示60度位置,屏幕同步数值
8.3 WS2812控制
WS2812显示蓝色灯,屏幕同步数值
8.4 ADC读取
实时读取光敏ADC,屏幕同步数值
8.5 蜂鸣器PWM
蜂鸣器输出PWM,屏幕同步数值
8.6 蓝牙交互
手机连接ESP32 BLE vor蓝牙,发送数据
屏幕读取状态
手机实时接收设备信息
电脑串口显示设备状态和接收手机数据
这是我第四次参加嵌入式相关的网上比赛活动
- 第一次是RT-Thread的【基于RT-Thread+RA6M4的智能鱼缸系统设计之鱼我所欲也】活动,作品是2022年暑假做的获得第六名,还是比较开心!
- 第二次2023年寒假做的是【基于MAX7800羽毛板语音控制ESP8266小车】,成绩还没有出来,第七名。
- 第三次2023年春做的【基于腾讯云的CH32V307开发板远程机械臂小车】,由于图床引用CSDN导致最后评审没有显示出来,最后获得安慰奖
这次最大的收获是第一次实现了PCB板设计、制作和调试全流程,加深了对手机蓝牙双向通信,对esp32国产单片机更有信心!
这次最大的遗憾是没有加入蓝牙控制程序,相信大家自己解决哒。
建议:
- 希望得捷电子优化国内访问网站浏览和提高scheme-it工具设计水平;
- 期待硬禾联合各大平台推出更多有质量有意义持续性的创客活动!
非常感谢硬禾联合得捷电子官方组织的FastBond2活动,大家都为这个国内嵌入式生态出一份力,只要努力认真做了都会有所收获,期盼这些作品在将来某一天为构建美好未来贡献一份微博之力!
我后期会持续更新我测评的一系列国内开发板测评,并且作为宣传大使努力鼓励大家有所获参加有质量的硬禾活动🛹🛹🛹每天都一点点结合实际需求联动丰富生活,从而实现对外部世界进行充分的感知,尽最大努力认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣
🥳🥳🥳再次非常感谢硬禾的Lucia支持等等🥳🥳🥳期待这一次的成绩哟!
参考文献:
FastBond2阶段1——基于ESP32C3开发的简易IO调试设备
【Arduino环境下驱动合宙esp32c3单片机基本外设】