body:
hey guys I have a access control system working perfect with rfid and keypad.

I would like to implement : If the PIN is entered more than 3 times incorrectly the card is disabled.

someone could give a help or a tip?

here is my code:  https://pastiebin.com/5e4c315d97d5e

    #include <Keypad.h>                 // This sketch uses the Keypad.h library
    #include <SPI.h>                    // This sketch uses the SPI.h library
    #include <MFRC522.h>                // This sketch uses the MFRC522.h library

    #define SS_PIN 10                   // Define SS_PIN of the RC522 RFID Reader to digital pin 10 of the Arduino
    #define RST_PIN 9                   // Define RST_PIN of the RC522 RFID Reader to digital pin 9 of the Arduino
    MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance.

    int RedLed    = A3;                 // Red LED output is analog pin A3
    int GreenLed  = A4;                 // Green LED output is analog pin A4
    int Buzzer    = A5;                 // Buzzer output is analog pin A5
    unsigned long Timer;                // Variable for the Timer

    const byte ROWS = 4;                // Four rows
    const byte COLS = 3;                // Three columns

    char Keys[ROWS][COLS] = {           // Define the symbols on the buttons of the keypads
      {'1','2','3',},
      {'4','5','6',},
      {'7','8','9',},
      {'*','0','#',}
    };

    byte rowPins[ROWS] = {5, 4, 3, 2};  // Connect to the row pinouts of the keypad
    byte colPins[COLS] = {8, 7, 6};     // Connect to the column pinouts of the keypad
    Keypad keypad = Keypad( makeKeymap(Keys), rowPins, colPins, ROWS, COLS); // Initialize an instance of class NewKeypad

    int RightCard;                      // Variable for a known Mifare Card
    int RightPinCode;                   // Variable for valid key input in combination with a known Mifare Card
    int WrongPinCode;                   // Variable for a invalid key input in combination with a known Mifare Card
    int PinCodeCounter;                 // Variable Counter for counting the number of pincode inputs on the keypad

    int Code1Correct;                   // Variable for the first correct digit (Code) input on the keypad
    int Code2Correct;                   // Variable for the second correct digit (Code) input on the keypad
    int Code3Correct;                   // Variable for the third correct digit (Code) input on the keypad
    int Code4Correct;                   // Variable for the fourth correct digit (Code) input on the keypad
    int Code5Correct;                   // Variable for the fifth correct digit (Code) input on the keypad
    int Code6Correct;                   // Variable for the sixth correct digit (Code) input on the keypad
    int Reset;                          // Reset for the loop

    int MifareCard1;                               // We need this specific variable to determine the valid PinCode in combination with the UID nummer of the Mifare Card
    const int Code1MifareCard1 = '6';              // Determine here the first digit of your 6 digit PIN
    const int Code2MifareCard1 = '6';              // Determine here the second digit of your 6 digit PIN
    const int Code3MifareCard1 = '6';              // Determine here the third digit of your 6 digit PIN
    const int Code4MifareCard1 = '2';              // Determine here the fourth digit of your 6 digit PIN
    const int Code5MifareCard1 = '2';              // Determine here the fifth digit of your 6 digit PIN
    const int Code6MifareCard1 = '2';              // Determine here the sixth digit of your 6 digit PIN

    int MifareCard2;                               // We need this specific variable to determine the valid PinCode in combination with the UID nummer of the Mifare Card
    const int Code1MifareCard2 = '1';              // Determine here the first digit of your 6 digit PIN
    const int Code2MifareCard2 = '1';              // Determine here the second digit of your 6 digit PIN
    const int Code3MifareCard2 = '1';              // Determine here the third digit of your 6 digit PIN
    const int Code4MifareCard2 = '3';              // Determine here the fourth digit of your 6 digit PIN
    const int Code5MifareCard2 = '3';              // Determine here the fifth digit of your 6 digit PIN
    const int Code6MifareCard2 = '3';              // Determine here the sixth digit of your 6 digit PIN

    void setup()

    {
      Serial.begin(9600);                                     // Initialize serial communications with the PC
      SPI.begin();                                            // Initialize the SPI bus
      mfrc522.PCD_Init();                                     // Initialize the MFRC522
      pinMode (RedLed, OUTPUT);                               // Define RedLed as OUTPUT
      pinMode (GreenLed, OUTPUT);                             // Define GreenLed as OUTPUT
      pinMode (Buzzer, OUTPUT);                               // Define Buzzer as OUTPUT
    }

    void loop() {

    //----------------------------------------------Code for the reset function of the loop--------------------------------------------------------------------------------------------------------

    if (Reset == 1)                                           // If Reset has value 1 (HIGH) all variables will be reset to 0 and the RC522 RFID reader will be waiting for a new Mifare Card.
    {
      RightCard = 0;
      MifareCard1 = 0;
      MifareCard2 = 0;
      RightPinCode = 0;
      WrongPinCode = 0;
      Code1Correct = 0;
      Code2Correct = 0;
      Code3Correct = 0;
      Code4Correct = 0;
      Code5Correct = 0;
      Code6Correct = 0;
      PinCodeCounter = 0;
      delay (50);
      Reset = 0;
    }

    //----------------------------------------------Code for the control for a valid pincode within the timelimit of 7 seconds after presenting/offering a valid Mifare Card ---------------------------

    if (millis()- Timer > 7000 && RightCard == 1)            // If the Timer will be larger as 7 seconds and a valid Mifare Card is offered, reset value will be high.
       {                                                     // This means that you have after presenting a valid card, 7 seconds to enter a valid code or the loop resets.
        Reset = 1;
        Serial.println("CardAccesOff");
       }

    //----------------------------------------------Reading the presented/offered Mifare Card at the MFRC522 -----------------------------------------------------------------------------------------

    if   (mfrc522.PICC_IsNewCardPresent() &&
          mfrc522.PICC_ReadCardSerial())
        {

    //----------------------------------------------Code for detect the first Mifare Card in the Database. This is a UID number with 4 pairs of digits. Example: 69 7C 01 9C------------------------------------
         if
         (mfrc522.uid.uidByte[0] == 0x69   &&                // Fill in the first digits of the UID number of your Mifare card
          mfrc522.uid.uidByte[1] == 0x7C   &&                // Fill in the seconds digits of the UID number of your Mifare card
          mfrc522.uid.uidByte[2] == 0x01   &&                // Fill in the third digits of the UID number of your Mifare card
          mfrc522.uid.uidByte[3] == 0x9C)                    // Fill in the fourth digits of the UID number of your Mifare card

         {
          RightCard = 1;                                     // The offered Mifare Card is known in the database, set variable "RightCard" to 1
          MifareCard1 = 1;                                   // This Mifare Card is known as Mifare Card 2 in the Database, so set variable MifareCard2 to value 1.
          digitalWrite (Buzzer, HIGH);                       // Make a beep for the accepted Mifare Card
          delay (150);                                       //
          digitalWrite (Buzzer, LOW);                        //

          PinCodeCounter = 0;                                // Reset the PinCodeCounter to 0
          Timer =  millis();                                 // Reset the Timer. The 7 seconds limit is running now for a valid PinCode
          Serial.println("CardAccesOn");                     // Print the text "CardAccesOn" to the serial monitor
          delay (200);                                       // Wait 200 milliseconds
          }

    //-----------------------------------------------Code for detect the second Mifare Card in the Database. This is a UID number with 4 pairs of digits. Example: EB 70 C0 BC----------------------------------------------
         if
         (mfrc522.uid.uidByte[0] == 0xEB   &&                 // Fill in the first digits of the UID number of your Mifare card
          mfrc522.uid.uidByte[1] == 0x70   &&                 // Fill in the seconds digits of the UID number of your Mifare card
          mfrc522.uid.uidByte[2] == 0xC0   &&                 // Fill in the third digits of the UID number of your Mifare card
          mfrc522.uid.uidByte[3] == 0xBC)                     // Fill in the fourth digits of the UID number of your Mifare card

        {
          RightCard = 1;                                       // If the offered Mifare Card is known in the database, set variable "RightCard" to 1
          MifareCard2 = 1;
          digitalWrite (Buzzer, HIGH);                         // Make a beep for the accepted Mifare Card
          delay (150);                                         //
          digitalWrite (Buzzer, LOW);                          //

          PinCodeCounter = 0;                                  // Reset the PinCodeCounter to 0
          Timer =  millis();                                   // Reset the Timer. The 7 seconds limit is running now for a valid PinCode
          Serial.println("CardAccesOn");                       // Print the text "CardAccesOn" to the serial monitor
          delay (200);                                         // Wait 200 milliseconds
        }

        }

    //-----------------------------------------------Code for accepting a valid MifareCard + valid PinCode-------------------------------------------------------------------------------------------------

    if (Code6Correct == 1 && RightCard == 1)                    // If the PinCode is the correct and you did enter this within 7 seconds
      {
        RightPinCode = 1;                                       // Variable RightPinCode will be set to 1

        digitalWrite (GreenLed, HIGH);                          // Make a nice beep for the correct Pincode and set the Green LED high for 1 second
        delay (150);                                            //
        digitalWrite (Buzzer, HIGH);                            //
        delay (150);                                            //
        digitalWrite (Buzzer, LOW);                             //
        delay (50);                                             //
        digitalWrite (Buzzer, HIGH);                            //
        delay (150);                                            //
        digitalWrite (Buzzer, LOW);                             //
        delay (500);                                            //
        digitalWrite (GreenLed, LOW);                           //

        Serial.println("Correct PinCode");                      // Print the text "Correct PinCode" to the serial monitor
        Reset = 1;                                              // Reset the loop
      }

    //-----------------------------------------------Code for refusing a valid MifareCard + invalid PinCode------------------------------------------------------------------------------------------------

    if ((Code6Correct == 0) && (PinCodeCounter >= 6) && (RightCard == 1))       // If you offered a valid Mifare Card and the Pincode is not correct and you already entered 6 digitkeys
      {
        WrongPinCode = 1;                                                       // Variable WrongPinCode will be set to 1
        Serial.println("WrongCode");                                             // Print the text "WrongKey" to the serial monitor
        Reset = 1;                                                              // Reset the loop
      }

    //-----------------------------------------------Code for refusing a Wrong/Invalid PinCode or the Timer (7seconds) expired----------------------------------------------------------------------------

    if ((WrongPinCode == 1) || (millis()- Timer > 7000 && RightCard == 1))      // If you offered a valid Mifare Card and  you entered a wrong PinCode or the timer (7 seconds) expires
      {
        digitalWrite (Buzzer, HIGH);                                            // Make a long beep and set the Red LED HIGH for the wrong code or timer expiry
        digitalWrite (RedLed, HIGH);                                           //
        delay(1500);                                                            //
        digitalWrite (Buzzer, LOW);                                             //
        digitalWrite (RedLed, LOW);                                             //

        Serial.println("WrongCode or Timer expired");                           // Print the text "WrongCode or Timer expired" to the serial monitor
        Reset = 1;                                                              // Reset the loop
      }

    //-----------------------------------------------Code for counting the inputs on the keypad----------------------------------------------------------------------------------------------------------

    char KeyDigit = keypad.getKey();                                           // Get the DigitKey from the keypad

    if ((RightCard == 1) &&                                                    // If you offered a valid Mifare Card and any DigitKey on the keypad is pressed
        ((KeyDigit == '1') ||
        (KeyDigit == '2')  ||
        (KeyDigit == '3')  ||
        (KeyDigit == '4')  ||
        (KeyDigit == '5')  ||
        (KeyDigit == '6')  ||
        (KeyDigit == '7')  ||
        (KeyDigit == '8')  ||
        (KeyDigit == '9')  ||
        (KeyDigit == '0')  ||
        (KeyDigit == '*')  ||
        (KeyDigit == '#')))

        {
          PinCodeCounter++;                                                       // PinCodeCounter value +1 for every press on any Digitkey on the keypad
          digitalWrite (Buzzer, HIGH);                                            // Make a short beep for a DigitKey press on the keypad
          delay (50);                                                             //
          digitalWrite (Buzzer, LOW);                                             //
        }

    //-----------------------------------------------Code for determine the correct PinCode for MifareCard1----------------------------------------------------------------------------------------------------------

    if ((KeyDigit == Code1MifareCard1) && (RightCard == 1) && (Code1Correct == 0) && (MifareCard1 == 1))           // If you offered the valid MifareCard1, first PinCode and you did not entered it before (Otherwise we conflict with same KeyDigits)
        {
          Code1Correct = 1;                                                                                // Variable Code1Correct is set to 1
          return;                                                                                // Return to begin loop
        }

    if ((KeyDigit == Code2MifareCard1) && (Code1Correct == 1) && (Code2Correct == 0) && (MifareCard1 == 1))        // If you offered the valid MifareCard1, second PinCode and you did not entered it before (Otherwise we conflict with same KeyDigits)
        {
          Code2Correct = 1;                                                                                // Variable Code2Correct is set to 1
          return;                                                                                // Return to begin loop
        }

    if ((KeyDigit == Code3MifareCard1) && (Code2Correct == 1) && (Code3Correct == 0) && (MifareCard1 == 1))         // If you offered the valid MifareCard1, third PinCode and you did not entered it before (Otherwise we conflict with same KeyDigits)
        {
          Code3Correct = 1;                                                                                // Variable Code3Correct is set to 1
          return;                                                                                // Return to begin loop
        }

    if ((KeyDigit == Code4MifareCard1) && (Code3Correct == 1) && (Code4Correct == 0) && (MifareCard1 == 1))         // If you offered the valid MifareCard1, fourth PinCode and you did not entered it before (Otherwise we conflict with same KeyDigits)
        {
          Code4Correct = 1;                                                                                // Variable Code4Correct is set to 1
          return;                                                                                // Return to begin loop
        }
    if ((KeyDigit == Code5MifareCard1) && (Code4Correct == 1) && (Code5Correct == 0) && (MifareCard1 == 1))         // If you offered the valid MifareCard1, fifth PinCode and you did not entered it before (Otherwise we conflict with same KeyDigits)
        {
          Code5Correct = 1;                                                                                // Variable Code5Correct is set to 1
          return;                                                                                // Return to begin loop
        }

    if ((KeyDigit == Code6MifareCard1) && (Code5Correct == 1) && (Code6Correct == 0) && (MifareCard1 == 1))         // If you offered the valid MifareCard1, sixth PinCode and you did not entered it before (Otherwise we conflict with same KeyDigits)
        {
          Code6Correct = 1;                                                                                // Variable Code6Correct is set to 1
          return;                                                                                // Return to begin loop
        }

    //-----------------------------------------------Code for determine the correct PinCode for MifareCard2----------------------------------------------------------------------------------------------------------

    if ((KeyDigit == Code1MifareCard2) && (RightCard == 1) && (Code1Correct == 0) && (MifareCard2 == 1))              // If you offered a the valid MifareCard2, first PinCode and you did not entered it before (Otherwise we conflict with same KeyDigits)
        {
          Code1Correct = 1;                                                                                // Variable Code1Correct is set to 1
          return;                                                                                // Return to begin loop
        }

    if ((KeyDigit == Code2MifareCard2) && (Code1Correct == 1) && (Code2Correct == 0) && (MifareCard2 == 1))           // If you offered a the valid MifareCard2, second PinCode and you did not entered it before (Otherwise we conflict with same KeyDigits)
        {
          Code2Correct = 1;                                                                                // Variable Code2Correct is set to 1
          return;                                                                                // Return to begin loop
        }

    if ((KeyDigit == Code3MifareCard2) && (Code2Correct == 1) && (Code3Correct == 0) && (MifareCard2 == 1))           // If you offered a the valid MifareCard2, third PinCode and you did not entered it before (Otherwise we conflict with same KeyDigits)
        {
          Code3Correct = 1;                                                                                // Variable Code3Correct is set to 1
          return;                                                                                // Return to begin loop
        }

    if ((KeyDigit == Code4MifareCard2) && (Code3Correct == 1) && (Code4Correct == 0) && (MifareCard2 == 1))          // If you offered a the valid MifareCard2, fourth PinCode and you did not entered it before (Otherwise we conflict with same KeyDigits)
        {
          Code4Correct = 1;                                                                                // Variable Code4Correct is set to 1
          return;                                                                                // Return to begin loop
        }
    if ((KeyDigit == Code5MifareCard2) && (Code4Correct == 1) &&  (Code5Correct == 0) && (MifareCard2 == 1))         // If you offered a the valid MifareCard2, fifth PinCode and you did not entered it before (Otherwise we conflict with same KeyDigits)
        {
          Code5Correct = 1;                                                                                // Variable Code5Correct is set to 1
          return;                                                                                // Return to begin loop
        }

    if ((KeyDigit == Code6MifareCard2) && (Code5Correct == 1) &&  (Code6Correct == 0) && (MifareCard2 == 1))         // If you offered a the valid MifareCard2, sixth PinCode and you did not entered it before (Otherwise we conflict with same KeyDigits)
        {
          Code6Correct = 1;                                                                                // Variable Code6Correct is set to 1
          return;                                                                                // Return to begin loop
        }

    }

thank you very much.

title: Access Control System with an 4x3 Keypad & RFID-RC522

Answers: 3

body:
Add  ``int passCount = '0';`` to the top of your file and then increment that value by one every time the wrong password gets entered (For example replace ``Reset = 1;`` with ``passCount ++;`` on line 199)
And add ``passCount = '0'`` to your reset on line 85.
And add another if statement to reset loop if password has been entered more than 3 times. ``if (passCount == 3) {Reset = 1;}``

Hope this helps :-)

EDIT:

You can comment out/delete the If statement on lines 222 - 232 ```if ((WrongPinCode == 1) || (millis()- Timer > 7000 && RightCard == 1))```.

And add your Buzzer and Led code to the if statement above (same statement with ```passCount ++;``` in it)
The timeout reset will be take care of code on lines 108 - 112.

body:
1.initialize a global variable ```int failcount=0,MiFareCardMode=0;```

2. for reset put it in an if statement that checks fail count
      ```
         if(failcount==0)
                      {reset code}```
3. in this piece of code increase the failcount number(line 195:200)
   also add an if statement to check which card was detected
   initialize a global variable to set the card status
   MiFareCardMode(0=unblocked,1=card1 block,2=card2 block)

```
if ((Code6Correct == 0) && (PinCodeCounter >= 6) && (RightCard == 1))
  {
    WrongPinCode = 1;
    Serial.println("WrongCode");
    Reset = 1;
    failcount++       ///here increase the value with each wrong password
    if (failcount>=3)
     {   if(MifareCard1==1)
              MifareCardMode=1; ///create a variable for mode (blocked OR non blocked)
         if(MiFareCard2==1)
               MifareCardMode=2;
}
 failcount=0; }

```
4.In lines 125:142 put them in an if statement which check the variable MiFareCardMode
```
       if(MiFareCardMode==0)
                 {
                    lines 125 to 142
                    }
         if(MiFareCardMode==1)
                   { Serial.println("Card 1 blocked permanently");
                    //add anything you want to do after blocking }
```
4.In lines 146:163 put them in an if statement which check the variable MiFareCardMode for card 2
```
    if(MiFareCardMode==0)
          {   lines 146:163  }
    if(MiFareCardMode==2)
           {Serial.println("Card2 blocked permanently");}

```

body:
Your code written more complex, than it has to be, and you have much repeated code, that makes it harder to understand and change the code. So I will first describe, how to shorten and generalize your code. That will make it easier to implement new features, like invalidating a card after 3 wrong PIN entries.

- **Handling the RFID cards:** Currently you are using single variables for each card (for example `RightCard`). Your if statements all have to reference these single variables for each card, which makes it hard to not write repeated code. Instead you should use arrays to store the information. See this piece of code:

        #define MAX_CARD_N        2
        #define SERIAL_LENGTH     4
        uint8_t card_serials[MAX_CARD_N][SERIAL_LENGTH] = {
            {0x69, 0x7C, 0x01, 0x9C},
            {0xEB, 0x70, 0xC0, 0xBC}
        };

        #define PIN_LENGTH        6
        char card_pins[MAX_CARD_N][PIN_LENGTH] = {
            {'6','6','6','2','2','2'},
            {'1','1','1','3','3','3'}
        };

        int current_card = -1;
        uint8_t current_pin_position = 0;
        bool pin_correct = true;

     What happens here? First we set defines for later use, where we can centrally set the number of cards, that we want to use, and the length of their serial data. Then we declare a 2 dimensional array, which stores the serial for each card (for example in a loop). We can now access the serials of the cards by simple integer indices. Then we do the same with the PINs of these cards. (And declare variables for holding the current card index, the current pin position and the correctness of the pin for later use.) We can implement a function, that will give us the index of the currently scanned card in our card arrays:

        int find_card(){
            if(mfrc522.uid.uidByte[0] == 0x00) return -1;
            for(uint8_t card_index=0; card_index < MAX_CARD_N; card_index++){
                uint8_t found_card_flag = 1;
                for(uint8_t serial_index=0; serial_index < SERIAL_LENGTH; serial_index++){
                    if(card_serials[card_index][serial_index] != mfrc522.uid.uidByte[serial_index]){
                        found_card_flag = 0;
                        break;
                    }
               }
               if(found_card_flag){
                   return card_index;
               }
           }
           return -1;
        }

    This function will return -1, if the scanned card serial can not be found in our `card_serials` array. If it was found, the function returns the index of the card. I also added an if statement at the start, that forbids to find cards with the first element being zero, which will come in handy at a later time (I only used the first element here for making it easy, but you can also check every of the 4 serial bytes, if you want to forbid zeros everywhere in the serial).

- **Organizing your code:** Currently you have many individual if statements, which all need extra variables, so that you can execute the right code at the right situation. A better approach for something like this is a Finite State Machine (FSM). It is an important concept, that sound more difficult, than it is. Basically you divide your code into different states, where specific things should happen. Actions or specific situations can do a transition to a different state. Every state only executes it's own code. The current state is held in a variable, called state variable. In my answer to [this question][1] I already explained the principle in detail (including some graphs). You should really learn this principle; it changed my coding style completely for better.

    I would use 2 different states: `WAIT_FOR_CARD` and `WAIT_FOR_PIN`, so that we can seperate the RFID and the keypad code. Look at this piece of code:

        enum State {WAIT_FOR_CARD, WAIT_FOR_PIN};
        State state = WAIT_FOR_CARD;

        void loop() {
            switch(state){
              case WAIT_FOR_CARD:
                  if(mfrc522.PICC_IsNewCardPresent() &&
                     mfrc522.PICC_ReadCardSerial()){
                      int scanned_card = find_card();
                      if(scanned_card != -1){
                          current_card = scanned_card;
                          current_pin_position = 0;
                          code_correct = true;
                          // Insert code for correct card in here (buzzer, setting timestamp, ...)
                          state = WAIT_FOR_PIN;
                      } else {
                          // Insert code for incorrect card in here
                      }
                  }
                  break;
              case WAIT_FOR_PIN:
                  char KeyDigit = keypad.getKey();
                  if(KeyDigit != NO_KEY){
                    if(KeyDigit != card_pins[current_card][current_pin_position]) pin_correct = false;
                    current_pin_position++;
                    if(current_pin_position >= PIN_LENGTH){
                        if(pin_correct){
                            // Insert code for correct pin in here
                        } else {
                            // Insert code for wrong pin in here
                        }
                        current_card = -1;
                        state = WAIT_FOR_CARD;
                    }
                  }
                  break;
            }
        }

    We first define our states as an `enum`, since this makes the code more readable. Then we declare a state variable from that `enum`. In the `loop()` function we use a `switch case` statement to execute the code corresponding to the current state. In the `WAIT_FOR_CARD` state, we are constantly scanning for a new card. If we found one, we check with the `find_card()` function, if we have the serial of this card saved in our array. If yes, we set our variables accordingly, execute the needed code for a valid card and then set the state variable to the next state. The `break` will get us out of the switch statement, but on the next loop iteration, we are now executing the other case (since we changed the state variable). We are now constantly checking for a pressed key. If the pressed key was not the one defined in our PIN array for the current position, we set `pin_correct` to `false` (If every key is correct, it will stay `true`. If any is incorrect, it will get set to `false`). We increment the PIN position and then check if we reached the end of the PIN, where we decide, if the PIN was correct or not, doing the appropriate things, and at the end reset our `current_card` variable and the state variable. (I left out the timeout feature. When you have understood the FSM principle, it should be easy to add this to the code.)

    This code is better structured and way shorter. Also it can easily handle extensions (more cards, other functions,...). You can add more states and transitions to insert new features.

- **Disabling cards on 3 wrong pin entries:** I assume, that you want, that 3 incorrect PIN entries will disable the RFID card, so that it is no longer accepted as valid. For that you could remove the corresponding serial from the `card_serials` array. First we need to track the number of consecutive wrong PIN entries. For that I would use another array and a define for the max number of wrong entries (here 2, since 2 wrong entries are still allowed; the third wrong entry will trigger the invalidation of the card):

        uint8_t pin_strikes[MAX_CARD_N] = {0};
        #define MAX_STRIKES    2

    When we have a wrong PIN, you can increment this counter by 1:

        pin_strikes[current_card]++;

    When we have a correct PIN, we want to reset this counter:

        pin_strikes[current_card] = 0;

    After incrementing in the case of a wrong PIN we can check, how many times the pin was already wrong consecutively, and then remove the serial, if it was too much:

        if(pin_strikes[current_card] > MAX_STRIKES){
            for(uint8_t i=0; i < SERIAL_LENGTH; i++) card_serials[current_card][i] = 0;
            current_card = -1;
        }

    We should reset the `current_card` variable here, since this index doesn't point to a valid card anymore. We can invalidate the card by setting the serial to zero, since we ruled out all card with a zero in the first byte at the start of the `find_card()` function.

[1]: https://arduino.stackexchange.com/questions/63488/wanted-to-control-2-servos-with-serial-read/63491#63491


body:
I'm trying to construct a program for an ESP32 Dev Board that writes my AWS cert files [(https://medium.com/@flynam/securing-your-iot-device-using-ssl-4643110ab901)][1] to SPIFFS so that I can later read them from another program that's loaded via an OTA (over the air) updater.

However, it looks like something is being lost during the read & write process.  The certs will work if hardcoded, but error out when loaded from SPIFFS.

Hardcoding to a variable like the one in ```Secrets.h``` works:

```static const char AWS_CERT_CA[] PROGMEM```

But when writing that to a file and printing via ```Serial.println``` I'm missing things like ```R"EOF(``` and ```)EOF"``` which I'm assuming are hidden characters.

Does this have to do with writing as a .txt file or perhaps storing in the wrong kind of variable?

The code below is missing some functions, but the relevant portions are below.

I should also mention I am very much a C++ beginner so there's probably some things off with my code above and beyond my initial question.

main.ino
```
// ...
#include "Secrets.h" // contains cert files info
#include <WiFiClientSecure.h>
#include <MQTTClient.h>
#include <ArduinoJson.h>
#include "Esp.h"
#include "SPIFFS.h"
// ...

// Where I'm wanting to store my cert files
static char AWS_CERT_CA_FILEPATH[] = "/AWS_CERT_CA.txt";
static char AWS_CERT_CRT_FILEPATH[] = "/AWS_CERT_CRT.txt";
static char AWS_CERT_PRIVATE_FILEPATH[] = "/AWS_CERT_PRIVATE.txt";

// Save a file to the designated location
void saveFile(const char* filePath, const char* contents){
  if(!SPIFFS.exists(filePath)) {
      File writeLog = SPIFFS.open(filePath, FILE_WRITE);
      if(!writeLog) {
          Serial.print("Couldn't open ");
          Serial.println(filePath);
      } else {
        writeLog.print(contents);
        delay(50);
        Serial.print(contents);
        Serial.print(" written to file system");
        Serial.println(filePath);
        delay(50);
        writeLog.close();
      }
      delay(50);

  } else {
    Serial.print(filePath);
    Serial.print(" already exists.  Call remove() first.");
  }
}

// Remove files if they are there already, then save anew
void saveCerts(){

  SPIFFS.remove(AWS_CERT_CA_FILEPATH);
  SPIFFS.remove(AWS_CERT_CRT_FILEPATH);
  SPIFFS.remove(AWS_CERT_PRIVATE_FILEPATH);

  saveFile(AWS_CERT_CA_FILEPATH, AWS_CERT_CA);
  saveFile(AWS_CERT_CRT_FILEPATH, AWS_CERT_CRT);
  saveFile(AWS_CERT_PRIVATE_FILEPATH, AWS_CERT_PRIVATE);
}

// Load the file into char* ...
// Loads, but perhaps not into the correct format?
bool loadFile(const char* filePath, char* buffer){
    File f = SPIFFS.open(filePath, "r");
    if (f && f.size()) {

      Serial.print("Reading ");
      Serial.print(f.size());
      Serial.print(" bytes from file ");
      Serial.println(filePath);

      int pos = 0;
      while (f.available()) {
        buffer[pos] = f.read();
        pos++;
      }

      buffer[pos] = 0;

      f.close();
      return true;

    } else {
      Serial.print("No contents available for ");
      Serial.println(filePath);
      return false;
    }
}

// Allows for creation of correctly size char arrays
int getFileSize(const char* filePath){
    File f = SPIFFS.open(filePath, "r");
    if (f && f.size()) {
      return (int)f.size();

    } else {
      return 0;
    }
}

void connectAWS()
{
  // Need to save these to file
  char AWS_CERT_CA_LOADED[getFileSize(AWS_CERT_CA_FILEPATH)];
  char AWS_CERT_CRT_LOADED[getFileSize(AWS_CERT_CRT_FILEPATH)];
  char AWS_CERT_PRIVATE_LOADED[getFileSize(AWS_CERT_PRIVATE_FILEPATH)];

  loadFile(AWS_CERT_CA_FILEPATH, AWS_CERT_CA_LOADED);
  loadFile(AWS_CERT_CRT_FILEPATH, AWS_CERT_CRT_LOADED);
  loadFile(AWS_CERT_PRIVATE_FILEPATH, AWS_CERT_PRIVATE_LOADED);

  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  // From here on out is code from tutorials and works when
  // certs are hardcoded

  Serial.println("Connecting to Wi-Fi");

  // TODO Put in some code when auth fails
  while (WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }

  // Configure WiFiClientSecure to use the AWS IoT device credentials
  net.setCACert(AWS_CERT_CA_LOADED);
  net.setCertificate(AWS_CERT_CRT_LOADED);
  net.setPrivateKey(AWS_CERT_PRIVATE_LOADED);

  // Connect to the MQTT broker on the AWS endpoint we defined earlier
  client.begin(AWS_IOT_ENDPOINT, 8883, net);

  // Create a message handler
  client.onMessage(messageHandler);

  Serial.print("Connecting to AWS IOT");

  while (!client.connect(THINGNAME)) {
    Serial.print(".");
    delay(100);
  }

  if(!client.connected()){
    Serial.println("AWS IoT Timeout!");
    return;
  }

  // Subscribe to a topic
  client.subscribe(AWS_IOT_SUBSCRIBE_TOPIC);

  Serial.println("AWS IoT Connected!");
}

void setup() {
  Serial.begin(9600);
  SPIFFS.begin();
  saveCerts();
  connectAWS();
  publishMessage();
}

```

In secrets.h
```
#include <pgmspace.h>

#define SECRET

// Amazon Root CA 1
static const char AWS_CERT_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
awholebunchofrandomlettersandnumbers
-----END CERTIFICATE-----
)EOF";

// Device Certificate
static const char AWS_CERT_CRT[] PROGMEM = R"KEY(
-----BEGIN CERTIFICATE-----
awholebunchofrandomlettersandnumbers
-----END CERTIFICATE-----

)KEY";

// Device Private Key
static const char AWS_CERT_PRIVATE[] PROGMEM = R"KEY(
-----BEGIN RSA PRIVATE KEY-----
awholebunchofrandomlettersandnumbers
-----END RSA PRIVATE KEY-----
)KEY";
```

 Print and Error Message
```
[E][vfs_api.cpp:135] remove(): /AWS_CERT_CRT.txt does not exists or is directory
[E][vfs_api.cpp:135] remove(): /AWS_CERT_PRIVATE.txt does not exists or is directory

-----BEGIN CERTIFICATE-----
someprivatestuffIerased
-----END CERTIFICATE-----
 written to file system/AWS_CERT_CA.txt

-----BEGIN CERTIFICATE-----
someprivatestuffIerased
-----END CERTIFICATE-----
 written to file system/AWS_CERT_CRT.txt

-----BEGIN RSA PRIVATE KEY-----
someprivatestuffIerased
-----END RSA PRIVATE KEY-----
 written to file system/AWS_CERT_PRIVATE.txt
Reading 1189 bytes from file /AWS_CERT_CA.txt
Reading 1221 bytes from file /AWS_CERT_CRT.txt
Reading 1676 bytes from file /AWS_CERT_PRIVATE.txt
[D][WiFiGeneric.cpp:337] _eventCallback(): Event: 0 - WIFI_READY
[D][WiFiGeneric.cpp:337] _eventCallback(): Event: 2 - STA_START
Connecting to Wi-Fi
[D][WiFiGeneric.cpp:337] _eventCallback(): Event: 4 - STA_CONNECTED
[D][WiFiGeneric.cpp:337] _eventCallback(): Event: 7 - STA_GOT_IP
[D][WiFiGeneric.cpp:381] _eventCallback(): STA IP: 192.168.1.192, MASK: 255.255.255.0, GW: 192.168.1.1
.Connecting to AWS IOT[V][ssl_client.cpp:56] start_ssl_client(): Free internal heap before TLS 258252
[V][ssl_client.cpp:58] start_ssl_client(): Starting socket
[V][ssl_client.cpp:93] start_ssl_client(): Seeding the random number generator
[V][ssl_client.cpp:102] start_ssl_client(): Setting up the SSL/TLS structure...
[V][ssl_client.cpp:115] start_ssl_client(): Loading CA cert
[V][ssl_client.cpp:163] start_ssl_client(): Loading CRT cert
[V][ssl_client.cpp:170] start_ssl_client(): Loading private key
[V][ssl_client.cpp:180] start_ssl_client(): Setting hostname for TLS session...
[V][ssl_client.cpp:195] start_ssl_client(): Performing the SSL/TLS handshake...
Guru Meditation Error: Core  1 panic'ed (Unhandled debug exception)
Debug exception reason: Stack canary watchpoint triggered (loopTask)
Core 1 register dump:
PC      : 0x4008c363  PS      : 0x00060036  A0      : 0x8008c458  A1      : 0x3ffb0060
A2      : 0x3ffd9cbc  A3      : 0xbaad5678  A4      : 0x3ffd9cb0  A5      : 0x3ffb0190
A6      : 0x00000001  A7      : 0x00000000  A8      : 0x3ffd9cc8  A9      : 0x3ffd9cb4
A10     : 0x00000001  A11     : 0x3ffd9cb0  A12     : 0x00005640  A13     : 0x00005568
A14     : 0x3ffd9da8  A15     : 0x3ffd9ccc  SAR     : 0x0000001f  EXCCAUSE: 0x00000001
EXCVADDR: 0x00000000  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff

Backtrace: 0x4008c363:0x3ffb0060 0x4008c455:0x3ffb0090 0x40084e00:0x3ffb00b0 0x400850a3:0x3ffb00d0 0x400845c8:0x3ffb00f0 0x400f1099:0x3ffb0110 0x400ee30a:0x3ffb0130 0x400eed36:0x3ffb0150 0x400eeda1:0x3ffb0190 0x400ef154:0x3ffb01c0 0x400ef2ff:0x3ffb0240 0x400ef577:0x3⸮

```

Update

Exception can be fixed by making the variables global, but I now receive a repeating invalid certificate format error.

```
[ssl_client.cpp:56] start_ssl_client(): Free internal heap before TLS 256736
[V][ssl_client.cpp:58] start_ssl_client(): Starting socket
[V][ssl_client.cpp:93] start_ssl_client(): Seeding the random number generator
[V][ssl_client.cpp:102] start_ssl_client(): Setting up the SSL/TLS structure...
[V][ssl_client.cpp:115] start_ssl_client(): Loading CA cert
[E][ssl_client.cpp:33] _handle_error(): [start_ssl_client():122]: (-8576) X509 - The CRT/CRL/CSR format is invalid, e.g. different type expected
[E][WiFiClientSecure.cpp:132] connect(): start_ssl_client: -8576
[V][ssl_client.cpp:248] stop_ssl_socket(): Cleaning SSL connection.
[V][ssl_client.cpp:56] start_ssl_client(): Free internal heap before TLS 256124
[V][ssl_client.cpp:58] start_ssl_client(): Starting socket
[V][ssl_client.cpp:93] start_ssl_client(): Seeding the random number generator
[V][ssl_client.cpp:102] start_ssl_client(): Setting up the SSL/TLS structure...
[V][ssl_client.cpp:115] start_ssl_client(): Loading CA cert
[E][ssl_client.cpp:33] _handle_error(): [start_ssl_client():122]: (-8576) X509 - The CRT/CRL/CSR format is invalid, e.g. different type expected

```

Update 2

Added the following
```
// At top of file
#define FORMAT_SPIFFS_IF_FAILED true

// In setup()
if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){
   Serial.println("SPIFFS Mount Failed");
   return;
}

```

title: How do I write and read .pem certs from SPIFFS?

Answers: 0


body:
I'm new on this so go easy on me.

I'm trying to make an IR blaster to control my TV and ACs. I realized that when I capture the IR code, power button/temp up and down/mode send raw codes that are almost similar to each other.

I've searched the net(maybe missed some answers) and came through [this][1]. The raw IR code provided on the blog did turned on my AC but I wasn't able to turn it off. So I think that the code isn't the power button. That's because I remember leaving the AC off at 23°C and when I send that code, my AC started at 20°C.

 So, how do I know which code to use for off, temp up etc? The codes I captured seems not to work when I send the codes to the AC. Nothing happened. No beep or anything. I'm using a GREE AC by the way.

Here's an example of the raw code that turned on my AC:

    uint16_t irACon1[139] = {9050, 4500, 800, 1600, 750, 550, 700, 550, 700, 1600, 750, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 1600, 750, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 1600, 750, 1600, 750, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 1600, 750, 550, 700, 1600, 750, 550, 700, 550, 700, 1600, 750, 550, 700, 19950, 750, 500, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 1600, 750, 550, 700, 550, 750, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 550, 700, 1550, 800, 550, 750, 500, 700, 1600, 750};

And few other codes that I had captured:

    Raw: (139) 9068, -4404, 708, -1580, 712, -488, 712, -484, 712, -1580, 712, -1580, 708, -1580, 712, -488, 708, -488, 708, -1584, 708, -1584, 708, -1580, 708, -492, 708, -488, 704, -496, 704, -492, 708, -492, 708, -492, 704, -492, 708, -492, 708, -488, 712, -488, 712, -1580, 708, -1580, 712, -488, 712, -484, 712, -488, 712, -488, 712, -484, 712, -1580, 712, -484, 712, -1580, 712, -484, 716, -484, 712, -1580, 712, -484, 712, -19848, 684, -512, 704, -496, 708, -492, 708, -488, 708, -492, 708, -488, 712, -488, 712, -488, 708, -488, 712, -488, 712, -484, 712, -488, 712, -488, 708, -1580, 712, -488, 712, -484, 712, -488, 708, -488, 712, -488, 712, -488, 708, -488, 712, -488, 708, -488, 712, -488, 712, -488, 708, -488, 712, -488, 708, -492, 708, -488, 708, -492, 708, -1584, 704, -1584, 708,

    Raw: (139) 8988, -4540, 556, -1736, 564, -688, 520, -676, 524, -652, 548, -1688, 600, -1688, 604, -648, 548, -652, 548, -1688, 604, -1684, 604, -1688, 604, -648, 548, -652, 548, -648, 548, -652, 548, -652, 548, -648, 548, -652, 548, -652, 548, -648, 548, -676, 524, -1688, 600, -1688, 604, -676, 520, -676, 524, -676, 524, -672, 524, -676, 524, -1712, 576, -680, 520, -1688, 604, -756, 440, -788, 412, -1688, 600, -816, 384, -20092, 468, -840, 348, -848, 352, -848, 352, -820, 384, -812, 388, -788, 412, -784, 412, -784, 416, -760, 440, -760, 436, -760, 440, -756, 444, -756, 440, -1824, 468, -780, 416, -760, 440, -756, 444, -728, 468, -732, 468, -728, 472, -700, 496, -704, 496, -700, 496, -676, 524, -676, 520, -652, 548, -648, 552, -624, 572, -624, 576, -620, 580, -1740, 548, -620, 580,

PS: Sorry for my bad English. And I somehow feel that the title isn't specific so let me know if there's a better title I should put.

**UDPATE**: Now the off and temp up is working but the temp is somewhat like an on button. It instantly put my AC on 23°C and won't increase when pressed multiple time. I understand that AC's remote fires the whole setup string when a button is pressed so which means different temps has different codes?

  [1]: https://myesp8266.blogspot.com/2016/05/keep-your-house-cool-with-esp8266.html

title: Determining which raw IR code to use for AC

Answers: 1

body:
It appears from the data you've posted, the remote is holding the presets for what the A/C unit needs to be doing when after every button is pressed.  This will keep the remote with LCD disply? in Sync with the A/C master.

Ie.  The remote is sending an entire setup string EVERY time ANY button is pressed.

Can you post a capture of an ON and OFF Raw's only?  Do not press any other buttons after pressing ON, or before pressing OFF.


body:
Yesterday evening everything worked well. Today morning I am trying to upload sketch to the Arduino (nano china, CH340) and get the following:
```
Writing |

avrdude: stk500_paged_write(): (a) protocol error, expect=0x14, resp=0x00

############avrdude: stk500_cmd(): programmer is out of sync

avrdude: stk500_recv(): programmer is not responding
```

Check wiring, settings, cable, another PC. The same result.
Took another Arduino from the same supply. Works.

What could damage my Arduino nano? Static voltage? This is the first time in 3 years of insensitive playing with Arduino. I was told that Arduino nano is quite tolerant to static voltage.

What can I do with this damaged Arduino? Is it possible to restore it?
The boards is still recognizable by PC and blinks with leds when it is connected.

title: What killed my Arduino nano?

Answers: 0


body:
I'm still inexperienced in programming and i apologize in advance if my mistakes are stupidly obvious. This sketch I'm working on is a basic GSM project using SIM900a Mini and an Arduino UNO that could send a message to a recipient with a press of a button. I created a function so that if i send a command to the GSM, i could change the recipient and check the current recipient through my phone.

One thing to note is that before i resorted to creating this sketch, I created an almost working project with the same concept using SIM800L and an arduino Nano and i used the [GSM Library][1]. However, when it was hooked up to a variable Step-up converter for the needed supply of the ~4 V using a 3.7V Li-Po battery, it was damaged because the booster suddenly supplied 12V to the GSM. The SIM800L won't connect to the network anymore after that incident. I resorted to using SIM900a-Mini and it wasn't compatible with the GSM Library i guess because it can't get pass the initialization stage. Though i've seen youtube videos using both the SIM900 and the GSM Library, though i can't seem to make it work even though the two share the same chipset (i think). This current sketch works with some issues. Here's the sketch:

``````
#include <SoftwareSerial.h>
#include <SIM900.h>
#include <sms.h>
#define button 10
SMSGSM sms;

char senderNumber[15], recipientNumber[15] = "No recipient", newRecipient[15], commandkey[30] = {0};
char SmsText[30], smsRecieved[30];;
boolean validRecip, GSMconnected = false;
int buttonState = 0;

void setup(){
  Serial.begin(9600);
  Serial.println("Micro_GSM_Project");
  Serial.print("Initializing Serial:");
  pinMode(button, INPUT);
  pinMode(buzzer, OUTPUT);
  while (!Serial){
    Serial.println("Serial not connected");
  }
  delay(500);
  Serial.println(" Done");
  delay(1000);
  Serial.print("Initializing GSM Module:");
  if (gsm.begin(2400)) {
    Serial.println("\nWaiting for messages");
    GSMconnected = true;
    delay(1000);
  }
  else Serial.print("GSM Connecting");
}

void loop() {
  if (GSMconnected)
    {
    buttonState = digitalRead(button);
    if (buttonState == HIGH)
    {
      activate();
    }
    if (gsm.readSMS(SmsText, 30, senderNumber, 15))
    {
      Serial.print("\nMessage received from: +");
      Serial.println(senderNumber);
      Serial.println(SmsText);
      parseData();

     if (strcmp(commandkey, "CURRENT RECIP") == 0)
        {
          currentRecip();
        }
     else if (strcmp(commandkey, "SET RECIP") == 0)
        {
          changeRecip();
          confirmation();
        }
     else
     Serial.println("Invalid Command");
     sms.SendSMS(senderNumber, "The command you sent is invalid");
    }
  }
}

void activate() {
  delay(800);
  Serial.println("I have become self aware. Run");
  sms.SendSMS(recipientNumber,"I have become self aware. Run");
}

void parseData() {
  char * strtokIndx;
  strtokIndx = strtok(SmsText, ",");  //Read first part of Command either "SET RECIP" or "CURRENT RECIP"
  strcpy(commandkey, strtokIndx);         //store to commandkey variable

  strtokIndx = strtok(NULL, ",");         //Read where the last call left off, separated by a comma
  strcpy(newRecipient, strtokIndx);       //store to newRecipient variable

  Serial.print("Command Selected:");
  Serial.println(commandkey);
}

void currentRecip() {
  Serial.print("Current Recipient is: ");
  Serial.println(recipientNumber);
  delay(1000);
  sms.SendSMS(senderNumber, "Current Recipient is: recipientNumber");// i currently dont know how to log the variable recipientNumber to this string
}

void changeRecip()
    {
  validate();
    if (validRecip == true)
    {
    strcpy(recipientNumber, newRecipient);
    sms.SendSMS(senderNumber, "The Recipient number you have entered is valid");
    Serial.print("Recipient Number: ");
    Serial.print(recipientNumber);
    Serial.println("a");
    Serial.print("Sender Number");
    Serial.println(senderNumber);
    }
    if (validRecip == false)
    {
      Serial.println("Invalid Recipient");
      sms.SendSMS(senderNumber, "The Recipient number you have entered is invalid");
    }
    }

void validate()
  {
  if (strlen(newRecipient) == 13)   //I've put 13 here as a reference because the output strlen of the parsed newRecipient is 13 instead of the 12 characters composing the newRecipient i sent through sms. I think this is the null terminating character used by the strtokIndx? Please correct me if I'm wrong
  {
    Serial.println("Recipient is Valid\n");
    validRecip = true;
  }
  else
  {
    validRecip = false;
  }
}

void confirmation()
{
    if (validRecip == true)
    {
    Serial.println("Recipient Number successfully changed");    //Serial Monitor confirmation (for troubleshooting)
    Serial.print("New Recipient: +");
    Serial.println(recipientNumber);
    Serial.println("Informing Admin...");
    }
    if (sms.SendSMS(senderNumber, "Recipient Number successfully changed\nNew recipient: recipientNumber"))  //same here
    {
    Serial.println("Message Sent\n\n");
    }
    else
    {
    Serial.println("Invalid Recipient");
    sms.SendSMS(senderNumber, "The Recipient number you have entered is invalid");     //uncomment for SMS confirmation, need load
    }
}

``````

These are the current issues with my current code (in order of priority) .

 1. Even though the serial monitor displays the correct new recipient, **the recipient doesn't receive any message when the device is activated.**I think this is because of the data parsing method i used which creates a null character which increases the byte size of the recipientNumber variable. Through strlen, I've found out that the recipientNumber's size is 13 while the senderNumber fetched by the library has a size of 12. Even though the displayed number of characters in the serial are both 12. I tried changing the byte size of the array to 12 but once i did that, whenever i send the command to change the recipient, the program doesnt recognize the parsed command. It comes as blank.

 2. If i send the command "CURRENT RECIP" the serial outputs both the currentRecip() and the "Invalid command". If i put the "CURRENT RECIP" in the else if statement, swapping with the "SET RECIP", the "CURRENT RECIP" command works properly. For some reason, the command which is put in the else if statement works properly. I've tried adding another statement. i honestly don't fully understand what i wrote there myself. Still doesn't work tho.
``````
else if ((strcmp(commandkey, "CURRENT RECIP") != 0) || (strcmp(commandkey, "SET RECIP") != 0){
Serial.println("Invalid Command");
}
``````
 3. The project is supposed to activate at a simple push of a button. However, with my current sketch, it only activates when the button is long pressed. The issue i have here is i dont know where to properly put the activate(). I've tried placing it at the beginning of the loop and inside the if (GSMconnected) statement. However, both have the same result. I still have to press it long enough for the arduino to stop checking for available messages and proceed to the if (buttonState) statement.
```
if (buttonState == HIGH){
activate();
}
```

This sketch uses [this GSM Library][2] and i implemented the data parsing method from [Serial Input Basics][3]. The sketch properly separates the command i send which is "SET RECIP,XX**********" and proceeds to save it to the recipientNumber variable. The button can then be pressed and the GSM sends the message to the newly set recipient. Unfortunately, I am currently in a deadline and i dont think i have to time to scrap this sketch i made and just resort to AT commands. Please feel free to ask about any details i haven't covered. Any help would be appreciated and again i apologize in advance because some issues here might be fixed with just a simple syntax correction. Thank you in advance.

  [1]: https://www.arduino.cc/en/Reference/GSM
  [2]: https://github.com/MarcoMartines/GSM-GPRS-GPS-Shield
  [3]: https://forum.arduino.cc/index.php?topic=288234.0

title: Using SMS to send commands to the Arduino. Having problems in data parsing

Answers: 0


body:
I’ve got a quite weird behavior of DHT library.

I’ve got DHT22 sensor. If it’s signal cable is not connected, reading the sensor causes a problem: Arduino reboots or hangs in unpredictable places.

If I connect the signal cable again, the problem vanishes.

Is this normal behavior or some sort of bug? I think unsuccessful reading affects some part of Memory.

PS. The project is quite big and I can’t share the code here.

It happens that I found an evidence that dht object influences foreign memory. Look at this code:

    DV("pClock->isInited 3", pClock->isInited); // prints 1
    dht1.readHumidity();
    DV("pClock->isInited 4", pClock->isInited); // print 0 !!!!
    // nothing more can be called between these lines.

    // DV is a macro which prints label and value.
    // Both objects created before this.

    DHT dht1(11, DHT22);
    …
    dht1.begin();
    …
    pClock = new ZhClock(); // uses RTC_DS1307
    pClock->init(&rtc); // rtc is RTC_DS1307

title: Reading DHT22 reboots arduino

Answers: 1

body:
This problem is usual if you are in shortage of RAM.
Adafruit's libraries wastes lots of memory. You should be very careful to run their stuff if you are in shortage of memory.

I suggest you to try another library which quite old, but uses much lesser memory to read DHT sensor’s data:
https://github.com/markruys/arduino-DHT


body:
I am 2 years old in this Arduino world.
I am currently working on a project where I am about to make use of a fingerprint sensor. Now my question is that could we be able to make use of a sensor that we usually find in our mobile phones with ATmega328p microcontroller chip. And what if that there were no libraries written for Arduino so that will make my life easier. And I wonder how these tech companies make use of any sensor they would like to use without any trouble while there is no existing textbook that taught these employees while pursuing a degree in CSE or ECE about how to write code for a particular sensor. Now I know that there are certain protocols like SPI, I2C, UART, etc. But how do they do it, and how do they know about microcontrollers and IC's that were never taught to them in any degree or course? I always scratch my head while looking at the consumer electronics, and the IC's and Chips that they have on their PCB board were never found on google, And by chance, if an IC or microcontroller is found then I barely understand the datasheet or the documentation which was written in Chinese or some other language. I hope someone could help me understand how all this happens.

title: How to use any module that has no library for arduino?

Answers: 1

body:
About the fingerprint sensors from mobile phones: You might find the answers to [this question][1] useful. They explain in detail, why it is not really worth the effort to try interfacing such a fingerprint sensor with Arduino.

> How to use any module that has no library for arduino?

You need to read the datasheet of the module. It should explain in detail, how the module is used. When you understood, how it works, (and understanding it is really really important) you can start implementing it in code, for example by writing your own library. A library is just a wrapper around the interfacing code for that module. If the module uses common used interfaces or is even a commonly used component, you can often stand on the shoulders of giants by making use of other libraries in your library (for example using the Wire library in a library for a specific I2C sensor). That makes it easier.

> But how do they do it, and how do they know about microcontrollers and IC's that were never taught to them in any degree or course?

The engineers don't get taught to use specific controllers or ICs. They get taught the fundamental principles, including common interfaces like I2C, SPI, UART, I2S ... . In the end it all comes down to the datasheet of a component. It should explain all details, that are needed to use the component correctly, or at least reference to further documents. For example most microcontroller datasheets directly explain, how I2C is implemented in these microcontrollers. You can use that to implement I2C communication, even without a preexisting library. Yes, that can be a tedious and complex task, but it is totally possible. Keep in mind, that most Arduino libraries are not written by the manufacturer of the used component, but by third party people (sometimes the community, sometimes resellers like Adafruit, e.g.).

I would say "it is not rocket sience", but yes, it can be rather difficult to dig into the very detail of interfacing a component. Without considering myself an especially smart guy, I'm writing a library for multi-master I2C communication on Attiny's (without having any degree in that field). I could start with code from others, which made the entry easier. But it also involves much time, to dig into it, write the code and test it correctly. It is difficult, but it is possible.

> And by chance, if an IC or microcontroller is found then I barely understand the datasheet or the documentation which was written in Chinese or some other language.

Good manufacturers and resellers provide a datasheet in english for their products. That cannot be said for every product, that you can purchase. Writing documentation takes time and thus costs money. Chips directly from China (where most electronics is produced these days) might have less good or no documentation at all, though these chips are often way cheaper. As a hobbyist you should stick to the good documentated components, if you don't want to really dig into it.

> the IC's and Chips that they have on their PCB board were never found on google

PCB designs are only found in the internet, if they are published under some open source license (or if they were illegally leaked by someone). If a company doesn't want to publish it's product designs, that is totally ok.

About the components in consumer electronics: I think you refer to that the chips often don't have a googleable product number/marking to find a datasheet. That is because often these chips are custom chips, made maybe only for this company or even this specific product. Why would they want to publish a datasheet for it? They are not meant for public use for all. The design of components is often a good kept secret, that the companies are not willing to share, since it generates their revenue.

Hobbyists and small companies use publicly available, good and publicly documented parts to make their life and investment in the project easier. Big companies can easily hire people to design a custom chip, that will only contain the needed features. (With mass produced products you can save money this way, by not always needing to buy even the unused resources of a standard controller). Another reason to use a custom (maybe even a not programmable) chip is to keep the code in it secret.

---

All in all keep in mind, that the hobbyist world of Arduino and the world of consumer electronics like smart phones are rather different. Sure, they rely on the same principles, but the way, how things are done and created, is very different.

  [1]: https://arduino.stackexchange.com/questions/68807/interface-a-mobile-phones-finger-print-scanner-with-arduino/68810#68810


body:
I have NodeMCU & ST7789 TFT display. I want to generate QR Code of any dynamic input and display it on my TFT display. Not able to find any suitable reference. All Standard QR code libraries only work for Arduino & not for NodeMcu, board not supported for them. Can someone please help ?

Libraries Tried :
https://github.com/yoprogramo/ESP_QRcode
https://github.com/anunpanya/ESP8266_QRcode
https://github.com/ricmoo/qrcode
https://github.com/onelife/rtt-qrcode

title: Generate & Display QR using Nodemcu on TFT Display ST7789 240*240

Answers: 0


body:
Im a newbie and Im trying to interface the temperature sensor mlx90614 to the arduino due using i2c bus. After a lot of digging I found this code which works,but it works only on the sda(20),scl(21) pins. I want to change this to SCL1 and SDA1 near the Aref and gnd pins. How do i modify this code? Thanks

```
#include <Arduino.h>
#include <include/twi.h>

#define ADDR      0x5A

//EEPROM 32x16
#define TO_MAX    0x00
#define TO_MIN    0x01
#define PWM_CTRL  0x02

//RAM 32x16
#define RAW_IR_1  0x04
#define RAW_IR_2  0x05
#define TA        0x06
#define TOBJ_1    0x07
#define TOBJ_2    0x08

#define SYNC_PIN  2

static const uint32_t TWI_CLOCK = 100000;
static const uint32_t RECV_TIMEOUT = 100000;
static const uint32_t XMIT_TIMEOUT = 100000;

Twi *pTwi = WIRE_INTERFACE;

static void Wire_Init(void) {
  pmc_enable_periph_clk(WIRE_INTERFACE_ID);
  PIO_Configure(
  g_APinDescription[PIN_WIRE_SDA].pPort,
  g_APinDescription[PIN_WIRE_SDA].ulPinType,
  g_APinDescription[PIN_WIRE_SDA].ulPin,
  g_APinDescription[PIN_WIRE_SDA].ulPinConfiguration);
  PIO_Configure(
  g_APinDescription[PIN_WIRE_SCL].pPort,
  g_APinDescription[PIN_WIRE_SCL].ulPinType,
  g_APinDescription[PIN_WIRE_SCL].ulPin,
  g_APinDescription[PIN_WIRE_SCL].ulPinConfiguration);

  NVIC_DisableIRQ(TWI1_IRQn);
  NVIC_ClearPendingIRQ(TWI1_IRQn);
  NVIC_SetPriority(TWI1_IRQn, 0);
  NVIC_EnableIRQ(TWI1_IRQn);
}

static void Wire1_Init(void) {
    pmc_enable_periph_clk(WIRE1_INTERFACE_ID);
  PIO_Configure(
      g_APinDescription[PIN_WIRE1_SDA].pPort,
      g_APinDescription[PIN_WIRE1_SDA].ulPinType,
      g_APinDescription[PIN_WIRE1_SDA].ulPin,
      g_APinDescription[PIN_WIRE1_SDA].ulPinConfiguration);
  PIO_Configure(
      g_APinDescription[PIN_WIRE1_SCL].pPort,
      g_APinDescription[PIN_WIRE1_SCL].ulPinType,
      g_APinDescription[PIN_WIRE1_SCL].ulPin,
      g_APinDescription[PIN_WIRE1_SCL].ulPinConfiguration);

  NVIC_DisableIRQ(TWI0_IRQn);
  NVIC_ClearPendingIRQ(TWI0_IRQn);
  NVIC_SetPriority(TWI0_IRQn, 0);
  NVIC_EnableIRQ(TWI0_IRQn);
}

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

  pinMode(SYNC_PIN, OUTPUT);
  digitalWrite(SYNC_PIN, LOW);

  Wire_Init();
  // Disable PDC channel
  pTwi->TWI_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
  TWI_ConfigureMaster(pTwi, TWI_CLOCK, VARIANT_MCK);
}

void loop() {
  uint16_t tempUK;
  float tempK;
  uint8_t hB, lB, pec;

  digitalWrite(SYNC_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(SYNC_PIN, LOW);

  TWI_StartRead(pTwi, ADDR, TOBJ_1, 1);

  lB = readByte();
  hB = readByte();

  //last read
  TWI_SendSTOPCondition(pTwi);
  pec = readByte();

  while (!TWI_TransferComplete(pTwi))
    ;
  //TWI_WaitTransferComplete(pTwi, RECV_TIMEOUT);

  tempUK = (hB << 8) | lB;
  if(tempUK & (1 << 16))
  {
    Serial.print("Error !");
    Serial.println(tempK);
  }
  else
  {
    tempK = ((float)tempUK * 2) / 100 ;
    //Serial.print("Temp UK: ");
    //Serial.print(tempUK);
    Serial.print(" C: ");
    Serial.println(tempK - 273.15);
  }
  //Serial.print(hB, HEX);
  //Serial.print(" : ");
  //Serial.print(lB, HEX);
  //Serial.print(" : ");
  //Serial.println(pec, HEX);

  delay(2000);
}

uint8_t readByte() {
  //TWI_WaitByteReceived(pTwi, RECV_TIMEOUT);
  while (!TWI_ByteReceived(pTwi))
    ;
  return TWI_ReadByte(pTwi);
}

static inline bool TWI_WaitTransferComplete(Twi *_twi, uint32_t _timeout) {
  while (!TWI_TransferComplete(_twi)) {
    if (TWI_FailedAcknowledge(_twi))
      return false;
    if (--_timeout == 0)
      return false;
  }
  return true;
}

static inline bool TWI_WaitByteReceived(Twi *_twi, uint32_t _timeout) {
  while (!TWI_ByteReceived(_twi)) {
    if (TWI_FailedAcknowledge(_twi))
      return false;
    if (--_timeout == 0)
      return false;
  }
  return true;
}

static inline bool TWI_FailedAcknowledge(Twi *pTwi) {
  return pTwi->TWI_SR & TWI_SR_NACK;
}

title: Newbie trying to interface MLX90614 with Arduino Due

Answers: 0


body:
I am doing a [project][1] with Arduino, making a synthesizer, in which an LDR is used.

Before connecting the Arduino to a power source and use the project, do I need to calibrate the LDR like it is explained in Arduino [website][2] ?

  [1]: https://www.instructables.com/id/The-Arduino-Synthesizer/
  [2]: https://www.arduino.cc/en/tutorial/calibration

title: Do we have to calibrate LDR before using it in a project?

Answers: 2

body:
An LDR is a pretty inaccurate device. It just gives you a number which relates to darkness or brightness. How do those numbers relate to darkness and brightness? Well, only in a very vague way. All you can really say with any confidence is that bigger numbers mean brighter light, and smaller numbers mean darker darkness.

Even after "calibration" the numbers are pretty meaningless in any real-world sense.

All the "calibration" does is give a rough guide to the range of the numbers produced in any given lighting situation. It's then up to you to program your sketch in such a way that it works within the ranges of those numbers.

And yes, those numbers will change depending on the current lighting situation.

You could incorporate some form of "calibration" routine in your sketch to adjust any relevant values and calculations, or you could just provide some interface for tweaking values. Or your system may just really not care. It's impossible to know until you actually start creating your system.

body:
My application was a little different. My illumination/light source was fixed (and exact). I compensated the sensor for temperature. The results I obtained were very exact and repeatable.

Here are my temperature compensation results.

[![Temp Compensation of LDR sensor][1]][1]

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


body:
Below is  the code for getting a value from Firebase and sending the received data to arduino for performing necessary action.
The code here here sends a string ```"o"``` to arduino once
```
//uploaded to ESP8266
.
.
.
if (cu_st == "c")
  {
    sent = 0;
  }
  cu_st = Firebase.getString("feeder");
   if (cu_st == "o")
   {
    Serial.println("\t\trecd req to feed");
    if(sent == 0)
    {
      esp.print("o");
      sent =1;
      cu_st = "c";
      Serial.println("setting feeder to close in firebase");
      Firebase.setString("feeder" ,"c");

   }
.
.
.
```
Below is the code that gets the value, carries out necessary actions.

```
//uploaded to arduino
.
.
.
void feed_cmd()
{
  while(ArduinoUno.available())
  {
    char valve = ArduinoUno.read();
    Serial.print("feeder cmd recd ");
    Serial.println(valve);
    if(valve=='o')
    {
       digitalWrite(led, HIGH);
       //feeder.write(0); //open position
       open_time = millis();
       feeder = 1 ;
       Serial.println("I am opening feeder");
    }
  }
}

void close_feed()
{

  if(feeder == 1)
  {
   close_time = millis();
   if(close_time - open_time > 5000)
  {
    feeder = 0;
    digitalWrite(led , LOW);
    Serial.println("I am closing feeder") ;
  }
  }
}
.
.
.
```

My expectation/understanding is that:

```feed_cmd()``` continually checks for any data
As soon as it receives data LED turns ON and after 5 sec ```close_feed()``` turns OFF the LED.

But what happens is that the ```while()``` in ```feed_cmd()``` continually executes showing some random data and also all of what I said above is also being carried out! (pic attached)

[![showing data received][1]][1]

[![showing action taken][2]][2]

Why is there random serial data, even after sending only once and even after reading the sent data?

Is it bad coding / hardware?

Thanks for reading through and would really appreciate it if you can help me sort it out!!

__Edit__ I found this link [smthg abt pin voltages ][3] when I was looking for possible explanation for my code's behaviour, If somebody can simplify it and explain it, it'd be better !!

  [1]: https://i.stack.imgur.com/JdtZ1.jpg
  [2]: https://i.stack.imgur.com/ssvnG.jpg
  [3]: https://forum.arduino.cc/index.php?topic=356079.0

title: Random characters transmitted from ESP8266 to Arduino

Answers: 1

body:
The baud rates, voltages, and timing all have to match up for serial communication to work right.

So, set both of your devices to the same baudrate (you specify the number in Serial.begin()), and ensure they're connected properly. (voltages match, TX to RX, and ground is connected)

You can just read/print the serial input to the arduino with something like Serial.print(softSerial.read()) in your code if you think you don't have serial wired up right.

Also in an unrelated issue; the esp32 spits out data on its main serial line at 115200 when it boots up which you can not disable. you can use the serial port afterwards though.

Here's a copy of what gets printed out on one of mine;

    rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
    configsip: 0, SPIWP:0xee
    clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
    mode:DIO, clock div:1
    load:0x3fff0018,len:4
    load:0x3fff001c,len:1044
    load:0x40078000,len:8896
    load:0x40080400,len:5816
    entry 0x400806ac


body:
I have an Adafruit Ultimate GPS connected to a MEGA2560. I am trying to get the data from the buffer and do other data processing at the same time, however. when i allow other processing to be done the output becomes garbled such as below. the first out is correct and then becomes garbled and outputs now useful data.

16:34:54.466 -> $GPGGA,163453.155,,,,,0,00,,,M,,M,,*7F

16:34:57.111 -> $GPRMC,163453.155,V,,,,$GP$GPGGA,1$GPGGA,$GPGGA

```Arduino

    void loop()
    {

    GetTotalPressure();
      char c = GPS.read();
      Serial.print(c);
       if (GPS.newNMEAreceived()) {

        if (!GPS.parse(GPS.lastNMEA()))   // this also sets the newNMEAreceived() flag to false
          return;  // we can fail to parse a sentence in which case we should just wait for another
      }
      if (timer2 > millis())  timer2 = millis();

      if (millis() - timer2 > 1000) {
        timer2 = millis(); // reset the timer
    GPSScreenUpdate();
      SDcardSave();

      }
```

When GetTotalPressue is commented out The GPS serial output is correct when it is no the error above happens.

GetTotalPressure is below the sensor is connected to a I2C bus

    void GetTotalPressure() {
      Totalpressure = ms5611.readPressure();

Many Thanks

title: i am having Strange issues when trying to read form gps serial connection

Answers: 1

body:
You are not reading the GPS often enough. The method
`Adafruit_GPS::read()` is documented in the [comments embedded in the
source code][doc]:

> Read one character from the GPS device.
>
> Call very frequently and multiple times per opportunity or the buffer
> may overflow if there are frequent NMEA sentences. An 82 character
> NMEA sentence 10 times per second will require 820 calls per second,
> and once a loop() may not be enough. Check for newNMEAreceived() after
> at least every 10 calls, or you may miss some short sentences.
>
> returns: The character that we received, or 0 if nothing was available

Accessing the I2C bus makes `loop()` slower, slow enough that you get a
buffer overflow, as explained above. I suggest that, instead of reading
a single character per loop iteration, you read as many as are present
in the buffer:

```c++
void loop()
{
    GetTotalPressure();

    // Empty the GPS port receive buffer.
    while (GPS.available()) {
        char c = GPS.read();
        Serial.print(c);
    }

    // Parse any newly received NMEA sentence.
    if (GPS.newNMEAreceived()) {  // clears the newNMEAreceived flag
        if (!GPS.parse(GPS.lastNMEA()))
            return;
    }

    // Display and log location every second.
    if (millis() - timer2 > 1000) {
        timer2 = millis(); // reset the timer
        GPSScreenUpdate();
        SDcardSave();
    }
}
```

As an aside, I removed the line

```c++
if (timer2 > millis()) timer2 = millis();
```

which serves no useful purpose. If you are trying to detect `millis()`
overflows, [you are almost certainly doing something wrong][millis].

[doc]: https://github.com/adafruit/Adafruit_GPS/blob/96625de7d35302294ee648af6a050332e0d30186/src/Adafruit_GPS.cpp#L352-L359
[millis]: https://arduino.stackexchange.com/questions/12587/how-can-i-handle-the-millis-rollover


body:
I'm trying to use this version of ESP8266 to access MPU 6050. However, it's not working.

https://www.amazon.com/gp/product/B07HF44GBT/ref=ppx_yo_dt_b_asin_title_o07_s00?ie=UTF8&psc=1 i.e. NodeMCU CP2102 ESP-12E

The code worked with nano very fine. However, when I tried to scan the I2C device, it's said I2C device not found.

I have tried

      Wire.begin(D2, D1);

and

      Wire.begin(4, 5);
i.e. to change the pin to GIOP 4 5 in case if the default was not working.
I have also tried to put a large capacitor between the power lines, still not working.

Why ESP8266 does not work with MPU 6050?(Serial and wire together)

**Updates:**
Sometimes it does say device found, but after two updates, it turned to be not found again.

**Updates 2:**
I watched [the video][1] and did what G6EJD suggested, i.e. restarted the IDE and everything. Now it's reading data. However, the data reading was somehow incorrect by a large factor.
For example, at flat the device is reading

    42.63/-38.37/7.82

for angle x,angle y,and angular speed z with complementary filter applied and steady at flat surface. It worked for nano but not for ESP 8266.

Also, I tried to adjust the circuit like the spectrum dandavis suggested. I tried resistor range from 4.7 k to 10, even directly connect to the power source. The attempts also included 100 $\mu$F capacitor and power board to stabilize the noise. Both pull up and pull down has been attempted as well as changing boards. However, none of those were working and the issue persisted. The pull up resistor did not seem to be response to what the device was reading.

**Update 3:**
The power consumption has been ruled out and a pair of 100k resistor was also attempted. Not working.

  [1]: https://www.youtube.com/watch?v=F4lzRPF7o0I

title: ESP8266 not working with MPU 6050 over wire library and I2C

Answers: 2

body:
try to use

    Wire.begin(0x68);

instead of

      Wire.begin(D2, D1);

body:
I've been struggling with getting anything with the MPU6050's to work with either a D1 Mini or an older NodeMCU v1. I'm using D1/D2.
I've used the i2cdevlib MPU6050 library as well as the Electronic Cats' version.
I've used an assortment of sketches and even tried code which uses just Wire (no MPU6050 specific libs).
* The best I've been able to get is the Electronic Cats MPU6050 library, without DMP, where at least it thinks the MPU6050 has been connected to, but it just puts out 0's as raw values.
* The second "best", maybe, was some code that just used plain Wire, but except for Wire.endTransmission() returning success (and I had to slow loop() down for that), its numbers are gibberish (either 0's, or Z will just increment.  Nothing is affected by the movement of the board itself).

The DMP versions always fail to initialize the DMP.
I've tried 8.2k and 4.1k pullups on D1 and D2.

It works fine on an atmega32u4-based Pro Micro 16.


body:
Consider the following:

    #define IN1 9
    #define IN2 10

    pinMode(IN1, OUTPUT);
    pinMode(IN2, OUTPUT);

    void LeftMotor(Direction direction) {
      digitalWrite(IN1, direction == Forward ? LOW : HIGH);
      digitalWrite(IN2, direction == Forward ? HIGH : LOW);
    }

How can I modify the `LeftMotor` method to achieve the same result without using digitalWrite?

title: How can I set up outputs without using digitalWrite?

Answers: 4

body:
Setting ports directly is a great way to learn AVR programming. I might recommend this book [Make: Avr Programming.][1]

  [1]: https://www.amazon.com/AVR-Programming-Learning-Software-Technology/dp/1449355781

First you need to set the direction of the port in the Data Direction Register as either input or output. If Input, check its state and handle it. Here is a small example.

    #define HIGH 1
    #define LOW 0

    #define  SWI_PIN PORTB0
    #define  BUTTON PORTB4

    int main (void)
    {
        // set the pin directions
        DDRB |=  (1 << SWI_PIN); // output
        DDRB &= ~(1<<PORTB4); //input
        while(true){

          if ((PINB & (1<<BUTTON)) == 0){ // pin is high! Rising edge
              PORTB &= ~(1<<SWI_PIN); // LOW turn off swi_pin
          }else {
              PORTB |= (1<<SWI_PIN); // HIGH  turn on swi_pin
          }

    }

body:
`digitalWrite()` is just a convenience function to hide away complexity from the user, so that she/he can just use a pin number and a value. This complexity takes some time to execute. If this is too slow for you, you need to go a bit deeper into the rabbit hole and use direct port manipulation:

Inside the microcontroller on the Arduino all the special functions for peripherals and such (digital IO, ADC, Serial(UART), SPI, Timer, ...) are configured via Special Function Registers (SFR). These are specific memory places, that are directly connected to the peripherals. You can configure the whole microcontroller by setting these registers to specific values.

For digital IO you first need to know, that the microcontrollers pins are ordered into groups of max 8 pins. These groups are called Ports. Each available port of the microcontroller gets a character, like PORTB. On the Arduino Nano for example PORTD includes the pins 0 to 7.

For each port we have 3 different SFRs (with the x being the character for the corresponding port), where each bit inside the registers corresponds to one pin:

- `DDRx` controls the direction of the pins. If you set a bit to 1 in there, the corresponding pin is set as output. If you set it to zero, the pin will be an input (which is also called High-Z for high impedance, because a digital input pin has a very high resistance).

- `PORTx` controls the output hardware of the digital pins. If you have set a pin as output (as described above) you can use the corresponding bit in the `PORTx` register to set it's state. If you write a 1 to the bit, the pin will become HIGH (means, the voltage on the pin will go to the same level as Vcc, the supply voltage of the micrcontroller). If you write a zero, the pin will go to LOW (meaning the same level as ground). The `PORTx` register has a different function, when you configured a pin as input. In this case, a 1 will turn on the interal pullup resistor of the pin, which pulls the level of the pin to HIGH, when nothing is pulling it down to ground (like a switch for example). A zero disables the pullup.

- `PINx` reflects the current state of the pins. If you configured the pins as input, this is the voltage level, that currently lies at the corresponding pin (about the actual voltage levels, see below). A 1 at a bit means, that the corresponding pin is HIGH, else it is LOW.

You can read all of this in the datasheet of the used microcontroller. The datasheet is a must read (at least the relevant chapters), if you want to control the microcontroller via its registers. In most microcontrollers these registers are named as above. But some microcontrollers might define other names. The corresponding datasheet will list all the registers with rather detailed descriptions.

Now let's take that knowledge into actual code. Here I assume an Arduino Nano, though you can exchange that for most other microcontrollers.

    // Configure pin D3 as output
    DDRD |= (1 << PD3);
    // Configure pin D2 as input
    DDRD &= ~(1 << PD2);
    // Check, if pin D2 is HIGH
    if(PIND & (1 << PD2)){
        // Set pin D3 to HIGH
        PORTD |= (1 << PD3);
    } else {
        // Set pin D3 to LOW
        PORTD &= ~(1 << PD3);
    }

---

**Excourse on bitwise operators:** The code above can only be understood by knowing bitwise operators, which are very important for direct port manipulations. I will break down the operations, that are done there:

- First we have `PD2` and `PD3`. These are defines from the Arduino core. They are set to the index of the bit, that corresponds to the named pin. So `PD2` is defined as 2, `PD3` is defined as 3, `PD0` as 0.

- `1 << PD3`: The `<<` operator does a bitwise left shift, which means all bits of the value on the left are shifted to the left by the amount standing on the right of the operator. We shift the value 1 three digits to the left here. In binary that looks like this:

        0b00000001 << 3 = 0b00001000

    That set bit in the result is exactly at the place, where the bits for pin PD3 will be in the Special Function Registers.

- `DDRD |= (1 << PD3)`:  This is the same as doing `DDRD = DDRD | (1 << PD3)`, so the `|=` operator is just an abbreviation for it. The bitwise OR operator `|` will unite the bits from both sides. If a bit is set to 1 at either side, the result will also have set this bit to 1. This means, that we can set a bit to 1 with this.

- `~(1 << PD2)`: The tilde `~` takes the inversion of the data. Alike above, the value inside the paranthesis can be written as binary value `0b00000100`. The inversion will flip all bits to the other value: `0b11111011`

- `DDRD &= ~(1 << PD2)`: The abbreviation is similar to the above. The bitwise AND operator `&` will also unite the bits of the values around it, but it will only set the resulting bits to 1, if both of the corresponding bits of the values are also set. Here this results in the third bit (the one for D2) being cleared to zero. All other bits (where you can see a 1 at the right value) are left untouched.

- `PIND & (1 << PD2)`: This is similar to the above, but now we don't have an inversion. We are doing `PIND & 0b00000100` here. All bits of the result will be set to zero, except for the bit for D2. It will only be zero, if the corresponding bit was zero in `PIND`. Thus we have isolated the needed bit by this way.

You can also combine the same operations on a single register. Let's say we want to set both D2 and D3 as output. Then we can either write this as two seperate statements

    DDRD |= (1 << PD2);
    DDRD |= (1 << PD3);

or we can combine them into one statement by connecting them with the bitwise OR

    DDRD |= (1 << PD2) | (1 << PD3);

---

The [Arduino documentation][1] also provides a site to explain direct port manipulation. Also again you should take the time to look into the datasheet of your used microcontroller. At first it will seems very difficult, but doing these direct port manipulations is a great way of learning how to use the SFRs, and then you can do all sorts of cool stuff with your microcontroller. So it really is worth it. You don't need to read or understand the whole datasheet at once.

---

> How can I modify the LeftMotor method to achieve the same result without using digitalWrite?

After all this text now to the specific question. On the Nano pin 9 and 10 are PB1 and PB2. You used a conditional inside your `digitalWrite()` statement, which I will replace by a complete if statement here. So you can use

    if(direction == Forward){
        PORTB &= ~(1 << PB1);
        PORTB |= (1 << PB2);
    } else {
        PORTB |= (1 << PB1);
        PORTB &= ~(1 << PB2);
    }

instead of your two `digitalWrite()` statements.

  [1]: https://www.arduino.cc/en/Reference/PortManipulation

body:
chrisl provided a very good reference answer. Here I am just adding a
few bits of information about the pin mapping and the pin electrical
states.

## Pin mapping

One of the firs things you need when dealing with direct port access is
the mapping between the Arduino pin names and the names of the
microcontroller (MCU) pins as given by the manufacturer. For the Arduino
Nano the mapping is the following:

```text
 Arduino │ MCU
─────────┼─────
   RX0   │ PD0
   TX1   │ PD1
   D2    │ PD2
        ...
   D7    │ PD7
   D8    │ PB0
        ...
   D13   │ PB5
   A0    │ PC0
        ...
   A5    │ PC5
```

where “PD0” means “pin number 0 of port D” and so on. Notice that pins
A6 and A7 are not listed here, as they are analog only, with no digital
I/O capability.

The information above can be found on the product page of the board,
under the “Documentation” tab. Alternatively, an image search for
“Arduino <board name> pinout” will find some nice schematics like
the one below:

[![Arduino Nano pinout][1]][1]

## Pin states

This has already been covered by chrisl's answer in the description of
the `DDRx` and `PORTx` registers. Below is a summary table showing the
four available electrical states of the pins, and how they are selected
with the DDR and PORT bits:

```text
 DDR │ PORT │ electrical state │ equation
─────┼──────┼──────────────────┼─────────────────
  0  │   0  │  INPUT (high-Z)  │ I = 0
  0  │   1  │  INPUT_PULLUP    │ V = Vcc − Rpu I
  1  │   0  │  OUTPUT LOW      │ V = 0
  1  │   1  │  OUTPUT HIGH     │ V = Vcc
```

The provided equations relate the output voltage (V) and the output
current (I) of the pin. Beware that these are just rough approximations,
as:

 * they neglect the output resistance, which is of the order of
   25 Ω
 * an input pin can have some (sub-µA) leakage current
 * the pullup resistor is not completely linear
 * the datasheet only provides weak guaranties, such as a range for the
   output voltage, conditioned on the output current being low enough.

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

body:
> How can I set up outputs without using digitalWrite?

So this question is actually about the fastest possible implementation of digitalWrite.

As described in other answers this can be achieved by using direct port manipulation. But there are actually libraries (for instance, https://github.com/mikaelpatel/Arduino-GPIO) that does this in a portable way and avoids some of the errors that can occur. The library is 10-100X faster than the Arduino core digital pin functions.

Pins in a MCU are organized in ports. On the AVR there are a set of 8-bit port registers that hold the current pin setting. To change the value of a pin the CPU has to read the register and change the corresponding bit associated with the pin. This has to be done as an atomic operation, i.e. an interrupt may not occur during the update of the port register.

To allow a very fast update, i.e. one instruction/1-2 clock cycle, the CPU has a set of special instructions. For the AVR there are bit set and clear instructions for the 32 first special registers. On the Arduino Mega some of the pins/ports have higher address special registers and cannot use the special instructions. To make the pin operation atomic explicit interrupt handling must be added.

Other issues with direct port manipulation is portability. Code written using the AVR io handling cannot be used on SAM (e.g. Arduino Due). There is actually even issues when changing between AVR MCUs.

In short, a portable faster implementation of digital pin functions is recommended.

Below is the code written with the [GPIO][1]. It is portable and as fast as direct port manipulation.

    #include "GPIO.h"

    GPIO<BOARD::D9> IN1;
    GPIO<BOARD::D10> IN2;

    IN1.output();
    IN2.output();

    void LeftMotor(Direction direction) {
      IN1 = (direction == Forward ? LOW : HIGH);
      IN2 = (direction == Forward ? HIGH : LOW);
    }

or

    void LeftMotor(Direction direction) {
      IN1 = direction != Forward;
      IN2 = direction == Forward;
    }

or

    void LeftMotor(Direction direction) {
      if (direction == Forward) {
        IN1.low();
        IN2.high();
      }
      else {
        IN1.high();
        IN2.low();
      }
    }

  [1]: https://github.com/mikaelpatel/Arduino-GPIO


body:
I'm using the same script(and standard wire and serial library only) one uploaded to Arduino nano one uploaded to ESP8266. However, despite ESP8266 running at 160MHz, 10 times faster than nano, it's taking 3.5 ms to complete the loop, compare to 2.5 ms than that of nano.

How could that be?  why ESP8266 was slower?

title: Why ESP8266 slower than Arduino nano?

Answers: 1

body:
> However, despite ESP8266 running at 160MHz, 10 times faster than nano, it's taking 3.5 ms to complete the loop, compare to 2.5 ms than that of nano.

There's a number of reasons for that. Chiefly:

1. The ESP8266 has no I2C hardware, so has to use software "bit-banging" to emulate I2C. That is slower to execute.
2. The ESP8266 also has to manage the WiFi hardware which takes a portion of the processing power away from the user

The result is slower execution for I2C operations and "jitter" added to timings of loops and such.

> will the same thing (wire) happen to esp32?

No (or not as much). The ESP32 has hardware I2C so it doesn't need to use bit-banging to emulate it, so it will be faster. Also it is dual core and one core is used for "system management" including managing the WiFi and Bluetooth, while the second core is used to execute your sketch, so there is no (or little1) interruption by the WiFi slowing down your sketch.

----

1: Two cores accessing the same area of RAM causes some contention as only one core can access the same block of RAM at a time, so it's not perfect. You may still get slight delays, but they will be minuscule compared to the processing needed for the ESP8266's WiFi code.


body:
I have an RFID shield connected to my Arduino Uno, but I want it to be able to send keystrokes to the computer when I scan the correct card. I have the Uno set up correctly so that when the card is scanned and verified it would send a 1 to the Leonardo. But when I have tried to receive the data using I2C, Leonardo doesn't get it. What could I try next?

This is the master code or the code that is sending the information. (On the Arduino Uno)
```
// Include the required Wire library for I2C<br>#include
int x = 0;
void setup() {
  // Start the I2C Bus as Master
  Wire.begin();
}
void loop() {
  Wire.beginTransmission(9); // transmit to device #9
  Wire.write(x);              // sends x
  Wire.endTransmission();    // stop transmitting
  x++; // Increment x
  if (x > 5) x = 0; // `reset x once it gets 6
  delay(500);
}
```
and this is the slave code (on the Leonardo)
```
// Include the required Wire library for I2C<br>#include <Wire.h>
int LED = 13;
int x = 0;
void setup() {
  // Define the LED pin as Output
  pinMode (LED, OUTPUT);
  // Start the I2C Bus as Slave on address 9
  Wire.begin(9);
  // Attach a function to trigger when something is received.
  Wire.onReceive(receiveEvent);
}
void receiveEvent(int bytes) {
  x = Wire.read();    // read one character from the I2C
}
void loop() {
  //If value received is 0 blink LED for 200 ms
  if (x == '0') {
    digitalWrite(LED, HIGH);
    delay(200);
    digitalWrite(LED, LOW);
    delay(200);
  }
  //If value received is 3 blink LED for 400 ms
  if (x == '3') {
    digitalWrite(LED, HIGH);
    delay(400);
    digitalWrite(LED, LOW);
    delay(400);
  }
}
```

title: Connecting Arduino Uno to Arduino Leonardo

Answers: 0


body:
![enter image description here](https://i.stack.imgur.com/lV1ig.jpg)![enter image description here](https://i.stack.imgur.com/MO6Xp.jpg)
I've already burned it for 24 hours and it is now giving the constant value of 932.36,pls tell me how to calculate the RZERO value.

title: How to calculate the RZERO value in MQ135 sensor, I have already burned it for 24 hours?

Answers: 1

body:
From the datasheet here --->[MQ135 datasheet][1], It is the value of Sensing resistor at 100 PPM of Ammonia(NH3) or from the graph in Fig. 3, you can use gases that has y intercept as 1 and appropriate concentration, i.e you need atleast some known parameter to get it. The legend in the graph is also not clear (as far as getting the values from the Log - Log graph, there are tutorials in youtube).

I'm also in need of solution to this, so far this is what I read on the internet... You need a chemistry lab to do it !!!

  [1]: https://www.olimex.com/Products/Components/Sensors/Gas/SNS-MQ135/resources/SNS-MQ135.pdf


body:
I'm using a Let's Start Coding Ultimate Kit 1 (it was a christmas present, don't ask) and I'm trying to use this as a typing sort of thing. I haven't implemented the actual letters though.
```c++
#include <MakerScreenXVI.h>;

MakerScreenXVI lcd;

int currentNumber = 1;
int ms = 0;
int totalMS = 0;
bool first = false;

void setup() {
  // put your setup code here, to run once:
  pinMode(A0, INPUT);
  pinMode(A3, INPUT);

  lcd.begin();
  lcd.print("Success");
  lcd.setCursor(0,1);
  lcd.print(currentNumber);

}

void loop() {
  delay(200);
  changeNumber();
  delay(200);
}

void clearLCDLine(int line) {
        lcd.setCursor(0,line);
        for(int n = 0; n < 16; n++) // 20 indicates symbols in line. For 2x16 LCD write - 16
        {
                lcd.print(" ");
        }
}

void changeNumber() {
  if (digitalRead(A0) == LOW) {
    if (first == false) {
      clearLCDLine(1);
      first = true;
    } else {
      first = false;
    }
    currentNumber++;
    if (currentNumber == 27) {currentNumber = 1;}

    lcd.print(currentNumber);
  } else if (digitalRead(A3) == LOW) {
    currentNumber = currentNumber - 1;
    if (currentNumber == 0) {currentNumber = 26;}
    //clearLCDLine(1);
    lcd.print(currentNumber);
  }
}
```

For some reason, after it deletes the 1, it stops. Nothing is printed onto the screen, and nothing is cleared from it. How can I fix this?
Also, the buttons always return the ```LOW``` value. How can I fix this?

title: loop() either stops working, or lcd stops working | buttons don't work

Answers: 1

body:
The buttons will send a LOW signal when pressed if they are set with pinMode INPUT_PULLUP.

The issue with currentNumber not displaying is that after you clear the screen with the 'for' loop, you need to reset the cursor to position 0,1 with `lcd.setCursor(0,1);` . Otherwise, the numbers are printing out of view.

If I add `lcd.setCursor(0,1);` just above each line with `lcd.print(currentNumber);` , I think the code has the behavior you're looking for.

**Edit from the person who asked the question:**
<br> You also have to add a delay of around 150-200, or else one push will count as many.


body: I have a question .. Please help me I don't know how Arduino can read the peak value of the sensor signal. The value I want is in the ADC value .. What I want is ... for 5 seconds there will be 1 average value from the highest peak value of the sensor, and the ADC value. I will use pin A0, but I don't know how to code the program that I want. Please help me What is the code?

title: How to find the peak value of analog signal?

Answers: 1

body:
See if I understand this correctly: For a given time period you want to find the peak.

```
void setup()
{
  unsigned long int cur_time = 0 ;
  unsigned long int time_elapsed = 0;
  int peaks[20]; // say you want to find 20 peaks , 1 peak for data arriving between 5 secs
  int time_period = 5000;
  int data = 0;
  int mx=0;
}

void loop()
{
   for(int i = 0 ; i<20;i++)
   {
      cur_time = millis();
      while(cur_time - time_elapsed <=time_period)
      {
             if(mx==0)
              { mx = analogRead(A0); }
              else:
               {  data = analogread(A0);
                  mx = max(data , mx);
               }
              cur_time = millis();
        }
         time_elapsed = cur_time;
         peaks[i] = mx;
         mx = 0;
        }
  }
```
Hope this helps!!