Skip to content

Commit d050951

Browse files
committed
add hx711 driver
1 parent 228e57c commit d050951

File tree

8 files changed

+1594
-2
lines changed

8 files changed

+1594
-2
lines changed

examples/hx711/main.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package main
2+
3+
import (
4+
"machine"
5+
"time"
6+
7+
"tinygo.org/x/drivers/hx711"
8+
)
9+
10+
const (
11+
clockOutPin = machine.D3
12+
dataInPin = machine.D2
13+
gainAndChannel = hx711.A128 // only the first channel A is used
14+
tickSleep = 1 * time.Microsecond // set it to zero for slow MCU's
15+
calibrationWait = 10 * time.Second
16+
cycleTime = 1 * time.Second
17+
)
18+
19+
// please adjust to your load used for calibration
20+
const (
21+
setLoad = 100 // used unit will equal the measured unit
22+
unit = "gram"
23+
)
24+
25+
func main() {
26+
time.Sleep(5 * time.Second) // wait for monitor connection
27+
28+
cfg := hx711.DefaultConfig
29+
cfg.TickSleep = tickSleep
30+
31+
clockOutPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
32+
dataInPin.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
33+
34+
clockOutPinSet := func(v bool) error { clockOutPin.Set(v); return nil }
35+
dataInPinGet := func() (bool, error) { return dataInPin.Get(), nil }
36+
37+
sensor := hx711.New(clockOutPinSet, dataInPinGet, gainAndChannel)
38+
if err := sensor.Configure(&cfg); err != nil {
39+
println("Configure failed")
40+
panic(err)
41+
}
42+
43+
println("Please remove the mass completely for zeroing within", calibrationWait.String())
44+
time.Sleep(calibrationWait)
45+
println("Zero starts")
46+
if err := sensor.Zero(false); err != nil {
47+
println("Zeroing failed")
48+
panic(err)
49+
}
50+
51+
println("Please apply the load (", setLoad, unit+" ) for calibration within", calibrationWait.String())
52+
time.Sleep(calibrationWait)
53+
println("Calibration starts")
54+
if err := sensor.Calibrate(setLoad, false); err != nil {
55+
println("Calibration failed")
56+
panic(err)
57+
}
58+
59+
offs, factor := sensor.OffsetAndCalibrationFactor(false)
60+
println("Calibration done completely, offset:", offs, "factor:", factor)
61+
62+
println("Measurement starts")
63+
for {
64+
if err := sensor.Update(0); err != nil {
65+
println("Sensor update failed", err.Error())
66+
}
67+
68+
v1, _ := sensor.Values()
69+
70+
println("Mass:", v1, unit)
71+
72+
time.Sleep(cycleTime)
73+
}
74+
}

fraction.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package drivers
2+
3+
import (
4+
"errors"
5+
"math"
6+
)
7+
8+
// Float32Fractions calculates an denominator "den" for a given floating point number "f" and returns this denominator
9+
// together with the resulting nominator "nom", so "f" can be reconstructed by "f = num / den".
10+
// All values are in the range MaxInt32: 2147483647, MinInt32: -2147483648. If the given "f" exceeds this range, it is
11+
// not possible anymore to represent "f" with "f = num / 1" and an error will be returned with the nearest values.
12+
// As an exception we define that "den" is always positive, so negative numbers "f" leads always to negative "num".
13+
//
14+
// Sign:
15+
// "abs(MaxInt32) > abs (MinInt32)", the sign can be applied to "den" or "nom", but we already defined "den" as positive
16+
//
17+
// Considered other options: see function in test file
18+
func Float32Fractions(f float32) (int32, int32, error) {
19+
return float32FractionsIntPartBaseMax(f, math.MaxInt32)
20+
}
21+
22+
// float32FractionsIntPartBaseMax calculates the denominator "den" from the integer part of a given floating point
23+
// number "f" and returns this denominator together with the resulting nominator "nom", so "f" can be reconstructed by
24+
// "f = num / den".
25+
//
26+
// Used formulas:
27+
// For "abs(f)=af < 1" applies the biggest denominator: "den = math.MaxInt32" and "num = af * den". For "af > 0" this
28+
// can be written more generalized when split integer part "ip" from fractional part "fp" with "af = ip + fp":
29+
// "den = math.MaxInt32/(ip + 1)"; "num = af * den"
30+
// very good accuracy can be reached, similar to calculating with "math/big.Rat", but 2-15 times faster:
31+
// max. epsilon = 1.9073486328125e-06 in test for "17459216/697177" on arm64, but better for this example on MCU,
32+
// nrf52840 12.207µs-14.496µs (independent of used base)
33+
func float32FractionsIntPartBaseMax(f float32, baseMax int32) (int32, int32, error) {
34+
//const baseMax = math.MaxInt32
35+
//const baseMax = 1000000000 // 10 digits
36+
//const baseMax = 2000000000 // 10.5 digits
37+
38+
ip, den, err := float32FractionsPreCheck(f)
39+
if den == 1 || err != nil {
40+
return ip, den, err
41+
}
42+
43+
if f < 0 {
44+
ip = -ip
45+
}
46+
47+
den = baseMax / (ip + 1)
48+
if den == 0 {
49+
den = 1
50+
}
51+
52+
return int32(float32(den) * f), den, nil
53+
}
54+
55+
func float32FractionsPreCheck(f float32) (int32, int32, error) {
56+
if f > math.MaxInt32 {
57+
return math.MaxInt32, 1, errors.New("input value exceeds +int32 range")
58+
}
59+
60+
if f < math.MinInt32 {
61+
return math.MinInt32, 1, errors.New("input value exceeds -int32 range")
62+
}
63+
64+
integerPart := int32(f)
65+
if float32(integerPart) == f {
66+
// float is an integer
67+
return int32(integerPart), 1, nil
68+
}
69+
70+
return integerPart, 0, nil
71+
}

0 commit comments

Comments
 (0)