message:
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.

body:
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.


sender: user

message:
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).

[![enter image description here][1]][1]

```c++
#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;
}
```

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

sender: assistant

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

```c++
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`.


message:
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
```

body:
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][1]. [Here are the calibration docs.][2]

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?

  [1]: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf#2f
  [2]: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html#adc-calibration


message:
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.

body:
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][1] supports different ATmega4809 configurations and Optiboot.

  [1]: https://github.com/MCUdude/MegaCoreX


message:
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:

```lang-cpp

//  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.

body:
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!");
        }
      }
    }


message:
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;

```c++
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.

body:
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][1].

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][2]) 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][3] 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][4] for more info.

  [1]: https://www.arduino.cc/reference/en/language/functions/analog-io/analogread/
  [2]: https://www.arduino.cc/reference/en/language/functions/communication/serial/println/
  [3]: https://docs.arduino.cc/software/ide-v2/tutorials/ide-v2-serial-monitor
  [4]: https://www.tutorialspoint.com/auto-format-code-in-arduino-ide


message:
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 !

body:
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:

```c++
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.


message:
Ethernet library compilation error

I'm just trying to connect my Adruino to internet and my Ethernet connection config code fails when I try to verify it, and I'm not sure what is the exact reason.

I'm using an Ethernet shield and have installed Ethernet v.2.0.0 library.

This is the running code:
```
WANStatus initialiseWAN() {
  // Enter a MAC address for your controller below.
  // Newer Ethernet shields have a MAC address printed on a sticker on the shield
  byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
  WANStatus res;

  Serial.println("[INFO]: Initialising WAN");
  // Try to initialise Ethernet connecion

  if (Ethernet.begin(mac) == 0) {
    res.error = true;
    res.retry = true;

    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      res.message = "Ethernet shield was not found";
      Serial.print("[ERROR]: "); Serial.println(res.message);
      return res;
    }

    // If all component are present try assigning a static IP address
    IPAddress ip(192, 168, 0, 177);
    IPAddress myDns(192, 168, 0, 1);
    Ethernet.begin(mac, ip, myDns)
    Serial.print("[INFO]: Assigned static IP: "); Serial.println(Ethernet.localIP());

    if (Ethernet.linkStatus() == LinkOFF) {
      res.message = "Ethernet cable is not connected";
      Serial.print("[ERROR]: "); Serial.println(res.message);
      return res;
    }
    if (Ethernet.linkStatus() == Unknown) {
      res.message = "Ethernet link status is 'Unknown' check the cable";
      Serial.print("[ERROR]: "); Serial.println(res.message);
      return res;
    }

//    Static IP assigned
    res.error = false;
    res.retry = false;
    res.message = "Static IP Address";
    return res;
  } else {
//    Received IP address from DHCP
    Serial.print("[INFO]: Received DHCP IP: "); Serial.println(Ethernet.localIP());
    res.error = false;
    res.retry = false;
    res.message = "DHCP IP Address";
    return res;
  }

//  ToDo: check WiFi modules here
}
```

And, the error message:

[![enter image description here][1]][1]

  [1]: https://i.stack.imgur.com/9TZ9k.png
```
[Starting] Verifying sketch 'controller\controller.ino'
[Warning] Output path is not specified. Unable to reuse previously compiled files. Build will be slower. See README.
Loading configuration...
Initialising packages...
Preparing boards...
Verifying...
In file included from C:\Program Files (x86)\Arduino\libraries\Ethernet\src\Dns.cpp:8:0:
C:\Program Files (x86)\Arduino\libraries\Ethernet\src\Dns.cpp: In member function 'uint16_t DNSClient::BuildRequest(const char*)':
C:\Program Files (x86)\Arduino\libraries\Ethernet\src\utility/w5100.h:457:25: warning: result of '(256 << 8)' requires 18 bits to represent, but 'int' only has 16 bits [-Wshift-overflow=]
#define htons(x) ( (((x)<<8)&0xFF00) | (((x)>>8)&0xFF) )
                      ~~~^~~
C:\Program Files (x86)\Arduino\libraries\Ethernet\src\Dns.cpp:164:18: note: in expansion of macro 'htons'
twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG);
^~~~~
Sketch uses 22574 bytes (69%) of program storage space. Maximum is 32256 bytes.
Global variables use 1467 bytes (71%) of dynamic memory, leaving 581 bytes for local variables. Maximum is 2048 bytes.
IntelliSense configuration already up to date. To manually rebuild your IntelliSense configuration run "Ctrl+Alt+I"
[Done] Verifying sketch 'controller\controller.ino'
```

body:
Everything is alright. There is no compiler error and your sketch is ready to upload.

The compiler warning "*result of '(256 << 8)' requires 18 bits to represent, but 'int' only has 16 bits*" from the Ethernet library source code is nothing you have to worry about.


message:
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:

````
#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

body:
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);
      }
    }


message:
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?

body:
Consider this excerpt from your code:

```c++
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][fsm]. However, for this simple example you can get away with a
quick-and-dirty solution: block while waiting for user input:

```c++
// 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.

[fsm]: https://majenko.co.uk/blog/finite-state-machine


message:
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][1] 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][2], branch bs18b20 of my repo. The pulse is generated line 293, with custom code.

**More context**

I had already asked for help [right here][3] 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][4] 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.

  [1]: https://gitlab.com/guillaume.deshors/brewing_thermometer
  [2]: https://gitlab.com/guillaume.deshors/brewing_thermometer/-/blob/bs18b20/thermometre/thermometre.ino
  [3]: https://arduino.stackexchange.com/questions/80700/arduino-uno-pwm-output-and-servo-plugged-on-it-becomes-unstable-if-i-use-1wi/80701?noredirect=1#comment180410_80701
  [4]: https://arduino.stackexchange.com/questions/49421/arduino-reading-ds18b20-interferes-with-servo

body:
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:

```c++
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:

```c++
// 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.


message:
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.`

[![enter image description here][1]][1]

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

body:
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.


message:
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";
```

body:
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:

* [Reading Serial on the Arduino](https://majenko.co.uk/blog/our-blog-1/reading-serial-on-the-arduino-27) - a blog post by me, also applicable to TCP/IP communication
* [String::toFloat()](https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/tofloat/) - Converting a `String` object to a floating point value
* [strtof()](https://www.cplusplus.com/reference/cstdlib/strtof/) - Convert a C string to a floating point value


body:
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
    }


body:
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


message:
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:
[![customChar limits to 8][1]][1]

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?

  [1]: https://i.stack.imgur.com/jWmrN.jpg

body:
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.


message:
I2C sensors not working when I connect to LCD 20X04

I am making a hydroponic nutrient monitoring system using Arduino Uno, Atlas  Scientific EC sensor, pH sensor, and RTD (temperature) sensor in I2C mode. I also want to use LCD 20x04 to display the sensor reading so that will display the EC, pH, and temperature values.
I connect all the SDA and SCL to pin A4 (SDA) and A5 (SCL), and powered all the sensors and LCD with 3.3 V. Each sensor's SDA and SCL are added with resistor 4.7 kOhm.

[![The Fritzing of my circuit][1]][1]

I tested the code first by connecting my Arduino Uno to the RTD EZO circuit and sensors, without the LCD. The Serial Monitor successfully displays the data sensor reading of RTD, as well as 'No Data' for EC and pH as I do not connect the EC and pH sensors. But when I connect all the circuits and sensors, it can not detect the pH sensor. The most frustrating part is the LCD. The LCD at first displays the EC and RTD data, but only run for 5 minutes and freeze. The LCD sometimes only shows a "0.00" value for EC and RTD even though the Serial Monitor shows the data sensor reading.

I want to know if there is something wrong with my code or maybe the problem with my own circuit.

Here is the code:

    #include <Ezo_i2c.h>
    #include <Wire.h>                //enable I2C.
    #include <LiquidCrystal_I2C.h>

    Ezo_board ec = Ezo_board(100, "EC");
    Ezo_board ph = Ezo_board(99, "PH");
    Ezo_board temp = Ezo_board(102, "RTD");
    LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4);

    bool reading_request_phase = true;        //selects our phase

    uint32_t next_poll_time = 0;              //holds the next time we receive a response, in milliseconds
    const unsigned int response_delay = 1000; //how long we wait to receive a response, in milliseconds

    void setup()                     //hardware initialization.
    {
      Serial.begin(9600);            //enable serial port.
      Wire.begin();                  //enable I2C port.
      Serial.println("ATLAS EZO I2C v2");
      Serial.print("Test date: ");
      lcd.init();
      lcd.backlight();
      lcd.setCursor(1,1);
      lcd.print("ATLAS EZO I2C v2");
      lcd.setCursor(0,2);

      delay(3000);
      lcd.clear();
     }

      void loop() {                                                      //the main loop.
      lcd.setCursor(0,1);
      lcd.print("EC: ");
      lcd.setCursor(4,1);
      lcd.print(ec.get_last_received_reading());
      lcd.setCursor(10,1);
      lcd.print("ppm");
      lcd.setCursor(0,2);
      lcd.print("pH: ");
      lcd.setCursor(4,2);
      lcd.print(ph.get_last_received_reading());
      lcd.setCursor(0,3);
      lcd.print("Temp.: ");
      lcd.setCursor(7,3);
      lcd.print(temp.get_last_received_reading());
      lcd.setCursor(13,3);
      lcd.print("C");

      if (reading_request_phase)             //if were in the phase where we ask for a reading
      {
        //send a read command
        //to let the library know to parse the reading
        ec.send_read_cmd();
        ph.send_read_cmd();
        temp.send_read_cmd();

        next_poll_time = millis() + response_delay;         //set when the response will arrive
        reading_request_phase = false;                      //switch to the receiving phase
      }
      else                                                //if were in the receiving phase
      {
        if (millis() >= next_poll_time)                    //and its time to get the response
      {
        receive_reading(ec);                              //get the reading from the EC circuit
        receive_reading(ph);                              //get the reading from the PH circuit
        receive_reading(temp);                              //get the reading from the RTD circuit

        reading_request_phase = true;                     //switch back to asking for readings
      }
     }
     }

      void receive_reading(Ezo_board &Sensor) {
      Serial.println();
      Serial.print(Sensor.get_name()); //print the name of the EZO circuit
      Serial.print(": ");
      Sensor.receive_read_cmd();

      switch (Sensor.get_error())                          //switch case based on what the response code is.
         {
        case Ezo_board::SUCCESS:
        Serial.print(Sensor.get_last_received_reading());               //the command was successful, print the reading
        break;

        case Ezo_board::FAIL:
        Serial.print("Failed ");                          //means the command has failed.
        break;

        case Ezo_board::NOT_READY:
        Serial.print("Pending ");                         //the command has not yet been finished calculating.
        break;

        case Ezo_board::NO_DATA:
        Serial.print("No Data ");                         //the sensor has no data to send.
        break;
     }
    }

  [1]: https://i.stack.imgur.com/t4PbL.jpg

body:
Welcome to Stack Exchange!

I can spot a few problems with the circuit. As @hcheung said, the I2C pull-up resistors should only be wired between SDA>3.3V and SCL>3.3V (in parallel), not in series with the sensors.

Also, another warning: You are powering your sensors with **3.3V**, but the outputs from the Arduino Uno are **5V!** Many boards will not like this and might fry themselves, or at least not function correctly. Their signals will also be 3.3V instead of 5V, potentially causing more weird behavior.

If all your components are compatible with 5 volt power (check their datasheets/guides), I would recommend powering them all with 5 volts.

Otherwise, you will need level shifters to convert between the 5V Arduino signals and the 3.3V board signals.


body:
Thank you for all your help.
I now realize that I have made the wrong I2C circuits. Then I modified them and now the program and the sensors work perfectly.

Here is my circuit now.

[![enter image description here][1]][1]

  [1]: https://i.stack.imgur.com/BHgWA.jpg


message:
Turn off backlight on 2.4" TFT screen

I have an Arduino Due and a 2.4" TFT screen shield [this one](http://www.lcdwiki.com/2.4inch_Arduino_Display#Program_Download).  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](http://www.lcdwiki.com/res/MAR2406/ILI9341_Datasheet.pdf) for the driver chip and it has the following section to `Write CTRL Display`, which is what I imagine I need:
[![enter image description here][1]][1]

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):
[![enter image description here][2]][2]

  [1]: https://i.stack.imgur.com/2VRCq.png
  [2]: https://i.stack.imgur.com/AH6Uw.png

body:
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.


message:
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][1] 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)

[![three usbs][2]][2]

I would like to power them on one USB connection:

[![one usb][3]][3]

  [1]: https://arduino.stackexchange.com/questions/28930/is-it-safe-to-use-the-same-power-source-for-arduino-and-its-motor-shield
  [2]: https://i.stack.imgur.com/Ezo0c.png
  [3]: https://i.stack.imgur.com/eBkM0.png

body: 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.


message:
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.)

body:
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][1], 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):

    [![enter image description here][2]][2]

- **A schematic:** A schematic is the standard way of describing any electronic circuit. For example look at the [Arduino Uno schematic][3]. 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][4]), 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.

  [1]: https://fritzing.org/
  [2]: https://i.stack.imgur.com/SDVyV.png
  [3]: https://www.arduino.cc/en/uploads/Main/arduino-uno-smd-schematic.pdf
  [4]: https://www.opensourceagenda.com/projects/arduino-kicad-library


message:
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](https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/server-examples.html). 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.

body:
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()`.


message:
How can I do web hosting having all the code of the site stored in a sd?

I am carrying out this project in which the arduino acts as web server and hosts a website in which I show the constantly updated temperature of a laboratory.

The problem is running all this code in the arduino, memory runs out easily.

    void loop() {
      int value= analogRead(PIN_LM35);
      float temperature= value/ 2.046;
      myFile = SD.open("temperature.txt");
      if (myFile) {
        Serial.println(temperature);
        }
        myFile.close();

       EthernetClient client = server.available();
      if (client) {
        while (client.connected()) {
          if (client.available()) {
            char c = client.read();

            //read char by char HTTP request
            if (readString.length() < 100) {
              //store characters to string
              readString += c;
              //Serial.print(c);
             }

             //if HTTP request has ended
             if (c == '\n') {
               Serial.println(readString); //print to serial monitor for debuging

               client.println(F("HTTP/1.1 200 OK")); //send new page
               client.println(F("Content-Type: text/html"));
               client.println();
               refreshcounter=refreshcounter+1;
               client.println(F(""));
               client.println(F(""));
               client.print(F("<meta http-equiv=\"refresh\" content=\"2\">"));
               client.println(F("<meta name='apple-mobile-web-app-capable' content='yes' />"));
               client.println(F("<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />"));
               client.println(F("<TITLE>TEMPERATURE SENSOR LAB01</TITLE>"));
               client.println(F(""));
               client.println(F(""));
               client.println(F("
TEMPERATURE SENSOR LAB01
"));
               client.println(F("
"));
               client.println(F("
"));
               client.println(F("
Arduino with Ethernet Shield
"));
               client.println(F("
"));
               if(temperatura<24){
                  client.println("
");
                  client.println(temperature);
                  client.println("
");
               }
               else if(temperature>=24 && temperature<=26){
                 client.println("
");
                 client.println(temperature);
                 client.println("
");
               }
               else{
                 client.println("
");
                 client.println(temperature);
                 client.println(F("
It is recommended to activate the air conditioner.
"));
                 client.println("
");
               }
               client.println(F("
Date/Time:
"));
               client.println(F(""));

               client.println("<svg width=\"1000\" height=\"250\">");
               client.println("<rect width=\"150\" height=\"5\" fill=\"gray\">");
               client.println("<animate attributeName=\"x\" from = \"0\" to =\"10000\" dur=\"10s\" fill=\"freeze\" />");
               client.println("</rect");
               client.println("</svg>");

               client.println("
");
               client.println("");
               client.println("");

               delay(1);
               //stopping client
               client.stop();
                //clearing string for next read
                readString="";

             }
           }
        }
    }
    }

I thought to save memory to put all the code of the web page in an external sd.
However, I don’t really know how to use it from SD card.

The problem that stops me is the fact that the site does not have to be static but constantly updated with new temperature data.

How can I do that?

body:
You wrote:
> the site does not have to be static but constantly updated with new
> temperature data.

A good option is to use Ajax.
The basic idea is to split the site in two parts:

- a static part, potentially large, which contains all the user
  interface, the styling, the bells and whistles...
- a tiny, dynamic part that contains the data that is constantly updated
  _and nothing more_.

The static part would be served from the SD card when the client sends a
`GET /` request. The dynamic part would be served from another endpoint,
for example as a reply to `GET /temperature`. Serving the dynamic part
should be very simple, something like:

```c++
client.println(temperature);
```

Yes, just send the number as ASCII, no HTML formatting. If you ever need
to send more than one number (e.g. multiple temperatures, or temperature
and humidity), format them in [JSON][]. No need to use a library for
that, plain `print()` should be cheaper and good enough:

```c++
client.print(F("{\"temperature\":"));
client.print(temperature);
client.print(F(",\"humidity\":"));
client.print(humidity);
client.print('}');
```

On the client side, `JSON.parse()` gets the data back as an easy-to-use
data structure.

Here is a minimal example of what the static part could look like.
Notice the JavaScript code sent to the client. This code is responsible
for querying the temperature every 1000 milliseconds, and updating the
Web page with the new data;

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Ajax test</title>
</head>
<body>

<h1>Ajax test</h1>

<p>Temperature: <span id="temperature">---</span> °C</p>

<script>
var data_field = document.getElementById("temperature");
setInterval(function() {
    var request = new XMLHttpRequest();
    request.onreadystatechange = function() {
        if (request.readyState != 4) return;
        data_field.innerText = JSON.parse(request.responseText);
    };
    request.open("GET", "/temperature");
    request.send();
}, 1000);
</script>
</body>
</html>
```

A few notes:

- This example is purposefully minimal. You may want to add some error
  checking, some decorations, some CSS and the such. Handling a
  temperature-dependent color also belongs to the client code.

- The example uses good old `XMLHttpRequest`. You may want to try the
  more modern [fetch API][] instead:

  ```js
  setInterval(function() {
      fetch("/temperature")
          .then(response => response.json())
          .then(data => { data_field.innerText = data; });
  }, 1000);
  ```

- If you are sending updates frequently enough to significantly load
  your Arduino, you may want to look at [Server-sent events][sse]. This
  is a technique that allows you to significantly reduce the overhead of
  sending data updates. It is not as popular as Web-sockets, but has the
  advantage of being simpler to implement server-side.

- If you can put a reverse-proxy between your Arduino and the Internet,
  the proxy can handle the static content. Your Arduino then only
  handles the dynamic data and wouldn't need an SD card. If you
  reverse-proxy Server-sent events, make sure the proxy doesn't buffer
  the server response. See for example these [tips on configuring
  Nginx][nginx] for this purpose.

- The static data could also be served from a completely different Web
  site. For this to work, you have to fulfill two conditions:

  1. The Arduino server has to add the header
     `Access-Control-Allow-Origin: *` to its responses.

  2. On the client code, you have to provide the full URL of the Arduino
     as an argument of `request.open()`, `fetch()` or
     `new EventSource()`.

- The previous trick also allows you to open the Web page directly from
  your local file system, which can be very handy for developing.

- Once you get the basic scheme working, Web technologies allow you to
  get as fancy as you want. You could create an analogue gauge (with SVG
  transform rotate). You could even [add a graph][plotly], updated in
  real time, that shows the time evolution of the temperature, and is
  entirely handled by the client.

[JSON]: https://www.json.org/
[fetch API]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
[sse]: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events
[nginx]:  https://stackoverflow.com/questions/13672743/eventsource-server-sent-events-through-nginx
[plotly]: https://plotly.com/javascript/