forked from google/periph
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hx711.go
153 lines (132 loc) · 3.66 KB
/
hx711.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package hx711 implements an interface to the HX711 analog to digital converter.
//
// Datasheet
//
// http://www.aviaic.com/Download/hx711F_EN.pdf.pdf
package hx711
import (
"errors"
"time"
"periph.io/x/periph/conn/gpio"
)
var (
// TimeoutError is returned from Read and ReadAveraged when the ADC took too
// long to indicate data was available.
TimeoutError = errors.New("timed out waiting for HX711 to become ready")
)
// InputMode controls the voltage gain and the channel multiplexer on the HX711.
// Channel A can be used with a gain of 128 or 64, and Channel B can be used
// with a gain of 32.
type InputMode int
const (
CHANNEL_A_GAIN_128 InputMode = 1
CHANNEL_A_GAIN_64 InputMode = 3
CHANNEL_B_GAIN_32 InputMode = 2
)
type Dev struct {
inputMode InputMode
clk gpio.PinOut
data gpio.PinIn
done chan struct{}
}
// New creates a new HX711 device.
// The data pin must support edge detection. If your pin doesn't natively
// support edge detection you can use PollEdge from
// periph.io/x/periph/experimental/conn/gpio/gpioutil
func New(clk gpio.PinOut, data gpio.PinIn) (*Dev, error) {
if err := data.In(gpio.PullDown, gpio.FallingEdge); err != nil {
return nil, err
}
if err := clk.Out(gpio.Low); err != nil {
return nil, err
}
return &Dev{
inputMode: CHANNEL_A_GAIN_128,
clk: clk,
data: data,
done: nil,
}, nil
}
// SetInputMode changes the voltage gain and channel multiplexer mode.
func (d *Dev) SetInputMode(inputMode InputMode) {
d.inputMode = inputMode
d.readImmediately()
}
// IsReady returns true if there is data ready to be read from the ADC.
func (d *Dev) IsReady() bool {
return d.data.Read() == gpio.Low
}
// Read reads a single value from the ADC. It blocks until the ADC indicates
// there is data ready for retrieval. If the ADC doesn't pull its Data pin low
// to indicate there is data ready before the timeout is reached, TimeoutError
// is returned.
func (d *Dev) Read(timeout time.Duration) (int32, error) {
// Wait for the falling edge that indicates the ADC has data.
if !d.IsReady() {
if !d.data.WaitForEdge(timeout) {
return 0, TimeoutError
}
}
return d.readImmediately(), nil
}
func (d *Dev) readImmediately() int32 {
// Shift the 24-bit 2's compliment value.
var value uint32
for i := 0; i < 24; i++ {
d.clk.Out(gpio.High)
level := d.data.Read()
d.clk.Out(gpio.Low)
value <<= 1
if level {
value |= 1
}
}
// Pulse the clock 1-3 more times to set the new ADC mode.
for i := 0; i < int(d.inputMode); i++ {
d.clk.Out(gpio.High)
d.clk.Out(gpio.Low)
}
// Convert the 24-bit 2's compliment value to a 32-bit signed value.
return int32(value<<8) >> 8
}
// StartContinuousRead starts reading values continuously from the ADC. It
// returns a channel that you can use to receive these values.
//
// You must call Halt to stop reading.
//
// Calling StartContinuousRead again before Halt is an error,
// and nil will be returned.
func (d *Dev) StartContinuousRead() <-chan int32 {
if d.done != nil {
return nil
}
done := make(chan struct{})
ret := make(chan int32)
go func() {
for {
select {
case <-done:
close(ret)
return
default:
value, err := d.Read(time.Second)
if err == nil {
ret <- value
}
}
}
}()
d.done = done
return ret
}
// Halt stops a continuous read that was started with StartContinuousRead.
// This will close the channel that was returned by StartContinuousRead.
func (d *Dev) Halt() {
if d.done != nil {
close(d.done)
d.done = nil
}
}