Xúc xắc điện tử với ESP32 và OLED: thí nghiệm xác suất cho học sinh

Làm xúc xắc điện tử bằng ESP32 và màn hình OLED kèm 4 nút: tung một lần, tung nhanh 60 lần, vẽ biểu đồ; xác suất lý thuyết, thực nghiệm và luật số lớn cho học sinh.

Tung một xúc xắc 6 lần, có chắc mỗi mặt ra đúng một lần không? Tung 600 lần thì sao? Câu hỏi đơn giản này là cửa vào của môn xác suất. Bài viết hướng dẫn làm xúc xắc điện tử bằng ESP32 và màn hình OLED 0.96 inch kèm 4 nút: bấm một nút để tung, bấm nút khác để tung nhanh 60 lần và xem biểu đồ. Nhờ mạch tung hàng trăm lần trong chớp mắt, học sinh tự quan sát được điều mà tung tay phải mất cả buổi.

Qua dự án, trẻ học được: máy tính tạo số ngẫu nhiên như thế nào, cách vẽ mặt xúc xắc bằng câu lệnh điều kiện, xác suất lý thuyết và xác suất thực nghiệm khác nhau ra sao, và vì sao tung càng nhiều lần thì kết quả càng "đều".

1. Chuẩn bị

2. Nối dây

Sơ đồ nối ESP32 DevKit V1 với màn hình OLED kèm 4 nút: GND với GND, VCC với 3V3, SCL với D22, SDA với D21, K1 với D32, K2 với D33, K3 với D25, K4 với D26; màn hình hiện bảng chọn K1 tung 1 lần, K2 tung 60 lần, K3 biểu đồ, K4 xóa
Hình minh họa: nối các chân cùng màu.
Nối màn hình OLED kèm 4 nút với ESP32
Chân moduleChân ESP32Chân moduleChân ESP32
GNDGNDK1D32
VCC3V3K2D33
SCLD22K3D25
SDAD21K4D26

Cách nối giống hệt trò chơi đo phản xạ trong cùng loạt bài, nên có thể dùng chung một bộ mạch cho cả hai dự án. Mỗi lô mạch có thể đổi chỗ VCC và GND: luôn đọc chữ in cạnh hàng chân trước khi cắm dây nguồn.

3. Chương trình xúc xắc và thống kê

// PYWORLD.VN - ESP32 + OLED 0.96 inch kèm 4 nút: xúc xắc điện tử và thí nghiệm xác suất
// K1: tung 1 lần; K2: tung nhanh 60 lần; K3: xem biểu đồ số lần ra mỗi mặt; K4: xóa thống kê
// OLED: SDA = D21, SCL = D22; nút: K1 = D32, K2 = D33, K3 = D25, K4 = D26

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

Adafruit_SSD1306 oled(128, 64, &Wire, -1);

const int SO_NUT = 4;
const int CHAN_NUT[SO_NUT] = {32, 33, 25, 26};   // K1, K2, K3, K4
int mucNghi[SO_NUT];
unsigned long soLanRa[7];                         // soLanRa[1]..soLanRa[6]
unsigned long tongSoLan = 0;

int nutVuaBam() {                                 // chờ nhả rồi mới trả về, mỗi lần bấm tính một lần
  for (int i = 0; i < SO_NUT; i++) {
    if (digitalRead(CHAN_NUT[i]) != mucNghi[i]) {
      while (digitalRead(CHAN_NUT[i]) != mucNghi[i]) delay(10);
      delay(30);
      return i;
    }
  }
  return -1;
}

// Vẽ mặt xúc xắc có số chấm n (1–6) trong ô vuông 56 x 56 ở góc trái trên (x, y)
void veMat(int x, int y, int n) {
  oled.drawRoundRect(x, y, 56, 56, 8, SSD1306_WHITE);
  int a = x + 14, b = x + 28, c = x + 42;         // ba cột
  int d = y + 14, e = y + 28, f = y + 42;         // ba hàng
  if (n % 2 == 1) oled.fillCircle(b, e, 5, SSD1306_WHITE);        // chấm giữa: 1, 3, 5
  if (n >= 2) { oled.fillCircle(a, d, 5, SSD1306_WHITE); oled.fillCircle(c, f, 5, SSD1306_WHITE); }
  if (n >= 4) { oled.fillCircle(c, d, 5, SSD1306_WHITE); oled.fillCircle(a, f, 5, SSD1306_WHITE); }
  if (n == 6) { oled.fillCircle(a, e, 5, SSD1306_WHITE); oled.fillCircle(c, e, 5, SSD1306_WHITE); }
}

void hienMotLan(int mat) {
  oled.clearDisplay();
  veMat(4, 4, mat);
  oled.setTextSize(1);
  oled.setCursor(70, 8);
  oled.print("Ra mat:");
  oled.setTextSize(3);
  oled.setCursor(84, 24);
  oled.print(mat);
  oled.setTextSize(1);
  oled.setCursor(70, 54);
  oled.printf("Lan %lu", tongSoLan);
  oled.display();
}

void hienBieuDo() {
  unsigned long lonNhat = 1;
  for (int m = 1; m <= 6; m++) if (soLanRa[m] > lonNhat) lonNhat = soLanRa[m];
  oled.clearDisplay();
  oled.setTextSize(1);
  oled.setCursor(0, 0);
  oled.printf("Tong %lu lan", tongSoLan);
  for (int m = 1; m <= 6; m++) {
    int cao = (int)(40 * soLanRa[m] / lonNhat);   // cột cao nhất 40 điểm ảnh
    int x = 4 + (m - 1) * 21;
    oled.fillRect(x, 54 - cao, 14, cao, SSD1306_WHITE);
    oled.setCursor(x + 4, 56);
    oled.print(m);
  }
  oled.display();
  Serial.printf("Tong %lu:", tongSoLan);
  for (int m = 1; m <= 6; m++) Serial.printf(" %d=%lu", m, soLanRa[m]);
  Serial.println();
}

int tung() {
  int mat = random(1, 7);                         // số ngẫu nhiên từ 1 đến 6
  soLanRa[mat]++;
  tongSoLan++;
  return mat;
}

void setup() {
  Serial.begin(115200);
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.setTextColor(SSD1306_WHITE);
  for (int i = 0; i < SO_NUT; i++) pinMode(CHAN_NUT[i], INPUT_PULLUP);
  delay(50);
  for (int i = 0; i < SO_NUT; i++) mucNghi[i] = digitalRead(CHAN_NUT[i]);
  oled.clearDisplay();
  oled.setTextSize(1);
  oled.setCursor(0, 0);
  oled.print("K1: tung 1 lan\nK2: tung 60 lan\nK3: bieu do\nK4: xoa");
  oled.display();
}

void loop() {
  int nut = nutVuaBam();
  if (nut == 0) {                                 // K1: tung một lần, có hiệu ứng lăn
    for (int i = 0; i < 8; i++) {
      oled.clearDisplay();
      veMat(4, 4, random(1, 7));
      oled.display();
      delay(60 + i * 15);
    }
    int mat = tung();
    hienMotLan(mat);
    Serial.printf("Lan %lu: %d\n", tongSoLan, mat);
  } else if (nut == 1) {                          // K2: tung nhanh 60 lần
    for (int i = 0; i < 60; i++) tung();
    hienBieuDo();
  } else if (nut == 2) {                          // K3: xem biểu đồ
    hienBieuDo();
  } else if (nut == 3) {                          // K4: xóa thống kê
    for (int m = 0; m <= 6; m++) soLanRa[m] = 0;
    tongSoLan = 0;
    oled.clearDisplay();
    oled.setCursor(0, 0);
    oled.print("Da xoa thong ke");
    oled.display();
  }
  delay(10);
}

Nạp chương trình khi không bấm nút nào. Màn hình hiện bảng chọn bốn chức năng:

  • K1: tung một lần. Mặt xúc xắc "lăn" qua 8 khung hình, chậm dần (60 ms, 75 ms, 90 ms…) rồi dừng ở kết quả.
  • K2: tung nhanh 60 lần và hiện biểu đồ. Bấm K2 nhiều lần thì số lần tung cộng dồn: 60, 120, 180…
  • K3: xem lại biểu đồ. K4: xóa thống kê để làm thí nghiệm mới.

Bốn nút trên module có ký hiệu ^ v # *, còn chương trình gọi theo tên chân K1–K4. Nếu chưa biết nút nào là K1, cứ bấm thử: nút làm xúc xắc lăn là K1, nút hiện biểu đồ ngay là K2 hoặc K3.

Máy tính tung xúc xắc thế nào?

Lệnh random(1, 7) cho một số nguyên từ 1 đến 6 (số 7 không bao giờ ra). Khác với Arduino Uno, ESP32 có sẵn bộ tạo số ngẫu nhiên bằng phần cứng, và hàm random() của gói esp32 lấy số từ bộ này, nên mỗi lần bật mạch không lặp lại cùng một dãy số.

Vẽ 6 mặt bằng 4 câu lệnh "nếu"

Hàm veMat() không vẽ riêng từng mặt mà dùng quy luật của các chấm, một bài tư duy rất hay cho học sinh:

  • Mặt lẻ (1, 3, 5) có chấm ở giữa: n % 2 == 1.
  • Từ mặt 2 trở lên có hai chấm ở đường chéo: trên trái và dưới phải.
  • Từ mặt 4 trở lên có thêm đường chéo còn lại.
  • Riêng mặt 6 có thêm hai chấm ở giữa hai bên.

Hỏi trẻ: mặt 5 được vẽ bởi những câu lệnh nào? Vì sao mặt 3 không có chấm ở góc trên phải?

Sáu màn hình OLED mô phỏng: bảng chọn bốn nút; mặt xúc xắc đang lăn; Ra mat 1, Lan 1; biểu đồ 6 cột Tong 61 lan; biểu đồ Tong 601 lan với các cột gần bằng nhau; dòng chữ Da xoa thong ke
Hình mô phỏng: hình và chữ theo đúng chương trình, kết quả tung là mô phỏng.

Biểu đồ trên màn hình tự co giãn: mặt ra nhiều nhất luôn cao 40 điểm ảnh, các mặt khác cao theo tỉ lệ. Muốn biết số lần chính xác, mở Serial Monitor ở 115200 baud: mỗi lần hiện biểu đồ, chương trình in một dòng dạng Tong 61: 1=11 2=4 3=12 4=10 5=13 6=11.

4. Xác suất lý thuyết và xác suất thực nghiệm

Sáu mặt xúc xắc, dưới mỗi mặt ghi 1/6, khoảng 16,7 phần trăm; ô xác suất lý thuyết: 6 mặt có khả năng như nhau, tung 60 lần mỗi mặt khoảng 10 lần nhưng hiếm khi đúng 10; ô xác suất thực nghiệm: số lần ra mặt đó chia tổng số lần tung, ví dụ mô phỏng 61 lần tung mặt 6 ra 11 lần, khoảng 18 phần trăm
Hình minh họa: hai cách nói về khả năng ra một mặt.
  • Xác suất lý thuyết: xúc xắc cân đối có 6 mặt khả năng như nhau, nên mỗi mặt có xác suất 1/6, khoảng 16,7 %.
  • Xác suất thực nghiệm: làm thí nghiệm thật, lấy số lần ra một mặt chia cho tổng số lần tung. Trong Chương trình Toán 2018, học sinh lớp 6 học khái niệm này.

Với 60 lần tung, mỗi mặt "nên" ra khoảng 10 lần, nhưng thực tế thường lệch vài lần. Đó không phải lỗi của chương trình: ngẫu nhiên nghĩa là không đoán trước được từng lần.

5. Tung càng nhiều, càng gần một phần sáu

Bốn biểu đồ cột tỉ lệ phần trăm số lần ra mỗi mặt sau 60, 600, 6.000 và 60.000 lần tung mô phỏng; độ lệch lớn nhất so với 16,7 phần trăm giảm từ 10 phần trăm còn 2, 0,9 và 0,2 phần trăm; đường nét đứt là xác suất lý thuyết
Hình mô phỏng trên máy tính: các cột dần sát đường 16,7 %.

Thí nghiệm với mạch: bấm K4 để xóa, bấm K2 một lần (60 lần tung) và ghi số lần ra từng mặt. Bấm K2 thêm 9 lần (600 lần) và ghi lại. Tính tỉ lệ phần trăm của từng mặt và so sánh. Các tỉ lệ sẽ tiến gần 16,7 % hơn. Các nhà toán học gọi hiện tượng này là luật số lớn: làm thí nghiệm càng nhiều lần, xác suất thực nghiệm càng gần xác suất lý thuyết.

6. Thí nghiệm và thử thách mở rộng

  • So với xúc xắc thật: mỗi nhóm tung xúc xắc thật 30 lần và ghi bảng, cả lớp cộng kết quả lại. Kết quả có giống xúc xắc điện tử không?
  • Số "giả" ngẫu nhiên: thêm dòng randomSeed(42); vào cuối setup(). Tung 5 lần, ghi lại, rồi bấm nút EN để khởi động lại và tung tiếp 5 lần. Hai dãy giống hệt nhau! Khi gọi randomSeed(), chương trình chuyển sang cách tính số "giả ngẫu nhiên": cùng một số khởi đầu thì cùng một dãy.
  • Xúc xắc gian lận: trong hàm tung(), đổi thành int mat = random(1, 8); if (mat == 7) mat = 6;. Mặt 6 bây giờ có xác suất 2/7. Một bạn sửa chương trình bí mật, bạn khác dùng thống kê để phát hiện xúc xắc có gian lận không. Cần tung bao nhiêu lần mới chắc chắn?
  • Hai xúc xắc: xem hình bên dưới.
Bảng 6 nhân 6 ghi tổng hai xúc xắc, các ô tổng 7 tô màu nằm trên đường chéo; biểu đồ số cách ra mỗi tổng từ 2 đến 12: 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1 trên 36, tổng 7 cao nhất với 6/36
Hình minh họa: tổng 7 có nhiều cách ra nhất.

Tung hai xúc xắc và cộng hai mặt, tổng nào hay ra nhất? Bảng 36 ô cho thấy tổng 7 có 6 cách, còn tổng 2 và 12 chỉ có 1 cách. Học sinh lớn có thể sửa chương trình: tung hai lần random(1, 7), cộng lại, đếm 11 loại tổng (mảng có 13 phần tử, dùng từ chỉ số 2 đến 12) và vẽ biểu đồ 11 cột hẹp hơn, rồi so với biểu đồ lý thuyết.

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

Lỗi thường gặp và cách xử lý
Hiện tượngNguyên nhân thường gặpCách xử lý
Màn hình không sángĐảo VCC và GND; lỏng dây SDA, SCL; địa chỉ khác 0x3CĐọc lại chữ in trên mạch; cắm chắc dây; đổi 0x3C thành 0x3D
Báo lỗi không tìm thấy Adafruit_SSD1306.hChưa cài thư việnCài Adafruit SSD1306 kèm Adafruit GFX Library và Adafruit BusIO
Vừa bật mạch, xúc xắc tự lăn liên tụcĐang giữ nút lúc khởi động nên mức nghỉ bị ghi saiBỏ tay ra, bấm nút EN để khởi động lại
Bấm nút không có phản ứngDây nút lỏng hoặc sai chân; nút nối lên nguồn mà mạch không có điện trở kéo xuốngKiểm tra dây; thử đổi INPUT_PULLUP thành INPUT_PULLDOWN
Bấm K3 thấy "Tong 0 lan" và không có cột nàoChưa tung lần nào, hoặc vừa bấm K4 xóa thống kêBấm K1 hoặc K2 để tung trước, rồi mới xem biểu đồ

8. Gợi ý cho phụ huynh và giáo viên

  • Đoán trước, đo sau: trước khi bấm K2, cho trẻ đoán mỗi mặt sẽ ra bao nhiêu lần trong 60 lần, viết ra giấy rồi so với kết quả.
  • Liên môn: Toán (phân số, tỉ số phần trăm, biểu đồ cột, xác suất thực nghiệm lớp 6), Tin học (câu lệnh điều kiện, mảng đếm, vòng lặp), và cả Khoa học (thí nghiệm lặp lại nhiều lần).
  • Trò chơi lớp học: dùng xúc xắc điện tử thay xúc xắc thật trong các trò chơi cờ, rồi thảo luận: xúc xắc điện tử có "công bằng" hơn không?
  • Không cổ vũ cờ bạc: nếu trẻ liên hệ với trò chơi ăn tiền, đây là dịp tốt để giải thích bằng số liệu vì sao người chơi lâu dài luôn thua: luật chơi được tính để nhà cái có lợi.
  • Thời lượng: 2 buổi 45 phút. Buổi 1: nối dây, chơi xúc xắc, đọc hàm veMat(). Buổi 2: thí nghiệm 60 và 600 lần, tính phần trăm, một thử thách mở rộng.

9. Xem thêm

  • Lệnh vẽ chữ, hình trên màn hình OLED: màn hình OLED 0.96 inch SSD1306 với Arduino Nano.
  • Hai dây SDA, SCL hoạt động thế nào: giao tiếp I2C trên ESP32.
  • Trong loạt phát triển tư duy cho trẻ bằng STEM và lập trình còn có: trò chơi đo phản xạ với ESP32 và màn hình OLED (có chương trình kiểm tra 4 nút), thuật toán qua trò chơi kiểu Bebras, số nhị phân cho trẻ với thẻ chấm.

Tin tức liên quan

Gia công xốp chống sốc cho thiết bị đo lường: mẫu thực tế và cách đặt
Gia công xốp chống sốc cho thiết bị đo lường: mẫu thực tế và cách đặt

PYWORLD gia công xốp chống sốc theo biên dạng thiết bị đo lường: máy đo cầm tay, bơm hiệu chuẩn áp suất, đầu nối. Xem hai mẫu thực tế, cách bố trí khoang và thông tin cần gửi khi đặt.

Chuẩn lực: máy tải trọng chết, đòn bẩy, khuếch đại thủy lực, máy so sánh và gia tốc trọng trường
Chuẩn lực: máy tải trọng chết, đòn bẩy, khuếch đại thủy lực, máy so sánh và gia tốc trọng trường

Bốn kiểu máy chuẩn lực: tải trọng chết, đòn bẩy, khuếch đại thủy lực, máy so sánh; cách tính lực từ quả cân, vì sao g tại Việt Nam lệch 0,25 % và chuỗi liên kết chuẩn lực.

Chuẩn rung: hiệu chuẩn gia tốc kế bằng giao thoa laser và so sánh theo ISO 16063, đáp ứng tần số
Chuẩn rung: hiệu chuẩn gia tốc kế bằng giao thoa laser và so sánh theo ISO 16063, đáp ứng tần số

Hiệu chuẩn gia tốc kế theo ISO 16063: dịch chuyển, vận tốc, gia tốc theo tần số, phương pháp giao thoa laser và so sánh lưng tựa lưng, đọc đáp ứng tần số và chuỗi liên kết chuẩn rung.

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
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.

Độ không đảm bảo đo theo GUM: sáu bước tính, loại A, loại B và ví dụ ngân sách hiệu chuẩn áp kế
Độ không đảm bảo đo theo GUM: sáu bước tính, loại A, loại B và ví dụ ngân sách hiệu chuẩn áp kế

Cách tính độ không đảm bảo đo theo GUM: sáu bước, đánh giá loại A và loại B, phân bố chuẩn, chữ nhật, tam giác, ví dụ ngân sách hiệu chuẩn áp kế, cách làm tròn và lỗi hay gặp.

Vẽ đa giác và hoa văn bằng lập trình: học góc trong môn Toán với Scratch
Vẽ đa giác và hoa văn bằng lập trình: học góc trong môn Toán với Scratch

Dùng nhóm lệnh Bút vẽ của Scratch để vẽ đa giác đều, ngôi sao, hoa văn, xoắn ốc; hiểu vì sao xoay góc ngoài 360 : n, góc trong, và liên hệ với môn Toán ở tiểu học.

Tư duy logic, phản biện, thiết kế và kỹ năng 4C: rèn cho trẻ qua hoạt động STEM
Tư duy logic, phản biện, thiết kế và kỹ năng 4C: rèn cho trẻ qua hoạt động STEM

Phân biệt tư duy logic, phản biện, thiết kế và kỹ năng 4C bằng ví dụ; câu đố logic 4 x 4, thí nghiệm kiểm chứng, dự án hộp bút theo tư duy thiết kế và bảng đánh giá 4C.

Đàn piano trái cây với ESP32: 6 phím cảm ứng, còi phát nốt nhạc cho học sinh
Đàn piano trái cây với ESP32: 6 phím cảm ứng, còi phát nốt nhạc cho học sinh

Dự án STEM âm nhạc: nối sáu quả vào chân cảm ứng ESP32, chạm quả nào còi phát nốt đó; tần số Đô Rê Mi Fa Son La, giai điệu viết bằng hai mảng nốt và phách.


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