Skip to content

Commit 866f3f1

Browse files
committed
feature/unit/weight_i2c: STM32+HX711 to achieve 24-bit precision weight
1 parent f00e114 commit 866f3f1

File tree

3 files changed

+147
-0
lines changed

3 files changed

+147
-0
lines changed

m5stack/libs/unit/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"RTC8563Unit": "rtc8563",
4949
"VMeterUnit": "vmeter",
5050
"AMeterUnit": "ameter",
51+
"WEIGHT_I2CUnit": "weight_i2c",
5152
}
5253

5354

m5stack/libs/unit/manifest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"rtc8563.py",
5151
"vmeter.py",
5252
"ameter.py",
53+
"weight_i2c.py",
5354
),
5455
base_path="..",
5556
opt=0,

m5stack/libs/unit/weight_i2c.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
from machine import I2C
2+
from .pahub import PAHUBUnit
3+
from .unit_helper import UnitError
4+
import struct
5+
import sys
6+
7+
if sys.platform != "esp32":
8+
from typing import Union
9+
10+
import time
11+
import struct
12+
13+
WEIGHT_I2C_ADDR = 0x26
14+
15+
ADC_REG = 0x00
16+
WEIGHT_REG = 0x10
17+
GAP_REG = 0x40
18+
OFFSET_REG = 0x50
19+
WEIGHT_X100_REG = 0x60
20+
WEIGHT_STR_REG = 0x70
21+
FILTER_IP_REG = 0x80
22+
FILTER_AVG_REG = 0x81
23+
FILTER_EMA_REG = 0x82
24+
FW_VER_REG = 0xFE
25+
I2C_ADDR_REG = 0xFF
26+
27+
class WEIGHT_I2CUnit:
28+
29+
def __init__(self, i2c: Union[I2C, PAHUBUnit], addr=WEIGHT_I2C_ADDR) -> None:
30+
"""Initialize the weight i2c sensor."""
31+
self.i2c = i2c
32+
if addr >= 1 and addr <= 127:
33+
self.unit_addr = addr
34+
self._available()
35+
36+
def _available(self) -> None:
37+
"""! Check if sensor is available on the I2C bus."""
38+
if not (self.unit_addr in self.i2c.scan()):
39+
raise UnitError("Weight Unit not found in Grove")
40+
41+
@property
42+
def get_adc_raw(self) -> int:
43+
"""! Get the ADC value."""
44+
data = self.i2c.readfrom_mem(self.unit_addr, ADC_REG, 4)
45+
return struct.unpack('<I', data)[0]
46+
47+
@property
48+
def get_weight_float(self) -> float:
49+
"""! Get the weight in grams(float)."""
50+
data = self.i2c.readfrom_mem(self.unit_addr, WEIGHT_REG, 4)
51+
return round(struct.unpack('<f', data)[0], 3)
52+
53+
def set_calibration(self, weight1_g: float, weight1_adc: int, weight2_g: float, weight2_adc: int) -> None:
54+
"""! Calibration the Weight I2C sensor.
55+
56+
(1) step 1: Reset offset;
57+
(2) step 2: Get RawADC, this is RawADC_0g
58+
(3) step 3: Put 100g weight on it, and get RawADC, this is RawADC_100g
59+
(4) step 4: Calculate the value of GAP = (RawADC_100g-RawADC0g) / 100
60+
(5) step 5: Write GAP value to the unit Via I2C
61+
62+
weight1_g: Weight1 in grams.
63+
weight1_adc: Weight1 in ADC.
64+
weight2_g: Weight2 in grams.
65+
weight2_adc: Weight2 in ADC.
66+
"""
67+
68+
gap = abs(weight2_adc - weight1_adc) / abs(weight2_g - weight1_g)
69+
self.i2c.writeto_mem(self.unit_addr, GAP_REG, struct.pack('<f', gap))
70+
time.sleep_ms(200)
71+
72+
def set_reset_offset(self) -> None:
73+
"""! Reset offest weight value to zero."""
74+
self.i2c.writeto_mem(self.unit_addr, OFFSET_REG, b'\x01')
75+
76+
@property
77+
def get_weight_int(self) -> int:
78+
"""! Get the weight in grams(int)."""
79+
data = self.i2c.readfrom_mem(self.unit_addr, WEIGHT_X100_REG, 4)
80+
return struct.unpack('<i', data)[0]
81+
82+
@property
83+
def get_weight_str(self) -> str:
84+
"""! Get the weight in grams(str)."""
85+
data = self.i2c.readfrom_mem(self.unit_addr, WEIGHT_STR_REG, 16)
86+
return data.replace(b'\x00', b'').decode('utf8')
87+
88+
def set_lowpass_filter(self, enabled: bool) -> None:
89+
"""! Set low pass filter enabled or not
90+
enabled: Enable or Disable
91+
"""
92+
self.i2c.writeto_mem(self.unit_addr, FILTER_IP_REG, bytes([enabled]))
93+
94+
@property
95+
def get_lowpass_filter(self) -> bool:
96+
"""! Get low pass filter enabled or not."""
97+
return bool(self.i2c.readfrom_mem(self.unit_addr, FILTER_IP_REG, 1)[0])
98+
99+
def set_average_filter_level(self, level: int) -> None:
100+
"""! Set average filter level
101+
level of average filter, larger value for smoother result but more latency
102+
level: 0~50
103+
"""
104+
if level > 50 or level < 0:
105+
raise UnitError("Level for average filter must between 0 ~ 50")
106+
107+
self.i2c.writeto_mem(self.unit_addr, FILTER_AVG_REG, struct.pack('b', level))
108+
109+
@property
110+
def get_average_filter_level(self) -> int:
111+
"""! Get average filter level."""
112+
return self.i2c.readfrom_mem(self.unit_addr, FILTER_AVG_REG, 1)[0]
113+
114+
def set_ema_filter_alpha(self, alpha: int) -> None:
115+
"""! Set ema filter alpha
116+
alpha of ema filter, smaller value for smoother result but more latency
117+
alpha: 0~99
118+
"""
119+
if alpha > 99 or alpha < 0:
120+
raise Exception("Alpha for EMA filter must between 0 ~ 99")
121+
122+
self.i2c.writeto_mem(self.unit_addr, FILTER_EMA_REG, struct.pack('b', alpha))
123+
124+
@property
125+
def get_ema_filter_alpha(self) -> int:
126+
"""! Get ema filter alpha."""
127+
return self.i2c.readfrom_mem(self.unit_addr, FILTER_EMA_REG, 1)[0]
128+
129+
def get_device_spec(self, mode) -> int:
130+
"""! Get device firmware version and i2c address.
131+
mode: 0xFE and 0xFF
132+
"""
133+
if mode >= FW_VER_REG and mode <= I2C_ADDR_REG:
134+
return self.i2c.readfrom_mem(self.unit_addr, mode, 1)[0]
135+
136+
def set_i2c_address(self, addr) -> None:
137+
"""! Set i2c address.
138+
addr: 1 to 127
139+
"""
140+
if addr >= 1 and addr <= 127:
141+
if addr != self.unit_addr:
142+
self.i2c.writeto_mem(self.unit_addr, I2C_ADDR_REG, struct.pack('b', addr))
143+
self.unit_addr = addr
144+
time.sleep_ms(200)
145+

0 commit comments

Comments
 (0)