text:
Receiving "ERROR: Timeout waiting for client." when connecting to a single table in database - mysql connector on Arduino Uno Wifi Rev2
I have a MariaDb database on a local server and I am using it to store data from various Arduino's around my shop. The database currently has 12 tables. I also have another Arduino Uno Wifi Rev2 that is able to connect to its two respective tables; it collects set point information from one table and inserts data perfectly into the other.
The Arduino I'm having a problem with can insert data perfectly fine into its data table (veg2_data) but fails when trying to select data from it's sp table (veg2_sp). It can also connect to any of the other tables in my database, including the one for the first Arduino. Only veg2_sp is malfunctioning.
Here is my code:
#include <SPI.h>
#include <WiFiNINA.h>
#include <MySQL_Connection.h>
#include <MySQL_Cursor.h>
#include "config.h"
//Node Libraries
#include <DHT.h>

#define O_UPPER 9
#define O_LOWER 10

//Wifi
byte mac_addr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //Do I need this?
char ssid[] = CONFIG_SSID;
char pass[] = CONFIG_PASS;
int status = WL_IDLE_STATUS;
int keyIndex = 0;
WiFiClient client;

//MySQL
IPAddress server_addr(192, 168, 1, 133);
char user[] = CONFIG_MYSQL_USER;
char password[] = CONFIG_MYSQL_PASS;
char db[] = CONFIG_MYSQL_DB;
char query[128];
char DATA_QUERY[] = "INSERT INTO veg2_data VALUES (now(), %d, %d, %s, %s, %s, %s, %s, %s, %d);";
char SP_QUERY[] = "SELECT * FROM veg2_sp ORDER BY timestamp DESC LIMIT 1;";
char rawTime[30];
byte refreshRate = 1;
uint32_t dbContactTimer;
MySQL_Connection conn((Client *)&client);
MySQL_Cursor cur = MySQL_Cursor(&conn);

//Node Specific
bool o_UpperState, o_LowerState, daytime = 0;
byte dayTempSP = 25, dayHumiditySP = 30, nightTempSP = 10, nightHumiditySP = 20,
     o_UpperLock = 0, o_LowerLock = 0, sunrise = 7, sunset = 19;
int soilMoisture;
float intakeTemp, intakeHum, roomTemp, roomHum, exhaustTemp, exhaustHum ;
char intakeTempArray[7], intakeHumArray[7], roomTempArray[7], roomHumArray[7],
     exhaustTempArray[7], exhaustHumArray[7];

DHT exhaust(6, DHT11);
DHT intake(7, DHT11);
DHT room(8, DHT11);

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

  exhaust.begin();
  intake.begin();
  room.begin();

  pinMode(O_UPPER, OUTPUT);
  pinMode(O_LOWER, OUTPUT);
  digitalWrite(O_UPPER, LOW);
  digitalWrite(O_LOWER, LOW);

  //spCheck();
  dbContactTimer = millis();
}

void loop() {

  //Default refesh rate is 5 seconds. Some nodes need to increase refesh rate at specific times
  if (millis() - dbContactTimer >= (refreshRate * 1000)) {
    dbUpdate();
    spCheck();

    //If set to auto (2), my lights will turn on and off depending on day/night. Currently unfinished
    if (o_UpperLock == 2) {
      if (daytime) {
        digitalWrite(O_UPPER, HIGH);
        o_UpperState = 1;
      }
      else {
        digitalWrite(O_UPPER, LOW);
        o_UpperState = 0;
      }
    }
    dbContactTimer = millis();
  }

}

//------------------------------------MySql Functions-------------------------
void spCheck() { //Updates setpoints
  if (!conn.connected()) {
    conn.close();
    if (!conn.connect(server_addr, port, user, password, db)) {
      return 0;
    }
  }
  row_values *row = NULL;
  cur.execute(SP_QUERY);
  column_names *columns = cur.get_columns();
  do {
    row = cur.get_next_row();
    if (row != NULL) {
      //Serial.println(row->values[0]);
      o_UpperLock = atol(row->values[1]);
      //o_LowerLock = atol(row->values[2]);
      //dayTempSP = atol(row->values[3]);
      //dayHumiditySP = atol(row->values[4]);
      //nightTempSP = atol(row->values[5]);
      //nightHumiditySP = atol(row->values[6]);
      //sunrise = atol(row->values[7]);
      //sunset = atol(row->values[8]);
    }
  } while (row != NULL);

  if (o_UpperLock < 2) {
    if (o_UpperLock) {
      digitalWrite(O_UPPER, HIGH);
      o_UpperState = 1;
    }
    else {
      digitalWrite(O_UPPER, LOW);
      o_UpperState = 0;
    }
  }
  return 1;
}

void dbUpdate() { //Updates data
  if (!conn.connected()) {
    conn.close();
    if (!conn.connect(server_addr, port, user, password, db)) {
      return 0;
    }
  }

  intakeTemp = intake.readTemperature();
  dtostrf(intakeTemp, 4, 2, intakeTempArray);

  intakeHum  = intake.readHumidity();
  dtostrf(intakeHum, 4, 2, intakeHumArray);

  roomTemp = room.readTemperature();
  dtostrf(roomTemp, 4, 2, roomTempArray);

  roomHum = room.readHumidity();
  dtostrf(roomHum, 4, 2, roomHumArray);

  exhaustTemp = exhaust.readTemperature();
  dtostrf(exhaustTemp, 4, 2, exhaustTempArray);

  exhaustHum = exhaust.readHumidity();
  dtostrf(exhaustHum, 4, 2, exhaustHumArray);

  soilMoisture = analogRead(A0);

  sprintf(query, DATA_QUERY, o_UpperState, o_LowerState, intakeTempArray,
          intakeHumArray, roomTempArray, roomHumArray, exhaustTempArray, exhaustHumArray, soilMoisture);
  cur.execute(query);

  return 1;
}

void wifiInit() {

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("No wifi Module - Abort");
    while (true);
  }
  while (status != WL_CONNECTED) {
    Serial.println("Connecting to wifi");
    for (byte i = 0; i < 2; i++) {
      digitalWrite(LED_BUILTIN, HIGH);
      delay(2000);
      digitalWrite(LED_BUILTIN, LOW);
      delay(1000);
    }
    status = WiFi.begin(ssid, pass);
  }

  IPAddress ip = WiFi.localIP();
  long rssi = WiFi.RSSI();
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  Serial.print("IP Address: ");
  Serial.println(ip);
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

The problem is with the SP_QUERY. I can change the table to any other in my database, and the code functions fine. If I read from veg2_sp, I get the error.
Tables: The first one is the one Im having problems with, the second is the one that is currently functioning.

I'm utterly baffled.

firewall on PC?

I thought so too, but I can still connect to the other table in the database. If I couldn't connect to anything, I'd agree, but what is stopping me from accessing a single table??

Just put in a little delay.
cur.execute(SP_QUERY);

delay(5);

column_names *columns = cur.get_columns();


text:
nRF24L01 using sender as receiver and vice versa with RF24 library
I have two nRF24L01 modules (I tried 2 with antenna and 2 without antenna) paired with their power base module and connected to two different Arduino Mega 2560 boards.
I'm able to send from one module to another up to 32 bytes of data and get the acknowledge without any problems. But when I switch them, when I try to send data from receiver and receive it on the sender I have nothing. No data received, no acknowledge sent as response.
As I said before, first part of this code works well, but when it comes to the second part, which is after delay(1000); there's silence.
Here is my code:
**Receiver**

    #include <RF24.h>
    #include <RF24_config.h>
    #include <SPI.h>
    #include "printf.h"

    // Set pipes
    const uint64_t pipe01_ = 0xE8E8F0F0A1LL;
    const uint64_t pipe02_ = 0xE8E8F0F0A2LL;
    const uint64_t pipe03_ = 0xA3LL;
    const uint64_t pipe04_ = 0xA4LL;
    const uint64_t pipe05_ = 0xA5LL;
    const uint64_t pipe06_ = 0xA6LL;

    RF24 radio(9, 53);

    void setup()
    {
        Serial.begin(115200);
        delay(250);
        radio.begin();
        radio.setChannel(0x57);
        radio.setPALevel(RF24_PA_LOW);
        radio.enableAckPayload();
        radio.openReadingPipe(1, pipe01_);
        radio.openWritingPipe(pipe02_);
        radio.enableDynamicPayloads();
        radio.startListening();
    }

    void loop()
    {
        if (radio.available())
        {
            char newMessage[33];
            memset(newMessage, 0, sizeof(byte) * 33);
            while (radio.available())
            {radio.read(newMessage, 32);}

            Serial.println("newMessage: " + String((const char*)newMessage));
            delay(1000);
            radio.stopListening();

            char response[32] = "1234567890qwertyuiopasdfghjklzxc";
            radio.write(response, 32);
            unsigned long ack = 0;
            if (radio.isAckPayloadAvailable())
            {
                radio.read(&ack, sizeof(ack));
                Serial.println("ack: " + String(ack));
            }
            radio.startListening();
        }
    }

**Sender**

    #include <RF24.h>
    #include <RF24_config.h>
    #include <SPI.h>
    #include "printf.h"
    // Set pipes
    const uint64_t pipe01_ = 0xE8E8F0F0A1LL;
    const uint64_t pipe02_ = 0xA2LL;
    const uint64_t pipe03_ = 0xA3LL;
    const uint64_t pipe04_ = 0xA4LL;
    const uint64_t pipe05_ = 0xA5LL;
    const uint64_t pipe06_ = 0xA6LL;

    RF24 radio(9, 53);

    void setup()
    {
        Serial.begin(115200);
        delay(250);
        radio.begin();
        radio.setChannel(0x57);
        radio.setPALevel(RF24_PA_LOW);
        radio.enableAckPayload();
        radio.openReadingPipe(2, pipe02_);
        radio.openWritingPipe(pipe01_);
        radio.enableDynamicPayloads();
        radio.stopListening();

        char message[32] = "qwertyuiopasdfghjklzxc1234567890";
        radio.write(message, 32);

        radio.startListening();
    }

    void loop()
    {
        if (radio.available())
        {
            char respMessage[33];
            memset(respMessage, 0, sizeof(byte) * 33);
            while (radio.available())
            {radio.read(respMessage, 32);}

            Serial.println("respMessage: " + String((const char*)respMessage));
        }
    }

Please help me.

The string qwertyuiopasdfghjklzxc1234567890 contains 32 characters plus an implicit null terminator - for which there is no space in the array. It would be safer to declare this as char message[] = "...". You might suffer from corrupted memory here.

Update: It was working yesterday, but today... same thing as with "delay()". What's wrong with these radio-modules??
I have discovered that the delay() function was causing this abnormal behavior.
So I have implemented periods instead of delay() and now I'm able to switch operating mode between "receiver" and "transmitter". Moreover, I have discovered few additional conditions that must be met (read the comments for the code).
Below is working sample code where transmitter sends some large message. Receiver gets it, waits 2 secs, then responds with another large message and gets the acknowledge for this message:
Sender
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>
#include "printf.h"
const uint64_t pipe01_ = 0xE8E8F0F0A1LL; //Writing pipe must be full address if acknowledges will be used
const uint64_t pipe02_ = 0xE8E8F0F0A2LL; //At least one of reading pipes must be full adress
const uint64_t pipe03_ = 0xA3LL;
const uint64_t pipe04_ = 0xA4LL;
const uint64_t pipe05_ = 0xA5LL;
const uint64_t pipe06_ = 0xA6LL;
RF24 radio(9, 53);

void setup()
{
    Serial.begin(115200);
    delay(250);
    radio.begin();
    radio.setChannel(0x57); //not necessary. But must be equal at both sides
    radio.setPALevel(RF24_PA_LOW); //not necessary. But must be equal at both sides
    radio.enableAckPayload(); //For ability to change the Ack Payload with writeAckPayload()
    radio.openReadingPipe(2, pipe02_); //At least one of reading pipes must be full adress
    radio.openWritingPipe(pipe01_); //Writing pipe must be full address if acknowledges will be used
    radio.enableDynamicPayloads(); //If not set, size will be of fixed length. Default fixed length is 32 bytes

    /*Must run this if "startListening()" will be used anywhere in the code below.
    nRF24L01 remembers it's state even if Arduino was restarted*/
    radio.stopListening();
    Serial.println("Sending the message...");
    char message[32] = "qwertyuiopasdfghjklzxc1234567890"; //some test message
    radio.write(message, 32); //Send message over the predefined "writing pipe"

    Serial.println("Waiting for response...");
    radio.startListening(); //Resets TX buffer and switches radio module's mode to "receiver"

    uint16_t ack = 123;
    radio.writeAckPayload(2, &ack, sizeof(ack)); //Custom ACK payload must be set after "startListening()". Because "startListening()" resets TX buffer
}

void loop()
{
    if (radio.available())
    {
        char respMessage[33];
        memset(respMessage, 0, sizeof(byte) * 33);
        while (radio.available())
        {radio.read(respMessage, 32);}

        Serial.println("respMessage: " + String((const char*)respMessage));
    }
}

Receiver
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>
#include "printf.h"

#define period_  2000

// Set pipes
const uint64_t pipe01_ = 0xE8E8F0F0A1LL; //At least one of reading pipes must be full adress
const uint64_t pipe02_ = 0xE8E8F0F0A2LL; //Writing pipe must be full address if acknowledges will be used
const uint64_t pipe03_ = 0xA3LL;
const uint64_t pipe04_ = 0xA4LL;
const uint64_t pipe05_ = 0xA5LL;
const uint64_t pipe06_ = 0xA6LL;

unsigned long checkPoint = 0;
bool messageReceived = false;
RF24 radio(9, 53);

void setup()
{
    Serial.begin(115200);
    delay(250);
    radio.begin();
    radio.setChannel(0x57); //not necessary. But must be equal at both sides
    radio.setPALevel(RF24_PA_LOW); //not necessary. But must be equal at both sides
    radio.enableAckPayload(); //For ability to change the Ack Payload with writeAckPayload()
    radio.openReadingPipe(1, pipe01_); //At least one of reading pipes must be full adress
    radio.openWritingPipe(pipe02_); //Writing pipe must be full address if acknowledges will be used
    radio.enableDynamicPayloads(); //Writing pipe must be full address if acknowledges will be used
    radio.startListening(); //If not set, size will be of fixed length. Default fixed length is 32 bytes
}

void loop()
{
    if (radio.available())
    {
        char newMessage[33];
        memset(newMessage, 0, sizeof(byte) * 33);
        while (radio.available())
        {radio.read(newMessage, 32);}

        Serial.println("newMessage: " + String((const char*)newMessage));
        checkPoint = millis();
        messageReceived = true;
    }

    unsigned long timePassed = millis() - checkPoint;

    //When it receives, controller waits for 2 seconds then sends the response just one time
    if (messageReceived && timePassed > period_)
    {
        messageReceived = false;
        checkPoint = millis();
        Serial.println("sending response...");

        //This must be called before sending anything (except acknowledges)
        radio.stopListening(); //Resets TX buffer and switches radio module's mode to transmitter

        char response[32] = "1234567890qwertyuiopasdfghjklzxc";
        radio.write(response, 32);

        unsigned long ack = 0;
        if (radio.isAckPayloadAvailable())
        {
            radio.read(&ack, sizeof(ack));
            Serial.println("ack received: " + String(ack));
        }

        radio.startListening(); //Resets TX buffer and switches radio module's mode to "receiver"
    }
}

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
How to manage variable I2C read lengths requiring address incrementation (Wire/I2C/EEPROM IC emulation)
The question is about how to have information/control of a variable length read for an Arduino acting as a slave device.
The concrete context is that I want to emulate an EEPROM IC.
A byte write to the EEPROM's address sets the internal EEPROM address to start reading from.
The subsequent read from the EEPROM's address, will start returning bytes from that internal address which is incremented for each byte read.
"Wire.onRequest(requestEvent);" allows us to set up a handler, but it seems to be called only once on the start of the read.
In the handler it is possible to provide a reply of multiple bytes.
However I did not find the documentation allowing to know how many bytes were effectively sent to the master.
I got the initial code from the arduino forum .  I've adapted it to this:
#include <Wire.h>
//#define DEBUG
byte XEEPROM[256] = {
  0x5D, 0x26, 0x31, 0x91, 0x3e, 0x12, 0x8e, 0x70, 0xa5, 0x57, 0x3d, 0xed, 0x91, 0x99, 0xb4, 0x11,
  0x38, 0xde, 0x1b, 0xd6, 0x4c, 0xd9, 0xf5, 0x13, 0x23, 0x94, 0xb8, 0x3d, 0x9c, 0xb0, 0xc4, 0x54,
  0xf0, 0x69, 0xca, 0xb3, 0x28, 0x84, 0xa5, 0xc1, 0x80, 0x53, 0x69, 0x0c, 0x38, 0x4f, 0x0c, 0x74,
  0xa1, 0x5b, 0x8c, 0x71, 0x34, 0x30, 0x38, 0x30, 0x30, 0x38, 0x31, 0x35, 0x33, 0x31, 0x30, 0x35,
  0x00, 0x12, 0x5a, 0x1e, 0xbd, 0x9e, 0x00, 0x00, 0x02, 0x82, 0x30, 0xaa, 0x10, 0xb7, 0x7f, 0x8d,
  0x0a, 0xcb, 0x2e, 0xc1, 0xeb, 0x52, 0x20, 0xdc, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x97, 0x55, 0x57, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4d, 0x54, 0x00, 0x42, 0x53, 0x54, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x02, 0x03, 0x05, 0x00, 0x01,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0xff, 0xff, 0xff,
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
  0x68, 0xaa, 0xdd, 0x02, 0x46, 0x45, 0x8f, 0x8f, 0x78, 0x56, 0xbb, 0x69, 0x01, 0x04, 0x46, 0x45,
  0x8f, 0x8f, 0x78, 0x56, 0xbb, 0x69, 0x01, 0x04, 0x46, 0x45, 0x8f, 0x8f, 0x78, 0x56, 0xbb, 0x69,
  0x12, 0x03, 0x46, 0x45, 0x8f, 0x8f, 0x78, 0x56, 0xbb, 0x69, 0x02, 0x02, 0x46, 0x45, 0x8f, 0x8f,
  0x78, 0x56, 0xbb, 0x69, 0x12, 0x02, 0x84, 0x79, 0x80, 0x00, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00
};
static volatile byte rQ;

void setup()
{
 Wire.begin(0x50);
 Wire.onReceive(receiveEvent);
 Wire.onRequest(requestEvent);
 Serial.begin(115200);
 Serial.println("I2C EEPROM EMULATION\n");
}

void loop()
{
}

void requestEvent(){
  //Wire.write(XEEPROM[rQ]); // Just 1
  Wire.write(XEEPROM+rQ,6); /// More than 1
  #ifdef DEBUG
  Serial.print("ADR:");
  Serial.print(rQ,HEX);
  Serial.print("R:");
  Serial.print(XEEPROM[rQ],HEX);  // print the character
  Serial.println();
  #endif
  rQ++; // Increment should depend on number of reads - not sure how to detect that.
}

void receiveEvent(int iData){
    rQ = Wire.read();
    Serial.print("ADR:");
    Serial.print(rQ,HEX);
    bool dwHeader=false;
    // loop through all but the last
    while(1 < Wire.available())
    {
      if(!dwHeader) {
          dwHeader=true;
          Serial.print("DATAW:");
      }
      XEEPROM[rQ]=Wire.read();;
      Serial.print(XEEPROM[rQ],HEX);  // print the character
    }
    Serial.println(); // new line
}

The question is about requestEvent and specifically:
void requestEvent(){
  //Wire.write(XEEPROM[rQ]); // Just 1
  Wire.write(XEEPROM+rQ,6); /// More than 1
  rQ++; // Increment should depend on number of reads - not sure how to
}

I would like to send one at a time, or at least be able to increment rQ according to the number of bytes effectively sent.
If you want to look at a datasheet, you can look at the AT24C02 datasheet.
With regards to the incrementing internal EEPROM address, the EEPROM specification says:

CURRENT ADDRESS READ: The internal data word address counter maintains
  the last address accessed during the last read or write operation,
  incremented by one. This address stays valid between operations as
  long as the chip power is maintained. The address “roll over” during
  read is from the last byte of the last memory page to the first byte
  of the first page. The address “roll over” during write is from the
  last byte of the current page to the first byte of the same page.

This is why the Arduino code emulating the EEPROM should know exactly how many bytes were read.
Thanks.

Please add more information to your question. Is the master device also an arduino board? If not, you are in trouble because the arduino as a slave is not the same as a eeprom. Which arduino board do you use for the slave and the master? The "loop through all but the last" is not normal, it is from an example but that is a bad example. If you use arduino unos, then the i2c buffer size is 32, and you may do a Wire.write with 32 bytes. When using the arduino wire libray, the slave does not know how many bytes will be read or are read by the master device.

The master is also an Arduino for the test, but normally it isn't and that does not matter. * I agree that there are some other bugs, I just wanted a quick start * I am using Arduino Nanos * The Arduino should act as an EEPROM - this avoids getting one for the test, but I am surprised that there is no way to know how many bytes are sent at the end of the I2C Transaction * I looked at Wire.cpp and twi.c just now * The only way to know how many bytes are sent would be to fill the buffer completely, and then fill it constantly (in the loop) using twi_transmit() and count one when it returns 0.

It matters a lot if the master is a arduino or not. The arduino as a slave uses clock pulse stretching and an eeprom does not. It is therefor impossible to act in the same way as an eeprom. Can you find an example of the arduino that simulates an eeprom in exactly the same way? That is not possible. For the software it is possible to change the library or use a library that generates interrupts for every single byte (I forgot the name of that library). The master often writes the register address before reading the data, then it is no problem to fill up the buffer with 32 bytes.

Ok, I understand that it can not be perfect.  An EEPROM does not do clock stretching because it is fast enough at the maximum I2C frequency.  The Arduino emulating the EEPROM could still be functionnaly equivalent which is enough.

Note, that I haven't tested the code below, since I currently don't have enough time for it. But it may help you to get, what you want to do.
The way the I2C interface works is, that after each byte read from the slave, the master will answer with ACK or NACK, depending on if he wants to read more data or not. So the slave doesn't know beforehand, how many bytes the master wants to read.
But you can change the Wire library, to call the onRequest callback for every single byte, instead of every request. The important code lies in the path of your Arduino installation at hardware/arduino/avr/libraries/Wire/src/utility/twi.c at line 575 (I refer to my installation of version 1.8.5; might be slightly different for you):
case TW_ST_SLA_ACK:          // addressed, returned ack
case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack
      // enter slave transmitter mode
      twi_state = TWI_STX;
      // ready the tx buffer index for iteration
      twi_txBufferIndex = 0;
      // set tx buffer length to be zero, to verify if user changes it
      twi_txBufferLength = 0;
      // request for txBuffer to be filled and length to be set
      // note: user must call twi_transmit(bytes, length) to do this
      twi_onSlaveTransmit();
      // if they didn't change buffer & length, initialize it
      if(0 == twi_txBufferLength){
        twi_txBufferLength = 1;
        twi_txBuffer[0] = 0x00;
      }
      // transmit first byte from buffer, fall
case TW_ST_DATA_ACK: // byte sent, ack returned
      // copy data to output register
      TWDR = twi_txBuffer[twi_txBufferIndex++];
      // if there is more to send, ack, otherwise nack
      if(twi_txBufferIndex < twi_txBufferLength){
        twi_reply(1);
      }else{
        twi_reply(0);
      }
      break;

When receiving a request with correct address, the first case will be executed (of course after other stuff with receiving address and sending ACK). The twi_onSlaveTransmit() function will execute the onRequest callback. When that is done, the code falls directly into the next case statement, which sends the first byte. When the slave receives an ACK after that byte, it should come back to this case and send another byte.
We can now put the buffer filling code into the second case statement, so that the callback will be executed for every requested byte. In this case we also need to change the if statement after that, so that it only triggers and sends NACK, if the user didn't write a byte in the callback. The original library seems to write at minimum 1 byte (even it nothing is in the buffer; it is set to zero). So we will also do this by setting a flag in the first case statement. The code now looks like this:
case TW_ST_SLA_ACK:          // addressed, returned ack
case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack
      // enter slave transmitter mode
      twi_state = TWI_STX;
      twi_slave_transmit_first_byte = 1;
      // transmit first byte from buffer, fall
case TW_ST_DATA_ACK: // byte sent, ack returned
      // ready the tx buffer index for iteration
      twi_txBufferIndex = 0;
      // set tx buffer length to be zero, to verify if user changes it
      twi_txBufferLength = 0;
      // request for txBuffer to be filled and length to be set
      // note: user must call twi_transmit(bytes, length) to do this
      twi_onSlaveTransmit();
      if(twi_slave_transmit_first_byte == 1){
          twi_slave_transmit_first_byte = 0;
          // if they didn't change buffer & length, initialize it
          if(0 == twi_txBufferLength){
            twi_txBufferLength = 1;
            twi_txBuffer[0] = 0x00;
          }
      }
      // copy data to output register
      TWDR = twi_txBuffer[twi_txBufferIndex++];
      // if there is more to send, ack, otherwise nack
      if(twi_txBufferIndex < twi_txBufferLength){
        twi_reply(1);
      }else{
        twi_reply(0);
      }
      break;

And we have to add the flag declaration at the top of the file (where all the other static volatile variables are defined) as static volatile:
static volatile uint8_t twi_slave_transmit_first_byte = 0;

In the onRequest callback you can now write a single byte to the buffer and incrementing your counter.

I think, that should work. If someone knows better, please correct me.

Hi, changing the Wire library is one way to go about it - for portability this would have to be added as a new Wire library, possibly just extending the standard library.  I'll try to check this out.

This is exactly what I stumbled upon when trying to create a I2C slave with a memory-based interface.
You are right, the requestEvent callback is called only once. So you have to prepare it beforehand. What is positive, however, is that the write function will discard all the unused bytes.
So, what can you do? Well, first of all a sum up of the I2C "messages". You, as a master, can

Send a "write" command, with a payload
Send a "read" command, with no payload, and the slave will reply with bytes as long as you continue to send ACKs

In my mind there were two different approaches:

The "write" command should contain the initial register and the number of registers to read; this approach, however, complicates distinguishing between a "read from EEPROM" and "write to EEPROM" commands
The write command should send only the initial register for reading from EEPROM, and the initial register + content to be written for writing to EEPROM.

In my project I chose the second approach. For this reason, when the master writes something on the I2C bus, the first byte of the payload is the register number, and then if there is no other data the slave prepares for sending the contents of the register and the next ones, while if there is any data this is treated as a write command.
The only problem with this approach is that the slave has to prepare a buffer, and the buffer size limits the maximum number of registers returned. I set this limit to 8 in my code; if the master asks for more than only 0s are returned.
Here is the library I wrote for this project.
File I2CInterface.h:
#ifndef I2CINTERFACE_H
#define I2CINTERFACE_H

#include <stdint.h>

class I2CInterface
{
  public:
    static I2CInterface instance;

  public:
    void start();

  private:
    I2CInterface();

    static void requestEvent();
    static void receiveEvent(int howMany);
    void resetSendingBuffer();

  private:
    static const uint8_t Address = 0x46;

    static const uint8_t MaxBufferLength = 8; // (max) 8 byte
    uint8_t sendingBuffer[MaxBufferLength];
};

#endif // I2CINTERFACE_H

File I2CInterface.cpp
#include <Arduino.h>
#include <Wire.h>
#include "I2CInterface.h"

I2CInterface I2CInterface::instance;

I2CInterface::I2CInterface()
{

}

void I2CInterface::start()
{
  Wire.begin(Address);
  Wire.onRequest(requestEvent);
  Wire.onReceive(receiveEvent);
  resetSendingBuffer();
}

void I2CInterface::requestEvent()
{
  Wire.write(instance.sendingBuffer, MaxBufferLength);
  instance.resetSendingBuffer();
}

void I2CInterface::receiveEvent(int howMany)
{
  if (howMany <= 0)
    return;
  else if (howMany == 1)
  { // Reading request
    uint8_t regist = Wire.read();
    for (uint8_t i = 0; i < MaxBufferLength; i++)
      instance.sendingBuffer[i] = Configuration.getRegister(regist++);
  }
  else
  { // Writing request
    uint8_t regist = Wire.read();
    while (Wire.available())
    {
      Configuration.setRegister(regist++, Wire.read());
    }
    instance.resetSendingBuffer();
  }
}

void I2CInterface::resetSendingBuffer()
{
  for (uint8_t i = 0; i < MaxBufferLength; i++)
    sendingBuffer[i] = 0x00;
}

Please note that the Configuration.getRegister and Configuration.setRegister are the functions I used to get and set some registers; you can substitute them with a direct EEPROM access or your own functions.
You just need to add, in your main file,
#include "I2CInterface.h"
...

void setup()
{
  ...
  I2CInterface::instance.start();
  ...
}

Thank you for your reply.  This is more or less what I do with "Wire.write(XEEPROM+rQ,6);", where 6 is currently increased to 16 which is all that I need in my setup. *  However, the address counter does not get correctly updated on reads, so while 16 or more bytes may be prepared for sending to the master, I would have to know how many have been actually sent...  Either during or after the transfer.
Most importantly, you confirm that requestEvent is called only once for the read from the master.

@le_top Well, in my case the new request (which is a write with one single byte) will have a new start address, so you should not increment rQ. The sequence to read, for instance, 20 bytes from byte 5 in your master should be: write address 5; read 6 bytes; write address 11; read 6 bytes; write address 17; read 4 bytes. It is the master who keeps track of the increment, not the slave. As for the only once, I detected it experimenting (I did not go deep in the Wire library to confirm this)

By changing the protocol, the Slave will no longer behave as the EEPROM.   I add an extract of the EEPROM specification to the question.

@le_top sorry, I've always used the EEPROMs this way (by always asking for a particular address every read operation rather than relying on the internal counter), so I totally forgot the usage of that feature. If you want this feature, I think the library should be modified (I think like chrisl suggests), since the number of written bytes information is not available AFAIK

I understand.  For safety it is best to always send the address first.  However, when emulating exactly the behavior, one woul hve to follow the specification.
My main question is related to the right method to find how many bytes were replied or how to reply byte by byte - this is what basically triggered the question.
The EEPROM example is the concrete application.
As the core question seemed to be new, I decided to open this topic.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
how do you capture the top value in a fallen edge in analogs data (flex sensor)
Guys i'm working with a flex sensor and I'm trying to capture a specific value which is the moment before the user lets go of a flexed flex sensor and its represented as the top point of a falling edge as sub picture A in the picture I included. using an array I tried two methods, which can produce a close value at times but at other it will give me wrong values
first I tried the following logic, whenever I detect a value below a certain threshold it indicates that a fallen edge has occurred so get me the value that came right before it as shown in sub picture C but depending on the delay this can be quite unpredictable.
the second method is to store the maximum value of but this returns the peak and it's not always the top of the fallen edge as shown in subpicture B
what do you guys suggest to capture those values?
this is my code so far
bool loaded = false;
int threshold = 760;
int index = 0 ;
int _max=0;
int values[4];
int values_size = 4;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  int data = analogRead(A0);

  if (loaded) {
    values[index] = data;
    if(data>_max){
      _max=data;
      }

    if (data < threshold) {
      loaded = false;
      Serial.flush();
      Serial.print('a');
      Serial.print(',');
      Serial.print(_max);
      Serial.println();
      _max=0;
      delay(300);
    }
    index++;
    index %= values_size;
  }
  else if ( data > threshold && !loaded) {

    loaded = true;
  }

  delay(20);

}

Did you forget the picture?

yeah, sorry about that...it's now up :)

I suggest you consider as “top value of the falling edge” the maximum of
the values you have read during a specified time window before the edge
is detected. This means you have to compute the maximum at the time you
detect the edge. If you instead continuously compute a running maximum,
then you are going to get a global maximum. Amended source:
bool loaded = false;
int threshold = 760;
int index = 0 ;
const int values_size = 4;  // this controls the time window
int values[values_size];

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

void loop() {
  int data = analogRead(A0);

  if (loaded) {
    // Store the reading.
    values[index] = data;
    index = (index + 1) % values_size;

    // Detect falling edge.
    if (data < threshold) {
      loaded = false;

      // Find the max.
      int _max = 0;
      for (int i = 0; i < values_size; i++) {
        if (values[i] > _max) _max = values[i];
        values[i] = 0;  // clear, for next time
      }

      // Report it.
      Serial.flush();
      Serial.print('a');
      Serial.print(',');
      Serial.print(_max);
      Serial.println();
      delay(300);
    }
  }

  // Detect rising edge.
  else if (!loaded && data > threshold) {
    loaded = true;
  }
  delay(20);
}

Notice the line values[i] = 0;. It is intended to avoid the reading of
one falling edge being seen on the next one.

I think this solved my problem, I increased the size of my array to 8 and added index=0 after delay(300) i think you forgot it, and so far the results are as wanted , thank you :)

@Raed: Resetting index doesn't hurt, but it's not really needed: the values array is used as a circular buffer, and when you are in a circle it doesn't matter where you start.

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Can BearSSL certstore be loaded from PROGMEM without needing a filesystem?
I have a relative small sketch that makes https requests of a 3rd party API.  This sketch is used by other people in their own homes, so I can't assume any other infrastructure.
Now because I don't control the API server I can't guarantee the CA uses, so I load a complete certstore.  All of the examples I've found use a filesystem (eg LittleFS) to hold the cert file.  This works OK if the ESP8266 can be connected to USB, but I'm not sure how to do this OTA (e.g. with BasicOTA).
Now the sketch is small enough that I can include the certstore content in PROGMEM
e.g.
static const unsigned char certs_ar[] PROGMEM = {
0x21,0x3c,0x61,0x72,0x63,0x68,0x3e,0x0a,0x63,0x61,0x5f,0x30,0x30,0x30,0x2e,0x64,0x65,0x72,0x2f,0x20,0x20,0x20,0x20,0x20,0x31,0x37,0x32,0x31,0x37,0x36,
...
0xb4,0x03,0x25,0xbc
};
#define SIZE_OF_CERTS 191944

Currently on startup I write this array out into a filesystem.
  if (!FSTYPE.begin())
  {
    Serial.println("Failed!");
    return;
  }

  if (!FSTYPE.format())
  {
    Serial.println("Failed to format!");
    return;
  }

  Serial.println("Creating cert store");
  File f=FSTYPE.open("/certs.ar","w");
  if (!f)
  {
    Serial.println(F("Can not open file for writing"));
    return;
  }
  Serial.println("Writing");
  // NOTE: f.write(certs_ar);  doesn't work 'cos certs_ar is in PROGMEM
  PROGMEMprint(f,certs_ar);
  Serial.println("Complete");
  f.close();

I can now do the standard
  int numCerts = certStore.initCertStore(FSTYPE, "/certs.idx", "/certs.ar");

to load the certstore.
I do this so it's easy to do a network update of the code; e.g. if the certstore needs to change the user can just do BasicOTA of the code base and not need to worry about having to push a new filesystem image over the network.
But this seems wasteful because I now have a copy of the same data in PROGMEM and in LittleFS.
Is there any way to initialize the certstore from PROGMEM?  Or, alternatively, any way of using BasicOTA to update the filesystem?

you can certainly upload to SPIFFS over http, there's an example of that, but I'm not sure about lfs...


text:
SPIFFS and LittleFS don't show all my files with readdir() and can't open() them
I created a simple sketch that just tries to list the files in SPIFFS. The SPIFFS filesystem was created with the version of mkspiffs that's part of the esp8266 package. The upload all seems to work, but it only lists the first file and not the rest.
After running the sketch I downloaded the flash memory and it compared OK so nothing is being corrupted.
    $ esptool.py --port=/dev/ttyUSB0 read_flash  0x200000 0x10000 foo
    $ cmp html.img foo
    $

If I try the same with LittleFS then I get no files reported!
I also tried upgrading to the 3.0.0 libraries (and thus also the later version of mkspiffs that came with the library).
Clearly I'm doing something stupid and wrong!
Hopefully the following (showing how I build it, upload it) will help point out my mistake!
Thanks for any assistance.
================================================================
Creating Image file. This is done using the mkspiffs that comes with the package so it should(!) match the library used by the ESP8266.
    $ ~/.arduino15/packages/esp8266/tools/mkspiffs/2.5.0-4-b40a506/mkspiffs -c html html.img
    /menu_frame.html
    /change_ap.html
    /top_frame.html
    /index.html
    /main_frame.html

Compiling with 4M2M memory layout.
    $ arduino-cli compile --fqbn=esp8266:esp8266:nodemcuv2:eesz=4M2M
    Executable segment sizes:
    IROM   : 265840          - code in flash         (default or ICACHE_FLASH_ATTR)
    IRAM   : 26888   / 32768 - code in IRAM          (ICACHE_RAM_ATTR, ISRs...)
    DATA   : 1248  )         - initialized variables (global, static) in RAM/HEAP
    RODATA : 800   ) / 81920 - constants             (global, static) in RAM/HEAP
    BSS    : 25120 )         - zeroed variables      (global, static) in RAM/HEAP
    Sketch uses 294776 bytes (28%) of program storage space. Maximum is 1044464 bytes.
    Global variables use 27168 bytes (33%) of dynamic memory, leaving 54752 bytes for local variables. Maximum is 81920 bytes.

Uploading, writing the bin at 0x0 and the filesystem at 0x200000.
    $ python ~/.arduino15/packages/esp8266/hardware/esp8266/2.7.4/tools/esptool/esptool.py --port=/dev/ttyUSB0 write_flash 0x0 SPIFFS.esp8266.esp8266.nodemcuv2.bin 0x200000 html.img
    esptool.py v2.8
    Serial port /dev/ttyUSB0
    Connecting....
    Detecting chip type... ESP8266
    Chip is ESP8266EX
    Features: WiFi
    Crystal is 26MHz
    MAC: b4:e6:2d:67:b1:45
    Uploading stub...
    Running stub...
    Stub running...
    Configuring flash size...
    Auto-detected Flash size: 4MB
    Compressed 298928 bytes to 219676...
    Writing at 0x00034000... (100 %)
    Wrote 298928 bytes (219676 compressed) at 0x00000000 in 19.5 seconds (effective 122.7 kbit/s)...
    Hash of data verified.
    Compressed 65536 bytes to 1353...
    Writing at 0x00200000... (100 %)
    Wrote 65536 bytes (1353 compressed) at 0x00200000 in 0.1 seconds (effective 4232.8 kbit/s)...
    Hash of data verified.

    Leaving...
    Hard resetting via RTS pin...

Results:
It shows 2M for the filesystem.
But only one file is listed?
If I use LittleFS instead then no files are listed!
Starting...
Total size of FS is: 1953282
Used size of FS is: 2259
File list:
/menu_frame.html
Finished

And, finally, the sketch.
    #include <FS.h>

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

      Serial.println("Starting...");

      SPIFFS.begin();

      FSInfo fs_info;
      SPIFFS.info(fs_info);

      Serial.print("Total size of FS is: ");
      Serial.println(fs_info.totalBytes);

      Serial.print("Used size of FS is: ");
      Serial.println(fs_info.usedBytes);

      Serial.println("File list: ");
      Dir dir = SPIFFS.openDir("/");
      while (dir.next())
      {
        Serial.println(dir.fileName());
      }
      Serial.println("Finished");
    }

    void loop() { }

3 years later, I found the answer!
mklittlefs and mkspiffs are sensitive to block size, page size, and total file system size.  Just calling mklittlefs on its own creates a filesystem, but the software on the ESP doesn't recognise it because the data structures are in the wrong place.
LittleFS
For a 4M1M image, this works:
BSIZE=8192
PSIZE=256
FSIZE=1024000

~/.arduino15/packages/esp8266/tools/mklittlefs/*/mklittlefs -c data -p $(PSIZE) -b $(BSIZE) -s $(FSIZE) data.img

For 4M2M set FSIZE=2072576
SPIFFS
BSIZE=8192
PSIZE=256

~/.arduino15/packages/esp8266/tools/mkspiffs/*/mkspiffs -c data -p $(PSIZE) -b $(BSIZE) data.img


text:
Arduino keeps restarting with L9110 and DC motor
I am trying to control a DC motor using the L9110 motor driver and Arduino MEGA 2560.
Here's the code.
#include <Arduino.h>

const int rightA = A3;
const int rightB = A2;

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

  pinMode(rightA, OUTPUT);
  pinMode(rightB, OUTPUT);
}

void loop() {
  Serial.println("tick");

  digitalWrite(rightA, HIGH);
  digitalWrite(rightB, LOW);
  Serial.println("waiting for 1s...\n");

  delay(1000);

  Serial.println("stopping");
  digitalWrite(rightA, LOW);
  digitalWrite(rightB, LOW);

  Serial.println("waiting for 5s...\n");
  delay(5000);
}

So it should spin the motor for 1s, then wait for 5s and repeat. This only happens once or twice and then Arduino either freezes or restarts and the motor stays on.

I use a separate power supply for the driver board, connected GND of Arduino and the driver, and also have a 100nF capacitor connected. These are the first most obvious issues I found on other forums, so this shouldn't be a problem.
The external power adapter is 5V 1A, and the motor current draw shouldn't exceed 500mA. Yet, it still doesn't work. Could anyone point me in the right direction as to where to look?

I use these motors

The startup motor current is likely many times that of a running motor. As soon as the motor exceed the power capacity of the supply, the supply voltage will likely drop. After dropping lower than either Arduino pin A1 or A2, the motor will try to pull current from the Arduino I/O pins. That could cause a number of problems. Some of which include trying to pull power from the Macbook USB port.
When choosing a power supply, many choose double the highest expected current. Motors are difficult to deal with because the more work they do the more current they can pull.
If you are constrained to a 5V/1A power supply consider solving this problem in software. Consider using a PWM signal to "gently start" the electric motor.
Or obtain a power supply rated at many more Amps to cover the motor startup current draw.

Thanks for the insights. I eventually fixed it by using TB6612FNG driver with MOSFETs and also use PWM to start the motors gently.

Your 5V 1A power adapter may not provide enough current for the motor and driver board. Motors can draw more current during startup or under load. Try a power supply with a higher current rating, such as 5V 2A or more. Measure the voltage across the motor driver's Vcc and GND pins when the motor is running. If the voltage drops significantly below 5V, the power supply is insufficient. Add a 10µF or 100µF electrolytic capacitor in parallel with the 100nF ceramic capacitor for better signal smoothing. You may also want to make an L9110 module by yourself:
https://www.pcbway.com/project/shareproject/DIY_Motor_Control_Building_and_Using_the_L9110_Module_679076e3.html

hey thanks for you answer, I eventually resolved it by replacing the L9110 module with TB6612FNG


text:
Arduino with bmp280 sensor not entering void loop
I've been working on a project in which I need to know my altitude. For this purpose I've been using the BMP280 sensor. But I have an issue.
I've been trying to test if the sensor works with the program "bmp280_sensortest.ino", already included in the library. When I open the serial monitor the message "BMP280 Sensor event test" is displayed, indicating that there is a valid sensor on board. Below that the temperature, pressure and altitude data should be displayed, but nothing happens.
I've added a simple Serial.print("hello") at the start of void loop(), but not even that is displayed. The program doesn't seem to enter void loop() and I don't know why.
Here is the code:
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_BMP280.h>

Adafruit_BMP280 bmp; // use I2C interface
Adafruit_Sensor *bmp_temp = bmp.getTemperatureSensor();
Adafruit_Sensor *bmp_pressure = bmp.getPressureSensor();

void setup() {
  Serial.begin(9600);
  Serial.println(F("BMP280 Sensor event test"));

  if (!bmp.begin()) {
    Serial.println(F("Could not find a valid BMP280 sensor, check wiring!"));
    while (1) delay(10);
  }

  /* Default settings from datasheet. */
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
                  Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
                  Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
                  Adafruit_BMP280::FILTER_X16,      /* Filtering. */
                  Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */

  bmp_temp->printSensorDetails();
}

void loop() {
  sensors_event_t temp_event, pressure_event;
  bmp_temp->getEvent(&temp_event);
  bmp_pressure->getEvent(&pressure_event);

  Serial.print("hello");
  Serial.print(F("Temperature = "));
  Serial.print(temp_event.temperature);
  Serial.println(" *C");

  Serial.print(F("Pressure = "));
  Serial.print(pressure_event.pressure);
  Serial.println(" hPa");

  Serial.println();
  delay(2000);
}

Any reply is greatly appreciated.
edit:
if I remove
!bmp.begin()
from the if statement and replace it with a 1 it enters the void loop but it displays 0°C and 0pa

If you are using Serial.print("hello"); to test the entering of void loop(), you should follow it with Serial.flush(); so that you know your message has been sent before your code has an opportunity to lock up, because if that happens the absence of the "Hello" message might lead you to believe that you didn't make it to that line when you in fact did.

put print statements throughout setup()

But you don't get the "check wiring" message? ;)

Add prints after every call in setup to pin down which of those calls does not return...

Does your BMP280 show up if you run the I2C scanner sketch? Does that sketch fail to run to completion?

@timemage the I2C scanner sketch is stuck at 'scanning...'

There is something fundamental going on then and not enough information to provide a proper answer that matches your question.  It may be as @SimSon suggested, wiring.  It may be that your pull-up resistors are too weak or non-existent.  A simple way to lock up the AVR Wire implementation is to hold SCL LOW indefinitely.  But it could be any number of other things.

What you might do is delete this question before it is "answered".  Work on your wiring, and if you're still having trouble with it start a new question to the effect "why is my bme280 connected to nano ble etc etc not show up in the i2c scanner" and provide details needed to trouble shoot that.  E.g. link to the bme280 breakout used.  Pictures of wiring, etc.  Then whatever answer that results will match the question.  Though, you'll probably figure it out on your own.

"replace it with a 1 it enters the void loop" - in this case the sketch is not supposed to enter the loop, instead it will get stuck in the while(1) loop. Please clarify this point. An all time classic is missing pullup resistors, do you have those attached?

It could be a faulty library/sensor, most likely the sensor, sometimes sensors can begin but then another connection could be faulty or the chip itself is faulty and so the Arduino might just be waiting forever for a response that will never come.
To see where it gets stuck, you can add Serial.println(F("1")); after bmp.setsampling then Serial.println(F("2"));  after bmp_temp->printSensorDetails to see where exactly it's getting stuck
One thing I also like to do is to buy two/three of a sensor, so that I can replace a sensor with another one. That way if a piece of code doesn't work for all three sensors then I can pretty sure it's a problem with the code and not the device. Not sure if you have a spare sensor to try that but I would recommend it in future


text:
I have five pushbuttons that refer to a specific pin number. I need an efficient code to set the variable for the pin with state 1. What can I use?
There are 5 push buttons each which correspond to a certain pin let us use 1 to 5 for an example. I want to set a variable, ActiveButton which will be set equal to the the only pin in the one state.
We make use of the concept that there can only be one active push button which means the pin of that would have a state of 1 and the rest would be 0. The long method for this would be to use if else and digitalRead(pin) == 1 for everything but that would be so long on code. I've considered using do while or while loops to stop until it reaches the push button with a state of 1, but I was wondering if there was a more efficient code. I was also thinking if there was something that made use of an array?
Though the idea of like having a simple array return the index which results to a corresponding value, like lets say Array[3] ==1 among all the indices from 0 to 4 feels easy to conceptualize, I believe this can be really taxing on the code and might not be able to be done in a short way.
I've also thought of possibly using switch case, where the variable would be the high state and the case values would be the digitalRead for each pin? But that would be wrong probably because I'm not sure but you can't set the switch variable to be a constant. It would be something like
switch (1)
case digitalRead(1):
case digitalRead(2):

what does this mean? but that would be so long on code ... you can use an array ... how do you expect to refer to the array elements without using a loop or multiple if- else if statements?

Array would definitely be used but I was thinking that if else is too long IF other codes like loops like do while, while, for can do the job with less code.

you could use hardware ... search priority encoder

don't be thinking of being fancy with the code by using switch-case form instead of multiple if statements ... the compiler may actually produce the same code

put the button pin numbers in an array ... then you can use a for loop to read each pin and return either the lowest, or the highest pin number (or both)

It is not clear to me, what behavior you want. I understood the following: the user might press multiple buttons, but only the one, which is first in the row of pressed buttons will be registered. So id the user pressed button 3,4 and 6, only button 3 would be registered. Is that correct?

No, let us assume that the user might only press one button. I'm currently working on just a TinkerCAD simulation of this idea, so I will disregard the multiple buttons scenario since virtually your cursor can really only hold on to one push button there.

There are 5 push buttons each which correspond to a certain pin let us use 1 to 5 for an example. I want to set a variable, ActiveButton which will be set equal to the the only pin in the one state.

Here is a short snippet of what I think, that you want. This is quite a long shot, since your question is not clear enough.
int ActiveButton = -1; // Initialize ActiveButton with -1 (no button is active)
int button_pins[] = {1, 2, 3, 4, 5}; //Array with pin numbers of the buttons

void loop(){
    for(int i=0;i < sizeof(button_pins)/sizeof(button_pins[0]); i++){
        if(digitalRead(button_pins[i])){ //if the i-th button was pressed
            ActiveButton = button_pins[i]; // assign i-th button pin number to variable
            break; // Break, since we have found our pressed button, ignore all following pins
        }
    }
}

This will assign the pin number of the pressed button to the variable. The condition in the for loop
sizeof(button_pins)/sizeof(button_pins[0])

will make the code loop over all elements of the button_pins array. sizeof(button_pins) returns the number of bytes in the button_pins array. Then we divide through the number of bytes in the first element to get the number of elements in the array.

Yes, this kind of code is exactly what I wanted. I needed to use it for lighting up LEDs differently. The problem when I tried this is my lights did not turn off when the buttons weren't pressed and only changed when another button was pressed. I did not indicate this in the original post because I already knew how to do the LED part and wanted to focus on that, but yeah I had to bring it up now. How do you make it so that the loop turns off when the pressed button is unpressed?

That is the only problem. Everything else works. I appreciate your effort. I've tried putting an else condition to set the ActivePushButton to 0 but that didn't seem to do as I intended. For more context, after that code of yours I put a switch function for cases 1 to 5 to execute the custom five functions then the code for the custom five functions after.

Update. I actually did this already by setting the ActiveButton equal to 0 after the switch cases. I just left this question in case you were gonna offer a different suggestion.

Yes, I would have suggested something like that. If it now works, I don't have anything to add.


text:
Arduino uno and 1602A I2C not working
I'm a newbie in engineering.
I bought this with arduino learning kit.
It's simply not working.
There are several possible problems:

The display is not working due to a hardware problem. It could need to be repaired or soldered better.
The library that I chose could be buggy (software problem)

How can I check this? Thanks!
PS Build-in led is blinking as expected.
Here is the code:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup()
{
  lcd.init();
  lcd.begin(8,2);

  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  digitalWrite(LED_BUILTIN, HIGH);
  lcd.setCursor(0, 0);
  lcd.print("TEST");
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  lcd.setCursor(0, 0);
  lcd.print("   ");
  delay(1000);
}

Scanner is definitely best approach, but if 0x27 address is wrong, try 0x35 as a quick test. Unless you have soldered jumpers, these are the two most likely addresses. Your wiring looks correct.

Try with this address 0x3F or 0x27
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // or 0x27
void setup() {
lcd.begin(16, 2);
}
void loop()
{
  digitalWrite(LED_BUILTIN, HIGH);
  lcd.setCursor(0, 0);
  lcd.print("TEST");
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  lcd.setCursor(0, 0);
  lcd.print("   ");
  delay(1000);
}

Scaner helped me to find this address. https://arduino-info.wikispaces.com/LCD-Blue-I2C

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Measure cycle count and time of Digital Input
I am currently working on a project which is read a digital input signal from a machine. The machine operation is as below:
when the mold close, the machine gives the "HIGH" signal, when mold is open the machine gives "LOW" signal. A cycle is counted as one cycle when from the mold close --> open --> close.
My goal is to count the cycle and cycle time of each cycle. I am struggling when the Input comes from HIGH to LOW. Appreciate your help to give me some guildance on this project.
int MoldInput = 2;
int MoldState = 0;
int lastMoldState = 0;
int CycleTimeCounter = 0;
int CycleCount = 0;
unsigned long CycleTime;
volatile unsigned long TimeTemp1 = 0;
volatile unsigned long TimeTemp2 = 0;
void setup() {
  // put your setup code here, to run once:
  pinMode (MoldInput,INPUT);
  attachInterrupt(0, RealTimeMoldClose, RISING);
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println(CycleTime);
}
void RealTimeMoldClose(){
  unsigned long t = millis();
  TimeTemp2 = t;
  CycleTime = TimeTemp2 - TimeTemp1;
  TimeTemp1 = TimeTemp2;
}

What is connected to pin 5 and what is connected to pin 2? For the cycle time store the millis value and the next time the MoldState turns HIGH, substract the previous millis value from the current millis value.

This is my mistake. Only digital signal connected to pin 2.

Not sure, but pulseIn seems to be appropriate

upvote for presenting properly formatted code listing

I have updated a new code from myself after remember the attachInterrupt function. Appreciate your guys comment on this.

You don't need to do anything on HIGH to LOW. For example, if you are counting how often a door opens you don't also need to count how often it closes, because it must close before it re-opens.
I don't see the point of the interrupt since your code is doing nothing else than checking if the interrupt occurred, so it may as well be checking if the input has changed anyway. This code is simpler:
const int MoldInput = 2;

int lastMoldState = 0;
unsigned long startTime = 0;
unsigned long TotalTime = 0;
unsigned long CycleTimeCounter = 0;

void setup() {
  pinMode (MoldInput, INPUT);
  Serial.begin(115200);
}

unsigned long lastReportedCycleCount = 0;

void loop() {
  int MoldState = digitalRead(MoldInput);
  if (MoldState != lastMoldState) {
    if (MoldState == HIGH) {
      CycleTimeCounter++;  // count times it was high
      TotalTime += millis() - startTime;  // add up time interval
      startTime = millis ();
      delay (100);    // debounce
    }  // end of state being HIGH
    lastMoldState = MoldState;
  }   // end of state change

  if (CycleTimeCounter % 10 == 0 && CycleTimeCounter != lastReportedCycleCount)
    {
    Serial.print (F("Average time after "));
    Serial.print (CycleTimeCounter);
    Serial.print (F(" cycles is "));
    Serial.print (TotalTime / CycleTimeCounter);
    Serial.println (F(" milliseconds"));
    lastReportedCycleCount = CycleTimeCounter;
    }
} // end of loop


text:
I need two (25 and 30 kHz) pwm output on a nano
How do I create a second output with a different frequency?
void setup() {

const byte DRIVEa = 3;  // Timer 2 "B" output: OC2B
  pinMode (DRIVEa, OUTPUT);  // driver a.

  TCCR2A = _BV (WGM20) | _BV (WGM21) | _BV (COM2B1); // fast PWM, clear OC2B on compare.
  TCCR2B = _BV (WGM22) | _BV (CS21);         // fast PWM, prescaler of 8.

}

void loop() {

  OCR2A =  ((F_CPU / 8) / 30000) - 1;    // 30kHz, zero relative.
  OCR2B = ((OCR2A + 1) / 2) - 1;      // 50% duty cycle.

}

Use a different timer?  The frequency of a timer depends on the mode and the TOP value.  What other timers are you not using?

only using one pwm output and can move other things around if required.  I see on "secrets of PWM" that maybe pin 11 can be a second output??  I borrowed the above code from another post and don't understand how it works.

Welcome to SE/Arduino! Please take the [tour] to learn how this site works, and read "[ask]" and other pages of the [help]. You did read the manual and application notes of the MCU, didn't you? Please [edit] your question to clarify why they don't help you.

@tedthomas: https://docs.arduino.cc/tutorials/generic/secrets-of-arduino-pwm/ is good.  https://gammon.com.au/timers explains it very well.  pin11 is also controlled by timer2, and it's PWM-ish register OCR2A is used to set the 30KHz frequency, so it won't work.  Would using Pin 10 on Timer1 with appropriate settings for TCCR1A, TCCR1B, OCR1A and OCR1B be feasible?  The TimerHelpers example on https://gammon.com.au/timers might make it easy.

Try to modify your code like this:
void setup() {
  // Timer 2 - First output (DRIVEa)
  const byte DRIVEa = 3;  // Timer 2 "B" output: OC2B (pin 3 on Arduino UNO)
  pinMode (DRIVEa, OUTPUT);  // driver a

  TCCR2A = _BV (WGM20) | _BV (WGM21) | _BV (COM2B1); // fast PWM, clear OC2B on compare
  TCCR2B = _BV (WGM22) | _BV (CS21);                 // fast PWM, prescaler of 8

  // Timer 1 - Second output (DRIVEb)
  const byte DRIVEb = 9;  // Timer 1 "A" output: OC1A (pin 9 on Arduino UNO)
  pinMode (DRIVEb, OUTPUT);  // driver b

  TCCR1A = _BV(WGM10) | _BV(WGM11) | _BV(COM1A1);  // fast PWM, clear OC1A on compare
  TCCR1B = _BV(WGM12) | _BV(WGM13) | _BV(CS11);    // fast PWM, prescaler of 8
}

void loop() {
  // Timer 2 - Set frequency and duty cycle for first output (DRIVEa)
  OCR2A = ((F_CPU / 8) / 30000) - 1;    // 30kHz frequency
  OCR2B = ((OCR2A + 1) / 2) - 1;        // 50% duty cycle

  // Timer 1 - Set frequency and duty cycle for second output (DRIVEb)
  OCR1A = ((F_CPU / 8) / 10000) - 1;    // 10kHz frequency
  OCR1B = ((OCR1A + 1) / 4) - 1;        // 25% duty cycle (for example)
}

Timer 2 is used for generating the first PWM signal (30kHz) on Pin 3.
Timer 1 is used to generate the second PWM signal (10kHz) on Pin 9.
The prescaler for both timers is set to 8 (CS21 and CS11), but the frequency is determined by the values you set for OCR2A and OCR1A.
You can modify the duty cycle for Timer 1 by adjusting OCR1B.

Timer 2 working like a champ but nothing from Timer 1.

I tried this and get nothing from Timer 1.  I note the Timer 1 uses 0C1"A" where Timer 2 uses B.  and the addition of WGM13

Timer 1 output locked high.  Think it has anything to do with 8 vs 16-bit ?

Used the code on Timers 0 and 2 and it works perfectly.  I need other timer 0 functions so need to get 1 working...

Finally found a solution.  Never could get Timer 1 to act like Timer 2 but this tool
https://dbuezas.github.io/arduino-web-timers/#mcu=ATMEGA328P&timer=1&CompareOutputModeA=toggle&OCR1A=48059&timerMode=FPWM
allowed me to experiment
void setup() {

const byte DRIVEb = 9;  // Timer 1 "A" output: OC1A
pinMode (DRIVEb, OUTPUT);  // driver b

TCCR1A = _BV (COM1A0) | _BV (WGM11) | _BV (WGM10); // fast PWM, toggle
TCCR1B = _BV (WGM13)  | _BV (WGM12) | _BV (CS11);   // fast PWM, prescaler of 8

const byte DRIVEa = 3;  // Timer 2 "B" output: OC2B
pinMode (DRIVEa, OUTPUT);  // driver a

TCCR2A = _BV (WGM20) | _BV (WGM21) | _BV (COM2B1); // fast PWM, clear OCR2A on compare
TCCR2B = _BV (WGM22) | _BV (CS21);                 // fast PWM, prescaler of 8

}

void loop() {

OCR2A =  ((F_CPU / 8) / 30000) - 1;    // 30kHz, zero relative
OCR2B = ((OCR2A + 1) / 2) - 1;         // 50% duty cycle

OCR1A = ((F_CPU / 8 ) / 80000) - 1;    // 40kHz, F/2 toggle mode

}


text:
MC60E GSM Shield can't connect to Network
I am using a GSM MC60E Shield (Model: https://forum.arduino.cc/index.php?topic=234200.0) on top of an Arduino Mega 2560; the Arduino is connected to other sensors that are not important now.
I want to take values stored in the Arduino Mega and send them via the GSM MC60E Shield to my phone every 12h.
But I am stuck at a previous step: the GSM MC60E can't connect to the network. I turn it on by holding the power button for 4s, the redLED is supposed to flash every 2s when it is on. I am not sure if...

It is a problem of the code. I read rx and tx should be connected opposite. But since it is a shield, how can I oppose them?
It is a physical connection problem (weird because there are no cables or anything, only the shield on top of the Arduino and the USB Port to the computer)

So far this is the code that has worked. It stops at the output "Waiting for Network..." and then "fail":
/**********************
 *
 * This sketch connects to a website and downloads a page.
 * It can be used to perform HTTP/RESTful API calls.
 *
 * TinyGSM Getting Started guide:
 *   https://tiny.cc/tinygsm-readme
 *
 **********************/

// Select your modem:
//#define TINY_GSM_MODEM_SIM800
// #define TINY_GSM_MODEM_SIM808
// #define TINY_GSM_MODEM_SIM868
// #define TINY_GSM_MODEM_SIM900
// #define TINY_GSM_MODEM_SIM7000
// #define TINY_GSM_MODEM_SIM5360
// #define TINY_GSM_MODEM_SIM7600
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_SARAR4
// #define TINY_GSM_MODEM_M95
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
// #define TINY_GSM_MODEM_M590
// #define TINY_GSM_MODEM_MC60
#define TINY_GSM_MODEM_MC60E
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_XBEE
// #define TINY_GSM_MODEM_SEQUANS_MONARCH

// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial

// Set serial for AT commands (to the module)
// Use Hardware Serial on Mega, Leonardo, Micro
#define SerialAT Serial1

// or Software Serial on Uno, Nano
//#include <SoftwareSerial.h>
//SoftwareSerial SerialAT(1, 0); // RX, TX

// Increase RX buffer to capture the entire response
// Chips without internal buffering (A6/A7, ESP8266, M590)
// need enough space in the buffer for the entire response
// else data will be lost (and the http library will fail).
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 650
#endif

// See all AT commands, if wanted
// #define DUMP_AT_COMMANDS

// Define the serial console for debug prints, if needed
#define TINY_GSM_DEBUG SerialMon

// Range to attempt to autobaud
#define GSM_AUTOBAUD_MIN 9600
#define GSM_AUTOBAUD_MAX 115200

// Add a reception delay - may be needed for a fast processor at a slow baud rate
// #define TINY_GSM_YIELD() { delay(2); }

// Uncomment this if you want to use SSL
// #define USE_SSL

// Define how you're planning to connect to the internet
#define TINY_GSM_USE_GPRS true
#define TINY_GSM_USE_WIFI false

// set GSM PIN, if any
#define GSM_PIN ""

// Your GPRS credentials, if any
const char apn[]  = "YourAPN";
const char gprsUser[] = "";
const char gprsPass[] = "";

// Your WiFi connection credentials, if applicable
const char wifiSSID[]  = "YourSSID";
const char wifiPass[] = "YourWiFiPass";

// Server details
const char server[] = "vsh.pp.ua";
const char resource[] = "/TinyGSM/logo.txt";

#include <TinyGsmClient.h>

// Just in case someone defined the wrong thing..
#if TINY_GSM_USE_GPRS && not defined TINY_GSM_MODEM_HAS_GPRS
#undef TINY_GSM_USE_GPRS
#undef TINY_GSM_USE_WIFI
#define TINY_GSM_USE_GPRS false
#define TINY_GSM_USE_WIFI true
#endif
#if TINY_GSM_USE_WIFI && not defined TINY_GSM_MODEM_HAS_WIFI
#undef TINY_GSM_USE_GPRS
#undef TINY_GSM_USE_WIFI
#define TINY_GSM_USE_GPRS true
#define TINY_GSM_USE_WIFI false
#endif

#ifdef DUMP_AT_COMMANDS
  #include <StreamDebugger.h>
  StreamDebugger debugger(SerialAT, SerialMon);
  TinyGsm modem(debugger);
#else
  TinyGsm modem(SerialAT);
#endif

#ifdef USE_SSL
  TinyGsmClientSecure client(modem);
  const int  port = 443;
#else
  TinyGsmClient client(modem);
  const int  port = 80;
#endif

void setup() {
  // Set console baud rate
  SerialMon.begin(115200);
  delay(10);

  // !!!!!!!!!!!
  // Set your reset, enable, power pins here
  // !!!!!!!!!!!

  SerialMon.println("Wait...");

  // Set GSM module baud rate
  TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
  // SerialAT.begin(9600);
  delay(6000);

  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  SerialMon.println("Initializing modem...");
  modem.restart();
  // modem.init();

  String modemInfo = modem.getModemInfo();
  SerialMon.print("Modem Info: ");
  SerialMon.println(modemInfo);

#if TINY_GSM_USE_GPRS
  // Unlock your SIM card with a PIN if needed
  if ( GSM_PIN && modem.getSimStatus() != 3 ) {
    modem.simUnlock(GSM_PIN);
  }
#endif
}

void loop() {

#if TINY_GSM_USE_WIFI
  // Wifi connection parameters must be set before waiting for the network
  SerialMon.print(F("Setting SSID/password..."));
  if (!modem.networkConnect(wifiSSID, wifiPass)) {
    SerialMon.println(" fail");
    delay(10000);
    return;
  }
  SerialMon.println(" success");
#endif

#if TINY_GSM_USE_GPRS && defined TINY_GSM_MODEM_XBEE
  // The XBee must run the gprsConnect function BEFORE waiting for network!
  modem.gprsConnect(apn, gprsUser, gprsPass);
#endif

  SerialMon.print("Waiting for network...");
  if (!modem.waitForNetwork()) {
    SerialMon.println(" fail");
    delay(10000);
    return;
  }
  SerialMon.println(" success");

  if (modem.isNetworkConnected()) {
    SerialMon.println("Network connected");
  }

#if TINY_GSM_USE_GPRS
  // GPRS connection parameters are usually set after network registration
    SerialMon.print(F("Connecting to "));
    SerialMon.print(apn);
    if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
      SerialMon.println(" fail");
      delay(10000);
      return;
    }
    SerialMon.println(" success");

  if (modem.isGprsConnected()) {
    SerialMon.println("GPRS connected");
  }
#endif

  SerialMon.print("Connecting to ");
  SerialMon.println(server);
  if (!client.connect(server, port)) {
    SerialMon.println(" fail");
    delay(10000);
    return;
  }
  SerialMon.println(" success");

  // Make a HTTP GET request:
  SerialMon.println("Performing HTTP GET request...");
  client.print(String("GET ") + resource + " HTTP/1.1\r\n");
  client.print(String("Host: ") + server + "\r\n");
  client.print("Connection: close\r\n\r\n");
  client.println();

  uint32_t timeout = millis();
  while (client.connected() && millis() - timeout < 10000L) {
    // Print available data
    while (client.available()) {
      char c = client.read();
      SerialMon.print(c);
      timeout = millis();
    }
  }
  SerialMon.println();

  // Shutdown

  client.stop();
  SerialMon.println(F("Server disconnected"));

#if TINY_GSM_USE_WIFI
    modem.networkDisconnect();
    SerialMon.println(F("WiFi disconnected"));
#endif
#if TINY_GSM_USE_GPRS
    modem.gprsDisconnect();
    SerialMon.println(F("GPRS disconnected"));
#endif

  // Do nothing forevermore
  while (true) {
    delay(1000);
  }
}

Thanks in advance :)

your code has a lot of serialmon.print statements ... why are you not including the serial monitor output in your post?

@jsotola Since the GSM is not connected, the code stucks at "Waiting for Network..." "fail".


text:
Power LED Matrix With LiPo Battery & ESP32
I want to power an ESP32 with a 3.7V LiPo battery. There's a LED matrix of 64 WS2812 LEDs attached to the ESP32. I learned that I need a buck boost converter to power the microcontroller as it needs a 5V power input. The boost converter delivers that when there is no matrix attached. However if the matrix is attached it only receives about 2.7V. Turning the potentiometer on the boost converter changes nothing in this case. What is the reason for this? I am sorry if this question seems basic to you. I am an beginner with electronics.
Here is a rather hideous scetch of the connections. I hope this is okay:

This is the buck converter I used: https://www.amazon.de/gp/product/B079H3YD8V/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1

the converter is probably not able to supply required current to power the LEDs

Obviously @jsotola is right, 20x3 = 60mA each led group X 64 means almost 4 amps. way above 2 amps advertised by the seller which are never true. Even with a good boost converter, is your battery capable of supplying 5.5 amps required at the boost converter input?

The way you have it set up is fine if you aren't going to light up all the LEDs at full brightness. And if you do, you're not going to break your ESP32 Dev Board the way you have it set up in your diagram (since you are not running the power THROUGH the board). The LiPo battery probably has its own little regulator on it to prevent it from being damaged.
Check your dev board specifications on how much power you actually need to supply to the Vin pin. The ESP32 chip operates between 2.3 and 3.6 volts (3.3 recommended). Your dev board regulates the 5v to provide that amount to the chip.
Most likely, your dev board will run fine on the 3.7V provided by your LiPo without the buck-boost. I use a similar setup (without a buck-boost) to demo little projects to friends. I use a ESP32U-01 dev board from EZSBC, a 64 LED Matrix from Adafruit, and a 3.7v LiPo battery.
Depending on how many LEDs are lit (and what color), you shouldn't expect the battery to last very long. And the overall brightness of your led matrix will be limited.
If you are using the FastLED Animation Library, I would recommend setting a power limit using set_max_power_in_milliwatts function and limiting it to 1500mW for starters. Again, if you are not drawing power THROUGH the ESP32 board, you're fine.

By the way, if you really want 5v power, which will power your your LEDs better, I would suggest using a standard mobile phone battery pack, like an Anker PowerCore 10000. But DO NOT plug the USB directly into your dev board! Take an old USB cable, cut the end off and create a pigtail with the power wires to plug into the same Vin and LED cables you are using in your diagram.


text:
So many missed bytes with serial comm
I have a setup with serial comm from Raspberry Pi to Arduino. It's communicating at baud 9600 on both devices, and from Raspberry Pi 3b+ GPIO-14,UART0,TX0 to Arduino Nano RX0. There's a level shifter in between setup as recommended by AdaFruit tutorials. I'm sending data from Raspberry Pi as such:
#loop here
m = []
m.append(255)
m.append(i) // index value between 0-150
m.append(p[0][i]) // value between 0-254
m.append(p[1][i]) // value between 0-254
m.append(p[2][i]) // value between 0-254
#print statement here
'''
Data: [255, 94, 0, 0, 0, 255, 95, 254, 0, 0, 255, 96, 0, 254, 0]
...
'''

And receiving data on Arduino as such:
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    byte inChar = (byte)Serial.read();
    sprintf(printString, "Received: %d", inChar);
    Serial.println(printString);
  }
}
/*
Received: 255
Received: 94
Received: 0
Received: 255
Received: 95
Received: 254
Received: 0
Received: 255
Received: 96
Received: 0
Received: 254
Received: 255
Received: 94
Received: 0
Received: 0
Received: 0
Received: 255
Received: 254
Received: 255
...
*/

Any idea why there are so many missed bytes and how to fix this?
EDIT: @juraj There is a ground between both. I've measured with a portable oscilloscope. I can post the picture of the setup tomorrow.
@Edgar Bonet The loop function is empty, and looks as follows:
void loop() {
}

I also don't have any data being sent back to the Raspberry Pi. I have the Serial TX wire out from Arduino completely disconnected

It does not matter if you wire TX or not. Serial.println() takes the same time in any case. Did you try to shorten the string, like just the hex representation of the received bytes?

Re: “I have the Serial TX wire out from Arduino completely disconnected”: this is irrelevant. The Arduino doesn't care, and doesn't even know the wire is disconnected. It is still sending the data out. This takes time: about 14 times the time it took to receive the data.

@EdgarBonet Could you please clarify why it is sending out the data? Is it because of the serial print statement?

Yes, Serial.println(...) means “please, send out this data”.

Without the full codes, we can only guess. My guess would be the serial
receive buffer on the Arduino is overflowing.
One reason this could happen is if serialEvent() is not called
frequently enough. This function is called by the Arduino core on every
loop iteration, just after loop() returns. If your loop() takes too
long (e.g. you are using delay() or blocking waits), the receive
buffer can overflow before serialEvent() has a chance to empty it.
Another reason is if the Raspberry Pi is sending too much data, too
fast. For every byte the Arduino receives, it must send back
between 13 and 15 bytes. If too much data comes too fast, the transmit
buffer will eventually get full, and then Serial.println() becomes
really slow, because it has to wait for the bytes to actually get out
on the wire. This in turn slows down serialEvent() to the point where
it can make the receive buffer overflow.
Edit: If this (the Raspberry sending data too fast) is the cause of
the problem, the obvious solution is to have it send data more slowly,
as:
repeat:
    send a message
    delay for some suitable time

I totally agree with Edgar Bonet. You are sending 13 to 15 bytes per input byte. This takes time in the hardware, regardless of whether you have anything connected to it or not. So you expect it to misread data after 1/15 of the size of the output buffer, which I think is 64 bytes by default.

@NickGammon Thanks, that sounds reasonable to me. Do either of you have a suggestion for receiving data and debugging correctly? Should I have both TX and RX hooked up and do some sort of acknowledgment?

I have a post here about debugging using SPI (and also I2C) if you have those pins free. That is much faster than using serial comms.

@errolflynn Also reduce the length of your debugging messages, that will help. For example, instead of "Received:" send "R".


text:
Arduino unable to wake up using interrupt after sending SMS
my use case is that I am building a distance sensor using Arduino Uno. The idea is when the distance is between a threshold, an SMS is sent from the device.
I am using DS3231, SIM800L, and HCSR04 for my needs.
I want to save power consumption too so I am trying to put my Arduino into a deep sleep and then wake up using RTC interrupt.
The code below works fine when the distance is NOT in the threshold. Meaning Arduino is waking up by the interrupt and then doing what it needs to do. However, if the distance is in between the threshold the SMS is sent and received but after that Arduino never wakes up again. I checked out the SQW pin DS3231, using a multimeter and the signal indeed is going LOW, but Arduino does not wake up again.
Libraries that I am using,
ds3231, Sim800l, NewPing
Here is the code that I am using,
#include <Arduino.h>
#include <avr/sleep.h>
#include <wire.h>
#include <ds3231.h>
#include <NewPing.h>
#include <Sim800L.h>

#define WAKEUP_PIN 2  // when low, makes 328P wake up, must be an interrupt pin (2 or 3 on ATMEGA328P)
#define LED_PIN 13  // output pin for the LED (to show it is awake)

#define TRIGGER_PIN 7
#define ECHO_PIN 6
#define MAX_DISTANCE 200 //max distance we want to measure in cm
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);

// DS3231 alarm time
uint8_t wake_HOUR;
uint8_t wake_MINUTE;
uint8_t wake_SECOND;

static boolean goToSleep = false; //to track the when to go to sleep and when to get data and do stuff

#define SIM_MODULE_RX 10
#define SIM_MODULE_TX 11
Sim800L gsmModule(SIM_MODULE_RX, SIM_MODULE_TX);

///* A struct is a structure of logical variables used as a complete unit
// struct ts {
//    uint8_t sec;         /* seconds */
//    uint8_t min;         /* minutes */
//    uint8_t hour;        /* hours */
//    uint8_t mday;        /* day of the month */
//    uint8_t mon;         /* month */
//    int16_t year;        /* year */
//    uint8_t wday;        /* day of the week */
//    uint8_t yday;        /* day in the year */
//    uint8_t isdst;       /* daylight saving time */
//    uint8_t year_s;      /* year in short notation*/
//#ifdef CONFIG_UNIXTIME
//    uint32_t unixtime;   /* seconds since 01.01.1970 00:00:00 UTC*/
//#endif
//};
struct ts t;

// When WAKEUP_PIN is brought LOW this interrupt is triggered FIRST (even in PWR_DOWN sleep)
void sleepISR()
{
    // Prevent sleep mode, so we don't enter it again, except deliberately, by code
    sleep_disable();

    // Detach the interrupt that brought us out of sleep
    detachInterrupt(digitalPinToInterrupt(WAKEUP_PIN));

    // Now we continue running the main Loop() just after we went to sleep
}

// Double blink just to show we are running. Note that we do NOT
// use the delay for the final delay here, this is done by checking
// millis instead (non-blocking)
void doBlink()
{
    static unsigned long lastMillis = 0;

    if (millis() > lastMillis + 1000)
    {
        digitalWrite(LED_PIN, HIGH);
        delay(10);
        digitalWrite(LED_PIN, LOW);
        delay(200);
        digitalWrite(LED_PIN, HIGH);
        delay(10);
        digitalWrite(LED_PIN, LOW);
        lastMillis = millis();
    }
}

// Set the next alarm
void setNextAlarm(void)
{
    // flags define what calendar component to be checked against the current time in order
    // to trigger the alarm - see datasheet
    // A1M1 (seconds) (0 to enable, 1 to disable)
    // A1M2 (minutes) (0 to enable, 1 to disable)
    // A1M3 (hour)    (0 to enable, 1 to disable)
    // A1M4 (day)     (0 to enable, 1 to disable)
    // DY/DT          (dayofweek == 1/dayofmonth == 0)
    uint8_t flags[5] = {0, 0, 0, 1, 1};

    // get current time so we can calc the next alarm
    DS3231_get(&t);

    wake_SECOND = t.sec;
    wake_MINUTE = t.min;
    wake_HOUR = t.hour;

    // Add a some seconds to current time. If overflow increment minutes etc.
    wake_SECOND = wake_SECOND + 10;
    if (wake_SECOND > 59)
    {
        wake_MINUTE++;
        wake_SECOND = wake_SECOND - 60;

        if (wake_MINUTE > 59)
        {
            wake_HOUR++;
            wake_MINUTE -= 60;
        }
    }

    // Set the alarm time (but not yet activated)
    DS3231_set_a1(wake_SECOND, wake_MINUTE, wake_HOUR, 0, flags);

    // Turn the alarm on
    DS3231_set_creg(DS3231_CONTROL_INTCN | DS3231_CONTROL_A1IE);
}

void getDistance(){

    // Send ping, get distance in cm
    float distance = sonar.ping_cm();

    // Send results to Serial Monitor
    Serial.print("Distance = ");

    Serial.print(distance);
    Serial.println(" cm");
    delay(500);

    if (distance < 10.00)
    {
        //Setup Sim800 for sms sending
        gsmModule.begin(9600);
        bool err = gsmModule.sendSms("+91790xxxxxxx", "CLose");
        Serial.println(err);
        gsmModule.end();
        delay(3000);
    }

    //sleep arduino after the above operation
    goToSleep = true;
}

// Standard setup( ) function
void setup()
{
    Serial.begin(9600);

    // Keep pins high until we ground them
    pinMode(WAKEUP_PIN, INPUT_PULLUP);

    // Flashing LED just to show the µController is running
    digitalWrite(LED_PIN, LOW);
    pinMode(LED_PIN, OUTPUT);

    // Clear the current alarm (puts DS3231 INT high)
    Wire.begin();
    DS3231_init(DS3231_CONTROL_INTCN);
    DS3231_clear_a1f();

    Serial.println("Setup completed.");
}

// The loop blinks an LED when not in sleep mode
void loop()
{

    // Just blink LED twice to show we're running
    doBlink();

    // Is the "go to sleep" pin now LOW?
    if (goToSleep == true)
    {
        // Set the DS3231 alarm to wake up in X seconds
        setNextAlarm();

        // Disable the ADC (Analog to digital converter, pins A0 [14] to A5 [19])
        static byte prevADCSRA = ADCSRA;
        ADCSRA = 0;

        /* Set the type of sleep mode we want. Can be one of (in order of power saving):
         SLEEP_MODE_IDLE (Timer 0 will wake up every millisecond to keep millis running)
         SLEEP_MODE_ADC
         SLEEP_MODE_PWR_SAVE (TIMER 2 keeps running)
         SLEEP_MODE_EXT_STANDBY
         SLEEP_MODE_STANDBY (Oscillator keeps running, makes for faster wake-up)
         SLEEP_MODE_PWR_DOWN (Deep sleep)
         */
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
        sleep_enable();

        // Turn of Brown Out Detection (low voltage)
        // Thanks to Nick Gammon for how to do this (temporarily) in software rather than
        // permanently using an avrdude command line.
        //
        // Note: Microchip state: BODS and BODSE only available for picoPower devices ATmega48PA/88PA/168PA/328P
        //
        // BODS must be set to one and BODSE must be set to zero within four clock cycles. This sets
        // the MCU Control Register (MCUCR)
        MCUCR = bit(BODS) | bit(BODSE);

        // The BODS bit is automatically cleared after three clock cycles so we better get on with it
        MCUCR = bit(BODS);

        // Ensure we can wake up again by first disabling interupts (temporarily) so
        // the wakeISR does not run before we are asleep and then prevent interrupts,
        // and then defining the ISR (Interrupt Service Routine) to run when poked awake
        noInterrupts();
        attachInterrupt(digitalPinToInterrupt(WAKEUP_PIN), sleepISR, LOW);

        // Send a message just to show we are about to sleep
        Serial.println("Deep Sleep");
        Serial.flush();

        // Allow interrupts now
        interrupts();

        // And enter sleep mode as set above
        sleep_cpu();

        // --------------------------------------------------------
        // µController is now asleep until woken up by an interrupt
        // --------------------------------------------------------

        // Wakes up at this point when WAKEUP_PIN is brought LOW - interrupt routine is run first
        Serial.println("Awake");

        // Clear existing alarm so int pin goes high again
        DS3231_clear_a1f();

        // Re-enable ADC if it was previously running
        ADCSRA = prevADCSRA;

        goToSleep = false; //reset so that arduino does what it needs to do

    }
    else
    {

        //check if distance is less
        Serial.println("Checking");
        getDistance();
    }
}

I would first remove all that just-for-sure code like the interrupt handler, repeated attach and detach, interrupts disabling,  BOD

@Juraj  Not sure how that would help cause the moment I remove the if (distance < 10.00) block everything works as expected. (Arduino wakes up every 10 seconds, gets the distance and sleeps, the cycle continues)


text:
SIM900 AT+CCID ERROR
I have my SIM900 connected to a 12v 2A power source, I have inserted my sim card changed it to 3G/2G(autoconnect) ( I did research it to know wheteher it is possible and it turns out it is, the only problem would be not having the same speed according to them) There are no pin/password on the sim. There is still a remaining balance (should be enough to send a text or two)
Also my SIM900 netlight led blinks every 1 sec.
I also did try AT commands that I found on the internet and this is the results:
I have also posted this on this site: https://forum.arduino.cc/t/sim900-at-ccid-error/922283
CODE
#include <SoftwareSerial.h>

//Create software serial object to communicate with SIM900
SoftwareSerial mySerial(7, 8); //SIM900 Tx & Rx is connected to Arduino #7 & #8

void setup()
{
//Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
Serial.begin(19200);

//Begin serial communication with Arduino and SIM900
mySerial.begin(19200);

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

mySerial.println("AT"); //Handshaking with SIM900
updateSerial();
mySerial.println("AT+CSQ"); //Signal quality test, value range is 0-31 , 31 is the best
updateSerial();
mySerial.println("AT+COPS");
updateSerial();
mySerial.println("AT+CCID"); //Read SIM information to confirm whether the SIM is plugged
updateSerial();
mySerial.println("AT+CREG?"); //Check whether it has registered in the network
updateSerial();
}

void loop()
{
updateSerial();
}

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

SERIAL MONITOR
Initializing...
AT

OK
AT+CSQ

+CSQ: 17,0

OK
AT+COPS?

+COPS: 0

OK
AT+CCID?

ERROR
AT+CREG?

+CREG: 1,0

OK


text:
HC 08 Module with Arduino Uno
I recently bought the HC 08 Bluetooth module (link here). As the specs state, this module supports Bluetooth 4.0 which indicates that it supports BLE (Bluetooth low energy).
My goal is to be able to use something similar to the CurieBLE library: I want to code services and characteristics on my Arduino so I can discover those on LightBlue (iOS).
I searched the internet for some guidelines, but I only found code using AT commands and honestly I don't know anything about those.
Can you please recommend any source to achieve the goal?
Update
After following the connections in this link (In Spanish I guess but helpful), I was able to discover the Arduino on LightBlue. The characteristic name was Tx/Rx and I was able to write, read and subscribe to notifications (data coming in). Of course if would be better to find something that allows the definition of services and characteristics.


text:
Wifi networking with ESP8266 (NODEMCU version)
I am doing some experiments with nodemcu 12 (which has built in esp8266). There most of the tutorials I found by internet describe how to connect to home wifi connection using it.
But when I power on nodemcu, I can see wifi network called "ESPXXX" in my laptop's wifi connection list.
So is there a way to directly connect to the wifi nw of esp8266 by my laptop or via another esp8266 (so I don't have to switch on my home wifi router)?
If it is possible, is there is way to change ssid of esp8266's wifi connection and add password (again this is not about connecting to home wifi and this is about the wifi connection on esp8266 it self)?
So we can make one esp8266 as a wifi host and connect other esp8266s as slave to it.
I am using arduino IDE to upload program into esp8266 and not Lua.
Thanks.

If you are programming in Lua then we do not know. I do know that it is possible to program (using the Arduino IDE plugins) the NodeMCU as a WiFi access point, and the SSID etc are up to you to select when you write the sketch.

Why did you tag your question "arduino-uno"? I see no Arduino UNO involved here, not even any Arduino at all. Could you describe your circuit? If there is no Arduino, then this is not a question for this site.

Sorry it seems my question is not clear. I will modify it.

That's a little better.  But you should provide the details of the sketch you loaded, and what you expect it to do, especially network wise.  If you have not loaded one yet, then that should be the obvious first step.

Here you are the working code allowing you to choose SSID, password, network name and IP address of your ESP8266 acting as an access point. In addition, you can specify wifi channel to avoid interference with other devices. A password must be at least 8 characters long or it wouldn't work.
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

IPAddress ip(192,168,1,81);         // choose IP address
IPAddress subnet(255,255,255,0);

ESP8266WebServer server(80);

void handleRoot() {
  String page = "<!DOCTYPE html>\n";

  page += "\n\n
Some heading

Generated by ESP8266\n\n";
  server.send(200, "text/html", page);
}

// what to do when accessed through http://ip_address/something_undefined
void handleNotFound(){
  String message = "File not found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
}

void setup(void){
  Serial.begin(74880);                      // so you can see debug messages automatically sent by ESP8266
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(ip, ip, subnet);        // declared as: bool softAPConfig (IPAddress local_ip, IPAddress gateway, IPAddress subnet)
  WiFi.softAP("SOME_NAME", "password", 7);  // network name, network password, wifi channel

  IPAddress myIP = WiFi.softAPIP();
  Serial.println();
  Serial.print("AP IP address: ");
  Serial.println(myIP);

  server.on("/", handleRoot);               // what to do when accessed through browser using http://IP_address

  // what to do when accessed through http://ip_address/test
  server.on("/test", [](){
    server.send(200, "text/plain", "This is another page");
  });

  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started...");
}

void loop(void){
  server.handleClient();
}

You can write something like:
server.on("/open_door", [](){
        // the code to switch on the relay to open the door
        // ... <-- put here the code
        server.send(200, "text/html", "Door: opened");
});

so you can open the door with http://ip_address/open_door.
You can try http://ip_address/something_undefined?a=24&b=25 to get an idea how to process the parameters.


text:
Unable to store data in variable from Serial.read()
I have a relay and bluetooth module connected to Arduino Uno. I send data such as digit 1 to the bluetooth module and I view it in the Serial Monitor. If I send 1 from serial monitor I get 4910 printed.
I would like to turn on the relay and have it stay on until I send a different digit. However, in my code below it doesnt work, the relay doesnt stay on.
Only, if I put the digital.write under while(Serial.available()) it works.
const int ledPin =  11;
int relayOn;

void setup() {

  //initialize serial port for logs
  Serial.begin(9600);

  pinMode(ledPin, OUTPUT);

}

void loop() {

  while (Serial.available()) {

      Serial.println("Data: ");

      Serial.println(Serial.read());

      if(Serial.read())
      {
        relayOn = Serial.parseInt();
      }

      while (relayOn > 1)
      {
        digitalWrite(ledPin, HIGH);

      }

    }

}

You can make it easier by using commands which are only 1 character. For example '1' or 'A' to turn it on and '0' or 'a' to turn it off. Start with a good description of the commands and the communication. A Serial.read() read a character, and you can not read it again with another Serial.read().

But can I store the data from Serial.read() inside a variable without having to keep sending the data continuously, I want the relay to stay on until I send different data 0 or 1 etc

@condo1234 You are rushing ahead. First describe the data/commands that you transmit. Do you want, for example, make it hard for yourself and be able to send the number "15"? Then step by step write it in code, if possible without the parseInt.

Now I am sending number 5 to turn on relay and 0 to turn off. Would it make a difference to send 1 to turn on? I also tried to assign variable relayOn in my code with Serial.read() and define it as char, but still didn't match. Do you have any example code I am a little confused with how to keep the relay on after I send data from bluetooth

what is the value of relayOn when you input a 1 and and also when you input a  0?

@jsotola when I send 1 I get 0 when doing Serial.printIn(relayOn)

Serial.println(Serial.read()); removes the data from the serial buffer.  if(Serial.read()) will be always false

Actually  the second "Serial.read()" will always return -1, this should be interpreted as true.

@Dorian you are correct!! That was the issue

Your input is "5\n" with '\n' as line ending setting in Serial Monitor.
In the code you have first Serial.println(Serial.read());. It will read and print the '5'. Then you have if(Serial.read()). It will read the '\n'. It is not 0 so the next line is relayOn = Serial.parseInt(). It will find no input and times out returning 0.
if you want to use parseInt():
void loop() {
  if (Serial.available()) {
    Serial.print("Data: ");
    relayOn = Serial.parseInt();
    Serial.println(relayOn);
    if (relayOn > 1) {
      digitalWrite(ledPin, HIGH);
    }
  }
}

Ok thanks that makes sense, I will try send with 1 and 0 and see if that works

Sorry I meant I already tried Serial.parseInt() and that outputs 0 when output relayOn in serial monitor, tried the same as your above code

it is not about what number you send, but how you read it. the answer explains the 0

I have changed to send 1 and used your code with Serial.parseInt() and when I output Serial.printIn(relayOn) I get 0 and Serial.printIn(Serial.read()) I get -1.

replace your loop() function with the loop() function from my answer

Ok I did that and now it outputs 0 if I send 1

I used in void setup() { Serial.begin(9600);}. In serial monitor I use 9600, its strange when I enter 1 from serial I get output 4910 everytime inside Serial.printIn(Serial.read())

49 is ascii code of the character '1'. 10 is ascii code of  the character '\n' (new line)

So, what do I do to make the relay turn on and stay on and then turn off when I send different character... that is all I need to do ... any code ideas? thanks for your help so far. I am sending a 1 from the Serial monitor and android app, seems like both not sending an integer

So in if statement do I check for string, i.e. if (relayOn == '1') instead? And do I change relayOn from int to char?

It's not fair to delete an answer with usefull comments from OP then after the issue was solved to show up with it. The answer wasn'there when I made my comments.

@Dorian, I am really sorry. I deleted the answer, because OP indicated that the problem is something else and the answer didn't solve it. I wrote first a similar comment then yours. It was 3th or 4th comment and was totally ignored by OP and other commenters. Then I wrote the answer and deleted the comment. Then the answer seemed to be off...

It was at least part of the solution, I would upvoted your answer if I would find-it as i did with kuskus's answer posted shortly after my comment to let op know that it really has an issue there.

@Dorian, sorry. it was a bad decision

You could try something like (not tested):
void loop() {
 if(Serial.available()){
   input = Serial.parseInt();
   Serial.print("Data: ");
   Serial.println(input);
   if(input == 1){
      digitalWrite(RELAY, HIGH);
      digitalWrite(LED, HIGH);
   }
   else if(input == 2{
      digitalWrite(RELAY, LOW);
      digitalWrite(LED, LOW);
   }
 }
}

don't forget to declare input variable, use 1 to turn on, 2 off :)

Try using serial interrupt in arduino
void loop() {
}

void serialEvent()
{
  while (Serial.available())
    {
       char inChar = (char)Serial.read();
      Serial.print("Data: ");
      Serial.println(inChar);
       if (inChar == '1')
        {
              digitalWrite(ledPin,HIGH);
              break;
        }
       else
        {
              digitalWrite(ledPin,LOW);
              break;
        }
     }
}

it is not an interrupt. https://github.com/arduino/ArduinoCore-avr/blob/5755ddea49fa69d6c505c772ebee5af5078e2ebf/cores/arduino/main.cpp#L45

but is acts as serial interrupt in arduino