# Question
Title: Having trouble reading multiple thermistors w/ Arduino 2560
I'm trying to get my code to read multiple thermistors and I can't quite seem to get it correct using my arduino 2560. The first issue is it's not reading more than the first thermistor. The next issue is the for loop that displays the current temperature always reads "TURN OFF" when its below the 60C range.

Here is my code:

```
/* Here we have a few constants that make editing the code easier. I will go
  through them one by one.

  A reading from the ADC might give one value at one sample and then a little
  different the next time around. To eliminate noisy readings, we can sample
  the ADC pin a few times and then average the samples to get something more
  solid. This constant is utilized in the readThermistor function.
  */
const int    SAMPLE_NUMBER      = 10;

/* In order to use the Beta equation, we must know our other resistor
  within our resistor divider. If you are using something with large tolerance,
  like at 5% or even 1%, measure it and place your result here in ohms. */
const double BALANCE_RESISTOR0   = 10060.0; //
const double BALANCE_RESISTOR1   = 10000.0;
const double BALANCE_RESISTOR2   = 10000.0;
const double BALANCE_RESISTOR3   = 10000.0;
const double BALANCE_RESISTOR4   = 10000.0;
const double BALANCE_RESISTOR5   = 10000.0;
const double BALANCE_RESISTOR6   = 10000.0;
const double BALANCE_RESISTOR7   = 10000.0;
const double BALANCE_RESISTOR8   = 10000.0;
const double BALANCE_RESISTOR9   = 10000.0;

// This helps calculate the thermistor's resistance (check article for details).
const double MAX_ADC            = 1023.0;

/* This is thermistor dependent and it should be in the datasheet, or refer to the
  article for how to calculate it using the Beta equation.
  I had to do this, but I would try to get a thermistor with a known
  beta if you want to avoid empirical calculations. */
const double BETA               = 3977.0;

/* This is also needed for the conversion equation as "typical" room temperature
  is needed as an input. */
const double ROOM_TEMP          = 295.950;   // room temperature in Kelvin

/* Thermistors will have a typical resistance at room temperature so write this
  down here. Again, needed for conversion equations. */
const double RESISTOR_ROOM_TEMP = 10980.0;

//===============================================================================
//  Variables
//===============================================================================
// Here is where we will save the current temperature
double currentTemperature = 0;

//===============================================================================
//  Pin Declarations
//===============================================================================
//Inputs:
int thermistorPin0 = 0;  // Where the ADC samples the resistor divider's output
int thermistorPin1 = 1;
int thermistorPin2 = 2;
int thermistorPin3 = 3;
int thermistorPin4 = 4;
int thermistorPin5 = 5;
int thermistorPin6 = 6;
int thermistorPin7 = 7;
int thermistorPin8 = 8;

//Outputs:

//===============================================================================
//  Initialization
//===============================================================================

void setup()
{
 // Set the port speed for serial window messages
 Serial.begin(9600);
}

//===============================================================================
//  Main
//===============================================================================

//===============================================================================
//  Functions
//===============================================================================
/////////////////////////////
////// readThermistor ///////
/////////////////////////////

double readThermistor()
{
 // variables that live in this function
 double rThermistor0 = 0; // Holds thermistor resistance value
 double rThermistor1 = 0;
 double rThermistor2 = 0;
 double rThermistor3 = 0;
 double rThermistor4 = 0;
 double rThermistor5 = 0;
 double rThermistor6 = 0;
 double rThermistor7 = 0;
 double rThermistor8 = 0;

 double tKelvin0     = 0;            // Holds calculated temperature
 double tKelvin1     = 0;
 double tKelvin2     = 0;
 double tKelvin3     = 0;
 double tKelvin4     = 0;
 double tKelvin5     = 0;
 double tKelvin6     = 0;
 double tKelvin7     = 0;
 double tKelvin8     = 0;

 double tCelsius0    = 0;            // Hold temperature in celsius
 double tCelsius1    = 0;
 double tCelsius2    = 0;
 double tCelsius3    = 0;
 double tCelsius4    = 0;
 double tCelsius5    = 0;
 double tCelsius6    = 0;
 double tCelsius7    = 0;
 double tCelsius8    = 0;

 double adcAverage0  = 0;            // Holds the average voltage measurement
 double adcAverage1  = 0;
 double adcAverage2  = 0;
 double adcAverage3  = 0;
 double adcAverage4  = 0;
 double adcAverage5  = 0;
 double adcAverage6  = 0;
 double adcAverage7  = 0;
 double adcAverage8  = 0;

 int    adcSamples0[SAMPLE_NUMBER];  // Array to hold each voltage measurement
 int    adcSamples1[SAMPLE_NUMBER];
 int    adcSamples2[SAMPLE_NUMBER];
 int    adcSamples3[SAMPLE_NUMBER];
 int    adcSamples4[SAMPLE_NUMBER];
 int    adcSamples5[SAMPLE_NUMBER];
 int    adcSamples6[SAMPLE_NUMBER];
 int    adcSamples7[SAMPLE_NUMBER];
 int    adcSamples8[SAMPLE_NUMBER];

 /* Calculate thermistor's average resistance:
    As mentioned in the top of the code, we will sample the ADC pin a few times
    to get a bunch of samples. A slight delay is added to properly have the
    analogRead function sample properly */

 for (int i = 0; i < SAMPLE_NUMBER; i++)
 {
   adcSamples0[i] = analogRead(thermistorPin0);  // read from pin and store
   adcSamples1[i] = analogRead(thermistorPin1);
   adcSamples2[i] = analogRead(thermistorPin2);
   adcSamples3[i] = analogRead(thermistorPin3);
   adcSamples4[i] = analogRead(thermistorPin4);
   adcSamples5[i] = analogRead(thermistorPin5);
   adcSamples6[i] = analogRead(thermistorPin6);
   adcSamples7[i] = analogRead(thermistorPin7);
   adcSamples8[i] = analogRead(thermistorPin8);

   delay(10);        // wait 10 milliseconds
 }

 /* Then, we will simply average all of those samples up for a "stiffer"
    measurement. */
 for (int i = 0; i < SAMPLE_NUMBER; i++)
 {
   adcAverage0 += adcSamples0[i];      // add all samples up . . .
   adcAverage1 += adcSamples1[i];
   adcAverage2 += adcSamples2[i];
   adcAverage3 += adcSamples3[i];
   adcAverage4 += adcSamples4[i];
   adcAverage5 += adcSamples5[i];
   adcAverage6 += adcSamples6[i];
   adcAverage7 += adcSamples7[i];
   adcAverage8 += adcSamples8[i];

 }
 adcAverage0 /= SAMPLE_NUMBER;        // . . . average it w/ divide
 adcAverage1 /= SAMPLE_NUMBER;
 adcAverage2 /= SAMPLE_NUMBER;
 adcAverage3 /= SAMPLE_NUMBER;
 adcAverage4 /= SAMPLE_NUMBER;
 adcAverage5 /= SAMPLE_NUMBER;
 adcAverage6 /= SAMPLE_NUMBER;
 adcAverage7 /= SAMPLE_NUMBER;
 adcAverage8 /= SAMPLE_NUMBER;

 /* Here we calculate the thermistor’s resistance using the equation
    discussed in the article. */
 rThermistor0 = BALANCE_RESISTOR0 * ( (MAX_ADC / adcAverage0) - 1);
 rThermistor1 = BALANCE_RESISTOR1 * ( (MAX_ADC / adcAverage1) - 1);
 rThermistor2 = BALANCE_RESISTOR2 * ( (MAX_ADC / adcAverage2) - 1);
 rThermistor3 = BALANCE_RESISTOR3 * ( (MAX_ADC / adcAverage3) - 1);
 rThermistor4 = BALANCE_RESISTOR4 * ( (MAX_ADC / adcAverage4) - 1);
 rThermistor5 = BALANCE_RESISTOR5 * ( (MAX_ADC / adcAverage5) - 1);
 rThermistor6 = BALANCE_RESISTOR6 * ( (MAX_ADC / adcAverage6) - 1);
 rThermistor7 = BALANCE_RESISTOR7 * ( (MAX_ADC / adcAverage7) - 1);
 rThermistor8 = BALANCE_RESISTOR8 * ( (MAX_ADC / adcAverage8) - 1);

 /* Here is where the Beta equation is used, but it is different
    from what the article describes. Don't worry! It has been rearranged
    algebraically to give a "better" looking formula. I encourage you
    to try to manipulate the equation from the article yourself to get
    better at algebra. And if not, just use what is shown here and take it
    for granted or input the formula directly from the article, exactly
    as it is shown. Either way will work! */
 tKelvin0 = (BETA * ROOM_TEMP) /
           (BETA + (ROOM_TEMP * log(rThermistor0 / RESISTOR_ROOM_TEMP)));

 tKelvin1 = (BETA * ROOM_TEMP) /
           (BETA + (ROOM_TEMP * log(rThermistor1 / RESISTOR_ROOM_TEMP)));

 tKelvin2 = (BETA * ROOM_TEMP) /
           (BETA + (ROOM_TEMP * log(rThermistor2 / RESISTOR_ROOM_TEMP)));

 tKelvin3 = (BETA * ROOM_TEMP) /
           (BETA + (ROOM_TEMP * log(rThermistor3 / RESISTOR_ROOM_TEMP)));

 tKelvin4 = (BETA * ROOM_TEMP) /
           (BETA + (ROOM_TEMP * log(rThermistor4 / RESISTOR_ROOM_TEMP)));

 tKelvin5 = (BETA * ROOM_TEMP) /
           (BETA + (ROOM_TEMP * log(rThermistor5 / RESISTOR_ROOM_TEMP)));

 tKelvin6 = (BETA * ROOM_TEMP) /
           (BETA + (ROOM_TEMP * log(rThermistor6 / RESISTOR_ROOM_TEMP)));

 tKelvin7 = (BETA * ROOM_TEMP) /
           (BETA + (ROOM_TEMP * log(rThermistor7 / RESISTOR_ROOM_TEMP)));

 tKelvin8 = (BETA * ROOM_TEMP) /
           (BETA + (ROOM_TEMP * log(rThermistor8 / RESISTOR_ROOM_TEMP)));

 /* I will use the units of Celsius to indicate temperature. I did this
    just so I can see the typical room temperature, which is 25 degrees
    Celsius, when I first try the program out. I prefer Fahrenheit, but
    I leave it up to you to either change this function, or create
    another function which converts between the two units. */
 tCelsius0 = tKelvin0 - 273.15;  // convert kelvin to celsius
 tCelsius1 = tKelvin1 - 273.15;
 tCelsius2 = tKelvin2 - 273.15;
 tCelsius3 = tKelvin3 - 273.15;
 tCelsius4 = tKelvin4 - 273.15;
 tCelsius5 = tKelvin5 - 273.15;
 tCelsius6 = tKelvin6 - 273.15;
 tCelsius7 = tKelvin7 - 273.15;
 tCelsius8 = tKelvin8 - 273.15;

 return tCelsius0; // Return the temperature in
 return tCelsius1;
 return tCelsius2;
 return tCelsius3;
 return tCelsius4;
 return tCelsius5;
 return tCelsius6;
 return tCelsius7;
 return tCelsius8;

}

void loop()
{
 /* The main loop is pretty simple, it prints what the temperature is in the
    serial window. The heart of the program is within the readThermistor
    function. */
 currentTemperature = readThermistor();
 delay(3000);

 /* Here is how you can act upon a temperature that is too hot,
 too cold or just right. */
 if (currentTemperature > 0.0 && currentTemperature < 60.0)
 {
   Serial.print("It is ");
   Serial.print(currentTemperature);

 }
 else (currentTemperature >= 60.0);

 {
   Serial.print("It is ");
   Serial.print(currentTemperature);
   Serial.println("C. SHUT OFF!");
 }
}

```

I'm no expert in coding, so if you have any suggestions that could help, I would very much appreciate it.

# Answer
Welcome to Stack Exchange!

The problem causing the first issue is your multiple `return` statements in the `readThermistor` function. `return` exits the function, so when the code runs `return tCelsius0` it will exit the function and not run any of the later return statements.

Try storing your temperatures in an array and then returning that array. However, you also only read one of the values in the `main()` function anyway.

The problem causing the second issue is you have an `if` and an `else`. To properly check for your second condition `currentTemperature >= 60.0`, you need to have an `else if` instead.
> 2 votes

---
Tags: arduino-mega, c++, temperature-sensor, thermistor
---


# Question
Title: Can I change the text on the LCD by rotating the potentiometer?
I am working on a project on my Arduino Uno in which I want to change the text on the LCD every time the potentiometer has been rotated. In order to do this, I have stored the angle values into an `int`, constantly check if the angle has been rotated enough to change the text, and if it has, print the next message. I am not sure if either my code or circuit is wrong as nothing happens at all when i rotate the potentiometer.

Here is my code so far and an image of the circuit (the innermost potentiometer is for the brightness, the one on the right is for changing the text on the LCD. I think I may have wired the second potentiometer incorrectly but I am not sure how to fix this).

```
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // removed 3
// set up a constant for the button
const int buttonPin = 6;
// variable to hold the value of the button
int buttonState = 0;
// variable to hold previous value of the button
//int prevbuttonState = 0;
// a variable to choose which reply will be displayed
int reply = -1;
int prevReply = -1;
int potPin = A0;
int potVal = 0;
int angle = 0;
int prevAngle = 0;
//int startTime = 0;
//int timeElasped = 0;
//int workoutTime = 0;

void setup() {
  // set up the number of columns and rows on the LCD
  lcd.begin(16, 2);

  // set up the switch pin as an input
  pinMode(buttonPin, INPUT);

  Serial.begin(9600);
  prevAngle = map(potVal,0,1023,0,300); // set prevAngle to original angle. later, code that if the angle isnt 0 tell user to reset it
  // Print a message to the LCD.
  lcd.print("Pick a");
  // set the cursor to column 0, line 1
  // line 1 is the second row, since counting begins with 0
  lcd.setCursor(0, 1);
  // print to the second line
  lcd.print("Muscle Group!");
}

void loop() {
  // check the status of the switch
  buttonState = digitalRead(buttonPin);
  potVal = analogRead(potPin);
  Serial.print("potVal: ");
  Serial.print(potVal);
  angle=map(potVal,0,1023,0,300);//used to be 179, changed to 300 assuming it equals the max angle available in the potentiometer
  Serial.print(", angle: ");
  Serial.println(angle);
  if (angle > prevAngle+69){ // if the pot has been rotated enough clockwise, display next group
    if (reply!=3)
      reply = reply+1;//provide next muscle group
    else
      reply = 0;//return to first muscle group
    /*if (prevReply==-1)
      prevReply=reply;*/
  }
  else if (angle < prevAngle-69){ // if the pot has been rotated enough counterclockwise, display prev group
    if (reply!=0 && reply!=-1)
      reply = reply-1;//provide previous muscle group
    else if (reply==0)// check if reply is still equal to -1 btw
      reply = 3;//return to last muscle group
    else if (reply==-1){
      reply = 0;
      //prevReply=reply;
    }
  }
  //prevReply = reply;
  if (buttonState == HIGH) { //if the button has been pressed, display new random exercise within muscle group that was chosen
      if (reply == 0)
        reply = random(4,6);
      if (reply == 1)
        reply = random(7,9);
      if (reply == 2)
        reply = random(10,12);
      if (reply == 3)
        reply = random(13,15);
      // clean up the screen before printing a new reply
      lcd.clear();
      // set the cursor to column 0, line 0
      lcd.setCursor(0, 0);
      // print some text
      lcd.print("Time to do some");
      // move the cursor to the second line
      lcd.setCursor(0, 1);
      delay(500);
      lcd.clear();
      lcd.setCursor(0, 0);
      /*if (workoutTime - millis() + startTime==0){
           lcd.clear();
           lcd.setCursor(0, 0);
           lcd.print("You did it!! :]"); //if reply keeps looping, stop loop once timer=0. if reply never loops, figure out how to make it loop for the timer*/
      }
      //if (prevReply != reply) // if we have chosen a new workout, change the starting time
        //startTime = millis(); // record millis() function to see how much time passes btwn start of program to start of timer
      if (prevReply != reply){
      switch (reply) { // choose a saying to print based on the value in reply
        case 0:
          lcd.print("Arms");
          break;

        case 1:
          lcd.print("Core");
          break;

        case 2:
          lcd.print("Chest");
          break;

        case 3:
          lcd.print("Legs");
          break;

        case 4:
          //workoutTime = 2400;
          lcd.print("Arm wrkt 1; " /*+ workoutTime - millis() + startTime*/); // temporary workout names, to be replaced in a later draft
          break;

        case 5:
          //workoutTime = 1200;
          lcd.print("Arm wrkt 2; " /*+ workoutTime - millis() + startTime*/);
          break;

        case 6:
          //workoutTime = 1500;
          lcd.print("Arm wrkt 3; " /*+ workoutTime - millis() + startTime*/);
          break;

        case 7:
          //workoutTime = 1800;
          lcd.print("Core wrkt 1; " /*+ workoutTime - millis() + startTime*/);
          break;

        case 8:
          //workoutTime = 900;
          lcd.print("Core wrkt 2; " /*+ workoutTime - millis() + startTime*/);
          break;

        case 9:
          //workoutTime = 2400;
          lcd.print("Core wrkt 3; " /*+ workoutTime - millis() + startTime*/);
          break;

        case 10:
          //workoutTime = 2100;
          lcd.print("Chest wrkt1; " /* + workoutTime - millis() + startTime*/);
          break;

        case 11:
          //workoutTime = 1200;
          lcd.print("Chest wrkt2; " /* + workoutTime - millis() + startTime*/);
          break;

        case 12:
          //workoutTime = 1200;
          lcd.print("Chest wrkt3; " /* + workoutTime - millis() + startTime*/);
          break;

        case 13:
          //workoutTime = 1500;
          lcd.print("Leg wrkt 1; " /* + workoutTime - millis() + startTime*/);
          break;

        case 14:
          //workoutTime = 2400;
          lcd.print("Leg wrkt 2; " /* + workoutTime - millis() + startTime*/);
          break;

        case 15:
          //workoutTime = 1800;
          lcd.print("Leg wrkt 3; " /*+ workoutTime - millis() + startTime*/);
          break;
        prevReply=reply;
      }
  }
  prevAngle=angle;
}

```

# Answer
Here is a (heavily) stripped-down version of your code:

```
void loop() {
    potVal = analogRead(potPin);
    angle = map(potVal, 0, 1023, 0, 300);
    if (angle > prevAngle + 69) {
        // stuff...
    } else if (angle < prevAngle - 69) {
        // stuff...
    }
    // lots of more stuff...
    prevAngle = angle;
}

```

Imagine this executing a few thousand times a second. Each time, it computes the angle of the potentiometer's knob, then copies the computed angle into `prevAngle`. Unless you turn the pot *really* fast, the angle is unlikely to change by more than 69° in that fraction of a millisecond.

I suggest *not* updating `prevAngle` on every iteration. Instead, let `angle` slowly drift away from `prevAngle` through many iterations of the loop. When the two are more than 69° apart, then you take the action you wanted to take, *and only then* you update `prevAngle`.
> 2 votes

---
Tags: arduino-uno, lcd, potentiometer
---


# Question
Title: Obtaining wrong analog readings using the ESP32 devkitc v4
I know that the topic is not related to Arduino, but I am completely sure that someone can help me find the problem. I am testing 6 temperature sensors (3 digital, 3 analog). The digital ones are "DS18B20" which I trust, the analog ones are "MCP9701A", "TC1047A" and "MCP9700A". By reading the analog sensors using Arduino-UNO or Arduino-mega the results of the 6 sensors are almost identical and I don't face any problem. But when make the test using the ESP32-devkitc-v4 I obtain wrong reading from the 3 analog sensors. In the code "serial monitor" I obtain a voltage value completely different from the one I measure physically by a multi-meter

For example : The 3 digital sensors a giving the value of 23.56C to 23.81C but for the "MCP9701A" analog sensor I obtain 16.26C and the voltage obtain in the serial monitor is 0.718 volts, however it is 0.851 volts by the multi-meter. And according to the calculations from the data-sheet: (0.851-0.4)/(19.5mVolts)= 23.12C which is so close to the digital sensors. I have the same problem with the other analog sensors, so if you can help me find my error, I will appreciate it.

Here are the data-sheets of the analog sensors:

**MCP9701A and MCP9711A**

https://ww1.microchip.com/downloads/en/DeviceDoc/20001942G.pdf

**TC1047A**

https://ww1.microchip.com/downloads/en/DeviceDoc/21498D.pdf

**Here is my code:**

```
#include <OneWire.h>
#include <DallasTemperature.h>
#include "driver/adc.h"

// GPIO where the DS18B20 is connected to
const int oneWireBus = 4;
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(oneWireBus);

// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);

#define analogInPin0 35
#define analogInPin1 32
#define analogInPin2 33

float analogTempTC1047=0.0;
float analogTempMCP9700=0.0;
float analogTempMCP9701=0.0;

float volt0=0.0;
float volt1=0.0;
float volt2=0.0;

int sensorValue0 = 0;
int sensorValue1 = 0;
int sensorValue2 = 0;

void setup() {
  // Start the Serial Monitor
  Serial.begin(9600);
  // Start the DS18B20 sensor
  sensors.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  sensorValue0 = analogRead(analogInPin0);
  sensorValue1 = analogRead(analogInPin1);
  sensorValue2 = analogRead(analogInPin2);

  volt0= (3.3/4096.0)*sensorValue0;
  analogTempMCP9701= ((volt0-0.4)/0.0195);

  volt1= (3.3/4096.0)*sensorValue1;
  analogTempTC1047= ((volt1-0.5)/0.01);

  volt2= (3.3/4096.0)*sensorValue2;
  analogTempMCP9700= ((volt2-0.5)/0.01);

  sensors.requestTemperatures();
  float temperatureC1 = sensors.getTempCByIndex(0);
  float temperatureC2 = sensors.getTempCByIndex(1);
  float temperatureC3 = sensors.getTempCByIndex(2);
  Serial.print("S1= ");
  Serial.print(temperatureC1);
  Serial.print("ºC");
  Serial.print(", S2= ");
  Serial.print(temperatureC2);
  Serial.print("ºC");
  Serial.print(", S3= ");
  Serial.print(temperatureC3);
  Serial.print("ºC,------- ");

  Serial.print("input sensor1= ");
  Serial.print(sensorValue0);
  Serial.print(", volt1=  ");
  Serial.print("= ");
  Serial.print(volt0, 3);
  Serial.print(", Analog sensor MCP9701 = ");
  Serial.print(analogTempMCP9701);

  Serial.print("----");
  Serial.print("input sensor2= ");
  Serial.print(sensorValue1);
  Serial.print(", volt2=  ");
  Serial.print("= ");
  Serial.print(volt1, 3);
  Serial.print(" --Analog sensor TC1047 = ");
  Serial.print(analogTempTC1047);

  Serial.print("----");
  Serial.print("input sensor3= ");
  Serial.print(sensorValue2);
  Serial.print(", volt2=  ");
  Serial.print("= ");
  Serial.print(volt2, 3);
  Serial.print(" --Analog sensor MCP9700 = ");
  Serial.println(analogTempMCP9700);
  delay(4000);
}

```

**And here is the serial monitor output:**

```
S1= 23.56ºC, S2= 23.81ºC, S3= 23.50ºC,------- input sensor1= 895, volt1=  = 0.721, Analog sensor MCP9701 = 16.47----input sensor2= 747, volt2=  = 0.602 --Analog sensor TC1047 = 10.18----input sensor3= 752, volt2=  = 0.606 --Analog sensor MCP9700 = 10.59
S1= 23.56ºC, S2= 23.75ºC, S3= 23.50ºC,------- input sensor1= 894, volt1=  = 0.720, Analog sensor MCP9701 = 16.42----input sensor2= 747, volt2=  = 0.602 --Analog sensor TC1047 = 10.18----input sensor3= 755, volt2=  = 0.608 --Analog sensor MCP9700 = 10.83
S1= 23.56ºC, S2= 23.75ºC, S3= 23.50ºC,------- input sensor1= 905, volt1=  = 0.729, Analog sensor MCP9701 = 16.88----input sensor2= 746, volt2=  = 0.601 --Analog sensor TC1047 = 10.10----input sensor3= 753, volt2=  = 0.607 --Analog sensor MCP9700 = 10.67

```

# Answer
Not a full answer, only a direction to consider:

The ESP32 ADC seems to be shipped with a ADC calibration tolerance of ±6%, as stated in the ESP32 datasheet, chapter 4.1.2. Here are the calibration docs.

It seems like you're still off by more than those 6% (didn't calculate it through). Maybe your power supply is a bit weak, pulling the internal reference voltage down?
> 0 votes

---
Tags: esp32, espressif
---


# Question
Title: What is the minimum sampling rate in ADC in Arduino due?
I am looking for a very low frequency application like below 300Hz. What is the minimum sampling rate in Arduino due? I am very new to this. I see in the datasheet that max sampling rate is 20MHz.

# Answer
There is no "minimum" sampling rate.

You can better understand why that would be if you first understand how *Successive Approximation* ADCs operate.

An SAR ADC is simply a small capacitor, a DAC, and a comparator - along with a number of digital switches. When you perform a sampling the capacitor is first connected to the IO pin for an amount of time. The capacitor then charges up to the level of the incoming signal. Then the capacitor is disconnected from the IO pin and instead connected to the comparator. The DAC is then used to generate a sequence of voltages which the comparator then compares against the voltage in the capacitor - one voltage for each bit of resolution.

The maximum sampling rate is defined by how long the capacitor takes to be charged up by the incoming voltage. A bigger capacitor will take longer to charge up and thus give you a lower maximum sampling speed. A smaller capacitor charges faster, giving you higher sampling speeds.

However there is a big caveat: a smaller capacitor holds its charge for a shorter length of time, so getting an accurate reading from it when you have to hold the voltage for a number of cycles while you do successive comparisons can be hard. For this reason it's common to reduce the sampling resolution for higher sampling speeds: switch in a smaller capacitor, but take less time to sample it with less bits of data.

So from that it stands to reason that there is a minimum amount of time that you want the capacitor connected to the IO pin, and a predefined amount of time required to perform the comparisons, but there is no lower limit on how long the capacitor can be connected to the IO pin - it will just track the voltage changes for a while until the moment it's switched to conversion mode and the current voltage is captured (successive approximation ADCs are also known as sample-and-hold for this reason). And of course there is no requirement to immediately start a new sampling of the IO pin immediately you have finished a conversion. You can wait any amount of time before triggering a new ADC conversion. Seconds, weeks, decades...

This of course is all for *manual* triggering of the ADC. If you want automatic triggering from one of the internal timers then the minimum sampling speed will be whatever you can configure the timer to. And we can't tell you that, since timers can be configured to run from different clock sources, including your own external clock signal running at whatever speed you like.

So for automatic conversions you should not be looking at the ADC, other than to find what clock sources and interrupts can be used to trigger a conversion, and instead look at the relevant timer sections in the datasheet to work out what frequency you can configure those for to suit your needs.
> 1 votes

---
Tags: arduino-due, adc, frequency
---


# Question
Title: Why is the server.on() function from "ESPAsyncWebServer.h" executed in the setup() side and not on the loop() side?
I'm implementing an example in which 2 ESP32's communicate each other using the HTTP Protocol. One acts as Server the other as Client. In the examples provided, I am curious about the declaration on the server, as its implementation is declared in the setup() function (I am using the standard Arduino IDE), which is supposed to have code that executes only once, rather than the loop() function (at least in this example), which is supposed to refresh the call every cycle, yet it remains empty:

```
  Complete project details at https://RandomNerdTutorials.com/esp32-client-server-wi-fi/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

// Import required libraries
#include "WiFi.h"
#include "ESPAsyncWebServer.h"

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

// Set your access point network credentials
const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";

/*#include <SPI.h>
#define BME_SCK 18
#define BME_MISO 19
#define BME_MOSI 23
#define BME_CS 5*/

Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

String readTemp() {
  return String(bme.readTemperature());
  //return String(1.8 * bme.readTemperature() + 32);
}

String readHumi() {
  return String(bme.readHumidity());
}

String readPres() {
  return String(bme.readPressure() / 100.0F);
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);
  Serial.println();

  // Setting the ESP as an access point
  Serial.print("Setting AP (Access Point)…");
  // Remove the password parameter, if you want the AP (Access Point) to be open
  WiFi.softAP(ssid, password);

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

  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readTemp().c_str());
  });
  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readHumi().c_str());
  });
  server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readPres().c_str());
  });

  bool status;

  // default settings
  // (you can also pass in a Wire library object like &Wire2)
  status = bme.begin(0x76);
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  // Start server
  server.begin();
}

void loop(){

}

```

You can see the "server.on(....)" declarations in the setup() side of the code, and the empty loop() function in the end.

```
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readTemp().c_str());
  });

```

So, my assumption is that the server is already running in the background when executing server.begin() and does not need to be explicitly called, but it still confuses me because there is no explicit declaration on the loop() such as server.loop() or something similar. Can you explain how this works and why it is not necessary to explicitly declare the function on the loop()?

Thanks -EZ

# Answer
> 1 votes
`Server.on()` sets a *callback function*. That registers a function to be executed when a certain event happens at a later date. In this case it's when a certain URL is requested with a `GET` method.

Any time a request is made to the web server a list of "on" registered events is examined for one that matches the request, then the associated function (in this case a *lambda function*) is executed.

And all that is done *asynchronously* (hence the name) in the background in another thread so you don't need to explicitly do anything.

# Answer
> 1 votes
The construct with a lambda function

```
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readTemp().c_str());
  });

```

is same as

```
server.on("/temperature", HTTP_GET, onGetTemperature);

```

where `onGetTemperature` is a function defined before `void setup()`

```
void onGetTemperature(AsyncWebServerRequest *request) {
  request->send_P(200, "text/plain", readTemp().c_str());
}

```

Would you in this case ask why it is "executed in the setup()?"

# Answer
> 0 votes
Yes, `server.on()` is a callback function, but that's not the entirety of the story.

You don't see anything related to the server in `loop()` either, because somewhere in the backend of all that code, probably in `server.begin()`, the server attaches a callback or ISR of its own to the networking stack of the ESP. Now, when the ESP gets a message across the network of the right type, the networking stack redirects the message into the server's internal callback, at which point the server checks the page that was viewed and executes the appropriate `server.on`-specified function that you put in `setup()`.

I haven't yet had the chance to look into exactly how the server's callback is attached to the networking stack, but that's how it operates asynchronously. Either it's originally activated by a Wi-Fi hardware ISR (allowing it to temporarily pause your code's execution to run the server) or it's run by a small scheduler-like section of code that is executed outside of `loop()` (meaning that between iterations of `loop()`, it might be handling the server. It's probably this case since this is when some parts of the networking stack are handled anyway).

One minor note: this operation has a potential side effect of causing memory use or CPU use by the server when you might have *intended* to allocate either to your own application code, so if you start seeing odd timing errors or memory corruption on a *really* large application, you may want to look into this as a potential cause.

---
Tags: c++, esp32, web-server
---


title: Bootloader For Atmega4809

text:
# Question
Title: Bootloader For Atmega4809
I have designed a project using Arduino Every board which uses MCU Atmega4809 chip and I have used Arduino IDE for programming but now I am planning to design my custom board I have used schematics of Arduino every board available on Arduino website . how can i upload the bootloader (Where can I get the bootloader from ) and how can I upload the Arduino code on new Atmega4809 Chips.

# Answer
> 2 votes
Nano Every doesn't use a bootloader. The ATmega4809 on Nano Every is flashed with the SAMD11 used as UPDI programmer with Arduino firmware.

Optiboot supports ATmega4809 and MCUDude MegaCoreX supports different ATmega4809 configurations and Optiboot.

---
Tags: bootloader, arduino-nano-every
---


# Question
Title: How do I keep one function continued until a variable is completed?
The code's purpose is to change from one led to another if the LDR detects a certain level of light for a given time. Currently, since I cannot wait 5 minutes to complete one circuit, each LED should be on for 1000 ms. At one stage in the code, there are no LEDs on. The LEDs should not turn on until the LDR has sensed no light and then light levels necessary for the code to restart.

Here is the code;

```
const int buzzer=3;
const int ldr = A4;

void setup () {
    Serial.begin(9600);
    pinMode(13, OUTPUT);
    pinMode(12, OUTPUT);
    pinMode(buzzer, OUTPUT);
    pinMode(ldr, INPUT);
}

void loop() {
    int ldrStatus = analogRead(ldr);

    if (ldrStatus >= 300) {
        digitalWrite(13, HIGH);
        delay(1000);
    } else {
        noTone(buzzer);
        digitalWrite(13, LOW);
        digitalWrite(12, LOW);
    }

    if (ldrStatus >= 300) {
        digitalWrite(13, LOW);
        digitalWrite(12, HIGH);
        tone(buzzer, 100, 30);
        delay(1000);
        tone(buzzer, 100);
        digitalWrite(12, LOW);
        digitalWrite(13, LOW);
    } else {
        noTone(buzzer);
        digitalWrite(13, LOW);
        digitalWrite(12, LOW);
    }
}

```

I have realised that the purpose of my code is unclear. What happens is one LED turns on when the LDR senses light. If the light continues, then the buzzer will sound once and the LED will change to a different colour LED. If the LDR continues to detect light, then all LEDs will turn off and the buzzer will sound continuously. The only problem is that the code doesn't stop until the LDR has sensed a high enough decrease in light levels.

# Answer
> 1 votes
You have a couple of issues in your code.

Analog inputs are versatile and (most) can be used as digital inputs (ie. on/off). For this application you are after the analog value of the LDR, however this is not how you have implemented it. You are declaring the LDR pin as a digital pin by `pinmode(ldr, INPUT)`. Delete this line altogether. For reference, see the analog read documentation.

Secondly you have two `if` statements that are the same.

```
if (ldrStatus>=300) {
  digitalWrite(13, HIGH);

```

and

```
if (ldrStatus>=300) {
  digitalWrite(13, LOW);

```

I suspect that one of them is supposed to be a less than `<` sign.

Both LEDS are off beause it is executing this section of code:

```
}else{
  noTone (buzzer);
  digitalWrite (13, LOW);
  digitalWrite (12, LOW);

```

}

I suggest you add `Serial.println()` lines (documentation here) to your code for debugging. Particularly helpful would be to add it in the `if` and `else` statements as well as adding `Serial.println(ldrStatus)` as follows:

```
int ldrStatus=analogRead(ldr);
Serial.println(ldrStatus);
if (ldrStatus>=300) {

```

Refer to this document on how to open your Serial Monitor in the Arduino Software (IDE).

Bonus Hint:
You can auto-format your code by using `ctrl + T`. See this article for more info.

---
Tags: arduino-uno, led
---


title: How to process 20-bit sensor data

text:
# Question
Title: How to process 20-bit sensor data
I have an acceleration sensor (**ADXL355**) that returns 20-bit data in three bytes, formatted as **2s complement** :

* acc3 (bits 19-12) in byte register 3 (mapped to bits 7-0)
* acc2 (bits 11-4) in byte register 2 (mapped to bits 7-0)
* acc1 (bits 3-0) in byte register 1 (mapped to bits 7-4 while 3-0 are unused)

the acceleration value is taken as a signed 32 bit integer from the above 3 registers as follows :

```
int32_t acc32 = ((uint32_t)acc3 << 12) | ((uint16_t)acc2 << 4) | (acc1 >> 4);

if (acc32 & (1UL << 19)) acc32 -= 1UL << 20;

```

Then, I am doing some statistical analysis on acceleration values to calculate an offset trim as a signed 32 bit integer.

```
int32 off32;

```

This offset has to be written back to sensor as a 16 bit 2s complement value as follows :

* offset high byte (bits 15-8)
* offset low byte (bits 7-0)

The datasheet says that "***The significance of offset bits 15-0 matches the significance of acceleration bits 19-4***".

I found this rather tricky so I am asking how to convert this signed 32 bit offset integer to a 16 bit offset integer that follows the above specification.

I had this idea but don't know whether it is correct :

```
int16_t off16[i] = (int16_t)(off32[i] / 16);

sendSPI((uint8_t)(off16 >> 8));
sendSPI((uint8_t)off16);

```

Any comment should be greatly appreciated !

# Answer
Other than the subscript `[i]`, which looks suspicious, what you did seems perfectly correct to me. Now, if I go nitpicking, I may suggest:

* use a bit shift, as it is way cheaper than a division
* round to nearest, rather than towards zero or minus infinity.

This gives:

```
int16_t off16 = (off32 + 8) >> 4;

```

Note that the bit shift behaves like a division that rounds towards −∞ (regular division rounds towards zero). Adding 8 achieves round-to-nearest, with ties rounded up.
> 2 votes

---
Tags: c, accelerometer
---


# Question
Title: Displaying multiple temperature outputs w/Thermistors
So I asked this question a couple days ago but did some more work with some of the coding, but I'm really stuck and need some help. I'm trying to display the temperature for each separate thermistor from input pins A0-A8 on the 2560 board. My current issue that it only reads the A8 input pin. Do I need to make more declarations such as "double readThermistor1, double readThermistor2..." etc. After I make those declarations, how would I go about displaying each separate thermistor? I'll post what I have so far:

```

//  Constants

const int    SAMPLE_NUMBER      = 10;
const double BALANCE_RESISTOR   = 10000.0;
const double MAX_ADC            = 1023.0;
const double BETA               = 3977.0;
const double ROOM_TEMP          = 298.15;   // room temperature in Kelvin
const double RESISTOR_ROOM_TEMP = 10060.0;

// Here is where we will save the current temperature
double currentTemperature = 0;

//  Pin Declarations

//Inputs:

int thermistorPin[] = {A0,A1,A2,A3,A4,A5,A6,A7,A8};  // Where the ADC samples the resistor divider's output

//Outputs:

void setup()
{
  // Set the port speed for serial window messages
  Serial.begin(9600);
}

double readThermistor()
{
  // variables that live in this function
  double rThermistor = 0;            // Holds thermistor resistance value
  double tKelvin     = 0;            // Holds calculated temperature
  double tCelsius    = 0;            // Hold temperature in celsius
  double adcAverage  = 0;            // Holds the average voltage measurement
  int    adcSamples[SAMPLE_NUMBER];  // Array to hold each voltage measurement

  /* Calculate thermistor's average resistance:
     As mentioned in the top of the code, we will sample the ADC pin a few times
     to get a bunch of samples. A slight delay is added to properly have the
     analogRead function sample properly */

  for (int i = 0; i < SAMPLE_NUMBER; i++)
  {
    adcSamples[i] = analogRead(thermistorPin[0]);  // read from pin and store
    delay(10);        // wait 10 milliseconds
    adcSamples[i] = analogRead(thermistorPin[1]);
    delay(10);        // wait 10 milliseconds
    adcSamples[i] = analogRead(thermistorPin[2]);  // read from pin and store
    delay(10);        // wait 10 milliseconds
    adcSamples[i] = analogRead(thermistorPin[3]);  // read from pin and store
    delay(10);        // wait 10 milliseconds
    adcSamples[i] = analogRead(thermistorPin[4]);  // read from pin and store
    delay(10);        // wait 10 milliseconds
    adcSamples[i] = analogRead(thermistorPin[5]);  // read from pin and store
    delay(10);        // wait 10 milliseconds
    adcSamples[i] = analogRead(thermistorPin[6]);  // read from pin and store
    delay(10);        // wait 10 milliseconds
    adcSamples[i] = analogRead(thermistorPin[7]);  // read from pin and store
    delay(10);        // wait 10 milliseconds
    adcSamples[i] = analogRead(thermistorPin[8]);  // read from pin and store
    delay(10);        // wait 10 milliseconds
  }

  /* Then, we will simply average all of those samples up for a "stiffer"
     measurement. */
  for (int i = 0; i < SAMPLE_NUMBER; i++)
  {
    adcAverage += adcSamples[i];      // add all samples up . . .
  }
  adcAverage /= SAMPLE_NUMBER;        // . . . average it w/ divide

  rThermistor = BALANCE_RESISTOR * ( (MAX_ADC / adcAverage) - 1);

  tKelvin = (BETA * ROOM_TEMP) /
            (BETA + (ROOM_TEMP * log(rThermistor / RESISTOR_ROOM_TEMP)));

  tCelsius = tKelvin - 273.15;  // convert kelvin to celsius

  return tCelsius;    // Return the temperature in Celsius
}

void loop()

{
  currentTemperature = readThermistor();
  delay(3000);

  /* Here is how you can act upon a temperature that is too hot,
  too cold or just right. */
  if (currentTemperature > 0.0 && currentTemperature < 60.0)
  {
    Serial.print("It is ");
    Serial.print(currentTemperature);
    Serial.println("C. Ahhh, very nice temperature.");

  }
  else if (currentTemperature >= 60.0)
  {
    Serial.print("It is ");
    Serial.print(currentTemperature);
    Serial.println("C. I feel like a hot tamale!");
  }
}

```

Any help is appreciated, thank you.

# Answer
Here is my proposal:

Sum the readings (samples) of each sensor(thermistor) and store the sum in an array. Then divide each sum by the number of samples that were taken. Instead of computing one tCelsius, compute one tCelsius for each average values and store it in an array too. Then print each of them. Feel free to print it as you like.

BTW I did not compile and test the code. There might be errors in it. Use it as a hint/example.

```
const int    SAMPLE_NUMBER      =    10;
const double BALANCE_RESISTOR   = 10000.0;
const double MAX_ADC            =  1023.0;
const double BETA               =  3977.0;
const double ROOM_TEMP          =   298.15;
const double RESISTOR_ROOM_TEMP = 10060.0;

// PIN_COUNT is the length of the thermistorPin list.
const double PIN_COUNT = 9;
int thermistorPin[] = {A0,A1,A2,A3,A4,A5,A6,A7,A8};

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

double readThermistor()
{
  double rThermistor = 0.0;
  double tKelvin     = 0.0;

  // The count of the zeros below should be equal
  // to the PIN_COUNT
  double tCelsius[]
           = {0.0, 0.0, 0.0, 0.0, 0.0,
              0.0, 0.0, 0.0, 0.0};
  double adcSampleSumPerPin[]
           = {0.0, 0.0, 0.0, 0.0, 0.0,
              0.0, 0.0, 0.0, 0.0};

  for (int i = 0; i < SAMPLE_NUMBER; i++)
  {
    for (int j = 0; j < PIN_COUNT; i++)
    {
      adcSampleSumPerPin[j] +=
                   (double) analogRead(thermistorPin[j]);
      delay(10);
    }
  }

  for (int i = 0; i < PIN_COUNT; i++)
  {
    adcSampleSumPerPin[i] /= SAMPLE_NUMBER;
    rThermistor = BALANCE_RESISTOR *
                  ((MAX_ADC / adcSampleSumPerPin[i]) - 1);
    tKelvin = (BETA * ROOM_TEMP) /
              (BETA + (ROOM_TEMP * log(rThermistor /
              RESISTOR_ROOM_TEMP)));
    tCelsius[i] = tKelvin - 273.15;
  }

  return tCelsius;
}

void loop()
{
  delay(3000);
  currentTemps = readThermistor();

  for (i = 0; i < PIN_COUNT; i++)
  {
    double currentTemperature = currentTemp[i];
    if (currentTemperature > 0.0 && currentTemperature < 60.0)
    {
      Serial.print("Sensor A");
      Serial.print(i);
      Serial.println(":");

      Serial.print("It is ");
      Serial.print(currentTemperature);
      Serial.println("C. Ahhh, very nice temperature.");
    }
    else if (currentTemperature >= 60.0)
    {
      Serial.print("Sensor A");
      Serial.print(i);
      Serial.println(":");

      Serial.print("It is ");
      Serial.print(currentTemperature);
      Serial.println("C. I feel like a hot tamale!");
    }
  }
}

```
> 1 votes

---
Tags: arduino-mega, programming, code-review, thermistor
---


title: Can't manage my calculator to work

text:
# Question
Title: Can't manage my calculator to work
Yesterday, I've got myself an arduino uno. Since I'm pretty newbie in it, I'd like to ask here for a hint, because I can't manage to make my "calculator" working. I don't have much experience in programming, but I thought, the loop should wait for one of the function called to end, instead of it, it looks like it is running all function, over again, and probably that's why I getting error in console output.

Code:

```
  #include <Key.h>
#include <Keypad.h>

const byte rows = 4;
const byte columns = 4;

char first_number;

char keyboard[rows][columns] = {
    {'1','2','3','+'},
    {'4','5','6','-'},
    {'7','8','9','/'},
    {'C','0','=','*'}
  };

byte  rowsPins[rows] = {9, 8, 7, 6};
byte columnsPins[columns] = {5, 4, 3, 2};

Keypad keys = Keypad(makeKeymap(keyboard), rowsPins, columnsPins, rows, columns);

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

int getNumber(){
    char user_input = keys.getKey();
    int value;

    if (user_input){
    switch (user_input){
          case '0':
            value = 0;
            break;
          case '1':
            value = 1;
            break;
          case '2':
            value = 2;
            break;
          case '3':
            value = 3;
            break;
          case '4':
            value = 4;
            break;
          case '5':
            value = 5;
            break;
          case '6':
            value = 6;
            break;
          case '7':
            value = 7;
            break;
          case '8':
            value = 8;
            break;
          case '9':
            value = 9;
            break;
          default:
            Serial.print("Error int");
    }
  }
  return value;
}

int calculate(int first_number, int second_number){
    char operation = keys.getKey();
    int value;

    switch(operation){
        case '+':
          value = first_number+second_number;
          break;
        case '-':
          value = first_number-second_number;
          break;
        case '*':
          value = first_number*second_number;
          break;
        case '/':
          value = first_number/second_number;
          break;
        default:
          Serial.println("Error cal");
      }
      if (value){
          Serial.println(value);
        }
     return value;
  }

void loop(){

  int first_number = getNumber();
  int second_number = getNumber();
  int test = calculate(first_number, second_number);
}

```

What I wanted to do, is read numeric input from the keypad twice (it's just for now. I know it should be done different), and then, input the operation, such as multiply, but since the loop calling the function all over again, I can't actually do it. How I should approach it?

# Answer
> 2 votes
Consider this excerpt from your code:

```
int getNumber() {
    char user_input = keys.getKey();
    int value;
    if (user_input) {
        // ...
    }
    return value;
}

```

Think about what would happen if the condition `if (user_input)` turns out to be false. The function would simply return an uninitialized variable, which contains basically garbage.

The method `getKey()` from the Keypad library is intentionally *non-blocking*. It returns immediately in order to avoid the rest of your program being stuck while waiting for keypad input. If some key is pressed, the method returns that key. Otherwise it returns `NO_KEY`, which is zero and, as a boolean, evaluates to false. This means that, when no key is pressed, the function `getNumber()` returns immediately, and it returns garbage.

The correct approach would probably involve some sort of finite state machine. However, for this simple example you can get away with a quick-and-dirty solution: block while waiting for user input:

```
// Wait for user input.
do {
    user_input = keys.getKey();
} while (!user_input);

```

Keep in mind though that, if your program is going to evolve, at some point the blocking approach can become an issue, and you may have to completely rewrite the logic in a non-blocking fashion.

---
Tags: arduino-uno
---


# Question
Title: Why does my delay get inaccurate after one minute ? It makes my servo vibrate
I have a fancy setup to cool my beer at a controlled temperature (you can find details and a photo here if you want). The input of my system is a temperature, the output is a servo position.

**Long story short**

On startup the servo is stable enough, but every time after 67s of runtime suddenly the servo starts vibrating. I have an oscilloscope and I can see that after 67s, instead of a steady 2.3 ms the length of the pulses oscillate in a small range, like between 2.300 and 2.320 ms, and it's enough of a range to be a problem.

What happens at 67s ?? Is there some kind of overflow ? I'm very puzzled because all in all my code for the pulse is very simple.

I'm having my problem on this code, branch bs18b20 of my repo. The pulse is generated line 293, with custom code.

**More context**

I had already asked for help right here with my setup. We had determined that using Servo.h along along with the 1Wire protocol make the interruptions used by both libraries get in the way of one another, so the servo receives bad values and vibrates too. In my last comment in this thread I said that the problem was solved, but I discovered later the problem of the servo getting unstable after some time, as exposed above.

To overcome that I changed tactics, switched my bs18b20 for a lm35 which doesn't need 1Wire, and switched back to Servo.h. It worked very well... in my electronics lab. But then (reality sucks) I found out when actually using my device in the kitchen that sometimes the temperatures start getting very wrong, and I suspect that the humidity alters the voltage reading of my lm35. And that's why I'm trying to change back again to my previous solution with a waterproof bs18b20.

While writing this, stackexchange proposed this thread with a very promising solution, I will definitely try that. Nonetheless, for the sake of it, I'm still interested in knowing what causes my problem above, so I'm posting this anyway.

# Answer
Without looking into the details of your code, it looks like you are having issues with interrupts. According to your comment, this simple code gives a very uneven pulse length:

```
digitalWrite(SERVO_PIN, HIGH);
delayMicroseconds(servo_value*1000);
digitalWrite(SERVO_PIN, LOW);

```

The function `delayMicroseconds()` delays for the requested time, *plus any time taken by interrupts*. Thus, if the delay is inconsistent while `servo_value` does not change, it can only be because of interrupts. Trying to understand the exact symptoms is likely to be quite hard, as one would have to dig into the source of the libraries you are using, and look at every ISR in there. The fact that the version delaying with `micros()` only starts misbehaving after some time is probably due to some very slow “beating” between the timing of your servo and the timing of an interrupt. The fact that the pulse is occasionally 20 µs longer is consistent with it having been interrupted for 20 µs, which for an ISR would be kind of long but not insanely long.

Rather than trying to analyze in detail how the interrupts are interfering with your servo, I would recommend sidestepping the problem completely and driving the servo with a hardware-generated PWM signal. That would give a very consistent pulse length, completely immune to being disrupted by interrupts. You can achieve 0.5 µs resolution with a 20 ms period by setting Timer 1 to fast PWM and clocking it at 2 MHz, like this:

```
// Configure timer 1 for driving a servo
// on pin OC1A = PB1 = digital 9.
void setup_timer()
{
    TCCR1A = 0;           // undo the Arduino core configuration
    TCCR1B = 0;           // ditto
    ICR1   = 40000 - 1;   // period = 20 ms = 40000 timer ticks
    OCR1A  =  3000 - 1;   // pulse length = 1.5 ms = 3000 timer ticks
    TCCR1A = _BV(COM1A1)  // non-inverting PWM on OC1A
           | _BV(WGM11);  // mode 14: fast PWM, TOP = ICR1
    TCCR1B = _BV(WGM12)   // ditto
           | _BV(WGM13)   // ditto
           | _BV(CS11);   // clock @ F_CPU/8 = 2 MHz
}

```

Then you can change the pulse length simply by writing to `OCR1A`: write one less than the desired pulse length, in units of 0.5 µs.
> 1 votes

---
Tags: arduino-uno, servo, 1-wire
---


title: Flip text in LCD screen

text:
# Question
Title: Flip text in LCD screen
Im using \<LiquidCrystal.h\> arduino library,on a 2x16 LCD screen, with an accelerometer. I'd like to flip the the text when my x value exceeds N value. I get how to output text. I tried straight up flipping the text, with an online converter, but the text that renders is garbage.  `lcd.print("¡pןɹoʍ 'oןןǝɥ"); // Print a message to the LCD.`

# Answer
It's not possible. The text is a simple ASCII character set that is encoded in ROM. It can't (other than a few user-defined characters) be changed. And being simple ASCII it doesn't support any UNICODE characters which are used for "upside down" text.

To do what you want you'd need a graphical LCD screen instead of a pure text one.
> 5 votes

---
Tags: lcd
---


# Question
Title: ATMega328p internal comparator problem - ISR(ANALOG_COMP_vect) not firing
After being introduced to this code on github, and exploring electronoobs tutorial I was compelled to try and recreate it with the Arduino Nano, and using the A0-A3 analog comparator inputs. Currently, I am just trying to get the rising edge of the receiver transducer to be recognized in the interrupt. Thus, I think my problem resides in `ISR(ANALOG_COMP_vect)`

Using an oscilloscope confirms that the ultrasonic transducer is firing every 100 ms, and I can detect the ping with the receiver as a small voltage above GND, which should trigger the ISR interrupt with DIO6 connected to GND... but that is not happening...

Here is my code:

```
#include  <avr/interrupt.h>

#include  <stdint.h>
#include  <stdlib.h>
#include  <stdio.h>
#include  <stdbool.h>

#include <Arduino.h>
#include  "fastio.h"

#define F_CPU 16000000UL

// pins for TX driver
#define PING0   PB1
#define PING1   PB2

#define LED     DIO13

#ifndef MASK
  #define MASK(m) (1UL << m)
#endif

#define DEBUG 0
#define INTERVAL 100
#define diff(a,b) (((a) >= (b))?((a)-(b)):((b)-(a)))

inline bool ge(uint32_t a, uint32_t b) {
  return ((a - b) & 0x80000000UL) == 0;
}

inline bool lt(uint32_t a, uint32_t b) {
  return ((a - b) & 0x80000000UL) != 0;
}

volatile uint32_t milliseconds = 0;

uint16_t starttime = 0;
volatile uint16_t envelopetime = 0;
volatile uint16_t phasetime = 0;

#define PULSECOUNT_X2 16
volatile uint8_t edges = 0;

void pins_init(void) {
  WRITE(PING0, 0);
  SET_OUTPUT(PING0);

  WRITE(PING1, 0);
  SET_OUTPUT(PING1);

  WRITE(LED, 0);
  SET_OUTPUT(LED);

}

void timer_init(void) {
  // init timers
  GTCCR = MASK(TSM) | MASK(PSRSYNC); // pause clocks

  PRR &= ~MASK(PRTIM1) & ~MASK(PRTIM0) & ~MASK(PRADC); // enable timers 0 and 1 and ADC

  // use timer1 for output waveform generation and analog comparator timing
  TCCR1A = 0;                       // normal mode, no match behaviour
  TCCR1B = MASK(CS10);              // maximum speed (no prescale)

  // use timer0 for our millisecond clock
  TCCR0A = MASK(WGM01);             // CTC mode
  TCCR0B = MASK(CS00) | MASK(CS01); // prescaler=64, ie clock is 250kHz
  OCR0A  = 250;                     // interrupt at 1kHz, ie every 1ms
  TIMSK0 = MASK(OCIE0A);            // interrupt on compare

  // set up analog comparator
  ADCSRA = (0 << ADEN);
  ADCSRB = (1 << ACME);
  ADMUX = 0;
  ACSR |= 0x03;

  GTCCR = 0; // re-enable clocks
}

void setup(){
  pins_init();
  Serial.begin(115200);
}

void loop() {
  timer_init();
  sei();
  Serial.println("Start");

  uint32_t pingtime = INTERVAL;

  for (;;) {
    if (ge(milliseconds, pingtime) && (edges == 0)) {
      // note when we should ping next
      pingtime += INTERVAL;

      // start in a millisecond from now to avoid race conditions
      starttime = TCNT1 + (F_CPU / 1000);
      OCR1A = OCR1B = starttime;

      // reset edge counter
      edges = PULSECOUNT_X2;

      // set A and clear B on match
      TCCR1A = MASK(COM1A0) | MASK(COM1A1) | MASK(COM1B1);

      // disable interrupt on comparator
      TIMSK1 &= ~MASK(ICIE1);

      // clear flag in case it triggered during startup
      TIFR1 = MASK(OCF1A);

      // enable interrupt
      TIMSK1 |= MASK(OCIE1A);
    }
    if (phasetime != 0) {
      uint16_t eoff = envelopetime - starttime; // time when Rx signal became loud enough to consider, ie start of envelope
      uint16_t poff = phasetime - starttime;    // time of first zero crossing after envelope, use for calculating phase offset

      //printf_P(PSTR("envelope +%u (%uus) phase +%u (%uus)\n"), eoff, eoff >> 4, poff, poff >> 4);

     Serial.println(eoff);
     //Serial.println(poff);

      // zero so we only print once, process data before this
      phasetime = 0;
    }
  }
}

ISR(TIMER1_COMPA_vect) {
  if (edges == PULSECOUNT_X2) {
    TCCR1B |= MASK(ICES1);   // listen for rising edge
    TIFR1 = MASK(ICF1);      // clear flags in case it triggered during startup
    TIMSK1 |= MASK(ICIE1);   // interrupt on comparator

    TCCR1A = MASK(COM1A0) | MASK(COM1B0); // toggle on match
    //Serial.println("PULSE");
    WRITE(LED, 1);
  }
  else if (edges == 1) {
    TCCR1A = MASK(COM1A1) | MASK(COM1B1); // clear both on match
  }
  else if (edges == 0) {
    //putc('>');

    TIMSK1 &= ~MASK(OCIE1A);   // disable interrupt

    return;
  }
  edges--;
  OCR1A = OCR1B += F_CPU / 80000; // set next timeout
}

ISR (ANALOG_COMP_vect)
  {
  phasetime = ICR1;
  if((ACSR & B00100000)){
    envelopetime = ICR1;      // store timestamp
    WRITE(LED, 0);
    TIMSK1 &= ~MASK(ICIE1);   // disable interrupt on comparator
  }
}

ISR(TIMER0_COMPA_vect) {
  milliseconds++;
}

```

# Answer
> 3 votes
You have not enabled the comparator interrupt.

Just need to change the line where you set ACSR.

```
//Comparator interrupt on rising output edge.
ACSR |= (1 << ACIS0) | (1 << ACIS1);

//Enable comparator interrupt
ACSR |= (1 << ACIE)

```

Can also be achieved with.

```
ACSR = 0x0B

```

If you want to change what triggers an interrupt. Bits 0 and 1 control how an interrupt is fired (Toggle, falling or rising).

```
//Toggle (Default, only required if another interrupt mode is already selected)
ACSR &= ~(0b11)

//Falling
ACSR &= ~(1 << ACIS0); //Only required if ACIS0 is set
ACSR |= (1 << ACIS1);

//Rising
ACSR |= (1 << ACIS0) | (1 << ACIS1);
//Or
ACSR | = 0x03;

```

You will also need to enable global interrupts. (Which you have done) Which can be done by calling...

```
interrupts(); //Arduino only
sei();        //AVR and Arduino

```

I see you are calling "sei" in the loop, it only needs to be called once (unless you have disabled them with "cli()," and I believe its not even required at all with Arduino as I think interrupts are already enabled.

The datasheet is your friend. Tutorials are a great way to learn, but if you really want to increase your skill set you should try to break free from tutorials as much as possible by reading the datasheet, and experimenting on your own. The comparator starts on page 202, and would be a great place to start as its an easy peripheral to get going.

---
Tags: arduino-nano, interrupt
---


title: Location of examples folder in Ubuntu

text:
# Question
Title: Location of examples folder in Ubuntu
I'm trying to add some additional example files to the Arduino IDE in Ubuntu 14.04. However, I can't for the life of me find where the examples are stored in my system. I checked the Arduino website, but can't find any information there. Does anyone know where I need to put my additional files?

# Answer
After some more searching I found it in /usr/share/arduino/examples.
> 8 votes

# Answer
I found mine in Linux Mint 17.3 under `opt/arduino/examples`
> 2 votes

# Answer
In Ubuntu I found arduino library on /home/MYUSERNAME/snap/arduino

where MYUSERNAME is user name
> 1 votes

---
Tags: arduino-ide
---


# Question
Title: lcd.createChar() only allows for 8 custom characters
I have a teensy4.1, with a 16 by 2 LCD screen, and an I2C LCD interface. I was trying to write a bunch of custom characters to an LCD screen, to flip some text.

my issue is that it works fine, but on only up to 8 custom characters. any more than that produces odd results. with a loop of 16, the first 8 characters are printed. should more than 8 characters be defined, only the last assigned are in use.

I commented out all but the first 8 custom characters, and iterates through them in a loop of 16 iterations. this loops over the start. -- I guess that works as I would expect. If I define more than 8 custom Characters, only the last 8 assigned will output.

Here is a picture of that in action:

here is my code:

```
#include <Adafruit_LiquidCrystal.h>
Adafruit_LiquidCrystal lcd(0);

//upside down char glyphs... default characters are 7x5 1 px w/space on the bottom
//these glyphs are 7x5 with space on the top
byte uA[8] = {  B00000,  B10001,  B10001,  B10001,  B11111,  B10001,  B10001,  B01110};
byte uB[8] = {  B00000,  B01111,  B10001,  B10001,  B01111,  B10001,  B10001,  B01111};
byte uC[8] = {  B00000,  B01110,  B10001,  B00001,  B00001,  B00001,  B10001,  B01110};
byte uD[8] = {  B00000,  B00111,  B01001,  B10001,  B10001,  B10001,  B01001,  B00111};
byte uE[8] = {  B00000,  B11111,  B00001,  B00001,  B01111,  B00001,  B00001,  B11111};
byte uF[8] = {  B00000,  B00001,  B00001,  B00001,  B01111,  B00001,  B00001,  B11111};
byte uG[8] = {  B00000,  B11110,  B10001,  B10001,  B11101,  B00001,  B10001,  B01110};
byte uH[8] = {  B00000,  B10001,  B10001,  B10001,  B11111,  B10001,  B10001,  B10001};
byte uI[8] = {  B00000,  B01110,  B00100,  B00100,  B00100,  B00100,  B00100,  B01110};
byte uJ[8] = {  B00000,  B00110,  B01001,  B01000,  B01000,  B01000,  B01000,  B11100};
byte uK[8] = {  B00000,  B10001,  B01001,  B00101,  B00011,  B00101,  B01001,  B10001};
byte uL[8] = {  B00000,  B01111,  B00001,  B00001,  B00001,  B00001,  B00001,  B00001};
byte uM[8] = {  B00000,  B10001,  B10001,  B10001,  B10101,  B10101,  B11011,  B10001};
byte uN[8] = {  B00000,  B10001,  B10001,  B11001,  B10101,  B10011,  B10001,  B10001};
byte uO[8] = {  B00000,  B01110,  B10001,  B10001,  B10001,  B10001,  B10001,  B01110};
byte uP[8] = {  B00000,  B00001,  B00001,  B00001,  B01111,  B10001,  B10001,  B01111};
byte uQ[8] = {  B00000,  B10110,  B01001,  B10101,  B10001,  B10001,  B10001,  B01110};
byte uR[8] = {  B00000,  B10001,  B01001,  B00101,  B01111,  B10001,  B10001,  B01111};
byte uS[8] = {  B00000,  B01111,  B10000,  B10000,  B01110,  B00001,  B00001,  B11110};
byte uT[8] = {  B00000,  B00100,  B00100,  B00100,  B00100,  B00100,  B00100,  B11111};
byte uU[8] = {  B00000,  B01110,  B10001,  B10001,  B10001,  B10001,  B10001,  B10001};
byte uV[8] = {  B00000,  B00100,  B01010,  B10001,  B10001,  B10001,  B10001,  B10001};
byte uW[8] = {  B00000,  B01010,  B10101,  B10101,  B10101,  B10001,  B10001,  B10001};
byte uX[8] = {  B00000,  B10001,  B10001,  B01010,  B00100,  B01010,  B10001,  B10001};
byte uY[8] = {  B00000,  B00100,  B00100,  B00100,  B01010,  B10001,  B10001,  B10001};
byte uZ[8] = {  B00000,  B11111,  B00001,  B00010,  B00100,  B01000,  B10000,  B11111};
//pockets
byte cornerA[]={B11111,B10000,B10000,B10000,B10000,B10000,B10000,B10000};//top left
byte cornerB[]={B10000,B10000,B10000,B10000,B10000,B10000,B10000,B11111};//btm left
byte cornerC[]={B11111,B00001,B00001,B00001,B00001,B00001,B00001,B00001};//top right
byte cornerD[]={B00001,B00001,B00001,B00001,B00001,B00001,B00001,B11111};//btm right
void flip(char *text);
void setup() {
  Serial.begin(9600);
  lcd.begin(16,2); //
  //flipped characters
lcd.createChar(0,uA);
lcd.createChar(1,uB);
lcd.createChar(2,uC);
lcd.createChar(3,uD);
lcd.createChar(4,uE);
lcd.createChar(5,uF);
lcd.createChar(6,uG);
lcd.createChar(7,uH);
lcd.createChar(8,uI);
lcd.createChar(9,uJ);
lcd.createChar(10,uK);
lcd.createChar(11,uL);
lcd.createChar(12,uM);
lcd.createChar(13,uN);
lcd.createChar(14,uO);
lcd.createChar(15,uP);
/*lcd.createChar(16,uQ);
lcd.createChar(17,uR);
lcd.createChar(18,uS);
lcd.createChar(19,uT);
lcd.createChar(20,uU);
lcd.createChar(21,uV);
lcd.createChar(22,uW);
lcd.createChar(23,uX);
lcd.createChar(24,uY);
lcd.createChar(25,uZ);
lcd.createChar(26,cornerA);
lcd.createChar(27,cornerB);
lcd.createChar(28,cornerC);
lcd.createChar(29,cornerD);
*/
  //ascii coversion prolly like n+66
  //setCursor be like: (column, row) 16 cols, 2 rows, both start at 0
lcd.setCursor(0,0);

  for (int i=0; i<16;i++){
  lcd.write(i); //prints ABCDEFGHABCDEFGH
  lcd.setCursor(i+1,0);
  delay (500);
  }
  lcd.setCursor(0,1);
  lcd.print("LIMIT 8 CHARS?");
}

void loop() {}

```

I would like to make more than 8 customChars, am I approaching this correctly? is there a limit somewhere I can change?

# Answer
> 6 votes
These displays only allow up to 8 custom defined characters. The hardware just only has the character RAM for at most 8 characters. They will be mapped to char codes 0 to 7 and 8 to 15. The character code 8 always prints the same character as code 0, 9 as 1 and so on.

So no, there is no way to use more than 8 custom characters *at once*. Of course, you can change the characters dynamically, so that a certain location of the screen always shows a changing custom character icon.

---
Tags: programming, lcd, c
---


# Question
Title: What is my code lacking that the servo rotates non-stoppingly? Servo should rotate 180 when distance is <= 50 and 0 when this condition is not true
My code represents a water level sensor, and the components are the Arduino Uno, a breadboard, an ultrasonic servo and two LEDS in which one is red and the other is green.

The condition that I don't know how to include in my code properly to make the servo rotate and activate the LEDs simultaneously:

When the distance is \<= 50, servo rotates 180 and activates the red LED else servo goes to zero and activates the green LED.

My code:

<pre><code>#include <Servo.h>
int position = 0;
Servo srv;

const int trigPin = 4;
const int echoPin = 2;
const int ServoPin = 3;
const int green = 5;
const int red = 6;

int durantion;
int distance;

// **************************************//
void setup()
{

 Serial.begin(9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(green, OUTPUT);
  pinMode(red, OUTPUT);
  srv.attach(ServoPin);

}

void loop() {

  int duration, distance;
  pinMode(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
 distance = pulseIn(echoPin, HIGH);
 distance = duration *30/2500;

  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.println(" cm");

 if (distance <= 50)

{
  digitalWrite(red, HIGH);
  srv.write(180);
   delay(1000);
}
else
{
  digitalWrite(green, LOW);
  delay(1000);
  srv.write(0);
}
}

```

[![System][1]][1]

  [1]: https://i.stack.imgur.com/6YXgf.png
</code></pre>

# Answer
Checking your program I found two errors IMHO. Please see the comments in the copied code below. The one also pointed out by @EdgarBonet definitely prevents your program from working correctly. The other one only has impact of the correctness if the values of the constants OUTPUT and LOW differ. I don't know if that is the case.

I'm pretty sure, that the continously turning servo is not caused by the program. There are two kinds of servos. One type that gets a signal which indicates the angle of the turn of the servos arms. The other type gets the same signal (called PWM = Pulse Width Modulation) and interprets it as the speed with that it continously turns the servo arms.

If you use the latter one the arduino sends a signal like turn about 180° but the servo understands turn with full speed. There is nothing you can do programatically to avoid that.

There are workarounds like build a feedback loop with a potentiometer that measures the angle of the turn or use stopper sensors. But the simplest way is to use a servo that is made for your usecase. (A non continous or standard servo for e.g. RC Cars, RC Ships, RC Air Planes)

BTW: The picture your provided shows a simulation. If the Servo in the simulator turns continuously, perhaps there is a property you can use to change the servo type from continuous to standard. ??

```
#include <Servo.h>

int position = 0;
Servo srv;

const int trigPin = 4;
const int echoPin = 2;
const int ServoPin = 3;
const int green = 5;
const int red = 6;

int durantion;
int distance;

void setup()
{
  Serial.begin(9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(green, OUTPUT);
  pinMode(red, OUTPUT);
  srv.attach(ServoPin);
}

void loop()
{

  int duration, distance;
  // error: you already set the pinmode to OUTPUT
  // pinMode(trigPin, LOW);
  // perhaps you mean
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  // error: duration or distance ? ;-)
  // distance = pulseIn(echoPin, HIGH);
  duration = pulseIn(echoPin, HIGH);
  distance = duration * 30 /2500;

  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.println(" cm");

  if (distance <= 50)
  {
    digitalWrite(red, HIGH);
    srv.write(180);
    // improvement: delay necessary?
    // delay(1000);
  }
  else
  {
    digitalWrite(green, LOW);
    // improvement: delay necessary?
    // delay(1000);
    srv.write(0);
  }
}

```
> 1 votes

---
Tags: arduino-uno, programming
---


# Question
Title: Problem on Sending float number and multiple float numbers
Im having trouble in sending float number and multiple float numbers. Im currently working on project matlab and arduino mkr1000. The situation is that i want to send float number and multiple float numbers through communication(which in client.available() code) and view it in Serial Monitor. I have been searching throughout the internet but unfortunately could not receive it. The more i read the more confused i became. Im new to this environment. I do need consider bitshifting right?. Is there any similar examples and guidances from others would be really highly appreciated. Thank you.

Arduino Ide

```
    /* Latest Progress of the Project*/
#include <SPI.h>
#include <WiFi101.h>

// sensitive data placed in arduino_secrets.h
#include "arduino_secrets.h"
char ssid[] = SECRET_SSID; // name wifi
char pass[] = SECRET_PASS; // password
int status = WL_IDLE_STATUS; // status of wifi

// variables used
float value;

IPAddress ipserver(192, 168, 1, 109); // home wifi ip address

// initialize the client library
WiFiClient client;

void setup()
{
  // initialize serial and wait for port to open:
  Serial.begin(115200);
  Serial.println();
  Serial.println();
  Serial.println("Attempting to connect to WPA network...");
  Serial.print("SSID:");
  Serial.println(ssid);

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED)
  {
    // will keep trying until connected
    Serial.print("Attempting to connect to network: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds(enough time) for connection:
    delay(10000);
  }

  // if you're connected now, so print the data status:
  Serial.println("You're connected to the network");
  Serial.println("------------------------------------");
  Serial.println("Hi FYP63333 Group");
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  Serial.println("------------------------------------");
  Serial.println("\nStarting connection to server...");
}

void loop()
{
  // Client connect or not connect in serial monitor:
  if (!client.connect(ipserver, 1234))
  {
    // if you didnt't get a connection to the server:
    Serial.println("Can't connect to server, try again.");
    delay(5000);
    return;
  }
  else
  {
    // if you get connection to the server:
    Serial.println("Connected to server!!!");
    Serial.println("MATLAB READY");
    //client.println("Hello from MKR1000");
  }

  // If there are incoming bytes available from the server, read and print them
  // Read all the lines of the reply from server and print them inside Serial Monitor:
  Serial.println();
  Serial.println("Incoming and receiving data from remote server:");
  while (client.connected() || client.available() || Serial.available())
  {
    while (Serial.available())
    {
      char data;
      data = Serial.read();
      if (client.connected())
      {
        client.print(data);
      }
    }
    while (client.available())
    {

      //------------------main-code(works)--------------for string//
      char ch = static_cast<char>(client.read());
      Serial.println(ch);
    }
  }

  // if the server's disconnected, stop the client:
  if (!client.connected())
  {
    Serial.println();
    Serial.println("Disconnecting from the server.");
    client.stop();
  }
}

```

Matlab code

```
clear;
clc;
%% Connecting matlab and Arduino IDE(TCP/IP Server)
t = tcpserver("192.168.1.109",1234);
t.ByteOrder = "big-endian";

```

# Answer
> 2 votes
Sending numerical values between systems is fraught with difficulty. Not only do you have to ensure that both ends agree on the size of the data (16 bit vs 32 bit ints, float vs double, etc) but that the byte ordering is handled correctly. On top of that is knowing *where* a number is in the stream of data. With nothing to delimit each value (and when you have 8 bits of communication width and 8 bits of data there's no room for "out of band" control signals) yo have no way of knowing which byte in the data stream corresponds to which byte in a value's raw data.

It's far better to encode the data into some other format that leaves you room to add delimiting control signals and has a predefined machine-agnostic data format.

The simplest encoding: ASCII. Simply "print" the numbers as text with the precision you desire (number of decimal places) as one number per line. Then on the Arduino you can read text data a line at a time then use the internal float conversion routines to turn that data into an actual floating point value again.

Some references:

# Answer
> 0 votes
Check out the I2C\_Anything library. It is used to transfer any data type bit-by-bit using the I2C serial protocol, but the algorithms could be just as easily used over ANY serial connection. You do have to make sure that the size of a particular datatype is the same on both ends, but that's about it.

```
Here's my subroutine running on a Teensy 3.5 that acquires VL53L0X LIDAR data from another Arduino processor (actually a Teensy 3.2).

    bool GetRequestedVL53l0xValues(VL53L0X_REQUEST which)
{
  //Purpose: Obtain VL53L0X ToF sensor data from Teensy sensor handler
  //Inputs:
  //    which = VL53L0X_REQUEST value denoting which combination of value to retrieve
  //        VL53L0X_CENTERS_ONLY -> Just the left/right center sensor values
  //        VL53L0X_RIGHT -> All three right sensor values, in front/center/rear order
  //        VL53L0X_LEFT -> All three left sensor values, in front/center/rear order
  //        VL53L0X_ALL -> All seven sensor values, in left/right front/center/rear/rear order
  //        VL53L0X_REAR_ONLY -> added 10/24/20 Just the rear sensor reading

  //Outputs:
  //    Requested sensor values, obtained via I2C from the VL53L0X sensor handler
  //    Returns TRUE if data retrieval successful, otherwise FALSE
  //Plan:
  //    Step1: Send request to VL53L0X handler
  //    Step2: get the requested data
  //Notes:
  // Copied from FourWD_WallE2_V4.ino's IsIRBeamAvail() and adapted
    // 08/05/20 added a VL53L0X_ALL request type
    // 01/24/21 added error detection/reporting
    // 01/16/22 rev to use I2C_Anything1 functions for Wire1

  //Step1: Send request to VL53L0X handler
  //DEBUG!!
    //myTeePrint.printf("Sending %d to slave\n", which);
  //DEBUG!!

  //myTeePrint.printf("In GetRequestedVL53l0xValues(%d)\n", (int)which);

  //03/01/22 rev to cvt all readings to cm
  uint16_t Lidar_RightFrontMM = 0;
  uint16_t Lidar_RightCenterMM = 0;
  uint16_t Lidar_RightRearMM = 0;
  uint16_t Lidar_RearMM = 0;

  uint16_t Lidar_LeftFrontMM = 0;
  uint16_t Lidar_LeftCenterMM = 0;
  uint16_t Lidar_LeftRearMM = 0;

  Wire1.beginTransmission(VL53L0X_I2C_SLAVE_ADDRESS);
  I2C_writeAnything((uint8_t)which, &Wire1);
  Wire1.endTransmission();

  //Step2: get the requested data
  int readResult = 0;
  int data_size = 0;
  switch (which)
  {
  case VL53L0X_READYCHECK: //11/10/20 added to prevent bad reads during Teensy setup()
    Wire1.requestFrom(VL53L0X_I2C_SLAVE_ADDRESS, (uint16_t)(sizeof(bVL53L0X_TeensyReady)));
    readResult = I2C_readAnything(bVL53L0X_TeensyReady, &Wire1);
    break;

  case VL53L0X_CENTERS_ONLY:
    //just two data values needed here
    data_size = 2 * sizeof(uint16_t);
    Wire1.requestFrom(VL53L0X_I2C_SLAVE_ADDRESS, (uint16_t)(2 * sizeof(Lidar_RightCenterMM)));
    readResult = I2C_readAnything(Lidar_RightCenterMM, &Wire1);
    glRightCenterCm = Lidar_RightCenterMM / 10; //integer truncation OK

    if (readResult > 0)
    {
      I2C_readAnything(Lidar_LeftCenterMM, &Wire1);
      glLeftCenterCm = Lidar_LeftCenterMM / 10; //integer truncation OK
    }

    //DEBUG!!
        //myTeePrint.printf("VL53L0X_CENTERS_ONLY case: Got LC/RC = %d, %d\n", Lidar_LeftCenterMM, Lidar_RightCenterMM);
    //DEBUG!!

    break;
  case VL53L0X_RIGHT:
    //four data values needed here
    data_size = 3 * sizeof(uint16_t) + sizeof(float);

    //DEBUG!!
        //myTeePrint.printf("data_size = %d\n", data_size);
    //DEBUG!!

    Wire1.requestFrom(VL53L0X_I2C_SLAVE_ADDRESS, data_size);
    readResult = I2C_readAnything(Lidar_RightFrontMM, &Wire1);
    glRightFrontCm = Lidar_RightFrontMM / 10; //integer truncation OK

    if (readResult > 0)
    {
      readResult = I2C_readAnything(Lidar_RightCenterMM, &Wire1);
      glRightCenterCm = Lidar_RightCenterMM / 10; //integer truncation OK
    }
    if (readResult > 0)
    {
      readResult = I2C_readAnything(Lidar_RightRearMM, &Wire1);
      glRightRearCm = Lidar_RightRearMM / 10; //integer truncation OK
    }
    if (readResult > 0)
    {
      readResult = I2C_readAnything(glRightSteeringVal, &Wire1);
    }

    //DEBUG!!
        //myTeePrint.printf("VL53L0X_RIGHT case: Got L/C/R/S = %d, %d, %d, %3.2f\n",
        //  glRightFrontCm, Lidar_RightCenterMM, Lidar_RightRearMM, ToFSteeringVal);
    //DEBUG!!

    break;
  case VL53L0X_LEFT:
    //four data values needed here
    //data_size = 3 * sizeof(int) + sizeof(float);
    data_size = 3 * sizeof(uint16_t) + sizeof(float);

    Wire1.requestFrom(VL53L0X_I2C_SLAVE_ADDRESS, data_size);
    readResult = I2C_readAnything(Lidar_LeftFrontMM, &Wire1);
    glLeftFrontCm = Lidar_LeftFrontMM / 10; //integer truncation OK

    if (readResult > 0)
    {
      readResult = I2C_readAnything(Lidar_LeftCenterMM, &Wire1);
      glLeftCenterCm = Lidar_LeftCenterMM / 10; //integer truncation OK
    }
    if (readResult > 0)
    {
      readResult = I2C_readAnything(Lidar_LeftRearMM, &Wire1);
      glLeftRearCm = Lidar_LeftRearMM / 10; //integer truncation OK
    }
    if (readResult > 0)
    {
      readResult = I2C_readAnything(glLeftSteeringVal, &Wire1);
    }

    //DEBUG!!
        //myTeePrint.printf("VL53L0X_RIGHT case: Got L/C/R/S = %d, %d, %d, %3.2f\n",
        //  Lidar_LeftFrontMM, Lidar_LeftCenterMM, Lidar_LeftRearMM, ToFSteeringVal);
    //DEBUG!!

    break;
  case VL53L0X_ALL: //added 08/05/20, chg to VL53L0X_ALL 10/31/20
    //nine data values needed here - 7 ints and 2 floats
    data_size = 7 * sizeof(uint16_t) + 2 * sizeof(float); //10/31/20 added rear distance

    //myTeePrint.printf("In VL53L0X_ALL case with data_size = %d\n", data_size);

    Wire1.requestFrom(VL53L0X_I2C_SLAVE_ADDRESS, data_size);

    //Lidar_LeftFrontMM
    readResult = I2C_readAnything(Lidar_LeftFrontMM, &Wire1);
    glLeftFrontCm = Lidar_LeftFrontMM / 10; //integer truncation OK

    if (readResult != sizeof(Lidar_LeftFrontMM))
    {
      myTeePrint.printf("Error reading Lidar_LeftFrontMM\n");
    }

    //Lidar_LeftCenterMM
    readResult = I2C_readAnything(Lidar_LeftCenterMM, &Wire1);
    glLeftCenterCm = Lidar_LeftCenterMM / 10; //integer truncation OK

    if (readResult != sizeof(Lidar_LeftCenterMM))
    {
      myTeePrint.printf("Error reading Lidar_LeftCenterMM\n");
    }

    //Lidar_LeftRearMM
    readResult = I2C_readAnything(Lidar_LeftRearMM, &Wire1);
    glLeftRearCm = Lidar_LeftRearMM / 10; //integer truncation OK

    if (readResult != sizeof(Lidar_LeftRearMM))
    {
      myTeePrint.printf("Error reading Lidar_LeftRearMM\n");
    }

    //glLeftSteeringVal
    readResult = I2C_readAnything(glLeftSteeringVal, &Wire1);
    if (readResult != sizeof(glLeftSteeringVal))
    {
      myTeePrint.printf("Error reading glLeftSteeringVal\n");
    }

    //Lidar_RightFrontMM
    readResult = I2C_readAnything(Lidar_RightFrontMM, &Wire1);
    glRightFrontCm = Lidar_RightFrontMM / 10; //integer truncation OK

    if (readResult != sizeof(Lidar_RightFrontMM))
    {
      myTeePrint.printf("Error reading Lidar_RightFrontMM\n");
    }

    //Lidar_RightCenterMM
    readResult = I2C_readAnything(Lidar_RightCenterMM, &Wire1);
    glRightCenterCm = Lidar_RightCenterMM / 10; //integer truncation OK

    if (readResult != sizeof(Lidar_RightCenterMM))
    {
      myTeePrint.printf("Error reading Lidar_RightCenterMM\n");
    }

    //Lidar_RightRearMM
    readResult = I2C_readAnything(Lidar_RightRearMM, &Wire1);
    glRightRearCm = Lidar_RightRearMM / 10; //integer truncation OK

    if (readResult != sizeof(Lidar_RightRearMM))
    {
      myTeePrint.printf("Error reading Lidar_RightRearMM\n");
    }

    //Lidar_RearMM
    readResult = I2C_readAnything(Lidar_RearMM, &Wire1);
    glRearCm = Lidar_RearMM / 10; //integer truncation OK
    if (readResult != sizeof(Lidar_RearMM))
    {
      myTeePrint.printf("Error reading Lidar_RearMM\n");
    }

    //glRightSteeringVal
    readResult = I2C_readAnything(glRightSteeringVal, &Wire1);
    if (readResult != sizeof(glRightSteeringVal))
    {
      myTeePrint.printf("Error reading glLeftSteeringVal\n");
    }

    //myTeePrint.printf("%lu: VL53l0x - %d, %d, %d, %d, %d, %d, %d\n",
    //  millis(),
    //  Lidar_LeftFrontMM, Lidar_LeftCenterMM, Lidar_LeftRearMM,
    //  glRightFrontCm, Lidar_RightCenterMM, Lidar_RightRearMM,
    //  Lidar_RearMM);
    break; //10/31/20 bugfix

  case VL53L0X_REAR_ONLY:
    //just ONE data value needed here
    data_size = sizeof(uint16_t);
    Wire1.requestFrom(VL53L0X_I2C_SLAVE_ADDRESS, (uint16_t)(sizeof(Lidar_RearMM)));
    readResult = I2C_readAnything(Lidar_RearMM, &Wire1);
    glRearCm = Lidar_RearMM / 10; //integer truncation OK

    //DEBUG!!
        //myTeePrint.printf("VL53L0X_REAR_ONLY case: Got Rear = %d\n", Lidar_RearMM);
    //DEBUG!!

    break;

  default:
    break;
  }
  //myTeePrint.printf("GetRequestedVL53l0xValues(): LR/LC/LF/RR/RC/RF/R = %d\t%d\t%d\t%d\t%d\t%d\t%d\n",
  //  Lidar_LeftRearMM, Lidar_LeftCenterMM, Lidar_LeftFrontMM,
  //  Lidar_RightRearMM, Lidar_RightCenterMM, glRightFrontCm, Lidar_RearMM);

  return readResult > 0; //this is true only if all reads succeed
}

```

and here's the corresponding code on the other end of the I2C link:

```
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  //Purpose: Send requested sensor data to the Mega controller via main I2C bus
  //Inputs:
  //  request_type = uint8_t value denoting type of data requested (from receiveEvent())
  //      0 = left & right center distances only
  //      1 = right side front, center and rear distances, plus steering value
  //      2 = left side front, center and rear distances, plus steering value
  //      3 = both side front, center and rear distances, plus both steering values
//Outputs:
  //  Requested data sent to master
  //Notes:
  //  08/05/20 added VL53L0X_ALL request type to get both sides at once
  //  10/24/20 added VL53L0X_REAR_ONLY request type
  //  11/09/20 added write to pin for O'scope monitoring

  int data_size = 0;

//DEBUG!!
    //Serial.printf("RequestEvent() with request_type = %d: VL53L0X Front/Center/Rear distances = %d, %d, %d\n",
    //    request_type, RF_Dist_mm, RC_Dist_mm, RR_Dist_mm);
//DEBUG!!

  //digitalWrite(LED_BUILTIN, HIGH);//added 01/22/22
  digitalWrite(REQUEST_EVENT_DURATION_OUTPUT_PIN, HIGH);

  digitalToggle(LED_BUILTIN);//2/21/22 added for visual indication of I2C activity
  switch (request_type)
  {
  case  VL53L0X_READYCHECK: //added 11/10/20 to prevent bad reads during Teensy setup()
    //Serial.printf("in VL53L0X_READYCHECK case at %lu with bTeensyReady = %d\n", millis(), bTeensyReady);
    I2C_writeAnything(bTeensyReady);
    break;

  case VL53L0X_CENTERS_ONLY:

    //DEBUG!!
      //data_size = 2*sizeof(uint16_t);
      //Serial.printf("Sending %d bytes LC_Dist_mm = %d, RC_Dist_mm = %d to master\n", data_size, LC_Dist_mm, RC_Dist_mm);
    //DEBUG!!

    I2C_writeAnything(RC_Dist_mm);
    I2C_writeAnything(LC_Dist_mm);
    break;

  case VL53L0X_RIGHT:

    //DEBUG!!
            //data_size = 3 * sizeof(uint16_t) + sizeof(float);
            //Serial.printf("Sending %d bytes RF/RC/RR/RS vals = %d, %d, %d, %3.2f to master\n",
            //    data_size, RF_Dist_mm, RC_Dist_mm, RR_Dist_mm, RightSteeringVal);
    //DEBUG!!

    I2C_writeAnything(RF_Dist_mm);
    I2C_writeAnything(RC_Dist_mm);
    I2C_writeAnything(RR_Dist_mm);
    I2C_writeAnything(RightSteeringVal);
    break;

  case VL53L0X_LEFT:

    //DEBUG!!
            //data_size = 3 * sizeof(uint16_t) + sizeof(float);
            //Serial.printf("Sending %d bytes LF/LC/LR/LS vals = %d, %d, %d, %3.2f to master\n",
            //    data_size, LF_Dist_mm, LC_Dist_mm, LR_Dist_mm, LeftSteeringVal);
    //DEBUG!!

    I2C_writeAnything(LF_Dist_mm);
    I2C_writeAnything(LC_Dist_mm);
    I2C_writeAnything(LR_Dist_mm);
    I2C_writeAnything(LeftSteeringVal);
    break;

  case VL53L0X_ALL:
    //Serial.printf("In VL53L0X_ALL case\n");
    //added 08/05/20 to get data from both sides at once
    //10/31/20 chg to VL53L0X_ALL & report all 7 sensor values

//DEBUG!!
    //data_size = 3 * sizeof(uint16_t) + sizeof(float);
    //data_size = 7 * sizeof(uint16_t) + 2 * sizeof(float);
    //Serial.printf("Sending %d bytes to master\n", data_size);
    //Serial.printf("%d bytes: %d\t%d\t%d\t%3.2f\t%d\t%d\t%d\t%d\t%3.2f\n",
    //    data_size, LF_Dist_mm, LC_Dist_mm, LR_Dist_mm, LeftSteeringVal,
    //  RF_Dist_mm, RC_Dist_mm, RR_Dist_mm, Rear_Dist_mm, RightSteeringVal);
//DEBUG!!

    //DEBUG!!
      //data_size = 3 * sizeof(uint16_t) + sizeof(float);
      //Serial.printf("Sending %d bytes LF/LC/LR/LS vals = %d, %d, %d, %3.2f to master\n",
      //    data_size, LF_Dist_mm, LC_Dist_mm, LR_Dist_mm, LeftSteeringVal);
    //DEBUG!!

    //left side
    I2C_writeAnything(LF_Dist_mm);
    I2C_writeAnything(LC_Dist_mm);
    I2C_writeAnything(LR_Dist_mm);
    I2C_writeAnything(LeftSteeringVal);

    //DEBUG!!
      //data_size = 3 * sizeof(uint16_t) + sizeof(float);
      //data_size = 4 * sizeof(uint16_t) + sizeof(float);
      //Serial.printf("Sending %d bytes RF/RC/RR/R/RS vals = %d, %d, %d, %d, %3.2f to master\n",
      //    data_size, RF_Dist_mm, RC_Dist_mm, RR_Dist_mm, Rear_Dist_mm, RightSteeringVal);
    //DEBUG!!

       //right side
    I2C_writeAnything(RF_Dist_mm);
    I2C_writeAnything(RC_Dist_mm);
    I2C_writeAnything(RR_Dist_mm);
    I2C_writeAnything(Rear_Dist_mm);
    I2C_writeAnything(RightSteeringVal);

    break;

  case VL53L0X_REAR_ONLY:

    //DEBUG!!
      //data_size = sizeof(uint16_t);
      //Serial.printf("Sending %d bytes Rear_Dist_mm = %d to master\n", data_size, Rear_Dist_mm);
    //DEBUG!!

    I2C_writeAnything(Rear_Dist_mm);
    break;

  default:
    break;
  }
  digitalToggle(LED_BUILTIN);//2/21/22 added for visual indication of I2C activity

  digitalWrite(REQUEST_EVENT_DURATION_OUTPUT_PIN, LOW);
  //digitalWrite(LED_BUILTIN, LOW);//added 01/22/22
}

```

# Answer
> 0 votes
As an alternative, you can send the numbers as text, as suggested by Edgar Bonet above. Here's a short program I just whipped up that demos this capability, using two Teensy 3.x processors. The program waits for a character on its serial port, and if any are found, they are transmitted to the other processor via a serial connection between the two, and also echoed back to the sending serial port. This should work with any Arduino processor that has two serial ports (Serial for talking to the PC, Serial1 for talking to the other processor). I used the built-in LED as an activity monitor.

```
/*
    Name:       Serial_Anything.ino
    Created:    4/26/2022 6:23:01 PM
    Author:     FRANKNEWXPS15\Frank

    Project to demonstrate passing arbitrary data types over a serial connection
    The idea is to port I2C_Anything to use over a common serial port connection
*/

#include "Serial_Anything.h"

//char buff[30];

void setup()
{
  Serial.begin(115200);
  delay(1000);
  Serial1.begin(115200);
  delay(1000);

  Serial.printf("Serial_Anything Demo\n");

  pinMode(LED_BUILTIN, OUTPUT);

  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);

}

void loop()
{
  if (Serial.available())
  {
    //buff[buffidx] = Serial.read();
    //buffidx++;
    char c = Serial.read();
    Serial1.write(c);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(50);
    digitalWrite(LED_BUILTIN, LOW);
    Serial.write(c);
  }

  if (Serial1.available())
  {
    //buff[buffidx] = Serial.read();
    //buffidx++;
    char c = Serial1.read();
    Serial.write(c);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(50);
    digitalWrite(LED_BUILTIN, LOW);
  }
}

```

Here's a short section of output from a typical run:

Teensy1:

```
Port closed
Opening port
Port open
Serial_Anything Demo
y
y
y
y
X
X
X
X
the quick
314159
3.14159

```

Teensy2:

```
Opening port
Port open
y
y
y
y
y
y
y
y
y
y
y
y
y
X
X
X
X
the quick
314159
3.14159

```

---
Tags: communication, float, matlab, mkr1000
---


# Question
Title: Is there a standard way to describe devices?
I'm new to Arduino. I'm curious whether there is a standard way to record the plan of a device—for instance, if I wanted to share it or communicate the design to other people. I realize the short answer here might be, “yes, make a circuit diagram.” Are there perhaps widely used tools for producing those, perhaps with add-ons for Arduino boards? (I'd prefer a more semantic representation than, say, making a diagram in Inkscape.)

# Answer
There is no plugin to a program like Inkscape - as far as I know. It doesn't make much sense to have one. With an Arduino circuit you normally want to show the real electrical connections. A block diagram without real electrical connections doesn't help much in reproducing the project. You can do it, but you will have to do it on your in in a graphic program. I think this is only helpful for rather big projects, where each block contains not only the Arduino but also many further components of that functional unit in your project.

To show the circuit you basically have 2 options:

* **A wiring diagram:** This is an image, mostly created via the software Fritzing, which shows a breadboard and the components of the project placed on it. The electrical connections are represented by colored lines. This is good for beginners, who cannot yet read a schematic and want to reproduce the circuit on their own breadboard. Though wiring diagrams, especially Fritzing, is only standard in the Arduino/Beginner world. The more you get into professional realm, the less you will see them. They look like this (please note the internal connections, that a breadboard has in its numbered rows):
* **A schematic:** A schematic is the standard way of describing any electronic circuit. For example look at the Arduino Uno schematic. Every part is represented by a symbol with pins. The pins get connected with lines (representing wires or PCB traces). There are many different softwares for creating schematics, for example Eagle, KiCAD, EasyEDA and Altium Designer. You can choose yourself what to use. Look at the options, that the softwares provide. Some are premium but have free options, others (like KiCAD) are open source. I personally use KiCAD. At least for KiCAD you can download part repository files (like this one), which include Arduino boards, so that you can place them directly on your schematic. I'm sure there are similar resources for other programs as well. Export the resulting schematic to PDF or an image format so that everyone can read the schematic without having your program installed.

An additional benefit in creating a schematic is, that all these programs also support creating a PCB layout from the schematic. So it gets easier to design a PCB from your circuit for DIY or ordered production.
> 5 votes

---
Tags: system-design
---


# Question
Title: Is it safe to power multiple ESP32-CAM circuits from the same battery output?
I have setup two ESP32-CAMs, sharing the signal from a PIR sensor via an optocoupler.

Plus I have a 12V LED ring on a 5V to 12V booster, turned on/off by a relay.

The ESP32s go to deep sleep, wake up on the signal from the PIR sensor, turn on the 12V IR LED ring, take some photos and go back to deep sleep.

When they are on three separate power circuits, they seem to work well.

Is it safe to connect all these to the same USB output from an USB power bank?

Or can it be done safely at all?

(Could be similar to this question but I'm not sure.)

I am new at this and I don't have any intuition about whether that would create odd voltages and currents that might damage the components on the long-term, as they keep turning on/off and draw varying amount of power.

Instead of three USB connections like this:

(trying to illustrate only the power circuits)

I would like to power them on one USB connection:

# Answer
> 1 votes
There is no difference between your circuits. Internally to the powerbank all three outlets are typically wired together just like in your second schematic. One outlet or three outlets it's all the same.

---
Tags: esp32
---


title: Turn off backlight on 2.4" TFT screen

text:
# Question
Title: Turn off backlight on 2.4" TFT screen
I have an Arduino Due and a 2.4" TFT screen shield this one. I'm trying to turn off the backlight to save power but not having any luck. I'm using the super nice MCUFriend library:

```
#include <Adafruit_GFX.h>
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;

```

It has worked great to make buttons and graphics, it's just the backlight I can't figure out. There's a datasheet for the driver chip and it has the following section to `Write CTRL Display`, which is what I imagine I need:

So I have been trying to send 0x00 to register 0x53, but the display stays lit. I've tried using MCUFriend\_kbv to set it, then thought maybe I'm doing something wrong so I tried their sample `LCD_ID_readreg.ino` and added some lines:

```
readReg(0x54, 3, "Read CTRL Display");
lcdWriteRegister(0x53, 0x00);
readReg(0x54, 3, "Read CTRL Display after update");

```

I am not sure if I'm just misunderstanding something but the results show:

```
reg(0x0054) 00 00 00    Read CTRL Display
reg(0x0054) 00 00 00    Read CTRL Display after update

```

I guess I was expecting the register to say the backlight was on before I update it, but it says `00` even before I make the update- yet the backlight is clearly on. Any idea what I'm missing? Maybe it's the comment there about "control lines must be low"? I have no idea what that means. If you search the document for "control lines" nothing comes up.

The read above to 0x54 is because that's apparently where you read that register (unlike some where you call the same address to read/write):

# Answer
That screen has no backlight control. The same chip is used on many LCDs and whether the inbuilt backlight control registers are used very much depends on the screen the chip is attached to.

If you want to control the backlight you will have to modify the shield to allow access to the right signal. I can't get a schematic for that specific screen, but from the images it looks like R2 on the underside may be a current limiting resistor for the backlight. Removing that resistor may turn off the back light, in which case you could replace it with a suitable transistor and similar resistor (you will have to check if it's high-side or low-side switched - does it provide power to the LEDs or sink it to ground) which you can control from a free GPIO pin.
> 3 votes

---
Tags: shields, tft
---


# Question
Title: Node MCU Esp12-E does not support server accept function
I am trying to get a web server to run on the ESP12E on the Node MCU variant, and following the example from the esp8266 documentation page here. But the code does not compile, throwing the following error message:

```
'class WiFiServer' has no member named 'accept'; did you mean '_accept'?

```

I'm relatively new to MCUs in general, and cannot find a solution for this on any website. Any help would be appreciated.

# Answer
> 2 votes
The 'latest' documentation applies for git master branch.

`accept()` is ready for the next release of Arduino esp8266. It will be version 3.1.0. Until then you can use `server.available()`. It works the same way as `accept()` in ESP8266WiFi library's WiFiServer.

I initiated the addition of `server.accept()`, because `server.available()` in esp8266 WiFiServer works as Ethernet library's `server.accept()`, not as `server.available()`.

---
Tags: esp8266, nodemcu, esp8266webserver
---