title: Nema 17 stepper motor speed problem

text:
# Question
Title: Nema 17 stepper motor speed problem
This code is quoted from here. May I know how to increase the speed of the NEMA 17 stepper motor further? I tried to increase the step speed to 2000rpm but it does not even work. It only works for less than 300rpm in my case. The max rpm of the Nema 17 should be 5000rpm I googled. I used a 20V power supply lithium ion battery on the L298N motor driver. How do I solve this problem so that the Nema 17 can be faster? I believe the problem its with the code.

Thank you for reading and have a nice day :)

---

```
#include <Stepper.h>

const int stepsPerRevolution = 100;  // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

void setup() {
  // set the speed at 60 rpm:
  myStepper.setSpeed(300);
  // initialize the serial port:
  Serial.begin(9600);
}

void loop() {
  // step one revolution  in one direction:
  Serial.println("clockwise");
  myStepper.step(stepsPerRevolution);
  //delay(500);
}

```

# Answer
Stepper motors need to be gradually brought up to speed. If you try to go from zero rpm to anything over a few hundred rpm they will often just sit there and hum. Try AccelStepper (https://www.arduino.cc/reference/en/libraries/accelstepper/). This library provides functions to accelerate a stepper and move it to a certain position.

Also, I think you should know that Many stepper motors won't go over around 1000 rpm (this is dependant on your stepper and driver of course). It's also equally important to note that as you increase the speed of a stepper motor its available torque will decrease, so even if you are able to coax 1000+ rpm out of a nema 17 the torque available will be too low to use.
> 3 votes

---
Tags: arduino-uno, arduino-mega, arduino-ide, arduino-nano, power
---


# Question
Title: I need help for applying a logic to this code
Here's the code:

```
int softStart = A0;
int enable = A1;
int powerBTN = A2, powerState = HIGH, lastPowerState = HIGH;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 25;
unsigned long powerTimer = 0;
unsigned long powerHoldTimer = 0;
bool softStartENB = 0;

void setup() {
  Serial.begin(115200);
  pinMode(softStart, OUTPUT);
  pinMode(enable, OUTPUT);
  digitalWrite(enable, LOW);
  digitalWrite(softStart, LOW);
  pinMode(powerBTN, INPUT_PULLUP);
}

void loop() {
  int powerReading = digitalRead(powerBTN);

  if (powerReading != lastPowerState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay && !softStartENB) {
    if (powerReading != powerState) {
      powerState = powerReading;
      if (powerState == HIGH) {
        digitalWrite(enable, !digitalRead(enable));
        Serial.print("Normal start: ");
        Serial.println(digitalRead(enable));
      }
    }
  }

  if (powerReading == LOW) {
    powerTimer = millis() - lastDebounceTime;
  } else {
    powerTimer = 0;
  }

  if (powerTimer >= 1000 && millis() - powerHoldTimer >= 2000) {
    softStartENB = 1;
    digitalWrite(enable, LOW);
    digitalWrite(softStart, HIGH);
    Serial.print("Soft start started: ");
    Serial.println(digitalRead(softStart));
    powerHoldTimer = millis();
  }

  if (softStartENB && lastPowerState == HIGH && powerReading == LOW) {
    digitalWrite(enable, HIGH);
    delay(2000);
    digitalWrite(softStart, LOW);
    Serial.print("Soft start ended: ");
    Serial.println(digitalRead(softStart));
    softStartENB = 0;
  }

  lastPowerState = powerReading;

}

```

So the logic is as this:

1. By pressing `powerBTN` the `enable` pin toggles.
2. By holding `powerBTN` for 1 seconds `softStartENB` condition becomes true.
3. When `softStartENB` is true, if I press `powerBTN` again it sets `enable` pin to high and after 2 seconds `softStart` to low.

The problem is that after setting `softStartENB` to 0, `lastPowerState = powerReading` toggles `enable` pin to low but I want `enable` pin to stay high until I press `powerBTN` again to toggle it.

* How can I apply the described logic?

# Answer
> 0 votes
I solved the problem by using JC\_button library:

```
#include <JC_Button.h>

const byte softStart(A0), enable(A1);
int powerStates = 0;
bool enableState;

Button powerBTN(A2);

void setup() {
  Serial.begin(115200);
  powerBTN.begin();
  pinMode(enable, OUTPUT);
  pinMode(softStart, OUTPUT);
}

void loop() {
  powerBTN.read();
  Serial.println(powerStates);

  switch (powerStates) {
    case 0:
      if (powerBTN.wasReleased())
        switchEnable();
      else if (powerBTN.pressedFor(1000))
        powerStates = 1;
      break;

    case 1:
      if (powerBTN.wasReleased()){
        digitalWrite(enable, LOW);
        digitalWrite(softStart, HIGH);
        enableState = false;
        powerStates = 2;
      }
      break;

    case 2:
      if (powerBTN.wasReleased()){
        digitalWrite(enable, HIGH);
        delay(2000);
        digitalWrite(softStart, LOW);
        enableState = true;
        powerStates = 0;
      }
      break;
  }
}

void switchEnable() {
  enableState = !enableState;
  digitalWrite(enable, enableState);
}

```

# Answer
> 0 votes
I restructured your code as a finite state machine. There is a minimal number of "foreign" flags and almost a 1:1 relationship between the code and the state diagram. You can test a simulation of it here: https://wokwi.com/projects/383445446722551809

```
int softStart = A0;
int enable = A1;
int powerBTN = A2;

enum State { OFF = 0, ON = 1, WAIT_ON = 2 , WAIT_OFF = 3, IN_SOFT_START = 4, SOFT_START_CONFIRM = 5 } ;
State state  ;
State oldState ;
bool stateChange = true ;

uint32_t inCurrentStateAtMs = 0 ;

void setState ( State newState ) {
  // forces change to new state
  inCurrentStateAtMs = millis() ;
  oldState = state ;
  state = newState ;
  stateChange = true ;
}

void setup() {
  Serial.begin(115200);
  pinMode(softStart, OUTPUT);
  pinMode(enable, OUTPUT);
  pinMode(powerBTN, INPUT_PULLUP) ;
  digitalWrite(enable, LOW);
  digitalWrite(softStart, LOW);

  setState( State::OFF ) ;

}

void loop() {

  if ( stateChange ) {
    //debug
    stateChange = false ;
    Serial.print("state changes to: ");
    Serial.println( state ) ;
  }

  switch ( state ) {

    case State::OFF : {
        if ( ! digitalRead( powerBTN ) && millis() - inCurrentStateAtMs > 100 ) {
          setState( State::WAIT_ON ) ;
        }
        break ;
      }

    case State::WAIT_ON : {

          if ( digitalRead( powerBTN ) && millis() - inCurrentStateAtMs < 500 ) {
            digitalWrite( enable, HIGH ) ;
            setState( State::ON );
          }
          else if ( digitalRead( powerBTN ) && millis() - inCurrentStateAtMs >= 500 ) {
            digitalWrite( enable, LOW ) ;
            digitalWrite( softStart, HIGH ) ;
            setState( State::IN_SOFT_START );
          }

        break ;
      }

    case State::ON : {
        if ( ! digitalRead( powerBTN ) && millis() - inCurrentStateAtMs > 100 ) {
          setState( State::WAIT_OFF );
        }
        break ;
      }

    case State::WAIT_OFF : {
        if ( digitalRead( powerBTN ) && millis() - inCurrentStateAtMs > 100 ) {
          digitalWrite( enable, LOW ) ;
          setState( State::OFF ) ;
        }
        break;
      }

    case State::IN_SOFT_START : {
        if ( ! digitalRead( powerBTN )  ) {
          digitalWrite( enable, HIGH ) ;
          state = State::SOFT_START_CONFIRM ;
        }
        else if ( millis() - inCurrentStateAtMs > 3000 ) {
          // timeout
          digitalWrite( softStart, LOW ) ;
          setState( State::OFF );
        }
        break ;
      }

    case State::SOFT_START_CONFIRM  : {
        if ( digitalRead( powerBTN ) && millis() - inCurrentStateAtMs > 2000  ) {
          digitalWrite( softStart, LOW ) ;
          setState( State::ON ) ;
        }
        break ;
      }

  } // switch

}  // loop

```

---
Tags: programming
---


# Question
Title: Calculate the Li-Po Battery Level in ESP-Wroom-02
I am very new to micro controller and circuits. I am not at all with this field. But trying to create a home project where I have a device image attached below.

This is 18650 Lipo battery powered device. Here **I want to calculate the battery level**. After doing some research on google I found that I need to have Voltage Divider which I think I already included in this with 220k ohms and 100k ohms

People are using different ways to calculate it. Which I found in few examples. Which I am not able to understand at all, that what formula or values they are referring to calculate it.

if someone can help to understand that will be helpful. Here is how I am coding it which I saw somewhere on internet itself.

```
      #include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
//#include "DHTesp.h"

#define DHT_PIN       16

//SSID and Password of your WiFi router
const char* ssid = "Asus";
const char* password = "Xmv02488!!**";

ESP8266WebServer server(80); //Server on port 80

/***************************************************************
 * SETUP
 **************************************************************/
void setup(void){
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);     //Connect to your WiFi router
  Serial.println("");

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

  //If connection successful show IP address in serial monitor
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());  //IP address assigned to your ESP

  server.on("/", handleRoot);      //Which routine to handle at root location

  server.begin();                  //Start server
  Serial.println("HTTP server started");

  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(A0, INPUT);

}
/***************************************************************
 * LOOP
 **************************************************************/
void loop(void){
  server.handleClient();          //Handle client requests

}

/***************************************************************
 * This function converts IPAddress struct to a String
 **************************************************************/
String IpAddress2String(const IPAddress& ipAddress)
{
  return String(ipAddress[0]) + String(".") +\
  String(ipAddress[1]) + String(".") +\
  String(ipAddress[2]) + String(".") +\
  String(ipAddress[3])  ;
}

/***************************************************************
 * This rutine is exicuted when you open its IP in browser
 **************************************************************/
 void handleRoot() {
  IPAddress ip_address = WiFi.localIP();
  String ip_str = IpAddress2String(ip_address);

  int nVoltageRaw = analogRead(A0);
  float fVoltage = (float)nVoltageRaw * 0.00486;

  float fVoltageMatrix[22][2] = {
    {4.2,  100},
    {4.15, 95},
    {4.11, 90},
    {4.08, 85},
    {4.02, 80},
    {3.98, 75},
    {3.95, 70},
    {3.91, 65},
    {3.87, 60},
    {3.85, 55},
    {3.84, 50},
    {3.82, 45},
    {3.80, 40},
    {3.79, 35},
    {3.77, 30},
    {3.75, 25},
    {3.73, 20},
    {3.71, 15},
    {3.69, 10},
    {3.61, 5},
    {3.27, 0},
    {0, 0}
  };

  int i, perc;

  perc = 100;

  for(i=20; i>=0; i--) {
    if(fVoltageMatrix[i][0] >= fVoltage) {
      perc = fVoltageMatrix[i + 1][1];
      break;
    }
  }

  server.send(200, "text/plain", "Hello from esp8266!\n\rIP: " + ip_str +
    ".\n\rTemp: " + "NO" +
    ", Hum: " + "NO" +
    "\n\r" + "NO" +
    "\n\r" + "Voltage: " + fVoltage +
    "\n\r" + "Charge: " + perc + '%');
}

```

This is a copied code. Where I am not sure about where they got the this formula and how they got the value of 0.00486

I copied this code from different source references. But I hope this will help you to understand the issue.

Any suggestions will be helpful!

Thank you! (In advance)

# Answer
> 0 votes
The problem with LiPo batteries is that the discharge curve is very flat. Here's an example:

As you can see, for about 95% of the life of the battery there is very little change in voltage. You can't just take the voltage between "full" and "empty" and get a percentage from that. Instead you have to map points along that curve to different percentages.

The simplest way is to just have a set of percentages that you are interested in - every 5% as in the code you have above. Then you say "If the voltage is above this value then it's 100%. If it's above this next value down it's 95%. If it's above the next value down then it's 90%". etc.

The array `fVoltageMatrix` contains that mapping. For 100% the voltage must be 4.2V or greater. For 95% it must be 4.15V or greater. And so on.

If we take those voltage values from the array and plot them on a graph they look like this:

As you see that looks kind of similar. Quite flat, with a sudden drop off.

The code that gets the percentage charge simply reads the value from the ADC and converts it to a voltage by multiplying it by 0.004861, then it steps through the array one element at a time. The first time it finds one that fails the test "This percentage's threshold is less than the voltage" makes it take the previous one in the list as the percentage. Personally, I think that's backwards and a bad way of doing it. Instead, it should be the first one that passes the test "The voltage is greater than or equal to this percentage's threshold" that should be taken. I'd rewrite the loop like this:

```
perc = 0;

for(i=0; fVoltageMatrix[i][0] > 0; i++) {
  if(fVoltage >= fVoltageMatrix[i][0]) {
    perc = fVoltageMatrix[i][1];
    break;
  }
}

```

---

1 The number 0.00486 is the number of volts applied to the input to give a 1 from the ADC. Incidentally, if I am using the right figures, I calculate it should be 0.003125. 1 * (1/1024) gives 0.000976563 (that's 1 volt maximum range on the ADC, multiplied by one bit - a 1024th since it's 10 bit resolution on the ESP8266). Multiply that by the ratio of the resistors ((R1 + R2)/R2) which is 3.2, and that gives 0.003125. To compress it, you get: `x = (R1 + R2) / R2 * 1/1024` = `320000 / 100000 * 0.000976563` = `0.003125`

However, my numbers could be wrong...

# Answer
> 3 votes
Another problem you can run into is that a lot of the A/D converters use the VCC as a voltage reference. Which means that as your input voltage drops (what you are trying to measure) the reference voltage also drops which means the values you are recording will not appear to change or at least will not give an accurate reference.

# Answer
> 0 votes
One problem I have with the ESP8266 is the crappy results from the A/D converter. There are a number of hoops that you need to go through for the planets to align in order to get consistent readings. See Fluctuating ADC with stabilized source https://github.com/esp8266/Arduino/issues/2070

The other issue I have is with the assumption that the range of operation of the A/D is 0-1.0 volts and that certainly is not the case.

> I calculate it should be 0.003125. 1 * (1/1024) gives 0.000976563 (that's 1 volt maximum range on the ADC

The above shows how precise our calculations can be but unfortunately the six digits of precision gets thrown out the window if the assumed 1 volt top end has variations of 5%. Unfortunately there are no specifications given as far as the A/D converter in the miniscule spec sheet.

Yes the ESP8266 A/D can be calibrated, and measurements taken under controlled conditions. But make sure that you do the required work and verify the results under all operating conditions before you trust your results.

# Answer
> 0 votes
Below you can find the digital density meter I made for beer and the software I created for temperature and battery tracking.

1 . This part is the process I did to equalize the voltage coming to the voltage divider to the voltage of the battery.
**float fVoltage = (float)nVoltageRaw * 1.23;)**
You can calculate and find this value (1.23) according to your voltage divider. But for some reason the battery status fluctuates a bit 2 . I used 2 BC238 transistors for the sensors and the voltage divider so that the ESP does not consume energy when not reading.voltage only passes when transistors are triggered 3 . **float pot = map(a.acceleration.x, yogunlukreset0, yogunlukreset1, 997, 1100 )**;

This part was used to calibrate the device.

```

    #include <ESP32Firebase.h>

    #include "I2Cdev.h"
    //#include "MPU6050.h"
    #include <Adafruit_MPU6050.h>
    #include <Adafruit_Sensor.h>

    #include <Wire.h>
    #include "Adafruit_MCP9808.h"

    #define _SSID ""
    #define _PASSWORD ""
    #define REFERENCE_URL ""

     Firebase firebase(REFERENCE_URL);

     Adafruit_MCP9808 tempsensor = Adafruit_MCP9808();
     Adafruit_MPU6050 mpu;
     sensors_event_t a, g, temp;

    #define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */
    #define TIME_TO_SLEEP  3600       /* Time ESP32 will go to sleep (in seconds) */

    #define bc1 33
    #define bc2 16

     RTC_DATA_ATTR int bootCount = 0;
     const int potPin = 34;

     #include <Preferences.h>
     Preferences pref;

    namespace{
     float yogunlukreset0;
     float yogunlukreset1;

    }
    void wakeup_reason(){
      esp_sleep_wakeup_cause_t wakeup_reason;
      wakeup_reason = esp_sleep_get_wakeup_cause();

    }

    void setup() {

      Serial.begin(115200);
      delay(100);
      pinMode(bc1, OUTPUT);
      pinMode(bc2, OUTPUT);
      delay(100);
      digitalWrite(bc1, HIGH);
      digitalWrite(bc2, HIGH);
      delay(100);

      Wire.begin();
      WiFi.mode(WIFI_STA);
      WiFi.disconnect();
      delay(1000);
      Serial.println();
      Serial.println();
      Serial.print("Connecting to: ");
      Serial.println(_SSID);
      WiFi.begin(_SSID, _PASSWORD);

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

      Serial.println("");
      Serial.println("WiFi Connected");

      Serial.print("IP Address: ");
      Serial.print("http://");
      Serial.print(WiFi.localIP());
      Serial.println("/");

      if (!tempsensor.begin(0x18)) {
      Serial.println("Couldn't find MCP9808! Check your connections and verify the address is correct.");
      while (1);
      }
      if (!mpu.begin()) {
        Serial.println("Failed to find MPU6050 chip");
        while (1) {
          delay(10);
        }
     }

    ++bootCount;

      Serial.flush();
      pref.begin("Relay-State", false);
      yogunlukreset0 = pref.getFloat("namespace", false);
      yogunlukreset1 = pref.getFloat("namespa", false);

    }

    void loop() {

      mpu.setCycleRate(MPU6050_CYCLE_20_HZ);

      mpu.getEvent(&a, &g, &temp);

      tempsensor.wake();

      pref.putFloat("namespace", yogunlukreset0);
      pref.putFloat("namespa", yogunlukreset1);

      float c = tempsensor.readTempC();

      String reset2 = firebase.getString("Data/RT2");

      if (reset2 == "1"){
      String reset0 = firebase.getString("Data/RT0");
      String reset1 = firebase.getString("Data/RT1");
      String reset3 = firebase.getString("Data/RT3");

      if (reset0=="1") {
        yogunlukreset0 = (a.acceleration.x);
        }
      if (reset1=="1") {
        yogunlukreset1 = (a.acceleration.x);
        }

      if (reset3 == "1"){
        pref.clear();
        bootCount = 0;
        }

      }

      if (reset2 == "0"){

      float pot = map(a.acceleration.x, yogunlukreset0, yogunlukreset1, 997, 1100 );

      int nVoltageRaw = analogRead(potPin);

      float fVoltage = (float)nVoltageRaw * 1.23;

      float fVoltageMatrix[22][2] = {
        {4150, 100},
        {4130, 95},
        {4110, 90},
        {4080, 85},
        {4040, 80},
        {4010, 75},
        {3970, 70},
        {3930, 65},
        {3890, 60},
        {3850, 55},
        {3810, 50},
        {3760, 45},
        {3710, 40},
        {3660, 35},
        {3610, 30},
        {3550, 25},
        {3490, 20},
        {3430, 15},
        {3370, 10},
        {3320, 5},
        {3270, 0},
        {0, 0}
      };

      int i, perc;

      perc = 100;

      for(i=20; i>=0; i--) {
        if(fVoltageMatrix[i][0] >= fVoltage) {
          perc = fVoltageMatrix[i + 1][1];
          break;
        }
      }

      firebase.setFloat("Data/YG", pot);
      firebase.setFloat("Data/TM", c);
      firebase.setFloat("Data/SYC", bootCount);
      firebase.setFloat("Data/VOLT", fVoltage);
      firebase.setFloat("Data/ORAN", perc);

      digitalWrite(bc1, LOW);
      digitalWrite(bc2, LOW);

      wakeup_reason();
      esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
      esp_deep_sleep_start();
      delay(50);
      }

    }

```

---
Tags: esp8266, lipo
---


# Question
Title: Wake esp8266 from deep sleep with PIR but disable while running code
I am using an ESP8266 to control a ring of neopixels. I want to use a PIR to trigger a brief light show. I'm using batteries and need them to last as long as possible.

I have it working by checking the PIR for motion. If there is motion I run the light show. If no motion I put the ESP8266 into deep sleep for 15 seconds. When I wake I try again.

I would prefer to use the PIR to reset the ESP, and I did get it to do that but the problem was that further movement would reset again and start the light show from the beginning. I would like to be able to disable reset while I'm running code.

I did some research and found this:

PIR motion wake ESP8266 from deepsleep

It's pretty much what I need.

Is there a final circuit diagram or a similar solution?

Thanks.

# Answer
> 1 votes
Hi I have being using the circuit below now for a few weeks and all seems to work.

When I wake from deep sleep I set the Latch pin to 0 to prevent any more resets. I do the work, I check if there is still motion by reading PIR out, if no movement I set the Latch pin to 1 and go into deep sleep.

---
Tags: esp8266, interrupt, sleep
---


# Question
Title: How to output two PWM signals, one of 50% duty cycle, the other 25% duty cycle, from an Arduino Uno?
I need to output two PWM signals, one of 50% duty cycle, the other 25% duty cycle, from an Arduino. Feed both signals into the 2 channels of a PicoScope and measure:

a) the time difference between the rising pulse of the traces and b) the time it takes for the signal to settle for the 50% trace.

I understand that I may not get help with the Picoscope part of the question, however I do need help with the other part.

I'm very new to Arduino and don't really know what I'm doing. Any help will be appreciated!

# Answer
> 1 votes
The function `analogWrite` generates PWM signals. See its documentation for details.

You use `analogWrite(pin_for_25_percent, 64);` for 25% and `analogWrite(pin_for_50_percent, 128);` for 50%.

```
const int pin_for_25_percent = /* your choice */;
const int pin_for_50_percent = /* your choice */;

void setup() {
    analogWrite(pin_for_25_percent, 64);
    analogWrite(pin_for_50_percent, 128);
}

void loop() {
}

```

---
Tags: arduino-uno, pwm
---


title: Matter protocol with Arduino Mega/Giga

text:
# Question
Title: Matter protocol with Arduino Mega/Giga
I would like to try matter protocol with Arduino mega or Arduino giga.

But I don't find any sample or library. I have only found libraries compatibles with ESP32.

Do you know how I can work with matter protocol on an Arduino Mega or Giga ?

Thanks

# Answer
> 0 votes
If this is the source code repository for the ESP32 Matter project, then this statement from the README file found there:

> Make sure that ESP32 board version is 2.0.14. This is crucial, because this library contains pre-compiled files.

...would infer that not all the source code is available. It follows that the application can not be ported to a different processor.

---
Tags: wifi, bluetooth, home-automation
---


# Question
Title: Converting raw data of IIS2MDC into angle
I do not know that this is a good place for asking question but I have a 3 axis magnetometer IIS2MDC. I used this with Arduino. I downloaded the library **IIS2MDC.h** in Arduino IDE. I used example code of **IIS2MDC.h** library for reading magnetometer data. I have 3 axis raw data.

My question is that how to convert magnetometer data into degrees? Is there any reference or solution for this?

# Answer
It is likely the magnetometer needs to be calibrated before it can be used. Before calibration is applied to the magnetometer's output values, comparing any 2 of the 3 orthogonal sensors will be difficult.

Search and learn the terms hard iron and soft iron distortion / calibration with respect to magnetometers. Hard iron distortion is an offset error. Find the maximum (point a particular magnetometer toward magnetic north) and the minimum (point the same magnetometer away from magnetic north) values of one of the magnetometers. Calculate an offset value such that when applied the maximum and minimum magnitudes are the same. Soft iron distortion is a magnitude error. Find the maximum and minimum values for all 3 sensors. From this find the total range of all 3 sensors. Arbitrarily pick one of the sensors ranges and calculate magnitude adjustment values for the remaining sensor ranges such that after applying them all 3 sensors have the same range.

At this point let us narrow the scope of the electronic compass to simplify the project. Let us constrain the compass to only be used on a table which is parallel to the surface of the earth. At which point we only need to use 2 of the sensors (the two that lie in the plane of the table).

To calculate the angle the magnetometer is pointing with respect to magnetic north we take the arctangent of the ratio of the 2 magnetic sensor which lie in the plane of the table. However, this math function only gives us angles for half the desired angles. Fortunately, the C programming math library contains a special function **atan2()** which can return a full circle of angles (from here):

> Synopsis. The atan2() function divides the first argument by the second and returns the arc tangent of the result, or arctan( y / x ) . The return value is given in radians, and is in the range -π ≤ atan2( y , x ) ≤ π.
> 0 votes

---
Tags: arduino-ide, stm32
---


# Question
Title: Why I always see while(serial.available() > 0) as the standard way of reading serial data?
Examples online always show this code to read bytes from the serial interface:

```
while(serial.available() > 0)
{
      char receivedByte = serial.read();
}

```

But I don't understand why it works.

The read() operation "removes" a single byte from the queue, so the while loop should consume all the bytes from the queue.

However, what guarantees that the incoming bytes are being pushed into the queue faster than the consuming process? I would imagine that any Arduino board is order of magnitude faster than a standard serial transmission, so it would starve the queue and effectively exit the while loop even though there are more incoming bytes to process. What am I missing here?

# Answer
> what guarantees that the incoming bytes are being pushed into the queue faster than the consuming process?

Nothing. In the code handling the transmitted data you need to account for that. The fact, that serial transmission is not as fast as the code runs, doesn't matter, when you regularly check execute that while loop again (on each iteration of a non-blocking `loop()` for example). The code shouldn't rely on a full message being received inside that while loop. The data is normally saved into its own buffer and only processed, when a full valid message is in there (which can be checked by using a delimiter byte at the end of each message). So this makes more sense in the context of the rest of the corresponding serial code.

Though you should always keep in mind, that there are many many codes for Arduino online and that many of them are not that good.
> 4 votes

# Answer
> Examples online always show this code ...

> ```
>  while(serial.available() > 0)
>  {
>        char receivedByte = serial.read();
>  }
>
> ```

You wouldn't have seen this "always" because it is `Serial` and not `serial`.

Also the code you posted would be useless because it would repeatedly read into the same byte and do nothing with it.

Assuming you are taking a bit of a licence with what you actually saw, it would be better for the code to gradually fill a buffer (and check for overflow) and then when a newline or other delimiter arrives, do something with it.

You are right that you would, generally speaking, read faster than data arrives. You are also right that putting delays in is a silly way of trying to allow for that.

I have an answer on this site plus a page with suggested code which goes into more detail.

Those posts might help.
> 1 votes

---
Tags: serial, serial-data
---


title: How to tri-state an output circuit?

text:
# Question
Title: How to tri-state an output circuit?
I need a circuit where an Arduino MCU can set an output to 3 different states.

* HIGH (12V)
* LOW (GND)
* N/A (completely disconnected)

Using transistors seems to be the correct way but I am too much of a noob in this area to be sure.

I’ve been researching “tri-state” online but there seems to be different meanings of this.

I’d appreciate a circuit for this or information that can get me on the right track.

Update:

I did test this schematic and it almost works. Although in the high state I got 2.7V output when the input was 12V. Very odd. I used two NPN transistors.

This is a half h-bridge, right?

# Answer
The simplest solution could probably be an H-bridge, like the ones you have on motor driver shields. Actually you only need half an H-bridge. You will typically be driving two inputs of the chip: “input 1” and “enable”:

* if you set “enable” to `LOW` the bridge output will be in the high impedance state (your “completely disconnected” state)
* if you set “enable” to `HIGH`, the output will be `HIGH` or `LOW`, mirroring “input 1”.

**Edit**: your transistor circuit looks slightly similar to half an H-bridge. However, in order to operate from 12 V, you typically need at least three transistors, one of them being a PNP. See for example this discussion in the Arduino forum. I suggest you use a ready-built H-bridge, as this will simplify things for you.
> 2 votes

# Answer
Another possibility is a tristate buffer with enable. There are lots available, just make sure the voltage can be 12 volts (eg MC14503B)
> 0 votes

# Answer
Another option is to use a pair of opto-mosfets arranged as half bridge. The opto's LEDs could easily be controlled by logic levels.

Another option is to use complementary pair of PNP and NPN transistors again arranges as half bridge (joined collectors as ouput, PNP emitter at +12V, NPN emitter at GND. The NPN transistor is controlled directly; the PNP via an auxiliary small NPN (collector driving the PNP base)
> 0 votes

---
Tags: arduino-uno, h-bridge
---


title: Read frequency of input in digital pins

text:
# Question
Title: Read frequency of input in digital pins
This is a somewhat theoretical question: Let's say I have some sensor that sends digital signals to one of Arduino's digital ports. Now, I don't know the frequency it sends those signals in. For example, the frequency of the sensor output could be 100Hz, so every 1/100 of a second it varies the voltage (or keeps the old voltage if the next signal is the same as the previous one), but it could just as well be 200Hz. Would Arduino be able to faithfully read the digital signal regardless of its frequency? Or is there a conventional frequency that digital devices usually use for output? Wouldn't it be the case that if Arduino expects 100Hz signal, but the signal is 200Hz it would miss half the inputs? For: (1 0 1 0 0 1...) wouldn't it see: (1 1 0) - that is skip every other input because it's sampling rate would be too slow by half? Thanks kindly for your help..

# Answer
100 Hz is pretty trivial. See my page about timers.

This sketch can detect frequencies up to about 5 MHz:

```
// Timer and Counter example
// Author: Nick Gammon
// Date: 17th January 2012

// Input: Pin D5

// these are checked for in the main program
volatile unsigned long timerCounts;
volatile boolean counterReady;

// internal to counting routine
unsigned long overflowCount;
unsigned int timerTicks;
unsigned int timerPeriod;

void startCounting (unsigned int ms)
  {
  counterReady = false;         // time not up yet
  timerPeriod = ms;             // how many 1 ms counts to do
  timerTicks = 0;               // reset interrupt counter
  overflowCount = 0;            // no overflows yet

  // reset Timer 1 and Timer 2
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR2A = 0;
  TCCR2B = 0;

  // Timer 1 - counts events on pin D5
  TIMSK1 = bit (TOIE1);   // interrupt on Timer 1 overflow

  // Timer 2 - gives us our 1 ms counting interval
  // 16 MHz clock (62.5 ns per tick) - prescaled by 128
  //  counter increments every 8 µs.
  // So we count 125 of them, giving exactly 1000 µs (1 ms)
  TCCR2A = bit (WGM21) ;   // CTC mode
  OCR2A  = 124;            // count up to 125  (zero relative!!!!)

  // Timer 2 - interrupt on match (ie. every 1 ms)
  TIMSK2 = bit (OCIE2A);   // enable Timer2 Interrupt

  TCNT1 = 0;      // Both counters to zero
  TCNT2 = 0;

  // Reset prescalers
  GTCCR = bit (PSRASY);        // reset prescaler now
  // start Timer 2
  TCCR2B =  bit (CS20) | bit (CS22) ;  // prescaler of 128
  // start Timer 1
  // External clock source on T1 pin (D5). Clock on rising edge.
  TCCR1B =  bit (CS10) | bit (CS11) | bit (CS12);
  }  // end of startCounting

ISR (TIMER1_OVF_vect)
  {
  ++overflowCount;               // count number of Counter1 overflows
  }  // end of TIMER1_OVF_vect

//******************************************************************
//  Timer2 Interrupt Service is invoked by hardware Timer 2 every 1 ms = 1000 Hz
//  16Mhz / 128 / 125 = 1000 Hz

ISR (TIMER2_COMPA_vect)
  {
  // grab counter value before it changes any more
  unsigned int timer1CounterValue;
  timer1CounterValue = TCNT1;  // see datasheet, page 117 (accessing 16-bit registers)
  unsigned long overflowCopy = overflowCount;

  // see if we have reached timing period
  if (++timerTicks < timerPeriod)
    return;  // not yet

  // if just missed an overflow
  if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 256)
    overflowCopy++;

  // end of gate time, measurement ready

  TCCR1A = 0;    // stop timer 1
  TCCR1B = 0;

  TCCR2A = 0;    // stop timer 2
  TCCR2B = 0;

  TIMSK1 = 0;    // disable Timer1 Interrupt
  TIMSK2 = 0;    // disable Timer2 Interrupt

  // calculate total count
  timerCounts = (overflowCopy << 16) + timer1CounterValue;  // each overflow is 65536 more
  counterReady = true;              // set global flag for end count period
  }  // end of TIMER2_COMPA_vect

void setup ()
  {
  Serial.begin(115200);
  Serial.println("Frequency Counter");
  } // end of setup

void loop ()
  {
  // stop Timer 0 interrupts from throwing the count out
  byte oldTCCR0A = TCCR0A;
  byte oldTCCR0B = TCCR0B;
  TCCR0A = 0;    // stop timer 0
  TCCR0B = 0;

  startCounting (500);  // how many ms to count for

  while (!counterReady)
     { }  // loop until count over

  // adjust counts by counting interval to give frequency in Hz
  float frq = (timerCounts *  1000.0) / timerPeriod;

  Serial.print ("Frequency: ");
  Serial.print ((unsigned long) frq);
  Serial.println (" Hz.");

  // restart timer 0
  TCCR0A = oldTCCR0A;
  TCCR0B = oldTCCR0B;

  // let serial stuff finish
  delay(200);
  }   // end of loop

```

---

> Or is there a conventional frequency that digital devices usually use for output?

No.

> Wouldn't it be the case that if Arduino expects 100Hz signal, but the signal is 200Hz it would miss half the inputs? For: (1 0 1 0 0 1...)

No.

Why would it "expect" a frequency? It isn't a person expecting a chocolate cake on its birthday.

---

> So whatever frequency the sensor sends its data in - be it 100Hz or 5Mhz - Arduino is smart enough to read all the voltage signals faithfully?

I'm not quite sure what you mean by "read all the voltage signals" which seems to imply you want to measure the voltage.

> so every 1/100 of a second it varies the voltage (or keeps the old voltage if the next signal is the same as the previous one)

But then you say:

> let's assume that the 1 voltage is high enough (but not too high) for Arduino to register a 1, and the 0 voltage is also within the threshold for Arduino to register a zero (say 5V for HIGH and 0.5V for LOW). It's the frequency of the signal I'm concerned with.

The voltage levels for 0 and 1 are documented in the datasheet. For the Atmega328P for *most* pins they are as follows:

You can see that if Vcc is 2.4V or above then LOW is -0.5V to 0.3 * Vcc, which if Vcc is 5V then a LOW is -0.5 to 1.5V.

Similarly a HIGH is 0.6V * Vcc to Vcc + 0.5, so if Vcc is 5V then a HIGH is 3V to 5.5V.

In between 1.5V and 3V then the digital status would be undefined.

So, if your LOW and HIGH are in those voltage ranges, yes you can detect the frequency of the signal.

I'm not sure about the bit where you said "keeps the old voltage if the next signal is the same as the previous one". That seems to imply that if the signals stay the same (eg. for a second) then the voltage won't change at all, and thus the frequency will be zero.
> 2 votes

# Answer
Another method if it's helpful to the world:

Using inspiration from https://forum.arduino.cc/t/how-to-read-frequency-with-arduino/528143/2

I am just measuring the seconds using micros() between each up or down portion of the waveform, multiplying the time by 2 to get the full period (assuming a duty cycle of 50%). And then inverting the full period to calculate the frequency.

I was using a Teensy 4.1 for this.

```
// READ FREQUENCY FROM A DIGITAL INPUT PIN SKETCH

// this cannot be used when the FreqMeasure.h toolbox is used if on teensy
// https://www.pjrc.com/teensy/td_libs_FreqMeasure.html

// define your digital input pin
#define inputPin 22

// initialize variables for the frequency reading function
boolean inputState = false; boolean lastInputState = false;
long lastTime; long period; double freq;

// the frequency reading function
double readFrequency(){
  inputState = digitalRead(inputPin);

  if (inputState != lastInputState) {
    period = micros() - lastTime; // in microseconds
    freq = 1/(2*period*pow(10,-6)); // conversion to Hz

    lastInputState = inputState;
    lastTime = micros();
  }
  return freq; // always return frequency even if it hasn't changed state...
}

// label the pin
void setup() {
  // Serial.begin(115200); // uncomment & adjust for Arduino - I was using a Teensy.
  pinMode(inputPin, INPUT);
}

// call the function and print the output at full speed
void loop() {
  Serial.print("Frequency:"); Serial.println(readFrequency());
  // works even if I put a delay in here (e.g., delay(1) millisecond)
}

```
> 0 votes

---
Tags: analogread, voltage-level, digital, frequency, voltage
---


# Question
Title: Diecimila with firmata standard not working
Hi would like to use an old Diecimila with home-assistant, and that seems to imply installing firmata-standard.

That fails since there is not enough space on the board.

Is there a workaround (I only need inputs, maybe even only digital)?

What would be a good way forward otherwise? Is there an alternative to firmata for homeassistant? Or should I just buy a newer board?

# Answer
> 1 votes
> Is there a workaround (I only need inputs, maybe even only digital)?

## OldStandardFirmata

I don't know enough about homeassistant to know what you need exactly. But it seems very likely that you can and probably should use OldStandardFirmata. And it is so similar to the modified `StandardFirmata` (below) that it will probably just work for you. It uses 505 (reported) bytes of RAM.

AllInputsFirmata may also work, but it's RAM usage is only a percent smaller.

## Modifying StandardFirmata

That said, it looks like you **can** get StandardFirmata.ino from current version 2.5.9 to be within limits by removing everything associated with I2C and Servo. It is probably worth trying OldStandardFirmata first, because much of these changes are what makes the difference between the `Old` and not-`Old` examples.

Under AVR support version 1.8.7.

```
Sketch uses 7978 bytes (55%) of program storage space. Maximum is 14336 bytes.
Global variables use 522 bytes (50%) of dynamic memory, leaving 502 bytes for local variables. Maximum is 1024 bytes.

```

So, slightly larger than OldStandardFirmata.

| Action | Reported `Global variables` |
| --- | --- |
| Nothing | 1079 bytes |
| Removing only I2C | 650 bytes |
| Removing servo | 951 bytes |
| Removing both I2C and SERVO | 522 bytes |

Removing servo-related stuff doesn't lower the ram using that much but it does remove some lines from this post. Removing `analogWrite`, `analogRead` can remove nontrivial amounts of code, but doesn't affect the memory footprint much. The final size is similar to OldFirmataStandard's size.

The following may work for you. It's the example in entirety after removing I2C and Servo related parts. I would have changed the formatting a bit, but leaving it as is you should be able to diff it against the original to see the changes if you care to.

```
/*
  Firmata is a generic protocol for communicating with microcontrollers
  from software on a host computer. It is intended to work with
  any host computer software package.

  To download a host software package, please click on the following link
  to open the list of Firmata client libraries in your default browser.

  https://github.com/firmata/arduino#firmata-client-libraries

  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.
  Copyright (C) 2010-2011 Paul Stoffregen.  All rights reserved.
  Copyright (C) 2009 Shigeru Kobayashi.  All rights reserved.
  Copyright (C) 2009-2016 Jeff Hoefs.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  See file LICENSE.txt for further informations on licensing terms.

  Last updated August 17th, 2017
*/

#include <Firmata.h>

// the minimum interval for sampling analog input
#define MINIMUM_SAMPLING_INTERVAL   1

/*==============================================================================
 * GLOBAL VARIABLES
 *============================================================================*/

#ifdef FIRMATA_SERIAL_FEATURE
SerialFirmata serialFeature;
#endif

/* analog inputs */
int analogInputsToReport = 0; // bitwise array to store pin reporting

/* digital input ports */
byte reportPINs[TOTAL_PORTS];       // 1 = report this port, 0 = silence
byte previousPINs[TOTAL_PORTS];     // previous 8 bits sent

/* pins configuration */
byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else

/* timer variables */
unsigned long currentMillis;        // store the current value from millis()
unsigned long previousMillis;       // for comparison with currentMillis
unsigned int samplingInterval = 19; // how often to run the main loop (in ms)

/* i2c data */
struct i2c_device_info {
  byte addr;
  int reg;
  byte bytes;
  byte stopTX;
};

boolean isResetting = false;

// Forward declare a few functions to avoid compiler errors with older versions
// of the Arduino IDE.
void setPinModeCallback(byte, int);
void reportAnalogCallback(byte analogPin, int value);
void sysexCallback(byte, byte, byte*);

/*==============================================================================
 * FUNCTIONS
 *============================================================================*/

void outputPort(byte portNumber, byte portValue, byte forceSend)
{
  // pins not configured as INPUT are cleared to zeros
  portValue = portValue & portConfigInputs[portNumber];
  // only send if the value is different than previously sent
  if (forceSend || previousPINs[portNumber] != portValue) {
    Firmata.sendDigitalPort(portNumber, portValue);
    previousPINs[portNumber] = portValue;
  }
}

/* -----------------------------------------------------------------------------
 * check all the active digital inputs for change of state, then add any events
 * to the Serial output queue using Serial.print() */
void checkDigitalInputs(void)
{
  /* Using non-looping code allows constants to be given to readPort().
   * The compiler will apply substantial optimizations if the inputs
   * to readPort() are compile-time constants. */
  if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false);
  if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
  if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false);
  if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
  if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
  if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
  if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
  if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
  if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
  if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
  if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
  if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
  if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
  if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
  if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
  if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
}

// -----------------------------------------------------------------------------
/* sets the pin mode to the correct state and sets the relevant bits in the
 * two bit-arrays that track Digital I/O and PWM status
 */
void setPinModeCallback(byte pin, int mode)
{
  if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE)
    return;

  if (IS_PIN_ANALOG(pin)) {
    reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting
  }
  if (IS_PIN_DIGITAL(pin)) {
    if (mode == INPUT || mode == PIN_MODE_PULLUP) {
      portConfigInputs[pin / 8] |= (1 << (pin & 7));
    } else {
      portConfigInputs[pin / 8] &= ~(1 << (pin & 7));
    }
  }
  Firmata.setPinState(pin, 0);
  switch (mode) {
    case PIN_MODE_ANALOG:
      if (IS_PIN_ANALOG(pin)) {
        if (IS_PIN_DIGITAL(pin)) {
          pinMode(PIN_TO_DIGITAL(pin), INPUT);    // disable output driver
#if ARDUINO <= 100
          // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
          digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
#endif
        }
        Firmata.setPinMode(pin, PIN_MODE_ANALOG);
      }
      break;
    case INPUT:
      if (IS_PIN_DIGITAL(pin)) {
        pinMode(PIN_TO_DIGITAL(pin), INPUT);    // disable output driver
#if ARDUINO <= 100
        // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
        digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
#endif
        Firmata.setPinMode(pin, INPUT);
      }
      break;
    case PIN_MODE_PULLUP:
      if (IS_PIN_DIGITAL(pin)) {
        pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP);
        Firmata.setPinMode(pin, PIN_MODE_PULLUP);
        Firmata.setPinState(pin, 1);
      }
      break;
    case OUTPUT:
      if (IS_PIN_DIGITAL(pin)) {
        if (Firmata.getPinMode(pin) == PIN_MODE_PWM) {
          // Disable PWM if pin mode was previously set to PWM.
          digitalWrite(PIN_TO_DIGITAL(pin), LOW);
        }
        pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
        Firmata.setPinMode(pin, OUTPUT);
      }
      break;
    case PIN_MODE_PWM:
      if (IS_PIN_PWM(pin)) {
        pinMode(PIN_TO_PWM(pin), OUTPUT);
        analogWrite(PIN_TO_PWM(pin), 0);
        Firmata.setPinMode(pin, PIN_MODE_PWM);
      }
      break;
    case PIN_MODE_I2C:
      if (IS_PIN_I2C(pin)) {
        // mark the pin as i2c
        // the user must call I2C_CONFIG to enable I2C for a device
        Firmata.setPinMode(pin, PIN_MODE_I2C);
      }
      break;
    case PIN_MODE_SERIAL:
#ifdef FIRMATA_SERIAL_FEATURE
      serialFeature.handlePinMode(pin, PIN_MODE_SERIAL);
#endif
      break;
    default:
      Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
  }
  // TODO: save status to EEPROM here, if changed
}

/*
 * Sets the value of an individual pin. Useful if you want to set a pin value but
 * are not tracking the digital port state.
 * Can only be used on pins configured as OUTPUT.
 * Cannot be used to enable pull-ups on Digital INPUT pins.
 */
void setPinValueCallback(byte pin, int value)
{
  if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) {
    if (Firmata.getPinMode(pin) == OUTPUT) {
      Firmata.setPinState(pin, value);
      digitalWrite(PIN_TO_DIGITAL(pin), value);
    }
  }
}

void analogWriteCallback(byte pin, int value)
{
  if (pin < TOTAL_PINS) {
    switch (Firmata.getPinMode(pin)) {
      case PIN_MODE_PWM:
        if (IS_PIN_PWM(pin))
          analogWrite(PIN_TO_PWM(pin), value);
        Firmata.setPinState(pin, value);
        break;
    }
  }
}

void digitalWriteCallback(byte port, int value)
{
  byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0;

  if (port < TOTAL_PORTS) {
    // create a mask of the pins on this port that are writable.
    lastPin = port * 8 + 8;
    if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS;
    for (pin = port * 8; pin < lastPin; pin++) {
      // do not disturb non-digital pins (eg, Rx & Tx)
      if (IS_PIN_DIGITAL(pin)) {
        // do not touch pins in PWM, ANALOG, SERVO or other modes
        if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) {
          pinValue = ((byte)value & mask) ? 1 : 0;
          if (Firmata.getPinMode(pin) == OUTPUT) {
            pinWriteMask |= mask;
          } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) {
            // only handle INPUT here for backwards compatibility
#if ARDUINO > 100
            pinMode(pin, INPUT_PULLUP);
#else
            // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier
            pinWriteMask |= mask;
#endif
          }
          Firmata.setPinState(pin, pinValue);
        }
      }
      mask = mask << 1;
    }
    writePort(port, (byte)value, pinWriteMask);
  }
}

// -----------------------------------------------------------------------------
/* sets bits in a bit array (int) to toggle the reporting of the analogIns
 */
//void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
//}
void reportAnalogCallback(byte analogPin, int value)
{
  if (analogPin < TOTAL_ANALOG_PINS) {
    if (value == 0) {
      analogInputsToReport = analogInputsToReport & ~ (1 << analogPin);
    } else {
      analogInputsToReport = analogInputsToReport | (1 << analogPin);
      // prevent during system reset or all analog pin values will be reported
      // which may report noise for unconnected analog pins
      if (!isResetting) {
        // Send pin value immediately. This is helpful when connected via
        // ethernet, wi-fi or bluetooth so pin states can be known upon
        // reconnecting.
        Firmata.sendAnalog(analogPin, analogRead(analogPin));
      }
    }
  }
  // TODO: save status to EEPROM here, if changed
}

void reportDigitalCallback(byte port, int value)
{
  if (port < TOTAL_PORTS) {
    reportPINs[port] = (byte)value;
    // Send port value immediately. This is helpful when connected via
    // ethernet, wi-fi or bluetooth so pin states can be known upon
    // reconnecting.
    if (value) outputPort(port, readPort(port, portConfigInputs[port]), true);
  }
  // do not disable analog reporting on these 8 pins, to allow some
  // pins used for digital, others analog.  Instead, allow both types
  // of reporting to be enabled, but check if the pin is configured
  // as analog when sampling the analog inputs.  Likewise, while
  // scanning digital pins, portConfigInputs will mask off values from any
  // pins configured as analog
}

/*==============================================================================
 * SYSEX-BASED commands
 *============================================================================*/

void sysexCallback(byte command, byte argc, byte *argv)
{
  byte mode;
  byte stopTX;
  byte slaveAddress;
  byte data;
  int slaveRegister;
  unsigned int delayTime;

  switch (command) {
    case SAMPLING_INTERVAL:
      if (argc > 1) {
        samplingInterval = argv[0] + (argv[1] << 7);
        if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
          samplingInterval = MINIMUM_SAMPLING_INTERVAL;
        }
      } else {
        //Firmata.sendString("Not enough data");
      }
      break;
    case EXTENDED_ANALOG:
      if (argc > 1) {
        int val = argv[1];
        if (argc > 2) val |= (argv[2] << 7);
        if (argc > 3) val |= (argv[3] << 14);
        analogWriteCallback(argv[0], val);
      }
      break;
    case CAPABILITY_QUERY:
      Firmata.write(START_SYSEX);
      Firmata.write(CAPABILITY_RESPONSE);
      for (byte pin = 0; pin < TOTAL_PINS; pin++) {
        if (IS_PIN_DIGITAL(pin)) {
          Firmata.write((byte)INPUT);
          Firmata.write(1);
          Firmata.write((byte)PIN_MODE_PULLUP);
          Firmata.write(1);
          Firmata.write((byte)OUTPUT);
          Firmata.write(1);
        }
        if (IS_PIN_ANALOG(pin)) {
          Firmata.write(PIN_MODE_ANALOG);
          Firmata.write(10); // 10 = 10-bit resolution
        }
        if (IS_PIN_PWM(pin)) {
          Firmata.write(PIN_MODE_PWM);
          Firmata.write(DEFAULT_PWM_RESOLUTION);
        }
        if (IS_PIN_DIGITAL(pin)) {
          Firmata.write(PIN_MODE_SERVO);
          Firmata.write(14);
        }
        if (IS_PIN_I2C(pin)) {
          Firmata.write(PIN_MODE_I2C);
          Firmata.write(1);  // TODO: could assign a number to map to SCL or SDA
        }
#ifdef FIRMATA_SERIAL_FEATURE
        serialFeature.handleCapability(pin);
#endif
        Firmata.write(127);
      }
      Firmata.write(END_SYSEX);
      break;
    case PIN_STATE_QUERY:
      if (argc > 0) {
        byte pin = argv[0];
        Firmata.write(START_SYSEX);
        Firmata.write(PIN_STATE_RESPONSE);
        Firmata.write(pin);
        if (pin < TOTAL_PINS) {
          Firmata.write(Firmata.getPinMode(pin));
          Firmata.write((byte)Firmata.getPinState(pin) & 0x7F);
          if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F);
          if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F);
        }
        Firmata.write(END_SYSEX);
      }
      break;
    case ANALOG_MAPPING_QUERY:
      Firmata.write(START_SYSEX);
      Firmata.write(ANALOG_MAPPING_RESPONSE);
      for (byte pin = 0; pin < TOTAL_PINS; pin++) {
        Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127);
      }
      Firmata.write(END_SYSEX);
      break;

    case SERIAL_MESSAGE:
#ifdef FIRMATA_SERIAL_FEATURE
      serialFeature.handleSysex(command, argc, argv);
#endif
      break;
  }
}

/*==============================================================================
 * SETUP()
 *============================================================================*/

void systemResetCallback()
{
  isResetting = true;

  // initialize a defalt state
  // TODO: option to load config from EEPROM instead of default

#ifdef FIRMATA_SERIAL_FEATURE
  serialFeature.reset();
#endif

  for (byte i = 0; i < TOTAL_PORTS; i++) {
    reportPINs[i] = false;    // by default, reporting off
    portConfigInputs[i] = 0;  // until activated
    previousPINs[i] = 0;
  }

  for (byte i = 0; i < TOTAL_PINS; i++) {
    // pins with analog capability default to analog input
    // otherwise, pins default to digital output
    if (IS_PIN_ANALOG(i)) {
      // turns off pullup, configures everything
      setPinModeCallback(i, PIN_MODE_ANALOG);
    } else if (IS_PIN_DIGITAL(i)) {
      // sets the output to 0, configures portConfigInputs
      setPinModeCallback(i, OUTPUT);
    }
  }
  // by default, do not report any analog inputs
  analogInputsToReport = 0;

  /* send digital inputs to set the initial state on the host computer,
   * since once in the loop(), this firmware will only send on change */
  /*
  TODO: this can never execute, since no pins default to digital input
        but it will be needed when/if we support EEPROM stored config
  for (byte i=0; i < TOTAL_PORTS; i++) {
    outputPort(i, readPort(i, portConfigInputs[i]), true);
  }
  */
  isResetting = false;
}

void setup()
{
  Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);

  Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
  Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
  Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
  Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
  Firmata.attach(SET_PIN_MODE, setPinModeCallback);
  Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback);
  Firmata.attach(START_SYSEX, sysexCallback);
  Firmata.attach(SYSTEM_RESET, systemResetCallback);

  // to use a port other than Serial, such as Serial1 on an Arduino Leonardo or Mega,
  // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this:
  // Serial1.begin(57600);
  // Firmata.begin(Serial1);
  // However do not do this if you are using SERIAL_MESSAGE

  Firmata.begin(57600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for ATmega32u4-based boards and Arduino 101
  }

  systemResetCallback();  // reset to default config
}

/*==============================================================================
 * LOOP()
 *============================================================================*/
void loop()
{
  byte pin, analogPin;

  /* DIGITALREAD - as fast as possible, check for changes and output them to the
   * FTDI buffer using Serial.print()  */
  checkDigitalInputs();

  /* STREAMREAD - processing incoming messagse as soon as possible, while still
   * checking digital inputs.  */
  while (Firmata.available())
    Firmata.processInput();

  // TODO - ensure that Stream buffer doesn't go over 60 bytes

  currentMillis = millis();
  if (currentMillis - previousMillis > samplingInterval) {
    previousMillis += samplingInterval;
    /* ANALOGREAD - do all analogReads() at the configured sampling interval */
    for (pin = 0; pin < TOTAL_PINS; pin++) {
      if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) {
        analogPin = PIN_TO_ANALOG(pin);
        if (analogInputsToReport & (1 << analogPin)) {
          Firmata.sendAnalog(analogPin, analogRead(analogPin));
        }
      }
    }
  }

#ifdef FIRMATA_SERIAL_FEATURE
  serialFeature.update();
#endif
}

```

## Upgrading the board

> Or should I just buy a newer board?

You probably don't need to because of the above. But you also have the option of upgrading it to an ATmega328P version with just the chip and burning the bootloader or having that done for you. Some hobby places will sell them burned with optiboot.

---
Tags: firmata
---


title: Recursive listing of sd card files

text:
# Question
Title: Recursive listing of sd card files
I'm working on a MP3 player and I want to list all files on the SD card.

I have found this code on internet :

```
void displaySdCardContent(FileItem& item, int numTabs) {
  for (int i = 0; i < numTabs; i++) {
    Serial.print('\t');
  }
  if (item.isDir) {
    Serial.println(item.name);
    for (FileItem fileElement : item.elements) {
      displaySdCardContent(fileElement, numTabs + 1);
    }
  } else {
    Serial.println(item.name);
  }
}

void displaySdCardContent(FileItem& item, int numTabs) {
  for (int i = 0; i < numTabs; i++) {
    Serial.print("...");
  }
  if (item.isDir) {
    Serial.println(item.name);
    for (FileItem& fileElement : item.elements) {
      displaySdCardContent(fileElement, numTabs + 1);
    }
  } else {
    Serial.println(item.name);
  }
}

```

It lists all the files but I can display only the first level directory. Here is my full code.

```
#define pushButton_pin   32
// Include required libraries
#include "Audio.h"
#include "SD.h"
#include "FS.h"
#include <Wire.h>
#include <TFT_eSPI.h>
#include <SPI.h>

// microSD Card Reader connections
#define SD_CS          5
#define SPI_MOSI      21
#define SPI_MISO      19
#define SPI_SCK       18

// I2S Connections
#define I2S_DOUT      22
#define I2S_BCLK      26
#define I2S_LRC       25

 // Create Audio object
Audio audio;

TFT_eSPI tft = TFT_eSPI();
//digitalWrite(TFT_BL, 1);

int maxIndex;
uint32_t Freq = 0;
int Val;
String Btn, SongName;
String Status = "Idle";
bool state = true;
bool Current_State = state;
int Current_Millis;
int Previous_Millis;
int Debounce = 175;
int Xindex = 0;
int Yindex = 0;

const uint8_t maxFileNameSize = 50;
struct FileItem {
  bool isDir;
  char name[maxFileNameSize + 1];
  FileItem* upDir;
  std::vector<FileItem> elements;
};

File dir;
String CurrDir;
String NextDir;
String Song;
String Liste[50];

void setup() {
  pinMode(pushButton_pin, INPUT);
  setCpuFrequencyMhz(160);
  tft.init();
  tft.setRotation(3);
  tft.fillScreen(TFT_BLACK);
  tft.setTextWrap(false);

  // Set microSD Card CS as OUTPUT and set HIGH
  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);

  // Initialize SPI bus for microSD Card
  SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);

  // Start Serial Port
  Serial.begin(115200);

  // Start microSD Card
  if (!SD.begin(SD_CS))
  {
    Serial.println("Error accessing microSD card!");
    while(true);
  }
  Serial.println("initialization done.");
  Serial.println("Creating structure of files");
  File root = SD.open("/");
  FileItem rootItem;
  if (strlen(root.name()) != 0)
    strncpy(rootItem.name, root.name(), maxFileNameSize);
  else
    strncpy(rootItem.name, "/", maxFileNameSize);
  rootItem.name[maxFileNameSize] = '\0';
  rootItem.isDir = true;
  readSdCard(root, rootItem);
  //Fin du listing

  Serial.println ("----Disp----");
  displaySdCardContent(rootItem, 0);
}

void readSdCard(File dir, FileItem& parentItem) {
  while (true) {
    File entry = dir.openNextFile();
    if (!entry) {
      break;  // no more files
    }
    FileItem item;
    item.isDir = entry.isDirectory();
    strncpy(item.name,  entry.name(), maxFileNameSize); // https://cplusplus.com/reference/cstring/strncpy/
    item.name[maxFileNameSize] = '\0';
    parentItem.elements.push_back(item);
    Serial.printf("Add %s to %s\n", item.name, parentItem.name);
    if (entry.isDirectory()) {
      readSdCard(entry, item);
    }
  }
}

void displaySdCardContent(FileItem& item, int numTabs) {
  for (int i = 0; i < numTabs; i++) {
    Serial.print("...");
  }
  if (item.isDir) {
    Serial.println(item.name);
    for (FileItem& fileElement : item.elements) {
      displaySdCardContent(fileElement, numTabs + 1);
    }
  } else {
    Serial.println(item.name);
  }
}

```

I have tried this to access the second level directories :

```
  FileItem* subFolder = &rootItem.elements.at(0);
  Serial.println ("----Disp----");
  FileItem _subFolder= *subFolder;

  displaySdCardContent(_subFolder, 0);

```

But it doesn't work ...

Here is what I get with the serial monitor :

```
23:36:23.419 -> Add 11-Avalanche.mp3 to War Eternal
23:36:23.419 -> Add 12-Down To Nothing.mp3 to War Eternal
23:36:23.419 -> Add 13-Not Long For This World.mp3 to War Eternal
23:36:23.451 -> Add folder.jpg to War Eternal
23:36:23.451 -> Add Will To Power to Arch Enemy
23:36:23.483 -> Add 01-Set Flame To The Night.mp3 to Will To Power
23:36:23.483 -> Add 02-The Race.mp3 to Will To Power
23:36:23.515 -> Add 03-Blood In The Water.mp3 to Will To Power
23:36:23.515 -> Add 04-The World Is Yours.mp3 to Will To Power
23:36:23.515 -> Add 05-The Eagle Flies Alone.mp3 to Will To Power
23:36:23.547 -> Add 06-Reason To Believe.mp3 to Will To Power
23:36:23.547 -> Add 07-Murder Scene.mp3 to Will To Power
23:36:23.579 -> Add 08-First Day In Hell.mp3 to Will To Power
23:36:23.579 -> Add 09-Saturnine.mp3 to Will To Power
23:36:23.612 -> Add 10-Dreams Of Retribution.mp3 to Will To Power
23:36:23.643 -> Add 11-My Shadow And I.mp3 to Will To Power
23:36:23.643 -> Add 12-A Fight I Must Win.mp3 to Will To Power
23:36:23.675 -> Add folder.jpg to Will To Power
23:36:23.675 -> ----Disp----
23:36:23.675 -> Arch Enemy

```

Edit : Attributes item i can print in `displaySdCardContent()`

```
14:58:54.763 -> ----Disp----
14:58:54.763 -> name : Arch Enemy
14:58:54.763 -> IsDir : 1

```

Debug in `ReadsdCard`

```
⸮⸮item name : 07. [Through The Eyes Of A Raven].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :7
Add 07. [Through The Eyes Of A Raven].mp3 to CD1 - Khaos Legions
item name : 08. [Cruelty Without Beauty].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :8
Add 08. [Cruelty Without Beauty].mp3 to CD1 - Khaos Legions
item name : 09. [We Are A Godless Entity].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :9
Add 09. [We Are A Godless Entity].mp3 to CD1 - Khaos Legions
item name : 10. [Cult Of Chaos].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :10
Add 10. [Cult Of Chaos].mp3 to CD1 - Khaos Legions
item name : 11. [Thorns In My Flesh].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :11
Add 11. [Thorns In My Flesh].mp3 to CD1 - Khaos Legions
item name : 12. [Turn To Dust].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :12
Add 12. [Turn To Dust].mp3 to CD1 - Khaos Legions
item name : 13. [Vengeance Is Mine].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :13
Add 13. [Vengeance Is Mine].mp3 to CD1 - Khaos Legions
item name : 14. [Secrets].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :14
Add 14. [Secrets].mp3 to CD1 - Khaos Legions
item name : CD2 - Kovered In Khaos
item IsDir : 1
item size :0
parent item name : 2011 - Khaos Legions (2xCD, Ltd)
parent item IsDir : 1
Parent item size :2
Add CD2 - Kovered In Khaos to 2011 - Khaos Legions (2xCD, Ltd)
item name : 01. [Warning].mp3
item IsDir : 0
item size :0
parent item name : CD2 - Kovered In Khaos
parent item IsDir : 1
Parent item size :1
Add 01. [Warning].mp3 to CD2 - Kovered In Khaos
item name : 02. [Wings Of Tomorrow].mp3
item IsDir : 0
item size :0
parent item name : CD2 - Kovered In Khaos
parent item IsDir : 1
Parent item size :2
Add 02. [Wings Of Tomorrow].mp3 to CD2 - Kovered In Khaos
item name : 03. [The Oath].mp3
item IsDir : 0
item size :0
parent item name : CD2 - Kovered In Khaos
parent item IsDir : 1
Parent item size :3
Add 03. [The Oath].mp3 to CD2 - Kovered In Khaos
item name : 04. [The Book Of Heavy Metal].mp3
item IsDir : 0
item size :0
parent item name : CD2 - Kovered In Khaos
parent item IsDir : 1
Parent item size :4
Add 04. [The Book Of Heavy Metal].mp3 to CD2 - Kovered In Khaos
item name : Folder.jpg
item IsDir : 0
item size :0
parent item name : 2011 - Khaos Legions (2xCD, Ltd)
parent item IsDir : 1
Parent item size :3
Add Folder.jpg to 2011 - Khaos Legions (2xCD, Ltd)
item name : War Eternal
item IsDir : 1
item size :0
parent item name : Arch Enemy
parent item IsDir : 1
Parent item size :4
Add War Eternal to Arch Enemy
item name : 01-Tempore Nihil Sanat (Prelude in F minor).mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :1
Add 01-Tempore Nihil Sanat (Prelude in F minor).mp3 to War Eternal
item name : 02-Never Forgive, Never Forget.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :2
Add 02-Never Forgive, Never Forget.mp3 to War Eternal
item name : 03-War Eternal.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :3
Add 03-War Eternal.mp3 to War Eternal
item name : 04-As The Pages Burn.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :4
Add 04-As The Pages Burn.mp3 to War Eternal
item name : 05-No More Regrets.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :5
Add 05-No More Regrets.mp3 to War Eternal
item name : 06-You Will Know My Name.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :6
Add 06-You Will Know My Name.mp3 to War Eternal
item name : 07-Graveyard Of Dreams.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :7
Add 07-Graveyard Of Dreams.mp3 to War Eternal
item name : 08-Stolen Life.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :8
Add 08-Stolen Life.mp3 to War Eternal
item name : 09-Time Is Black.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :9
Add 09-Time Is Black.mp3 to War Eternal
item name : 10-On And On.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :10
Add 10-On And On.mp3 to War Eternal
item name : 11-Avalanche.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :11
Add 11-Avalanche.mp3 to War Eternal
item name : 12-Down To Nothing.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :12
Add 12-Down To Nothing.mp3 to War Eternal
item name : 13-Not Long For This World.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :13
Add 13-Not Long For This World.mp3 to War Eternal
item name : folder.jpg
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :14
Add folder.jpg to War Eternal
item name : Will To Power
item IsDir : 1
item size :0
parent item name : Arch Enemy
parent item IsDir : 1
Parent item size :5
Add Will To Power to Arch Enemy
item name : 01-Set Flame To The Night.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :1
Add 01-Set Flame To The Night.mp3 to Will To Power
item name : 02-The Race.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :2
Add 02-The Race.mp3 to Will To Power
item name : 03-Blood In The Water.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :3
Add 03-Blood In The Water.mp3 to Will To Power
item name : 04-The World Is Yours.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :4
Add 04-The World Is Yours.mp3 to Will To Power
item name : 05-The Eagle Flies Alone.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :5
Add 05-The Eagle Flies Alone.mp3 to Will To Power
item name : 06-Reason To Believe.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :6
Add 06-Reason To Believe.mp3 to Will To Power
item name : 07-Murder Scene.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :7
Add 07-Murder Scene.mp3 to Will To Power
item name : 08-First Day In Hell.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :8
Add 08-First Day In Hell.mp3 to Will To Power
item name : 09-Saturnine.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :9
Add 09-Saturnine.mp3 to Will To Power
item name : 10-Dreams Of Retribution.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :10
Add 10-Dreams Of Retribution.mp3 to Will To Power
item name : 11-My Shadow And I.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :11
Add 11-My Shadow And I.mp3 to Will To Power
item name : 12-A Fight I Must Win.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :12
Add 12-A Fight I Must Win.mp3 to Will To Power
item name : folder.jpg
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :13
Add folder.jpg to Will To Power
----end of listing ----
rootItem.element[0] name : Arch Enemy
rootItem.element[0] IsDir : 1
rootItem.element[0] size :0

```

# Answer
> 0 votes
The error is hard to see, but it is essentially in this original sequence (irrelevant statements omitted):

```
    FileItem item;
    // ...
    parentItem.elements.push_back(item);
    // ...
      readSdCard(entry, item);
    }

```

The method `push_back()` **copies** the `item` to `elements`. Since at that moment `item` has no elements, the copy also has none. Later modifications of `item` do not change the copy.

There are multiple alternatives to correct.

**1. Recurse first, then push:**

```
    FileItem item;
    // ...
      readSdCard(entry, item);
    }
    // ...
    parentItem.elements.push_back(item);

```

This way `item`'s `elements` vector collect its entries before the `push_back()`.

However, the order of debug messages changes.

**2. Recurse with the copy:**

```
    FileItem item;
    // ...
    parentItem.elements.push_back(item);
    // ...
      readSdCard(entry, parentItem.elements.back());
    }

```

In this case `readSdCard()` uses the copy of `item` in `parentItem`'s `elements` to collect the entries.

---
Tags: recursion
---


# Question
Title: Equivalent libary of RTCZero for Arduino UNO
I am a beginner to Ardunino UNO This is my first program to light up an LED strip

```
#include <Adafruit_NeoPixel.h>

#include <RTCZero.h>

#define PIN            6
#define NUMPIXELS      60 // Define the total number of pixels in your strip
#define BRIGHTNESS     50 // Adjust the brightness (0-255)

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
RTCZero rtc;

void setup() {
  strip.begin(); // Intializes the neo pixel library for use
  strip.show();  // Initialize all pixels to 'off'

  rtc.begin();
// Intialzes the real time clock , the rtc is defined previuosly ,the dot access the the memebr in this case begin () , which is a method , method is used to perform an action , they belong to a class and defines how an object behaves

  // Set the initial time at the time of the project
  rtc.setHours(12);
  rtc.setMinutes(0);
  rtc.setSeconds(0);
}

void loop() {

  int currentHour = rtc.getHours(); // Get the current hour from the real time clock
  uint32_t color;

  // Set color based on the time of the day
  if (currentHour >= 6 && currentHour < 16) {
    // Yellow during 6 am to 4 pm

    color = strip.Color(255, 255, 0);
  } else if (currentHour >= 16 && currentHour < 20) {
    // Orange during 4 pm to 8 pm

    color = strip.Color(255, 165, 0);
  } else {
    // Blue during 8 pm to 6 am

    color = strip.Color(0, 0, 255);
  }

  // Set the color for all pixels
  fillStrip(color);

  // Optional: Adjust brightness
  strip.setBrightness(BRIGHTNESS);

  // Update the NeoPixel strip
  strip.show();

  // Delay to avoid updating the colors too frequently
  delay(60000); // Delay for 1 minute (adjust as needed)
}

// Uses for loop to itrate the color for all the pixels in the led strip
void fillStrip(uint32_t color) {
  for (int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, color);
  }
}

```

Unable to compile the program due to the below error. How do I find an equivalent function for Arduino UNO ??

WARNING: *library RTCZero claims to run on samd architecture(s) and may be incompatible with your current board which runs on avr architecture(s).*

# Answer
> 1 votes
There is no built in RTC on a normal Arduino UNO. If you want to do the same thing on an UNO you can either add an external RTC module like the DS3231 or the DS1307. There are libraries in the library manager for those devices that will work with your UNO. You can then find the functions that perform the same job as the ones in your code and replace them.

If your UNO is the new UNO-R4, then yes those do have an RTC and there is a library in the core for it, but the RTC on those boards is terribly inaccurate due to the lack of an accurate clock source to drive it. So even in that case I'd still recommend an external RTC.

---
Tags: arduino-uno, rtc
---


# Question
Title: DHT20 and OLED display not working together
I am trying to get my DHT20 and OLED (both from the Arduino Sensor Kit) to work at the same time. I am able to get them working separately with their respective test codes, but when I try to combine the codes the OLED display no longer works. Both are I2C connections but I checked and each device has a different address so that shouldn't be a problem.

Here is my DHT20 test code:

```
#include "Arduino_SensorKit.h"

//uncomment line below if using DHT20
#define Environment Environment_I2C

void setup() {
  //uncomment line below if using DHT20
  Wire.begin();
  Serial.begin(9600);
  Environment.begin();
}

void loop() {
  Serial.print("Temperature = ");
  Serial.print(Environment.readTemperature()); //print temperature
  Serial.println(" C");
  Serial.print("Humidity = ");
  Serial.print(Environment.readHumidity()); //print humidity
  Serial.println(" %");
  delay(2000);
}

```

Here is my OLED display test code:

```
#include "Arduino_SensorKit.h"

void setup() {
  Oled.begin();
  Oled.setFlipMode(true);
}

void loop() {
  int random_value = random(0, 1023); // create a random value
  Oled.setFont(u8x8_font_chroma48medium8_r);
  Oled.setCursor(0, 3);
  Oled.print("Value: ");
  Oled.print(random_value);
  delay(1000);
}

```

This is the code where I tried to get both devices working at the same time:

```
#include "Arduino_SensorKit.h"

#define Environment Environment_I2C

void setup() {
  Oled.begin();
  Oled.setFlipMode(true);
  Wire.begin();
  Serial.begin(9600);
  Environment.begin();
}

void loop() {
  Oled.setFont(u8x8_font_chroma48medium8_r);
  Oled.setCursor(0, 3);
  Oled.print("Testing");
  Serial.print("Temperature = ");
  Serial.print(Environment.readTemperature()); //print temperature
  Serial.println(" C");
  Serial.print("Humidity = ");
  Serial.print(Environment.readHumidity()); //print humidity
  Serial.println(" %");
  delay(2000);
}

```

When I use this code the temp and humidity values are printed in the serial monitor but the OLED does not display anything.

Any help is much appreciated!

# Answer
### The basic problem

I don't have this sensor kit. But am able to observe what you're describing with substitutes and stand-ins. There seem to be two things you can do.

The basic problem is that the Arduino\_SensorKit library is written to use software/bit-banged I2C for the display. Or rather, it tells U8G2LIB to do this, for what reason I don't know. When the ATmega328P I2C peripheral is enabled the GPIO hardware is no longer driving the pins. So the moment you enable the hardware I2C (via the DHT20 code) the GPIO bit-banging code in U8G2LIB cannot work correctly.

So, there are at least two ways this can be made to work.

* Modifying your code so it works with how the Arduino\_SensorKit library is written.
* The other is modifying the Arduino\_SensorKit library to use hardware I2C, in which case your original code works verbatim.

## Modifying the sketch

You can modify your sketch as follows:

```
#include "Arduino_SensorKit.h"
#define Environment Environment_I2C

void setup() {
  Oled.begin();
  Oled.setFlipMode(true);

  Serial.begin(9600);

  Wire.begin(); // only here to match the subsequent .end()
}

void loop() {
  Wire.end();  // make I2C release control back to GPIO
  {
    Oled.setFont(u8x8_font_chroma48medium8_r);
    Oled.setCursor(0, 3);
    Oled.print(millis()); //Oled.print("Testing");
  }
  Wire.begin(); // re-enable I2C for use by DHT20 ("Environment")

  Serial.print("Temperature = ");
  Serial.print(Environment.readTemperature()); //print temperature
  Serial.println(" C");
  Serial.print("Humidity = ");
  Serial.print(Environment.readHumidity()); //print humidity
  Serial.println(" %");

  delay(2000);
}

```

For the most part the AVR Wire library doesn't care if you use repeated `begin()` or repeated `end()` calls. It may affect your speed setting though. The braces around the `Oled` usage are just there for visual effect.

Anyway, it works when you make sure `Oled` can use GPIO.

## Modifying Arduino\_SensorKit

With the following changes to Arduino\_SensorKit library version 1.2.1 (current as of writing) I am able to use your sketch code verbatim. I also modified it to print `millis()` rather than `"Testing"` to be sure it was *continuing* to update the display.

### Arduino\_SensorKit.h

On line 24 of the libraries Arduino\_SensorKit.h file, change:

```
extern U8X8_SSD1306_128X64_NONAME_SW_I2C Oled;

```

to

```
extern U8X8_SSD1306_128X64_NONAME_HW_I2C Oled;

```

Note `HW` (hardware) rather than `SW` (software).

### Arduino\_SensorKit.cpp

Likewise make the counterpart change to the definition of `Oled` corresponding to above change in `extern` declaration of `Oled`, from:

```
U8X8_SSD1306_128X64_NONAME_SW_I2C Oled(/* clock=*/ _PIN_SCL, /* data=*/ _PIN_SDA, /* reset=*/ U8X8_PIN_NONE);

```

to:

```
U8X8_SSD1306_128X64_NONAME_HW_I2C Oled(/* clock=*/ _PIN_SCL, /* data=*/ _PIN_SDA, /* reset=*/ U8X8_PIN_NONE);

```

You can probably remove the arguments from the constructor call here; the ATMega328P has no options with respect to configuring TWI/I2C for more than one set of pins.

---

There's also nothing stopping you from leaving it as `U8X8_SSD1306_128X64_NONAME_SW_I2C`, but changing the pins so that the software I2C uses pins other than A4/A5 so as not to conflict with the DHT20 libraries use of hardware I2C.

---

For reference the U8G2LIB version I tested with was 2.33.15. arduino-cli version 0.32.2. arduino:avr core 1.8.7. *I don't think you need these. I'm just being complete in case someone finds this 5 years from now or whatever.*
> 3 votes

# Answer
I use a variable to store the readings.

```
#include "Arduino_SensorKit.h"

#define Environment Environment_I2C

void setup() {
  Oled.begin();
  Oled.setFlipMode(true); // Sets the rotation of the screen
  // uncomment line below if using DHT20 (black sensor)
  Wire.begin();
  // uncomment line below if you're connecting your DHT20 to pin a different than 3
  Serial.begin(9600);
  Environment.begin();
}

void loop() {
  Wire.begin();

  // You need variable to keep the reading because Enviroment will not work when LED in operation
  float temp= Environment.readTemperature();
  float hum= Environment.readHumidity();
  Serial.print("Temperature = ");
  Serial.print(temp); //print temperature
  Serial.println(" C");
  Serial.print("Humidity = ");
  Serial.print(hum); //print humidity
  Serial.println(" %");

  delay(2000);

  // int random_value = analogRead(A0);
  Wire.end();

  {
    Oled.setFont(u8x8_font_chroma48medium8_r);
    Oled.setCursor(0, 0);    // Set the Coordinates
    Oled.print("temp: ");
    Oled.print(temp); // Print the Values

    Oled.setCursor(0, 3); // Set the Coordinates
    Oled.print("Humidity: ");
    Oled.print(hum); // Print the Values
    Oled.refreshDisplay(); // Update the Display
  }
}

```
> 1 votes

---
Tags: arduino-uno, sensors, i2c, temperature-sensor, oled
---


# Question
Title: ESP01 won't boot when connected to the LED strip
I have a weird bug behavior. I have an ATX power supply, which powers a long WS2812B 5v strip, controlled by the Esp 01 and the board...

Now the bug happens only when I connect the data pin to the strip. The ESP won't start after I restart the ATX PSU. And if it does it just crashes after some time...

Here is the SPOOKY part: when I start the esp WITHOUT the pin connected and plug it in after it starts it will keeep working for days... but sometimes it just decides it will go bananas... W T F! Any ideas why?????

I suspected voltage drops, but nope. I tried a battery, a second adapter and a USB power... none helped. Same behavior as soon as you connect the strip and hit restart/update, it goes bananas...

# Answer
> 1 votes
I used a 470Ohm to connect GPIO2 and VCC. (to ensure HIGH during boot phase). As suggested on : https://www.esp8266.com/viewtopic.php?p=77993

esp01 5v to 3.3shifter 470Ohm

Regards, Dom

---
Tags: esp8266
---


title: HX711 Ridiculous speeds

text:
# Question
Title: HX711 Ridiculous speeds
I'm using a SparkFun HX711 board and an Adafruit AdaLogger (M0) Featherboard. I have cut the trace on the back of the HX711 to get a faster data rate (should be about 80 sps). I did this by reviewing the spec sheet and confirming with this post (Github link for faster rates).

Before I read from the board I get startTime from micros() and immediately after I get get the scale data, I call micros() again and record the endTime. I then write this data along with the load cell data to an SD card. Then to check the time, after the experiment is over in excel I take 1/((endTime - startTime)\*10^-6) to get the approximate number of samples per second.

My issue is that apparently, I'm recording at a max of around 6000 SPS but commonly around 600 SPS. Which, would be awesome if I wasn't so sure that it was a lie. I was hoping someone could take a look and see what I'm doing wrong? I used this same code on a different M0 with an unmodified HX711 and was getting around 10 SPS. The only thing different (I thought) was cutting the trace on the back of the board to enable the higher rate.

In the GitHub link above, they do mention that you can get a faster rate if you splice in a faster crystal with a cap to bridge pins 13 and 14. I have not done this, but perhaps the faster processor on the Feather might be playing some of a role in this?

VCC and VDD are both connected to 3.3V and GND is connected to the ground pin on the Feather. Pin 11 is connected to DAT and Pin 10 is connected to CLK

```
#include <SPI.h>
#include <SD.h>
#include "HX711.h"

#define FILE_BASE_NAME "FAST" // max six characters
#define DOUT_one 11   // Red
#define CLK_one  10   // Orange

const uint8_t CS_PIN = 4;
const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;

char fileName[] = FILE_BASE_NAME "00.csv";

float calibration_factor_one = -7050; // needs to be calibrated still

File file;

long startTime=0;
long endTime =0;

String dataString = "";

double scale_one_value = 0.0;

HX711 scale_one;

void SetUpSDCard(){
  if (!SD.begin(CS_PIN)) {
    Serial.println(F("begin failed"));
    return;
    }
   while (SD.exists(fileName)) {
    if (fileName[BASE_NAME_SIZE + 1] != '9') {
      fileName[BASE_NAME_SIZE + 1]++;
    } else if (fileName[BASE_NAME_SIZE] != '9') {
      fileName[BASE_NAME_SIZE + 1] = '0';
      fileName[BASE_NAME_SIZE]++;
    } else {
      Serial.println(F("Can't create file name"));
      return;
    }
  }
   file = SD.open(fileName, FILE_WRITE);
  if (!file) {
    Serial.println(F("open failed"));
    return;
  }
  Serial.print(F("opened: "));
  Serial.println(fileName);
  }

void SetUpLoadCell(){
  Serial.println("Remove all weight from scale");
  scale_one.begin(DOUT_one, CLK_one);
  scale_one.set_scale();
  scale_one.tare();

  long zero_factor_one = scale_one.read_average(); //Get a baseline reading
  Serial.print("Zero factor: ");
  Serial.println(zero_factor_one);
  Serial.println("Load cell one initialized");
  scale_one.set_scale(calibration_factor_one); //Adjust to this calibration factor
  }

void LogData(){
  startTime= micros();
  scale_one_value = scale_one.get_units();
  endTime = micros();

  dataString = String(startTime) + "," + String(scale_one_value) + "," + String(endTime);
  file.println(dataString);
  file.flush();
  }

void setup() {
  Serial.begin(9600);
  SetUpSDCard();
  Serial.println("Remove all weight from scale");
  SetUpLoadCell();
}

void loop() {
  LogData();
}

```

Then the saved data that is on the SD card is as follows, this is just the first 20 lines.

```
3383895,    0,      3384049
3401786,    0,      3401938
3411851,    0,      3412004
3421850,    -0.02,  3422004
3432012,    -0.03,  3432164
3442074,    0.01,   3442226
3452118,    0,      3452269
3462299,    0,      3462450
3472441,    0.03,   3473497
3483434,    0.03,   3485070
3495011,    0.02,   3496638
3506580,    0.01,   3508211
3518576,    0.03,   3519785
3529783,    0.02,   3531353
3541282,    0,      3542924
3552831,    0,      3554495
3564476,    0,      3566070
3575900,    0.01,   3577638
3587476,    -0.01,  3589209
3599068,    -0.03,  3600782

```

# Answer
You're not measuring how many samples you do in a second, instead you're measuring the amount of time it takes to retrieve one sample from the HX711.

You store the time, retrieve the next sample, then store the time again. Then you spend a comparative age storing that data to the SD card, during which time the HX711 is taking any number of other samples. By the time you eventually get around to reading from the HX711 again it's already ready to give you a sample.

You need to factor in the amount of time it takes to write to the SD card to have any kind of meaningful results - that is, the total amount of time that it takes to execute a loop(), or more simply: how long since the last time your logData() function has been run.

The actual sampling time of the HX711 will probably pale into insignificance compared to all the rest of your sequential code.
> 2 votes

# Answer
To measure data sampling rate, measure elapsed time to fill an array with 10 (or better yet - 100) measurements.

```
N = 100;
t0 = millis();
for (i=0; i<N; i++){
    s[i] = get_sample();
}
samplingTime = (millis()-t0)/N;

```
> 0 votes

---
Tags: adafruit, code-review
---


# Question
Title: Importing content of text file as string into Arduino code
Is there any macro for importing the content of a file (for example html code) located in the sketch folder as a string for the Arduino IDE during compilation time?

# Answer
> 3 votes
For ESP32 (and ESP8266), you can partition part of the Flash memory to be used as the file system and creating a `data/` folder in your project for storing files. Take a look at arduino-esp32littlefs-plugin (used for uploading the data to the partition) on how to install the plugin in Arduino IDE, and the LittleFS library or SPIFFS on how to use it to store and retrieve data.

I have a project on my github showing how the SPIFFS is used for storing webpages (html, JavaScript, CSS, icon, etc.) and serve it via an Async ESP32 Server. Following the link on the github for more detail explanation on the blog.

# Answer
> 2 votes
Try using the C++ Raw String Literal.

It's in the form of

```
const char *myLiteralText=R"abc123~~~(
   this is
   literal text
   which includes all spaces
   and newlines
)abc123~~~"

```

The `abc123~~~` is a delimiter.

The test.h file must be modified by adding the first and last lines.

Actually, the last line can be in the `test.ino` file after the #include line, so only the first line has to be added to the `test.h` file.

Example at https://wokwi.com/projects/384484092370522113

test.ino

```
void setup() {

  Serial.begin(9600);

  const char *index_html=
    #include "test.h"
  ;

  Serial.print(index_html);

}

void loop() {}

```

test.h

```
R"html(

<!DOCTYPE html>
<html lang="en">
  <head>
      <meta charset="UTF-8">
      <title>VIPSDK MONITOR</title>
      <meta http-equiv="refresh" content="10">
  </head>
  <style type="text/css">
  </style>
</html>

)html"

```

# Answer
> 0 votes
In short, no. That I'm aware of the IDE, languages, and build system don't provide anything to do that automatically. It would be nice if C++ had something like Rust's `include_str` or `include_bytes` but so far as I know it still doesn't.

Your question is tagged with esp32. You may want to put strings on on your data partition if they're large.

There are other ways to do it, but the usual way to build arbitrary data into a C++ or C program is to run a utility that converts it into source code. Either into a string literal or an initialized array of some character type. The xxd utility that usually comes with VIM is one such utility. It's normally used to generate hex dumps of files, but can be told to produce source code of an initialized array. Utilities like that are often run in a pre-build stage of a more conventional build process for C++. You could probably hack something into platform.txt that would do it. Or into something like a git hook. But the IDE doesn't have that sort of flexibility.

Here's a webpage that does the same sort of thing. You may have to manually null terminate the array if you want to do this.

---
Tags: arduino-uno, arduino-ide, esp32
---


# Question
Title: Arduino Serial Monitor works but not on PySerial and PuTTY
I made simple custom arduino board using an atmega328p and the PL2303 serial to USB chip.

In my arduino program, I am in a loop that sends out a string continuously. I can read this in the Arduino serial monitor with a baudrate of 9600. However, in my python program using the pySerial library, the readline function doesn't return anything. I checked using PuTTY but it still doesn't do anything.

Now I tried messing with the serial settings and found out that these lines of code work (the readline returns the string) if I call it in the exact same order.

```
ser = serial.Serial(comm_port)
ser.xonxoff = True
ser.rtscts = True
ser.dsrdtr = True
ser.readline()

```

However, the code below doesn't work

```
ser = serial.Serial(comm_port, xonxoff=True, rtscts=True, dsrdtr=True)
ser.readline()

```

What could be causing this? My guess is somehow I've switched the datalines in my USB cable and that the arduino serial monitor handles this somehow.

Another thing to note is that I couldn't program the Arduino the normal way via USB. I always have to program it using the ICSP port and a USBasp programmer.

# Answer
I wrote a python application which communicated with an arduino and for some reason I had to insert a delay after opening the serial for it to work correctly, if I didn't the first data I sent would always get dropped. Perhaps that's what's occuring here? Setting the attributes of the serial connection like that is probably slower than doing it in initialisation.

For myself I found that a delay of 3 seconds was what I needed for it to work 100% correctly on all computers (on some a second was enough). You only had to wait after opening it once open it worked fine.

To do a delay import the time module and use the sleep function which takes an argument of seconds.

```
import time

time.sleep(3)

```

Also worth noting depending on your application it's worth setting a timeout value for the serial that's appropriate or just keeping it open with the timeout paramter.

```
 ser = serial.Serial(com, 115200, timeout=0)

```

If you do this make sure to close it when you finished with it though (I personally used a try finally block which makes sure its always closed).

```
try:
  ser = serial.Serial(com, 115200, timeout=0)
  #go nuts with whatever communicating your doing
finally:
  ser.close()

```

I'm afraid I can't really tell you what caused the issue though. I also realise that this question is quite old so I hope my answer is still helpful, if not to you then to someone else who stumbles across it. To note for future the people on the official Arduino forum may be of more help for arduino related questions in general.
> 0 votes

# Answer
"Another thing to note is that I couldn't program the Arduino the normal way via USB. I always have to program it using the ICSP port and a USBasp programmer." sounds like your atmega328p does not have a bootloader. Or the PL2303 does not have the correct driver.

I never used PL2303, but I have used FTDI USB TTL (ft232r) adapters. When I first used the adapter, my Windows computer installed the wrong driver for the adapter and I had to manually download the correct firmware from the FTDI website and install it manually. You can check if the driver is correct in the device manager, the author of the driver should be the manufacturer's name (not Microsoft).
> -1 votes

---
Tags: serial, python
---