แนะนำการใช้งาน TinyGo สำหรับบอร์ด Raspberry Pico (ตอนที่ 1)#
Keywords: Go / TinyGo, Microcontroller Programming, Raspberry Pico, RP2040
▷ TinyGo#
TinyGo เป็นคอมไพเลอร์สำหรับภาษา Go ที่สามารถนำไปใช้กับบอร์ดไมโครคอนโทรลเลอร์ได้ โดยปรกติแล้วในการเขียนโปรแกรมไมโครคอนโทรลเลอร์ ก็นิยมใช้ภาษา C/C++ หรือ Framework อย่างเช่น Arduino เป็นต้น แต่บทความนี้ขอนำเสนอแนวทางและตัวอย่างการเขียนโค้ดด้วยภาษา Go และคอมไพล์โค้ดด้วย TinyGo Compiler โดยเลือกใช้บอร์ด Raspberry Pi Pico (RP2040 Soc) เป็นตัวอย่าง
แนะนำให้ผู้อ่านได้ติดตั้งซอฟต์แวร์ต่อไปนี้ก่อน
- Go Compiler
- TinyGo Compiler
- VS Code IDE
- Go Extension for VS Code IDE
- TinyGo Extension for VS Code IDE
บอร์ดที่ได้นำมาทดลองใช้งาน ได้แก่
- Raspberry Pi Pico / Pico-W
- VCC GND Studio YD-RP2040
- WaveShare Zero-RP2040
รูป: แผนผังแสดงตำแหน่งขาของบอร์ด YD-RP2040
การเขียนโค้ดด้วยภาษา Go และใช้งานวงจรต่าง ๆ ของไมโครคอนโทรลเลอร์ รวมถึงการใช้งานร่วมกับโมดูลอิเล็กทรอนิกส์ประเภทต่าง ๆ ก็มีตัวช่วย กล่าวคือ มีไลบรารีให้เลือกใช้งาน และผู้ใช้สามารถดูได้จาก
รูป: github.com/tinygo-org/drivers/examples
▷ ตัวอย่างที่ 1: LED Blink#
ตัวอย่างโค้ดแรก (ใช้ไฟล์ชื่อ main.go
) คือ การทำให้ LED บนบอร์ด Pico กระพริบได้
โดยเลือกใช้ขา GP25 ซึ่งตรงกับวงจร LED บนบอร์ด Pico
package main
import (
"machine"
"time"
)
func main() {
println("TinyGo on Pico-RP2040 Board")
led := machine.LED // or machine.GP25
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
for { // an endless loop
state := !led.Get() // Toggle the state
println( "LED:", state ) // Send output string to serial
led.Set( state ) // Update the LED output
time.Sleep( 100*time.Millisecond ) // Wait for 0.1 sec
}
}
ในโค้ดตัวอย่างภายในฟังก์ชัน main
คำสั่ง println()
ส่งข้อความผ่าน USB-CDC ไปยังคอมพิวเตอร์ของผู้ใช้
ถัดไปมีการใช้ตัวแปร led
เพื่ออ้างอิง machine.LED
ซึ่งมีชนิดข้อมูลเป็น machine.Pin
และมีการใช้คำสั่ง Configure()
ของ machine.Pin
เพื่อตั้งค่าโหมดการใช้งาน
โดยให้เป็นขาเอาต์พุต (machine.PinOutput
)
led := machine.LED // or machine.GP25
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
การใช้คำสั่ง Get()
และ Set()
ของ machine.Pin
เป็นการอ่านค่าปัจจุบันและเขียนค่าใหม่ให้ขา GPIO ที่ใช้งาน
และคำสั่ง time.Sleep(100*time.Millisecond)
เป็นการหน่วงเวลาไว้ 0.1 วินาที ก่อนทำคำสั่งถัดไป
การตั้งค่าบอร์ด RP2040 เพื่อเข้าสู่โหมด Bootloader
- กดปุ่ม
BOOTSEL
บนบอร์ด Raspberry Pi Pico - เชื่อมต่อบอร์ดเข้ากับคอมพิวเตอร์ผ่านสาย USB
- เมื่อเข้าสู่โหมด Bootloader สำเร็จ บอร์ดจะปรากฏเป็นไดรฟ์ USB ชื่อ
RPI-RP2
การคอมไพล์โค้ดเพื่อสร้างไฟล์เอาต์พุตเป็น .elf
และ .uf2
และการอัปโหลดไปยังบอร์ด Pico ด้วยคำสั่งต่อไปนี้
tinygo clean
tinygo build -target=pico -size=short -o firmware.elf main.go
tinygo build -target=pico -size=short -o firmware.uf2 main.go
tinygo flash -target=pico main.go
รูป: ตัวอย่างการคอมไพล์โค้ดและอัปโหลดโปรแกรมไปยังบอร์ด Pico โดยใช้ซอฟต์แวร์ VS Code IDE
แต่ถ้าจะไม่ใช้คำสั่ง time.Sleep()
และเปลี่ยนเป็นวิธีตรวจสอบช่วงเวลาระหว่างเวลาปัจจุบันกับเวลาครั้งก่อนที่ได้มีการสลับสถานะของเอาต์พุต ก็มีแนวทางการเขียนโค้ดดังนี้
package main
import (
"machine"
"time"
)
func main() {
println("TinyGo LED Blink")
// Initialize the onboard LED
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
// Set the toggle interval
intervalMsec := time.Millisecond * 100
lastTime := time.Now()
for {
now := time.Now() // Get the current time
// Check if the time difference exceeds the toggle interval
if now.Sub(lastTime) >= intervalMsec {
led.Set(!led.Get()) // Toggle the LED
lastTime = now // Update the last time
}
}
}
▷ ตัวอย่างที่ 2: LED Blink + USB-CDC#
โค้ดตัวอย่างนี้สาธิตการใช้ machine.USBCDC
เป็นช่องทางการส่งข้อความที่จะต้องมีการแปลงเป็นข้อมูลไบต์ก่อนส่งไปยังคอมพิวเตอร์ของผู้ใช้
โดยใช้คำสั่ง machine.USBCDC.Write()
แต่จะให้ผลเหมือนการใช้คำสั่ง println()
package main
import (
"fmt"
"machine"
"time"
)
var (
usbcdc = machine.USBCDC
)
func main() {
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
count := 0
for {
value := (count%2 == 0) // Compute logic value
led.Set(value) // Update the LED
textStr := fmt.Sprintf("Count: %v\n", count)
usbcdc.Write([]byte(textStr)) // Write bytes to USB-CDC
count++ // Increment counter
time.Sleep(500 * time.Millisecond)
}
}
รูป: ตัวอย่างการรับข้อความจากบอร์ด Pico
▷ ตัวอย่างที่ 3: LED Toggle Upon Button Click (Polling Loop)#
ตัวอย่างสำหรับการอ่านค่าจากปุ่มกด และเมื่อมีการกดปุ่มแล้วปล่อยแต่ละครั้ง จะสลับสถานะลอจิกของ LED บนบอร์ด บอร์ดทดลองที่ได้นำมาใช้คือ YD-RP2040 ซึ่งมีวงจร LED ต่ออยู่ที่ขา GPIO25 และมีวงจรปุ่มกดอยู่ที่ขา GPIO24 (ต่อใช้งานแบบ Active-Low)
package main
import (
"machine"
"time"
)
func main() {
led := machine.LED // Use GPIO25 pin for LED output
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
btn := machine.GPIO24 // Use GPIO24 pin for active-low button
btn.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
lastState := btn.Get() // Get the current button state
ledState := !lastState
led.Set(ledState)
for {
currentState := btn.Get() // Read the button input
if currentState && !lastState { // Detect state change
ledState = !ledState // Toggle LED state
led.Set(ledState) // Write the LED output
println("LED State:", ledState)
}
lastState = currentState
time.Sleep(10 * time.Millisecond)
}
}
รูป: ตัวอย่างการรับข้อความจากบอร์ด Pico
▷ ตัวอย่างที่ 4: LED Toggle Upon Button Click (Interrupt-Driven)#
โค้ดตัวอย่างนี้สาธิตการใช้งานคำสั่ง SetInterrupt()
ของ machine.Pin
เพื่อเปิดใช้งานอินเทอร์รัพท์ที่ขา GPIO
และต่อใช้งานกับปุ่มกด เมื่อมีการเปลี่ยนสถานะลอจิกจาก High เป็น Low
(เกิดเหตุการณ์ขอบขาลง หรือ Falling Edge ที่ขาอินพุตสำหรับปุ่มกด)
จะมีการทำคำสั่งของฟังก์ชัน Callback (หรือเรียกฟังก์ชันนี้ว่า ISR: Interrupt Service Routine)
เช่น สลับสถานะลอจิกของ LED หนึ่งครั้ง
package main
import (
"machine"
"time"
)
var (
led = machine.GPIO25 // for LED output
btn = machine.GPIO24 // for active-low button
ledState = false
)
func main() {
// Configure the onboard LED as output
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
// Configure button as input with pull-up
btn.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
// Set up an interrupt on the button pin
btn.SetInterrupt(machine.PinFalling, func(machine.Pin){ // Callback function
ledState = !ledState // Toggle LED state
led.Set(ledState)
})
for { // endless loop
time.Sleep(time.Second)
}
}
▷ ตัวอย่างที่ 5: LED Toggle Upon Button Click (Interrupt + Go Channel)#
โค้ดตัวอย่างนี้มีการทำงานคล้ายกับตัวอย่างที่แล้ว แต่มีการใช้งาน Go Channel เพื่อใช้สื่อสารจากฟังก์ชัน
Callback เมื่อเกิดอินเทอร์รัพท์แต่ละครั้ง ไปยังฟังก์ชัน main
เมื่อฟังก์ชัน main
ได้รับข้อมูลตัวเลขจาก
Go Channel ที่อ้างอิงด้วยตัวแปรชื่อ buttonPressed
ก็จะสลับสถานะลอจิกของ LED หนึ่งครั้ง
package main
import (
"machine"
"time"
)
var (
led = machine.GPIO25 // for LED output
btn = machine.GPIO24 // for active-low button
)
func main() {
// Configure the onboard LED as output
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
// Configure button as input with pull-up
btn.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
// Create a channel for button press events
buttonPressed := make(chan int, 1)
// Set up an interrupt on the button pin
btn.SetInterrupt(machine.PinFalling, func(machine.Pin){ // Callback function
select {
case buttonPressed <- 1: // Send signal to channel
default: // Avoid blocking if channel is full
}
})
ledState := false
for {
select {
case <-buttonPressed: // Wait for signal from ISR
ledState = !ledState // Toggle the LED output
led.Set(ledState)
println("LED:", ledState)
default: // Avoid blocking if channel is empty
time.Sleep(10 * time.Millisecond)
}
}
}
หรืออาจปรับเปลี่ยนโครงสร้างของโค้ดใหม่ เช่น มีการสร้างฟังก์ชัน Goroutine เพื่อสื่อสารกับฟังก์ชัน Callback
package main
import (
"machine"
)
var (
led = machine.GPIO25 // for LED output
btn = machine.GPIO24 // for active-low button
buttonPressed = make(chan int, 1) // Go chnanel of int with capacity=1
)
func callback(pin machine.Pin) {
select {
case buttonPressed <- 1: // Send signal to channel
default: // Avoid blocking if channel is full
}
}
func main() {
// Configure the onboard LED as output
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
// Configure button as input with pull-up
btn.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
// Set up an interrupt on the button pin
btn.SetInterrupt(machine.PinFalling, callback)
go func() { // Start a goroutine
ledState := false
for {
<-buttonPressed // Wait for signal from ISR (blocking)
ledState = !ledState // Toggle the LED output
led.Set(ledState)
println("LED:", ledState)
}
}()
select {} // Block the main function
}
▷ ตัวอย่างที่ 6: LED Toggle Using Time Ticker#
ตัวอย่างโค้ดถัดไปสาธิตการใช้งาน time.Ticker
ที่จะสร้างสัญญาณและส่งผ่าน
Channel ที่มีชื่อว่า ticker.C
ตามระยะเวลาที่กำหนดไว้ เช่น 50 msec
ดังนั้นเมื่อได้รับสัญญาณจาก ticker.C
ก็จะมีการทำคำสั่งของฟังก์ชันตามระยะเวลาที่กำหนด
เช่น สลับสถานะลอจิกของ LED
package main
import (
"machine"
"time"
)
var (
led = machine.GPIO25 // for LED output
)
func main() {
// Configure the onboard LED
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
// Create a ticker with 50ms interval
ticker := time.NewTicker(50 * time.Millisecond)
for range ticker.C { // Wait for a signal from the Ticker
led.Set(!led.Get()) // Toggle the LED state
}
}
หรือจะแก้ไขโค้ด โดยสร้างฟังก์ชัน Goroutine เพื่อรอสัญญาณจาก time.Ticker
และสลับสถานะลอจิกของ LED ตามตัวอย่างดังนี้
package main
import (
"machine"
"time"
)
var (
led = machine.GPIO25 // for LED output
)
func ledToggle(ticker *time.Ticker) {
for range ticker.C { // Wait for a signal from the time ticker.
led.Set(!led.Get()) // Toggle the LED state
}
}
func main() {
// Configure the onboard LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
// Create a ticker with 50ms interval
ticker := time.NewTicker(50 * time.Millisecond)
go ledToggle(ticker) // Start a goroutine
select {} // Block the main function
}
ถ้าลองลดระยะเวลาในการสลับสถานะลอจิกแต่ละครั้งให้น้อยลง เช่น 500 ไมโครวินาที แล้ววัดสัญญาณเอาต์พุตด้วยออสซิลโลสโคปแบบดิจิทัล
รูป: การวัดสัญญาณ เมื่อกำหนดให้มีระยะเวลา 500us ซึ่งจะได้ความถี่ 1kHz ช่วงเวลาที่สัญญาณมีลอจิก High และ Low กว้างเท่ากัน (หนึ่งคาบกว้าง 1000us หรือ 1ms)
แต่ถ้าลดลงระยะเวลาให้เป็น 100 ไมโครวินาที จะได้รูปสัญญาณดังนี้
รูป: การวัดสัญญาณ เมื่อกำหนดให้มีระยะเวลา 100us ซึ่งจะได้ความถี่ 5kHz แต่ช่วงเวลาที่สัญญาณมีลอจิก High และ Low กว้างไม่เท่ากัน
▷ ตัวอย่างที่ 7: PWM-based LED Dimming#
ถัดไปเป็นตัวอย่างการสร้างสัญญาณ PWM (Pulse Width Modulation) โดยเลือกใช้ขา GPIO25 สำหรับสัญญาณเอาต์พุต และต่อกับวงจร LED บนบอร์ด Pico
สัญญาณ PWM ที่ได้เป็นเอาต์พุตแบบดิจิทัลนั้น มีความถี่คงที่ 500Hz และมีการปรับค่าความกว้างของพัลส์ช่วงที่เป็นลอจิก High ในหนึ่งคาบเวลา (หรือเรียกว่า Duty Cycle) ให้เพิ่มขึ้นหรือลดลงได้ ค่าที่ใช้สำหรับ Duty Cycle จะเป็นตัวเลขจำนวนเต็ม 16 บิต
ในโค้ดตัวอย่างมีฟังก์ชัน pwmInit()
ทำหน้าที่ตั้งค่าเริ่มต้นและเปิดใช้งานวงจร PWM สำหรับขา
machine.GPIO25
(ชนิดข้อมูล machine.Pin
) ซึ่งตรงกับ
machine.PWM4
(ชนิดข้อมูล *machine.pmwGroup
) ฟังก์ชันนี้ให้ค่ากลับคืนมาเป็นหมายเลขของ PWM Channel
และค่า PWM Top (ขนาด 16 บิต) ซึ่งเป็นค่าสูงสุดสำหรับคาบเวลาของสัญญาณ PWM
package main
import (
"machine"
"time"
)
const FREQ_HZ = 500 // PWM Frequency
const PWM_PERIOD uint64 = (1e9 / FREQ_HZ) // in nanoseconds
var (
pwmPin = machine.GPIO25 // Use GPIO25 pin for PWM output.
pwm = machine.PWM4 // Pin 25 corresponds to PWM Group 4.
)
func pwmInit() (channel uint8, top uint32) {
// Configure the PWM with the given period.
pwm.Configure(machine.PWMConfig{
Period: PWM_PERIOD,
})
// Create a PWM channel
channel, err := pwm.Channel(pwmPin)
if err != nil {
return 0, 0 // error
}
top = pwm.Top() // Get the PWM top value
return channel, top
}
func main() {
println("TinyGo RP2040 PWM Demo...")
time.Sleep(1 * time.Second)
pwmChannel, pwmTop := pwmInit() // Initialize PWM output
println("PWM Channel :", pwmChannel)
println("PWM top value :", pwmTop)
if pwmChannel < 1 {
panic("PWM creation failed!")
}
for {
value := 0
for i := 0; i < 200; i++ {
if i > 100 {
value = 200 - i
} else {
value = i
}
// Set PWM duty cycle (0% … 100%)
pwm.Set(pwmChannel, uint32(value)*pwmTop/100)
time.Sleep(time.Millisecond * 10)
}
}
}
ในการเลือกใช้ขา GPIO สำหรับการสร้างสัญญาณ PWM จะต้องเลือกหมายเลขของ PWM Group สำหรับชิป RP2040 ให้ถูกต้องด้วย ซึ่งสามารถดูได้จากเอกสารออนไลน์
รูป: ข้อมูลเกี่ยวกับการเลือกใช้ขา PWM ของบอร์ด Pico
หากจะลองปรับเปลี่ยนโค้ดตัวอย่าง โดยประยุกต์ใช้ Timer Ticker และ Goroutine และให้ผลการทำงานเหมือนเดิม ก็มีแนวทางด้งนี้
package main
import (
"machine"
"time"
)
const FREQ_HZ = 500 // PWM Frequency
const PWM_PERIOD uint64 = (1e9 / FREQ_HZ) // in nanoseconds
var (
pwmPin = machine.GPIO25 // Use GPIO25 pin for PWM output.
pwm = machine.PWM4 // Pin 25 corresponds to PWM Group 4.
// pwmPin = machine.GPIO15 // Use GPIO15 pin for PWM output.
// pwm = machine.PWM7 // Pin 15 corresponds to PWM Group 7.
)
func pwmInit() (channel uint8, top uint32) {
// Configure the PWM with the given period.
pwm.Configure(machine.PWMConfig{
Period: PWM_PERIOD,
})
// Create a PWM channel
channel, err := pwm.Channel(pwmPin)
if err != nil {
return 0, 0 // error
}
top = pwm.Top() // Get the PWM top value
return channel, top
}
func main() {
println("TinyGo RP2040 PWM Demo...")
pwmChannel, pwmTop := pwmInit() // Initialize PWM output
println("PWM Channel :", pwmChannel)
println("PWM top value :", pwmTop)
if pwmChannel < 1 {
panic("PWM creation failed!")
}
// Create a ticker with 50ms interval
ticker := time.NewTicker(10 * time.Millisecond)
go func() { // Start a goroutine for PWM update
value := 0
i := 0
for range ticker.C {
if i > 100 {
value = 200 - i
} else {
value = i
}
// Set PWM duty cycle (0% … 100%)
pwm.Set(pwmChannel, uint32(value)*pwmTop/100)
i = (i + 1) % 200
}
}()
select {} // Blocking the main function
}
รูป: ตัวอย่างรูปคลื่นสัญญาณ PWM ที่มีความถี่ 500Hz แต่มีค่า Duty Cycle แตกต่างกันในแต่ละช่วงเวลา
▷ ตัวอย่างที่ 8: RGB LED (Single-Pixel WS2812)#
ตัวอย่างโค้ดถัดไปสาธิตการใช้งานไลบารี tinygo.org/x/drivers/ws2812
เพื่อใช้ในการกำหนดค่าสีให้กับไอซี WS2812 จำนวน 1 พิกเซล โดยนำมาต่อเข้ากับขา GPIO23
และเปลี่ยนค่าสีไปตามลำดับในอาร์เรย์ COLORS
เว้นระยะเวลา 500 มิลลิวินาที
package main
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers/ws2812"
)
// Create a color pattern (RGB values)
var COLORS = []color.RGBA{
{R: 255, G: 0, B: 0}, // Red
{R: 0, G: 255, B: 0}, // Green
{R: 0, G: 0, B: 255}, // Blue
{R: 255, G: 255, B: 0}, // Yellow
{R: 0, G: 255, B: 255}, // Cyan
{R: 255, G: 0, B: 255}, // Magenta
{R: 255, G: 255, B: 255}, // White
{R: 0, G: 0, B: 0}, // Off
}
var neopixel ws2812.Device
func main() {
// Define the data pin for WS2812
dataPin := machine.GPIO23
dataPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
// Initialize the WS2812 RGB LED
neopixel = ws2812.NewWS2812(dataPin)
numColors := len(COLORS)
for {
for _, c := range COLORS { // For each color
neopixel.WriteColors([]color.RGBA{c}) // Update Color
time.Sleep(500 * time.Millisecond)
}
for i := 0; i < numColors; i++ { // For each color
neopixel.WriteColors(COLORS[i : i+1]) // Update color
time.Sleep(500 * time.Millisecond)
}
}
}
ชิป RP2040 มีวงจรภายในประเภทหนึ่งที่เรียกว่า PIO (Programmable Input/Output) และสามารถนำมาใช้ในการส่งข้อมูลเพื่อกำหนดค่าสีให้กับ WS2812B ได้ และช่วยลดภาระการทำงานของซีพียู การเขียนโค้ดก็ทำได้สะดวกเนื่องจากมีไลบารีต่อไปนี้ให้ใช้งาน
github.com/tinygo-org/pio/rp2-pio/piolib
(อ้างอิงโดยใช้ชื่อpio
) สำหรับการใช้งานวงจร PIOgithub.com/tinygo-org/pio/rp2-pio/piolib
สำหรับการใช้ PIO เพื่อควบคุมการทำงานของ WS2812B
ตัวอย่างโค้ดมีดังนี้
package main
import (
"image/color"
"machine"
"time"
pio "github.com/tinygo-org/pio/rp2-pio"
"github.com/tinygo-org/pio/rp2-pio/piolib"
)
// Create a color pattern (RGB values)
var COLORS = []color.RGBA{
{R: 255, G: 0, B: 0}, // Red
{R: 0, G: 255, B: 0}, // Green
{R: 0, G: 0, B: 255}, // Blue
{R: 255, G: 255, B: 0}, // Yellow
{R: 0, G: 255, B: 255}, // Cyan
{R: 255, G: 0, B: 255}, // Magenta
{R: 255, G: 255, B: 255}, // White
{R: 0, G: 0, B: 0}, // Off
}
type NeoPixel struct {
Pin machine.Pin
ws2812 *piolib.WS2812B
}
func NewNeoPixel(pin machine.Pin) *NeoPixel {
// Use the state machine (SM) of the PIO unit 0
sm, _ := pio.PIO0.ClaimStateMachine()
// Create piolib.WS2812B that uses the SM of PIO0
ws, _ := piolib.NewWS2812B(sm, pin)
ws.EnableDMA(true)
return &NeoPixel{
ws2812: ws,
}
}
func (neopixel *NeoPixel) PutColor(c color.Color) {
neopixel.ws2812.PutColor(c)
}
func (neopixel *NeoPixel) WriteRaw(rawGRB []uint32) error {
return neopixel.ws2812.WriteRaw(rawGRB)
}
func main() {
println("Tinygo RP2040-PIO WS2812 Demo..")
// Define the data pin for WS2812
dataPin := machine.GPIO23
dataPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
// Initialize the WS2812 RGB LED
neopixel := NewNeoPixel(dataPin)
for {
for _, c := range COLORS {
neopixel.PutColor(c)
time.Sleep(1000 * time.Millisecond)
}
}
}
▷ ตัวอย่างที่ 9: Device ID & CPU Temperature Reading#
โค้ดตัวอย่างถัดไป สาธิตการอ่านหมายเลขของชิป (Device ID) โดยใช้คำสั่ง machine.DeviceID()
ซึ่งจะได้ข้อมูล 8 ไบต์ และอ่านค่าอุณหภูมิภายในชิป RP2040 โดยใช้คำสั่ง machine.ReadTemperature()
ซึ่งจะได้ค่าตัวเลขจำนวนเต็มแบบ int32
ที่จะต้องนำไปหารด้วย 1000 จึงจะได้ค่าอุณหภูมิที่เป็นเลขทศนิยม
และมีหน่วยเป็นองศาเซลเซียล แล้วส่งเป็นข้อความออกมาพอร์ต USB-CDC
package main
import (
"encoding/hex"
"machine"
"strconv"
"time"
)
func main() {
time.Sleep(time.Second)
// Retrieve the device ID as a byte slice
deviceID := machine.DeviceID()
println("#Number of bytes: ", len(deviceID))
println("#DeviceID: " + hex.EncodeToString(deviceID))
for {
// Read the built-in temperature sensor.
value := float64(machine.ReadTemperature()) / 1000.0
// Convert a float (64-bit) to a string
valueString := strconv.FormatFloat(value, 'f', 1, 64)
println("CPUTemp:" + valueString)
time.Sleep(100 * time.Millisecond)
}
}
รูป: ตัวอย่างการรับข้อความและแสดงผลเป็นรูปกราฟสัญญาณด้วย Arduino Serial Plotter
▷ กล่าวสรุป#
บทความนี้ได้นำเสนอตัวอย่างการเขียนโค้ดด้วยภาษา Go และคอมไพล์โค้ดด้วย TinyGo Compiler สำหรับบอร์ดไมโครคอนโทรลเลอร์ RP2040 SoC เช่น Raspberry Pi Pico และ VCC-GND Studio YD-RP2040
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Created: 2024-12-20 | Last Updated: 2024-12-23