Esp32 run run run python and microPython

2026-10-01

Esp32 run run run python

Đây là bảng so sánh nhanh Arduino vs ESP-IDF vs MicroPython trên ESP32:

Tiêu chí Arduino ESP-IDF MicroPython
Ngôn ngữ C/C++ C/C++ Python
Độ dễ Dễ Khó hơn Dễ nhất
Build/compile Có Có Thường không
Upload code Flash firmware Flash firmware Copy .py
Tốc độ Nhanh Nhanh nhất / kiểm soát sâu Chậm hơn
RAM usage Vừa Tối ưu nhất nếu làm kỹ Cao hơn
Thư viện sensor Rất nhiều Ít tiện hơn Arduino Khá nhiều
GPIO/I2C/SPI/UART ✅ ✅ ✅
Wi-Fi ✅ ✅ ✅
BLE ✅ ✅ ✅
MQTT ✅ ✅ ✅
HTTPS/TLS ✅ ✅ ✅
FreeRTOS Có bên dưới ✅ dùng trực tiếp Không trực tiếp như IDF
Multi-task Khá dễ Rất mạnh Có asyncio, thread hạn chế hơn
Debug Khá Tốt nhất Đơn giản
OTA ✅ ✅ rất mạnh Có thể làm
Low power Tốt Tốt nhất Có nhưng ít kiểm soát hơn
Production ✅ ✅ tốt nhất Có, nhưng tùy project
Prototype ✅ Có ✅ tốt nhất

python in esp32

Ví dụ cùng một việc bật LED.

Arduino:

void setup() {
    pinMode(2, OUTPUT);
}

void loop() {
    digitalWrite(2, HIGH);
    delay(1000);
    digitalWrite(2, LOW);
    delay(1000);
}

MicroPython:

from machine import Pin
import time

led = Pin(2, Pin.OUT)

while True:
    led.on()
    time.sleep(1)
    led.off()
    time.sleep(1)

ESP-IDF sẽ dài hơn vì thường đi theo kiểu API chính thức:

gpio_reset_pin(GPIO_NUM_2);
gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT);

while (1) {
    gpio_set_level(GPIO_NUM_2, 1);
    vTaskDelay(pdMS_TO_TICKS(1000));

    gpio_set_level(GPIO_NUM_2, 0);
    vTaskDelay(pdMS_TO_TICKS(1000));
}

Nếu nhìn theo workflow thì khác biệt khá rõ:

Arduino
code
→ compile
→ flash
→ chạy
ESP-IDF
code
→ build
→ link
→ flash
→ monitor/debug
MicroPython
MicroPython firmware đã flash sẵn
→ sửa main.py
→ copy vào ESP32
→ reset
→ chạy

Về performance thì đại khái:

ESP-IDF ≈ Arduino
>>>>>>>> MicroPython

Nhưng trong các project kiểu:

đọc sensor
→ xử lý chút dữ liệu
→ gửi MQTT
→ điều khiển relay/LED

thì thường không cảm nhận được khác biệt lớn giữa Arduino và MicroPython.

Khác biệt sẽ rõ nếu làm:

camera
audio processing
DSP
high-frequency PWM
motor control tốc độ cao
rất nhiều interrupt
BLE + Wi-Fi + nhiều task
real-time timing nghiêm ngặt

thì nên dùng ESP-IDF hoặc Arduino C++.

Còn về thư viện thì Arduino thường thắng:

Arduino ecosystem
████████████████████

MicroPython
████████████

ESP-IDF
████████

ESP-IDF không phải ít khả năng, mà là nhiều sensor không có kiểu:

sensor.begin();
sensor.readTemperature();

sẵn tiện như Arduino. Bạn thường phải làm driver hoặc dùng component của bên thứ ba.

Một điểm rất quan trọng nữa là Arduino ESP32 thực ra chạy trên ESP-IDF.

Kiến trúc đại khái:

Your Arduino code
       ↓
Arduino ESP32 Core
       ↓
ESP-IDF
       ↓
FreeRTOS
       ↓
ESP32 hardware

Nên Arduino không phải một hệ hoàn toàn tách biệt.

Thậm chí bạn có thể dùng API ESP-IDF bên trong project Arduino:

#include "esp_system.h"

void setup() {
    Serial.begin(115200);

    Serial.println(esp_get_free_heap_size());
}

Đây là lý do Arduino khá hấp dẫn: dễ viết nhưng vẫn có thể xuống tầng thấp khi cần.

Nếu chia theo project thực tế thì tôi sẽ chọn như này:

Project Nên dùng
LED / relay MicroPython
Sensor IoT MicroPython / Arduino
MQTT MicroPython / Arduino
OLED/LCD Arduino / MicroPython
Home automation ESPHome
Robot đơn giản Arduino
Servo / stepper Arduino
Motor control chính xác ESP-IDF
ESP32-CAM Arduino / ESP-IDF
Audio ESP-IDF
BLE phức tạp ESP-IDF
Sản phẩm thương mại ESP-IDF / Arduino
Prototype 1 ngày MicroPython
Học ESP32 Arduino hoặc MicroPython

Nếu bạn đang bắt đầu ESP32 mà đã biết Python, mình thấy lộ trình khá hay là:

MicroPython
    ↓
hiểu GPIO / I2C / SPI / UART / Wi-Fi
    ↓
Arduino C++
    ↓
ESP-IDF

Như vậy ban đầu không bị mất quá nhiều thời gian vào build toolchain, rồi khi cần tốc độ hoặc project lớn mới chuyển sang C/C++.

Có khá nhiều “cách chạy ESP32”, nhưng nên tách ra thành framework/runtime và công cụ build/IDE vì nhiều cái hay bị gọi lẫn.

Những lựa chọn phổ biến nhất:

Nếu xếp theo độ dễ:

ESPHome
↓
MicroPython / CircuitPython
↓
Arduino
↓
ESP-IDF
↓
Zephyr / Rust

Còn nếu xếp theo độ kiểm soát/performance:

ESP-IDF
≈ Zephyr / Rust native
↓
Arduino
↓
MicroPython / CircuitPython
↓
ESPHome

Một điểm dễ nhầm: PlatformIO không phải framework chạy trên ESP32. Nó là công cụ build/project manager. Trong PlatformIO bạn có thể chọn:

PlatformIO
 ├─ Arduino
 └─ ESP-IDF

Tương tự, VS Code hay Arduino IDE chỉ là môi trường viết code.

Nếu mục tiêu của bạn là:

Nếu muốn, tôi có thể làm luôn bảng so sánh Arduino vs ESP-IDF vs MicroPython theo RAM, tốc độ, Wi-Fi, BLE, thư viện, build, debug và độ khó.

esp32 chạy python sao nó không cần build vậy

Vì ESP32 không chạy “Python thường” trực tiếp. Với MicroPython, bạn đã flash sẵn một firmware có interpreter Python vào chip rồi.

Luồng thực tế là:

ESP32
↓
MicroPython firmware
↓
Python interpreter
↓
main.py

Nên khi bạn sửa:

print("hello")

thì không cần build lại toàn bộ firmware. Interpreter sẽ đọc và thực thi code Python.

Nó giống máy tính của bạn đã cài Python:

python main.py

Bạn cũng không compile main.py thành .exe mỗi lần.

Trong khi Arduino/C++ là:

source .cpp
↓
compiler
↓
machine code
↓
flash vào ESP32

ESP32 chỉ hiểu machine code, nên C/C++ phải được compile trước.

Còn MicroPython:

main.py
↓
MicroPython interpreter đọc
↓
chuyển thành bytecode nội bộ
↓
VM thực thi

Nói chính xác hơn, MicroPython thường vẫn có bước compile Python source thành bytecode, nhưng việc này diễn ra ngay trên runtime, rất nhanh và tự động. Bạn không phải tự chạy build.

Có thể hình dung:

Arduino / ESP-IDF
-----------------
main.cpp
  ↓
compile trên PC
  ↓
firmware.bin
  ↓
ESP32 chạy machine code
MicroPython
-----------
MicroPython firmware.bin  ← flash một lần
  ↓
main.py
  ↓
compile thành bytecode lúc chạy
  ↓
MicroPython VM chạy bytecode

Vì vậy main.py chỉ là “script” nằm trong flash filesystem.

Đổi code:

main.py cũ
↓
copy main.py mới
↓
reset
↓
chạy code mới

không cần build lại firmware.

Đổi lại, cái giá phải trả là:

Nhưng với sensor, MQTT, Wi-Fi, relay, OLED, API… thì rất tiện.

Có một chi tiết khá thú vị: bạn còn có thể compile trước file Python thành .mpy để giảm dung lượng và load nhanh hơn. Nhưng với development bình thường thì cứ .py là đủ.

So sánh lúc chạy

Với ESP32 classic không PSRAM, chip có tổng RAM khoảng 528 KB, nhưng một phần bị ESP-IDF, Wi-Fi/BLE, stack hệ thống… dùng mất. :chatgpt-content-reference{index=”0”}

MicroPython hiện tại khởi tạo Python heap khá nhỏ rồi mở rộng thêm khi cần. Với ESP32 classic, cấu hình hiện tại đặt heap ban đầu khoảng 56 KB. :chatgpt-content-reference{index=”1”} Một ví dụ chính thức của MicroPython trên ESP32 không PSRAM cho thấy lúc mới boot, Python có thể thấy khoảng 170 KB bộ nhớ khả dụng tổng cộng cho heap sau khi tính cả vùng có thể mở rộng. :chatgpt-content-reference{index=”2”}

Có thể hình dung RAM như này:

ESP32 RAM ~528 KB
│
├── ESP-IDF / FreeRTOS
├── Wi-Fi / BLE buffers
├── stack
├── driver
├── MicroPython runtime
└── Python heap
      └── khoảng ~100–200 KB usable
          tùy firmware / Wi-Fi / BLE / board

Nếu bật Wi-Fi, TLS, MQTT, BLE cùng lúc thì RAM trống giảm khá nhanh.

Bạn có thể tự xem trực tiếp:

import gc

print(gc.mem_alloc())
print(gc.mem_free())

Hoặc chi tiết hơn:

import micropython

micropython.mem_info()

MicroPython docs cũng khuyến nghị dùng gc.mem_free() và micropython.mem_info() để xem bộ nhớ Python thực tế. :chatgpt-content-reference{index=”3”}

Về ROM/Flash, MicroPython firmware bản thân nó thường chiếm cỡ 1–2 MB flash tùy build và tính năng. ESP32_GENERIC hiện yêu cầu board thường có 4 MB flash trở lên; phần flash còn lại được chia cho filesystem, partition, OTA nếu bật, v.v. :chatgpt-content-reference{index=”4”}

Ví dụ board:

ESP32 WROOM
4 MB Flash
528 KB RAM

sau khi flash MicroPython đại khái:

Flash 4 MB
├── bootloader + partition
├── MicroPython firmware ~1–2 MB
└── filesystem cho main.py/lib/data...

Còn RAM lúc chạy:

528 KB
↓
hệ thống + runtime ăn một phần
↓
Python app thường còn khoảng 100–200 KB để chơi

Đây là lý do đoạn kiểu này rất dễ chết:

data = bytearray(500_000)

với lỗi:

MemoryError

Nhưng nếu board có PSRAM, câu chuyện khác hẳn. ESP32/ESP32-S3 có board 2 MB, 4 MB, 8 MB PSRAM; MicroPython có thể tận dụng vùng đó. MicroPython thậm chí khuyến nghị ESP32-S3 + PSRAM nếu cần nhiều RAM. :chatgpt-content-reference{index=”5”}

Ví dụ ESP32-S3 N16R8:

Flash: 16 MB
PSRAM: 8 MB

thì chạy MicroPython thoải mái hơn rất nhiều:

main.py
HTTP
MQTT
JSON
display buffer
nhiều sensor

đều dễ thở hơn ESP32 528 KB RAM thường.

Còn nếu bạn đang hỏi Python desktop CPython thì khác một trời một vực: chỉ khởi động interpreter trên Windows/Linux thường đã dùng hàng chục MB RAM, import numpy, pandas có thể lên 100 MB+ rất nhanh.

Nên so tương đối:

Arduino/C:
vài KB → vài chục KB RAM

MicroPython ESP32:
vài chục KB runtime
+ ~100–200 KB heap khả dụng

Python desktop CPython:
~10–30+ MB chỉ runtime
+ thư viện có thể lên hàng trăm MB

Đó cũng chính là lý do không thể bê nguyên CPython xuống ESP32, mà phải có MicroPython được cắt gọn rất mạnh.

Ai chế python cho esp32

Người khởi tạo MicroPython là Damien George. Dự án bắt đầu khoảng 2013 với mục tiêu đưa Python 3 xuống vi điều khiển; trang chính thức của MicroPython hiện vẫn ghi đây là “A project by Damien George.”
https://micropython.org/download/?mcu=stm32f4 https://github.com/micropython/micropython-esp32

https://github.com/micropython/micropython/blob/master/ports/esp32/README.md

Nhưng ông ấy không “viết Python riêng cho ESP32” ngay từ đầu. MicroPython ban đầu chạy trên các vi điều khiển khác như STM32/pyboard, rồi sau đó cộng đồng làm port cho ESP32. Port ESP32 hiện đã nằm trong repo chính của MicroPython và dùng ESP-IDF + FreeRTOS ở bên dưới. :chatgpt-content-reference{index=”1”}

Kiến trúc có thể hiểu như này:

code Python của bạn
        ↓
MicroPython interpreter
        ↓
ESP32 port của MicroPython
        ↓
ESP-IDF
        ↓
FreeRTOS
        ↓
ESP32 hardware

Nên bên dưới MicroPython trên ESP32 thực ra vẫn là một đống C/C++ native code rất tối ưu. Python chỉ là lớp bạn viết ở phía trên.

Điểm hay là port ESP32 hỗ trợ khá sâu: GPIO, UART, SPI, I2C, ADC, DAC, PWM, touch, watchdog, timer, Wi-Fi và BLE. :chatgpt-content-reference{index=”2”}

Nói ngắn gọn: Damien George tạo MicroPython; sau đó ông ấy cùng cộng đồng port nó sang ESP32. Espressif hiện cũng hỗ trợ ESP32 như một port cấp cao trong dự án MicroPython. :chatgpt-content-reference{index=”3”} https://github.com/micropython/micropython

Python chạy được ở đâu

Python có thể chạy ở rất nhiều nơi, từ máy tính mạnh cho tới vi điều khiển nhỏ như ESP32. Điểm khác nhau là implementation/runtime dùng để chạy Python.

Có thể chia như này:

Điểm thú vị là “Python chạy được ở đâu” phụ thuộc rất nhiều vào phần cứng:

PC / Server
→ CPython

Raspberry Pi
→ CPython

ESP32 / STM32 / RP2040
→ MicroPython / CircuitPython

Browser
→ Pyodide / WebAssembly

Nếu xét riêng kiểu giống ESP32, tức là vi điều khiển nhỏ, thì những chip/board đáng chú ý nhất là:

ESP32
STM32
RP2040 / Raspberry Pi Pico
nRF52
SAMD21 / SAMD51
micro:bit
Teensy một số dòng

Trong số này, ESP32 và Raspberry Pi Pico là hai lựa chọn rất phổ biến để chạy MicroPython.

Nếu muốn, tôi có thể làm tiếp bảng ESP32 vs Raspberry Pi Pico vs STM32 khi chạy MicroPython, xem con nào mạnh hơn, RAM/flash bao nhiêu và dùng cho việc gì.

Có. Website chính thức của MicroPython là chỗ tốt nhất để xem đầy đủ import, class, method, function và phần riêng cho ESP32.

Bạn nên bookmark mấy trang này:

Ví dụ bạn muốn GPIO thì vào machine.Pin: :chatgpt-content-reference{index=”6”}
machine.Pin documentation

Muốn I2C: :chatgpt-content-reference{index=”8”}
machine.I2C documentation

Muốn SPI: :chatgpt-content-reference{index=”10”}
machine.SPI documentation

Kiểu tra cứu sẽ như này:

from machine import Pin, ADC, PWM, I2C, SPI, UART

rồi vào docs sẽ thấy:

machine
├── Pin
│   ├── value()
│   ├── on()
│   ├── off()
│   ├── irq()
│   └── init()
│
├── ADC
├── PWM
├── UART
├── SPI
├── SoftSPI
├── I2C
├── SoftI2C
├── I2S
├── RTC
├── Timer
└── WDT

Ngoài machine, mấy module rất hay dùng trên ESP32 là:

import network
import bluetooth
import socket
import ssl
import time
import json
import os
import gc
import micropython
import esp32
import neopixel

Có một điểm cần chú ý: docs ở /en/latest/ là development/latest docs, nên đôi khi có API chưa có trong firmware bạn đang chạy. Chính docs cũng cảnh báo điều này. :chatgpt-content-reference{index=”12”}

Nếu muốn xem chính xác firmware ESP32 của bạn hỗ trợ cái gì, ngay trên ESP32 có thể chạy:

help('modules')

Nó sẽ liệt kê module có trong firmware đó.

Sau đó:

import machine
help(machine)

hoặc:

from machine import Pin
help(Pin)

Đây mới là cách chắc chắn nhất xem board hiện tại thực sự hỗ trợ gì.

Nếu bạn muốn, tôi có thể làm cho bạn một cheat sheet toàn bộ MicroPython ESP32 kiểu import → class → function → ví dụ, gói gọn trong 1 bảng để tra rất nhanh.

Cách chạy 1 file

Tối thiểu nhất thì MicroPython trên ESP32 chỉ cần main.py.

Ví dụ:

# main.py
print("Hello ESP32")

Cách chạy là:

ESP32 bật nguồn / reset
        ↓
MicroPython firmware khởi động
        ↓
boot.py   (nếu có)
        ↓
main.py   (nếu có)
        ↓
chạy code trong main.py

Cấu trúc tối thiểu:

/
└── main.py

Không bắt buộc phải có boot.py.

Nếu có boot.py thì thường dùng cho phần khởi tạo hệ thống:

# boot.py
print("Booting...")

rồi:

# main.py
print("Main program")

Kết quả khi reset:

Booting...
Main program

Một ví dụ thực tế tối thiểu với LED:

# main.py

from machine import Pin
import time

led = Pin(2, Pin.OUT)

while True:
    led.on()
    time.sleep(1)

    led.off()
    time.sleep(1)

Quy trình dev thường là:

1. Flash MicroPython firmware vào ESP32
2. Kết nối USB
3. Copy main.py vào filesystem của ESP32
4. Reset ESP32
5. main.py tự chạy

Không cần lệnh kiểu:

python main.py

trên ESP32.

MicroPython tự tìm main.py sau khi boot.

Nếu đang dùng REPL thì bạn cũng có thể chạy từng câu trực tiếp:

>>> print("hello")
hello

hoặc import một file khác:

/
├── main.py
└── wifi.py

wifi.py:

def connect():
    print("connecting wifi...")

main.py:

import wifi

wifi.connect()

MicroPython sẽ tìm wifi.py trong filesystem và import nó.

Project thực tế thường tổ chức kiểu:

/
├── boot.py
├── main.py
├── config.py
├── wifi.py
├── sensor.py
└── lib/
    └── ssd1306.py

Nhưng tối thiểu nhất vẫn chỉ là:

main.py

và reset board là chạy.

Được, bạn hoàn toàn có thể tự tổ chức MicroPython theo kiểu Arduino setup() + loop() cho dễ nhìn.

Ví dụ cấu trúc:

/
├── main.py
└── mycode.py

mycode.py:

from machine import Pin

led = Pin(2, Pin.OUT)

def setup():
    print("Setup")
    led.off()

def loop():
    led.value(not led.value())

main.py:

import time
import mycode

def setup():
    mycode.setup()

def loop():
    mycode.loop()
    time.sleep(1)

setup()

while True:
    loop()

Nhìn nó sẽ rất giống Arduino:

void setup() {
    ...
}

void loop() {
    ...
}

bên MicroPython:

def setup():
    ...

def loop():
    ...

setup()

while True:
    loop()

Bạn cũng có thể chia file đẹp hơn:

/
├── main.py
├── config.py
├── wifi.py
├── sensor.py
└── led.py

main.py:

import time

import wifi
import sensor
import led

def setup():
    wifi.connect()
    sensor.init()
    led.init()

def loop():
    value = sensor.read()

    print(value)

    led.update(value)

    time.sleep(1)

setup()

while True:
    loop()

Cách này rất dễ maintain.

Một kiểu mình thấy còn sạch hơn là:

import time
from app import App

app = App()

app.setup()

while True:
    app.loop()
    time.sleep_ms(10)

app.py:

class App:

    def setup(self):
        print("Starting app")

    def loop(self):
        print("Running...")

Thực tế MicroPython không bắt bạn phải viết setup() và loop(). Nó chỉ chạy từ trên xuống dưới:

print("1")
print("2")
print("3")

rồi kết thúc.

Muốn loop thì tự viết:

while True:
    ...

Nên có thể hiểu:

Arduino framework
    ↓
framework tự gọi setup()
    ↓
framework tự gọi loop() liên tục

còn MicroPython:

main.py
    ↓
bạn tự gọi setup()
    ↓
bạn tự tạo while True
    ↓
bạn tự gọi loop()

Nếu bạn quen Arduino thì cứ viết MicroPython theo style này là rất ổn:

import time
from machine import Pin

led = Pin(2, Pin.OUT)

def setup():
    print("ESP32 starting...")

def loop():
    led.toggle()
    time.sleep_ms(500)

setup()

while True:
    loop()

Nhìn code sẽ đỡ cảm giác “Python chạy lung tung từ trên xuống dưới” hơn nhiều. 😄

Có. Nếu bạn muốn học cú pháp MicroPython từ cơ bản như biến, hàm, class, import, vòng lặp…, thì nên dùng song song Python docs và MicroPython docs.

MicroPython cố gắng tương thích cú pháp Python 3, nên phần ngôn ngữ như biến, if, for, while, def, class, import gần như học theo Python bình thường. MicroPython docs cũng nói phần lớn language syntax giống Python 3. :chatgpt-content-reference{index=”0”}

Mình khuyên đi theo thứ tự này:

  1. Python Tutorial — học biến, string, list, dict, if, for, while, function, class, import: Python Official Tutorial

  2. MicroPython Language Reference — xem những điểm riêng của MicroPython: MicroPython Language & Implementation :chatgpt-content-reference{index=”3”}

  3. MicroPython builtins — tra các hàm có sẵn như print(), len(), range(), int(), str(), list(), dict()…: MicroPython Built-in Functions :chatgpt-content-reference{index=”5”}

  4. MicroPython Library Reference — tra tất cả import, module, class, function: MicroPython Libraries :chatgpt-content-reference{index=”7”}

  5. Sau khi biết Python cơ bản thì vào ESP32 Quick Reference để học phần hardware: MicroPython ESP32 Quick Reference

Ví dụ phần cơ bản bạn cần nắm chỉ khoảng này:

# Variable
name = "ESP32"
count = 10
temperature = 25.5
enabled = True

# List
values = [10, 20, 30]

# Dictionary
config = {
    "wifi": "MyWifi",
    "port": 1883
}

# If
if temperature > 30:
    print("Hot")
else:
    print("Normal")

# For
for value in values:
    print(value)

# While
count = 0

while count < 5:
    print(count)
    count += 1

Function:

def add(a, b):
    return a + b

result = add(10, 20)

print(result)

Class:

class Led:

    def __init__(self, pin):
        self.pin = pin

    def on(self):
        print("LED ON")

    def off(self):
        print("LED OFF")


led = Led(2)

led.on()

Import file của mình:

/
├── main.py
└── led.py

led.py:

def on():
    print("LED ON")

def off():
    print("LED OFF")

main.py:

import led

led.on()

Hoặc:

from led import on, off

on()

Rồi khi chuyển sang ESP32 thì chỉ thay phần hardware:

from machine import Pin

led = Pin(2, Pin.OUT)

led.on()
led.off()

Một trang nữa rất hữu ích là MicroPython vs CPython, vì nó liệt kê cụ thể những chỗ khác nhau ở functions, classes, import, dict, list, str… :chatgpt-content-reference{index=”9”}

MicroPython differences from Python

Nếu mục tiêu của bạn chỉ là học đủ Python để code ESP32, thì thực ra không cần học hết Python desktop. Chỉ cần khoảng:

variable
↓
if / else
↓
for / while
↓
list / dict
↓
function
↓
import
↓
class cơ bản
↓
try / except
↓
machine.Pin
↓
I2C / SPI / UART
↓
Wi-Fi

là đã làm được khá nhiều project ESP32 rồi.

So sánh php với python

Đúng, nhìn MicroPython/Python ngắn hơn PHP khá rõ, chủ yếu vì Python bỏ rất nhiều “ký hiệu cú pháp” như {}, ;, $, ->, function.

Ví dụ cùng một việc.

PHP:

<?php

$name = "ESP32";
$count = 10;

if ($count > 5) {
    echo "Hello " . $name;
}

MicroPython:

name = "ESP32"
count = 10

if count > 5:
    print("Hello", name)

Python ngắn hơn vì:

PHP        Python
$var       var
;          không cần
{}         dùng indent
echo       print()
function   def
->         .
. nối chuỗi  thường dùng + hoặc f-string

Function cũng khác khá rõ.

PHP:

function add($a, $b) {
    return $a + $b;
}

$result = add(10, 20);

MicroPython:

def add(a, b):
    return a + b

result = add(10, 20)

Array/list:

PHP:

$items = [10, 20, 30];

foreach ($items as $item) {
    echo $item;
}

MicroPython:

items = [10, 20, 30]

for item in items:
    print(item)

Dictionary giống associative array PHP.

PHP:

$config = [
    "wifi" => "Home",
    "port" => 1883
];

echo $config["wifi"];

MicroPython:

config = {
    "wifi": "Home",
    "port": 1883
}

print(config["wifi"])

Class cũng gọn hơn khá nhiều.

PHP:

class Led
{
    private $pin;

    public function __construct($pin)
    {
        $this->pin = $pin;
    }

    public function on()
    {
        echo "LED ON";
    }
}

$led = new Led(2);
$led->on();

MicroPython:

class Led:

    def __init__(self, pin):
        self.pin = pin

    def on(self):
        print("LED ON")


led = Led(2)
led.on()

Cái này là một trong những chỗ Python nhìn rất “thoáng”:

PHP
$this->pin
$led->on()

Python
self.pin
led.on()

Import cũng ngắn:

PHP:

require_once 'Led.php';

$led = new Led(2);

MicroPython:

from led import Led

led = Led(2)

Try/catch:

PHP:

try {
    doSomething();
} catch (Exception $e) {
    echo $e->getMessage();
}

MicroPython:

try:
    do_something()
except Exception as e:
    print(e)

Boolean:

PHP:

if ($enabled === true && $count > 10) {
    echo "OK";
}

MicroPython:

if enabled and count > 10:
    print("OK")

Loop:

PHP:

$i = 0;

while ($i < 10) {
    echo $i;
    $i++;
}

MicroPython:

i = 0

while i < 10:
    print(i)
    i += 1

Điều thú vị là Python không có ++:

i += 1

chứ không có:

i++

String interpolation cũng rất đẹp:

PHP:

$name = "ESP32";
$temp = 26;

echo "Device: {$name}, Temp: {$temp}";

Python:

name = "ESP32"
temp = 26

print(f"Device: {name}, Temp: {temp}")

Với MicroPython trên ESP32, code hardware nhìn còn gọn hơn:

from machine import Pin
import time

led = Pin(2, Pin.OUT)

while True:
    led.on()
    time.sleep(1)

    led.off()
    time.sleep(1)

Nếu viết tư duy kiểu PHP thì có thể tưởng tượng:

$led = new Pin(2, Pin::OUT);

while (true) {
    $led->on();
    sleep(1);

    $led->off();
    sleep(1);
}

Python ngắn chủ yếu nhờ triết lý của nó: ít ký hiệu, code đọc gần giống tiếng Anh, dùng indentation để biểu diễn block.

Nhưng có một cái giá: indentation là cú pháp thật. Ví dụ cái này sai:

if x > 10:
print("hello")

phải là:

if x > 10:
    print("hello")

Nếu bạn đã biết PHP rồi thì học MicroPython khá nhanh. Phần cần làm quen nhất chỉ là indent, def, self, list/dict và cách import; logic if, while, class, function thực ra rất giống PHP.

Kiểu dữ liệu ở python

Được. Python là dynamic typing, nên biến không cần khai báo kiểu dữ liệu trước như C/Java.

Ví dụ cùng một biến có thể đổi kiểu:

x = 10
print(type(x))   # int

x = "hello"
print(type(x))   # str

x = [1, 2, 3]
print(type(x))   # list

x = {1, 2, 3}
print(type(x))   # set

Tức là Python không “gắn kiểu vào biến”, mà kiểu nằm ở giá trị/object mà biến đang trỏ tới.

Ví dụ:

a = 10

hiểu là:

a  --->  object int 10

sau đó:

a = "ESP32"

thì thành:

a  --->  object str "ESP32"

Các kiểu cơ bản thường dùng:

x = 10              # int
y = 3.14            # float
name = "ESP32"      # str
enabled = True      # bool

items = [1, 2, 3]   # list
config = {"a": 1}   # dict
values = {1, 2, 3}  # set
point = (10, 20)    # tuple

Nếu muốn “ghi rõ kiểu” cho dễ đọc code, Python có type hint:

age: int = 30
name: str = "ESP32"
items: list = [1, 2, 3]

Hoặc function:

def add(a: int, b: int) -> int:
    return a + b

Nhưng chú ý: type hint thường không ép kiểu ở runtime.

Ví dụ vẫn có thể viết:

age: int = "hello"

Python thường vẫn chạy, chỉ IDE/linter sẽ cảnh báo.

So với PHP hiện đại thì khá giống:

PHP có thể viết:

$age = 30;
$age = "hello";

Python cũng vậy:

age = 30
age = "hello"

Nếu bạn muốn, tôi có thể làm tiếp bảng PHP type vs Python type kiểu array -> list/dict, null -> None, bool, object, set, tuple để nhìn phát hiểu luôn.

Python list ký hiệu

Có. Với Python/MicroPython, nếu bạn muốn nhìn toàn bộ “ký hiệu trong code” thì có thể chia thành mấy nhóm dưới đây. MicroPython dùng gần như cùng syntax với Python 3.

1. Gán biến

x = 10
name = "ESP32"

= là gán giá trị.

=      gán
:=     walrus operator, vừa gán vừa dùng trong biểu thức

Ví dụ:

if (x := 10) > 5:
    print(x)

2. Toán học

+      cộng
-      trừ
*      nhân
/      chia
//     chia lấy phần nguyên
%      chia lấy dư
**     lũy thừa

Ví dụ:

a = 10 + 5
b = 10 - 5
c = 10 * 5
d = 10 / 3
e = 10 // 3
f = 10 % 3
g = 2 ** 3

Kết quả:

15
5
50
3.333...
3
1
8

3. Gán kết hợp

+=
-=
*=
/=
//=
%=
**=

Ví dụ:

x = 10
x += 5

tương đương:

x = x + 5

Cũng có:

&=
|=
^=
>>=
<<=

cho bitwise.


4. So sánh

==     bằng
!=     khác
>      lớn hơn
<      nhỏ hơn
>=     lớn hơn hoặc bằng
<=     nhỏ hơn hoặc bằng

Ví dụ:

if age >= 18:
    print("OK")

Khác PHP/C một điểm quan trọng:

x = 10      # gán
x == 10     # so sánh

5. Logic

Python không dùng:

&&
||
!

mà dùng:

and
or
not

Ví dụ:

if age > 18 and enabled:
    print("OK")
if a or b:
    print("yes")
if not enabled:
    print("disabled")

6. Kiểm tra object

is
is not

Ví dụ:

value = None

if value is None:
    print("empty")

Thường:

x == y

so sánh giá trị.

Còn:

x is y

kiểm tra có phải cùng object hay không.


7. Kiểm tra phần tử

in
not in

Ví dụ:

items = [10, 20, 30]

if 20 in items:
    print("found")

String cũng được:

if "ESP" in "ESP32":
    print("yes")

8. Ngoặc tròn ()

Dùng cho:

Function call:

print("hello")

Khai báo function:

def add(a, b):
    return a + b

Thay đổi thứ tự toán:

x = (10 + 5) * 2

Tuple:

point = (10, 20)

9. Ngoặc vuông []

Dùng cho list:

items = [10, 20, 30]

Lấy phần tử:

items[0]

Slice:

items[1:3]

Dictionary access:

config["wifi"]

10. Ngoặc nhọn {}

Dictionary:

config = {
    "wifi": "Home",
    "port": 1883
}

Set:

numbers = {1, 2, 3}

Chú ý:

{}

là dict rỗng, không phải set.

Set rỗng phải là:

set()

11. Dấu :

Rất quan trọng trong Python.

Sau if:

if x > 10:
    print(x)

Sau for:

for item in items:
    print(item)

Sau while:

while True:
    print("running")

Sau function:

def hello():
    print("hello")

Sau class:

class Led:
    pass

Trong dictionary:

config = {
    "port": 1883
}

Trong slice:

items[1:5]

12. Dấu ,

Phân cách giá trị:

print("Temp", 25)

List:

items = [1, 2, 3]

Function arguments:

def add(a, b):
    pass

Tuple:

x = 1, 2, 3

Thậm chí:

x = 1,

là tuple một phần tử.


13. Dấu .

Truy cập property/method/module:

led.on()
config.port
time.sleep(1)
machine.Pin

PHP tương đương kiểu:

$led->on();

Python:

led.on()

14. String quote

Có thể dùng:

"hello"

hoặc:

'hello'

Multiline:

"""
hello
world
"""

hoặc:

'''
hello
world
'''

15. Escape \

Ví dụ:

print("hello\nworld")

Các escape phổ biến:

\n     xuống dòng
\t     tab
\r     carriage return
\\     dấu \
\"     dấu "
\'     dấu '

Raw string:

path = r"C:\test\abc"

16. Comment #

# đây là comment
x = 10

Inline:

x = 10  # count

Python không có:

// comment
/* comment */

như C/JS/PHP.


17. F-string {} trong string

name = "ESP32"
temp = 25

print(f"Device: {name}, Temp: {temp}")

Rất hay dùng.

Có thể nhét expression:

print(f"Total: {10 + 20}")

18. Index và slice

text = "ESP32"
text[0]

→ E

text[-1]

→ 2

Slice:

text[0:3]

→ "ESP"

text[:3]
text[2:]
text[::2]

Syntax tổng quát:

[start : stop : step]

19. Bitwise

Quan trọng khi code ESP32.

&      AND bit
|      OR bit
^      XOR
~      NOT
<<     shift left
>>     shift right

Ví dụ:

flags = 0b0010

if flags & 0b0010:
    print("bit enabled")

Binary:

x = 0b1010

Hex:

x = 0xFF

Octal:

x = 0o77

20. @

Dùng decorator:

@staticmethod
def test():
    pass

Hoặc:

@property
def name(self):
    return self._name

Ngoài ra @ còn là matrix multiplication trong Python desktop, nhưng MicroPython/ESP32 hiếm khi dùng.


21. ->

Dùng type hint cho return:

def add(a: int, b: int) -> int:
    return a + b

Không phải operator truy cập object như PHP.

PHP:

$user->name

Python:

user.name

22. * trong function

Ngoài phép nhân:

2 * 3

nó còn dùng unpack:

items = [1, 2, 3]

print(*items)

Kết quả:

1 2 3

Trong function:

def test(*args):
    print(args)

23. **

Ngoài lũy thừa:

2 ** 3

còn dùng dictionary unpack:

config = {
    "port": 1883,
    "debug": True
}

def start(**kwargs):
    print(kwargs)

start(**config)

24. _

Underscore được dùng rất nhiều.

Tên biến:

sensor_value = 10

Tên private theo convention:

_internal_value = 20

Special method:

__init__()
__str__()
__name__

Bỏ qua giá trị:

for _ in range(10):
    print("hello")

25. ;

Python có hỗ trợ, nhưng gần như không nên dùng.

x = 10; y = 20; print(x + y)

Thông thường viết:

x = 10
y = 20
print(x + y)

26. Xuống dòng và indentation

Cái này cực kỳ quan trọng.

PHP:

if ($x > 10) {
    echo "hello";
}

Python:

if x > 10:
    print("hello")

Python dùng indent thay cho {}.

Thông thường là 4 spaces:

if x > 10:
    print("level 1")

    if x > 20:
        print("level 2")

27. Keywords của Python

Đây không phải ký hiệu nhưng là các từ đặc biệt của syntax:

False
None
True

and
as
assert
async
await
break
class
continue
def
del
elif
else
except
finally
for
from
global
if
import
in
is
lambda
nonlocal
not
or
pass
raise
return
try
while
with
yield

MicroPython có thể khác nhẹ tùy version/port, đặc biệt với một số tính năng mới của CPython.


28. Những thứ bạn sẽ dùng nhiều nhất khi code ESP32

Thực tế code MicroPython ESP32 thì khoảng 90% thời gian bạn chỉ dùng mấy cái này:

=           gán

+ - * /     toán

== !=
> < >= <=   so sánh

and or not  logic

()          function
[]          list/index
{}          dict/set
.           method/property
:           block
,           phân cách
#           comment

if
elif
else

for
while

def
return

import
from

try
except

Ví dụ gom gần hết syntax phổ biến vào một đoạn:

from machine import Pin
import time

led = Pin(2, Pin.OUT)

count = 0
enabled = True

def toggle_led(delay_ms=500):
    global count

    if enabled and count < 10:
        led.value(not led.value())

        print(f"Count: {count}")

        count += 1

        time.sleep_ms(delay_ms)

while True:
    try:
        toggle_led()

    except Exception as e:
        print("Error:", e)
        break

Nếu bạn đã biết PHP thì chỉ cần nhớ mấy chuyển đổi lớn nhất này:

PHP                 Python

$variable           variable

->                   .

function             def

&&                   and
||                   or
!                    not

true                 True
false                False
null                 None

elseif               elif

foreach (...)        for ... in ...

{} block             indentation

;                    không cần

echo                 print()

$array[] = x         list.append(x)

Thật ra Python nhìn ít ký hiệu chính vì nó thay nhiều ký hiệu bằng từ tiếng Anh + indentation, nên mới có cảm giác code ngắn và “trống” hơn PHP.

Python có switch case không

Có, nhưng MicroPython hiện chưa có switch/case kiểu C/PHP, và tính năng match/case của Python 3.10 cũng chưa được MicroPython hỗ trợ chính thức; issue theo dõi tính năng này vẫn đang mở. :chatgpt-content-reference{index=”0”}

Nên trên ESP32 + MicroPython thường viết kiểu:

status = 2

if status == 1:
    print("Start")
elif status == 2:
    print("Running")
elif status == 3:
    print("Stop")
else:
    print("Unknown")

So với PHP:

switch ($status) {
    case 1:
        echo "Start";
        break;

    case 2:
        echo "Running";
        break;

    case 3:
        echo "Stop";
        break;

    default:
        echo "Unknown";
}

Trong Python, nếu case nhiều thì cách đẹp hơn là dùng dict:

status_text = {
    1: "Start",
    2: "Running",
    3: "Stop"
}

print(status_text.get(status, "Unknown"))

Hoặc muốn mỗi case chạy function:

def start():
    print("Start")

def running():
    print("Running")

def stop():
    print("Stop")

actions = {
    1: start,
    2: running,
    3: stop
}

actions.get(status, lambda: print("Unknown"))()

Cái này khá giống switch nhưng linh hoạt hơn.

Còn Python desktop từ Python 3.10 có:

match status:
    case 1:
        print("Start")

    case 2:
        print("Running")

    case 3:
        print("Stop")

    case _:
        print("Unknown")

Nhưng với MicroPython ESP32 hiện tại, cứ ưu tiên:

if / elif / else

hoặc dict là an toàn nhất.