ESP32-CAM là gì: sơ đồ chân, cách nạp code, xem video trên trình duyệt, chụp ảnh lưu thẻ nhớ

Giới thiệu mạch ESP32-CAM AI Thinker, sơ đồ chân, nạp code bằng đế MB hoặc USB-TTL, chương trình xem video MJPEG trên trình duyệt, chụp ảnh có đèn flash và lưu vào thẻ microSD.

ESP32-CAM là mạch ESP32 nhỏ cỡ bao diêm có sẵn camera, khe thẻ nhớ microSD và đèn flash, giá rẻ hơn nhiều so với camera IP. Mạch này hay được dùng làm camera giám sát tự làm, chuông cửa có hình, chụp ảnh định kỳ cây trồng, hoặc làm "mắt" cho xe robot. Bài này giới thiệu mạch, sơ đồ chân, cách nạp code (mạch không có cổng USB riêng), rồi viết chương trình xem video trực tiếp trên trình duyệt, chụp ảnh và lưu ảnh vào thẻ nhớ.

1. ESP32-CAM là gì

Mạch ESP32-CAM mặt trước có camera, khe thẻ nhớ, đèn flash và hai hàng chân; bên cạnh là ESP32-CAM cắm trên đế nạp với dây cắm
Mạch ESP32-CAM loại AI Thinker (trái; vệt đỏ và chấm vàng là dấu tác giả ảnh vẽ thêm) và mạch cắm trên đế nạp (phải). Ảnh trái: Nowforever, CC BY-SA 4.0, Wikimedia Commons; ảnh phải: Promeroy, CC BY-SA 4.0, Wikimedia Commons; đã thu nhỏ.
Thành phầnThông số thường gặp (loại AI Thinker)
Vi điều khiểnESP32 hai nhân 240 MHz, Wi-Fi 2,4 GHz, Bluetooth
Bộ nhớFlash 4 MB, PSRAM 4 MB (cần cho ảnh lớn và luồng video)
CameraOV2640 2 MP, ảnh tối đa 1600 × 1200; có bản dùng OV3660, OV5640
Khe thẻ nhớmicroSD, nối kiểu SD_MMC
ĐènĐèn flash trắng ở GPIO4, LED đỏ nhỏ ở GPIO33
Nguồn5 V qua chân 5V, nên dùng nguồn chịu được 1–2 A
Cổng USBKhông có: nạp code bằng mạch USB-TTL hoặc đế nạp ESP32-CAM-MB

So với ESP32 DevKit, ESP32-CAM ít chân trống hơn nhiều vì camera và thẻ nhớ đã chiếm phần lớn GPIO. Muốn vừa camera vừa nhiều cảm biến thì thường dùng ESP32-CAM lo phần hình ảnh và một mạch ESP32 khác lo phần còn lại.

2. Sơ đồ chân

Sơ đồ chân ESP32-CAM AI Thinker: bên trái 5V, GND, IO12, IO13, IO15, IO14, IO2, IO4; bên phải 3V3, IO16, IO0, GND, VCC, U0R, U0T, GND, kèm chức năng từng chân
Sơ đồ chân nhìn mặt có camera; các chân màu tím được thẻ nhớ dùng (hình minh họa).
  • 5V, GND: cấp nguồn. Cấp 3,3 V vào chân 3V3 cũng được nhưng dễ bị sụt áp khi camera và Wi-Fi chạy cùng lúc.
  • IO0: nối GND khi bật nguồn thì mạch vào chế độ nạp code. Khi chạy chương trình thì để hở.
  • U0R, U0T: cổng Serial (GPIO3, GPIO1), dùng để nạp code và xem Serial Monitor.
  • IO2, IO4, IO12, IO13, IO14, IO15: nối thẻ nhớ. Khi chạy thẻ nhớ ở chế độ 1 bit (như chương trình trong bài), IO4, IO12, IO13 được trả lại; IO4 thì dùng cho đèn flash.
  • IO16: dành cho PSRAM trên mạch, không dùng.
  • VCC: chân ra nguồn (3,3 V hoặc 5 V tùy miếng hàn trên mạch), không phải chân cấp vào.

3. Linh kiện cần chuẩn bị

  • Mạch ESP32-CAM loại AI Thinker kèm camera OV2640.
  • Đế nạp ESP32-CAM-MB (có cổng micro USB) hoặc một mạch USB-TTL CH340/CP2102 đặt ở 5 V.
  • Dây USB nạp code loại có truyền dữ liệu và dây cắm cái–cái.
  • Thẻ microSD (FAT32, 32 GB trở xuống) nếu muốn lưu ảnh.
  • Khi lắp cố định: nguồn 5 V ổn định. Lấy từ adapter 12 V thì hạ áp bằng mạch hạ áp MP1584 hoặc LM2596 chỉnh ra 5 V.

4. Nạp code cho ESP32-CAM

Nối mạch USB-TTL với ESP32-CAM để nạp code: 5V vào 5V, GND vào GND, TXD vào U0R, RXD vào U0T, IO0 nối GND khi nạp
Nạp code bằng mạch USB-TTL: TX nối chéo sang RX, IO0 nối GND trong lúc nạp (hình minh họa).
  1. Trong Arduino IDE 2, chọn bo AI Thinker ESP32-CAM (Tools → Board → esp32). Phân vùng mặc định của bo này là Huge APP, đủ chỗ cho chương trình camera.
  2. Dùng đế ESP32-CAM-MB: cắm mạch vào đế, cắm USB, chọn cổng COM rồi bấm Upload. Đa số đế tự đưa mạch vào chế độ nạp; nếu báo lỗi kết nối thì giữ nút IO0 trên đế, bấm RST, nhả IO0 rồi nạp lại.
  3. Dùng mạch USB-TTL: nối dây như hình, nối IO0 với GND, bấm nút RST trên ESP32-CAM, rồi bấm Upload.
  4. Nạp xong: tháo dây IO0–GND (nếu có), bấm RST để chạy chương trình, mở Serial Monitor ở 115200.

Chưa cài gói ESP32 cho Arduino IDE thì làm theo bài cài ESP32 vào Arduino IDE 2. Bài dùng gói esp32 phiên bản 3.3.10, đã có sẵn thư viện camera.

5. Chương trình xem video, chụp ảnh, lưu thẻ nhớ

Sửa TEN_WIFI, MAT_KHAU_WIFI thành Wi-Fi 2,4 GHz nhà bạn rồi nạp:

// PYWORLD.VN - ESP32-CAM (AI Thinker): xem video trên trình duyệt, chụp ảnh JPEG, lưu ảnh vào thẻ microSD
// Chọn bo "AI Thinker ESP32-CAM"; trang chính ở cổng 80, luồng video MJPEG ở cổng 81
// Thẻ nhớ chạy chế độ 1 bit để chân GPIO4 (đèn flash) không bị dùng chung với thẻ

#include "esp_camera.h"
#include "esp_http_server.h"
#include <WiFi.h>
#include "FS.h"
#include "SD_MMC.h"

const char *TEN_WIFI = "TEN_WIFI";
const char *MAT_KHAU_WIFI = "MAT_KHAU_WIFI";
const int CHAN_DEN_FLASH = 4;

// Chân camera OV2640 trên mạch AI Thinker ESP32-CAM
#define CHAN_PWDN 32
#define CHAN_RESET -1
#define CHAN_XCLK 0
#define CHAN_SIOD 26
#define CHAN_SIOC 27
#define CHAN_Y9 35
#define CHAN_Y8 34
#define CHAN_Y7 39
#define CHAN_Y6 36
#define CHAN_Y5 21
#define CHAN_Y4 19
#define CHAN_Y3 18
#define CHAN_Y2 5
#define CHAN_VSYNC 25
#define CHAN_HREF 23
#define CHAN_PCLK 22

httpd_handle_t mayChuTrang = NULL;
httpd_handle_t mayChuLuong = NULL;
bool coTheNho = false;
uint32_t soAnh = 0;

const char TRANG[] = R"HTML(<!doctype html><html lang="vi"><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1"><title>ESP32-CAM</title>
<style>body{font-family:sans-serif;margin:12px;background:#111;color:#eee}img{width:100%;max-width:640px;border-radius:8px}
button{font-size:18px;padding:10px 16px;margin:8px 8px 0 0}</style>
<h2>ESP32-CAM</h2><img id="v"><br>
<button onclick="location.href='/chup'">Chụp ảnh</button>
<button onclick="location.href='/chup?den=1'">Chụp có đèn</button>
<button onclick="fetch('/luu').then(r=>r.text()).then(t=>alert(t))">Lưu vào thẻ nhớ</button>
<script>document.getElementById('v').src=location.protocol+'//'+location.hostname+':81/stream'</script></html>)HTML";

bool khoiDongCamera() {
  camera_config_t c = {};
  c.pin_pwdn = CHAN_PWDN;
  c.pin_reset = CHAN_RESET;
  c.pin_xclk = CHAN_XCLK;
  c.pin_sccb_sda = CHAN_SIOD;
  c.pin_sccb_scl = CHAN_SIOC;
  c.pin_d7 = CHAN_Y9;
  c.pin_d6 = CHAN_Y8;
  c.pin_d5 = CHAN_Y7;
  c.pin_d4 = CHAN_Y6;
  c.pin_d3 = CHAN_Y5;
  c.pin_d2 = CHAN_Y4;
  c.pin_d1 = CHAN_Y3;
  c.pin_d0 = CHAN_Y2;
  c.pin_vsync = CHAN_VSYNC;
  c.pin_href = CHAN_HREF;
  c.pin_pclk = CHAN_PCLK;
  c.xclk_freq_hz = 20000000;
  c.ledc_timer = LEDC_TIMER_0;
  c.ledc_channel = LEDC_CHANNEL_0;
  c.pixel_format = PIXFORMAT_JPEG;          // cảm biến tự nén JPEG, ESP32 chỉ việc gửi đi
  c.frame_size = FRAMESIZE_VGA;             // 640 x 480
  c.jpeg_quality = 12;                      // 0-63, số nhỏ là ảnh đẹp hơn nhưng nặng hơn
  c.fb_count = psramFound() ? 2 : 1;
  c.fb_location = psramFound() ? CAMERA_FB_IN_PSRAM : CAMERA_FB_IN_DRAM;
  c.grab_mode = CAMERA_GRAB_LATEST;         // luôn lấy khung hình mới nhất
  esp_err_t loi = esp_camera_init(&c);
  if (loi != ESP_OK) {
    Serial.printf("Loi khoi dong camera 0x%x: kiem tra cap camera, nguon 5V\n", loi);
    return false;
  }
  return true;
}

// Đếm tiếp số thứ tự ảnh đã có trên thẻ, để khởi động lại không ghi đè ảnh cũ.
uint32_t soAnhLonNhat() {
  uint32_t lonNhat = 0;
  File thuMuc = SD_MMC.open("/");
  for (File f = thuMuc.openNextFile(); f; f = thuMuc.openNextFile()) {
    unsigned so;
    if (sscanf(f.name(), "anh_%u.jpg", &so) == 1 && so > lonNhat) lonNhat = so;
    f.close();
  }
  return lonNhat;
}

esp_err_t xuLyTrang(httpd_req_t *req) {
  httpd_resp_set_type(req, "text/html");
  return httpd_resp_send(req, TRANG, HTTPD_RESP_USE_STRLEN);
}

esp_err_t xuLyChup(httpd_req_t *req) {
  char truyVan[16] = "";
  bool batDen = httpd_req_get_url_query_str(req, truyVan, sizeof(truyVan)) == ESP_OK && strstr(truyVan, "den=1");
  if (batDen) {
    digitalWrite(CHAN_DEN_FLASH, HIGH);
    delay(150);                             // chờ cảm biến chỉnh lại độ sáng
    esp_camera_fb_return(esp_camera_fb_get());   // bỏ khung chụp lúc đèn chưa sáng hẳn
  }
  camera_fb_t *khung = esp_camera_fb_get();
  digitalWrite(CHAN_DEN_FLASH, LOW);
  if (!khung) {
    httpd_resp_send_500(req);
    return ESP_FAIL;
  }
  httpd_resp_set_type(req, "image/jpeg");
  httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=anh.jpg");
  esp_err_t kq = httpd_resp_send(req, (const char *)khung->buf, khung->len);
  esp_camera_fb_return(khung);
  return kq;
}

esp_err_t xuLyLuu(httpd_req_t *req) {
  char traLoi[64];
  if (!coTheNho) {
    snprintf(traLoi, sizeof(traLoi), "Khong co the nho");
  } else {
    camera_fb_t *khung = esp_camera_fb_get();
    if (!khung) {
      snprintf(traLoi, sizeof(traLoi), "Loi chup anh");
    } else {
      char ten[24];
      snprintf(ten, sizeof(ten), "/anh_%04lu.jpg", (unsigned long)++soAnh);
      File f = SD_MMC.open(ten, FILE_WRITE);
      bool duoc = f && f.write(khung->buf, khung->len) == khung->len;
      if (f) f.close();
      snprintf(traLoi, sizeof(traLoi), duoc ? "Da luu %s (%u byte)" : "Loi ghi %s", ten, (unsigned)khung->len);
      esp_camera_fb_return(khung);
      Serial.println(traLoi);
    }
  }
  httpd_resp_set_type(req, "text/plain");
  return httpd_resp_send(req, traLoi, HTTPD_RESP_USE_STRLEN);
}

// Luồng MJPEG: gửi liên tục từng ảnh JPEG, ngăn cách bằng một chuỗi biên (boundary).
esp_err_t xuLyLuong(httpd_req_t *req) {
  static const char *BIEN = "\r\n--khunghinh\r\n";
  httpd_resp_set_type(req, "multipart/x-mixed-replace;boundary=khunghinh");
  httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  char dau[64];
  while (true) {
    camera_fb_t *khung = esp_camera_fb_get();
    if (!khung) return ESP_FAIL;
    int n = snprintf(dau, sizeof(dau), "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n", (unsigned)khung->len);
    esp_err_t kq = httpd_resp_send_chunk(req, BIEN, strlen(BIEN));
    if (kq == ESP_OK) kq = httpd_resp_send_chunk(req, dau, n);
    if (kq == ESP_OK) kq = httpd_resp_send_chunk(req, (const char *)khung->buf, khung->len);
    esp_camera_fb_return(khung);
    if (kq != ESP_OK) return kq;            // trình duyệt đóng trang: dừng luồng
  }
}

void khoiDongMayChu() {
  httpd_config_t cauHinh = HTTPD_DEFAULT_CONFIG();
  httpd_uri_t trang = {"/", HTTP_GET, xuLyTrang, NULL};
  httpd_uri_t chup = {"/chup", HTTP_GET, xuLyChup, NULL};
  httpd_uri_t luu = {"/luu", HTTP_GET, xuLyLuu, NULL};
  if (httpd_start(&mayChuTrang, &cauHinh) == ESP_OK) {
    httpd_register_uri_handler(mayChuTrang, &trang);
    httpd_register_uri_handler(mayChuTrang, &chup);
    httpd_register_uri_handler(mayChuTrang, &luu);
  }
  cauHinh.server_port = 81;                 // luồng video chạy máy chủ riêng để trang chính không bị chặn
  cauHinh.ctrl_port += 1;
  httpd_uri_t luong = {"/stream", HTTP_GET, xuLyLuong, NULL};
  if (httpd_start(&mayChuLuong, &cauHinh) == ESP_OK) httpd_register_uri_handler(mayChuLuong, &luong);
}

void setup() {
  Serial.begin(115200);
  pinMode(CHAN_DEN_FLASH, OUTPUT);
  digitalWrite(CHAN_DEN_FLASH, LOW);
  Serial.printf("PSRAM: %s\n", psramFound() ? "co" : "khong");
  if (!khoiDongCamera()) return;

  coTheNho = SD_MMC.begin("/sdcard", true);  // true: chế độ 1 bit
  if (coTheNho) soAnh = soAnhLonNhat();
  Serial.println(coTheNho ? "Da gan the nho" : "Khong thay the nho (van xem, chup duoc)");

  WiFi.mode(WIFI_STA);
  WiFi.setSleep(false);                     // tắt tiết kiệm điện Wi-Fi cho video mượt hơn
  WiFi.begin(TEN_WIFI, MAT_KHAU_WIFI);
  Serial.print("Dang vao Wi-Fi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.printf("\nMo trinh duyet: http://%s\n", WiFi.localIP().toString().c_str());
  khoiDongMayChu();
}

void loop() {
  delay(1000);                              // máy chủ HTTP chạy trong task riêng
}

6. Trang web và hai máy chủ HTTP

Trình duyệt mở trang ESP32-CAM có khung video và ba nút; trang ở cổng 80 gọi chụp, lưu, còn video lấy từ cổng 81; ảnh lưu vào thẻ microSD
Trang ở cổng 80 lấy video từ cổng 81; nút Lưu ghi ảnh vào thẻ nhớ (hình minh họa).

Mở Serial Monitor để xem địa chỉ IP, rồi gõ địa chỉ đó vào trình duyệt của máy tính hoặc điện thoại cùng mạng Wi-Fi. Trang hiện video trực tiếp và ba nút: Chụp ảnh mở một ảnh JPEG độ phân giải 640 × 480, Chụp có đèn bật đèn flash lúc chụp, Lưu vào thẻ nhớ ghi ảnh thành file anh_0001.jpg, anh_0002.jpg…

7. Giải thích các phần chính

  • camera_config_t: khai báo các chân nối camera của mạch AI Thinker, tần số xung nhịp 20 MHz, kiểu ảnh JPEG (cảm biến tự nén), cỡ ảnh VGA và chất lượng nén 12. Mạch ESP32-CAM của hãng khác có thể nối chân khác: phải lấy đúng bảng chân của mạch đó.
  • PSRAM: có PSRAM thì chương trình giữ 2 bộ đệm khung hình trong PSRAM, camera chụp khung sau trong lúc khung trước đang gửi đi. CAMERA_GRAB_LATEST luôn đưa ra khung mới nhất nên video ít bị trễ.
  • Luồng MJPEG: trình duyệt nhận một dòng dữ liệu kiểu multipart/x-mixed-replace, trong đó các ảnh JPEG nối tiếp nhau, ngăn bởi chuỗi biên --khunghinh. Ảnh sau thay ảnh trước nên ta thấy thành video.
  • Hai máy chủ: luồng video không bao giờ kết thúc nên chiếm trọn kết nối của nó. Đặt luồng ở máy chủ riêng (cổng 81) thì các nút ở cổng 80 vẫn trả lời được. Đây cũng là cách làm của ví dụ CameraWebServer trong gói esp32.
  • Thẻ nhớ 1 bit: SD_MMC.begin("/sdcard", true) chỉ dùng một đường dữ liệu. Tốc độ ghi chậm hơn chế độ 4 bit nhưng đủ cho ảnh, và chân GPIO4 không bị thẻ nhớ dùng chung nên đèn flash không chớp mỗi lần ghi.
  • soAnhLonNhat() đọc tên các file đã có trên thẻ để đánh số tiếp, khởi động lại không ghi đè ảnh cũ.
  • WiFi.setSleep(false) tắt chế độ tiết kiệm điện của Wi-Fi: tốn điện hơn nhưng video ít giật.

8. Kết quả trên Serial Monitor

Serial Monitor của ESP32-CAM in PSRAM có, đã gắn thẻ nhớ, địa chỉ IP để mở trình duyệt, tên các ảnh đã lưu; và lỗi khởi động camera 0x105 khi cáp lỏng
Khi chạy bình thường và khi cáp camera chưa cắm chặt (hình minh họa, số liệu ví dụ).

9. Chỉnh cho ảnh đẹp hơn

  • Cỡ ảnh: đổi FRAMESIZE_VGA thành FRAMESIZE_SVGA (800 × 600), FRAMESIZE_XGA (1024 × 768) hoặc FRAMESIZE_UXGA (1600 × 1200). Ảnh càng lớn thì video càng ít khung hình mỗi giây.
  • Chất lượng JPEG: jpeg_quality từ 10 đến 15 là hợp lý; nhỏ hơn 10 ảnh nặng, dễ hết bộ nhớ.
  • Lấy nét: ống kính OV2640 xoay được để chỉnh nét, thường dính keo cố định; muốn chụp gần dưới 20 cm thì cạo keo và xoay nhẹ.
  • Ánh sáng: cảm biến cần vài giây để tự chỉnh độ sáng sau khi bật. Trong tối, đèn flash chỉ chiếu tốt trong khoảng 1 m.
  • Anten: sóng yếu thì video giật. Mạch có chỗ gắn anten rời (IPEX) nhưng phải chuyển một điện trở 0 Ω trên mạch sang vị trí anten rời mới dùng được.

10. Xử lý lỗi thường gặp

Hiện tượngNguyên nhân thường gặpCách xử lý
Nạp báo "Failed to connect", "Wrong boot mode"IO0 chưa nối GND lúc reset, đảo TX/RX, mạch USB-TTL đặt 3,3 VNối IO0–GND rồi bấm RST; TX → U0R, RX → U0T; đặt USB-TTL ở 5 V
"Brownout detector was triggered", mạch khởi động lại liên tụcNguồn yếu: cổng USB máy tính, dây USB dài, dây cắm nhỏDùng nguồn 5 V từ 1 A trở lên, dây ngắn; thêm tụ 470–1000 µF giữa 5V và GND
"Loi khoi dong camera 0x105"Cáp camera chưa cắm hết, chưa gài khóa; chọn sai bo nên sai chânMở khóa đầu nối, cắm lại cáp đúng chiều, gài khóa; chọn bo AI Thinker ESP32-CAM
Trang mở được nhưng không có videoMạng chặn cổng 81, đang có trình duyệt khác xemĐóng các tab đang xem; thử mở thẳng http://<IP>:81/stream
"Khong thay the nho"Thẻ trên 32 GB hoặc định dạng exFAT, thẻ cắm lệchĐịnh dạng FAT32, dùng thẻ 4–32 GB
Ảnh có sọc, màu tím xanhThiếu PSRAM hoặc xung nhịp cao với nguồn yếuKiểm tra dòng "PSRAM: co"; giảm xclk_freq_hz xuống 10000000

11. Xem thêm


Tin tức liên quan

Hướng dẫn sử dụng màn hình LCD 1602 I2C với Arduino Uno
Hướng dẫn sử dụng màn hình LCD 1602 I2C với Arduino Uno

Hướng dẫn nối màn hình LCD 1602 I2C với Arduino Uno, cài thư viện LiquidCrystal_I2C, chạy code hiển thị và quét địa chỉ I2C 0x27/0x3F.

Hướng dẫn đo điện áp 16 bit bằng module ADS1115 với ESP32
Hướng dẫn đo điện áp 16 bit bằng module ADS1115 với ESP32

Hướng dẫn nối module ADC 16 bit ADS1115 với ESP32 DevKit V1 qua I2C, cài thư viện Adafruit ADS1X15, đọc 4 kênh ra vôn, đo vi sai và chọn gain an toàn.

Đóng relay làm ESP32, Arduino bị reset hoặc treo: nguyên nhân và cách khắc phục
Đóng relay làm ESP32, Arduino bị reset hoặc treo: nguyên nhân và cách khắc phục

Vì sao đóng relay làm ESP32, Arduino tự khởi động lại hoặc treo: sụt áp nguồn, xung cuộn dây, hồ quang tiếp điểm, chân khởi động; cách khắc phục và chương trình đo sụt áp.

Xe tránh vật cản với ESP32: cảm biến siêu âm HC-SR04 trên servo quét, tự chọn đường
Xe tránh vật cản với ESP32: cảm biến siêu âm HC-SR04 trên servo quét, tự chọn đường

Làm xe robot tự tránh vật cản với ESP32: cảm biến siêu âm HC-SR04 gắn trên servo quét trái phải, cầu phân áp cho chân ECHO, thuật toán chọn đường, lưu đồ và thí nghiệm STEM.

Hướng dẫn dùng mạch tạo trễ NE555 có relay: đấu dây và chỉnh thời gian trễ
Hướng dẫn dùng mạch tạo trễ NE555 có relay: đấu dây và chỉnh thời gian trễ

Hướng dẫn dùng mạch tạo trễ NE555 có relay bản 5 V và 12 V: nguyên lý tạo trễ, ý nghĩa các cọc VCC, GND, COM, CK, CB, cách chỉnh thời gian trễ, sơ đồ đấu dây và xử lý lỗi thường gặp.

Hướng dẫn dùng Deep Sleep trên ESP32: tiết kiệm pin, đánh thức bằng timer và nút nhấn
Hướng dẫn dùng Deep Sleep trên ESP32: tiết kiệm pin, đánh thức bằng timer và nút nhấn

Hướng dẫn đưa ESP32 vào Deep Sleep trên Arduino IDE để tiết kiệm pin: các chế độ nguồn, đánh thức bằng timer và nút nhấn, giữ biến trong bộ nhớ RTC và ước tính thời lượng pin.

ESP32 làm mạch điều khiển bay cho flycam mini động cơ có chổi than: lọc bù, PID, bộ trộn, giá thử
ESP32 làm mạch điều khiển bay cho flycam mini động cơ có chổi than: lọc bù, PID, bộ trộn, giá thử

Dùng ESP32 làm mạch điều khiển bay cho flycam mini động cơ có chổi than: kênh MOSFET, bộ lọc bù, hai vòng PID, bộ trộn bốn động cơ, điều kiện an toàn và cách chỉnh PID trên giá thử.

Hướng dẫn giao tiếp I2C trên ESP32: quét địa chỉ, đổi chân SDA/SCL và nối nhiều thiết bị
Hướng dẫn giao tiếp I2C trên ESP32: quét địa chỉ, đổi chân SDA/SCL và nối nhiều thiết bị

Hướng dẫn dùng bus I2C trên ESP32 với Arduino IDE: quét địa chỉ thiết bị, đổi chân SDA và SCL, nối màn hình OLED và ADS1115 chung một bus, xử lý khi hai thiết bị trùng địa chỉ.


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