FastBond2阶段2——基于ESP32C3开发的简易IO调试设备
-
1. 项目介绍
之前买了许多国产单片机esp32c3一直在吃灰,没有发挥它的真实价值。非常感谢硬禾组织的Fastbond2活动,刚好两者经过微妙的碰撞。恰可以用于FastBond2活动主题4 - 测量仪器(单片机开发测试领域),或者用于国产ESP32C3单片机简单应用开发教育等领域。回顾立项过程,且听我娓娓道来!
1.1 立项目标
设计用户操作界面,该设备具备简单易用的操作界面,外加显示屏SSD1306和旋转编码器进行显示和控制,用户后期可进行二次开发WiFi或蓝牙连接电脑或手机监控。
1.2 立项指标
- 多种数字和模拟信号的输入输出:用户可以选择不同的输入输出模式,并通过设备的操作界面进行设置。例如,用户可以选择某个GPIO口作为模拟输入引脚,然后通过设备的操作界面设置输入的电压值,以模拟外部信号的输入,达到调试简易传感器读取和执行器输出功能。
- 支持PWM输出、舵机控制特性:用户可以选择某个GPIO口作为PWM输出引脚,并通过设备的操作界面设置PWM输出的频率和占空比。用户还可以选择某个GPIO口作为舵机控制引脚,并通过设备的操作界面设置舵机的角度。
- 因此系统具有一定的电流输出能力、信号辨识能力和显示交互功能。
-
2. 市场应用介绍
《FastBond2阶段2——基于ESP32C3开发的简易IO调试设备》是一种基于ESP32C3芯片开发的简易IO调试设备。它具有小巧、便携、功能强大等特点,可广泛应用于各个领域的电子设备调试和开发过程中。
市场应用介绍如下:
-
电子产品调试:该设备可以作为一种便携式的IO调试工具,用于电子产品的调试和测试。它支持多种接口,如GPIO、I2C、SPI、UART等,可以方便地与各种电子设备进行连接和通信,帮助工程师快速调试和验证电路功能。
-
物联网设备开发:随着物联网技术的发展,越来越多的设备需要与互联网进行连接和通信。该设备可以作为物联网设备开发过程中的工具,帮助开发者快速连接和通信,实现设备与云平台的数据传输和控制。
-
教育培训:该设备具有简单易用的特点,适合在教育培训领域使用。学生可以通过该设备学习和实践各种电子接口和通信协议的使用,提高他们的电子技术能力和创新能力。
-
嵌入式系统开发:对于嵌入式系统开发者来说,该设备可以作为一种基础工具,用于快速原型设计和验证。通过该设备,开发者可以快速连接和测试各种外设,并进行相关的软硬件开发工作。
-
DIY爱好者:该设备适合DIY爱好者使用,他们可以利用该设备进行各种创意项目的开发。无论是控制LED灯的亮灭,还是与其他传感器进行数据交互,都可以通过该设备实现,并为DIY爱好者们带来更多的乐趣和创造力。
综上所述,《FastBond2阶段2——基于ESP32C3开发的简易IO调试设备》具有广泛的市场应用前景。它可以满足不同领域的需求,为电子产品调试、物联网设备开发、教育培训、嵌入式系统开发和DIY爱好者等提供了简单、便捷、高效的解决方案。
-
3. 项目设计思路
项目地址:Scheme-it | 嵌入式快速调试设备 | DigiKey
得捷电子的Scheme-it工具融合了原理图、框图和流程图绘制等功能,支持多种格式导出。并且,得捷电子提供原理图kicad格式导出的功能,同步导出对应器件的封装,减少查找封装的麻烦。Scheme-it无需专门下载安装,在浏览器在线运行,上手速度很快。这里我非常迅速画了系统的方案框图:
这里面的外设驱动详细内容见:【Arduino环境下驱动合宙esp32c3单片机基本外设】
-
4. 项目方案框图和原理图解释
4.1 系统设计流程图
接下来就是一步一个脚印把模块调通,最后进行解耦实验,有机会就用3D打印机打印一个外壳。如系统设计流程图所示
系统设计流程图是一个用于描述系统设计过程的流程图。在这个流程中,首先进行的是项目立项,然后进入系统设计阶段,包括结构设计和硬件模块设计。在硬件模块设计中,又包括硬件模块设计和软件模块设计。然后进行联合调试,如果调试成功,就进行系统设计修改,如果调试失败,就回到硬件模块设计进行更改,直到调试成功。最后,进行是总结并记录归档。
4.2 电路原理图
这里采用kicad绘制的原理图,这里面的蜂鸣器电路设计有缺陷,因此我加250Ω电阻直接飞线绕过三极管驱动蜂鸣器,我之前画过电路图(设计有诸多不合理,欢迎大家批评指正),但从来都没有打板子,这是我第一次打板子验证项目,非常感谢硬禾给机会,太感动了!
设计用户操作界面,该设备具备简单易用的操作界面,外加显示屏SSD1306和旋转编码器进行显示和控制,用户后期可进行二次开发WiFi或蓝牙连接电脑或手机监控。
多种数字和模拟信号的输入输出:用户可以选择不同的输入输出模式,并通过设备的操作界面进行设置。 引出了开发板全部可用端口,其中包括GPIO、ADC、UART、IIC、SPI端口。
这里面的外设驱动详细内容见:【Arduino环境下驱动合宙esp32c3单片机基本外设】
-
5. 设计中用到规定厂商的元器件介绍
这里采用了 乐鑫科技(Espressif)的ESP32-C3-MINI-1-N4,由于之前合宙esp32c3可以等效替代,对此采用这款合宙esp32c3开发板代替,是采用ESP32-C3-MINI-1-N4模组设计的。
ESP32C3MINI1技术规格书
ESP32-C3 系列芯片
由于项目需要达到300元包邮,所以我选购了Pi400键盘系统
期待后期有发光发热的地方叫上鹏鹏哦!
-
6. PCB绘制打板介绍及遇到的问题和解决方法
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. 关键代码及说明
总共迭代了四个版本
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 0U8G2_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 servomyservo.attach(SERVO_PIN, 1000, 2000); // attaches the servo on pin 18 to the servo objectSerial.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 menuu8g2.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 controlservoAngle = 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 controlledColorIndex = ledColorIndex + checkencoder();if (ledColorIndex < 0) {ledColorIndex = 0;} else if (ledColorIndex > 2) {ledColorIndex = 2;}setLedColor();break;case 3: // Sensor menuu8g2.setCursor(0, 20);u8g2.print("Sensor Value: ");u8g2.setCursor(30, 40);u8g2.print(sensorValue);// Read sensor valuesensorValue = analogRead(SENSOR_PIN);break;}u8g2.sendBuffer();// Handle menu navigationencoderButtonState = digitalRead(ENCODER_SW);if (encoderButtonState == LOW) {delay(50); // Debounce delayencoderButtonState = 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 13U8G2_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 servomyservo.attach(SERVO_PIN, 1000, 2000); // attaches the servo on pin 18 to the servo objectSerial.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 menuu8g2.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 controlwhile (1) {if (checkencoder() == true) {setLedColor();increment = 0;}if (checkswitch() == true) {break;}}break;case 3: // Sensor menuu8g2.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 valuesensorValue = analogRead(SENSOR_PIN);sensorValue2 = analogRead(SENSOR_PIN2);break;case 4: // Buzzer menuu8g2.setFont(u8g2_font_ncenB14_tr);u8g2.setCursor(0, 20);u8g2.print("Buzzer Value: ");u8g2.setCursor(30, 40);u8g2.print(BuzzerValue);// Handle Buzzer controlwhile (1) {if (checkencoder() == true) {setbuzzer();increment = 0;}if (checkswitch() == true) {break;}}break;}increment = 0;u8g2.sendBuffer();// Handle menu navigationif (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 delayencoderButtonState = 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 servomyservo.attach(SERVO_PIN, 1000, 2000); // attaches the servo on pin 18 to the servo objectSerial.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 DeviceBLEDevice::init("ESP32 BLE vor");// 创建蓝牙服务器BLEServer *pServer = BLEDevice::createServer();pServer->setCallbacks(new MyServerCallbacks());// // 创建广播服务的UUIDBLEService *pService = pServer->createService(SERVICE_UUID);// 创建广播服务的UUIDpCharacteristic = 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 menuu8g2.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 controlwhile (1) {if (checkencoder() == true) {setLedColor();increment = 0;}if (checkswitch() == true) {break;}}break;case 3: // Sensor menuu8g2.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 valuesensorValue = analogRead(SENSOR_PIN);sensorValue2 = analogRead(SENSOR_PIN2);break;case 4: // Buzzer menuu8g2.setFont(u8g2_font_ncenB14_tr);u8g2.setCursor(0, 20);u8g2.print("Buzzer Value: ");u8g2.setCursor(30, 40);u8g2.print(BuzzerValue);// Handle Buzzer controlwhile (1) {if (checkencoder() == true) {setbuzzer();increment = 0;}if (checkswitch() == true) {break;}}break;case 5: // Blue uartu8g2.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 controlwhile (1) {setbluetooth();if (checkswitch() == true) {break;}}break;default:break;}increment = 0;u8g2.sendBuffer();// Handle menu navigationif (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 delayencoderButtonState = 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 servomyservo.attach(SERVO_PIN, 1000, 2000); // attaches the servo on pin 18 to the servo objectSerial.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 DeviceBLEDevice::init("ESP32 BLE vor");// 创建蓝牙服务器BLEServer *pServer = BLEDevice::createServer();pServer->setCallbacks(new MyServerCallbacks());// // 创建广播服务的UUIDBLEService *pService = pServer->createService(SERVICE_UUID);// 创建广播服务的UUIDpCharacteristic = 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 menuu8g2.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 controlwhile (1) {if (checkencoder() == true) {setLedColor();increment = 0;}if (checkswitch() == true) {break;}}break;case 3: // Sensor menuu8g2.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 valuesensorValue = analogRead(SENSOR_PIN);sensorValue2 = analogRead(SENSOR_PIN2);break;case 4: // Buzzer menuu8g2.setFont(u8g2_font_ncenB14_tr);u8g2.setCursor(0, 20);u8g2.print("Buzzer Value: ");u8g2.setCursor(30, 40);u8g2.print(BuzzerValue);// Handle Buzzer controlwhile (1) {if (checkencoder() == true) {setbuzzer();increment = 0;}if (checkswitch() == true) {break;}}break;case 5: // Blue uartu8g2.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 controlwhile (1) {setbluetooth();if (checkswitch() == true) {break;}}break;default:break;}increment = 0;u8g2.sendBuffer();// Handle menu navigationif (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 delayencoderButtonState = 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. 功能展示及说明
8.1 主菜单显示
主菜单显示,所有设备初始化,舵机归位,灯灭,蜂鸣器静音
8.2 舵机控制
舵机显示60度位置,屏幕同步数值
8.3 WS2812控制
WS2812显示蓝色灯,屏幕同步数值
8.4 ADC读取
实时读取光敏ADC,屏幕同步数值
8.5 蜂鸣器PWM
蜂鸣器输出PWM,屏幕同步数值
8.6 蓝牙交互
手机连接ESP32 BLE vor蓝牙,发送数据
屏幕读取状态
手机实时接收设备信息
电脑串口显示设备状态和接收手机数据
-
9总结
这是我第四次参加嵌入式相关的网上比赛活动
- 第一次是RT-Thread的【基于RT-Thread+RA6M4的智能鱼缸系统设计之鱼我所欲也】活动,作品是2022年暑假做的获得第六名,还是比较开心!
- 第二次2023年寒假做的是【基于MAX7800羽毛板语音控制ESP8266小车】,成绩还没有出来,第七名。
- 第三次2023年春做的【基于腾讯云的CH32V307开发板远程机械臂小车】,由于图床引用CSDN导致最后评审没有显示出来,最后获得安慰奖
这次最大的收获是第一次实现了PCB板设计、制作和调试全流程,加深了对手机蓝牙双向通信,对esp32国产单片机更有信心!
这次最大的遗憾是没有加入蓝牙控制程序,相信大家自己解决哒。
建议:
- 希望得捷电子优化国内访问网站浏览和提高scheme-it工具设计水平;
- 期待硬禾联合各大平台推出更多有质量有意义持续性的创客活动!
非常感谢硬禾联合得捷电子官方组织的FastBond2活动,大家都为这个国内嵌入式生态出一份力,只要努力认真做了都会有所收获,期盼这些作品在将来某一天为构建美好未来贡献一份微博之力!
我后期会持续更新我测评的一系列国内开发板测评,并且作为宣传大使努力鼓励大家有所获参加有质量的硬禾活动🛹🛹🛹每天都一点点结合实际需求联动丰富生活,从而实现对外部世界进行充分的感知,尽最大努力认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣
🥳🥳🥳再次非常感谢硬禾的Lucia支持等等🥳🥳🥳期待这一次的成绩哟!
参考文献:
FastBond2阶段1——基于ESP32C3开发的简易IO调试设备 - 电子森林 (eetree.cn)
【esp32c3配置arduino IDE教程】-CSDN博客
【Arduino环境下驱动合宙esp32c3单片机基本外设】-CSDN博客
相关文章:

FastBond2阶段2——基于ESP32C3开发的简易IO调试设备
1. 项目介绍 之前买了许多国产单片机esp32c3一直在吃灰,没有发挥它的真实价值。非常感谢硬禾组织的Fastbond2活动,刚好两者经过微妙的碰撞。恰可以用于FastBond2活动主题4 - 测量仪器(单片机开发测试领域),或者用于国…...

03、SpringBoot + 微信支付 ---- 创建订单、保存二维码url、显示订单列表
目录 Native 下单1、创建课程订单保存到数据库1-1:需求:1-2:代码:1-3:测试结果: 2、保存支付二维码的url2-1:需求:2-2:代码:2-3:测试:…...

【echarts基础】在柱形图上设置文本
一、需求描述 在柱状图上设置文本标签,按需修改它的颜色、大小、边框、阴影等,如下。 二、代码展示 series:[{name:"螺蛳粉",type:"bar",data:data.data.chartData.chartData.num.螺蛳粉,label:{//图形上显示文本标签formatter:&q…...

小户型工业风,陌生上开花知书香。福州中宅装饰,福州装修
漫步陌上 只因陌上花开 花是自然的那种 朴素而恬淡,不落尘俗。—徐志摩 小户型工业风格 满足业主需求 筑造书香押韵家 从动线、色彩、选材、定制等各个环节 与业主一起畅谈家的构造 形成别“居”一格的温暖品质家 以书做墙 告别电视墙 这是一个实用性很强的…...

Gorm 中的迁移指南
探索使用 GORM 在 Go 中进行数据库迁移和模式更改的世界 在应用程序开发的不断变化的景观中,数据库模式更改是不可避免的。GORM,强大的 Go 对象关系映射库,通过迁移提供了一种无缝的解决方案来管理这些变化。本文将作为您全面的指南…...

基于.NET、Uni-App开发支持多平台的小程序商城系统 - CoreShop
前言 小程序商城系统是当前备受追捧的开发领域,它可以为用户提供一个更加便捷、流畅、直观的购物体验,无需下载和安装,随时随地轻松使用。今天给大家推荐一个基于.NET、Uni-App开发支持多平台的小程序商城系统(该商城系统完整开源…...
[python] 在多线程中将`logging.info`输出到不同的文件中 (生产者消费者)
在多线程中将logging.info输出到不同的文件中,可以使用Python标准库中的Queue和Thread模块。具体实现步骤如下: 创建多个Queue队列用于不同线程的日志输出,每个队列对应一个日志文件。 import queue# 创建三个队列用于不同线程的日志输出 l…...

MySQL进阶_5.逻辑架构和SQL执行流程
文章目录 第一节、逻辑架构剖析1.1、服务器处理客户端请求1.2、Connectors1.3、第1层:连接层1.4、第2层:服务层1.5、 第3层:引擎层1.6、 存储层1.7、小结 第二节、SQL执行流程2.1、查询缓存2.2、解析器2.3、优化器2.4、执行器 第三节、数据库…...

【油猴脚本】学习笔记
目录 新建用户脚本模板源注释 测试代码获取图标 Tampermonkey v4.19.0 原教程:手写油猴脚本,几分钟学会新技能——王子周棋洛 Tampermonkey首页 面向 Web 开发者的文档 Greasy Fork 新建用户脚本 打开【管理面板】 点击【】,即…...

宝塔面板使用Supervisor进程守护插件,配置守护Mysql的操作教程。
本篇文章主要讲解,在宝塔面板中使用Supervisor进程守护插件,配置守护Mysql的操作教程。 作者:任聪聪 日期:2023年11月5日 一、安装守护进程插件 安装插件一、进程守护插件 安装说明:在软件商店中搜索“进程守护”&am…...
Electron[2] Electron使用准备
1 背景 介绍一个技术栈的入门基础,往往要以该技术栈的入门案例作为开始比较合适,更能诱惑到刚需的粉丝,深度的学习。Electron的入门也不例外。在入门案例的讲解过程中,我们会学习到Electron引入需要的准备工作有哪些。 2 入门案例…...
npm create vue@latest 原理
文章目录 使用实际调用流程 使用 npm create vitelatest当执行上述命令时,会通过一个可交互的命令行终端下载模版,实际最终是调用 create-vue 库实现的 实际调用流程 npm create、innit 实际是 npm init 别名 ,npm init 后面加包名时,实际…...

【Unity基础】7.动画状态参数
【Unity基础】7.动画状态参数 大家好,我是Lampard~~ 欢迎来到Unity基础系列博客,所学知识来自B站阿发老师~感谢 (一)创建动画状态 (1) 创建动画状态 不好意思各位~最近工作比较忙,稍微耽误了这两周的博客。话…...

C语言映射表在串口数据解析中的应用
一、映射表在串口数据解析中的应用 1、数据结构 typedef struct {char CMD[CMDLen];unsigned char (*cmd_operate)(char *data); }Usart_Tab; 2、指令、函数映射表 static const Usart_Tab InstructionList[CMDMax] {{"PWON",PowOn},{"PWOFF",PowOff}…...
叁[3],感兴趣区域ROI
1,简介 ROI,感兴趣区域(region of interest),截取图像 2,获取方法 方法1:使用Rect cv::Mat srccv::imread("*.bmp");//读取原图 cv::Mat matROI src(cv::Rect(100,200,50,100));//截取原图&am…...
文件数据交换格式说明
对于文件的说明 二进制文件和文本文件的对比 对比项二进制文件文本文件定义二进制文件直接由二进制数字0和1组成,不存在统一的字符编码。文本文件是基于字符编码的文件,一般采用定长编码方式,如ASCII编码、UNICODE编码。优势1. 存储利用率高…...
2023NOIP A层联测24 总结
T1 给出树的一度点和三度点的数量,构造树的形态,节点数不超过 2000 2000 2000。我考虑先构造出三度点,发现这一度点至少是三度点2,打完后测样例不对,发现加一度点时要特判是否为三度点,花 5min 打完&#…...
vue3 项目如何配置测试环境打包
vue3 项目如何配置测试环境打包 根目录下创建.env.staging # 测试环境 NODE_ENV staging VUE_APP_MODE staging VUE_APP_TITLE 系统名称# 测试环境API接口地址 VUE_APP_API_URL 接口地址package.json文件中 scripts配置中添加以下代码 "scripts": {"serve&q…...
【CSS】样式的计算过程
标签的 CSS 样式 现在有这么一段 HTML 代码: <div class"test"><h1>Hello World</h1> </div>目前我们没有给 h1 设置任何样式,可以看到 h1 自带了一些样式,eg:font-size、font-weight、margi…...
【ArcGIS微课1000例】0076:KMZ转换KML的方法
文章目录 ArcGIS转kmzkmz转kmlArcGIS转kmz ArcGIS可以很方便的将dwg,shp、等矢量数据转为kmz。 拓展阅读: 【ArcGIS微课1000例】0075:将AutoCAD(Dwg、Dxf)文件转换为shp、KML(kml、kmz)文件...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...