# Question
Title: Arduino IDE EEPROM put() then read() returns different data on ESP32
I'm trying to understand how to read/write a UID struct from miguelbalboa to EEPROM to persist a card ID across system restarts on my ESP32-S3 through the Arduino IDE. I expected Put/Get/Read to be symmetrical but can't seem to prove that. Here's my test program:

```
/**
 * This is a simple script to experiment with reading and writing MFRC522::Uid
 * structures to eeprom.
 */

#include <MFRC522.h>
#include <EEPROM.h>

#define UID_EEPROM_LOCATION 0
#define EEPROM_SIZE 256

void setup() {

  Serial.begin(115200);   // Initialize serial communications with the PC
  Serial.println("Serial started.");
  EEPROM.begin(EEPROM_SIZE);
  Serial.print("EEPROM started ");
  Serial.println(EEPROM_SIZE);
  printBytesFromEeprom();
  MFRC522::Uid uidToWrite = {
    0x04,
    {B00000000, B10000000, B11100000, B01100000},
    0
  };
  Serial.print("UID Before Write: ");
  printUid(&(uidToWrite));
  storeUidInEeprom(&(uidToWrite));
  printBytesFromEeprom();
  Serial.println("UID was put.");
  MFRC522::Uid uidFromRead;
  readUidFromEeprom(&(uidFromRead));
  printBytesFromEeprom();
  Serial.print("UID from Read: ");
  printUid(&(uidFromRead));
}

void loop() {
}

void printUid(MFRC522::Uid *uid) {
  Serial.print(uid->size, HEX);
  Serial.print(F(" byte card UID:"));
  for (byte i = 0; i < uid->size; i++) {
    if(uid->uidByte[i] < 0x10)
      Serial.print(F(" 0"));
    else
      Serial.print(F(" "));
    Serial.print(uid->uidByte[i], HEX);
  }
  Serial.println();
}

void readUidFromEeprom(MFRC522::Uid* result) {
  EEPROM.get(UID_EEPROM_LOCATION, result);
  delay(1000);
}

void storeUidInEeprom(MFRC522::Uid *uid) {
  EEPROM.put(UID_EEPROM_LOCATION, uid);
  EEPROM.commit();
  delay(1000);
}

void printBytesFromEeprom() {
  Serial.print("256 bytes from EEPROM: ");
  for (int i = 0; i < 256; i++) {
    byte myByte = EEPROM.read(UID_EEPROM_LOCATION + i);
    if(myByte < 0x10)
      Serial.print(F(" 0"));
    else
      Serial.print(F(" "));
    Serial.print(myByte, HEX);
  }
  Serial.println();
}

```

I'm an experienced Java developer, but new to C++. I could have made any number of basic errors.

When I run the above on my ESP32-S3-DevKitC-1, I get the following output:

```
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd0108,len:0x43c
load:0x403b6000,len:0xbd0
load:0x403ba000,len:0x29c8
entry 0x403b61d8
Serial started.
EEPROM started 256
256 bytes from EEPROM:  E4 2C CE 3F FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
UID Before Write: 4 byte card UID: 00 80 E0 60
256 bytes from EEPROM:  94 2D CE 3F FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
UID was put.
256 bytes from EEPROM:  94 2D CE 3F FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
UID from Read: C0 byte card UID: 79 CD 3F 00 00 00 00 00 00 00 00 0C FA 3B C7 00 00 00 00 04 00 00 00 4C 2F CE 3F 01 00 00 80 00 00 00 00 F0 2D CE 3F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2E CE 3F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

```

There are two unexpected things from this output:

* The output of `readUidFromEeprom()` is different than the input to `storeUidInEeprom()`

Any help would be welcome!

# Answer
You wrote:

```
void readUidFromEeprom(MFRC522::Uid* result) {
  EEPROM.get(UID_EEPROM_LOCATION, result);
  delay(1000);
}

```

The `EEPROM.get()` method expects a *reference* to the variable you are setting. Here, you are providing a *pointer* instead. The outcome is that this call is updating the `result` local variable (the pointer), rather than the memory region pointed by it.

You may try this:

```
void readUidFromEeprom(MFRC522::Uid* result) {
  EEPROM.get(UID_EEPROM_LOCATION, *result);  // notice the `*' operator
  delay(1000);
}

```

Same thing for `EEPROM.put()`.

**Edit**: As suggested by Juraj in a comment, it can make more sense to have `readUidFromEeprom()` accept a reference rather than a pointer:

```
void readUidFromEeprom(MFRC522::Uid &result) {
  EEPROM.get(UID_EEPROM_LOCATION, result);
  delay(1000);
}

```

But then you have to also change the caller:

```
readUidFromEeprom(uidFromRead);

```
> 3 votes

# Answer
Well...

I still don't know why the above wasn't working. But if I switch to my own byte encoding in EEPROM (the obvious one that I assumed `put()` used, then I get the right behavior:

```
/**
 * This is a simple script to experiment with reading and writing MFRC522::Uid
 * structures to eeprom.
 */

#include <MFRC522.h>
#include <EEPROM.h>

#define UID_EEPROM_LOCATION 0
#define EEPROM_SIZE 256

void setup() {

  Serial.begin(115200);   // Initialize serial communications with the PC
  Serial.println("Serial started.");
  EEPROM.begin(EEPROM_SIZE);
  Serial.print("EEPROM started ");
  Serial.println(EEPROM_SIZE);
  printBytesFromEeprom();
  MFRC522::Uid uidToWrite = {
    0x04,
    {B00000000, B10000000, B11100000, B01100000},
    0
  };
  Serial.print("UID Before Write: ");
  printUid(&(uidToWrite));
  storeUidInEeprom(&(uidToWrite));
  printBytesFromEeprom();
  Serial.println("UID was put.");
  MFRC522::Uid uidFromRead;
  readUidFromEeprom(&(uidFromRead));
  printBytesFromEeprom();
  Serial.print("UID from Read: ");
  printUid(&(uidFromRead));
}

void loop() {
}

void printUid(MFRC522::Uid *uid) {
  Serial.print(uid->size, HEX);
  Serial.print(F(" byte card UID:"));
  for (byte i = 0; i < uid->size; i++) {
    if(uid->uidByte[i] < 0x10)
      Serial.print(F(" 0"));
    else
      Serial.print(F(" "));
    Serial.print(uid->uidByte[i], HEX);
  }
  Serial.println();
}

void readUidFromEeprom(MFRC522::Uid* result) {
  byte uidSize = EEPROM.read(UID_EEPROM_LOCATION);
  for (byte i = 0; i < uidSize; i++) {
    result->uidByte[i] = EEPROM.read(UID_EEPROM_LOCATION + 1 + i);
  }
  byte uidSak = EEPROM.read(UID_EEPROM_LOCATION + 2 + uidSize);
  result->size = uidSize;
  result->sak = uidSak;
}

void storeUidInEeprom(MFRC522::Uid *uid) {
  EEPROM.write(UID_EEPROM_LOCATION, uid->size);
  for (byte i = 0; i < uid->size; i++) {
    EEPROM.write(UID_EEPROM_LOCATION + 1 + i, uid->uidByte[i]);
  }
  EEPROM.write(UID_EEPROM_LOCATION + 2 + uid->size, uid->sak);
  EEPROM.commit();
}

void printBytesFromEeprom() {
  Serial.print("256 bytes from EEPROM: ");
  for (int i = 0; i < 256; i++) {
    byte myByte = EEPROM.read(UID_EEPROM_LOCATION + i);
    if(myByte < 0x10)
      Serial.print(F(" 0"));
    else
      Serial.print(F(" "));
    Serial.print(myByte, HEX);
  }
  Serial.println();
}

```

And output as expected is:

```
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd0108,len:0x43c
load:0x403b6000,len:0xbd0
load:0x403ba000,len:0x29c8
entry 0x403b61d8
Serial started.
EEPROM started 256
256 bytes from EEPROM:  04 00 80 E0 60 FF 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
UID Before Write: 4 byte card UID: 00 80 E0 60
256 bytes from EEPROM:  04 00 80 E0 60 FF 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
UID was put.
256 bytes from EEPROM:  04 00 80 E0 60 FF 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
UID from Read: 4 byte card UID: 00 80 E0 60

```
> 0 votes

# Answer
On the ESP23 platform, consider using the Preferences library. EEPROM in arduino-esp32 is emulated using the Preferences library. Might mess up the calls to MFRC522 lib though.

Preferences docs include the API and tutorial.
> -1 votes

---
Tags: esp32, eeprom
---


title: memory leak w/ no Strings involved

text:
# Question
Title: memory leak w/ no Strings involved
I'm trying to read data being transferred via Infrared from my Smartmeter on my ESP8266 using the following sketch:

```
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
#include <Ticker.h>
#include <AsyncMqttClient.h>

#ifndef STASSID
#define STASSID "mySSID"
#define STAPSK  "myPassword"
#endif

#ifndef MQTT_HOST
#define MQTT_HOST IPAddress(192, 168, 0, 100)
#define MQTT_PORT 1883
#endif

#ifndef IR
#define SerialDebug Serial1
#define IR Serial
#endif

AsyncMqttClient mqttClient;
Ticker mqttReconnectTimer;

WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;
Ticker wifiReconnectTimer;

const char* host = "esp8266-webupdate";

const byte firstByte = 0x7E;
const byte lastByte = 0x7E;

uint8_t i;

ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;

void connectToWifi() {
  SerialDebug.println("Connecting to WiFi ...");
  WiFi.begin(STASSID, STAPSK);
}

void connectToMqtt() {
  SerialDebug.println("Connecting to MQTT ...");
  mqttClient.connect();
}

void onWifiConnect(const WiFiEventStationModeGotIP& event) {
  SerialDebug.println("Connected to Wi-Fi.");
  connectToMqtt();
}

void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
  SerialDebug.println("Disconnected from Wi-Fi.");
  mqttReconnectTimer.detach();
  wifiReconnectTimer.once(2, connectToWifi);
}

void onMqttConnect(bool sessionPresent) {
  SerialDebug.println("Connected to MQTT.");
  SerialDebug.print("Session present: ");
  SerialDebug.println(sessionPresent);
}

void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
  SerialDebug.println("Disconnected from MQTT.");

  if (WiFi.isConnected()) {
    mqttReconnectTimer.once(2, connectToMqtt);
  }
}

void array_to_string(byte array[], unsigned int len, char buffer[]) {
  for (unsigned int i = 0; i < len; i++) {
    byte nib1 = (array[i] >> 4) & 0x0F;
    byte nib2 = (array[i] >> 0) & 0x0F;
    buffer[i*2+0] = nib1  < 0xA ? '0' + nib1  : 'A' + nib1  - 0xA;
    buffer[i*2+1] = nib2  < 0xA ? '0' + nib2  : 'A' + nib2  - 0xA;
  }
  buffer[len*2] = '\0';
}

void setup() {

  SerialDebug.begin(115200);
  IR.begin(9600);
  SerialDebug.println();
  SerialDebug.println("Booting Sketch...");

  wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
  wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);

  mqttClient.onConnect(onMqttConnect);
  mqttClient.onDisconnect(onMqttDisconnect);
  mqttClient.setServer(MQTT_HOST, MQTT_PORT);

  connectToWifi();

  httpUpdater.setup(&httpServer);
  httpServer.begin();

  mqttClient.setWill("smartmeter/online", 0, true, "no");
}

void loop() {
  httpServer.handleClient();

  uint32_t timeout = 2000;

  int readCnt = 0;
  uint32_t start_time = millis();
  byte tempChar = 0;
  byte *readMessage;
  uint32_t messageLen = 0;

  while ((tempChar != 0x7E) && (millis() - start_time < timeout)) {
    if (IR.available()) {
      tempChar = IR.read();
    }
  }

  start_time = millis();
  timeout = 1000;
  bool done = false;

  if (tempChar == firstByte) { // if first byte == 0x7E
    while ((millis() - start_time) < timeout && !done) {
      if (IR.available()) {
        tempChar = IR.read(); // second byte must be 0xA0
        if(tempChar == 0xA0) {
          while ((millis() - start_time) < timeout && !done) {
            if (IR.available()) {
              tempChar = IR.read(); // 3rd byte tells the legth of the message

              readMessage = new byte[tempChar+2];
              memset(readMessage, 0, tempChar+2);
              readMessage[0] = firstByte;
              readMessage[1] = 0xA0;
              readMessage[2] = tempChar;
              messageLen = ((uint32_t)(tempChar))+2;
              readCnt = 3;

              while ( readCnt < messageLen && ((millis() - start_time) < timeout)) { // minimum len 120 chars for 0x7E format
                if (IR.available()) {
                  readMessage[readCnt] = IR.read();
                  readCnt++;

                  if(readCnt == tempChar+2 && readMessage[readCnt-1] != lastByte) { // correct len but last byte not 0x7E
                    done = true;
                    SerialDebug.printf("Wrong end byte found - %d\n", readMessage[readCnt-1]);
                  } else if(readCnt == tempChar+2) { // correct len and correct last byte
                    done = true;
                    char str[251] = "";
                    array_to_string(readMessage, readCnt, str);
                    mqttClient.publish("smartmeter/raw", 0, false, str);
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  mqttClient.publish("smartmeter/online", 0, true, "yes");
  char heap[6] = "";
  itoa(ESP.getFreeHeap(), heap, 10);
  mqttClient.publish("smartmeter/freeHeap", 0, false, heap);
}

```

I'm getting the encoded HEX-data published on my MQTT Topic as desired, the outputs length is 250 characters long (= 125 Bytes) which is correct:

> 7ea07bcf000200231362b1e6e700db08534d536770075f626120000e32e62addedaede38e64c8c3173035a0a853851a28efc57f7fd76a9df59dbb152f796939328ff0f28df7f257d20b5cb2a458c4eb9188e2c1c251701c891244d859ed9c159714bb4451c090d9b1ed3bbb1fc89785ebafbf59ec4f9d540eb4c90d47e

As I found out, the ESP's heap is decreasing by 100-300 by each iteration of the loop (data is being transmitted every second via Infrared from the power-grid Smartmeter) until the ESP will eventually be rebooted by the watchdog after like 5-8 minutes.

I explicitly did not use String variables in the sketch but I legit cannot find the reason for the memory leak. Tried turning off wifi, webserver and mqtt one after each other which didn't actually made a difference.

The heap-size stays at a constant level though when there is no data being received via the Infrared serial port, so I imagine something is fishy when storing the data in the byte array "readMessage".

Anything obvious that immediately pops into someones eye that I missed?

# Answer
> 2 votes
You do a `new` inside the loop

```
 readMessage = new byte[tempChar+2];

```

which causes the heap to be filled with `tempChar+2` bytes, but you never delete this.

Try reusing this memory (making it a local, or make it 'dirty' global).

Probably (not tested) the above line can be rewritten as:

```
byte readMessage[tempChar+2];

```

---
Tags: esp8266, programming, memory, serial-data, infrared
---


title: Weak Arduino output pins

text:
# Question
Title: Weak Arduino output pins
I've been learning Arduino for a while, and for my next project I'm attempting to build a drone. When I tested the motors that I purchased before, they seemed to work fine using the PWM pins and I saw no need for a motor driver.

However, now, a week later, the PWM pins are much too weak. I've set them to OUTPUT mode and HIGH.

Should the basic digital output pins be able to run fairly small drone motors like mine?

# Answer
The Absolute Maximum is 40 mA per pin, but you shouldn't go even close to that; max. 20 mA per pin is about where you want to be. Total current (all pins) shouldn't exceed 200 mA.

Only you know what current your "fairly small" motors pull, but you may have fried a few IO pins.

Also, you need flyback (or maybe bidirectional TVS) diodes and a few capacitors on your motors to keep noise and inductive kick-back away from your pins. Motor driver modules often have these installed, but your Arduino pins don't. Inductive kick-back can easily kill IO pins also.
> 3 votes

# Answer
Time to purchase another Arduino or use the other pins. Before you connect the new one you need to get a method of driving the motors. Keep in mind they are inductive and will reverse polarity and kick back a voltage that will keep rising until adsorbed. If you will be reversing them pick a MOSFET bridge to drive them. If just on/off/PWM pick a Logic rated avalanche rated N-Channel MOSFET with a high enough voltage and current rating. If your Arduino is 3V3 you need to be sure the gate will be on at about 2.5V. Connect all the grounds together and connect the source of the MOSFET to ground as well. Place something in the 25-50 Ohm resistor from the Arduino pin to the Gate of the MOSFET. Then connect the motor to the drain and the appropriate + supply. No diodes need as it has one built into the MOSFET designed for this. If you want the MOSFET off place something like a 10K resistor from the Arduino pin to ground. Remember a Power Supply the Arduino is NOT! While you are waiting on the parts go through several tutorials on the arduino and motors. There are some good ones and some not so good.
> 0 votes

---
Tags: arduino-uno, motor, pwm, current
---


# Question
Title: Differences between two common RS485 to TTL modules
I want to "translate" existing code that utilizes one of these modules for the other module.

Specifically, I have code that utilizes an "RS485 to TTL converter". As you can see in this picture:

The side that connects to the Arduino has four pins, VCC, GND, TX, and RX, but out of those pins, only two are data pins.

However, if we look at the MAX485 module:

The Arduino side has four pins as well, DI, DE, RE, and RO. However, all four of these pins are data pins.

Since the protocol is the same, how come the pins are different?

In the "RS485 to TTL converter" code, `SoftWareSerial` is being used, and it gets the two pins that will eventually connect to the TX and RX on the module as arguments.

How can I translate this code for the MAX485? How should the pinout be?

**EDIT:** I find it funny that I won the "notable question badge (question with 2500 views)"... And then I look and it has a -1 rating. lol

# Answer
So far as I'm able to tell, your first module must have a feature that automatically enabled RS485 driver when you are sending and disabled it as soon as you aren't. This is not an uncommon feature.

The latter doesn't support it apparently. It looks like a common MAX485 type design which doesn't. Instead it exposes driver enable and receiver enable pins. These are normally active at opposite levels, which allows you to tie them together and run them to a single pin on the Arduino for controlling both at the same time. Any code that you had using the prior module would need to be changed to manually enable the driver when sending and then disable it afterwards.

You would need an extra digital pin (`PIN_DE_RE`) connected from the Arduino to the module, to both of its RE and DE pins. It would need to be set to output in `setup()` with `pinMode(PIN_DE_RE, OUTPUT);` And set to low `digitalWrite(PIN_DE_RE, LOW);` for a chip following the MAX485 design such that the receiver is enabled and driver disabled initially.

Your write transactions would then need to look like this:

```
delayMicroseconds(10);
digitalWrite(PIN_DE_RE, HIGH);
delayMicroseconds(10);
your_serial.write(whatever); // or .print etc
your_serial.flush();
delayMicroseconds(10);
digitalWrite(PIN_DE_RE, LOW);
delayMicroseconds(10);

```

You *may* not need explicit delays around the `digitalWrite` since `digitalWrite` is often slow enough anyway, but the point of them is to give support the minimum time needed between changing the RE/DE pins and a transaction. I picked 10uS somewhat arbitrarily. More than anything it's just there to raise the point that the timing between the signal change and sending/receiving is important.

For `SoftwareSerial` `.flush()` does nothing usually, at least it doesn't on the AVR. But I include it just to make the point that whatever you use to send serial you must make sure the transaction has left the actual device and not merely been queued for send before disabling the RS485 driver. If you were doing this with `Serial1` on a Leonardo/Micro/Mega etc it would be important. I'd leave `.flush()` as is for `SoftwareSerial` in part because it won't cost you anything to do so and it will make things work if you switch to a buffered-output type serial connection.
> 4 votes

# Answer
RS485 is a standard for a communication bus with potentially multiple senders, of course not at the same time. As such, a device needs to disable its transmitting circuit to let others communicate. The application layer protocol is not defined by RS485.

For this reason, a good driver module provides two control inputs beside the data lines:

* DE is "driver enable". It needs to be active, if the device wants to drive the bus and send its message.
* RE is "receiver enable". It needs to be active, if the device wants to listen to the bus and receive some message.

The data lines are commonly denoted like this:

* DI is "driver input". If you use the ubiquitous serial communication, this is the same as TXD.
* RO is "receiver output". If you use the ubiquitous serial communication, this is the same as RXD.

---

How does this work in the module that only has TXD and RXD?

Well, the hardware assumes some specific baud rate, which should be documented.

As soon as the start bit is detected on TXD, the module internally activates the driver (DE). It might additionally disable the receiver (RE) to avoid reception of the message as an echo.

This activation is controlled by a timer that lasts at least as long as the transmission at the specific baud rate needs to be sent.

---

Now, what to do with the MAX485 module's control lines?

You can connect TXD to DI and RXD to RO, respectively.

If your module simply uses the driver chip manufactured by Maxim, the control input RE has actually inverted logic. This means, the receiver is active, if the line is low. In contrast, the driver is active, if the line DE is high.

Put appropriate calls of `digitalWrite()` at the places where you want to send something to the sensor. Please be aware that the transmission needs some time. You need to make sure that all bits are sent before you disable the driver.

If you only want to receive from the sensor, just disable the driver and enable the receiver all the time.
> 2 votes

---
Tags: rs485
---


# Question
Title: digitalWrite giving different output voltages between programs
I'm using an arduino uno R3 for lighting a few LEDs in response to coputer control. I've written two programs, the first to try an Object Oriented style, and the second to split up the code into more manageable chunks. They both implement the same function, turning one led on, then off and repeat for the other led. I'd also put 100uF capacitors between the anode and ground of each led for a fade effect. When running with the first sketch this works fine, but I noticed with the second sketch, the fade no longer works and the leds are much brighter. There was no change in hardware between sketches, and reverting to either doesn't change anything. On inspection with a multimeter there appears to be a large difference in output voltage (1.6v -\> 5.2v) between programs. I've tried changing pins and this seems to have no effect. Is it the code or have I missed something obvious with the hardware?

Program 1

```
#include "Arduino.h"
// create signal class
class two_aspect_signal {
  //store pin numbers
  const int danger_aspect;
  const int clear_aspect;

  public:
    two_aspect_signal(int danger_pin, int clear_pin):
      danger_aspect(danger_pin),
      clear_aspect(clear_pin)
    {}
    void setup(){
      //set to output
      pinMode(danger_aspect,OUTPUT);
      pinMode(clear_aspect,OUTPUT);
    }

    void danger(){
      //turn red light on, green light off
      digitalWrite(danger_aspect,HIGH);
      digitalWrite(clear_aspect,LOW);
    }

    void cleaR(){
      //turn red light off, green light on
      digitalWrite(danger_aspect,LOW);
      digitalWrite(clear_aspect,HIGH);
    }
};
//create signal object
two_aspect_signal sig(7,8);
void setup() {
}
void loop() {
  //turn red light on, green off
  sig.danger();
  delay(2000);
  //turn green light on, red light off
  sig.cleaR();
  delay(2000);
}

```

Program 2

```
#include "sig2.h"
//create signal object
two_aspect sig(7,8);
void setup(){}
void loop() {
  // set red light on, green off
  sig.danger();
  delay(2000);
  // set green on, red off
  sig.cleaR();
  delay(2000);
}

```

Program 2 (sig2.cpp)

```
#include "Arduino.h"
#include "sig2.h"

two_aspect::two_aspect(int clear_pin, int danger_pin)
{
  //set pins to output and store
  pinMode(danger_pin,OUTPUT);
  pinMode(clear_pin,OUTPUT);
  _danger_pin = danger_pin;
  _clear_pin = clear_pin;
}

void two_aspect::danger()
{
  //set red light on, green off
  digitalWrite(_danger_pin,HIGH);
  digitalWrite(_clear_pin,LOW);
}
void two_aspect::cleaR()
{
  //set green led on, red led off
  digitalWrite(_danger_pin,LOW);
  digitalWrite(_clear_pin,HIGH);
}

```

Program 2 (sig2.h)

```
#ifndef sig2_h
#define sig2_h

#include "Arduino.h"

class two_aspect
{
  public:
    two_aspect(int clear_pin, int danger_pin);
    void danger();
    void cleaR();
  private:
    int _clear_pin;
    int _danger_pin;
};

#endif

```

Please let me know if this should've been in the electronics forum, thanks for reading.

# Answer
The difference is, that in your first sketch you never call `two_aspect_signal.setup()`, thus the pins are never set as output. By default pins are configured as inputs. Doing `digitalWrite()` while the pin is configured as input will enable or disable the internal pullup resistor of that pin.

So in your first sketch you are powering the LEDs through the internal pullup resistor (if I correctly remember about 10kOhm). Thus they are rather dim. Also it takes some time for the capacitor to be charged through the big pullup resistor.

In your second sketch you configure the pins as output. So the LEDs will now be actively driven through the pins output driver. It can provide way more current than the pullup resistor, thus the LEDs light up brigther. And the bigger current can also charge the capacitor in way less time (a time so small, that you don't even see it). Thus you don't see any fading (the fading is there, but just too fast for your eyes).

**What to do know?** You can of course just use the pullup resistor (and not configuring the pins as output). Or you can configure the pins as outputs and add a current limiting resistor between the pin and the LED/capacitor bundle. With your second sketch and the current circuit you are risking to damage the output drivers of that pin (through the LED current and through the high inrush current until the capacitor is charged). The sizing of that resistor depends on your needs. Make sure, that the current never exceeds 20mA (sustainable pin max current) (for 5V this would be R=U/I=5V/20mA=250Ohm as minimum resistance). The higher the resistance, the dimmer the LED will be and the longer the capacitor needs to charge. After that you can also change the capacitance. The higher the capacitance, the longer it will take to charge it (so longer fade effect).
> 0 votes

---
Tags: arduino-uno, digitalwrite
---


# Question
Title: Arduino cannot connect to port (arduino nano rp2040)
My arduino cannot connect to any port of my computer. So far i tried the following, without any luck:

1. Using another arduino to check the usb, and it worked. So no problem with usb cable.
2. Resetting the arduino (double tap the reset-button)
3. Inserting deleting and updating the drivers from the device manager
4. Deleting the drivers, and then inserting the arduino while pressing the reset button.
5. Connecting the arduino to a different pc and it still doesn't work.
6. I followed everything listed here. (Resetting, uploading a uf2 blink file). I even compiled my blink uf2 file, with the newest version of mbed os for rp2040. And i even tried with older versions of the mbed os.
7. I tried uploading a flash\_nuke.uf2 file

Is there something else i can do? Or is it permenantly damaged?

When i connect to to the computer, this comes up:

In my device manager, i see the following:

Also, in the IDE, i cannot select any port.

**Extra info :** I was trying to use Serial2 from another arduino to this, so i was changing some jumper wires while they were powered. So it is possible it is damaged. I also tried uploading some sketches to use a second serial with some modifications to the core of the OS. The changes were on the spirit of this post, but not necessairily the same.

# Answer
> 1 votes
The RP2040 doesn't have a USB serial port *unless you program it to have one*.

Unlike "traditional" Arduinos the RP2040 uses the UF2 bootloader system. This involes the RP2040 pretending to be a USB flash drive, and then uploading code is as simple as copying the .UF2 file to that drive.

If you are seeing that drive then the chip is ready and waiting for you to upload code. You don't need to select a port in the IDE to upload the code since the port is not used for uploading (only for resetting the board to enter the bootloader mode, which you don't need since you are already in bootloader mode).

If the IDE is struggling to find the virtual flash drive then just find the .UF2 file that the IDE created and manually drag and drop it to that drive and it will program the code onto the drive for you.

# Answer
> 0 votes
I had the same issue, even after following all the possible RESET/HARD RESET/BOOTLOADER procedures. I have found a solution for this board to regularly work under Windows, and this involves reintalling it as a DIFFERENT board.

What I became aware of, is that my Win OS (8.1) was not properly installing the Arduino Nano RP2024 driver, for reasons unknown. So, I was first trying to manually reinstall the driver after searching for the proper .inf driver file, which is located in "C:\Users\<USERNAME\>\AppData\Local\Arduino15\packages\arduino\hardware\mbed\_nano\3.2.0\drivers". Unfortunately this come up with the same issue.

So I went for a "fake" manual install of the device, by selecting "Manually choose from a list of device drivers in your PC". I then selected "Ports (COM and LPT)", because this is how you would like your board to behave under your OS. THIS STEP IS ESSENTIAL. As far I could see, if you simply chose the Nano RP2024 .inf file located in the above folder, the boards will continue in not showing up in the COM ports list.

After this step, I went through a list of vendors, finding several Arduino-like entries. Among these, I selected "Arduino SA", which ws containing "Arduino Nano 33 BLE" as a device, which I found to be a working option. The board is now regulary showing up into the IDE, even after several connect/disconnect cycles, and also the serial monitor works.

NOTE: in case you select a different working mode of the board (e.g. HID peripheral such as mouse, keyboard or similar) you may have to reinstall it following the procedure above.

Hope this helps! Cheers Attila

---
Tags: usb, hardware, windows, arduino-nano-rp2040
---


# Question
Title: Arduino Square Wave Phase Shift by 270 degrees
I am using this code to generate a square wave with Arduino and shift it by 90 and 180 degrees. However, this code is not able to shift it to 270 degrees. Could you please suggest how may I modify the code so that it supports a 270 degrees square wave phase shift operation.

```
void setup() {
  pinMode( 9 , OUTPUT );    // Arduino Pin  9 = OCR1A
  pinMode( 10 , OUTPUT );   // Arduino Pin 10 = OCR1B
  // Both outputs in toggle mode
  TCCR1A = _BV( COM1A0 ) |_BV( COM1B0 );
  // CTC Waveform Generation Mode
  // TOP=ICR1
  // Note clock is left off for now
  TCCR1B = _BV( WGM13) | _BV( WGM12);
  OCR1A = 0;    // First output is the base, it always toggles at 0
}
// prescaler of 1 will get us 8MHz - 488Hz
// User a higher prescaler for lower freqncies

#define PRESCALER 1
#define PRESCALER_BITS 0x01
#define CLK 16000000UL    // Default clock speed is 16MHz on Arduino Uno

// Output phase shifted wave forms on Arduino Pins 9 & 10
// freq = freqnecy in Hertz (  122 < freq <8000000 )
// shift = phase shift in degrees ( 0 <= shift < 180 )
// Do do shifts 180-360 degrees, you could invert the OCR1B by doing an extra toggle using FOC
/// Note phase shifts will be rounded down to the next neared possible value so the higher the frequency, the less phase shift resolution you get. At 8Mhz, you can only have 0 or 180 degrees because there are only 2 clock ticks per cycle.
int setWaveforms( unsigned long freq , int shift ) {
  // This assumes prescaler = 1. For lower freqnecies, use a larger prescaler.
  unsigned long clocks_per_toggle = (CLK / freq) / 2;    // /2 becuase it takes 2 toggles to make a full wave
  ICR1 = clocks_per_toggle;
  unsigned long offset_clocks = (clocks_per_toggle * shift) / 180UL; // Do mult first to save precision
  OCR1B= offset_clocks;
  // Turn on timer now if is was not already on
  // Clock source = clkio/1 (no prescaling)
  // Note: you could use a prescaller here for lower freqnencies
  TCCR1B |= _BV( CS10 );
}
// Demo by cycling through some phase shifts at 50Khz
void loop() {
  setWaveforms( 40000 , 0 );
  delay(1000);
  setWaveforms( 40000 , 90 );
  delay(1000);
  setWaveforms( 40000 , 180 );
  delay(1000);
}

```

# Answer
The Arduino can only shift across a range of 180 degrees in CTC-mode using a 16 bit Timer. If you shift one channel to 90 degrees (other OCR set to 1, not zero) and then add a logic-inverter, you'll get the equivalent of 270 degrees as mentioned by Edgar Bonet.

As for using FOC (forced output compare), Edgar B. is again correct. It's possible to preset a channel as inverted, then perform the shift with an OCR set for 90 degrees -- you won't need an extra logic inverter. But this method is not for someone new. You'll want an O-Scope handy to make it work (and some time to study FOC and CTC mode-12).

I think it easier to use a single section from a 7404 hex-inverter to flip your 90 degree shifted waveform to 270.

Search for "Phase Shift Square Waves" and you'll find a VIDEO (as of 2022) for an example project that uses FOC tactics to create runtime-adjustable phase shifts on an Arduino. Perhaps you'll see a way to make an easy code change for the flipped-phase you want...

FWIW `stockvu`
> 1 votes

---
Tags: arduino-uno, communication, signal-processing, software
---


# Question
Title: Difference between data type int and long on Arduino
I was learning to program for a *void obstacle robot* but when I looked at the code I saw two data types long and int.

Int are datatypes that holds -2,147,483,648 to 2,147,483,647. Long are also datatypes that holds -2,147,483,648 to 2,147,483,647.

Int and long are like same but I came up with the code where two types of datatype is used as seen below:

```
int trigPin = 2;
int echoPin = 4;
long duration, cm, inches;

```

But how can you know when to use which datatype? I searched a lot in the web but I didn't understand so can someone explain this to me please.

# Answer
> 8 votes
On the Arduino (AVR models) an `int` is 16 bits, not 32 bits. Thus it goes from -32768 to +32767.

That is **different** from `long` which is 32 bits.

# Answer
> 5 votes
According to the C language specification, `int` must be at least 16 bits or longer and `long` must be at least 32 bits or longer.

It is OK for a compiler to implement `int` as 32 bits or even 64 bits. It is OK for a compiler to implement `long` as 64 bits or longer. But it is not allowed for a compiler to implement `long` as 16 bits.

So when to use which type?

If the values you will be working with can be represented within 16 bits then it's OK to use `int`. If you need more than 16 bits use `long`. If you need more than 32 bits use `long long`.

Do not be caught up with compiler and/or CPU specifics. As mentioned by others, even within the same product range, Arduinos, there are 16 and 32 bit CPUs available. Instead, only trust what the standard guarantees.

The full specification of types in C are:

* `char` must be at least 8 bits
* `int` must be at least 16 bits
* `long` must be at least 32 bits
* `long long` must be at least 64 bits

Note: It is perfectly legal for compilers to implement char, int, long and long long as 64 bits. This is in fact not uncommon among DSPs.

# Answer
> 4 votes
`int` in AVR GCC is **16** bits, *not* 32.

# Answer
> 3 votes
It's the same reasoning as in C: the size of the `int` type is expected to be *the natural word size that your system handles most efficiently*. It must also be at least 16 bits wide, no smaller than a `short`, and no larger than a `long`.

So an `int` may be 16-, 32-, or 64-bits, based on the whatever your system handles best, and so is most likely to be 16 bits wide on an 8- or 16-bit CPU, 32 on a 32-bit CPU etc.

I use `int` when I want the best performance, whilst taking care to guard when I need more range than offered by 16 bits. These days, you tend to know when you are writing application code for 16-bit systems, although that's not so true for "library" code where portability may be of greater concern.

In your example, assuming the author had chosen their types carefully, the `int` variables probably require a small range and could afford to be word-size, leading to potentially shorter or faster code (or both). The `long` ones presumably required more than 16-bit range (they are guaranteed to be at least 32 bits wide). On the processor you'd selected as a compilation target, it looks like `int` and `long` were both implemented as 32-bit; this would be different (or *should* be) if you selected a 16-bit target CPU.

# Answer
> 2 votes
I like to use types from `stdint.h`.

While they do have minor drawbacks, the benefit they provide is you know exactly the size your are handling, even when compiling on other architectures.

```
#include <stdint.h>

uint8_t  my_byte = 0xf0;
int16_t  trig_pin = 2;
int16_t  echo_pin = 4;
uint32_t duration, cm , blah;
uint64_t big_int;

// etc.

```

But obviously you don't want to be moving around a bunch of int32\_t when your data only needs int16\_t.

# Answer
> 0 votes
if you are using Esp32 boards in Arduino IDE:

---
Tags: programming, c++
---


# Question
Title: Standalone ATMega328 - do I need to burn the bootloader?
I want to get an ATMega328 off of the Digi-Key, and use it like an Arduino (without requiring the whole Arduino board).

When it comes to programming, do I need to do anything special like burn the bootloader onto it or something like that?

I want to use the Arduino IDE to program it.

# Answer
> 2 votes
At the risk of having my answer closed as "link only" I want to tell you that I have a page describing how to make an Atmega328P into an Arduino-compatible board.

There is far too much detail to post here, but once you have installed your processor with a resistor and a couple of decoupling capacitors you can use another Arduino to burn the bootloader.

Once you have done that you can use an FTDI cable to program your new Arduino-compatible from the Arduino IDE. The cable would be hooked up like this:

Now you can program the chip just using the IDE as if it was a "real" Arduino.

# Answer
> 0 votes
No, you do NOT need to burn the bootloader. But depending on your equipment and programing habits you may want to.
The bootloader used by Arduino (which is known by the name 'optiboot') is used to allow to program the microcontroller via serial interface. If you want to program your microcontroler this way, then you need the bootloader. Otherwise you will need a programmer for In-System-Programing that uses the SPI interface like Atmel AVRISP MKII, any cheap clone like USBtinyISP or any regular Arduino with ArduinoISP flashed on it.

---
Tags: arduino-uno, arduino-mega, arduino-ide, atmega328, bootloader
---


# Question
Title: Serial comm UART1 works on Arduino but makes ESP32 continuously reboot
This comm sketch simply read incoming bytes from the UART 1 where a device is attached. It works normally on a real Arduino device. But on ESP32, it makes it continuously reboot with the following messages:

(\[UPDATE\] Note that there is no reboot on ESP32 is I use Serial2 instead of Serial1)

```
9:13:19.676 -> ets Jun  8 2016 00:22:57
19:13:19.676 ->
19:13:19.676 -> rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
19:13:19.676 -> configsip: 0, SPIWP:0xee
19:13:19.676 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
19:13:19.676 -> mode:DIO, clock div:1
19:13:19.676 -> load:0x3fff0018,len:4
19:13:19.676 -> load:0x3fff001c,len:1216
19:13:19.714 -> ho 0 tail 12 room 4
19:13:19.714 -> load:0x40078000,len:10944
19:13:19.714 -> load:0x40080400,len:6388
19:13:19.714 -> entry 0x400806b4
19:13:19.786 -> Yo! from serial UART 18/19
19:13:19.786 -> SbmDi⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮@D@⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮
@%cGuru Meditation Error: Core  1 panic'ed (IllegalInstruction). Exception was unhandled.
19:13:19.823 -> Memory dump at 0x400e90f4: ffffffff ffffffff ffffffff
19:13:19.823 -> Core 1 register dump:
19:13:19.823 -> PC      : 0x400e90f8  PS      : 0x00060530  A0      : 0x800d1529  A1      : 0x3ffb1f80
19:13:19.823 -> A2      : 0x3ffbfe88  A3      : 0x3ffbfe6c  A4      : 0x0001c200  A5      : 0x0800001c
19:13:19.823 -> A6      : 0x00004e20  A7      : 0x00000000  A8      : 0x800d0c4f  A9      : 0x3ffb1f60
19:13:19.857 -> A10     : 0x3ffbfe6c  A11     : 0x3f40013b  A12     : 0x0800001c  A13     : 0x00000009
19:13:19.857 -> A14     : 0x00000009  A15     : 0x00000000  SAR     : 0x00000016  EXCCAUSE: 0x00000000
19:13:19.857 -> EXCVADDR: 0x00000000  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffbd
19:13:19.857 ->
19:13:19.857 -> ELF file SHA256: 0000000000000000
19:13:19.857 ->
19:13:19.857 -> Backtrace: 0x400e90f8:0x3ffb1f80 0x400d1526:0x3ffb1fb0 0x400860ed:0x3ffb1fd0
19:13:19.891 ->
19:13:19.891 -> Rebooting...

```

Here's my code:

```
#include <Arduino.h>

#define SbmDisplaySerial Serial1

void setup() {
  Serial.begin(115200);
  //Serial.setDebugOutput(true);
  Serial.println("Yo v0.0.1! from serial UART 18/19");

  SbmDisplaySerial.begin(9600, SERIAL_8N1);//, 16, 17);

  Serial.print("SbmDisplaySerial is ");
  Serial.println(SbmDisplaySerial);
}

int _loop = 1;

void loop() {
  // put your main code here, to run repeatedly:
  Serial.print("Loop #"); Serial.println(_loop++);
  delay(1000);

  if (!SbmDisplaySerial.available()) {
    delay(2000);
    Serial.println("No byte avail from the UART, looping…");
    return;
  }

   int b = 0;

   Serial.print("Synching with message limit (waiting for 0xA5 (165) header byte): ");
   int i=0;
   do {
     delay(10);
     b = SbmDisplaySerial.read();
     Serial.print(b);
     Serial.print(" ");
     if (i%128==0) Serial.println();
      i++;
   }
   while(b!=0xa5);

  Serial.println("Ok, packet started!");
  Serial.print("Received bytes: ");
  Serial.print(b);
  Serial.print(" ");

  int soc = 0;
  int voltage = 0;
  int current = 0;
  int capacity = 0;

  for(int i=1; i<16; i++) {
    b = SbmDisplaySerial.read()&0xff;

    Serial.print(b);
    Serial.print(" ");

    switch(i) {
      case  0: Serial.print("Header byte 0xA5");
        voltage = 0;
        current = 0;
        capacity = 0;
      break;
      case  1: soc = b; Serial.print("(SoC: ");  Serial.print(soc); Serial.print("%) "); break;

      case  2: voltage = b<<8; break;
      case  3: voltage |= b;  Serial.print("(");  Serial.print(float(voltage)*0.01); Serial.print("V) "); break;

      case  4: capacity = b<<24; break;
      case  5: capacity = b<<16; break;
      case  6: capacity = b<<8; break;
      case  7: capacity |= b;  Serial.print("(");  Serial.print(float(capacity)*0.001); Serial.print("A.h) "); break;

      case  8: current = b<<24; break;
      case  9: current = b<<16; break;
      case 10: current = b<<8; break;
      case 11: current |= b;  Serial.print("(");  Serial.print(float(current)*0.001); Serial.print("A) "); break;

      //case 12: current = b<<8; break;
      //case 13: current = b<<8; break;
      //case 10: current |= b;  Serial.print("(TOA: ");  Serial.print(float(current)*0.001); Serial.print("Seconds) "); break;
    }

    if (!SbmDisplaySerial.available()){
      delay(2000);
      Serial.print(" No more byte prior reaching 16 bytes, looping…");

      break;
    }
  }

  Serial.println("Waiting for next packet");
  delay(10000);

}

```

*\[UPDATE\]* When ran on Arduino, I get typical logs as follows:

```
11:20:18.217 -> Yo v0.0.1! from serial UART 18/19
11:20:18.217 -> SbmDisplaySerial is 1
11:20:18.217 -> Loop #1
11:20:19.204 -> Synching with message limit (waiting for 0xA5 (165) header byte): 0
11:20:19.204 -> 0 0 0 0 165 Ok, packet started!
11:20:19.275 -> Received bytes: 165 28 (SoC: 28%) 4 251 (12.75V) 0 0 54 248 (14.07A.h) 255 255 0 0 (0.00A) 0 0 0 0 Waiting for next packet
11:20:29.263 -> Loop #2
11:20:30.266 -> Synching with message limit (waiting for 0xA5 (165) header byte): 0
11:20:30.266 -> 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 165 Ok, packet started!
11:20:30.508 -> Received bytes: 165 28 (SoC: 28%) 4 251 (12.75V) 0 0 182 0 (46.59A.h) 0 0 0 0 (0.00A) 0 0 0 0 Waiting for next packet

```

# Answer
Here is what I've ended up with: I dropped Serial1 as I did not find anyway to make it run and I switched to Serial2, where everything works as expected.
> 1 votes

# Answer
```
#define SER1_RX 35
#define SER1_TX 32

void setup()
{
    Serial.begin(115200);                       //
    Serial.setDebugOutput(1);

    // For Serial1, be sure to set the communication port.
    Serial1.begin(115200, SER1_RX, SER1_TX);    // set the communication port
}

```
> 0 votes

---
Tags: serial, esp32, uart
---


# Question
Title: I'm using nRF2401 and in my transmitter and receiver the Rx is not blinking and Tx is blinking; why does Rx not blink?
I did a search on the meaning of RX and TX and it seems TX means sending data and RX means receiving data. So when my transmitter is turned off, my receiver looks like this and it works with a battery:

and when I turn on the transmitter my receiver looks like this:

So Tx is blinking and I'm confused, because Rx is not blinking and I think I receive nothing.

receiver code:

```
#include <RF24.h>
#include <SPI.h>

int speedpin1=5;
int dir11=3;
int dir12=7;

int speedpin2=A4;
int dir21=8;
int dir22=A3;

int speedpin3=A2;
int dir31=A1;
int dir32=A0;

int speedpin4=2;
int dir41=4;
int dir42=6;

int mspeed;

const byte CE = 9;
const byte CS = 10;

int data[1];

RF24 Radio(CE,CS);
const byte address[6]="00001";

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
pinMode(speedpin1,OUTPUT);
pinMode(dir11,OUTPUT);
pinMode(dir12,OUTPUT);

pinMode(speedpin2,OUTPUT);
pinMode(dir21,OUTPUT);
pinMode(dir22,OUTPUT);

pinMode(speedpin3,OUTPUT);
pinMode(dir31,OUTPUT);
pinMode(dir32,OUTPUT);

pinMode(speedpin4,OUTPUT);
pinMode(dir41,OUTPUT);
pinMode(dir42,OUTPUT);

Radio.begin();
Radio.openReadingPipe(1,address);
Radio.startListening();
}

void loop() {
  // put your main code here, to run repeatedly:
if(Radio.available()){
  Radio.read(data,sizeof(data));
  if (data[0]>131){

    digitalWrite(dir41,LOW);
    digitalWrite(dir42,HIGH);

    analogWrite(dir31,0);
    analogWrite(dir32,255);

    digitalWrite(dir21,HIGH);
    analogWrite(dir22,0);

    digitalWrite(dir11,HIGH);
    digitalWrite(dir12,LOW);

    mspeed=255;

    analogWrite(speedpin1,mspeed);
    analogWrite(speedpin2,mspeed);
    analogWrite(speedpin3,mspeed);
    analogWrite(speedpin4,mspeed);
    Serial.println(mspeed);

  }
  if (data[0]<131){

    digitalWrite(dir41,HIGH);
    digitalWrite(dir42,LOW);

    analogWrite(dir31,255);
    analogWrite(dir32,0);

    digitalWrite(dir21,LOW);
    analogWrite(dir22,255);

    digitalWrite(dir11,LOW);
    digitalWrite(dir12,HIGH);

    mspeed=255;

    analogWrite(speedpin1,mspeed);
    analogWrite(speedpin2,mspeed);
    analogWrite(speedpin3,mspeed);
    analogWrite(speedpin4,mspeed);
    Serial.println(mspeed);

  }
  if (data[0]==131){

    mspeed=0;
    analogWrite(speedpin1,mspeed);
    analogWrite(speedpin2,mspeed);
    analogWrite(speedpin3,mspeed);
    analogWrite(speedpin4,mspeed);
    Serial.println(mspeed);

  }

}

```

transmitter code:

```
#include <RF24.h>
#include <SPI.h>
const byte CE = 9;
const byte CS = 10;
int jpin=A0;
int datax;
int data[1];

RF24 Radio(CE,CS);
const byte address[6]="00001";
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
Radio.begin();
Radio.setRetries(5,10);
Radio.openWritingPipe(address);
}

void loop() {
  // put your main code here, to run repeatedly:
datax=analogRead(jpin);
datax=map(datax, 0, 1023, 0, 255);
data[0]=datax;
Serial.print("data x: ");
Serial.println(data[0]);
Radio.write(data,sizeof(data));

}

```

I'm using nRF2401 and in my transmitter and my receiver the Rx is not blinking and Tx is blinking; why does Rx not blinking?

I also don't know that why does Tx in my receiver not blinking when I move the joystick in my transmitter.

I can control my motors only a few times with a Joystick and after that the Tx in my receiver does not blink and then my motors are keep working or they stop and I can't control them.

---

## Edit

# Answer
We've got multiple questions here, so:

## Why is TX/RX blinking weirdly?

The RX and TX LEDs on the Arduino Nano are connected to the RX0 and TX1 pins: they show activity on the Serial-over-USB port that connects your Arduino to the PC.

So, every time you receive data, you do a `Serial.print()`, transmitting text to the PC (where you can see that text in the Serial monitor). And *that* is what's showing up in the RX/TX LEDs: the text you send over the serial line to the PC. If you want to get RX blinking in this setup, just enter some text in the Serial monitor's input box and send it. The TX LED should blink shortly, then (maybe too short to be noticeable).

Reusing those LEDs to show activity on the wireless transceiver by writing to the RX0/TX1 pins would mean that you'll lose the Serial monitor, i.e. `Serial.print()` would no longer be possible. Not recommended.

Your best option would be to introduce your own LEDs as an activity monitor. Just add an LED in series with an 1K resistor to pins D11 and D12 each (which are the MOSI and MISO lines of the SPI interface, i.e. the equivalent of RX and TX of a serial interface).

In other words, add these components:

```
  D11 --> -LED+ --> 1K resistor --> 5V
  D12 --> -LED+ --> 1K resistor --> 5V

```

## Why does my transmission stop?

That's harder to see, but: I think you're using the RF24 library interface wrong.

According to the code example "Transmitter Lv2" on this page, `Radio.read()` and `Radio.write()` expect a *reference* to the data array, so you'd need to use `Radio.read(&data, sizeof(data))` and `Radio.write(&data, sizeof(data))` (note the ampersands).

It also may be that your transmitter is transmitting faster than your receiver can accept data, so you could try and add a `delay(5)` in the `loop()` of your transmitter.
> 1 votes

---
Tags: arduino-uno, serial, arduino-nano, motor, pins
---


# Question
Title: IF statement inside of a function call? Code help
I was browsing a library for steppers motors when I ran across this line of foreign-looking code:

```
digitalWrite(enable_pin, (enable_active_state == HIGH) ? LOW : HIGH);

```

Is this some kind of shortcut to tossing an if statement into a function call? I've never seen this before. What exactly does it do, and what is this particular arrangement of code called?

Thanks!

# Answer
> 6 votes
You could look at this as an "if expression", the correct term is "conditional operator" (C++ standard chapter 8.16). Many know it as "ternary operator" because it has three operands. You might already know the "unary operator" with one operand like the negation sign `-x`, or the "binary operator" with two operands like the addition `a + b`.

This expression consists of:

* the first operand
* the operator `?`
* the second operand
* the operator `:`
* the third operand

The first operator is evaluated and converted (if necessary) into a boolean.

If the result is `true`, the second operand is evaluated and gives the value of the expression.

If the result is `false`, the third operand is evaluated and gives the value of the expression.

Only one of the second and third operands is evaluated. This is important, if you use operands with side effects, like function calls can have.

This operator is often frowned upon. If used excessively, the source becomes easily unreadable. Many professional code style guide prohibit its use for this reason.

In your case it could have been written more clearly as

```
if (enable_active_state == HIGH) {
    digitalWrite(enable_pin, LOW);
} else {
    digitalWrite(enable_pin, HIGH);
}

```

It outputs the inverted value of the variable `enable_active_state` at the pin `enable_pin`.

Experienced Arduino users know that `HIGH` and `LOW` are represented in a way that are compatible with boolean values. Boolean inversions can be simpler expressed with the logical negation operator:

```
digitalWrite(enable_pin, !enable_active_state);

```

Anyway, the current compilers are commonly smart enough to generate the same machine code for each of the variants. Therefore, please write your source in the best way to express your intention. Anything else is "premature optimization", which is a bad thing. But this is a completely other topic.

---
Tags: c++
---


# Question
Title: Is it possible to use multiple I2C sensors with Arduino without an I2C multiplexer?
I have an IMU sensor and a Bluerobotics temperature sensor, both have different I2C addresses.

I want to integrate both with an Arduino UNO, I know I can do this with an I2C multiplexer but I don't have access to one right now.

Is it possible to integrate them with arduino without a multiplexer, i.e., by just connecting them parallelly on the A4 and A5 pins of Arduino? (This didn't work though when I tried, the temperature sensor was giving values but the values of IMU sensor were only zeros on the Arduino Serial Monitor)

I've found some videos on it on YT, some have connected pull up resistors to the sensors, but this method doesn't seem to work.

So before delving deeper into it, I'd like to know if this is even possible to do without a multiplexer, because my time is precious since I have a project deadline.

# Answer
first of all , you said they have different I2C addresses , so you don't need **I2C multiplexer** , I2C multiplexer is only used when having more than one device having same I2C address , and refer to Adafruit I2C multiplexer as they say :

> Finally, a way to get up to 8 same-address I2C devices hooked up to one microcontroller

which means it can handle 8 devices having the same address , but in your case , the addresses already are different , so why you need I2C multiplexer.

your problem needs to dig deep into debugging , you can get your self a cheap logic analyzer like this cheap 10$ saleae clone analyzer to see what data is actually put into the bus , the analyzer will make your debugging way more easy than you think , like the below picture obtained from saleae official website and also this cheap saleae clone works perfect with *logic* software offered from saleae:

but for your problem , I am guessing that it's due to pull resistors and the parasitic capacitance between the 2 buses , reading from I2C specification file, at section 7.1 , there is equation from minimum and maximum allowed pull up resistors according to nodes connected to the bus :

> Rp(min) = (Vdd - Vol(max)) / Iol
>
> Rp(max) = tr / (0.8473 * Cb)

where `Vdd` is 5V when using arduino , `tr` is the rise time maximum and it depends on MCU, `Cb` is estimated bus capacitance and you can get that from datasheet of every component in your bus line as for arduino its capacitance is specified in datasheet at page 264 saying

> Capacitance for each I/O pin Ci – 10 pF

other symbols , you can get from the I2C specifications mentioned above , but your problem is due to pull up resistors I guess and you can't really know without debugging. I recommend you using logic analyzers.
> 1 votes

# Answer
Since you did not give links I went on line and checked them. Be sure the I2C modules do not have pull up resistors. If so note the value. Adjust your external so the pull up to 3V3 is about 3.1K. You will need a level translator for both the IMU module and the Bluerobotics temperature sensor they are both 3V3 boars. Good news one set of level translators will work for both. Remember you will need pull ups on both sides of the translators, check as not all do.

Since you are just getting started you can pick one of the fine 3V3 micros in the Arduino or ESP series of boards. Simple starting point rule for pull up on I2C: 3.1K for 3V3 and 4.7K for 5V. Let us know how you do.

Bad News it is possible you damaged one or both of the I2C boards with 5V.
> 0 votes

---
Tags: i2c
---


# Question
Title: Tasks in ESP32: guidelines rather than blink example
I'm using an ESP8266 for IOT devices.

I wish to work with an ESP32 and harvest its benefits - for my uses managing WiFi and MQTT connectivity.

Most tasks examples are *very* basic and quite the same (blinking LEDs). But for a real time application, more data is needed for which I can't find a guide.

For example:

1. when to use `core0` or `core1`?
2. How to evaluate stack size needed for a task?
3. Are there any limitation for a task? Is a `mqtt.loop()` for example, ligit, memory wise?

I'd be happy to read about real life-implementations for tasks (especially "dos" and "don'ts")

Example usage from ESP32 DOCS

```
 // Dimensions the buffer that the task being created will use as its stack.
 // NOTE:  This is the number of bytes the stack will hold, not the number of
 // words as found in vanilla FreeRTOS.
#define STACK_SIZE 200

 // Structure that will hold the TCB of the task being created.
 StaticTask_t xTaskBuffer;

 // Buffer that the task being created will use as its stack.  Note this is
 // an array of StackType_t variables.  The size of StackType_t is dependent on
 // the RTOS port.
 StackType_t xStack[ STACK_SIZE ];

 // Function that implements the task being created.
 void vTaskCode( void * pvParameters )
 {
     // The parameter value is expected to be 1 as 1 is passed in the
     // pvParameters value in the call to xTaskCreateStatic().
     configASSERT( ( uint32_t ) pvParameters == 1UL );

     for( ;; )
     {
         // Task code goes here.
     }
 }

 // Function that creates a task.
 void vOtherFunction( void )
 {
     TaskHandle_t xHandle = NULL;

     // Create the task without using any dynamic memory allocation.
     xHandle = xTaskCreateStatic(
                   vTaskCode,       // Function that implements the task.
                   "NAME",          // Text name for the task.
                   STACK_SIZE,      // Stack size in bytes, not words.
                   ( void * ) 1,    // Parameter passed into the task.
                   tskIDLE_PRIORITY,// Priority at which the task is created.
                   xStack,          // Array to use as the task's stack.
                   &xTaskBuffer );  // Variable to hold the task's data structure.

     // puxStackBuffer and pxTaskBuffer were not NULL, so the task will have
     // been created, and xHandle will be the task's handle.  Use the handle
     // to suspend the task.
     vTaskSuspend( xHandle );
 }

```

# Answer
> 1 votes
> in a real time application, more data is needed which I can't find a guide for it

That is because there isn't one. The amount of memory needed is completely defined by the application and the task you want to run, so no "guide" can tell you what that will be.

You will have to analyze the actual software you want to run to see what it does and how it works to estimate the likely size of stack needed (note: stack is used for local (non-static) variables as well as storage for registers when calling functions). It's entirely up to you to work it out. The basic assumption (since the SDK is aimed at professional users not hobbyists like typical Arduino users) is that you know what your software is doing since it's you writing that software.

> when to use core0 or core1?

When you need to balance your processing load. Again that's entirely down to your software and how you need it to work. Maybe you have one task that has to have almost exclusive use of a core - in which case you bind everything except that task to the same core, and place that task on its own core. Or maybe you just want to spread the tasks out evenly. It's your choice.

> Are there any limitation for task?

Yes. The chip only has finite memory. You can't give a task more memory than there is. Also be aware that there may be a watchdog monitoring your tasks so you have to be sure to "kick" it regularly and not block too long.

---
Tags: esp32, task
---


title: compress data with 8-4-2-1-BCD-Code

text:
# Question
Title: compress data with 8-4-2-1-BCD-Code
Hello I would like to optimise a few values for transmission via radio (LoRa) beforehand. I have a sensor number (1-255), temperature (00.00-99.99) and humidity. (00.00-99.99) I would like to transmit this data compressed as a byte array. I have already calculated that I need 5 bytes via BCD for this.

How do I get my numbers mapped into the respective byte?

```
float temperature = 24.12;
float humidity = 60.12;
byte message[5];

void setup() {
  Serial.begin(9600);
  message[0] = 12; //sensor id 12
}

void loop() {
  float temperature1 = floor(temperature);
  float temperature2 = (temperature - temperature1) * 100;
  Serial.println(temperature1, 0);
  Serial.println(temperature2, 0);
  message[1] //?? temperature1
  message[2] //?? temperature2

  float humidity1 = floor(humidity);
  float humidity2 = (humidity - humidity1) * 100;
  message[3] //?? humidity1
  message[4] //?? humidity2
}

```

# Answer
Why don't you use the following mapping:

1 byte: sensor number (0-255)

2 bytes: temperature (0-65535) by mapping the temperature to

```
(int) (65536.0 * (temperature / 100.0))

```

2 bytes: humidity (0-65535) by mapping the humidity to

```
(int) (65536.0 * (humidity / 100.0))

```

You will lose a little bit of accuracy for the temperature and humidity. If you know ranges in which the temperature/humidity will be, you can get a better accuracy.

```
message[0] = 12; // Sensor id 12
message[1] = highByte(temperature);
message[2] = lowByte(temperature);
message[3] = highByte(humidity);
message[4] = lowByte(humidity);

```

Note if you have multiple sensors and have to transmit them all, you don't need to send the sensor number, send in bytes 0..3 the temperature/humidity for sensor 0, in bytes 4..7 the temperature/humidity for sensor 1 etc.
> 1 votes

# Answer
This is my final solution with BCD-Code

```
int temperature1 = int(floor(temperature));
int temperature2 = int(round((temperature - temperature1) * 100));
uint8_t bcdTemperature1 = uint8_t((temperature1/10) <<4) | (temperature1 %10);
uint8_t bcdTemperature2 = uint8_t((temperature2/10) <<4) | (temperature2 %10);

message[0] = moduleUniqueidentifier;
message[1] = bcdTemperature1;
message[2] = bcdTemperature2;
message[3] = uint8_t(ceil(humidity));

```
> 0 votes

---
Tags: lora
---


# Question
Title: Does avr-libc have any reason to word-align C++ class member variables?
This sounds straightforward enough, but I'm struggling to find a good answer.

Suppose I declare a C++ class with private members that collectively occupy an odd number of bytes. Say...

```
class Foo {
private:
    uint8_t bitflags;
    uint32_t millis;
}

```

or

```
class Foo {
private:
    uint8_t rawData[3];
}

```

If I compile it using GCC or Clang (possibly, wrapped inside the Arduino IDE, or multiply-wrapped inside PlatformIO, CMake, and an IDE like CLion), is there any likely scenario where the compiler (when targeting 8-bit AVR... specifically, the ATmega2560 on an Arduino Mega2560) would be inclined to add padding bytes to the portion of the class stored in SRAM? Say... between `bitflags` and `millis`, or between an instance of `Foo` and a `uint64_t` right after it?

If yes, what do I need to use to tell the compiler, "absolutely, positively ***DO NOT*** pad variables in SRAM (and, if you find yourself in a situation where it's seemingly unavoidable, at least output a prominent compile-time warning, if not an outright compilation-stopping error)?

Then... if I do that... are there any negative *consequences* to doing that with code that's targeting (and ultimately running upon) an 8-bit AVR?

As far as I know, 8-bit AVR has *never* had specific opcodes for copying a *pair* of consecutive bytes between registers and SRAM (I think, because Atmel literally ran out of opcode mapping space, and had nowhere to *put* hypothetical new opcodes like, "ldw rz, $f00d"), and `movw` only applied to pairs of *registers*... so, in theory, there's no reason *for* the compiler to "optimize" SRAM access to be word-aligned.

That said... I suppose it's not inconceivable that a compiler might *default* to word-alignment (even on platforms where it doesn't *matter*), just for the sake of ABI consistency between different platforms.

Before someone suggests, "try it and see!"... I've gotten far enough into learning C++ to know that with C++, you ***can't trust*** "compiles without errors and passes unit tests on *my computer*, with *{this} IDE*" as a general-purpose proof-of-correctness for C++ involving "implementation-defined" or "undefined" behavior. AFAIK, padding behavior is "implementation-defined".

# Answer
GCC has an extension to add attributes to types, which you can use to tell it your alignment requirements.

Additionally it has a `#pragma` to define the alignment, which could be used alternatively.

But as you already suspect, for this 8-bit target there should be no reason to insert padding bytes.

---

So your question boils down to find a method to detect unwanted padding. You can do this in a standard compliant way, which I show below. Yes, it does introduce additional types, one per structure. But it does not generate any unnecessary objects that eat your precious resources.

The "trick" is to use the `sizeof` operator to calculate a valid array size only, if the size of the checked type meets the expectation. If not, a compiler error safely breaks the generation of code. Granted, the error message is misleading an unsuspecting user, so it is really necessary to name the macro and the type accordingly.

This example compiles successfully with a PC as target, but not with an AVR as target. This is intentionally to demonstrate the working, because with an AVR target the type `UP` should have no padding bytes.

```
#define ASSERT_TYPE_SIZE(Type, size) \
    typedef char Assert##Type##Size[2 * (sizeof(Type) == (size)) - 1]

typedef struct {
    char c;
    long l;
} UP;
ASSERT_TYPE_SIZE(UP, sizeof (long) + sizeof(long));

typedef struct __attribute__((packed)) {
    char c;
    long l;
} P1;
ASSERT_TYPE_SIZE(P1, sizeof (char) + sizeof(long));

#pragma pack(1)
typedef struct {
    char c;
    long l;
} P2;
ASSERT_TYPE_SIZE(P2, sizeof (char) + sizeof(long));
#pragma pack()

```
> 1 votes

---
Tags: c++
---


title: Methods of programming the Arduino

text:
# Question
Title: Methods of programming the Arduino
I took a look at a barebones Arduino schematic. It had three different ways of programming the chip.

The first interface is for programming through SPI (For example with "Pocket AVR Programmer", or "USBTinyISP").

The second interface is for programming through an FTDI to USB module.

What is the third programming interface? It only has `MOSI, MISO and SCK`.

EDIT: This is a picture of the full schematic. Unfortunately, I could not find the link from which I downloaded it. I am sure it was from Github though.

# Answer
JP2 and JP8 are both serial pin headers suitable for programming -- they connect to the same pins of the chip: RXD, TXD and RST. This is programming via UART: A bootloader software (which has to be "pre-burnt" in the chip's flash memory) is the first thing that is run after a reset (RST) signal. It waits a little moment for data to arrive on RXD. If data arrives, the bootloader goes into programming mode: the data is written to flash memory, making it the firmware to be executed after the next RST. (If no data arrives: well, then the firmware that already is there is executed.)

Programming the chip via JP4 would use "hardware-supported" programming interface via SPI, recognizeable by the pins MISO, MOSI and SCK. That is the only way to get the first bootloader into the flash memory. It also provides you with a way to flash and re-flash a firmware without a pre-burnt bootloader (making the bootloader space available to your firmware). That method is described in the ATmega328P datasheet, chapter 27.8 and is the primary method employed by "ISP programmer boards". You could use those from the Arduino IDE using the menu option "Upload using programmer".

If this "barebone Arduino" circuit is meant to use an ATmega328P with the Arduino bootloader, however, I would assume that JP4 is meant to provide a pin header for some SPI sensor module (even though you could program and even un-brick the chip using this interface).

NB: "FTDI" is a red herring here. One of the most-used ISP programmer boards employs an chip made by FTDI, so you could call this method "programming via FTDI" ... but a specific USB-to-Serial cable using an chip made by FTDI and an 1x5 pin header is also called an "FTDI cable". (For a while, FTDI made the best USB-to-Serial chips. Clones just did not work that reliable. Today, CH340G and CP2104 are reliable enough for hobby projects, but somehow, "FTDI" stuck as a name.)
> 2 votes

# Answer
The 2x2 pin JP2 is connected to the Atmel 16U2 or 32U2 processor (whichever the manufacturer used) which provides the USB I/O interface to/from the Atmel 328p, the one we usually consider to be the Uno's processor. When pins are actually installed on that pad, jumpers may be placed across either or both pairs to connect the xxU2's pin-4 to pin-6, and/or pin-5 to pin-7, which connect to that processor's interrupts (numbered the same as those pins).

My searches have not yielded any answer to the question of why it was provided, other than to suggest that they may have been intended for a feature that was never implemented. You can see JP2 and its connections to the xxU2 processor in the center of this schematic.

Update:

I was looking at the 3-pin connector(?) marked '???' in your question, and JP4 on the schematic in your update. Since your schematic does not show the xxU2 chip, and the connections of '???' are marked D11, D12, and D13, I'm going to guess instead that these are either auxilliary pins to access the 328's SPI interface, or is showing half of the ICSP hardware programming interface (the 3x2 pin block just above the '328 on the schematic I linked).
> 1 votes

---
Tags: spi, ftdi, programmer
---


title: Use same pin for two purposes

text:
# Question
Title: Use same pin for two purposes
I have only one pin available and I'd need to use it both for a digitalRead and for sending serial messages (assigning it the Tx role within a SoftwareSerial). I can alternate these two operations, but I don't seem to succeed. I could be interested in other pairs as well (digitalRead+Rx, digitalWrite+Tx and digitalWrite+Rx) and I hope that understanding one will solve them all, but for now I'd be happy to get the first one working. My first naive attempt would be something like:

```
 #include <SoftwareSerial.h>

SoftwareSerial swSerial(7,6);
int val;

void setup() {

  pinMode(6, INPUT_PULLUP);

}

void loop() {

  val = digitalRead(6);

  delay(2000);

  swSerial.begin(19200);
  swSerial.print("myData");
  swSerial.end();

  delay(2000);

}

```

But I've made other experiments, for example with a digitalWrite, hoping that combining two forms of output would be feasible, but again no way. I know I can alternate a pin role between output and input as long as common digital read/write operations are involved, but SoftwareSerial appears to be less flexible. It seems to me it refuses to work as soon as the pin is declared/used for common digital purposes. Is there a way to accomplish my goal?

I guess that similar requirements and fixes (make a pin role more flexible) led to the Software Serial with Half Duplex library, but I'd refrain from adopting it because I feel it is overcomplicated and seems like overkill for my purpose, moreover it doesn't seem actively supported.

To avoid a XY problem, my very initial need (I may have further ones, requiring the different pairs mentioned at the beginning) would be to check whether this pin is floating or connected to something (I can chose between Vcc or Gnd, setting up the pull-up or an external pull-down accordingly) and to send back some information (obviously this is useful if the pin is actually connected, but I have no reason not to send data anyway) alternating the tasks a few times per second at least.

# Answer
First of all, for using the Software Serial you need to set your tx and rx pins to OUTPUT, that what the library does under the hood.

What you may try to do is to set a millis timer (forget about delay(), never ever use it) and change pin mode to INPUT once every 200ms let's say. And after your measurements put it back to output as soon as you can.

200ms delay is normally ok for some readings like button click. If you can read the value more rare do it (for example you may read some sensor value only once per hour). Here is an example:

```
    #include <SoftwareSerial.h>

SoftwareSerial swSerial(7,6);
int val;

byte timer = 200; // Read value every 200ms
uint32_t prevTime = 0;

void setup() {

    // Don't change pin mode here
    swSerial.begin(19200);

}

void loop() {

    if (millis() - prevTime > timer) {
        // you could try swSerial.flush(); here...
        prevTime = millis(); // reset timer
        pinMode(6, INPUT_PULLUP); // changing pin mode and reading value
        val = digitalRead(6);
        pinMode(6, OUTPUT); // changing pin mode back
    }

    swSerial.print("myData");
    // swSerial.end(); // I don't think you need this line;

}

```

It may be a solution from a programming point of view. But another task is to organize an electric multiplexing for 2 different devices on the same pin as was mentioned by @the busybee
> 2 votes

---
Tags: softwareserial, pinmode
---


title: Motor with ultrasonic sensor

text:
# Question
Title: Motor with ultrasonic sensor
I am new to programming so bear with me. I am writing a simple code to control a motor such that the motor will turn at full speed as long as the sensor does not detect an object within 5" of the sensor. If it does see something at 5 inches or less, then I want to motor to stop. My question is this: When using an IF statement, do you have to have the ELSE, or can you simply do two IF statements with no ELSE?

Here is my example:

---

```
int motorpin1 = 10 , motorpin2 = 11;
int trig = 12;
int echo = 9;
float distance;
float time;

void setup()
{
  pinMode (motorpin1, OUTPUT);
  //yellow wire
  pinMode (motorpin2, OUTPUT);
  //blue wire

  pinMode (trig, OUTPUT);
  pinMode (echo, INPUT);
  Serial.begin (9600);

}

void loop()
{
 // setup ultrasonic sensor to control
 //motor
  digitalWrite(trig, LOW);
  delayMicroseconds(2);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  time = pulseIn(echo, HIGH);
  distance = time/148.1;

  Serial.println(distance);

 if distance <5,digitalWrite (motorpin1, LOW);
 digitalWrite (motorpin2, LOW);

 if distance >=5, digitalWrite (motorpin1, HIGH);
 digitalWrite (motorpin2, LOW);
 delay (1000); //wait for 1 second

```

---

Is there a better way to do this with an ELSE statement? I want to capture the parameter where the code controls the specific parameters of \>5 and then \<or=5. Also, my next thing is to pause, and reverse the motor if after 1 second, the sensor still sees an object \<=5.

Definitely a learning curve for this old brain of mine!

# Answer
You can do something along the line of

```
if (distance < 5) {
    digitalWrite (motorpin1, LOW);
}
else {
    digitalWrite (motorpin1, HIGH);
}

```

It seems like you only set `motorpin2` to `LOW` and never to `HIGH`. If you don't want to set it `HIGH`, move that line to the `setup()` section. There is no need to keep setting it `LOW`.
> 1 votes

---
Tags: programming, motor, ultrasonics
---


# Question
Title: Serial communication with 2 Arduinos and one optocoupler
I just started working with Arduinos on Tinkercad in a school assignment and have non preexisting electrical knowledge. Tried to read up on the subject and I think I've gotten some of the facts straight but i still can't get them to communicate when using the optocoupler. It works fine with the code if i connect them to each other directly with the tx/rx pins.

```
//Sender code
char string[5] = {'h', 'e', 'l', 'l', 'o'};
void setup()
{
  Serial.begin(9600);
}
void loop()
{
  Serial.write(string,5);
  delay(1000);
}

```

```
//Reciving arduino code

char text[10];

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

void loop()
{
  Serial.readBytes(text,5);
  Serial.println(text);
  delay(1000);
}

```

My guess is I've done something wrong connecting the receiving Arduino but i can't find whats wrong. Any feedback is immensely appreciated!

# Answer
Here is a diagram that I would suggest you to to try it out. The transmitting Arduino pin will turn the internal infrared LED on or off depend on the whether the pin is at LOW or HIGH. When the infrared LED is on, it will turn on the phototransistor, and produce a LOW at the receiving arduino pin.

The LED is optional but it gives you a visual clue on whether you are receiving the data or not.

simulate this circuit – Schematic created using CircuitLab
> 1 votes

# Answer
EDIT: Even though the OP may be long gone, I wanted to finish what I started with my response.

This circuit works fine for me using two UNOs (and one UNO and a serial board for a PC). It is, essentially, the same as in the first response by @hcheung. I used 4.7K and 10K for R2/R4 and they worked fine. I tested it using this program running on both UNOs.

```
    #include <SoftwareSerial.h>

SoftwareSerial SSerial(4,5); // RX, TX

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

}

void loop() {
  // display whatever comes in through software serial on the Arduino monitor
  if(SSerial.available()) {
    Serial.write(SSerial.read());
  }
  // send whatever comes in on serial to software serial
  if(Serial.available()) {
    SSerial.write(Serial.read());
  }
}

```

Note that the programs use software serial and both Tx and Rx are isolated.

If you use this for the hardware serial port on two UNOs, take care. First, don't hang things on 0/1 until after the program loads and how much you can get away with is unclear to me.

Second, if you use a simple program like this, on both UNOs, you will quickly see that the first bytes sent will ping-pong and causes problems.

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

void loop() {
  if(Serial.available()){
    Serial.write(Serial.read());
  }
}

```

I note that the OP was only using one end.

Personally, I found several junk box 4N25s that would not work - that took me a bit of time to figure out. Finally, I don't see the point of optically isolating two UNOs as I did for example, but that is another story.

\______ older msg is below \_______________________________

A typical way of doing this is illustrated here .

// \*** I am leaving my original text below, but I want to back off of this a bit. I spent a few hours on this today and I am not happy with the results or my understanding. If I come to any worthwhile conclusions, I will post them. I do like getting to the bottom of things, but I was premature. It is simply not working the way I would expect when I get into 9600 speed and I need to investigate further. Yes, I am accounting for the UNO 0&1 involvement with USB.

// \***

The advantage is that you will not be inverting the line on the receiving end. The choice of R1 and R2 is important. I used R1=330 and R2=1K and transmission was fine at 9600 using a junk box 4N25. My testing was with a single UNO and after uploading a simple program.

See https://github.com/pepaslabs/Electronics/wiki/Designing-a-TTL-Serial-Opto-isolator for a good discussion on exactly this topic.

PS: As mentioned you should have submitted a schematic and you could have used a meter to see what voltages you were getting - those are good steps to understanding things.
> 1 votes

---
Tags: uart
---


# Question
Title: ArduinoJSON :: How to determine Array's size in a DOC conatinaing not only Arrays
Parameter file containing MQTT topics as shown below, is read into `StaticJsonDocument<1250> DOC` variable.

Size of some groups may differ between MCU's, for example `sub_topics_win` may contain more topics, if MCU is 8 relay unit. For that I need the flexibility to read a specific topic that can differ in size.

What is the rifht way to do it?

```
{
    "pub_gen_topics": [
        "myHome/Messages",
        "myHome/log",
        "myHome/debug"
    ],
    "pub_topics": [
        "myHome/Cont_A/Avail",
        "myHome/Cont_A/State"
    ],
    "sub_topics": [
        "myHome/Cont_A",
        "myHome/All",
        "myHome/lockdown"
    ],
    "sub_topics_win": [
        "myHome/Windows/gFloor/TwinWindow",
        "myHome/Windows/gFloor/Pergola"
    ],
    "sub_topics_SW": [
        "myHome/Light/int/gFloor/SalAmbient1",
        "myHome/Light/int/gFloor/SalAmbient2",
        "myHome/Light/int/gFloor/Lobby",
        "myHome/Light/int/gFloor/Corridor"
    ],
    "sub_topics_win_g": [
        "myHome/Windows",
        "myHome/Windows/gFloor"
    ],
    "sub_topics_SW_g": [
        "myHome/Light",
        "myHome/Light/int",
        "myHome/Light/int/gFloor/"
    ],
    "ver": 0.1
}

```

# Answer
> 2 votes
If your question is *How can I read each element of an array when I don't know its size?*, then simply use a for-loop, like so:

```
JsonArray sub_topics_win = doc["sub_topics_win"];

for (const char* topic : pub_gen_topics) {
  Serial.println(topic);
}

```

See also: JsonArray::begin() / end(), JsonArray::size().

# Answer
> 0 votes
As I understand, your question is *How can I determine the best capacity for a `JsonDocument` when my input varies?*

If that's the case, I recommend that you read How to determine the capacity of the JsonDocument?. Here is an extract from the section "What if my input varies?":

> If your program must deserialize a JSON document that changes, you must allocate a `JsonDocument` that is large enough for the largest valid input. I insist on the term *valid* because your program doesn't need to support any JSON document, but only the ones relevant to your use case.

Applying this to your problem, you need to put eight topics in each list and pass this document to the ArduinoJson Assistant, which results in a recommended capacity of 3027 bytes on ESP8266. Now, this is a bit large for a `StaticJsonDocument`, so consider switching to a `DynamicJsonDocument.`

---
Tags: json
---


title: get data from arduino using python

text:
# Question
Title: get data from arduino using python
I am trying to **read potential meter data from Arduino using python**, with the program on Arduino as follows :

```
#include <cvzone.h>

SerialData serialData;
int sendVals[2];

void setup() {
  serialData.begin(9600);
}

void loop() {
  int potVal = analogRead(A0);
  sendVals[0]= potVal;
  serialData.Send(sendVals);
}

```

the program on the arduino side is running fine

and program in python as follows

```
from cvzone.SerialModule import SerialObject

arduino = SerialObject("COM7")

while True:
   data = arduino.getData()
   print(data[0])

```

but I get this error:

```
Traceback (most recent call last):
    data = arduino.getData()
  File "C:...\site-packages\cvzone\SerialModule.py", line 68, in getData
    data = data.decode("utf-8")
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf7 in position 0: invalid start byte

```

How to solve it?

# Answer
I would embed the call to `.getData()` into a `try` block and handle this specific exception with `except UnicodeDecodeError`. There can always be a transmission error, especially when the script is started.

However, I would do it differently:

```
void loop() {
  Serial.println(analogRead(A0));
}

```

...and on the python side use `serial.readline()` from pyserial instead. But I don't know cvzone and you might have a reason to use this instead of the commonly used pyserial.
> 2 votes

# Answer
There seems that there *may* be an issue with the implementation of `getData()` in `SerialModule.py`.

From line 62

```
    def getData(self):
        """
        :param numOfVals: number of vals to retrieve
        :return: list of data received
        """
        data = self.ser.readline()
        data = data.decode("utf-8")
        data = data.split('#')
        dataList = []
        [dataList.append(d) for d in data]
        return dataList[:-1]

```

The block of code containing the `readLine()` should probably be with in a `try...except` block, like so:

```
    def getData(self):
        """
        :param numOfVals: number of vals to retrieve
        :return: list of data received
        """
        try:
            data = self.ser.readline()
            data = data.decode("utf-8")
            data = data.split('#')
            dataList = []
            [dataList.append(d) for d in data]
            return dataList[:-1]
        except Exception as e:
            print(e)
            self.ser.close

```

An issue has been raised on Github: SerialModule.py - readLine() should be within try block. #49
> 0 votes

---
Tags: arduino-mega, python
---


title: ATTiny84 I2C with NeoPixels not working

text:
# Question
Title: ATTiny84 I2C with NeoPixels not working
I fetch RGB values via I2C - which works (with a splitting function).

Now I have a problem:

* When I write values directly into strip.color() like strip.Color(255,0,0,0) the NeoPixels turn red when receiving the values.
* When I use the values from the I2C connection it won't work anymore. But the values are correct if I have a look in the Serial Monitor.

Maybe the data type is wrong or something?

```
#include <Wire.h>
#include <Adafruit_NeoPixel.h>

#define LED_PIN   4
#define LED_COUNT 4

static const int SLAVE_ADDRESS = 0x08;

uint32_t currentColor;
int currentBrightness = 50;
int flashState = 0;
String ledRed, ledGreen, ledBlue, ledWhite;

String temp;
String payload;

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRBW + NEO_KHZ800);

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

  strip.begin();
  strip.show(); // Turn off all pixels asap
  strip.setBrightness(50); // Set brightness

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

  Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(change);
}

// Set all pixels to color
void setPixelColors(uint32_t color) {
  for(int p = 0; p < LED_COUNT; p++) {
    strip.setPixelColor(p, color);
  }
  strip.show();

  delay(1000);
  digitalWrite(3, HIGH);
}

// Split the I2C message
String split(String s, char parser, int index) {
  String rs="";
  int parserIndex = index;
  int parserCnt=0;
  int rFromIndex=0, rToIndex=-1;
  while (index >= parserCnt) {
    rFromIndex = rToIndex+1;
    rToIndex = s.indexOf(parser,rFromIndex);
    if (index == parserCnt) {
      if (rToIndex == 0 || rToIndex == -1) return "";
      return s.substring(rFromIndex,rToIndex);
    } else parserCnt++;
  }
  return rs;
}

void loop() {
  // ...
}

void change(int howMany) {
  digitalWrite(3, LOW);
  temp = "";
  if (Wire.available()) {
    // Fetch the string
    while(Wire.available()) {
      char c = Wire.read();
      temp.concat(c);
    }

    payload = String(temp);
    flashState = split(payload, ',', 0).toInt();
    ledRed = split(payload, ',', 1);
    ledGreen = split(payload, ',', 2);
    ledBlue = split(payload, ',', 3);
    ledWhite = split(payload, ',', 4);

    byte bufRed[3];
    ledRed.toCharArray(bufRed, 3);

    byte bufGreen[3];
    ledGreen.toCharArray(bufGreen, 3);

    byte bufBlue[3];
    ledBlue.toCharArray(bufBlue, 3);

    byte bufWhite[3];
    ledWhite.toCharArray(bufWhite, 3);

    //setPixelColors(strip.Color(255, 0, 255, 0)); // WORKING

    currentColor = strip.Color(bufRed, bufGreen, bufBlue, bufWhite);
    setPixelColors(currentColor); // NOT WORKING
  }

  // Proof the I2C reading is finished
  delay(10);
}

```

I tried different data types, attached a status LED so I know it the I2C connection is working. When I test it with my UNO I get for R=255 G=0 B=255 W=0; like intended.

"Fun fact": On my UNO it works like a charm. It's just the ATTiny85 that won't accept that values(?)

---

New Code:

```
#include <Wire.h>
#include <Adafruit_NeoPixel.h>

#define LED_PIN   4
#define LED_COUNT 20

static const int SLAVE_ADDRESS = 0x08;

int currentBrightness = 50;
int flashState = 0;
int ledRed, ledGreen, ledBlue, ledWhite;

volatile bool recvFlag = false;
volatile uint32_t currentColor = 0;
String temp;

String payload;

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRBW + NEO_KHZ800);

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

  strip.begin();
  strip.show(); // Turn OFF all pixels ASAP
  strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)

  Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(change);
}

void setPixelColors(uint32_t color) {
  for (int p = 0; p < LED_COUNT; p++) {
    strip.setPixelColor(p, color);
    strip.show();
  }
}

String split(String s, char parser, int index) {
  String rs = "";
  int parserIndex = index;
  int parserCnt = 0;
  int rFromIndex = 0, rToIndex = -1;
  while (index >= parserCnt) {
    rFromIndex = rToIndex + 1;
    rToIndex = s.indexOf(parser, rFromIndex);
    if (index == parserCnt) {
      if (rToIndex == 0 || rToIndex == -1) return "";
      return s.substring(rFromIndex, rToIndex);
    } else parserCnt++;
  }
  return rs;
}

void loop() {
  if (recvFlag) {
    payload = String(temp);
    flashState = split(payload, ',', 0).toInt();
    ledRed = split(payload, ',', 1).toInt();
    ledGreen = split(payload, ',', 2).toInt();
    ledBlue = split(payload, ',', 3).toInt();
    ledWhite = split(payload, ',', 4).toInt();

    currentColor = strip.Color(ledRed, ledGreen, ledBlue, ledWhite);
    setPixelColors(currentColor);

    recvFlag = false;
  }
}

void change(int howMany) {
  temp = "";
  if (Wire.available()) {
    // Fetch the string
    while (Wire.available()) {
      char c = Wire.read();
      temp.concat(c);
    }

    // Proof the I2C reading is finished
    recvFlag = true;
  }
}

```

# Answer
> 0 votes
Honestly I don't know, why exactly this works on your Uno. You need to know, that the `onReceive` callback function is called from an ISR (Interrupt Service Routine). And inside an ISR you cannot do things, that rely on interrupts to work (like `delay()`), since only one interrupt can run at a time. I'm not sure, how the Neopixel library works in its core, but its probably not a good idea to run the `show()` method inside an ISR. Also generally you don't want to do long things inside an ISR, since it will block all the other interrupt powered functions of your microcontroller (for example I2C, Serial, time keeping via `delay()` or `millis()`...).

Instead the best practice is to only set a flag and then do these things in the main code (aka in `loop()`). So something like this:

```
volatile bool recv_flag = false;
volatile uint32_t current_color = 0;

void setup(){
    // Initiating everything like you already did in your code
    ...
}

void loop(){
    if(recv_flag){
        setPixelColors(currentColor);
        recv_flag = false;
    }
}
void change(int howMany) {
  digitalWrite(3, LOW);
  temp = "";
  if (Wire.available()) {
    // Doing all the data parsing like you already did
    ...
    // save current color in global variable
    currentColor = strip.Color(bufRed, bufGreen, bufBlue, bufWhite);
    // set flag
    recv_flag = true;
  }
}

```

Note that every variable, that will be written to inside an ISR should be declared as `volatile`. This prevents the compiler from optimizing it out, since it cannot know when the interrupts will happen. So it might think that this variable will never change and just replace it with a literal. The `volatile` keyword prevents that.

---

As mentioned above I'm even wondering, why your code works on the Uno. Though the main difference between the Uno and the Attiny84 is, that the Uno as a full fledged I2C hardware interface, while the Attiny84 only has an USI (Universal Serial interface). So the Uno has most of the I2C communication implemented in hardware, while the Attiny84 needs to run (probably interrupt based) code to do the communication.

---
Tags: attiny85
---