การเชื่อม WiFi ด้วย ESP32 + Arduino IDE (C/C++)
#include <WiFi.h>
const char* ssid = "Your_SSID"; // Your WiFi SSID
const char* password = "Your_PASSWORD"; // Your WiFi Password
void setup() {
Serial.begin(115200); // Start the serial communication
delay(10);
// Connect to Wi-Fi
Serial.println();
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Print local IP address
Serial.println("");
Serial.println("WiFi connected.");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
// Nothing to do here
}
เลือก Tools -> Serial Monitor
» ใน ESP32 ด้วย Arduino IDE, ไลบรารี WiFi.h มีฟังก์ชั่นสำหรับการจัดการกับการเชื่อมต่อ WiFi หลายฟังก์ชั่น เช่น:
» การเริ่มต้นการเชื่อมต่อ WiFi: คำสั่ง WiFi.begin(ssid, password); เป็นการเริ่มต้นการเชื่อมต่อ WiFi ด้วย SSID และรหัสผ่าน
» การตรวจสอบสถานะของการเชื่อมต่อ: คำสั่ง WiFi.status(): รับสถานะของการเชื่อมต่อ WiFi
» การจัดการ IP Address: คำสั่ง WiFi.localIP(): รับ IP address ของ ESP32 ที่ได้รับจากเราเตอร์
» WiFi.gatewayIP(): รับ IP address ของ Gateway
» WiFi.subnetMask(): รับ Subnet mask
» การจัดการ DNS: คำสั่ง WiFi.dnsIP(): รับ IP address ของ DNS server
» การจัดการ MAC Address: คำสั่ง WiFi.macAddress(): รับ MAC address ของ ESP32
» การสแกน SSID ที่มีอยู่รอบ ๆ: คำสั่ง WiFi.scanNetworks(): สแกนและรายงานจำนวนของเครือข่าย WiFi ที่พบ
» การตัดการเชื่อมต่อ: คำสั่ง WiFi.disconnect(): ตัดการเชื่อมต่อจาก WiFi
» การจัดการโหมดการทำงาน: คำสั่ง WiFi.mode(): ตั้งหรือรับโหมดการทำงานของ WiFi (เช่น WIFI_AP, WIFI_STA, ฯลฯ)
» การจัดการเซิร์ฟเวอร์และไคลเอ็นต์: คำสั่ง WiFiServer และ WiFiClient: คลาสสำหรับการจัดการการเชื่อมต่อแบบเซิร์ฟเวอร์และไคลเอ็นต์
» การจัดการ RSSI: คำสั่ง WiFi.RSSI(): รับค่า RSSI ของการเชื่อมต่อ WiFi ปัจจุบัน
การเขียน ESP32 ด้วย Arduino IDE (ภาษา C/C++) แสดงรายชื่อ SSID ที่ไม่ต้องป้อนรหัสผ่าน
» การสแกน SSID ที่ไม่มีรหัสผ่านบน ESP32 ด้วยภาษา C/C++ โดยใช้ Arduino IDE สามารถทำได้ด้วยการตรวจสอบ encryptionType ของแต่ละเครือข่ายที่สแกนพบ เพื่อดูว่ามีการเข้ารหัสหรือไม่ ดังตัวอย่างโค้ดด้านล่าง:
#include
const int MAX_NUM_SSID = 10; // กำหนดจำนวน SSID สูงสุดที่จะเก็บ
char* openSSIDs[MAX_NUM_SSID];
int openSSIDCount = 0;
void setup() {
Serial.begin(115200);
// เริ่มการสแกน SSID
int numNetworks = WiFi.scanNetworks();
for (int i = 0; i < numNetworks; i++) {
// ตรวจสอบว่าเครือข่ายนี้ไม่มีการเข้ารหัส
if (WiFi.encryptionType(i) == WIFI_AUTH_OPEN) {
openSSIDs[openSSIDCount] = strdup(WiFi.SSID(i).c_str());
openSSIDCount++;
// หยุดเก็บข้อมูลเมื่อถึงจำนวนที่กำหนด
if (openSSIDCount >= MAX_NUM_SSID) {
break;
}
}
}
// พิมพ์รายชื่อ SSID ที่ไม่มีรหัสผ่าน
for (int i = 0; i < openSSIDCount; i++) {
Serial.println(openSSIDs[i]);
}
}
void loop() {
// ทำงาน
}
การเชื่อมต่อ ESP32 กับ WiFi และอ่านค่าจากเว็บด้วย HTTP
» การอ่านค่าจากเว็บจะมีแบบ HTTP และ HTTPS
#include
#include
const char* ssid = "DSDI";
const char* password = "11111111111";
const char* url = "http://dsdi.msu.ac.th/iot/random.php";
void setup() {
Serial.begin(9600);
Serial.println("Connecting to WiFi...");
// เชื่อมต่อ WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println();
Serial.println("Connected to WiFi!");
}
void loop() {
if (WiFi.status() == WL_CONNECTED) { // ตรวจสอบว่ายังเชื่อมต่ออยู่
HTTPClient http;
http.begin(url);
int httpCode = http.GET(); // รับค่าจากเว็บ
if (httpCode > 0) {
String payload = http.getString(); // ดึงข้อมูลที่ได้จากเว็บ
Serial.println(payload);
}
http.end(); // ปิดการเชื่อมต่อ
}
delay(5000); // รอ 5 วินาทีก่อนเรียกข้อมูลใหม่
}
การเชื่อมต่อ ESP32 กับ WiFi และอ่านค่าจากเว็บด้วย HTTPS
» เพื่อเชื่อมต่อ ESP32 กับ WiFi และอ่านค่าจากเว็บ, คุณต้องใช้ WiFi.h และ HTTPClient.h ซึ่งเป็น libraries ที่มากับ Arduino core สำหรับ ESP32.
» ด้านล่างเป็นตัวอย่างโค้ดสำหรับการทำเช่นนั้น:
#include
#include
const char* ssid = "DSDI";
const char* password = "11111111111";
const char* url = "https://dsdi.msu.ac.th";
const char* test_endpoint = "/iot/random.php";
// ใส่ fingerprint ของเว็บไซต์
const char* fingerprint = "A8:98:5D:3A:65:E5:E5:C4:B2:D7:D6:6D:40:C6:DD:2F:B1:9C:54:36";
void setup() {
Serial.begin(9600);
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println();
Serial.println("Connected to WiFi!");
WiFiClientSecure client;
if (!client.connect(url, 443)) {
Serial.println("Connection failed!");
return;
}
// ตรวจสอบ fingerprint
if (client.verify(fingerprint, url)) {
Serial.println("Connection secured.");
} else {
Serial.println("Connection unverified! Disconnecting...");
client.stop();
return;
}
client.print(String("GET ") + test_endpoint + " HTTP/1.1\r\n" +
"Host: " + url + "\r\n" +
"Connection: close\r\n\r\n");
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") {
break;
}
}
while (client.available()) {
String line = client.readStringUntil('\n');
Serial.println(line);
}
client.stop();
}
void loop() {
// Nothing in loop
}
» fingerprint หรือ SHA-1 certificate fingerprint คืออักขระเฉพาะของ SSL certificate ที่ใช้บนเว็บไซต์. ESP32 ใช้ fingerprint นี้เพื่อตรวจสอบว่าเว็บไซต์ที่มันกำลังเชื่อมต่อนั้นเป็นแท้จริงและมีความปลอดภัย.
» การรับ fingerprint สำหรับเว็บไซต์:
» ใช้เบราว์เซอร์ firefox บนคอมพิวเตอร์ของคุณเพื่อเปิดเว็บไซต์ที่คุณต้องการ (ในกรณีนี้คือ https://dsdi.msu.ac.th).
» คลิกที่ 🔒 หรือสัญลักษณ์ความปลอดภัยที่อยู่ฝั่งซ้ายของ URL.
» คลิกที่ Certificate (valid) หรือคำสัมมนาที่คล้ายกัน.
» ไปที่แท็บ Details.
» ค้นหา SHA-1 fingerprint หรือ Thumbprint ในภาษาอังกฤษ.
» คัดลอกค่า fingerprint นั้นและใส่ลงในโค้ดของคุณ.
» เมื่อได้ fingerprint แล้ว, คุณสามารถใส่ค่านั้นในตัวแปร fingerprint ในโค้ด ESP32 ของคุณ.
» หมายเหตุ: สิ่งที่ควรระวังคือ fingerprint จะเปลี่ยนแปลงเมื่อ SSL certificate ของเว็บไซต์หมดอายุและได้รับการต่ออายุ. ดังนั้น, หากโค้ดของคุณเชื่อมต่อกับเว็บไซต์แล้วไม่ทำงานในอนาคต, คุณอาจจะต้องตรวจสอบและอัปเดต fingerprint ใหม่.
การอ่านและถอดรหัส QR Code ด้วย ESP32 + Arduino IDE
» 2 บริษัท 1) ธนาคารกรุงเทพ โอนครั้งละ 1 บาท โอนในวันถัดไป 2) GB Prime Pay ค่าธรรมเนียมร้อยละ 0.8 บาท ระยะเวลาโอนเงิน 7 วัน เช็คหลังบ้านได้ว่ามีเงินเข้า สั่งตรงมาจาก server เพื่อเปิดปิดเซอร์โวเลย
» แอ็ปแม่มณีและพร้อมเพย์ ต้องมาดักจับข้อความ
» หลังจากโอนเสร็จแล้ว จะมีรูป QR code แนบมาด้วย ให้นำไปสแกนจากกล้อง ESP32 camera และถอดข้อความออกมาจึงจะตอบได้ว่าโอนมาแล้ว รหัสคำนี้คือคำว่าอะไร ?
» EMV QRCPS Merchant Presented Mode เป็นมาตรฐานของระบบ QR Code Payment ที่ถูกพัฒนาโดย EMVCo, ซึ่งเป็นบริษัทที่ก่อตั้งขึ้นโดยบริษัทบัตรเครดิตหลักๆ เช่น MasterCard, Visa, American Express และอื่นๆ เพื่อการพัฒนามาตรฐานสำหรับการชำระเงินด้วยบัตรเครดิตและเดบิต
» ภายในมาตรฐาน EMV QR Code Payment Specification (QRCPS) มีการกำหนดสองโหมดหลักๆ คือ:
1. **Merchant Presented Mode (MPM)**: ซึ่งเป็นโหมดที่ผู้ขาย (Merchant) แสดง QR code ให้ลูกค้า (Customer) สแกนเพื่อดำเนินการชำระเงิน. กล่าวคือ, ร้านค้าหรือผู้ขายจะแสดง QR Code และลูกค้าจะใช้แอปฯ บนสมาร์ทโฟนของตนเพื่อสแกนและยืนยันการชำระเงิน.
2. **Consumer Presented Mode (CPM)**: ซึ่งเป็นโหมดที่ลูกค้าแสดง QR code ให้ผู้ขายสแกนเพื่อดำเนินการชำระเงิน.
» EMV QRCPS Merchant Presented Mode (MPM) จึงหมายถึงการที่ผู้ขายแสดง QR Code ที่ได้รับการสร้างขึ้นตามมาตรฐานของ EMVCo และลูกค้าจะสแกน QR Code นี้เพื่อดำเนินการชำระเงิน. การใช้มาตรฐานนี้จะช่วยให้การชำระเงินด้วย QR Code มีความปลอดภัย, เพราะว่ามันถูกออกแบบมาในรูปแบบที่ยากต่อการปลอมแปลง และสามารถรองรับการทำรายการทั่วโลกได้.
» มาตรฐาน EMVco คือ หมายเลขประจำฟิลด์ข้อมูล (เป็น 00-99), ความยาวของข้อมูลในฟิลด์นั้น (เป็น 01-99), และตัวข้อมูลจริงๆ การอ่านข้อมูลตัวอย่างจะทำเป็นขั้นได้ดังนี้
- หมายเลขเวอร์ชั่น ฟิลด์ 00 ความยาว 02 ข้อมูลตอนนี้คือ 01 เสมอ ดังนั้นข้อมูลชุดแรกคือ "000201"
- ประเภทของ QR ฟิลด์ 01 ความยาว 02 ข้อมูล "11" แปลว่า QR นี้สร้างขึ้นเพื่อใช้สำหรับการขายหลายครั้ง เช่นระบุผู้ขาย หรือระบุราคาสินค้า ถ้าเป็น 12 คือ QR สร้างขึ้นเพื่อใช้ครั้งเดียว เช่น เป็นการจ่ายสำหรับใบเสร็จใบเดียว
- ข้อมูลผู้ขาย (merchant account information) ฟิลด์ 29 ความยาว 37 ข้อมูล "0016A00000067701011101130066000000000" โดยข้อมูลนี้แบ่งออกเป็นสองฟิลด์ย่อย
- หมายเลขแอปพลิเคชั่น (application ID - AID) เป็นหมายเลขที่ปกติแล้วใช้อ้างอิงประเภทบัตรสมาร์ตการ์ดแบบต่างๆ ตั้งแต่บัตรประชาชนไปจนถึงบัตรเครดิตทั้งหลาย ในกรณีนี้มีการนำหมายเลขนี้มาใช้ใน QR เพื่อระบุว่า QR นี้เป็น PromptPay หมายเลขฟิลด์ย่อย 00 ความยาว 16 ข้อมูล "A000000677010111"
- หมายเลขบัญชี เป็นหมายเลข PromptPay โดยตรง ตอนนี้มีหมายเลขฟิลด์ เช่น
- 01 หมายเลขโทรศัพท์ ความยาว 13 นำหน้าด้วย 00 แล้วตามด้วยรหัสประเทศ 66 แล้วจึงเป็นหมายเลขโทรศัพท์ตัดศูนย์นำหน้าออก 00-000-0000
- 02 หมายเลขบัตรประชาชนไม่มีขีดคั่น
- ประเทศ ฟิลด์ 58 ความยาว 02 ข้อมูล "TH" หมายถึงประเทศไทย
- สกุลเงินที่ใช้งาน ฟิลด์ 53 ความยาว 03 ข้อมูล "764" โดยหมายเลข 764 เป็นหมายเลขประจำค่าเงินบาทตาม ISO 4217
- ค่า check sum ฟิลด์ 63 ความยาว 04 ข้อมูล "8956" ข้อมูลนี้ต้องอยู่ท้ายสุดเสมอ โดยค่า check sum เป็นการคำนวณจากข้อมูลทั้งหมด รวมถึงหมายเลขฟิลด์ของ check sum และความยาวของฟิลด์ check sum เอง กระบวนการหาค่า check sum ใช้ CRC-16 และ ค่าคงที่ polynomial 0x1021 (XMODEM) พร้อมกับค่าเริ่มต้น 0xFFFF (อันนี้ต้องระวังเพราะไลบรารีส่วนมากมักใส่ค่าเริ่มต้นเป็น 0x0000) ตัวไลบรารีสามารถใช้ pycrc16 ได้โดยตรง
» มาตรฐานในธุรกรรมการชำระเงินด้วย Thai QR Code
» การสร้าง QR Code สำหรับ PromptPay ด้วย Python นั้นสามารถทำได้โดยใช้ไลบรารีต่าง ๆ ที่มีพร้อมใช้งาน ต่อไปนี้เป็นตัวอย่างโค้ด Python สำหรับการสร้าง QR Code สำหรับ PromptPay:
» การติดตั้งจากซอร์สโค๊ด
git clone https://github.com/jojoee/promptpay
cd promptpay
python setup.py install
» ติดตั้ง pip install promptpay==1.1.7
from promptpay import qrcode
# generate a payload
id_or_phone_number = "0841234567"
payload = qrcode.generate_payload(id_or_phone_number)
payload_with_amount = qrcode.generate_payload(id_or_phone_number, 1.23)
# export to PIL image
img = qrcode.to_image(payload)
# export to file
qrcode.to_file(payload, "./qrcode-0841234567.png")
qrcode.to_file(payload_with_amount, "/Users/joe/Downloads/qrcode-0841234567.png")
» การสร้าง QR Code สำหรับ PromptPay ด้วย Python นั้นสามารถทำได้โดยใช้ไลบรารีต่าง ๆ ที่มีพร้อมใช้งาน ต่อไปนี้เป็นตัวอย่างโค้ด Python สำหรับการสร้าง QR Code สำหรับ PromptPay:
» ติดตั้ง pip install promptpay-qr
import promptpay_qr
from PIL import Image
# กำหนดข้อมูลสำหรับการโอนเงิน
recipient = "0987654321" # แทนด้วยหมายเลขโทรศัพท์หรือหมายเลขประจำตัวประชาชน
amount = 123.45 # แทนด้วยจำนวนเงินที่ต้องการโอน
# สร้าง payload สำหรับ QR Code
payload = promptpay_qr.generate_payload(recipient, amount)
# สร้าง QR Code จาก payload
qr_code = promptpay_qr.generate_qr_code(payload)
# แสดง QR Code
qr_code.show()
» การสังเคราะห์ QR Code PromptPay -> https://genpromptpay.web.app
» https://promtpay.io/เบอร์โทรศัพท์ -> ภาพจะเป็น <img src="https://promptpay.io/เบอร์โทรศัพท์.png">
» ฟรีค่าธรรมเนียมเมื่อโอนไม่เกิน 5,000 บาท และสามารถโอนได้ไม่จำกัดจำนวนครั้ง การโอนที่ยอดเกินกว่า 5,000 บาท/ครั้ง จะมีค่าธรรมเนียมเป็นขั้นบันได เริ่มตั้งแต่ 2 บาท/ครั้ง
» ธนาคารอะไรเข้าร่วมบ้าง ธนาคารพาณิชย์ทุกแห่งในประเทศไทย เช่น ธนาคารกสิกรไทย ธนาคารไทยพาณิชย์ ธนาคารกรุงไทย ธนาคารกรุงเทพ ธนาคารกรุงศรี
» PromptPay.io ให้บริการฟรีและจะฟรีตลอดไป โดยทีมงานเบื้องหลัง Page365 ผู้เชี่ยวชาญเรื่องร้านค้าออนไลน์
» https://github.com/fustyles/Arduino/tree/master/ESP32-CAM_QRCode_Recognition
» ป้อนเบอร์โทรศัพท์ เลขบัตรประชาชน จำนวนเงินมันจะสังเคราะห์ QR Code
» https://promptpay2.me/
การติดต่อ Lora E220-400T22D และ ESP32
» 433/470MHz 22dBm LoRa Wireless Module ระยะทาง 5km
» https://github.com/xreef/EByte_LoRa_E220_micropython_library
» E220-400T22D เป็นโมดูล LoRa รับส่งข้อมูลไร้สายระยะไกล 5 กม. สื่อสารผ่านพอร์ตอนุกรม (UART) ทำงานในช่วงความถี่ 410.125 ถึง 493.125 MHz ใช้แรงดัน 3.3v และ 5v สำหรับ IO
» คุณสมบัติ
- สื่อสารได้ไกลขึ้นและทนสัญญาณรบกวน
- รองรับการตั้งรหัสสำหรับการสื่อสารช่วยเพิ่มความปลอดภัยของข้อมูล
- รองรับฟังก์ชั่น LBT เพื่อตรวจสอบสัญญาณรบกวนในช่องสัญญาณก่อนการส่งข้อมูล
- รองรับฟังก์ชั่นแสดงความแรงของสัญญาณ RSSI เพื่อประเมินคุณภาพสัญญาณและปรับปรุงระบบการสื่อสาร
- รองรับฟังก์ชั่นการเริ่มทำงานด้วยสัญญาณไร้สาย และบริโภคพลังงานต่ำมาก เหมาะสำหรับแอพลิเคชั่นที่ใช้พลังงานจากแบตเตอร์รี่
- รองรับการหลับลึกซึ่งบริโภคพลังงานต่ำมากเพียง 5uA
- มี PA+LNA ภายในทำให้สื่อสารได้ไกล 5km
- พารามิเตอร์ถูกบันทึกหลังจากปิดเครื่องและโมดูลจะทำงานตามพารามิเตอร์ที่ตั้งไว้เมื่อเริ่มต้นทำงาน
- การออกแบบ watchdog ที่มีประสิทธิภาพ หากมีข้อผิดพลาดเกิดขึ้นโมดูลจะเริ่มทำงานใหม่และดำเนินการต่อตามค่าพารามิเตอร์ที่ตั้งไว้ก่อนหน้า
- รองรับอัตราบิต 2.4k ถึง 62.5 kbps
- รองรับแหล่งจ่ายไฟ 3.0 - 5.5v
- รองรับการทำานที่ 40 - 85℃
- มีอินเตอร์เฟสสำหรับเสาอากาศแบบ SMA
การออกแบบฮาร์ดแวร์
- แหล่งจ่ายไฟควรใช้ไฟที่เรียบและไม่มีการกระชาก
- โปรดระวังในการเชื่อมต่อขั้วบวกและขั้วลบให้ถูกต้อง หากต่อสลับขั้วอาจทำให้โมดูลเสียหาย
- โปรดต่อแหล่งจ่ายไฟด้วยแรงดันที่กำหนดไว้ คือ 3.0-5.5v
- โมดูลควรอยู่ห่างจากแหล่งจ่ายไฟ ขดลวดและส่วนอื่น ๆ ที่มีสัญญาณแม่เหล็กรบกวน
การติดต่อ Lora module
» ใช้การสื่อสารอนุกรม
» AT # คือคำสั่งตอบกลับว่า OK นั่นคือโมดูลพร้อมใชังาน
» AT+ADDRESS=2 #การตั้งเลขเลขแอดเดรสให้กับโมดูล (ถ้ากำหนดเป็น 0 จะส่งไปยังทุกโหนด) ทำทุก ๆ โหนด
» AT+BAND=923000000 #ตั้งแบรด์ ทุก ๆ โมดูล
» AT+NETWORKID=5 #Network ID คือ เลขหมู่บ้าน ใช้ค่าได้จาก 3-15 และเลข 18 ทำทุก ๆ โหนด
» AT+SEND=2,11,HELLO_WORLD #เลข 2 คือ Address ที่ส่งไป ส่วน 11 คือจำนวนข้อมูลที่ส่งออกไป และ HELLO_WORLD (ส่งได้ ประมาณ 250 ไบต์)
การตรวจสอบว่ามีโมดูลอะไรบ้างใน Micropython
» คำสั่ง help('modules')
__main__ framebuf socket upip
_boot gc ssl upip_utarfile
_onewire hashlib struct upysh
_thread heapq sys urandom
_webrepl inisetup time ure
apa106 io ubinascii urequests
array json ucollections uselect
binascii machine ucryptolib usocket
btree math uctypes ussl
builtins micropython uerrno ustruct
cmath neopixel uhashlib utime
collections network uhashlib utimeq
dht ntptime uheapq uzlib
ds18x20 onewire uio webrepl
errno os ujson webrepl_setup
esp random umqtt/robust websocket
esp32 re umqtt/simple websocket_helper
flashbdev select uos zlib
Plus any modules on the filesystem
การใช้งาน Network และ URL Request ด้วย Micropython บน ESP32
def do_connect():
import network
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('connecting to network...')
wlan.connect('ชื่อ wifi (ssid)', 'รหัสผ่าน wifi')
while not wlan.isconnected():
pass
print('network config:', wlan.ifconfig())
do_connect()
import urequests as requests
import ujson
import time
res = requests.get(url = 'https://dsdi.msu.ac.th/iot/random.php').text
การใช้งาน Fourier Transform ด้วย Micropython บน ESP32
» ulab อ่านว่า micro lab เป็นไลบรารี่คำนวณคณิตศาสตร์ มีฟังก์ชั่น fft (Fast Fourier Transform) เพื่อแปลงข้อมูลเวลาเป็นความถี่
» Micropython และ ulab เฟิร์มแวร์ https://gitlab.com/rcolistete/micropython-firmwares/-/tree/master/ESP32
# ulab version 0.5
import ulab as np
a = np.array([1, 2, 3, 4, 1, 2, 3, 4], dtype=np.float)
np.fft.fft(a)
# ผลลัพธ์:
# array([20.+0.j, 0.+0.j, -4.+4.j, 0.+0.j, -4.+0.j, 0.+0.j, -4.-4.j, 0.+0.j])
การใช้งาน Fast Furier Transform
import ulab as np
x = np.linspace(0, 10, num=1024)
from math import sin
y = list(map(lambda xi:sin(xi),x))
z = np.zeros(len(x))
a,b=np.fft.fft(x)
print('real: ',a, '\nimaginary:',b)
#real: array([5119.996, -5.004725, -5.004798, ..., -5.005443, -5.005628, -5.006485], dtype=float)
#imaginary: array([0.0, 1631.333, 815.659, ..., -543.7639, -815.6587, -1631.333], dtype=float)
c,d=np.fft.fft(x,z)
print('real: ',c, '\nimaginary:',d)
#real: array([5119.996, -5.004725, -5.004798, ..., -5.005443, -5.005628, -5.006485], dtype=float)
#imaginary: array([0.0, 1631.333, 815.659, ..., -543.7639, -815.6587, -1631.333], dtype=float)
การใช้งาน Invert Fast Furier Transform
import ulab as np
x = np.linspace(0, 10, num=1024)
from math import sin
y = list(map(lambda xi:sin(xi),x))
y=np.array(y)
a, b = np.fft.fft(y)
print('original vector:\t', y)
#original vector: array([0.0, 0.009775016, 0.0195491, ..., -0.5275068, -0.5357859, -0.5440139], dtype=float)
y, z = np.fft.ifft(a, b)
print('\nreal part of inverse:\t', y)
# real part of inverse: array([8.940697e-08, 0.009775251, 0.01954916, ..., -0.5275063, -0.5357856, -0.5440133], dtype=float)
print('\nimaginary part of inverse:\t', z)
#imaginary part of inverse: array([-1.466833e-08, -2.501297e-07, 7.005331e-08, ..., -1.597692e-07, 5.291355e-08, 9.805394e-08], dtype=float)
» คำสั่ง print(np.eye(5)) คือสร้างเมตริกซ์เอกลักษณ์ขนาด 5x5
» คำสั่ง print(np.eye(4, M=6, k=-1, dtype=np.int16)) คือสร้างเมตริกเอกลักษณ์ขนาด 4x6
» คำสั่ง np.ones(6, dtype=np.uint8) คือ สร้างเมตริกซ์ 1x6 มีค่า [1,1,1,1,1,1]
» คำสั่ง a=np.array(range(4), dtyle=np.uint8); a.reshape((2,2)) แปลงเมตริกซ์เป็น 2x2
» คำสั่ง transpose() เช่น a.transpose()
» คำสั่ง a = np.array([1, 2, 3, 4, 5, 6, 7, 8], dtype=np.uint8); print(a < 5) จะได้ [True, True, True, True, False, False, False, False]
มอเตอร์ไฟฟ้ากระแสตรงแบบไม่ใช้แปลงถ่าน (Brushless DC Motor: BLDC Motor)
» มอเตอร์ BLDC ให้ประสิทธิภาพสูง แรงบิตสูง เรียกอีกอย่างว่า ECM หรือ EC motor (Electronically Commutated motor) หรือ Synchronous DC motor)
» Hall effect sensor ใช้ตรวจจับการหมุนด้วยสนามแม่เหล็ก โดยจะตรวจจับทิศการหมุน
» การควบคุม BLDC นิยมใช้ Closed Loop Control โดยใช้เซนเซอร์ Hall Effect IC บอกตำแหน่งโรเตอร์ให้กับคอนโทรลเลอร์
» ปล. ระบบที่ไม่ใช้ hall sensor จะกินไฟมากกว่า
การใช้งานคอนโทรลเลอร์ STM32
» บริษัท STMicroelectronic หรือบริษัท ST หรือ STMicro เป็นบริษัทผลิตไอซี มีสิทธิบัตร 16,000 ชิ้น และการออกแบบ 9000 ชิ้น มีทีม R&D มากกว่า 11,000 คน
» สินค้าได้แก่ ทรานซีสเตอร์ แอมป์ ไดโอด ตัวควบคุมแรงดันไฟฟ้าและมอสเฟส
» ในอดีต STM32 ไม่มี IDE ต้องคอมไพล์จากของบริษัทอื่น เช่น IAR Embedded Workbench , µVision IDE (ARM Keil) และ ARMmbed
» ปัจจุบัน STMicroelectronics พัฒนา STM32CubeIDE เป็นคอมไพล์เลอร์และ IDE -> ดาวน์โหลด https://www.st.com/en/development-tools/stm32cubeide.html
» ดาวน์โหลดไฟล์โดยตรงที่นี่ -> https://www.st.com/content/ccc/resource/technical/software/sw_development_suite/group0/e8/14/a7/4e/fe/8a/4e/a0/stm32cubeide-win/files/st-stm32cubeide_1.12.1_16088_20230420_1057_x86_64.exe.zip/jcr:content/translations/en.st-stm32cubeide_1.12.1_16088_20230420_1057_x86_64.exe.zip
» การโหลดไฟล์ลงไมโครคอนโทรลเลอร์ เรียกว่า การโปรแกรม จะใช้อุปกรณ์ ST-Link v2 มี 4 ขา SWD, SWC, 3.3v และ GND
» แหล่งข้อมูล: https://www.artronshop.co.th/article/108/stm32-getstarted-with-stm32cubeide
» กิจกรรม 1: ติดตั้ง cube-ide จะเก็บไว้ใน C:\ST\STM32CubeIDE_1.12.1 -> โปรแกรม stm32cubeide.exe
» กิจกรรม 2: เขียนโปรแกรมไฟกระพริบ -> เปิดโปรแกรม -> File -> New -> Stm32 Project
- Part Number: เลือก STM32G030C6T6 เนื่องจากเอาไปจำลองใน preteus ได้
- ถ้า generate code ไม่สำเร็จให้ลองใหม่ โดยเลือก Project -> Generate code อีกรอบ
- จะได้ไดอะแกรมแสดงขาไอซีให้เลือก PB1 เป็น GPIO_Output
» กิจกรรม 3: จำลองการทำงานใน proteus
- เลือก STM32F103C6 และ Led Yellow
- วาง power เปลี่ยนค่าเป็น +3.3v ลากต่อกับ LED และลากหัวลูกศรชี้ออกไปยัง PA0-WKUP
- วาง power และ ground ลากสายออกไปและตั้งชื่อ VDDS และ VSSA
- เลือกที่ ไอซีคอนโทรลเลอร์ -> program file -> เลือกไฟล์ .hex -> กด Run
» ปล. การเปลี่ยนสีพื้น เลือกเมนู Template -> Set Colors -> เลือกสีพื้นตามต้องการ
บอร์ดควบคุม BLDC และ Hall Sensor
» แรงดัน 12-36v 500w 15A
» ความเร็วมอเตอร์เขียนด้วยโปรแกรมหรือใช้ potentiometer โดยสายกลางต่อกับ vr speed port และอีกสองเส้นต่อ 5v และ GND
» ทิศทางกำหนดโดย 5v หรือ GND
» ควรใส่ Heatsink
» ความเร็ว ใช้แรงดัน 0.1 - 5v
การประกอบใช้งาน
การใช้งาน STM32F411 และ Micropython
» STM32F11 เป็นคอร์ Cortext-M4 ทำงานที่ 100MHz ประกอบด้วย UARTx3 SPIx5 I2Cx2 USB Host OTG I2Sx5 ADC12bit Flash Size
» ไมโครไพธอนสามารถทำงานได้กับชิป STM32 ในรุ่น Seriea 411 ขึ้นไป ไม่สามารถใช้กับเวอร์ชั่นต่ำกว่าเนื่องจากพื้นที่เก็บข้อมูลไม่เพียงพอ
» เครื่องโปรแกรม รุ่น ST Link v2
» ดาวน์โหลดโปรแกรม ST Link ที่นี่
» ดาวน์โหลด Micropython ที่นี่
» เปิดโปรแกรม ST Link -> เลือกเมนู Target -> Connect
» เลือกเมนู Target -> Erase
» เลือกเมนู Target -> Program & Verify -> เลือกไฟล์ firmware_internal_rom_stm32f411_v1.12-35.hex
» ดาวน์โหลดโปรแกรม Thonny เลือกเมนู Run -> Conigure Interpreter -> เลือก Generic Python -> เลือก Port: Try to detect automatically
โครงสร้าง STM32F411
โปรแกรมไฟกระพริบ STM32F411 และ Micropython
import machine
import time
LED_OFF = 1
# use the onboard Blue LED
led = machine.Pin('PC13', machine.Pin.OUT)
try:
while True:
led.value( not led.value() )
time.sleep_ms( 100 )
except KeyboardInterrupt:
pass
finally:
led.value( LED_OFF )
print('Done')
โปรแกรมรับค่าจากการกดสวิตช์ด้วย STM32F411 และ Micropython
import utime as time
import pyb
sw = pyb.Switch() # user push button
led = pyb.LED(1) # on-board LED (blue), PC13 pin
try:
last_time = time.ticks_ms() # save timestamp
while not sw.value(): # is button pressed ?
now = time.ticks_ms() # read current timestamp
time_diff = time.ticks_diff( now, last_time )
if time_diff >= 500:
led.toggle() # toggle LED
last_time = now # update timestamp
except KeyboardInterrupt:
pass
finally:
led.off() # turn off LED
print('Done')
โปรแกรมกดสวิตช์มากกว่า 2 วินาทีให้ยุติการทำงานด้วย STM32F411 และ Micropython
import pyb
import utime as time
sw = pyb.Switch() # user push button
led = pyb.LED(1) # on-board LED (blue), PC13 pin
# set callback function for the push button.
# toggle the LED if the button switch is pressed.
sw.callback( lambda: led.toggle() )
try:
last_time = time.ticks_ms() # save timestamp
while True: # main loop
now = time.ticks_ms() # get current time (msec)
if sw.value(): # button hold pressed
if time.ticks_diff( now, last_time ) >= 2000:
print( 'button long pressed' )
break # exit the while loop
else:
last_time = now # update timestamp
except KeyboardInterrupt: # interrupted by Ctrl+C
pass
finally:
sw.callback(None) # disable callback for button
led.off() # turn off LED
print('Done')
การใช้ Hardware Timer ด้วย STM32F411 และ Micropython
คลาส pyb.Timer ใช้ไทมเมอร์ 11 ตัว จาก TIM1 ถึง TIM11 ขนาด 16 บิต (ยกเว้น TIM2 และ TIM5 มีขนาด 32 บิต)
import utime as time
from machine import Pin
import pyb
led = pyb.LED(1) # on-board LED (blue)
# create Timer (select from TIM1..TIM11),
# set timer frequency = 10 Hz (for fast LED blink)
tim = pyb.Timer( 2, mode=pyb.Timer.UP, freq=10 )
tim.callback( lambda t: led.toggle() )
try:
while True: # main loop
pass # do nothing in main loop
except KeyboardInterrupt:
pass
finally:
tim.callback(None) # disable timer callback
tim.deinit() # turn off the timer
led.off() # turn off the LED
print('Done')
การใช้ Software Timer ด้วย STM32F411 และ Micropython
Software Timer ใช้จากคลาส machine.Timer ใช้ FreeRTOS และกำหนดหมายเลข Timer ID = -1
import pyb
from machine import Timer
import utime as time
sw = pyb.Switch() # user push button
led = pyb.LED(1) # on-board LED (blue)
# create a software timer in periodic mode
tim = Timer(-1)
tim.init( mode=Timer.PERIODIC,
period=500, # period in msec
callback=lambda t: led.toggle() )
try:
while True:
if sw.value(): # check the button's state
break
except KeyboardInterrupt:
pass
finally:
sw.callback(None)
led.off()
tim.deinit()
print('Done')
การใช้ PWM ด้วย Hardware Timer บน STM32F411 และ Micropython
Software Timer ใช้จากคลาส machine.Timer โหมด One Shot แทน Periodic โดยจะเรียกฟังก์ชั่น callback เพียงครั้งเดียวเท่านั้น
ความถี่ของซีพียู (CPU) หรือ SysClk เท่ากับ 96 MHz
ความถี่ของการอินเทอร์เฟสด้วยบัส AHB เท่ากับ 96 MHz = SysClk/1
ความถี่ของการอินเทอร์เฟสด้วยบัส APB1 จะได้ 24 MHz = SysClk/4
ความถี่ของการอินเทอร์เฟสด้วยบัส APB2 จะได้ 48 MHz = SysClk/2
ความถี่ของ Timer (TIM4) ได้ตั้งค่าให้นับด้วยความถี่เท่ากับ 5 Hz
ตัวหารความถี่ (Prescaler) เท่ากับ 624 และคาบ (Period) เท่ากับ 15359
import utime as time
from machine import Pin
import pyb
# print system frequencies
freq = pyb.freq()
print( 'CPU freq. [Hz]:', freq[0] ) # 96 MHz
print( 'AHB freq. [Hz]:', freq[1] ) # 96 MHz
print( 'APB1 freq. [Hz]:', freq[2] ) # 24 MHz
print( 'APB2 freq. [Hz]:', freq[3] ) # 48 MHz
# create Timer (use TIM4)
tim = pyb.Timer( 4, freq=5 ) # 5 Hz (for LED blink)
# Choose PB8 pin for TIM4_CH3 or PB9 pin for TIM4_CH4
pwm = tim.channel( 3, pyb.Timer.PWM,
pin=pyb.Pin.board.PB8, pulse_width=0 )
pwm.pulse_width( tim.period()//2 ) # 50% duty cycle
print( 'prescaler : {:>8}'.format( tim.prescaler()) )
print( 'frequency : {:>8} [Hz]'.format( tim.freq()) )
print( 'source freq.: {:>8} [Hz]'.format( tim.source_freq()) )
print( 'period : {:>8} [us]'.format( tim.period()) )
print( 'pulse width : {:>8} [us]'.format( pwm.pulse_width()) )
try:
while True:
pass # do nothing in the main loop
except KeyboardInterrupt:
pass
finally:
tim.deinit()
print('Done')
การปรับค่า PWM ตามค่าในตัวแปรอาร์เรย์ ด้วย STM32F411 และ Micropython
กำหนดค่า duty cycle ลงในอาร์เรย์
นำค่าในอาร์เรย์แต่ละตัวมาสร้าง pwm
import utime as time
from machine import Pin
import pyb
import math
# create a hardware Timer (use TIM4)
tim = pyb.Timer( 4, prescaler=47, period=999 ) # TIM4
# Freq.(Hz) = APB2 freq. (Hz)/(prescaler+1)/(period+1)
# = 48 MHz /48 /1000 = 1 kHz or 1000 Hz
# choose PB8 pin for TIM4_CH3, or PB9 pin for TIM4_CH4
pwm = tim.channel(4, pyb.Timer.PWM,
pin=pyb.Pin.board.PB9, pulse_width=0)
print( 'PWM period :', tim.period() )
print( 'PWM frequency:', tim.freq() )
try:
P = tim.period() # get PWM period
N = 16
steps = [int(P*math.sin(math.pi*i/N)) for i in range(N)]
while True:
for pw in steps:
pwm.pulse_width( pw ) # change pulse width
time.sleep_ms( 100 )
except KeyboardInterrupt:
pass
finally:
tim.deinit() # disable timer
print('Done')
การใช้ software timer สร้างความถี่ที่แตกต่างกัน ด้วย STM32F411 และ Micropython
สร้าง 3 ความถี่ คือ 1hz, 2hz และ 4hz ต่อกับ PB7, PB8 และ PB9 และ active low ( 0 คือ led on หรือ 1 คือ led off)
import utime as time
from machine import Pin, Timer
from micropython import const
import pyb
LED_ON = const(0)
LED_OFF = const(1)
pin_names = ['PB7', 'PB8', 'PB9'] # output pins
leds = []
timers = []
def timer_cb(t): # timer callback function
for i in range(len(leds)):
if t is timers[i]:
# toggle: read-modify-write
x = leds[i].value()
leds[i].value( not x )
break
for pin in pin_names: # create Pin objects
leds.append( Pin(pin,mode=Pin.OUT_PP,value=LED_OFF) )
for i in range(len(leds)): # create Timer objects
timers.append( Timer(-1, freq=(1<<i), callback=timer_cb) )
try:
while True:
pass # do nothing in the main loop
except KeyboardInterrupt:
pass
finally:
for led in leds: # turn off all LEDs
led.value(LED_OFF)
for tim in timers: # turn off all timers
tim.deinit()
print('Done')
การใช้งาน ulab บน RP 2040
» ulab เป็นไลบรารีที่เพิ่มการทำงานทางด้านคณิตศาสตร์และวิทยาศาสตร์ของ Python ในแพลตฟอร์มที่มีทรัพยากรจำกัด, เช่น microcontroller ที่ใช้ MicroPython หรือ CircuitPython. ulab มีความคล้ายคลึงกับไลบรารี numpy และ scipy ที่ใช้ใน Python แบบปกติ, ทำให้ผู้พัฒนาที่มีประสบการณ์ในการทำงานกับ numpy สามารถใช้งาน ulab ได้โดยง่าย.
» คุณสมบัติหลักของ ulab:
1. เร็วและทรัพยากรน้อย: ulab ได้รับการพัฒนาเพื่อให้การทำงานที่รวดเร็วและใช้ทรัพยากรต่ำสุด.
2. ทำงานใน MicroPython และ CircuitPython: ไลบรารีนี้สามารถทำงานในแพลตฟอร์มที่ใช้ MicroPython และ CircuitPython, ทำให้เหมาะสมสำหรับ microcontroller.
3. มีฟังก์ชันคล้าย numpy: คุณสามารถทำ array operations, ใช้ฟังก์ชันทางคณิตศาสตร์, ทำ Fourier transforms, และอื่น ๆ ได้.
4. ใช้งานง่าย: หากคุณคุ้นเคยกับ numpy, คุณจะพบว่า ulab ใช้งานได้ง่ายและคุ้นเคย
1. กดปุ่ม boot + เสียบสาย usb เข้าคอมพิวเตอร์
2. จะมีไดรว์ RP 2040 เกิดขึ้น ให้คัดลอกไฟล์ ADAFRUIT_FEATHER_RP2040.uf2 ลงใน ไดรว์ RP2040
3. หลังจากนั้นโปรแกรมจะบูตอัตโนมัติ
4. เปิด Thonny -> เลือก RP2040 -> จะสามารถใช้งาน ulab ได้
>>> import ulab
>>> dir(ulab)
['__class__', '__name__', '__dict__', '__version__', 'dtype', 'numpy', 'scipy', 'utils']
ปล. ดาวน์โหลดเฟิร์มแวร์ https://github.com/v923z/micropython-builder/releases
from ulab import numpy as np
x = np.linspace(0, 10, num=1024)
y = np.sin(x)
a, b = np.fft.fft(y)
print('original vector:\t', y)
y, z = np.fft.ifft(a, b)
# the real part should be equal to y
print('\nreal part of inverse:\t', y)
# the imaginary part should be equal to zero
print('\nimaginary part of inverse:\t', z)
original vector: array([0.0, 0.009775011, 0.01954908, ..., -0.5275068, -0.535786, -0.5440211], dtype=float32)
real part of inverse: array([8.940695e-08, 0.009778291, 0.01955077, ..., -0.527504, -0.5357838, -0.5440156], dtype=float32)
imaginary part of inverse: array([2.095475e-08, 6.65376e-07, 4.454848e-07, ..., 6.856771e-06, 6.02012e-06, 9.188228e-06], dtype=float32)
อ่านเสียง
» Raspberry Pi Pico (RP2040) สามารถใช้เพื่ออ่านสัญญาณเสียงด้วยการใช้โค้ด MicroPython แต่ต้องมีอุปกรณ์ที่ช่วยในการแปลงสัญญาณเสียงเป็นสัญญาณอิเล็กทรอนิกส์ที่สามารถวัดได้ (เช่น microphone module). ตัวอย่างโค้ดที่ใช้กับ microphone module สามารถเป็นดังนี้:
import machine
import array
import utime
# สร้าง object ADC (Analog-to-Digital Converter)
adc = machine.ADC(26) # ค่า 26 ต้องถูกเปลี่ยนตาม pin ที่ microphone เชื่อมต่อ
# สร้าง array เพื่อเก็บข้อมูล
buffer = array.array('H', [0] * 1000)
# อ่านข้อมูลจาก microphone
for i in range(1000):
buffer[i] = adc.read_u16()
utime.sleep_us(10) # หน่วงเวลาเล็กน้อยระหว่างการอ่านข้อมูล
# ตอนนี้ 'buffer' มีข้อมูลเสียงจาก microphone
# คุณสามารถใช้ข้อมูลนี้ในการวิเคราะห์เสียง, ทำ FFT, หรือการประมวลผลที่ต้องการ
from ulab import numpy as np
a = np.array([1, 2, 3, 4, 5], dtype=np.float)
np.mean(a)
np.std(a)
» ใน np ประกอบด้วยคำสั่ง
» all, any, bool, sort, sum, acos, acosh, arange, arctan2, argmax, argmin, argsort, around, array, asarray, asin, asinh, atan, atanh, bitwise_and, bitwise_or, bitwise_xor, ceil, clip, complex, compress, concatenate, conjugate, convolve, cos, cosh, cross, degrees, delete, diag, diff, dot, e, empty, equal, exp, expm1, eye, fft, flip, float, floor, frombuffer, full, get_printoptions, imag, inf, int16, int8, interp, isfinite, isinf, left_shift, linalg, linspace, load, loadtxt, log, log10, log2, logspace, max, maximum, mean, median, min, minimum, nan, ndarray, ndinfo, nonzero, not_equal, ones, pi, polyfit, polyval, radians, real, right_shift, roll, save, savetxt, set_printoptions, sin, sinc, sinh, size, sort_complex, sqrt, std, tan, tanh, trace, trapz, uint16, uint8, vectorize, where, zeros
MicroMLGen
» MicroMLGen คือเครื่องมือที่ใช้แปลงโมเดลจากการเรียนรู้เครื่องจาก Scikit-learn ให้อยู่ในรูปแบบของโค้ด C ที่สามารถใช้งานได้บนไมโครคอนโทรลเลอร์เช่น RP2040.
ขั้นตอนทั่วไป:
การเตรียมโมเดล:
สร้างและฝึกฝนโมเดลใน Python ใช้ Scikit-learn หรือฟรีมเวิร์คการเรียนรู้เครื่องอื่น ๆ
ใช้ MicroMLGen เพื่อแปลงโมเดลเป็นโค้ด C
การนำโค้ด C ไปใช้บน RP2040:
นำโค้ด C ที่ได้จาก MicroMLGen ไปใช้บนโปรแกรมที่รันบน RP2040
ทำการเชื่อมต่อและอ่านข้อมูลจากเซ็นเซอร์หรืออินพุตต่าง ๆ
ป้อนข้อมูลเหล่านี้เข้าไปยังโมเดลและทำนายผล
from sklearn import datasets
from sklearn.tree import DecisionTreeClassifier
from micromlgen import port
# โหลดข้อมูลตัวอย่างและสร้างโมเดล
iris = datasets.load_iris()
X, y = iris.data, iris.target
clf = DecisionTreeClassifier()
clf.fit(X, y)
# แปลงโมเดลเป็นโค้ด C
c_code = port(clf)
print(c_code)
#ตัวอย่างโค้ด C บน RP2040:
#include "pico/stdlib.h"
// ตรงนี้คุณต้อง include โค้ด C ที่ได้จาก MicroMLGen
#include "your_model.h"
int main() {
stdio_init_all();
// ตัวอย่างการใช้งานโมเดล
// ป้อนข้อมูลให้กับโมเดล
float features[] = {5.1, 3.5, 1.4, 0.2};
// ทำนายผล
int prediction = your_model_predict(features);
// แสดงผลลัพธ์
printf("Prediction: %d\n", prediction);
}
โค้ด C ที่ได้จาก MicroMLGen ควรถูกนำไปใส่ในโปรเจ็คของคุณที่รันบน RP2040.
การใช้งาน Embedded Linux
» การควบคุม I/O (Input/Output) สามารถใช้ผ่าน Shell ได้ดังนี้
$ sudo gpio -g mode 17 out # กำหนดให้ GPIO 17 เป็น Output
$ sudo gpio -g write 17 1 # กำหนดให้ GPIO 17 มีสถานะเป็น High
$ sudo gpio -g write 17 0 # กำหนดให้ GPIO 17 มีสถานะเป็น Low
$ for i in {1..12}; do gpio -g write 17 1; sleep 0.2; done # วนรอบ 12 ครั้งให้เปิดปิดขา GPIO17 และหน่วง 0.2 วินาที
การใช้งาน NRF24L01และ ESP8266
» การเชื่อมต่อสายสัญญาณ
» ดาวน์โหลดไลบรารี่ nrf2401.py เก็บไว้ในไมโครไพธอน /lib หรือไดเร็คทอรี่นอกสุด /
# MASTER
import sys
import ustruct as struct
import utime
from machine import Pin, SPI
from nrf24l01 import NRF24L01
from micropython import const
from urandom import getrandbits
# Slave pause between receiving data and checking for further packets.
_RX_POLL_DELAY = const(15)
# Slave pauses an additional _SLAVE_SEND_DELAY ms after receiving data and before
# transmitting to allow the (remote) master time to get into receive mode. The
# master may be a slow device. Value tested with Pyboard, ESP32 and ESP8266.
_SLAVE_SEND_DELAY = const(10)
if sys.platform == 'pyboard':
cfg = {'spi': 2, 'miso': 'Y7', 'mosi': 'Y8', 'sck': 'Y6', 'csn': 'Y5', 'ce': 'Y4'}
elif sys.platform == 'esp8266': # Hardware SPI
cfg = {'spi': 1, 'miso': 12, 'mosi': 13, 'sck': 14, 'csn': 4, 'ce': 5}
elif sys.platform == 'esp32': # Software SPI
cfg = {'spi': -1, 'miso': 32, 'mosi': 33, 'sck': 25, 'csn': 26, 'ce': 27}
else:
raise ValueError('Unsupported platform {}'.format(sys.platform))
pipes = (b'\xf0\xf0\xf0\xf0\xe1', b'\xf0\xf0\xf0\xf0\xd2')
def master():
csn = Pin(cfg['csn'], mode=Pin.OUT, value=1)
ce = Pin(cfg['ce'], mode=Pin.OUT, value=0)
if cfg['spi'] == -1:
spi = SPI(-1, sck=Pin(cfg['sck']), mosi=Pin(cfg['mosi']), miso=Pin(cfg['miso']))
nrf = NRF24L01(spi, csn, ce, payload_size=8)
else:
nrf = NRF24L01(SPI(cfg['spi']), csn, ce, payload_size=8)
nrf.open_tx_pipe(pipes[0])
nrf.open_rx_pipe(1, pipes[1])
nrf.start_listening()
num_needed = 16
num_successes = 0
num_failures = 0
led_state = 0
print('NRF24L01 master mode, sending %d packets...' % num_needed)
while num_successes < num_needed and num_failures < num_needed:
# stop listening and send packet
nrf.stop_listening()
millis = utime.ticks_ms()
led_state = max(1, (led_state << 1) & 0x0f)
print('sending:', millis, led_state)
try:
#nrf.send(struct.pack('ii', millis, led_state))
z=getrandbits(8)
nrf.send("hello")
except OSError:
pass
# start listening again
nrf.start_listening()
# wait for response, with 250ms timeout
start_time = utime.ticks_ms()
timeout = False
while not nrf.any() and not timeout:
if utime.ticks_diff(utime.ticks_ms(), start_time) > 250:
timeout = True
if timeout:
print('failed, response timed out')
num_failures += 1
else:
# recv packet
got_millis, = struct.unpack('i', nrf.recv())
# print response and round-trip delay
print('got response:', got_millis, '(delay', utime.ticks_diff(utime.ticks_ms(), got_millis), 'ms)')
num_successes += 1
# delay then loop
utime.sleep_ms(250)
print('master finished sending; successes=%d, failures=%d' % (num_successes, num_failures))
print('NRF24L01 test module loaded')
print('NRF24L01 pinout for test:')
print(' CE on', cfg['ce'])
print(' CSN on', cfg['csn'])
print(' SCK on', cfg['sck'])
print(' MISO on', cfg['miso'])
print(' MOSI on', cfg['mosi'])
print('run master()')
# SLAVE
"""Test for nrf24l01 module. Portable between MicroPython targets."""
import sys
import ustruct as struct
import utime
from machine import Pin, SPI
from nrf24l01 import NRF24L01
from ws2812b import *
from micropython import const
# Slave pause between receiving data and checking for further packets.
_RX_POLL_DELAY = const(15)
# Slave pauses an additional _SLAVE_SEND_DELAY ms after receiving data and before
# transmitting to allow the (remote) master time to get into receive mode. The
# master may be a slow device. Value tested with Pyboard, ESP32 and ESP8266.
_SLAVE_SEND_DELAY = const(10)
if sys.platform == 'pyboard':
cfg = {'spi': 2, 'miso': 'Y7', 'mosi': 'Y8', 'sck': 'Y6', 'csn': 'Y5', 'ce': 'Y4'}
elif sys.platform == 'esp8266': # Hardware SPI
cfg = {'spi': 1, 'miso': 12, 'mosi': 13, 'sck': 14, 'csn': 4, 'ce': 5}
elif sys.platform == 'esp32': # Software SPI
cfg = {'spi': -1, 'miso': 32, 'mosi': 33, 'sck': 25, 'csn': 26, 'ce': 27}
else:
raise ValueError('Unsupported platform {}'.format(sys.platform))
pipes = (b'\xf0\xf0\xf0\xf0\xe1', b'\xf0\xf0\xf0\xf0\xd2')
def slave():
csn = Pin(cfg['csn'], mode=Pin.OUT, value=1)
ce = Pin(cfg['ce'], mode=Pin.OUT, value=0)
if cfg['spi'] == -1:
spi = SPI(-1, sck=Pin(cfg['sck']), mosi=Pin(cfg['mosi']), miso=Pin(cfg['miso']))
nrf = NRF24L01(spi, csn, ce, payload_size=8)
else:
nrf = NRF24L01(SPI(cfg['spi']), csn, ce, payload_size=8)
nrf.open_tx_pipe(pipes[1])
nrf.open_rx_pipe(1, pipes[0])
nrf.start_listening()
print('NRF24L01 slave mode, waiting for packets... (ctrl-C to stop)')
while True:
if nrf.any():
while nrf.any():
buf = nrf.recv()
n, r,g,b = struct.unpack('iiii', buf)
#millis, led_state = struct.unpack('ii', buf)
#print('received:', millis, led_state)
#t = struct.unpack('sssss', buf)
print(n,r,g,b)
utime.sleep_ms(_RX_POLL_DELAY)
# Give master time to get into receive mode.
utime.sleep_ms(_SLAVE_SEND_DELAY)
nrf.stop_listening()
try:
#nrf.send(struct.pack('i', millis))
nrf.send(struct.pack('i', 0))
except OSError:
pass
#print('sent response')
nrf.start_listening()
leds=[]
การใช้ Raspberry Pi Pico Clone
» ราคา 79 บาท
» https://youtu.be/EChO4o4Z9v8
from machine import Pin
led=Pin(25, Pin.OUT)
led.toggle()
from neopixel import NeoPixel
import machine
np=NeoPixel(machine.Pin(23), 1)
np[0] = (255,0,0);np.write()
แหล่งข้อมูลเพิ่มเติม
» ไลบรารี่ต่าง ๆ สำหรับ MicroPython
» Fourier Transforms With scipy.fft: Python Signal Processing
» โรงงานผลิตหลอด WS2812B KTRLIGHT
» JarutEx
» micropython-for-stm32
» ESP32 ภาษาไทย
» ESP32-CAM
การเขียนโปรแกรมควบคุมการขยายพอร์ตด้วยไอซี 74hc595 เข้า 3 ออก 8 (Multiplexer)
» ชิป 74HC595 (74HC595N) เป็นชิปขนาดเล็กที่ใช้ในงานขยายจำนวนขาอินพุตและขาเอาท์พุตของไมโครคอน๊ทรอลเลอร์หรืออุปกรณ์อื่น ๆ โดยมีโครงสร้างหลักดังนี้:
1. ขาอินพุตข้อมูล (Serial Data Input - DS): นี่คือขาที่ใช้ในการรับข้อมูลเข้าสู่ชิป 74HC595 โดยใช้โหมดขยาย (Serial-In, Parallel-Out) ข้อมูลจะถูกเลื่อนเข้ามาทีละบิตเพื่อเก็บไว้ในชิป.
2. ขาของชนิดข้อมูล (Clock Input - SHCP): นี่คือขาที่ใช้ในการกำหนดระยะเวลาของการเลื่อนข้อมูลเข้ามา ข้อมูลจะถูกอ่านจากขา DS และเลื่อนข้ามไปข้ามอินพุตข้อมูลเพื่อเข้าสู่ชิป 74HC595 ทีละบิต.
3. ขาของล็อก (Storage Register Clock Input - STCP): นี่คือขาที่ใช้ในการเก็บข้อมูลที่ถูกเลื่อนเข้ามาจากขา DS และนำข้อมูลนี้เข้าไปในที่เก็บข้อมูลในชิป 74HC595.
4. ขาอโพล็กเอาท์ (Parallel Data Outputs - Q0 ถึง Q7): มี 8 ขาเอาท์พุตที่ใช้ในการเอาท์พุตข้อมูลจากชิป 74HC595 โดยข้อมูลที่ถูกเก็บในชิปจะถูกนำออกผ่านขาเอาท์พุตนี้ ซึ่งคุณสามารถเชื่อมต่อกับอุปกรณ์อื่น ๆ เพื่อควบคุมและควบคุมอุปกรณ์เหล่านั้น.
5. ขาอินพุตของคลีร์ (Clear Input - MR): นี่คือขาที่ใช้ในการล้างข้อมูลที่ถูกเก็บในชิป 74HC595 โดยที่เมื่อถูกเปิด ข้อมูลในชิปจะถูกล้าง.
6. ขาอินพุตของโหมดขยาย/โหมดเก็บข้อมูล (Output Enable - OE): นี่คือขาที่ใช้ในการเปิดหรือปิดการใช้งานขาเอาท์พุต ถ้าถูกเปิดใช้งาน (ให้ล๊อกขานี้) ข้อมูลที่ถูกเก็บในชิปจะถูกส่งออกผ่านขาเอาท์พุต ถ้าถูกปิดใช้งาน (ไม่ล๊อกขานี้) ข้อมูลจะไม่ถูกส่งออก.
7. ขาอินพุตของตัวควบคุมข้อมูล (Master Reset - MR): นี่คือขาที่ใช้ในการล้างข้อมูลที่ถูกเก็บในชิป 74HC595 โดยการใช้โหมดขยาย ถ้าถูกเปิดใช้งาน, ข้อมูลที่ถูกเก็บในชิปจะถูกล้าง.
8. ขา VCC และ GND: ขา VCC ใช้ในการจ่ายแหล่งจ่ายไฟให้กับชิป 74HC595 และขา GND เป็นขาอ้างอิงเป็นอันดับสูงของจ่ายแหล่งจ่ายไฟ.
รวมถึงคุณสมบัติอื่น ๆ ของชิป 74HC595 เช่น ความสามารถในการจัดการข้อมูลที่ถูกเก็บ การทำงานในโหมดขยายและโหมดเก็บข้อมูล และความเสถียรในการทำงานในระดับไฟต่าง ๆ และความเร็วในการเลื่อนข้อมูล ซึ่งทั้งหมดนี้ทำให้ชิป 74HC595 เป็นชิปที่นิยมในการควบคุมอุปกรณ์หลาย ๆ ตัวจากไมโครคอน๊ทรอลเลอร์หรือไมโครคอน๊ทรอลเลอร์อื่น ๆ โดยใช้ขาเข้าน้อยลง
import machine
import time
# กำหนดขาที่เชื่อมต่อระหว่าง RP2040 และ 74HC595
data_pin = machine.Pin(2, machine.Pin.OUT) # ขาข้อมูล (DS)
clock_pin = machine.Pin(3, machine.Pin.OUT) # ขาคล็อก (SHCP)
latch_pin = machine.Pin(4, machine.Pin.OUT) # ขาล็อก (STCP)
# สร้างฟังก์ชันสำหรับส่งข้อมูลไปยังชิป 74HC595
def shift_out(data_pin, clock_pin, latch_pin, data):
for i in range(7, -1, -1):
bit_value = (data >> i) & 1
data_pin.value(bit_value)
clock_pin.on()
clock_pin.off()
latch_pin.on()
latch_pin.off()
# รหัสส่งผ่านข้อมูลสำหรับแสดงตัวเลข 0-9 บน 7-Segment Display
seven_segment_codes = [0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110,
0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111]
# ฟังก์ชัน settext สำหรับแสดงตัวเลขบน 7-Segment Display
def settext(number):
if 0 <= number <= 9:
shift_out(data_pin, clock_pin, latch_pin, seven_segment_codes[number])
else:
print("Invalid number. Please enter a number between 0 and 9.")
# ตัวอย่างการใช้งาน
try:
while True:
for i in range(10):
settext(i)
time.sleep(1)
except KeyboardInterrupt:
pass
การเขียนโปรแกรมสื่อสารไร้สายด้วย LORA และ RPI 2040
» เชื่อมต่อ Lora และ RP2040 ทุกชุดทั้งตัวรับตัวส่งเหมือนกันหมด ดังนี้
- LORA.GND -> RP2040.GND
- LORA.VCC -> RP2040.3.3v
- LORA.AUX -> ไม่ต้องต่อ
- LORA.Tx -> RP2040.Pin2(Rx0)
- LORA.Rx -> RP2040.Pin1(Tx0)
- LORA.M1 -> RP2040.Gnd
- LORA.M0 -> RP2040.Gnd
- เว็บ micropeta.com/video24
#Transmitter code starts here
import utime
from machine import UART
from machine import Pin
lora = UART(0,9600)
switch1 = Pin(20, Pin.IN, Pin.PULL_DOWN)
switch2 = Pin(19, Pin.IN, Pin.PULL_DOWN)
switch3 = Pin(18, Pin.IN, Pin.PULL_DOWN)
while True:
if switch1.value() and switch2.value() and switch3.value():
lora.write("SECRET111")
elif switch1.value() and switch2.value():
lora.write("SECRET110")
elif switch1.value() and switch3.value():
lora.write("SECRET101")
elif switch2.value() and switch3.value():
lora.write("SECRET011")
elif switch1.value():
lora.write("SECRET100")
elif switch2.value():
lora.write("SECRET010")
elif switch3.value():
lora.write("SECRET001")
else:
lora.write("SECRET000")
utime.sleep(0.2)
#Transmitter code Ends here
#Receiver code starts here
import utime
from machine import UART
from machine import Pin
lora = UART(0,9600)
led_red = machine.Pin(20, machine.Pin.OUT)
led_green = machine.Pin(19, machine.Pin.OUT)
led_blue = machine.Pin(18, machine.Pin.OUT)
led_red.value(0)
led_green.value(0)
led_blue.value(0)
while True:
dataRead = lora.readline()
if dataRead is not None and "SECRET000" in dataRead:
led_red.value(0)
led_green.value(0)
led_blue.value(0)
elif dataRead is not None and "SECRET001" in dataRead:
led_red.value(0)
led_green.value(0)
led_blue.value(1)
elif dataRead is not None and "SECRET010" in dataRead:
led_red.value(0)
led_green.value(1)
led_blue.value(0)
elif dataRead is not None and "SECRET011" in dataRead:
led_red.value(0)
led_green.value(1)
led_blue.value(1)
elif dataRead is not None and "SECRET100" in dataRead:
led_red.value(1)
led_green.value(0)
led_blue.value(0)
elif dataRead is not None and "SECRET101" in dataRead:
led_red.value(1)
led_green.value(0)
led_blue.value(1)
elif dataRead is not None and "SECRET110" in dataRead:
led_red.value(1)
led_green.value(1)
led_blue.value(0)
elif dataRead is not None and "SECRET111" in dataRead:
led_red.value(1)
led_green.value(1)
led_blue.value(1)
utime.sleep(0.2)
#Receiver code Ends here
การใช้ UART จำนวน 6 ตัวด้วย ESP32 และ Micropython
»
ESP32 สร้าง Web Server
»
try:
import usocket as socket
except:
import socket
import network
import esp
esp.osdebug(None)
import gc
gc.collect()
ssid = 'MicroPython-AP'
password = '123456789'
ap = network.WLAN(network.AP_IF)
ap.active(True)
ap.config(essid=ssid, authmode=network.AUTH_WPA2_PSK, password=password)
while ap.active() == False:
pass
print('Connection successful')
print(ap.ifconfig())
def web_page():
html = """
Hello, World!
"""
return html
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)
while True:
conn, addr = s.accept()
print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
print('Content = %s' % str(request))
response = web_page()
conn.send(response)
conn.close()
การใช้ rshell กับ ESP32
» ติดตั้ง rshell: ให้ติดตั้ง rshell บนคอมพิวเตอร์ของคุณ โดยใช้คำสั่ง pip install rshell
» เชื่อมต่อ ESP32: เข้าสู่โหมด REPL บน ESP32 เช่น Thonny, ampy, หรือ esptool ในการอัปโหลด MicroPython firmware ลงใน ESP32
» เชื่อมต่อ ESP32 กับคอมพิวเตอร์: เมื่อ ESP32 อยู่ในโหมด REPL (อ่าน-ส่งคำสั่ง), ให้เชื่อมต่อ ESP32 กับคอมพิวเตอร์ของคุณผ่านพอร์ต UART ด้วยสาย USB-to-Serial
» ให้เขียนไฟล์ boot.py เพิ่มคำสั่งต่อไปนี้
import machine
import os
import esp
esp.osdebug(None)
# Enable REPL on UART0 (USB-to-Serial)
uart = machine.UART(0, baudrate=115200)
os.dupterm(uart)
» กดปุ่ม reset บนบอร์ด ESP32
» รัน rshell: เมื่อ ESP32 กำลังทำงานและเชื่อมต่อกับคอมพิวเตอร์, ให้เปิดหน้าต่างคอมพิวเตอร์ใหม่และใช้คำสั่งต่อไปนี้เพื่อเริ่มใช้งาน rshell:
rshell --buffer-size=30 -p /dev/ttyUSB0 # ให้แทน /dev/ttyUSB0 ด้วยพอร์ตของ USB-to-Serial ของคุณ
--buffer-size=30: ระบุขนาดของบัฟเฟอร์สำหรับคำสั่ง (buffer size) เพื่อให้การทำงานดีขึ้น (สามารถปรับขนาดตามความเหมาะสม).
-p /dev/ttyUSB0: ระบุพอร์ตของ USB-to-Serial ที่ ESP32 เชื่อมต่อกับคอมพิวเตอร์ของคุณ.
» พิมพ์คำสั่ง repl เพื่อเข้าสู่ python prompt บนหน้าจอจะปรากฎหน้าจอ >>>
» ใช้คำสั่ง rshell: เมื่อเชื่อมต่อสำเร็จ, คุณสามารถใช้คำสั่ง rshell เพื่อควบคุมและจัดการกับ ESP32 ได้ เช่น:
- ls: แสดงรายการไฟล์บน ESP32.
- cd directory_name: เปลี่ยนไปยังไดเรกทอรีที่ระบุ.
- get file_name: ดาวน์โหลดไฟล์จาก ESP32 ไปยังคอมพิวเตอร์ของคุณ.
- put file_name: อัปโหลดไฟล์จากคอมพิวเตอร์ของคุณไปยัง ESP32.
- repl: เข้าสู่โหมด REPL บน ESP32.
- exit: ออกจากรshell.
» ออกจาก rshell: เมื่อคุณเสร็จสิ้นการใช้งาน rshell, ให้ปิด rshell โดยการพิมพ์ exit และกด Enter.
การอ่านเขียนข้อมูล ESP32 และ UART
» ESP32.pin16(Rx) -> Module.Tx
» ESP32.pin17(Tx) -> Module.Rx
» ESP32.3v3 -> Module.vcc
» ESP32.Gnd -> Module.Gnd
import machine
import time
# กำหนดค่า UART
uart = machine.UART(1, baudrate=9600, tx=17, rx=16) # ตั้งค่า UART กับพิน GPIO 17 (TX) และ 16 (RX)
while True:
# ส่งข้อมูลผ่าน UART
#uart.write("Hello, ESP32!\n")
# รับข้อมูลจาก UART
if uart.any():
r = uart.read()
print("Received:", r)
การใช้งานบอร์ด Freenove ESP32-Wrover CAM Board ถ่ายภาพและส่งขึ้น Php Server
» เฟิร์มแวร์ https://www.freenove.com/tutorial
» esp32spiram-20220618-v1.19.1.bin ไม่สามารถใช้ import camera
» esp32spiram-idf4-20191220-v1.12.bin ไม่สามารถใช้ import camera
» micropython_camera_feeeb5ea3_esp32_idf4_4.bin สามารถใช้ import camera
import camera
def camera_init():
# Disable camera initialization
camera.deinit()
# Enable camera initialization
camera.init(0, d0=4, d1=5, d2=18, d3=19, d4=36, d5=39, d6=34, d7=35,
format=camera.JPEG, framesize=camera.FRAME_VGA,
xclk_freq=camera.XCLK_20MHz,
href=23, vsync=25, reset=-1, pwdn=-1,
sioc=27, siod=26, xclk=21, pclk=22, fb_location=camera.PSRAM)
camera.framesize(camera.FRAME_VGA) # Set the camera resolution
# The options are the following:
# FRAME_96X96 FRAME_QQVGA FRAME_QCIF FRAME_HQVGA FRAME_240X240
# FRAME_QVGA FRAME_CIF FRAME_HVGA FRAME_VGA FRAME_SVGA
# FRAME_XGA FRAME_HD FRAME_SXGA FRAME_UXGA
# Note: The higher the resolution, the more memory is used.
# Note: And too much memory may cause the program to fail.
camera.flip(1) # Flip up and down window: 0-1
camera.mirror(1) # Flip window left and right: 0-1
camera.saturation(0) # saturation: -2,2 (default 0). -2 grayscale
camera.brightness(0) # brightness: -2,2 (default 0). 2 brightness
camera.contrast(0) # contrast: -2,2 (default 0). 2 highcontrast
camera.quality(10) # quality: # 10-63 lower number means higher quality
# Note: The smaller the number, the sharper the image. The larger the number, the more blurry the image
camera.speffect(camera.EFFECT_NONE) # special effects:
# EFFECT_NONE (default) EFFECT_NEG EFFECT_BW EFFECT_RED EFFECT_GREEN EFFECT_BLUE EFFECT_RETRO
camera.whitebalance(camera.WB_NONE) # white balance
# WB_NONE (default) WB_SUNNY WB_CLOUDY WB_OFFICE WB_HOME
camera_init()
การบันทึกภาพลง storage
img = camera.capture()
with open("test.jpg", "wb") as file:
file.write(img)
file.close()
การส่งภาพขึ้น Php Server
import urequests as requests
import ubinascii
camera_init()
img = camera.capture()
base64_img = ubinascii.b2a_base64(img)
url = "http://dsdi.msu.ac.th/iot/esp32/upload.php" # เปลี่ยน URL เป็น URL ของเซิร์ฟเวอร์ PHP ที่นี่
headers = {
"Content-Type": "application/json",
}
data = {
"image_data": base64_img,
}
try:
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
print("Image uploaded successfully")
print(response.text)
else:
print("Failed to upload image")
except Exception as e:
print("Error:", e)
upload.php
<?php
header("Content-Type: application/json");
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$data = json_decode(file_get_contents("php://input"));
if ($data && isset($data->image_data)) {
$image_data = $data->image_data;
$image_name = "captured_image.jpg"; // กำหนดชื่อไฟล์ภาพที่จะบันทึก
$image_path = "./img/$image_name"; // ระบุเส้นทางที่จะบันทึกภาพ
// บันทึกภาพลงในเซิร์ฟเวอร์
if (file_put_contents($image_path, base64_decode($image_data))) {
echo json_encode(["message" => "Image uploaded successfully"]);
} else {
echo json_encode(["message" => "Failed to upload image"]);
}
} else {
echo json_encode(["message" => "Invalid data"]);
}
} else {
echo json_encode(["message" => "Invalid request"]);
}
?>
การติดตั้ง package ด้วย upip
» upip เป็นการติดตั้ง package บนไมโครไพธอน
import network
# สร้างออบเจ็กต์ WLAN(สามารถใช้ได้กับ STA_IF หรือ AP_IF)
wlan = network.WLAN(network.STA_IF)
# เปิดการใช้งาน Wi-Fi interface
wlan.active(True)
# เชื่อมต่อกับ Wi-Fi network (SSID และ Password ของคุณ)
wlan.connect('ชื่อ Wi-Fi', 'รหัสผ่าน Wi-Fi')
# รอจนกว่า ESP32 จะเชื่อมต่อกับ Wi-Fi
while not wlan.isconnected():
pass
# พร้อมแสดง IP address ของ ESP32
print('Connected to Wi-Fi')
print('IP address:', wlan.ifconfig()[0])
import upip
upip.install('urequests')
การอ่าน QR-Code
» ESP32 Cam อ่าน QR-Code
- MC_QR_Reader
- QR-Code-via-MQTT-with-only-ESP32
- ESP32QRCodeReader
» โมดูล Tiny Code Reader ใช้ RP2040 ในการประมวลผล
» เพื่อความสะดวกควรใช้โมดูล Tiny Code Reader สื่อสารด้วย I2C ราคา $7 เหรียญ
การใช้งานจอ 2.8 นิ้ว SPI Module ILI9341 และ ESP32 ด้วย micropython
» SPI Module ILI9341 เป็นโมดูลที่ใช้ในการเชื่อมต่อกับหน้าจอ TFT (Thin-Film Transistor) แบบสีที่มีชื่อรุ่น ILI9341 ซึ่งมักนำมาใช้ในการสร้างหน้าจอแสดงผลสำหรับโปรเจคอิเล็กทรอนิกส์และโปรเจคอื่น ๆ ที่ต้องการแสดงข้อมูลแบบกราฟิกหรือภาพสี
» SPI Module ILI9341 มีลักษณะสำคัญดังนี้:
» หน้าจอ TFT สี: มีความสามารถในการแสดงสีที่มีความละเอียดสูง มักมีความละเอียดสี 16 บิตหรือ 18 บิต ซึ่งช่วยให้คุณสามารถแสดงภาพและกราฟิกสีได้หลากหลาย
» การเชื่อมต่อผ่าน SPI: โมดูลนี้ใช้การเชื่อมต่อผ่าน SPI (Serial Peripheral Interface) ซึ่งเป็นอินเทอร์เฟซสื่อสารแบบคีย์ข้อมูลซีเรียล ทำให้มันสามารถทำงานกับไมโครคอนโทรลเลอร์หรือไมโครคอมพิวเตอร์อย่าง ESP32 หรือ Raspberry Pi
» ขนาดหน้าจอสูง: ILI9341 มักมีขนาดหน้าจอที่ใหญ่ ส่วนใหญ่มีขนาด 2.8 นิ้ว หรือ 3.2 นิ้ว ซึ่งเหมาะสำหรับการแสดงผลข้อมูลใหญ่
» ความละเอียดสูง: หน้าจอ ILI9341 มักมีความละเอียดสูงสามารถแสดงผลข้อมูลที่คมชัดและละเอียด
» ความสามารถในการควบคุมสี: โมดูล ILI9341 สามารถแสดงสีแบบ RGB (Red-Green-Blue) ซึ่งช่วยให้คุณสามารถกำหนดสีต่าง ๆ ให้กับแต่ละพิกเซลได้
» อินเตอร์เฟซที่ง่ายต่อการใช้งาน: โมดูล ILI9341 มักมีไลบรารีและคู่มือการใช้งานที่ช่วยให้คุณสามารถเริ่มต้นใช้งานได้ง่าย
» ความเร็วในการส่งข้อมูล: SPI มีความเร็วในการส่งข้อมูลสูง ทำให้ ILI9341 สามารถแสดงผลข้อมูลอย่างรวดเร็ว
» การเขียนภาษาไทยบนจอกราฟิกบนไมโครคอนโทรลเลอร์ https://www.praphas.com/forum/index.php?topic=314.0
» การใช้งานจอ 2.8" ด้วย ESP32 https://www.artronshop.co.th/article/95
การออกแบบป้ายความเร็ว 7-SegmentC ด้วยหลอด WS2812
» ให้ออกแบบทีละส่วนทั้งหมด 7 ส่วน จะใช้พื้นที่ขนาดเล็กและใช้ PCB น้อยลง
การใช้งาน ESP32-2432S028 และ LVGL
» ESP32-2432S028 เป็น จอสัมผัส 2.8 นิ้ว ขนาด 240x320 spi ili9341 มี 4MB flash memory
- Expanded IO x 2 คือ P3 (Gnd, GPIO35, GPIO22, GPIO21)
- CN1 (Gnd, NC, GPI27, 3v3)
- SD Slot (Micro SD)
- RGB LED (Blue:GPIO16, Red:GPIO4, Green:GPIO17)
- CDS (GT36516) GPIO34
- External Power Connector
- P1 (Vin, TX, RX, Gnd)
- Audio Out (Audio amp SC8002b)
- P4 Speak(2=Vo2, 1=Vo1)
- Touch Pen, 4pin external connector, USB Cable
- Display Library: LovyanGFX (ILI9341, SPI2_HOST
- Upload Speed: Windows (921600), MacOS(460800)
» LVGL เป็นไลบรารี่สำหรับออกแบบการโต้ตอบกราฟิกบนไมโครคอนโทรลเลอร์
» ดาวน์โหลด: http://www.jczn1688.com/zlxz หรือ http://pan.jczn1688.com/directlink/1/ESP32%20module/2.8inch_ESP32-2432S028R.rar
» ปล. ทดลอง burn lvgl_firmware-thaifont/firmware_GENERIC/firmware.bin ด้วย Thronny ทำงานได้ แต่เขียนด้วย ESP Flash Downloader Tool 3.9.3 ใช้ไม่ได้
print(dir(disp))
['__class__', '__init__', '__module__', '__qualname__', '__dict__', 'height', 'stat', 'send_data', 'dc', 'cs', 'width', 'initialize', 'deinit', 'spi', 'monitor', 'miso', 'init', 'flush', 'mosi', 'power', 'start_x', 'start_y', 'power_on', 'word_trans_data', 'send_cmd', 'display_name', 'spimode', 'display_type', 'init_async', 'mhz', 'trans', 'clk', 'backlight_on', 'end_time_ptr', 'spi_send_dma', 'monitor_acc_px', 'bytes_transmitted', 'buf_size', 'spi_send', 'buf1', 'buf2', 'disp_spi_init', '_init', 'asynchronous', 'backlight', 'trans_buffer', 'rst', 'disp_drv', 'cycles_in_ms', 'spihost', 'monitor_count', 'send_trans_word', 'madctl', 'flush_acc_setup_cycles', 'flush_acc_dma_cycles', 'power_down', 'trans_result_ptr', 'hybrid', 'cmd_trans_data', 'factor', 'spi_callbacks', 'start_time_ptr', 'send_data_dma', 'TRANS_BUFFER_LEN', 'event_loop', 'init_cmds', 'monitor_acc_time', 'half_duplex']
การตั้งค่าหน้าจอให้กับจอภาพบน LVGL
# จอภาพของบอร์ดรุ่น ESP32-2432S028R
from ili9XXX import ili9341
disp = ili9341(rot=0x60 , clk=14, cs=15, dc=2, rst=12, power=23, backlight=21, miso=12, mosi=13,width=240, height=320,backlight_on=1)
# จอภาพของบอร์ดรุ่น ESP32- wt32-sc01
# clk (14), cs(15), dc(21), rst(22), backlight(23), power(-1), miso(-1), mosi(13), width(480), height(320)
from ili9XXX import *
disp=st7796(invert=True, hybrid=True, double_buffer=True, rot=REVERSE_LANDSCAPE) #dark theme
การตั้งค่า touch ให้กับจอภาพบน LVGL
# จอภาพของบอร์ดรุ่น ESP32-2432S028R ใช้ไม่ได้เพราะ SPI ไม่แชร์ ถ้าใช้เฉพาะการสัมผัสใช้โค๊ดต่อไปนี้
from xpt2046 import xpt2046
touch = xpt2046(clk=25, mosi=32, miso=39, cs=33, mhz=2)
touch.screen_width=240
touch.screen_height=320
while 1:
print(touch.get_coords())
# จอภาพของบอร์ดรุ่น ESP32- wt32-sc01
from ft6x36 import ft6x36
touch = ft6x36(sda=18, scl=19, width=320, height=480, inv_x=False, inv_y=True, swap_xy=True)
# ไดรว์เวอร์ -> https://dsdi.msu.ac.th/articles/iot/lvgl/touch-ft6x36/ft6x36.py
การตรวจสอบเวอร์ชั่นของ LVGL
print(lv.version_major())
print(lv.version_minor())
from ili9XXX import ili9341
disp = ili9341(rot=0x60 , clk=14, cs=15, dc=2, rst=12, power=23, backlight=21, miso=12, mosi=13,width=240, height=320,backlight_on=1)
สร้างปุ่มกลางจอภาพ
from display import *
import lvgl as lv
lv.init()
scr = lv.obj()
btn = lv.btn(scr)
btn.align(lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text('Hello World!')
lv.scr_load(scr)
กำหนดพื้นหลังจอภาพและเขียนข้อความ
from display import *
import lvgl as lv
lv.init()
scr = lv.scr_act() #lv.screen_active()
scr.set_style_bg_color(lv.color_hex(0x003a57), lv.PART.MAIN)
label = lv.label(lv.scr_act())
label.set_text("Hello world")
label.set_style_text_color(lv.color_hex(0xffffff), lv.PART.MAIN)
label.align(lv.ALIGN.CENTER, 0, 0)
WT32-SC01: สร้างปุ่มเมื่อกดจะเปลี่ยนจาก hello เป็น ok
» เอกสารการใช้งาน WT32-SC01
import lvgl as lv
from ili9XXX import *
disp=st7796(invert=True, hybrid=True, double_buffer=True, rot=REVERSE_LANDSCAPE) #dark theme
from ft6x36 import ft6x36
touch = ft6x36(sda=18, scl=19, width=320, height=480, inv_x=False, inv_y=True, swap_xy=True)
scr = lv.obj() # สร้างหน้าจอหลัก
btn = lv.btn(scr) # สร้างปุ่ม
btn.align(lv.ALIGN.CENTER, 0, 0) # จัดตำแหน่งตรงกลางหน้าจอ
label = lv.label(btn) # สร้างป้ายกำกับบนปุ่ม
label.set_text("Hello")
def btn_event_cb(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.CLICKED:
label.set_text("OK")
btn.add_event_cb(btn_event_cb, lv.EVENT.ALL, None)
lv.scr_load(scr)
WT32-SC01: สร้างปุ่มเมื่อกดจะเปลี่ยนจาก hello เป็น ok สลับกันไป
import lvgl as lv
from ili9XXX import *
disp=st7796(invert=True, hybrid=True, double_buffer=True, rot=REVERSE_LANDSCAPE) #dark theme
from ft6x36 import ft6x36
touch = ft6x36(sda=18, scl=19, width=320, height=480, inv_x=False, inv_y=True, swap_xy=True)
scr = lv.obj() # สร้างหน้าจอหลัก
btn = lv.btn(scr) # สร้างปุ่ม
btn.align(lv.ALIGN.CENTER, 0, 0) # จัดตำแหน่งตรงกลางหน้าจอ
label = lv.label(btn) # สร้างป้ายกำกับบนปุ่ม
label.set_text("Hello")
def btn_event_cb(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.CLICKED:
current_text = label.get_text()
if current_text == "Hello":
label.set_text("OK")
else:
label.set_text("Hello")
btn.add_event_cb(btn_event_cb, lv.EVENT.ALL, None)
lv.scr_load(scr)
WT32-SC01: สร้างปุ่มเมื่อกดจะเปลี่ยนจาก ON เป็น OFF และเปิดปิดหลอด LED สลับกันไป
import lvgl as lv
from ili9XXX import *
disp=st7796(invert=True, hybrid=True, double_buffer=True, rot=REVERSE_LANDSCAPE) #dark theme
from ft6x36 import ft6x36
touch = ft6x36(sda=18, scl=19, width=320, height=480, inv_x=False, inv_y=True, swap_xy=True)
import machine
gpio4 = machine.Pin(4, machine.Pin.OUT)
scr = lv.obj() # สร้างหน้าจอหลัก
btn = lv.btn(scr) #สร้างปุ่ม
btn.align(lv.ALIGN.CENTER, 0, 0) # จัดตำแหน่งตรงกลางหน้าจอ
label = lv.label(btn) # สร้างป้ายกำกับบนปุ่ม
label.set_text("ON")
def btn_event_cb(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.CLICKED:
current_text = label.get_text()
if current_text == "ON":
label.set_text("OFF")
gpio4.on() # เปิด GPIO4
else:
label.set_text("ON")
gpio4.off() # ปิด GPIO4
btn.add_event_cb(btn_event_cb, lv.EVENT.ALL, None)
lv.scr_load(scr)
สร้างปุ่ม 2 ปุ่ม ปรับมุมมนของปุ่มและสร้างสไลด์บาร์
from display import *
import lvgl as lv
lv.init()
style_button = lv.style_t()
style_button_red = lv.style_t()
style_button_pressed = lv.style_t()
# Create a simple button style
style_button.init()
style_button.set_radius(10)
style_button.set_bg_opa(lv.OPA.COVER)
style_button.set_bg_color(lv.palette_lighten(lv.PALETTE.GREY, 3))
style_button.set_bg_grad_color(lv.palette_main(lv.PALETTE.GREY))
style_button.set_bg_grad_dir(lv.GRAD_DIR.VER)
# Add a border
style_button.set_border_color(lv.color_white())
style_button.set_border_opa(lv.OPA._70)
style_button.set_border_width(2)
# Set the text style
style_button.set_text_color(lv.color_white())
# Create a red style. Change only some colors.
style_button_red.init()
style_button_red.set_bg_color(lv.palette_main(lv.PALETTE.RED))
style_button_red.set_bg_grad_color(lv.palette_lighten(lv.PALETTE.RED, 2))
# Create a style for the pressed state.
style_button_pressed.init()
style_button_pressed.set_bg_color(lv.palette_main(lv.PALETTE.BLUE))
style_button_pressed.set_bg_grad_color(lv.palette_darken(lv.PALETTE.RED, 3))
# Create a button and use the new styles
button = lv.btn(lv.scr_act()) # Add a button the current screen
# Remove the styles coming from the theme
# Note that size and position are also stored as style properties
# so lv_obj_remove_style_all will remove the set size and position too
button.remove_style_all() # Remove the styles coming from the theme
button.set_pos(10, 10) # Set its position
button.set_size(120, 50) # Set its size
button.add_style(style_button, 0)
button.add_style(style_button_pressed, lv.STATE.PRESSED)
label = lv.label(button) # Add a label to the button
label.set_text("Button") # Set the labels text
label.center()
# Create a slider in the center of the display
slider = lv.slider(lv.scr_act())
slider.set_width(200) # Set the width
slider.center() # Align to the center of the parent (screen)
# Create another button and use the red style too
button2 = lv.btn(lv.scr_act())
button2.remove_style_all() # Remove the styles coming from the theme
button2.set_pos(10, 80) # Set its position
button2.set_size(120, 50) # Set its size
button2.add_style(style_button, 0)
button2.add_style(style_button_red, 0)
button2.add_style(style_button_pressed, lv.STATE.PRESSED)
button2.set_style_radius(lv.RADIUS_CIRCLE, 0) # Add a local style
label = lv.label(button2) # Add a label to the button
label.set_text("Button 2") # Set the labels text
label.center()
การเพิ่ม Event ให้กับปุ่ม
class CounterBtn():
def __init__(self):
self.cnt = 0
#
# Create a button with a label and react on click event.
#
button = lv.button(lv.screen_active()) # Add a button the current screen
button.set_pos(10, 10) # Set its position
button.set_size(120, 50) # Set its size
button.align(lv.ALIGN.CENTER,0,0)
button.add_event(self.button_event_cb, lv.EVENT.ALL, None) # Assign a callback to the button
label = lv.label(button) # Add a label to the button
label.set_text("Button") # Set the labels text
label.center()
def button_event_cb(self,e):
code = e.get_code()
button = e.get_target_obj()
if code == lv.EVENT.CLICKED:
self.cnt += 1
# Get the first child of the button which is the label and change its text
label = button.get_child(0)
label.set_text("Button: " + str(self.cnt))
counterBtn = CounterBtn()
การสร้างปุ่มแสดงข้อความ Click เมื่อกดปุ่มเปลี่ยนข้อความเป็นคำว่า Button
import lvgl as lv
import display_driver
def btn_event_cb(e):
print("Clicked")
# Create a Button and a Label
btn = lv.btn(lv.scr_act())
btn.center()
btn.set_size(100, 50)
btn.add_event_cb(btn_event_cb, lv.EVENT.CLICKED, None)
label = lv.label(btn)
label.set_text("Button")
label.center()
การแสดงรายการ checkbox เมื่อกดให้แสดงข้อความของแต่ละตัวเลือกออกมา
def event_handler(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
txt = obj.get_text()
if obj.get_state() & lv.STATE.CHECKED:
state = "Checked"
else:
state = "Unchecked"
print(txt + ":" + state)
lv.scr_act().set_flex_flow(lv.FLEX_FLOW.COLUMN)
lv.scr_act().set_flex_align(lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.START, lv.FLEX_ALIGN.CENTER)
cb = lv.checkbox(lv.scr_act())
cb.set_text("Apple")
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
cb = lv.checkbox(lv.scr_act())
cb.set_text("Banana")
cb.add_state(lv.STATE.CHECKED)
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
cb = lv.checkbox(lv.scr_act())
cb.set_text("Lemon")
cb.add_state(lv.STATE.DISABLED)
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
cb = lv.checkbox(lv.scr_act())
cb.add_state(lv.STATE.CHECKED | lv.STATE.DISABLED)
cb.set_text("Melon")
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
การเขียนข้อความด้วย lvgl label
import sys
from ili9XXX import ili9341
disp = ili9341(rot=0x60 , clk=14, cs=15, dc=2, rst=12, power=23, backlight=21, miso=12, mosi=13,width=240, height=320,backlight_on=1)
import lvgl as lv
lv.init()
# การเพิ่ม label
a= lv.label(lv.scr_act())
a.set_text('สารสนเทศศาสตร์')
a.align(lv.ALIGN.CENTER, 0, -130)
a.set_style_text_font(lv.Kanit_Regular_20, 0)
การสร้างมิเตอร์เข็ม
import sys
from ili9XXX import ili9341
disp = ili9341(rot=180 , clk=14, cs=15, dc=2, rst=12, power=23, backlight=21, miso=12, mosi=13,width=240, height=320,backlight_on=1)
import lvgl as lv
lv.init()
def set_value(indic, v):
meter.set_indicator_value(indic, v)
#
# A simple meter
#
meter = lv.meter(lv.scr_act())
meter.set_size(180, 180)
meter.center()
#Add a scale first
meter.set_scale_ticks(41, 2, 10, lv.palette_main(lv.PALETTE.GREY))
meter.set_scale_major_ticks(8, 4, 15, lv.color_black(), 10)
#meter.set_style_text_font(lv.font_montserrat_18, 0)
indic = lv.meter_indicator_t()
# Add a blue arc to the start
indic = meter.add_arc(3, lv.palette_main(lv.PALETTE.BLUE), 0)
meter.set_indicator_start_value(indic, 0)
meter.set_indicator_end_value(indic, 20)
# Make the tick lines blue at the start of the scale
indic = meter.add_scale_lines(lv.palette_main(lv.PALETTE.BLUE), lv.palette_main(lv.PALETTE.BLUE), False, 0)
meter.set_indicator_start_value(indic, 0)
meter.set_indicator_end_value(indic, 20)
# Add a red arc to the end
indic = meter.add_arc(3, lv.palette_main(lv.PALETTE.RED), 0)
meter.set_indicator_start_value(indic, 80)
meter.set_indicator_end_value(indic, 100)
# Make the tick lines red at the end of the scale
indic = meter.add_scale_lines(lv.palette_main(lv.PALETTE.RED), lv.palette_main(lv.PALETTE.RED), False, 0)
meter.set_indicator_start_value(indic, 80)
meter.set_indicator_end_value(indic, 100)
# Add a needle line indicator
indic = meter.add_needle_line(4, lv.palette_main(lv.PALETTE.GREY), -10)
meter_value = lv.label(lv.scr_act())
meter_value.set_text('มหาวิทยาลัยมหาสารคาม')
meter_value.align(lv.ALIGN.CENTER, 0, -105)
meter_value.set_style_text_font(lv.Kanit_Regular_16, 0)
meter_value = lv.label(lv.scr_act())
meter_value.set_text('สารสนเทศศาสตร์')
meter_value.align(lv.ALIGN.CENTER, 0, -130)
meter_value.set_style_text_font(lv.Kanit_Regular_20, 0)
meter_value = lv.label(lv.scr_act())
meter_value.set_text("LVGL")
meter_value.align(lv.ALIGN.CENTER, -80, 120)
meter_value.set_style_text_font(lv.Kanit_Regular_16, 0)
meter_value = lv.label(lv.scr_act())
meter_value.set_text("V "+str(lv.version_major())+"."+str(lv.version_minor())+"."+str(lv.version_patch()))
meter_value.align(lv.ALIGN.CENTER, 0, 120)
meter_value.set_style_text_font(lv.Kanit_Regular_16, 0)
meter_value = lv.label(lv.scr_act())
meter_value.set_text("Micropython")
meter_value.align(lv.ALIGN.CENTER, -52, 140)
meter_value.set_style_text_font(lv.Kanit_Regular_16, 0)
meter_value = lv.label(lv.scr_act())
meter_value.set_text(str(sys.implementation[1]))
meter_value.align(lv.ALIGN.CENTER, 25, 140)
meter_value.set_style_text_font(lv.Kanit_Regular_16, 0)
# Create an animation to set the value
a = lv.anim_t()
a.init()
a.set_var(indic)
a.set_values(0, 100)
a.set_time(2000)
a.set_repeat_delay(100)
a.set_playback_time(500)
a.set_playback_delay(100)
a.set_repeat_count(lv.ANIM_REPEAT_INFINITE)
a.set_custom_exec_cb(lambda a,val: set_value(indic,val))
lv.anim_t.start(a)
สร้างปุ่มสีเหลืองขอบฟ้าข้อความ สวัสดีชาวโลก ฟอนต์ Kanit
from ili9XXX import ili9341
import lvgl as lv
disp = ili9341(rot=180 , clk=14, cs=15, dc=2, rst=12, power=23, backlight=21, miso=12, mosi=13,width=240, height=320,backlight_on=1)
lv.init()
scr = lv.obj()
lv.scr_load(scr)
btn = lv.btn(scr)
btn.align(lv.ALIGN.CENTER, 0, 0)
btn.set_style_outline_width(3, lv.STATE.DEFAULT)
btn.set_style_outline_color(lv.color_hex(0xFF0000), lv.STATE.DEFAULT)
# Set focused outline color
btn.set_style_outline_color(lv.color_black(), lv.STATE.FOCUSED)
label = lv.label(btn)
label.set_style_text_font(lv.Kanit_Regular_20, 0)
label.set_text('สวัสดี')
การใช้ Touch Screen บนบอร์ด ESP32 2432S028
» ESP32-2432S028 ทำงานบน ESP32-DOWDQ6 ความถี่สูงสุด 240MHz ออกแบบโดย Adeept in China ติดต่อ support@adeept.com,
» https://www.adeept.com/video/
from xpt2046 import xpt2046
touch = xpt2046(clk=25, mosi=32, miso=39, cs=33, mhz=2)
touch.screen_width=240
touch.screen_height=320
while 1:
print(touch.get_coords())
การสร้างปุ่มและข้อความบนปุ่ม
import lvgl as lv
lv.init()
scr = lv.obj()
btn = lv.btn(scr)
btn.set_size(100, 50) # Set the button size
label = lv.label(btn)
label.set_text("Click me!")
lv.scr_load(scr)
disp.display_name # ILI9341
print(disp.width , disp.height , disp.cs, disp.dc ,disp.power) # 240 320 15 2 23
print(dir(lv.PALETTE))
['RED', 'PINK', 'BROWN', 'DEEP_ORANGE', 'CYAN', 'DEEP_PURPLE', 'BLUE', 'LIME', 'PURPLE', 'YELLOW', 'NONE', 'INDIGO', 'LIGHT_GREEN', 'GREEN', 'AMBER', 'ORANGE', 'GREY', 'TEAL', 'BLUE_GREY', 'LIGHT_BLUE']
» ใช้ขาสัญญาณตามนี้ https://github.com/rzeldent/esp32-smartdisplay/blob/main/include/esp32_smartdisplay.h
คู่มือและโปรแกรมจำลองการทำงาน lvgl
» https://sim.lvgl.io/
» คู่มือไลบรารี่ LVGL version 9
» ตัวอย่าง
บอร์ด ESP32 2432S028 อ่าน QR Code
» การต่อสายสัญญาณ
- ESP32.pin27 -> GM805.Tx
- ESP32.vcc -> GM805.vcc
- ESP32.gnd -> GM805.gnd
import sys
from ili9XXX import ili9341
disp = ili9341(rot=180 , clk=14, cs=15, dc=2, rst=12, power=23, backlight=21, miso=12, mosi=13,width=240, height=320,backlight_on=1)
import lvgl as lv
lv.init()
def set_value(indic, v):
meter.set_indicator_value(indic, v)
#
# A simple meter
#
meter = lv.meter(lv.scr_act())
meter.set_size(180, 180)
meter.center()
#Add a scale first
meter.set_scale_ticks(41, 2, 10, lv.palette_main(lv.PALETTE.GREY))
meter.set_scale_major_ticks(8, 4, 15, lv.color_black(), 10)
#meter.set_style_text_font(lv.font_montserrat_18, 0)
indic = lv.meter_indicator_t()
# Add a blue arc to the start
indic = meter.add_arc(3, lv.palette_main(lv.PALETTE.BLUE), 0)
meter.set_indicator_start_value(indic, 0)
meter.set_indicator_end_value(indic, 20)
# Make the tick lines blue at the start of the scale
indic = meter.add_scale_lines(lv.palette_main(lv.PALETTE.BLUE), lv.palette_main(lv.PALETTE.BLUE), False, 0)
meter.set_indicator_start_value(indic, 0)
meter.set_indicator_end_value(indic, 20)
# Add a red arc to the end
indic = meter.add_arc(3, lv.palette_main(lv.PALETTE.RED), 0)
meter.set_indicator_start_value(indic, 80)
meter.set_indicator_end_value(indic, 100)
# Make the tick lines red at the end of the scale
indic = meter.add_scale_lines(lv.palette_main(lv.PALETTE.RED), lv.palette_main(lv.PALETTE.RED), False, 0)
meter.set_indicator_start_value(indic, 80)
meter.set_indicator_end_value(indic, 100)
# Add a needle line indicator
indic = meter.add_needle_line(4, lv.palette_main(lv.PALETTE.GREY), -10)
meter_value = lv.label(lv.scr_act())
meter_value.set_text('มหาวิทยาลัยมหาสารคาม')
meter_value.align(lv.ALIGN.CENTER, 0, -105)
meter_value.set_style_text_font(lv.Kanit_Regular_16, 0)
meter_value = lv.label(lv.scr_act())
meter_value.set_text('สารสนเทศศาสตร์')
meter_value.align(lv.ALIGN.CENTER, 0, -130)
meter_value.set_style_text_font(lv.Kanit_Regular_20, 0)
a = lv.anim_t()
a.init()
a.set_var(indic)
a.set_values(0, 100)
a.set_time(2000)
a.set_repeat_delay(100)
a.set_playback_time(500)
a.set_playback_delay(100)
a.set_repeat_count(lv.ANIM_REPEAT_INFINITE)
a.set_custom_exec_cb(lambda a,val: set_value(indic,val))
lv.anim_t.start(a)
from machine import Pin, UART
uart = UART(1,baudrate=9600, rx=27, bits=8, parity=None, stop=1)
import time
def read_uart_data(uart, threshold_time):
start_time = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), start_time) < threshold_time * 1000:
if uart.any():
return uart.read()
return None
def show():
meter_value = lv.label(lv.scr_act())
meter_value.set_text('สารสนเทศศาสตร์')
meter_value.align(lv.ALIGN.CENTER, 0, -130)
meter_value.set_style_text_font(lv.Kanit_Regular_20, 0)
while 1:
data = read_uart_data(uart, 2.0)
if data:
show()
meter_value.set_text(data.strip())
meter_value.align(lv.ALIGN.CENTER, 0, 110)
meter_value.set_style_text_font(lv.Kanit_Regular_20, 0)
else:
show()
meter_value.set_text(" ")
meter_value.align(lv.ALIGN.CENTER, 0, 110)
meter_value.set_style_text_font(lv.Kanit_Regular_20, 0)
meter_value.set_text("คิวอาร์ไอโอที")
meter_value.align(lv.ALIGN.CENTER, 0, 110)
meter_value.set_style_text_font(lv.Kanit_Regular_20, 0)
บอร์ด WT32-SC01 และ WT32-SC01 PLUS
» บอร์ด WT32-SC01 เป็นบอร์ดที่มีจอสัมผัสขนาด 3.5 นิ้ว มีสองรุ่น คือ WT32-SC01 และ WT32-SC01 PLUS
» https://www.marutsu.co.jp/contents/shop/marutsu/datasheet/khe_WT32-SC01-PLUS.pdf
» ใช้ downloader tool -> เขียนเฟิร์มแวร์ firmware_s3_thai_font กำหนด [x] DIO -> start
» ใช้ thonny -> เข้าไป micropython -> ดาวน์โหลดไฟล์ไดรเวอร์มาใส่ lib/ -> https://github.com/russhughes/wt32sc01py
» เวอร์ชั่นแรก วันที่ 1 สค พ.ศ. 2565 -> เวอร์ชั่น 2 วันที่ 22 กันยายน พ.ศ. 2565 เพิ่ม firmware burining และ GUI development platform
» Debugging: pin1(5v), pin2(3.3v) , pin3(Tx), pin4(Rx), pin5(Chip Enable), pin6(GPIO0:Boot) , pin7(GPIO14:Gnd)
» Speaker Interface Pin1(SPK+), Pin2(SPK-)
» SD Card: sd_cs(gpio 41), mosi(gpio 40), clk(gpio 39), miso(gpio 38)
» LCD: bl_pwm(gpio 45), reset(gpio 4), rs(gpio0), wr(gpio 47), te(gpio48), db0(gpio 9), db1(gpio 46), db2 (gpio 3), db3(gpio 8), db4(gpio 18), db5(gpio 17), db6(gpio 16), db7(gpio 15), int (gpio 7), sda(gpio 6), scl(gpio 5), rst(gpio 4)
» RS485: pin1( A ), pin2 (B), pin3 (gnd) pin4(+5v), rx(gpio 1), tx(gpio 42), rts (gpio 2)
» Audio lrck(gpio 35), bclk(gpio 36), dout (gpio 37)
» display: st7796ui, 480x320, MCU8080 8bit, RGB565
» Touch: capacitive, FT6336U, I2C
» wt32sc01 plus driver -> https://penfold.owt.com/wt32sc01py/
import wt32sc01py as wt32
import vga2_bold_16x32 as font
tft = wt32.WT32SC01(1)
tft.rotation(0) # 0, 1, 2, 3
tft.clear()
tft.text(font, "OK",10,10, wt32.color565(255,255,255), wt32.color565(0,0,0))
# เขียนข้อความสีขาว พื้นหลังสีเขียว
tft.text(font, "Hello!",10,10, wt32.color565(255,0,0), wt32.color565(0,255,0))
#ค่าการเชื่อมต่อสายสัญญาณ
print(tft.dc, tft.cs, tft.width, tft.rst, tft.bl)
# Pin(0) Pin(6) 320 Pin(4) Pin(45)
# การ fill จะช้ามาก
tft.fill(wt32.color565(0,255,0))
แม่สูตรคูณ
import wt32sc01py as wt32
import vga2_bold_16x32 as font
tft = wt32.WT32SC01(1)
tft.rotation(0) # 0, 1, 2, 3
tft.clear()
for i in range(1,13):
tft.text(font, "3 x %d = %d"%(i,3*i),10,30*i, wt32.color565(255,255,255), wt32.color565(0,0,0))
บอร์ด Freenove-ESP32-Wrover-CAM
การรับ/ส่งข้อมูล ESP32 และ 433mhz LoRa E32-433T20D V8.0 UART
» เชื่อมต่อ ESP32 และ 433mhz LoRa E32-433T20D V8.0 UART
- ESP32.3v3 -> LoRa.3v3
- ESP32.Gnd -> LoRa.Gnd
- ESP32-Uart2.Tx(GPIO17) -> LoRa.Rx
- ESP32-Uart2.Rx(GPIO16) -> LoRa.Tx
» คัดลอกไฟล์ https://github.com/xreef/EByte_LoRa_E32_micropython_library/tree/main/src 1) lora_e32.py 2) lora_e32_constants.py 3) lora_e32_operation_constant.py เก็บใน ESP32 -> โฟลเดอร์ /lib
» ตัวอย่างโค๊ดอยู่ใน https://github.com/xreef/EByte_LoRa_E32_micropython_library/tree/main/examples
ส่ง Broadcast String
from lora_e32 import LoRaE32, Configuration
from machine import UART
from lora_e32_constants import FixedTransmission
from lora_e32_operation_constant import ResponseStatusCode
# Initialize the LoRaE32 module
uart2 = UART(2)
lora = LoRaE32('433T20D', uart2, aux_pin=15, m0_pin=21, m1_pin=19)
code = lora.begin()
print("Initialization: {}", ResponseStatusCode.get_description(code))
# Set the configuration to default values and print the updated configuration to the console
# Not needed if already configured
configuration_to_set = Configuration('433T20D')
configuration_to_set.ADDL = 0x02 # Address of this sender no receiver
configuration_to_set.OPTION.fixedTransmission = FixedTransmission.FIXED_TRANSMISSION
code, confSetted = lora.set_configuration(configuration_to_set)
print("Set configuration: {}", ResponseStatusCode.get_description(code))
# Send a string message (fixed)
message = 'Hello, world!'
code = lora.send_broadcast_message(23, message)
# The receiver must be configured with ADDH = 0x00, ADDL = 0x01, CHAN = 23
print("Send message: {}", ResponseStatusCode.get_description(code))
รับข้อมูลสตริงใน channel
from lora_e32 import LoRaE32, Configuration, BROADCAST_ADDRESS
from machine import UART
import utime
from lora_e32_constants import FixedTransmission
from lora_e32_operation_constant import ResponseStatusCode
# Initialize the LoRaE32 module
uart2 = UART(2)
lora = LoRaE32('433T20D', uart2, aux_pin=15, m0_pin=21, m1_pin=19)
code = lora.begin()
print("Initialization: {}", ResponseStatusCode.get_description(code))
# Set the configuration to default values and print the updated configuration to the console
# Not needed if already configured
configuration_to_set = Configuration('433T20D')
# With BROADCASS ADDRESS we receive all message
configuration_to_set.ADDL = 0x01
configuration_to_set.ADDH = 0x00
configuration_to_set.CHAN = 23
configuration_to_set.OPTION.fixedTransmission = FixedTransmission.FIXED_TRANSMISSION
code, confSetted = lora.set_configuration(configuration_to_set)
print("Set configuration: {}", ResponseStatusCode.get_description(code))
print("Waiting for messages...")
while True:
if lora.available() > 0:
code, value = lora.receive_message()
print(ResponseStatusCode.get_description(code))
print(value)
utime.sleep_ms(100)
การใช้งานเซนเซอร์วัดปุ๋ย NPK Sensor
» เซ็นเซอร์วัดค่า NPK ของดินเหมาะสำหรับตรวจจับปริมาณของไนโตรเจน, ฟอสฟอรัส และโพแทสเซียมในดิน ซึ่งช่วยในการกำหนดความอุดมสมบูรณ์ของดิน และส่งเสริมการประเมินสภาพดินอย่างเป็นระบบ เซ็นเซอร์นี้สามารถฝังอยู่ในดินได้นาน เซ็นเซอร์นี้มีโพรบที่มีคุณภาพสูง ทนต่อสนิม, ทนต่อการกัดกร่อนทางไฟฟ้า, ทนต่อเกลือและด่าง ซึ่งช่วยให้ส่วนโพรบทำงานได้อย่างยาวนาน ดังนั้นจึงเหมาะสำหรับทุกประเภทของดิน นอกจากนี้ยังเหมาะสำหรับการตรวจจับดินด่าง, ดินเปรี้ยว, ดินปลูกพืช, ดินปลูกต้นกล้า และดินมะพร้าวกระสอบได้เป็นอย่างดี
» อุปกรณ์ 1) NPK Sensor 2) RS485 to TTL 3) Micro Controller
» ค่าที่ส่งออกมาคือ ระดับของ NPK (ไนโตรเจน,ฟอสฟอรัส,โพแทสเซียม)
การใช้งานเซนเซอร์วัดออกซิเจนในน้ำ (Dissolved Oxygen Sensor)
» เซ็นเซอร์วัดออกซิเจนละลายในน้ำ (Dissolved Oxygen Sensor) ทำงานตามหลักการของการวัดปริมาณออกซิเจนที่ละลายอยู่ในน้ำ ซึ่งเป็นตัวบ่งชี้สำคัญของคุณภาพน้ำและสิ่งแวดล้อมทางน้ำ ออกซิเจนที่ละลายในน้ำจำเป็นสำหรับการหายใจของสัตว์น้ำและเป็นตัวชี้วัดการมีชีวิตทางน้ำที่สำคัญ หลักการทำงานของเซ็นเซอร์วัดออกซิเจนละลายในน้ำมีดังนี้:
1. Electrochemical Oxygen Sensors: เซ็นเซอร์ชนิดนี้ใช้กระบวนการไฟฟ้าเคมีในการวัดปริมาณออกซิเจนที่ละลายในน้ำ โดยทั่วไปจะมีอิเล็กโทรดสองอันซึ่งเกิดปฏิกิริยาออกซิเดชั่น-รีดักชั่น เมื่อออกซิเจนติดต่อกับอิเล็กโทรด ปฏิกิริยานี้จะทำให้เกิดกระแสไฟฟ้าที่สามารถวัดได้ และกระแสนี้เป็นตัวบ่งชี้ถึงปริมาณออกซิเจนที่ละลายในน้ำ
2. Optical Oxygen Sensors: เซ็นเซอร์ชนิดนี้ใช้หลักการของดาราศาสตร์แสง (luminescence) ในการวัดออกซิเจน โดยมีสารที่สามารถเรืองแสงเมื่อกระตุ้นด้วยแสงที่ความยาวคลื่นเฉพาะ และเมื่อสารนี้ติดต่อกับออกซิเจน การเรืองแสงจะถูกยับยั้งหรือลดลง การวัดความเข้มของแสงที่เรืองแสงจะให้ค่าของปริมาณออกซิเจนที่ละลายในน้ำ
- การใช้ Diode สีฟ้ามีความยาวคลื่น 450-495 nm และสีแดงที่มีความยาวคลื่น 630-700 nm ส่งออกมากระตุ้นสารเชิงซ้อน (sensing foil) เมื่อมีปริมาณอ็อกซิเจนมากจะทำให้การเปล่งแสงจากการกระตุ้นเชิงซ้อนน้อยลง
- Photodiodes หรือ Phototransistors มีความไวต่อช่วงความยาวคลื่นของแสงสีฟ้า
- Color Sensors สามารถตรวจจับได้หลายสีและจะใช้ฟิลม์สีฟ้ากรองเพื่อวัดค่าสีฟิลเตอร์นั้น
- Spectrophotometers ใช้กับงานวิจัยที่ต้องการความละเอียดที่มากยิ่งขึ้น
- อินฟราเรด (IR) มีความยาว 700nm - 1mm มองไม่เห็น เพราะแสงที่มองเห็นคือ (380-700nm) ก) NIR 700-1400nm 2) MIR 1400-3000nm 3) FIR 3000-1um
3. Clark Electrode Oxygen Sensors: เซ็นเซอร์ตามหลักการของ Clark Electrode ใช้เทคนิคปิดผนึกอิเล็กโทรดไว้ในเมมเบรนที่ออกซิเจนสามารถผ่านเข้ามาได้ อิเล็กโทรดนี้จะวัดปริมาณออกซิเจนที่ละลายในน้ำโดยการวัดกระแสไฟฟ้าที่เกิดจากปฏิกิริยาเคมีของออกซิเจนกับสารเคมีบนอิเล็กโทรด
» เซ็นเซอร์วัดออกซิเจนละลายในน้ำสามารถใช้ในหลายๆ สถานการณ์ เช่น การตรวจสอบคุณภาพน้ำในบ่อเลี้ยงปลา การตรวจวิเคราะห์น้ำในโรงงานบำบัดน้ำเสีย หรือในการศึกษาทางนิเวศวิทยาของแหล่งน้ำธรรมชาติ เป็นต้น
การใช้งาน EasyEDA
» EasyEDA ใช้ออกแบบวงจร ทำงาน 1) บนเว็บ easyeda.com 2) บน Desktop Computer
» การซูม: หมุนสกอร์
» การเลื่อน: คลิ๊กขวาแล้วเลื่อนเมาส์
» แถบเครื่องมือด้านขวา: เป็นการตั้งค่าคุณสมบัติเอกสาร ก) background color ข) visible grid ค) grid size ขนาดกริด ง) snap size จ) alt snap (กด alt และเลื่อนวัตถุ)
» แถบ Drawing Tools สำหรับวาด
» แถบ Wiring Tools ใช้ลากสายระหว่างอุปกรณ์ เช่น เครื่องมือลากเส้น, ไฟ 5 โวลต์
» แถบ Sheet1, Sheet2 ด้านล่างเหมือนใน Excel
» เครื่องมือด้านซ้าย Design Manager จัดการอุปกรณ์
» เครื่องมือด้านซ้าย Commonly LIbrary คืออุปกรณ์ที่ใช้งานบ่อย เช่น LED, Transistor , 7-Segment ฯลฯ
» เครื่องมือด้านซ้าย Library จะเป็น online library จำนวนมากให้ใช้งาน ผู้ใช้อื่น ๆ สร้างเอาไว้ มีอุปกรณ์ของบริษัท LCSC Electronics จำหน่ายอุปกรณ์ให้เลือกใช้ได้
» เครื่องมือด้านซ้าย JLCPCB คือ สั่งผลิตจากบริการ JLCPCB
» การหมุนอุปกรณ์ ให้เลือกอุปกรณ์ จากนั้นกดแป้น space bar
» กด w เมื่อต้องการวาดเส้นระหว่างอุปกรณ์
» เพิ่ม Crystal เลือก library -> Crystals/Oscillator -> Crystals -> เลือกรุ่นที่ต้องการ
» เพิ่ม ICSP
การตรวจสอบว่ามี PSRAM (Pseudo Static Random Access Memory) ใน Micropython
» การตรวจสอบว่ามี PSRAM (Pseudo Static Random Access Memory) ในระบบที่ใช้ MicroPython สามารถทำได้โดยการเขียนสคริปต์ที่จะลองเข้าถึงหน่วยความจำ PSRAM และดูว่ามีข้อผิดพลาดหรือไม่ เนื่องจาก MicroPython ไม่มีฟังก์ชันมาตรฐานที่จะบอกว่ามี PSRAM หรือไม่โดยตรง สคริปต์จะขึ้นอยู่กับบอร์ดและการตั้งค่าระบบที่คุณใช้งานอยู่
try:
# สำหรับ ESP32, การใช้งาน PSRAM อาจทำได้ผ่านการเรียกใช้งาน memoryview
# โดยตรงบนบัฟเฟอร์ที่ใหญ่กว่าขนาดของหน่วยความจำภายใน
ram_buffer = bytearray(4 * 1024 * 1024) # สมมติว่าเรามี PSRAM ขนาด 4MB
ram_view = memoryview(ram_buffer)
ram_view[0] = 123 # เขียนค่าลงไปใน PSRAM
print(ram_view[0]) # อ่านค่าที่เขียนไป
print("PSRAM is available!")
except MemoryError:
print("PSRAM is not available or not enough memory to allocate the buffer.")
» เมื่อคุณรันสคริปต์นี้, ถ้าไม่มีข้อผิดพลาด MemoryError แสดงว่าบอร์ดของคุณมี PSRAM และสามารถใช้งานได้ หากมีข้อผิดพลาด MemoryError แสดงว่าไม่มี PSRAM หรือหน่วยความจำที่คุณพยายามจองไม่สามารถใช้งานได้
» สำคัญที่จะต้องทราบว่า, วิธีนี้ไม่ได้รับประกันว่าจะทำงานได้กับทุกบอร์ดที่รัน MicroPython เนื่องจากการใช้งาน PSRAM อาจต้องมีการตั้งค่าหรือการคอนฟิกเฉพาะใน firmware ที่คุณใช้งาน. คุณอาจต้องอ่านเอกสารสำหรับบอร์ดของคุณเพื่อดูวิธีการที่ถูกต้องในการทดสอบ PSRAM.
อื่น ๆ
» บอร์ด IOXESP32
» IOXESP32 ใช้ ESP32 ECO V3 ออกแบบโดย ArtronShop และผลิตโดย บริษัท Gravitech Thai ราคา 275 บาท
» Wifi 2.4GHz และ Bluetooth v4.2
» Flash 4MB SRAM 520kB
» I2C x 2, SPI x2, UART x 3, I2S x 2, ADC 16 channels) DAC x2, CAN x 1, VCC=3.3v
» ขาใช้งานตรงกับ Node32U, Node32Lite, NodeMCU-32S
» maxpromer เป็นคนออกแบบ IOXESP32 ด้วย EasyEDA ในปี ค.ศ. 2020 -> https://github.com/maxpromer
» บริษัท artronshop.co.th พัฒนาบอร์ดเพื่อจำหน่ายด้าน maker -> https://www.artronshop.co.th/article
ESP32-S2 Mini
» ESP32-S2 Mini เป็นรุ่นย่อยของชิป ESP32-S2 ซึ่งเป็นชิปไมโครคอนโทรลเลอร์ที่พัฒนาโดย Espressif Systems ชิป ESP32-S2 เป็นส่วนหนึ่งของซีรีย์ ESP32 ซึ่งเป็นที่รู้จักในด้านการเชื่อมต่อ Wi-Fi และความสามารถในการเขียนโปรแกรมหลากหลายแพลตฟอร์ม
» โดยทั่วไป, ESP32-S2 Mini มีคุณสมบัติเหล่านี้:
1. Wi-Fi แบบเดี่ยว: ชิปมีการเชื่อมต่อ Wi-Fi ที่ให้การสื่อสารไร้สายแบบ 2.4 GHz.
2. หน่วยประมวลผล: มักจะมี CPU แบบ Xtensa® 32-bit LX7 ซึ่งให้ประสิทธิภาพการประมวลผลที่ดี.
3. หน่วยความจำและที่เก็บข้อมูล: มีหน่วยความจำแบบ SRAM และมีตัวเลือกในการเพิ่ม flash memory ภายนอก.
4. การเชื่อมต่อ: ชิปนี้มีหลากหลายพอร์ตเชื่อมต่อ เช่น GPIO, SPI, UART, I2C, และอื่นๆ.
5. ความสามารถในการเขียนโปรแกรม: สามารถเขียนโปรแกรมได้ผ่านทาง Arduino IDE, ภาษา C/C++ ใน ESP-IDF, และแพลตฟอร์มอื่นๆ.
6. ขนาดเล็กและประหยัดพลังงาน: ดีไซน์เพื่อการใช้งานที่ต้องการขนาดเล็กและการบริโภคพลังงานต่ำ.
» ESP32-S2 Mini เหมาะสำหรับโปรเจ็กต์ DIY, การพัฒนา IoT หรือการใช้งานที่ต้องการขนาดเล็กและการเชื่อมต่อ Wi-Fi.
» การเขียน micropython ให้ใช้ thonny เวอร์ชั่น thonny-4.1.3-windows-portable หรือใหม่กว่า
» ต่อสาย usb type-c -> option -> installation -> เลือก ESP32 รุ่น S2 -> เลือก firmware ในรายการ -> เขียน Firmware
» การใช้งานด้วย Thronny เหมือนการใช้งานทั่วไป
การตรวจสอบ Loopback บน ESP32-S2 Mini
» การเชื่อมต่อ TX pin และ RX pin บนบอร์ด ESP32-S2 เดียวกันสำหรับทดสอบการส่งและรับข้อมูลในเวลาเดียวกันนั้นเป็นไปได้ และเป็นวิธีที่ใช้ในการทดสอบโปรโตคอล UART บนบอร์ดเดียว. วิธีนี้เรียกว่า "loopback test" หรือการทดสอบลูปแบ็ก.
» ในการทดสอบลูปแบ็ก, ข้อมูลที่ส่งออกไปจาก TX pin จะถูกส่งกลับเข้ามาที่ RX pin ของบอร์ดเดียวกัน. นี่เป็นวิธีที่ดีในการทดสอบว่า UART กำลังทำงานอย่างถูกต้องหรือไม่ โดยไม่ต้องใช้อุปกรณ์ภายนอก.
» การส่งและรับข้อมูลในเวลาเดียวกันในรูปแบบนี้ไม่ใช่การสื่อสารแบบ full-duplex (ที่สามารถส่งและรับข้อมูลพร้อมกันได้อย่างแท้จริง) แต่เป็นการทดสอบการส่งและรับข้อมูลเป็นครั้งคราว.
» เชื่อมสายสัญญาณจาก pin 17 ไปยัง p 12 จากนั้นรันโค๊ดต่อไปนี้
from machine import UART, Pin
import time
# กำหนดขา GPIO สำหรับ TX และ RX
tx_pin = Pin(17) # GPIO 17 เป็น TX
rx_pin = Pin(16) # GPIO 16 เป็น RX
# สร้างอินสแตนซ์ของ UART โดยกำหนดบอดเรตและขา TX และ RX
uart = UART(1, baudrate=9600, tx=tx_pin, rx=rx_pin)
# ส่งและรับข้อมูล
while True:
uart.write('Hello ESP32-S2')
time.sleep(1)
if uart.any():
data = uart.read()
print("Received:", data)
การใช้งาน GM805 2D Barcode Scanner
GM805-S และ GM805-L ผลิตโดยบริษัท Gangzhou Grow Technology Co., Ltd (www.hzgrow.com) สองรุ่นนี้ต่างกันที่เลนส์และระยะการอ่าน QR Code
- GM805-S ระยะอ่าน 5-30cm
- GM805-L ระยะาน 7-50cm
» ซีรีส์ GM805 มีรุ่น GM805-S และ GM805-L ความแตกต่างเพียงอย่างเดียวระหว่าง GM805-S และ GM805-L คือเลนส์ ระยะอ่านของเลนส์ GM805-S คือ 5-30 ซม. ในขณะที่ระยะอ่านของเลนส์ GM805-L คือ 7-50 ซม. (ข้อมูลจริงขึ้นอยู่กับขนาดและเนื้อหาของรหัส)
» โมดูลอ่านบาร์โค้ดของซีรีส์ GM805 เป็นสแกนเนอร์ที่มีประสิทธิภาพสูง สามารถอ่านบาร์โค้ด 1 มิติได้ง่าย และอ่านบาร์โค้ด 2 มิติด้วยความเร็วสูง นอกจากนี้ยังมีความเร็วในการสแกนสูงสำหรับรหัสเส้นตรง แม้กระทั่งบาร์โค้ดบนกระดาษหรือหน้าจอ โมดูลอ่านบาร์โค้ดของซีรีส์ GM805 เป็นอัลกอริทึมการถอดรหัสบาร์โค้ดขั้นสูงที่พัฒนาขึ้นบนอัลกอริทึมการรู้จำภาพ ซึ่งสามารถอ่านบาร์โค้ดได้ง่ายและแม่นยำ ทำให้การพัฒนาต่อยอดง่ายขึ้น
» การเชื่อมต่อสายสัญญาณ
- UART 9600bps, Data format: data (8 bit), stop( 1 bit), No parity bit
- Controller MCU 3.3v ต่อตรงเข้ากับ Tx, Rx ได้โดยตรง
- ต่อกับคอมพิวเตอร์ต้อใช้ RS232 level converter chip
» คู่มือ articles/iot/qr/GM805-V1.2.pdf
from machine import Pin, UART
from time import sleep #sleep_us
uart = UART(1,baudrate=9600, rx=16, bits=8, parity=None, stop=1)
while True:
if uart.any():
data = uart.read()
print(data)
WT32-SC01 Plus - ESP32 dev board With 3.5 Inch LCD Touch Screen
» ใช้ ESP32-S3
» ESP32-S3 เป็นไมโครคอนโทรลเลอร์ที่พัฒนาโดยบริษัท Espressif Systems ซึ่งเป็นรุ่นที่ปรับปรุงใหม่จากชิป ESP32 ที่ได้รับความนิยมอย่างสูง มันเป็นชิปที่มาพร้อมกับ Wi-Fi และ Bluetooth แบบ dual-mode (BLE และ Bluetooth Classic) และมีคุณสมบัติพิเศษที่เพิ่มเข้ามาเช่นการสนับสนุนการประมวลผล AI ระดับขอบ (edge computing) และการประมวลผลสัญญาณดิจิตอล (DSP) ที่ปรับปรุงใหม่
» ESP32-S3 ออกแบบมาเพื่อการประยุกต์ใช้งานที่ต้องการประสิทธิภาพการประมวลผลที่สูงกว่าเดิมและการสนับสนุนคุณสมบัติการเชื่อมต่อที่เหนือกว่า เช่น การใช้งานในอุปกรณ์สมาร์ทโฮม, อุปกรณ์สวมใส่ได้, อุปกรณ์ IoT ที่มีความสามารถในการประมวลผลข้อมูลอัจฉริยะ และอื่นๆ นอกจากนี้ยังมีการสนับสนุนสำหรับการเข้ารหัสและการถอดรหัสภาพและเสียงที่ปรับปรุงใหม่ ทำให้เหมาะสำหรับการใช้งานที่เกี่ยวข้องกับมัลติมีเดีย
» รายละเอียดทางเทคนิคของ ESP32-S3 มักจะรวมถึง:
- ซีพียู Xtensa® 32-bit LX7 dual-core ที่สามารถทำงานได้สูงสุดที่ประมาณ 240 MHz
- เนื้อที่ RAM และ ROM ที่ใหญ่กว่าเมื่อเทียบกับรุ่นก่อน
- การสนับสนุนการเชื่อมต่อ Wi-Fi 802.11 b/g/n และ Bluetooth 5 (LE)
- สามารถสนับสนุนการทำงานด้าน AI ด้วย NPU (Neural Processing Unit)
- หน่วยความจำ PSRAM แบบเสริมสำหรับการประมวลผลข้อมูลขนาดใหญ่
- หน่วยความจำ Flash ที่สามารถเพิ่มเติมได้ผ่าน SPI
- การสนับสนุนการทำงานของหลากหลายเซ็นเซอร์และอุปกรณ์นอกบอร์ดผ่าน GPIO
» ESP32-S3 ยังมีความยืดหยุ่นสูงในการพัฒนาด้วยการสนับสนุนจากการพัฒนาซอฟต์แวร์เช่น
- Arduino IDE, Espressif IoT Development Framework (ESP-IDF), และ MicroPython ทำให้เป็นที่นิยมในหมู่ผู้พัฒนาและนักสร้างสรรค์โปรเจ็กต์ DIY.
การใช้งานสวิตช์ระดับน้ำแบบไม่สัมผัส Xkc-y21
» เป็นเซนเซอร์แบบ NPN โดยจะส่งสัญญาณเป็น Gnd (0v) เมื่อพบว่ามีน้ำในระดับเดียวกับสวิตช์ แรงดัน 5vdc
» มีจำหน่าย 1) XKC-Y25-v จะมีผลลัพธ์เป็น 0/1 2) รุ่น NPN และ PNP 3) XKC-Y25-RS485
» เวลาตอบสนอง 500ms , อุณหภูมิน้ำ -20 ถึง 105 องศาเซลเซียส ระยะห่างจากผนังและน้ำ 2 cm , ความผิดพลาดของระดับน้ำ ~1.5 mm
» สาย mode ถ้าต่อเข้ากับ 1) Gnd จะมีเอาพุตแบบ NC (Normal Close) คือเท่าแรงดันที่จ่ายให้ MCU ~ 3.3 - 5vdc 2) ถ้าสาย mode ไม่มีต่อ เอาพุตจะเป็น NO (Normal Open)
» ปล. สามารถใช้ IR Sensor ส่งคลืน Infrared และวัดพลังงานที่สะท้อนกลับมาได้
» ต้องตรวจสอบว่าบอร์ดที่คุณใช้งานรองรับการตั้งค่า pull-up สำหรับ GPIO ที่คุณต้องการใช้งาน และหมายเลขพินที่ใช้ในโค้ดอาจแตกต่างกันไปในแต่ละบอร์ด
from machine import Pin
# ฟังก์ชัน callback ที่จะถูกเรียกเมื่อมี interrupt
def on_interrupt(pin):
print("Interrupt detected on pin:", pin)
# กำหนด GPIO 3 ให้เป็น input พร้อม pull-up
pin = Pin(3, Pin.IN, Pin.PULL_UP)
# กำหนดให้เรียกฟังก์ชัน callback เมื่อตรวจจับได้ falling edge
pin.irq(trigger=Pin.IRQ_FALLING, handler=on_interrupt)
» Pin.IRQ_FALLING หมายถึงการตรวจจับการเปลี่ยนแปลงของสัญญาณจากสูงไปต่ำ (falling edge).
» handler=on_interrupt กำหนดให้ฟังก์ชัน on_interrupt เป็นฟังก์ชัน callback ที่จะถูกเรียกเมื่อมี interrupt.
» หมายเหตุ: ในการใช้งาน interrupt, ควรหลีกเลี่ยงการทำงานที่ใช้เวลานานหรือการทำงานที่ซับซ้อนในฟังก์ชัน callback เพราะอาจส่งผลต่อการทำงานของระบบโดยรวม. นอกจากนี้, โปรดตรวจสอบว่าบอร์ดที่คุณใช้รองรับการใช้งาน interrupt กับ GPIO ที่คุณเลือก.
การใช้งาน SquareLine Studio ร่วมกับ MicroPython และ ESP32 เพื่อใช้งานกับ LVGL
» การใช้งาน SquareLine Studio ร่วมกับ MicroPython และ ESP32 เพื่อใช้งานกับ LVGL (Light and Versatile Graphics Library) ทำได้โดยการสร้างอินเทอร์เฟซผู้ใช้ (UI) ด้วย SquareLine Studio และจากนั้นนำโค้ดที่สร้างได้มาใช้ในโปรเจ็กต์ MicroPython บน ESP32
» ขั้นตอนการใช้งาน SquareLine Studio กับ MicroPython + ESP32
- การติดตั้ง SquareLine Studio:
- ดาวน์โหลดและติดตั้ง SquareLine Studio จากเว็บไซต์อย่างเป็นทางการของ SquareLine Studio.
» การออกแบบ UI ด้วย SquareLine Studio:
- เปิด SquareLine Studio และเริ่มต้นการสร้างอินเทอร์เฟซผู้ใช้ (UI) ของคุณ. คุณสามารถใช้วิดเจ็ตและองค์ประกอบต่างๆ ที่มีให้เลือกมากมาย.
- ทำการออกแบบ UI ให้ตรงกับความต้องการของโปรเจกต์ของคุณ.
» การส่งออกโค้ดจาก SquareLine Studio:
- หลังจากที่ออกแบบ UI เสร็จสมบูรณ์, ให้ทำการส่งออกโค้ดจาก SquareLine Studio. โค้ดนี้จะถูกใช้ในโปรเจกต์ MicroPython ของคุณ.
» การตั้งค่าเพื่อใช้งาน LVGL บน ESP32 ด้วย MicroPython:
- ตรวจสอบให้แน่ใจว่า MicroPython ที่ติดตั้งบน ESP32 ของคุณรองรับ LVGL. บางเวอร์ชันของ MicroPython มีการรวม LVGL มาให้แล้ว.
- ถ้าจำเป็น, คุณอาจต้องติดตั้งไลบรารี LVGL เพิ่มเติมบน ESP32.
- การนำโค้ดที่ส่งออกมาใช้ในโปรเจกต์ MicroPython:
» นำโค้ดที่ได้จาก SquareLine Studio ไปใช้ในโปรเจกต์ MicroPython ของคุณบน ESP32.
» ทำการปรับแต่งโค้ดตามความจำเป็นเพื่อให้สอดคล้องกับโครงสร้างโปรแกรมและฮาร์ดแวร์ของคุณ.
» การทดสอบและการปรับแต่ง:
» อัปโหลดโค้ดลงใน ESP32 และทำการทดสอบ UI ที่คุณได้ออกแบบมา.
» ทำการปรับแต่งและแก้ไขปัญหาที่อาจเกิดขึ้นจนกว่า UI จะทำงานได้อย่างลื่นไหลและตรงตามความต้องการ.
การควบคุม Stepper Motor ด้วย A4988 และ DRV8825
» A4988: สามารถรองรับการควบคุมในรูปแบบ microstepping ได้สูงสุดถึง 1/16 step.
» DRV8825: สามารถรองรับการควบคุมในรูปแบบ microstepping ได้สูงสุดถึง 1/32 step ซึ่งทำให้มีความละเอียดในการควบคุมที่สูงกว่า A4988.
» แรงดันและกระแสไฟฟ้าสูงสุด:
- A4988: ทำงานได้ดีที่แรงดันประมาณ 8V ถึง 35V และสามารถจัดการกระแสได้สูงสุดประมาณ 1A โดยไม่ต้องใช้ heat sink, และสูงสุด 2A กับ heat sink.
- DRV8825: สามารถจัดการกับแรงดันไฟฟ้าได้ระหว่าง 8.2V ถึง 45V และกระแสไฟฟ้าสูงสุดถึง 1.5A โดยไม่ต้องใช้ heat sink, และสูงสุด 2.2A กับ heat sink.
» การจัดการความร้อน:
- A4988 อาจจำเป็นต้องใช้ heat sink หรือระบบระบายความร้อนในการใช้งานที่กระแสไฟฟ้าสูง.
- DRV8825 มีประสิทธิภาพในการจัดการความร้อนที่ดีกว่า แต่ยังคงแนะนำให้ใช้ heat sink ในการใช้งานที่กระแสไฟฟ้าสูง.
» การลดสัญญาณรบกวนและการสั่นสะเทือน:
- DRV8825 มีการปรับปรุงในแง่ของการลดสัญญาณรบกวนและการสั่นสะเทือน เมื่อเทียบกับ A4988.
» ความเข้ากันได้:
- ทั้งสองไดร์เวอร์มีรูปแบบที่คล้ายกันและสามารถถูกใช้แทนกันได้ในหลายๆ โปรเจกต์. อย่างไรก็ตาม, อาจต้องมีการปรับแต่งการตั้งค่าในซอฟต์แวร์หรือฮาร์ดแวร์เล็กน้อยเมื่อเปลี่ยนจากหนึ่งไดร์เวอร์ไปยังอีกหนึ่งไดร์เวอร์.
การใช้งาน YOLOv8
» YOLO, หรือ "You Only Look Once", เป็นระบบการตรวจจับวัตถุแบบเรียลไทม์ที่ใช้งานง่ายและมีประสิทธิภาพสูงในการวิเคราะห์ภาพและวิดีโอ. มันถูกพัฒนาขึ้นเพื่อสามารถระบุและจำแนกวัตถุต่างๆ ในภาพหรือวิดีโอได้อย่างรวดเร็ว. ระบบ YOLO มีคุณสมบัติหลักดังนี้:
- การตรวจจับแบบเรียลไทม์: YOLO สามารถประมวลผลภาพหรือวิดีโอและตรวจจับวัตถุในเวลาจริงได้.
- การทำงานอย่างมีประสิทธิภาพ: แทนที่จะแยกการวิเคราะห์ภาพออกเป็นหลายขั้นตอน, YOLO วิเคราะห์ภาพทั้งหมดในเวลาเดียว (หรือ "look once") ซึ่งทำให้มีความเร็วและประสิทธิภาพสูง.
- ความแม่นยำ: แม้ว่าในเวอร์ชันแรกๆ ความแม่นยำของ YOLO อาจไม่สูงเท่าระบบการตรวจจับวัตถุอื่นๆ, แต่ด้วยการพัฒนาต่อเนื่อง, ระบบ YOLO ได้ปรับปรุงความแม่นยำอย่างมากในเวอร์ชันหลังๆ.
- การใช้งานที่หลากหลาย: YOLO ถูกใช้ในหลากหลายสถานการณ์ เช่น ระบบเฝ้าระวัง, การวิเคราะห์วิดีโอ, การจดจำป้ายทะเบียนรถยนต์, และอื่นๆ.
» ติดตั้ง pip install ultralytics=8.0.20
from ultralytics import YOLO
model=YOLO('yolov8n.pt') #yolov8n-seg.pt,
# results = model.predict("dog_bike_car.jpg")
results=model('dog_bike_car.jpg',verbose=False)
# จำนวนวัตถุที่ค้นพบ 4 ชิ้นภายในภาพ dog_bike_car.jpg
result = results[0]
len(result.boxes)
# result เป็น
for box in result.boxes:
class_id = result.names[box.cls[0].item()]
cords = box.xyxy[0].tolist()
cords = [round(x) for x in cords]
conf = round(box.conf[0].item(), 2)
print("Object type:", class_id)
print("Coordinates:", cords)
print("Probability:", conf)
print("---")
ผลลัพธ์วัตถุในไฟล์ภาพ: dog_bike_car.jpg
Object type: dog
Coordinates: [131, 220, 309, 542]
Probability: 0.91
---
Object type: bicycle
Coordinates: [131, 140, 568, 421]
Probability: 0.89
---
Object type: car
Coordinates: [467, 75, 692, 172]
Probability: 0.53
---
Object type: truck
Coordinates: [467, 75, 693, 172]
Probability: 0.51
---
การเทรนวัตถุใหม่ด้วย Yolov8
» ติดตั้ง labelimg ด้วยคำสั่ง pip install labelimg
» เรียกคำสั่ง labelimg
» เปิดไฟล์วีดีโอ -> เลือก yolo -> Create RectBox ->
» การ detect เรียกคำสั่ง yolo task-detect mode-predict model-yolov8n.py conf=0.25 source="http://abc.com/dog.jpg" save=True
» การ train เรียกคำสั่ง yolo task=detect mode=train model=yolov8s.pt data=/datasets/data.yaml epochs=100 imgs=800 plots=True
- จากนั้นจะได้ผลลัพธ์ไฟล์ runs/detect/train/weight/best.pt
» ศึกษาเพิ่มเติม : https://youtu.be/ARHjcG509jo
การใช้งาน cvzone
» cvzone เป็น library ที่ใช้งานร่วมกับ Python ซึ่งทำงานเกี่ยวกับการประมวลผลภาพและวิดีโอ ถูกออกแบบมาเพื่อทำให้งานที่เกี่ยวข้องกับ Computer Vision ง่ายขึ้นและเข้าถึงได้มากขึ้นสำหรับนักพัฒนา และมีคุณสมบัติที่หลากหลายเกี่ยวกับการตรวจจับและการติดตามวัตถุ, การแยกแยะสี, การทำงานกับมือและท่าทาง, และอื่นๆ.
» คุณสมบัติของ cvzone ได้แก่:
- การตรวจจับวัตถุและการติดตาม (Object Detection and Tracking): cvzone มีความสามารถในการตรวจจับและติดตามวัตถุต่างๆ ในภาพหรือวิดีโอ
- การตรวจจับมือและท่าทาง (Hand Detection and Gesture Recognition): มีความสามารถในการตรวจจับมือและเข้าใจท่าทางของมือ, ซึ่งมีประโยชน์ในการสร้างปฏิสัมพันธ์ที่อิงกับท่าทาง
- การประมวลผลภาพ (Image Processing): สามารถใช้ cvzone ในการประมวลผลภาพด้วยการใช้งานต่างๆ เช่น การปรับแต่งสี, การตรวจจับขอบ, และอื่นๆ
- ความเข้ากันได้กับ OpenCV: cvzone ได้รับการพัฒนาให้ทำงานร่วมกับ OpenCV, ซึ่งเป็นห้องสมุดที่นิยมสำหรับการประมวลผลภาพและวิดีโอ
- เรียบง่ายและเข้าถึงได้ง่าย: ห้องสมุดถูกออกแบบมาเพื่อทำให้การทำงานกับ Computer Vision เป็นเรื่องที่เข้าใจง่ายและเข้าถึงได้สำหรับนักพัฒนาที่มีระดับประสบการณ์ต่าง ๆ
- cvzone เหมาะสำหรับโปรเจ็กต์ที่ต้องการความสามารถในการประมวลผลภาพและวิดีโอที่มีความซับซ้อนน้อยกว่า, หรือสำหรับผู้ที่เพิ่งเริ่มต้นเรียนรู้เกี่ยวกับ Computer Vision และต้องการเครื่องมือที่ใช้งานง่าย
การตรวจจับมือด้วย cvzone
import cv2
from cvzone.HandTrackingModule import HandDetector
# กำหนดการใช้งานกล้อง
cap = cv2.VideoCapture(0)
# สร้างตัวตรวจจับมือ
detector = HandDetector(detectionCon=0.8, maxHands=2)
while True:
# อ่านภาพจากกล้อง
success, img = cap.read()
# ค้นหามือในภาพ
hands, img = detector.findHands(img)
# หากตรวจพบมือ
if hands:
# วนซ้ำทุกมือที่ตรวจพบ
for hand in hands:
# ข้อมูลที่เกี่ยวข้องกับมือ
lmList, bboxInfo = hand["lmList"], hand["bbox"]
# ทำงานกับข้อมูลนี้ตามต้องการ, อาทิเช่น พิมพ์พิกัด
print(lmList)
# แสดงผลภาพ
cv2.imshow("Image", img)
# หากกดปุ่ม 'q' จะหยุดการทำงาน
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# ปิดการใช้งานกล้องและหน้าต่าง
cap.release()
cv2.destroyAllWindows()
การตรวจจับท่าทางของมือเพื่อควบคุมวิดีโอเล่นหรือหยุด
import cv2
from cvzone.HandTrackingModule import HandDetector
import cvzone
# กำหนดการใช้งานกล้อง
cap = cv2.VideoCapture(0)
# สร้างตัวตรวจจับมือ
detector = HandDetector(detectionCon=0.8)
# โหลดวิดีโอ
videoPlayer = cvzone.VideoPlayer("path/to/video.mp4")
playing = False
while True:
# อ่านภาพจากกล้อง
success, img = cap.read()
# ค้นหามือในภาพ
hands, img = detector.findHands(img)
# หากตรวจพบมือ
if hands:
hand = hands[0]
fingers = detector.fingersUp(hand)
# หากยกนิ้วชี้และโป้ง ให้เปลี่ยนสถานะการเล่นวิดีโอ
if fingers[1] and fingers[0]:
playing = not playing
if playing:
img = videoPlayer.nextFrame(img)
else:
videoPlayer.pause()
# แสดงผลภาพ
cv2.imshow("Image", img)
# หากกดปุ่ม 'q' จะหยุดการทำงาน
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# ปิดการใช้งานกล้องและหน้าต่าง
cap.release()
cv2.destroyAllWindows()
การคำนวณความเร็วของวัตถุที่เคลื่อนไหวและนับจำนวนวัตถุในวิดีโอ
» อ่านวิดีโอ: ใช้ cv2.VideoCapture เพื่ออ่านฟรอมเฟรมของวิดีโอ.
» ตรวจจับวัตถุ: ใช้ตัวตรวจจับวัตถุ (เช่น YOLO, SSD หรืออื่นๆ) เพื่อตรวจจับวัตถุในแต่ละเฟรม.
» ติดตามวัตถุ: ใช้วิธีการติดตามวัตถุ (เช่น KCF, CSRT หรือ MOSSE tracker ใน OpenCV) เพื่อติดตามวัตถุที่ตรวจจับได้.
» คำนวณความเร็ว: คำนวณความเร็วของวัตถุโดยใช้การเปลี่ยนแปลงของตำแหน่งวัตถุในเวลาที่ผ่านไป.
» นับจำนวนวัตถุ: นับจำนวนวัตถุที่ตรวจจับได้.
import cv2
import time
from cvzone.ObjectDetectionModule import Detector
cap = cv2.VideoCapture("path/to/video.mp4")
# ตั้งค่าตัวตรวจจับ
detector = Detector("path/to/yolov3.weights", "path/to/yolov3.cfg", "path/to/coco.names")
# ตัวแปรสำหรับเก็บข้อมูลของวัตถุ
objects_prev_frame = {}
object_speed = {}
frame_id = 0
fps = cap.get(cv2.CAP_PROP_FPS)
frame_time = 1/fps
while True:
success, img = cap.read()
if not success:
break
img, bboxs = detector.findObjects(img)
objects_current_frame = {}
for bbox in bboxs:
x, y, w, h, id, index = bbox
center_x, center_y = x + w // 2, y + h // 2
if index in objects_prev_frame:
prev_center_x, prev_center_y = objects_prev_frame[index]
distance = ((center_x - prev_center_x) ** 2 + (center_y - prev_center_y) ** 2) ** 0.5
speed = (distance / frame_time) / fps
object_speed[index] = speed
else:
object_speed[index] = 0
objects_current_frame[index] = (center_x, center_y)
cv2.putText(img, f"ID: {index} Speed: {object_speed[index]:.2f}", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
objects_prev_frame = objects_current_frame.copy()
frame_id += 1
cv2.imshow("Image", img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
การพิมพ์สลิปด้วยเครื่อง Thermal Printer RS232-TTL
» เครื่องพิมพ์ความร้อนแบบฝังใช้เทคโนโลยีความร้อน ซึ่งไม่จำเป็นต้องใช้หมึกหรือผงหมึก มีประสิทธิภาพที่มั่นคงและขนาดที่เล็กกระทัดรัด ทำให้เหมาะสมกับการใช้งานในหลากหลายสถานการณ์ เช่น ในเครื่องใช้ทางการแพทย์ การตรวจสอบอาหาร เครื่องจุดขาย และตู้ล็อกเกอร์ เครื่องพิมพ์เหล่านี้สามารถพบเห็นได้ในตู้เอทีเอ็ม ตู้ล็อกเกอร์ เครื่องจุดขายและตาชั่งอิเล็กทรอนิกส์ในซูเปอร์มาร์เก็ต เครื่องพิมพ์เหล่านี้ใช้ไฟฟ้าแรงดันกว้าง 5-9V โดยที่แรงดันไฟฟ้าที่สูงขึ้นจะทำให้ภาพพิมพ์ชัดเจนยิ่งขึ้น และรองรับกับม้วนกระดาษความร้อนที่มีความกว้าง 58MM นอกจากนี้ยังสามารถให้บริการพิมพ์ได้ยาวนานถึง 50 กิโลเมตร
» เครื่องพิมพ์เหล่านี้รองรับกับระบบ Arduino, Raspberry Pi และ Windows โดยใช้ชุดคำสั่งที่มีให้ เราสามารถส่งคำสั่งผ่านพอร์ตอนุกรม USB หรือ TTL เพื่อให้เครื่องพิมพ์ทำการพิมพ์ข้อความ ตัวอักษร บาร์โค้ด รหัส QR และภาพขาวดำตามคำสั่งที่ได้รับ นอกจากนี้ เรายังสามารถเชื่อมต่อกับบอร์ดควบคุม Arduino หรือ Raspberry Pi ผ่านพอร์ตอนุกรม และร่วมกับเซ็นเซอร์ต่างๆ เพื่อสร้างเครื่องมือทางปฏิบัติการได้หลากหลาย เช่น ตาชั่งอิเล็กทรอนิกส์ อุปกรณ์วัดค่าความดันโลหิต อุปกรณ์วิเคราะห์สารประกอบในดิน และกล้องบันทึกการขับขี่ นอกจากนี้ เรายังสามารถสร้างเครื่องพิมพ์ตั๋วขนาดเล็กของตัวเองได้ โดยเนื้อหาบนตั๋วสามารถกำหนดเองได้ และหลังจากการพัฒนาเพิ่มเติม เรายังสามารถทำการพิมพ์แบบรีโมทได้อีกด้วย
» CircuitPython and Python
การใช้งาน SimpleFOC Mini
» SimpleFOC เป็นบอร์ดสำหรับขับมอเตอร์ BLDC
» ไลบรารี่ https://github.com/simplefoc/
» https://docs.simplefoc.com/mini_connect_hardware
import simplefoc
commander = simplefoc.commander.serial("COM1", 115200)
commander.connect()
motor = commander.full_control('M')
motor.set_target(10)
motor.set_limits(max_voltage=12.0, max_current=1.0, max_velocity=20.0)
motor.set_mode(MotionControlType.torque, TorqueControlType.voltage)
motor.enable()
วงจรหน่วงเวลา
» ชิปทริกเกอร์หน่วงเวลา มัลติฟังก์ชั่น 10 ชิ้น จับเวลา IC Timing 2s-1000h
» แหล่งข้อมูล: shopee
บอร์ด P10 Matrix Panel Shield Arduino DMD2 Libraries
» P10 Matrix Panel:
- P10 คือ LED Matrix Panel ที่มี "Pixel Pitch" 10 มิลลิเมตร หมายความว่าระยะห่างระหว่างแต่ละ LED ในแผงคือ 10 มิลลิเมตร
- ถูกใช้ในการสร้างจอแสดงผลขนาดใหญ่ ทั้งในร่มและกลางแจ้ง สำหรับการแสดงข้อความ, ภาพกราฟิก, หรือแม้กระทั่งวิดีโอ
» DMD2 Libraries
- DMD2 (Dot Matrix Display 2) Libraries เป็นชุดไลบรารีสำหรับ Arduino ที่ใช้ในการควบคุมและแสดงผลบน Dot Matrix Displays และ LED Panels
- ไลบรารีนี้ช่วยให้นักพัฒนาสามารถเขียนโค้ดสำหรับควบคุม LED Panels ได้ง่ายขึ้น โดยมีฟังก์ชันสำหรับการจัดการข้อความ, ภาพกราฟิก และอื่นๆ
» โปรแกรม HD 2018 สำหรับเขียนตัวอักษรลงบนจอ P10 Led Matrix
» ป้าย P10 มีระยะห่างหลอด LED 10มม มีจำหน่ายสีแดง เหลือง เขียว ขาว และ RGB
» บอร์ดควบคุมจะมี Slot 1, 2, 3, 4 .. 16 สำหรับควบคุมแต่ละชั้น หนึ่งชั้นสามารถต่ออนุกรมได้หลายตัว
» โปรแกรม HD2018
- ปรับความสว่าง -> Operation -> Brightness Settings -> ปรับ custom 50% -> ok -> กดปุ่ม U Disk เพื่อบันทึกลง Flash Drive
» P10 led ใช้ไอซี 74HC595 แปลงอนุกรมเป็นขนาน เพื่อขยาย I/O -> https://youtu.be/RMLYRQvhhVs
การใช้งาน Lightburn เพื่องานเลเซอร์ตัดชิ้นงาน
» ดาวน์โหลด Lightburn-v1.0.04 (ใส่นามสกุลไฟล์)
» การแปลงภาพเป็นเวกเตอร์ 1) File->Import-> ไฟล์ภาพ 2) เลือกภาพ -> Tools -> Trace Image (Alt+t) -> ok -> ลบภาพ ให้เหลือแต่ลายเส้นที่ต้องการ
» ขนาดชิ้นงาน ให้ปรับภาพวัตถุให้มีขนาดที่ต้องการโดยดูไม้บรรทัดที่ด้านซ้ายและล่าง
» หน้าต่างการพิมพ์ จะมีสัญลักษณ์ หยุด (stop) หยุดชั่วคราว (pause) สตาร์ท (start)
- เลือกเครื่องพิมพ์ ให้เลือก COM Port ที่เชื่อมต่อกับเครื่องพิมพ์ -> กำหนดขนาดกว้างxยาว ให้ใส่ตามต้องการเพราะซอฟต์รองรับความกว้างและยาวไม่จำกัด
» หน้าต่าง move จะมีรูปไอคอน < > ^ ฯลฯ และมี set origin, clear origin -> ให้เลื่อนหัวเลเซอร์ไปยังตำแหน่งเริ่มต้น (ใช้มือเลื่อนได้เลยที่เครื่อง) -> กดปุ่ม clear origin -> กดปุ่ม set origin
» กดปุ่ม frame เพื่อทดสอบเคลื่อนหัวเลเซอร์
» การตั้งค่าเครื่องพิมพ์ -> Edit -> Device Setting -> ตั้งความเร็ว กำลังเลเซอร์ และจำนวนรอบการตัด
การใช้เครื่องตัดเลเซอร์ K40
activate py38
pip install meerk40t[all]
meerk40t
meerk->ปุ่ม console (>>) -> พิมพ์ ruidacontrol
lightburn -> device -> Create Mnually -> Ruida -> Ethernet/UDP -> ไอพี 127.0.0.1 -> ตั้งชื่อ กำหนดความกว้าง 300mm สูง 200mm -> next
ที่โปรแกรม meek40t -> Config tab -> Config -> Interface tab -> ใส่ serial number: 81453C660A975553
การใช้งาน meerk40t ผ่าน command line
activate py38
meerk40t -zc
>> help แสดงคำสั่งทั้งหมด
>> ruidacontrol #เปิด ruidacontrol server port 50200 (data server) และ 50207 (jog server)
>> quit คำสั่งออกจากโปรแกรม
>> usb_connect เชื่อมต่อ usb+เครื่องตัดเลเซอร์
>> usb_disconnect ยุติการเชื่อมต่อ usb+เครื่องตัดเลเซอร์
>> usb_release ยกเลิกการเชื่อมต่อ
>> usb_reset รีเซต USB device
>> home เลื่อนหัวเลเซอร์ไปตำแหน่ง home
>> move 10mm 10mm ย้ายไปซ้ายและขวาตำแหน่งที่ 10
ปล. การเปิด/ปิด เลเซอร์จะต้องควบคุมผ่านคำสั่ง G-Code (M3 เปิดเลเซอร์, M5 ปิดเลเซอร์) เท่านั้น ไม่สามารถสั่งผ่าน console โดยตรงเพื่อความปลอดภัย
ปล. ความเร็ว 1400 mm/min ; number passes: 2; power: 40%
Two Mosfet Driver
» อุปกรณ์ที่ออกแบบมาเพื่อขับเคลื่อนและควบคุมการทำงานของสอง MOSFETs (Metal-Oxide-Semiconductor Field-Effect Transistors) ซึ่งเป็นประเภทของทรานซิสเตอร์ที่ใช้ในหลายๆ อุปกรณ์อิเล็กทรอนิกส์เพื่อการสวิตช์หรือขยายสัญญาณ
เครื่องเชื่อม IGBT
» การเช็คว่า Mosfet เสียหรือไม่ (ใช้กับ IGBT ได้เช่นกัน) 1) ขามอสเฟตทุกเบอร์จะเป็น Gate - Drain - Source 2) ตั้งมิเตอร์เข็มที่ 10K ohm ต่อสาย meter.+ เข้ากับ Mosfet.source และต่อสาย Meter.- เข้ากับ Mosfet.drain 3) ใช้นิ้วมือจับที่ขา gate + drain ที่มิเตอร์เข็มจะเลื่อนขึ้นมา 4) ใช้สาย meter.+ แต่ที่ขา mosfet.gate เข็มจะต้องกลับมาที่ตำแหน่ง 0
» หลอดไฟซ้ายมือต่อเอาพุต หลอดกลางและขวาต่ออนุกรมและวัดไฟ 300โวลต์ที่ผ่าน diode bridge dc เพื่อดูว่าไฟนิ่งมั้ย
» การต่อ soft switch ต่อดังภาพด้านบน บริเวณ input + bridge
» หม้อแปลง CT (Current Transformer) จะต่ออนุกรมในหม้อแปลงหลักฝั่งอินพุต เพื่อตรวจจับกระแสเกิน
» R shunt จะต่อจากขั้ว Center ของหม้อแปลงหลักฝั่งขาออก และต่อลงกราวด์ เพื่อต้องการแรงดันที่คล่อม R-shunt เข้า opamp และไปเข้า SG3525.pin9 เพื่อปรับแต่งค่า duty cycle
» แรงดันที่หน้าตู้ก่อนผ่าน R shunt จะนำไปขยาย เพื่อควบคุมที่ขา sg3525.pin9 เพื่อควบคุม duty cycle จากภายนอก โดยอาศัยศักย์แรงดันที่ R-shunt ไปขยาย
» Diode Bridge 80A 1000v
» C 0.1/630v by pass สัญญาณรบกวน
» เมื่อไฟ 220vac ผ่าน Diode Bridge และจะผ่าน NTC ซึ่งเป็นตัวต้านทานเปลี่ยนค่าตามอุณหภูมิ เมื่อร้อนขึ้นความต้านทานลดลง สมัยก่อนจะใช้ R กระเบื้อง (R100 10W) แทน NTC เพราะตัวต้านทานจะใช้งานในช่วงเปิดเพียง 1 วินาที
» ต่อ Relay คล่อม NTC เพื่อให้ NTC ทำหน้าที่ลดการกระชากไฟเข้า C อย่างรุนแรง เนื่องจากหากไม่มีประจุใน C แล้วเปิดเครื่องจะมีความต้านทานแฝงที่ต่ำ กระแสจึงเข้าไปชาร์จตัวมันอย่างแรง เรียกกระแสกระชาก ซึ่งใช้ NTC มาช่วยลดกระแสกระชาก
» หลังจากชุดไฟต่ำทำงาน Relay 24v จะทำงานทำให้หน้าสัมผัสทำให้ไฟ 220v วิ่งผ่านหน้าสัมผัสของ Relay แทนการไหลผ่าน NTC
» C 100k ต่อค่อมไฟ 300v เมื่อปิดสวิตช์จะทำการ discharge ไฟที่ตกค้างใน C ออก
» IGBT เวลาช็อตจะแตกรุนแรง เพราะ
1) IGBT และ MOSFET ไม่มีรอยต่อไม่มีจังชั่นทำให้มีความไวสูง 2) Transistor มีรอยต่อจังชั่นทำให้มีความไวในการสลับช้ากว่า
2) ก) IGBT และ MOSFET ไบอัสด้วยแรงดันหรือสนามไฟฟ้า ดังนั้น ห้ามลอยขา Gate แล้วเสียบไฟอย่างเด็ดขาด ข) Transistor ไปอัสด้วยกระแส
» AC Bias คือ หม้อแปลงฝั่งขาออกพันกลับทิศกัน ทำให้มีไฟออกเป็นทั้งบวกและลบ
» ไอซี SG3525 ขา CT และ RT เป็นตัวกำหนดความถี่ ห้ามวัดเพราะจะทำให้ความถี่เปลี่ยนแปลงรูปสัญญาณเพี้ยนทำให้ IGBT ช็อตได้
» ไอซี SG3525.pin8 เป็นขาป้องกัน แต่จริง ๆ เป็น softstart วัดไฟได้ประมาณ 3.8v แต่ถ้ามีแรงดัน 0v มันจะหยุดสร้าง pwm นอกจากนั้นขา 8 มีโครงสร้างสั่งให้ shutdownได้ ถ้าช็อตขา 8 ลง Gnd มันจะหยุดสร้าง PWM
» ไอซี OpAmp ที่นิยมใช้มีสองเบอร์ ไม่สามารถใช้แทนกันได้
1) LM358 เป็น opamp คู่อยู่ในไอซีตัวเดียว ตัวแรกขา 1,2,3 และอีกตัวขา 6,7,5 ใช้ปรับกระแส
- LM358.pin1 = output, LM358.pin2 = inverting (ขั้วลบ) , LM358.pin3 = non inverting (ขั้วบวก)
- ก) จ่ายไฟ 5v เข้าขา 3 ข) แรงดัน 12.4v ผ่านอนุกรม R6.2k -> เข้าขา 2 จะมีแรงดัน 3.6v และ R5.1k เข้าขา 3 3) ถ้า ขา 2 > ขา 3 = ขา 1 = Low; ถ้าขา 2 < ขา 3 = ขา 1 = HIgh ->>>> ส่งไปขา Sg3525.pin8 เพื่อให้หยุดสร้าง pwm
2) CA3140 เป็น opamp ตัวเดียว
» SCR ถ้ามีสัญญาณไป Trig แล้วมันจะเปิดอยู่อย่างนั้นตลอด
» Converter คือ การเปลี่ยนแรงดันและความถี่
» Inverter คือ เปลี่ยนแรงดัน เช่น แปลงจากไฟ 12vdc เป็น 220vac
» Bulk Converter คือ แรงดันอินพุตต้องมากกว่าแรงดันเอาพุตเสมอ ประกอบด้วย 1) Transistor ใช้ NPN เป็นหลัก ปัจจุบันใช้ Mosfet หรือ IGBT 2) Diode 3) Inductor (L) ตัวเหนี่ยวนำ 4) Capacitor (C) ตัวเก็บประจุ
» ประเทศไทยใช้ไฟ 220vac เมื่อแปลงเป็นกระแสตรงจะได้ไฟ 300vdc -> Transistor ได้รับสัญญาณ PWM เข้ามาที่ขาเกต ถ้า PWM.+ จะทำให้ไฟผ่านตัวเหนี่ยวนำและผ่านโหลดออกไป อีกส่วนเก็บไว้ในตัวเก็บประจุ เมื่อ PWM.- ทรานซีสเตอร์จะ cut off ทำให้ตัวเหนี่ยวนำที่มีสนามแม่เหล็กเกิดการยุบตัว ทำให้ไฟลบผ่านไดโอดและไหลผ่านโหลดออกไป จากนั้นจะมีวงจรแบ่งแรงดันด้วยตัวต้านทานสองตัว และแบ่งแรงดันออกมาเป็น Feedback และส่งให้วงจรเปรียบเทียบแรงดัน จากนั้นนำแรงดันที่เป็นผลต่างเอาไปควบคุม Pwm เพื่อให้แรงดันคงที่
DM13A (16-bit Constant Current LED Driver)
» DM13A ไดรเวอร์ LED แบบ 16 บิตสำหรับกระแสคงที่ รุ่น DM13A จากบริษัท Silicon Touch Technology Inc. ไดรเวอร์นี้ออกแบบมาสำหรับการใช้งานแสดงผล LED และมีคุณสมบัติเด่นดังนี้:
มีช่องออกแสง LED ทั้งหมด 16 ช่อง สามารถปรับกระแสแต่ละช่องได้ด้วยตัวต้านทานภายนอกเดียวตั้งแต่ 3mA ถึง 60mA.
- รองรับแรงดันไฟฟ้าสูงสุดที่ 17V.
- ความถี่สูงสุดที่ 25MHz.
- ใช้ไฟเลี้ยงตั้งแต่ 3.3V ถึง 5V.
- มีการควบคุมกระแสเริ่มต้นที่เข้าสู่ระบบ.
- ใช้งานได้กับระบบแสดงผล LED ทั้งในร่มและกลางแจ้ง.
ไดรเวอร์นี้มีการออกแบบให้สามารถเข้ากันได้กับแพ็คเกจและขาเชื่อมต่อของไดรเวอร์ LED แบบเดิมๆ เช่น ST2221C, DM134/5/6 ซึ่งทำให้ง่ายต่อการใช้งานและเปลี่ยนแปลงในการออกแบบระบบไฟ LED ที่มีอยู่
from machine import Pin
import utime
# กำหนด GPIO pins สำหรับ DM13A
data_pin = Pin(2, Pin.OUT) # DAI
clock_pin = Pin(3, Pin.OUT) # DCK
latch_pin = Pin(4, Pin.OUT) # LAT
enable_pin = Pin(5, Pin.OUT) # EN
# ฟังก์ชันสำหรับส่งข้อมูลไปยัง DM13A
def send_data(data):
for i in range(16): # DM13A มี 16-bit ข้อมูล
bit = (data >> i) & 1 # คำนวณ bit ที่ i จากท้าย
data_pin.value(bit) # ตั้งค่าข้อมูล
clock_pin.value(1) # ตั้งค่านาฬิกา
utime.sleep_us(10) # รอสักครู่
clock_pin.value(0) # รีเซ็ตนาฬิกา
# ลงล็อกข้อมูลในรีจิสเตอร์ของ DM13A
def latch_data():
latch_pin.value(1)
utime.sleep_us(10)
latch_pin.value(0)
# ฟังก์ชันสำหรับเปิดใช้งาน DM13A
def enable_output():
enable_pin.value(0) # เปิดใช้งาน output
# ฟังก์ชันสำหรับปิดใช้งาน DM13A
def disable_output():
enable_pin.value(1) # ปิดใช้งาน output
# เริ่มต้นโดยการตั้งค่า
disable_output() # ปิดใช้งานขาออกเพื่อตั้งค่าเริ่มต้น
send_data(0x0000) # ส่งข้อมูลเริ่มต้น
latch_data()
enable_output()
# ตั้งค่าเพื่อเปิด LED ที่ Do, D1, D3
# คำนวณ bit pattern ที่จำเป็น: 0000000000001011 คือ 0x000B
send_data(0x000B)
latch_data()
การควบคุม DM13A ต่ออนุกรมรวม 32 หลอด LED
from machine import Pin
import time
# กำหนดขาที่ใช้สำหรับการส่งข้อมูล (DATA), นาฬิกา (CLOCK), LATCH, และ ENABLE
data_pin = Pin(18, Pin.OUT)
clock_pin = Pin(19, Pin.OUT)
latch_pin = Pin(21, Pin.OUT) # กำหนดขาสำหรับ LATCH
enable_pin = Pin(22, Pin.OUT) # กำหนดขาสำหรับ ENABLE
# ข้อมูลหลอด LED ที่ต้องการแสดง 0 คือ OFF, 1 คือ ON
led_state = "11010111100110010101100011011011"
def send_bit(value):
data_pin.value(value)
clock_pin.value(1)
time.sleep_us(1) # หน่วงเวลาสั้นๆ เพื่อให้นาฬิกาได้ถูกอ่าน
clock_pin.value(0)
def update_leds(state):
enable_pin.value(0) # เปิดการทำงานของชิพ
for bit in state:
send_bit(int(bit))
latch_pin.value(0)
latch_pin.value(1) # Latch ข้อมูลที่ส่งเข้าไป
latch_pin.value(0)
enable_pin.value(1) # ปิดการทำงานของชิพเพื่อลดการรบกวน
# อัปเดตสถานะของหลอด LED
update_leds(led_state)
แหล่งข้อมูล
» ไลบรารี่ micropython -> https://awesome-micropython.com/