|
| 1 | +/* |
| 2 | + Use the Qwiic Scale to read load cells and scales |
| 3 | + By: Paul Clark @ SparkFun Electronics |
| 4 | + Date: February 25th, 2024 |
| 5 | + License: MIT - see License.md for more details. |
| 6 | +
|
| 7 | + This example shows how to setup a scale complete with zero offset (tare), |
| 8 | + and linear calibration using the NAU7802's external calibration mode. |
| 9 | +
|
| 10 | + This is similar to Example2, except here we use the NAU7802's external calibration |
| 11 | + function and internal offset register to store the zero point. By default .begin |
| 12 | + performs an _internal_ calibration. In this example we overwrite the offset register |
| 13 | + with the result of the _external_ calibration. |
| 14 | +
|
| 15 | + If you know the calibration and offset values you can send them directly to |
| 16 | + the library and NAU7802. This is useful if you want to maintain values between power cycles |
| 17 | + in EEPROM or Non-volatile memory (NVM). If you don't know these values then |
| 18 | + you can go through a series of steps to calculate the offset and calibration value. |
| 19 | +
|
| 20 | + SparkFun labored with love to create this code. Feel like supporting open |
| 21 | + source? Buy a board from SparkFun! |
| 22 | + https://www.sparkfun.com/products/15242 |
| 23 | +
|
| 24 | + Hardware Connections: |
| 25 | + Plug a Qwiic cable into the Qwiic Scale and a RedBoard Qwiic |
| 26 | + If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425) |
| 27 | + Open the serial monitor at 115200 baud to see the output |
| 28 | +*/ |
| 29 | + |
| 30 | +#include <Wire.h> |
| 31 | +#include <EEPROM.h> //Needed to record user settings |
| 32 | + |
| 33 | +#include "SparkFun_Qwiic_Scale_NAU7802_Arduino_Library.h" // Click here to get the library: http://librarymanager/All#SparkFun_NAU8702 |
| 34 | + |
| 35 | +NAU7802 myScale; //Create instance of the NAU7802 class |
| 36 | + |
| 37 | +//EEPROM locations to store 4-byte variables |
| 38 | +#define EEPROM_SIZE 100 //Allocate 100 bytes of EEPROM |
| 39 | +#define LOCATION_CALIBRATION_FACTOR 0 //Float, requires 4 bytes of EEPROM |
| 40 | +#define LOCATION_ZERO_OFFSET 20 //Must be more than 4 away from previous spot. 24-bit signed, stored as int32_t. Requires 4 bytes of EEPROM |
| 41 | + |
| 42 | +bool settingsDetected = false; //Used to prompt user to calibrate their scale |
| 43 | + |
| 44 | +//Average the weight over this many samples. This helps smooth out jitter. |
| 45 | +const uint8_t avgWeights = 20; //At 40 SPS, this will produce readings at 2Hz |
| 46 | + |
| 47 | +//Allow negative weights. Why not? |
| 48 | +const bool allowNegative = true; |
| 49 | + |
| 50 | +void setup() |
| 51 | +{ |
| 52 | + EEPROM.begin(EEPROM_SIZE); //Some platforms need this. Comment this line if needed |
| 53 | + |
| 54 | + delay(1000); //Some platforms need this. Comment this line if needed |
| 55 | + |
| 56 | + Serial.begin(115200); |
| 57 | + Serial.println(F("Qwiic Scale Example")); |
| 58 | + |
| 59 | + Wire.begin(); |
| 60 | + Wire.setClock(400000); //Qwiic Scale is capable of running at 400kHz if desired |
| 61 | + |
| 62 | + if (myScale.begin() == false) //begin performs an internal calibration. We will overwrite this with readSystemSettings |
| 63 | + { |
| 64 | + Serial.println(F("Scale not detected. Please check wiring. Freezing...")); |
| 65 | + while (1); |
| 66 | + } |
| 67 | + Serial.println(F("Scale detected!")); |
| 68 | + |
| 69 | + myScale.setSampleRate(NAU7802_SPS_40); //Set sample rate: 10, 20, 40, 80 or 320 |
| 70 | + myScale.setGain(NAU7802_GAIN_16); //Gain can be set to 1, 2, 4, 8, 16, 32, 64, or 128. |
| 71 | + myScale.setLDO(NAU7802_LDO_3V0); //Set LDO (AVDD) voltage. 3.0V is the best choice for Qwiic |
| 72 | + |
| 73 | + readSystemSettings(); //Load NAU7802 offset and calibrationFactor from EEPROM |
| 74 | + |
| 75 | + Serial.print(F("NAU7802 offset register: ")); |
| 76 | + Serial.println(myScale.getChannel1Offset()); |
| 77 | + Serial.print(F("Library calibration factor: ")); |
| 78 | + Serial.println(myScale.getCalibrationFactor()); |
| 79 | + |
| 80 | + Serial.println(F("\r\nPress 'c' to calibrate the scale\r\n")); |
| 81 | +} |
| 82 | + |
| 83 | +void loop() |
| 84 | +{ |
| 85 | + if (myScale.available() == true) |
| 86 | + { |
| 87 | + float currentWeight = myScale.getWeight(allowNegative, avgWeights); |
| 88 | + |
| 89 | + Serial.print(F("Weight: ")); |
| 90 | + Serial.print(currentWeight, 2); //Print 2 decimal places |
| 91 | + |
| 92 | + if(settingsDetected == false) |
| 93 | + { |
| 94 | + Serial.print(F("\tScale not calibrated. Press 'c'.")); |
| 95 | + } |
| 96 | + |
| 97 | + Serial.println(); |
| 98 | + } |
| 99 | + |
| 100 | + if (Serial.available()) |
| 101 | + { |
| 102 | + byte incoming = Serial.read(); |
| 103 | + |
| 104 | + if (incoming == 'c') //Calibrate |
| 105 | + calibrateScale(); |
| 106 | + } |
| 107 | +} |
| 108 | + |
| 109 | +//Gives user the ability to set a known weight on the scale and calculate a calibration factor |
| 110 | +void calibrateScale(void) |
| 111 | +{ |
| 112 | + Serial.println(); |
| 113 | + Serial.println(); |
| 114 | + Serial.println(F("Scale calibration")); |
| 115 | + |
| 116 | + Serial.println(F("Setup scale with no weight on it. Press a key when ready.")); |
| 117 | + while (Serial.available()) Serial.read(); //Clear anything in RX buffer |
| 118 | + while (Serial.available() == 0) delay(10); //Wait for user to press key |
| 119 | + |
| 120 | + //Perform an external offset - this sets the NAU7802's internal offset register |
| 121 | + myScale.calibrateAFE(NAU7802_CALMOD_OFFSET); //Calibrate using external offset |
| 122 | + |
| 123 | + Serial.print(F("New NAU7802 offset register: ")); |
| 124 | + Serial.println(myScale.getChannel1Offset()); |
| 125 | + |
| 126 | + Serial.println(F("Place known weight on scale. Press a key when weight is in place and stable.")); |
| 127 | + while (Serial.available()) Serial.read(); //Clear anything in RX buffer |
| 128 | + while (Serial.available() == 0) delay(10); //Wait for user to press key |
| 129 | + |
| 130 | + Serial.print(F("Please enter the weight, without units, currently sitting on the scale (for example '4.25'): ")); |
| 131 | + while (Serial.available()) Serial.read(); //Clear anything in RX buffer |
| 132 | + while (Serial.available() == 0) delay(10); //Wait for user to press key |
| 133 | + |
| 134 | + //Read user input |
| 135 | + float weightOnScale = Serial.parseFloat(); |
| 136 | + Serial.println(); |
| 137 | + |
| 138 | + //Tell the library how much weight is currently on it |
| 139 | + //We are sampling slowly, so we need to increase the timeout too |
| 140 | + myScale.calculateCalibrationFactor(weightOnScale, 64, 3000); //64 samples at 40SPS. Use a timeout of 3 seconds |
| 141 | + Serial.print(F("Weight on scale: ")); |
| 142 | + Serial.println(weightOnScale, 2); |
| 143 | + Serial.print(F("New library calibration factor: ")); |
| 144 | + Serial.println(myScale.getCalibrationFactor(), 2); |
| 145 | + |
| 146 | + recordSystemSettings(); //Commit these values to EEPROM |
| 147 | + |
| 148 | + settingsDetected = true; //Mark the settings as detected |
| 149 | +} |
| 150 | + |
| 151 | +//Record the current system settings to EEPROM |
| 152 | +void recordSystemSettings(void) |
| 153 | +{ |
| 154 | + //Get various values from the library and commit them to NVM |
| 155 | + EEPROM.put(LOCATION_CALIBRATION_FACTOR, myScale.getCalibrationFactor()); |
| 156 | + EEPROM.put(LOCATION_ZERO_OFFSET, myScale.getChannel1Offset()); |
| 157 | + |
| 158 | + EEPROM.commit(); //Some platforms need this. Comment this line if needed |
| 159 | +} |
| 160 | + |
| 161 | +//Reads the current system settings from EEPROM |
| 162 | +//If anything looks weird, reset setting to default value |
| 163 | +void readSystemSettings(void) |
| 164 | +{ |
| 165 | + float settingCalibrationFactor; //Value used to convert the load cell reading to lbs or kg |
| 166 | + int32_t offsetRegister; //Zero value that is found when scale is tared |
| 167 | + |
| 168 | + //Look up the calibration factor |
| 169 | + //If the EEPROM has been erased, default to 1.0 |
| 170 | + EEPROM.get(LOCATION_CALIBRATION_FACTOR, settingCalibrationFactor); |
| 171 | + if (settingCalibrationFactor == 0xFFFFFFFF) |
| 172 | + { |
| 173 | + settingCalibrationFactor = 1.0; //Default to 1.0 |
| 174 | + EEPROM.put(LOCATION_CALIBRATION_FACTOR, settingCalibrationFactor); |
| 175 | + } |
| 176 | + |
| 177 | + //Look up the offset register |
| 178 | + //If the EEPROM has been erased, default to 0 |
| 179 | + EEPROM.get(LOCATION_ZERO_OFFSET, offsetRegister); |
| 180 | + if (offsetRegister == 0xFFFFFFFF) |
| 181 | + { |
| 182 | + offsetRegister = 0; //Default to 0 - i.e. no offset |
| 183 | + EEPROM.put(LOCATION_ZERO_OFFSET, offsetRegister); |
| 184 | + } |
| 185 | + |
| 186 | + //Pass these values to the library and NAU7802 |
| 187 | + myScale.setCalibrationFactor(settingCalibrationFactor); |
| 188 | + myScale.setChannel1Offset(offsetRegister); |
| 189 | + |
| 190 | + settingsDetected = true; //Assume for the moment that there are good cal values |
| 191 | + if (settingCalibrationFactor == 1.0 || offsetRegister == 0) |
| 192 | + settingsDetected = false; //Defaults detected. Prompt user to cal scale. |
| 193 | +} |
0 commit comments