Mạch ESP32 tích hợp OLED 0.96 và pin 18650: sơ đồ chân, sạc pin, đo % pin và chương trình đầu tiên

Mạch ESP32 tích hợp OLED 0.96 inch và đế pin 18650: chân OLED GPIO5, GPIO4, LED GPIO16, sạc pin, công tắc, gắn cầu phân áp đo phần trăm pin và chương trình hiện lên màn hình.

Mạch ESP32 tích hợp màn hình OLED 0.96 inch và đế pin 18650 gom vào một bo những thứ mà thiết bị cầm tay cần: vi điều khiển có Wi-Fi, Bluetooth, màn hình hiển thị, pin sạc và công tắc nguồn. Không cần cắm dây cho màn hình, không cần mạch sạc rời. Bài này giới thiệu các phần trên mạch, sơ đồ chân và các chân đã dùng sẵn, cách sạc pin, cách gắn thêm cầu phân áp để đo phần trăm pin, và một chương trình đầu tiên hiện thông tin lên màn hình.

1. Trên mạch có gì

Mạch ESP32 tích hợp màn hình OLED 0.96 inch và đế pin 18650 của PYWORLD, mặt trên có màn hình, module ESP32, cổng Micro USB và công tắc
Ảnh thực tế mạch ESP32 OLED 18650, mặt trên.
  • Module ESP32-WROOM-32: Wi-Fi, Bluetooth, lập trình bằng Arduino IDE như mạch ESP32 DevKit.
  • Màn hình OLED 0.96 inch 128 × 64 điểm, chip SSD1306, giao tiếp I2C địa chỉ 0x3C, đã nối sẵn vào GPIO5 (SDA) và GPIO4 (SCL).
  • Đế pin 18650 ở mặt sau (pin không kèm theo mạch) và mạch sạc, xả trên bo: cắm nguồn 5 V qua cổng Micro USB là vừa sạc pin vừa chạy.
  • Đèn báo trạng thái sạc và đầy pin; công tắc bật, tắt nguồn.
  • LED trên mạch nối vào GPIO16.

Theo mô tả của shop, một pin 18650 cho mạch chạy khoảng 20 giờ với chương trình đơn giản; thời gian thực tế phụ thuộc pin và việc dùng Wi-Fi nhiều hay ít.

2. Sơ đồ chân và các chân đã dùng sẵn

Sơ đồ chân mạch ESP32 OLED 18650: hai hàng 20 chân, GPIO5 GPIO4 nối màn hình OLED, GPIO16 nối LED, chân chỉ đọc 34 35 36 39, chân khởi động 0 2 12 15, chân flash 6 đến 11
Hai hàng chân của mạch, tô màu theo công dụng (hình minh họa).
ChânĐang dùng choLưu ý
GPIO5, GPIO4Màn hình OLED (SDA, SCL)Không dùng việc khác. Cảm biến I2C thêm vào thì nối chung hai chân này.
GPIO16LED trên mạchDùng làm đèn báo trong chương trình.
GPIO34, 35, 36, 39TrốngChỉ đọc (ADC1, đọc nút nhấn, cảm biến analog); không có điện trở kéo lên bên trong.
GPIO0, 2, 12, 15TrốngChân ảnh hưởng tới lúc khởi động: tránh nối thiết bị kéo mức cố định.
GPIO6 đến 11Bộ nhớ flashKhông dùng.
GPIO13, 14, 17, 18, 19, 21, 22, 23, 25, 26, 27, 32, 33TrốngDùng thoải mái cho cảm biến, relay, nút nhấn.

Thứ tự chân trong hình vẽ theo tài liệu của nhà cung cấp. Trước khi hàn hay cắm dây, đối chiếu với chữ in cạnh từng chân trên mạch. Cách chọn chân ESP32 chi tiết hơn xem bài sơ đồ chân ESP32 DevKit V1.

3. Lắp pin, sạc pin và công tắc

Đường nguồn trên mạch ESP32 OLED 18650: Micro USB 5 V vào mạch sạc xả, pin 18650 mặt sau, công tắc bật tắt nguồn cho ESP32 và màn hình
Đường nguồn trên mạch nhìn từ phía người dùng (hình minh họa).
  1. Lắp pin 18650 vào đế ở mặt sau, đúng chiều theo ký hiệu + và − trên đế. Lắp ngược pin có thể làm hỏng mạch ngay.
  2. Sạc: cắm củ sạc 5 V (từ 1 A) vào cổng Micro USB. Đèn báo cho biết đang sạc hay đã đầy.
  3. Chạy bằng pin: rút USB, gạt công tắc sang bật.
  4. Cất máy: gạt công tắc về tắt để pin không bị xả dần.

Dùng pin 18650 thật, dung lượng 2000–3500 mAh; pin ghi dung lượng quá cao thường là hàng kém. Cách chọn, ghép pin 18650 được trình bày trong bài về ghép pin 18650 cùng loạt bài này.

4. Cài đặt để lập trình

  1. Trong Arduino IDE 2, cài gói ESP32 và chọn bo mạch ESP32 Dev Module như bài cài ESP32 vào Arduino IDE 2.
  2. Vào Tools → Manage Libraries, tìm và cài Adafruit SSD1306; Arduino IDE hỏi cài kèm Adafruit GFX Library thì chọn cài cả hai.
  3. Cắm cáp Micro USB có dây dữ liệu, chọn đúng cổng COM. Máy tính không nhận cổng thì xem bài ESP32 không nhận cổng COM.

5. Gắn cầu phân áp để đo phần trăm pin

Mạch không có sẵn chân đo điện áp pin. Muốn hiện phần trăm pin, gắn thêm một cầu phân áp hai điện trở 100 kΩ:

Cầu phân áp hai điện trở 100 kΩ từ cực dương pin 18650 xuống GND, điểm giữa nối vào GPIO35 của mạch ESP32 OLED 18650 để đo điện áp pin
Cầu phân áp đo điện áp pin (hình minh họa).
  • R1 100 kΩ: một đầu hàn vào cực dương của đế pin ở mặt sau, đầu kia nối vào chân GPIO35.
  • R2 100 kΩ: từ GPIO35 xuống chân GND.
  • Pin đầy 4,2 V cho 2,1 V ở GPIO35, trong khoảng đo của ESP32. Dòng chạy qua cầu khoảng 21 µA, tức khoảng 0,5 mAh mỗi ngày, không đáng kể so với dung lượng pin.
  • GPIO35 thuộc ADC1 nên đo được cả khi bật Wi-Fi.

Phần trăm pin được ước lượng từ điện áp theo một bảng có sẵn, nên chỉ là số gần đúng: khi ESP32 đang phát Wi-Fi, điện áp pin tụt xuống một chút và phần trăm hiện thấp hơn. Cách đo pin bằng ADC và hiệu chỉnh số đo được trình bày kỹ ở bài đo điện áp pin 18650 bằng ESP32.

6. Chương trình đầu tiên

Chương trình hiện chữ PYWORLD, thời gian chạy và điện áp, phần trăm pin lên màn hình, nháy LED GPIO16 mỗi giây và in cùng thông tin ra Serial Monitor (115200 baud). Khi chưa gắn cầu phân áp, để nguyên DA_GAN_CAU_DO_PIN = false; màn hình hiện "Pin: chua do". Gắn cầu xong thì đổi thành true và nạp lại.

Bài dùng gói esp32 phiên bản 3.3.10, thư viện Adafruit SSD1306 2.5.17 và Adafruit GFX Library 1.12.6.

// PYWORLD.VN - Chương trình đầu tiên cho mạch ESP32 tích hợp màn hình OLED 0.96 inch và đế pin 18650
// PYWORLD.VN - Màn hình SSD1306 nối sẵn trên mạch: SDA = GPIO5, SCL = GPIO4; LED trên mạch ở GPIO16
// PYWORLD.VN - Đo điện áp pin qua cầu phân áp 100 kΩ / 100 kΩ hàn thêm vào GPIO35, hiện phần trăm pin ước lượng

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

const int SDA_PIN = 5;
const int SCL_PIN = 4;
const int LED_PIN = 16;
const uint8_t DIA_CHI_OLED = 0x3C;

// Đổi thành true sau khi đã hàn cầu phân áp từ cực dương đế pin xuống GPIO35 (xem bài viết).
// Khi chưa hàn, chân GPIO35 bỏ trống nên số đọc được không có nghĩa.
const bool DA_GAN_CAU_DO_PIN = false;
const int CHAN_DO_PIN = 35;           // chân chỉ đọc, thuộc ADC1: đo được cả khi bật Wi-Fi
const float R1_OHM = 100000.0;        // nối từ cực dương pin tới GPIO35
const float R2_OHM = 100000.0;        // nối từ GPIO35 xuống GND
const float HE_SO_CHINH = 1.000;      // = điện áp đo bằng đồng hồ / điện áp chương trình in ra

// Bảng điện áp pin Li-ion lúc nghỉ và phần trăm tương ứng (ước lượng thô, giống bài đo pin 18650 bằng ADC)
const float BANG_VON[] = {4.20, 4.06, 3.98, 3.92, 3.87, 3.82, 3.79, 3.77, 3.74, 3.68, 3.45, 3.00};
const int BANG_PHAN_TRAM[] = {100, 90, 80, 70, 60, 50, 40, 30, 20, 10, 5, 0};
const int SO_MUC = sizeof(BANG_PHAN_TRAM) / sizeof(BANG_PHAN_TRAM[0]);

Adafruit_SSD1306 manHinh(128, 64, &Wire, -1);
bool coManHinh = false;

float docDienApPin() {
  uint32_t tong = 0;
  for (int i = 0; i < 16; i++) {
    tong += analogReadMilliVolts(CHAN_DO_PIN);
    delay(2);
  }
  float vonTaiChan = tong / 16.0 / 1000.0;
  return vonTaiChan * (R1_OHM + R2_OHM) / R2_OHM * HE_SO_CHINH;
}

int phanTramPin(float von) {
  if (von >= BANG_VON[0]) {
    return 100;
  }
  for (int i = 1; i < SO_MUC; i++) {
    if (von >= BANG_VON[i]) {
      // Nội suy tuyến tính giữa hai mức liền nhau trong bảng
      float tiLe = (von - BANG_VON[i]) / (BANG_VON[i - 1] - BANG_VON[i]);
      return BANG_PHAN_TRAM[i] + (int)(tiLe * (BANG_PHAN_TRAM[i - 1] - BANG_PHAN_TRAM[i]) + 0.5);
    }
  }
  return 0;
}

// Biểu tượng pin 24 x 12 điểm ảnh ở góc phải, phần tô đậm theo phần trăm
void veBieuTuongPin(int phanTram) {
  manHinh.drawRect(100, 46, 24, 12, SSD1306_WHITE);
  manHinh.fillRect(124, 49, 3, 6, SSD1306_WHITE);
  manHinh.fillRect(102, 48, 20 * phanTram / 100, 8, SSD1306_WHITE);
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  analogSetAttenuation(ADC_11db);  // thang đo rộng nhất cho mọi chân ADC

  Wire.begin(SDA_PIN, SCL_PIN);
  // Hỏi thử địa chỉ I2C trước: hàm begin() của thư viện SSD1306 không tự phát hiện màn hình chưa nối
  Wire.beginTransmission(DIA_CHI_OLED);
  if (Wire.endTransmission() == 0 && manHinh.begin(SSD1306_SWITCHCAPVCC, DIA_CHI_OLED)) {
    coManHinh = true;
  } else {
    Serial.println("Khong thay OLED o dia chi 0x3C (SDA GPIO5, SCL GPIO4)");
  }
  Serial.println("PYWORLD.VN - ESP32 OLED 18650");
}

void loop() {
  static uint32_t lanTruoc = 0;
  static bool denSang = false;
  if (millis() - lanTruoc < 1000) {
    return;
  }
  lanTruoc = millis();

  denSang = !denSang;
  digitalWrite(LED_PIN, denSang ? HIGH : LOW);  // nháy LED trên mạch mỗi giây
  unsigned long giay = millis() / 1000;

  float von = 0;
  int phanTram = -1;
  if (DA_GAN_CAU_DO_PIN) {
    von = docDienApPin();
    phanTram = phanTramPin(von);
    Serial.printf("Chay %lu s | Pin %.2f V, khoang %d %%\n", giay, von, phanTram);
  } else {
    Serial.printf("Chay %lu s | chua gan cau do pin\n", giay);
  }

  if (coManHinh) {
    manHinh.clearDisplay();
    manHinh.setTextColor(SSD1306_WHITE);
    manHinh.setTextSize(2);
    manHinh.setCursor(0, 0);
    manHinh.print("PYWORLD");
    manHinh.setTextSize(1);
    manHinh.setCursor(0, 20);
    manHinh.print("ESP32 OLED 18650");
    manHinh.setCursor(0, 34);
    manHinh.printf("Chay: %lus", giay);
    manHinh.setCursor(0, 48);
    if (phanTram >= 0) {
      manHinh.printf("Pin %.2fV %d%%", von, phanTram);
      veBieuTuongPin(phanTram);
    } else {
      manHinh.print("Pin: chua do");
    }
    manHinh.display();
  }
}
Màn hình OLED của mạch ESP32 OLED 18650 khi chạy chương trình: chữ PYWORLD, thời gian chạy, điện áp và phần trăm pin kèm biểu tượng pin
Màn hình khi chưa và đã gắn cầu đo pin (hình minh họa, số liệu ví dụ).

Các phần chính của chương trình:

  • Wire.begin(5, 4) mở I2C ở đúng hai chân màn hình đã nối sẵn. Chương trình hỏi thử địa chỉ 0x3C trước khi khởi tạo, vì hàm begin() của thư viện không tự phát hiện màn hình không phản hồi.
  • phanTramPin() nội suy tuyến tính giữa hai mức trong bảng điện áp, giống bài đo pin bằng ADC.
  • HE_SO_CHINH: đo điện áp pin bằng đồng hồ vạn năng, chia cho số chương trình in ra, ghi kết quả vào đây để số đo khớp hơn.
  • Vòng lặp dùng millis() để cập nhật mỗi giây mà không chặn chương trình, dễ thêm phần đọc cảm biến hay Wi-Fi về sau.

7. Lỗi thường gặp

Hiện tượngNguyên nhân hay gặpCách xử lý
Màn hình không hiện, Serial báo không thấy OLEDDùng chân I2C mặc định 21, 22 thay vì 5, 4Gọi Wire.begin(5, 4) trước khi khởi tạo màn hình
Màn hình hiện nhiễu, lệch cộtDùng nhầm thư viện của chip khácMàn hình trên mạch dùng thư viện Adafruit SSD1306
Rút USB là mạch tắtCông tắc đang tắt, chưa lắp pin hoặc pin hếtGạt công tắc, kiểm tra chiều pin, sạc pin
Phần trăm pin luôn 0 % hoặc nhảy lung tungChưa gắn cầu phân áp mà đã để true, hoặc mối hàn hởKiểm tra cầu phân áp, đo điện áp ở GPIO35 bằng đồng hồ
Thiết bị cảm biến I2C thêm vào làm màn hình tắtTrùng địa chỉ 0x3C, hoặc nối sang chân I2C khácNối chung GPIO5, GPIO4; quét địa chỉ để kiểm tra trùng
Nạp code xong mạch khởi động lại liên tụcNối thiết bị vào GPIO0, 2, 12, 15 làm sai mức khởi độngChuyển thiết bị sang các chân trống khác

8. Xem thêm

Cần tư vấn chọn mạch ESP32 cho thiết bị cầm tay, liên hệ PYWORLD qua số 0915703319.


Tin tức liên quan

Tự làm tay điều khiển flycam bằng ESP32 và ESP-NOW, bộ thu xuất PPM, SBUS cho mạch điều khiển bay
Tự làm tay điều khiển flycam bằng ESP32 và ESP-NOW, bộ thu xuất PPM, SBUS cho mạch điều khiển bay

Tự làm tay điều khiển flycam bằng ESP32: hai joystick, hai công tắc, gửi 8 kênh qua ESP-NOW; bộ thu ESP32 xuất PPM bằng RMT và SBUS bằng UART, có failsafe, dùng với Betaflight.

Điều khiển relay từ xa bằng ESP-NOW: remote ESP32 một nút nhấn có phản hồi trạng thái
Điều khiển relay từ xa bằng ESP-NOW: remote ESP32 một nút nhấn có phản hồi trạng thái

Hướng dẫn làm bộ điều khiển relay từ xa bằng hai mạch ESP32 và ESP-NOW hai chiều: remote gửi lệnh, mạch relay báo lại trạng thái, lọc theo địa chỉ MAC và bật mã hóa.

Hướng dẫn lưu dữ liệu vào bộ nhớ flash của ESP32 bằng thư viện Preferences
Hướng dẫn lưu dữ liệu vào bộ nhớ flash của ESP32 bằng thư viện Preferences

Hướng dẫn dùng thư viện Preferences trên ESP32 với Arduino IDE để lưu số đếm, trạng thái relay và thông số cài đặt vào bộ nhớ flash, không mất khi tắt nguồn.

Tưới cây tự động với ESP32: cảm biến độ ẩm đất, relay và bơm mini, ngưỡng có trễ
Tưới cây tự động với ESP32: cảm biến độ ẩm đất, relay và bơm mini, ngưỡng có trễ

Làm hệ thống tưới cây tự động với ESP32: cảm biến độ ẩm đất điện dung, hiệu chỉnh khô ướt, relay điều khiển bơm mini, ngưỡng có trễ, giới hạn thời gian bơm và thí nghiệm STEM.

Hướng dẫn dùng màn hình LCD 2004 I2C với ESP32
Hướng dẫn dùng màn hình LCD 2004 I2C với ESP32

Hướng dẫn nối màn hình LCD 2004 I2C (mạch PCF8574) với ESP32 DevKit V1, quét địa chỉ I2C, hiển thị 4 dòng chữ, tạo ký tự riêng, làm bộ đếm thời gian và đổi sang LCD 1602.

Hướng dẫn dùng màn hình OLED SSD1306 với ESP8266
Hướng dẫn dùng màn hình OLED SSD1306 với ESP8266

Hướng dẫn nối OLED SSD1306 với ESP8266, quét địa chỉ I2C, cài thư viện và hiển thị thời gian bằng mã Arduino mẫu.

Tự làm máy vẽ (pen plotter) 2 trục bằng ESP32 và động cơ bước, tự viết bộ đọc G-code
Tự làm máy vẽ (pen plotter) 2 trục bằng ESP32 và động cơ bước, tự viết bộ đọc G-code

Tự làm máy vẽ 2 trục với ESP32, hai A4988, NEMA 17 và servo nhấc bút; chương trình tự đọc G-code G0 G1 G2 G3, nội suy Bresenham có tăng tốc, script Python gửi file G-code.

Mạch hạ áp LM2596 và MP1584: cách chọn, chỉnh điện áp và cấp nguồn ESP32
Mạch hạ áp LM2596 và MP1584: cách chọn, chỉnh điện áp và cấp nguồn ESP32

So sánh mạch hạ áp LM2596 và MP1584, cách chỉnh điện áp ra bằng đồng hồ vạn năng trước khi nối tải, cấp nguồn 5 V cho ESP32 DevKit V1 từ nguồn 12 V và xử lý lỗi thường gặp.


Bình luận
Đã thêm vào giỏ hàng