# Question
Title: How to save a float variable to the EEPROM?
This is my first post here and I'm hoping there are some Arduino hobbyists here to help me.

Does anyone here know how to save a float variable directly to the EEPROM? If so, could you have a look at the program I wrote and hopefully explain how it would be set up to work with the other 2 variables I'm saving to the EEPROM?

The program I wrote displays a voltmeter to the LCD. The program has an adjustable alarm set point as to when to sound an alarm when the voltage drops below a user-set alarm set point. I want to be able to declare the alarm set point as a float variable and save it directly to the EEPROM. I can't seem to find any programs that I could use as an example to try and figure out how to do that.

I did manage to get my program working to save my Volt\_Alarm\_Set\_Point by declaring it as an int var and then comparing it to my Volt\_Set\_Point (declared as a float var) to 165 if statements to save the right Volt\_Alarm\_Set\_Point value. And it works a treat but uses up 4956 bytes of program space. That's ok if I'm using an Arduino Mega but I'd like to be able to have my program run on an Arduino Nano which could cause problems with some bigger programs.

If anyone here could show me how to do this it would be greatly appreciated and I would be in your dept. Here is my code below. I don't understand how the code is suppose to be put here? Other forums are dead easy to post code but I can't figure this one out. Sorry about that... Thanks jessey

```
 #include <EEPROM.h>
 #include <LiquidCrystal_I2C.h>
 LiquidCrystal_I2C lcd(0x27, 20, 4);

//----------Volt Meter Code----------//
    int analogInput = A6;
    float vout = 0.0;
    float vin = 0.0;
    float R1 = 99300.0;
    float R2 = 9970.0;
    int value = 0;
//----------Volt Meter Code----------//

  int Volt_Alarm_Set_Point; // this works
  float Volt_Set_Point;
//  float Volt_Alarm_Set_Point; // this dosen't work
  int s = 0;
  int a = 0;
  int b = 0;

 int Button_1 = 5;
 int Button_2 = 6;
 int Button_3 = A1;
 int Button_4 = A0;
 int Alarm_Relay_1 = A3;
 int Relay_2 = A2;
 int Relay_3 = 8;
 int Blinking_Led = 3;// this one is ready to be used anytime

 #define VOLT_ALARM_SET_POINT_ADDR 0
 #define A_ADDR VOLT_ALARM_SET_POINT_ADDR + sizeof(int)
 #define B_ADDR A_ADDR + sizeof(int)

 #define Is_Pressed  0  // used for pushbuttons
 #define Is_Turned_On 1  // used for the relays
 #define Is_Turned_Off 0 // used for the relays

 //|---------void setup---------void setup---------|//
void setup() {

    pinMode(Alarm_Relay_1, OUTPUT);
    pinMode(Relay_2, OUTPUT);
    pinMode(Relay_3, OUTPUT);
    pinMode(Blinking_Led, OUTPUT);
    pinMode(Button_1, INPUT); // on pin 5
    pinMode(Button_2, INPUT); // on pin 6
    pinMode(Button_3, INPUT); // on pin A1
    pinMode(Button_4, INPUT); // on pin A0
//-----------Volt Meter Code--------------//
    pinMode(analogInput, INPUT);
//-----------Volt Meter Code--------------//

    lcd.begin();

    lcd.setCursor(0, 0);
    lcd.print(F("  This Program Is   "));
    lcd.setCursor(0, 1);
    lcd.print(F("to try and save a   "));
    lcd.setCursor(0, 2);
    lcd.print(F("float variable      "));
    lcd.setCursor(0, 3);
    lcd.print(F("to the eeprom       "));
    delay(500);

    lcd.clear();

    EEPROM.get(VOLT_ALARM_SET_POINT_ADDR, Volt_Alarm_Set_Point);
    EEPROM.get(A_ADDR, a);
    EEPROM.get(B_ADDR, b);
//  EEPROM.put( VOLT_ALARM_SET_POINT_ADDR, Volt_Alarm_Set_Point);
//  EEPROM.put(A, a);
//  EEPROM.put(B, b);

}// end of the void setup()

//|---------void setup---------void setup---------|//
//|---------void loop---------void loop---------|//

void loop() {

    delay(50);
  //increment & decrement Volt_Alarm_Set_Point
    if (digitalRead(Button_1)==Is_Pressed
      ||digitalRead(Button_2)==Is_Pressed)
      {Adjust_The_Volt_Alarm_Set_Point();}

    Read_Volt_Meter();
    //Multiply_By_0_Point_1;
    Display_A_Float_Voltage_Reference();

    lcd.setCursor(0, 0);
    lcd.print(F("This is the Volt adj"));
    lcd.setCursor(0, 1);
    lcd.print(F("Volt Set Pnt = "));

    if (Volt_Alarm_Set_Point<=9){
    lcd.setCursor(16, 1);
    lcd.print(" ");}
    lcd.setCursor(15, 1);
    lcd.print(Volt_Set_Point);

    lcd.setCursor(0,2);
    lcd.print(F("VoltageX= "));
    lcd.setCursor(10, 2);
    lcd.print(vin);

    if (Volt_Alarm_Set_Point<=9){
    lcd.setCursor(17, 2);
    lcd.print(" ");}
    lcd.setCursor(16, 2);
    lcd.print(Volt_Alarm_Set_Point);

    if (vin < Volt_Set_Point){digitalWrite(Relay_3, Is_Turned_On);}
    if (vin > Volt_Set_Point){digitalWrite(Relay_3, Is_Turned_Off);}

    lcd.setCursor(0, 3);lcd.print("A = ");lcd.setCursor(4, 3);lcd.print(a);
    lcd.setCursor(6, 3);lcd.print("B = ");lcd.setCursor(11, 3);lcd.print(b);

    if (a==0) {digitalWrite(Relay_2, Is_Turned_Off);}
    if (a==1) {digitalWrite(Relay_2, Is_Turned_On);}

    if (b==0) {digitalWrite(Alarm_Relay_1, Is_Turned_Off);}
    if (b==1) {digitalWrite(Alarm_Relay_1, Is_Turned_On);}

    if (digitalRead(Button_4)==Is_Pressed){
      if (a==0){a=1;}else{a=0;}
      while (digitalRead(Button_4)==Is_Pressed){
      if (a==0) {digitalWrite(Relay_2, Is_Turned_Off);}
      if (a==1) {digitalWrite(Relay_2, Is_Turned_On);}
      lcd.setCursor(0, 3);lcd.print("A = ");lcd.setCursor(4,3);lcd.print(a);
      lcd.setCursor(6, 3);lcd.print("B = ");lcd.setCursor(11,3);lcd.print(b);
      }
      EEPROM.put(A_ADDR, a); EEPROM.put(B_ADDR, b);
    }

    if (digitalRead(Button_3)==Is_Pressed){
     if (b==0){b=1;}else{b=0;}
     while (digitalRead(Button_3)==Is_Pressed){
     if (b==0) {digitalWrite(Alarm_Relay_1, Is_Turned_Off);}
     if (b==1) {digitalWrite(Alarm_Relay_1, Is_Turned_On);}
     lcd.setCursor(0, 3);lcd.print("A = ");lcd.setCursor(4,3);lcd.print(a);
     lcd.setCursor(6, 3);lcd.print("B = ");lcd.setCursor(11,3);lcd.print(b);
     }
     EEPROM.put(A_ADDR, a); EEPROM.put(B_ADDR, b);
    }
  }// end of the void loop()

//|---------void loop---------void loop---------|//
//======= Subroutine Area ======= Subroutine Area =======//
///*
void Display_A_Float_Voltage_Reference()
{
if (Volt_Alarm_Set_Point==0){Volt_Set_Point=0.00;}// this code uses 165 if statements for 4956 bytes of program space and 4 bytes of dynamic memory.
if (Volt_Alarm_Set_Point==1){Volt_Set_Point=0.10;}
if (Volt_Alarm_Set_Point==2){Volt_Set_Point=0.20;}
if (Volt_Alarm_Set_Point==3){Volt_Set_Point=0.30;}
if (Volt_Alarm_Set_Point==4){Volt_Set_Point=0.40;}
if (Volt_Alarm_Set_Point==5){Volt_Set_Point=0.50;}
if (Volt_Alarm_Set_Point==6){Volt_Set_Point=0.60;}
if (Volt_Alarm_Set_Point==7){Volt_Set_Point=0.70;}
if (Volt_Alarm_Set_Point==8){Volt_Set_Point=0.80;}
if (Volt_Alarm_Set_Point==9){Volt_Set_Point=0.90;}
if (Volt_Alarm_Set_Point==10){Volt_Set_Point=1.00;}

if (Volt_Alarm_Set_Point==11){Volt_Set_Point=1.10;}
if (Volt_Alarm_Set_Point==12){Volt_Set_Point=1.20;}
if (Volt_Alarm_Set_Point==13){Volt_Set_Point=1.30;}
if (Volt_Alarm_Set_Point==14){Volt_Set_Point=1.40;}
if (Volt_Alarm_Set_Point==15){Volt_Set_Point=1.50;}
if (Volt_Alarm_Set_Point==16){Volt_Set_Point=1.60;}
if (Volt_Alarm_Set_Point==17){Volt_Set_Point=1.70;}
if (Volt_Alarm_Set_Point==18){Volt_Set_Point=1.80;}
if (Volt_Alarm_Set_Point==19){Volt_Set_Point=1.90;}
if (Volt_Alarm_Set_Point==20){Volt_Set_Point=2.00;}

if (Volt_Alarm_Set_Point==21){Volt_Set_Point=2.10;}
if (Volt_Alarm_Set_Point==22){Volt_Set_Point=2.20;}
if (Volt_Alarm_Set_Point==23){Volt_Set_Point=2.30;}
if (Volt_Alarm_Set_Point==24){Volt_Set_Point=2.40;}
if (Volt_Alarm_Set_Point==25){Volt_Set_Point=2.50;}
if (Volt_Alarm_Set_Point==26){Volt_Set_Point=2.60;}
if (Volt_Alarm_Set_Point==27){Volt_Set_Point=2.70;}
if (Volt_Alarm_Set_Point==28){Volt_Set_Point=2.80;}
if (Volt_Alarm_Set_Point==29){Volt_Set_Point=2.90;}
if (Volt_Alarm_Set_Point==30){Volt_Set_Point=3.00;}

if (Volt_Alarm_Set_Point==31){Volt_Set_Point=3.1;}
if (Volt_Alarm_Set_Point==32){Volt_Set_Point=3.2;}
if (Volt_Alarm_Set_Point==33){Volt_Set_Point=3.3;}
if (Volt_Alarm_Set_Point==34){Volt_Set_Point=3.4;}
if (Volt_Alarm_Set_Point==35){Volt_Set_Point=3.5;}
if (Volt_Alarm_Set_Point==36){Volt_Set_Point=3.6;}
if (Volt_Alarm_Set_Point==37){Volt_Set_Point=3.7;}
if (Volt_Alarm_Set_Point==38){Volt_Set_Point=3.8;}
if (Volt_Alarm_Set_Point==39){Volt_Set_Point=3.9;}
if (Volt_Alarm_Set_Point==40){Volt_Set_Point=4.0;}

if (Volt_Alarm_Set_Point==41){Volt_Set_Point=4.1;}
if (Volt_Alarm_Set_Point==42){Volt_Set_Point=4.2;}
if (Volt_Alarm_Set_Point==43){Volt_Set_Point=4.3;}
if (Volt_Alarm_Set_Point==44){Volt_Set_Point=4.4;}
if (Volt_Alarm_Set_Point==45){Volt_Set_Point=4.5;}
if (Volt_Alarm_Set_Point==46){Volt_Set_Point=4.6;}
if (Volt_Alarm_Set_Point==47){Volt_Set_Point=4.7;}
if (Volt_Alarm_Set_Point==48){Volt_Set_Point=4.8;}
if (Volt_Alarm_Set_Point==49){Volt_Set_Point=4.9;}
if (Volt_Alarm_Set_Point==50){Volt_Set_Point=5.0;}

if (Volt_Alarm_Set_Point==51){Volt_Set_Point=5.1;}
if (Volt_Alarm_Set_Point==52){Volt_Set_Point=5.2;}
if (Volt_Alarm_Set_Point==53){Volt_Set_Point=5.3;}
if (Volt_Alarm_Set_Point==54){Volt_Set_Point=5.4;}
if (Volt_Alarm_Set_Point==55){Volt_Set_Point=5.5;}
if (Volt_Alarm_Set_Point==56){Volt_Set_Point=5.6;}
if (Volt_Alarm_Set_Point==57){Volt_Set_Point=5.7;}
if (Volt_Alarm_Set_Point==58){Volt_Set_Point=5.8;}
if (Volt_Alarm_Set_Point==59){Volt_Set_Point=5.9;}
if (Volt_Alarm_Set_Point==60){Volt_Set_Point=6.0;}

if (Volt_Alarm_Set_Point==61){Volt_Set_Point=6.1;}
if (Volt_Alarm_Set_Point==62){Volt_Set_Point=6.2;}
if (Volt_Alarm_Set_Point==63){Volt_Set_Point=6.3;}
if (Volt_Alarm_Set_Point==64){Volt_Set_Point=6.4;}
if (Volt_Alarm_Set_Point==65){Volt_Set_Point=6.5;}
if (Volt_Alarm_Set_Point==66){Volt_Set_Point=6.6;}
if (Volt_Alarm_Set_Point==67){Volt_Set_Point=6.7;}
if (Volt_Alarm_Set_Point==68){Volt_Set_Point=6.8;}
if (Volt_Alarm_Set_Point==69){Volt_Set_Point=6.9;}
if (Volt_Alarm_Set_Point==70){Volt_Set_Point=7.0;}

if (Volt_Alarm_Set_Point==71){Volt_Set_Point=7.1;}
if (Volt_Alarm_Set_Point==72){Volt_Set_Point=7.2;}
if (Volt_Alarm_Set_Point==73){Volt_Set_Point=7.3;}
if (Volt_Alarm_Set_Point==74){Volt_Set_Point=7.4;}
if (Volt_Alarm_Set_Point==75){Volt_Set_Point=7.5;}
if (Volt_Alarm_Set_Point==76){Volt_Set_Point=7.6;}
if (Volt_Alarm_Set_Point==77){Volt_Set_Point=7.7;}
if (Volt_Alarm_Set_Point==78){Volt_Set_Point=7.8;}
if (Volt_Alarm_Set_Point==79){Volt_Set_Point=7.9;}
if (Volt_Alarm_Set_Point==80){Volt_Set_Point=8.0;}

if (Volt_Alarm_Set_Point==81){Volt_Set_Point=8.1;}
if (Volt_Alarm_Set_Point==82){Volt_Set_Point=8.2;}
if (Volt_Alarm_Set_Point==83){Volt_Set_Point=8.3;}
if (Volt_Alarm_Set_Point==84){Volt_Set_Point=8.4;}
if (Volt_Alarm_Set_Point==85){Volt_Set_Point=8.5;}
if (Volt_Alarm_Set_Point==86){Volt_Set_Point=8.6;}
if (Volt_Alarm_Set_Point==87){Volt_Set_Point=8.7;}
if (Volt_Alarm_Set_Point==88){Volt_Set_Point=8.8;}
if (Volt_Alarm_Set_Point==89){Volt_Set_Point=8.9;}
if (Volt_Alarm_Set_Point==90){Volt_Set_Point=9.0;}

if (Volt_Alarm_Set_Point==91){Volt_Set_Point=9.1;}
if (Volt_Alarm_Set_Point==92){Volt_Set_Point=9.2;}
if (Volt_Alarm_Set_Point==93){Volt_Set_Point=9.3;}
if (Volt_Alarm_Set_Point==94){Volt_Set_Point=9.4;}
if (Volt_Alarm_Set_Point==95){Volt_Set_Point=9.5;}
if (Volt_Alarm_Set_Point==96){Volt_Set_Point=9.6;}
if (Volt_Alarm_Set_Point==97){Volt_Set_Point=9.7;}
if (Volt_Alarm_Set_Point==98){Volt_Set_Point=9.8;}
if (Volt_Alarm_Set_Point==99){Volt_Set_Point=9.9;}
if (Volt_Alarm_Set_Point==100){Volt_Set_Point=10.0;}

if (Volt_Alarm_Set_Point==101){Volt_Set_Point=10.1;}
if (Volt_Alarm_Set_Point==102){Volt_Set_Point=10.2;}
if (Volt_Alarm_Set_Point==103){Volt_Set_Point=10.3;}
if (Volt_Alarm_Set_Point==104){Volt_Set_Point=10.4;}
if (Volt_Alarm_Set_Point==105){Volt_Set_Point=10.5;}
if (Volt_Alarm_Set_Point==106){Volt_Set_Point=10.6;}
if (Volt_Alarm_Set_Point==107){Volt_Set_Point=10.7;}
if (Volt_Alarm_Set_Point==108){Volt_Set_Point=10.8;}
if (Volt_Alarm_Set_Point==109){Volt_Set_Point=10.9;}
if (Volt_Alarm_Set_Point==110){Volt_Set_Point=11.0;}

if (Volt_Alarm_Set_Point==111){Volt_Set_Point=11.1;}
if (Volt_Alarm_Set_Point==112){Volt_Set_Point=11.2;}
if (Volt_Alarm_Set_Point==113){Volt_Set_Point=11.3;}
if (Volt_Alarm_Set_Point==114){Volt_Set_Point=11.4;}
if (Volt_Alarm_Set_Point==115){Volt_Set_Point=11.5;}
if (Volt_Alarm_Set_Point==116){Volt_Set_Point=11.6;}
if (Volt_Alarm_Set_Point==117){Volt_Set_Point=11.7;}
if (Volt_Alarm_Set_Point==118){Volt_Set_Point=11.8;}
if (Volt_Alarm_Set_Point==119){Volt_Set_Point=11.9;}
if (Volt_Alarm_Set_Point==120){Volt_Set_Point=12.0;}

if (Volt_Alarm_Set_Point==121){Volt_Set_Point=12.1;}
if (Volt_Alarm_Set_Point==122){Volt_Set_Point=12.2;}
if (Volt_Alarm_Set_Point==123){Volt_Set_Point=12.3;}
if (Volt_Alarm_Set_Point==124){Volt_Set_Point=12.4;}
if (Volt_Alarm_Set_Point==125){Volt_Set_Point=12.5;}
if (Volt_Alarm_Set_Point==126){Volt_Set_Point=12.6;}
if (Volt_Alarm_Set_Point==127){Volt_Set_Point=12.7;}
if (Volt_Alarm_Set_Point==128){Volt_Set_Point=12.8;}
if (Volt_Alarm_Set_Point==129){Volt_Set_Point=12.9;}
if (Volt_Alarm_Set_Point==130){Volt_Set_Point=13.0;}

if (Volt_Alarm_Set_Point==131){Volt_Set_Point=13.1;}
if (Volt_Alarm_Set_Point==132){Volt_Set_Point=13.2;}
if (Volt_Alarm_Set_Point==133){Volt_Set_Point=13.3;}
if (Volt_Alarm_Set_Point==134){Volt_Set_Point=13.4;}
if (Volt_Alarm_Set_Point==135){Volt_Set_Point=13.5;}
if (Volt_Alarm_Set_Point==136){Volt_Set_Point=13.6;}
if (Volt_Alarm_Set_Point==137){Volt_Set_Point=13.7;}
if (Volt_Alarm_Set_Point==138){Volt_Set_Point=13.8;}
if (Volt_Alarm_Set_Point==139){Volt_Set_Point=13.9;}
if (Volt_Alarm_Set_Point==140){Volt_Set_Point=14.0;}

if (Volt_Alarm_Set_Point==141){Volt_Set_Point=14.1;}
if (Volt_Alarm_Set_Point==142){Volt_Set_Point=14.2;}
if (Volt_Alarm_Set_Point==143){Volt_Set_Point=14.3;}
if (Volt_Alarm_Set_Point==144){Volt_Set_Point=14.4;}
if (Volt_Alarm_Set_Point==145){Volt_Set_Point=14.5;}
if (Volt_Alarm_Set_Point==146){Volt_Set_Point=14.6;}
if (Volt_Alarm_Set_Point==147){Volt_Set_Point=14.7;}
if (Volt_Alarm_Set_Point==148){Volt_Set_Point=14.8;}
if (Volt_Alarm_Set_Point==149){Volt_Set_Point=14.9;}
if (Volt_Alarm_Set_Point==150){Volt_Set_Point=15.0;}

} // end of void Display_A_Float_Voltage_Reference()
//*/

  void Adjust_The_Volt_Alarm_Set_Point()
 { s=0;
  // push button to increase this Alarm Set Point
  if (digitalRead(Button_2) == Is_Pressed)
     { s=1;
      if (Volt_Alarm_Set_Point <= 150)
      {
       Volt_Alarm_Set_Point = Volt_Alarm_Set_Point  + 1;// this line is using a int variable
       if (Volt_Alarm_Set_Point > 150)
          {Volt_Alarm_Set_Point = 150;}
      }
     }
 // push button to decrease this Alarm Set Point
  if (digitalRead(Button_1) == Is_Pressed)
    { s=1;
     Volt_Alarm_Set_Point = Volt_Alarm_Set_Point  - 1;// this line is using a int variable
     if (Volt_Alarm_Set_Point <= 0)
     {Volt_Alarm_Set_Point = 0;}
    }
    if (s==1){EEPROM.put( VOLT_ALARM_SET_POINT_ADDR,Volt_Alarm_Set_Point);}
 }

void Read_Volt_Meter()
{
   //-------------------------------Volt Meter Code-------------------------------//
   //-----------------------------------// This code reads the value at analog
   value = analogRead(analogInput);//---// input A6 and this is where we can change
   vout = (value * 4.72) / 1024.0;//----// the volts value to what the actual supply
   vin = vout / (R2/(R1+R2));//---------// voltage is equal to by checking it with an
   if (vin<0.09) {//--------------------// accurate Digital Votl Meter then entering
   vin=0.0;//---------------------------// it here-->(value * 4.79) changing the 4.79
   }//----------------------------------// to whatever your meter reads...
   //-------------------------------Volt Meter Code-------------------------------//
}
//======= Subroutine Area ======= Subroutine Area =======//
// end the Subroutine Area
// end of the program...

```

# Answer
> 7 votes
Since your floating point value always uses only 1 digit after the comma, why not multiply it by 10 and put it in an integer? For a value up to 15.0 (resulting in 150 int), you can use a simple byte and store it in EEPROM directly.

Then you can get rid of all `if` statements. To make a better formula, you can even add rounding *(so adding + 0.5 before converting to an int)*.

Thus:

```
EEPROM.put(VOLT_ALARM_SET_POINT_ADDR, (byte) (value * 10.0 + 0.5);

```

And to retrieve the value:

```
EEPROM.get(VOLT_ALARM_SET_POINT_ADDR, f);
f = (float) (f / 10.0);

```

# Answer
> 4 votes
@Michel Keijzers

I tried to use the code suggestion you sent but I couldn't get it set up properly to work with-in my code. I do thank you for your answer though. I did manage to figure out a way to save the value of my float variable to an integer and it works good. I'm including the working program below so if anyone ever googles the question I was asking they will find this and hopefully it'll be helpful to them because this works...

```
    {
        // this program uses 6986 bytes of program space
    // the old program with all the if statements used 11872 bytes
    // This program uses 4,886 less bytes of program space to accomplish the same thing

     #include <EEPROM.h>
     #include <LiquidCrystal_I2C.h>
     LiquidCrystal_I2C lcd(0x27, 20, 4);

    //----------Volt Meter Code----------//
        int analogInput = A6;
        float vout = 0.0;
        float vin = 0.0;
        float R1 = 99300.0;
        float R2 = 9970.0;
        int value = 0;
    //----------Volt Meter Code----------//

      int Volt_Alarm_Set_Point; // this works
      float Volt_Set_Point;
      int s = 0;
      int a = 0;
      int b = 0;

     int Button_1 = 5;
     int Button_2 = 6;
     int Button_3 = A1;
     int Button_4 = A0;
     int Alarm_Relay_1 = A3;
     int Relay_2 = A2;
     int Relay_3 = 8;
     int Blinking_Led = 3;// this one is ready to be used anytime

     #define VOLT_ALARM_SET_POINT_ADDR 0
     #define A_ADDR VOLT_ALARM_SET_POINT_ADDR + sizeof(int)
     #define B_ADDR A_ADDR + sizeof(int)

     #define Is_Pressed  0  // used for pushbuttons
     #define Is_Not_Pressed  1  // used for pushbuttons
     #define Is_Turned_On 1  // used for the relays
     #define Is_Turned_Off 0 // used for the relays

     //|---------void setup---------void setup---------|//
    void setup() {

        pinMode(Alarm_Relay_1, OUTPUT);
        pinMode(Relay_2, OUTPUT);
        pinMode(Relay_3, OUTPUT);
        pinMode(Blinking_Led, OUTPUT);
        pinMode(Button_1, INPUT); // on pin 5
        pinMode(Button_2, INPUT); // on pin 6
        pinMode(Button_3, INPUT); // on pin A1
        pinMode(Button_4, INPUT); // on pin A0
    //-----------Volt Meter Code--------------//
        pinMode(analogInput, INPUT);
    //-----------Volt Meter Code--------------//

        lcd.begin();

        lcd.setCursor(0, 0);
        lcd.print(F(" This Program Is an "));
        lcd.setCursor(0, 1);
        lcd.print(F("example on how to   "));
        lcd.setCursor(0, 2);
        lcd.print(F("save a float. Named "));
        lcd.setCursor(0, 3);
        lcd.print(F("Save_Float_Using_Int"));
        delay(3500);

        lcd.clear();

        EEPROM.get(VOLT_ALARM_SET_POINT_ADDR, Volt_Alarm_Set_Point);
        EEPROM.get(A_ADDR, a);
        EEPROM.get(B_ADDR, b);

    }// end of the void setup()

    //|---------void setup---------void setup---------|//
    //|---------void loop---------void loop---------|//

    void loop() {

        delay(50);
      //increment & decrement Volt_Alarm_Set_Point
        if (digitalRead(Button_1)==Is_Pressed
          ||digitalRead(Button_2)==Is_Pressed)
          {Adjust_The_Volt_Alarm_Set_Point();}

        Volt_Set_Point = Volt_Alarm_Set_Point*0.1;// this math displays the correct float value to the Lcd

        Read_Volt_Meter();

        lcd.setCursor(0, 0);
        lcd.print(F("This is the Volt adj"));

        if (Volt_Set_Point<10.00)// this if statement gets rid of leftover unwanted #'s
        {lcd.setCursor(19, 1);   // while decrementing the Volt_Set_Point variable
        lcd.print(" ");}
        lcd.setCursor(0, 1);
        lcd.print(F("Volt Set Pnt = "));
        lcd.setCursor(15, 1);
        lcd.print(Volt_Set_Point); // 2nd line of Lcd (displays float variable)

        lcd.setCursor(0,2);
        lcd.print(F("Voltage = "));
        lcd.setCursor(10, 2);
        lcd.print(vin);
        if (Volt_Alarm_Set_Point<10)//this if statement gets rid of leftover unwanted #'s
        {lcd.setCursor(17, 2);      // while decrementing the Volt_Alarm_Set_Point variable
        lcd.print(" ");}
        if (Volt_Alarm_Set_Point<100)// this if statement gets rid of leftover unwanted #'s
        {lcd.setCursor(18, 2);       // while decrementing the Volt_Alarm_Set_Point variable
        lcd.print("  ");}
        lcd.setCursor(16, 2);
        lcd.print(Volt_Alarm_Set_Point);  // 3rd line of Lcd (displays saved integer variable)

        if (vin <= Volt_Set_Point){digitalWrite(Relay_3, Is_Turned_On);}
        if (vin > Volt_Set_Point){digitalWrite(Relay_3, Is_Turned_Off);}

        lcd.setCursor(0, 3);lcd.print("A = ");lcd.setCursor(4, 3);lcd.print(a);
        lcd.setCursor(6, 3);lcd.print("B = ");lcd.setCursor(10, 3);lcd.print(b);

        if (a==0) {digitalWrite(Relay_2, Is_Turned_Off);}
        if (a==1) {digitalWrite(Relay_2, Is_Turned_On);}

        if (b==0) {digitalWrite(Alarm_Relay_1, Is_Turned_Off);}
        if (b==1) {digitalWrite(Alarm_Relay_1, Is_Turned_On);}

        if (digitalRead(Button_4)==Is_Pressed){
          if (a==0){a=1;}else{a=0;}
          while (digitalRead(Button_4)==Is_Pressed){
          if (a==0) {digitalWrite(Relay_2, Is_Turned_Off);}
          if (a==1) {digitalWrite(Relay_2, Is_Turned_On);}
          lcd.setCursor(0, 3);lcd.print("A = ");lcd.setCursor(4,3);lcd.print(a);
          }
          EEPROM.put(A_ADDR, a); EEPROM.put(B_ADDR, b);
        }

        if (digitalRead(Button_3)==Is_Pressed){
         if (b==0){b=1;}else{b=0;}
         while (digitalRead(Button_3)==Is_Pressed){
         if (b==0) {digitalWrite(Alarm_Relay_1, Is_Turned_Off);}
         if (b==1) {digitalWrite(Alarm_Relay_1, Is_Turned_On);}
         lcd.setCursor(6, 3);lcd.print("B = ");lcd.setCursor(10,3);lcd.print(b);
         }
         EEPROM.put(A_ADDR, a); EEPROM.put(B_ADDR, b);
        }
      }// end of the void loop()

    //|---------void loop---------void loop---------|//
    //======= Subroutine Area ======= Subroutine Area =======//

      void Adjust_The_Volt_Alarm_Set_Point()
     { s=0;
      // push button to increase this Alarm Set Point
      if (digitalRead(Button_2) == Is_Pressed)
         { s=1;
          if (Volt_Alarm_Set_Point <= 150)
          {
           Volt_Alarm_Set_Point = Volt_Alarm_Set_Point + 1;// this line is using a int variable
           if (Volt_Alarm_Set_Point > 150)
              {Volt_Alarm_Set_Point = 150;}
          }
         }
     // push button to decrease this Alarm Set Point
      if (digitalRead(Button_1) == Is_Pressed)
        { s=1;
         Volt_Alarm_Set_Point = Volt_Alarm_Set_Point - 1;// this line is using the int variable
         if (Volt_Alarm_Set_Point <= 0)
         {Volt_Alarm_Set_Point = 0;}
        }// the s variable here insures we save once & only when a button is pressed
        if (s==1){EEPROM.put( VOLT_ALARM_SET_POINT_ADDR,Volt_Alarm_Set_Point);}
     }

    void Read_Volt_Meter()
    {
       //-------------------------------Volt Meter Code-------------------------------//
       //-----------------------------------// This code reads the value at analog
       value = analogRead(analogInput);//---// input A6 and this is where we can change
       vout = (value * 4.72) / 1024.0;//----// the volts value to what the actual supply
       vin = vout / (R2/(R1+R2));//---------// voltage is equal to by checking it with an
       if (vin<0.09) {//--------------------// accurate Digital Votl Meter then entering
       vin=0.0;//---------------------------// it here-->(value * 4.79) changing the 4.79
       }//----------------------------------// to whatever your meter reads...
       //-------------------------------Volt Meter Code-------------------------------//
    }
    //======= Subroutine Area ======= Subroutine Area =======//
    // end the Subroutine Area
    // end of the program...
    }

```

# Answer
> -1 votes
Here, these are universal functions you should be able to use anywhere.

Call this function by using `SaveFloat(your float)`; eg SaveFloat (12.34); or call `float yourfloat = LoadFloat();`

```
void SaveFloat (float input) {

  String valstring = String(input);

  int digitcount = 0;

  for (int index = 0; index < valstring.length(); index++) {

    if (String(valstring.charAt(index)) != ".") {

      String temp = String(valstring.charAt(index));
      int digit = temp.toInt();

      EEPROM.update(index + 10, digit); // Change + 10 to whatever address you want to be the starting address. eg + 11 will be EEPROM.read(11);

    } else {

      EEPROM.update(index + 10, 254); // Change + 10 to whatever address you want to be the starting address. eg + 11 will be EEPROM.read(11);

    }

    digitcount++;

  }

  EEPROM.update(9, digitcount); //This address is important, so set it to an address you arent using.

}

float LoadFloat () {

  String output = "";

  for (int index = 0; index < EEPROM.read(//where you stored "digitcount"); index++) {

    if (EEPROM.read (index + 10) < 10) { // Change + 10 to whatever address you want to be the starting address. eg + 11 will be EEPROM.read(11);

      output += EEPROM.read (index + 10); // Change + 10 to whatever address you want to be the starting address. eg + 11 will be EEPROM.read(11);

    } else {

      output += ".";

    }

  }

  return output.toFloat();

}

```

---
Tags: eeprom
---


# Question
Title: Reading multiple DI pins in parallel as one byte/word
I need to capture a single parallel 'snapshot' from a 10-bit shaft encoder. I understand that I can read individual bits and shift them into position, but any given input pin might change while reading the bits sequentially, which would give an bogus value. In fact, given the asynchronous nature of the device this is guaranteed to happen on occasion.

I've read hints that it might be possible to combine pins into a 'port' for this purpose but I can't find any examples. Is this ability available only on certain processors? Or is there some way to latch the input pins while scanning them into a pair of bytes, to avoid them changing while I read?

If not I suppose I could use external latches but I'm hoping to avoid additional hardware.

It did occur to me that I could sync readings using an ISR triggered by a change in the LSB, but alas, this encoder outputs Gray code. :(

# Answer
If you would like to read multiple inputs, you can access port register directly. For 8 bit AVR:

```
DDRA = 0;            // set pins A0-A7 as input, modeInpit() in Arduino
uint8_t data = PINA; // read all A0-A7 inputs (8 bits)

```

To read more than 8 bits, you need 32 bit ARM based MCU/board like Arduino Due, other Atmel SAM, STM32Fxxx MCU etc. For STM32, there is Arduino like IDE available - http://www.stm32duino.com/

Even on 32 bit MCU you can read only 16 GPIO simultaneously (GPIO registers are 32 bit but handles 16 GPIO).
> 3 votes

# Answer
Without knowing the encoder in question (which you seem extremely reluctant to disclose for some reason that I have trouble understanding) it is hard to give a good answer. However ...

---

The 8-bit AVR processors can only read 8 bits atomically. This is indeed called a port. The Atmega328P (used in the Uno) organizes its I/O ports as ports B, C and D (I don't know where A went).

Exposed on the board are PORTB (bits 0 to 5), PORT C (bits 0 to 5) and PORT D (bits 0 to 7) - that's 20 pins in total.

Thus, port D is the closest you will get, as you could read 8 bits at once. However having said that, two of those bits are used for serial I/O so you couldn't use the serial hardware at the same time.

To read all of port D you could just do this:

```
byte foo = PIND;

```

(For inputting it is PINx, for outputting it is PORTx).

---

What could help is an I/O expander such as the MCP23017.

> I'm hoping to avoid additional hardware

Well, that's a pity.

---

I'm a tiny bit surprised that the device doesn't support some sort of "latching" of the data which gives you a finite time to extract the information from it. However without reading the datasheet I can't comment further.
> 2 votes

# Answer
I'm sure time has already passed for this persons project. But for those visiting this page for whatever reason (mine was different than the information here) here is a solution I would implement. Also this is assuming the individual is not willing to use a latched external buffer where they can read from it however they need to. Simply split the total pins among 2 registers making sure the following

1. The pins used are in sequential order to both the MCU and the encoder (gray coding will require some thought to this).
2. Group as many on a single register as possible and this will be the low order value.

Read from the low order value first (the one that will be changing at the highest rate). Then read from the high order value (where it will be far less likely to change between the low order and the high order read). You need to understand bit masks and bit shifting to do this...

uint16\_t nEncoder = (PINB & 0x1F); // Example if your 5 pins are the low ones on PORTB

uint16\_t nEncoder = ((PINB & 0x7C) \>\> 2); // Example if your 5 pins are 6:2 where you pull your set of pins off of PORTB then bitshift them down into their proper place.

then you read in the high order part

nEncoder |= ((PIND & 0x1F) \<\< 5); // Example if your 5 pins are the low ones on PORTD. However you pull them off of the next port, you will need to make sure you bitshift them into the upper 10 bits of nEncoder to get your final value.

In the above, you can see that the more bits (pins) you can use on your first register (port), the less likely your second read will have a pin change.

Gray coding will be different than binary. The above example assumes binary where the high order bit will change the least and the low order the most. Gray coding is specifically used because of how minimally the bits change in-between each number change (i.e. they are suppose to only have 1 bit change per number change no matter the number rather than 10 bits change when a binary count rolls over - i.e. it minimizes this exact problem). So for the original poster, most of this should be irrelevant (since they said they were using a gray code encoder).

But for those seeking an optimal solution (for binary counters or just because) where they cannot stick all pins on a single port. Splitting it between two registers with only two reads will optimize your read time and minimize the pin change possibility.
> 2 votes

# Answer
I mean, *you could* look up the port and the pin in the port and read in the portByte. This example does work:

```
//given two GPIOs on a port(PortC) eg: 12(right button) & 13(left button)
byte portByte = (*portInputRegister(digitalPinToPort(rightButtonGpio)));
rightButtonPinHigh = portByte & (digitalPinToBitMask(rightButtonGpio));
leftButtonPinHigh = portByte & (digitalPinToBitMask(leftButtonGpio));

```

However, in my experience, your output will look pretty much the same as if you had done two sequential Arduino blessed `digitalRead`. I suppose you might (in the example above) get the leftButtonHigh value 1 instruction ealier, but I don't know if the register can even update at that resolution.
> 0 votes

---
Tags: digital-in
---


# Question
Title: How to detect, if Serial is really connected to listening PC program? (on atmega32u4)
How to detect, if **Serial** is really connected to listening PC program? (on **atmega32u4**)

I need to connect from PC to **Arduino Micro Pro** over USB `Serial` and disconnect again and not slow down the Arduino with timeouting on all `Serial.print`.

## Difference from other

Not same as Arduino Leonardo(Atmega32u4) - Detecting if USB is connected to a computer?

* difference is what should happen after disconnecting PC program
    + "it is still connected to PC" (so it is **OK**, solved there)
    + "it is not listend to" and timeouting (so it is **BAD**, asked **here**)
* I tried the both solutions mentioned there (UDADDR & \_BV(ADDEN)) and (USBSTA & \_BV(VBUS)) as well as (Serial) - it behave the same from my point of view
    + fast before `screen` connects, fast when `screen` connected, **slow** after `screen` ends, fast when `screen` reconnected

## Details

I have **Arduino Micro Pro** managing a lot of things at its own, but I want sometimes connect to it via USB from my computer. I open `screen /dev/ttyACM0 115200` and get a lot of debugging info and so on. Then I close the `screen` and let it work in peace. But there is problem with timeouts - when I stop listening, it waits for me and everything is terribly slow, until I connect there again.

Here is my loop

```
    void loop() {
        DoSomethingImportant(); // it works
        StatusOff(); // Green LED off, Yellow On
        if (displayTime()) {  // print debug only on new second
            if (Serial) {   // ######## If there is somebody listening ... #########
                Serial.print(F("Ctrl: "));Serial.print(W00.Used());
                Serial.print(F("); R1/W1: "));Serial.print(R01.Used());Serial.print(F("/"));Serial.print(W01.Used());Serial.print(F(" ("));Serial.print(R01.Total_Count());Serial.print(F("/"));Serial.print(W01.Total_Count());
                Serial.print(F("); R2/W2: "));Serial.print(R02.Used());Serial.print(F("/"));Serial.print(W02.Used());Serial.print(F(" ("));Serial.print(R02.Total_Count());Serial.print(F("/"));Serial.print(W02.Total_Count());
                Serial.print(F("); R3/W3: "));Serial.print(R03.Used());Serial.print(F("/"));Serial.print(W03.Used());Serial.print(F(" ("));Serial.print(R03.Total_Count());Serial.print(F("/"));Serial.print(W03.Total_Count());
                Serial.println(F("); "));
            };
        };
        StatusOn(); // Green LED on, Yellow Off
    }

```

## Problem

When I connect the Arduino to PC (so it gets powered, I do not have much of the rest HW completed yet), it starts to do Something Important as fast as it can and every second the yellow LED blinks too fast to see that Green was off. It is OK.

Then I connect with `screen /dev/ttyACM0 115200` and it gets new long line every second. Still the Green looks all time on and Yellow can be seen just blink. Still OK.

Then I end `screen` and it went **slow** \- Yellow is on for like 7 second, while Green is on for 1 sec. And it is BAD.

Then I connect with `screen /dev/ttyACM0 115200` and it gets new long line every second. The Green looks all time on and Yellow can be seen just blink. Again OK.

## Question

How to detect, if I am connected or not?

Or maybe better, how to prevent the terrible slowdown, when I am not connected?

# Answer
I can reproduce this on Ubuntu, however it seems to be an anomaly of the screen program. If I use this small Python program to listen to the port, the Micro doesn't seem to slow down.

```
import serial

ser = serial.Serial('/dev/ttyACM0', 115200)  # Adjust the serial port accordingly

while True:
    if ser.readable():
        line = ser.readline().decode().strip()
        print (line)

```

You may need to import pyserial into Python, for example:

```
python -m pip install pyserial

```

My Arduino test code was:

```
const byte LED_PIN = 5;  // some pin for an LED

void setup() {
  Serial.begin (115200);
  pinMode (LED_PIN, OUTPUT);

}

void loop() {
  digitalWrite (LED_PIN, HIGH);
  delay (250);
  digitalWrite (LED_PIN, LOW);
  delay (250);

  Serial.println(F("Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
   "Ut molestie quam cursus, feugiat massa eget, lobortis ante.\n"
   "Nulla semper nisi a pretium finibus. Proin rutrum accumsan massa sit amet gravida.\n"
   "Etiam mollis, ipsum ac sagittis aliquam, sem urna euismod ipsum,\n"
   "eget accumsan orci sapien ornare felis. Nulla ex felis, facilisis in tincidunt at,\n"
   "dignissim vitae ligula. Aliquam facilisis tristique velit,\n"
   "a scelerisque turpis mollis quis. Nulla porta, mi vel ornare feugiat,\n"
   "mauris ligula commodo felis, in congue orci neque a est. "));

}

```

By looking at the rate of flashes of the LED I can see that it doesn't slow down when running the Python program, or if you Ctrl+C to exit the Python program.

However it does slow down if you attach to the USB using `screen` and then kill it.

---

I don't think the Arduino can per se know whether or not a program on the PC happens to be listening to the USB port or not. That is a function of what is happening in the operating system, not a function of the USB hardware.

---

Another approach which I haven't tested might be to get your Python program to periodically (eg. for each line) send a character, and get the Arduino to check for serial input. If no serial input (ie. not prompting character) then don't echo the debugging data.

---

Another approach (and possibly the simplest) is just to have a switch on the micro on a spare port, and close the switch if you want debugging information, and open it if you don't. Then you have total control over the debugging.
> 1 votes

# Answer
Thanks to Nick Gammon for his answer, the problem is really in the `screen` program.

There is detailed explanation from Majenko in if(Serial) not working correctly on micro or pro micro

The problem is, that some programs (like `screen`) or some systems, or drivers, or so do not pull down `RTS` and `DTR` signals for Micro. (The `DTR` down is supposed to restart Uno and other non-USB arduinos).

It could be solved by running some small program to `close` the USB Serial properly after the `screen` is done with it - here are two which works for me

C program

```
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>

int main(int argc, char *argv[]) {
        // Check if the correct number of command-line arguments is provided
        if (argc != 2 ) {
                fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
                fprintf(stderr, "  %s /dev/ttyACM0 - close USB Serial for Arduino on the port\n", argv[0]);
                return 1; // Return an error code
        }
        int fd;
        fd = open(argv[1],O_RDWR | O_NOCTTY );//Open Serial Port

        int RTS_flag;
        RTS_flag = TIOCM_RTS;

        int DTR_flag;
        DTR_flag = TIOCM_DTR;

//      ioctl(fd,TIOCMBIS,&RTS_flag);//Set RTS pin
//      ioctl(fd,TIOCMBIS,&DTR_flag);//Set DTR pin

        ioctl(fd,TIOCMBIC,&RTS_flag);//Clear RTS pin
        ioctl(fd,TIOCMBIC,&DTR_flag);//Clear DTR pin
        close(fd);
}

```

Python

```
#!/usr/bin/python -u

import serial
import sys

# Check if the correct number of command-line arguments is provided
if not len(sys.argv) in {2,3}:
        print("Usage: {} <filename> [baudrate]".format(sys.argv[0]))
        print(" {} /dev/ttyACM0 - close USB Serial for Arduino on the port".format(sys.argv[0]))
        sys.exit(1)  # Exit with a non-zero error code

# Get the filename from the command-line argument
baudrate=115200
filename = sys.argv[1]
if len(sys.argv) > 2:
        baudrate=sys.argv[2]

# Open the serial port
ser = serial.Serial(filename, baudrate, xonxoff=False , rtscts=True , dsrdtr=True )
ser.rts=False
ser.dtr=False

```
> 1 votes

---
Tags: usb, atmega32u4
---


title: using PN532 chip on arduino

text:
# Question
Title: using PN532 chip on arduino
I've recently purchased an NFC-PN532 module online, which I connected to my arduino board and tried to get working. After connecting the pins and using the PN532 adafruit lib I encountered and error where the board was not being picked up. I was using the 'readMifareClassic' example from the lib and uploaded the example to the board and it resulted in the image below where I would receive a '?' or the first print output which is 'hello' in the code.

I'm not that experienced with NFC atm and so im seeking some guidance on what may be the issue. If you need more information please leave a comment.

Thank you

# Answer
> 0 votes
A very common error when PN532 module is not recognized, is that you are not using the right bus (I2C, SPI, UART).

Make sure:

In Arduino sketch make sure to follow carefully the lines that need to be commented out.

On the PN532 make sure that DIP switches match your bus configuration

---
Tags: nfc
---


# Question
Title: Code not Executing Reliably on Push Button Activation
I have put together the following code to activate a motor using an Arduino Uno via push buttons.

* Two push buttons should be pressed simultaneously to activate the motor for a specified number of steps,
* then when both buttons are pressed again the motor will spin in reverse, returning the motor to its original position.

The code works, but not every time the button is pressed. I've gone through every line of the code and can't seem to find the issue. I know that the connections are correct since the code executes sometimes, but I don't know if there is an error in the code causing the unreliable response or if I have faulty/cheap push buttons with bad connections.

```
    #include <Bounce2.h> // Include the Bounce2 library

    // Define stepper motor connections:
    #define dirPin 3
    #define stepPin 2
    #define motorEnablePin 4 // Motor driver's enable pin
    #define buttonPin 8 // Push button connected to pin 8
    #define buttonPin2 9 // Push button connected to pin 8

    boolean motorRunning = false; // Flag to track motor rotation
    boolean oddRotation = true; // Flag to track odd/even rotations

    // Create a Bounce object for the button
    Bounce debouncer1 = Bounce();
    Bounce debouncer2 = Bounce();

    void setup() {
      // Declare pins as output or input:
      pinMode(stepPin, OUTPUT);
      pinMode(dirPin, OUTPUT);
      pinMode(motorEnablePin, OUTPUT); // Enable pin as output
      pinMode(buttonPin, INPUT_PULLUP); // Use internal pull-up resistor for the button
      pinMode(buttonPin2, INPUT_PULLUP); // Use internal pull-up resistor for the button
      digitalWrite(dirPin, LOW); // Set the spinning direction CW/CCW
      digitalWrite(motorEnablePin, HIGH); // Disable motor driver initially

      // Attach the debouncer to the button pin
      debouncer1.attach(buttonPin);
      debouncer2.attach(buttonPin2);
      debouncer1.interval(50); // Set debounce time
      debouncer2.interval(50);
    }

    void loop() {
      // Update the debouncer
      debouncer1.update();
      debouncer2.update();

      if (debouncer1.fell() && debouncer2.fell()) {
        // Button pressed and motor is not running, initiate motor rotation
        motorRunning = true;
        oddRotation = !oddRotation; // Toggle the rotation direction

        int stepsPerRevolution = 200; // Number of steps for one full revolution
        int desiredRevolutions = 10;  // Number of desired revolutions
        int totalSteps = stepsPerRevolution * desiredRevolutions;
        int stepCount = 0; // Counter for the steps taken

        // Set the motor rotation direction
        digitalWrite(dirPin, oddRotation ? LOW : HIGH);

        // Enable the motor driver
        digitalWrite(motorEnablePin, LOW);

        while (stepCount < totalSteps) {
          // Rotate the motor
          digitalWrite(stepPin, HIGH);
          delayMicroseconds(600);
          digitalWrite(stepPin, LOW);
          delayMicroseconds(600);

          stepCount++;

          // If the desired number of rotations is reached, stop the motor
          if (stepCount >= totalSteps) {
            // Disable the motor driver
            digitalWrite(stepPin, LOW);
            digitalWrite(motorEnablePin, HIGH);

            // Reset the flag to stop motor rotation
            motorRunning = false;
          }
        }

        // Disable the motor driver when idle
        digitalWrite(motorEnablePin, HIGH);
      }
    }

```

# Answer
> 1 votes
Bounce.fell() returns true only if the input fell since the last update(). So your code will only work if both buttons are pressed at exactly the same time.

I suggest that you record the time at which each button is pressed and execute your code if the press times are less than 100ms apart. That should give reliable operation.

You can test if this is the problem simply by removing the debouncer2.fell() call. The code should then work reliably when only button 1 is pressed.

---
Tags: motor, button
---


# Question
Title: 800l v1 Baud rate is not fixing at 115200, How fix it for 115200 for lifelong
I am trying t change the baud rate of sim800l v1. But not successfully happening, every power cycle again going to AT+IPR= 0. I am using the following AT commands for changing the baud rate.

1.AT 2.AT+IPR? 3.AT+IPR=115200 4.AT&W

after power rebooting of sim800L going it is going AT+IPR=0.

Thank you

# Answer
> 2 votes
From a quick scan of its AT command manual, I think you want to look at section 1.7.1, "Parameter Saving Mode". There are several modes, and while the description isn't quite clear, it looks like one command causes all subsequent parameter changes to be saved into NVRAM (so they will survive over a power-down), while another one causes the most recently changed parameter into NVRAM. I'm not sure which mode would best serve your needs, but the latter one would appear to answer your immediate need, retaining the baud rate.

# Answer
> 2 votes
Your mistake is using AT&W to save the parameter, for some reason you have to add the profile number which is only 0 and use AT&W0 on a sim800l a sim800c with newer firmware accepts AT&W. I've learnt this the hard way.

---
Tags: sim800
---


# Question
Title: What's the difference/relationship between Arduino and AVR?
I'd always thought Arduino was a microcontroller platform but the actual microcontroller is an AVR chip made by Atmel, or something like that made by someone else, based on a RISC ISA, and Arduino is usually used to refer to the whole circuit board powered by this AVR chip. Is my understanding correct?

What's the difference/relationship between Arduino and AVR?

# Answer
> 7 votes
Arduino is a prototyping board, and the term "Arduino" is also used to refer to the IDE and library on the PC side, and the whole ecosystem. AVR is the architecture (developed by Atmel) of the microcontroller chip used in all official 8-bit boards, and almost all clones. Arduino UNO and 2009, the most used boards, use the AtMega328P chip.

Many times, Arduino is used to quickly test some idea, sensor, and circuitry, then a stand-alone board is built around the AtMega chip, as it cost 1/10 of the Arduino board, soldered circuit on a stripboard or on a custom PCB are more reitable, and can be optimized on some aspect, like power usage, space occupied, high current/voltage, and so on.

Newest and advanced Arduino board use a different chip with a very different architecture; the Arduino Yun uses a SAM plus a classic AVR, the Due uses an ARM (same architecture used by many smartphones), the Galileo use an x86 (like a classic single-core cpu).

# Answer
> 5 votes
Arduino is a set of open-sourced hardware- and software specifications, originally conceived as a students' platform. I would add that the specifications, though openly available, are distributed under various public licenses.

There are "official" Arduino boards made by an Italian company of the same name, but as the board designs are open-sourced, there are lots of good (and a few "less good") variants from other sources.

AVR refers to the line of MCUs manufactured by Atmel and used in the original designs. Atmel was acquired in 2016 by Microchip Technology, who continue to manufacture the AVR devices.

Some of the more recent Arduino designs use more capable processors from other chip manufacturers, but many still use the Atmel/Microchip AVR processors. The smaller AVRs' relative simplicity (ATtiny & ATmega, f/ex) make them ideal for quickly designing/building boards and software for less demanding applications and for learning about programming and digital controls.

# Answer
> 2 votes
The Arduino is an AVR processor running special code that lets you use the Arduino environment.

AVR's can be used by themselves with some additional supporting components.

Arduino is a combination of both AVR(chip) and breadboard.

AVR is a single chip, and would require a breadboard.

# Answer
> 1 votes
Arduino is really a common set of code that makes using the dev boards they sell accessible to wide range of user base.

Arduino is basically an IDE that uses the C/C++ language and a set of classes that are adaptable to common set of hardware, predominantly Atmel and mostly AVR although as people have mentioned already the Arduino boards are becoming increasingly more powerful. But is amazing how much you can do with the ATmega328p.

You don't have to use the Arduino IDE to program your board and in fact, I tend to use Atmel Studio myself or Notepad++. You can get a plug-in for Atmel Studio 6.2 and above that allows you to create sketches and upload them to most Arduino boards.

# Answer
> 0 votes
The Arduino tools and ecosystem supports processors other than just Atmel AVR chips. For instance the Arduino Due uses an ARM Cortex-M3 processor.

# Answer
> -1 votes
Although the previous answers are technically correct, I think there is currently a shift in the meaning of "Arduino".

When the original Arduino boards were released they were head and shoulders better than the competition, especially when looking at the cost vs performance tradeoff.

But this is no longer the case. Boards based around the ESP8266 and ESP32 chips are cheaper and far more powerful than the Atmel chips. Also, the AVR IDE environment has been extended to support these chips. And to further confuse the issue this "Arduinio" forum has almost 2000 questions tagged ESP8266 and around 850 tagged ESP32.

So expect changes. They are already happening. Will "Arduino" come to mean any chip supported by the IDE? Will this forum move to a more generic name like IOT? I really don't know.

---
Tags: avr
---


title: Addressable LEDs using SM16704

text:
# Question
Title: Addressable LEDs using SM16704
I've been asked to interface with some LED strips that use SM16704 pixel chips.

A site search here doesn't show any mentions of this chip, so I wonder if anyone knows if they're compatible with the more common ones like WS281x and can be addressed using FastLED or other library?

Edit:

**Here's** the datasheet for the -PB version of the chip. I can't find one for a plain 16704 but I don't think the protocol is any different.

# Answer
The best data I can find says that this chip / protocol is compatible with the WS2813 and should require only a minor tweak, if any.
> -1 votes

---
Tags: arduino-nano, led-strip
---


title: Arduino pulls i2c bus down

text:
# Question
Title: Arduino pulls i2c bus down
I am building an airplane. As a controller I am using a Raspberry pi 4. There are 3 sensors (MPU6050, QMC5883L, BME280) and arduino pro mini connected to the raspberry via i2c. When sending requests to the arduino it pulls the bus to 0 and shuts down(?).

* First screenshot. On the first search for all devices on the bus, the arduino responds and shuts down, but does not pull the bus to 0. On the second search It responds and pulls the bus to 0.
* Second screenshot. Rebooting the arduino, the SDA line goes up. Repeated runs of the search leads to what is shown in the first screenshot.
* Third screenshot. The arduino generates a PWM signal that is interrupted after a request to i2c.

As a test request I use the i2cdetect command on the Raspberry. Raspberry is connected to the sensor bus through a level converter, because the level of signals from Raspberry is 3.3V, and sensors accept 5 volt logic.

There is no bus pull-up to the upper level, it is on the schematic of all sensors used (will it be enough?).

The arduino has a simple slave i2c device code, writing to registers the value arrived and output it to other elements (servo drives, motor controller, stepper motor drivers). The Arduino acts as a port expander because the Raspberry has only 2 buses and too few outputs for all the necessary devices

Why is the bus falling and how can I fix it?

arduino code

```
    #include <Wire.h>
    #include <Servo.h>
    #include <Stepper.h>

    uint16_t servoAngle1 = 90;
    uint16_t servoAngle2 = 90;
    uint16_t servoAngle3 = 90;
    uint16_t servoAngle4 = 90;

    bool zoomIn = false;
    bool zoomOut = false;

    bool focusIn = false;
    bool focusOut = false;

    Servo servo1;
    Servo servo2;
    Servo servo3;
    Servo servo4;

    Servo ESC;

    Stepper zoomMotor(100, 2, 4, 7, 8);
    Stepper focusMotor(100, 10, 11, 12, 13);

    void setup() {
      Wire.begin(0x23);
      Wire.onReceive(receiveEvent);

      servo1.attach(3);
      servo2.attach(5);
      servo3.attach(6);
      servo4.attach(9);
      ESC.attach(11, 1000, 2000);
    }

    void loop() {
      servo1.write(servoAngle1);
      servo2.write(servoAngle2);
      servo3.write(servoAngle3);
      servo4.write(servoAngle4);
      ESC.write(0);
      if (zoomIn) {
        zoomMotor.step(100);
        zoomIn = false;
      }
      if (zoomOut) {
        zoomMotor.step(-100);
        zoomOut = false;
      }

      if (focusIn) {
        focusMotor.step(100);
        focusIn = false;
      }
      if (focusOut) {
        focusMotor.step(-100);
        focusOut = false;
      }
    }

    void receiveEvent(int howMany) {
      if (howMany == 2) {
        uint8_t action = Wire.read();
        uint8_t value = Wire.read();

        if (action == 1) { servoAngle1 = value; }
        if (action == 2) { servoAngle2 = value; }
        if (action == 3) { servoAngle3 = value; }
        if (action == 4) { servoAngle4 = value; }

        if (action == 10) {
          if (value == 1) { zoomIn = true; }
          if (value == 2) { zoomOut = true; }
        }

        if (action == 11) {
          if (value == 1) { focusIn = true; }
          if (value == 2) { focusOut = true; }
        }
      } else {
        while (true) {
          Wire.read();
        }
      }
    }

```

**Screenshot 1**

**Screenshot 2**

**Screenshot 3**

**and wiring diagram**

# Answer
For I2C to work there needs to be pull-ups on SDA and SCL somewhere (not one for each device). Typically 4.7k resistors or thereabouts would be used.

Also you need a bi-directional voltage level translator. An example schematic is:

Image credit: Sparkfun: Bi-Directional Logic Level Converter Hookup Guide

This is because I2C devices actively pull SDA and SCL low, however they rely on the pull-up resistors to pull them high. Also this won't work unless the voltage level shifter is bi-directional.

For more information see the Philips Application Note AN97055 - Bi-directional level shifter for I²C-bus and other systems.

If you use the level shifter you need pull-up resistors on both the 3.3V part and the 5V part of the circuit (shown as Rp below).
> 3 votes

---
Tags: i2c, arduino-pro-mini, raspberrypi
---


# Question
Title: Error while uploading "A fatal esptool.py error occurred: Write timeout"
I have constantly been getting this error while trying to upload a sketch on Wemos D1 Mini R1 & R2 type board.

> A fatal esptool.py error occurred: Write timeout

I've recently updated my Arduino IDE, so I assumed that it might be due to a bad installation. But after reinstalling everything including the Board Manager lib for ESP, Arduino IDE itself nothing worked. When I click on the Board Info, it displays an error "Native serial port, can't obtain info".

I've also tried different type of ESP boards (e.g. NodeMCU) but for all boards the problem is same. When I plug an Arduino to the same USB Port, it auto-detect the board, but when I plug-in the ESP boards, it doesn't recognize the boards automatically. So my guess is it has something to do with the CH34X driver. However I have tried reinstalling few versions of the driver from authentic sources, but nothing made an impact.

Any help is appreciated.

Following is the full trace of log getting printed:

```
. Variables and constants in RAM (global, static), used 28104 / 80192 bytes (35%)
║   SEGMENT  BYTES    DESCRIPTION
╠══ DATA     1496     initialized variables
╠══ RODATA   920      constants
╚══ BSS      25688    zeroed variables
. Instruction RAM (IRAM_ATTR, ICACHE_RAM_ATTR), used 59667 / 65536 bytes (91%)
║   SEGMENT  BYTES    DESCRIPTION
╠══ ICACHE   32768    reserved space for flash instruction cache
╚══ IRAM     26899    code in IRAM
. Code in flash (default, ICACHE_FLASH_ATTR), used 232148 / 1048576 bytes (22%)
║   SEGMENT  BYTES    DESCRIPTION
╚══ IROM     232148   code in flash
esptool.py v3.0
Serial port COM8
Connecting...

A fatal esptool.py error occurred: Write timeout

```

Following is the IDE Settings while uploading:

# Answer
The "most common reason" mentioned in this answer was actually the problem I had. Unfortunately I was using a charge only cable even though the cable package clearly said it was a data-cable. At times, these cheap electronics products confuses us a lot and we often miss to critically scrutinize the most obvious problems. As described in this Adafruit tutorial this problem seems to be a very common one.
> 1 votes

# Answer
I've run into this a bunch recently, and typically, but not always, the cause is that I was using a GPIO pin that was reserved and couldn't be used during boot up. It's surprising how many of the pins cannot be used.

Check out this chart I found and saved, unfortunately I do not know the source, but I have found it to be very accurate, and I reference it a lot:
> 1 votes

# Answer
I had the same problem.

My solution:

Program for blinking led ESP8266MOD (cheap Chinese esp8266mod module)

I used Arduino IDE 2.1.0

info from https://vimalb.github.io/IoT-ESP8266-Starter/Lesson\_01/lesson.html

Connect resistor 220 Ohm and LED in serial. Connect resistor on D8 and the LED

on G (Ground). I used a breadboard and connect 5V pin on the esp board and

the pin G on the esp board to the Red en Bleu line on mij breadbord.

Write the program.

```
// Base ESP8266

#include <ESP8266WiFi.h>

WiFiClient WIFI_CLIENT;

#define LIGHT_SENSOR A0

#define LED 15    // this is pin D8 on the board

#define BUTTON 4

void setup() {

  // Initialize the serial port

  Serial.begin(115200);

  // Configure light sensor pin as an input

  pinMode(LIGHT_SENSOR, INPUT);

  // Configure LED pin as an output

  pinMode(LED, OUTPUT);

  // Configure BUTTON pin as an input with a pullup

  pinMode(BUTTON, INPUT_PULLUP);

}

void loop() {

  // Turn the LED on (HIGH is the voltage level)

  digitalWrite(LED, HIGH);

  // Wait for 1000 milliseconds

  delay(1000);

  // Turn the LED off by making the voltage LOW

  digitalWrite(LED, LOW);

  // Wait another 1000 milliseconds

  delay(1000);

  // Send a message over the serial port

  Serial.println("Finished loop");

}

```

Compile the program.

If Fault check the program.

Go to Tools -\> Port (I used com6)

Push the reset button on the espboard and keep it.

Connect the usb-cable on the espboard.

Release the reset button.

Besure everthing is connect.

Upload the program by using the upload button arduino IDE.

Start the serial monitor and check text "Finished loop" every 2 seconds.

Maybe this will help
> 1 votes

---
Tags: esp8266, arduino-ide, ch340, esp, arduino-ide-2
---


# Question
Title: ESP8266 not responding after random intervals of time
**4th Update:** I bought an ESP32 (the successor to ESP8266) and am getting the same problem. I used the same code except used the `Wifi.h` library instead, also removed the `ESP8266WiFiGratuitous.h` code. I added an LED flash at the start of the loop and can confirm the LED stops flashing, so I can confirm the `loop()` stops running. This makes me think it must be something to do with my WIFI network.

**3rd update:** I've removed all the code and instead uploaded a simple onboard LED blink sketch. The LED has been blinking for over 24 hrs which leads me to think there is something in the wifi code that is making the software crash.

**2nd update:** I've even tried resetting the board at the start of the `loop()` body, every 10 mins, using the millisDelay.h library, calling this method to reset:

```
void(* resetFunc) (void) = 0;

```

but that doesn't help either. The `loop()` method seems to completey stop running.

**Update:** I've added `experimental::ESP8266WiFiGratuitous::stationKeepAliveSetIntervalMs();` but am still failing to get a response after 1hr, with about 15 requests made in that hour.

I have this code which works on my ESP8266:

```
    #include <ESP8266WiFi.h>
    #include <ESP8266WiFiGratuitous.h>

    const size_t input_buffer_length = 256;

    const char* ssid = "iiNetC2DAD7";
    const char* wifiPassword = "aM9PrxcbtkS";
    const char* passwordToOpenDoor = "/87"; //password should begin with a slash

    const int doorPin = 5;
    const int buzzerPin = 4;
    const int toneDuration = 700;

    int numOfRequests = 0;

    WiFiServer server(301); //Pick any port number you like
    WiFiClient client;

    void setup() {
      Serial.begin(115200);
      delay(10);
      Serial.println(WiFi.localIP());

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

      pinMode(doorPin, OUTPUT);
      digitalWrite(doorPin, 0);

      pinMode(buzzerPin, OUTPUT);
      digitalWrite(buzzerPin, 0);

      Serial.println();
      Serial.print("Connecting to ");
      Serial.println(ssid);

      WiFi.begin(ssid, wifiPassword);

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

      experimental::ESP8266WiFiGratuitous::stationKeepAliveSetIntervalMs();

      server.begin();
      Serial.println("Server started.");
      Serial.println(WiFi.localIP());
    }

    void loop() {
      client = server.available();
      if (!client) {
        return;
      }

      while(!client.available()){
        delay(1);
      }

      char request[input_buffer_length];
      client.readBytesUntil('\r', request, input_buffer_length);
      Serial.println(request);

      if(strstr(request, passwordToOpenDoor)) {//Is password correct?
        GenerateResponse("Password is correct");
        OpenDoor();
        CorrectPasswordSound();
      }
      //Got a GET request and it wasn't the favicon.ico request, must have been a bad password:
      else if (!strstr(request, "favicon.ico")) {
        GenerateResponse("Password is incorrect.");
      }
    }

    void OpenDoor() {
      digitalWrite(LED_BUILTIN, 0); //flash the onboard LED to help during testing.
      digitalWrite(doorPin, 1);
      delay(500);
      digitalWrite(LED_BUILTIN, 1);
      digitalWrite(doorPin, 0);
    }

    void GenerateResponse(const char *text) {
      Serial.println(text);
      client.print(
          "HTTP/1.1 200 OK\r\n"
          "Content-Type: text/html\r\n"
          "\r\n"
          "<!DOCTYPE HTML>\r\n"
          "<html>\r\n"
          "<br><h1><b>"
      );
      client.print(text);
      client.print("</b></h1><br><h1><b>Num of requests: ");
      client.print(++numOfRequests);
      client.print("</b></h1></html>\r\n");
      client.flush();
    }

    void CorrectPasswordSound() {
      //Play 1700, 1800, 1900Hz
      for(int i = 17; i < 20; i++){
        int frequency = i * 100;
        tone(buzzerPin, frequency);
        delay(toneDuration);
        noTone(buzzerPin);
      }
    }

```
* However, after a random amount of time, the software crashes and the device won't respond to HTTP requests anymore.
* I've tested this by printing to the serial monitor every loop. It seems as though it crashes and the `loop()` function stops running since it stops printing to the monitor.
* I noticed that it'll still reply to pings.
* It won't reconnect after restarting the router, I need to press the reset button on the ESP8266 to get it to start working again.
* I've tested it by sending an HTTP Get request every 5 mins for many hours (using a C# console app). Sometimes it failed after 45 mins, sometimes 7 hours.
* I initially thought it was because I was using String objects, but after getting an answer to this question and testing it out with only C-strings, I still have the same problem.
* I've been sending HTTP Get requests using Chrome on my phone and laptop, as well as the .NET Framework class `System.Net.Http.HttpClient`.

Spec:

* Board: AI-Thinker ESP8266MOD
* IDE: Arduino 1.8.12
* ESP8266 Boards version = 2.6.3
* IDE Settings:

I've tried resetting the connection using:

```
server.stop();
delay(1000);
server.begin();

```

Then this:

```
ESP.reset();

```

Then after those 2 didn't work, this:

```
ESP.restart();

```

Resetting it frequently did nothing.

Is there anything in my code that stands out? If there's nothing wrong withe code, then maybe my only option is to hard reset the board every 30 mins some how.

# Answer
I don't know if this is your problem, but I'll leave it here because it is certainly a potential bug.

This code in loop:

```
  while(!client.available()){
    delay(1);
  }

```

can cause a deadlock if you have a client that drops or doesn't talk. Turn that around and let the loop keep running.

```
boolean haveClient = false;

void loop() {
  client = server.available();
  if (client) {
    haveClient = true;
  } else {
    haveClient = false;
  }

  if(haveClient && client.available()){

     // The rest of your loop where you read
     //  from the client goes inside here.

```

That way if you get a client and then available keeps returning false you can at least keep checking for a client.

This may not be and is not intended to be a code solution. This is probably not the best way to code what I'm trying to say. I don't know if server.available will keep giving you back the same client or if it is going to cut you off to call that again before the client disconnects. There may be some method in there to check the connection. Either way, that's not the point. The point is to never capture your code into a locked up while loop. That is always asking for a deadlock. It's bad practice except for cases like fatal errors where you truly want to lock the thing up. Let the loop keep looping. Use if statements to decide which parts get run when.

If you want to check that this is where you are locking up, put some sort of output before and after that while loop. Print something or turn a light on before and off after. That way you can tell if this is the spot you're locking up.
> 3 votes

# Answer
Thanks to Delta\_G for pointing me in the right direction. The trick was to not get stuck in the `loop()` function, ie. no while loops.

The problem was that after you run `client = server.available();`, the client needs some time before `client.available()` returns true, which is what the while loop is for, **however**, for some reason, the client would lose its connection every now and then and `client.available()` would never return true, in which case you get stuck in the while loop. You need to give it a second chance and let the process start again.

By delaying about 50ms, it seems to be enough time for the client to establish a connection, and if it doesn't, it loops and tries again so quickly that it appears as though the client always gets the connection and the code works fine.

Here's the working code:

```
void loop() {
  WiFiClient client = server.available();

  if(client){
    delay(50);
    if(client.available()) {
        //rest of code here
    }
}

```
> 2 votes

# Answer
I'm facing the similar problem especially when the WIFI signal is weak. The connection drop prematurely, end up the software execution is stuck within the while(!client.available()) loop.

A fail-safe timer can be implemented to get out from this loop as follow:

```
  unsigned int u32FailSafeTimer = 3000;   /*Set 3s timeout*/
  while(!client.available())
  {
    u32FailSafeTimer--;
    delay(1);   /*pause for 1ms*/
    if (0 == u32FailSafeTimer)   /*Fail-safe timer elapsed, get out from unexpected error*/
    {
      Serial.printf("timeout (RSSI: %d dBm)\n\n", WiFi.RSSI());
      client.flush();   /*Kill and prepare for next session*/
      return;
    }
  }

```
> 1 votes

# Answer
This will be the "server unreachable after a while" problem, which is solved solved by sending gratuitous ARP requests. In the esp8266 Arduino core 2.7 they added functions for this. The main function is `experimental::ESP8266WiFiGratuitous::stationKeepAliveSetIntervalMs();`. Include `<#include "ESP8266WiFiGratuitous.h>`

Notes:

* You don't know if your loop stops. It doesn't print anything if no client can reach it.
* remove the flush() after readBytesUntil(). it doesn't do what you think it does.
> 0 votes

# Answer
I will take a SWAG and say it sounds like the watchdog may be getting you. I was getting similar problems but nothing to do with WiFi or anything like that. I determined that when it got stuck in a loop it would sit for a while and then crash. I was able to determine (guess) something was timing out and since the external hardware did not reset and yet it would run setup() again the processor was resetting itself. It would hang with some things appearing to work. After I dug down into it I found that I had to release my code to allow the watchdog to be reset by the internal ESP software. I based this on some information I found about the maximum time allowed for the delay() function. Hopefully this helps.
> 0 votes

---
Tags: esp8266, arduino-ide, http
---


# Question
Title: Uploading a Library to the library manager from a Github branch
I am trying to upload a library to the Arduino Library Manager. I know the GitHub - arduino/library-registry: Arduino Library Manager list repository, and I have already read the instructions, but I have a question that I hope someone can explain to me.

The project I am working on is multiplatform, and to fulfill all the requirements for multiple platforms, many files are not required for the Arduino compilation process. I work around this because, with the help of GitHub actions, I have automated a workflow that publishes a branch within the project with an adequate file structure that complies with the Arduino library specification.

On the library-registry repo, step 7 says: " This should be the URL of the repository home page. For example: https://github.com/arduino-libraries/Servo" I am wondering if, in this section, I can put the link to the Arduino branch on the project.

This would mean to include : https://github.com/myProfileName/myProjectName/tree/Arduino

Instead of : https://github.com/myProfileName/myProjectName

With the reasoning that the second URL would contain many files that are not needed in an Arduino environment

# Answer
> 4 votes
No. As stated in the instructions for submitting a library to the Arduino Library Manager registry, the URL must be to the home page of the repository.

The way the Library Manager index generation system works:

1. Clone the repository from the URL that was registered URL.
2. Check out each Git tag in the repository.
3. Check to see whether the repository contains an Arduino library at that tag.
4. Check to see whether the library release at that tag is already in the index.
5. If it is a valid new library release, add the release to the index.

So there is no problem with having the Arduino library in a different branches in the repository because the indexer doesn't work from branches. It works from tags, which are independent from branches. You must only make sure to make a Git tag at the commit ref in the Arduino library branch of your repository at the point in the revision history where you make a release of the library.

In case you also want to tag other branches, that is fine. Even though tags are the unit of release for Library Manager, the versioning of the library releases is done exclusively using the value of the `version` field of the `library.properties` metadata file. So you can add something to the tag names to differentiate the Arduino library release tags from tags made in other branches (e.g., `Arduino-1.2.3`, `1.2.3`).

The one consideration with the release strategy I mentioned above is that the submission validation system that checks for problems with the library when you submit it for inclusion in Library Manager checks out the most recent tag in the repository and does that initial validation on the contents of the repository at that specific tag. So you do need to make sure that the Arduino Library release tag is the most recent tag at the time you submit the library.

Once the submission is accepted, all tags in the repository will always be processed (ignoring those that don't pass Arduino Library validation), so it won't matter if tags from branches that don't contain an Arduino library are the most recent tags in the repository after the library has been registered.

---
Tags: library
---


# Question
Title: Returning to parent directory with the SD library
I have a `File` variable called `dir` and i'm building a simple file explorer for my device. Is there a way to get a reference to `dir`'s parent directory?

# Answer
I don't think there is an inbuilt function returning the parent, but you could do:

```
FS &file_system = SD; // pick whichever file system you use

File get_parent(File dir) {
  String dirPath = dir.path();
  int lastSlashIndex = dirPath.lastIndexOf('/');
  if (lastSlashIndex != -1) {
    String parentDirPath = dirPath.substring(0, lastSlashIndex);
    File parentDir = file_system.open(parentDirPath.c_str());
    return parentDir;
  }
  return File();
}

```
> -1 votes

---
Tags: sd-card, sd, sd.h
---


# Question
Title: Send Keyboard Media Keys with Keyboard Library
I have an Arduino Pro Micro (ATMega32u4) that I want to use as an IR receiver for a media PC and need to send codes like Volume Up, Media Home, Play, etc. But when I look up the scan codes for those and send them to Keyboard.press() it just prints out '0' every time.

Any way to send those keyboard commands?

# Answer
You have to do some tweaks to the usbkeyboard libraries that comes with the IDE.

For a video tutorial, take a look at this:

Arduino Leonardo as a multimedia keyboard

Which uses the information from this site, if you prefer text only:

Arduino Leonardo multimedia keys

The Leonardo and ProMicro both use the ATMega32u4 and should both work with theses tweaks. If you need more functionality than the ones that this tweak gives you, you have to dig down into usb descriptors on usb.org for the commands you need.
> 3 votes

# Answer
It is indeed possible and also without the requirement to modify the Arduino environment itself. Just ***register an HID descriptor*** for the "report ID" for "Consumer Control" (the code is 4 (constant `kHID_ReportID_ConsumerControl`), where the "report ID" code for keyboard and mouse are 2 and 1, respectively):

```
static HIDSubDescriptor node(HID_ReportDescriptor_ConsumerControl,
                             sizeof(HID_ReportDescriptor_ConsumerControl));

HID().AppendDescriptor(&node);

```

After the registration, `HID().SendReport()` now works for "report ID" equal to 4 (the first parameter), and the audio volume can be changed, etc.

The registration needs to done once and can be put into the init() function, for instance, after the `Keyboard.begin();` and `Mouse.begin();` calls.

### Usage

Example usage, increasing the audio volume by one step:

```
uint8_t data[2];
data[0] = kVolumeUp;
data[1] = 0;
HID().SendReport(kHID_ReportID_ConsumerControl, data, 2);

```

The constants are at the end.

### Notes

"Consumer Control" has the multimedia controls *Volume up*, *Volume down*, *Mute*, *Play*, etc.

The registration is similar to the way the constructors for the built-in keyboard and mouse libraries do it. `HID_ReportDescriptor_ConsumerControl` and constants are listed at the end because it is quite long, but they must come first (for instance, in the beginning of the file).

All this could be packaged into a reusable form. Here I have demonstrated it in a paste-and-forget form to keep it short.

`HID().SendReport()` looks strange, but `HID()` is a global function that returns an instance of the class `HID_` (all built into the standard Arduino libraries, presumably to avoid some initialisation order problems with global/static objects - I thought Scott Meyers had solved that a long time ago (47. in the first book)).

`HID().SendReport()` can also be used to circumvent the limitation of a presumption of a US keyboard. E.g. using code 100, page 56 (and kHID\_ReportID\_Keyboard, like in the standard class `keyboard_`) to emulate the 102th key on European keyboards (e.g. a Spanish keyboard).

Only volume up and volume down were tested.

### Definition of `HID_ReportDescriptor_ConsumerControl` and constants:

```

// For direct use of USB HID (yes, 3 is left out)
const uint8_t kHID_ReportID_Mouse           =  1;
const uint8_t kHID_ReportID_Keyboard        =  2;
const uint8_t kHID_ReportID_ConsumerControl =  4;
const uint8_t kHID_ReportID_SystemControl   =  5;
const uint8_t kHID_ReportID_Gamepad         =  6;
const uint8_t kHID_ReportID_MouseAbsolute   =  7;
const uint8_t kHID_ReportID_NKRO_keyboard   =  8;
const uint8_t kHID_ReportID_TeensyKeyboard  =  9;
const uint8_t kHID_ReportID_SurfaceDial     = 10;

// For use in "Consumer Control". They are bit coded.
const uint8_t kVolumeUp   = 1 << 0; // Bit 0
const uint8_t kVolumeDown = 1 << 1; // Bit 1
const uint8_t kVolumeMute = 1 << 2; // Bit 2

static const uint8_t HID_ReportDescriptor_ConsumerControl[] PROGMEM =
{
    0x05, 0x0c,                           // Usage Page ("Consumer Devices")
    0x09, 0x01,                           // Usage (Consumer Control)
    0xa1, 0x01,                           // Collection (Application)
    0x85, kHID_ReportID_ConsumerControl,  // "Report ID"
    0x15, 0x00,                           // Logical Minimum (0)
    0x25, 0x01,                           // Logical Maximum (1)
    0x09, 0xe9,                           // Usage (Volume Up)
    0x09, 0xea,                           // Usage (Volume Down)
    0x75, 0x01,                           // Report Size (1)
    0x95, 0x02,                           // Report Count (2)
    0x81, 0x06,                           // Input (Data, Variable, Relative)

    0x09, 0xe2,                           // Usage (Mute)
    0x95, 0x01,                           // Report Count (1)
    0x81, 0x06,                           // Input (Data, Variable, Relative)

    0x09, 0xb0,                           // Usage (Play)
    0x95, 0x01,                           // Report Count (1)
    0x81, 0x06,                           // Input (Data, Variable, Relative)

    0x09, 0xb1,                           // Usage (Pause)
    0x95, 0x01,                           // Report Count (1)
    0x81, 0x06,                           // Input (Data, Variable, Relative)

    0x09, 0xb7,                           // Usage (Stop)
    0x95, 0x01,                           // Report Count (1)
    0x81, 0x06,                           // Input (Data, Variable, Relative)

    0x09, 0xb5,                           // Usage (Next)
    0x95, 0x01,                           // Report Count (1)
    0x81, 0x06,                           // Input (Data, Variable, Relative)

    0x09, 0xb6,                           // Usage (Previous)
    0x95, 0x01,                           // Report Count (1)
    0x81, 0x06,                           // Input (Data, Variable, Relative)

    0x09, 0xb3,                           // Usage (Fast Forward)
    0x95, 0x01,                           // Report Count (1)
    0x81, 0x06,                           // Input (Data, Variable, Relative)

    0x09, 0xb4,                           // Usage (Rewind)
    0x95, 0x01,                           // Report Count (1)
    0x81, 0x06,                           // Input (Data, Variable, Relative)

    0x95, 0x06,                           // Report Count (6) Number of bits remaining in byte
    0x81, 0x07,                           // Input (Constant, Variable, Relative)
    0xc0                                  // End Collection
}; // Table for USB HID "Consumer Control" (for audio volume control, etc.)

```

### Platform

This was tested with:

* Arduino Leonardo (already used as a macro keyboard, using an old PS/2 keyboard. Two new macro keys were assigned for testing audio volume up / down).
* The Arduino Leonardo connected to an *extra current* port of a D-Link USB hub (necessary, for unknown reasons - probably a local problem)
* Arduino IDE v. 1.18.10
* Linux, Ubuntu 19.10 (Eoan Ermine), but with the buggy GNOME replaced by Cinnamon.
> 3 votes

# Answer
If you are getting zeros, the most probably cause is it's the library for the IR. Reinstall or update the library. Sometimes you have to reinstall more than one time. That should work.

About media keys, the keyboard library doesn't have media keys functionality, so you need to use another one. This one worked for me: https://github.com/NicoHood/HID

After you install this library, you have to change your code. The code for pressing media keys is different. You have to use *Consumer.write*, for example, *Consumer.write(MEDIA\_VOLUME\_UP)* for volume up. You can find the name of every key here: https://github.com/NicoHood/HID/wiki/Consumer-API

For normal keys, just use Keyboard.write(). If you want, I can send you the code I made to do this.
> 2 votes

# Answer
Keyboard.press() presses a key and “holds it down” until a Keyboard.release() or releaseAll() is issued. That is, Keyboard.press() isn't appropriate for simulation of just tapping and releasing a key, unless you follow it with a delay and a release.

Also see Keyboard.write(). But note the following, from Keyboard.write()'s documentation:

> Only ASCII characters that are on the keyboard are supported. For example, ASCII 8 (backspace) would work, but ASCII 25 (Substitution) would not.

On my linux system, `xev` (used via `xev -event keyboard`) shows the following data for media keys labeled as shown.

```
  Excerpt from info displayed by xev           Picture
keycode 180 (keysym 0x1008ff18, XF86HomePage)   house
keycode 179 (keysym 0x1008ff81, XF86Tools)   quarter-notes
keycode 163 (keysym 0x1008ff19, XF86Mail)      envelope
keycode 172 (keysym 0x1008ff14, XF86AudioPlay)  >/||
keycode 122 (keysym 0x1008ff11, XF86AudioLowerVolume)  speaker
keycode 123 (keysym 0x1008ff13, XF86AudioRaiseVolume)  speaker
keycode 121 (keysym 0x1008ff12, XF86AudioMute)  x'd-speaker
keycode 148 (keysym 0x1008ff1d, XF86Calculator)  Calculator

```
> 1 votes

# Answer
Peter's answer probably is the way to go from scratch. But if you want to start from somewhere there's also another library by BleKeyboard https://github.com/T-vK/ESP32-BLE-Keyboard/blob/master/BleKeyboard.cpp. It shows you pretty much the whole process how the media report is created.

```
// ------------------------------------------------- Media Keys
  USAGE_PAGE(1),      0x0C,          // USAGE_PAGE (Consumer)
  USAGE(1),           0x01,          // USAGE (Consumer Control)
  COLLECTION(1),      0x01,          // COLLECTION (Application)
  REPORT_ID(1),       MEDIA_KEYS_ID, //   REPORT_ID (3)
  USAGE_PAGE(1),      0x0C,          //   USAGE_PAGE (Consumer)
  LOGICAL_MINIMUM(1), 0x00,          //   LOGICAL_MINIMUM (0)
  LOGICAL_MAXIMUM(1), 0x01,          //   LOGICAL_MAXIMUM (1)
  REPORT_SIZE(1),     0x01,          //   REPORT_SIZE (1)
  REPORT_COUNT(1),    0x10,          //   REPORT_COUNT (16)
  USAGE(1),           0xB5,          //   USAGE (Scan Next Track)     ; bit 0: 1
  USAGE(1),           0xB6,          //   USAGE (Scan Previous Track) ; bit 1: 2
  USAGE(1),           0xB7,          //   USAGE (Stop)                ; bit 2: 4
  USAGE(1),           0xCD,          //   USAGE (Play/Pause)          ; bit 3: 8
  USAGE(1),           0xE2,          //   USAGE (Mute)                ; bit 4: 16
  USAGE(1),           0xE9,          //   USAGE (Volume Increment)    ; bit 5: 32
  USAGE(1),           0xEA,          //   USAGE (Volume Decrement)    ; bit 6: 64
  USAGE(2),           0x23, 0x02,    //   Usage (WWW Home)            ; bit 7: 128
  USAGE(2),           0x94, 0x01,    //   Usage (My Computer) ; bit 0: 1
  USAGE(2),           0x92, 0x01,    //   Usage (Calculator)  ; bit 1: 2
  USAGE(2),           0x2A, 0x02,    //   Usage (WWW fav)     ; bit 2: 4
  USAGE(2),           0x21, 0x02,    //   Usage (WWW search)  ; bit 3: 8
  USAGE(2),           0x26, 0x02,    //   Usage (WWW stop)    ; bit 4: 16
  USAGE(2),           0x24, 0x02,    //   Usage (WWW back)    ; bit 5: 32
  USAGE(2),           0x83, 0x01,    //   Usage (Media sel)   ; bit 6: 64
  USAGE(2),           0x8A, 0x01,    //   Usage (Mail)        ; bit 7: 128
  HIDINPUT(1),        0x02,          //   INPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
  END_COLLECTION(0)                  // END_COLLECTION

```

If you are curious why these media button works, you can checkout the USB doc https://www.usb.org/sites/default/files/documents/hut1\_12v2.pdf, Page 75, where it states why each key usage is used.
> 0 votes

---
Tags: arduino-leonardo, arduino-pro-micro, keyboard
---


# Question
Title: AccelStepper.h - How can I quickly increase the speed of a NEMA 17 motor?
I'm pretty new to Arduino. I am trying to build a self-balancing robot. I am using A4988 drivers, an ESP32 microcontroller, NEMA 17 motors, and a 6050 MPU.

The problem is that, although the speed variable changes according to the position of the MPU, the motors rotate at a slow and constant speed, without varying according to the inclination of the robot.

Here is the code:

```
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <AccelStepper.h>

#define STEP_IZQ 26
#define DIR_IZQ 27
#define STEP_DER 12
#define DIR_DER 13

AccelStepper stepperizq(AccelStepper::FULL2WIRE,STEP_IZQ,DIR_IZQ);
AccelStepper stepperder(AccelStepper::FULL2WIRE,STEP_DER,DIR_DER);
Adafruit_MPU6050 mpu;

float kp = 20;
float ki = 0.5;
float kd = 30;

float angulo_grad, error, cumError, rateError, output, lastError;
float pid_error_temp, pid_i_mem, pid_setpoint, gyro_input, pid_output, pid_last_d_error;
int speed, outputAbs;

void setup(void) {
  Serial.begin(115200);
  while (!Serial)
    delay(10); // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("Adafruit MPU6050 test!");

  // Try to initialize!
  if (!mpu.begin()) {
    Serial.println("Failed to find MPU6050 chip");
    while (1) {
      delay(10);
    }
  }
  Serial.println("MPU6050 Found!");
  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_5_HZ);

  pinMode(DIR_IZQ, OUTPUT);
  pinMode(DIR_DER, OUTPUT);

  stepperizq.setMaxSpeed(3000);
  stepperder.setMaxSpeed(3000);
  stepperizq.setAcceleration(1000); // 1000
  stepperder.setAcceleration(1000); // 1000
}

void loop() {
  // Get new sensor events with the readings
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  angulo_grad = atan((a.acceleration.x)/(a.acceleration.z))*(180/3.14);            // 0 to 90 degrees
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // pid
  /////////////////////////////////////////////////////////////////////////////////////////////////

  pid_error_temp = angulo_grad;
  if ((pid_error_temp > -2.0) && (pid_error_temp < 2.0)) pid_error_temp = 0.0;

  pid_i_mem += ki * pid_error_temp;                                 // Calculate the I-controller value and add it to the pid_i_mem variable
  if (pid_i_mem > 800) pid_i_mem = 800;                                       // Limit the I-controller to the maximum controller output
  else if (pid_i_mem < -800) pid_i_mem = -800;
  // Calculate the PID output value
  pid_output = kp * pid_error_temp + pid_i_mem + kd * (pid_error_temp - pid_last_d_error);
  if (pid_output > 5000) pid_output = 5000;                                     // Limit the PI-controller to the maximum controller output
  else if (pid_output < -5000)pid_output = -5000;

  if (output < 50 && output > 50) output = 0;
  pid_last_d_error = pid_error_temp;
  ////////////////////////////////////////////////////////////////////////////////////////////////////
  //motors nema 17
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////
  outputAbs = (int)abs(pid_output);
  speed = map(outputAbs, 0, 5000, 0, 3000);

  stepperizq.setSpeed(speed);
  stepperder.setSpeed(speed);

  if (pid_output<0) {
    digitalWrite(DIR_IZQ, LOW);
    digitalWrite(DIR_DER, HIGH);
  }
  else if (pid_output>0) {
    digitalWrite(DIR_IZQ, HIGH);
    digitalWrite(DIR_DER, LOW);
  }
  stepperizq.runSpeed();
  stepperder.runSpeed();
}

```

# Answer
To write down my guess from the comments in a proper answer:

When a stepper motor driven with AccelStepper shows a constant speed, though the speed is set to different values, it suggests, that the time interval of the steps is defined by something else.

The `runSpeed()` function works by saving a timestamp of the last step and then checking the elapsed time on the basis of the set speed, to check if the time for another step has come and if yes, then execute exactly one step. For this to work correctly, you need to call this function within intervals smaller than the smallest period between two consecutive steps for your speed.

If for whatever reason you call the function with larger intervals, the `runSpeed()` function will always see, that the time for a new step has come, but it will always only do one step per execution. Thus you overall get one step per `runSpeed()` execution, and this is determined by the rest of your code, not the set speed.

The rest of the code in `loop()` is for getting the measurements of the MPU and calculating the resulting speeds from that. Probably this is taking too long and thus hindering the AccelStepper library from running the motor at the specified speeds. So you need to provide a larger timeslot for the stepper driving on your ESP by cutting down on your MPU sampling rate. This is easiest done by using

```
// Running MPU sampling and calculation only every 100ms
if(millis() - previousMillis >= 100){
  previousMillis += 100;
  // MPU and calculation code here
}
// Running the stepper code on every loop iteration
stepperizq.runSpeed();
stepperder.runSpeed();

```

which is the non-blocking coding style used in the `BlinkWithoutDelay` example. If you don't know how to use `millis()`, there are many tutorials online for that.
> 0 votes

---
Tags: esp32, stepper-motor, pid, a4988
---


title: Sparkfun Pro Micro (5v) as ISP error

text:
# Question
Title: Sparkfun Pro Micro (5v) as ISP error
I'm trying to use Sparkfun Pro Micro (5v 16MHz) as ISP to program Attiny chips (OS:Windows10Pro). I followed instructions. Installed proper driver and added Sparkfun boards to ArduinoIDE:

Using Arduino IDE uploaded ArduinoISP sketch on it. As you can see there are two options available to choose for programmer:

1. Arduino as ISP
2. Arduino Leonardo/Pro Micro as ISP

Which unfortunately both of them give the same error:

```
Sketch uses 28 bytes (2%) of program storage space. Maximum is 1024 bytes.
Global variables use 0 bytes (0%) of dynamic memory, leaving 64 bytes for local variables. Maximum is 64 bytes.
C:\Users\K1\AppData\Local\Arduino15\packages\MicroCore\tools\avrdude\7.1-arduino.1/bin/avrdude -CC:\Users\K1\AppData\Local\Arduino15\packages\MicroCore\hardware\avr\2.3.0/avrdude.conf -v -pattiny13a -cstk500v1 -PCOM16 -b19200 -Uhfuse:w:0xff:m -Ulfuse:w:0b00111010:m -Uflash:w:C:\Users\K1\AppData\Local\Temp\arduino_build_207900/sketch_aug28a.ino.hex:i

avrdude: Version 7.2
Copyright the AVRDUDE authors;
see https://github.com/avrdudes/avrdude/blob/main/AUTHORS

System wide configuration file is C:\Users\K1\AppData\Local\Arduino15\packages\MicroCore\hardware\avr\2.3.0\avrdude.conf

Using Port                    : COM16
Using Programmer              : stk500v1
Overriding Baud Rate          : 19200
avrdude stk500_recv() error: programmer is not responding
avrdude stk500_getsync() warning: attempt 1 of 10: not in sync: resp=0x00
avrdude stk500_recv() error: programmer is not responding
avrdude stk500_getsync() warning: attempt 2 of 10: not in sync: resp=0x00
...

avrdude done.  Thank you.
the selected serial port
 does not exist or your board is not connected

```

I tried avrdude in command line with these parameters and got the same results:

```
avrdude -p attiny13a -P COM16 -c avrisp -b 19200 -U flash:w:r.hex -v

```

I also found out that issue most probably has nothing to do with:

* Target chip that I'm using: because changing it has no effect
* Wiring: because even when there is no chip connected to SPI pins of ProMicro I get the same error
* USB cable is good: I can upload sketches successfully to Pro Micro but cannot use it as ISP and replaced cable to rule that probably out.

This is while in this video the guy does what I want easily and has no issues whatsoever: https://www.youtube.com/watch?v=7Rz9A9VbDx4

Any ideas appreciated.

# Answer
> 1 votes
GOTCHA... After two days of search and speculation finally found the solution:

**Short answer:** In avrdude command instead of **-c avrisp** use **-c arduino**:

```
avrdude -p attiny13a -P COM16 -c arduino -b 19200 -U flash:w:r.hex -v

```

**Long answer:** My target chip was ATtiny13a, so I had to use MicroCore v2.3.0 which is the only core supporting ATtiny13 for Arduino. Contrary to other cores, in this core's programmers.txt list, each entry should have a *upload.protocol* line:

```
arduinoasispatmega32u4.upload.protocol=

```

otherwise it will give this error:

```
avrdude programmer_not_found() error: cannot find programmer id {upload.protocol}

```

I have added this line before to make that error go away but apparently with wrong parameter of **stk500v1** that I have imitated from fabric entries! Converting this parameter to **arduino** solved the problem. This is what that entry should look like for ATtiny13 of MicroCore v2.3.0 (\packages\MicroCore\hardware\avr\2.3.0\programmers.txt):

```
arduinoasispatmega32u4.name=Arduino Leo/Micro as ISP
arduinoasispatmega32u4.communication=serial
arduinoasispatmega32u4.protocol=arduino
arduinoasispatmega32u4.upload.protocol=arduino
arduinoasispatmega32u4.speed=19200
arduinoasispatmega32u4.program.protocol=arduino
arduinoasispatmega32u4.program.speed=19200
arduinoasispatmega32u4.program.tool=avrdude
arduinoasispatmega32u4.program.extra_params=-P{serial.port} -b{program.speed}

```

For other cores, like ATTinyCore v1.5.2 (\packages\ATTinyCore\hardware\avr\1.5.2\programmers.txt) no such line is needed hence this entry works fine:

```
arduinoasispatmega32u4.name=Arduino Leo/Micro as ISP
arduinoasispatmega32u4.communication=serial
arduinoasispatmega32u4.protocol=arduino
arduinoasispatmega32u4.speed=19200
arduinoasispatmega32u4.program.protocol=arduino
arduinoasispatmega32u4.program.speed=19200
arduinoasispatmega32u4.program.tool=avrdude
arduinoasispatmega32u4.program.extra_params=-P{serial.port} -b{program.speed}

```

Also you should update avrdude in the Arduino core manually: Download latest release from HERE, and replace them IDE's related files. If you can not find them take a look at HERE. If avrdude is not updated you might get an error like this:

```
Error during upload using programmer
The uploader process failed

The uploader process failed
The uploader returned an error
avrdude: Version 6.3-20201216
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch
         System wide configuration file is "C:\Users\K1\AppData\Local\arduino15\packages\MicroCore\hardware\avr\2.3.0/avrdude.conf"
avrdude: error at C:\Users\K1\AppData\Local\arduino15\packages\MicroCore\hardware\avr\2.3.0/avrdude.conf:421: syntax error
avrdude: error reading system wide configuration file "C:\Users\K1\AppData\Local\arduino15\packages\MicroCore\hardware\avr\2.3.0/avrdude.conf"

```

**Third Solusion:** Use this App with this configuration:

---
Tags: arduino-pro-micro, arduinoisp
---


# Question
Title: Weird behaviour with BearSSL on GPIO ESP8266
I use GPIO 5 to trigger a relay. My code also connects with a secure MQTT connection for which I have to use the BearSSL certificate definitions.

Without the BearSSL certificates, when the ESP restarts it does not re-trigger the relay, and the GPIO maintains its state between reboots, but when I use the bearSSL certificates the behavior changes, and GPIO 5 goes low on restart. Any explanation why and how to mitigate it?

I am 100% sure it is because of the import, because I removed components from my code until I could find the piece of code that caused this, and it was because of the declarations.

```
#include <WiFiClientSecure.h>

static const char AWS_CERT_CA[] PROGMEM = R"EOF(aws root)EOF";
static const char AWS_CERT_CRT[] PROGMEM = R"KEY(device cert)KEY";
static const char AWS_CERT_KEY[] PROGMEM = R"KEY(device key)KEY";

BearSSL::X509List cert(AWS_CERT_CA);
BearSSL::X509List client_crt(AWS_CERT_CRT);
BearSSL::PrivateKey key(AWS_CERT_KEY);

WiFiClientSecure espClient;

void setup() {
  pinMode(5, OUTPUT);
  delay(2000);
  digitalWrite(5, HIGH);
  delay(2000);
  ESP.restart();
}

void loop() {}

```

Without the following three lines the LED on GPIO 5 does not flicker on restarts, but adding these lines makes them flicker:

```
BearSSL::X509List cert(AWS_CERT_CA);
BearSSL::X509List client_crt(AWS_CERT_CRT);
BearSSL::PrivateKey key(AWS_CERT_KEY);

```

Any solution or suggestion towards a solution for this problem will be really helpful.

# Answer
What worked for me was to move the BearSSL declaration and usage after the pinMode setting of the GPIO.

I had to make the certificate and keys local variables and wrap the entire setting up of WiFi, connecting to it, setting up and connecting to the AWS core in a single function after setting up the GPIO pins.

```
void setupWiFiAndConnectAWS() {
  BearSSL::X509List cert(AWS_CERT_CA);
  BearSSL::X509List client_crt(AWS_CERT_CRT);
  BearSSL::PrivateKey key(AWS_CERT_KEY);
  WiFi.persistent(false);
  DEBUG_MSG("[setupWiFi] Setting host name\n");
  WiFi.hostname(deviceId);
  DEBUG_MSG("[setupWiFi] Setting station mode\n");
  WiFi.mode(WIFI_STA);

  if (WiFi.getMode() & WIFI_AP) {
    WiFi.softAPdisconnect(true);
  }

  WiFi.persistent(false);
  DEBUG_MSG("[setupWiFi] Loading certificates\n");
  net.setTrustAnchors(&cert);
  net.setClientRSACert(&client_crt, &key);
  loadCredentials();
  connectWiFi();
  attachInputInterrupts(false);
  setupNTP();
  connectAWS();
}

```

Although this is a workaround, I still don't understand the core problem and would like to understand it.
> 1 votes

---
Tags: esp8266, pins, mqtt
---