RPi Pico RP2040 Code Examples
โต้ดตัวอย่างสาธิตการใช้งานไมโครไพธอนร่วมกับบอร์ด Raspberry Pi Pico (RP2040) -- เริ่มต้นเขียนเมื่อวันที่ 12 กุมภาพันธ์ พ.ศ. 2564
คำแนะนำ
ในการต่อวงจรเพื่อทดลองการทำงานของโค้ดตัวอย่างโดยใช้บอร์ดไมโครคอนโทรลเลอร์ RPi Pico ร่วมกับวงจรหรือโมดูลต่าง ๆ ควรมีความรู้พื้นฐานในการต่อวงจรและระมัดระวังเพื่อมิให้เกิดความเสียหายกับอุปกรณ์
การต่อวงจรที่ขา I/O ของบอร์ด ควรตรวจสอบจาก Pinout Diagram ของบอร์ดทุกครั้ง


โค้ดตัวอย่างที่ 1: LED Blink
โค้ดตัวอย่างแรก สาธิตการทำให้ LED กระพริบได้ โดยเลือกใช้ LED บนบอร์ด Pico ซึ่งต่อวงจรอยู่กับขา GPIO-25 และสาธิตการใช้คลาส machine.Pin ที่เกี่ยวข้องกับขา GPIO
ตัวแปร led อ้างอิงขา GPIO-25 Pin ที่เปิดใช้งานในทิศทางเอาต์พุต และใช้คำสั่ง led.value() สำหรับอ่านสถานะลอจิกในขณะนั้น และกำหนดสถานะใหม่ได้เช่นกัน โดยทำคำสั่ง เช่น led.value(0) หรือ led.value(1)
ถ้าต้องการจบการทำงานของโค้ดนี้เมื่อรันผ่านทาง MicroPython REPL ให้กดคีย์ Ctrl+C
โค้ดตัวอย่างที่ 2: Input Button
โค้ดตัวอย่างนี้ สาธิตการอ่านค่าจากขา GPIO ที่ต่อรับสัญญาณอินพุตจากวงจรปุ่มกด (Active-Low Push Button) โดยกำหนดให้ขา GPIO-16 เป็นขาอินพุตและเปิดใช้งาน Internal Pull-Up สำหรับขาดังกล่าว และใช้ตัวแปร button ในการอ้างอิงขาดังกล่าว ในตัวอย่างนี้ เมื่อกดปุ่มจะอ่านค่าโดยใช้คำสั่ง button.value() ได้เป็น 0 หรือลอจิก LOW และจบการทำงานของโปรแกรม
หรือจะเปลี่ยนไปใช้วิธีการตรวจสอบอินเทอร์รัพท์ (Interrupt) ที่ขาอินพุตตามตัวอย่างต่อไปนี้ โดยการตรวจสอบดูว่า มีการเปลี่ยนแปลงสถานะที่ขาอินพุตหรือไม่ เหตุการณ์ที่จะทำให้เกิดอินเทอร์รัพท์ในกรณีนี้คือ เมื่อมีการเปลี่ยนจาก HIGH เป็น LOW หรือ Falling-Edge Transition
ตัวแปร button ใช้ในการอ้างอิงขา GPIO-16 (GP16) สำหรับวงจรปุ่มกด และการใช้คำสั่ง button.irq() เป็นการเปิดใช้งานและกำหนดรูปแบบของอินเทอร์รัพท์ เช่น เลือกรูปแบบเป็น Pin.IRQ_FALLING และระบุฟังก์ชันที่ใช้สำหรับทำหน้าที่เป็น Callback (Interrupt Handler)
โค้ดตัวอย่างที่ 3: Push Button + Toggle LED
ตัวอย่างนี้สาธิตการเปิดใช้งานอินเทอร์รัพท์ที่ขา GPIO-14 (GP14) ที่ต่อกับวงจรปุ่มกดบนเบรดบอร์ด เมื่อมีการกดปุ่มแล้วปล่อยแต่ละครั้ง จะทำให้ LED บนบอร์ดสลับสถานะหนึ่งครั้ง
โค้ดตัวอย่างที่ 4: PWM-based LED Fading
ตัวอย่างนี้สาธิตการสร้างสัญญาณแบบ PWM (Pulse Width Modulation) และให้เป็นเอาต์พุตที่ขา GPIO-25 กำหนดความถี่ให้เท่ากับ 1000 Hz (1 kHz) และเริ่มต้นให้มีค่า Duty Cycle เป็น 0 การกำหนดค่า Duty Cycle สำหรับ PWM นั้น จะต้องเป็นเลขจำนวนเต็มขนาด 16 บิต อยู่ในช่วง 0..65535
โค้ดตัวอย่างนี้ จะเพิ่มค่า Duty Cycle จาก 0 และไปจนถึงค่าเท่ากับ 255*256 จากนั้นจะลดลงไปจนถึง 0 อีกครั้ง แล้วจะวนซ้ำในลักษณะนี้ไปเรื่อย ๆ
ถ้าทดสอบการทำงานของโค้ดตัวอย่างนี้กับบอร์ด RPi Pico จะเห็น LED บนบอร์ดค่อย ๆ สว่างขึ้นและดับลงซ้ำไปเรื่อย ๆ
ถ้าจะลองใช้โมดูล RGB LED ที่ใช้ขาสัญญาณควบคุมแบบ 3 ขา ก็สามารถทำได้เช่นกัน โค้ดตัวอย่างนี้สาธิตการใช้ขา GPIO-11, 12, 13 (GP11,GP12,GP13) เป็นขาสัญญาณเอาต์พุต นำไปต่อกับขาสัญญาณของโมดูล RGB LED (Active-High) เพื่อเปลี่ยนค่า Duty Cycle ของสัญญาณแต่ละช่องไปตามลำดับ

โค้ดตัวอย่างที่ 5: Timer-based LED Blink
ตัวอย่างนี้สาธิตการใช้งาน Timer (ตอนนี้ใช้ได้เฉพาะ Software Timer และใช้ Timer id เท่ากับ -1) เพื่อทำคำสั่งหรือเรียกใช้ฟังก์ชันตามคาบเวลาหรือความถี่ที่ได้กำหนดไว้ ซึ่งเป็นเหตุการณ์ที่เกิดขึ้นซ้ำ (Periodic) เช่น การสลับสถานะเอาต์พุตของ LED ที่อัตรา 10 Hz
โค้ดตัวอย่างที่ 6: LED Blink Using a Thread
ตัวอย่างนี้สาธิตการใช้คำสั่ง _thread.start_new_thread() เพื่อสร้าง"เธรด" (Thread) ใหม่ให้ทำงานบน CPU Core อีกอันหนึ่ง โดยให้ทำหน้าที่สลับสถานะลอจิกของ LED ตามข่วงเวลาที่กำหนดไว้
แต่มีข้อจำกัดคือ เนื่องจาก MicroPython สำหรับ RP2040 ไม่ได้ทำงานโดยใช้ RTOS หรือระบบปฏิบัติการเวลาจริง ดังนั้นการใช้งาน "เธรด" ใหม่ จะถูกกำหนดให้รันบน CPU Core 1 ในขณะที่โค้ดของเธรดหลัก (Main Thread) จะรันบน CPU Core 0
เนื่องจากมีการทำงานพร้อมกันโดยใช้ CPU Core ทั้งสองแกน และต้องมีการใช้วิธีการป้องกันที่เรียกว่า Mutex Lock โดยใช้คำสั่ง _thread.allocate_lock() เพื่อสร้าง Lock Object มาใช้งาน และอ้างอิงโดยใช้ตัวแปร lock จากนั้นจึงใช้คำสั่ง lock.acquire() และ lock.release() ตามลำดับ ก่อนและหลังการใช้คำสั่งที่ต้องใช้ทรัพยากรของระบบที่อาจต้องใช้ร่วมกันระหว่างเธรดในระบบ เช่น การใช้คำสั่ง print() เพื่อส่งข้อความออกทาง REPL
โค้ดตัวอย่างที่ 7: OLED I2C Display
โค้ดตัวอย่างนี้สาธิตการใช้งานบัส I2C และเชื่อมต่อกับโมดูล OLED I2C Display (SSD1306 Driver) โดยใช้งานร่วมกับไลบรารี ssd1306 ซึ่งสามารถดาวน์โหลดไฟล์ ssd1306.py ได้จาก Github แล้วนำไปใส่ลงในไดรฟ์ของไมโครไพธอน
เนื่องจาก RP2040 มีบัส I2C ให้ใช้งาน 2 ชุด ในตัวอย่างนี้ได้เลือกใช้ I2C1 และใช้ขา GPIO-14 และ GPIO 15 ซึ่งสามารถใช้เป็นขา I2C1_SDA และ I2C1_SCL ได้
ขนาดของโมดูล OLED I2C ได้เลือกมาลองใช้งาน มีขนาด 128 x 32 พิกเซล และมีแอดเดรสตรงกับ 0x3C
โค้ดตัวอย่างที่ 8: SSD1306 OLED + BH1750 Light Sensor
ตัวอย่างนี้เป็นการใช้งานบัส I2C โดยนำบอร์ด RP2040 ไปเชื่อมต่อกับโมดูล SSD1306 OLED Display และโมดูลเซ็นเซอร์แสง BH1750 ทั้งสองโมดูลนี้ใช้บัส I2C1 ร่วมกัน และใช้แรงดันไฟเลี้ยง +3.3V จากบอร์ด RP2040
แอดเดรสของโมดูล SSD1306 และ BH1750 ตรงกับ 0x3C และ 0x23 ตามลำดับ

ตัวอย่างการสร้างคลาสในภาษาไมโครไพธอนสำหรับ BH1750 แล้วนำมาใช้งาน โดยบันทึกลงในไฟล์ bh1750.py
และโค้ดสาธิตการใช้งานไฟล์ bh1750.py
โค้ดตัวอย่างที่ 9: WDT (Watchdog Timer)
โค้ดตัวอย่างนี้สาธิตการเปิดใช้งาน Watchdog Timer (WDT) ซึ่งเป็นวงจรภายใน RP2040 และเมื่อเปิดการทำงานของ WDT แล้ว จะต้องมีการป้อนค่าให้ WDT (WDT feeding) ภายในระยะเวลาที่กำหนด มิฉะนั้นแล้ว วงจร WDT จะรีเซตการทำงานของไมโครไพธอน
ในตัวอย่างนี้ จะต้องมีการต่อวงจรปุ่มกดภายนอกที่ขา GPIO-16 ด้วย และเมื่อโค้ดนี้เริ่มทำงาน จะต้องมีการกดปุ่มค้างไว้ในช่วงเวลาดังกล่าว จึงจะเปิดการทำงานของ WDT
โค้ดตัวอย่างที่ 10: System Info
โค้ดตัวอย่างนี้สาธิตการใช้คำสั่งของโมดูล uos เพื่อสอบถามข้อมูลเกี่ยวกับระบบและการใช้งานระบบไฟล์ในหน่วยความจำแฟลช (Flash File System) ของไมโครไพธอน
ตัวอย่างข้อความเอาต์พุต
โค้ดตัวอย่างที่ 11: On-Chip Temperature Reading with ADC
ตัวอย่างนี้สาธิตการใช้งานวงจร ADC (Analog-to-Digital Converter) ภายใน RP2040 เพื่ออ่านค่าจากเซ็นเซอร์วัดอุหภูมิที่อยู่ภายในชิป และต่อสัญญาณแบบแอนะล็อกเข้าช่องหมายเลข 4 ของวงจร ADC
วงจร ADC ภายใน RP2040 มีช่องอินพุตทั้งหมด 5 ช่อง (ช่องหมายเลข 0 ถึง 4) และมีความละเอียดในการแปลงข้อมูลเท่ากับ 12 บิต (0..4095) แต่ไมโครไพธอนจะแปลงให้เป็นข้อมูลขนาด 16 บิต (0..65535)
ช่องอินพุต 3 ช่องแรกของ ADC บนบอร์ด Pico ตรงกับขา GP26, GP27, GP28 ตามลำดับ แต่ช่องที่ 4 จะใช้สำหรับอ่านแรงดันไฟฟ้าที่ขา VSYS/3 ของบอร์ด (แรงดันไฟฟ้าที่วัดได้จะเท่ากับ VSYS / 3) และถ้าใช้แรงดันไฟเลี้ยงจาก VUSB แรงดันไฟฟ้าที่วัดได้จาก ADC ที่ขา VSYS จะเท่ากับ (VBUS / 3) ซึ่งได้จากวงจรหารความถี่โดยใช้ตัวต้านทาน
ข้อสังเกต: VBUS ต่อผ่านไดโอด Schottky ไปยัง VSYS (ต้องอยู่ในช่วง 1.8V .. 5.5V) และต่อไปยังวงจร Switching Power Supply (RT6150 buck-boost SMPS) เพื่อสร้างแรงดันไฟฟ้า +3.3V
โค้ดตัวอย่างนี้สาธิตการอ่านค่าอินพุต 4 ช่องของ ADC ตามลำดับ
โค้ดตัวอย่างที่ 12: TM1637 4-Digit 7-Segment Display
ตัวอย่างนี้สาธิตการใช้งานไลบรารีสำหรับ TM1637 ซึ่งเป็นไอซีควบคุมการทำงานของโมดูล 4-Digit 7-Segment Display
ไฟล์ tm637.py ซึ่งเป็นไลไบรารีและมีโค้ดที่เขียนด้วยภาษาไมโครไพธอนสำหรับ TM1637 สามารถดาวน์โหลดได้จาก Github ดังนั้นต้องดาวน์โหลดไฟล์นี้แล้วนำไปใส่ไว้ใน File System ของบอร์ด RP2040
การทำงานของโค้ดนี้ได้เลือกใช้ขา GP15 และ GP14 สำหรับขาสัญญาณ CLK แลพ DIO ของโมดูล TM1637 ตามลำดับ (ใช้แรงดันไฟเลี้ยง 3.3V) และจะแสดงผลตัวเลขเป็นนาฬิกาที่นับถอยหลัง เริ่มต้นที่ 2:00 นาที แล้วลดลงทีละหนึ่งทุก ๆ หนึ่งวินาที

โค้ดตัวอย่างที่ 13: UART Loopback Test
ตัวอย่างนี้สาธิตการรับส่งข้อมูลผ่านทาง UART ของ RP2040 ในลักษณะ Serial Loopback คือ ส่งข้อมูลออกไปทางขา Tx แล้วก็รับข้อมูลนั้นวกกลับเข้ามาที่ขา Rx
RP2040 มีวงจร UART จำนวน 2 ชุด คือ UART0 และ UART1 และสามารถเลือกใช้ขา GPIO ได้แตกต่างกัน (ดูได้จาก Pico PinMap) แต่ในตัวอย่างนี้ได้เลือกใช้ UART0 และขา GP0 และ GP1 สำหรับขา Tx และ Rx ตามลำดับ และตั้งค่า Baudrate ไว้เท่ากับ 115200
โค้ดตัวอย่างที่ 14: Rotary Encoder Input
โค้ดตัวอย่างนี้ สาธิตการใช้งานโมดูล Rotary Encoder Switch ซึ่งจะได้สัญญาณดิจิทัล A, B และมีการเปลี่ยนสถานะลอจิกเมื่อมีการหมุนตามเข็มหรือทวนเข็มนาฬิกา (Clockwise / Anti-Clockwise Rotation) นอกจากนั้นแล้ว ยังมีอีกหนึ่งสัญญาณ SW ให้ผลเหมือนกับวงจรกดปุ่มหรือสวิตช์ปุ่มกด
การตรวจสอบดูว่า มีการหมุนเปลี่ยนตำแหน่งหรือไม่ และเปลี่ยนไปในทิศทางใด เราจะใช้อินเทอร์รัพท์เพื่อดูการเปลี่ยนสถานะที่ขา A ทั้งขอบขาขึ้นและขาลง (Both Rising Edge & Falling Edge) ถ้าไม่มีการเปลี่ยนตำแหน่ง สถานะลอจิกของขา A และ B จะเป็น High
เมื่อเกิดเหตุการณ์ในแต่ละครั้ง ก็ทำให้ฟังก์ชันที่เป็น ISR Handler ที่เกี่ยวข้องทำงาน โดยตรวจสอบดูว่า สถานะของขา A และ B เป็นอย่างไร แล้วใช้ในการเพิ่มหรือลดค่าของตัวนับ (Incremental / Decremental Counter)
ในตัวอย่างนี้ได้เลือกใช้ขา GPIO-16, 17, 18 (GP16,GP17,GP18) ตรงกับขาสัญญาณ A, B, SW ของโมดูล Rotary Encoder Switch ที่ได้นำมาต่อวงจรร่วมกับบอร์ด RPi Pico ถ้าหมุนครบหนึ่งรอบจะได้ทั้งหมด 20 ตำแหน่ง (Positions per Revolution)
ในการต่อวงจรบนเบรดบอร์ด แนะนำให้เพิ่มวงจร R-C Filter (low-pass) ที่ขาสัญญาณ A และ B เพื่อลดปัญหาที่เกิดการกระเด้งของสวิตช์ (Switch Bouncing)

โค้ดตัวอย่างที่ 15: Memory Info
ตัวอย่างนี้สาธิตการใช้คำสั่งจากโมดูล gc (Garbage Collector) ของไมโครไพธอน และใช้คำสั่งเพื่อตรวจสอบดูปริมาณการใช้หน่วยความจำ หรือที่ยังเหลืออยู่
ตัวอย่างข้อความเอาต์พุต
Memory (total/alloc/free): 192,080 / 60,368 / 131,712 bytes
โค้ดตัวอย่างที่ 16: SH1106 OLED I2D Display
ตัวอย่างนี้สาธิตการใช้โมดูล SH1106 OLED Display ที่เชื่อมต่อด้วยบัส I2C โดยเลือกใช้ I2C0 ของ RP2040 และใช้ขา GP16 / GP17 สำหรับขา SDA/SCL ตามลำดับ และนำมาแสดงข้อความเป็นตัวอย่าง
การใช้งานโมดูล SH1106 ทำได้ไม่ยากเนื่องจากมีไลบรารีไว้ให้ใช้งาน สามารถดาวน์โหลดไฟล์ sh1106.py จาก Github แล้วนำไปใส่ลงในไดรฟ์ของไมโครไพธอนสำหรับบอร์ด RPi Pico

โค้ดตัวอย่างที่ 17: Ultrasonic Distance Sensor
โค้ดนี้สาธิตการสร้างสัญญาณเอาต์พุตแบบพัลส์ เพื่อส่งไปยังโมดูลเซนเซอร์วัดระยะห่างจากสิ่งกีดขวางด้วยคลื่นอัลตร้าโซนิก (Ultrasonic Distance Sensor Module) และวัดความกว้างของสัญญาณพัลส์ที่ได้จากโมดูลเพื่อนำมาคำนวณระยะห่าง
โมดูลเซนเซอร์มีขา Trig (Trigger) เป็นอินพุต และขา Echo เป็นเอาต์พุต (เลือกใช้รุ่นที่ทำงานได้โดยใช้แรงดันไฟเลี้ยง +3.3V) ไมโครคอนโทรลเลอร์จะต้องสร้างสัญญาณพัลส์ เช่น มีความกว้างช่วง High อย่างน้อย 10 usec ไปยังขา Trig จากนั้นให้วัดความกว้างของสัญญาณพัลส์ที่ขา Echo
การวัดความกว้างของสัญญาณพัลส์ที่ขา Echo จะต้องรอให้สัญญาณนั้น เปลี่ยนจาก Low เป็น High แล้วเปลี่ยนจาก High เป็น Low ตามลำดับ
ในตัวอย่างนี้ได้เลือกใช้ขา GP19 และ GP18 สำหรับขา Trig และ Echo ตามลำดับ
โค้ดตัวอย่างที่ 18: 74HC595 Bit Shifting with SPI
ตัวอย่างนี้สาธิตการส่งข้อมูลไปยังไอซี 74HC595 ที่มีขาเอาต์พุต 8 ขา ต่อกับโมดูล 8x LED Bar สำหรับแสดงสถานะลอจิก และการส่งข้อมูลจะใช้วิธีเลื่อนบิตทีละบิตตามจังหวะสัญญาณ Clock
การทำงานของ 74HC595 จะใช้ขาสัญญาณดังนี้ (ศึกษาเพิ่มเติมได้จาก Datasheet [1][2])
Serial Clock (SCLK) เป็นขาอินพุต รับสัญญาณ Clock กำหนดจังหวะการเลื่อนบิต
Serial Data (SDA) เป็นขาอินพุต รับสัญญาณข้อมูลบิตเข้ามา
Load (LOAD) เป็นขาสัญญาณอินพุต รับสัญญาณพัลส์ เพื่อทำให้วงจรภายในไอซี นำข้อมูลที่ได้รับ ไปอัปเดตสถานะบิตที่ขาเอาต์พุต Q0..Q7 หลังจากที่ได้เลื่อนข้อมูลเข้าไปครบแล้ว
Q0..Q7 เป็นขาสัญญาณเอาต์พุต สำหรับข้อมูล 8 บิตแบบขนาน
Q7S เป็นขาสัญญาณเอาต์พุตสำหรับข้อมูลบิตที่ถูกเลื่อนออกมา (ใช้สำหรับการต่อไอซีแบบ Cascade หรือ Daisy Chain)
Master Clear (/MCLR) -- Active-low (ต่อตัวต้านทาน Pullup) ใช้สำหรับรีเซตข้อมูลภายใน
Output Enable (/OE) -- Active-low (ต่อตัวต้านทาน Pullup) เปิดหรือปิดขาเอาต์พุต Q0.. Q7
โค้ดนี้ใช้ขา GPIO ในการสร้างสัญญาณควบคุมและส่งข้อมูลไปยัง 74HC595 โดยเลือกใช้ขาดังนี้
GP9 = LOAD
GP10 = SCK
GP11 = SDA
ฟังก์ชัน send_byte() ใช้สำหรับการส่งข้อมูลขนาดหนึ่งไบต์เท่านั้นไปยัง 74HC595 และเลือกได้ว่าจะเลื่อนข้อมูลออกแบบ MSB First หรือ LSB First
อีกแนวทางหนึ่งคือ เปลี่ยนมาใช้ Hardware SPI ของ RP2040 ก็มีโค้ดตัวอย่างดังนี้ แต่มีข้อจำกัดของไมโครไพธอน "rp2" ในเวอร์ชันที่ใช้งานคือ สามารถใช้ได้เพียงโหมด MSB First เท่านั้น
โค้ดนี้ใช้ขา GPIO เหมือนเดิม เมื่อเปลี่ยนมาใช้ SPI ก็จะตรงกับ SPI1 ของ RP2040 ( ขา GP10 ตรงกับ SPI1_SCK และ ขา GP11 ตรงกับ SPI1_MOSI )

กล่าวสรุป
เนื้อหาในส่วนนี้ ได้นำเสนอตัวอย่างโค้ดไมโครไพธอนที่สามารถนำไปทดสอบการทำงาน โดยใช้บอร์ดไมโครคอนโทรลเลอร์ RPi Pico (RP2040) และจะเห็นได้ว่า มีการนำไปใช้งานร่วมกับโมดูลอิเล็กทรอนิกส์แบบต่าง ๆ ตัวอย่างเหล่านี้ จะช่วยให้ผู้เริ่มศึกษา เห็นรูปแบบการใช้คำสั่งต่าง ๆ ของไมโครไพธอน และเป็นแนวทางในการนำไปประยุกต์ใช้งานต่อไป
Last updated
Was this helpful?