diff --git a/.circleci/config.yml b/.circleci/config.yml index 78ec7ed..b3f460d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -25,5 +25,6 @@ jobs: - run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/mag3110/main.go - run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/mma8653/main.go - run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/mpu6050/main.go + - run: tinygo build -size short -o test.elf -target=circuitplay-express ./examples/thermistor/main.go - run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/vl53l1x/main.go - run: tinygo build -size short -o test.elf -target=circuitplay-express ./examples/ws2812/main.go diff --git a/README.md b/README.md index 9cc14de..9af0a3a 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ func main() { | [MAG3110 magnetometer](https://www.nxp.com/docs/en/data-sheet/MAG3110.pdf) | I2C | | [MMA8653 accelerometer](https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf) | I2C | | [MPU6050 accelerometer/gyroscope](https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf) | I2C | +| [Thermistor](https://www.farnell.com/datasheets/33552.pdf) | ADC | | [VL53L1X time-of-flight distance sensor](https://www.st.com/resource/en/datasheet/vl53l1x.pdf) | I2C | | [WS2812 RGB LED](https://cdn-shop.adafruit.com/datasheets/WS2812.pdf) | GPIO | diff --git a/examples/thermistor/main.go b/examples/thermistor/main.go new file mode 100644 index 0000000..281d273 --- /dev/null +++ b/examples/thermistor/main.go @@ -0,0 +1,26 @@ +// This example uses the settings for the thermistor that is built in to the +// Adafruit Circuit Playground Express. +package main + +import ( + "machine" + "time" + + "github.com/tinygo-org/drivers/thermistor" +) + +const ADC_PIN = machine.TEMPSENSOR + +func main() { + machine.InitADC() + + sensor := thermistor.New(ADC_PIN) + sensor.Configure() + + for { + temp, _ := sensor.ReadTemperature() + println("Temperature:", temp/1000, "ºC") + + time.Sleep(2 * time.Second) + } +} diff --git a/thermistor/thermistor.go b/thermistor/thermistor.go new file mode 100644 index 0000000..462b9ed --- /dev/null +++ b/thermistor/thermistor.go @@ -0,0 +1,86 @@ +// Package thermistor is for temperature sensing using a thermistor +// such as the NTC 3950. +// +// Datasheet: https://www.farnell.com/datasheets/33552.pdf +// +// This code is an interpretation of Adafruit Thermistor module in Python: +// https://github.com/adafruit/Adafruit_CircuitPython_Thermistor +// +// It uses the Steinhart–Hart equation to calculate the temperature +// based on the resistance: +// https://en.wikipedia.org/wiki/Steinhart%E2%80%93Hart_equation +// +// To use with other thermistors adjust the BCoefficient and NominalTemperature +// values to match the specific thermistor you wish to use. +// +// sensor.NominalTemperature = 25 +// sensor.BCoefficient = 3950 +// +// Set the SeriesResistor and NominalResistance based on the microcontroller voltage and +// circuit that you have in use. Set HighSide based on if the thermistor is connected from +// the ADC pin to the powered side (true) or to ground (false). +// +// sensor.SeriesResistor = 10000 +// sensor.NominalResistance = 10000 +// sensor.HighSide = true +// +package thermistor + +import ( + "machine" + "math" +) + +// Device holds the ADC pin and the needed settings for calculating the +// temperature based on the resistance. +type Device struct { + adc *machine.ADC + SeriesResistor uint32 + NominalResistance uint32 + NominalTemperature uint32 + BCoefficient uint32 + HighSide bool +} + +// New returns a new thermistor driver given an ADC pin. +func New(pin uint8) Device { + adc := machine.ADC{pin} + return Device{ + adc: &adc, + SeriesResistor: 10000, + NominalResistance: 10000, + NominalTemperature: 25, + BCoefficient: 3950, + HighSide: true, + } +} + +// Configure configures the ADC pin used for the thermistor. +func (d *Device) Configure() { + d.adc.Configure() +} + +// ReadTemperature returns the temperature in celsius milli degrees (ºC/1000) +func (d *Device) ReadTemperature() (temperature int32, err error) { + var reading uint32 + if d.HighSide { + // Thermistor connected from analog input to high logic level. + val := d.adc.Get() + reading = uint32(val) / 64 + reading = (1023 * d.SeriesResistor) / reading + reading -= d.SeriesResistor + } else { + // Thermistor connected from analog input to ground. + reading = d.SeriesResistor / uint32(65535/d.adc.Get()-1) + } + + var steinhart float64 + steinhart = float64(reading) / float64(d.NominalResistance) // (R/Ro) + steinhart = math.Log(steinhart) // ln(R/Ro) + steinhart /= float64(d.BCoefficient) // 1/B * ln(R/Ro) + steinhart += 1.0 / (float64(d.NominalTemperature) + 273.15) // + (1/To) + steinhart = 1.0 / steinhart // Invert + steinhart -= 273.15 // convert to C + + return int32(steinhart * 1000), nil +}