text:
DHT22 sensor reading code interprets negative values weirdly
The following code reads the DHT22 temperature and humidity values, assuming the pin value as the sensor's host pin.
When the temperature drops below 0°C, this code returns inadequate values in the range from -3200 to -3300 (most often the values range around -3275). When using a popular Adafruit library, the values are also incorrect. The code was not written by me, it originates from here, but the comments in the source are in Russian.

The problem is quite common, but there was no adequate solution provided in any case. It was mentioned in the Adafruit library issues quite a few times (here, here and here (related)), and on other websites. People even reported this issue on DHT11 and DHT21 sensors.

// "DHTLif.h"

#pragma once
#include <Arduino.h>
#include <Firmata.h>

uint64_t readingTime;

void DHTt(const uint8_t pin) {
  if ((millis() - readingTime) > 2000) {
    unsigned char receivedDHTData[5];
    float temperature, humidity;

    #define DHT_PORT PORTD
    #define DHT_DDR DDRD
    #define DHT_PIN PIND
    #define DHT_BIT pin
    int count = 32;
    unsigned char i, j;

    ReLoad: // Restarting point for error handling
    //=============MCU send START
    DHT_DDR |= (1 << DHT_BIT); // exit
    DHT_PORT &= ~(1 << DHT_BIT); // the pin's level is low, set it to high and wake up the sensor
    delay(18); // 18 ms delay from the docs
    DHT_PORT |= (1 << DHT_BIT); // set the pin's level to low
    DHT_DDR &= ~(1 << DHT_BIT); // the pin as exit

    //=============Initialize DHT
    delayMicroseconds(50); // delay from the docs
    if (DHT_PIN & (1 << DHT_BIT)) { // DHT must return 0
      if (count != 0) {
        goto ReLoad;
        count--;
      } else {
        // send initialization error message
        Firmata.sendString("ERR;DHTt;INIT");
        return;
      }
    }

    delayMicroseconds(80);
    if (!(DHT_PIN & (1 << DHT_BIT))) { // the bus must be set to 0 after 80 ms
      if (count != 0) {
        goto ReLoad;
        count--;
      } else {
        // send weird behaviour error message
        Firmata.sendString("ERR;DHTt;BHVR");
        return;
      }
    }

    //===============Receive 40 bits of data
    while (DHT_PIN & (1 << DHT_BIT)); // wait until the bus is set to 1
    for (j = 0; j < 5; j++) { // loop for 0-4 bytes
      receivedDHTData[j] = 0;
      for (i = 0; i < 8; i++) { // receive bits and pack them into bytes
        while (!(DHT_PIN & (1 << DHT_BIT))); // wait until the bus is set to 0
        delayMicroseconds(30); // 30 ms delay from the docs
        if (DHT_PIN & (1 << DHT_BIT)) // if the pin is 1 after the delay,
          receivedDHTData[j] |= 1 << (7 - i); //set the i'th bit to 1
        while (DHT_PIN & (1 << DHT_BIT)); // wait until the bus is set to 0
      }
    }

    if ((unsigned char)(receivedDHTData[0] + receivedDHTData[1] + receivedDHTData[2] + receivedDHTData[3]) != receivedDHTData[4]) { // checksum
      Firmata.sendString("ERR;DHTt;CHSM");
      return;
    }

    temperature = (receivedDHTData[3] * 0.1) + ((receivedDHTData[2] & 0b01111111) * 25.6); // calculating temperature for DHT22
    if (receivedDHTData[2] & 0b10000000) temperature *= -1; // if the temperature is negative
    humidity = (receivedDHTData[1] * 0.1) + (receivedDHTData[0] * 25.6); //calculating humidity for DHT22

    // form the final message
    char result[32], catres[8];
    readingTime = millis();
    strcpy(result, "OK;DHTt;");

    dtostrf(temperature, 5, 2, catres);
    strcat(result, catres);
    strcat(result, ";");
    dtostrf(humidity, 5, 2, catres);
    strcat(result, catres);
    Firmata.sendString(result);
    return;
  }
}

The only fix I found looks really silly and it does not work, the values don't drop below zero.
// The temperature is a 16 bit signed integer, 10 times the actual value in degrees Celsius
int16_t temperatureTimesTen = (int16_t)((receivedDHTData[2] << 8) | receivedDHTData[3]);
float temperature = (float)(temperatureTimesTen) * 0.1f;

// The maximum possible temperature for an DHT22 is 80 degrees Celsius
if (temperature > 80) temperature = temperature - 3276.7f;

That seems to be a bit of a silly way of combining bytes to form a 16 bit value if you ask me...

I've got the exactly same code in another library. I'll try to put my DHT22 into the freezer tomorrow and see what happens.

@Majenko, at least this thing manages to work while the temperature is positive. I now wait until the temperature outside drops below zero, since my DHT22 is installed outside without a possibility to move it. Maybe, changing temperature *= -1; to temperature *= -1.0f; will help?

That's unlikely to help, because temperature is already a float at that point.

Looking at the data sheet (Page 3), the DHT22 uses, unlike the DHT11 and unlike the implementation in many libraries, a standard Base-2 format for the temperature. So converting the temperature should be as easy as:
// The temperature is a 16 bit signed integer, 10 times the actual value in degrees Celsius
int16_t temperatureTimesTen = (int16_t)((receivedDHTData[2] << 8) | receivedDHTData[3]);
float temperature = (float)(temperatureTimesTen) * 0.1;

I was not able to confirm this yet (couldn't get my sensor cold enough), but your observation that the wrong values report as being in the order of -3300 point to the same conclusion.
EDIT
I need to correct myself. The documentation is misleading, therefore my understanding of it was incorrect. After I finally got the possibility to really test my DHT22 in negative temperatures (it's snowing outside now), I found the correct formula to be:
int temp = ((receivedDHTData[2] & 0x7F) << 8 | receivedDHTData[3]) * 0.1;
// if MSB = 1 we have negative temperature
temp = ((receivedDHTData[2] & 0x80) == 0 ? temp : -temp);

return temp; // in degrees celsius

EDIT 2
For this particular sensor, decoding seems to be as follows. It appears that on negative temperatures, the resolution is only 1 degree, not 0.1 degrees.
float temperature = 0;
int32_t temp = ((receivedDHTData[2]) << 8 | receivedDHTData[3]);
// if MSB = 1 we have negative temperature
if (temp & 0x8000)
{
    temp = temp | 0xFFFF0000; // sign-extend
    temperature = temp; // Convert to negative whole-degrees
}
else
{
    temperature = (float)temp / 10.0f;
}

I will try to implement this solution. I will get back to you shorty after getting any results.

That didn't help, the -3275-like values are still reported.

That is weird. Can you try to print out the values of receivedDHTData[2] and receivedDHTData[3]? The byte value at index 2 should be 255 (0xFF) if my assumption is right.

indeed, it does: https://skr.sh/i/031121/YWJ4uO4E.jpg?download=1&name=Скриншот%2003-11-2021%2016:26:01.jpg

When I feed my code with exactly these values I get the correct result. Maybe this is also a compiler/board issue? I have tested on an AVR board (Arduino Nano)

my board is also an AVR-based Arduino Uno. I am using this simple sketch: https://github.com/StarterCraft/Hyrex_AsQamm/blob/6eb87320997e0b2cf4a714d13f210cb1359f640e/AsQammArduino/DHTTest/DHTTest.ino

and this is a Serial.println-converted version of the code in question: https://github.com/StarterCraft/Hyrex_AsQamm/blob/6eb87320997e0b2cf4a714d13f210cb1359f640e/AsQammArduino/Features/DHTLifo.h

Please use the code I posted above exactly as it is, replacing lines 71 and 72. Do not squeeze it into one line (two casts on the same line may confuse some compilers).

replaced the lines, please check.

nothing has changed after changing this statement to a two lines.

Let us continue this discussion in chat.

I just saw https://stackoverflow.com/questions/69870078/visual-studio-c-has-different-comparison-results-for-uint16-and-uint32?noredirect=1#comment123516299_69870078 Maybe this is related. You should maybe try a manual sign-extend?

Could you confirm your information with freezing the sensor?

No, I didn't have the time to test this again. I seriously wonder why you get different results than I am. I will try again.

@Starter I'm sorry this took so long, but I think the above formula should now do the trick. The data was different than what I expected from the documentation.

https://skr.sh/i/051221/kWFdQYc1.jpg?download=1&name=Скриншот%2005-12-2021%2014:27:41.jpg that didn't help, though :<

@Starter: That looks like what I originally expected that it should be, but my observation showed a different binary pattern for negative temperatures. Are you sure you have a DHT22? These are the sensors with the white enclosure.

Yes, I am totally sure. This is the item card from the Aliexpress seller I've bought the sensor from. I use the DHT22 Module variant. Also, can you please share your binary data? https://github.com/StarterCraft/Hyrex_AsQamm/blob/29eb8f825140b98287feeb3cac1f1e4cc3ada88c/AsQammArduino/Features/DHTLifo.h#L72 is the code producing my output

My data was [2] = 0x80 and [3] = 0x04 for -0.4°C. Yours looks like base-2 encoded. Can you confirm that the correct temperature is -2.5°C?

Right now, according to local weather forecast provider (https://skr.sh/i/061221/qEcPFcRN.jpg), the temperature is around -9 degrees Celsius, and this is the current binary data: https://skr.sh/i/061221/fYC1gHnH.jpg

Also please fix your syntax: there is no var in C++, there is auto

1111 1111 1111 0111 is -9 in standard base-2 encoding. There's no DHT variant I'm aware of that uses this encoding, particularly since all variants provide the temperature in tenths of a degree. Do you have the possibility to get a data set with a positive measurement?

can you offer me a way to decode this correctly?

I am afraid I can't do this, my sensor is installed statically outside

I think the following should do: int32_t temperature = ((receivedDHTData[2] << 8) | receivedDHTData[3]); if (temperature & 0x8000) temperature |= 0xFFFF0000; The result is then in whole degrees.

https://skr.sh/i/071221/bF9R2Yb2.jpg?download=1&name=Скриншот%2007-12-2021%2009:31:24.jpg Positive reading

It gets more confusing each time :-( As you show, this is decoded correctly, and 100101b is 37 decimal, which can (as specified) be correctly divided by 10 to result in 3.7°. (I'm assuming it's not 37° outside) I've more and more got the impression that you've got some chinese clone there that doesn't align with the official specs. I'll add the suggested code for this finding above, but it must remain a guess.

https://skr.sh/i/141221/775SSTjY.jpg?download=1&name=Скриншот%2014-12-2021%2008:36:51.jpg oumph, that's pretty cold. I think I need to multiply it by 0.1

Yea, apparently. Then at least it would be consistent. Still not sure why my first suggestion didn't match then. However, I'm happy that it finally works for you.

I ran into this issue of getting -3200 values. I swapped the sensor with another one from the same vendor (tenstar robot on ali express) and the values for the 2nd sensor were normal. I put a regular thermometer next to the sensor and the reading are within a couple of degree of each other at -15c. I am supplying my sensors with 3.3 volts which in some cases can also cause issues.  Might be worth trying 5 volts to see it that makes any difference.


text:
Wifi Scanning code for esp32 wroom 32
I am trying to scan wifi in sta_ap mode in my esp32 wroom 32 module but it is not scanning new wifi .Can anybody tell more about how does wifi mode works in this module and what's the problem in my code.Same code is working in esp8266.
CODE:
#include <WiFi.h>

const char *ap_ssid = "ESP32";
const char *ap_password = "";

const char *sta_ssid = "KKACT";
const char *sta_password = "kk25990418";
void setup() {
  Serial.begin(115200);

  WiFi.mode(WIFI_AP_STA);
  WiFi.disconnect();
  delay(100);
  Serial.print("Configuring access point...");
  WiFi.softAP(ap_ssid, ap_password);

  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);

  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(sta_ssid);
  WiFi.begin(sta_ssid, sta_password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
   Serial.println("Now scanning wifi continously");
   int n=WiFi.scanNetworks();
   for (int i = 0; i < n; ++i)
  {
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");

  }
    delay(2000);
}

And if you disconnect before scanning?

I tried disconnecting at the end of void main loop ,but the results were same i was getting the wifi list but new wifi are not being detected or maybe not getting scanned

This is a issue raised on github about this:
https://github.com/espressif/arduino-esp32/issues/3294
And the issue seems to be that a failed connect prevent the scanning and the solution is:

So what i did was when entering the portal:
WiFi.mode(WIFI_OFF); // otherwise Wifi.Scannetworks() fails
delay(5000);
This seems to stop the processes that prevent the scanning.
After that an immediate scan works without problems.

so where should i add this line ,at the end of void setup like this?
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
WiFi.mode(WIFI_OFF);
delay(5000);```

You are not doing it correctly. In order to perform WiFi scan:

It must be in WIFI_STA mode;
It has to be disconnect from the AP;
After you done with the scanned SSID, BSSID and RSSI, you need to called WiFi.scanDelete() if you are going to do a scan again, otherwise you will get the same previous scanned result.

So in summary, here is the code:
#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  Serial.println();
}

void loop() {
  Serial.println("Scanning WiFi Networks...");
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  int n = WiFi.scanNetworks();
  for (int i=0; i<n; i++) {
    Serial.printf("%2d SSID=%-20s RSSI=%d\n", i+1, WiFi.SSID(i).c_str(), WiFi.RSSI(i));
  }
  WiFi.scanDelete();

  delay(10000);
}

i tried  WiFi.scanDelete(); but it didnt work ,I know i can use wifi_sta mode but esp32 has wifi_sta_ap which has both the station and access point mode ,so it should work in this mode too.                                                                                I tried the same code in esp8266 and it worked,something in void setup is breaking the wifi scan.

Are you using your code by just adding WiFi.scanDelete() or you are using my example?

i am using your code only but with Wifi.mode(WIFI_AP_STA );

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Why use a module rather than sensor directly?
I'm trying to understand when one would use an Arduino module rather than directly a sensor.
Here's an example to contextualize my question: I need to use a Hall sensor to measure the number of rotations per minute of a magnet mounted on a computer fan. I see that I can either buy the Hall sensor and wire it to the Arduino (Hall-Effect Sensor Analog 49E), or alternatively I could buy a sensor module (e.g., Digital Hall Effect Sensor Module or Linear Hall Effect Sensor Module). What is the advantage of buying modules, rather than the sensors directly?

do you not see a difference between the bare sensor and the sensor module?

The same reason why ready made meals exist when you can just buy individual ingredients.

@Gerben you don't see the advantage of having a power circuit and a schmitt trigger wired up and properly tuned for a range of magnetic fields?

The only difference i see between the sensor and the first module is the LED with its resistor. Not much of an advantage i think.

I usually use a module first and then, when I'm sure everything works as I intended, I might make a PCB that carries the sensor directly (and usually also the MCU).

One other way to look at it - it's the same benefit as using an Arduino (microcontroller module) rather than directly using an atmega328p integrated circuit (the main chip of the Arduino)

The modules are typically easier to work with, particularly for DIY projects. They have standardized connectors, have their connections labeled and can be mounted into wiring boards. The particular sensor you have there does have quite big legs, so this may work fine without the board, but this is often not true. Consider sensors such as the BME/BMP types (BME680 data sheet). They're far to small to be used directly without a PCB. And they require some external components to work correctly, which are already included on the module. So for experimental purposes, the module is the way to go.

It's a question of convenience and application use-case specific. Sometimes a module will give you additional functionality and/or structural stability, just by providing a mini-PCB (maybe with screw holes) for a low price overhead.
For example, compared to the bare element the module you posted has additional components (LED or A0,D0 on the pricier one) is easily mountable and provides standarized connection pins.
If you already have a PCB (or other circuitry) the module could be superfluous, maybe you just need the sensor itself, but often those modules come as neat packages, sometimes with controller chips speaking I²C and comparable protocols (like the DHT11/DHT22 and others).

Since nobody else has addressed your example directly, and to use it as an example, in addition to the other observations about these two items, let's also take note of :
Hall-Effect Sensor Analog 49E

The 49E sensor can detect the magnetic N/S pole and relative strength of a magnetic field and outputs an analog voltage

Vcc Range    2.3 – 10V
Output : Analog 1.9mV/GS (± 0.2mV/GS)

Digital Hall Effect Sensor Module

3144 sensor detects presence of magnetic field and outputs logic level.

Vcc Range    4.5 – 24V
Output :  Open Collector

Linear Hall Effect Sensor Module

Detects N/S poles and relative strength of a magnetic field.

Vcc Range 3.3 – 5V
Output : Analog 2.5mV / G PLUS digital output
Includes 49E sensor plus everything in the schematic below :

So the sensor you've linked provides an analog signal, allowing you measure the magnetic field strength.  The digital module provides only an open-collector output (ie: ON/OFF) which indicates either the absence or presence of a magnetic field above some threshold of intensity. These are entirely different functions which you would use for entirely different applications.  The digital module also works with VCC up to 24V, which makes it handy to integrate with 24V automation systems.  The linear module provides an analog output as well as some indicators and an additional digital output, but is capped at 5V Vcc (whereas the raw module accepts up to 10V).
Why would you choose either?  What do you need to do?  Do you want to check for the presence of a magnetic field only, or do you also want to measure its intensity?  Or both?  The modules do some of the work for you and, in the case of the linear module, actually give you an additional output that the raw sensor does not.  It's up to you to decide which of these serves your needs.

+1 for nice markup, but I think OPs question was more general, why one would chose some module over a component at all, rather than the differences in those specific modules/components (which are obvious, hopefully)

@scitor, I think this answer explains the difference in general using a specific example brought by OP

In your case it only makes sense if you want to put the module on a breadboard and don't have the other components on the board at hand.
Example: for a DS18B20 one wire temperature sensor you need a pullup resistor. If you have this resistor at hand there is no sense to buy a module. But if you have to buy one resistor it is more easy to buy a module.
For experimental setups, it is often easier to use a module. If you want to build the circuit permanently later, the modules are rather annoying. Because the modules are often very bulky. The direct mounting of the components on a perfboard is then more space-saving.

It's a tradeoff between convenience and your time, money and expertise. You could design the module's circuitry and function into your circuit board, or, at slightly more expense, you could solder a module to your circuit board, with the designing and functionality already built-in. It might cost a little bit more and maybe be somewhat larger, than if you did it yourself. Ultimately it's up to you, which way works better for you in your particular circumstance.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
stop motor instantaneous with hall sensor problem
I have a problem with stopping motor at same spot when magnet pass.. I tried to add interrupt and to make code as clean as possible but no joy so far. Any suggestions? sw will add later, just ignore..
byte outPin = 12;        // the number of the output pin
byte inPin = 2;          // the number of the input pin

byte hallPin = 3;        // hall sensor

byte sw;
byte previous;
int state = LOW;         // the current state of the output pin
int reading;             // the current reading from the input pin

void setup()
{
  pinMode(inPin, INPUT_PULLUP);
  pinMode(outPin, OUTPUT);

  pinMode(hallPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(hallPin), stop, FALLING);   //hall read low when magnet pass
}

void loop()
{
  sw=0;

  reading = digitalRead(inPin);       //read(LOW when press!)
  if (reading == HIGH) previous=0;

  if (previous == 1 && sw == 0) state=LOW;
  else if (reading == HIGH) state=LOW;
  else state=HIGH;

  digitalWrite(outPin, state);
}

void stop() {
  if (sw == 0 && reading == LOW) {
    state=LOW;
    previous=1;
  }
}

What is the problem you are facing exactly?

well code works, but I'm having delays, and motor does not stop instantly... any way to enhance code further?

You can enhance it by switching changing state's declaration to volatile bool state ...

motor does not stop instantly ... can you stop a car instantly?

@timemage will try that, thanks

@jsotola well true that, but I meant at least on approximately same spot at least...

stopping instantly and stopping at a chosen spot are two different things ... think about stopping a car at a stop sign ... how is that done? ... the motor behaves the same way as the car

I didn't notice before, but same with sw and previous regard to volatile. If these aren't factoring into the problem, you could update the code to include them so that they're not there anymore as a distraction from whatever the actual issue is.

@milos, what board are you using?

@Coder9390 arduino Micro

You can stop a BDC faster if you short-circuit it. This is possible with an H-Bridge and the appropriate components.
It would be easier to use a L293D, which already provides this mode.
If you want to try it with this component, of course you can also build the h-bridge yourself, pay attention to the D on the component. With the D-version the protection diodes are already built in. You can power two motors from 4.5V to 36V with a maximum current of 600mA.
For up to 2A you can use a L298N.

He may be able to stop it still faster by powering it in reverse for a very short time. The current draw can be very large though.

@Georg Thanks for recommendation, will consider if no code give acceptable result

The motor can't stop instantly because it has inertia, plus the inertia of whatever stuff the motor is moving.
So if you want it to stop at a set position, you have to slow it down before it reaches the desired position, so it will come to a stop where you want. It's not possible to do that with only one sensor.
A complicated solution would be to use a position encoder, like a rotary encoder, to know the position at all times, so you could use a control algo like PID on the motor. This offers the most features, as you can then set the desired stop position in software, without needing to move the sensor.
If the stop position never moves then a simpler solution is to use multiple sensors. That's often how it's done with elevators: there is a sensor to accurately align the elevator with the floor it has to stop on, but there are also several others slightly before that on the track to tell the controller that it's time to start slowing down, then slow down to a crawl, then stop.
To keep it simple you can use just two sensors: when it goes past the first, slow down the motor to a crawl. When it activates the second sensor, since it is going slow, it will stop quickly and end up where you want.


text:
How to get Bpm with 4 heart beat pulses
I'm trying to get an average from three intervals to get bpm. However, when I use the code below the bpm would slowly decrease when used with the sensor. Can anyone please check for what is wrong with the code and for reference I have to modify the below code from the link for 4 beats to get bpm. Getting BPM from the given code
#include <LiquidCrystal.h>

LiquidCrystal lcd(24, 25, 26, 27, 28, 29);

//global variables

int  ibeats, iInterval1, iInterval2, iInterval3, iCount = 1;
unsigned long iFirstPulse, iSecondPulse, iThirdPulse, iFourthPulse;
bool bIgnoreread = false;
bool bFirstPulse = false, bSecondPulse = false, bThirdPulse = false, bFourthPulse = false;

float BPM, fAverage;

void setup()
{
  //initialize USB serial port, I2C bus and LCD
  Serial.begin(115200);         //set this comm up in-case you want to troubleshoot

  lcd.begin(20, 4); delay(2);
  lcd.clear(); delay(2);

  lcd.setCursor(0, 0); lcd.print(" Patient Prober");

}

void loop()
{

  ibeats = analogRead(15); delay(5);//  Read the Pulse Sensor's value.

  lcd.setCursor(0, 3); lcd.print("BPM:"); lcd.print(BPM); lcd.print(" ");// displaying bpm value on LCD

  if (ibeats > 780 && bIgnoreread == false)     //once the signal is high and bIgnoread is false inital condition, inside if statment will start
  {
    if (bFirstPulse == false && iCount == 1)
    {
      iFirstPulse = millis();   // time when the pulse is high for the FirstPulse
      bFirstPulse = true;      // to turn off if statement
    }

    if (bSecondPulse == false && iCount == 2)
    {
      iSecondPulse = millis();
      iInterval1 = iSecondPulse - iFirstPulse;   // first interval
      bSecondPulse = true;
    }

    if (bThirdPulse == false && iCount == 3)
    {
      iThirdPulse = millis();
      iInterval2 = iThirdPulse - iSecondPulse;    //Second Interval
      bThirdPulse = true;
    }

    if (bFourthPulse == false && iCount == 4)
    {
      iFourthPulse = millis();
      iInterval3 = iFourthPulse - iThirdPulse;    // third interval
      bFourthPulse = true;
    }

    bIgnoreread = true; // to turn off when millis second is assign to variable Pulse  When the signal is high
  }

  // reseting all the bollean to intial condition
  if (ibeats < 300)
  {
    bIgnoreread = false;
    bFirstPulse = false;
    bSecondPulse = false;
    bThirdPulse = false;
    bFourthPulse = false;
    iCount++;               // incrment to help to diffrent if ststment above
  }

  //if(ibeats==0)iCount++;

  fAverage = ( iInterval1 + iInterval2 + iInterval3) / 3;         // Average for the interval
  BPM = (60000.0 / fAverage);                                    // Bpm calculation

  if (iCount > 4)iCount = 1;                                    // reseting icount to start the cycle again
}
//********************************************************************************************

your sketch contains no debugging code ... add some ... you cannot pinpoint the problem without it

you don't need to know when the second and third pulses occur ... get the timestamp of first pulse ... detect second pulse and third pulse ... calculate the BPM using the 1st and the 4th pulses

It sounds like you actually want to implement a rolling average for this. You want the average time of the previous four beats, (or rather the previous three time intervals), and each time you get a new interval you "forget" the oldest and add the newest, calculating the average of the three you have each time.


text:
Multiple SoftwareSerial's at the same time?
I need to receive some data from USB and send it to the Android device via Bluetooth. The problem is that multiple SoftwareSerials won't connect at the same time.
Here is my code:
SoftwareSerial bluetooth(2,3);
SoftwareSerial usbConverter(4, 5);

void setup() {
  usbConverter.begin(9600);
  bluetooth.begin(9600);
  checkConnection();
}

void checkConnection() {
  while(true) {
    int areBothDevicesConnected = 0;
    if(bluetooth.available()) {
      areBothDevicesConnected++;
      bluetooth.println("Bluetooth connected");
      if(usbConverter.available()) {
        areBothDevicesConnected++;
        bluetooth.println("USB converter connected");
      } else {
        bluetooth.println("USB converter is not available");
      }
    }
    if(areBothDevicesConnected == 2) {
      bluetooth.println("All devices connected");
      break;
    }
    delay(2000);
  }
}

As far as I understand only one SoftwareSerial can listen at the same time but in my case, I can't even connect both devices. On Android device I always receive USB converter is not available.
My setup:

Arduino UNO.
HC-05 Bluetooth.
USB to TTL converter.

Any clue?

receive some data from USB ... why are you not using  hardware serial for this?

Any clue? is not a question about arduino

I think you misunderstand what SoftwareSerial.available() does. It does not say anything about if the serial port is connected. It returns the number of received bytes in the buffer. When you don't send anything over the interfaces to the Arduino it will always return 0 aka false. Though - as you yourself already mentioned - you cannot receive on two SoftwareSerial interfaces at the same time, so your logic cannot ever work. Use hardware serial for one of the interfaces and rethink your connection check

When you have multiple instances of SoftwareSerial, you need to setup the .listen() method to switch between the instances if you are going to read from them. See https://arduino.stackexchange.com/a/43125/40646

Thank you. That is what I needed!


text:
SoftwareSerial fails to receive on Nano but works with Uno
I have built a circuit board that includes a BLE module and an oxygen sensor that has a UART.  Writing arbitrary data to the BLE works fine, but for some reason every configuration of SoftwareSerial I can think of will not pick up anything from the oxygen sensor TX.  It simply never has any bytes available.
Here's the code:
#include <SoftwareSerial.h>

const int HM10_TX = 8;
const int HM10_RX = 9;
const int LOXO2_TX = A6;
const int LOXO2_RX = A7;

SoftwareSerial BLE(HM10_RX, HM10_TX);
SoftwareSerial oxygen(LOXO2_RX, LOXO2_TX);

void setup() {
  BLE.begin(9600);
  oxygen.begin(9600);
  oxygen.listen();
}

void loop() {
  if (oxygen.available() > 0) {
    BLE.write(oxygen.read());
  }
}

Meanwhile, I uploaded a short serial passthrough sketch to an Uno, connected probes between it and directly to the pins on the Nano that are used for the O2 sensor TX/RX, and I can see the expected bytes being received in my serial monitor.  So I'm 99% sure the problem isn't with the sensor.  Maybe the circuit, but so far I don't seem to have evidence of that.
I've been under the impression that any pin on the Nano can be used with SoftwareSerial.  All the reading I've done hasn't yielded any useful information as to why nothing is being read when clearly there are voltage changes on the pin that are being picked up by the Uno.
The reason I'm not using hardware serial is I will be using multiple sensors and the hardware serial pins need to be available for USB.
Am I doing something wrong?  The passthrough code I write for the Uno really isn't that different from the above code except it's of course using the hardware serial so I can observe the serial output on my laptop.

which oxygen sensor are you using? ... how is everything connected? ... please draw a connection diagram

A6 and A7 are analog input only and not available on Uno.

@Juraj I think you meant the Nano?  This is really disappointing to learn.  I did a lot of reading before building my PCB, and nothing I found said there were any particular pins on the Nano or Uno that couldn't be used for SoftwareSerial.  Fortunately I designed extra holes on my PCB for the only few digital pins I have left, so I can add jumpers that should make my project feasible.  Thanks for the help!

Uno doesn't have A6 and A7 so your sketch can't work on Uno as it is


text:
`ConfigTime` daylight saving update
I'm using an ESP8266 to get clock NTP sync in this manner:
void myIOT2::_startNTP(const int gmtOffset_sec, const int daylightOffset_sec, const char *ntpServer)
{
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); //configuring time offset and an NTP server
    while (now() < 1627735850)                                /* while in 2021 */
    {
        delay(20);
    }
    delay(100);
}

But now, when daylight saving ended on 31/10/2021, what "flags" code that now daylight saving has ended, and 3600 sec have to reduced (or add) ?
in my case gmtOffset_sec=2*3600 and daylightOffset_sec=1*3600 ntpServer="pool.ntp.org"

the SDK adjusts automatically. I use only configTime(TZ_Europe_Bratislava, "pool.ntp.org"); TZ constants are in TZ.h  in esp8266 core

@Juraj I guess that ‘TZ_Europe_Bratislava’ encapsulates similar constants as mine. But still my time sync hasn’t updated

the DST info is not from the NTP server. my esp8266 clock changed time at 3 AM to 2 AM, but it syncs with NTP only once a day

@Juraj I used my TZ constant, and it worked as you said. Can you please explain why my method did not work as needed?

@Juraj What should I do in ESP32 ?

@Juraj NTP was not shifted as needed

@Juraj TNX, and that relates to my question about ESP32 ( since TZ.h belongs to ESP8266.h)

the esp32 has the configTzTime function for timezone. it is missing the TZ.h file. you can copy the TZ.h file or only the string with zone definition for your time zone.

For reference: https://github.com/esp8266/Arduino/blob/14c3798d4ff959254599f2904579412acba3f175/cores/esp8266/TZ.h#L338

Summing @juraj's comments

instead of defining UTC+x and Daylight offset, using NTZ instead.

While ESP8266 has `TZ.h as part of its core I used relevant TZ as shown.

for ESP32: a) replace to configTzTime as shown. b) Copy relevant TZ from TZ.h for current lib and use as follows.

for ESP8266:
configTime(TZ_Asia_Jerusalem, ntpServer);
for ESP32:
configTzTime(TZ_Asia_Jerusalem, ntpServer); // Tz value was copied to code


text:
HW-477 Module having VS1838B IR Sensor: Help with Pins
Ordered Universal IR Receiver and I got HW-477 module with VS1838B IR Sensor.
Good thing is datasheet for VS1838B is available but not for HW-477.
VS1838B pins as: Ref
Signal | GND | VCC
while HW-477 says:
(- minus) | R | G
Can't understand which one to follow and R is for Receiver? G is for GND and what is - (minus sign) for?
So can anyone help me with ( - R G ) of HW-477 ?
Images:

These may help?!
this & this one.
Updates:
I looked to trace the Foil (PCB Board Lines) but it didn't worked because the circuit as whole is coated.
Using Connectivity (Continuity (diode test)) option of Digital Multimeter, found these to play beep:

VS1838B
HW-477

Signal
G & (minus pin of HW-477)

GND
(- minus pin of HW-477)

VCC
R

But a person in this video saying

- is of course GND

There is a huge confusion which can only be cleared if I got a reply from seniors. I have two of this and can try one (even to burn) to better understand what is going on.
(Tried contacting the vendor about datasheet but they are not responding)

The only problem I am having is: If I press one button one single time it gives, let suppose this value: Code: 1086138583 but holding it for a second it gives another value of Code: 4294967295 which I don't know is a feature or fault. lol

That's how IR works. The first code is "You pressed the button" and the second is "You're still pressing the button". Not all buttons do it, but things like volume control do.

The problem here is that HW-477 refers not to the module as a whole but a generic PCB that is re-used (in some starter kits for sure) for many different sensors. I think the idea is that whatever device is attached to the board there's a position where the output is always the same (- = GND, R = VCC, G = Signal).
On some variants of the board you can see them labelled as - + S.

Thank You Sir! It worked. Just a note IRremote library from Arduino by Armin Joachimsmeyer latest version 3.4.0 didn't worked with legacy code found all over web, so I had to install 2.6.0 version and everything is fine now. Just a note so someone will get benefited.


text:
Analog UV sensor displaying incorrect values in serial monitor (GUVA-S12SD)
Using Arduino Uno and a GUVA-S12SD sensor (https://www.adafruit.com/product/1918).
Here's my circuit. 5V into sensor+, GND into sensor-, A0 to sensor out.

Here's my code:
void setup()
{
  Serial.begin(9600);
}

void loop()
{
  float sensorVoltage;
  float sensorValue;
  float uvIndex;

  sensorValue = analogRead(A0);
  Serial.print("Analog out: ");
  Serial.println(sensorValue);

  // 5 because 5V
  sensorVoltage = sensorValue * (5.0 / 1023.0);
  Serial.print("Output voltage: ");
  Serial.println(sensorVoltage);

  uvIndex = sensorVoltage / 0.1;
  Serial.print("UV Index: ");
  Serial.println(uvIndex);

  Serial.println();

  delay(1000);
}

Here's a sample from the serial monitor. The values stay about the same regardless of where I am in my house (in a sunny room, in the dark bathroom, etc.).
Analog out: 853.00
Output voltage: 4.17
UV Index: 41.69

Analog out: 853.00
Output voltage: 4.17
UV Index: 41.69

Analog out: 853.00
Output voltage: 4.17
UV Index: 41.69

Analog out: 853.00
Output voltage: 4.17
UV Index: 41.69

Output voltage is supposed to be very low. The UV index maxes out at around 11 - so 41 is too high. I checked what it is in my city right now, and it's 3. So this is super wrong. I don't have a multimeter to test with right now.
Any ideas about what could be going on? Did I order a bad sensor?

"regardless of where I am in my house" -  window glass blocks UV radiation almost completely (just FYI), so don't expect to get a reading inside ifyour house.

looks like the sensor module pins are not soldered

@SimSon I just tested outside and am getting the same readings

@jsotola Do they need to be soldered? I was hoping to be pretty modular with this experiment

@Dan the pins should be soldered to the module ... i am talking about the three pins visible in the three gold rings next to - Out +

@jsotola Ah I don't have any soldering equipment. I might be able to get some soon though. Is there any way to test this in the meantime or is soldering sort of the first step?

take the red jumper and insert it from the back of the board through the + hole ... insert the other two jumpers into the other two holes ... tie the three jumpers to the back of the board using the mounting hole next to the adafruit logo ... use a cable tie, or twist tie, or string, or rubber band ... pull on the jumper wire so that the ends are at an angle in the holes and are pressed tight against the side og the holes .... hopefuly that will work

@jsotola I managed to get the thing soldered but I'm getting the same high readings. Safe to say that the sensor is bad I guess?

analogRead returns an integer ... try defining sensorValue as integer


text:
Why must I detach the Arduino from the computer when making adjustment to the circuit?
I am new to Arduino and am reading Learn Electronics with Arduino: An Illustrated Beginner's Guide to Physical Computing. On page 118, it says:

Remember, whenever you make adjustments to a circuit, your Arduino should not be attached to your computer.

To give more context, it means when you make adjustment to the circuit on the breadboard, you should detach the USB cable from the computer.
I am wondering why?
Is it because a short circuit can crash my computer similar to how the USBKill works? Are there other reasons?

Arduino should not be attached to your computer. that is misleading ... it should say Arduino should not be powered.

Is it because a short circuit can crash my computer ...

It is more that you don't want an inadvertent mis-routing of cables to burn out your chips while they are powered.
I wouldn't personally be making changes to a breadboard circuit while it is powered. It is better to do it un-powered, and then check it over, than wonder why there is smoke coming from it.

"Adjustments to a circuit" can mean removing, adding or repositioning components on the breadboard. One can accidentally position a component lead in an incorrect location on the board, creating a circuit that is undesirable and possibly damaging to the assembled project.
If the misplaced lead or leads are in a particularly unsuited location, the circuit can include the USB portion of the system. The probabilities are low that one would accidentally damage that specific set of traces, or send voltage where it should not be, but they are non-zero. Even if one damages the Arduino, the cost is low compared to a damaged USB port or computer.
If you've been creating simple Arduino circuits and have misplaced or mis-routed a lead or component, you've learned how easily that can happen. Disconnecting the USB is comparably a minor inconvenience.

Is it because a short circuit can crash my computer

More than crashing it, there is some risk that a short-circuit on your board could cause damage to the computer's USB port that is powering it. Most computers have overload protection on their USB ports but you don't want to test it unnecessarily, risking permanent damage to the port.


text:
My program is using too much memory
I work in a warehouse and I was tasked to make a device which will show the location of any product when Product ID is given. All of our product has 3 things. Product ID, Rack Number and Gap number.
So the basic program is like that When I enter Product ID: 1640
The program will show in display that it is located in RCK 113 GAP 88
For this I used Arduino Mega, 4x3 Keypad and 16x2 LCD Display with I2C adapter.
I found a Arduino Keypad Calculator code on the Internet and modify my code from there.
So currently my code is working fine and everything
What I noticed is Arduino mega has only 2% memory left with all that string value (For that I couldn't use Arduino Uno at first). Now due to new products are added I need more space or ways to store data elsewhere.
I can not use internet or WIFI as Another team has already made a device using ESP8266 Nodemcu which shows data from a Google sheet but since my device stores data in itself it is very fast (almost instant) to show any result on the other hand the device with NODEMCU ESP8266 can be easily updated and doesn't bother about size yet it is very slow to show result and needs good wifi connection so it is not efficient in warehouse environment. So every staff use my device on the go and other device as a backup
Currently I have around 1000 product address stored in my device but a new shipment of almost 3000 product is coming and my mega has only 2% memory left.
So any genius here can you help me to compress my program more ? or any fault I made during my coding ? Also this is my first post and sorry for my bad English.
My Code is given below. It is huge please take your time to understand it.
Even I can't copy my code here
Body is limited to 30000 characters; you entered 132142.
This is a sample of my code for you to understand
Here is full code uploaded. Download
What I want to know is, if it is possible to add a Arduino SD card module and keep portion of my string memory in there.
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 4;
unsigned int integerValue=0;
//define the keymap
char keys [ROWS] [COLS] = {
  {'1', '2', '3', 'X'},
  {'4', '5', '6', '*'},
  {'7', '8', '9', '='},
  {'/', '0', '-', '+'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};

//create the keypad
Keypad myKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
LiquidCrystal_I2C lcd(0x27, 16, 2);

//variables declaration
boolean valOnePresent = false;
boolean result = false;
String num1;
int ans;
boolean getvalue = false;

void setup(){
  Serial.begin(9600);
  lcd.init(); // initialize the lcd
  lcd.backlight();
  frstscreen();
  //lcd.clear();

}

void loop(){
  char key = myKeypad.getKey();

  if (key != NO_KEY && (key=='1'||key=='2'||key=='3'||key=='4'||key=='5'||key=='6'||key=='7'||key=='8'||key=='9'||key=='0')){
      num1 = num1 + key;
      int numLength = num1.length();
      lcd.setCursor(15 - numLength, 1);
      lcd.print(num1);
      valOnePresent = true;
  }

  else if (valOnePresent == true && key != NO_KEY && key == '='){

      ans = num1.toInt();

      lcd.clear();
      lcd.setCursor(15,1);
      lcd.autoscroll();
      lcd.print(ans);
      lcd.noAutoscroll();
      result = true;

  }
  else if (key != NO_KEY && key == 'X'){
    lcd.clear();
    valOnePresent = false;
    num1 = "";
    frstscreen();
    getvalue = false;
}

    integerValue = ans;

if (result == true) {

if (integerValue ==  9   ) { IDScrn(); lcd.print("109");lcd.setCursor(12,1);lcd.print("63 "); delayfunc();}
if (integerValue == 15    ) { IDScrn(); lcd.print("107");lcd.setCursor(12,1);lcd.print("60 "); delayfunc();}
if (integerValue == 15    ) { IDScrn(); lcd.print("109");lcd.setCursor(12,1);lcd.print("63 "); delayfunc();}
if (integerValue == 20    ) { IDScrn(); lcd.print("109");lcd.setCursor(12,1);lcd.print("63 "); delayfunc();}
if (integerValue == 22    ) { IDScrn(); lcd.print("110");lcd.setCursor(12,1);lcd.print("68 "); delayfunc();}
if (integerValue == 23    ) { IDScrn(); lcd.print("109");lcd.setCursor(12,1);lcd.print("63 "); delayfunc();}

//TOP and components

if (integerValue ==  1001   ) { IDScrn(); lcd.print("RCK 115 COL A                  "); delayfunc();}
if (integerValue == 1002   ) { IDScrn(); lcd.print("RCK 115 COL A                  "); delayfunc();}
if (integerValue == 1003   ) { IDScrn(); lcd.print("RCK 115 COL A                  "); delayfunc();}

//Stock and CBOX

if (integerValue ==   376    ) { ComScrn(); lcd.print(" Stock Box 1"); delayfunc();}
if (integerValue ==   15     ) { ComScrn(); lcd.print(" Stock Box 1"); delayfunc();}
if (integerValue ==   919    ) { ComScrn(); lcd.print(" Stock Box 1"); delayfunc();}

//CBOX

if (integerValue ==   245    ) { ComScrn(); lcd.print(" 39K COL I "); delayfunc();}
if (integerValue ==   245    ) { ComScrn(); lcd.print(" 10K COL I "); delayfunc();}
if (integerValue ==   245    ) { ComScrn(); lcd.print(" 47k COL I "); delayfunc();}
if (integerValue ==   245    ) { ComScrn(); lcd.print(" 1k  COL I "); delayfunc();}
if (integerValue ==   245    ) { ComScrn(); lcd.print(" 2k  COL I "); delayfunc();}
if (integerValue ==   245    ) { ComScrn(); lcd.print(" 4.7k  COL I "); delayfunc();}
if (integerValue ==   245    ) { ComScrn(); lcd.print(" 27k COL I "); delayfunc();}
if (integerValue ==   766    ) { ComScrn(); lcd.print(" 0 ohm   COL I "); delayfunc();}
if (integerValue ==   766    ) { ComScrn(); lcd.print(" 220 ohm COL I "); delayfunc();}
if (integerValue ==   766    ) { ComScrn(); lcd.print(" 560 ohm COL I "); delayfunc();}
if (integerValue ==   766    ) { ComScrn(); lcd.print(" 470 ohm COL I "); delayfunc();}
if (integerValue ==   766    ) { ComScrn(); lcd.print(" 330 ohm COL I "); delayfunc();}
if (integerValue ==   766    ) { ComScrn(); lcd.print(" 100 ohm COL I "); delayfunc();}
if (integerValue ==   1291     ) { ComScrn(); lcd.print(" Cbox 1  GAP 101 "); delayfunc();}
if (integerValue ==   1314     ) { ComScrn(); lcd.print(" Cbox 1  GAP 101 "); delayfunc();}

if (getvalue == false) { noproduct(); }

}
 }
void frstscreen()
{
  lcd1stline();
  lcd.print("Warehouse Stock");
  lcd.setCursor(0,1);
  lcd.print("Enter ID: ");
}
void pressA(){

  lcd.clear();
  lcd.setCursor(0,1);
  lcd.print("Press A again");
}
void noproduct(){

  lcd1stline();
  lcd.print("Not Found");
  lcd.setCursor(0,1);
  lcd.print("Press A again");
  result= false;
}
void delayfunc(){
  result = false;
  delay (2000);
  pressA();
  getvalue = true;

}
void lcd1stline(){
lcd.clear();
lcd.setCursor(0,0);
}
void IDScrn(){
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("ID: ");
  lcd.setCursor(4,0);
  lcd.print(integerValue);
  lcd.setCursor(0,1);
  lcd.print("RCK     GAP");
  lcd.setCursor(4,1);
}

void ComScrn(){
    lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("ID: ");
  lcd.setCursor(4,0);
  lcd.print(integerValue);
  lcd.setCursor(1,1);
}

Have you thought about storing the data on an SD card? Fast, no internet needed, and easy to update. And no memory problems.

Using an SD card as memory to build your database is the way to go here, because it is future proof. As the number of items in the warehouse increases you might get to the memory limit of the Mega at some point. With an SD card you will never reach that with a simple text database of items. Additionally that will force you to write ONE function to get ANY entry form the database. Every time you see yourself writing basically the same code lines many times you should really think about a better code structure

the question is "What I want to know is, if it is possible to add a Arduino SD card module and keep portion of my string memory in there."

Warehouse... commercial... operations... don't use an Arduino.  Seriously. It's a toy.  There are far more suitable SBCs and micro controllers out there with vastly more resources to deal with scaling real-world problems.  You're trying to solve a business problem.  Scrimping for RAM is NOT a problem you need to burden yourself with when you have a real job to get done.  This isn't hobby time any longer - there's business depending on this.  Don't hobble yourself with weak and inappropriate tools.

@J... I'm not sure Arduinos shouldn't be used for commercial operations, especially as a prototype (which this clearly is).

you could also consider upgrading to a Raspberry Pi, which has more gigabytes of memory than you'll ever need for this program, but also uses more power and you have to deal with Linux

@user253751 Prototyping on a platform you'll need to throw out and start over with when you realize that database-connected business inventory problems don't fit in 8kB of RAM is absolutely pointless.  It's not 1980 any more.  We don't need to make our lives difficult on purpose by using absurdly overpriced and underpowered hardware.  An Arduino isn't even cheap - it's just a brutal handicap with no defensible justification for choosing it.  You'll do nothing but fight to squeeze the solution into that tiny chip  and leave yourself zero room to grow and expand.  Why?

@user253751I think a Raspberry Pi would be a much better platform if this "device" needs to be compact. Much easier to update, can have the entire database in memory, and application may be easier to develop for non-embedded devs

Your repeated comments sound like you have a X for Y problem and you don't understand that people are pointing out that the real solution to the problem presented is Y.

There are lots of repetitions in your code. This is something you should
generally avoid, not only because of memory usage, but also, and most
importantly, because of maintainability.
The most common way of getting rid of repetitions is to write a loop
that walks through an array. For the first part of your program (the
rack/gap scheme), that array could look like this:
// Data structure describing a recorded location.
struct Location {
    uint16_t id;
    uint8_t rack;
    uint8_t gap;
};

// List of recorded product locations.
const Location locations[] = {
    {  9, 109, 63 },
    { 15, 109, 63 },
    { 20, 109, 63 },
    { 22, 110, 68 },
    { 23, 109, 63 },
    // etc...
};

// Number of items in the above list.
const size_t nb_locations = sizeof locations / sizeof locations[0];

Note that the structure uses the smallest possible integers for each
field, in order to save memory. The main benefit, however, is that the
data is now in a format that is easier to update: a simple list of
numbers.
Then, all the code that handles this data becomes a loop, instead of a
repetition. For example, the following function can print the location
of any item on the LCD. It returns true or false to let you know
whether it did find the requested item:
// If the item is found, print its location and return true.
// Otherwise return false.
bool print_location(uint16_t id) {
    for (size_t i = 0; i < nb_locations; i++) {
        if (locations[i].id == id) {
            IDScrn();
            lcd.print(locations[i].rack);
            lcd.setCursor(12,1);
            lcd.print(locations[i].gap);
            delayfunc();
            return true;  // found
        }
    }
    return false;  // not found
}

This scheme still has the problem that all the data is copied to RAM at
initialization. If you have 4,000 items, that would require
16,000 bytes of RAM, or about twice the RAM of your Mega. You can
save RAM by keeping all constant data in flash, using the PROGMEM
qualifier. You have 32 times more flash than RAM. You
would then need, however, to bring each item back to RAM in order to use
it, which can be done with the memcpy_P() function. Here
is a version of the previous code that stores the array in flash:
// List of recorded product locations.
PROGMEM const Location locations[] = {
    {  9, 109, 63 },
    { 15, 109, 63 },
    { 20, 109, 63 },
    { 22, 110, 68 },
    { 23, 109, 63 },
    // etc...
};

// Number of items in the above list.
const size_t nb_locations = sizeof locations / sizeof locations[0];

// If the item is found, print its location and return true.
// Otherwise return false.
bool print_location(uint16_t id) {
    for (size_t i = 0; i < nb_locations; i++) {
        Location location;  // RAM copy of locations[i]
        memcpy_P(&location, &locations[i], sizeof location);
        if (location.id == id) {
            IDScrn();
            lcd.print(location.rack);
            lcd.setCursor(12,1);
            lcd.print(location.gap);
            delayfunc();
            return true;  // found
        }
    }
    return false;  // not found
}

This approach should enable you to store all the database in the flash
of your Mega, and maybe even on an Uno. That being said, I second the
commenters that say that using an SD card should make upgrading the
database a lot more convenient.

I didn't know about the memcpy_p ... upvoted

Did you try using the (PROGMEM)  F macro. It is described in the official Arduino documentation at the end of https://www.arduino.cc/reference/en/language/variables/utilities/progmem/
This forces all strings to be stored in Flash memory instead of the scarce SRAM memory.
You can try with a few strings to see if the memory lowers and calculate if it would be enough (to fit in Flash). If even Flash is not enough, than SD card would be an alternative.
Also some refactorings that might clean up the code (not necessarily reduce the memory used):

instead of the many if (integerValue == xxx) constructs, use  switch/case statements.
A possible bug are the identical values within (like 245 and 766 used many times, but for different products)
Move the function lcd.print("...") inside function ComScrn and pass the string (using F(..))
Similar as above but for IDScrn, using two strings and set the cursor inside IDScrn as well.
(key != NO_KEY && key == 'X') ... if key is 'X' it can never be NO_KEY so the first check can be removed.
if (result == true) can be written as if (result).

the question is "What I want to know is, if it is possible to add a Arduino SD card module and keep portion of my string memory in there."

@Juraj Simply: yes (but my alternative possibly makes this unnecessary.

What I want to know is, if it is possible to add a Arduino SD card module and keep portion of my string memory in there
Well, given that two contributors have already gave a handful of advices to both improving your code and the benefits of using an SD card. I find nothing else to say except answering your very specific question.
The answer is simple, and it is a yes.
There is no problem in dividing your data into two parts, one part on your microcontroller/Arduino and the other part on your SD card, you will have to know which part is where so you can access it without any problems and almost instantly as well.
I hope that answers your question fully.

In order to put the data on an SD card, the OP would still first have to write the program to have the data in a data structure rather than repeated if/print statements.  So the other answers still apply.

Indeed they do, this is why I stated very clearly at the beginning of my answer, that the other answers already gave a handful of advices on how to improve the code, which surely mentioned the usage of data structures, however he kept commenting on those answers and with the same question again.
What I want to know is, if it is possible to add a Arduino SD card module and keep portion of my string memory in there
So basically, yeah.

The Arduino Uno uses a rather old, weak processor. It is still a perfectly cromulent microcontroller - it does just fine - but much newer ones do exist.
You mentioned the ESP8266. Did you know it has 40kB of RAM compared to the Uno's 2kB? And the successor, the ESP32, has 320kB of RAM.
Since your application is basically a miniature computer, with a keyboard and screen, have you considered using something that's designed as a miniature computer? A Raspberry Pi (any model) has more gigabytes of RAM than you know what to do with. But it does use a lot more power. But you can also write the software in a normal Linux way (if you happen to like Linux programming). Or, you could consider writing an app for your Android cellphone.
If you insist on using the Uno, another option is to add an SPI RAM expansion chip, for example this 1-euro chip with 32kB (they do go bigger). Now, the Uno has no built-in RAM expansion ability, so you can't just access it with pointers or something, but you can still use the SPI bus to tell the chip to read or write certain bytes, kinda like you can with an SD card.
After writing this, I realized SPI RAM is not so useful for your application, because you don't want to store the data only while the device is turned on. You could use a SPI FRAM or SPI EEPROM chip instead which can store data while it's powered off. The Arduino IDE doesn't have a way to automatically put data into any of these chips... so to input the data you'd probably have to send it over the serial port, into a separate program you wrote, which writes it to the chip. Or you could make a user interface that allows the user to edit the data directly on the device.
Or you can use an SD card, yes. Honestly that's probably the simplest way.


text:
MAX30102 not working?
I have a project to find the pulse oximetry rate. I used MAX30102 and ESP8266 as shown in the first picture.
Wiring
GND ------> GND
VIN ------> 3.3V
SDA ------> D2
SCL ------> D1

Code
I also used the following code in esp2866 programming:
#include <Wire.h>
#include "MAX30105.h"
#include "spo2_algorithm.h"

MAX30105 particleSensor;

#define MAX_BRIGHTNESS 255

uint32_t irBuffer[100]; //infrared LED sensor data
uint32_t redBuffer[100];  //red LED sensor data

int32_t bufferLength; //data length
int32_t spo2; //SPO2 value
int8_t validSPO2; //indicator to show if the SPO2 calculation is valid
int32_t heartRate; //heart rate value
int8_t validHeartRate; //indicator to show if the heart rate calculation is valid

void setup()
{
  Serial.begin(115200); // initialize serial communication at 115200 bits per second:

  // Initialize sensor
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  {
    Serial.println(F("MAX30102 was not found. Please check wiring/power."));
    while (1);
  }

  Serial.println(F("Attach sensor to finger with rubber band. Press any key to start conversion"));
  while (Serial.available() == 0) ; //wait until user presses a key
  Serial.read();

  byte ledBrightness = 60; //Options: 0=Off to 255=50mA
  byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32
  byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  byte sampleRate = 100; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
  int pulseWidth = 411; //Options: 69, 118, 215, 411
  int adcRange = 4096; //Options: 2048, 4096, 8192, 16384

  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
}

void loop()
{
  bufferLength = 100; //buffer length of 100 stores 4 seconds of samples running at 25sps

  //read the first 100 samples, and determine the signal range
  for (byte i = 0 ; i < bufferLength ; i++)
  {
    while (particleSensor.available() == false) //do we have new data?
      particleSensor.check(); //Check the sensor for new data

    redBuffer[i] = particleSensor.getRed();
    irBuffer[i] = particleSensor.getIR();
    particleSensor.nextSample(); //We're finished with this sample so move to next sample

    Serial.print(F("red="));
    Serial.print(redBuffer[i], DEC);
    Serial.print(F(", ir="));
    Serial.println(irBuffer[i], DEC);
  }

  //calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples)
  maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);

  //Continuously taking samples from MAX30102.  Heart rate and SpO2 are calculated every 1 second
  while (1)
  {
    //dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top
    for (byte i = 25; i < 100; i++)
    {
      redBuffer[i - 25] = redBuffer[i];
      irBuffer[i - 25] = irBuffer[i];
    }

    //take 25 sets of samples before calculating the heart rate.
    for (byte i = 75; i < 100; i++)
    {
      while (particleSensor.available() == false) //do we have new data?
        particleSensor.check(); //Check the sensor for new data

      redBuffer[i] = particleSensor.getRed();
      irBuffer[i] = particleSensor.getIR();
      particleSensor.nextSample(); //We're finished with this sample so move to next sample

      //send samples and calculation result to terminal program through UART
      Serial.print(F("red="));
      Serial.print(redBuffer[i], DEC);
      Serial.print(F(", ir="));
      Serial.print(irBuffer[i], DEC);

      Serial.print(F(", HR="));
      Serial.print(heartRate, DEC);

      Serial.print(F(", HRvalid="));
      Serial.print(validHeartRate, DEC);

      Serial.print(F(", SPO2="));
      Serial.print(spo2, DEC);

      Serial.print(F(", SPO2Valid="));
      Serial.println(validSPO2, DEC);
    }

    //After gathering 25 new samples recalculate HR and SP02
    maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
  }
}

Error
When executing, it showed me in the window that:
11:48:31.564 -> MAX30102 was not found. Please check wiring/power.

I have used two of the max30102, but it shows the same result.
The MAX30102 does not turn on and the light also doesn't work. Are there any solutions?

The text and the wiring image show two different connections: The first with SDA to pin D1 and SCL to pin D2, while the image shows them swapped. What do you actually have on your hardware?

Yeah sorry ,I made a mistake , SDA ---->D2    SCL----->D1  I will adjust it.

Can you please try the I2C Scanner sketch and see if there are any devices reported on the I2C bus? It just checks at what addresses there are devices that actually answer on the bus.

Ok,thanks for the reply, . I tried it, but after executing it shows me a window that  "No I2C devices found".

please post a clear, well lit, in focus picture of the wiring

@jsotola ok i added another picture

@chrisl I try agagin the I2C scanner after removed resistors now it display "i2c device found at address 0x57 done " but the led not lit

Before someone pulls the trigger on closing this, please note that they'd added the wiring image requested. It just wasn't displaying owing to a markdown problem (now corrected).

Alright, no one else is going to say it, so I will: You have particleSensor.begin(Wire, I2C_SPEED_FAST).   Switch this to I2C_SPEED_STANDARD and see if it makes a difference and use the configuration you'd seen return 0x57 in the scanner.


text:
Rp2040 dual core example sketches
So i have a rp2040 board, and i could not find a dual core example codes. The closest i could find is the scheduler library example given to me by the IDE
/*
 Multiple Blinks

 Demonstrates the use of the Scheduler library for the boards:

 - Arduino Nano 33 BLE, or
 - Arduino Portenta H7, or
 - Arduino Nano RP2040 Connect

 Hardware required :
 * None (LEDs are already conencted to RGB LED)

 ATTENTION: LEDs polarity is reversed (so loop3 will turn the LED off by writing 1)

 created 8 Oct 2012
 by Cristian Maglie
 Modified by
 Scott Fitzgerald 19 Oct 2012

 This example code is in the public domain

 http://www.arduino.cc/en/Tutorial/MultipleBlinks
*/

// Include Scheduler since we want to manage multiple tasks.
#include <Scheduler.h>

// On Nano RP2040 Connect, RGB leds are connected to the wifi module
// The user APIs are the same, but we can't convert to int, so use defines
#if defined(ARDUINO_NANO_RP2040_CONNECT)

#include "WiFiNINA.h"
#define led1  LEDR
#define led2  LEDG
#define led3  LEDB

// On Nicla Sense ME, RGB leds are connected via an I2C module
// The user APIs are the same, but we can't convert to int, so use defines
#elif defined(ARDUINO_NICLA)

#include "Nicla_System.h"
#define led1  LEDR
#define led2  LEDG
#define led3  LEDB

#else

int led1 = LEDR;
int led2 = LEDG;
int led3 = LEDB;

#endif

void setup() {
  Serial.begin(9600);

  // Setup the 3 pins as OUTPUT
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);

  // Add "loop2" and "loop3" to scheduling.
  // "loop" is always started by default.
  Scheduler.startLoop(loop2);
  Scheduler.startLoop(loop3);
}

// Task no.1: blink LED with 1 second delay.
void loop() {
  digitalWrite(led1, HIGH);

  // IMPORTANT:
  // When multiple tasks are running 'delay' passes control to
  // other tasks while waiting and guarantees they get executed.
  delay(1000);

  digitalWrite(led1, LOW);
  delay(1000);
}

// Task no.2: blink LED with 0.1 second delay.
void loop2() {
  digitalWrite(led2, HIGH);
  delay(100);
  digitalWrite(led2, LOW);
  delay(100);
}

// Task no.3: accept commands from Serial port
// '0' turns off LED
// '1' turns on LED
void loop3() {
  if (Serial.available()) {
    char c = Serial.read();
    if (c == '0') {
      digitalWrite(led3, LOW);
      Serial.println("Led turned off!");
    }
    if (c == '1') {
      digitalWrite(led3, HIGH);
      Serial.println("Led turned on!");
    }
  }

  // IMPORTANT:
  // We must call 'yield' at a regular basis to pass
  // control to other tasks.
  yield();
}

but i do not think its using the second core of the rp2040. Does anybody have an example codes? because im really lost how to do it

Just launch a new main() with multicore_launch_core1().

@Majenko So I have 3 functions now setup() , loop() , and main() , ? where do i put the multicore_launch_core1()

The RP2040 SDK is your friend: https://raspberrypi.github.io/pico-sdk-doxygen/

And: https://raspberrypi.github.io/pico-sdk-doxygen/group__pico__multicore.html#multicore_example

@Majenko ooooh... You can use all sdk function in arduino IDE?? I did not know you can do that.

Yep. The Arduino core is merely a wrapper around the SDK.

Note: This information is about the pure "Arduino" core, not the "MBED" core. The MBED core gets in the way of using the RP2040 SDK, so install the pure bare metal core from here.
By default the second core isn't doing anything.
But you can run anything you want on it directly. No need for any libraries.  You use the function multicore_launch_core1(func) to start a function on that core. You could make it Arduino-like by writing a wrapper function, such as this code:

void setup2() {
    pinMode(1, OUTPUT);
}

void loop2() {
    digitalWrite(1, HIGH);
    delay(750);
    digitalWrite(1, LOW);
    delay(750);
}

void main2() {
    setup2();
    while (1) {
        loop2();
    }
}

void setup() {
    multicore_launch_core1(main2);
    pinMode(0, OUTPUT);
}

void loop() {
    digitalWrite(0, HIGH);
    delay(1000);
    digitalWrite(0, LOW);
    delay(1000);
}

The code throws an error in arduino IDE. sketch_nov05a:21:5: error: 'multicore_launch_core1' was not declared in this scope

@DrakeJest Sure you have the right board selected, and the right core installed? I use that function all the time without needing to do anything.

I double checked, and yes .  I am using Arduino Mbed OS RP2040 Boards - Raspberry pi pico

@DrakeJest Ah, sounds like you're not using the Raspberry Pi core but the MBED core. I've never used that. Stick to the proper Pi one.

@DrakeJest This is the one I use: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json

What is the name of the pi core? The only one showing up inside the board manager is  that one, it even says its made by arduino, so i think this is the official one

Got it to compile now ! And wow there so many boards included in this one, can even change core clock and stuff. Whats up with that Arduino Mbed Os then?

@DrakeJest The problem with the MBED one is it runs MBED. That's an operating system (like FreeRTOS) which sits between your code and the hardware.

Oh thats a bummer, so i loose access to the scheduler library then. are there similar alternatives? I guess i will have to code my project the hard way then

The scheduler library is a crutch. You don't need crutches.

You are right, if i want an OS might as well go for a full-blown raspberry pi 4/zero. Thank you for your help Majenko, Ill get right to starting my project. Have a nice day


text:
Why can't I just plug a stepper or gimbal motor (BLDC) into the ground, 5v, and analog pins of my Arduino?
I plugged a BLDC gimbal motor in to my Arduino today, and it made a very small jitter. I tried to set an analog pin for the signal pin of the motor (motor had three pins, I assumed one was power, one was ground, and one was signal/data/position) but the motor barely moved. I wanted to see my motor spin at some constant rate determined by that signal pin, or maybe move to the position specified in the signal pin.
Upon further research, I find many pages advising me to use "controllers" or other complicated setups to manage a motor. I am confused as to why it is so complicated. Can't it be simple to plug a stepper motor into an Arduino and get some constant revolutions based on Arduino control?

the arduino is not a power supply ... its output current capacity is very limited ... it cannot drive a motor directly ... you are lucky if your arduino output pins are still alive after your experiment

Not only is the available current limited, but a stepper motor in particular is not capable of running just by supplying power.
It's drive coils must be energized in sequence to "pull" the rotor around, and sequenced at a rate that drives the rotor at the desired RMP. The circuitry to do that is external to the stepper, usually a combination of logic signals from a micro-controller (typically) and hardware to translate those signals into drive currents sequenced to the stator-coils. This is what makes steppers so flexible - controllable in direction and speed, down to the single-step level (subject to the rotor's interia) - at the cost of more complex drive circuitry. In short, steppers need to be programmed, continuously, to drive them however the mechanical system requires.

It is a power issue. By that I mean Power = Votage x Current.
Put simply, the 5V supply regulator IC on the Arduino is only designed to power the microcontroller(s) and a handful of other electronic components.
The Arduino has a little 5V regulator that is capable of delivering 100mA to 500mA depending on your Arduino. Don't forget that the microcontroller itself uses roughly 20mA. The remaining current is capable of runing very low power items such as sensors, switches, LEDs etc but not parts that require more power. Unfortunately motors require a lot more power than what the regulator on the Arduino can provide.
I suggest that you use a second 5V supply. For example you could use:

Benchtop power supply
Plugpack or phone charger type power supply
An old computer power supply
A DC/DC converter (like this one)

These are just a few. There are many more options.

A brushless DC motor consists of three coils of wire wired in a Y (wye) or Δ (delta) configuration and a magnetic rotor. The coils are evenly spaced around the 360 degrees of the motor. There can be multiple poles, or "copies" of each coil, so it's not necessarily 120 degrees from a coil A to a coil B - e.g. it could be ABCABCABC to go around the full circle with 40 degrees between coils. There are no power or ground or data wires, just electromagnets.
Anyway, when current goes through one of the coils it forms an electromagnet and attracts the rotor to that position. We say the coil is energized. By repeatedly energizing and de-energizing different coils you make the rotor spin around in circles. If you energize A, then B, then C, then A, then B, then C it spins one way; energize C, then B, then A, then C, then B, then A and it spins the other way. The current direction also matters because an opposite current produces an opposite magnetic field. Of course you also have to get the timing right - so the magnetic force is always pulling the rotor ahead of where it currently is. When the rotor catches up with the magnet coil you switch to the next one. I'm oversimplifying.
To use one you can buy a controller which does have power and data and ground wires, as well as the 3 wires for the magnets, and you tell the controller to go, and it handles all the switching and timing for you. You could design your own, but good luck.

Steppers are the same basic idea but optimized for low speed and precise movements instead of big movements. Because you don't care about timing so much for a stepper - you're moving it one step at a time and not really trying to use its inertia - you can write your own control algorithm if you want. Note the Arduino's digital pins still can't output enough current so you still need some circuitry. Or you can buy a stepper motor controller.


text:
How to connect Nodemcu ESP-32s and GSM SIM800L
The code that I use:
#include <SoftwareSerial.h>

//Create software serial object to communicate with SIM800L
SoftwareSerial mySerial(16, 17);

void setup()
{
  //Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
  Serial.begin(9600);

  //Begin serial communication with Arduino and SIM800L
  mySerial.begin(9600);

  Serial.println("Initializing...");
  delay(1000);

  mySerial.println("AT"); //Once the handshake test is successful, it will back to OK
  updateSerial();
  mySerial.println("AT+CSQ"); //Signal quality test, value range is 0-31 , 31 is the best
  updateSerial();
  mySerial.println("AT+CCID"); //Read SIM information to confirm whether the SIM is plugged
  updateSerial();
  mySerial.println("AT+CREG?"); //Check whether it has registered in the network
  updateSerial();
}

void loop()
{
  updateSerial();
}

void updateSerial()
{
  delay(500);
  while (Serial.available())
  {
    mySerial.write(Serial.read());//Forward what Serial received to Software Serial Port
  }
  while(mySerial.available())
  {
    Serial.write(mySerial.read());//Forward what Software Serial received to Serial Port
  }
}

but if I run it, the GSM doesn't seem to respond or it show me different characters as its output "???".
Connection:

SIM800L
Nodemcu ESP-32s

RX
GIOP17

TX
GIOP16

the expected output:

the output I have:

how do you know that the GSM module is not responding? ... please edit your post with a description of what you expected to happen and what you observed

why don't you use hardware serial, instead of software serial?

The by default baud rate of sim800 is 115200 try using this baud rate if it works if it works then try changing the baudrate using AT command AT+IPR=<baudrate> and then use AT&W to store the baud rate


text:
SIM900 AT+CCID ERROR
I have my SIM900 connected to a 12v 2A power source, I have inserted my sim card changed it to 3G/2G(autoconnect) ( I did research it to know wheteher it is possible and it turns out it is, the only problem would be not having the same speed according to them) There are no pin/password on the sim. There is still a remaining balance (should be enough to send a text or two)
Also my SIM900 netlight led blinks every 1 sec.
I also did try AT commands that I found on the internet and this is the results:
I have also posted this on this site: https://forum.arduino.cc/t/sim900-at-ccid-error/922283
CODE
#include <SoftwareSerial.h>

//Create software serial object to communicate with SIM900
SoftwareSerial mySerial(7, 8); //SIM900 Tx & Rx is connected to Arduino #7 & #8

void setup()
{
//Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
Serial.begin(19200);

//Begin serial communication with Arduino and SIM900
mySerial.begin(19200);

Serial.println("Initializing...");
delay(1000);

mySerial.println("AT"); //Handshaking with SIM900
updateSerial();
mySerial.println("AT+CSQ"); //Signal quality test, value range is 0-31 , 31 is the best
updateSerial();
mySerial.println("AT+COPS");
updateSerial();
mySerial.println("AT+CCID"); //Read SIM information to confirm whether the SIM is plugged
updateSerial();
mySerial.println("AT+CREG?"); //Check whether it has registered in the network
updateSerial();
}

void loop()
{
updateSerial();
}

void updateSerial()
{
delay(500);
while (Serial.available())
{
mySerial.write(Serial.read());//Forward what Serial received to Software Serial Port
}
while(mySerial.available())
{
Serial.write(mySerial.read());//Forward what Software Serial received to Serial Port
}
}

SERIAL MONITOR
Initializing...
AT

OK
AT+CSQ

+CSQ: 17,0

OK
AT+COPS?

+COPS: 0

OK
AT+CCID?

ERROR
AT+CREG?

+CREG: 1,0

OK


text:
Rp2040 How to signal the second core from first core as an indicator to do something
Im new to dual core programming and i do not know the best practices yet. In my current project, i would like the second core to only do something after it is being told by the first core.
The approach i am using somewhat of a brute force is something like this:
bool indicator = false;
int a,b;

void loop () { // core1
  if(indicator == false){  //check if core2 is still processing
     a=random(100);
     b=random(100);
     indicator = true;
  }
}

void loop1(){ //core2
  if(indicator == true){
     int sum = a+b;
     Serial.println(sum);
     indicator == false;
  }
}

this is just a simplified idea of how my code is going to be. Are there better ways of going about this? In general i want to tell core2 from core1 that it needs to start/stop doing something.

What you have created there is called a semaphore.
In multi-threaded (or multi-core) programming there are two important signalling concepts:

Mutex - This is an object of some form that is used to allow access to a shared resource by only one core or thread at a time.  A thread tries to "lock" a mutex before using a resource.  A mutex can only be "locked" by one thread at a time, and if the mutex is already locked by another thread it can either block (aka a "spinlock") waiting for the mutex to be unlocked, or it can fail gracefully and try again later.
Semaphore - This is a simple flag that is used for one thread to tell another thread that something has happened or that it should do something. It is typically set by one thread then read and cleared by the other thread.

As I mentioned before, a semaphore is what you have created, and a simple boolean value is the most basic semaphore there is. Note, though, that you should really have the variable as volatile to prevent the compiler optimizing it away.
The RP2040 SDK has some functions built in for allowing the cores to communicate, including a "lockout" facility allowing one core to tell the other to stall until such time as it should start processing again, and a FIFO to allow the asynchronous passing of data from one core to the other.

Even after two days im still having troubles grasping the concepts. Which one should i use? both mutex and semaphore seems to be able to do the job, but which is much proper?

Also , in my example i just used basic datatypes. is it possible to lock a class data type.

@DrakeJest A mutex is used when you want to share a resource. For example if you have two threads that both want to print to serial. One thread "locks" the serial port mutex, prints what it wants, then releases it again. The other thread waits until it is able to lock the mutex itself before printing. That way you keep the serial data separate and don't end up with a garbled mess.

A semaphore is used to just inform another thread that something has happened. Maybe thread 1 has filled up a buffer with data and thread 2 should grab and process that data. Or maybe thread 1 has detected something happen on a sensor and wants to tell thread 2 that it happened.

And yes, you can use anything you like as a semaphore or mutex. You rarely want more than a simple bool or maybe an int. If you have a class you'll just be using a bool or int inside that class as the semaphore/mutex.


text:
Plug in analog sensor into digital pin
If I take an Arduino (samd21, if it matters) and plug in an analog sensor/pot into a digital pin and then set that pin to be an input, would digitalRead(#) trigger HIGH and LOW at some threshold point?  Or does it not work at all?

I don't have the parts

According to SAMD21 the digital input pin detects HIGH if the voltage on pin is higher than 0.55 of supply voltage. So at 3.3 V it is 1.8 V.
The input pin detects LOW if the voltage is lower than 0.3 of supply voltage. It is 0.99 V at 3.3 V.
For voltages between these values (1 V to 1.8 V) the result can be HIGH or LOW.

Yes. If you read the datasheet you will find a set of voltage specifications. The ones you are interested in are VIH and VIL.
Most MCUs use a "Schmitt Trigger" for the inputs. This means that when the voltage rises above the HIGH threshold (VIH) the input switches to HIGH. When the voltage drops below the LOW threshold (VIL) the input switches to LOW.  This "hysteresis" provides a certain amount of noise rejection to give a clean digital input signal.


text:
What does a delay(0) actually do?
I've seen some code where the developers add delay(0), it doesnt make sense, what does it do? Delay with zero milliseconds, why?
bool DFRobotDFPlayerMini::waitAvailable(unsigned long duration){
  unsigned long timer = millis();
  if (!duration) {
    duration = _timeOutDuration;
  }
  while (!available()){
    if (millis() - timer > duration) {
      return false;
    }
    delay(0);
  }
  return true;
}

Delay (traditionally) has two functions that it performs:

Wait for a period
Yield processing to other threads through the yield() weak symbol.

By using a delay(0) the author thinks they are saying "I don't want to delay here, but if anything is using the yield() function it can run now."
However, that is not correct.
The code for delay() in the AVR core looks like this:
void delay(unsigned long ms)
{
    uint32_t start = micros();

    while (ms > 0) {
        yield();
        while ( ms > 0 && (micros() - start) >= 1000) {
            ms--;
            start += 1000;
        }
    }
}

You can see that, as well as delaying for a period, yield() is regularly called. However that only ever happens if ms is greater than 0. If you pass 0 as the delay length then the delay() function essentially does nothing at all.
Now it could be that an earlier version of the core had yield() always being called even with ms==0, but the current version doesn't. Maybe this is a hangup from an old coding style.  But for the current core if you want to yield you must explicitly call yield() or delay for at least one millisecond.

esp8266 delay has yield with 0 delay and esp32 delay directly calls vTaskDelay in SDK. The mded cores call RTOS thread sleep.

Is there anything to yield to in the AVR core?

@AndreKR Not in the core, no. yield() is defined "weak" so that you (or a library) can override it to implement a form of crude cooperative threading.

Yepp this is exactly what i saw when looking at the delay() method. That made it more confusing. So it does nothing since milliseconds is lower then zero.

Not "lower than" but "not greater than". Subtle difference.

@Majenko Sorry =P


text:
Arduino LiquidCrystal library code prevents ESP32 from running. For 16x2 character display
See bottom for solution.
I am trying to run the Arduino LiquidCrystal library example HelloWorld.ino on an ESP32. It seems like it never even executes the Setup() loop. The ESP resets after eight seconds and then repeats the cycle.
I have used character LCD many times before (with Arduino) but always using I2C. For the current design I am eliminating the I2C to parallel chip and I am instead driving the LCD directly from the ESP32. I am using 4 bit mode to reduce the number of pins required. I have connected Register select, Enable, and D4-D7. These details are not relevant since the ESP32 does not even run with the LiquidCrystal library.
I have looked at the library code and I didn't see anything that I thought would be a problem. But I am a hardware designer (for 36 years) and not a programmer. I use the Arduino IDE because it is quick and easy to test hardware.
The library code can be found here. https://github.com/arduino-libraries/LiquidCrystal/tree/master/src
This is what I get from the serial monitor.
rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1240
load:0x40078000,len:13012
load:0x40080400,len:3648
entry 0x400805f8
ets Jun  8 2016 00:22:57

I tried the example code, and when that didn't work so I added a couple of serial print lines to the code. I am listing that below.
#include <LiquidCrystal.h>

const int rs = 26, en = 25, d4 = 16, d5 = 17, d6 = 18, d7 = 19;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {
  Serial.begin(115200);
  Serial.println("Start");

  lcd.begin(16, 2);
  lcd.print("hello, world!");
}

void loop() {
  delay(1000);

  lcd.setCursor(0, 1);
  lcd.print(millis() / 1000);

  Serial.println(millis() / 1000);
}

Details that I didn't list above. I am powering the LCD from 5 volts. The LCD data/control lines are specified as VinLo = 0.55v and VinHi = 2.4 volts. Not that this matters since the code above never executes. I have used a Arduino Nano powered with 3.3 volts, running the above code, to confirm that the display actually works under these conditions. I really want this to work with an ESP32-C3. I tried that originally but switched to the ESP32 because it wasn't working with the code.
I hope someone can provide some guidance here. My other option is not using the library and writing my own code, which ends up being brute force and simplistic.
EDIT:
A big thanks to Majenko who was spot on. After removal of the call the code executed properly.

My guess: the constructor calls ::init(). ::init() calls ::begin(). ::begin() uses delays. Those delays may depend on things that aren't configured yet when the constructors are running, and lock up causing a WDT. That library looks to be poorly written TBH. Remove the call to begin() in the ::init() function.

I just recently was having a similar issue. I was trying to get the I2C display to work on an ESP32 using the adafruit library, without success. I then went ahead and used another LCD library. (Debugging the library was out of scope for me, since all I wanted to do was test the I2C bus).

Tipp: Install https://github.com/me-no-dev/EspExceptionDecoder. You can then paste the line that says "Backtrace" from the ESP32 crash dump into that tool and get a nice stack trace. Very helpful.

@PMF The code did not execute so there was no backtrace to examine. Majenko was spot on with his comment to "Remove the call to begin() in the ::init() function." I removed that call and now the code executes and works properly.

My guess:

the constructor calls LiquidCrystal::init().
LiquidCrystal::init() calls LiquidCrystal::begin().
LiquidCrystal::begin() uses delays.

Those delays may depend on things that aren't configured yet when the constructors are running, and lock up causing a WDT.
Remove the call to begin() in the LiquidCrystal::init() function and it should at least get past running the constructor so it gets to run the rest of your code.
Quite why they have that call in there is beyond me.  Rule number one of writing an Arduino library: never perform any operations more strenuous than assigning variables in the constructor as resources you may rely on may not have been initialized yet.

I guess the reason was that they wanted the display to also work if you don't call begin() in setup(). The AVR boards have no exception handling, so the general rule seems to be "Let's always do a best guess what the user wanted when something is not right"


text:
ESP32 not detecting PN532 module running in SPI mode
I am trying to get the Pn532 module working on the esp32, first I tried to get it working with i2c and had some "success"(it worked, but as soon as I had another i2c device, in my case a display, 90% of the time it refused to work) and after some research, it's mentioned in the github repo the module doesnt work with multiple devices attached on the i2c bus. Now I am trying to get it working trough spi, but it doesn't get detected.
Code: readMirafe example from the Adafruit Pn532 Library, but I modified the pins from line 42-45
/**************************************************************************/
/*!
    @file     readMifare.pde
    @author   Adafruit Industries
    @license  BSD (see license.txt)
    This example will wait for any ISO14443A card or tag, and
    depending on the size of the UID will attempt to read from it.

    If the card has a 4-byte UID it is probably a Mifare
    Classic card, and the following steps are taken:

    - Authenticate block 4 (the first block of Sector 1) using
      the default KEYA of 0XFF 0XFF 0XFF 0XFF 0XFF 0XFF
    - If authentication succeeds, we can then read any of the
      4 blocks in that sector (though only block 4 is read here)

    If the card has a 7-byte UID it is probably a Mifare
    Ultralight card, and the 4 byte pages can be read directly.
    Page 4 is read by default since this is the first 'general-
    purpose' page on the tags.
This is an example sketch for the Adafruit PN532 NFC/RFID breakout boards
This library works with the Adafruit NFC breakout
  ----> https://www.adafruit.com/products/364

Check out the links above for our tutorials and wiring diagrams
These chips use SPI or I2C to communicate.
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
*/
/**************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_PN532.h>

// If using the breakout with SPI, define the pins for SPI communication.
#define PN532_SCK  (18)
#define PN532_MISO (19)
#define PN532_MOSI (23)
#define PN532_SS   (27)

// If using the breakout or shield with I2C, define just the pins connected
// to the IRQ and reset lines.  Use the values below (2, 3) for the shield!
#define PN532_IRQ   (2)
#define PN532_RESET (3)  // Not connected by default on the NFC Shield

// Uncomment just _one_ line below depending on how your breakout or shield
// is connected to the Arduino:

// Use this line for a breakout with a software SPI connection (recommended):
Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS);

// Use this line for a breakout with a hardware SPI connection.  Note that
// the PN532 SCK, MOSI, and MISO pins need to be connected to the Arduino's
// hardware SPI SCK, MOSI, and MISO pins.  On an Arduino Uno these are
// SCK = 13, MOSI = 11, MISO = 12.  The SS line can be any digital IO pin.
//Adafruit_PN532 nfc(PN532_SS);

// Or use this line for a breakout or shield with an I2C connection:
//Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET);

void setup(void) {
  Serial.begin(115200);
  while (!Serial) delay(10); // for Leonardo/Micro/Zero

  Serial.println("Hello!");

  nfc.begin();

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  // Got ok data, print it out!
  Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
  Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);

  // configure board to read RFID tags
  nfc.SAMConfig();

  Serial.println("Waiting for an ISO14443A Card ...");
}

void loop(void) {
  uint8_t success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)

  // Wait for an ISO14443A type cards (Mifare, etc.).  When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);

  if (success) {
    // Display some basic information about the card
    Serial.println("Found an ISO14443A card");
    Serial.print("  UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
    Serial.print("  UID Value: ");
    nfc.PrintHex(uid, uidLength);
    Serial.println("");

    if (uidLength == 4)
    {
      // We probably have a Mifare Classic card ...
      Serial.println("Seems to be a Mifare Classic card (4 byte UID)");

      // Now we need to try to authenticate it for read/write access
      // Try with the factory default KeyA: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
      Serial.println("Trying to authenticate block 4 with default KEYA value");
      uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

      // Start with block 4 (the first block of sector 1) since sector 0
      // contains the manufacturer data and it's probably better just
      // to leave it alone unless you know what you're doing
      success = nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keya);

      if (success)
      {
        Serial.println("Sector 1 (Blocks 4..7) has been authenticated");
        uint8_t data[16];

        // If you want to write something to block 4 to test with, uncomment
        // the following line and this text should be read back in a minute
        //memcpy(data, (const uint8_t[]){ 'a', 'd', 'a', 'f', 'r', 'u', 'i', 't', '.', 'c', 'o', 'm', 0, 0, 0, 0 }, sizeof data);
        // success = nfc.mifareclassic_WriteDataBlock (4, data);

        // Try to read the contents of block 4
        success = nfc.mifareclassic_ReadDataBlock(4, data);

        if (success)
        {
          // Data seems to have been read ... spit it out
          Serial.println("Reading Block 4:");
          nfc.PrintHexChar(data, 16);
          Serial.println("");

          // Wait a bit before reading the card again
          delay(1000);
        }
        else
        {
          Serial.println("Ooops ... unable to read the requested block.  Try another key?");
        }
      }
      else
      {
        Serial.println("Ooops ... authentication failed: Try another key?");
      }
    }

    if (uidLength == 7)
    {
      // We probably have a Mifare Ultralight card ...
      Serial.println("Seems to be a Mifare Ultralight tag (7 byte UID)");

      // Try to read the first general-purpose user page (#4)
      Serial.println("Reading page 4");
      uint8_t data[32];
      success = nfc.mifareultralight_ReadPage (4, data);
      if (success)
      {
        // Data seems to have been read ... spit it out
        nfc.PrintHexChar(data, 4);
        Serial.println("");

        // Wait a bit before reading the card again
        delay(1000);
      }
      else
      {
        Serial.println("Ooops ... unable to read the requested page!?");
      }
    }
  }
}

My wiring is the following
(PN523 Module->esp32):
SCK  -> D18;
MSO  -> D19;
MOSI -> D23;
SS   -> D27

And yes, the board is in SPI mode(the dip switch). Thank you!

try hw SPI. now you use the library in software SPI mode

Same issues here, same setup, any news?

The project has just been sitting here, collecting dust. Didn't have the time to look into it

@AllanAlmeida found the solution! https://github.com/adafruit/Adafruit-PN532/issues/80#issuecomment-649915457

Got it working by running the module in VSPI and modifying the library a bit: https://github.com/adafruit/Adafruit-PN532/issues/80#issuecomment-649915457

There is a switch on your PN5322 by default it is set to 0, 0. Switch to the mode of communication you are using.