Garbled Display. Advice on debugging Please

Hi All,

I'v cobbled together a scale connected to an rfid scanner. The basic premise of the application is I have a heap of boxes with rfid tags (mifare) attached and I want to weigh them intermittently, get their ID using the rfid tag and then push their weight and ID to a mysql database using http POST. At the same time, the weight and box info gets displayed on an LCD

The program works fine for the first few scans and then the LCD screen output becomes garbeld, with random characters jumping all over the place. Serial output confirms the program is still running as expected, however it does become unresponsive at times which corresponds to but not always concomitant with LCD output being garbled.

Each component works appropriately when using basic sketches without changing wiring, but when I try to run everything together I can't get a stable result. The project is powered via usb for now, but I get the same result when powered by a 5V/2A power supply with + to ESP32-VIN and LCD-VCC with a 1000uF cap bridging supply.

I don't have any experience in troubleshooting something like this. Would really appreciate some guidance on how to proceed.

Schematic and code below.

Thanks.


/*

  This sketch utilises an ESP32 hooked up to a HX711 with 4 load cells and an MFRC522 RFID scanner to read RFID tags attached to honey supers.
  The weight of the honey super is recorded and trasmitted via http POST to a local SQL server.

*/

#include <soc/rtc.h>
#include "esp_wifi.h"
#include <WiFi.h>
#include <HTTPClient.h>
#include <ESPmDNS.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <MFRC522.h>
#include <HX711.h>

// ===== Network credentials and Config =====
const char* localHostname = "nodeboxout" ;        // UDV // The hostname of this device
const char* ssid     = "Apollo" ;                // UDV // Your WiFi network NAME.
const char* password = "XXXXXXXX" ;          // UDV // Your WiFi network PASSWORD.
const char* regType = "OUT" ;                     // UDV // Role if this NODE = "IN" or "OUT"
const char* sqlServer = "raspberrypi" ;          // UDV // Hostname of the SQL Server.
const char* apiKeyValue = "SdnSO87hjJYS9S8" ;    // UDV // apiKey use for posting data.
const char* sqlPass = "XXXXXXXX" ;                // UDV // SQL Server password
IPAddress serverIp(0, 0, 0, 0) ;

// ==== MFRC522 ====
#define SS_PIN 4
#define RST_PIN 5
MFRC522 rfid(SS_PIN, RST_PIN) ;
MFRC522::MIFARE_Key key ;
byte nuidPICC[4] ;                                // array that will store new UID (NUID)
boolean newTag = false ;
int newTagReg ;                                   // when was the tag registered in millis()
boolean tagMatch = false;
const int tagRegThresh = 2000 ;                    // 2 seconds between scans. Don't want to keep scanning while there is weight on the scale.
const char* ver = "beta2.5_DOS";
const char* blank = "                "; // 16 ch empty char for clearing lcd

// ==== HX711 ====
const int LOADCELL_DOUT_PIN = 25 ;
const int LOADCELL_SCK_PIN = 26 ;
HX711 scale ;
float weight ;
char weightChar[4] ;
const int weightThresh = 7.5 ;                            // UDV //  How many kg on scale before RFID reader fires UP ?
const int calFact = -20810.00;                             // UDV // Calibration factor for the scales.

// ==== LCD ====
int lcdColumns = 16 ;
int lcdRows = 2 ;
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows) ;
const int errorDelay = 5000 ;                       // How long to print Error Messages to LCD
const int printDelay = 3000 ;                       // How long to print regular Messages to LCD

// Char arrays for storing credentials
char sqlUID[18] ;
char brandID[4] = "UA1" ;
char loadID[10] ;
char hiveNum[4] ;
char boxNum[4] ;
char rfidMatchChar[18] ;

void setup() {
  rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M) ;   // slow ESP32 to 80 mHz to prevent HX711 issues
  Serial.begin(115200) ;
  Serial.println(F("Begin Setup"));

  lcd.init() ;  // Inititalise LCD
  lcd.backlight() ;
  lcd.print(ver);   // print current sketch version
  delay(printDelay);
  lcd.setCursor(0, 0);
  lcd.print("Welcome!        ") ;
  lcd.setCursor(0, 1) ;
  lcd.print("Node role: ") ; lcd.print(regType) ;
  delay(printDelay) ;
  lcd.clear();

  init_network() ; // connect to wifi and locate IP address of sql server

  // initialise rfid scanner
  SPI.begin() ;
  delay(50) ;
  rfid.PCD_Init() ;                         // Init MFRC522
  for (byte i = 0; i < 6; i++) {            // Fill key with empty values
    key.keyByte[i] = 0xFF ;
  }

  init_scale() ; // initialize load cells

  lcd.clear() ; lcd.print("All Services OK!") ;
  lcd.clear() ;
  Serial.println(F("End Setup"));
  //end setup
}

void loop() {
  // commented for testing in isolation from load cells
  //weight = scale.get_units(5) ;
  weight = 51.11 ;
  lcd.setCursor(0, 0);
  lcd.print("Scan Box");
  lcd.setCursor(0, 1) ;
  lcd.print(weight) ;
  lcd.print(" kg        ") ;

  if (int(weight) >= weightThresh ) {                       //if more than X kg on scale, fire up the rfid reader and look for a new tag
    if (!newTag && millis() - newTagReg > tagRegThresh ) {  // cond. No new tag and X(tagRegThresh) seconds has passed since last tag reg
      delay(5);
      readTag() ;
      if (newTag) { // if we got a new tag from the reader...

        // get matching record from the LAMP Server
        Serial.println(F("Matching sqlUID: ")) ;
        getRfidMatch() ;

        if (tagMatch) { // if the tag exists in db and credentials were obtained...
          splitCredentials(); // split rfidMatchChar to populate box credentials
          // print box info to lcd
          lcd.clear();
          lcd.setCursor(0, 0) ; lcd.print(F("BOX: ")); lcd.print(loadID); lcd.print(F(" ")); lcd.print(hiveNum);
          //report to Serial Monitor too
          Serial.print(F("BOX: ")); Serial.print(loadID); Serial.print(F(" ")); Serial.println(hiveNum);

          // weight = scale.get_units(10) ;         // get weight again this time average of 10 reads
          lcd.setCursor(0, 1) ;
          lcd.print("Posting DATA") ;
          postData() ;                          // Send data to SQL server using POST
          delay(printDelay);
        }
      }


    }
  }
  newTag = false ;                      // Finished with the tag so reset flags.
  tagMatch = false ;

}

void getRfidMatch() {

  // Empty Credentials
  loadID[0] = '\0' ;
  hiveNum[0] = '\0' ;
  boxNum[0] = '\0' ;
  rfidMatchChar[0] = '\0' ;
  tagMatch = false ;

  char GET_URL[150] = "" ;
  append("http://", GET_URL) ;
  char IPChar[16] ;
  serverIp.toString().toCharArray(IPChar, 16) ;
  append(IPChar, GET_URL) ;
  append("/rfid2hiveid_0.3_secure.php?", GET_URL) ;

  // Format GET request
  append2("api_key=", apiKeyValue, GET_URL) ;
  append2("&pass=", sqlPass, GET_URL) ;
  append2("&rfid=", sqlUID, GET_URL) ;

  // *DEBUGGING report what is being sent in GET request
  //  Serial.print(F("GET Request: ")) ;
  //  Serial.println(GET_URL) ;

  // Send formatted GET request
  HTTPClient http ;  // Declare object of class HTTPClient
  http.begin(GET_URL);
  int httpResponseCode = http.GET() ;
  String payload = http.getString();    //Get the response payload
  if (payload == "0 results") { // if there's no match, report and bail

    lcd.setCursor(0, 1); lcd.print("No Match in DB!!");
    Serial.println(F("No match for this ID!"));
    delay(printDelay);
    lcd.clear();
    return ;
  }

  // If sql reqcord returned form server
  tagMatch = true ;
  // assign variable values from payload
  int payload_len = payload.length() + 1;
  payload.toCharArray(rfidMatchChar, payload_len); // place returned ":" delimeted data into char
  //Serial.print(F("Server response code : ")); Serial.println(httpResponseCode);
  // print the matching credentials
  Serial.println(rfidMatchChar);
  lcd.setCursor(0, 1); lcd.print(rfidMatchChar);
  http.end();
}

void postData() {
  char POST_URL[200] ;
  char php_loc[50] = {0} ;
  dtostrf(weight, 5, 2, weightChar) ;
  append("http://", php_loc) ;
  char IPChar[16] ;
  serverIp.toString().toCharArray(IPChar, 16) ;
  append(IPChar, php_loc) ;
  // Format POST request
  append("/post-extraction-data.php?", php_loc) ;
  append2("api_key=", apiKeyValue, POST_URL) ;
  append2("&regtype=", regType, POST_URL) ;
  append2("&brand=", brandID, POST_URL) ;
  append2("&rfid=", sqlUID, POST_URL) ;
  append2("&loadid=", loadID, POST_URL) ;
  append2("&hivenum=", hiveNum, POST_URL) ;
  //append2("&boxnum=", boxNum, POST_URL) ;
  append2("&weight=", weightChar, POST_URL) ;

  // report what is being sent in POST request
  //  Serial.print(F("PHP loc: ")); Serial.println(php_loc) ;
  //  Serial.print(F("POST_URL: ")); Serial.print(POST_URL);

  HTTPClient http ;                               //Declare object of class HTTPClient
  http.begin(php_loc) ;
  http.addHeader("Content-Type", "application/x-www-form-urlencoded") ;
  int httpResponseCode = http.POST(POST_URL) ;

  Serial.print(F("Response code from POST request: ")) ; Serial.println(httpResponseCode) ;
  if (httpResponseCode == 200) {
    Serial.println(F("Data was written to db.")) ;
    lcd.setCursor(0, 0); lcd.print(blank) ; lcd.setCursor(0, 0) ; lcd.print(rfidMatchChar);
    lcd.setCursor(0, 1) ;
    lcd.print("DATA WRITE OK!  ") ;
    delay(printDelay) ;
    lcd.clear() ;

  }
  else {
    Serial.println(F("Data Post Error")) ;
    lcd.clear() ; lcd.print(F("DATA WRITE FAIL!")) ;
    delay(errorDelay) ;
    lcd.clear() ;
  }
}




void init_network() { // Initialise network interface
  esp_wifi_set_max_tx_power(20);            // Set to low to reduce brown-out issues
  lcd.clear(); lcd.setCursor(0, 0) ; lcd.print(F("Join WiFi       ")) ;
  WiFi.setHostname(localHostname) ;         // set hostname
  WiFi.begin(ssid, password) ;

  while (WiFi.status() != WL_CONNECTED) {
    delay(500) ;
    Serial.print(F(". ")) ;
  }
  lcd.setCursor(14, 0); lcd.print(F("OK"));
  Serial.print(F("Local IP: ")) ;
  Serial.println(WiFi.localIP()) ;

  // Start the mDNS responder for "nodeboxin.local"
  if (!MDNS.begin(localHostname)) {
    Serial.println(F("mDNS fail!")) ;
  }
  else {
    Serial.println(F("mDNS Up")) ;
  }

  // Resolve the IP Address for the mySQL Server
  serverIp = MDNS.queryHost(sqlServer) ;
  lcd.setCursor(0, 1) ;  lcd.print("Locate Server   ");
  while (serverIp.toString() == "0.0.0.0") {
    Serial.println(F("Can't find sqlServer")) ;
    Serial.println(F("Retrying")) ;
    delay(50) ;
    serverIp = MDNS.queryHost(sqlServer) ;
  }
  lcd.setCursor(14, 1); lcd.print("OK"); delay(printDelay);
  Serial.print(F("Server IP: ")) ;
  Serial.println(serverIp.toString()) ;
}

void init_scale() {
  Serial.println(F("Initializing Scale"));
  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN) ;
  scale.set_scale(calFact);
  lcd.clear() ;
  lcd.print(F("Tare function.")) ;
  lcd.setCursor(0, 1) ;
  lcd.print(F("Empty Scale:    ")) ;
  for (int i = 5; i > 0; i--) {
    lcd.setCursor(13, 1) ;
    lcd.print(i) ;
    delay(200) ;
  }
  scale.tare() ;                // reset the scale to 0
}


void readTag() { // scans for a new tag. If none found function will exit immediately
  if ( ! rfid.PICC_IsNewCardPresent()) // Reset the loop if no new card present
    return ;
  if ( ! rfid.PICC_ReadCardSerial())   // Verify if the NUID has been read
    return ;
  MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak) ;
  if (rfid.uid.uidByte[0] != nuidPICC[0] ||
      rfid.uid.uidByte[1] != nuidPICC[1] ||
      rfid.uid.uidByte[2] != nuidPICC[2] ||
      rfid.uid.uidByte[3] != nuidPICC[3] ) {

    Serial.println(F("A new card has been detected.")) ;
    lcd.setCursor(0, 0); lcd.print(F("Tag Registered  "));

    // Set newTag and newTagReg(ms)
    newTag = true ;
    newTagReg = millis() ;

    // Store NUID into nuidPICC array
    for (byte i = 0; i < 4; i++) {
      nuidPICC[i] = rfid.uid.uidByte[i] ;
    }
    // concatenate nuidPICC to ":" delimeted char "sqlUID"
    array2delim(nuidPICC, sqlUID) ;  // push uid byte array to delimeted char sqlUID
    Serial.print(F("delimeted UID: "));  Serial.println(sqlUID); // print delimeted ID to the console
  }
  else {
    Serial.println(F("Card read previously.")) ;
    // Don't report to lcd
    newTag = false;
  }

  // cleanup and exit func
  rfid.PICC_HaltA() ;   // Halt PICC
  rfid.PCD_StopCrypto1() ; // Stop encryption on PCD
}

void array2delim(unsigned char* b, char* s) // converts byte array to delimeted char array
{
  int i = 4 ;
  for (;;) {
    unsigned char f1 = *b % 10 ;
    unsigned char f100 = *b / 10 ;
    unsigned char f10 = f100 % 10 ;
    f100 /= 10 ;
    if (f100) {
      *s++ = '0' + f100 ;
      *s++ = '0' + f10 ;
    } else if (f10)
      *s++ = '0' + f10 ;
    *s++ = '0' + f1 ;
    if (!--i) {
      *s = '\0' ;
      return ;
    }
    *s++ = ':' ; // delimeter
    b++ ;
  }
}

void append (const char *s, char *c) {                  // append string s to char c
  strncat (c, s, strlen(s)) ;
}

void append2 (const char *s, const char *t, char *c) {  // append string s and char t to char c
  strncat (c, s, strlen(s)) ;
  strncat (c, t, strlen(t)) ;
}

void splitCredentials() { // helper func to split rfidMatch payload
  char* ptr = strtok(rfidMatchChar, ":");
  byte i = 0;
  while (ptr) {
    if (i == 0) {
      strcpy(loadID, ptr);
    }
    else if (i == 1) {
      strcpy(hiveNum, ptr);
    }
    else if (i == 2) {
      strcpy(boxNum, ptr);
    }
    ptr = strtok(NULL, ":");
    i++;
  }
}

type or paste code here

Did you stop to look at that schematic? Red wires all going to a point and then emerging and going elsewhere? Did you not stop to think how useless that is?

Anyway you don’t seem to have any pull up resistors on your I2C lines, 3k3 to the 3V3 supply should do it.

Sorry I don't really get what you mean? Are you talking about the IIC/I2C > LCD connections? yes they overlap in the schematic, but obviously aren't connected.. Or are you referring to another part?

Thanks for the suggestion. I'll give this a try. Is this only a problem if you are using multiple I2C devices or is this standard practice for any I2C connections? [edit] Never mind.. Time to read some docs.

Cheers.

Is there any need to use pull up resistors on the load cell signal lines? They aren't using I2C, but is it good practice nonetheless?

No, it is essential for an I2C device, but unless a digital output identifies itself as open collector or open drain, there is no need to add a pull-up resistor.

Great :+1:

Added those pull up resistors and it's all working well now.

Thanks again for helping.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.