學 Go 玩創客,TinyGo 初體驗(3):使用 BBC micro:bit 與 TinyGo drivers 驅動周邊元件,Part I

Why micro:bit?

micro:bit 在全球各地區都有經銷,因此這塊板子在台灣的小學程式課程也相當熱門。微軟與 Python 基金會分別提供了線上版的 MakeCode 積木編輯器(TypeScript)和 MicroPython 編輯器,此外也有大量來自對岸的 micro:bit 擴充教材出現。

Photo by Annie Spratt on Unsplash
  1. 不須安裝額外的燒錄程式。
  2. 甚至,在使用 tinygo flash 指令上傳程式時,你還不必指定 -port 參數。(就目前筆者在 Windows 上測試是如此。)除非是你同時接了一些其他板子,無法燒錄時會要求你指定 port。
Photo by Mohammad Metri on Unsplash

目前 TinyGo 對 micro:bit 還不支援的地方

  1. 無法使用藍芽或「廣播」。
  2. 沒有 ADC(類比輸入)。
  3. 有驅動程式能用來控制其 5x5 LED 矩陣,但還沒有能顯示文字的字庫。

準備材料

你需要一片 BBC micro:bit,以及一塊 micro:bit 用的腳位擴充板(edge connector)。你不需購買那種很貴、裝有電池或一堆感測器的擴充板,只要能將所有腳位轉成針腳即可。

micro:bit 腳位

共時性 LED 控制

第一個範例先回頭來看 Blinky 範例的一個變形版 — — 這回我們要控制 2 個外接 LED 以不同部的速度閃爍。這正是 Go 語言最出名的特色之一:concurrency(共時性)。這也是先前在使用 Arduino Uno 時所無法使用的功能。

  1. LED 2 正極 -> P2
  2. LED 負極 -> G (Gnd)
package mainimport (
"machine"
"time"
)
func main() {
go led1()
led2()
}
func led1() {
led := machine.P1
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
for {
led.High()
delay(500)
led.Low()
delay(500)
}
}
func led2() {
led := machine.P2
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
for {
led.High()
delay(400)
led.Low()
delay(400)
}
}
func delay(t uint16) {
time.Sleep(time.Duration(1000000 * uint32(t)))
}
tinygo flash -target microbit main
tinygo flash -target microbit -port COMX main
func main() {
go led1()
go led2()
delay(100)
}
Photo by JOSHUA COLEMAN on Unsplash
tinygo flash -scheduler coroutines -target arduino -port COMX main

不使用 time.Sleep 和共時性的延遲方法

如果不使用前面的辦法,另一個讓 LED 燈不同步閃爍的可能解法是用 time.Since() 來判斷程式執行後過了多少時間:

package mainimport (
"machine"
"time"
)
func main() {
led1 := machine.P1
led2 := machine.P2
led1.Configure(machine.PinConfig{1})
led2.Configure(machine.PinConfig{1})
ledSwitch1 := true
ledSwitch2 := true
start1 := time.Now()
start2 := time.Now()
for {
if time.Since(start1) >= time.Millisecond*500 {
led.Set(ledSwitch1)
ledSwitch1 = !ledSwitch1
start1 = time.Now()
}
if time.Since(start2) >= time.Millisecond*400 {
led.Set(ledSwitch2)
ledSwitch2 = !ledSwitch2
start2 = time.Now()
}
}
}

使用 TinyGo drivers

Photo by Louis Hansel @shotsoflouis on Unsplash

下載 TinyGo drivers

最簡單的下載方式是先安裝 Git,然後在命令提示字元或終端機輸入以下指令:

go get tinygo.org/x/drivers

NeoPixel(WS2812)RGB LED

又稱 NeoPixel 的 WS2812 RGB LED 燈條是個神奇的

  1. Vcc -> 3V
  2. Gnd -> G
package mainimport (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers/ws2812"
)
const (
LED_PIN = machine.Pin(2)
LED_NUM = 12
LED_MAX = 64 // max 255
LED_ROTATE_DELAY = 50 // ms
)
func main() { LED_PIN.Configure(machine.PinConfig{Mode: machine.PinOutput})
neoPixel := ws2812.New(LED_PIN)
var leds [LED_NUM]color.RGBA
change := uint8(LED_MAX / (LED_NUM / 3))
index := [3]uint8{0, uint8(LED_NUM / 3), uint8(LED_NUM / 3 * 2)}
for i := range leds {led_color := [3]uint8{0, 0, 0}
for j := range index {
if abs(int8(uint8(i)-index[j])) <= index[1] {
led_color[j] = LED_MAX_LEVEL - abs(int8(uint8(i)-index[j]))*change
}
}
if uint8(i) >= index[2] {
led_color[0] = LED_MAX_LEVEL - (LED_NUM-uint8(i))*change
}
leds[i] = color.RGBA{R: led_color[0], G: led_color[1], B: led_color[2]}
} neoPixel.WriteColors(leds[:])
time.Sleep(time.Millisecond * 10)
for { var ledsTmp []color.RGBA ledsTmp = leds[1:LED_NUM]
ledsTmp = append(ledsTmp, leds[0])
copy(leds[:], ledsTmp[:])
neoPixel.WriteColors(leds[:])
time.Sleep(time.Millisecond * LED_ROTATE_DELAY)
}}func abs(x int8) uint8 {
if x < 0 {
return uint8(-x)
} else {
return uint8(x)
}
}
        for {
for i := range colors {
for j := range neoLeds {
neoLeds[j] = colors[i]
ws.WriteColors(neoLeds[:])
time.Sleep(time.Millisecond * 100)
}
}
}

Former translator, after-hours Maker, sunny-day analog film shooter. Currently a junior tech-book editor based in Taiwan. https://krantasblog.blogspot.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store