my01 — Aitewinrobot Esp32C3 Supermini simulation

An interactive Aitewinrobot Esp32C3 Supermini circuit simulation you can run free in your browser on Velxio, by y_xg.

Components

Sketch code

#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 6, 5);

// ===== 引脚 =====
#define VIBRATOR    0
#define LED_RED     1
#define LED_YELLOW  2
#define LED_GREEN   3
#define BTN_BACK    4
#define BTN_OK      7
#define BTN_ADJUST  10

// ===== 预设点 =====
float homeLat = 39.9087, homeLon = 116.3975;
float workLat = 39.9087, workLon = 116.3975 + 0.036;

float curLat = 39.9087;
float curLon = 116.3975 + 0.018;
float stepLon = 0.0024;

// ===== 菜单状态 =====
int menuState = 0;
int selectedPoint = 1;
int selectedOption = 0;
bool homeEnabled = true;
bool workEnabled = true;

unsigned long okPressStart = 0;
bool okLongHandled = false;
unsigned long lastKey = 0;
unsigned long lastDraw = 0;
unsigned long okPressTime = 0;
bool okWasPressed = false;

void setup() {
  Serial.begin(115200);
  pinMode(VIBRATOR, OUTPUT);
  pinMode(LED_RED, OUTPUT);
  pinMode(LED_YELLOW, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(BTN_BACK, INPUT_PULLUP);
  pinMode(BTN_OK, INPUT_PULLUP);
  pinMode(BTN_ADJUST, INPUT_PULLUP);

  Wire.begin(5, 6);
  u8g2.begin();
  u8g2.enableUTF8Print();
}

// ===== 图标 =====
void drawPinIcon(int x, int y) {
  u8g2.drawDisc(x + 6, y + 5, 4);
  u8g2.drawLine(x + 3, y + 8, x + 6, y + 14);
  u8g2.drawLine(x + 9, y + 8, x + 6, y + 14);
  u8g2.drawDisc(x + 6, y + 5, 1);
}

void drawArrowIcon(int x, int y) {
  u8g2.drawLine(x + 2, y + 3, x + 9, y + 7);
  u8g2.drawLine(x + 9, y + 7, x + 2, y + 11);
}

void drawGpsIcon(int x, int y, int state) {
  if (state == 2) return;
  if (state == 0) {
    if ((millis() / 500) % 2 == 0) u8g2.drawDisc(x + 8, y + 8, 3);
  } else {
    u8g2.drawDisc(x + 8, y + 12, 3);
    u8g2.drawLine(x + 8, y + 12, x + 8, y + 4);
    u8g2.drawLine(x + 8, y + 4, x + 4, y + 1);
    u8g2.drawLine(x + 8, y + 4, x + 12, y + 1);
    u8g2.drawDisc(x + 4, y + 1, 2);
    u8g2.drawDisc(x + 12, y + 1, 2);
  }
}

void drawBtIcon(int x, int y) {
  u8g2.setFont(u8g2_font_open_iconic_embedded_2x_t);
  u8g2.drawGlyph(x + 8, y + 14, 74);
}

void drawBatteryIcon(int x, int y, int level) {
  u8g2.drawFrame(x, y, 20, 10);
  u8g2.drawBox(x + 20, y + 3, 2, 4);
  u8g2.drawBox(x + 2, y + 2, level * 3, 6);
}

// ===== 宽度 =====
bool isWideChar(char c) { return (c & 0x80) != 0; }

int textWidth(String s) {
  int w = 0;
  for (int i = 0; i < s.length(); i++) {
    if (isWideChar(s[i])) { w += 14; i += 2; }
    else w += 7;
  }
  return w;
}

String truncateToWidth(String s, int maxW) {
  String result = "";
  int w = 0;
  for (int i = 0; i < s.length(); i++) {
    int charW = isWideChar(s[i]) ? 14 : 7;
    if (w + charW > maxW) break;
    result += s[i];
    if (isWideChar(s[i])) { result += s[i+1]; result += s[i+2]; i += 2; }
    w += charW;
  }
  return result;
}

// ===== 距离 =====
float calcDistance(float lat1, float lon1, float lat2, float lon2) {
  float dLat = radians(lat2 - lat1);
  float dLon = radians(lon2 - lon1);
  float a = sin(dLat/2) * sin(dLat/2) +
            cos(radians(lat