Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2024:iotelea:dalya.tobescu [2024/05/26 19:29]
dalya.tobescu
pm:prj2024:iotelea:dalya.tobescu [2024/05/26 23:04] (current)
dalya.tobescu
Line 8: Line 8:
 ===== Descriere generală ===== ===== Descriere generală =====
  
-Cântarul se bazează pe o celulă de încărcare cu o capacitate de kg, care convertește presiunea exercitată de obiectele plasate pe platformă într-un semnal analog. Acest semnal este apoi transmis la modulul de citire a greutății HX711, care îl transformă într-un semnal digital ce poate fi citit de către microcontrollerul Arduino. Prin intermediul unui ecran LCD, greutatea este afișată cu precizie utilizatorului. ​De asemenea, este integrat un buton pentru a reseta greutatea curentă la zero, permițând efectuarea de măsurători repetate cu ușurință.+Cântarul se bazează pe o celulă de încărcare cu o capacitate de kg, care convertește presiunea exercitată de obiectele plasate pe platformă într-un semnal analog. Acest semnal este apoi transmis la modulul de citire a greutății HX711, care îl transformă într-un semnal digital ce poate fi citit de către microcontrollerul Arduino. Prin intermediul unui ecran LCD, greutatea este afișată cu precizie utilizatorului. ​Este integrat un buton pentru a reseta greutatea curentă la zero, permițând efectuarea de măsurători repetate cu ușurință. De asemenea, este integrat un buton pentru functia de PLATE, in aceasta functie putem sa cantarim ce dorim fara a fi luata in calcul si farfuria cu care masuram.
  
  
-{{:​pm:​prj2024:​iotelea:​last.drawio.png?500|}}+{{:​pm:​prj2024:​iotelea:​lastone.drawio_1_.png|}}
  
  
Line 37: Line 37:
  
 ==Schema EAGLE:== ==Schema EAGLE:==
-{{:​pm:​prj2024:​iotelea:​eagle.png?700|}}+{{:​pm:​prj2024:​iotelea:​schema_angle_last.png?700|}} 
  
  
Line 80: Line 81:
  
 ==LED:== ==LED:==
-  ​+
    * pe pinul 9 Arduino    * pe pinul 9 Arduino
  
Line 95: Line 96:
 ==Implementare hardware in faza finala:== ==Implementare hardware in faza finala:==
  
 +{{:​pm:​prj2024:​iotelea:​whatsapp_image_2024-05-26_at_19.38.50.jpeg?​500}}
  
-Am rezolvat problema cu Black Boxes, adaugand un potentiomtru ​cu ajutorul caruia setez luminozitatea ecranului. Am adaugat led-ul care imi indica cand cantarul este in Plate Function si un buton cu care intru in Plate Function +Am rezolvat problema cu Black Boxes, adaugand un potentiometru ​cu ajutorul caruia setez luminozitatea ecranului. Am adaugat led-ul care imi indica cand cantarul este in Plate Function si un buton cu care intru in Plate Function.
  
 ===== Software Design ===== ===== Software Design =====
  
 +==Inainte de orice implementare software, a trebuit sa calibrez celula de incarcare:​==
 +1) Am pregatit un obiect cu o greutate cunoscută. Mi-am folosit cântarul de bucătărie și am cântărit o sticluta de parfum (160g).
 +
 +2) Am incarcat următorul cod pe placa Arduino. Am scris următorul cod ținând cont de instrucțiunile de calibrare a celulei de sarcină furnizate de documentația bibliotecii.
 +
 +3) Am determinat factorul de calibrare si l-am inclus in codul proiectului meu.
 +
 +<​code>​
 +
 +#include <​HX711_ADC.h>​
 +#if defined(ESP8266)|| defined(ESP32) || defined(AVR)
 +#include <​EEPROM.h>​
 +#endif
 +
 +//pins:
 +const int HX711_dout = 2; //mcu > HX711 dout pin
 +const int HX711_sck = 3; //mcu > HX711 sck pin
 +
 +//HX711 constructor:​
 +HX711_ADC LoadCell(HX711_dout,​ HX711_sck);
 +
 +const int calVal_eepromAdress = 0;
 +unsigned long t = 0;
 +
 +void setup() {
 +  Serial.begin(57600);​ delay(10);
 +  Serial.println();​
 +  Serial.println("​Starting..."​);​
 +
 +  LoadCell.begin();​
 +  //​LoadCell.setReverseOutput();​ //uncomment to turn a negative output value to positive
 +  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());​
 +  calibrate();​ //start calibration procedure
 +}
 +
 +void loop() {
 +  static boolean newDataReady = 0;
 +  const int serialPrintInterval = 0; //increase value to slow down serial print activity
 +
 +  // check for new data/start next conversion:
 +  if (LoadCell.update()) newDataReady = true;
 +
 +  // get smoothed value from the dataset:
 +  if (newDataReady) {
 +    if (millis() > t + serialPrintInterval) {
 +      float i = LoadCell.getData();​
 +      Serial.print("​Load_cell output val: ");
 +      Serial.println(i);​
 +      newDataReady = 0;
 +      t = millis();
 +    }
 +  }
 +
 +  // 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
 +  }
 +
 +  // 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(calVal_eepromAdress);​
 +  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(calVal_eepromAdress,​ newCalibrationValue);​
 +#if defined(ESP8266)|| defined(ESP32)
 +        EEPROM.commit();​
 +#endif
 +        EEPROM.get(calVal_eepromAdress,​ newCalibrationValue);​
 +        Serial.print("​Value ");
 +        Serial.print(newCalibrationValue);​
 +        Serial.print("​ saved to EEPROM address: ");
 +        Serial.println(calVal_eepromAdress);​
 +        _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(calVal_eepromAdress);​
 +  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(calVal_eepromAdress,​ newCalibrationValue);​
 +#if defined(ESP8266)|| defined(ESP32)
 +        EEPROM.commit();​
 +#endif
 +        EEPROM.get(calVal_eepromAdress,​ newCalibrationValue);​
 +        Serial.print("​Value ");
 +        Serial.print(newCalibrationValue);​
 +        Serial.print("​ saved to EEPROM address: ");
 +        Serial.println(calVal_eepromAdress);​
 +        _resume = true;
 +      }
 +      else if (inByte == '​n'​) {
 +        Serial.println("​Value not saved to EEPROM"​);​
 +        _resume = true;
 +      }
 +    }
 +  }
 +  Serial.println("​End change calibration value"​);​
 +  Serial.println("​***"​);​
 +}
 +</​code>​
 +
 +
 +==Descriere detaliată a codului:==
 +==Biblioteci incluse:==
 +* LiquidCrystal.h:​ pentru controlul afișajului LCD.
 +
 +* HX711_ADC.h:​ pentru citirea datelor de la senzorul de greutate HX711.
 +
 +
 +<code c>
 +#include <​LiquidCrystal.h>​
 +#include <​HX711_ADC.h>​
 +</​code>​
 +
 +==Definirea pinilor și inițializarea componentelor:​==
 +
 +* Pinii DOUT_PIN și SCK_PIN sunt definiți pentru senzorul HX711.
 +
 +* Obiectul LoadCell este creat pentru a interacționa cu senzorul HX711.
 +
 +* Pinii pentru afișajul LCD sunt definiți (rs, en, d4, d5, d6, d7), iar obiectul lcd este creat.
 +
 +* Pinii buttonPin, ledPin și plateButton sunt definiți pentru butoanele de control și LED.
 +
 +<​code>​
 +// Define HX711 pins
 +#define DOUT_PIN 2
 +#define SCK_PIN 3
 +
 +// Initialize the HX711
 +HX711_ADC LoadCell(DOUT_PIN,​ SCK_PIN);
 +
 +// Initialize the LCD library with the numbers of the interface pins
 +const int rs = 13, en = 12, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
 +LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
 +
 +const int buttonPin = 8;  // Define the pin for the button
 +const int ledPin = 9; 
 +const int plateButton= 10;
 +</​code>​
 +
 +==Funcția setup:==
 +* Setează pinul ledPin ca ieșire și pinurile buttonPin și plateButton ca intrări.
 +* Inițializează comunicarea serială la 57600 baud.
 +* Inițializează conexiunea la senzorul HX711 și setează factorul de calibrare.
 +* Resetează senzorul la zero.
 +* Inițializează afișajul LCD și afișează un mesaj de bun venit timp de 3 secunde.
 +
 +<​code>​
 +void setup() {
 +  // initialize the LED pin as an output:
 +  pinMode(ledPin,​ OUTPUT);
 +  // initialize the pushbutton pin as an input:
 +  pinMode(buttonPin,​ INPUT);
 +  pinMode(plateButton,​ INPUT);
 +  ​
 +  Serial.begin(57600);​
 +
 +  // Start the connection to HX711
 +  LoadCell.begin();​
 +  LoadCell.start(1000);​ // Allow the load cells to stabilize for 1000ms
 +  LoadCell.setCalFactor(-386.62);​ // Set the calibration factor
 +  // -386.92
 +  // -385.88
 +  LoadCell.tare();​ // Reset the scale to zero
 +
 +  // Initialize the LCD
 +  lcd.begin(16,​ 2);
 +  lcd.setCursor(1,​ 0); // Set cursor to the first row
 +  lcd.print("​Cook Pro"); // Print out to LCD
 +  lcd.setCursor(4,​ 1); // Set cursor to the second row
 +  lcd.print("​Measure"​);​ // Print out to LCD
 +  delay(3000);​
 +  lcd.clear();​
 +}
 +</​code>​
 +
 +==Funcția loop:==
 +* Citirea și afișarea greutății măsurate de senzorul HX711.
 +* Verifică dacă greutatea este stabilă și dacă este prima rulare.
 +* Afișează greutatea pe afișajul LCD, fie ca greutate simplă, fie ca greutate ajustată pentru un suport (tavă).
 +* Gestionează resetarea și funcția de suport prin intermediul butoanelor:
 +* Dacă buttonPin este apăsat, resetează greutatea și afișează mesajul de resetare.
 +* Dacă plateButton este apăsat, activează funcția de suport și afișează mesajul corespunzător.
 +
 +<​code>​
 +
 +void loop() {
 +  static float lastWeight = 0;
 +  static bool isStable = false;
 +  static bool isFirstRun = true;
 +  static bool plate = false;
 +  static float plateWeight = 0;
 +  static int ledBrightness = 0; // Variable to store LED brightness
 +
 +  LoadCell.update();​
 +  float weight = LoadCell.getData();​
 +
 +  Serial.print("​Weight:​ ");
 +  Serial.print(weight,​ 2); // Print the weight with 2 decimal places
 +  Serial.println("​ g");
 +
 +  // Retrieve data from the load cell
 +  if (isFirstRun) {
 +    lastWeight = 0.0; // Set lastWeight to 0.0 for the first run
 +    isFirstRun = false; // Set isFirstRun to false after the first run
 +  }
 +
 +  // Check if weight is stable
 +  if (abs(weight - lastWeight) < 0.05) { // Adjust the threshold as needed
 +    isStable = true;
 +  } else {
 +    isStable = false;
 +  }
 +
 +  if (weight < 0) {
 +    weight = 0;
 +  } else if (weight > 0 && weight < 1) {
 +    weight = 0;
 +  }
 +
 +  if (isStable) {
 +    if (!plate) {
 +      lcd.clear();​
 +      lcd.setCursor(0,​ 0); // Set cursor to the first row
 +      lcd.print("​Weight:​ ");
 +      lcd.print(weight);​ // Print the weight with 2 decimal places
 +      lcd.print("​ g");
 +    } else {
 +      if (weight < 20 && weight > 15) {
 +        plateWeight = weight;
 +        weight = 0;
 +      }
 +      if (weight > plateWeight) {
 +        weight = weight - plateWeight;​
 +      }
 +      lcd.clear();​
 +      lcd.setCursor(0,​ 0); // Set cursor to the first row
 +      lcd.print("​Weight:​ ");
 +      lcd.print(weight);​ // Print the weight with 2 decimal places
 +      lcd.print("​ g");
 +
 +      lcd.setCursor(0,​ 1); // Adjust cursor position
 +      lcd.print("​With plate"​);​
 +    }
 +  }
 +
 +  lastWeight = weight;
 +
 +  // Check if the button is pressed
 +  if (digitalRead(buttonPin) == HIGH) {
 +    analogWrite(ledPin,​ 0); // Turn off the LED
 +    Serial.println("​Reset button pressed"​);​
 +    plate = false;
 +    weight = 0;
 +    lcd.clear();​
 +    lcd.setCursor(0,​ 1); // Set cursor to the second row
 +    lcd.print(" ​   Reset... ​   ");
 +    LoadCell.start(1000);​
 +    LoadCell.tare();​ // Reset the scale to zero
 +    delay(1000);​ // Allow some time for the reset to stabilize
 +    lcd.clear();​
 +  }
 +
 +  // Plate button functionality with PWM
 +  if (digitalRead(plateButton) == HIGH) {
 +    Serial.println("​PLATE FUNCTION"​);​
 +    plate = true;
 +    lcd.clear();​
 +    lcd.setCursor(0,​ 1); // Set cursor to the second row
 +    lcd.print("​ Plate function ");
 +    LoadCell.start(1000);​
 +    LoadCell.tare();​ // Reset the scale to zero
 +    delay(1000);​ // Allow some time for the reset to stabilize
 +    lcd.clear();​
 +
 +    // Gradually increase LED brightness using PWM
 +    for (int brightness = 0; brightness <= 255; brightness += 5) {
 +      analogWrite(ledPin,​ brightness);​
 +      delay(10);
 +    }
 +  }
 +
 +  // Decrease LED brightness over time
 +  if (ledBrightness > 0) {
 +    ledBrightness -= 5;
 +    if (ledBrightness < 0) {
 +      ledBrightness = 0;
 +    }
 +    analogWrite(ledPin,​ ledBrightness);​
 +  }
 +
 +  delay(100); // Update every 100ms
 +}
 +</​code>​
 +
 +==Funcționalități cheie:==
 +* Stabilizarea greutății:​ Codul verifică dacă greutatea citită este stabilă (variația este sub un prag specificat).
 +
 +* Resetare: Butonul de resetare setează greutatea la zero și resetează senzorul.
 +
 +* Funcția de suport: Un buton suplimentar activează o funcție care ajustează greutatea pentru a scădea greutatea suportului (tăvii).
 +
 +* Acest program este util pentru aplicații unde este necesară măsurarea precisă a greutății,​ cum ar fi în bucătării pentru măsurarea ingredientelor sau în alte aplicații de cântărire.
  
-<note tip> 
-TODO 
-</​note>​ 
  
 ===== Rezultate Obţinute ===== ===== Rezultate Obţinute =====
  
-<note tip+== Am atasat un videoclip in care sunt prezentate functionalitatile proiectului meu:== 
-TODO + 
-</note>+<html
 +<iframe width="​560"​ height="​315"​ src="​https://​www.youtube.com/​embed/​AlmW5XAIM84?​si=xkNJ2FCtBS_oSJnm"​ title="​YouTube video player"​ frameborder="​0"​ allow="​accelerometer;​ autoplay; clipboard-write;​ encrypted-media;​ gyroscope; picture-in-picture;​ web-share"​ referrerpolicy="​strict-origin-when-cross-origin"​ allowfullscreen></​iframe>​ 
 +</html>
  
 ===== Concluzii ===== ===== Concluzii =====
 +
 +Am considerat acest proiect extrem de interesant și util în viața de zi cu zi, oferindu-mi satisfacția de a-l realiza de la zero. Deși am întâmpinat câteva dificultăți,​ în special în partea de calibrare, am reușit să le depășesc. Modulul HX711 este foarte sensibil și necesită o poziționare precisă pentru a măsura corect greutatea. Am rezolvat această problemă adăugând un suport stabil pentru cântar, asigurându-mă că forța aplicată acționează într-o direcție specifică asupra load cell-ului și că toate componentele sunt bine fixate. Această ajustare a fost esențială pentru obținerea unor măsurători precise și consistente.
  
 ===== Download ===== ===== Download =====
  
 <note warning> <note warning>
-TODO+{{:​pm:​prj2024:​iotelea:​cantar_bucatarie.ino.zip|}}
 </​note>​ </​note>​
  
 ===== Jurnal ===== ===== Jurnal =====
- +    * 05.05.2024: Creare pagina wiki 
-    * Trebuie sa rezolv ​problema ​cu Black Boxes+    * 13.05.2024: Comandare piese hardware 
 +    * 15.05.2024: Crearea schemelor pentru circuit 
 +    * 17.05.2024: Asamblarea circuitului hardware 
 +    * 19.05.2024: Rezolvare ​problema ​LCD ului (Black boxes) 
 +    * 20.05.2024: Scriere cod si calibrarea load cell-ului 
 +    * 21.05.2024: Adaugare buton de reset 
 +    * 22.05.2024: Adaugarea butonului de Plate Function si a LED-ului 
 +    * 24.05.2024: Retusarea codului si a circuitului
  
 ===== Bibliografie/​Resurse ===== ===== Bibliografie/​Resurse =====
Line 129: Line 555:
 https://​www.diyengineers.com/​2022/​05/​19/​load-cell-with-hx711-how-to-use-with-examples/​ https://​www.diyengineers.com/​2022/​05/​19/​load-cell-with-hx711-how-to-use-with-examples/​
 https://​nicuflorica.blogspot.com/​2018/​02/​cantar-electronic-pentru-greutati-mic.html https://​nicuflorica.blogspot.com/​2018/​02/​cantar-electronic-pentru-greutati-mic.html
 +
 +==Resurse Software==
 +https://​randomnerdtutorials.com/​arduino-load-cell-hx711
 +
 +https://​www.instructables.com/​Tutorial-How-to-Calibrate-and-Interface-Load-Cell-/​
  
 <​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</​a></​html>​ <​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</​a></​html>​
  
pm/prj2024/iotelea/dalya.tobescu.1716740957.txt.gz · Last modified: 2024/05/26 19:29 by dalya.tobescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0