message:
Why Would Declaring a Global Variable Change How An Unrelated Conditional is Evaluated?

Here is my entire sketch. This is my first Arduino project.  I included all of it because I don't know what's relevant.  I am printing out to a 4-digit 7 segment display.  To do that I use sprintf to format the contents of a char[] called tempString  and that gets sent to the display. I declared a new local char[] each time I needed one.  I had a problem with the Arduino Pro Mini running out of memory.   I tried declaring a global chart[] and reusing it when I needed it, but that changed the way the program executed.  That was the only change I made.

After I made that change, the Arduino would always evaluate this true:

     if (countDownTimer.TimeCheck(0, 0, 0))

The CountDownTimer was always evaluating to a time of 0, even after it had been assigned a valid time and the timer hadn't started running. I verified I was setting it correctly, but by the time the conditional was reached, the Timer was back to 0.

If I remove the global declaration for tempString[] and go back to locals the logic works as designed.  I made tempString[] smaller as a local and that seems to have fixed the memory issue but I would like to know why declaring a global caused a problem.

     #include <SoftwareSerial.h>
    #include <CountUpDownTimer.h>
    #include <EEPROM.h> //Needed to access the eeprom read write functions

    //values for EEPROM
    int stepsToWrite = 0;
    int stepsToRead = 0;
    int priorValue = 0;

    // addresses to write to and read from
    const int thirtySecondAddress = 0;  // constant
    const int threeMinuteAddress = 4;   // constant
    int addressToUse = 0;   // this will change depending on time user selects

    // set uo the serial display
    const int displayTx = 5;  // the pins we need to create the software serial instance
    const int displayRx = 7;   // we will only use Tx
    SoftwareSerial s7s(displayRx, displayTx);

    //set up the timer
    CountUpDownTimer countDownTimer(DOWN);
    const long displaychangeInterval = 10000; // in milliseconds
    const long countdownInterval = 1000; // in milliseconds

    long previousMillis = 0; // for changing between time left and step count
    long previousTimerMillis = 0;  // for updating the display with the new time
    const int thirtySecondTime = 30;
    const int threeMinuteTime = 180; // 3 minutes expressed as seconds
    int timerStartValue = 0;  // needed for some control logic

    // booleans to control what is displayed
    bool doDisplayStepCount = false;
    bool doDisplayCountDown = false;
    bool doDisplayHighScore = true;  // we want to display this at startup

    // set up the buttons
    const int timerbuttonPin = 6;     // the number of the timer pushbutton pin
    const int resetbuttonPin = 4;     // the number of the reset button pin

    int timerbuttonPushCounter = 0;   // counter for the number of button presses
    int timerbuttonState = 0;         // current state of the button
    int timerlastButtonState = 0;     // previous state of the button

    int resetbuttonPushCounter = 0;   // counter for the number of button presses
    int resetbuttonState = 0;         // current state of the button
    int resetlastButtonState = 0;     // previous state of the button

    int stepsTaken = 0; // the number of steps (jumps)
    boolean timerStarted = false;

    // for the force resistor
    const int FSR_PIN = A0; // Pin connected to FSR/resistor divider
    const float VCC = 5.10; // Measured voltage of Ardunio 5V line
    const float R_DIV = 3265.0; // Measured resistance of 3.3k resistor

    double currentForce = 0;
    double previousForce = 0;
    boolean previousPos = false;
    boolean currentPos = false;

    boolean doChangeDisplay = false;

    char tempString[4];
    void setup() {

      boolean debug = true;
      if (debug)
      {
        EEPROMWriteInt(thirtySecondAddress, 0);  // zero out EEPROM
        EEPROMWriteInt(threeMinuteAddress, 0);  // zero out EEPROM
      }
      // start serial connection
      Serial.begin(9600);

      // set up pins
      pinMode(FSR_PIN, INPUT);
      pinMode(timerbuttonPin, INPUT);
      pinMode(resetbuttonPin, INPUT);

      // serial display
      // Must begin s7s software serial at the correct baud rate.

      // Clear the display
      //  The default of the s7s is 9600.
      s7s.begin(9600);
      //clearDisplay();  // Clears display, resets cursor
      // s7s.print("-HI-");
      // delay(1000);

      displayHighScores();

    }

    void loop() {

      // Serial.print("freeMemory()=");
      // Serial.println(freeMemory());

      //  Serial.println("Starting loop");
      // button pushes
      // if tinmerbuttonPushCounter = 1, set timerValue to 30 seconds
      // if 2 pushes, set to 3 minutes and reset push counter to 0

      //Serial.println("Reading timer button, state is: " + timerbuttonState);
      timerbuttonState = digitalRead(timerbuttonPin);
      // Serial.println("Reading reset button, state is: " + resetbuttonState);
      resetbuttonState = digitalRead(resetbuttonPin);

      // compare the buttonState to its previous state

      if (timerbuttonState != timerlastButtonState)
      {
        Serial.println("selecting time");
        if (timerbuttonState == HIGH)
        {

          doDisplayHighScore = false;
          timerbuttonPushCounter++;
          // if the current state is HIGH then the timer button went from off to on:
          if (timerbuttonPushCounter == 1)
          {
            doChangeDisplay = false;
            doDisplayCountDown = true;
            timerStartValue = thirtySecondTime;
            addressToUse = thirtySecondAddress;
            Serial.println("timer button pushed: " + String(timerbuttonPushCounter));
            Serial.println("start value: " + String(timerStartValue));
            clearDisplay();
            setDecimals(0b010000);  // Turn on colon
            sprintf(tempString, "d", thirtySecondTime);
            Serial.println("Timer set to: " + String(tempString));
            s7s.print(tempString);
          }

          else if (timerbuttonPushCounter == 2)
          {
            timerStartValue = threeMinuteTime;
            addressToUse = threeMinuteAddress;
            doChangeDisplay = true;

            int timerinminutes = timerStartValue / 60;
            Serial.println("timer button pushed: " + timerbuttonPushCounter);
            Serial.println("start value  " + timerStartValue);
            timerbuttonPushCounter = 0;
            clearDisplay();
            setDecimals(0b010000);  // Turn on colon
            sprintf(tempString, "0�0", timerinminutes);
            Serial.println("Timer set to: " + String(tempString));
            s7s.print(tempString);
          }
        }  // end of if timer state high

        // Delay a little bit to avoid bouncing
        delay(50);
      }
      // save the current state as the last state, for next time through the loop
      timerlastButtonState = timerbuttonState;

      // for reset button, logic is much simpler
      // if state is high, button has been pushed so reset everything
      if (resetbuttonState != resetlastButtonState)
      {
        if (resetbuttonState == HIGH)
        {
          Serial.println("Reset button pushed!");
          doDisplayHighScore = true;
          resetStepCounter();
          // Delay a little bit to avoid bouncing
          delay(50);
        }
      }

      resetlastButtonState = resetbuttonState;

      // step pad logic
      int fsrADC = analogRead(FSR_PIN);
      previousForce = currentForce;
      currentForce = calculateForce(fsrADC);
      // trying this using force values
      // when we step force is always positive
      // when we lift our foot force is always negative

      if (currentForce > 0)
      {
        currentPos = true;
        Serial.println("Force detected!");
        delay(1000);
      }
      if (previousForce < 0)
      {
        previousPos = true;
      }

      if (currentPos && previousPos)
      {
        // start the timer on the first step
        if (!timerStarted)
        {
          Serial.println("First steop!");
          timerStarted = true;
          // Serial.println("Timer start value: " +String(timerStartValue));
          countDownTimer.SetTimer(0, 0, timerStartValue);
          countDownTimer.StartTimer();

          //  char tempstring[10];
          sprintf(tempString, "M", countDownTimer.ShowMinutes(), countDownTimer.ShowSeconds());
          Serial.println("Timer set to: " + String(tempString));
          //  Serial.println("Timer started");
          //  delay(2000);
          doDisplayCountDown = true;
        }

        stepsTaken++;
        Serial.println("Step Detected!");
        currentPos = false;
        previousPos = false;
      }

      // if timer is 0 we have run out of time
      // this needs to be done here as it must always be done and can't depend
      // on displayCountDown being true

      if (timerStarted)
      {
        if (countDownTimer.TimeCheck(0, 0, 0))
        {
          //Serial.println("out of time");
          //delay(500);
          timerStarted = false;  // set timerRunning to false
          countDownTimer.StopTimer();
          if (timerStartValue == thirtySecondTime)
          {
            WriteHighScore(thirtySecondAddress, stepsTaken);
          }

          if (timerStartValue == threeMinuteTime)
          {
            WriteHighScore(threeMinuteAddress, stepsTaken);
          }
          Serial.println("wrote high score");
          delay(500);
          // clearDisplay();
          //displayStepCount();
          // resetStepCounter();

          // displayCountDownTimer();
        }

        //else

        if (!(countDownTimer.TimeCheck(0, 0, 0))) // && timerStarted)
        {

          countDownTimer.Timer(); // run the timer
          Serial.println("Timer is running");
          // timer logic
          // every 10 seconds, change booleans on what gets displayed
          unsigned long currentMillis = millis();
          // the last 10 seconds only display the step count
          //if (countDownTimer.TimeCheck(0, 0, 10))
          // {
          //
          //   displayStepCount();
          // }

          // else
          //  {

          if (doChangeDisplay)
          {
            if ((currentMillis - previousMillis) >= displaychangeInterval)
            {
              // save the last time we checked the interval
              //  Serial.println("10 second interval!");
              previousMillis = currentMillis;

              // if this is true, set it to false
              // set the countdown display to true
              if (doDisplayStepCount)
              {
                doDisplayStepCount = false;
                doDisplayCountDown = true;
              }

              else
                // countdown display is true, so set it to false
                // and set stepcount display to true
              {
                doDisplayStepCount = true;
                doDisplayCountDown = false;
              }

            }
          }

          // only display step count if this is the interval to do it
          if (doDisplayStepCount)
          {
            displayStepCount();
          }

          // only display countdown timer if this is the 10 second interval to do it
          if (doDisplayCountDown)
          {
            displayCountDownTimer();
          }

          //  }

        }
      }

    }

    // Send the clear display command (0x76)
    //  This will clear the display and reset the cursor
    void clearDisplay()
    {
      s7s.write(0x76);  // Clear display command
    }

    // Turn on any, none, or all of the decimals.
    //  The six lowest bits in the decimals parameter sets a decimal
    //  (or colon, or apostrophe) on or off. A 1 indicates on, 0 off.
    //  [MSB] (X)(X)(Apos)(Colon)(Digit 4)(Digit 3)(Digit2)(Digit1)
    // (0b010000) - colon only
    //  (0b111111) - all decimals
    void setDecimals(byte decimals)
    {
      s7s.write(0x77);
      s7s.write(decimals);
    }

    void resetStepCounter()
    {
      timerbuttonPushCounter = 0;
      if (timerStarted)
      {
        countDownTimer.StopTimer();
        timerStarted = false;
      }

      // clean up
      stepsTaken = 0;
      clearDisplay();
      timerStartValue = 0;
      doDisplayHighScore = true;
    }

    void displayStepCount()
    {
      setDecimals(0b000000);  // Turn off the colon
      // Will be used with sprintf to create strings
      sprintf(tempString, "d", stepsTaken);
      Serial.print("Steps taken: " + String(tempString));
      clearDisplay();
      s7s.print(tempString);
    }

    void displayCountDownTimer()
    {
      // example formats
      //sprintf(tempString, "M", deciSecond); //Convert deciSecond into a string that is right adjusted
      //sprintf(tempString, "%d", deciSecond); //Convert deciSecond into a string that is left adjusted
      //sprintf(tempString, "d", deciSecond); //Convert deciSecond into a string with leading zeros
      //sprintf(tempString, "M", deciSecond * -1); //Shows a negative sign infront of right adjusted number
      unsigned long currentMillis = millis();
      int seconds = 0;
      int minutes = 0;

      // only update the display if 1 second has passed
      // if(currentMillis - previousTimerMillis >=  countdownInterval)
      // CountUpDownTimer TimeHasChanged() returns boolean (in seconds)

      if (countDownTimer.TimeHasChanged())
      {
        // previousTimerMillis = currentMillis;
        seconds = countDownTimer.ShowSeconds();
        Serial.println("Time left: " + seconds);
        minutes = countDownTimer.ShowMinutes();
        sprintf(tempString, "dd", minutes, seconds);

        clearDisplay();
        setDecimals(0b010000);  // Turn on colon
        Serial.println(tempString);
        s7s.print(tempString);
      }
    }
    void EEPROMWriteInt(const int p_address, const int p_value)
    {
      byte lowByte = ((p_value >> 0) & 0xFF);
      byte highByte = ((p_value >> 8) & 0xFF);

      EEPROM.write(p_address, lowByte);
      EEPROM.write(p_address + 1, highByte);
    }

    //This function will read a 2 byte integer from the eeprom at the specified address and address + 1
    int EEPROMReadInt(const int p_address)
    {
      byte lowByte = EEPROM.read(p_address);
      byte highByte = EEPROM.read(p_address + 1);

      return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
    }

    void WriteHighScore(int address, int value)
    {
      // int valueRead = EEPROMReadInt(address);
      //if (valueRead < value)
      // {
      EEPROMWriteInt(address, value);

      delay(500);
      sprintf(tempString, "d", value);
      Serial.print("high score: " + String(tempString));
      clearDisplay();
      s7s.print("-HI-");
      delay(500);
      clearDisplay();
      s7s.print("SCOR");
      delay(500);
      clearDisplay();
      s7s.print(tempString);
      delay(500);

      // }
    }
    void displayHighScores()
    {
      int thirtySecondScore = EEPROMReadInt(thirtySecondAddress);
      int threeMinuteScore = EEPROMReadInt(threeMinuteAddress);
      sprintf(tempString, "d", thirtySecondScore);
      Serial.println("thirty second score: " + String(tempString));
      sprintf(tempString, "d", threeMinuteScore);
      Serial.println("Three minute score: " + String(tempString));

      clearDisplay();  // Clears display, resets cursor
      s7s.println("-HI-");
      delay(1000);
      clearDisplay();
      Serial.println("SCOR");
      s7s.print("SCOR");
      delay(1000);
      clearDisplay();
      sprintf(tempString, "d", thirtySecondScore);
      Serial.println(tempString);
      s7s.print(tempString);
      delay(1000);

      clearDisplay();
      sprintf(tempString, "d", threeMinuteScore);
      Serial.println(tempString);
      s7s.print(tempString);
      delay(1000);
      clearDisplay();
    }

    float calculateForce(int pinvalue)
    {
      // Use ADC reading to calculate voltage:
      float fsrV = pinvalue * VCC / 1023.0; // 1023 is # of units of voltage between 0 and 5V
      // Use voltage and static resistor value to
      // calculate FSR resistance:
      float fsrR = R_DIV * (VCC / fsrV - 1.0);
      // Serial.println("Resistance: " + String(fsrR) + " ohms");
      // Guesstimate force based on slopes in figure 3 of
      // FSR datasheet:
      float force;
      float fsrG = 1.0 / fsrR; // Calculate conductance
      // Break parabolic curve down into two linear slopes:
      force = (fsrG - 0.00075) / 0.00000032639;
      return force;
    }

body:
This line:

    sprintf(tempString, "d", thirtySecondTime);

writes 5 characters to tempString, the four digits and a terminating null.  You only gave the array room for four.

This:

    Serial.println("Timer set to: " + String(tempString));

is a total waste of resources.  If you want to talk about memory usage then don't use the String class and definitely don't use it where it simply is not needed.

Write that as:

    Serial.print("Timer set to: ");
    Serial.println(tempString);

or better yet from a memory standpoint as:

    Serial.print(F("Timer set to: "));
    Serial.println(tempString);


sender: user

message:
NodeMCU burned, did I something fundamental wrong?

I have a NodeMCU where I connected a LED strip (WS2812b, which operates at 5V).

NodeMCU is powered via USB 5V. The used power adapter can supply 2.5A max.

I don't have a separate power supply for the LED strip yet, so I connected it to VIN/GND of the NodeMCU.

That worked.

Yesterday, I took the NodeMCU (without led strip) to my PC and uploaded an updated sketch.
After that, back in the living room, I connected the NodeMCU with the led strip and the USB power supply.
I didn't need an ambilight at the moment so I left it off.
After 5 minutes, I smelled something burned. As you can see in the second image, the component below ground is burned.

I had this setup successful running for a week (with ambilight turned on for several hours) and had no issues at all.

Did I something fundamental wrong?
Any guess, why it works flawless and then suddenly burned after just 5minutes?

Any tip/suggestion is very appreciated!

[![enter image description here][1]][1]

The white component on the right is a DHT22 temperature sensor and has been added for completeness.

[![enter image description here][2]][2]

The resistor and LED on the right are not used, they were just plugged in from a previous setup.

Best regards

Casper

  [1]: https://i.stack.imgur.com/zRoqr.png
  [2]: https://i.stack.imgur.com/2mTMG.jpg

sender: assistant

body:
Yes, you did something fundamentally wrong.

The component that blew up is a diode.  It is designed to protect the USB from voltage being injected into the board.

That diode can handle an absolute maximum of 1A.

Any fault on your LED strip connection (a short to ground) will cause that diode to vacate the premises. As yours did.

The purpose of the VIN pin (as the label suggests) is as a voltage *input*. It's not really designed to provide power to other devices, especially as the ESP8266 itself can take more than half that 1A power budget when communicating.  You should not use VIN for powering anything more than maybe a couple of low power sensors. LED strips are a big no-no.


body:
Something happened to me yesterday.  I had made sure that the diode & regulator could handle the stress of 14 V ( this unit is installed  in a voat).

The diode blew as soon as the ignition was turned on.  However I noticed that the 10 uF. capacitor was still smoldering away.   That should not have happened.

I removed both faulty components & tested the board.  All OK!
Replaced the diode and the capacitor with a 10uF/20VW diode and the board works fine with 14.4 V input (when battery is charging).

So, I reckon the prpblem is that the capacitor has insufficient voltage rating(6V?) and goes short circuit.  The schotky diode will try and pass AMPS and it fails.

Solution replace the 10uF de-coupling capacitors with capacitors of known rating.

There is no real way of knowing what rating capacitors were used in the manufacture.
Lee


message:
Servo starts to shake when I added SIM900.begin(19200);

Hello I'm working on this mini project. This project works this way, Whenever someone type wrong password, LCD will display "Access Denied" and send an alert to SMS using GSM module.  I used 2 Arduinos for this project, The 1st Arduino is powered up by my laptop this is where the signal pins are connected the RX/TX of GSM is connected in (pin 10 and 11) respectively and the LCD is in pin (2-9) and Servo to (A4) . The second Arduino I used is powered up with a charger and used it for GSM power source it function well as it blinks every 2 sec. I'm really wondering why my servo is shaking whenever I add the  SIM900.begin(9600); at the setup in Arduino IDE?

This is the code
<!-- language-all: lang-cpp -->

    #include <Keypad.h>
    #include <Password.h>
    #include <Servo.h>
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>

    #include <SoftwareSerial.h>
    SoftwareSerial SIM900(10, 11);

    LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
    Password password = Password( "9999" );
    Servo myservo;

    const byte ROWS = 4;
    const byte COLS = 4;

    char keys[ROWS][COLS] = {
        {'1','2','3','A'},
        {'4','5','6','B'},
        {'7','8','9','C'},
        {'*','0','#','D'}
    };

    byte rowPins[ROWS] = {3, 4, 5, 6};
    byte colPins[COLS] = {7, 8, 9, 10};

    Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
    int pos = 0;

    void setup(){

      Serial.begin(9600);
      SIM900.begin(9600);

      myservo.attach(13);
      lcd.begin(16, 2);
      lcd.print("Arduino Password");
      lcd.setCursor ( 0, 1 );
      lcd.print (" Door  Lock ");
      delay ( 2000 );
      setup1();

    }
    void setup1(){

      lcd.clear();
      lcd.home();
      lcd.print("Enter your code:");
      keypad.addEventListener(keypadEvent);
    }

    void loop(){
      keypad.getKey();
    }

    //take care of some special events
    void keypadEvent(KeypadEvent eKey){
      switch (keypad.getState()){
        case PRESSED:
            Serial.println(eKey);
            switch (eKey){
              case '4': checkPassword(); break;
              case '2': password.reset(); break;
              case '8': lock(); break;
              default: password.append(eKey);
         }
      }
    }

    void checkPassword(){
      if (password.evaluate()){
        lcd.clear();
        lcd.print("Access granted");
        delay(1000);
        unlock();
      }else{
        lcd.clear();
        lcd.print("Access denied");
        delay(2000);
        sendSMS();
        delay(1000);

      }
      password.reset();
      delay(1000);
      setup1();
    }

    void unlock(){
      lcd.clear();
      lcd.print("Unlocking...");
      delay(2000);
      pos = 90;
      myservo.write(pos);
      lcd.clear();
      lcd.print("Unlocked! Press");
      lcd.setCursor(0, 1);
      lcd.print("* to lock!");
      delay(1000);
    }

    void lock(){
      lcd.clear();
      lcd.print("Locking...");
      delay(1000);
      pos = 0;
      myservo.write(pos);
      setup1();
    }
    void sendSMS() {

      SIM900.print("AT+CNMI=2,2,0,0,0\r");
      delay(100);
      SIM900.print("AT+CMGF=1\r");
      delay(100);
      SIM900.println("AT + CMGS = \"+6XXXXXXXXXX\"");
      delay(100);
      SIM900.println("Wrong password Typed");
      delay(100);
      SIM900.println((char)26);
      delay(100);
      SIM900.println();
      // Give module time to send SMS
      delay(5000);
    }

body:
Servo.h use interrupts to generate the control signal. However, SoftwareSerial really messes interrupts up.

You can't use SoftwareSerial with anything that relies on interrupts for timing, like Servo.h.

Solutions:

1. Use a better Arduino with an unused hardware UART
2. Use an external hardware PWM controller to drive the servos
3. Use the internal hardware PWM (you'd need to find a library to do this) to drive the servos.


message:
Pilot the the reset line by two input

I have two input signal that when activated have to restart the ardiuno board so I have to connect them to the RESET pin. As you know the arduino board have only one RESET pin so I can't connect both to the same pin.
I think that a good idea is a circuit that takes the two inputs and activate the RESTART pin when one of the two is active.
Have you any idea to solve that problem?

Thank you.

body:
Just use diode logic.

The resistor is probably not needed because the Arduino has an internal pullup resistor.

This assumes that the two reset inputs are `active low`

<!-- Begin schematic: In order to preserve an editable schematic, please
     don't edit this section directly.
     Click the "edit" link below the image in the preview instead. -->

![schematic](https://i.stack.imgur.com/Zp7uj.png)

<!-- End schematic -->


message:
Why is dtostrf() not working for this one value?

I'm building a weather station using an ESP32 and BME280. I'm feeding the data via MQTT and Python into a database that is then used to make a nice dashboard for the data.

The MQTT message needs to be a char, and the sensor readings are floats, so I'm using `dtostrf()` to convert them. This works fine for the temperature and pressure readings, but for some reason not for the humidity reading.

I declare my variables:

    float temp;
    float hum;
    float pres;

    char mqttTemp[6];
    char mqttHum[6];
    char mqttPres[5];

Then I get my readings:

    temp = mySensor.readTempC();
    Serial.print("Temp: ");
    Serial.print(temp);
    hum = mySensor.readFloatHumidity();
    Serial.print("Hum: ");
    Serial.print(hum);
    pres = mySensor.readFloatPressure();
    Serial.print("Pres: ");
    Serial.print(pres);

This returns:

`Temp: 25.57 Hum: 40.15 Pres: 97684.39`

Then I run the results through the function:

    dtostrf(temp,4,2,mqttTemp);
    dtostrf(hum,4,2,mqttHum);
    dtostrf(pres,5,0,mqttPres);

Then I output these to Serial:

    Serial.print("Temperature: ");
    Serial.print(mqttTemp);
    Serial.print("Humidity: ");
    Serial.print(mqttHum);
    Serial.print("Pressure: ");
    Serial.print(mqttPres);

Which gives me:

    Temperature: 25.57
    ------------------------------
    Humidity:
    ------------------------------
    Pressure: 97684

There is also no message sent via MQTT for humidity, but it works perfectly for the other two readings. What gives?

body:
What is happening is that the variables you declared for mqttTemp etc are stored in memory something like this

    variable   memory address
    mqttPres @ 1000-1004 (5 bytes)
    mqttHum  @ 1005-1010 (6 bytes)
    mqttTemp @ 1011-1015 (6 bytes)

For a start, you only have enough room (with the mandatory NUL byte string terminator) for 4, 5 and 5 characters

When you convert pressure, the NUL byte is being placed as the first byte in mqttHum, therefore, when printing mqttHum you get an empty string output (since the first byte is NUL)

To really see what's happening, here's some code that illustrates the issue

    char mqttTemp[6] = "TTTTT";
    char mqttHum[6] = "HHHHH";
    char mqttPres[5] = "PPPP";
    void setup() {
      float temp = 25.57;
      float hum = 40.15;
      float pres = 97684.39;

      Serial.begin(74880);
      // put your setup code here, to run once:
      delay(100);
      Serial.println("before");
      printThem();
      dtostrf(temp, 4, 2, mqttTemp);
      Serial.println("converted temp");
      printThem();
      dtostrf(hum, 4, 2, mqttHum);
      Serial.println("converted hum");
      printThem();
      dtostrf(pres, 5, 0, mqttPres);
      Serial.println("converted press");
      printThem();
    }
    void printThem()
    {
      Serial.print("mqttPres ");
      Serial.print((unsigned long) &mqttPres, DEC);
      Serial.print(": ");
      for (int i = 0; i < 5; i++) {
        Serial.print((int) mqttPres[i], DEC);
        Serial.print(' ');
      }
      Serial.println();

      Serial.print("mqttHum  ");
      Serial.print((unsigned long) &mqttHum, DEC);
      Serial.print(": ");
      for (int i = 0; i < 6; i++) {
        Serial.print((int) mqttHum[i], DEC);
        Serial.print(' ');
      }
      Serial.println();

      Serial.print("mqttTemp ");
      Serial.print((unsigned long) &mqttTemp, DEC);
      Serial.print(": ");
      for (int i = 0; i < 6; i++) {
        Serial.print((int) mqttTemp[i], DEC);
        Serial.print(' ');
      }
      Serial.println();
    }

    void loop() {
      delay(50);
      // put your main code here, to run repeatedly:

    }

The above outputs the following:

    before
    mqttPres 1073644748: 80 80 80 80 0
    mqttHum  1073644753: 72 72 72 72 72 0
    mqttTemp 1073644759: 84 84 84 84 84 0
    converted temp
    mqttPres 1073644748: 80 80 80 80 0
    mqttHum  1073644753: 72 72 72 72 72 0
    mqttTemp 1073644759: 50 53 46 53 55 0
    converted hum
    mqttPres 1073644748: 80 80 80 80 0
    mqttHum  1073644753: 52 48 46 49 53 0
    mqttTemp 1073644759: 50 53 46 53 55 0
    converted press
    mqttPres 1073644748: 57 55 54 56 52
    mqttHum  1073644753: 0 48 46 49 53 0
                         ^ ======== note the leading 0
    mqttTemp 1073644759: 50 53 46 53 55 0

The simplest fix, of course, is to declare your variables with the correct size

    char mqttTemp[7]; // because -10.00 takes 6 characters + 1 for NULL
    char mqttHum[7];  // because 100.00 takes 6 characters + 1 for NULL
    char mqttPres[6]; // because 97684 takes 5 characters + 1 for NULL - if pressure can reach 100000 then use 7 here as well

and then use `dtostrf` **correctly**, i.e. the second argument is the total width, including `.` and a possible `-`

    dtostrf(temp,6,2,mqttTemp);
    dtostrf(hum,6,2,mqttHum);
    dtostrf(pres,5,0,mqttPres);


message:
Serial.print prints but lcd.print does not

The following code reads a txt file from a SD card, finds the corresponding character and prints the next 12 characters:

    ...
          char temp;
          byte who = random(1, 13); // 1 to 12
          temp = findName(who);
          Serial.print(who);
          Serial.print("  ==> ");
          Serial.println(temp);
    ...

        char findName (byte number) {
          char text[12];
          byte i;
          txt = SD.open("test.txt");
          txt.seek(12 * (number - 1));
          for (i = 0; i < 11; i++) text[i] = txt.read();
          txt.close();
          return text;
        }

But the following, on a LCD, does not. (setCursor, etc. ommited for clarity)

    ...
    char temp;
    byte who = random(1, 13); // 1 to 12
    temp = findName(who);
    lcd.print(who);
    lcd.print("  ==> ");
    lcd.print(temp);
    ...

I'm certain the cause is a variable data type mismatch, but I don't know how to solve it. Any help is appreciated.

Thank you.

body:
In the `findName()` function, you declare a char array of name `text`. Internally, `text` is a pointer to a block of memory 12 bytes in size.

When you `return text` within the `findName()` function, you are passing back the pointer to the block of memory. The return type of `char` is inconsistent with the return command. But probably more problematic is that once `findName()` ends, the memory set aside for the `text` array is marked as unused. It is no longer reserved for holding anything and may be reallocated at any time by some other function or operation.

In C/C++, array variables do not refer to the entire array, but to the first element in the array. The fact that your program works with `Serial.print()` is probably just good luck. `lcd.print()` may declare some variable or buffer which overwrites what the `findName()` function had put in those 12 bytes.

There are many approaches to take to resolve this. One way is to declare char arrays in the "highest" scope in which it will be used, and to declare it with the largest size that you could ever see in the operation of your program.

In your case, you can:

    ...
          char temp[12];
          byte who = random(1, 13); // 1 to 12
          findName(temp, who);
          Serial.print(who);
          Serial.print("  ==> ");
          Serial.println(temp);
    ...

        void findName (char *text, byte number) {
          byte i;
          txt = SD.open("test.txt");
          txt.seek(12 * (number - 1));
          for (i = 0; i < 11; i++) text[i] = txt.read();
          txt.close();
        }

What this does:

1. `temp` is now the char array
2. `findName()` takes the pointer to the char array, and the number as arguments
3. `findName()` modifies `text`, which refers to the same block of already-allocated memory as `temp`, and that block of memory does not go away at the end of `findName()`.
4. Because `findName()` is not returning a value, it's return type is `void`.


message:
Interconnected Arduinos via digital pins and magnets

Before i get too far into the design phase of a project i have in mind, is there a way to connect arduinos in a non-master/slave manner to pass a few different combinations of HIGH/LOW (say 5) or 'information' both ways using digital pins? Perhaps some library i don't know about?

Each of these modules should be identical and be able to connect on any face to any other module. I've included a crude image of what I would like to accomplish.

[![magnet modules][1]][1]

I've already determined that i can solder to these neodymium magnets without loss of magnetic properties by having the little magnets attached to a stronger magnet during the soldering process. Magnet to magnet connection shows only a very tiny resistance.

If it can't be accomplished, i will need to abandon the project and look for some other means to make my project. Thanks in advance!

~zen

  [1]: https://i.stack.imgur.com/Kc6PY.jpg

body:
While idea looks cool, you need some kind of "locks" because not "any combination" can work.

Rotate second Arduino in bottom row on 180 degree and you will see that GND/5V reversed relatively to first arduino in second row.

You have to account magnet N-S polarities to allow good lock. Probably you can use magnet polarities to achieve proper orientation.


message:
Random number/sequence output

The program I'm trying to build is:

1. Type in 1st name, hit enter, type in 2nd name and then hit enter again.
2. Register those names from string input to char `naming` in `student` struct.
3. Print out the names in serial monitor.
4. Use those names in the main program.

The problem is I got randomize results whenever I typed in the names.

My target output:

    Program Starts
    Insert 2 students name:

    First student: Adam     //When input -> Adam
    Second student: Eve     //When input -> Eve
    First student: John    //When input -> John
    Second student: Amy    //When input -> Amy
    //the sequences should repeat
...but what happened is the sequences of the names randomized. For example:

    Program Starts
    Insert 2 students name:

    First student: Adam
    First student: Eve
    Second student: John
    First student: Amy
    //the sequences will keep randomizing

Can anyone point out what I've missed out?

The program:

    typedef struct
        {
            char naming[20];
        }student;

        student record[]{
          {""},
          {""},
        };

        String readString;
        String str="";

        // the setup routine runs once when you press reset:
        void setup() {
          Serial.begin(9600);    // initialize serial communication at 9600 bits per second
          while (!Serial);              // wait for Serial Monitor to open
          SerialUSB.println("Program Starts \n Insert 2 students name:");  // Title of sketch
        }

        void loop() {
            namedata();
            mainprg();
        }

        void namedata()
        {
        for(uint8_t i = 0; i < sizeof(record)/sizeof(student); i++){
              while (Serial.available()) {
                char c = Serial.read();
                readString += c;
                readString.trim();
              }

              if (readString.length() >0) {
                str = readString;
                str.toCharArray(record[i].naming,20);
                if(i==0){
                   Serial.print("First student: ");
                }else if(i==1){
                   Serial.print("Second student: ");
                }
                Serial.println(record[i].naming);
              }
                readString="";
            }
        }

        void mainprg()
        {
          //main program using student`s name
        }

Additional infos:

1.Why use struct? Because I've more data to process/store for one "student" in my main program.
2.Currently using Arduino Yun Mini, Arduino 1.8.7

Thanks in advance!

body:
Even though this is not elegant by any means, for now this is what I've came out with:

    typedef struct
    {
      char naming[20];
    } student;

    student record[] {
      {""},
      {""},
    };

    int a = 0;

    char buf[20];

    // the setup routine runs once when you press reset:
    void setup() {
      Serial.begin(9600);    // initialize serial communication at 9600 bits per second
      while (!Serial);              // wait for Serial Monitor to open
      Serial.println("Program Starts \n Insert 2 students name:");  // Title of sketch
    }

    void loop() {
      if (readline(Serial.read(), buf, 20) > 0) {
        if (a == 0) {
          Serial.print("First student: ");
          strncpy(record[a].naming, buf, 20);
          Serial.println(record[a].naming);
          a = 1;
        }
        else if ( a == 1) {
          Serial.print("Second student: ");
          strncpy(record[a].naming, buf, 20);
          Serial.println(record[a].naming);
        }

      }
    }

    int readline(int readch, char *buffer, int len) {
      static int pos = 0;
      int rpos;

      if (readch > 0) {
        switch (readch) {
          case '\r': // Ignore CR
            break;
          case '\n': // Return on new-line
            rpos = pos;
            pos = 0;  // Reset position index ready for next time
            return rpos;
          default:
            if (pos < len - 1) {
              buffer[pos++] = readch;
              buffer[pos] = 0;
            }
        }
      }
      return 0;
    }

Basically by using `int a`, the program decides the sequences of the name. Although it will not repeat the sequence after the 2nd input (ie 1st>2nd>1st>2nd), at least the sequence is not randomize anymore.

Btw thanks for the tips @chrisl!


message:
AVR-GCC can't call function located on fixed address

I wrote the following code:

    #include <avr/io.h>

    __attribute__((noinline, section(".app_start"))) void app_start() //app_start section starts at 0xFA0
    {
     //register_packet_dispatch(packet_received);
     PORTB = 0xFF;
    }

    __attribute__ ((noinline)) void call_app()
    {
     asm ("call 0xFA0\nret");
     //app_start();
    }

    int main()
    {
     DDRB = 0xFF;
     //call_app();
     app_start();
     while(1){}
    }

What I compiled with:

    avr-gcc -Wl,--section-start=.reg_dispatch=0xdac -Wl,--section-start=.app_start=0xFA0 -mmcu=atmega328p -Os -o ubb.o ub_bootloader.cpp -DF_CPU=16000000

Which tries to simulate a host application that tries to call a relocated client application, begins from the 4000 address (0xFA0). If it would work, it's light up the LED wired to the arduino's 13. pin. But why `app_start` won't be called?

I've also inspected the output assemlby:

    avr-objcopy -j .text -j .data -O ihex ubb.o ubb.hex

    00000fa0 <_Z9app_startv>:
     fa0: 8f ef        ldi r24, 0xFF ; 255
     fa2: 85 b9        out 0x05, r24 ; 5
     fa4: 08 95        ret

    00000080 <main>:
      80: 8f ef        ldi r24, 0xFF ; 255
      82: 84 b9        out 0x04, r24 ; 4
      84: 0e 94 d0 07  call 0xfa0 ; 0xfa0 <_Z9app_startv>
      88: ff cf        rjmp .-2       ; 0x88 <main+0x8>

Everything seems correct, why it isn't working at all?
Of course, if i remove the "noinline" attribute, it works. But that's a mirage, the compiler inlines the content of the function, but when I build this into an application, the code after the 0xFA0 address will be rewritten by the host application.

body:
I've tried this code with arduino and it worked (i taught, of course, i can't add the "-Wl,--section-start=.app_start=0xFA0" flag to the compilation process so the function not gonna be moved to other section)
So i set the arudino IDE to show every command from the compilation to the end of the upload process.

The problem lies in the usage of avr-objdump, whose i found somewhere and used witouth overview the CLI switches.

I've also made a mistake when i wrote the question. To disassemble the object file, the right command is:

    avr-objdump -S --disassemble  ubb.o > ubb.asm

THe command i've used to create hex file:

    avr-objcopy -j .text -j .data -O ihex ubb.o ubb.hex

The working one (extracted from arduino):

    avr-objcopy -O ihex -R .eeprom ubb.o ubb.hex

-j means keep only the given section(s)

while

-R means, remove only the given section(s)


message:
RGB LED lights and Arduino

I am doing my thesis project which is a kinetic light/sound sculpture. My first step is to learn how to work with RGB LED lights and how to choose them and what other kinds of equipment I need.

I started to learn Arduino uno and learned how to light an LED, now I need to expand it much bigger.
I want to be able to control each LEDs.

I want 30 meters LED light divided to 7 channels, in which each channel have a unique function that will trigger 7 channels of sound.

I hope I could use your help and thanks in advance for your time :)

body:
I suggest you to use RGB Led Driver like: [WS2812][1].
You can build led strip as long as you want.

There are a lot of example/tutorial using Arduino and Strip Led composed by **WS2812** Led Driver (For example, [here][2] there is a tutorial).

NB: You pay attention that using 30 meters strip led, you need an external power supply and you can't use 5V pin of Arduino, because Arduino doesn't supply sufficient power for supply a strip led too long.

  [1]: https://cdn-shop.adafruit.com/datasheets/WS2812.pdf
  [2]: https://core-electronics.com.au/tutorials/ws2812-addressable-leds-arduino-quickstart-guide.html


message:
What is the state of Arduino pins when the arduino is unpowered?

I'm building a control box to provide logical control of power outlets.

I'm using a 4 channel 5V optically isolated relay system to control 4 separate outlets.

To use optical isolation you connect arduino +5V to the VCC line, and logic inputs to the 4 channels of the relay unit, and connect a separate +5V supply to run the coils of the relays.

To energize one of the relays, you pull that control line LOW. To de-energize the coil, you drive the line HIGH.

If I power on the relay but leave the Arduino unpowered, all the relay coils energize.

Do Arduino pins float when it is powered down, or are they grounded?

Could I wire a pullup resistor to the inputs? And how would I do that without losing optical isolation? If I connect my pullup resistors to the +5V for the relays, the relay's +5 is connected to the Arduino's logic lines. If I instead use the Arudino's +5 rail, then when the Arduino is powered down, it's +5V line is dead.

body:
The pins have input protection diodes that clamp the pins to Vcc and Gnd. If a pin gets to >VCC +0.5V the positive diode clamp conducts and Vcc is powered via the internal Vcc bus, and if a pin get to < -0.5V the negative diode clamp conducts.  With Vcc = 0V, the pin could act as if it were a low, but more generally folks see the chip acting like it was phantom powered and attempting to run code with perhaps unpredictable results.  That's why the datasheet says to not drive the pins when th chip is unpowered.  If the clamp current becomes too much, the diode can blow, and either just the one pin is impacted, or the whole chip dies and it will feel warm/hot to the touch when powered up.

So don't power up the relays without also powering up the Arduino.


body:
As it turns out my question was a bit of an X/Y problem. I wanted to know what the pins on the Arduino do when the board is unpowered, because I was feeding +5V into the VCC input on my relay board when the Arduino was unpowered, and having the relay control lines connected to Arduino pins.

If you remove the jumper on my relay board, it has a VCC line that ONLY powers the logic level inputs to the relay control optical isolators  and a JVCC line that drives the relay coils. (The VCC line might also power the optical isolators and the other CMOS circuitry on the board, I'm not sure.)

I have my Arduino wired to a USB input that is driven by a regulated AC power supply when it's running stand-alone, and from my computer when it's being programmed. Sometimes I forget to plug the AC powered USB cable into the Arduino when I switch to running it stand-alone off of AC, and in those cases the relay lines tend to energize when I don't want to, **and** I end up driving +5V into the Arduino's relay control GPIO lines, which is not a good idea.

The simple answer is to connect the +5V line from the Arduino to the VCC pin on the relay board. Then when the relay's JVCC is powered but the Arduino is not, the VCC line to the relay and the control lines to the relay are all unpowered, so the relay is off.

Duh.


message:
'RtcDateTime' does not name a type

I've tested a code that compiles successfully.

But after i merged it to another code, here it shown an error says RtcDateTime doesn't name a type.

Used library : https://github.com/Makuna/Rtc

[![enter image description here][1]][1]

  [1]: https://i.stack.imgur.com/WbAw8.png

Some notes :
- RtcDateTime instances are being used in setup() and loop() without a problem.
- RtcDS3231 header file is included (which includes RtcDateTime.h inside it).
- Tried to include RtcDateTime.h in my sketch, doesn't work !

Code : (Contains combination of 3 devices : RTC , I2C Ultrasonic and HX711 loadcell)

    /*
    Below, I define the SCL and SDA pins by their ATMEGA pins I have included links to common mappings below.
        UNO:  http://arduino.cc/en/Hacking/PinMapping168
        NANO: (matches UNO but has fewer pins)
        MEGA 2560: http://arduino.cc/en/Hacking/PinMapping2560
    The current data matches the setup for the Arduino Uno -- they may need to be changed if the hardware changes.
    You can also switch the I2C interface
    to any of the tristate pins that you want (not just the SDA or SCL pins).
    */
    #define SCL_PIN D2              //Default SDA is Pin5 PORTC for the UNO -- you can set this to any tristate pin
    #define SDA_PIN D1              //Default SCL is Pin4 PORTC for the UNO -- you can set this to any tristate pin
    #define I2C_TIMEOUT 100        //Define a timeout of 100 ms -- do not wait for clock stretching longer than this time

    #include "HX711.h"  //You must have this library in your arduino library folder

    #define DOUT  D1
    #define CLK  D2

    HX711 scale(DOUT, CLK);
    float calibration_factor = -10060; //-106600 worked for my 40Kg max scale setup

    /*
    I have included a couple of extra useful settings for easy reference.
    //#define I2C_CPUFREQ (F_CPU/8)//Useful if you plan on doing any clock switching
    #define I2C_FASTMODE 1         //Run in fast mode (400 kHz)
    #define I2C_SLOWMODE 1         //If you do not define the mode it will run at 100kHz with this define set to 1 it will run at 25kHz
    */
    #include <SlowSoftI2CMaster.h>     //You will need to install this library
    // create new instance with A4 as SDA, A5 as SCL and enable internal pullups
    SlowSoftI2CMaster si = SlowSoftI2CMaster(SDA_PIN, SCL_PIN);

    /*
     * RTC Code starts here
     */

    #include <Wire.h> // must be included here so that Arduino library object file references work
    #include <RtcDS3231.h>
    RtcDS3231<TwoWire> Rtc(Wire);
    /*
     * RTC Headers Ending
     */

    void setup(){
      // Initialize both the serial and I2C bus
      Serial.begin(9600);
      Serial.println("Press T to tare");
      scale.set_scale(calibration_factor);  //Calibration Factor obtained from first sketch
      scale.tare();             //Reset the scale to 0

    if (!si.i2c_init()) // initialize I2C module
            Serial.println("I2C init failed");

     /*
      * RTC Setup :
      */
      Rtc.Begin(SDA_PIN,SCL_PIN);

        RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
        printDateTime(compiled);
        Serial.println();

        if (!Rtc.IsDateTimeValid())
        {
            // Common Cuases:
            //    1) first time you ran and the device wasn't running yet
            //    2) the battery on the device is low or even missing

            Serial.println("RTC lost confidence in the DateTime!");

            // following line sets the RTC to the date & time this sketch was compiled
            // it will also reset the valid flag internally unless the Rtc device is
            // having an issue

            Rtc.SetDateTime(compiled);
        }

        if (!Rtc.GetIsRunning())
        {
            Serial.println("RTC was not actively running, starting now");
            Rtc.SetIsRunning(true);
        }

        RtcDateTime now = Rtc.GetDateTime();
        if (now < compiled)
        {
            Serial.println("RTC is older than compile time!  (Updating DateTime)");
            Rtc.SetDateTime(compiled);
        }
        else if (now > compiled)
        {
            Serial.println("RTC is newer than compile time. (this is expected)");
        }
        else if (now == compiled)
        {
            Serial.println("RTC is the same as compile time! (not expected but all is fine)");
        }

        // never assume the Rtc was last configured by you, so
        // just clear them to your needed state
        Rtc.Enable32kHzPin(false);
        Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);

     /*
      * RTC Setup Ending
      */
    }
    #define countof(a) (sizeof(a) / sizeof(a[0]))

    void loop()
    {
      if (!si.i2c_init()) // initialize I2C module
            Serial.println("I2C init failed");
      // (OPTIONAL) Read a sensor at the default address
      read_the_sensor_example();

      scale.begin(SDA_PIN,SCL_PIN);
      Serial.print("Weight: ");
      Serial.print(scale.get_units(), 5);  //Up to 3 decimal points
      Serial.println(" kg"); //Change this to kg and re-adjust the calibration factor if you follow lbs

      if(Serial.available())
      {
        char temp = Serial.read();
        if(temp == 't' || temp == 'T')
          scale.tare();  //Reset the scale to zero
      }

      /*
       *  RTC Loop Start
       */
      if (!Rtc.IsDateTimeValid())
        {
            // Common Cuases:
            //    1) the battery on the device is low or even missing and the power line was disconnected
            Serial.println("RTC lost confidence in the DateTime!");
        }

        RtcDateTime now = Rtc.GetDateTime();

        Serial.println();
        // String date = dateS(now);
        // String time = timeS(now);

      RtcTemperature temp = Rtc.GetTemperature();
      temp.Print(Serial);
      // you may also get the temperature as a float and print it
        // Serial.print(temp.AsFloatDegC());
        Serial.println("C");

      /*
       *    RTC loop Ending
       */
    }

    void printDateTime(const RtcDateTime& dt)
    {
        char datestring[20];

        snprintf_P(datestring,
                countof(datestring),
                PSTR("u/u/u u:u:u"),
                dt.Month(),
                dt.Day(),
                dt.Year(),
                dt.Hour(),
                dt.Minute(),
                dt.Second() );
        Serial.print(datestring);
    }

    ///////////////////////////////////////////////////
    // Function: Start a range reading on the sensor //
    ///////////////////////////////////////////////////
    //Uses the I2C library to start a sensor at the given address
    //Collects and reports an error bit where: 1 = there was an error or 0 = there was no error.
    //INPUTS: byte bit8address = the address of the sensor that we want to command a range reading
    //OUPUTS: bit  errorlevel = reports if the function was successful in taking a range reading: 1 = the function
    //  had an error, 0 = the function was successful
    boolean start_sensor(byte bit8address){
      boolean errorlevel = 0;
      bit8address = bit8address & B11111110;               //Do a bitwise 'and' operation to force the last bit to be zero -- we are writing to the address.
      errorlevel = !si.i2c_start(bit8address) | errorlevel;   //Run i2c_start(address) while doing so, collect any errors where 1 = there was an error.
      errorlevel = !si.i2c_write(81) | errorlevel;            //Send the 'take range reading' command. (notice how the library has error = 0 so I had to use "!" (not) to invert the error)
      si.i2c_stop();
      return errorlevel;
    }

    ///////////////////////////////////////////////////////////////////////
    // Function: Read the range from the sensor at the specified address //
    ///////////////////////////////////////////////////////////////////////
    //Uses the I2C library to read a sensor at the given address
    //Collects errors and reports an invalid range of "0" if there was a problem.
    //INPUTS: byte  bit8address = the address of the sensor to read from
    //OUPUTS: int   range = the distance in cm that the sensor reported; if "0" there was a communication error
    int read_sensor(byte bit8address){
      boolean errorlevel = 0;
      int range = 0;
      byte range_highbyte = 0;
      byte range_lowbyte = 0;
      bit8address = bit8address | B00000001;  //Do a bitwise 'or' operation to force the last bit to be 'one' -- we are reading from the address.
      errorlevel = !si.i2c_start(bit8address) | errorlevel;
      range_highbyte = si.i2c_read(0);           //Read a byte and send an ACK (acknowledge)
      range_lowbyte  = si.i2c_read(1);           //Read a byte and send a NACK to terminate the transmission
      si.i2c_stop();
      range = (range_highbyte * 256) + range_lowbyte;  //compile the range integer from the two bytes received.
      if(errorlevel){
        return 0;
      }
      else{
        return range;
      }
    }

    /////////////////////////////////////////
    // Function: Change the sensor address //
    /////////////////////////////////////////
    //Uses the I2C library to change the address of a sensor at a given address
    //Collects and reports an error bit where: 1 = there was an error or 0 = there was no error.
    //INPUTS: byte oldaddress = the current address of the sensor that we want to change
    //INPUTS: byte newddress  = the address that we want to change the sensor to
    //OUPUTS: bit  errorlevel = reports if the function was successful in changing the address: 1 = the function had an
    //      error, 0 = the function was successful
    boolean change_address(byte oldaddress,byte newaddress){
      //note that the new address will only work as an even number (odd numbers will round down)
      boolean errorlevel = 0;
      oldaddress = oldaddress & B11111110;  //Do a bitwise 'and' operation to force the last bit to be zero -- we are writing to the address.
      errorlevel = !si.i2c_start(oldaddress) | errorlevel; //Start communication at the new address and track error codes
      errorlevel = !si.i2c_write(170) | errorlevel;        //Send the unlock code and track the error codes
      errorlevel = !si.i2c_write(165) | errorlevel;        //Send the unlock code and track the error codes
      errorlevel = !si.i2c_write(newaddress) | errorlevel; //Send the new address
    //  si.i2c_stop();
      return errorlevel;
    }

    //////////////////////////////////////////////////////////
    // Code Example: Read the sensor at the default address //
    //////////////////////////////////////////////////////////
    void read_the_sensor_example(){
      boolean error = 0;  //Create a bit to check for catch errors as needed.
      int range;

      //Take a range reading at the default address of 224
      error = start_sensor(224);    //Start the sensor and collect any error codes.
      if (!error){                  //If you had an error starting the sensor there is little point in reading it as you will get old data.
        delay(100);
        range = read_sensor(224);   //reading the sensor will return an integer value -- if this value is 0 there was an error
        Serial.print("R:");Serial.println(range);
      }
    }

    ////////////////////////////////////////////////////////////////
    // Code Example: Poll all possible addresses to find a sensor //
    ////////////////////////////////////////////////////////////////
    void address_polling_example(){
      boolean error = 0;  //Create a bit to check for catch errors as needed.
      int range = 0;
      Serial.println("Polling addresses...");

      //Walk through all possible addresses and check for a device that can receive the range command and will
      //    return two bytes.
      for (byte i=2; i!=0; i+=2){   //start at 2 and count up by 2 until wrapping to 0. Checks all addresses (2-254) except 0 (which cannot be used by a device)
        error = 0;
        error = start_sensor(i);    //Start the sensor and collect any error codes.
        if (!error){                //If you had an error starting the sensor there is little point in reading it.
          delay(100);
          range = read_sensor(i);   //reading the sensor will return an integer value -- if this value is 0 there was an error
          Serial.println(i);
          if (range != 0){
            Serial.print("Device found at:");Serial.print(i);Serial.print(" Reported value of:");Serial.println(range);
          }
        }
        else{
          Serial.print("Couldn't start:");Serial.println(i);
        }
      }

      Serial.println("Address polling complete.");
    }

    //////////////////////////////////////////////
    // Code Example: Change the default address //
    //////////////////////////////////////////////
    void default_address_change_example(){
      boolean error = 0;  //Create a bit to check for catch errors as needed.
      int range;

      Serial.println("Take a reading at the default address");

      //Take a range reading at the default address of 224
      error = start_sensor(224);    //Start the sensor and collect any error codes.
      if (!error){                  //If you had an error starting the sensor there is little point in reading it.
        delay(100);
        range = read_sensor(224);   //reading the sensor will return an integer value -- if this value is 0 there was an error
        Serial.print("R:");Serial.println(range);
      }

       Serial.println("Change the sensor at the default address to 222");
      //Change the address from 224 to 222
      error = 0;
      error = change_address(224,222);  //Change the address -- I don't do anything with the error handler at this point but you can if you want.
      delay(200);    //Wait 125ms for the sensor to save the new address and reset

       Serial.println("Take a reading at the new address");

      //Take a range reading at the new address of 222
      error = 0;
      error = start_sensor(222);     //Same as above but at the new address
      if (!error){
        delay(100);
        range = read_sensor(222);
        Serial.print("N:");Serial.println(range);
      }

       Serial.println("Change the sensor back to the default address");

      //Change the address from 222 to 224
      error = 0;
      error = change_address(222,224);
      delay(200);    //Wait 125ms for the sensor to save the new address and reset

    }

So i have no idea why this happens .

Any help ?

body:
I was also getting the same problem,  place the printDateTime function on the first page or the page where the headers and declaration's available

below function

    #define countof(a) (sizeof(a) / sizeof(a[0]))
    void printDateTime(const RtcDateTime& dt)
    {
        char datestring[20];

        snprintf_P(datestring,
                countof(datestring),
                PSTR("u/u/u u:u:u"),
                dt.Month(),
                dt.Day(),
                dt.Year(),
                dt.Hour(),
                dt.Minute(),
                dt.Second() );
        Serial.print(datestring);
    }


message:
Measure Sofware Serial write() time

As you probably know, SoftwareSerial uses Interrupts to do some of the timing stuff of the Serial communication.

What I am trying to accomplish is to measure the time that it takes `SoftwareSerial.write()` to write/send one byte.

Obviously, I started trying with timestamps based on `millis()`, but found out that SoftwareSerial messes with the `millis()` timer and it simply doesn't count properly.

I have something like this:

    timestamp = millis();
    HC12.write(endByte); //HC12 is a SoftwareSerial object

    //After sending waits for the answer
    while (HC12.available() > 0) {
      byte r = HC12.read();
      if (r == (byte) 254) { //The other HC12 module sends 0xFE
        unsigned long received = millis() - timestamp;
        Serial.println(received);
      }
    ...

Any suggestion on how I could measure this?

I am trying to implement a half-duplex communication with HC12 433MHz modules and I am testing some theoretical/real timing values for the communication between two boards.

body:
It is very simple, and you don't need any code to work it out.

SoftwareSerial is completely synchronous (i.e., *blocking*) when writing.  That means that the amount of time taken to peform the write is the time taken to send the data on the line plus a small function call overhead.

That means the time taken is:

    1 / baud * 10 seconds

So at 9600 baud one bit is sent in 1/9600 of a second, and there are 10 bits (1 start, 8 data, and 1 stop bit), so it takes 1/960th of a second.

That's about 1ms per byte, plus a few extra clock cycles for calling the actual functions.

To put it in more detail, when you send a byte this happens:

1. Set the line level to the start bit level
2. Wait 1/9600th of a second
3. Set the line level to the first data bit level
4. Wait 1/9600th of a second
5. Repeat 3&4 for the rest of the data bits
6. Set the line level to the stop bit level
7. Wait 1/9600th of a second
8. Set the line level to the idle level

So you have 10 "wait 1/9600th of a second" in total, or a total time of 1/960th of a second.

The same can be said of receiving data. When the start bit arrives it triggers a *pin change* interrupt.  A synchronous blocking interrupt routine then executes that does the same as above but with reading instead of writing. So that takes about 1ms to execute at 9600 baud - plus some extra to insert the incoming byte into a circular buffer, which you then read from in your sketch.

So the round-trip time of a single byte from unit A to unit B then from unit B to unit A can be estimated as:

    1/960 + 1/960 + overheads

That means the minimum time will be 1/480 seconds plus whatever time is spent at the remote unit processing the byte to send data back to you, and a little bit for the function call overheads.

Incidentally, it's that last operation in the interrupt, the "adding the byte to a circular buffer" that means you can't reliably receive at 115200 baud with SoftwareSerial. That takes more time to process than the typical gap between bytes (could be zero - just the width of the stop bit...) that the next byte could have already started to arrive at the GPIO pin before the Arduino is capable of triggering the ISR again, so it misses the start bit.


message:
Combining code for multiple sensors in a single program

I need to operate 3 different sensors (taken 6 sensors of each type) by Arduino Mega2560 :-

1. DHT11 (temperature-Humidity sensor)
2. MQ5 (gas sensor) and
3. Soil Moisture sensor
{taken 6 of each type (total=18).}

I have managed to run each one of them separately and I don't know how to manipulate the code so they could work all together. My background in coding is basic, so it would be great help if someone can help me for combining these codes.

Here are the sketches:

**MQ5 Code:**

    int sensor=7;
    int gas_value;
    void setup()
    {

    pinMode(sensor,INPUT);
    Serial.begin(9600);

    }

    void loop()
    {

    gas_value=digitalRead(sensor);
    Serial.println(gas_value);
    }
{other digital pins to be used: D6,D5,D4,D3,D2}

**DHT11 Code:**

    #include <dht.h>
    #include <dht.h>
    #include "dht.h"
    #define dht_apin A0 // Analog Pin sensor is connected to
    dht DHT;

    void setup(){

      Serial.begin(9600);
      delay(500);//Delay to let system boot
      Serial.println("DHT11 Humidity & temperature Sensor\n\n");
      delay(1000);//Wait before accessing Sensor

    }//end "setup()"

    void loop(){
      //Start of Program

        DHT.read11(dht_apin);

        Serial.print("Current humidity = ");
        Serial.print(DHT.humidity);
        Serial.print("%  ");
        Serial.print("temperature = ");
        Serial.print(DHT.temperature);
        Serial.println("C  ");

        delay(5000);//Wait 5 seconds before accessing sensor again.

      //Fastest should be once every two seconds.

    }// end loop()
{analog pins for other sensors: A1,A2,A3,A4,A5}

**Soil_Moisture Sensor Code:**

    int sensor_pin = A6;
    int output_value ;

    void setup() {

       Serial.begin(9600);
       Serial.println("Reading From the Sensor ...");
       delay(2000);

       }

    void loop() {

       output_value= analogRead(sensor_pin);
       output_value = map(output_value,550,0,0,100);
       Serial.print("Mositure : ");
       Serial.print(output_value);
       Serial.println("%");
       delay(1000);
       }
{Analog pins for other sensors to be used: A6,A7,A8,A9,A10}

body:
In general:

All `#define`s and `#include`s get put from all separate sketches, at the top.

Globals and function definitions (except for `setup()` and `loop()`) get mixed together below the `#define`s and `#include`s.

All code in the separate `setup()`s get put in the combined `setup()`.

All code in the separate `loop()`s get put in the combined `loop()`.

You have to be aware that any `loop()` from the separate programs that include a `delay()` will likely have to be refactored to use the same kind of scheduled execution method as the [Blink Without Delay][1] example from Arduino. `delay()` stops the whole program while it twiddles thumbs, which means your other sensors aren't being read or managed during that time.

  [1]: https://www.arduino.cc/en/tutorial/BlinkWithoutDelay


body:
All things before `void setup()` put before one `setup()` function. All things in `void setup()` put to the one `void setup()` - do not duplicate things like `#include` or `Serial.begin()`. And things from `loop()` function put to the `loop()` function.
It's a good practice to don't use `delay()` in  `loop()` when you are processing more things than one. Instead of `delay()` use `millis()` to get current uptime and after that compare this uptime to last uptime of check.

I modified your code, so read it and try it.

```
#include <dht.h>

#define dht_apin A0 // Analog Pin sensor is connected to
dht DHT;

int sensor=7;
int gas_value;

int sensor_pin = A6;
int output_value ;

unsigned long gas_last_time = 0;
unsigned long dht11_last_time = 0;
unsigned long analog_last_time = 0;

void setup(){
  Serial.begin(9600);
  pinMode(sensor,INPUT);
}

void loop(){
  if(millis() - gas_last_time >= 10){
    gas_last_time = millis();

    gas_value=digitalRead(sensor);
    Serial.println(gas_value);
  }

  if(millis() - dht11_last_time >= 5000){
    dht11_last_time = millis();

    DHT.read11(dht_apin);

    Serial.print("Current humidity = ");
    Serial.print(DHT.humidity);
    Serial.print("%  ");
    Serial.print("temperature = ");
    Serial.print(DHT.temperature);
    Serial.println("C  ");
  }

  if(millis() - analog_last_time >= 1000){
    analog_last_time = millis();

    output_value= analogRead(sensor_pin);
    output_value = map(output_value,550,0,0,100);
    Serial.print("Mositure : ");
    Serial.print(output_value);
    Serial.println("%");
  }
}
```


message:
How to multitask while writing on Serial

I am trying to send real-time data taken from an ADC by Arduino Uno (SPI) to Arduino IDE through a USB cable. I found that one byte takes around 70 microseconds when Serial.write() is used at a baud rate of 115200. My question is that if I send 14400 bytes (which would be the maximum limit at this baud rate), can I perform any other tasks? Does Arduino allow multitasking while the serial buffer is busy writing data?

body:
Until you fill the transmit buffer (64 bytes by default but can be recompiled to enlarge it if you need to), Serial.print() or Serial.write() will return immediately. The characters in the buffer will be transmitted by an interrupt service routine, so essentially, the Arduino is double-tasking for that purpose. If the buffer is full when you call Serial.print() or Serial.write() or Serial.print() fills it before having sent all of its characters, those calls block (won't return) until there is buffer-space for their remaining characters.

So yes, you can do other things while the writing happens, as long as you haven't filled the buffer. You can call Serial.availableForWrite() to find out how many characters you can send without blocking.

By the way, at 115200 baud, or 11520 bytes/second, each character should take 1/11520 seconds or 86.8 microseconds, not 70 milliseconds.


message:
Trouble with reading Bitmaps from SD-Card

I'm having problems with reading a bitmap file with the SD library.
I wrote a small header that reads uncompressed 24-bit bitmap files. It works fine when I try it on Windows 10 MingW with fread() instead of SD.read().
On my UNO it only reads the correct offset address, the other parts are garbage.

For a pure red 1x1 px bitmap I get the following expected output on Windows with MingW:

    Fname: ..\rot.bmp
    Offset: 00000036
    W * H: 1 * 1
    Bit# 24
    Cmp: 0
    ArraySize: 1
    ---------------------------
    RGB: ff0000

Arduino outputs:

    Fname: rot.bmp
    Offset: 00000036
    W * H: 0 * 2304
    Bit# 58
    Cmp: 0
    ArraySize: 8
    ---------------------------
    Error while reading BMP file

bmp.hpp

    #ifndef BMP_HEADER
    #define BMP_HEADER

    #if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA)
    #include <SD.h>
    #include<stdint.h>
    #define BYTE uint8_t
    #define WORD uint16_t
    #define DWORD uint32_t
    #define LONG int32_t
    #else
    #include<stdlib.h>
    #include<windows.h>
    #endif // defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA)
    #pragma pack(2)
    typedef struct
    {
      BYTE B;
      BYTE G;
      BYTE R;
    } pixel;

    typedef struct
    {
      WORD bfType;
      DWORD bfSize;
      DWORD bfReserved;
      DWORD bfOffset; //offset to byte array
    } bfheader;

    typedef struct
    {
      DWORD biSize; //size of this header
      LONG biWidth; //image width
      LONG biHeight;//image height
      WORD biPlanes;
      WORD biBitCount; //color depth in bit per pixel
      DWORD biCompression; //0 for none(RGB mode)
      DWORD biSizeImage; //size of image in byte; may be 0 if biCompression is RGB
      LONG biXPelsPerMeter;
      LONG biYPelsPerMeter;
      DWORD biClrUsed; //palete stuff
      DWORD biClrImportant; //more palete stuff
    } biheader;

    //returns BGR array of bitmap
    //header and biheader are assumed to be allocated upon execution
    //returns null if unsuccessful
    inline pixel* readBMP(const char* filename, bfheader* header, biheader* infoheader)
    {
        #if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA)
        SDLib::File f = SD.open(filename);
        if(!f) return NULL;
        f.read((uint8_t *)header, sizeof(bfheader)); // read the 14-byte file header
        f.read((uint8_t *)infoheader, sizeof(biheader)); //read the 40-byte info header
        #else
        FILE* f = fopen(filename, "rb");
        if(f == NULL) return NULL;
        fread(header, sizeof(bfheader), 1, f);
        fread(infoheader, sizeof(biheader), 1, f);
        #endif //defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA)
      if(infoheader->biCompression != 0 || infoheader->biBitCount != 24) //if the file is not RGB encoded or if its not 24bit
      {
        #if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA)
        f.close();
        #else
        fclose(f);
        #endif // defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA)
        return NULL;
      }
      int size = (int) infoheader->biSizeImage/sizeof(pixel); //get byte size of pixel array
      pixel* data = (pixel*) malloc(sizeof(pixel)*size); // allocate
      #if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA)
        f.seek(header->bfOffset); //set file cursor to starting address of RGB array
        f.read((uint8_t *)data, sizeof(uint8_t)*size); // read the rest of the data at once
        f.close();
      #else
        fseek(f, header->bfOffset, SEEK_SET);
        fread(data, sizeof(pixel), size, f);
        fclose(f);
      #endif //__arm__
      return data;
    }
    #endif //BMP_HEADER

readbmp_test.ino

    #include<arduino.h>
    #include <SPI.h>
    #include "bmp.hpp"

    void setup() {
      Serial.begin(9600);
      while (!Serial) {
        ; // wait for serial port to connect. Needed for native USB port only
      }
      Serial.print("Initializing SD card...");

      if (!SD.begin(4)) {
        Serial.println("initialization failed!");
        while (1);
      }
      Serial.println("initialization done.");
    }

    void loop()
    {
      char debug[160];
      char rgbdata[8];
      const char* const files[] = {"rot.bmp", "gruen.bmp", "blau.bmp"};
      int files_len = 3;
      bfheader header;
      biheader infoheader;
      pixel* image;
      for(int i=0; i<files_len; i++)
      {
        image = readBMP(files[i], &header, &infoheader);
        Serial.println("----------------------------");
        sprintf(debug,  "Fname: %s\n"
                    "Offset: lx\n"
                    "W * H: %ld * %ld\n"
                    "Bit# %u\n"
                    "Cmp: %lu\n"
                    "ArraySize: %lu\n"
                    "---------------------------\n",
                      files[i],
                      header.bfOffset,
                      infoheader.biWidth, infoheader.biHeight,
                      infoheader.biBitCount,
                      infoheader.biCompression,
                      infoheader.biSizeImage/sizeof(pixel));
        Serial.print(debug);
        if(image != NULL)
        {

          for(unsigned j=0; j<infoheader.biSizeImage/sizeof(pixel); j++)
          {
            sprintf(rgbdata, "x x x", image[j].R, image[j].G, image[j].B);
            Serial.println(rgbdata);
          }
        }else{
            sprintf(debug, "Error while reading BMP file\n");
            Serial.print(debug);
        }
        free(image);
      }
    }

main.cpp //MingW Windows Test

    #if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA)  //arduino compiler wants to run this main?
    #else
    #include<stdio.h>
    #include "bmp.hpp"

    int main(const int argc, const char** argv)
    {
        if(argc < 2) return -1;

        bfheader header;
        biheader infoheader;
        for(int i=1; i<argc; i++)
        {
            pixel* image = readBMP(argv[i], &header, &infoheader);
            if(image != NULL)
            {
                printf("Fname: %s\n"
                        "Offset: x\n"
                        "W * H: %d * %d\n"
                        "Bit# %d\n"
                        "Cmp: %d\n"
                        "ArraySize: %d\n"
                        "---------------------------\n",
                        argv[i],
                        header.bfOffset,
                        infoheader.biWidth, infoheader.biHeight,
                        infoheader.biBitCount,
                        infoheader.biCompression,
                        infoheader.biSizeImage/sizeof(pixel));
                for(int j=0; j<infoheader.biSizeImage/sizeof(pixel); j++)
                {
                    printf("RGB: xxx\n", image[j].R, image[j].G, image[j].B);
                }
            }else{
                    printf("Error while reading BMP file\n");
                    return 1;
            }
            free(image);
        }
        return 0;
    }
    #endif

I'm really stuck on this, I actually rewrote it a couple times already.
I would really appreciate some help.

body:
`f.read((uint8_t *)infoheader, sizeof(infoheader));`

should be

`f.read((uint8_t *)infoheader, sizeof(biheader));`

the size of the variable (pointer) is only 2. you want to read 40 bytes of `biheader` struct

and

 `f.read((uint8_t *)data, sizeof(uint8_t)*size)`

should be

`f.read((uint8_t *)data, sizeof(pixel)*size)`

----------

The next problem is %d and %x in sprintf. %d and %x read two bytes on Arduino, not 4, not 1. Print the values without sprintf as `Serial.println(number)`


message:
Method to iterate over the bits in a byte sent over serial

In my current project which integrates Arduino/avr IC with Raspberry-Pi, and each communicating via serial, I'm looking to send a byte of data to the Arduino from the RPi, which then would be iterated over, bit by bit.

Each bit represents a setting. If a bit is 0, then the Arduino would turn that respective device off, if a bit is 1, then Arduino would turn that respective device on. For example, a byte such as: 01100110, would mean the Arduino would have to turn four devices off, and four devices on.

I'm looking for information on how to take a byte over serial, and iterate over that byte bit by bit, and have the Arduino make decisions based on the value of each bit.

Excuse my post for lacking much technical detail, I'm refraining from using terms that are still very vague to me.

Regards.

body:
In all the examples below, `value` is the value of the byte

LSB -> MSB - so 00001111 would turn ON the first 4 devices and turn OFF the last 4

    for(int i = 0, mask = 1; i < 8; i++, mask = mask << 1)
    {
        if (value & mask)
        {
            // bit is on
        }
        else
        {
            // bit is off
        }
    }

Alternatively, you can do the following, but `value` will be altered

    for(int i = 0; i < 8; i++, value = value >> 1)
    {
        if (value & 1)
        {
            // bit is on
        }
        else
        {
            // bit is off
        }
    }

Working the other way around in each byte:
MSB -> LSB - so 00001111 would turn OFF the first 4 devices and turn ON the last 4

    for(int i = 0, mask = 128; i < 8; i++, mask = mask >> 1)
    {
        if (value & mask)
        {
            // bit "i" is on
        }
        else
        {
            // bit "i" is off
        }
    }

Alternatively, you can do the following, but `value` will be altered

    for(int i = 0; i < 8; i++, value = value << 1)
    {
        if (value & 128)
        {
            // bit is on
        }
        else
        {
            // bit is off
        }
    }


message:
Do you need an ESC to run this brushless DC motor with Arduino Uno?

This is the motor:

https://www.aliexpress.com/item/Wholesale-JGA25-2418-8-5-1977-rpm-Electric-Motors-Brushless-Motor-High-Torque-Speed-Controlled-DC/32360228129.html

I'm hooking it up to the arduino as described and giving the PWM outputpin analogWrite functions, but it's not working.

body:
No. It has an ESC built in.

You just provide power and a PWM signal, and optionally a direction signal.

To test:

1. Connect red to +12V.
2. Connect black to 12V GND and to Arduino GND
3. Connect white to D5
4. `analogWrite(5, 128)`;


message:
Button for Delay Select

My target is to make an Arduino system that is able to change modes with different delays by pushing a button. For example, if I pressed the button, it will go into mode 1 with loop 1 that has a 30s delay. If I pressed it one more time, it will go to mode 2 with with loop 2 that has a 1 min delay, etc. The important thing is that mode 1 should be breaked when the push button pressed.

The code below solved part of the problem. However, LEDs are only constant ON, they are not blinking for a certain time then it turned either on-off within the mode when the push button pressed.

    int b =3;int rl= 5;int gl=6;
    int yl=7; int s=0; int o=0;
     int bp =0;

    void setup() {
      // put your setup code here, to run once:
    pinMode(b,INPUT);
    pinMode(rl,OUTPUT);
    pinMode(gl,OUTPUT);
    pinMode(yl,OUTPUT);

     digitalWrite(rl,LOW);
    digitalWrite(gl,LOW);
    digitalWrite(yl,LOW);
    }

    void loop() {
      // put your main code here, to run repeatedly:

    bp=digitalRead(b);
    if (bp==1){
      delay(50);
      bp=digitalRead(b);
      if (bp==0){
        s=o+1;}}
        else{
          delay(100);}
          switch(s){
            case 1:
            digitalWrite(rl,HIGH);
    digitalWrite(gl,LOW);
    digitalWrite(yl,LOW);
    o=s;
    break;

    case 2 :
    digitalWrite(rl,LOW);
    digitalWrite(gl,HIGH);
    digitalWrite(yl,LOW);
    o=s;
    break;

    case 3:

    digitalWrite(rl,LOW);
    digitalWrite(gl,LOW);
    digitalWrite(yl,HIGH);
    o=s;
    break;
    default:

    digitalWrite(rl,LOW);
    digitalWrite(gl,LOW);
    digitalWrite(yl,LOW);
    o=0;
    break;}}

[![Connection diagram][1]][1]

  [1]: https://i.stack.imgur.com/Cg3k0.jpg

S1 is responsible to activate D12 to be constant ON (when it’s pressed once) which lead UNO2 to be powered then blink the right LED ON (1min) OFF(4Hr), (pressing it twice should turn D12 OFF (optional)). The same thing with S2, when it’s pressed once it should first disable D12 and activate D11 instead, powering UNO3, blinking the left LED ON(30S), OFF (4Hr).

In addition, blinking on() off() repeatedly is needed (unless action break/occur, ex: pressing S1 or S2).

About S1 and S2. The LED on D12 will flash ON for 1 minute then turn off for 4 hours. After the 4 hours, the LED on D12 will flash ON again for 1 min then turn off for 4 hours again & again...as an infinite loop. With S2 The LED on D11 will flash ON for 30 seconds then turn off for 4 hours. After the 4 hours, the LED On D11 will flash ON again for 30 s then turn off for 4 hours again and again as an infinite loop.

body:
Do not use delay but millis().
Example:
```
#define BTN 2
#define MAX_MODE 1   //2 modes

const unsigned int times[] = {1000, 2000};

unsigned int time = times[0];

unsigned long btn_tm = 0;
unsigned long l_time = 0;

byte mode = 0;

void setup(){
  Serial.begin(9600);
  pinMode(BTN, INPUT);
}

void loop(){
  if(digitalRead(BTN) == 1 && millis() - btn_tm > 200){
    btn_tm = millis();
    mode ++
    if(mode > MAX_MODE) mode = 0;
    time = times[mode];
 }
  if(millis() - l_time >= time){
    l_time = millis();
    if(mode == 0) Serial.println("mode 0");
    if(mode == 1) Serial.println("mode 1");
 }
}
```
Read it and try it.


body:
In response to your comment on Matej's answer @Ibrahim.M: "I wish I can abbreviate it with only one UNO that able to do the same task by using programming.". You can do this with just one Uno.

I would start by detecting the button presses and debouncing them. This is easy to do using the Bounce2 library. You can use the button presses to start timers which will turn the LEDs On and Off.

**EDIT**

To make an LED flash on and off, and to keep time, you can use the `millis()` function. I started with the [BlinkWithoutDelay][1] tutorial, and came up with the following sketch. It only has one timer / LED flasher, but there is enough information in the sketch to figure out how to make the second timer / LED flasher.

    #include <Bounce2.h>

    byte led1State = LOW;
    byte timer1Active = 0;
    const byte led1Pin = LED_BUILTIN;
    const byte buttonPin1 = 6;
    const byte buttonPin2 = 7;
    unsigned int timer1Counter = 0;
    const unsigned long debouncerInterval = 50;
    const unsigned long oneSecond = 1000;
    unsigned long previousMillis = 0;

    Bounce debouncer = Bounce();
    Bounce debouncer2 = Bounce();

    void setup(){
      Serial.begin(9600);
      debouncer.attach(buttonPin1, INPUT_PULLUP);
      debouncer.interval(debouncerInterval);
      debouncer2.attach(buttonPin2, INPUT_PULLUP);
      debouncer2.interval(debouncerInterval);
      pinMode(led1Pin, OUTPUT);
    }

    void loop(){

      unsigned long currentMillis = millis();

      // 4 hour, 30 second timer.
      if((currentMillis - previousMillis >= oneSecond) && (timer1Active == 1)){
        previousMillis = currentMillis;
        timer1Counter++;
        if(timer1Counter < 31){
          //if(led1State == LOW){
            led1State = HIGH;
          //}
          //else{
            //led1State = LOW;
          //}
          digitalWrite(led1Pin, led1State);
        }
        else if(timer1Counter == 31){
          digitalWrite(led1Pin, LOW);
        }

        // 60 sec X 60 min X 4 hours + 30 seconds.
        if(timer1Counter > 14430){
          timer1Counter = 0;
        }
      }

      // Button 1
      if(debouncer.update()){
        if(debouncer.read() == 0){
          Serial.println("Start 30 second ON, 4 hour OFF timer.");
          timer1Active = 1;
          timer1Counter = 0;
        }
      }

      // Button 2
      if(debouncer2.update()){
        if(debouncer2.read() == 0){
          Serial.println("Start 1 minute ON, 4 hour OFF timer.");
          timer1Active = 0;
          digitalWrite(led1Pin, LOW);
        }
      }

    }

Based on this part of your last comment "I’ve a trick! ‘const unsigned long oneSecond = 1000;’ should be edited to ‘const unsigned long oneSecond = 10;’ this make the led be as a constant ON.", it sounds like you want the LED to remain ON constantly for the 30 or 60 seconds. I have "commented out" 5 lines of the above sketch that will make this happen.

  [1]: https://www.arduino.cc/en/tutorial/BlinkWithoutDelay


message:
RC-oscillator calibration in real time

This pesky watchdog RC oscillator is at the limit of its 10% tolerance already at room temperature. i was looking to bringing it to more like 5% (it stems from an internak 128 kHz RC oscillator) and the whole -40 ... 125 deg Celsius operating range. Can this reliably be done by reading the temperature of the MCU and applying an algorithm ? Any such working algorithm ?

The *calibration* is actually the adjusting of the number of cycles (of say, 125ms) the watchdog will run for. i.e. for 12.5 seconds I would run the watchdog timer 100 times, nominally. How do I temperature-compensate the 100 figure ?

body:
Your description is pretty detailed but you've missed to tell, which device you are talking about.

I assume you are talking about the ATmega 328P in an Arduino Uno.
AFAIK you can only calibrate the so called `Calibrated internal RC oscillator`, which is used for the main operations.
You cannot calibrate the `Internal 128kHz RC oscillator` from the watchdog.

I think you might have some overhead from your sleep/wake cycles.
Instead of sleeping 100 times to get from 125ms to 12.5s you could sleep for 8s + 4s + 0.5s. Thus sleeping only 3 times. Which might save you some battery life.


body:
We've been using the WDT delta as a temperature sensing method:

[https://thecavepearlproject.org/2019/02/25/no-parts-temperature-measurement-with-arduino-pro-mini-to-0-005c-or-better/][1]

Point being that once you have those calibration constants, you could use them use them to correct for WDT variation. OR you might be able to get away with a much shorter  interval than the 1sec we use, with the micros reading as your WDT correction factor more directly.

  [1]: https://thecavepearlproject.org/2019/02/25/no-parts-temperature-measurement-with-arduino-pro-mini-to-0-005c-or-better/


message:
Can I power a Wemos D1 R2 via the VIN and GND pins?

If so, at what voltage?

body:
[Wemos D1 R2][1] has on-board regulator with input from power jack and Vin pin. The regulator is for 9 to 24 V.

  [1]: https://wiki.wemos.cc/products:d1:d1#features


message:
My software serial code won't work at > 4800bps

I've put together a simple software serial (send-only) implementation for use on my attiny8[45] microcontrollers.  I realize that there are more efficient USI-based implementations out there; this was mostly an educational exercise.  The code uses TIMER0 in CTC mode to time the sending of bits on an available output pin.

It works fine from 300bps up to 4800bps, but anything faster than that just results in garbage.

The complete code is at the bottom of this answer.    The following settings all work correctly:

1. 4800bps

        #define BPS 4800
        #define SCALE_FLAG 1
        #define SCALE_VAL 1

1. 2400bps

        #define BPS 2400
        #define SCALE_FLAG 2
        #define SCALE_VAL 8

1. 1200bps

        #define BPS 1200
        #define SCALE_FLAG 2
        #define SCALE_VAL 8

1. 300bps

        #define BPS 300
        #define SCALE_FLAG 3
        #define SCALE_VAL 64

While this fails:

1. 9600bps

        #define BPS 9600
        #define SCALE_FLAG 1
        #define SCALE_VAL 1

Because everything other than 9600bps works I'm tempted to think that my code is correct, and yet I expect that I should be able to achieve 9600bps with these microcontrollers.

Are there any obvious bugs in this code? I think that's the most likely explanation, but after poking at this for a couple of days I'm not seeing it.

---

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/atomic.h>
    #include <string.h>

    #define BPS 9600
    #define SCALE_FLAG 1  // This is the value that goes in the TCCR0B register
    #define SCALE_VAL 1   // This is the divisor selected by SCALE_FLAG

    #define TXPORT PORTB
    #define TXDDR DDRB
    #define TXPIN PORTB0

    #define TICKS_PER_BIT (F_CPU/BPS/SCALE_VAL)
    #define mS_PER_BIT (1000000/BPS/1000)
    #define uS_PER_BIT ((1000000 / BPS) - (1000 * mS_PER_BIT))

    typedef struct SERIAL_PORT {
        uint8_t data;
        uint8_t index;
        uint8_t busy;
    } SERIAL_PORT;

    void millis_init();
    uint32_t millis();

    void serial_init();
    void serial_putchar(char c);
    void serial_print(char *s);
    void serial_println(char *s);
    void delay(uint32_t m);

    volatile SERIAL_PORT port;
    volatile uint32_t _millis,
             _micros = 1000;

    int main() {
        millis_init();
        serial_init();
        while (1) {
            serial_println("hello world");
            delay(500);
        }
    }

    void delay(uint32_t m) {
        uint32_t t_start = millis();
        while (millis() - t_start < m);
    }

    void millis_init() {
        ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
            _millis = 0;
        }
    }

    uint32_t millis() {
        uint32_t x;
        ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
          x = _millis;
        }
        return x;
    }

    void serial_init() {
        DDRB |= 1<<TXPIN;       // Set TXPIN as an output
        TXPORT |= 1<<TXPIN;     // Set TXPIN high (serial idle)
        TCCR0A = 1<<WGM01;      // Select CTC mode
        TCCR0B = SCALE_FLAG;    // Set clock scaler
        OCR0A = TICKS_PER_BIT;  // Set CTC target value
        TIMSK0 |= 1<<OCIE0A;    // Enable compare match interrupt
        sei();
    }

    void serial_putchar(char c) {
        while (port.busy);
        port.data = c;
        port.index = 0;
        port.busy = 1;
    }

    void serial_print(char *s) {
        while (*s) serial_putchar(*s++);
    }

    void serial_println(char *s) {
        serial_print(s);
        serial_putchar('\r');
        serial_putchar('\n');
    }

    ISR(TIM0_COMPA_vect) {
        if (port.busy) {
            switch(port.index) {
                case 0:
                    // send start bit
                    TXPORT &= ~(1<<TXPIN);
                    break;
                case 9:
                    // send stop bit
                    TXPORT |= (1<<TXPIN);
                    port.busy = 0;
                    break;
                default:
                    // send data bit
                    if (port.data & 1) {
                        TXPORT |= 1<<TXPIN;
                    } else {
                        TXPORT &= ~(1<<TXPIN);
                    }
                    port.data >>= 1;
                    break;
            }
            port.index++;
        }

        _millis += mS_PER_BIT;

        if (uS_PER_BIT > _micros) {
            _millis++;
            _micros = 1000;
        } else {
            _micros -= uS_PER_BIT;
        }
    }

body:
At 1MHz and 9600 baud, you have a total of 104 clock cycles available to run your interrupt routine in.  A quick count up of the assembly instructions generated comes to more than that (around 126 at first glance), so you can't fit it into the time.

As a result, your baud rate will actually be lower than 9600, and the chip will be completely starved of clock cycles for doing anything in your main loop.


message:
Find vehicle movement by IMU and GPS

I'm using `MPU9250` which has both accelerometer and gyroscope in a vehicle. What I want is to just know that if the vehicle is currently moving or not. I searched and find out that I can't get velocity easily so I skipped that but I was wondering how can I found movement with an IMU.

Edit:
As @Duncan said, it seems that it cannot be examined with only IMU. I also have a GPS sensor in my device and having the speed value from GPS but it is not very accurate. For example, if the vehicle is stopped for 5 minutes I get variable speeds between 0 to 10.0 kmph and on the other hand getting the location as lat/long has about 20 meters error. So I can't really rely on it. I was wondering can I combine both GPS and IMU to find out if it is really moving or not?
One solution that I came was relying on GPS speed but for spikes just check the accelerometer variations and if it is beyond a threshold, it means that it actually moved.

body:
You noted that your goal is to determine whether or not a vehicle is in motion. Because you are trying an IMU, I assume the device that needs to know this is on-board the vehicle.

There are many complicated ways to know this, such as using the acceleration data from the IMU to perform [Inertial Dead Reckoning][1], this has the problem of temporal drift. A GPS has the issue of needing it's speed data to be filtered a bit to get rid of high-speed spikes.

But -- if you just need to know if the vehicle is moving or not, and if the vehicle has wheels, you can use an light detector, such as an IR emitter and IR receiver pair, along with a slitted disc attached to the wheel, and simply count when the last time the receiver was activated -- if beyond some threshold of time, then you assume the wheel is not turning, and thus that the vehicle is not moving. Or perhaps just use a light sensor and paint white and dark patterns on the wheel.

Or put a magnet on the wheel and place a hall effect sensor (magnet sensor) near where the magnet will pass. Count the pulses from the hall effect sensor.

If the vehicle is not a wheel-based vehicle, then you may have to rely on GPS or some other method, however.

  [1]: https://en.wikipedia.org/wiki/Inertial_navigation_system


message:
Arduino SIM5320e HTTP GET request to 000webhost.com

Im having trouble getting a successful HTTP GET request to a domain under [000webhost.com][1]

I am trying to do a GET request which sends data to a php file on my domain and save it to MySQL database. I also did this first on my browser and it works fine so I don't think there are problem in my php file.

**MY DOMAIN:** ***wastedb.000webhostapp.com***

But if I try to send a request to [dweet.io][2], it works as expected.

I am using a modified version of Adafruit_FONA library and will post the code snippet and response from serial monitor below.

Here are the parameters that I used for the ***WORKING*** GET request:

**Host Address:** *www.dweet.io*

**Host:** *dweet.io*

**Response from Serial monitor for dweet.io (working):**

    ---> AT+CHTTPSSTART
    <--- OK
    ---> AT+CHTTPSOPSE="www.dweet.io",80,1
    <--- OK
    ---> AT+CHTTPSSEND=64
    <--- >
    ---> GET /dweet/for/gearhead?hello=world HTTP/1.1
    Host: dweet.io

    <--- OK
    ---> AT+CHTTPSSEND
    <--- OK
    <--- +CHTTPSSEND: 0
    ---> AT+CHTTPSRECV?
    <--- +CHTTPSRECV: LEN,361
    ---> AT+CHTTPSRECV=361
    <--- OK
    +CHTTPSRECV: DATA,361
    HTTP/1.1 200 OK
    Access-Control-Allow-Origin: *
    Date: Wed, 30 Jan 2019 00:16:43 GMT
    Connection: keep-alive
    Content-Length: 196

    {"this":"succeeded","by":"dweeting","the":"dweet","with":{"thing
    ---> AT+CHTTPSCLSE
    <--- OK
    ---> AT+CHTTPSSTOP
    <--- OK

As we can see, the Arduino received a JSON response from the website.

Here are the parameters that I used for the ***NOT WORKING*** GET request:

**Host Address:** *wastedb.000webhostapp.com*

**Host:** *wastedb.000webhostapp.com*

**Response from Serial monitor for wastedb.000webhostapp.com (NOT WORKING):**

    ---> AT+CHTTPSSTART
    <--- OK
    ---> AT+CHTTPSOPSE="wastedb.000webhostapp.com",80,1
    <--- OK
    ---> AT+CHTTPSSEND=113
    <--- >
    ---> GET /wastedb/get_location.php?lat=14.640155&lon=120.974920&stat=LOW HTTP/1.1
    Host: wastedb.000webhostapp.com

    <--- OK
    ---> AT+CHTTPSSEND
    <--- ERROR

Am I missing something here? Seems like the shield cannot find the Host Server I provided for my website.

***EDIT:*** It is working now. The only solution that worked for me is to find another [hosting site][3].

  [1]: http://000webhost.com
  [2]: http://dweet.io
  [3]: https://hostbuddy.com

body:
Try just using IP address for the Host line instead. I did the same thing for POST and it works fine for me.

Example:

Host: 13.xxx.xx.xx

[![sucessful POST][1]][1]

  [1]: https://i.stack.imgur.com/Ilxn2.png