102 lines
2.4 KiB
Go
102 lines
2.4 KiB
Go
package main
|
||
|
||
// Thermal camera example using AMG88xx 8x8 IR sensor.
|
||
// Connect the sensor to I2C1: SDA=P0_17, SCL=P0_20 (3.3V power).
|
||
//
|
||
// The 8x8 sensor data is scaled to 24x24 with bilinear interpolation and
|
||
// rendered with an iron-palette color map on the 240x135 display.
|
||
// Each scaled pixel is drawn as a 10x5 px block → 240x120 total, centered.
|
||
|
||
import (
|
||
"image"
|
||
"machine"
|
||
|
||
draw2 "golang.org/x/image/draw"
|
||
|
||
"tinygo.org/x/drivers/amg88xx"
|
||
"tinygo.org/x/drivers/st7789"
|
||
)
|
||
|
||
const (
|
||
sensorSize = 8 // AMG88xx is 8x8
|
||
scaledSize = 24 // intermediate bilinear-scaled image
|
||
blockW = 10 // px per scaled pixel (horizontal): 24*10 = 240
|
||
blockH = 5 // px per scaled pixel (vertical): 24*5 = 120
|
||
yOffset = 7 // center 120px vertically in 135px display: (135-120)/2
|
||
)
|
||
|
||
var (
|
||
display st7789.Device
|
||
data [sensorSize * sensorSize]int16
|
||
)
|
||
|
||
func main() {
|
||
machine.SPI0.Configure(machine.SPIConfig{
|
||
SCK: machine.P1_01,
|
||
SDO: machine.P1_02,
|
||
Frequency: 8000000,
|
||
Mode: 0,
|
||
})
|
||
|
||
machine.I2C1.Configure(machine.I2CConfig{
|
||
SDA: machine.P0_17,
|
||
SCL: machine.P0_20,
|
||
Frequency: 400000,
|
||
})
|
||
|
||
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,
|
||
})
|
||
|
||
camera := amg88xx.New(machine.I2C1)
|
||
camera.Configure(amg88xx.Config{})
|
||
|
||
src := image.NewRGBA(image.Rect(0, 0, sensorSize, sensorSize))
|
||
dst := image.NewRGBA(image.Rect(0, 0, scaledSize, scaledSize))
|
||
|
||
for {
|
||
camera.ReadPixels(&data)
|
||
|
||
// map each sensor pixel to a palette color
|
||
for j := 0; j < sensorSize; j++ {
|
||
for i := 0; i < sensorSize; i++ {
|
||
v := data[63-(i+j*sensorSize)]
|
||
// clamp to 18°C–33°C range → index 0–432
|
||
if v < 18000 {
|
||
v = 0
|
||
} else {
|
||
v = (v - 18000) / 36
|
||
if v > 432 {
|
||
v = 432
|
||
}
|
||
}
|
||
src.Set(i, j, colors[v])
|
||
}
|
||
}
|
||
|
||
// bilinear upscale 8x8 → 24x24
|
||
draw2.BiLinear.Scale(dst, dst.Bounds(), src, src.Bounds(), draw2.Over, nil)
|
||
|
||
// draw horizontally mirrored (acts as a selfie mirror)
|
||
for j := 0; j < scaledSize; j++ {
|
||
for i := 0; i < scaledSize; i++ {
|
||
display.FillRectangle(
|
||
int16((scaledSize-1-i)*blockW),
|
||
yOffset+int16(j)*blockH,
|
||
blockW, blockH,
|
||
dst.RGBAAt(i, j),
|
||
)
|
||
}
|
||
}
|
||
}
|
||
}
|