Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions examples/hx711/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package main

import (
"machine"
"time"

"tinygo.org/x/drivers/hx711"
)

const (
clockOutPin = machine.D3
dataInPin = machine.D2
gainAndChannel = hx711.A128 // only the first channel A is used
tickSleep = 1 * time.Microsecond // set it to zero for slow MCU's
calibrationWait = 10 * time.Second
cycleTime = 1 * time.Second
)

// please adjust to your load used for calibration
const (
setLoad = 100 // used unit will equal the measured unit
unit = "gram"
)

func main() {
time.Sleep(5 * time.Second) // wait for monitor connection

cfg := hx711.DefaultConfig
cfg.TickSleep = tickSleep

clockOutPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
dataInPin.Configure(machine.PinConfig{Mode: machine.PinInputPullup})

clockOutPinSet := func(v bool) error { clockOutPin.Set(v); return nil }
dataInPinGet := func() (bool, error) { return dataInPin.Get(), nil }

sensor := hx711.New(clockOutPinSet, dataInPinGet, gainAndChannel)
if err := sensor.Configure(&cfg); err != nil {
println("Configure failed")
panic(err)
}

println("Please remove the mass completely for zeroing within", calibrationWait.String())
time.Sleep(calibrationWait)
println("Zero starts")
if err := sensor.Zero(false); err != nil {
println("Zeroing failed")
panic(err)
}

println("Please apply the load (", setLoad, unit+" ) for calibration within", calibrationWait.String())
time.Sleep(calibrationWait)
println("Calibration starts")
if err := sensor.Calibrate(setLoad, false); err != nil {
println("Calibration failed")
panic(err)
}

offs, factor := sensor.OffsetAndCalibrationFactor(false)
println("Calibration done completely, offset:", offs, "factor:", factor)

println("Measurement starts")
for {
if err := sensor.Update(0); err != nil {
println("Sensor update failed", err.Error())
}

v1, _ := sensor.Values()

println("Mass:", v1, unit)

time.Sleep(cycleTime)
}
}
71 changes: 71 additions & 0 deletions fraction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package drivers

import (
"errors"
"math"
)

// Float32Fractions calculates an denominator "den" for a given floating point number "f" and returns this denominator
// together with the resulting nominator "nom", so "f" can be reconstructed by "f = num / den".
// All values are in the range MaxInt32: 2147483647, MinInt32: -2147483648. If the given "f" exceeds this range, it is
// not possible anymore to represent "f" with "f = num / 1" and an error will be returned with the nearest values.
// As an exception we define that "den" is always positive, so negative numbers "f" leads always to negative "num".
//
// Sign:
// "abs(MaxInt32) > abs (MinInt32)", the sign can be applied to "den" or "nom", but we already defined "den" as positive
//
// Considered other options: see function in test file
func Float32Fractions(f float32) (int32, int32, error) {
return float32FractionsIntPartBaseMax(f, math.MaxInt32)
}

// float32FractionsIntPartBaseMax calculates the denominator "den" from the integer part of a given floating point
// number "f" and returns this denominator together with the resulting nominator "nom", so "f" can be reconstructed by
// "f = num / den".
//
// Used formulas:
// For "abs(f)=af < 1" applies the biggest denominator: "den = math.MaxInt32" and "num = af * den". For "af > 0" this
// can be written more generalized when split integer part "ip" from fractional part "fp" with "af = ip + fp":
// "den = math.MaxInt32/(ip + 1)"; "num = af * den"
// very good accuracy can be reached, similar to calculating with "math/big.Rat", but 2-15 times faster:
// max. epsilon = 1.9073486328125e-06 in test for "17459216/697177" on arm64, but better for this example on MCU,
// nrf52840 12.207µs-14.496µs (independent of used base)
func float32FractionsIntPartBaseMax(f float32, baseMax int32) (int32, int32, error) {
//const baseMax = math.MaxInt32
//const baseMax = 1000000000 // 10 digits
//const baseMax = 2000000000 // 10.5 digits

ip, den, err := float32FractionsPreCheck(f)
if den == 1 || err != nil {
return ip, den, err
}

if f < 0 {
ip = -ip
}

den = baseMax / (ip + 1)
if den == 0 {
den = 1
}

return int32(float32(den) * f), den, nil
}

func float32FractionsPreCheck(f float32) (int32, int32, error) {
if f > math.MaxInt32 {
return math.MaxInt32, 1, errors.New("input value exceeds +int32 range")
}

if f < math.MinInt32 {
return math.MinInt32, 1, errors.New("input value exceeds -int32 range")
}

integerPart := int32(f)
if float32(integerPart) == f {
// float is an integer
return int32(integerPart), 1, nil
}

return integerPart, 0, nil
}
Loading
Loading