Bài đầu tiên với ESP32 cho học sinh: đèn nhấp nháy và phát tên bằng mã Morse

Dự án STEM đầu tiên với ESP32 không cần linh kiện: nháy đèn LED có sẵn trên mạch, rồi phát tên của bé bằng mã Morse; cài Arduino IDE, giải thích code và trò chơi đoán tên.

Chương trình đầu tiên khi học lập trình mạch điện tử thường là làm một đèn nhấp nháy. Với mạch ESP32 DevKit V1, bài này không cần thêm linh kiện nào, vì trên mạch đã có sẵn một đèn LED. Chỉ cần mạch, một dây USB và máy tính, học sinh sẽ thấy dòng lệnh mình viết làm đèn sáng, tắt thật.

Bài viết có hai chương trình: đèn nhấp nháy đều, và phát tên của bé bằng mã Morse, một trò chơi giúp trẻ hiểu máy móc "nói chuyện" bằng tín hiệu bật, tắt như thế nào. Phù hợp với học sinh từ khoảng 10 tuổi, có người lớn đi cùng.

1. Chuẩn bị

Mạch ESP32 DevKit V1 có đèn LED trên mạch nối chân GPIO2 gần cổng USB, nối với máy tính có Arduino IDE bằng dây USB có truyền dữ liệu
Hình minh họa: mạch ESP32, đèn LED trên mạch và dây USB.
  • Một mạch ESP32 DevKit V1.
  • Một dây USB nạp code đúng loại cổng của mạch. Dây chỉ dùng để sạc sẽ không nạp được chương trình.
  • Máy tính cài Arduino IDE 2.x.

Đèn LED trên mạch ESP32 DevKit V1 nối với chân GPIO2; trên mạch thường là một đèn xanh nhỏ gần cổng USB. Ngoài đèn này, mạch còn một đèn nguồn luôn sáng khi cắm USB.

2. Cài đặt Arduino IDE cho ESP32

  1. Cài driver cho chip giao tiếp USB của mạch (CP2102 hoặc CH340) nếu máy chưa nhận cổng; xem trang Driver trên pyworld.vn.
  2. Mở Tools > Board > Boards Manager, tìm esp32 và cài gói esp32 by Espressif Systems.
  3. Chọn Tools > Board > esp32 > DOIT ESP32 DEVKIT V1.
  4. Cắm mạch vào máy tính, chọn đúng cổng ở Tools > Port.

Bài dùng gói esp32 phiên bản 3.3.10. Hai chương trình chỉ dùng lệnh có sẵn, không cần cài thư viện.

3. Chương trình 1: đèn nhấp nháy

// PYWORLD.VN - ESP32 DevKit V1: chương trình đầu tiên cho học sinh
// Nháy đèn LED có sẵn trên mạch (GPIO2): sáng 0,5 giây, tắt 0,5 giây
// Mở Serial Monitor ở tốc độ 115200 baud để xem đèn đang sáng hay tắt

const int LED_PIN = 2;             // đèn LED xanh trên mạch ESP32 DevKit V1
const int THOI_GIAN_SANG = 500;    // mili giây (1000 mili giây = 1 giây)
const int THOI_GIAN_TAT = 500;

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);        // chân 2 là chân ra: ESP32 bật, tắt điện ở chân này
  Serial.println("Bat dau nhay den");
}

void loop() {
  digitalWrite(LED_PIN, HIGH);     // bật đèn
  Serial.println("Den SANG");
  delay(THOI_GIAN_SANG);           // chờ, đèn vẫn sáng

  digitalWrite(LED_PIN, LOW);      // tắt đèn
  Serial.println("Den TAT");
  delay(THOI_GIAN_TAT);            // chờ, đèn vẫn tắt
}                                  // hết loop() thì ESP32 tự chạy lại từ đầu loop()

Bấm nút Upload (mũi tên sang phải). Nạp xong, đèn xanh trên mạch sáng 0,5 giây, tắt 0,5 giây, lặp lại mãi. Mở Tools > Serial Monitor, chọn tốc độ 115200 baud để xem các dòng chương trình in ra.

Đồ thị mức điện chân 2 theo thời gian: sáng 500 ms, tắt 500 ms lặp lại; Serial Monitor hiện Bat dau nhay den rồi Den SANG, Den TAT xen kẽ
Hình minh họa: mức điện ở chân 2 và các dòng trên Serial Monitor.

Giải thích cho trẻ

  • setup() chạy một lần khi mạch vừa bật: chuẩn bị chân 2 làm chân ra, mở cổng in chữ.
  • loop() chạy lặp lại mãi. Đây là vòng lặp, giống thẻ "lặp lại" trong trò chơi robot.
  • digitalWrite(LED_PIN, HIGH) bật đèn; LOW tắt đèn.
  • delay(500) bảo mạch đứng chờ 500 mili giây, tức nửa giây.

Thử thay đổi: đổi THOI_GIAN_SANG thành 100 và THOI_GIAN_TAT thành 900, nạp lại. Đèn chớp ngắn như đèn báo. Đổi cả hai thành 50: đèn nhấp nháy nhanh đến mức mắt gần như thấy sáng liên tục.

4. Mã Morse là gì?

Mã Morse dùng hai loại tín hiệu, chấm (ngắn) và gạch (dài), để ghi các chữ cái và chữ số. Trước khi có điện thoại, người ta dùng mã Morse để gửi điện tín, và ngày nay mã Morse vẫn được dùng trong vô tuyến nghiệp dư. Với trẻ, đây là ví dụ dễ hiểu về mã hóa: một chữ cái được đổi thành một dãy tín hiệu.

Bảng mã Morse quốc tế cho chữ A đến Z và số 0 đến 9 vẽ bằng chấm và gạch
Hình minh họa: bảng mã Morse quốc tế, đúng bảng trong chương trình.

Quy ước thời gian của mã Morse quốc tế tính theo một đơn vị:

  • chấm sáng 1 đơn vị, gạch sáng 3 đơn vị;
  • giữa hai ký hiệu trong một chữ: tắt 1 đơn vị;
  • giữa hai chữ: tắt 3 đơn vị; giữa hai từ: tắt 7 đơn vị.

5. Chương trình 2: phát tên của bé bằng mã Morse

// PYWORLD.VN - ESP32 DevKit V1: phát tên của bé bằng mã Morse
// Đèn LED trên mạch (GPIO2) nháy chấm, gạch theo mã Morse quốc tế
// Gõ tên (chữ không dấu) vào Serial Monitor 115200 baud rồi nhấn Enter

#include <ctype.h>

const int LED_PIN = 2;
const int DON_VI = 200;   // độ dài 1 đơn vị thời gian (mili giây); chấm dài 1 đơn vị, gạch dài 3

// Mã Morse quốc tế cho chữ A đến Z và số 0 đến 9
const char* MA_CHU[26] = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--",
                          "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."};
const char* MA_SO[10] = {"-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----."};

String ten = "AN";        // tên phát lúc mới bật; gõ tên khác vào Serial Monitor để đổi

// Tra mã của một ký tự; ký tự không có trong bảng (chữ có dấu, dấu câu) trả về nullptr
const char* maCua(char c) {
  c = toupper(c);
  if (c >= 'A' && c <= 'Z') return MA_CHU[c - 'A'];
  if (c >= '0' && c <= '9') return MA_SO[c - '0'];
  return nullptr;
}

// Phát một ký hiệu: chấm sáng 1 đơn vị, gạch sáng 3 đơn vị, sau đó tắt 1 đơn vị
void phatKyHieu(char k) {
  digitalWrite(LED_PIN, HIGH);
  delay(k == '.' ? DON_VI : 3 * DON_VI);
  digitalWrite(LED_PIN, LOW);
  delay(DON_VI);
}

void phatChu(const String& s) {
  for (unsigned int i = 0; i < s.length(); i++) {
    char c = s[i];
    if (c == ' ') {                 // giữa hai từ: tắt tổng cộng 7 đơn vị (3 đã có + 4)
      Serial.print("/ ");
      delay(4 * DON_VI);
      continue;
    }
    const char* ma = maCua(c);
    if (ma == nullptr) continue;    // bỏ qua ký tự không có mã
    Serial.print((char)toupper(c));
    Serial.print(' ');
    Serial.print(ma);
    Serial.print("  ");
    for (const char* p = ma; *p; p++) phatKyHieu(*p);
    delay(2 * DON_VI);              // giữa hai chữ: tắt tổng cộng 3 đơn vị (1 đã có + 2)
  }
  Serial.println();
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  Serial.println("Go ten (khong dau) roi nhan Enter");
}

void loop() {
  if (Serial.available()) {
    String moi = Serial.readStringUntil('\n');
    moi.trim();
    if (moi.length() > 0) ten = moi;
  }
  phatChu(ten);
  delay(2000);                      // nghỉ 2 giây rồi phát lại
}

Nạp chương trình, mở Serial Monitor ở 115200 baud và chọn kiểu xuống dòng New Line. Lúc đầu mạch phát tên "AN". Gõ tên của bé bằng chữ không dấu, ví dụ MINH hoặc BAO AN, rồi nhấn Enter; từ lần phát sau, đèn nháy theo tên mới.

Tên AN phát bằng đèn theo thời gian: chữ A chấm gạch, chữ N gạch chấm, các khoảng tắt 1 và 2 đơn vị, tổng 16 đơn vị bằng 3,2 giây; Serial Monitor in A .- N -.
Hình minh họa: dãy sáng, tắt của tên "AN" và dòng in trên Serial Monitor.

Chương trình làm gì?

  • MA_CHU và MA_SO là hai bảng tra: chữ A ở vị trí 0, chữ B ở vị trí 1… Hàm maCua() đổi chữ thường thành chữ hoa rồi tra bảng.
  • phatKyHieu() bật đèn 1 hoặc 3 đơn vị tùy chấm hay gạch, rồi tắt 1 đơn vị.
  • phatChu() đi lần lượt từng chữ của tên, phát mã của chữ đó, rồi tắt thêm 2 đơn vị để khoảng cách giữa hai chữ đủ 3 đơn vị. Gặp dấu cách thì tắt thêm 4 đơn vị để giữa hai từ đủ 7 đơn vị.
  • Chữ có dấu như "Ă", "Đ" không có trong bảng nên chương trình bỏ qua. Vì vậy cần gõ tên không dấu.

6. Trò chơi đoán tên

  1. Một bạn gõ một tên ngắn (2–4 chữ) mà người kia không nhìn thấy.
  2. Người đoán nhìn đèn, ghi lại chấm, gạch trên giấy.
  3. Dùng bảng mã Morse để dịch ra tên.
  4. Nếu khó quá, tăng DON_VI từ 200 lên 400 để đèn nháy chậm hơn.

Trò chơi này rèn sự tập trung, ghi chép có hệ thống và kỹ năng giải mã.

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

Lỗi thường gặp
Hiện tượngNguyên nhân thường gặpCách xử lý
Không thấy cổng ở Tools > PortChưa cài driver; dây USB chỉ để sạcCài driver CP2102 hoặc CH340; đổi dây USB khác
Nạp báo lỗi kết nối, dừng ở "Connecting…"Mạch chưa vào chế độ nạpGiữ nút BOOT trên mạch khi IDE hiện "Connecting…", thả ra khi bắt đầu nạp
Nạp xong nhưng đèn không nháyBản mạch dùng chân khác cho đènXem chữ in cạnh đèn trên mạch; thử đổi LED_PIN
Serial Monitor hiện ký tự lạSai tốc độ baudChọn 115200 baud
Gõ tên mới không đổiChưa chọn kiểu xuống dòngChọn New Line ở Serial Monitor; chương trình chỉ đọc tên mới sau khi phát xong tên cũ

8. Gợi ý dùng trong giờ học STEM

  • Toán: tính thời gian phát tên của từng bạn trong lớp theo số đơn vị; tên nào dài nhất?
  • Khoa học: đèn chớp nhanh đến mức nào thì mắt không còn thấy chớp? Thử 200, 100, 50, 20 mili giây và ghi lại.
  • Lịch sử, xã hội: tìm hiểu tín hiệu cấp cứu SOS (... --- ...) và vì sao chọn dãy này.
  • Thời lượng gợi ý: 2 buổi, mỗi buổi 45 phút: buổi 1 cài đặt và đèn nhấp nháy, buổi 2 mã Morse và trò chơi đoán tên.

9. Xem thêm

Bài trước trong loạt so sánh các bo mạch cho học sinh; bài tiếp theo dùng chân cảm ứng có sẵn trên ESP32 để chạm tay bật đèn, cũng không cần linh kiện. Khi muốn chỉnh độ sáng đèn thay vì chỉ bật, tắt, xem bài PWM trên ESP32: điều chỉnh độ sáng LED.


Tin tức liên quan

Modbus TCP/IP (phần 2): ESP32 làm máy khách và cổng chuyển đổi Modbus TCP sang RTU
Modbus TCP/IP (phần 2): ESP32 làm máy khách và cổng chuyển đổi Modbus TCP sang RTU

Hướng dẫn dùng ESP32 làm máy khách Modbus TCP đọc thanh ghi của một thiết bị trong mạng, và làm cổng chuyển đổi Modbus TCP sang Modbus RTU qua RS-485: cách đổi khung, mã thiết bị, thời gian chờ, mã lỗi 0x0B.

HX711 với load cell và LCD 1602 bằng MicroPython
HX711 với load cell và LCD 1602 bằng MicroPython

Hướng dẫn ESP32 đọc load cell qua HX711 và hiển thị LCD 1602 bằng MicroPython, gồm đấu dây, hiệu chuẩn và xử lý lỗi.

Chân D+ D− (DP, DM) trên jack USB Type-C: vị trí, cách nối và phân biệt với DisplayPort
Chân D+ D− (DP, DM) trên jack USB Type-C: vị trí, cách nối và phân biệt với DisplayPort

D+ D− (DP, DM) là cặp dữ liệu USB 2.0 nằm ở chân A6, A7, B6, B7 của cổng Type-C. Bài hướng dẫn nối jack Type-C 4 dây vào mạch có USB, vai trò của D+ D− khi sạc và cách phân biệt với DisplayPort.

Hiệu chuẩn đồng hồ so theo ISO 463 và đồng hồ chân gạt ISO 9493: đặc tính sai số và sai số cosin
Hiệu chuẩn đồng hồ so theo ISO 463 và đồng hồ chân gạt ISO 9493: đặc tính sai số và sai số cosin

Hiệu chuẩn đồng hồ so theo ISO 463: sai số trong 1/10 vòng, 1 vòng, toàn dải, trễ, lặp lại; trình tự trên máy hiệu chuẩn, ví dụ kết quả, sai số cosin của đồng hồ chân gạt.

Cảm biến tiệm cận điện dung: cấu tạo, nguyên lý, cách chế tạo và tự làm cảm biến mức nước với ESP32
Cảm biến tiệm cận điện dung: cấu tạo, nguyên lý, cách chế tạo và tự làm cảm biến mức nước với ESP32

Cảm biến tiệm cận điện dung hoạt động thế nào: điện cực, điện cực bù, điện trường viền, hằng số điện môi, báo mức xuyên thành bồn, cách chế tạo và tự làm cảm biến mức nước bằng chân cảm ứng ESP32.

Lập trình không cần máy tính: 8 trò chơi rèn tư duy cho trẻ 4–8 tuổi
Lập trình không cần máy tính: 8 trò chơi rèn tư duy cho trẻ 4–8 tuổi

8 trò chơi lập trình không cần máy tính cho trẻ 4–8 tuổi: người máy, thẻ mũi tên, dãy hạt, điệu nhảy, nếu thì, tô tranh theo mã, tìm lỗi; cách chơi và khái niệm trẻ học được.

Sơ đồ chân USB Type-C (pinout): cổng 24 chân, 16 chân, 6 chân
Sơ đồ chân USB Type-C (pinout): cổng 24 chân, 16 chân, 6 chân

Sơ đồ chân (pinout) cổng USB Type-C loại 24 chân, 16 chân và 6 chân: bảng tra VBUS, GND, CC1, CC2, D+, D−, SBU, TX RX, lý do cắm được hai chiều và cách các chân gom thành jack 2, 4, 6 dây.

Số nhị phân cho trẻ: đếm bằng 5 thẻ chấm, giải mật thư như máy tính
Số nhị phân cho trẻ: đếm bằng 5 thẻ chấm, giải mật thư như máy tính

Dạy trẻ số nhị phân bằng 5 thẻ chấm 1, 2, 4, 8, 16: viết số, đếm và tìm quy luật, giải mật thư chữ cái, liên hệ với bit, màn hình và mạch ESP32. Hoạt động không cần máy tính.


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