message:
Round to first significant digit

I want to round a decimal number (x), but I need to do it differently depending on how it is. If it has integer significant digits, we round to the nearest integer, and if not, we round to the first significant digit. So the following would happen with these example numbers: 11.871->12, 11.177->11, 37.233->37, 37.779->38, 0.578->0.6, 0.544->0.5, 0.0257->0.03, 0.0223->0.02... (The numbers could have more or less decimal places than in the examples).

To implement this, I have created a function (type) in which we check if the most significant digit is of type integer or decimal. This function returns this characteristic of the number in the form of a "string". So if the most significant digit is an integer we just use the "round()" function. However, I don't know how to round a number to the first significant digit (roundto_fsd() function). Does anyone know of any function capable of doing this or any method to do it?

```
float x;

char type(float number) {
  char type[8];
  if (int(number) != 0) {
    type = "integer";
  } else {
    type = "decimal";
  }
  return type;
}

float roundto_fsd(float number) {}

void setup() {
  Serial.begin(9600);
  if (!type(x).compareTo("integer")) {
    Serial.println(round(x));
  } else if (!type(x).compareTo("decimal")) {
    Serial.println(roundto_fsd(x));
  }
}

void loop() {}
```

body:
First of all, let me clarify that there is nothing “decimal” in a
`float`: a `float` is a **binary** (not decimal) floating point number.
The `Serial.println()` function does a binary-to-decimal conversion for
the purpose of representing the number as human-readable text. If you
want a specific number of **decimal** digits after the radix point, you
should ask `Serial.println()` to provide them. This is done by passing
this number as a second parameter:

```c++
Serial.println(sqrt(2));    // prints "1.41" (2 decimals by default)
Serial.println(sqrt(2), 0); // prints "1"
Serial.println(sqrt(2), 5); // prints "1.41421"
```

Now the question is: how to compute the number of required digits after
the radix point? This depends on how big the `float` is. If it is
smaller than 1 but larger or equal to 0.1, you want just one digit. If
it is ten times smaller than that, you want to digits, and so on:

    numbers      digits
    ───────────────────
    [1, +∞)        0
    [0.1, 1)       1
    [0.01, 0.1)    2
    [0.001, 0.01)  3

I suggest repeatedly multiplying your `float` by 10 until it gets ≥ 1,
and count the number of times you had to do so:

```c++
/* How many decimal places to print. */
int decimal_places(float x)
{
    int i = 0;
    while (x < 1) {
        x *= 10;
        i++;
    }
    return i;
}
```

You would use this function like this:

```c++
Serial.println(x, decimal_places(x));
```

Note that there is a small issue with this approach. If you try to print
0.97, `decimal_places()` will say you need one decimal, and
`Serial.println()` will print “1.0”. If you would rather have it print
“1”, then change the loop condition within `decimal_places()` to:

```c++
while (x < 0.95)
```

**Caveat**: All this assumes that the numbers you want to print are all
strictly larger than zero. Otherwise `decimal_places()` would have an
infinite loop.


sender: user

message:
Generalize webserver routing

I'm following the examples for ESP32:

      AsyncWebServer _server(80);

      _server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
      {
        request->send(SPIFFS, "/index.html", String(), false);
      });

      _server.on("/css/index.css", HTTP_GET, [](AsyncWebServerRequest *request){
        request->send(SPIFFS, "/css/index.css", "text/css");
      });

      _server.onNotFound([](AsyncWebServerRequest *request){
        request->send(404);
      });

    _server.begin();

With this approach I have to know in advance each file I store in the `SPIFFS` and add a handler for each one.

Is there a more elegant way to automatically serve any file that exists in the flash?

sender: assistant

body:
You can tell the webserver to serve the static content from a specific folder:

    server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.html");

In this case it serves on the root URL the content from the SPIFFS root. So if I place a file called `image.jpg` in the SPIFFS root it will be served at `/image.jpg`.
 For more information you can look at [the corresponding section of the libraries Readme file][1].

  [1]: https://github.com/me-no-dev/ESPAsyncWebServer#serving-static-files


message:
How often does a mpu6050 gyro sonsor need calibration?

I want to use it in my real car for daily use to measure yaw angle when needed.

Is is ok to only calibrate it once at first then use it every day when driving without any problem? if not, how often should I recalibrate it?

body:
Most accelerometers and gyroscopes need little if any calibration.  Consult the manufactures specification sheets.  If any calibration is made and correction values found, then it is assumed those values may be used in the future for the same accelerometer / gyroscope.

[This analog.com document][1] goes into gyroscope calibration details.

Deriving the angle of the car (the "yaw") at any given moment will likely be problematic.  Errors from integrating the gyroscope's axis which is perpendicular to the ground will accumulate over time.  Which is the main problem when using [dead reckoning][2].

Consider using a magnetometer & accelerometer along with the gyroscope in order to mitigate the accumulated errors from only using the gyroscope.

  [1]: https://www.analog.com/media/en/technical-documentation/technical-articles/gyrocalibration_edn_eu_7_2010.pdf
  [2]: https://en.wikipedia.org/wiki/Dead_reckoning


message:
Can't make attachInterrupt() work

I have an accel+gyro sensor connected to an Arduino Zero. It's configured to output an interrupt signal on pin 2 when tapped. I can do a `digitalRead()` on the pin, and it does go high, so the interrupt from the sensor is triggering as expected.

However, when I try to `attachInterrupt()` to that pin, so I can update a Boolean variable to use later in the code, it doesn't work; the boolean variable never updates.

Am I doing something wrong in the code, or is it a hardware issue? Thank you for your help.

    byte int2 = 2;
    int int2_val;
    volatile boolean tapcheck = false;

    void interrupt_setup() {
      // set up the sensor to fire interrupts
      // ...

      pinMode(int2, INPUT);

      // attach an interrupt on pin 2
      attachInterrupt(digitalPinToInterrupt(int2), tapdummyf, RISING);
    }

    // double tap ISR function
    void tapdummyf () {
      tapcheck = !tapcheck;
    }

    void interrupt_test() {
      int2_val = digitalRead(int2);
      if (int2_val == 1) {
        SerialUSB.println ("interrupt triggered ");
        int2_val = 0;
      }
    }

    void loop(void) {
    // in loop
      interrupt_test();
        if (tapcheck){
              SerialUSB.println("dt1");
        }
    }

body: You should use an external pulldown resistor on your input pin, 10K would probably be ideal, tapcheck will only be true on alternate interrupts as you're toggling it.


body:
Pin 2 on Arduino M0 is the only pin on headers which doesn't support external interrupt because it is mapped to SAMD21G pin PA08 which is the only pin of SAMD which can't be multiplexed as external interrupt (because it is the only pin which supports NMI).

On Arduino Zero SAMD pin PA08 is mapped to headers pin 4, which is a better choice for a board in Uno format since on Uno only pins 2 and 3 support external interrupt. Maybe there was originally an idea that NMI (non-maskable interrupt) is an even better external interrupt.

Function attachInterrupt requires a pin which support external interrupt.

It looks like you have an Arduino M0 board, not Arduino Zero.


message:
How to append to array of Strings in arduino?

Here is my code:
```lang-cpp
char *StrAB[] = {"29 EC C7 C1", "69 5B C9 C2", "22 3B 83 34",  "12 BF BF 34", "C6 78 8E 2C" };
void setup() {
  Serial.begin(9600);
}
void loop() {
  for (int i = 0; i < sizeof(*StrAB)+1; i++)
  {
    Serial.println(StrAB[i]);
    delay(1000);
  }
  Serial.println(sizeof(*StrAB)+1);
  StrAB[sizeof(*StrAB)+1]= "00 00 00 00";
}
```

I'm trying to append to the end of array of strings but it doesn't work? How can I delete a string from the array?

body:
As stated by Sim Son in a comment, an array is a fixed-size data
structure in C++. You thus have to choose beforehand a suitable size,
and then keep track of how much of the array is actually used. For
example:

```c++
const int AB_max = 10;  // array capacity
const char *AB_str[AB_max] = {"29 EC C7 C1", "69 5B C9 C2",
    "22 3B 83 34",  "12 BF BF 34", "C6 78 8E 2C"};
int AB_count = 5;  // used slots
```

To add a string to this array, you write it to the next available slot.
But you have first to make sure there is still room available:

```c++
void AB_add(const char *s) {
    if (AB_count < AB_max)
        AB_str[AB_count++] = s;
}
```

If you want to remove an item (other than the last one), you will have
to shift all the following items down the array. The `memmove()`
function comes handy for this:

```c++
void AB_remove(const char *s) {
    // Find the index of s.
    int i;
    for (i = 0; i < AB_count; i++)
        if (strcmp(s, AB_str[i]) == 0) break;

    // Do nothing if not found.
    if (i == AB_count) return;

    // Move subsequent items down the array.
    memmove(&AB_str[i], &AB_str[i+1],
            (AB_count - (i + 1)) * sizeof *AB_str);
    AB_count--;
}
```

Note that moving these items down can be costly if the array is pretty
long. An array may then not be the best data structure for you. I
wouldn't worry though if it's just a dozen items or so.

Here is now a small test for all of the above:

```c++
void AB_print() {
    Serial.print("AB: ");
    Serial.print(AB_count);
    Serial.println(" items");
    for (int i = 0; i < AB_count; i++) {
        Serial.print("    ");
        Serial.println(AB_str[i]);
    }
    Serial.println();
}

void setup() {
    Serial.begin(9600);
    AB_print();
    AB_add("00 00 00 00");
    AB_print();
    AB_remove("12 BF BF 34");
    AB_print();
}

void loop() {}
```

Note that this is a very “C” style of doing things. If you want to go to
more idiomatic C++, you can start by putting everything that is named
with the prefix `AB_` inside a class.

If you really want an array where you can vary the length, you may
allocate it with `malloc()` and resize it with `realloc()`. These
functions, however, are not very friendly to memory-constrained devices.
They are thus often avoided in the embedded world. They may also not
play well with code that uses `new` and `delete`, including library code
that you may not be aware of.


message:
Adjusting Threshold for Digital Pins

I am working on a project using Force Sensors to build a keyboard for MD patients.
I have connected the sensors (each with 4 input pins) to **digital pins** to *Arduino Due*.
I want to adjust the threshold of the digital pins in order to cancel out the initial weight of a user's hand when using the keyboard.
I have read that digital pins have a built-in threshold ("low"<0.3 Vcc and "high">0.6Vcc). I can't connect my sensors to Analog pins (due to needing 20 input pins), and was wondering if adjusting the threshold is possible?
I have researched and found one project that used Analog pins and adjusted the threshold, which I am trying to emulate: https://www.instructables.com/Arduino-Programmable-Button-Panel-As-Keyboard/
P.S: I am a beginner at Arduino and would appreciate the help

body:
No, you cannot change these threshold. They are set by the digital input hardware (technically a Schmitt trigger) inside the microcontroller. They are not meant to be adjustable, since they are digital input, not analog inputs.

So you either need to build your own adjustable logic (involving opamps and variable resistors), feeding the output of that to the Arduino, or you need to use analog inputs.

I would suggest using the second method. You can extend the number of analog inputs basically by 2 means:

- You can buy analog multiplexers. These are chips that can connect one analog input of the Arduino on one side to X pins on the other side. Most of them are controlled via digital pins. Then you cycle through each setting of the multiplexer to connect one sensor at a time and do a measurement on each of them. Each analog pin can be connected to one analog multiplexer

- You can buy an external ADC board. These are often connected via interfaces like I2C or SPI (for example [this one from Adafruit][1] with 4 channels each). You can use multiple of them.

  [1]: https://www.adafruit.com/product/1085


message:
ESP32 Potentiometer issue: Resolution mismatch of the potentiometer with unlimited resolution and reading the values with Wire.h

I have the problem, that the potentiometer goes from the range of 0 Volts to 3,3 volts. But within this range the measured value goes **from about 0 to 65535 multiple times** (over 10 cycles).

When I change the code from my ADC library to 32 bit I get 32 bit values (0 - 4294967296) but the same error with the beginning at 0 multiple times within the potentiometer range occurs.

**Hardware:**

**Board:** ESP32
**ADC:** MAX11613 (12 bit adc)
https://www.mouser.de/datasheet/2/256/MAX11612-MAX11617-1508955.pdf
**Potentiometer:** 3046L - 3 - 203 https://www.mouser.de/datasheet/2/54/3046-776396.pdf

Part of the code that reads the adc values:

```
uint8_t MAX11613::MAX11613_ADC_Read(structMAX11613* chip, uint8_t channel, uint16_t* val){

 uint8_t configurationByte = ( (channel<<1) & 0x0e) | 0x61;
 MAX11613_Configuration(chip, configurationByte);

 Wire.beginTransmission(chip->devAddress);
 Wire.requestFrom(chip->devAddress, (byte) 2);    // request 2 bytes from slave device wireIface
   while (Wire.available()) { // slave may send less than requested
    //char c = Wire.read(); // receive a byte as character

 uint16_t value = 0;
 value =  Wire.read();
 value |= Wire.read() << 8;

    //This also works:
 /*uint32_t buf1;
 size_t actually_read = Wire.readBytes((uint8_t*)&buf1, 2);
 *val = actually_read;
 //Serial.println(value);*/

 *val = value;
 }
 if (Wire.endTransmission() != 0){
 return 1;
 }
 return 0;

}
```

body:
The MAX1161x are 12-bit ADCs, so the problem is not related to an uint16 overflow as you seem to assume.
The ADC transmits most significant bits (MSB) first as can be seen [in figure 10 on page 17][1]. To account for that you need to change

    value =  Wire.read();
    value |= Wire.read() << 8;

to

    value = Wire.read() << 8;
    value |=  Wire.read();

  [1]: https://www.mouser.de/datasheet/2/256/MAX11612-MAX11617-1508955.pdf


message:
Help with Arduino sleep and watchdog timer interrupt

I want to use Arduino's sleep and wakeup functionality but have hit a roadblock and can't seem to get past it. As I am just prototyping for a final system, I cannot use the LowPower library to implement the functionality so I am doing it barebones. I am able to put the Arduino to sleep just fine, the main problem is with the watchdog timer. I have or I think I have configured it for a 8 sec interrupt to wake the Arduino back up from sleep but Arduino comes out of the sleep just as it enters it without any delay.
The code is

    #include <Arduino.h>
    #include <avr/sleep.h>

    void goToSleep();
    void setupWDT();
    void stopWDT();

    ISR(WDT_vect) {
      sleep_disable(); // wake up the Arduino
    }

    void setup() {
      set_sleep_mode(SLEEP_MODE_PWR_DOWN);

      stopWDT();

      pinMode(LED_BUILTIN, OUTPUT);

      Serial.begin(9600);
      Serial.println("Uno is in setup funtion.");

      bool ledState = 0;
      while(millis()<3000){
        digitalWrite(LED_BUILTIN, ledState);
        ledState = !ledState;
        delay(500);
      }
    }

    void loop() {
      Serial.println("Uno is awake.");
      digitalWrite(LED_BUILTIN, HIGH);
      delay(2000);
      Serial.println("Going to sleep...");
      digitalWrite(LED_BUILTIN, LOW);
      delay(100);

      setupWDT();
      goToSleep();
      stopWDT();
      delay(100);
      digitalWrite(LED_BUILTIN, HIGH);
    }

    void goToSleep() {
      ADCSRA &= ~(1<<ADEN); // disable ADC
      sleep_mode(); // put the Arduino to sleep
    }

    void setupWDT() {
      cli();
      WDTCSR |= (1 << WDCE);
      WDTCSR &= ~(1 << WDE);
      WDTCSR |= (1 << WDCE) | (1 << WDIE) | (1 << WDP3) | (1 << WDP0); // configured for 8 sec delay interrupt
      sei();
    }

    void stopWDT() {
      cli();
      MCUSR &= ~(1 << WDRF); // clear reset flag
      WDTCSR |= (1 << WDCE);
      WDTCSR &= ~(1<<WDE);
      WDTCSR = 0x00; // stop WDT
      sei();
    }

body:
Try changing this:
```
void setupWDT() {
  cli();
  WDTCSR |= (1 << WDCE);
  WDTCSR &= ~(1 << WDE);
  WDTCSR |= (1 << WDCE) | (1 << WDIE) | (1 << WDP3) | (1 << WDP0); // configured for 8 sec delay interrupt
  sei();
}
```
to:
```
void setupWDT() {
  cli();
  WDTCSR = (1 << WDCE) | (1 << WDE) ;
  WDTCSR = (1 << WDCE) | (1 << WDIE) | (1 << WDP3) | (1 << WDP0); // configured for 8 sec delay interrupt
  sei();
}
```
It appears that your construct violates the 4 clock cycle window that the WDCE Watchdog Change Enable bit allows for updates to the WDE bit.


message:
Apparently the photoresistors don't pass the input at the leds

I am making a school project where i need to create a parking loot in tinkercad. Me and my mate tried to use a bunch of photoresistor that worked as a sensor. No light = car = red led; light = no car = green led. We can't figure out why the leds dont turn on. We are still on a low level of abilities on this type of work and in class we didn't see a lot of components, so the photoresistor were one of the best choice.

Here is the screenshot of the whole project, it's in italian so if you guys needs a transduction of the variable just tell me. Don't mind the button, we were trying something.

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

Here is the code: In this line "if(analogRead(fotoresistori[i]) < 300)" we put 300 because with 0 etc. it did not work
```
int fotoresistori[] = {A0, A1, A2, A3, A4};
int verdi[] = {11, 10, 9, 8, 7};
int rossi[] = {6, 5 , 4, 3, 2};

void setup()
{
  pinMode(13, INPUT);
  pinMode(12, INPUT);
  pinMode(11, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(2, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  Serial.println(postiDisponibili);
  if(digitalRead(13) == HIGH){
    postiDisponibili++;
  }
  else if(digitalRead(12) ){
    postiDisponibili--;
  }
  for(int i = 0; i<5; i++){
    if(analogRead(fotoresistori[i]) < 300){
      digitalWrite(rossi[i], HIGH);
      digitalWrite(verdi[i], LOW);
    }else{
      digitalWrite(rossi[i], LOW);
      digitalWrite(verdi[i], HIGH);
    }
  }
  delay(500);
}
```

The value of A0 is always at 0.

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

body: You're not applying any voltage to the photoresistors and the other end is connected to earth so it will always be zero. You need to connect the analog end to +5v via a suitable current limiting resistor (suggest 10K for a typical photoresistor) then measure the voltage.


message:
How to do multiple serial.read()

first of all im new here and im really sorry if there's some mistakes when im making this question. So im trying to make a program to calculate using serial read, and im going to input a lot of values.

These are the codes that im trying to upload, but it wont shows the input.

```int perlakuan;
int PpmNeed;
int Ppmpertank;
int nyala;
int tangki;
int sensor;
int mlkeluar;
int perlakuan;
void setup() {
  Serial.begin(115200);
  Serial.setTimeout(10);
}

void loop() {
    Serial.println("Besar Tangki");
    while(Serial.available() == 0){}
    tangki = Serial.parseInt();

    Serial.println("Kadar Dari Sensor");
    while(Serial.available() == 0){}
    sensor = Serial.parseInt();

    Serial.println("Data Perlakuan");
    while(Serial.available() == 0){}
    perlakuan = Serial.parseInt();

    Serial.print("Besar Tangki : ");
    Serial.println(tangki);
    Serial.print("Kadar Dari Sensor : ");
    Serial.println(sensor);
    Serial.print("Data Perlakuan : ");
    Serial.println(perlakuan);
}

body:
Your problem is that humans are slow. Very slow.

Functions like `Serial.parseInt()` etc are designed for reading data from sensors. As such they expect data to arrive fast. They have a *timeout* whereby they will abort if data doesn't arrive in a timely fashion.

That's not conducive to interacting with a human that likes to take their time typing in numbers.

Instead you will need to write a routine (or find one online, such as the one I show [here](https://majenko.co.uk/blog/our-blog-1/reading-serial-on-the-arduino-27)) which stops and waits for input to be provided before then parsing the given data and continuing.

If you're interacting with a serial terminal rather than the Arduino IDE's serial "monitor" then it can also be good to echo back the characters as they are received so the person typing can see what they have typed. Line editing (or at least basic backspace handling) would also be useful in that situation too.


body:
a short function to read user Inputs.
do not wort if user sends multiple numbers at once

USE ONLY FOR HUMAN INPUT.

    #define NOP __asm__ __volatile__ ("nop\n\t")

    //Read next number
    int nextNumber() {
      int input = 0;

      //wait for next Byte
      while (Serial.available() == 0) {NOP;}

      /read number
      input = Serial.parseInt();

      //Give some time for bytes to get over Serial bus, then remove it
      delay(1);
      while (Serial.available() > 0) {
        int incomingByte = Serial.read();
      }
      return input;
    }


body:
While your way to read the input from user is sub-optimal, to make it work you have to read the new line characters Serial Monitor sends (if line ending are selected in the drop down box).

The new line characters are available on Serial after the digits, so they make
```
while(Serial.available() == 0){}
```
to end immediately.

You can patch it up by reading the trailing line ending characters.
```
int PpmNeed;
int Ppmpertank;
int nyala;
int tangki;
int sensor;
int mlkeluar;
int perlakuan;
void setup() {
  Serial.begin(115200);
  Serial.setTimeout(10);
}

void loop() {
    Serial.println("Besar Tangki");
    while (Serial.available()) {
      Serial.read();
    }
    while(Serial.available() == 0){}
    tangki = Serial.parseInt();

    Serial.println("Kadar Dari Sensor");
    while (Serial.available()) {
      Serial.read();
    }
    while(Serial.available() == 0){}
    sensor = Serial.parseInt();

    Serial.println("Data Perlakuan");
    while (Serial.available()) {
      Serial.read();
    }
    while(Serial.available() == 0){}
    perlakuan = Serial.parseInt();

    Serial.print("Besar Tangki : ");
    Serial.println(tangki);
    Serial.print("Kadar Dari Sensor : ");
    Serial.println(sensor);
    Serial.print("Data Perlakuan : ");
    Serial.println(perlakuan);
}
```


message:
How to perform multitask using arduino such as update data as well as check condition?

Here data is updated after every 2 seconds. But when the condition is true then the valve and motor process starts and data is updated only after completion of that part (i.e., data is updated after 25 seconds). I want data updation and condition checking simultaneously.

    #include <Wire.h>
    #include <Adafruit_Sensor.h>
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <SPI.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>

    #define ONE_WIRE_BUS 4
    #define TEMPERATURE_PRECISION 9

    #define motor 6
    #define valve 7

    OneWire oneWire(ONE_WIRE_BUS);
    DallasTemperature sensors(&oneWire);

    const float thld = 35;

    #define SCREEN_WIDTH 128 // OLED display width, in pixels
    #define SCREEN_HEIGHT 64
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

    void setup() {
      Serial.begin (115200);
      pinMode(motor, OUTPUT);
      pinMode(valve, OUTPUT);
      delay(10);

        if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
        Serial.println(F("SSD1306 allocation failed"));
        for(;;);
      }
        delay(2000);

      display.setTextColor(WHITE);
    }
     void loop() {
     sensors.requestTemperatures();
      float temp = sensors.getTempCByIndex(0);
      Serial.println(temp);
      Serial.println((char)176);
      Serial.println("C  |  ");
        if ( temp > thld)
      {
      digitalWrite (valve, LOW);
      delay (5000);
      digitalWrite (motor, LOW);
      delay (10000);

      digitalWrite (motor, HIGH);
      delay (6000);
        digitalWrite (valve, HIGH);
      delay (2000);
      }
      else
      {
        digitalWrite (motor, HIGH);
        digitalWrite (valve, HIGH);
      }

       display.clearDisplay();
       display.setCursor(0, 0);
       display.setTextSize(1);
       display.println("Temperature");
       display.setCursor(0, 30);
       display.println("Soil & Water Engg.");
       display.setTextSize(2);
       display.setCursor(0,10);
       display.println(temp);
       display.setCursor(75, 10);
       display.println("C");
       display.setCursor(0,40);
         display.display();

    delay (2000);
     }

body:
You need to think about this with a real-world analogue.

I like to use boiling an egg...

There are three ways you can boil an egg:

Blocking operation
------------------

1. Put the egg in the boiling water
2. Stand there staring at it for three minutes or so
3. Take the egg out of the water and eat it

Timer operation
---------------

1. Put the egg in the boiling water
2. Set a timer for 3 minutes time
3. Go off and do something else
4. When the alarm goes off take the egg out and eat it

Time polling
------------

1. Put the egg in the boiling water and record the current time
2. Go off and do something else, every so often glancing at your watch and comparing the time to the time you started
3. When three minutes have passed take the egg out and eat it

Currently you are using the *blocking* operation where you're stood staring at the egg until it's time to do something.  You need to change your code to use one of the other methods.

Most times the *time polling* method is good enough. You may get some *jitter* where whatever else it is you are doing causes a delay before you get to glance at your watch, but that is rarely an issue. For greater precision (better for higher frequency checking) you use a timer which triggers an interrupt so you always do things at more precise intervals.

There is an example in the IDE called `BlinkWithoutDelay` which implements the time polling in a very simplistic way - record the time, then compare that time and the current time, and when it's elapsed change the LED's state, recording a new time.


body:
The general approach for non-blocking code is to use millis() and compare durations:

    bool active = false;
    unsigned long start = 0;
    const unsigned long duration = 25000; // 25 seconds

    void loop() {
        unsigned long now = millis();
        if (start_condition) {
            active = true;
            start = now;
            turn_on();
        }
        if (active && now - start >= duration) {
            active = false;
            turn_off();
        }
    }

Properly written non-blocking code never uses delay() but instead records time stamps and
compares durations to see when to do something.

One trap for beginners: Never compare times, only durations!
Because millis() wraps around (after 2^32 msec which is ~49.7 days) you can have a start time
that is greater than the current time, but if you subtract 2 times it always gives a proper
duration (as long as the duration is itself less than 50 days)

So the only correct way to do time checks with millis is:

    (later_time - earlier_time) compared-with duration

There is a library I like that makes all of this so easy: "Ticker"
 - https://www.arduino.cc/reference/en/libraries/ticker/
 - Documentation: https://github.com/sstaub/Ticker

One subtlety with Ticker is the resolution - it can use milliseconds or microseconds, and the time can be specified in milliseconds or microsecoonds.

The default is to use microsecond resolution with millisecond specification:

    Ticker x(callback, time_in_millisec); // repeat defaults to 0 (continuous), resolution to MICROS

This only works for durations up to 70 minutes, for longer durations you have to use milliseconds:

    Ticker x(callback, time_in_millisec, /*repeat=*/0, /*resolution=*/MILLIS);

When specifying a callback for ticker you can use a function that takes no args and no return value:

    void mycallback() {dostuff();}
    Ticker x(mycallback, ....);

Or you can use a C++ lambda expression to create an unnamed function that does the same thing.

    Ticker x([](){dostuff();}, ....);

Here is your code rewritten with Ticker with some assumptions on my part about what you intend, you should be able to adapt the ideas

    #include <Wire.h>
    #include <Adafruit_Sensor.h>
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <SPI.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>
    #include <Ticker.h>

    #define ONE_WIRE_BUS 4
    #define TEMPERATURE_PRECISION 9

    #define motor 6
    #define valve 7

    OneWire oneWire(ONE_WIRE_BUS);
    DallasTemperature sensors(&oneWire);

    // use a separatethreshold for on/off to give some hysteresis
    const float on_thld = 36;
    const float off_thld = 35;

    #define SCREEN_WIDTH 128 // OLED display width, in pixels
    #define SCREEN_HEIGHT 64
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

    void check_sensors();

    // This Ticker will call check_sensors every 2seconds
    Ticker ticker_sensors(check_sensors, 2000, 0);

    // When we turn on the valves, we'll use this to schedule turning on the motor 5 seconds later (a 1-time event each time we do start())
    Ticker ticker_motor_start([](){ digitalWrite(motor, LOW); }, 5000, 1);
    // if you dislike this syntax, you could use:
    //    void turn_on_motor() {digitalWrite(motor, LOW);}
    //    Ticker ticker_motor_start(turn_on_motor, 500, 1);

    // When we turn off the motor, we'll use this to schedule turning off the valve 5 seconds later (a 1-time event each time we do start())
    Ticker ticker_valve_off([](){ digitalWrite(valve, HIGH); }, 5000, 1);

    void check_sensors() {
        sensors.requestTemperatures();
        float temp = sensors.getTempCByIndex(0);
        Serial.println(temp);
        Serial.println((char)176);
        Serial.println("C  |  ");
        if (temp > on_thld) {
            if (ticker_motor_start.state() != RUNNING) {
                // cancel any pending valve turn-off
                ticker_valve_off.stop();

                // turn on valve and schedule motor turn-on
                digitalWrite(valve, HIGH);
                ticker_motor_start.start();
            }
        } else if (temp < off_thld) {
            if (ticker_motor_start.state() == RUNNING) {
                // turn off motor and schedule valves to turn off
                digitalWrite(motor, HIGH);
                ticker_valve_off.start();
            }
        }

        display.clearDisplay();
        display.setCursor(0, 0);
        display.setTextSize(1);
        display.println("Temperature");
        display.setCursor(0, 30);
        display.println("Soil & Water Engg.");
        display.setTextSize(2);
        display.setCursor(0,10);
        display.println(temp);
        display.setCursor(75, 10);
        display.println("C");
        display.setCursor(0,40);
        display.display();
    }

    void setup() {
        Serial.begin(115200);
        digitalWrite(motor, HIGH); // set value before enabling output
        digitalWrite(valve, HIGH); // set value before enabling output
        pinMode(motor, OUTPUT);
        pinMode(valve, OUTPUT);

        if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
            Serial.println(F("SSD1306 allocation failed"));
            for(;;);
        }

        display.setTextColor(WHITE);
        ticker_sensors.start();
    }

    void loop() {
        // update all the tickers - if they're not running it's a no-op
        // They only check times and decide when to call their callbacks during update()
        ticker_sensors.update();
        ticker_motor_start.update();
        ticker_valve_off.update();
    }


body:
Not all processes are time-based, so for completeness

    loop:
      read the time;
      if time to run process1,
        process1();
      if time to run process2,
        process2();
      poll external event1;
      if event1 completed,
         external1();
      poll external event2;
      if event2 completed,
         external2();
    end;


message:
How to toggle a pin (LED) simply

I am not a programmer but rather a hardware guy. In the good old machine code days, you could 'read' the status of the port and flip it.. admittedly a much simpler processor. Is it not possible to do this with the 328 without many lines of code?

body:
It is perfectly possible to do this without "many lines of code". The ATMega328P is actually a pretty simple chip (certainly by today's standards). Reading and writing pins is just the same as it has always been - read a port's byte value from the PINx register, modify it, and write it back to the PORTx register.

Much of what the Arduino API does is abstract things to make complex operations simpler. One side effect is it can make simple operations seem more complex (and in fact can slow things down as a result). But you don't *have* to always use the Arduino API for everything.

It is common to directly manipulate the IO registers to perform higher speed manipulation of the IO pins especially when you want to do such things as emulate other communication protocols, or shrink your code to fit into a really small microcontroller with as little flash usage as possible.


body:
To toggle a pin, just read the pjn and invert the value:

    #define LEDPIN 2

    void loop() {
        digitalWrite(LEDPIN, !digitalRead(LEDPIN));
    }

You can also just "remember" the last value:

    #define LEDPIN 2
    bool led_on = false;
    unsigned long led_time = 500; // 1/2 sec on and 1/2 sec off
    unsigned long lasttime = 0; // last millis() time we turned the led off or on

    void setup() {
        digitalWrite(LEDPIN, LOW);
        pinMode(LEDPIN, OUTPUT);
    }
    void loop() {
        unsigned long now = millis();
        if (lasttime - now > led_time) {
            led_on = !led_on;
            digitalWrite(LEDPIN, led_on);
            last_time = now;
        }
    }


message:
What are these 18 extra ports on the adafruit-gfx 2.8"

I recently got the Adafruit gfx 2.8" display, which works fine.

It's quite obvious that it requires almost all of the pins on the UNO. *However, I don't understand what are the 18 avaliable "soldier ports" are at the bottom of the Adafruit shield.*

Can these ports be used with sensors, ie: push button, so you wouldn't need to plug anything else into the UNO board? What do these holes do?
I'm unable to find out, as it doesn't seem to be a common shield, most Adafruit shields don't seem to have those ports.

If these ports do nothing, should I saw them off - save space?

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

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

body:
Those are an alternative way of connecting to the screen. Basically they mirror the connections to the "shield" pins.

To save costs the manufacturer will have made a PCB that can be used in multiple different ways just by soldering different connectors. In this case either as an Arduino shield or as a board on the end of a ribbon cable. You have the version with the Arduino shield pins soldered in.

They are of no use to you unless you should want to put the screen on the end of a ribbon cable. Can you remove them? Possibly, possibly not. It depends on how the PCB traces are routed. Cutting the board may cut important PCB traces that connect the screen to the Arduino shield pins.

Only close inspection of the board and understanding the routing of the traces will be able to tell you yes or no. If in doubt, though, no you don't want to be randomly cutting off chunks of the circuit.


message:
My Atlas Scientific sensors measurement give zero values at first reading

I am still continuing my [hydroponic nutrient monitoring project](https://arduino.stackexchange.com/questions/89451/i2c-sensors-not-working-when-i-connect-to-lcd-20x04). In short, I made a hydroponic nutrient monitoring system with I2C connection, and decided to do serial communication with Raspberry Pi 3B+ to save sensor reading data in CSV file. I am curious about why after uploading the sketch, the sensors always gives zero values at first reading on Serial Monitor.

This is the screenshot of my Serial Monitor.

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

From left to right: timestamp, EC, pH, Temperature.

Everytime I reset the Arduino, the Serial Monitor first will show no values. On the second line, it shows only EC value. The third line only EC and pH value, then the fourth line and so on will show all values.

**How to make the Arduino show all sensor values from the start in the Serial Monitor?**

Here is my code that I modified from Atlas Scientific page for my project:
```
#include <Ezo_i2c.h>
#include <Wire.h>

Ezo_board ec = Ezo_board(100, "EC");
Ezo_board ph = Ezo_board(99, "PH");
Ezo_board temp = Ezo_board(102, "RTD");

bool reading_request_phase = true;

uint32_t next_poll_time = 0;
const unsigned int response_delay = 1000;

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  delay(1000);

}

void loop() {
  if (reading_request_phase)
  {
    ec.send_read_cmd();
    ph.send_read_cmd();
    temp.send_read_cmd();

    next_poll_time = millis() + response_delay;
    reading_request_phase = false;
  }
  else
  {
    if (millis() >= next_poll_time)
    {
      receive_reading(ec);
      receive_reading(ph);
      receive_reading(temp);

      reading_request_phase = true;
    }
  }
}

void receive_reading(Ezo_board &Sensor) {
  Sensor.receive_read_cmd();
  Serial.println();
  Serial.print(ec.get_last_received_reading()/1000);
  Serial.print(",");
  Serial.print(ph.get_last_received_reading());
  Serial.print(",");
  Serial.print(temp.get_last_received_reading());
  Serial.print("");
  delay(1000);
}
```

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

body:
Each time you call `receive_reading()` you pass it *one* sensor to read the value from. But each time you call `receive_reading()` you print out *all three* sensors.

So you:

1. Read EC and print EC PC TEMP
2. Read PC and print EC PC TEMP
3. Read TEMP and print EC PC TEMP

In step one you only have EC, you haven't read PC or TEMP yet.
In step two you have the old reading of EC and a new PC reading but still no TEMP reading.
By step three you finally have a TEMP reading but still the old EC and PC readings from earlier.

You should instead put the receiving command (`Sensor.receive_read_cmd()`) once for each sensor as a separate thing to displaying the received values. More like:

```c++
#include <Ezo_i2c.h>
#include <Wire.h>

Ezo_board ec = Ezo_board(100, "EC");
Ezo_board ph = Ezo_board(99, "PH");
Ezo_board temp = Ezo_board(102, "RTD");

bool reading_request_phase = true;

uint32_t next_poll_time = 0;
const unsigned int response_delay = 1000;

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  delay(1000);

}

void loop() {
  if (reading_request_phase)
  {
    ec.send_read_cmd();
    ph.send_read_cmd();
    temp.send_read_cmd();

    next_poll_time = millis() + response_delay;
    reading_request_phase = false;
  }
  else
  {
    if (millis() >= next_poll_time)
    {
      ec.receive_read_cmd();
      ph.receive_read_cmd();
      temp.receive_read_cmd();
      display_reading();

      reading_request_phase = true;
    }
  }
}

void display_reading() {
  Serial.print(ec.get_last_received_reading()/1000);
  Serial.print(",");
  Serial.print(ph.get_last_received_reading());
  Serial.print(",");
  Serial.println(temp.get_last_received_reading());
}
```

Also remove the `delay()` after each printed line, it's just confusing everything and slowing down your reading.


message:
error: 'MonoOutput' has not been declared (Mozzi library, Arduino Nano)

I know this error is specific to this particular family of sketches, but please bear with me; when I try to compile this against an Arduino Nano/Uno (with Arduino IDE 1.8.15) the compiler complains that 'MonoOutput' has not been declared, like so:

```cpp
Triple_DCO_1.3:697:14: error: 'MonoOutput' has not been declared
    return MonoOutput::from8Bit((aSin1.next() * (pgm_read_byte(&(gain_table[0][gain]))) / 512 + aSin2.next() * (pgm_read_byte(&(gain_table[1][gain]))) / 512 + aSin3.next() * (pgm_read_byte(&(gain_table[2][gain]))) / 512 + aSin4.next() * (pgm_read_byte(&(gain_table[3][gain]))) / 512 + aSin5.next() * (pgm_read_byte(&(gain_table[4][gain]))) / 512 + aSin6.next() * (pgm_read_byte(&(gain_table[5][gain]))) / 512 + aSin7.next() * (pgm_read_byte(&(gain_table[6][gain]))) / 512 )*Gain_CV_2/128);
           ^~~~~~~~~~
```

I have found that this issue has come up once on ModWiggler, once in YouTube comments, and once in the Mozzi GitHub repository (but in the last case only pertaining to the *Nano Every* and not a vanilla Nano), so I know it's not unique to my situation; but since most people don't seem to be experiencing this problem, it must be something particular to my setup or am missing something obvious.

The code in question (Triple_DCO_1.3.ino) is from [luislutz][1] GitHub; it is too long to post here, but a different sketch from the same family, pasted below, exhibits the same error for me:

```cpp
#include <MozziGuts.h>
#include <Oscil.h> // oscillator template

#include <tables/saw2048_int8.h> // saw table for oscillator
#include <tables/square_no_alias512_int8.h> // saw table for oscillator
#include <tables/triangle_hermes_2048_int8.h> // saw table for oscillator
#include <tables/sin2048_int8.h> // sine table for oscillator
#include <tables/waveshape_chebyshev_3rd_256_int8.h> // sine table for oscillator
#include <tables/halfsin256_uint8.h> // sine table for oscillator
#include <tables/waveshape_sigmoid_int8.h> // sine table for oscillator
#include <tables/phasor256_int8.h> // sine table for oscillator

Oscil <SAW2048_NUM_CELLS, AUDIO_RATE> aSaw1(SAW2048_DATA);
Oscil <SAW2048_NUM_CELLS, AUDIO_RATE> aSaw2(SAW2048_DATA);
Oscil <SAW2048_NUM_CELLS, AUDIO_RATE> aSaw3(SAW2048_DATA);
Oscil <SAW2048_NUM_CELLS, AUDIO_RATE> aSaw4(SAW2048_DATA);
Oscil <SAW2048_NUM_CELLS, AUDIO_RATE> aSaw5(SAW2048_DATA);

Oscil <SQUARE_NO_ALIAS512_NUM_CELLS, AUDIO_RATE> aSqu1(SQUARE_NO_ALIAS512_DATA);
Oscil <SQUARE_NO_ALIAS512_NUM_CELLS, AUDIO_RATE> aSqu2(SQUARE_NO_ALIAS512_DATA);
Oscil <SQUARE_NO_ALIAS512_NUM_CELLS, AUDIO_RATE> aSqu3(SQUARE_NO_ALIAS512_DATA);
Oscil <SQUARE_NO_ALIAS512_NUM_CELLS, AUDIO_RATE> aSqu4(SQUARE_NO_ALIAS512_DATA);
Oscil <SQUARE_NO_ALIAS512_NUM_CELLS, AUDIO_RATE> aSqu5(SQUARE_NO_ALIAS512_DATA);

Oscil <TRIANGLE_HERMES_2048_NUM_CELLS, AUDIO_RATE> aTri1(TRIANGLE_HERMES_2048_DATA);
Oscil <TRIANGLE_HERMES_2048_NUM_CELLS, AUDIO_RATE> aTri2(TRIANGLE_HERMES_2048_DATA);
Oscil <TRIANGLE_HERMES_2048_NUM_CELLS, AUDIO_RATE> aTri3(TRIANGLE_HERMES_2048_DATA);
Oscil <TRIANGLE_HERMES_2048_NUM_CELLS, AUDIO_RATE> aTri4(TRIANGLE_HERMES_2048_DATA);
Oscil <TRIANGLE_HERMES_2048_NUM_CELLS, AUDIO_RATE> aTri5(TRIANGLE_HERMES_2048_DATA);

Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin1(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin2(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin3(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin4(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin5(SIN2048_DATA);

Oscil <CHEBYSHEV_3RD_256_NUM_CELLS, AUDIO_RATE> aChb1(CHEBYSHEV_3RD_256_DATA);
Oscil <CHEBYSHEV_3RD_256_NUM_CELLS, AUDIO_RATE> aChb2(CHEBYSHEV_3RD_256_DATA);
Oscil <CHEBYSHEV_3RD_256_NUM_CELLS, AUDIO_RATE> aChb3(CHEBYSHEV_3RD_256_DATA);
Oscil <CHEBYSHEV_3RD_256_NUM_CELLS, AUDIO_RATE> aChb4(CHEBYSHEV_3RD_256_DATA);
Oscil <CHEBYSHEV_3RD_256_NUM_CELLS, AUDIO_RATE> aChb5(CHEBYSHEV_3RD_256_DATA);

Oscil <HALFSIN256_NUM_CELLS, AUDIO_RATE> ahSin1(HALFSIN256_DATA);
Oscil <HALFSIN256_NUM_CELLS, AUDIO_RATE> ahSin2(HALFSIN256_DATA);
Oscil <HALFSIN256_NUM_CELLS, AUDIO_RATE> ahSin3(HALFSIN256_DATA);
Oscil <HALFSIN256_NUM_CELLS, AUDIO_RATE> ahSin4(HALFSIN256_DATA);
Oscil <HALFSIN256_NUM_CELLS, AUDIO_RATE> ahSin5(HALFSIN256_DATA);

Oscil <WAVESHAPE_SIGMOID_NUM_CELLS, AUDIO_RATE> aSig1(WAVESHAPE_SIGMOID_DATA);
Oscil <WAVESHAPE_SIGMOID_NUM_CELLS, AUDIO_RATE> aSig2(WAVESHAPE_SIGMOID_DATA);
Oscil <WAVESHAPE_SIGMOID_NUM_CELLS, AUDIO_RATE> aSig3(WAVESHAPE_SIGMOID_DATA);
Oscil <WAVESHAPE_SIGMOID_NUM_CELLS, AUDIO_RATE> aSig4(WAVESHAPE_SIGMOID_DATA);
Oscil <WAVESHAPE_SIGMOID_NUM_CELLS, AUDIO_RATE> aSig5(WAVESHAPE_SIGMOID_DATA);

Oscil <PHASOR256_NUM_CELLS, AUDIO_RATE> aPha1(PHASOR256_DATA);
Oscil <PHASOR256_NUM_CELLS, AUDIO_RATE> aPha2(PHASOR256_DATA);
Oscil <PHASOR256_NUM_CELLS, AUDIO_RATE> aPha3(PHASOR256_DATA);
Oscil <PHASOR256_NUM_CELLS, AUDIO_RATE> aPha4(PHASOR256_DATA);
Oscil <PHASOR256_NUM_CELLS, AUDIO_RATE> aPha5(PHASOR256_DATA);
#define CONTROL_RATE 128 // Hz, powers of 2 are most reliable

int freq1 = 110;//base freq
int voct = 1000;//external V/OCT LSB

int freqv1 = 440;//apply voct
int freqv2 = 440;
int freqv3 = 440;
int freqv4 = 440;
int freqv5 = 440;

byte note1 = 0;//Root
byte note2 = 0;//2nd
byte note3 = 0;//3rd
byte note4 = 0;//4th
byte note5 = 0;//Root

byte inv_aply1 = 0; //0 = no inv , 1 = inv , Root
byte inv_aply2 = 0; //2nd
byte inv_aply3 = 0; //3rd
byte inv_aply4 = 0; //4th
bool inv_aply5 = 0; //0 = no output root sound , 1 = output root sound

int inv = 0;
int inv_knob = 0;
int chord = 0;
byte wave = 0;//0=saw,1=squ,2=tri,3=sin,etc...

const static float voctpow[1024] PROGMEM = {
 0,  0.004882, 0.009765, 0.014648, 0.019531, 0.024414, 0.029296, 0.034179, 0.039062, 0.043945, 0.048828, 0.05371,  0.058593, 0.063476, 0.068359, 0.073242, 0.078125, 0.083007, 0.08789,  0.092773, 0.097656, 0.102539, 0.107421, 0.112304, 0.117187, 0.12207,  0.126953, 0.131835, 0.136718, 0.141601, 0.146484, 0.151367, 0.15625,  0.161132, 0.166015, 0.170898, 0.175781, 0.180664, 0.185546, 0.190429, 0.195312, 0.200195, 0.205078, 0.20996,  0.214843, 0.219726, 0.224609, 0.229492, 0.234375, 0.239257, 0.24414,  0.249023, 0.253906, 0.258789, 0.263671, 0.268554, 0.273437, 0.27832,  0.283203, 0.288085, 0.292968, 0.297851, 0.302734, 0.307617, 0.3125, 0.317382, 0.322265, 0.327148, 0.332031, 0.336914, 0.341796, 0.346679, 0.351562, 0.356445, 0.361328, 0.36621,  0.371093, 0.375976, 0.380859, 0.385742, 0.390625, 0.395507, 0.40039,  0.405273, 0.410156, 0.415039, 0.419921, 0.424804, 0.429687, 0.43457,  0.439453, 0.444335, 0.449218, 0.454101, 0.458984, 0.463867, 0.46875,  0.473632, 0.478515, 0.483398, 0.488281, 0.493164, 0.498046, 0.502929, 0.507812, 0.512695, 0.517578, 0.52246,  0.527343, 0.532226, 0.537109, 0.541992, 0.546875, 0.551757, 0.55664,  0.561523, 0.566406, 0.571289, 0.576171, 0.581054, 0.585937, 0.59082,  0.595703, 0.600585, 0.605468, 0.610351, 0.615234, 0.620117, 0.625,  0.629882, 0.634765, 0.639648, 0.644531, 0.649414, 0.654296, 0.659179, 0.664062, 0.668945, 0.673828, 0.67871,  0.683593, 0.688476, 0.693359, 0.698242, 0.703125, 0.708007, 0.71289,  0.717773, 0.722656, 0.727539, 0.732421, 0.737304, 0.742187, 0.74707,  0.751953, 0.756835, 0.761718, 0.766601, 0.771484, 0.776367, 0.78125,  0.786132, 0.791015, 0.795898, 0.800781, 0.805664, 0.810546, 0.815429, 0.820312, 0.825195, 0.830078, 0.83496,  0.839843, 0.844726, 0.849609, 0.854492, 0.859375, 0.864257, 0.86914,  0.874023, 0.878906, 0.883789, 0.888671, 0.893554, 0.898437, 0.90332,  0.908203, 0.913085, 0.917968, 0.922851, 0.927734, 0.932617, 0.9375, 0.942382, 0.947265, 0.952148, 0.957031, 0.961914, 0.966796, 0.971679, 0.976562, 0.981445, 0.986328, 0.99121,  0.996093, 1.000976, 1.005859, 1.010742, 1.015625, 1.020507, 1.02539,  1.030273, 1.035156, 1.040039, 1.044921, 1.049804, 1.054687, 1.05957,  1.064453, 1.069335, 1.074218, 1.079101, 1.083984, 1.088867, 1.09375,  1.098632, 1.103515, 1.108398, 1.113281, 1.118164, 1.123046, 1.127929, 1.132812, 1.137695, 1.142578, 1.14746,  1.152343, 1.157226, 1.162109, 1.166992, 1.171875, 1.176757, 1.18164,  1.186523, 1.191406, 1.196289, 1.201171, 1.206054, 1.210937, 1.21582,  1.220703, 1.225585, 1.230468, 1.235351, 1.240234, 1.245117, 1.25, 1.254882, 1.259765, 1.264648, 1.269531, 1.274414, 1.279296, 1.284179, 1.289062, 1.293945, 1.298828, 1.30371,  1.308593, 1.313476, 1.318359, 1.323242, 1.328125, 1.333007, 1.33789,  1.342773, 1.347656, 1.352539, 1.357421, 1.362304, 1.367187, 1.37207,  1.376953, 1.381835, 1.386718, 1.391601, 1.396484, 1.401367, 1.40625,  1.411132, 1.416015, 1.420898, 1.425781, 1.430664, 1.435546, 1.440429, 1.445312, 1.450195, 1.455078, 1.45996,  1.464843, 1.469726, 1.474609, 1.479492, 1.484375, 1.489257, 1.49414,  1.499023, 1.503906, 1.508789, 1.513671, 1.518554, 1.523437, 1.52832,  1.533203, 1.538085, 1.542968, 1.547851, 1.552734, 1.557617, 1.5625, 1.567382, 1.572265, 1.577148, 1.582031, 1.586914, 1.591796, 1.596679, 1.601562, 1.606445, 1.611328, 1.61621,  1.621093, 1.625976, 1.630859, 1.635742, 1.640625, 1.645507, 1.65039,  1.655273, 1.660156, 1.665039, 1.669921, 1.674804, 1.679687, 1.68457,  1.689453, 1.694335, 1.699218, 1.704101, 1.708984, 1.713867, 1.71875,  1.723632, 1.728515, 1.733398, 1.738281, 1.743164, 1.748046, 1.752929, 1.757812, 1.762695, 1.767578, 1.77246,  1.777343, 1.782226, 1.787109, 1.791992, 1.796875, 1.801757, 1.80664,  1.811523, 1.816406, 1.821289, 1.826171, 1.831054, 1.835937, 1.84082,  1.845703, 1.850585, 1.855468, 1.860351, 1.865234, 1.870117, 1.875,  1.879882, 1.884765, 1.889648, 1.894531, 1.899414, 1.904296, 1.909179, 1.914062, 1.918945, 1.923828, 1.92871,  1.933593, 1.938476, 1.943359, 1.948242, 1.953125, 1.958007, 1.96289,  1.967773, 1.972656, 1.977539, 1.982421, 1.987304, 1.992187, 1.99707,  2.001953, 2.006835, 2.011718, 2.016601, 2.021484, 2.026367, 2.03125,  2.036132, 2.041015, 2.045898, 2.050781, 2.055664, 2.060546, 2.065429, 2.070312, 2.075195, 2.080078, 2.08496,  2.089843, 2.094726, 2.099609, 2.104492, 2.109375, 2.114257, 2.11914,  2.124023, 2.128906, 2.133789, 2.138671, 2.143554, 2.148437, 2.15332,  2.158203, 2.163085, 2.167968, 2.172851, 2.177734, 2.182617, 2.1875, 2.192382, 2.197265, 2.202148, 2.207031, 2.211914, 2.216796, 2.221679, 2.226562, 2.231445, 2.236328, 2.24121,  2.246093, 2.250976, 2.255859, 2.260742, 2.265625, 2.270507, 2.27539,  2.280273, 2.285156, 2.290039, 2.294921, 2.299804, 2.304687, 2.30957,  2.314453, 2.319335, 2.324218, 2.329101, 2.333984, 2.338867, 2.34375,  2.348632, 2.353515, 2.358398, 2.363281, 2.368164, 2.373046, 2.377929, 2.382812, 2.387695, 2.392578, 2.39746,  2.402343, 2.407226, 2.412109, 2.416992, 2.421875, 2.426757, 2.43164,  2.436523, 2.441406, 2.446289, 2.451171, 2.456054, 2.460937, 2.46582,  2.470703, 2.475585, 2.480468, 2.485351, 2.490234, 2.495117, 2.5,  2.504882, 2.509765, 2.514648, 2.519531, 2.524414, 2.529296, 2.534179, 2.539062, 2.543945, 2.548828, 2.55371,  2.558593, 2.563476, 2.568359, 2.573242, 2.578125, 2.583007, 2.58789,  2.592773, 2.597656, 2.602539, 2.607421, 2.612304, 2.617187, 2.62207,  2.626953, 2.631835, 2.636718, 2.641601, 2.646484, 2.651367, 2.65625,  2.661132, 2.666015, 2.670898, 2.675781, 2.680664, 2.685546, 2.690429, 2.695312, 2.700195, 2.705078, 2.70996,  2.714843, 2.719726, 2.724609, 2.729492, 2.734375, 2.739257, 2.74414,  2.749023, 2.753906, 2.758789, 2.763671, 2.768554, 2.773437, 2.77832,  2.783203, 2.788085, 2.792968, 2.797851, 2.802734, 2.807617, 2.8125, 2.817382, 2.822265, 2.827148, 2.832031, 2.836914, 2.841796, 2.846679, 2.851562, 2.856445, 2.861328, 2.86621,  2.871093, 2.875976, 2.880859, 2.885742, 2.890625, 2.895507, 2.90039,  2.905273, 2.910156, 2.915039, 2.919921, 2.924804, 2.929687, 2.93457,  2.939453, 2.944335, 2.949218, 2.954101, 2.958984, 2.963867, 2.96875,  2.973632, 2.978515, 2.983398, 2.988281, 2.993164, 2.998046, 3.002929, 3.007812, 3.012695, 3.017578, 3.02246,  3.027343, 3.032226, 3.037109, 3.041992, 3.046875, 3.051757, 3.05664,  3.061523, 3.066406, 3.071289, 3.076171, 3.081054, 3.085937, 3.09082,  3.095703, 3.100585, 3.105468, 3.110351, 3.115234, 3.120117, 3.125,  3.129882, 3.134765, 3.139648, 3.144531, 3.149414, 3.154296, 3.159179, 3.164062, 3.168945, 3.173828, 3.17871,  3.183593, 3.188476, 3.193359, 3.198242, 3.203125, 3.208007, 3.21289,  3.217773, 3.222656, 3.227539, 3.232421, 3.237304, 3.242187, 3.24707,  3.251953, 3.256835, 3.261718, 3.266601, 3.271484, 3.276367, 3.28125,  3.286132, 3.291015, 3.295898, 3.300781, 3.305664, 3.310546, 3.315429, 3.320312, 3.325195, 3.330078, 3.33496,  3.339843, 3.344726, 3.349609, 3.354492, 3.359375, 3.364257, 3.36914,  3.374023, 3.378906, 3.383789, 3.388671, 3.393554, 3.398437, 3.40332,  3.408203, 3.413085, 3.417968, 3.422851, 3.427734, 3.432617, 3.4375, 3.442382, 3.447265, 3.452148, 3.457031, 3.461914, 3.466796, 3.471679, 3.476562, 3.481445, 3.486328, 3.49121,  3.496093, 3.500976, 3.505859, 3.510742, 3.515625, 3.520507, 3.52539,  3.530273, 3.535156, 3.540039, 3.544921, 3.549804, 3.554687, 3.55957,  3.564453, 3.569335, 3.574218, 3.579101, 3.583984, 3.588867, 3.59375,  3.598632, 3.603515, 3.608398, 3.613281, 3.618164, 3.623046, 3.627929, 3.632812, 3.637695, 3.642578, 3.64746,  3.652343, 3.657226, 3.662109, 3.666992, 3.671875, 3.676757, 3.68164,  3.686523, 3.691406, 3.696289, 3.701171, 3.706054, 3.710937, 3.71582,  3.720703, 3.725585, 3.730468, 3.735351, 3.740234, 3.745117, 3.75, 3.754882, 3.759765, 3.764648, 3.769531, 3.774414, 3.779296, 3.784179, 3.789062, 3.793945, 3.798828, 3.80371,  3.808593, 3.813476, 3.818359, 3.823242, 3.828125, 3.833007, 3.83789,  3.842773, 3.847656, 3.852539, 3.857421, 3.862304, 3.867187, 3.87207,  3.876953, 3.881835, 3.886718, 3.891601, 3.896484, 3.901367, 3.90625,  3.911132, 3.916015, 3.920898, 3.925781, 3.930664, 3.935546, 3.940429, 3.945312, 3.950195, 3.955078, 3.95996,  3.964843, 3.969726, 3.974609, 3.979492, 3.984375, 3.989257, 3.99414,  3.999023, 4.003906, 4.008789, 4.013671, 4.018554, 4.023437, 4.02832,  4.033203, 4.038085, 4.042968, 4.047851, 4.052734, 4.057617, 4.0625, 4.067382, 4.072265, 4.077148, 4.082031, 4.086914, 4.091796, 4.096679, 4.101562, 4.106445, 4.111328, 4.11621,  4.121093, 4.125976, 4.130859, 4.135742, 4.140625, 4.145507, 4.15039,  4.155273, 4.160156, 4.165039, 4.169921, 4.174804, 4.179687, 4.18457,  4.189453, 4.194335, 4.199218, 4.204101, 4.208984, 4.213867, 4.21875,  4.223632, 4.228515, 4.233398, 4.238281, 4.243164, 4.248046, 4.252929, 4.257812, 4.262695, 4.267578, 4.27246,  4.277343, 4.282226, 4.287109, 4.291992, 4.296875, 4.301757, 4.30664,  4.311523, 4.316406, 4.321289, 4.326171, 4.331054, 4.335937, 4.34082,  4.345703, 4.350585, 4.355468, 4.360351, 4.365234, 4.370117, 4.375,  4.379882, 4.384765, 4.389648, 4.394531, 4.399414, 4.404296, 4.409179, 4.414062, 4.418945, 4.423828, 4.42871,  4.433593, 4.438476, 4.443359, 4.448242, 4.453125, 4.458007, 4.46289,  4.467773, 4.472656, 4.477539, 4.482421, 4.487304, 4.492187, 4.49707,  4.501953, 4.506835, 4.511718, 4.516601, 4.521484, 4.526367, 4.53125,  4.536132, 4.541015, 4.545898, 4.550781, 4.555664, 4.560546, 4.565429, 4.570312, 4.575195, 4.580078, 4.58496,  4.589843, 4.594726, 4.599609, 4.604492, 4.609375, 4.614257, 4.61914,  4.624023, 4.628906, 4.633789, 4.638671, 4.643554, 4.648437, 4.65332,  4.658203, 4.663085, 4.667968, 4.672851, 4.677734, 4.682617, 4.6875, 4.692382, 4.697265, 4.702148, 4.707031, 4.711914, 4.716796, 4.721679, 4.726562, 4.731445, 4.736328, 4.74121,  4.746093, 4.750976, 4.755859, 4.760742, 4.765625, 4.770507, 4.77539,  4.780273, 4.785156, 4.790039, 4.794921, 4.799804, 4.804687, 4.80957,  4.814453, 4.819335, 4.824218, 4.829101, 4.833984, 4.838867, 4.84375,  4.848632, 4.853515, 4.858398, 4.863281, 4.868164, 4.873046, 4.877929, 4.882812, 4.887695, 4.892578, 4.89746,  4.902343, 4.907226, 4.912109, 4.916992, 4.921875, 4.926757, 4.93164,  4.936523, 4.941406, 4.946289, 4.951171, 4.956054, 4.960937, 4.96582,  4.970703, 4.975585, 4.980468, 4.985351, 4.990234, 4.995117
};
const static byte chord_table[8][4]PROGMEM = {
 {  0,  68, 119,  205,  },//Maj
 { 0,  68, 119,  187,  },//Maj7
 { 0,  68, 119,  239,  },//Majadd9
 { 0,  34, 119,  205,  },//sus2
 { 0,  51, 119,  239,  },//minadd9
 { 0,  51, 119,  170,  },//min7
 { 0,  51, 119,  205,  },//min
 { 0,  0,  0,  0,  }//root
};

void setup()
{
 startMozzi(CONTROL_RATE); // :)
}
void updateControl() {
 //chord setting
 chord = (mozziAnalogRead(3) / 128) + (mozziAnalogRead(5) / 128);
 chord = constrain(chord, 0, 7);

 //inversion setting
 inv_knob = mozziAnalogRead(1);
 inv = (inv_knob  / 64)+ (mozziAnalogRead(4) / 64);
 inv = constrain(inv, 0, 15);

 if (inv_knob < 1020) { //when selecting wave , not apply
   switch (inv) {
     case 0:
       inv_aply1 = 0;
       inv_aply2 = 0;
       inv_aply3 = 0;
       inv_aply4 = 0;
       inv_aply5 = 0;
       break;

     case 1:
       inv_aply1 = 1;
       inv_aply2 = 0;
       inv_aply3 = 0;
       inv_aply4 = 0;
       inv_aply5 = 0;
       break;

     case 2:
       inv_aply1 = 1;
       inv_aply2 = 1;
       inv_aply3 = 0;
       inv_aply4 = 0;
       inv_aply5 = 0;
       break;

     case 3:
       inv_aply1 = 1;
       inv_aply2 = 1;
       inv_aply3 = 1;
       inv_aply4 = 0;
       inv_aply5 = 0;
       break;

     case 4:
       inv_aply1 = 1;
       inv_aply2 = 1;
       inv_aply3 = 1;
       inv_aply4 = 1;
       inv_aply5 = 0;
       break;

     case 5:
       inv_aply1 = 2;
       inv_aply2 = 1;
       inv_aply3 = 1;
       inv_aply4 = 1;
       inv_aply5 = 0;
       break;

     case 6:
       inv_aply1 = 2;
       inv_aply2 = 2;
       inv_aply3 = 1;
       inv_aply4 = 1;
       inv_aply5 = 0;
       break;

     case 7:
       inv_aply1 = 2;
       inv_aply2 = 2;
       inv_aply3 = 2;
       inv_aply4 = 1;
       inv_aply5 = 0;
       break;

     case 8:
       inv_aply1 = 2;
       inv_aply2 = 2;
       inv_aply3 = 2;
       inv_aply4 = 1;
       inv_aply5 = 1;
       break;

     case 9:
       inv_aply1 = 2;
       inv_aply2 = 2;
       inv_aply3 = 1;
       inv_aply4 = 1;
       inv_aply5 = 1;
       break;

     case 10:
       inv_aply1 = 2;
       inv_aply2 = 1;
       inv_aply3 = 1;
       inv_aply4 = 1;
       inv_aply5 = 1;
       break;

     case 11:
       inv_aply1 = 1;
       inv_aply2 = 1;
       inv_aply3 = 1;
       inv_aply4 = 1;
       inv_aply5 = 1;
       break;

     case 12:
       inv_aply1 = 1;
       inv_aply2 = 1;
       inv_aply3 = 1;
       inv_aply4 = 0;
       inv_aply5 = 1;
       break;

     case 13:
       inv_aply1 = 1;
       inv_aply2 = 1;
       inv_aply3 = 0;
       inv_aply4 = 0;
       inv_aply5 = 1;
       break;

     case 14:
       inv_aply1 = 1;
       inv_aply2 = 0;
       inv_aply3 = 0;
       inv_aply4 = 0;
       inv_aply5 = 1;
       break;

     case 15:
       inv_aply1 = 0;
       inv_aply2 = 0;
       inv_aply3 = 0;
       inv_aply4 = 0;
       inv_aply5 = 1;
       break;
   }
 }
 //setting chord note
 if (inv_knob < 1020) { //when selecting wave , not apply
   note1 = (pgm_read_byte(&(chord_table[chord][0])));
   note2 = (pgm_read_byte(&(chord_table[chord][1])));
   note3 = (pgm_read_byte(&(chord_table[chord][2])));
   note4 = (pgm_read_byte(&(chord_table[chord][3])));
   note5 = (pgm_read_byte(&(chord_table[chord][0])));
 }

 //OSC frequency knob
 freq1 = mozziAnalogRead(0) / 4 ;

 //set wave
 if (inv_knob >= 1020) { //inv knob max
   wave = (mozziAnalogRead(3) / 128);
 }

 //frequency setting
 voct = mozziAnalogRead(7) ;
 freqv1 = freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply1 + note1])))); //ROOT
 freqv2 = freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply2 + note2])))); //2nd
 freqv3 = freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply3 + note3])))); //3rd
 freqv4 = freq1 * pow(2, (pgm_read_float(&(voctpow[voct + 205 * inv_aply4 + note4])))); //4th
 freqv5 = freq1 * pow(2, (pgm_read_float(&(voctpow[voct + note5])))); //ROOT

 switch (wave) {
   case 0://saw
     aSaw1.setFreq(freqv1); // set the frequency
     aSaw2.setFreq(freqv2);
     aSaw3.setFreq(freqv3);
     aSaw4.setFreq(freqv4);
     aSaw5.setFreq(freqv5);
     break;

   case 1://squ
     aSqu1.setFreq(freqv1); // set the frequency
     aSqu2.setFreq(freqv2);
     aSqu3.setFreq(freqv3);
     aSqu4.setFreq(freqv4);
     aSqu5.setFreq(freqv5);
     break;

   case 2://tri
     aTri1.setFreq(freqv1); // set the frequency
     aTri2.setFreq(freqv2);
     aTri3.setFreq(freqv3);
     aTri4.setFreq(freqv4);
     aTri5.setFreq(freqv5);
     break;

   case 3://sin
     aSin1.setFreq(freqv1); // set the frequency
     aSin2.setFreq(freqv2);
     aSin3.setFreq(freqv3);
     aSin4.setFreq(freqv4);
     aSin5.setFreq(freqv5);
     break;

   case 4://
     aChb1.setFreq(freqv1); // set the frequency
     aChb2.setFreq(freqv2);
     aChb3.setFreq(freqv3);
     aChb4.setFreq(freqv4);
     aChb5.setFreq(freqv5);
     break;

   case 5://
     ahSin1.setFreq(freqv1); // set the frequency
     ahSin2.setFreq(freqv2);
     ahSin3.setFreq(freqv3);
     ahSin4.setFreq(freqv4);
     ahSin5.setFreq(freqv5);
     break;

   case 6://
     aSig1.setFreq(freqv1); // set the frequency
     aSig2.setFreq(freqv2);
     aSig3.setFreq(freqv3);
     aSig4.setFreq(freqv4);
     aSig5.setFreq(freqv5);
     break;

   case 7://
     aPha1.setFreq(freqv1); // set the frequency
     aPha2.setFreq(freqv2);
     aPha3.setFreq(freqv3);
     aPha4.setFreq(freqv4);
     aPha5.setFreq(freqv5);
     break;
 }
}

int updateAudio() {
 switch (wave) {

   case 0:
     return MonoOutput::from8Bit(aSaw1.next() / 32 + aSaw2.next() / 32 + aSaw3.next() / 32 + aSaw4.next() / 32 + aSaw5.next() / 32 * inv_aply5);
     break;

   case 1:
     return MonoOutput::from8Bit(aSqu1.next() / 32 + aSqu2.next() / 32 + aSqu3.next() / 32 + aSqu4.next() / 32 + aSqu5.next() / 32 * inv_aply5);
     break;

   case 2:
     return MonoOutput::from8Bit(aTri1.next() / 32 + aTri2.next() / 32 + aTri3.next() / 32 + aTri4.next() / 32 + aTri5.next() / 32 * inv_aply5);
     break;

   case 3:
     return MonoOutput::from8Bit(aSin1.next() / 32 + aSin2.next() / 32 + aSin3.next() / 32 + aSin4.next() / 32 + aSin5.next() / 32 * inv_aply5);
     break;

   case 4:
     return MonoOutput::from8Bit(aChb1.next() / 32 + aChb2.next() / 32 + aChb3.next() / 32 + aChb4.next() / 32 + aChb5.next() / 32 * inv_aply5);
     break;

   case 5:
     return MonoOutput::from8Bit(ahSin1.next() / 32 + ahSin2.next() / 32 + ahSin3.next() / 32 + ahSin4.next() / 32 + ahSin5.next() / 32 * inv_aply5);
     break;

   case 6:
     return MonoOutput::from8Bit(aSig1.next() / 32 + aSig2.next() / 32 + aSig3.next() / 32 + aSig4.next() / 32 + aSig5.next() / 32 * inv_aply5);
     break;

   case 7:
     return MonoOutput::from8Bit(aPha1.next() / 32 + aPha2.next() / 32 + aPha3.next() / 32 + aPha4.next() / 32 + aPha5.next() / 32 * inv_aply5);
     break;

 }
}
void loop() {
 audioHook(); // required here
}
```
(Yeah, it's still a lot...)

Any assistance in resolving this would be *greatly* appreciated!

  [1]: https://github.com/luislutz/Arduino-VDCO

body:
I don't get a compilation error with your sketch with the latest [git version][1].

If you installed the release version, delete the library in sketchbbok's `library` folder and download and install the latest git version.

  [1]: https://github.com/sensorium/Mozzi


message:
CH340G based USB to UART adapter - Pinouts - Can't find schematics

[This][1] is the board I will be referring to.
[![Board image][2]][2]

There are different variations of it (with built in buttons etc.) but they all seem to be based on the CH340 chip.

My problem is, that I do not know what the pinouts on the board stand for. I cannot find any schematics for the adapter (I can find some for the CH340). Does anyone have a clue as to what the different pins are for?

  [1]: https://minielektro.dk/dev-10053.html?gclid=CjwKCAjwyryUBhBSEiwAGN5OCIxnaU5lCMS4IczQlnlLFWL2wgJWJj6RQ1qy8xyN4i50NNoEWv6rqBoCLuUQAvD_BwE
  [2]: https://i.stack.imgur.com/tgJ9f.jpg

body:
This module appears to be designed for communicating with the [ESP8266 ESP-01][1] board. The pinout for the ESP-01 is shown below, taken from a typical [datasheet][2]:

[![ESP-01 Pinout][3]][3]

[Updated]The arrow on the CH340 board next to the yellow header indicates the connection orientation. The bulk of the ESP-01 goes on the side of the header pointed to by the arrow, covering the CH340 board, as shown below.

[![connection orientation][4]][4]

Information on the WCH CH340 product set including the G model is [here][5].

[![CH340G pinout][6]][6]

There is plenty of online information on getting started with the ESP8266 ESP-01 using the Arduino IDE. A good example is at [instructables.com][7].

The other model variations you mentioned (with built in buttons) are probably in response to a known problem with this board when flashing ESP-01s. See [here][8] for more info.

  [1]: https://en.wikipedia.org/wiki/ESP8266
  [2]: https://www.microchip.ua/wireless/esp01.pdf
  [3]: https://i.stack.imgur.com/uycDa.png
  [4]: https://i.stack.imgur.com/Y4LU2.jpg
  [5]: http://www.wch-ic.com/products/CH340.html
  [6]: https://i.stack.imgur.com/OrWNG.png
  [7]: https://www.instructables.com/Getting-Started-With-Esp-8266-Esp-01-With-Arduino-/
  [8]: https://www.instructables.com/USB-to-ESP-01-Board-Adapter-Modification/


message:
How to turn led lights off and on in order when below a certain photovalue?

I'm making a traffic light simulation with a photoresistor but it's not working properly.
When the photovalue drops below a certain point ( a car comes by) a peeping sound should play for a second and then red light should turn into yellow light and then it should turn green and stay green until the photovalue is back to normal, and then it should turn red again and stay red until the photovalue drops below that point again ( photovalue goes back to normal when the car moves) . I tried different, but did not get the result I was hoping for, the yellow light kept pulsing instead of actually turning off, the green light was turned on but it did not turn off when it was supposed to. In my recent attempt, the green light is not turning off, while red and yellow turn off on. What have I done wrong and how do I fix it?
here's my code for the last attempt.

[![This is how my circuit looks like, not the most refined but it works as intended ig][1]][1]

    byte PhotoInput= 0;
    int PhotoValue;
    int Pin = 8;
    void PlayTone( int freq,  int duration) {

    delay( duration);
    tone ( Pin ,freq, duration );

    }

    int red = 10;
    int yellow= 7;
    int green= 5;

     void setup() {
      pinMode(red, OUTPUT);
      pinMode( yellow, OUTPUT);
      pinMode( green, OUTPUT);
      Serial.begin(9600);
    }

    void loop() {

      PhotoValue = analogRead(PhotoInput);
        ;Serial.println(PhotoValue);
        delay(50);

        if ( PhotoValue < 100 ) {
          digitalWrite  (red, HIGH);
          delay ( 500);
          digitalWrite ( red,LOW);
          digitalWrite (yellow,HIGH);
          delay(1000);
          PlayTone( 100, 50);

          digitalWrite(green,HIGH);
         digitalWrite ( yellow, LOW);

        }else if ( PhotoValue > 100) {
           digitalWrite ( red,HIGH);
          digitalWrite(yellow,LOW);
          digitalWrite(green,LOW);

        }

       if (PhotoValue > 50 ){
        PlayTone( 100, 50);
       }else if ( PhotoValue > 60 )   {
        PlayTone ( 300, 50);
       }else if ( PhotoValue > 120 )   {
        PlayTone ( 600, 50);
        }else if ( PhotoValue > 160) {
        PlayTone ( 900, 50);
        }else if ( PhotoValue < 180 )   {
        PlayTone ( 1100, 50);
        }else if ( PhotoValue > 200)   {
        PlayTone ( 1300, 50);
        }else if ( PhotoValue < 240 )   {
        PlayTone ( 1600, 50);
        }else if ( PhotoValue > 260 )   {
        PlayTone ( 1000, 50);
        }else if ( PhotoValue < 80 )   {
        PlayTone ( 600, 50);
       }
    }

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

body:
To make this simpler I've taken away the buzzer from the code to just concentrate on the lights (from your diagram the buzzer wasn't connected anyway!). I've also tried to keep as much of your code as possible, and just introduce a single flag that is set to true when a car is detected.

When the program first starts `car_detected` is `false` and the red light is switched on in the `setup()` code. When the `PhotoValue` has a low value (<100) then it will set `car_detected` to `true` and go through the sequence of lights, with green finally switching on. Whilst the light input is low, it will see the `car_detected` flag remains `true` and won't perform any further actions.

When the car moves away and the `PhotoValue` is high again (>100) then the flag is cleared, and the red light is switched on again. Again - because of the flag, no further action will take place until the light level changes again.

This is a simplistic example of how you can use a flag to control the state of your program and hopefully will allow you to progress.

    byte PhotoInput=0;
    int PhotoValue;
    bool car_detected = false ;

    int red = 10;
    int yellow= 7;
    int green= 5;

    void setup() {
      pinMode(red, OUTPUT);
      pinMode(yellow, OUTPUT);
      pinMode(green, OUTPUT);

      digitalWrite(red,HIGH);
      digitalWrite(yellow,LOW);
      digitalWrite(green,LOW);

      Serial.begin(9600);
    }

    void loop() {

      PhotoValue = analogRead(PhotoInput);
      Serial.println(PhotoValue);

      if ( PhotoValue < 100 ) {

        if ( !car_detected ) {
          car_detected = true ;

          digitalWrite(red, HIGH);
          delay (500);
          digitalWrite(red,LOW);
          digitalWrite(yellow,HIGH);
          delay(1000);

          digitalWrite(green,HIGH);
          digitalWrite(yellow, LOW);
        }
      }else if ( PhotoValue >= 100) {
        if ( car_detected ) {
          car_detected = false ;
          digitalWrite(red,HIGH);
          digitalWrite(yellow,LOW);
          digitalWrite(green,LOW);
        }
      }
    }


message:
breadboards and accurate voltage measurments

I am trying to setup a thermistor(PT1000) to work with arduino. For that I used voltage divider and 5V pin as the voltage source. I was getting very unstable results so I removed the thermistor and used 2 1kOhm resistors instead.

I was still getting results ranging from very close to true value of 1kOhm to 1.2kOhm. For reference, 4 Ohms are equivalent temperature change of 1 degree celsius.

I measured the voltage drop of each resistor and was surprised that it is far from equivalent. Check the video of full setup and the closeup wiring of the voltage divider - https://easyupload.io/5fctxm

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

I cannot explain the 0.3V voltage drop difference between two resistors of the same rating (resistance of 1000 Ohm +-0.5% was verified by multimeter) in any other way but that the breadboard contacts and jump wires are not suitable for accurate voltage measurement. Can someone with more experience confirm if my breadboard is broken or is such behaviour intended.

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

body:
Schematics even for such a question are indispensable.

Assuming from the following:

> I cannot explain the 0.3V voltage drop difference between two
> resistors of the same rating

... means the voltage across each of 2 different resistors both labeled 1K Ohms in series with the same 2.1K Ohm resistor connected to 5V and 0V is different by 0.3V.

<!-- Begin schematic: In order to preserve an editable schematic, please
     don't edit this section directly.
     Click the "edit" link below the image in the preview instead. -->

![schematic](https://i.stack.imgur.com/ngxwL.png)

<!-- End schematic -->

If the two 1K Ohm resistors are assumed to be 0.5% (5th color band green) and the 2.1K Ohm resistor is perfect as well as the 5V potential.  Then a 1K Ohm resistor of, say, 0.5% less impedance would be 995 ohms.  And another, say, 0.5% more impedance would be 1005 ohms.  The voltage across the 1st in this resistor divider circuit would be 1005 x ( 5 / (1005 + 2100)) or 1.62V.  And the 2nd would be 995 x (5 / (995 + 2100)) or 1.61.  This is a difference of 0.01V.  That is less then the measured difference between the two different 1K Ohm resistors given the maximum possible percent error of 0.5%.

So the the 0.3V difference between voltage readings of the two different 1K Ohm resisters are difficult to account for.  Perhaps cleaning the connections may improve the measurements.


body:
In order to assess the stability of analog readings on a breadboard, I
did an experiment very similar to yours. I plugged two 1 kΩ
resistors on a breadboard, connected in series between my Arduino's GND
and +5V. I connected the middle point to A0 and made an histogram of one
million consecutive calls to `analogRead(A0)`.

Here is my test code:

```c++
const int histo_length = 64;
const long histo_count = 1000000;
long histo[histo_length];
int histo_start;

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

    // Center the histogram on the average reading.
    int sum = 0;
    for (int i = 0; i < 16; i++)
        sum += analogRead(A0);
    int average = sum / 16;
    histo_start = average - histo_length/2;

    // Fill the histogram.
    Serial.println("Ouliers:");
    for (long i = 0; i < histo_count; i++) {
        int x = analogRead(A0);
        if (x >= histo_start && x < histo_start + histo_length)
            histo[x - histo_start]++;
        else
            Serial.println(x);  // print oulier
    }

    // Print it out.
    Serial.println("Histogram:");
    for (int i = 0; i < histo_length; i++) {
        Serial.print(histo_start + i);
        Serial.print(" ");
        Serial.println(histo[i]);
    }
}

void loop() {}
```

Note that the full histogram would not fit in the memory of my Uno,
hence the trick of printing out the outliers instead of recording them.

And here is the resulting histogram:

```text
508 0
509 39386
510 960567
511 47
512 0
```

All other histogram bins were empty (no outliers).

As you can see, 96% of the calls returned 510. Most of those that
did not return 510 returned 509, and less than 0.005% of them
returned 511. The RMS dispersion of the readings is about
0.04 ADC steps.

I can hardly imagine anything more stable than this.


message:
About the FFT library on Arduino

From the output results, i see that the arduinoFFT returns only positive frequencies, thus i think it self removes the negative sided values and compensates the lost energy by multiplying by 2. Is this correct?Ar

body:
I don't know what you mean by a "negative" frequency.

FFT takes a set of samples and returns a group of "buckets", the number of buckets equal to half the number of samples. These buckets cover frequencies from 0Hz to F/2 where F is the sample frequency.

Each bucket contains the power magnitude of a block of frequencies in both the real and imaginary "axis" (effectively a pair of coordinates depicting a vector).

You compute the absolute power of a bucket through taking the square root of the sum of the squares of the real and imaginary components (basically good ol' pythagoras).

This "absolute power" value is the magnitude of a vector. A vector can never have a magnitude < 0. After all, if you have a vector of (1,1) and one of (-1, -1) they are both the same magnitude, just with a different angle (in this example a phase difference of 180 degrees).


message:
Safe to solder a slide switch to unused GPIO pins?

I have a Digispark Rev.3 Kickstarter with ATTiny85 (see pinout below) and a three pin slide switch (see example below). I want to use the slide switch to control a task running on the Digispark, with the example code below.

The center pin of the slide switch will be connected to GND, one pin will be soldered to pin 2 on the Digispark (`pinMode(2, INPUT_PULLUP);`) and the remaining pin will be unused.

To install the switch, I want to have the center pin of the switch go through P3 on the pinout, one pin through P2 (which will be addressed in the code) and the remaining pin through P4. This means, P3 will be soldered to GND and depending on the switches position, P2 or P4 will connect to GND as well.

Could these connections between P2, P3 or P4 and GND interfere with the functionality or damage the Digispark?

    int switchPos;
    void setup() {
      pinMode(2, INPUT_PULLUP);
    }

    void loop() {
      switchPos = digitalRead(2);
      if (sensorVal == HIGH) {
        runCode();
      } else {
        delay(1000);
      }
    }

[![Digispark Rev.3 Kickstarter with ATTiny85][1]][1]
[![Three pin slide switch][2]][2]

  [1]: https://i.stack.imgur.com/lPmI2.png
  [2]: https://i.stack.imgur.com/LGfhL.jpg

body:
Yes, you will lose the USB connection, since PB3 and PB4 are used for the USB communication. Normally you wouldn't solder a component directly onto a board if it doesn't fit with all pins. Instead you would use wires or a breakout PCB to do the job.

If you really want to to that and you don't need any of the other pins, then you can use PB0 and PB1. Set PB1 to OUTPUT LOW and PB0 as input. The OUTPUT LOW is basically the same as ground and configuring a pin as INPUT will make it high resistance, so it doesn't interfere with the circuit.


message:
How to shift binary into a shift register (serial in, parallel out) sequentially

I'm trying to make a continuity tester at work where I connect the input and output of a harness into a test fixture powered by an Arduino. This tester tests whether the position of the connects are pinned correctly.

Here is the diagram of my initial idea:

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

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

From one end of the connector (the output in the diagram), I want to shift in a binary that is in the power of 2. For instance, shifting in `0001`, check for continuity by reading the 75HC165 (parallel in, serial out), then clear the register and then shift in `0010`, and then `0100` and so on. For a correctly pinned harness, the write and read binary subtraction will be zero.

Here is my loop that attempts to perform the above:

    void loop() {
      for (int i = 1; i < 4; i++) {
        reset_SIPO_register();
        shift_SIPO(pow(2,i));
        delay(2000);
        shift_SIPO(0x00));
        check_continuity(); // not implemented yet
      }
    }

    void reset_SIPO_register() {
      digitalWrite(reset_pin, LOW);
      digitalWrite(reset_pin, HIGH);
    }

    void shift_SIPO(int sequence) {
      digitalWrite(latch_pin, LOW);
      shiftOut(data_pin, clock_pin, MSBFIRST, sequence);
      digitalWrite(latch_pin, HIGH);
    }

I am testing this concept on a breadboard with LEDs and the above kind of works. However, the LED is lit up one at a time and they don't turn off, not following the binary.

Is there something I'm missing here? thanks!

body:
Do not use `pow()`. This is a function that works with floating point
numbers. It is roughly equivalent (for y > 0) to

```c++
double pow(double x, double y)
{
    return exp(y * log(x));
}
```

As all transcendental functions, its implementation is prone to rounding
errors. It is not even guaranteed to give you the “correctly” rounded
version of the exact (i.e. infinite precision) result. In fact, very few
floating point functions give this guarantee.

As an example, if you compute `pow(2, i)` for i = 3, you get
7.9999980926513671875. This is 4 [ULPs][] smaller than the exact value.
Passing this number to `shift_SIPO()` implicitly converts it to an
`int`, and this conversion always rounds to zero. Thus you get 7, i.e.
`0b0111`.

What you want is an integer, exact implementation of `pow(2, i)`. It
turns out this is quite simple: Take the integer 1 in binary, then shift
it `i` times to the left. That is

```c++
shift_SIPO(1 << i);
```

[ULPs]: https://en.wikipedia.org/wiki/Unit_in_the_last_place


message:
Interrupt is sporatic, potentially after 220Hz or so

Background although likely not needed: I am recieving a frequency on the destination side of a opto isolater.  A fan trips a hall effect sensor, and grounds a circuit which lights the opto.  On the recieving end I have a fully isolated arduino circuit that accurately reads this 550Hz (peak) signal.  However, my Uno stopped reading this value correctly.  So I debounced the circuit which did not fix the issue.  I now brought in a new (and isolated) Uno that has nothing else going on but reading this signal and its Interrupt is also sporatic after several seconds.

I believe it is operating OK until the signal gets to about 420Hz (which is nothing..).  PulseIn also returns many "0" durations with the "900ns" good durations.  So it seems the high/low trigger is flipping too often, which was not fixed with debounce. I can see using the oscilloscope that the signal is good at 550Hz

    21:34:12.750 -> Htz: 0
    21:34:14.575 -> L: 44
    21:34:14.575 -> Htz: 88
    21:34:15.265 -> L: 70
    21:34:15.265 -> Htz: 140
    21:34:15.479 -> L: 89
    21:34:15.479 -> Htz: 178
    21:34:15.913 -> L: 109
    21:34:15.913 -> Htz: 218
    21:34:16.452 -> L: 117
    21:34:16.577 -> Htz: 234
    21:34:16.986 -> L: 134
    21:34:16.986 -> Htz: 268
    21:34:17.511 -> L: 186
    21:34:17.511 -> Htz: 372
    21:34:18.036 -> L: 213
    21:34:18.036 -> Htz: 426
    21:34:18.567 -> L: 702
    21:34:18.567 -> Htz: 1404
    21:34:19.195 -> L: 1913
    21:34:19.196 -> Htz: 3826
    21:34:19.838 -> L: 3508
    21:34:19.838 -> Htz: 7016

code

    unsigned long timestamp;
    int lsensorpin = 2;
    int PWMpin = 3;
    String printout;
    unsigned int reading;
    unsigned long L;
    unsigned int lRPM;
    unsigned int Htz;

    void setup() {
      pinMode(lsensorpin, INPUT);//_PULLUP); //2
      pinMode(PWMpin, OUTPUT);
      analogWrite(PWMpin, 100);
      Serial.begin(9600);
      Serial.println("FInish Setup");
    }

    void loop() {

      //printout=" High:";
      //reading= pulseIn(lsensorpin, HIGH);
      //printout=printout + reading + " Low:";
      //reading= pulseIn(lsensorpin, LOW);
      //printout= printout + reading;
      //Serial.println(printout + reading);

      L=0;
      attachl();
      delay(500);
      detachl();
      Htz=L*2;
      lRPM= L*60;
      Serial.print("L: ");
      Serial.println(L);
      //Serial.print("Htz: ");
      //Serial.println(Htz);

      //Serial.print("RPM: ");
      //Serial.println(lRPM);
    }

    void tickL() {
    L=L+1;
    }

    void attachl(){
        attachInterrupt(digitalPinToInterrupt(lsensorpin), tickL, RISING);
    }

    void detachl(){
        detachInterrupt(digitalPinToInterrupt(lsensorpin));
    }

[![Debounced Signal][1]][1]

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

body:
From my [post about interrupts](http://gammon.com.au/forum/?id=11488&reply=10#reply10):

---

I have seen example code suggesting you count things for a second by turning interrupts off for a second and then on again. I don't recommend this, because for one thing, you can't do serial prints if interrupts are off.

## Example (not recommended):

    volatile unsigned long events;
    const unsigned long INTERVAL = 1000;  // 1 second

    void eventISR ()
      {
      events++;
      }   // end of eventISR

    void setup ()
      {
      Serial.begin(115200);
      attachInterrupt (digitalPinToInterrupt (2), eventISR, FALLING);
      }   // end of setup

    void loop ()
      {
      events = 0;       // reset counter
      interrupts ();    // allow interrupts
      delay (INTERVAL); // wait desired time
      noInterrupts();   // stop interrupts

      Serial.print ("I counted ");
      Serial.println (events);
      }  // end of loop

That may work for simple situations, but turning interrupts off means that the Serial prints won't work until they are turned on again (which they may not be in a more complex sketch).

It is better to use the millis() result and just detect when the time limit is up.

## Improved sketch:

    volatile bool counting;
    volatile unsigned long events;

    unsigned long startTime;
    const unsigned long INTERVAL = 1000;  // 1 second

    void eventISR ()
      {
      if (counting)
        events++;
      }  // end of eventISR

    void setup ()
      {
      Serial.begin (115200);
      Serial.println ();
      attachInterrupt (digitalPinToInterrupt (2), eventISR, FALLING);
      }  // end of setup

    void showResults ()
      {
      Serial.print ("I counted ");
      Serial.println (events);
      }  // end of showResults

    void loop ()
      {
      if (counting)
        {
        // is time up?
        if (millis () - startTime < INTERVAL)
          return;
        counting = false;
        showResults ();
        }  // end of if

      noInterrupts ();
      events = 0;
      startTime = millis ();
      EIFR = bit (INTF0);  // clear flag for interrupt 0
      counting = true;
      interrupts ();
      }  // end of loop

In loop() here we wait for the interval (1 second in this case) to be up, otherwise we return, effectively doing nothing. You could of course do other things instead of just returning.

If the time is up we display the count.

If counting is not currently active (and presuming we want it to be active) we remember the start time, reset the counter to zero, and let it start counting up.

That code seemed to work OK up to 100 kHz, although the counts were getting a bit inaccurate. You can do more precise timings by using the hardware counters / timers. Details here:

<http://www.gammon.com.au/timers>

---

Also you should declare the variable **L** to be volatile.


message:
Unpredictable behavior of a 74HC595, Q0 has no output and LED flickering

Below is my schematics:

I am using a 74HC595 shift register and to test my connections, I have placed 8 LEDs to the output and shifted `0xFF` into the shift register (1111 1111), this should light up all the LEDs. However, Q1 to Q7 lit up, but Q0 didn't, it is very dim and flickering,
After doing some research and came across the decoupling capacitor and I have place a 10uF capacitor between the 5V and GND rail on the breadboard. However, the problem still persists, Am I missing something?
thanks!

Here is my code:

    int data_pin = 8;
    int latch_pin = 9;
    int clock_pin = 10;
    int reset_pin = 11;

    void setup() {
      pinMode(latch_pin, OUTPUT);
      pinMode(data_pin, OUTPUT);
      pinMode(clock_pin, OUTPUT);
      pinMode(reset_pin, OUTPUT);
      Serial.begin(9600);
    }

    void loop() {
      reset_SIPO_register();
      shift_SIPO(0xFF);
    }

    void reset_SIPO_register() {
      digitalWrite(reset_pin, LOW);
      digitalWrite(reset_pin, HIGH);
    }

    void shift_SIPO(byte sequence) {
      digitalWrite(latch_pin, LOW);
      shiftOut(data_pin, clock_pin, MSBFIRST, sequence);
      digitalWrite(latch_pin, HIGH);
    }

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

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

body:
There is a maximum current the 74HC595 can deliver. Probably you are using more than this current.

See e.g. https://electronics.stackexchange.com/questions/77841/how-much-current-can-my-74hc595-handle-on-each-output-pin

Some easy checks:

- Increase the resistor value so the total current is lowered
- Temporarily remove some LEDs, to see if the others behave like expected.
- Use other LEDs with a higher forward voltage to reduce the current.
- Changing the sketch to light one LED at a time to see if all outputs work.


message:
Requires accurate RGB color values by the tcs3200 RGB color sensore

I used the TCS3200 sensor to read the RGB color values.First, I calibrated the sensor with white and black colors.The sensor detects red, blue, and green correctly, but does not give an accurate value.For example, green is 105 190 150 instead of 0 255 0 .  I have to recognize the brown copper with the RGB value 138 73 49 .But it seems that I can not recognize this color with this method.I will be grateful if you can guide me.

    #define S0 4
    #define S1 5
    #define S2 6
    #define S3 7
    #define sensorOut 8
    int redPW = 0 ;
    int greenPW = 0 ;
    int bluePW = 0 ;

    void setup() {
      // Set S0 - S3 as outputs
      pinMode(S0, OUTPUT);
      pinMode(S1, OUTPUT);
      pinMode(S2, OUTPUT);
      pinMode(S3, OUTPUT);
      pinMode(sensorOut, INPUT);

      // Setting frequency-scaling to 20%
      digitalWrite(S0,HIGH);
      digitalWrite(S1,LOW);

      Serial.begin(9600);

    }

    void loop() {

    // Calibration Values
    int redMin=40;// Red minimum value
    int redMax=470;//346 Red maximum value
    int greenMin=40;// Green minimum value
    int greenMax=510;//348 Green maximum value
    int blueMin=30;// Blue minimum value
    int blueMax=390;//262 Blue maximum value

    int redValue;
    int greenValue;
    int blueValue;

    //Read Red Pulse Width
    digitalWrite(S2,LOW);
    digitalWrite(S3,LOW);
    // Read the output Pulse Width
    redPW = pulseIn(sensorOut,LOW);
    redValue=map(redPW, redMin,redMax,255,0);
    delay(200);

    // Read Green Pulse Width
    digitalWrite(S2,HIGH);
    digitalWrite(S3,HIGH);
    // Read the output Pulse Width
    greenPW = pulseIn(sensorOut,LOW);
    greenValue=map(greenPW, greenMin,greenMax,255,0);
    delay(200);

    // Read Blue Pulse Width
    digitalWrite(S2,LOW);
    digitalWrite(S3,HIGH);
    // Read the output Pulse Width
    bluePW = pulseIn(sensorOut,LOW);
    blueValue=map(bluePW, blueMin,blueMax,255,0);
    delay(200);

    // Print output to Serial Monitor
    Serial.print("redValue = ");
    Serial.print(redValue);
    Serial.print(" - greenValue = ");
    Serial.print(greenValue);
    Serial.print(" - blueValue = ");
    Serial.println(blueValue);

    }

body:
As I said, you MUST either
  - know the spectrum of the light source that exposes your sample or
  - calibrate the sensor under the exact same light you use for detection later on.

However, the actual calibration values don't matter at all. It should be as simple as saving the value you get for copper as a reference and compare your test color with that value, including some margin, of course. Any sensor will always have specific/individual properties, like the spectral sensitivity in case of the TCS3200. But the reason of calibration is that you don't have to bother.


message:
How to get the name of connected device over BLE?

I am implementing a BLE peripheral in my firmware with Arduino ESP32.

When the central gets connected to it, I'd like to log the name of the central & its address.

How can I do that?

```cpp
#include <BLEServer.h>

class ServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
  ble.log("ServerCallbacks: Connected");

// ==> how can I add the connected device ID or name in the log?

       ble.deviceConnected = true;

  #if SUPPORT_LEDS_INDICATOR

  // === Show France flag colors
  // RGBW = 1,2,3, 4
  // CODE : BBWRR
  // CODE = 33411
  const String code = "BBWRR";
  ledIndicator.showAccessCode(code);
  #endif

  #if SUPPORT_BUZZER
  /// BLE connection jingle
  buzzer.playBleConnectedMelody();
  #endif
    };

    void onDisconnect(BLEServer* pServer) {
  ble.deviceConnected = false;
  ble.log("ServerCallbacks: Disconnected");

  #if SUPPORT_BUZZER
  /// BLE connection jingle
  buzzer.playBleDisconnectedMelody();
  #endif
    }
};

/// Somewhere in the setup:
server = BLEDevice::createServer();

// == Set up our calbacks
server->setCallbacks(new ServerCallbacks());

```

body:
(Note: this is all just from reading the library source code, nothing has been tested).

You can't get the details of the just-connected-client. However you *can* get a list of the currently connected clients.

There is a function in the `BLEServer` class:

    std::map<uint16_t, conn_status_t> getPeerDevices(bool client);

You can use that to get the list of connected clients. The "key" of the map is the connection id, and the "value" of the map is the "conn_status_t" struct, which includes a pointer to the peer device structure:

```c++
typedef struct {
    void *peer_device;
    bool connected;
    uint16_t mtu;
} conn_status_t;
```

You can keep your own list of "current" connection IDs and compare that to the "live" list when a new connection is made to find which is the new connection.

So you can take that `peer_device` pointer, cast it to a `BLEClient` pointer, then you call any of the normal BLEClient functions on that, including `toString()` which will return a string representation of the client.

That of course isn't the "name" of the client. I am not sure (not being an expert on BLE) how you get the name, but I think you may have to actively query it from the client, which should be perfectly possible now you have the `BLEClient` object pointer.