2026-03-29 10:30:58 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
2026-03-29 17:58:08 +00:00
|
|
|
"image"
|
2026-03-29 10:30:58 +00:00
|
|
|
"machine"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"image/color"
|
|
|
|
|
|
2026-03-29 17:58:08 +00:00
|
|
|
draw2 "golang.org/x/image/draw"
|
|
|
|
|
|
|
|
|
|
"tinygo.org/x/drivers/amg88xx"
|
|
|
|
|
"tinygo.org/x/drivers/encoders"
|
2026-03-29 10:30:58 +00:00
|
|
|
"tinygo.org/x/drivers/st7789"
|
2026-03-29 17:58:08 +00:00
|
|
|
"tinygo.org/x/drivers/tone"
|
|
|
|
|
"tinygo.org/x/drivers/ws2812"
|
2026-03-29 10:30:58 +00:00
|
|
|
)
|
|
|
|
|
|
2026-03-29 17:58:08 +00:00
|
|
|
const AMG88XX_SIZE = 8
|
|
|
|
|
const AMG88XX_PIXELS = 24
|
|
|
|
|
|
|
|
|
|
var data [AMG88XX_SIZE * AMG88XX_SIZE]int16
|
|
|
|
|
var pixels [AMG88XX_PIXELS * AMG88XX_PIXELS]int16
|
|
|
|
|
var adj [16]int16
|
|
|
|
|
|
2026-03-29 10:30:58 +00:00
|
|
|
func main() {
|
2026-03-29 17:58:08 +00:00
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
|
i2c := machine.I2C1
|
|
|
|
|
i2c.Configure(machine.I2CConfig{
|
|
|
|
|
Frequency: 2.0 * machine.MHz,
|
|
|
|
|
SDA: machine.P0_17,
|
|
|
|
|
SCL: machine.P0_20,
|
|
|
|
|
})
|
2026-03-29 10:30:58 +00:00
|
|
|
|
|
|
|
|
machine.SPI0.Configure(machine.SPIConfig{
|
|
|
|
|
SCK: machine.P1_01,
|
|
|
|
|
SDO: machine.P1_02,
|
|
|
|
|
Frequency: 2000000,
|
|
|
|
|
Mode: 0,
|
|
|
|
|
})
|
|
|
|
|
display := st7789.New(machine.SPI0,
|
|
|
|
|
machine.P1_15, // TFT_RESET
|
|
|
|
|
machine.P1_13, // TFT_DC
|
|
|
|
|
machine.P0_10, // TFT_CS
|
|
|
|
|
machine.P0_09) // TFT_LITE
|
|
|
|
|
|
|
|
|
|
display.Configure(st7789.Config{
|
|
|
|
|
Rotation: st7789.ROTATION_90,
|
|
|
|
|
Width: 135,
|
|
|
|
|
Height: 240,
|
|
|
|
|
RowOffset: 40,
|
|
|
|
|
ColumnOffset: 53,
|
|
|
|
|
//FrameRate: st7789.FRAMERATE_111,
|
|
|
|
|
//VSyncLines: st7789.MAX_VSYNC_SCANLINES,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
width, height := display.Size()
|
|
|
|
|
width = 240
|
|
|
|
|
height = 135
|
|
|
|
|
white := color.RGBA{255, 255, 255, 255}
|
|
|
|
|
red := color.RGBA{255, 0, 0, 255}
|
|
|
|
|
blue := color.RGBA{0, 0, 255, 255}
|
|
|
|
|
green := color.RGBA{0, 255, 0, 255}
|
|
|
|
|
black := color.RGBA{0, 0, 0, 255}
|
|
|
|
|
|
2026-03-29 17:58:08 +00:00
|
|
|
wsPin := machine.P1_11
|
|
|
|
|
wsPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
|
|
|
|
ws := ws2812.NewWS2812(wsPin)
|
|
|
|
|
wsLeds := [2]color.RGBA{}
|
|
|
|
|
for i := range wsLeds {
|
|
|
|
|
wsLeds[i] = black
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 10:30:58 +00:00
|
|
|
machine.InitADC()
|
|
|
|
|
ax := machine.ADC{Pin: machine.P0_29}
|
|
|
|
|
ay := machine.ADC{Pin: machine.P0_02}
|
|
|
|
|
ax.Configure(machine.ADCConfig{})
|
|
|
|
|
ay.Configure(machine.ADCConfig{})
|
|
|
|
|
|
2026-03-29 17:58:08 +00:00
|
|
|
bzrPin := machine.P0_31
|
|
|
|
|
pwm := machine.PWM0
|
|
|
|
|
speaker, _ := tone.New(pwm, bzrPin)
|
|
|
|
|
|
|
|
|
|
enc := encoders.NewQuadratureViaInterrupt(machine.P1_00, machine.P0_24)
|
|
|
|
|
enc.Configure(encoders.QuadratureConfig{
|
|
|
|
|
Precision: 4,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
buttons := []machine.Pin{machine.P0_22, machine.P1_06, machine.P1_04}
|
|
|
|
|
for c := range buttons {
|
|
|
|
|
buttons[c].Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println("STARTING CAMERA")
|
|
|
|
|
camera := amg88xx.New(machine.I2C1)
|
|
|
|
|
camera.Configure(amg88xx.Config{})
|
|
|
|
|
println("CAMERA STARTED")
|
|
|
|
|
|
|
|
|
|
var value int16
|
|
|
|
|
|
2026-03-29 10:30:58 +00:00
|
|
|
display.FillScreen(black)
|
|
|
|
|
|
|
|
|
|
display.FillRectangle(0, 0, width/2, height/2, white)
|
|
|
|
|
display.FillRectangle(width/2, 0, width/2, height/2, red)
|
|
|
|
|
display.FillRectangle(0, height/2, width/2, height/2, green)
|
|
|
|
|
display.FillRectangle(width/2, height/2, width/2, height/2, blue)
|
|
|
|
|
display.FillRectangle(width/4, height/4, width/2, height/2, black)
|
|
|
|
|
|
2026-03-29 17:58:08 +00:00
|
|
|
redgreen := true
|
|
|
|
|
f := 100
|
|
|
|
|
rotaryOldValue := 0
|
2026-03-29 10:30:58 +00:00
|
|
|
for {
|
|
|
|
|
println(ax.Get(), ay.Get())
|
2026-03-29 17:58:08 +00:00
|
|
|
if redgreen {
|
|
|
|
|
wsLeds[0] = red
|
|
|
|
|
wsLeds[1] = green
|
|
|
|
|
} else {
|
|
|
|
|
wsLeds[0] = green
|
|
|
|
|
wsLeds[1] = red
|
|
|
|
|
}
|
|
|
|
|
redgreen = !redgreen
|
|
|
|
|
ws.WriteColors(wsLeds[:])
|
|
|
|
|
f++
|
|
|
|
|
|
|
|
|
|
if f >= 100 {
|
|
|
|
|
f = 0
|
|
|
|
|
speaker.SetNote(tone.C5)
|
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
speaker.Stop()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if newValue := enc.Position(); newValue != rotaryOldValue {
|
|
|
|
|
println("value: ", newValue)
|
|
|
|
|
rotaryOldValue = newValue
|
|
|
|
|
}
|
|
|
|
|
println("ROTARY BTN:", !buttons[0].Get(), "UP:", !buttons[1].Get(), "DOWN:", !buttons[2].Get())
|
|
|
|
|
|
|
|
|
|
// get the values of the sensor in millicelsius
|
|
|
|
|
camera.ReadPixels(&data)
|
|
|
|
|
|
|
|
|
|
srcImage := image.NewRGBA(image.Rect(0, 0, 8, 8))
|
|
|
|
|
for j := 0; j < AMG88XX_SIZE; j++ {
|
|
|
|
|
for i := 0; i < AMG88XX_SIZE; i++ {
|
|
|
|
|
value = data[63-(i+j*AMG88XX_SIZE)]
|
|
|
|
|
// treat anything below 18°C as 18°C
|
|
|
|
|
if value < 18000 {
|
|
|
|
|
value = 0
|
|
|
|
|
} else {
|
|
|
|
|
value = (value - 18000) / 36
|
|
|
|
|
// our color array only have 433 values, avoid getting a value that doesn't exist
|
|
|
|
|
if value > 432 {
|
|
|
|
|
value = 432
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
srcImage.Set(i, j, colors[value])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dst := image.NewRGBA(image.Rect(0, 0, 24, 24))
|
|
|
|
|
draw2.BiLinear.Scale(dst, image.Rect(0, 0, 24, 24), srcImage, image.Rect(0, 0, 8, 8), draw2.Over, nil)
|
|
|
|
|
|
|
|
|
|
for j := 0; j < AMG88XX_PIXELS; j++ {
|
|
|
|
|
for i := 0; i < AMG88XX_PIXELS; i++ {
|
|
|
|
|
display.FillRectangle(int16(60+(AMG88XX_PIXELS-i-1)*5), 7+int16(j*5), 5, 5, dst.RGBAAt(i, j))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 10:30:58 +00:00
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
}
|
|
|
|
|
}
|