Merge pull request #2241 from adafruit/TheKitty-patch-1
Files for the Clue Coffee Scale Guide
This commit is contained in:
commit
53e7a4c87f
7 changed files with 40379 additions and 0 deletions
2
Clue_Scale/README.md
Normal file
2
Clue_Scale/README.md
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Files for the ADafruit Learning System guide Clue Coffee Scale
|
||||
https://learn.adafruit.com/clue-coffee-scale/overview
|
||||
BIN
Clue_Scale/clue_scale_bkg.bmp
Normal file
BIN
Clue_Scale/clue_scale_bkg.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 225 KiB |
84
Clue_Scale/clue_scale_calibrator.py
Normal file
84
Clue_Scale/clue_scale_calibrator.py
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# SPDX-FileCopyrightText: 2022 Jan Goolsbey for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# clue_scale_calibrator.py
|
||||
# 2022-07-29 v1.1.0
|
||||
#
|
||||
# Clue Scale Calibrator - Single Channel Version
|
||||
# Adafruit NAU7802 Stemma breakout example
|
||||
|
||||
import time
|
||||
import board
|
||||
from adafruit_clue import clue
|
||||
from cedargrove_nau7802 import NAU7802
|
||||
|
||||
clue.pixel.brightness = 0.2 # Set NeoPixel brightness
|
||||
clue.pixel[0] = clue.YELLOW # Set status indicator to yellow (initializing)
|
||||
|
||||
SAMPLE_AVG = 500 # Number of sample values to average
|
||||
DEFAULT_GAIN = 128 # Default gain for internal PGA
|
||||
|
||||
# Instantiate 24-bit load sensor ADC
|
||||
nau7802 = NAU7802(board.I2C(), address=0x2A, active_channels=1)
|
||||
|
||||
|
||||
def zero_channel():
|
||||
"""Initiate internal calibration and zero the current channel. Use after
|
||||
power-up, a new channel is selected, or to adjust for measurement drift.
|
||||
Can be used to zero the scale with a tare weight."""
|
||||
nau7802.calibrate("INTERNAL")
|
||||
nau7802.calibrate("OFFSET")
|
||||
|
||||
|
||||
def read(samples=100):
|
||||
# Read and average consecutive raw sample values; return average raw value
|
||||
sample_sum = 0
|
||||
sample_count = samples
|
||||
while sample_count > 0:
|
||||
if nau7802.available:
|
||||
sample_sum = sample_sum + nau7802.read()
|
||||
sample_count -= 1
|
||||
return int(sample_sum / samples)
|
||||
|
||||
|
||||
# Activate the NAU780 internal analog circuitry, set gain, and calibrate/zero
|
||||
nau7802.enable(True)
|
||||
nau7802.gain = DEFAULT_GAIN # Use default gain
|
||||
zero_channel() # Calibrate and zero
|
||||
|
||||
print("-----------------------------------")
|
||||
print(" NAU7802 SINGLE CHANNEL CALIBRATOR")
|
||||
print("-----------------------------------")
|
||||
print("Place a calibration weight on the")
|
||||
print("load cell.")
|
||||
print("To re-zero the load cell, remove")
|
||||
print("any weights then press and hold A.")
|
||||
print("-----------------------------------")
|
||||
print("")
|
||||
|
||||
# Play "welcome" tones
|
||||
clue.play_tone(1660, 0.15)
|
||||
clue.play_tone(1440, 0.15)
|
||||
|
||||
# Main loop: Read sample and display value
|
||||
while True:
|
||||
clue.pixel[0] = clue.GREEN # Set status indicator to green
|
||||
|
||||
# Read the raw value; print raw value, gain setting, and % of full-scale
|
||||
value = read(SAMPLE_AVG)
|
||||
print(f"CHAN_{nau7802.channel:1.0f} RAW VALUE: {value:7.0f}")
|
||||
print(f"GAIN: x{DEFAULT_GAIN} full-scale: {(value / ((2**23) - 1)) * 100:3.2f}%")
|
||||
print("===================================")
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
if clue.button_a:
|
||||
# Zero and recalibrate the NAU780
|
||||
clue.play_tone(1660, 0.3) # Play "button pressed" tone
|
||||
clue.pixel[0] = clue.RED # Set status indicator to red (stopped)
|
||||
zero_channel()
|
||||
while clue.button_a:
|
||||
# Wait until button is released
|
||||
time.sleep(0.1)
|
||||
print("RECALIBRATED")
|
||||
clue.play_tone(1440, 0.5) # Play "reset completed" tone
|
||||
185
Clue_Scale/code.py
Normal file
185
Clue_Scale/code.py
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
# SPDX-FileCopyrightText: 2022 Jan Goolsbey for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# clue_scale_code.py
|
||||
# 2022-07-29 v1.2.0
|
||||
#
|
||||
# Clue Scale - Single Channel Version
|
||||
# Adafruit NAU7802 Stemma breakout example
|
||||
|
||||
# import clue_scale_calibrator # Uncomment to run calibrator method
|
||||
|
||||
import time
|
||||
import board
|
||||
from simpleio import map_range
|
||||
from adafruit_clue import clue
|
||||
from adafruit_display_shapes.circle import Circle
|
||||
from adafruit_display_text.label import Label
|
||||
from adafruit_bitmap_font import bitmap_font
|
||||
import displayio
|
||||
from cedargrove_nau7802 import NAU7802
|
||||
|
||||
clue.pixel.brightness = 0.2 # Set NeoPixel brightness
|
||||
clue.pixel[0] = clue.YELLOW # Set status indicator to yellow (initializing)
|
||||
|
||||
# Set Scale Defaults
|
||||
MAX_GR = 100 # Maximum (full-scale) display range in grams
|
||||
DEFAULT_GAIN = 128 # Default gain for internal PGA
|
||||
SAMPLE_AVG = 100 # Number of sample values to average
|
||||
SCALE_NAME_1 = "COFFEE" # 6 characters maximum
|
||||
SCALE_NAME_2 = "SCALE" # 6 characters maximum
|
||||
|
||||
"""Enter the calibration ratio for the individual load cell in-use. The ratio is
|
||||
composed of the reference weight in grams divided by the raw reading. For
|
||||
example, a raw reading of 215300 for a 100 gram weight results in a calibration
|
||||
ratio of 100 / 215300. Use the clue_scale_single_calibrate method to obtain the
|
||||
raw value.
|
||||
FYI: A US dime coin weighs 2.268 grams or 0.079 ounces."""
|
||||
CALIB_RATIO = 100 / 215300 # load cell serial#4540-02
|
||||
|
||||
# Instantiate the Sensor and Display
|
||||
nau7802 = NAU7802(board.I2C(), address=0x2A, active_channels=1)
|
||||
|
||||
display = board.DISPLAY
|
||||
scale_group = displayio.Group()
|
||||
|
||||
FONT_0 = bitmap_font.load_font("/fonts/Helvetica-Bold-24.bdf")
|
||||
FONT_1 = bitmap_font.load_font("/fonts/OpenSans-16.bdf")
|
||||
FONT_2 = bitmap_font.load_font("/fonts/OpenSans-9.bdf")
|
||||
|
||||
# Display the Background Bitmap Image
|
||||
bkg = displayio.OnDiskBitmap("/clue_scale_bkg.bmp")
|
||||
_background = displayio.TileGrid(bkg, pixel_shader=bkg.pixel_shader, x=0, y=0)
|
||||
scale_group.append(_background)
|
||||
|
||||
# Define and Display the Text Labels and Graphic Elements
|
||||
# Place the project name on either side of the graduated scale
|
||||
scale_name_1 = Label(FONT_1, text=SCALE_NAME_1, color=clue.CYAN)
|
||||
scale_name_1.anchor_point = (0.5, 0.5)
|
||||
scale_name_1.anchored_position = (40, 96)
|
||||
scale_group.append(scale_name_1)
|
||||
|
||||
scale_name_2 = Label(FONT_1, text=SCALE_NAME_2, color=clue.CYAN)
|
||||
scale_name_2.anchor_point = (0.5, 0.5)
|
||||
scale_name_2.anchored_position = (199, 96)
|
||||
scale_group.append(scale_name_2)
|
||||
|
||||
# Define the zeroing button graphic
|
||||
zero_button_circle = Circle(14, 152, 14, fill=None, outline=clue.RED, stroke=2)
|
||||
scale_group.append(zero_button_circle)
|
||||
|
||||
zero_button_label = Label(FONT_1, text="Z", color=clue.RED)
|
||||
zero_button_label.x = 8
|
||||
zero_button_label.y = 150
|
||||
scale_group.append(zero_button_label)
|
||||
|
||||
# Place tickmark labels next to the graduated scale
|
||||
for i in range(-1, 6):
|
||||
tick_value = Label(FONT_2, text=str((MAX_GR) // 5 * i), color=clue.CYAN)
|
||||
if i == -1:
|
||||
tick_value.anchor_point = (1.0, 1.1)
|
||||
elif i == 5:
|
||||
tick_value.anchor_point = (1.0, 0.0)
|
||||
else:
|
||||
tick_value.anchor_point = (1.0, 0.5)
|
||||
tick_value.anchored_position = (99, 201 - (i * 40))
|
||||
scale_group.append(tick_value)
|
||||
|
||||
# Place the grams and ounces labels and values near the bottom of the display
|
||||
grams_label = Label(FONT_0, text="grams", color=clue.BLUE)
|
||||
grams_label.anchor_point = (1.0, 0)
|
||||
grams_label.anchored_position = (80, 216)
|
||||
scale_group.append(grams_label)
|
||||
|
||||
ounces_label = Label(FONT_0, text="ounces", color=clue.BLUE)
|
||||
ounces_label.anchor_point = (1.0, 0)
|
||||
ounces_label.anchored_position = (230, 216)
|
||||
scale_group.append(ounces_label)
|
||||
|
||||
grams_value = Label(FONT_0, text="0.0", color=clue.WHITE)
|
||||
grams_value.anchor_point = (1.0, 0.5)
|
||||
grams_value.anchored_position = (80, 200)
|
||||
scale_group.append(grams_value)
|
||||
|
||||
ounces_value = Label(FONT_0, text="0.00", color=clue.WHITE)
|
||||
ounces_value.anchor_point = (1.0, 0.5)
|
||||
ounces_value.anchored_position = (230, 200)
|
||||
scale_group.append(ounces_value)
|
||||
|
||||
# Define the moveable indicator bubble
|
||||
indicator_group = displayio.Group()
|
||||
bubble = Circle(120, 200, 10, fill=clue.YELLOW, outline=clue.YELLOW, stroke=3)
|
||||
indicator_group.append(bubble)
|
||||
|
||||
scale_group.append(indicator_group)
|
||||
display.show(scale_group)
|
||||
|
||||
|
||||
# Helpers
|
||||
def zero_channel():
|
||||
"""Prepare internal amplifier settings and zero the current channel. Use
|
||||
after power-up, a new channel is selected, or to adjust for measurement
|
||||
drift. Can be used to zero the scale with a tare weight.
|
||||
The nau7802.calibrate function used here does not calibrate the load cell,
|
||||
but sets the NAU7802 internals to prepare for measuring input signals."""
|
||||
nau7802.calibrate("INTERNAL")
|
||||
nau7802.calibrate("OFFSET")
|
||||
|
||||
|
||||
def read(samples=100):
|
||||
"""Read and average consecutive raw samples; return averaged value."""
|
||||
sample_sum = 0
|
||||
sample_count = samples
|
||||
while sample_count > 0:
|
||||
if nau7802.available:
|
||||
sample_sum = sample_sum + nau7802.read()
|
||||
sample_count -= 1
|
||||
return int(sample_sum / samples)
|
||||
|
||||
|
||||
# Activate the Sensor
|
||||
# Enable the internal analog circuitry, set gain, and zero
|
||||
nau7802.enable(True)
|
||||
nau7802.gain = DEFAULT_GAIN
|
||||
zero_channel()
|
||||
|
||||
# Play "welcome" tones
|
||||
clue.play_tone(1660, 0.15)
|
||||
clue.play_tone(1440, 0.15)
|
||||
|
||||
# The Primary Code Loop
|
||||
# Read sensor, move bubble, and display values
|
||||
while True:
|
||||
clue.pixel[0] = clue.GREEN # Set status indicator to green (ready)
|
||||
|
||||
# Read the raw scale value and scale for grams and ounces
|
||||
value = read(SAMPLE_AVG)
|
||||
mass_grams = round(value * CALIB_RATIO, 1)
|
||||
mass_ounces = round(mass_grams * 0.03527, 2)
|
||||
grams_value.text = f"{mass_grams:5.1f}"
|
||||
ounces_value.text = f"{mass_ounces:5.2f}"
|
||||
print(f" {mass_grams:5.1f} grams {mass_ounces:5.2f} ounces")
|
||||
|
||||
# Reposition the indicator bubble based on grams value
|
||||
min_gr = (MAX_GR // 5) * -1 # Minimum display value
|
||||
bubble.y = int(map_range(mass_grams, min_gr, MAX_GR, 240, 0)) - 10
|
||||
if mass_grams > MAX_GR or mass_grams < min_gr:
|
||||
bubble.fill = clue.RED
|
||||
else:
|
||||
bubble.fill = None
|
||||
|
||||
# Check to see if the zeroing button is pressed
|
||||
if clue.button_a:
|
||||
# Zero the sensor
|
||||
clue.pixel[0] = clue.RED # Set status indicator to red (stopped)
|
||||
bubble.fill = clue.RED # Set bubble center to red (stopped)
|
||||
clue.play_tone(1660, 0.3) # Play "button pressed" tone
|
||||
|
||||
zero_channel()
|
||||
|
||||
while clue.button_a:
|
||||
# Wait until the button is released
|
||||
time.sleep(0.1)
|
||||
|
||||
clue.play_tone(1440, 0.5) # Play "reset completed" tone
|
||||
bubble.fill = None # Set bubble center to transparent (ready)
|
||||
5355
Clue_Scale/fonts/Helvetica-Bold-24.bdf
Normal file
5355
Clue_Scale/fonts/Helvetica-Bold-24.bdf
Normal file
File diff suppressed because it is too large
Load diff
20391
Clue_Scale/fonts/OpenSans-16.bdf
Normal file
20391
Clue_Scale/fonts/OpenSans-16.bdf
Normal file
File diff suppressed because it is too large
Load diff
14362
Clue_Scale/fonts/OpenSans-9.bdf
Normal file
14362
Clue_Scale/fonts/OpenSans-9.bdf
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue