commit 5777880859dafbb0381ac85c1f934ed351632cdf Author: qhga Date: Sun Mar 27 20:05:06 2022 +0200 Init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ed53a72 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.pio +.ccls +.ccls-cache/ diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..b58fd6b --- /dev/null +++ b/platformio.ini @@ -0,0 +1,19 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:nanoatmega328] +platform = atmelavr +board = nanoatmega328 +framework = arduino +board_build.mcu = atmega328p +lib_deps = + olkal/HX711_ADC@^1.2.7 + greiman/SSD1306Ascii@^1.3.0 +build_flags = -Wl,-u,vfprintf -lprintf_flt -lm \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..32cdb92 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,260 @@ +#include +#include +#include +#if defined(ESP8266) || defined(ESP32) || defined(AVR) +#include +#endif +#define SCREEN_W 128 +#define SCREEN_H 32 +#define HX711_dout 4 // mcu > HX711 dout pin +#define HX711_sck 5 // mcu > HX711 sck pin +#define EEPROM_ADDRESS 0 + +void calibrate(); +void changeSavedCalFactor(); +// HX711 constructor: +HX711_ADC LoadCell(HX711_dout, HX711_sck); +// OLED +// Adafruit_SSD1306 oled(SCREEN_W, SCREEN_H, &Wire, -1); +SSD1306AsciiWire oled; + +unsigned long t = 0; +float highest_force = 0; +bool first_run = true; + +void setup() { + Serial.begin(57600); + + oled.begin(&Adafruit128x32, 0x3c); + oled.setFont(System5x7); + + oled.clear(); + oled.print("Starting..."); + + delay(50); + + Serial.println(); + Serial.println("Starting..."); + + LoadCell.begin(); + unsigned long stabilizingtime = + 2000; // preciscion right after power-up can be improved by adding a few + // seconds of stabilizing time + boolean _tare = true; // set this to false if you don't want tare to be + // performed in the next step + LoadCell.start(stabilizingtime, _tare); + if (LoadCell.getTareTimeoutFlag() || LoadCell.getSignalTimeoutFlag()) { + Serial.println("Timeout, check MCU>HX711 wiring and pin designations"); + while (1) + ; + } else { + LoadCell.setCalFactor(1.0); // user set calibration value (float), initial + // value 1.0 may be used for this sketch + Serial.println("Startup is complete"); + } + while (!LoadCell.update()) + ; // wait + // calibrate(); // start calibration procedure + +#if defined(ESP8266) || defined(ESP32) + EEPROM.begin(512); +#endif + float eeprom_calibration_value; + EEPROM.get(EEPROM_ADDRESS, eeprom_calibration_value); + LoadCell.setCalFactor(eeprom_calibration_value); + // Set number of samples used to average out results (default: 16) + LoadCell.setSamplesInUse(1); + oled.clear(); + oled.println("Press to start..."); +} + +void loop() { + // static boolean newDataReady = 0; + // const int serialPrintInterval = 0; //increase value to slow down serial + // print activity + + if (LoadCell.update()) { + float curr_reading = LoadCell.getData(); + char curr[18]; + char high[18]; + char newt[18]; + + Serial.println(curr_reading); + + if (curr_reading < 0) + curr_reading = 0; + + if (first_run) { + oled.clear(); + first_run = false; + } + // Serial.println(curr_reading); + oled.setCursor(0, 0); + sprintf(curr, "Curr: %7.2f g", (double)curr_reading); + oled.println(curr); + if (highest_force < curr_reading) { + highest_force = curr_reading; + float newton = highest_force * 0.00980665; + sprintf(high, "High: %7.2f g", (double)highest_force); + sprintf(newt, "High: %7.2f N", (double)newton); + oled.println(high); + oled.println(newt); + } + } + + // receive command from serial terminal + if (Serial.available() > 0) { + char inByte = Serial.read(); + if (inByte == 't') + LoadCell.tareNoDelay(); // tare + else if (inByte == 'r') + calibrate(); // calibrate + else if (inByte == 'c') + changeSavedCalFactor(); // edit calibration value manually + else if (inByte == 'n') + highest_force = 0; + } + + // check if last tare operation is complete + if (LoadCell.getTareStatus() == true) { + Serial.println("Tare complete"); + } +} + +void calibrate() { + Serial.println("***"); + Serial.println("Start calibration:"); + Serial.println("Place the load cell an a level stable surface."); + Serial.println("Remove any load applied to the load cell."); + Serial.println("Send 't' from serial monitor to set the tare offset."); + + boolean _resume = false; + while (_resume == false) { + LoadCell.update(); + if (Serial.available() > 0) { + if (Serial.available() > 0) { + char inByte = Serial.read(); + if (inByte == 't') + LoadCell.tareNoDelay(); + } + } + if (LoadCell.getTareStatus() == true) { + Serial.println("Tare complete"); + _resume = true; + } + } + + Serial.println("Now, place your known mass on the loadcell."); + Serial.println( + "Then send the weight of this mass (i.e. 100.0) from serial monitor."); + + float known_mass = 0; + _resume = false; + while (_resume == false) { + LoadCell.update(); + if (Serial.available() > 0) { + known_mass = Serial.parseFloat(); + if (known_mass != 0) { + Serial.print("Known mass is: "); + Serial.println(known_mass); + _resume = true; + } + } + } + + LoadCell.refreshDataSet(); // refresh the dataset to be sure that the known + // mass is measured correct + float newCalibrationValue = + LoadCell.getNewCalibration(known_mass); // get the new calibration value + + Serial.print("New calibration value has been set to: "); + Serial.print(newCalibrationValue); + Serial.println( + ", use this as calibration value (calFactor) in your project sketch."); + Serial.print("Save this value to EEPROM adress "); + Serial.print(EEPROM_ADDRESS); + Serial.println("? y/n"); + + _resume = false; + while (_resume == false) { + if (Serial.available() > 0) { + char inByte = Serial.read(); + if (inByte == 'y') { +#if defined(ESP8266) || defined(ESP32) + EEPROM.begin(512); +#endif + EEPROM.put(EEPROM_ADDRESS, newCalibrationValue); +#if defined(ESP8266) || defined(ESP32) + EEPROM.commit(); +#endif + EEPROM.get(EEPROM_ADDRESS, newCalibrationValue); + Serial.print("Value "); + Serial.print(newCalibrationValue); + Serial.print(" saved to EEPROM address: "); + Serial.println(EEPROM_ADDRESS); + _resume = true; + + } else if (inByte == 'n') { + Serial.println("Value not saved to EEPROM"); + _resume = true; + } + } + } + + Serial.println("End calibration"); + Serial.println("***"); + Serial.println("To re-calibrate, send 'r' from serial monitor."); + Serial.println("For manual edit of the calibration value, send 'c' from " + "serial monitor."); + Serial.println("***"); +} + +void changeSavedCalFactor() { + float oldCalibrationValue = LoadCell.getCalFactor(); + boolean _resume = false; + Serial.println("***"); + Serial.print("Current value is: "); + Serial.println(oldCalibrationValue); + Serial.println("Now, send the new value from serial monitor, i.e. 696.0"); + float newCalibrationValue; + while (_resume == false) { + if (Serial.available() > 0) { + newCalibrationValue = Serial.parseFloat(); + if (newCalibrationValue != 0) { + Serial.print("New calibration value is: "); + Serial.println(newCalibrationValue); + LoadCell.setCalFactor(newCalibrationValue); + _resume = true; + } + } + } + _resume = false; + Serial.print("Save this value to EEPROM adress "); + Serial.print(EEPROM_ADDRESS); + Serial.println("? y/n"); + while (_resume == false) { + if (Serial.available() > 0) { + char inByte = Serial.read(); + if (inByte == 'y') { +#if defined(ESP8266) || defined(ESP32) + EEPROM.begin(512); +#endif + EEPROM.put(EEPROM_ADDRESS, newCalibrationValue); +#if defined(ESP8266) || defined(ESP32) + EEPROM.commit(); +#endif + EEPROM.get(EEPROM_ADDRESS, newCalibrationValue); + Serial.print("Value "); + Serial.print(newCalibrationValue); + Serial.print(" saved to EEPROM address: "); + Serial.println(EEPROM_ADDRESS); + _resume = true; + } else if (inByte == 'n') { + Serial.println("Value not saved to EEPROM"); + _resume = true; + } + } + } + Serial.println("End change calibration value"); + Serial.println("***"); +} \ No newline at end of file diff --git a/test/README b/test/README new file mode 100644 index 0000000..b94d089 --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html