message:
ESP8266 module doesn't respond to commands and sends garbage to serial on boot

I bought a ESP8266 module (like [this][1]).
I connected the module like on the following scheme:
[![scheme][2]][2]

I use a USB to TTL converter (cp2102) that I've connected to RX&TX pins of the module. It works. It successfully transmits data in both ways when I test it with a MCU. I often use it to send debug messages to my PC from a MCU.

I use linux and CuteCom as a program for monitoring the data sent through the serial port.

I supply 3.3V to the module (as required by the manufacturer) from the cp2102 converter (it has both 5V and 3.3V outputs).

**The problem**

The module does not respond to any command I send to it (AT, AT+GMR, AT+RST, ATE0, etc).
But it sends to the PC some data on boot (when I attach Vcc to CP_PD). Most of the data look like garbage, but at the very end I get meaningful data:

    Ai-Thinker Technology Co.,Ltd.

    invalid

The baud rate is 115200. No parity, 8-bit characters, 1 stop bit.
The full output from CuteCom:
[![data][3]][3]

The red LED on the module is always lightning while the power is supplied.
During the boot process (approximately first 500 milliseconds) also a blue LED blinks a few times (probably due to sending that mostly-garbage data to the PC I mentioned earlier).

**What have I tried?**

I experimented with the resistor R1, tried: no resistor, 1k, 3k, 10k.
I also tried other baud rates (1200, 2400, 4800, 9600, 19200, 38400, 57600).
And tried using all the parity types, 2 stop bits and other character lengths.
Nothing helped.

Why the module does not respond to any command?
Hope for your help!
Thanks in advance!

  [1]: https://www.amazon.com/DIYmall-ESP8266-ESP-01S-Serial-Transceiver/dp/B00O34AGSU
  [2]: https://i.stack.imgur.com/tJDBx.png
  [3]: https://i.stack.imgur.com/rc8VT.png

body:
The [ESP8266 bootloader outputs messages at that 74880 bits per second](https://docs.espressif.com/projects/esptool/en/latest/esp8266/esptool/serial-connection.html). At other speeds the bootloader's messages will look like garbage. Set your terminal speed to 74880 to see them.

On the ESP8266 it can be helpful to also use 74880 bits per second for the `Serial` speed in your program so that you can easily see both your programs output and the boot loader information when your program crashes.


sender: user

message:
How to reset flow control that prevents me from reading data from ESP8266?

I have a ESP8266 module (like [this][1]).
I ran a command `AT+UART_DEF=115200,8,1,0,3` as mentioned in documentation of ESP8266 SDK to change the baud rate of my ESP8266 module.
It seems like by running this command I bricked my ESP because now the module does not respond to any command (tried 9600, 74880, 115200 baud rates) and all the data that is sent after the bootloader messages on 74880 baud rate is garbage. The last argument of the above command sets the flow control to "both RTS and CTS" (3), but I don't have those pins.
The module's pinout:

[![pinout][1]][1]

So I suppose on my ESP I can't use hardware flow control. (Or I can?)

I still can receive bootloader's message that is sent on boot on baud rate 74880 bps:

    ets Jan  8 2013,rst cause:1, boot mode:(3,6)

    load 0x40100000, len 6960, room 16
    tail 0
    chksum 0x4f
    load 0x3ffe8008, len 24, room 8
    tail 0
    chksum 0xc6
    load 0x3ffe8020, len 3196, room 8
    tail 4
    chksum 0x3a
    csum 0x3a
    user code done

But all the data that is sent after the bootloader is garbage:
[![data][2]][2]

To clarify, before running the `AT+UART_DEF` command I could receive meaningful data and execute commands on baud rate 115200 bps.

I'm not sure if the command I ran is the problem, so please point me out if I'm wrong.
As per documentation:

    The configuration changes will be saved in the NVS area, and will still be valid when the chip is powered on
    again.

The new UART settings along with the flow control settings are stored in NVS area.
Is it possible to reset it? Or any other way to reset the flow control?

**What have I tried?**

I tried to erase all the flash memory of the module using `esptool`: `erase_region 0x0 0x1000000` and then tried to flash the latest AT firmware again. Didn't help. It still receives bootloader messages and some garbage data.

How can I unbrick my ESP?
Hope for your help! Thanks in advance!

  [1]: https://i.stack.imgur.com/Djlet.png
  [2]: https://i.stack.imgur.com/L2vV9.png

sender: assistant

body:
You can't brick an ESP8266 through software.

You can confirm this by flashing a different, very simple program to it, like this:

    #include <Arduino.h>

    void setup() {
      Serial.begin(74880);
      delay(1000);
      Serial.println("hello world");
    }

    loop() {
    }

With the serial monitor set to 74880 bits per second, you should see the bootloader messages as well as a single line of "hello world".

You also should completely erase the contents of the flash chip, not just a particular region.

    esptool.py erase_flash

Afterwards you'll need to reinstall the firmware you were trying to run.


message:
Slow WiFi reconnection after deep sleep (6 to 10 seconds)

With my ESP8266, I need to make a simple GET request to a server, and then go to deep sleep (the goal is 1 year battery powered)... until a signal comes on `RST` and then it starts again.

The following code works, but **it takes 6 to 10 seconds on each `RST` to get connected to my home WiFi using "WPA2 Personal"** (when it stops blinking in my code).

**Is this 6 to 10 seconds delay normal, do you have the same order of magnitude?** Or can we go down to 1 second, after a wake-up from deep sleep?

```
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266HTTPClient.h>
WiFiClient client;
HTTPClient http;
void setup() {
    pinMode(LED_BUILTIN, OUTPUT);
    if (WiFi.SSID() != WIFI_SSID) {     // don't do begin if not necessary, see tutorial link after
        WiFi.begin("MySSID", "MyPassword");
        WiFi.persistent(true);
        WiFi.setAutoConnect(true);
        WiFi.setAutoReconnect(true);
    }
    while(WiFi.status() != WL_CONNECTED) {
      digitalWrite(LED_BUILTIN, LOW); delay(10); digitalWrite(LED_BUILTIN, HIGH); delay(200);  // blinking
    }
    http.begin(client, "http://example.com/request.php");
    http.GET();
    http.end();
    digitalWrite(LED_BUILTIN, LOW); delay(500); digitalWrite(LED_BUILTIN, HIGH); delay(500);
    ESP.deepSleep(0);
}
void loop() {
}
```

Note: I have read and carefully respected this useful information about low power / battery-powered ESP8266:
 [Power Saving tips for the ESP8266](https://github.com/z2amiller/sensorboard/blob/master/PowerSaving.md)  (especially this [paragraph](https://github.com/z2amiller/sensorboard/blob/master/PowerSaving.md#do-not-call-wifibegin-in-setup)):

> Do not call WiFi.begin() in setup().
> The ESP8266 chip saves the last known wifi settings. Calling WiFi.begin() wipes those out. By calling WiFi.begin() only when it was needed, I shaved more than 2 seconds from the average amount of time it takes to associate with the AP. WiFi.begin() should be called only if the saved SSID does not match the configured SSID. You can check the configured SSID with the WiFi.SSID() call. Also, it is good practice to clear the saved WiFi settings if the timer expires. (See next section "Use watchdog timers")

body:
It is in general take around 6s for the ESP to scan all the 2.4GHz Wi-Fi channels to find the SSID and the associated BSSID (i.e. Mac Address), you can eliminate the scanning time by connecting using BSSID.

Using a static IP instead of rely on DHCP server to assign an IP would further reduce the WiFi connecting time by another 500ms.

See one of my [project](https://www.e-tinkers.com/2022/04/esp8266-ntp-clock-with-ntp-update-and-charlieplexing/) (under the "ESP8266 WiFi - How to speed up connection" section) where I cut the connection time from 6s down to about 2s.

Code signature for WiFi.begin with BSSID [here](https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.h#L38-L39):

```
    const byte WIFI_BSSID[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD, 0, WIFI_BSSID);
```

For calculating IoT battery consultion, use [IoT battery life calculator](https://www.of-things.de/battery-life-calculator.php).


message:
How do I wake the ESP8266 from deep sleep on a specific date and time?

I'd like to put my ESP8266 into deep sleep and then wake it up at at specific date and time, [roughly] to the second.

Edit: Unfortunately, ESP8266 deep sleep doesn't support values greater than about 3.5 hours. I tried sleeping for an hour at a time until the desired time is reached, but found that it's not very accurate; often dozens seconds of drift on each wake, adding up to many minutes of drift after several hours.

Edit: I want to wake every 24 hours at a specific time. A few seconds per week drift is more than acceptable, as I'll be re-syncing the clock every 24 hours or so.

Edit: I'm using `WAKE_RF_DISABLED` to disable WiFi to save power on wake, so when it wakes up, there is usually no internet connection to check the time (I want to connect to WiFi only once every 24h).

body:
Since the ESP8266 doesn't have a *[real][1]* onboard RTC (i.e. it's not capable of keeping very accurate time while in deep sleep) and is limited to a [short time period][2], one solution is to use an external RTC (real time clock) but there is a way of doing it without.

Below are 3 approaches, the first two involve a [DS3231][3] RTC (quite easy to get as a module). For low power, I prefer DS3231 over DS1307, since DS3231 modules seem to work fine at 2.6V (whereas DS1307 modules seem to require at least 3.3V... or more like 4.5V according to the [datasheet][4]). The 3rd approach is useful if you don't want to add an external RTC.

> "The DS3231 is a low-cost, extremely accurate I2C real-time clock (RTC)".
> The DS3231 "maintains the RTC to within ±2 minutes per year accuracy from -40°C to +85°C"

**Solution 1: Periodically wake the MCU and check the external RTC**

Probably, the most energy efficient solution (compared to using the alarm solution below) would be to wake the ESP8266 from deep sleep periodically to check the time on the external RTC and depending on desired accuracy, deep sleep for shorter periods as you approach the target wake time (e.g. wake and check the RTC every minute once you're about 10 mins away from the target time).

To save power, before sleeping the ESP8266, you can simply use a transistor connected to GPIO to turn off the Vcc power supply on the DS3231 module (it'll use the onboard 2032 battery while no power is supplied). Don't forget to turn off the I2C pull-ups too, as they can provide parasite power to the RTC. You can also just disconnect GND.

If restarted with WiFi off (`ESP.deepSleep(1e6, WAKE_RF_DISABLED)`), the ESP8266 only needs to wake for about 200 ms consuming 20 mA to check the DS3231 if it's time to wake up fully. This is probably the most energy efficient you can get with wanting to keep accurate time.

**Solution 2: Set an alarm on the external RTC to wake the MCU**

Using the DS3231, the SQW pin can be connected to the ESP8266 RST pin via a [monostable circuit][5]. The monostable circuit is important because the RST pin can't stay low, as it won't boot. The monostable circuit creates a pulse on the RST pin when the DS3231 SQW pin goes low.

A note on power consumption: The ESP8266 should consume only 20 µA in deep sleep, but DS3231 modules actually tend to use about **1 mA** when powered on (which is required to trigger the alarm), probably because of the EEPROM on the module. That power consumption is significant if you're designing a low power system. This is why this 2nd solution is less energy efficient compared to the 1st solution.

The following code will set an alarm to a specific time, and when the RST pin is pulled low (based on the SQW output of the DS3231), the ESP8266 then wakes up. Make sure you uncomment `SLEEP_DT` and set a date and time to wake at a specific date and time (of course, you can set this programmatically to any date and time), otherwise it'll wake up every *n* seconds (value of `SLEEP_SECONDS`) but that might also be useful (ESP8266 deep sleep time isn't very accurate).

    #include <ESP8266WiFi.h>

    // TODO: NTPClient is redundant; replace with native
    // ESP8266 NTP functions (configTime and localtime)
    #include <NTPClient.h>
    #include <WiFiUdp.h>

    #include <RTClib.h>

    #define WIFI_SSID "Your WiFi SSID"
    #define WIFI_PASS "Your WiFi password"

    // uncomment to wake up at specific date and time
    //#define SLEEP_DT
    #define SLEEP_DT_YEAR 2022
    #define SLEEP_DT_MONTH 12
    #define SLEEP_DT_DAY 02
    #define SLEEP_DT_HOUR 15
    #define SLEEP_DT_MINUTE 50
    #define SLEEP_DT_SECOND 25

    #define SLEEP_SECONDS 10 // easier for testing

    RTC_DS3231 rtc;
    WiFiUDP udp;
    NTPClient ntp(udp);

    void print_date(const DateTime& dt);

    void setup() {
      Serial.begin(9600);
      while (!Serial) { delay(1); }

      Serial.println('\n');
      Serial.println("Hello RTC wake deep sleep");

      Serial.println("Init DS3231");
      if(!rtc.begin()) {
        Serial.println("DS3231 failed");
        while (true) { delay(1); }
      }

      // not needed
      rtc.disable32K();

      // not used
      rtc.disableAlarm(2);

      // apparently can lead to problems if not cleared
      rtc.clearAlarm(1);
      rtc.clearAlarm(2);

      // stop oscillating; allows alarm to work
      rtc.writeSqwPinMode(DS3231_OFF);

      Serial.println("Init WiFi");
      WiFi.begin(WIFI_SSID, WIFI_PASS);

      Serial.println("Connecting to " WIFI_SSID);
      while (WiFi.status() != WL_CONNECTED) {
        delay(100);
      }
      Serial.print("Connected, IP: ");
      Serial.println(WiFi.localIP());

      ntp.begin();
      bool ntpOk = ntp.update();

      if (rtc.lostPower()) {
        Serial.println("RTC lost power, setting time");
        if (ntpOk) {
          Serial.println("Using time from NTP client");
          rtc.adjust(DateTime(ntp.getEpochTime()));
        }
        else {
          // untested code
          Serial.println("NTP unavailable, using time of build");
          rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
        }
      }

      Serial.print("Date and time set to: ");
      print_datetime(rtc.now());

    #ifdef SLEEP_DT

      DateTime alarm(
        SLEEP_DT_YEAR,
        SLEEP_DT_MONTH,
        SLEEP_DT_DAY,
        SLEEP_DT_HOUR,
        SLEEP_DT_MINUTE,
        SLEEP_DT_SECOND);

      Serial.print("Setting alarm for date: ");
      print_datetime(alarm);

      if (!rtc.setAlarm1(alarm, DS3231_A1_Date)) {
        Serial.println("Failed to set alarm");
      }

    #else

      // sleep for set seconds for the purposes of testing
      Serial.print("Setting alarm for seconds: ");
      Serial.print(SLEEP_SECONDS);
      Serial.println(" seconds");
      if (!rtc.setAlarm1(rtc.now() + TimeSpan(SLEEP_SECONDS), DS3231_A1_Second)) {
        Serial.println("Failed to set alarm");
      }

    #endif // SLEEP_DT

      Serial.println("Going into deep sleep (wake on RST low)");
      Serial.flush();
      ESP.deepSleep(0);
    }

    void print_datetime(const DateTime& dt) {
      char df[] = "YYYY-MM-DD hh:mm:ss";
      Serial.println(dt.toString(df));
    }

    void loop() { }

Here it is in action...

[![Arduino IDE and output][6]][6]

Note: The time jumps because I chopped out a few frames to save you from being bored (no smoke and mirrors, I promise).

**Solution 3: Use only the internal RTC**

Keeping with the low power theme: to use the internal RTC in deep sleep, you have to keep sleeping for *n* seconds until desired seconds elapse. You can keep track of how many seconds have elapsed by using the RTC memory. This approach allows you to implement time keeping without having to add an external RTC, and without having to reconnect connect to WiFi every hour. However, I have found the drift to be quite substantial (many seconds per hour), so this is probably useful only when accuracy is not a major concern.

  [1]: https://nodemcu.readthedocs.io/en/dev/modules/rtctime/
  [2]: https://nodemcu.readthedocs.io/en/dev/modules/rtctime/#rtctimedsleep
  [3]: https://datasheets.maximintegrated.com/en/ds/DS3231.pdf
  [4]: https://datasheets.maximintegrated.com/en/ds/DS1307.pdf
  [5]: https://electronics.stackexchange.com/a/644782/288848
  [6]: https://i.stack.imgur.com/fYn3g.gif


message:
What is the best (fastest and most robust) way to send messages back and forth between Python on a PC and an Arduino, over serial?

I am trying to communicate between a PC running Python using PySerial and an Arduino. The Arduino itself has a CAN shield, and is responsible for interfacing with a motor. My goal is for the PC to construct the desired CAN frame (8 bytes), send it over Serial to the Arduino, which then itself uses a CAN library to speak to the motor. The motor then send a return frame of the same size, which the Arduino copies to an array, and also prints it to serial.

This works in some cases, although I'm struggling to make it robust. As an example, I am driving the motor in torque control mode (Command 37 in [this datasheet][1]). For an arbitrary forward torque of '50', the sending frame should be:

    [161, 0, 0, 0, 50, 0, 0, 0]

And for a command of '-50', the frame should be:

    [161, 0, 0, 0, 206, 255, 255, 255]

I didn't appreciate this would be an issue, but my guess is that because this actually requires more characters, it takes longer to send. Positive torque commands are sent with no issues, while the negative ones cause the motor to skip or judder. I can see that the Arduino isn't actually receiving the correct command at times, see below (left is sent frame from Python, and right is what the Arduino receives printed straight back).

[![Left is desired and sent frame, right is what the Arduino gets.][2]][2]

I have tried:

 1. Flushing serial buffers before and after sending messages, on both devices
 2. Adding delays to try and slow the communication down
 3. Changing baudrates
 4. Trying to use Serial.write() instead of Serial.print() as I assumed it might be faster (?)

I have attached my code below, but in general, ***what is the best way to communicate over serial between Python and Arduino, robustly and quickly? Even if my current application is ignored, what might ideal scripts for each look like?***

Python:

```
    def serial_begin(self, baud, com):
        self.ser = serial.Serial(com, baud)
        self.ser.flushInput()
        self.ser.flushOutput()
        print("Connected to Serial Port " + com)
        t.sleep(1)

    def send_cam_frame(self, frame):

        self.send_frame = frame
        string_to_send = "<" + str(int(frame[0])) + "," + \
                         str(int(frame[1])) + "," + \
                         str(int(frame[2])) + "," + \
                         str(int(frame[3])) + "," + \
                         str(int(frame[4])) + "," + \
                         str(int(frame[5])) + "," + \
                         str(int(frame[6])) + "," + \
                         str(int(frame[7])) + ">"

        self.ser.write(string_to_send.encode('UTF-8'))
        self.receive_can_frame()

    def receive_can_frame(self):
        get_data = self.ser.readline().decode('UTF-8', errors='ignore')[0:][:-2]
        self.receive_frame = np.fromstring(get_data, dtype='int', count=8, sep=' ')

    def set_torque(self, torque):

        self.command = self.command_list["SET_TORQUE"]

        torque = int(self.constrain(torque * 2000 / 32, -2000, 2000))
        frame = [self.command, 0, 0, 0, torque & 0xFF, (torque >> 8) & 0xFF, (torque >> 16) & 0xFF,
                 (torque >> 24) & 0xFF]
        self.send_cam_frame(frame)

def main():

    arduino_port = "COM5"  # Default COM port
    baud_rate = 57600  # Default Baud Rate

    rmd = Motor()
    rmd.serial_begin(baud=baud_rate, com=arduino_port)

    set_torque = 0

    while True:
        try:

            if keyboard.is_pressed('w'):
                set_torque += 0.001
            if keyboard.is_pressed('s'):
                set_torque -= 0.001

            rmd.set_torque(set_torque)

        except KeyboardInterrupt:
            rmd.disable_motor()
            print("Keyboard Interrupt")

```

Arduino:

```

byte recvFrame[8] = {0, 0, 0, 0, 0, 0, 0, 0};
byte sendFrame[8] = {0, 0, 0, 0, 0, 0, 0, 0};

// Serial Read Parameters
const byte numChars = 32;  // Length of received char array from Serial
char receivedChars[numChars];  // Received char array from Serial
char tempChars[numChars];        // Temporary array for use when parsing
bool newData = false;  // Flag to check if newData has been received

void setup() {
  Serial.begin(57600);
  delay(1000);

}

void loop() {

  CANMessage frame;

  frame.id = 0x140 + 1;
  frame.len = 8;

  // Do not touch this section
  recvWithStartEndMarkers();  // Check Serial and receive data if there is newData
  if (newData == true) {
      strcpy(tempChars, receivedChars);  // Copy variables to prevent them being altered
      parseData();  // Parse data (split where there are commas)

      for (int i = 0; i  < 8; i++){
        frame.data[i] = sendFrame[i];
      }

      can.tryToSend(frame);

      newData = false;  // Set to false
  }

  if (can.available()){
    can.receive(frame);
  }

  for (int i = 0; i < 8; i++){
    recvFrame[i] = frame.data[i];
  }

  printFrame();

}

// Do not touch this function
void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

// Only touch this function if more data is being sent from Python code
void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars,",");
    sendFrame[0] = atoi(strtokIndx);

    strtokIndx = strtok(NULL,",");
    sendFrame[1] = atoi(strtokIndx);

    strtokIndx = strtok(NULL,",");
    sendFrame[2] = atoi(strtokIndx);

    strtokIndx = strtok(NULL,",");
    sendFrame[3] = atoi(strtokIndx);

    strtokIndx = strtok(NULL,",");
    sendFrame[4] = atoi(strtokIndx);

    strtokIndx = strtok(NULL,",");
    sendFrame[5] = atoi(strtokIndx);

    strtokIndx = strtok(NULL,",");
    sendFrame[6] = atoi(strtokIndx);

    strtokIndx = strtok(NULL, ",");
    sendFrame[7] = atoi(strtokIndx);

    // How to add a new variable
    // Currently, data is sent as <0, 0, 0, 0>
    // If a fourth parameter was to be sent (<0, 0, 0, 0, 1>), the following lines need to be added

    // strtokIndx = strtok(NULL, ", "); This reads the string, from where it was previously cut, up until the next comma
    // newVariableName = atoi(strtokIndx); atoi is 'to integer'. If newVariable is a float, atof is needed etc

}

void printFrame(){

  for (int i = 0; i < 8; i++){
    Serial.print(sendFrame[i]);
    Serial.print(" ");
  }
  Serial.println();
  //Serial.write(sendFrame, 8);
  //delay(3);

}

```

N.B: I have removed some of the unnecessary functions from both scripts (e.g: the rest of the Motor class for the Python, and the CAN Shield setup from the Arduino) for clarity.

  [1]: https://cdn.robotshop.com/media/m/mya/rbc-mya-04/pdf/rmd_servo_motor_control_protocol.pdf
  [2]: https://i.stack.imgur.com/SeQos.png

body:
There is no best way, but there is a better way (and more efficient way).

>For an arbitrary forward torque of '50', the sending frame should be:
>
>[161, 0, 0, 0, 50, 0, 0, 0]
>
>And for a command of '-50', the frame should be:
>
>[161, 0, 0, 0, 206, 255, 255, 255]

Most of the programmers who are new to embedded program, prepare their data to be send via communication as string instead of sending raw binary data, the problem is that
1) to send a value of 215, you are sending 3 bytes of ASCII('2', '1', '5') while the data can actually sent by one single byte.
2) both integer 256 (`0x0100`) and 32766 (`0x7FFE`) only took up two bytes, but when you encode it as ASCII, you are dealing with various length from 3 chars to 5 chars. This not only take more bytes to send the data but also make parsing of the data more difficult unless you had some delimiter to separate the data, e.g. ("256,32766" separated by comma).

Looking at your data set and datasheet, it is clear that the each data point is represented by a 4-byte signed data with small [endian](https://en.wikipedia.org/wiki/Endianness) (i.e. the lower byte get send first), so decimal `50` is `0x00000032`, it is store in memory as `0x32, 0x00, 0x00, 0x00` with small endian.

A negative value is represented in [two's compliment](https://en.wikipedia.org/wiki/Two's_complement) of the positive value, so `-50` in decimal is `0xFFFFFFCE` and stored as `0xCE, 0xFF, 0xFF, 0xFF`.

In python, the [struct](https://docs.python.org/3/library/struct.html) library allows you to converts between Python values and C structs represented as Python bytes objects.

```python
form struct import *

torque = -50

data = pack('<i', torque) # pack torque as a 4-byte integer with little endian
ser.write(torque)         # send over serial as bytes
```

On the Arduino side, read the data from Serial as `byte`(i.e. `uint8_t`) and store it in an array. You can then convert it back to a `int32`.

```c++
// assuming you had read these 4 bytes of data from Serial and add them into an array
uint8_t data[4]{0xCE, 0xFF, 0xFF, 0xFF};

// Convert received data bytes to int32_t
int32_t torque = static_cast<int32_t> (data[3]<< 24 | data[2] << 16 | data[1] << 8 | data[0]);

// This will return result of -50
Serial.println(torque);
```

This should reduce the code and improve the efficiency of the sending the data significantly.

The code along however does not improve the reliability, one advantage of sending data as string is that you could determine the end of data stream by detecting the `\0` terminator at end of the string. When sending raw binary, ideally you need to have the mechanism to signify the number of bytes the data of bytes that you are going to send over.


message:
Need help ATtiny85 not working as standalone

I have ATTiny85 that I want to drive a servo. Burned bootloader to the ATTiny85 and I am using HW-260 development board to program and to test the code. While the ATTiny85 works perfectly on the HW-260 development board, I cant get it to work as a standalone on a breadboard when testing with the servo by using the Adafruit_SoftServo library and with the blink example. Tried adding 4.7kOhm pull-up resistor to PB5 to prevent the ATTiny85 from resetting but I get the same result. Tried powering the standalone layout with 3V coin cell, USB 5V, powerbank 5V and nothing. This is the servo code I am using:

    Adafruit_SoftServo myservo;
    int pos = 0;
    void setup() {
      myservo.attach(PB0);
    }
    void loop() {
      for (pos = 0; pos <= 180; pos += 1) {
        myservo.write(pos);
        myservo.refresh();
        delay(15);
      }
      for (pos = 180; pos >= 0; pos -= 1) {
        myservo.write(pos);
        myservo.refresh();
        delay(15);
      }
    }

The blink code I am using is from the examples, I just change the output pin as PB1. If I connect the PB5 briefly to ground, I get the servo to turn a bit in random direction. Measured and the breadboard is not the problem, everything seems to be connected correctly.

This is the bootloader I used https://github.com/ashishchoudhary9998/ATtiny85-Boot-loader

**Edit:**
This is the schematic of the HW-260 board
[![enter image description here][1]][1]

This is my layout
[![enter image description here][2]][2]

  [1]: https://i.stack.imgur.com/iujqu.png
  [2]: https://i.stack.imgur.com/K2nIH.png

body:
After adding the schematics, a difference can be spotted:

PB3 needs a pull-up, on the development board it has 1,5 kΩ. This resistor is part of the [USB standard][1] and signals "low speed device". Presumably (because the source of it is not provided) the bootloader needs this to start at all, too.

The delay mentioned in a comment is typical for ATtiny85 development. Because of the low number of pins, the bootloader starts and waits for some seconds for a PC to connect. If no connection is established, the user program is started. It can then use all pins for its own purposes.

  [1]: https://en.wikipedia.org/wiki/USB_(Communications)#Line_transition_state


message:
IsTimeSet library - Assign variables

i get the current time with the example code istimneforset, everything works fine.

now i want to get the current time from the function "Serial.println(timeClient.getFormattedTime());" and i am trying to cache the first character of the array.

code:

    #include <NTPClient.h>
    // Change the next line to use with a different map/shield
    #include <ESP8266WiFi.h>
    //#include <WiFi.h> // for WiFi shield
    //#include <WiFi101.h> // for WiFi 101 shield or MKR1000
    #include <WiFiUdp.h>

    const char *ssid =" *";
    const char *password = "*";

    WiFiUDP ntpUDP;
    // initialized to a time offset of 10 hours
    NTPClient timeClient(ntpUDP, "pool.ntp.org", 36000, 60000);
    // HH:MM:SS
    // timeClient is initialized to 10:00:00 if it does not receive an NTP packet
    // before the timeout of 100ms is received.
    // Without isTimeSet(), the LED would be lit even though the time was
    // was not yet set correctly.

    const int hour = 10;
    const int minute = 0;

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

      WiFi.begin(ssid, password);

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

      timeClient.begin();
    }

    void loop() {
      timeClient.update();

     //Serial.println(timeClient.getFormattedTime());

     int stund2  = (timeClient.getFormattedTime()[0]);

    Serial.println(stund2);

    }

unfortunately it always gives me a wrong value. my goal is to have the current hour in a variable. can someone help me? thanks!

body:
There are a number of post in threads [here][1] and [here][2] that suggest using the NTPClient [here][3].

Also, if we inspect that [GIT repository's copy of NTPClient.cpp][4] starting a line 155 we see the function for getFormattedTime():

    String NTPClient::getFormattedTime(unsigned long secs) {
      unsigned long rawTime = secs ? secs : this->getEpochTime();
      unsigned long hours = (rawTime % 86400L) / 3600;
      String hoursStr = hours < 10 ? "0" + String(hours) : String(hours);

      unsigned long minutes = (rawTime % 3600) / 60;
      String minuteStr = minutes < 10 ? "0" + String(minutes) : String(minutes);

      unsigned long seconds = rawTime % 60;
      String secondStr = seconds < 10 ? "0" + String(seconds) : String(seconds);

      return hoursStr + ":" + minuteStr + ":" + secondStr;
    }

...we see that this function returns a String resembling "hh:mm:ss" where hh is hours, mm is minutes and ss is seconds.

To extract only hours we would have to "cut" the string or parse the string using the ":" character, use only the "hh" portion of the string and convert that back into a number.

This is complex.  Instead, consider using the function getHours():

    int NTPClient::getHours() {
      return ((this->getEpochTime()  % 86400L) / 3600);
    }

... this uses the epoch time after taking off the date (modulo 86400) and taking off the minutes and seconds (divide by 3600) leaving only the hours.

  [1]: https://randomnerdtutorials.com/esp32-ntp-client-date-time-arduino-ide/
  [2]: https://rntlab.com/question/ntpclient/
  [3]: https://github.com/taranais/NTPClient
  [4]: https://github.com/taranais/NTPClient/blob/master/NTPClient.cpp


body:
While st2000 gave a good answer about how to do it instead, I wanted to explain what actually went wrong with your first solution.

You are seeing the difference between binary and ASCII encoded data. Using `timeClient.getFormattedTime()` will give you an ASCII encoded string. Such a string is an array of `char`s, each one representing one character (according to the ASCII table) until the string gets terminated with the null character `\0`.

You are taking the first character and assign it to an integer variable. The value will be directly copied into that variable. But the first element in that `char` array is the ASCII digit `0`, which is the equivalent of decimal `48`. And that is what you get from your code. Also the hour field of that string is 2 characters wide, so you need to read both of them, not just the first character.

If you want to extract numbers from a string, you cannot just assign them. You need to parse the data correctly. For that you would tokenize the string (split it in individual parts with data) (for example with `strtok()`) and then parse each token with a corresponding function. To parse an integer value from a string you can use `atoi()`. This function will read the string, until a non-digit character appears, and convert that to an integer.

So - since we are only interested into the first number/token in that string, you can leave out the tokenizing and just parse that string (since after the number of hours there is always the `:` character, which is a non-digit character):

    int stund2 = atoi(timeClient.getFormattedTime());

I have not tested this, but it should also work, though not that efficient as the solution of st2000, since parsing string data is commonly more complex than working directly with integer numbers.


message:
Run encoder code simultaneously with other code in Arduino

volatile unsigned int temp, counter = 0;
    int county=0;
    void setup()
    {

      Serial.begin(9600);
      pinMode(2, INPUT_PULLUP);
      pinMode(3, INPUT_PULLUP);
      attachInterrupt(0, ai0, RISING);
      attachInterrupt(1, ai1, RISING);
    }

    void loop()
    {
      county= (counter);
      if (counter>2000){
    county=0;
      }
      temp = counter;

      Serial.println(county); // Encoder step counter

    }

      void ai0() {if(digitalRead(3)==LOW) {counter++;}else{counter--;}}
      void ai1() {if(digitalRead(2)==LOW) {counter--;}else{counter++;}}

Dear all, **above arduino code is used for encoder as counter** and **code is quoted** from [here][1], the above simple code works fine. However, if I were to **add some code lines below the `Serial.println(county);`which actually delays execution time**, the counter will actually **skip steps and mess up the counter** which I am very dissapointed.

May I ask how to solve this issue, my thought is can arduino actually run 2 void loop simultaneously so that the c**ounter code can be run simultaneously and not be affected by other code lines which introduces delay time that mess up the counter**. Any help will be appreciated :)

    volatile unsigned int temp, counter = 0;
    void setup()
    {

      Serial.begin(9600);   pinMode(2, INPUT_PULLUP); pinMode(3, INPUT_PULLUP); attachInterrupt(0, ai0, RISING);attachInterrupt(1, ai1, RISING);
    }

    void loop()
    {
    noInterrupts();
    unsigned int county = counter;
    interrupts();

      if (counter>2000){county=0;}

      Serial.println(county); // Encoder step counter

    }

      void ai0() {if(digitalRead(3)==LOW) {counter++;}else{counter--;}}
      void ai1() {if(digitalRead(2)==LOW) {counter--;}else{counter++;}}

**PID code**

    #include <PID_v1.h>
    double Setpoint ;  double Input; double Output ;
    volatile unsigned int temp, counterrr = 0;
    int county=0;

    double Kp=0, Ki=2, Kd=0;
    PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

    void setup()
    {

      Serial.begin(9600);
      Setpoint = 120;
      myPID.SetMode(AUTOMATIC);
      myPID.SetTunings(Kp, Ki, Kd);
      pinMode(2, INPUT_PULLUP);
      pinMode(3, INPUT_PULLUP);
      attachInterrupt(0, ai0, RISING);
      attachInterrupt(1, ai1, RISING);
    }

    void loop()
    {

    }

      void ai0() {
        if(digitalRead(3)==LOW) {
        counterrr++;}
        else{
          counterrr--;}

            county= (counterrr);
      Serial.println(county);
      Input = map(county, 0, 1024, 0, 1200);  // photo senor is set on analog pin 5
      myPID.Compute();
      analogWrite(9,Output);
      Serial.print(Input);
      }
      void ai1() {
        if(digitalRead(2)==LOW) {
          counterrr--;}
          else{
            counterrr++;
            }

              county= (counterrr);
      Serial.println(county);
      Input = map(county, 0, 1024, 0, 1200);  // photo senor is set on analog pin 5
      myPID.Compute();
      analogWrite(9,Output);
      Serial.print(Input);
            }

  [1]: https://www.youtube.com/watch?v=QE4IQlwOgiA&t=42s&ab_channel=MakerTutor

body:
> can arduino actually run 2 void loop simultaneously

No, it cannot. All AVR based Arduinos (like Uno, Nano, Mega) have only one core, thus they can only execute one thing at a time.

The typical way to go is to just not introduce delays and divide up complex things into smaller parts. That way you can rapidly switch between different parts of the code, without blocking for a longer time. For humans it will then seem as if the parts are executed simultaneously, though they are actually executed successively.

To do timed things, you would use the non-blocking coding style from the `BlinkWithoutDelay` example, that comes with the Arduino IDE. It uses the `millis()` function as a stop watch, on each loop iteration checking if enough time has passed since the last execution and executing again only if enough time passed. Much like you wouldn't bake a pizza and sitting in front of the oven until it is ready. You would regularly look at your clock to check, if enough time passed, doing other things in between.

---

That said, you changed the code after copying and mangled it in a weird way, so that it doesn't make much sense. Also the original code is not interrupt-safe.

The code in `loop()` has to do an atomic access to the volatile variable `counter`. This is to prevent the variable from changing in between reading it. Reading a single-byte variable (like one of type `byte`) is always atomic and cannot be interrupted, since this is one instruction, that will be finished before calling any interrupt service function (ISR). But `unsigned int` is 2 bytes big. So in rare cases the following might happen:

- First byte gets read from volatile variable into the non-volatile variable
- the ISR triggers and changes the volatile variable
- Second byte (which is now changed) gets read into the non-volatile variable

This can lead to occasionally corrupt data.

The typical way to do this is to temporarily disable interrupts, copy the volatile variable to a local variable and then enable interrupts again. Then you can use the local variable as a snapshot of the volatile variable without corrupting the data.

    noInterrupts();
    unsigned int local_counter = counter;
    interrupts();
    if(local_counter > 2000)
        ...

For your code you should also use the same mechanism as in the original code and only send the value over serial, if it really changed. Otherwise you will spam your serial connection, which automatically will slow down your code (since you are filling up the serial buffer faster, than it is send out, so that further calls to `Serial.println()` will block until enough space is available in the buffer).


message:
What is the ideal way to check if time on ESP8266 via NTP is ready?

With ESP8266, I noticed that for the first 1 or 2 loops, `localtime` returns Unix epoch (1970 date) until it has finished getting the actual time from NTP, after which point I see the real date. Sometimes it can take 10 seconds or so before NTP is available, depending on what time server I use and how frequently I make requests to it (most time servers have request throttling, it seems).

Right now, I'm checking whether the date is valid by testing if the year is `70` but this seems weird and hacky. Is there a better way? For instance, is there a function that returns `true` if the NTP update has been successful or `-1` if not?

All of the examples of `localtime` that I have found so far don't seem to check if the date is valid, and if I run their code, it almost always prints the 1970 Unix epoch date on the first loop.

```
#define TIME_SERVER_1 "time.google.com"
#define TIME_SERVER_2 "time.nist.gov"
#define TIME_SERVER_3 "pool.ntp.org"
#define TIMEZONE TZ_Europe_London

void setup() {

// ..

  configTime(TIMEZONE, TIME_SERVER_1, TIME_SERVER_2, TIME_SERVER_3);

// ..

}

void loop() {

// ..

      time_t now;
      time(&now);
      struct tm* timeinfo = localtime(&now);

      // TODO: maybe there's a better way to check unknown time?
      if (timeinfo->tm_year == 70) {
        TRACE_LN(F("ntp not yet available"));
      } else {
        epoch = mktime(timeinfo);
      }

//..

}
```

body:
If `time()` doesn't return `-1` as expected when it doesn't know, then I
have nothing cleaner (less “hacky”) to suggest. That being said,
converting the scalar time to a broken-down representation is a
relatively expensive operation. I suggest avoiding it and just comparing
the returned time to an arbitrary threshold:

```c++
// May we consider this valid as the "current" time?
// If it is too far in the past, it is centainly not valid.
static bool is_time_valid(time_t t) {
    const time_t old_past = 1577836800;  // 2020-01-01T00:00:00Z
    return t >= old_past;
}
```


body:
You can define a call back function which is triggered when SNTP updates the system time. There is an example of it on the [GitHub esp8266/Arduino project][1] with a short description in the comments. The call back function is registered by the example function call `settimeofday_cb(time_is_set)` where time_is_set() is a user defined funtion.

I have an application (a timeswitch) which maintains an indicator to show how 'fresh' the current time status is. If it is stale, the time source reverts to an RTC until a new time can be fetched. It uses this callback mechanism for that purpose.

  [1]: https://github.com/esp8266/Arduino/blob/da48a52d7a8854363946fe0c05f02ec029c852c5/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino#L241


body:
The following code snippet is most likely the best way of ensuring valid time from NTP. If the call to timeSetup(...) is made after already connected to the internet, then that connection will be used, otherwise the setup will connect to internet, using passed in credetials, and when finished getting NTP time, will disconnect. The code has been cut/pasted from a much bigger project and has not been tested, so there might be some syntax errors.

**The SNTP stuff:**

    #include "sntp.h"
    #include "time.h"
    #include <sys/time.h>
    #include <WiFi.h>

    int WiFiconnectedhere = 0;
    int timeIsSet = 0;

    // timeavailable() cannot be in a class has to be static
    //callback function when time has been set
    void timeavailable(struct timeval *t)
    {
      struct tm timeinfo;
      Serial.println("NTP notification that time is set");

      if (!getLocalTime(&timeinfo)){
        Serial.println("Using getLocalTime()No time available (yet)");
        return;
      }
      Serial.println(&timeinfo, "using getLocalTime() = %A, %B %d %Y   H:%M:%S");

      if (WiFiconnectedhere == 1) {
        WiFi.disconnect(true, true);  //WiFi off, erase AP
        WiFiconnectedhere = 0;
        Serial.println("WiFi has been disconnected");
      }
      timeIsSet = 1;
    }

    void ESP32Time::timeSetup(
        char *ssid,
        char *password,
        char *ntpServer1,
        char *ntpServer2,
        char *timezone)
    {
      timeIsSet = 0;
      //connect to WiFi if not already connected
      if (! WiFi.isConnected()) {  //standard WiFi call to check if connected
        sntp_servermode_dhcp(1);    // (optional)
        Serial.printf("Connecting to %s in time module\r\n", ssid);
        WiFi.begin(ssid, password);
        while (WiFi.status() != WL_CONNECTED) {
            delay(500);
            Serial.print(".");
        }
        Serial.printf(" CONNECTED to internet %s\r\n", ssid);
        WiFiconnectedhere = 1; // so we know to disconnect after done with it
      }
      else {
        Serial.println("WiFi is already connected");
      }

      // get a callback when time has been received locally
      sntp_set_time_sync_notification_cb( timeavailable );

      configTzTime(timezone, ntpServer1, ntpServer2);
      Serial.println("Getting localtime");
      setenv("TZ", timezone, 1);
      tzset();

    }

**Usage**:

    ESP32Time esptime;  // Instantiate the class

In arduino setup()

    //initialise the time.
    esptime.timeSetup(ssid, password, ntpserver1, ntpserver2, timezone);

**Retrieve local time:**

      struct tm timeinfo;
      time_t now;
      time(&now);
      localtime_r(&now, &timeinfo);
      time_t tt = mktime (&timeinfo);

****The timezones in a program usable array (sorry it is so long):****

    #ifndef TZDB_H
    #define TZDB_H

    typedef struct {
      char tzlit[35];
      char tzzone[45];
    } tTimezones;

    #ifndef TZARRAY
    #define TZARRAY

    tTimezones tz[470] =
    {
    {"TZ_Africa_Abidjan ","GMT0"},
    {"TZ_Africa_Accra " , "GMT0"},
    {"TZ_Africa_Addis_Ababa ","EAT-3"},
    {"TZ_Africa_Algiers ","CET-1"},
    {"TZ_Africa_Asmara ","EAT-3"},
    {"TZ_Africa_Bamako ","GMT0"},
    {"TZ_Africa_Bangui ","WAT-1"},
    {"TZ_Africa_Banjul ","GMT0"},
    {"TZ_Africa_Bissau ","GMT0"},
    {"TZ_Africa_Blantyre ","CAT-2"},
    {"TZ_Africa_Brazzaville ","WAT-1"},
    {"TZ_Africa_Bujumbura ","CAT-2"},
    {"TZ_Africa_Cairo ","EET-2"},
    {"TZ_Africa_Casablanca ","<+01>-1"},
    {"TZ_Africa_Ceuta ","CET-1CEST,M3.5.0,M10.5.0/3"},
    {"TZ_Africa_Conakry ","GMT0"},
    {"TZ_Africa_Dakar ","GMT0"},
    {"TZ_Africa_Dar_es_Salaam ","EAT-3"},
    {"TZ_Africa_Djibouti ","EAT-3"},
    {"TZ_Africa_Douala ","WAT-1"},
    {"TZ_Africa_El_Aaiun ","<+01>-1"},
    {"TZ_Africa_Freetown ","GMT0"},
    {"TZ_Africa_Gaborone ","CAT-2"},
    {"TZ_Africa_Harare ","CAT-2"},
    {"TZ_Africa_Johannesburg ","SAST-2"},
    {"TZ_Africa_Juba ","CAT-2"},
    {"TZ_Africa_Kampala ","EAT-3"},
    {"TZ_Africa_Khartoum ","CAT-2"},
    {"TZ_Africa_Kigali ","CAT-2"},
    {"TZ_Africa_Kinshasa ","WAT-1"},
    {"TZ_Africa_Lagos ","WAT-1"},
    {"TZ_Africa_Libreville ","WAT-1"},
    {"TZ_Africa_Lome ","GMT0"},
    {"TZ_Africa_Luanda ","WAT-1"},
    {"TZ_Africa_Lubumbashi ","CAT-2"},
    {"TZ_Africa_Lusaka ","CAT-2"},
    {"TZ_Africa_Malabo ","WAT-1"},
    {"TZ_Africa_Maputo ","CAT-2"},
    {"TZ_Africa_Maseru ","SAST-2"},
    {"TZ_Africa_Mbabane ","SAST-2"},
    {"TZ_Africa_Mogadishu ","EAT-3"},
    {"TZ_Africa_Monrovia ","GMT0"},
    {"TZ_Africa_Nairobi ","EAT-3"},
    {"TZ_Africa_Ndjamena ","WAT-1"},
    {"TZ_Africa_Niamey ","WAT-1"},
    {"TZ_Africa_Nouakchott ","GMT0"},
    {"TZ_Africa_Ouagadougou ","GMT0"},
    {"TZ_Africa_PortomNovo ","WAT-1"},
    {"TZ_Africa_Sao_Tome ","GMT0"},
    {"TZ_Africa_Tripoli ","EET-2"},
    {"TZ_Africa_Tunis ","CET-1"},
    {"TZ_Africa_Windhoek ","CAT-2"},
    {"TZ_America_Adak ","HST10HDT,M3.2.0,M11.1.0"},
    {"TZ_America_Anchorage ","AKST9AKDT,M3.2.0,M11.1.0"},
    {"TZ_America_Anguilla ","AST4"},
    {"TZ_America_Antigua ","AST4"},
    {"TZ_America_Araguaina ","<-03>3"},
    {"TZ_America_Argentina_Buenos_Aires ","<-03>3"},
    {"TZ_America_Argentina_Catamarca ","<-03>3"},
    {"TZ_America_Argentina_Cordoba ","<-03>3"},
    {"TZ_America_Argentina_Jujuy ","<-03>3"},
    {"TZ_America_Argentina_La_Rioja ","<-03>3"},
    {"TZ_America_Argentina_Mendoza ","<-03>3"},
    {"TZ_America_Argentina_Rio_Gallegos ","<-03>3"},
    {"TZ_America_Argentina_Salta ","<-03>3"},
    {"TZ_America_Argentina_San_Juan ","<-03>3"},
    {"TZ_America_Argentina_San_Luis ","<-03>3"},
    {"TZ_America_Argentina_Tucuman ","<-03>3"},
    {"TZ_America_Argentina_Ushuaia ","<-03>3"},
    {"TZ_America_Aruba ","AST4"},
    {"TZ_America_Asuncion ","<-04>4<-03>,M10.1.0/0,M3.4.0/0"},
    {"TZ_America_Atikokan ","EST5"},
    {"TZ_America_Bahia ","<-03>3"},
    {"TZ_America_Bahia_Banderas ","CST6"},
    {"TZ_America_Barbados ","AST4"},
    {"TZ_America_Belem ","<-03>3"},
    {"TZ_America_Belize ","CST6"},
    {"TZ_America_BlancmSablon ","AST4"},
    {"TZ_America_Boa_Vista ","<-04>4"},
    {"TZ_America_Bogota ","<-05>5"},
    {"TZ_America_Boise ","MST7MDT,M3.2.0,M11.1.0"},
    {"TZ_America_Cambridge_Bay ","MST7MDT,M3.2.0,M11.1.0"},
    {"TZ_America_Campo_Grande ","<-04>4"},
    {"TZ_America_Cancun ","EST5"},
    {"TZ_America_Caracas ","<-04>4"},
    {"TZ_America_Cayenne ","<-03>3"},
    {"TZ_America_Cayman ","EST5"},
    {"TZ_America_Chicago ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Chihuahua ","CST6"},
    {"TZ_America_Costa_Rica ","CST6"},
    {"TZ_America_Creston ","MST7"},
    {"TZ_America_Cuiaba ","<-04>4"},
    {"TZ_America_Curacao ","AST4"},
    {"TZ_America_Danmarkshavn ","GMT0"},
    {"TZ_America_Dawson ","MST7"},
    {"TZ_America_Dawson_Creek ","MST7"},
    {"TZ_America_Denver ","MST7MDT,M3.2.0,M11.1.0"},
    {"TZ_America_Detroit ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Dominica ","AST4"},
    {"TZ_America_Edmonton ","MST7MDT,M3.2.0,M11.1.0"},
    {"TZ_America_Eirunepe ","<-05>5"},
    {"TZ_America_El_Salvador ","CST6"},
    {"TZ_America_Fortaleza ","<-03>3"},
    {"TZ_America_Fort_Nelson ","MST7"},
    {"TZ_America_Glace_Bay ","AST4ADT,M3.2.0,M11.1.0"},
    {"TZ_America_Godthab ","<-02>2"},
    {"TZ_America_Goose_Bay ","AST4ADT,M3.2.0,M11.1.0"},
    {"TZ_America_Grand_Turk ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Grenada ","AST4"},
    {"TZ_America_Guadeloupe ","AST4"},
    {"TZ_America_Guatemala ","CST6"},
    {"TZ_America_Guayaquil ","<-05>5"},
    {"TZ_America_Guyana ","<-04>4"},
    {"TZ_America_Halifax ","AST4ADT,M3.2.0,M11.1.0"},
    {"TZ_America_Havana ","CST5CDT,M3.2.0/0,M11.1.0/1"},
    {"TZ_America_Hermosillo ","MST7"},
    {"TZ_America_Indiana_Indianapolis ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Knox ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Marengo ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Petersburg ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Tell_City ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Vevay ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Vincennes ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Winamac ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Inuvik ","MST7MDT,M3.2.0,M11.1.0"},
    {"TZ_America_Iqaluit ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Jamaica ","EST5"},
    {"TZ_America_Juneau ","AKST9AKDT,M3.2.0,M11.1.0"},
    {"TZ_America_Kentucky_Louisville ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Kentucky_Monticello ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Kralendijk ","AST4"},
    {"TZ_America_La_Paz ","<-04>4"},
    {"TZ_America_Lima ","<-05>5"},
    {"TZ_America_Los_Angeles ","PST8PDT,M3.2.0,M11.1.0"},
    {"TZ_America_Lower_Princes ","AST4"},
    {"TZ_America_Maceio ","<-03>3"},
    {"TZ_America_Managua ","CST6"},
    {"TZ_America_Manaus ","<-04>4"},
    {"TZ_America_Marigot ","AST4"},
    {"TZ_America_Martinique ","AST4"},
    {"TZ_America_Matamoros ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Mazatlan ","MST7"},
    {"TZ_America_Menominee ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Merida ","CST6"},
    {"TZ_America_Metlakatla ","AKST9AKDT,M3.2.0,M11.1.0"},
    {"TZ_America_Mexico_City ","CST6"},
    {"TZ_America_Miquelon ","<-03>3<-02>,M3.2.0,M11.1.0"},
    {"TZ_America_Moncton ","AST4ADT,M3.2.0,M11.1.0"},
    {"TZ_America_Monterrey ","CST6"},
    {"TZ_America_Montevideo ","<-03>3"},
    {"TZ_America_Montreal ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Montserrat ","AST4"},
    {"TZ_America_Nassau ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_New_York ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Nipigon ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Nome ","AKST9AKDT,M3.2.0,M11.1.0"},
    {"TZ_America_Noronha ","<-02>2"},
    {"TZ_America_North_Dakota_Beulah ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_North_Dakota_Center ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_North_Dakota_New_Salem ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Nuuk ","<-02>2"},
    {"TZ_America_Ojinaga ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Panama ","EST5"},
    {"TZ_America_Pangnirtung ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Paramaribo ","<-03>3"},
    {"TZ_America_Phoenix ","MST7"},
    {"TZ_America_PortmaumPrince ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Port_of_Spain ","AST4"},
    {"TZ_America_Porto_Velho ","<-04>4"},
    {"TZ_America_Puerto_Rico ","AST4"},
    {"TZ_America_Punta_Arenas ","<-03>3"},
    {"TZ_America_Rainy_River ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Rankin_Inlet ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Recife ","<-03>3"},
    {"TZ_America_Regina ","CST6"},
    {"TZ_America_Resolute ","CST6CDT,M3.2.0,M11.1.0"},


message:
Problem cleaning string read from serial buffer

I am trying to move a `stepper motor` when a specific command is send to `Arduino Mega 2560`. This command is read character by character and stored in a `string variable`. Whenever a new command is sent, an act should be performed. However, it is not happening and I believe that the problem is in reading the sent command. I tried clearing the character and string variables, but to no avail. The sketch should run a loop that moves the motor `clockwise` or `counterclockwise` according to the command sent, which can be `"crx*"` for clockwise or `"clx*"` for anticlockwise, where `"*"` is the reading stop criterion of the characters.
Any suggestions what to do?
The script:

```
void(* resetFunc) (void) = 0;//Reset turn

// Stepper Motor X
const int stepPinX = 2; //X.STEP
const int dirPinX = 5; // X.DIR
const int pinEnable = 8;

// String read
char c;
String readString; //main captured String

// Unit steps
double av_len = 1.029; //medium length
double interval;
int cnt_steps = 0;
const int num_d = 200;//parameterized step
int fact = int(num_d / av_len);
int unit_len = fact * 1;//unit length (1mm)

void setup()
{
  // Sets pins as Outputs
  pinMode(stepPinX, OUTPUT);
  pinMode(dirPinX, OUTPUT);
  pinMode(pinEnable, OUTPUT);

  digitalWrite(pinEnable, HIGH);//lock driver on cnc shield

  Serial.begin(115200);
  Serial.setTimeout(1);

  while (1) {

    while ( (Serial.available() == 0) )
    {

    }

    if (Serial.available())  {
      c = Serial.read();  //gets one byte from serial buffer
      //Serial.println(readString);
      if (c == '*') {
        Serial.println(readString);//test response
        if (readString == "crx") {
          cnt_steps = cnt_steps + 1;
          Serial.println(cnt_steps);
          digitalWrite(pinEnable, LOW);
          digitalWrite(dirPinX, HIGH);
          for (int x = 0; x < unit_len; x++) {
            digitalWrite(stepPinX, HIGH);
            delayMicroseconds(500);
            digitalWrite(stepPinX, LOW);
            delayMicroseconds(500);
          }

        }
        else if (readString == "clx") {
          cnt_steps += -1;
          Serial.println(cnt_steps);
          digitalWrite(pinEnable, LOW);
          digitalWrite(dirPinX, LOW);
          for (int x = 0; x < unit_len; x++) {
            digitalWrite(stepPinX, HIGH);
            delayMicroseconds(500);
            digitalWrite(stepPinX, LOW);
            delayMicroseconds(500);
          }
        }
         digitalWrite(pinEnable, HIGH);//lock driver on cnc shield
         c = (char)0;
         Serial.flush();
         readString = "";
         //resetFunc();
      }

      else {
        readString += c; //makes the string readString

      }
    }
  }
}

void loop() {

}
```

body:
When sending text commands to an Arduino, it is common to define a
“line-oriented protocol”: each command is transmitted as a single line,
with the line ending signifying the end of the command. Common line
endings are carriage return (CR = `'\r'` = `0x0d` = 13), line feed (LF =
`'\n'` = `0x0a` = 10) and the sequence CR+LF.

The Arduino serial monitor is designed to support this convention by
automatically appending a line ending when you press “Send”. This line
ending can be configured to one of the following options:
 - No line ending
 - Newline (meaning “line feed”)
 - Carriage return
 - Both NL & CR (but CR is actually sent before LF)

In your case, you have chosen to use `'*'` as a command termination
character. For this to work, you have to choose “No line ending” and add
the “\*” explicitly to the command. Alternatively, you may consider
changing your sketch so that it expects `'\r'` or `'\n'`, which is a
more standard way of ending a command.


body:
In addition to the good responses you have already received, I offer this.

For the Arduino, know the differences between String string and char arrays - there is much on this e.g., https://forum.arduino.cc/t/string-vs-string-vs-char-arrays-correct-approach/537468 . Many do not want to deal with the vagaries of String, but their use can be convenient.

Run this code:

    String readstring = "xxx";

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

    void loop() {
      if (Serial.available()) {
        readstring = Serial.readStringUntil('/n');
        Serial.print(readstring);
        Serial.println(" received");
        if (readstring.equals("crx")) {
          // move counter clockwise
          Serial.println("moving counter clockwise");
          // counterclockwise() <-- your function
        }
        else if (readstring.equals("clx") ) {
          // move clockwise
          Serial.println("moving clockwise");
          // clockwise() <-- your function
        }
        else {
          // bad command
          Serial.println("Bad command received - no action");
          // badcommand() <-- your function
        }
      }
    }

If you add functions for the stepper, it may do what you want within a limited context and with using the Arduino serial monitor for input. Take a look at the output.

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

Note that the serial monitor is set to "no line ending". The terminating character '/n' is provide by your input in the serial monitor. It will do what you want, but again, many advise you stay away from String.

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


message:
TMRpcm not compatible incompatible with current board

My goal is to play sounds with my Arduino Nano Every. I tried the example sketch that comes with the library but I get the error:
```
**WARNING: library TMRpcm-master claims to run on avr architecture(s) and may be incompatible with your current board which runs on megaavr architecture(s).**
```

Is there such a big difference between the Nano and Nano every?

body: I opened a issue on GitHub and the result is: tmrpcm only runs on avr architecture so it is incompatible with megaavr architecture(s).


message:
Reply from the SIM800l module is being cut short

I have a sim800l module connected to the Rpi pico hardware UART

```
/*
SIM800       RPi Pico
5v           *External 2A 5v supply*
GND          GND
VDD          3v3
TXD          GP1
RXD          GP0
*/

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

  while (!Serial)
    ;

  Serial1.begin(9600);

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

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

  Serial1.println("AT"); //Once the handshake test is successful, it will back to OK
  updateSerial();
  delay(3000);

  Serial1.println("ATI"); //Returns the module name and revision.
  updateSerial();
  delay(3000);

  Serial1.println("AT+CCID"); //Read SIM information to confirm whether the SIM is plugged
  updateSerial();
  delay(3000);

  Serial1.println("AT+COPS?"); //Checks which network you are connected to
  updateSerial();
  delay(3000);

  Serial1.println("AT+COPS=?"); //Returns the list of operators present in the network.
  updateSerial();
  delay(3000);

}

void loop()
{
  updateSerial();
}

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

}
```

terminal response
```
AT
OK
ATI
SIM800 R14.18

OK
AT+CCID
XXXXXXXXXXXXXXXXXXXX
AT+COPS?
+COPS: 0,0,"Vodaa TelAT+COPS=?
+COPS: (2,"Vodaa Telecom","Ver
```

From what i know so far the SIM800L always ends its response with an "OK" but there are some commands that are cut short and not end with OK.  such as AT+CDID and AT+COPS. I do not know if the problem is with the pico or with sim800l. The sim800l seems to be working fine so i suspect its with the pico but if so, it might be a problem with the internal libraries which is beyond me.  To supoort that theory the number of characters that is being cut is about 20 characters, so it might be a setting i have to adjust

body:
Took me quite a while, but upon reading the pico's [documentation][1]

> The size of the receive FIFO may also be adjusted from the default 32
> bytes by using the setFIFOSize call prior to calling begin()
>
>     Serial1.setFIFOSize(128);
>     Serial1.begin(baud);

settinng it to a much higher value like 256 solves the problem

  [1]: https://arduino-pico.readthedocs.io/en/latest/serial.html


message:
ESP8266 RTC memory (for bootcount)

I'm using an ESP8266 with deep sleep + wake up when `RST` pin goes low.

```
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266HTTPClient.h>
WiFiClient client;
HTTPClient http;
RTC_DATA_ATTR int bootcount = 0;

void setup() {
    bootcount ++;
    WiFi.begin("MySSID", "password");
    while (WiFi.status() != WL_CONNECTED) {
        delay(20);
    }
    // here I send "bootcount" with HTTP request
    ESP.deepSleep(0);
}
void loop() {
}
```

Here `RTC_DATA_ATTR int bootcount = 0;` fails with `RTC_DATA_ATTR` unknown.

**How to get the number of times the ESP8266 has woke up from deep sleep?**

body:
The ESP8266 RTC has 512 bytes of RAM that persist across restarts but not during power outages. While this RAM isn't persistent across power outages it also doesn't have the write limitations that flash memory has, making it appropriate for frequent writes which don't need to survive power loss.

The ESP32's compiler and software framework make it easy to access similar memory on it using the `RTC_DATA_ATTR` attribute; unfortunately as you found and @Juraj pointed out, the ESP8266's doesn't.

Thankfully the Arduino core for the ESP8266 includes support for reading and writing this area of memory using methods in the `ESP` object.

`ESP.rtcUserMemoryRead()` reads RTC memory and `ESP.rtcUserMemoryWrite()` writes RTC memory. In your case you could do something like this:
```
void setup() {
  uint32_t bootcount;

  if(!ESP.rtcUserMemoryRead(0, &bootcount, sizeof(bootcount))) {
    Serial.println("RTC read failed!");
    while(1)
      yield();
  }

  bootcount++;

  if(!ESP.rtcUserMemoryWrite(0, &bootcount, sizeof(bootcount))) {
    Serial.println("RTC write failed!");
    while(1)
      yield();
  }

  Serial.begin(115200);
  Serial.print("boot count is ");
  Serial.println(bootcount);
}

void loop() {
}
```

Not quite as convenient as the `RTC_DATA_ATTR` attribute but it still gets the job done.

I changed the type of `bootcount` from your example to `uint32_t` because it should never be negative, and the size of `uint32_t` is independent of the size of `int`.

Because the Arduino core is open source, you can [read the implementation of these functions][1] if you want to know how they work.

  [1]: https://github.com/esp8266/Arduino/blob/24c41524dc56c683d8926671bdd639d7411f2815/cores/esp8266/Esp.cpp#L141


message:
Error resolving FQBN (Fully Qualified Board Name)

In Arduino IDE, I get this error "Error resolving FQBN: getting", when compiling a sketch. Can anyone help me get around this problem?

I am using the Arduino IDE. I have installed the M5Stack official 2.0.5-1.0 boards in Board Manager and the STAMP-PICO 0.0.2 library in Library Manager.

I get the following Compile error with ALL sketches, even the STAMP-PICO Basics IO example sketch.

"Error resolving FQBN: getting Error compiling for board STAMP-PICO."

Strangely ... in Arduino IDE v2.0.3, on the same computer using the same libraries and boards, the sketch compiles ok.

Sounds like something specific to Arduino IDE v1

body:
OK - I resolved the issue, myself.

The Boards Manager installations became confused, probably because I was using both Arduino 1.8.19 and Arduino IDE 2.0.3 on the same computer.

Somehow, the folder ~/Library/Arduino15/packages/m5stack/hardware/esp32/ contained more than one version of the esp32 board libraries, v2.0.5 as well as v2.0.5-1.0 and c2.0.5+1.0.

My fix involved uninstalling the M5 esp32 board library altogether and making sure that all sub-folder versions had been deleted too. Then, reinstalling the latest board version and restarting the Arduino IDE app.


message:
Single Method for 2 Ultrasonic Sensor is not working as expected

So I have created a method to read and return Ultrasonic Sensor Data. I have 2 Ultrasonic Sensors.

Below is my code.

    // Ultrasonic Pins
    #define T1 2
    #define E2 4
    #define E1 3
    #define T2 5
    // Motor Pins
    #define M1 7
    #define M2 8
    #define M3 9
    #define M4 10
    // Motor Movements Definition
    enum MOTOR
    {
        FORWARD,
        BACKWARD,
        LEFT,
        RIGHT,
        STOP
    };

    long duration1, distance1, duration2, distance2;

    void setup()
    {
        Serial.begin(9600);
        pinMode(E1, INPUT);
        pinMode(E2, INPUT);
        pinMode(T1, OUTPUT);
        pinMode(T2, OUTPUT);
        pinMode(M1, OUTPUT);
        pinMode(M2, OUTPUT);
        pinMode(M3, OUTPUT);
        pinMode(M4, OUTPUT);
        Motor(STOP);
    }

    void loop()
    {

        // If Both Sensors detect object then go in backward Direction
        while (DetectObject(T1,E1,1) < 10 && DetectObject(T2,E2,2) < 10)
        {
            Serial.println("Backward");
            Motor(BACKWARD);
            delay(200);
            Motor(STOP);
            delay(50);
        }
        // If Left Sensor detect object then go in Right Direction
        while (DetectObject(T1,E1,1) < 10 && DetectObject(T2,E2,2) > 10)
        {
            Serial.println("Right");
            Motor(RIGHT);
            delay(200);
            Motor(STOP);
            delay(50);
        }
        // If Right Sensor detect object then go in Left Direction
        while (DetectObject(T1,E1,1) > 10 && DetectObject(T2,E2,2) < 10)
        {
            Serial.println("Left");
            Motor(LEFT);
            delay(200);
            Motor(STOP);
            delay(50);
        }
        // If Both Sensors detect no object then go in Forward Direction
        while (DetectObject(T1,E1,1) > 10 && DetectObject(T2,E2,2) > 10)
        {
            Serial.println("Forward");
            Motor(FORWARD);
            delay(200);
            Motor(STOP);
            delay(50);
        }
    }

    void Motor(MOTOR motor)
    {
        switch (motor)
        {
        case STOP:
            digitalWrite(M1, LOW);
            digitalWrite(M2, LOW);
            digitalWrite(M3, LOW);
            digitalWrite(M4, LOW);
            break;
        case FORWARD:
            digitalWrite(M1, HIGH);
            digitalWrite(M2, LOW);
            digitalWrite(M3, HIGH);
            digitalWrite(M4, LOW);
            break;
        case BACKWARD:
            digitalWrite(M1, LOW);
            digitalWrite(M2, HIGH);
            digitalWrite(M3, LOW);
            digitalWrite(M4, HIGH);
            break;
        case LEFT:
            digitalWrite(M1, HIGH);
            digitalWrite(M2, LOW);
            digitalWrite(M3, LOW);
            digitalWrite(M4, HIGH);
            break;
        case RIGHT:
            digitalWrite(M1, LOW);
            digitalWrite(M2, HIGH);
            digitalWrite(M3, HIGH);
            digitalWrite(M4, LOW);
            break;
        default:
            break;
        }
        delay(100);
    }

    long DetectObject(uint8_t trigPin, uint8_t echoPin, int sensorNo)
    {
        digitalWrite(trigPin, LOW);
        delayMicroseconds(2);
        digitalWrite(trigPin, HIGH);
        delayMicroseconds(10);
        digitalWrite(trigPin, LOW);
        Serial.print("Distance Sensor");
        Serial.print(sensorNo);
        Serial.print(": ");
        Serial.print(pulseIn(echoPin, HIGH) * 0.034 / 2);
        Serial.println(" cm");
        return pulseIn(echoPin, HIGH) * 0.034 / 2;
    }

I am getting continuously getting ```Backward``` in the Serial monitor.

Output of Serial Monitor -

```
Distance Sensor1: 20 cm
Distance Sensor2: 15 cm
Backward
Distance Sensor1: 17 cm
Distance Sensor2: 21 cm
Backward
Distance Sensor1: 24 cm
Distance Sensor2: 9 cm
Backward
```

But when I created 2 different methods for each Ultrasonic Sensor. It is working fine.

I want to have a single method for N number of Ultrasonic Sensors.

Thanks in Advance!

body:
The problem lies in the function, that does the ultrasonic detection. First I would suggest to not do Serial printing between the trigger pulse and `pulseIn()`, since the Serial transmission might take longer (for example when the buffer is full) and then your reading is garbage. Execute `pulseIn()` directly after the trigger pulse part and save the result in a local variable, which you can later print and return. If you do that, your problem is also solved.

For understanding what actually happens with your code, I annotated the function with some comments:

    long DetectObject(uint8_t trigPin, uint8_t echoPin, int sensorNo)
        {
            // Create Trigger pulse
            digitalWrite(trigPin, LOW);
            delayMicroseconds(2);
            digitalWrite(trigPin, HIGH);
            delayMicroseconds(10);
            digitalWrite(trigPin, LOW);

            // Do some printing
            Serial.print("Distance Sensor");
            Serial.print(sensorNo);
            Serial.print(": ");

            // Read a pulse and print it directly to Serial
            Serial.print(pulseIn(echoPin, HIGH) * 0.034 / 2);
            Serial.println(" cm");

            // Read ANOTHER pulse and return it
            return pulseIn(echoPin, HIGH) * 0.034 / 2;
        }

As you can see, you are trying to read 2 pulses. But there is only one echo pulse. That one pulse is read by the first execution of `pulseIn()` and you print the result to Serial, so in the Serial Monitor you are seeing the correct value.

After that you are executing `pulseIn()` again and returning the result. `pulseIn()` will wait for a pulse to begin (so it can start counting the time). But there is no second pulse on the echo line, so `pulseIn()` will exit after a timeout (by default 1s). On timeout this function returns zero. So every time you execute this function, it will return zero.

If you then look at the logic in `loop()`, you can easily see why you are only getting backwards. The code is stuck in the first while loop, because the value returned from the function is always zero, which is smaller than 10.

Here is a pseudo code version of how your function really should work:

    execute trigger pulse
    execute pulseIn function and save result in local variable
    print whatever you want to Serial
    return the value of the local variable


message:
Confusion regarding PID library?

PID library is available(built in) in standard installation  of arduino IDE or do we have to download it additionaly after installing our IDE?

How can i check which of libraries are available in my standard installation?

body:
Open the Library Manager and search for the library you want. You will
see a list of libraries matching your query. Under the name of each of
those libraries, you will see a line showing the author and the version
number.

- if this lines stats with “Built-in”, then it is a library that comes
  with the standard installation of the IDE

- if the line ends with “INSTALLED”, then this library is installed in
  your system.


message:
control 12v motor with NPN transistor via arduino

- i want to control this **12v** motor via arduino:

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

Power source is 12v 5A

motor will work 5 seconds in every 5 minutes and will be activated throught arduino mega

i will try to use **bd679a darlington transistor**:

 - Collector - Base Voltage (Vcbo) 80 V
 - Collector - Emitter Voltage (Vceo) 80 V
 - Collector Current (Ic) 4 A
 - Power Dissipation (Pd) [Tcase≤25°C] 40 W
 - Transition Frequency (fТ) 10 MHz
 - Min. DC current gain (β) 750
 - Integrated diode Yes
Case TO-126
Package type -14h

**Do i need to add diode(and will that drop voltage ) ?**

**also do i need any ressistors and why?**

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

  [1]: https://i.stack.imgur.com/HWJe4.jpg
  [2]: https://i.stack.imgur.com/P78fm.png

body:
You are missing 2 things:

- You should add a resistor between the Arduino digital IO pin and the base of the transistor. Bipolar transistors are current amplifiers. Normally for driving motors with a microcontroller you want the transistor to operate in saturation anyway, so there is no need to fine tune the resistor. It is there for protecting the output pin of the Arduino from over current. The calculation is easy: Resistance is voltage divided by current `R = U / I`. The voltage is 5V for an Arduino Mega (output voltage of the digital IO pins is equal to the operating voltage of the Mega, thus 5V). The current here is the max current, that the output pin can withstand (you find such information in the datasheet of the microcontroller). It is 20mA for continuous load.

    So `R = 5V / 20mA = 250 Ohm`. Thus you need a resistor with at least 250 Ohm. 330 Ohm is normally readily available, so often people use one of these.

    You also asked about how many wants it should withstand. This is also easy to calculate: Power (in Watts) is voltage multiplied by current. So `P = U * I = 5V * 20mA = 0.1W`. So in this configuration the resistor will not ever need to withstand more than 0.1W. So 1/4W is enough.

- When driving motors you should include a flyback diode. This is a diode in reverse direction connected across the terminals of the motor. A motor is an inductive load (since it basically consists of some coils and magnets). Driving it with a varying voltage (like you need for controlling the motors speed or just to start and stop the motor) will induce reverse voltage spikes. These might damage your transistor and/or the Arduino. With the flyback diode connnected these voltage spikes can safely dissipate through that diode and not causing any harm.

So the circuit looks like this:

<!-- 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/oDTSj.png)

<!-- End schematic -->


message:
i need help on how to use busy pin in df player to arduino

.... while playing one sound or df player is busy, i don't want to trigger df player by ultrasound sensors to play another song. here is my code without busy pin use in df player

```lang-cpp
#include "Arduino.h"
#include "SoftwareSerial.h"

#include "DFRobotDFPlayerMini.h"

const byte SENSOR_COUNT = 5;
byte triggerPins[SENSOR_COUNT] = {2,4,6,8,10};
byte echoPins[SENSOR_COUNT]    = {3,5,7,9,11};

SoftwareSerial mySoftwareSerial(12, 13); // RX, TX

DFRobotDFPlayerMini myDFPlayer;

void printDetail(uint8_t type, int value);

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

  for( byte i=0; i<SENSOR_COUNT; i++ )
  {
    pinMode(triggerPins[i], OUTPUT);
    pinMode(echoPins[i], INPUT);
  }

  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true);
  }
  Serial.println(F("DFPlayer Mini online."));

  myDFPlayer.volume(10);  //Set volume value. From 0 to 30

}

int currentSound = -1;
void loop()
{

  for( byte i=0; i<SENSOR_COUNT; i++ ) // loop through all distance sensors
  {
    if( detectPresence(i) ) // check if there is an object near it
    {
      if(currentSound!=i) // check that it's a different sensor than the one that was last triggered
      {
        Serial.print("play song number ");
        Serial.println(i);
        myDFPlayer.play(i+1); // play song nr `i+1`
      }
      currentSound = i;
    }
  }

  if (myDFPlayer.available()) {
    printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
  }

}

// detectPresence will return TRUE if there is an object close to it.
bool detectPresence(byte sensorNr)
{
  if( sensorNr>=SENSOR_COUNT )
    return false;
  long duration, distance;
  //digitalWrite(triggerPins[sensorNr], LOW);  // Added this line
  //delayMicroseconds(10); // Added this line
  digitalWrite(triggerPins[sensorNr], HIGH);
  delayMicroseconds(15); // Added this line
  digitalWrite(triggerPins[sensorNr], LOW);
  duration = pulseIn(echoPins[sensorNr], HIGH);
  distance = duration/58;

  return distance<30;// choose your own value here, from which distance it should trigger a sound
}

void printDetail(uint8_t type, int value){

  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
}
```

body:
The busy pin is just a pin, that gets driven LOW, when a song is playing, and HIGH when nothing is playing. So connect it to a free digital IO pin on your Arduino and set that pin to input with:

    pinMode(busy_pin, INPUT);

(Note: You yourself need to define `busy_pin`, since I don't know where you will connect it). Then just read this pin in the if statement together with `detectPresence(i)`:

    if(!digitalRead(busy_pin) && detectPresence(i))

The `!` is to make the expression true, when `digitalRead(busy_pin)` returns 0 (LOW). This way the code will not even check for presence, when there is currently a song playing.


message:
I need help with creating a menu using u8g2 library

I want to make a project with a (Nokia 5110) display using u8g2 library.
Here I have the code for my program:

```lang-cpp
#include <Arduino.h>
#include <U8g2lib.h>
#include <TM1637Display.h>
#include <EEPROM.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

#define LED_PIN 5
#define BUTTON_PIN 6
#define BUZZ_PIN 7
#define BUTTON_L 2
#define BUTTON_R 3
#define BUTTON_START 4

//48x84 disp.
U8G2_PCD8544_84X48_F_4W_SW_SPI u8g2(U8G2_R2, 13, 11, 10, 12, 8); //rotate, clk, DIN, CE, DC, RST //

byte lastButtonState = 0;
byte ledState;
float cpu_gauge = 0.0;
char buffer[40];
int move = 7;
float cpu_gauge_step = 0.5;
byte eeprom_led;

void set_led(){
  if( digitalRead(LED_PIN) == 1 ) ledState = 1;
      if( digitalRead(LED_PIN) == 0 ) ledState = 0;}

void backlight(){
byte buttonState = digitalRead(BUTTON_PIN);  //monitor button state
  if (buttonState != lastButtonState) {  //check if not equal
    lastButtonState = buttonState;       //if prev. true, make equal
      if (buttonState == HIGH) {
        ledState = (ledState == HIGH) ? LOW : HIGH;
          digitalWrite(LED_PIN, ledState);    }}}

void status_bar(){
  if (cpu_gauge > cpu_gauge_step*1) u8g2.drawBox(2,13,6,8); //x, y , size in x, size in y
    if (cpu_gauge > cpu_gauge_step*2) u8g2.drawBox(2 + 1*move,13,6,8);
      if (cpu_gauge > cpu_gauge_step*3) u8g2.drawBox(2 + 2*move,13,6,8);
        if (cpu_gauge > cpu_gauge_step*4) u8g2.drawBox(2 + 3*move,13,6,8);
          if (cpu_gauge > cpu_gauge_step*5) u8g2.drawBox(2 + 4*move,13,6,8);
            if (cpu_gauge > cpu_gauge_step*6) u8g2.drawBox(2 + 5*move,13,6,8);
              if (cpu_gauge > cpu_gauge_step*7) u8g2.drawBox(2 + 6*move,13,6,8);
                if (cpu_gauge > cpu_gauge_step*8) u8g2.drawBox(2 + 7*move,13,6,8);
                  if (cpu_gauge > cpu_gauge_step*9) u8g2.drawBox(2 + 8*move,13,6,8);
                    if (cpu_gauge >= cpu_gauge_step*10) u8g2.drawBox(2 + 9*move,13,6,8);
}

void setup(void) {
  pinMode(LED_PIN, OUTPUT);
    pinMode(BUTTON_PIN, INPUT);
      pinMode(BUZZ_PIN, OUTPUT);
       pinMode(BUTTON_L, INPUT);
        pinMode(BUTTON_R, INPUT);
          pinMode(A7, INPUT);
            pinMode(BUTTON_START, INPUT);
              eeprom_led = EEPROM.read(0);
                digitalWrite(LED_PIN, eeprom_led);
                  set_led(); //sets the led state to 1 or 0 depending on digital write
            Serial.begin(9600);
            u8g2.begin();

}

void loop(void) {

    EEPROM.update(0,ledState);
    /*pomiar = EEPROM[ 0 ];
    delay(2500);//
    Serial.println(pomiar);//
    Serial.println(cpu_gauge);
    int pomiar = digitalRead(BUTTON_START);
    Serial.println(pomiar);*/

  backlight();
  cpu_gauge = analogRead(A7) * (5.0/1022);

  u8g2.firstPage();
  do {
  u8g2.drawRFrame(0,12,74,10,3); //pos X,Y  length, width, corner
  status_bar();

  u8g2.setFont(u8g2_font_busdisplay8x5_tr);
    u8g2.setCursor(0,8);
      char pomiar_str[5];
        dtostrf(cpu_gauge,0,2, pomiar_str);
          sprintf(buffer, "LOAD: %sV", pomiar_str);
            u8g2.print(buffer);

  u8g2.setCursor(0,36);
    u8g2.print("bckgrnd_tsks:");
      u8g2.setCursor(48,48);
        sprintf(buffer, "led: %d", ledState);
          u8g2.print(buffer);
            u8g2.drawStr(0,48,"buzz:");

  if (cpu_gauge > 4.80){
    digitalWrite(7,1);
      u8g2.setCursor(0,48);
        u8g2.setFont(u8g2_font_busdisplay8x5_tr);
          u8g2.setFont(u8g2_font_open_iconic_play_1x_t);
          u8g2.drawGlyph(27, 48, 0x0040);}
  else
    digitalWrite(7,0);

  } while ( u8g2.nextPage() );}
```

I have succesfully made a program, that:

-Has a pushbutton, to turn off, and on the backlight with each press
-Writes to the EEPROM the state of the LED, and reads it at startup
-Displays an analogRead value, from the potentiometer and also displays a progress bar of the given value
-Displays the state of the backlight
-Turns on the buzzer, if the analogRead value exceedes some value
-Displays an indicator, if the buzzer is turned on

Now, let's assume that what this program does, is called option "A", and A in this example works all the time, because there is nothing else.
I want to create a menu, that would have option A, B, C, D. Assume that formatting and pushbutton actions, doesn't matter for now.

A: Is what was described before.
B: Clock. Just display a clock.
C: Stopwatch.
D: Setting the time.

I see two ways of creating such menu.

1: Is to build a selectable/scrollable menu that would have labels, and by choosing, and pressing a button, we would enter desired function.
2: Ditch the selectable menu. One pushbutton will switch from option A to D. Something like a casio watch.

I'd prefer the second option, I think it'll be easier to do

What I don't understand, is the U8G2 reference manual.
I don't really understand the concept of the buffer, sendBuffer, userInterfaceSelectionList, and some more stuff, that I can't name for now.

My understanding is, that i have to make some array, of functions.
Like:
```
Array [] = {default_display();, clock();, stopwatch();, setting();)
```
And with a button, I'd go thru this array like so:
```
Array = 0;
 If (digitalRead(some_button_pin) == High){
  Array + 1;}
If (Array > 3){
 Array = 0;}
```
And in those funtions, it would have implemented options, like the backlight turned on, or something else, whatever,

Now I don't know if that makes any sense. If it's transferable into code.
I don't know if I need to clear the display, and how do I do that only once before entering the option. How do I make it, so that all the variables related to clock, the stopwatch still work even if I'm not displaying it. I'm honestly lost, and I just need guidance with this, becuase I have only had C for 1 semester at Electrical Engineering. I'm not a programist, but I really want to make it work, but it just isn't explained in the way like I don't know, pulldown resistors, where you can make some assumptions, and with them explain how something works. No, it looks like this:
```
void u8g2_SetBufferPtr(u8g2_t *u8g2, uint8_t *buf)
```
And yeah, I just don't know how do I go around it, how do I navigate in it. Thank you for any help.

body:
I have figured it out.
First thing that has to be said. If you're used to creating function definitions before the setup, you can't do that with u8g2 library. You can create function definitions after calling u8g2.begin in setup. Now there are two ways how you can do it, in the "Casio watch" fashion, but first create a varaible that will read how many times you've clicked, and store that somewhere, and add a condition, that will revert it to 1 after some amount of clicks.
1st way: Create a switch case, where the variable will be your switch, and in the cases (x to n) write what you want, graphics, text, whatever. Now the problem that I've had, is that when I've pasted the same code, and changed only some minor text, the whole thing glitched. It went through 1 and 2, normally, and then everything from case 3 and 4 was merged toghether, and case 4 was empty, and so was the screen. I couldn't fix it, so I came up with the second approach. Create as many IF conditions, as you have menu option. So it goes like this:
 If (menu_counter == 1){ //your input to the screen// }
And so for the rest. As far as I have tested this, it works, even if the code is the same for both IF statements. Now I'd have to implement the menu selection list on top. Leaving the answer to my own question, hopefully someone will find it useful.


message:
How do I stop my servo from repeating the loop and perform the rest of the functions?

The project has a makeshift meter (via a half circle cutout and a servo motor operated lever). On program start (button 2), the lever will move to the left hand side at the 9 o'clock position. Once in place, after a short delay, the program will accept input from the button 1 and keep a count while moving the lever toward the 3 o’clock position stopping at at 10-2 w 2 sec delay. When it reaches the position, it stops the count and remembers it.

Repeat same thing but with buttons 4 and 5 respectively. Really important that the count is saved for both buttons 1 and 5.

Pressing button 3 will measure the inputs of button 5 and display them on the meter as a ratio of button 5 presses over button 1 + button 5 presses. If it leans right, that means you had more presses in the first stage than second (for ease of understanding I’ll probably have instructions that say to start with right hand so that leaning right means right hand dominance and left is left handed). Below is a picture of my set up.

*I numbered the buttons 1-5 left to right not by the pin number.

The problem I have is that after button 2 or 4 get pushed the servo just keeps moving to the seven positions I have set as a timer over and over.

    #include <Servo.h>

    const int button1 = 2;   // button 1 pin/left hand main pin
    const int button2 = 3;   // button 2 pin/left start pin
    const int button3 = 4;   // button 3 pin/right hand main pin
    const int button4 = 5;   // button 4 pin/right start pin
    const int button5 = 6;   // button 5 pin/results pin
    const int servoPin = 9;  // servo motor pin

    int count1 = 0;          // counter for button 1
    int count2 = 0;          // counter for button 5

    Servo servo;             // servo motor object

    void setup() {
      // set button pins as inputs
      pinMode(button1, INPUT);
      pinMode(button2, INPUT);
      pinMode(button3, INPUT);
      pinMode(button4, INPUT);
      pinMode(button5, INPUT);

      servo.attach(servoPin); // attach servo motor to pin
    }

    void loop() {
      if (digitalRead(button2) == HIGH) {  // if button 2 is pressed
        // move servo motor to 9 o'clock position
        servo.write(180);
        delay(500);  // wait for servo to reach position

        // start accepting input from button 1
        while (digitalRead(button1) == LOW) {
          count1++;  // increment counter
          // move servo motor to 3 o'clock position
          servo.write(180);
          delay(2000);  // wait for servo to reach position
          servo.write(150);
          delay(2000);  // wait for servo to reach position
          servo.write(120);
          delay(2000);  // wait for servo to reach position
          servo.write(90);
          delay(2000);  // wait for servo to reach position
          servo.write(60);
          delay(2000);  // wait for servo to reach position
          servo.write(30);
          delay(2000);  // wait for servo to reach position
          servo.write(0);
          delay(2000);  // wait for servo to reach position

        }

        // repeat the same process for button 4
        while (digitalRead(button4) == LOW) {
          count2++;  // increment counter
          // move servo motor to 3 o'clock position
          servo.write(180);
          delay(2000);  // wait for servo to reach position
          servo.write(150);
          delay(2000);  // wait for servo to reach position
          servo.write(120);
          delay(2000);  // wait for servo to reach position
          servo.write(90);
          delay(2000);  // wait for servo to reach position
          servo.write(60);
          delay(2000);  // wait for servo to reach position
          servo.write(30);
          delay(2000);  // wait for servo to reach position
          servo.write(0);
          delay(2000);  // wait for servo to reach position
        }
      }

      if (digitalRead(button3) == LOW) {  // if button 3 is pressed
        // calculate ratio of button 4 presses to total button presses
        float ratio = (float)count2 / (count1 + count2);

        // Display ratio on meter
        servo.write(90 + (int)(ratio * 90));
      }
    }

[![Arduino set up][1]][1]

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

body:
You have pulldown resistors on all your buttons, so all of your input pins are LOW when nobody is touching the buttons. When you press a button, the input goes HIGH. In your code, when you do

      if (digitalRead(button2) == HIGH) {  // if button 2 is pressed

it enters the if block, if the button is pressed, because the button2 input is high when the button is pressed. Then you move the servo to position 180 and wait a bit. The next line

        while (digitalRead(button1) == LOW) {

enters the while loop if the input pin is low. The input pin is that, when the button is NOT pressed, because of the pulldown resistor and that is why the servo starts moving when button2 is pressed, unless button1 is also pressed when you press button2. To stop that, change the LOW to HIGH in the while loop condition. Then it will only enter the while loop when the button is pressed and skip it if it is not pressed..

As suggested by the busybee, you might benefit from studying state machines.