# Question
Title: Change From One State Machine To Another
I have a project where I need to state from leds turning on and off to another one that will have all the leds turned on and send data and I was wondering how should I do that, this the code I have:

```
#include <CapacitiveSensor.h>

CapacitiveSensor cs_11_10 = CapacitiveSensor(11,10);

int state_s1 = 0;
int state_s2 = 0;
int state_s3 = 0;
int state_s4 = 0;
int state_prev_s1 =0;
int pin_s1 = 12;
int val_s1 = 0;

const unsigned int ledPins[]={2,3,4,5,6,7,8,9};
const unsigned int lenledPins=9;

unsigned long t_s1 = 0;
unsigned long t_0_s1 = 0;
unsigned long t_s3 = 0;
unsigned long t_0_s3 = 0;
unsigned long t_0_s4 = 0;
unsigned long t_s4 = 0;
unsigned long t_s2_4 = 0;
unsigned long tiempo = 250;

unsigned long bounce_delay_s1 = 5;

long total = 0;

void setup()
{
  pinMode(pin_s1, INPUT_PULLUP);
  Serial.begin(9600);

  for(int i=0; i<(9); i++)
  {
    pinMode(ledPins[i], OUTPUT);
  }

  cs_11_10.set_CS_AutocaL_Millis(0xFFFFFFFF);
  Serial.begin(9600);

}

void loop()
{

  MBoton();          //MAQUINA DE ESTADO

 MaquinaGeneral();

  if(state_s2 == 1)
  {
    led();
  }

  if(state_s1 != state_prev_s1)
  {
    Serial.print("state =");
    Serial.println(state_s3);
  }

  if(state_s4 == 6)
  {
    for(int i=0; i<lenledPins; i++)
    {
      digitalWrite(ledPins[i],HIGH);
    }
  }

  Serial.print("");

}

void MaquinaGeneral()
{
  switch(state_s2)
  {
    case 0:
    if(state_s1 == 4)
    {
      state_s2 = 1;
    }
    break;

    case 1:

    break;
  }
}

void MBoton()
{
  state_prev_s1 = state_s1;
  switch(state_s1)
  {
    case 0:         //RESET
    state_s1 = 1;
    break;

    case 1:        //START
    val_s1 = digitalRead(pin_s1);
    if(val_s1 == LOW)
     {
      state_s1 = 2;
     }
    break;

    case 2:         // GO!
    t_0_s1 = millis();
    state_s1 = 3;
    break;

    case 3:         //WAIT
    t_s1 = millis();
    if(t_s1 - t_0_s1 >= bounce_delay_s1)
    {
      state_s1 = 5;
    }
    break;

    case 5:         //ARMED
    val_s1 = digitalRead(pin_s1);
    if(val_s1 == HIGH)
     {
      state_s1 = 4;
     }
    break;

    case 4:       //TRIGGERED
    state_s1 = 0;
    break;

  }
}

void led()
{

  switch(state_s3)
  {
    case 0:         //OFF
    for(int i=0; i<lenledPins; i=i+2)
    {
      digitalWrite(ledPins[i],LOW);
    }
    for(int i=1; i<lenledPins; i=i+2)
    {
      digitalWrite(ledPins[i],HIGH);
    }

    t_0_s3 = millis();
    state_s3 = 1;
    break;

    case 1:         //WAIT
    t_s3 = millis();
    if(t_s3 - t_0_s3 >= tiempo)
    {
      state_s3 = 2;
    }
    break;

    case 2:         // ON
     for(int i=0; i<lenledPins; i=i+2)
    {
      digitalWrite(ledPins[i],HIGH);
    }

     for(int i=1; i<lenledPins; i=i+2)
    {
      digitalWrite(ledPins[i],LOW);
    }

    t_0_s3 = millis();
    state_s3 = 3;
    break;

    case 3:         //WAIT
    t_s3 = millis();
    if(t_s3 - t_0_s3 >= tiempo)
    {
     state_s3 = 0;
    }
    break;

  }

  }

void Capacitor()
 {

  switch(state_s4)
  {

    case 0:         //RESET
    state_s4 = 1;
    break;

    case 1:        //START
    total = cs_11_10.capacitiveSensor(10);
    if(total >= 1000)
     {
      state_s4 = 2;
     }
    break;

    case 2:         // GO!
    t_0_s4 = millis();
    state_s4 = 3;
    break;

    case 3:         //WAIT
    total = cs_11_10.capacitiveSensor(10);
    if(total < 1000)
     {
      state_s4 = 0;
     }

    t_s4 = millis();

    if(t_s4 - t_0_s4 >= 2000)
    {
      state_s4 = 5;
    }

    break;

    case 5:         //ARMED & WAIT
    t_s2_4 = millis();
    total = cs_11_10.capacitiveSensor(10);
    if(total < 1000)
     {
      state_s4 = 4;
     }

     if(t_s2_4-t_s4 >= 1000)
     {
      state_s4= 6;
     }
    break;

    case 4:       //TRIGGERED
    state_s4 = 0;
    break;

    case 6:     // ARMED 2
    Serial.println("Entro al estado 6");
    total = cs_11_10.capacitiveSensor(10);
    break;

}
}

```

# Answer
> 1 votes
If you think you need two finite state machines, where only one of them is running at any given time, then it is trivial to combine them together: draw them side by side, and add the required transitions between them. The set of states of the combined FSM will be the union of the states of the initial FSMs. For example, if you have:

* FSM 1 states: `STATE_A`, `STATE_B`, `STATE_C`
* FSM 2 stages: `STATE_D`, `STATE_E`
* global states: `FSM_1_RUNNING`, `FSM_2_RUNNING`

Then the combined FSM will have the states `STATE_A`, `STATE_B`, `STATE_C`, `STATE_D` and `STATE_E`, and all the transitions of both initial FSMs.

# Answer
> 0 votes
Similar to what others have commented, this is not the best implementation of a Finite State Machine (FSM). You should establish clear states and define what happens during all transitions of your system.

Follow Edgar's advice on using enumerators for your states.

Nick Gammon's guide will surely be of great help: https://www.gammon.com.au/statemachine

---
Tags: arduino-uno
---


# Question
Title: Can't upload sketches or flash Nodemcu 1.0 12E (CP2102) but have drivers and responds to RST on Serial monitor
I've been trying to get my nodemcu working for months and tried countless online references but none worked. I'm using the Arduino IDE to upload sketches and always get the error "Timed out waiting for packer header"

Here's my setup. I'm trying to upload the example blink code for the nodemcu 1.0 12E.

My board does show up on device manager and here's proof.

When i press reset on the nodemcu and have the serial monitor on at 74880 baud the board spits out this.

I have tried pressing the reset and flash buttons while uploading in the desired sequence but that didn't work. I even went as far as reflashing the firmware through the nodemcu flasher but it's always stuck at waiting for MAC and STA address.

Please help me fix the problem and i'm sure not the only one facing this issue. Hoping for help :).

# Answer
> 0 votes
Turns out it was a board problem. Switched it for an older version of the NodeMCU.

The newer ones are not known for the reliability it seems.

---
Tags: arduino-uno, esp8266, arduino-ide, nodemcu, uploading
---


# Question
Title: Why are the pin numbers of the diagrams and of the code different?
If I search Google for "arduino nano pin numbers", all results show that the pin number of D2 is 5. But that did not work. I searched for some sample codes, and they were 3 for D3 and 5 for D5, etc. So, in codes, the pin number for D`n` is `n`. Then what are the numbers in these diagrams?

# Answer
Every chip datasheet (and also the Arduino boards) uses 2 different ways to refer to the pins:

* Counting the physical pins in the order as they appear on the chosen package of the chip
* Referring to the pins by their function

The first way is only for referring to specific pin positions from the outside, for example when you are building the actual circuit. This also includes special pins like Vcc, GND and Reset. Those pins cannot be referenced by the code (wouldn't make much sense). Also the microcontroller on the inside of its package doesn't know in which package it got stuck by the manufacturer. Each package has a different pin order and form factor. So this counting only makes sense in the context of placing this specific package of the chip into a circuit (like where is Vcc, where ground and where do I need to connect to that specific digital pin), but makes no sense to use for the code inside the controller.

For referring to pins from inside the controller (aka in the code) we use the function of the pins. On an Arduino you have mainly digital and analog pins, which can be controlled. So for the convenience of beginners (which are targeted by the Arduino framework) the digital and analog pins are just numbered. Those are the numbers, that are normally written only the Arduino board. So D2 means the third digital pin inside the Arduino framework. A0 is the first analog pin. Where that pin is physically located on the board isn't interesting for the code, nore does the code know the actual location. For the code its just the third digital output hardware and so on.

**TL;DR:** For building the circuit we must refer to pin positions (like where is Vcc, where is ground) to connect the chip/microcontroller correctly. But the internal code doesn't know, where the physical pins are located and the actual location can also depend on the packaging. So internally we use a different counting system based on the pin function. The Arduino way of counting the digital and analog pins just hides away complexity for the beginner. As reference the numbers are also printed on the Arduino board itself.

---

In case you want to go deeper into the rabbit hole:

Actually the microcontroller has different hardware for different functions incorporated. For example: The analog pins can be used by the ADC (Analog to Digital Converter) to measure an analog voltage. But they also each have digital input and output hardware, just like any other digital pin. Most pins of a microcontroller are multi purpose. The code has to decide, what hardware gets to be connected to the respective pins. When I use `pinMode(2, OUTPUT)` I tell the microcontroller to connect the third digital output hardware to its respective physical pin. When I use `analogRead(A1)` I tell it to connect the second analog channel of the ADC to its respective pin and read an analog voltage through the ADC.

That means, that the code only knows of the function hardware and that it can be connected to their respective pins (whichever these pins are on the outside world). **The numbering in digital and analog pins is only an additional abstraction layer to hide the complexity from beginners.** Actually the code controls the hardware functions via Special Function Registers (SFR). These are special pieces of memory, which are physically hardwired to the respective hardware in the microcontroller. For the digital output hardware the pins are sorted into groups of up to 8 pins. These groups are called Ports, and are numbered with characters. When you look at this pinout of the Arduino Nano, you see, that the Arduino pin D2 is also named PD2, which means PortD third pin (counting from zero up). Arduino pin D8 is also named PB0, so PortB first pin. Functions like `pinMode()`, `digitalWrite()` and `digitalRead()` all just manipulate the SFRs for the wanted port to set the respective pin. Refer to the Documentation on Port Manipulation for learning how to do it yourself. For beginners it is just easier to use the markings on the board - the Arduino pin number - instead of bearing with the ports and their SFRs directly.
> 9 votes

# Answer
There are at least four ways of referring to pins on any Arduino board:

1. **Board-order**: Simple numeric order (1,2,3 ...) of physical location of pins on printed circuit board anticlockwise from the USB end (or some arbitrary end)
2. **Arduino-name**: Names used in Arduino source code and/or PCB silk-screen annotation (D1,D2 ... A0,A1 ...).
3. **IC-order**: Simple numeric order of corresponding pin on IC according to numbering used on manufacturers data sheet.
4. **IC Function name**: Names for functions available on pin (RESET, VCC, INT0, PB0,PB1,PB2 ...) as described in data sheet for IC.

For example:

| Nano PCB Pin# | Arduino Name | ATMega328 TQFP Pin# | ATMega328 DIP Pin# | ATMega328 function |
| --- | --- | --- | --- | --- |
| 1 | D13 | 17 | 19 | PB5, SCK, PCINT5 |
| 2 | 3V3 | N/A | N/A | N/A |
| 3 | REF | 20 | 21 | AREF |
| 4 | A0 | 23 | 23 | PC0, ADC0, PCINT8 |
| 5 | A1 | 24 | 24 | PC1, ADC1, PCINT9 |
| etc |  |  |  |  |

There are lots of different Arduino and Arduino-like boards that use the ATMega328, some use different ATMega328 packages (DIP, TQFP, etc) with different pin arrangements. Many arrange the physical PCB pins differently. This is why there isn't a fixed one to one relationship and it is partly why the Arduino IDE provides for it's own simplified naming that it attempts to apply consistently and portably across a variety of different microcontrollers.

---

<sup>(c) PigHixx w/o permission.</sup>
> 6 votes

# Answer
> Why are the pin numbers of the diagrams and of the code different?

Because the Arduino designers chose to re-use the name "pin" for the chip's programmable signal lines, despite it's more common and already existing use to mean any of the protruding external connections to the device.
> 1 votes

---
Tags: arduino-nano, pins
---


title: Arduino Due generate 400KHz sine waze

text:
# Question
Title: Arduino Due generate 400KHz sine waze
I new in Arduino environment. Found some code generate sine wave but frequency between 14kHz to 84kHz. URL is https://www.instructables.com/SineWave-Generator-for-Arduino-DUE/

I need to generate sine waze 400kHz frequency. Output should be on DAC0 or DAC1.

Any one can help to solve my problem.

# Answer
> 3 votes
The Due's DAC can go up to, and I quote direct from the datasheet:

> Up to 350ksps conversion rate

That means you can set *up to* 350,000 data points on your waveform per second. With two datapoints (giving you a square wave or, more realistically, a waveform with a sharks fin shape) the maximum you could get is (350,000/2) 175kHz.

Given that you stipulate you want a sine wave you're going to need many more than just 2 data points in your waveform. Assuming a (reasonable) minimum of 32 data points (more would give a smoother waveform) you'd be looking at a maximum frequency of about 10kHz. Sacrificing waveform fidelity you could increase that, but the higher you go the less and less it resembles a sine wave.

# Answer
> 2 votes
I think you may be overestimating the capabilities of the Due DAC. My understanding and experimentation is that waveform generating code (e.g., https://forum.arduino.cc/t/funkgenie-a-wavetable-based-function-generator/214938) can generate consistent output waves up to “a few kHz”. After which the wave shapes suffer from distortion.

If wave shape is not critical (though you did mention you specifically needed a sine wave) you may be able to push further using PWM outputs (e.g., https://forum.arduino.cc/t/due-high-frequency-waveform-up-too-500khz/423392).

However, I think you may need to design a suitable electronic circuit to generate the wave you’re seeking. That may be a topic for the Electrical Engineering stack exchange though? There is an introduction to wave generation circuit options going up into the RF frequencies here.

---
Tags: arduino-due, sine-wave
---


# Question
Title: Adafruit MPU-6050 and adafruit I2C Multiplexer
I have 3 adafruit MPUs hooked up to adafruit I2c Multiplexer. All of which is hooked up to a Arduino uno. Attached is also my code.

```
/* Assign a unique ID to this sensor at the same time */

/*Adafruit_HMC5883_Unified mpu1 = Adafruit_HMC5883_Unified(1);
Adafruit_HMC5883_Unified mpu2 = Adafruit_HMC5883_Unified(2);*/

#define TCAADDR 0x70

#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
Adafruit_MPU6050 mpu1 = Adafruit_MPU6050();
Adafruit_MPU6050 mpu2 = Adafruit_MPU6050();
Adafruit_MPU6050 mpu3 = Adafruit_MPU6050();

void displaySensorDetails(Adafruit_MPU6050 *mpu)
{
sensor_t sensor;
mpu->getGyroSensor();
Serial.println("------------------------------------");
Serial.print ("Sensor: "); Serial.println(sensor.name);
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" uT");
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" uT");
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" uT");
Serial.println("------------------------------------");
Serial.println("");
delay(500);
}

void setUpMPU(Adafruit_MPU6050 *mpu)
{
  mpu->setAccelerometerRange(MPU6050_RANGE_8_G);
  Serial.print("Accelerometer range set to: ");
  switch (mpu->getAccelerometerRange()) {
  case MPU6050_RANGE_2_G:
    Serial.println("+-2G");
    break;
  case MPU6050_RANGE_4_G:
    Serial.println("+-4G");
    break;
  case MPU6050_RANGE_8_G:
    Serial.println("+-8G");
    break;
  case MPU6050_RANGE_16_G:
    Serial.println("+-16G");
    break;
  }
  mpu->setGyroRange(MPU6050_RANGE_500_DEG);
  Serial.print("Gyro range set to: ");
  switch (mpu->getGyroRange()) {
  case MPU6050_RANGE_250_DEG:
    Serial.println("+- 250 deg/s");
    break;
  case MPU6050_RANGE_500_DEG:
    Serial.println("+- 500 deg/s");
    break;
  case MPU6050_RANGE_1000_DEG:
    Serial.println("+- 1000 deg/s");
    break;
  case MPU6050_RANGE_2000_DEG:
    Serial.println("+- 2000 deg/s");
    break;
  }

  mpu->setFilterBandwidth(MPU6050_BAND_21_HZ);
  Serial.print("Filter bandwidth set to: ");
  switch (mpu->getFilterBandwidth()) {
  case MPU6050_BAND_260_HZ:
    Serial.println("260 Hz");
    break;
  case MPU6050_BAND_184_HZ:
    Serial.println("184 Hz");
    break;
  case MPU6050_BAND_94_HZ:
    Serial.println("94 Hz");
    break;
  case MPU6050_BAND_44_HZ:
    Serial.println("44 Hz");
    break;
  case MPU6050_BAND_21_HZ:
    Serial.println("21 Hz");
    break;
  case MPU6050_BAND_10_HZ:
    Serial.println("10 Hz");
    break;
  case MPU6050_BAND_5_HZ:
    Serial.println("5 Hz");
    break;
}
}

void tcaselect(uint8_t i) {
if (i > 7) return;
Wire.beginTransmission(TCAADDR);
Wire.write(1 << i);
Wire.endTransmission();
}

void setup(void)
{
while (!Serial)
    delay(10); // will pause Zero, Leonardo, etc until serial console opens
Serial.begin(115200);
Serial.println("HMC5883 Magnetometer Test"); Serial.println("");
Serial.println("HMC5883 Magnetometer Test"); Serial.println("");

/* Initialise the 1st sensor */
tcaselect(0);
mpu1.setAccelerometerRange(MPU6050_RANGE_8_G);
Serial.print("Accelerometer range set to: ");
switch(mpu1.getAccelerometerRange()) {
case MPU6050_RANGE_2_G:
  Serial.println("+-2G");
  break;
case MPU6050_RANGE_4_G:
  Serial.println("+-4G");
  break;
case MPU6050_RANGE_8_G:
  Serial.println("+-8G");
  break;
case MPU6050_RANGE_16_G:
 Serial.println("+-16G");
  break;
}
mpu1.setGyroRange(MPU6050_RANGE_500_DEG);
Serial.print("Gyro range set to: ");
switch (mpu1.getGyroRange()) {
case MPU6050_RANGE_250_DEG:
  Serial.println("+- 250 deg/s");
  break;
case MPU6050_RANGE_500_DEG:
  Serial.println("+- 500 deg/s");
  break;
case MPU6050_RANGE_1000_DEG:
  Serial.println("+- 1000 deg/s");
  break;
case MPU6050_RANGE_2000_DEG:
  Serial.println("+- 2000 deg/s");
  break;
}
mpu1.setFilterBandwidth(MPU6050_BAND_21_HZ);
Serial.print("Filter bandwidth set to: ");
switch (mpu1.getFilterBandwidth()) {
case MPU6050_BAND_260_HZ:
  Serial.println("260 Hz");
  break;
case MPU6050_BAND_184_HZ:
  Serial.println("184 Hz");
  break;
case MPU6050_BAND_94_HZ:
  Serial.println("94 Hz");
  break;
case MPU6050_BAND_44_HZ:
  Serial.println("44 Hz");
  break;
case MPU6050_BAND_21_HZ:
  Serial.println("21 Hz");
  break;
case MPU6050_BAND_10_HZ:
  Serial.println("10 Hz");
  break;
case MPU6050_BAND_5_HZ:
  Serial.println("5 Hz");
  break;
}

/* Initialise the 2 sensor */
tcaselect(1);
mpu2.setAccelerometerRange(MPU6050_RANGE_8_G);
Serial.print("Accelerometer range set to: ");
switch(mpu1.getAccelerometerRange()) {
case MPU6050_RANGE_2_G:
  Serial.println("+-2G");
  break;
case MPU6050_RANGE_4_G:
  Serial.println("+-4G");
  break;
case MPU6050_RANGE_8_G:
  Serial.println("+-8G");
  break;
case MPU6050_RANGE_16_G:
 Serial.println("+-16G");
  break;
}
mpu2.setGyroRange(MPU6050_RANGE_500_DEG);
Serial.print("Gyro range set to: ");
switch (mpu1.getGyroRange()) {
case MPU6050_RANGE_250_DEG:
  Serial.println("+- 250 deg/s");
  break;
case MPU6050_RANGE_500_DEG:
  Serial.println("+- 500 deg/s");
  break;
case MPU6050_RANGE_1000_DEG:
  Serial.println("+- 1000 deg/s");
  break;
case MPU6050_RANGE_2000_DEG:
  Serial.println("+- 2000 deg/s");
  break;
}
mpu2.setFilterBandwidth(MPU6050_BAND_21_HZ);
Serial.print("Filter bandwidth set to: ");
switch (mpu1.getFilterBandwidth()) {
case MPU6050_BAND_260_HZ:
  Serial.println("260 Hz");
  break;
case MPU6050_BAND_184_HZ:
  Serial.println("184 Hz");
  break;
case MPU6050_BAND_94_HZ:
  Serial.println("94 Hz");
  break;
case MPU6050_BAND_44_HZ:
  Serial.println("44 Hz");
  break;
case MPU6050_BAND_21_HZ:
  Serial.println("21 Hz");
  break;
case MPU6050_BAND_10_HZ:
  Serial.println("10 Hz");
  break;
case MPU6050_BAND_5_HZ:
  Serial.println("5 Hz");
  break;
}

/* Initialise the 3rd sensor */
tcaselect(2);
mpu3.setAccelerometerRange(MPU6050_RANGE_8_G);
Serial.print("Accelerometer range set to: ");
switch(mpu1.getAccelerometerRange()) {
case MPU6050_RANGE_2_G:
  Serial.println("+-2G");
  break;
case MPU6050_RANGE_4_G:
  Serial.println("+-4G");
  break;
case MPU6050_RANGE_8_G:
  Serial.println("+-8G");
  break;
case MPU6050_RANGE_16_G:
 Serial.println("+-16G");
  break;
}
mpu3.setGyroRange(MPU6050_RANGE_500_DEG);
Serial.print("Gyro range set to: ");
switch (mpu1.getGyroRange()) {
case MPU6050_RANGE_250_DEG:
  Serial.println("+- 250 deg/s");
  break;
case MPU6050_RANGE_500_DEG:
  Serial.println("+- 500 deg/s");
  break;
case MPU6050_RANGE_1000_DEG:
  Serial.println("+- 1000 deg/s");
  break;
case MPU6050_RANGE_2000_DEG:
  Serial.println("+- 2000 deg/s");
  break;
}
mpu3.setFilterBandwidth(MPU6050_BAND_21_HZ);
Serial.print("Filter bandwidth set to: ");
switch (mpu1.getFilterBandwidth()) {
case MPU6050_BAND_260_HZ:
  Serial.println("260 Hz");
  break;
case MPU6050_BAND_184_HZ:
  Serial.println("184 Hz");
  break;
case MPU6050_BAND_94_HZ:
  Serial.println("94 Hz");
  break;
case MPU6050_BAND_44_HZ:
  Serial.println("44 Hz");
  break;
case MPU6050_BAND_21_HZ:
  Serial.println("21 Hz");
  break;
case MPU6050_BAND_10_HZ:
  Serial.println("10 Hz");
  break;
case MPU6050_BAND_5_HZ:
  Serial.println("5 Hz");
  break;
}

/* Display some basic information on this sensor */
tcaselect(0);
displaySensorDetails(&mpu1);
tcaselect(1);
displaySensorDetails(&mpu2);
tcaselect(2);
displaySensorDetails(&mpu2);
}

void loop(void)
{
/* Get a new sensor event */
sensors_event_t a, g, temp;
tcaselect(0);
mpu1.getEvent(&a, &g, &temp);
/* Display the results (magnetic vector values are in micro-Tesla (uT)) */
Serial.print("Sensor #1 - ");
//Serial.print("X: "); Serial.print(event.magnetic.x); Serial.print(" ");
//Serial.print("Y: "); Serial.print(event.magnetic.y); Serial.print(" ");
//Serial.print("Z: "); Serial.print(event.magnetic.z); Serial.print(" ");Serial.println("uT");
Serial.print("Acceleration X: ");
Serial.print(a.acceleration.x);
Serial.print(", Y: ");
Serial.print(a.acceleration.y);
Serial.print(", Z: ");
Serial.print(a.acceleration.z);
Serial.println(" m/s^2");

tcaselect(2);
mpu2.getEvent(&a, &g, &temp);
/* Display the results (magnetic vector values are in micro-Tesla (uT)) */
Serial.print("Sensor #2 - ");
Serial.print("X: "); Serial.print(event.magnetic.x); Serial.print(" ");
Serial.print("Y: "); Serial.print(event.magnetic.y); Serial.print(" ");
Serial.print("Z: "); Serial.print(event.magnetic.z); Serial.print(" ");Serial.println("uT");
Serial.print("Acceleration X: ");
Serial.print(a.acceleration.x);
Serial.print(", Y: ");
Serial.print(a.acceleration.y);
Serial.print(", Z: ");
Serial.print(a.acceleration.z);
Serial.println(" m/s^2");
delay(500);
}

```

In this configuration All of my mpu sensors are sending back unreasonable numbers for acceleration and temperature. Am I initializing my mpus correctly in my code?

# Answer
> 3 votes
It seems like you would need to call `.begin()` on your `Adafruit_MPU6050` instances, like the examples do.

So, following the pattern, in `setup()` you would need to:

```
 tcaselect(0);
 if (!mpu1.begin()) {
    Serial.println(F("Failed to find MPU6050 chip 1"));
    while (1) {
      delay(10);
    }
 }

 tcaselect(1);
 if (!mpu2.begin()) {
    Serial.println(F("Failed to find MPU6050 chip 2"));
    while (1) {
      delay(10);
    }
 }

 tcaselect(2);
 if (!mpu3.begin()) {
    Serial.println(F("Failed to find MPU6050 chip 3"));
    while (1) {
      delay(10);
    }
 }

```

I see you're removing some repetition with functions. I'm guessing you just haven't gotten to doing that with the repeated `switch` statements for printing frequencies and such. You may want to put your `mcu1`/`mcu2`/`mcu3` into an array instead for similar reasons.

An array of `Adafruit_MPU6050`:

```
Adafruit_MPU6050 mpus[3];

```

The code for calling `begin()` could look something like:

```
size_t index = 0;
for (auto &an_mpu: mpus) {
  tcaselect(index);
  if (!an_mpu.begin()) {
    Serial.print(F("Failed to find MPU6050 chip, mpu["));
    Serial.print(index);
    Serial.println(']');
    Serial.println(F("Halting..."));
    while (1) {
      delay(10);
    }
  }

  ++index;
}

```

# Answer
> 1 votes
You don't need the I2C multiplexors at all - I currently have seven MPU6050 modules being managed by one Teensy 3.5 chip. Four MPU6050's are on one of the T3.5's I2C busses, and the remaining three are on another. I could run them all from just one I2C bus, but I split them just for wiring convenience. The 'trick' is to replace the I2C address of each MPU6050 in turn in the setup() routine, as shown by the code associated with the blog post referenced below

See this post and related ones on my blog site 'Paynter's Palace'.

I've been using this technique for quite a while now, so let me know if you have any additional questions.

22 Sept 21 edit:

Here's the function that handles address initialization for the four MPU6050's on the Wire2 I2C bus:

```
bool InitWire2Sensors()
{
  delay(1000);
  Serial.printf("Initializing VL53L0X Sensor Array Elements on Wire2\n");
  bool retval = true;

  //Put all sensors in reset mode by pulling XSHUT low
  digitalWrite(LF_XSHUT_PIN, LOW);
  digitalWrite(LC_XSHUT_PIN, LOW);
  digitalWrite(LR_XSHUT_PIN, LOW);
  digitalWrite(Rear_XSHUT_PIN, LOW);

  //left-front
  //input w/o pullups sets line to high impedance so XSHUT pullup to 3.3V takes over
  pinMode(LF_XSHUT_PIN, INPUT);
  delay(10);

  if (!lidar_LF.init())
  {
    Serial.println("Failed to detect and initialize LF sensor!");
    retval = false;
  }
  else
  {
    Serial.printf("lidar_LF successfully initialized at %x\n", lidar_LF.getAddress());
    lidar_LF.setMeasurementTimingBudget(20000);
    lidar_LF.startContinuous();

    lidar_LF.setAddress(DEFAULT_VL53L0X_ADDR + 4);
    Serial.printf("lidar_LF. address is now 0x%x\n", lidar_LF.getAddress());
  }

  //now bring lidar_LC only out of reset and set it's address
  //input w/o pullups sets line to high impedance so XSHUT pullup to 3.3V takes over
  pinMode(LC_XSHUT_PIN, INPUT);
  delay(10);

  if (!lidar_LC.init())
  {
    Serial.println("Failed to detect and initialize LC sensor!");
    retval = false;
  }
  else
  {
    Serial.printf("lidar_LC successfully initialized at %x\n", lidar_LC.getAddress());
    lidar_LC.setMeasurementTimingBudget(20000);
    lidar_LC.startContinuous();

    lidar_LC.setAddress(DEFAULT_VL53L0X_ADDR + 5);
    Serial.printf("lidar_LC. address is now 0x%x\n", lidar_LC.getAddress());
  }

  //now bring lidar_LR only out of reset and set it's address
  //input w/o pullups sets line to high impedance so XSHUT pullup to 3.3V takes over
  pinMode(LR_XSHUT_PIN, INPUT);
  delay(10);

  if (!lidar_LR.init())
  {
    Serial.println("Failed to detect and initialize LR sensor!");
    retval = false;
  }
  else
  {
    Serial.printf("lidar_LR successfully initialized at %x\n", lidar_LR.getAddress());
    lidar_LR.setMeasurementTimingBudget(20000);
    lidar_LR.startContinuous();

    lidar_LR.setAddress(DEFAULT_VL53L0X_ADDR + 6);
    Serial.printf("lidar_LR. address is now 0x%x\n", lidar_LR.getAddress());
  }

  //now bring lidar_Rear only out of reset and set it's address
  //input w/o pullups sets line to high impedance so XSHUT pullup to 3.3V takes over
  pinMode(Rear_XSHUT_PIN, INPUT);
  delay(10);

  if (!lidar_Rear.init())
  {
    Serial.println("Failed to detect and initialize Rear sensor!");
    retval = false;
  }
  else
  {
    Serial.printf("lidar_Rear successfully initialized at %x\n", lidar_Rear.getAddress());
    lidar_Rear.setMeasurementTimingBudget(20000);
    lidar_Rear.startContinuous();

    lidar_Rear.setAddress(DEFAULT_VL53L0X_ADDR + 7);
    Serial.printf("lidar_Rear. address is now 0x%x\n", lidar_Rear.getAddress());
  }
  //input w/o pullups sets line to high impedance so XSHUT pullup to 3.3V takes over
  pinMode(LR_XSHUT_PIN, INPUT);
  delay(10);

  if (!lidar_LR.init())
  {
    Serial.println("Failed to detect and initialize LR sensor!");
    retval = false;
  }
  else
  {
    Serial.printf("lidar_LR successfully initialized at %x\n", lidar_LR.getAddress());
    lidar_LR.setMeasurementTimingBudget(20000);
    lidar_LR.startContinuous();

    lidar_LR.setAddress(DEFAULT_VL53L0X_ADDR + 2);
    Serial.printf("lidar_LR. address is now 0x%x\n", lidar_LR.getAddress());
  }

  return retval;
}

```

Frank

---
Tags: arduino-uno, i2c, mpu6050
---


title: Timer to send a periodic pulse

text:
# Question
Title: Timer to send a periodic pulse
I am looking for a very low power, small component (perhaps an arduino) that will send a pulse 3.3V logic HIGH pulse once every X seconds to another system. I want to be able to configure X (maybe a trim pot or something) based on the use case the most rapid use case would be about once per second and the slowest would be once per hour. The duration of the pulse doesn't really matter much as long as it's one second or less.

Adafruit sells an item (PRODUCT ID: 3573) based on a Texas Instruments TPL5110 chip that sort of does this but it's a timed constant HIGH signal, not a pulse. I am an electronics noob and am not sure what category of component this falls under but I have tried googling and reading tutorials on timers.

# Answer
> 4 votes
As Edgar Bonet commented, you can do this using an ATtiny85 IC in an 8-pin DIP package which is available for about $1 and can be programmed using the Arduino IDE.

You have to tell the Arduino software about the ATtiny85 by installing a "core" for it such as Spence Konde's

You will need a device to transfer the program into the ATtiny85, either a $5-$15 AVR programmer or something like an Arduino Uno using the Arduino-as-ISP sketch .

Writing the software will be extremely easy by Arduino standards.

One advantage of the ATtiny85 over the same sized NE555 is that the ATtiny85 needs no external components (resistors capacitors etc) and so is a lot simpler to use. You can run this ATtiny85 on a 3.3 Volt supply (anything from 2.7 → 5.5 V will work).

If you want an ATtiny85 on a pre-assembled PCB (like that Adafruit TPL5110 product), try a Digispark or a $1 Digispark clone, it can be plugged directly into a USB port for programming with the Arduino IDE. I haven't tried running one on 3.3V but I suspect that should be possible by connecting the 3.3V supply to the "5V" pin to bypass the Digispark's 5V regulator.

---

See https://wokwi.com/arduino/projects/310458692893934146

I was also able to run it on a cheap Digispark clone from a 3V3 supply

The only advantage over a bare ATtiny85 is that you don't need any programming hardware, just a USB port on a PC.

---
Tags: timers
---


title: Setup Due counter

text:
# Question
Title: Setup Due counter
How do I setup a Due to count rising edges on a pin automatically without having to waste time on an ISR?

I have some wheel encoders, the simplist implementation is direction less where you only count rising edges.

I went the Due to count rising edges automatically and an ISR on a timer will periodically pole the current count

# Answer
You need to pick a timer that isn't being used for anything else and configure it as a simple counter with the clock source set to the external clock pin for that timer.

> At block level, input clock signals of each channel can either be connected to the external inputs TCLK0, TCLK1 or TCLK2, or be connected to the internal I/O signals TIOA0, TIOA1 or TIOA2 for chaining by programming the TC Block Mode Register (TC\_BMR). See Figure 36-2. Each channel can independently select an internal or external clock source for its counter:
>
> * External clock signals(1): XC0, XC1 or XC2
> * Internal clock signals: MCK/2, MCK/8, MCK/32, MCK/128, SLCK This selection is made by the TCCLKS bits in the TC Channel Mode Register (TC\_CMR).

I am not personally familiar with the peripherals of the Due, but chapter 36 of the SAM3X datasheet details the workings and registers that you need to set.

Your encoder signal then connects to that clock input pin and the counter then counts every incoming pulse until you reset the count from your other periodic timer ISR.
> 2 votes

---
Tags: arduino-due, rotary-encoder
---


# Question
Title: Arduino, generating smaller frequency than 31Hz
I'm controlling a car instrument panel with Arduino using the tone() function, however with Arduino Uno's minimum 31Hz frequency I can only set the speedometer at ~12mph or more. I'd like to be able to set the speed from 0, which would require around 10Hz I believe. Are there any code tricks I could use? Maybe I should use hardware timer, or a different board?

# Answer
For this, I would consider using Timer 1 in mode 14 (fast PWM, with TOP value controlled by ICR1), with the prescaler set to 64. The timer would then be clocked at 250 kHz, giving you the following specs:

* timer frequency: 250 kHz (time resolution = 4 µs)
* minimum frequency: 3.81 Hz (exact period = 218 µs = 262,144 ms)
* maximum frequency: 125 kHz (period = 8 µs)

As the time resolution is constant, the frequency resolution worsens as you increase the frequency. At 400 Hz the resolution is about 0.16%, or 0.64 Hz.

This is not the only possible solution. Toggle mode would work also, and also other prescaler values, which would give different frequency ranges and resolutions.

Check the datasheet to see how to set the configuration bits (basically: non-inverting PWM on either OC1A or OC1B, waveform generation mode = 14, prescaler = 64). You may be able to find libraries to do this if you prefer that approach, I have not checked this possibility.
> 2 votes

---
Tags: arduino-uno, pwm, frequency
---


# Question
Title: Problem Using pins A4 and A5 for input and output I2C
Hardare used: Arduino nano ( old Bootloader ) Oled Monochrome Display ( 4 pins, 128 x 32 ) MPU 6050

Both display and MPU use A4 and A5 as I2C communication protocol, They interfere, as the MPU is used 2-way and the Display 1-way.

1. How can I change those 2 pins( does not matter witch Display/Sensor )
2. Can this method ( the one you propose ) be used for more cases like this? ( ex 3 sensors )

There is what I tried so far:

```
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels

#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif
MPU6050 mpu;

#define OUTPUT_READABLE_YAWPITCHROLL
#define OUTPUT_READABLE_REALACCEL

// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

// orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float euler[3];         // [psi, theta, phi]    Euler angle container
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector

#define INTERRUPT_PIN 2  // use pin 2 on Arduino Uno & most boards
volatile bool mpuInterrupt = false;
void dmpDataReady() {
  mpuInterrupt = true;
}

void setup() {
  volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high

  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
   for(;;); // Don't proceed, loop forever
  }

  // Clear the buffer
  display.clearDisplay();

  delay(150);

  #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();
    pinMode(INTERRUPT_PIN, INPUT);

    // verify connection
    Serial.println(F("Testing device connections..."));
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

    delay(50);

    // load and configure the DMP
    Serial.println(F("Initializing DMP..."));
    devStatus = mpu.dmpInitialize();

  if (devStatus == 0) {
        // Calibration Time: generate offsets and calibrate our MPU6050
        mpu.CalibrateAccel(6);
        mpu.CalibrateGyro(6);
        mpu.PrintActiveOffsets();
        // turn on the DMP, now that it's ready
        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);

        // enable Arduino interrupt detection
        Serial.print(F("Enabling interrupt detection (Arduino external interrupt "));
        Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
        Serial.println(F(")..."));
        attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();

        // set our DMP Ready flag so the main loop() function knows it's okay to use it
        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        dmpReady = true;

        // get expected DMP packet size for later comparison
        packetSize = mpu.dmpGetFIFOPacketSize();
    } else {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)
        Serial.print(F("DMP Initialization failed (code "));
        Serial.print(devStatus);
        Serial.println(F(")"));
    }

  Serial.begin(9600);
}

void loop() {
  if (!dmpReady) return;
    // read a packet from FIFO
    if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) { // Get the Latest packet

        #ifdef OUTPUT_READABLE_YAWPITCHROLL
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            /*
            data.gyro_data[0] = ypr[0] * 180/M_PI;
            data.gyro_data[1] = ypr[1] * 180/M_PI;
            data.gyro_data[2] = ypr[2] * 180/M_PI;
            */
        #endif

        #ifdef OUTPUT_READABLE_REALACCEL
            // display real acceleration, adjusted to remove gravity
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetAccel(&aa, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
            /*
            data.acc_data[0] = aaReal.x;
            data.acc_data[1] = aaReal.y;
            data.acc_data[2] = aaReal.z;
            */
        #endif
    }

    display.print(String(ypr[0] * 180/M_PI));
    display.print('/');
    display.print(String(ypr[1] * 180/M_PI));
    display.print('/');
    display.print(String(ypr[2] * 180/M_PI));
    display.print("\n\n");
    display.print(String(aaReal.x));
    display.print('/');
    display.print(String(aaReal.y));
    display.print('/');
    display.print(String(aaReal.z));

    //display.print(String(data.id));
    display.display();

    delay(500);
}

```

Now I know this looks like a bunch of code thrown together with the hope to work, But it is composed from 2 other of my codes separately for MPU and Display, those work fine.

# Answer
> 1 votes
So after repeated tests I found several problems, software and hardware.

1. The cables I used on the breadboard where facing each other. The metal parts where touching ( from a defect of the cables ). Turned them 90\*.
2. The Oled display was NOT Initialized properly. When using `display.write()` or `display.print()` you must first put the cursor at (0;0) by `display.setCursor(0,0)`. Furthermore for more compatibility in `Setup(){}` you have to add `display.setTextSize(1)` and `display.setTextColor(WHITE)`.
3. Power control. I found the best, either adding a capacitor on the VCC and GND lines when using them to power 2 Sensors at the same time, or ad a 5 mls delay in the first function. `delay(5)`

---
Tags: programming, arduino-nano, i2c, pins
---


# Question
Title: A9G gsm module not displaying message body after receiving SMS
I am trying to receive an SMS on my arduino and print it out to the serial monitor. I am using the A9G gsm/gps module for doing that. Here is the code for it

```
#include <SoftwareSerial.h>

//Create software serial object to communicate with A6
SoftwareSerial mySerial(10, 11); //A6 Tx & Rx is connected to Arduino #3 & #2

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

  //Begin serial communication with Arduino and A6
  mySerial.begin(115200);

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

  mySerial.println("AT"); //Once the handshake test is successful, it will back to OK
  updateSerial();

  mySerial.println("AT+CMGF=1"); // Configuring TEXT mode
  updateSerial();
  mySerial.println("AT+CNMI=2,2,0,0,0"); // Decides how newly arrived SMS messages should be handled
  updateSerial();
}

void loop()
{
  updateSerial();
}

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

```

The code works and I get a response but the response does not include the body of the message. This is the response I got after sending "hello" to it;

```
CIEV: "MESSAGE",1
+CMT: "+233201729573",,"2021/06/18,12:20:03

```

As you can see it rightly sends me a notification but it does not include the "hello" which is the actual message I want to receive. Can anyone help me out?

# Answer
> 1 votes
I have sorted that out for sometime now. It turns out for some reason SerialSoftware was truncating my messages because the serial buffer size was too small. All I had to do was increase the buffer size to a higher number in the SoftwareSerial.h file and it worked.

# Answer
> 0 votes
Your serial reception code is much much much too primitive to be of any use.

You're waiting for 0.5 seconds for data to come in, which gets stored in a 64 byte buffer. Then you read out the contents of that 64 byte buffer.

Anything more than 64 bytes gets discarded.

You need to read the data actively as it comes in (**NO** `delay()`!) looking for specific things in the data (OK, ERROR, your text message response, etc) until the whole response from the modem has been received.

---
Tags: gsm
---


# Question
Title: Esp32 external interrupts sometime is missing
In short. ESP32, two water meters (hot and cold). Booth, hot and cold, some interrupts are missed. When i connect ESP32 to serial monitor and watch then all interrupts are detected (about 5-10 minutes). But if i leave to 5v power only, then some interrupts are missed (in one day it can be up to 50 or even more).

About water counter \- one pulse per liter. Correct info about sensor is in PDF Original Operating Instructions.

Sensor connections. Brown wire to GND, white to PIN 32(hot),33(cold).

**Board**. Olimex ESP32-POE Rev C.

* Powered via 5v Samsung phone charger (standard 5V charger without 9v)
* WiFi enabled (For NTP and to see counter readings)
* OTA enabled
* WEB server running (plain html, ESPAsyncWebServer)
* Bluetooth disabled
* SD card attached (stores SQLite database only)
* Uses siara-cc/esp32\_arduino\_sqlite3\_lib library

**Water usage in last month (May)**

* hot - 4777 liters (counted with sensor - 2675)
* cold - 9289, with sensor - 5528

As we can see, difference is huge. Maybe ISR routine exec time is too long and some interrupts are skipped? I know that WiFi too uses interrupts... Is my interrupt code wrong? Water counter reading is stored in SQLite database when 10 liters are used. Thanks for anyone for your time in advance!

Here is image of water counter and sensor

Here is some code, related to interrupts (debug disabled).

```
struct WaterCounter
{
  const uint8_t PIN; // microcontroller pin...
  volatile uint32_t liters_total; // max 4294967295
  volatile uint16_t liters_in_session; // max 65535
  volatile uint32_t session_started; // unix timestamp
  volatile uint32_t session_last_pulse; // unix timestamp
  const char display_name[5];
  volatile unsigned long pulse_start;
  volatile unsigned long pulse_stop;
  volatile uint32_t isr_prev_time;
  volatile uint32_t liters_last_written;
  volatile uint32_t liters_used_today;
};
WaterCounter wc_hot =  { PIN_WC_HOT, 0, 0, 0, 0, "Hott", 0, 0, 0, 0, 0 };
WaterCounter wc_cold = {PIN_WC_COLD, 0, 0, 0, 0, "Cold", 0, 0, 0, 0, 0 };
void IRAM_ATTR handle_wc(WaterCounter *wc)
{
  uint32_t  t = micros();
  uint32_t dt = t - wc->isr_prev_time;
  if (dt<1500) return;
  wc->isr_prev_time = t;
  if (wc->pulse_start == 0)
  {
    wc->pulse_start = millis();
    #ifdef DEBUG_ISR
      //Serial.printf("Started %s pulse!\n", wc->display_name);
      ets_printf("Started %s pulse!\n", wc->display_name);
    #endif
  }else
  {
    wc->pulse_stop = millis();
    unsigned long pulsew = wc->pulse_stop - wc->pulse_start;
    wc->pulse_start = 0;
    if (pulsew > 40 && pulsew < 55)
    {
      wc->liters_total++;
      wc->liters_in_session++;
      wc->liters_used_today++;
      if (wc->session_started == 0)
      {
        wc->session_started = now;
      }
      wc->session_last_pulse = now;
    }
    #ifdef DEBUG_ISR
      //Serial.printf("%s: pulse_width: %ld\n", wc->display_name, pulsew);
      ets_printf("%s: pulse_width: %ld\n", wc->display_name, pulsew);
    #endif
  }
}
void IRAM_ATTR isr_wc_cold()
{
  handle_wc(&wc_cold);
}

void IRAM_ATTR isr_wc_hot()
{
  handle_wc(&wc_hot);
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Boot...");

  // allow some time to pull up pin, interrupt is attached below
  pinMode(wc_cold.PIN, INPUT_PULLUP);
  pinMode(wc_hot.PIN, INPUT_PULLUP);

  Serial.printf("Watchdog timeout: %dms\n", WATCHDOG_TIMEOUT);
  timerWD = timerBegin(0, 80, true);                  //timer 0, div 80
  timerAttachInterrupt(timerWD, &resetModule, true);  //attach callback
  timerAlarmWrite(timerWD, WATCHDOG_TIMEOUT * 1000, false); //set time in us
  timerAlarmEnable(timerWD); //enable interrupt
  timerWrite(timerWD, 0); //reset timer (feed watchdog)

  SD_MMC.begin();

  enqRC = sqlite3_initialize();
  if (enqRC == SQLITE_OK)
  {
    openDb();
    initSensorDatabase();
    timerWrite(timerWD, 0); //reset timer (feed watchdog)
    SetupWiFi();
    closeDb();
  }
  timerWrite(timerWD, 0); //reset timer (feed watchdog)
  pollNtp();
  timerWrite(timerWD, 0); //reset timer (feed watchdog)

  openDb();
  initTotalValues(&wc_cold);
  timerWrite(timerWD, 0); //reset timer (feed watchdog)
  initTotalValues(&wc_hot);
  closeDb();
  timerWrite(timerWD, 0); //reset timer (feed watchdog)

  attachInterrupt(digitalPinToInterrupt(wc_cold.PIN), &isr_wc_cold, FALLING);
  attachInterrupt(digitalPinToInterrupt(wc_hot.PIN), &isr_wc_hot, FALLING);

  timer_session = timerBegin(1, 80, true);
  timerAttachInterrupt(timer_session, &onSessionTimer, true);
  timerAlarmWrite(timer_session, 1000000, true); // every 1 second
  timerAlarmEnable(timer_session);

  EnableOTA();

  //* async web
  webServer.on("/", HTTP_GET, handleRootAsync);
  webServer.on("/heap", HTTP_GET, heapInfoAsync);
  webServer.on("/post", HTTP_POST, handlePostAsync);
  webServer.on("/params", HTTP_GET, handleParameterPage);
  webServer.onNotFound(onNotFoundAsync);
  webServer.begin();

  time(&now);
}

void loop() {
  // put your main code here, to run repeatedly:
  loop_task();
}
void loop_task()
{
  if (time_every_second <= now)
  {
    writeWcTotalToDb(&wc_cold);
    writeWcTotalToDb(&wc_hot);
    time_every_second = now + 1;
  }

  if (time_every_30_seconds <= now)
  {
    pollNtp();
    time_every_30_seconds = now + 30;
  }
}
void IRAM_ATTR finishSession(WaterCounter *wc, time_t tt)
{
  if (wc->session_started == 0)
  {
    return;
  }
  if (tt - wc->session_last_pulse > SESSION_LENGHT)
  {
    //finish session
    #ifdef DEBUG_ISR
      //Serial.printf("# %s liters in session: %d, duration %d(s)\n", wc->display_name, wc->liters_in_session, wc->session_last_pulse - wc->session_started);
      ets_printf("# %s liters in session: %d, duration %d(s)\n", wc->display_name, wc->liters_in_session, wc->session_last_pulse - wc->session_started);
    #endif

    wc->session_started = 0;
    wc->liters_in_session = 0;
  }
}

/* every 1s  */
void IRAM_ATTR onSessionTimer()
{
  timerWrite(timerWD, 0); //reset timer (feed watchdog)
  //ets_printf("\nonSessionTimer()\n");
  time(&now);
  getLocalTime(&timeinfo);
  strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%d %H:%M:%S", &timeinfo);
  if (now % 86400 == 75600) /* works if this function is called every second */
  {
    ets_printf("\n!!!midnight!!\n");
    wc_cold.liters_used_today = 0;
    wc_hot.liters_used_today = 0;
  }
  finishSession(&wc_cold, now);
  finishSession(&wc_hot, now);
}
void writeWcTotalToDb(WaterCounter *wc)
{
  #ifdef DEBUG_WRITE
    Serial.printf("writeWcTotalToDb(%s): begin\n", wc->display_name);
  #endif

  uint8_t ldiff = wc->liters_total - wc->liters_last_written;
  if (ldiff == 0)
  {
    #ifdef DEBUG_WRITE
      Serial.println("writeWcTotalToDb(): diff zero");
    #endif
    return;
  }
  if (ldiff <= LITERS_BEFORE_WRITE && wc->session_started > 0)
  {
    #ifdef DEBUG_WRITE
      Serial.println("writeWcTotalToDb(): ldiff <= LITERS_BEFORE_WRITE && wc->session_started > 0");
    #endif
    return;
  }
  #ifdef DEBUG_WRITE
    Serial.println("writeWcTotalToDb(): start writting procedure!");
  #endif
  if (!openDb())
  {
    char *sql = "INSERT INTO `water_counter` VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
    sqliteResultCode = sqlite3_prepare_v2(sqliteDb, sql, strlen(sql), &sqliteRes, NULL);
    if (sqliteResultCode != SQLITE_OK)
    {
      #ifdef DEBUG
        Serial.printf("writeWcTotalToDb(): ERROR preparing sql: %d -> %s\n", sqliteResultCode, sqlite3_errmsg(sqliteDb));
      #endif
    }else
    {
      #ifdef DEBUG
        Serial.print("writeWcTotalToDb(): Prepare OK\n");
      #endif
      //getLocalTime(&timeinfo); // inside every 1 sec
      //strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%d %H:%M:%S", &timeinfo);
      sqlite3_bind_int(sqliteRes, 1, now); // datums
      sqlite3_bind_int(sqliteRes, 2, wc->liters_total);
      sqlite3_bind_text(sqliteRes, 3, timeStringBuff, strlen(timeStringBuff), SQLITE_STATIC);
      sqlite3_bind_text(sqliteRes, 4, wc->display_name, strlen(wc->display_name), SQLITE_STATIC);
      sqlite3_bind_int(sqliteRes, 5, 0);
      sqlite3_bind_int(sqliteRes, 6, wc->liters_in_session);
      sqlite3_bind_int(sqliteRes, 7, wc->session_started);
      sqlite3_bind_int(sqliteRes, 8, 0); /* currently not used */

      if (sqliteResultCode = sqlite3_step(sqliteRes) != SQLITE_DONE)
      {
          #ifdef DEBUG
            Serial.printf("writeWcTotalToDb(): ERROR executing stmt: %d -> %s\n", sqliteResultCode, sqlite3_errmsg(sqliteDb));
          #endif
      }else
      {
          #ifdef DEBUG
            Serial.print("writeWcTotalToDb(): data saved!\n");
          #endif
          wc->liters_last_written = wc->liters_total;
          sqlite3_clear_bindings(sqliteRes);
          sqliteResultCode = sqlite3_reset(sqliteRes);
          if (sqliteResultCode != SQLITE_OK)
          {
            #ifdef DEBUG
              Serial.printf("writeWcTotalToDb(): sqlite3_reset(res) result code = [%s] %s\n", sqliteResultCode, sqlite3_errmsg(sqliteDb));
            #endif
          }else
          {
            #ifdef DEBUG
              Serial.print("writeWcTotalToDb(): sqlite3_reset(res) OK\n");
            #endif
          }
          sqlite3_finalize(sqliteRes);
      }
    }
    closeDb();
  }else
  {
    #ifdef DEBUG
      Serial.println("writeWcTotalToDb(): Failed to open database!");
    #endif
  }
  #ifdef DEBUG_WRITE
    Serial.printf("writeWcTotalToDb(%s): finished!\n", wc->display_name);
  #endif
} /* writeWcTotalToDb() */

```

# Answer
> 1 votes
As @Majenko suggested, i created solution with pulse counter.

Here is working code, based on espressif PCNT Example. Arduino studio, Olimex ESP32-POE board.

Each water meter uses separate pulse counter unit. Now I am testing this code and after several days i will accept answer if all works like i want :)

```
#include "freertos/queue.h"
#include "driver/pcnt.h"
#include "driver/periph_ctrl.h"
#include "driver/gpio.h"
#include "esp_attr.h"

#define PCNT_H_LIM_VAL      1
#define PCNT_L_LIM_VAL     -1
#define PCNT_THRESH1_VAL    0
#define PCNT_THRESH0_VAL   -0
#define PCNT_INPUT_SIG_WC_HOT   32 // hot water counter
#define PCNT_INPUT_SIG_WC_COLD  33 // cold water counter
/*
Cold meter uses PCNT_UNIT_1
hot meter uses PCNT_UNIT_0
*/
xQueueHandle pcnt_evt_queue;   // A queue to handle pulse counter events
pcnt_isr_handle_t user_isr_handle = NULL; //user's ISR service handle

/* A sample structure to pass events from the PCNT
 * interrupt handler to the main program.
 */
typedef struct {
    pcnt_unit_t unit;  // the PCNT unit that originated an interrupt
    uint32_t status; // information on the event type that caused the interrupt
} pcnt_evt_t;

/* Decode what PCNT's unit originated an interrupt
 * and pass this information together with the event type
 * the main program using a queue.
 */
static void IRAM_ATTR pcnt_example_intr_handler(void *arg)
{
    uint32_t intr_status = PCNT.int_st.val;
    int i;
    pcnt_evt_t evt;
    portBASE_TYPE HPTaskAwoken = pdFALSE;

    for (i = 0; i < PCNT_UNIT_MAX; i++) {
        if (intr_status & (BIT(i))) {
            evt.unit = (pcnt_unit_t)i;
            /* Save the PCNT event type that caused an interrupt
               to pass it to the main program */
            evt.status = PCNT.status_unit[i].val;
            PCNT.int_clr.val = BIT(i);
            xQueueSendFromISR(pcnt_evt_queue, &evt, &HPTaskAwoken);
            if (HPTaskAwoken == pdTRUE) {
                portYIELD_FROM_ISR();
            }
        }
    }
}

/* Initialize PCNT functions:
 *  - configure and initialize PCNT
 *  - set up the input filter
 *  - set up the counter events to watch
 */
static void pcnt_example_init()
{
    //Serial.printf("pcnt_example_init(%d, %d)\n", _unit, _pin);
    /* Prepare configuration for the PCNT unit */
    pcnt_config_t pcnt_config = {};
    pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_WC_HOT;
    pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
    pcnt_config.channel = PCNT_CHANNEL_0;
    pcnt_config.pos_mode = PCNT_COUNT_INC;
    pcnt_config.neg_mode = PCNT_COUNT_DIS;
    pcnt_config.lctrl_mode = PCNT_MODE_KEEP;//PCNT_MODE_REVERSE;
    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
    pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
    pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
    pcnt_config.unit = PCNT_UNIT_0;

    /* Initialize PCNT unit */
    ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));

    /* cold water meter */
    pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_WC_COLD;
    pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
    pcnt_config.channel = PCNT_CHANNEL_0;
    pcnt_config.pos_mode = PCNT_COUNT_INC;
    pcnt_config.neg_mode = PCNT_COUNT_DIS;
    pcnt_config.lctrl_mode = PCNT_MODE_KEEP;//PCNT_MODE_REVERSE;
    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
    pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
    pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
    pcnt_config.unit = PCNT_UNIT_1;
    ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));

    /* Configure and enable the input filter */
    ESP_ERROR_CHECK(pcnt_set_filter_value(PCNT_UNIT_0, 1000)); // filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
    ESP_ERROR_CHECK(pcnt_filter_enable(PCNT_UNIT_0));

    /* Set threshold 0 and 1 values and enable events to watch */
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1));
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
    /* Enable events on zero, maximum and minimum limit values */
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_ZERO));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_L_LIM));

    /* Initialize PCNT's counter */
    ESP_ERROR_CHECK(pcnt_counter_pause(PCNT_UNIT_0));
    ESP_ERROR_CHECK(pcnt_counter_clear(PCNT_UNIT_0));

    /* Register ISR handler and enable interrupts for PCNT unit */
    ESP_ERROR_CHECK(pcnt_isr_register(pcnt_example_intr_handler, NULL, 0, &user_isr_handle));
    ESP_ERROR_CHECK(pcnt_intr_enable(PCNT_UNIT_0));

    /* Everything is set up, now go to counting */
    ESP_ERROR_CHECK(pcnt_counter_resume(PCNT_UNIT_0));

    /* PCNT_UNIT_1 configuration  */
    /* Configure and enable the input filter */
    ESP_ERROR_CHECK(pcnt_set_filter_value(PCNT_UNIT_1, 1000)); // filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
    ESP_ERROR_CHECK(pcnt_filter_enable(PCNT_UNIT_1));

    /* Set threshold 0 and 1 values and enable events to watch */
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_1, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_THRES_1));
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_1, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_THRES_0));
    /* Enable events on zero, maximum and minimum limit values */
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_ZERO));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_H_LIM));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_L_LIM));

    /* Initialize PCNT's counter */
    ESP_ERROR_CHECK(pcnt_counter_pause(PCNT_UNIT_1));
    ESP_ERROR_CHECK(pcnt_counter_clear(PCNT_UNIT_1));

    ESP_ERROR_CHECK(pcnt_intr_enable(PCNT_UNIT_1));

    /* Everything is set up, now go to counting */
    ESP_ERROR_CHECK(pcnt_counter_resume(PCNT_UNIT_1));
}

void setup() {
  Serial.begin(115200);
  Serial.println("Boot...");
  // put your setup code here, to run once:
  pinMode(PCNT_INPUT_SIG_WC_HOT, INPUT_PULLUP);
  pinMode(PCNT_INPUT_SIG_WC_COLD, INPUT_PULLUP);
  /* Initialize PCNT event queue and PCNT functions */
  pcnt_evt_queue = xQueueCreate(10, sizeof(pcnt_evt_t));

  pcnt_example_init();
  //  pcnt_example_init(PCNT_UNIT_WC_HOT, PCNT_INPUT_SIG_WC_HOT);
    //pcnt_example_init(PCNT_UNIT_WC_COLD, PCNT_INPUT_SIG_WC_COLD);

    Serial.printf("Setup done\n");
}

int16_t count = 0;
pcnt_evt_t evt;
portBASE_TYPE res;

char * chToName(int ch)
{
  if (ch == 1) return "Cold";
  if (ch == 0) return "Hot";

  return "Unc";
}

void loop() {
  // put your main code here, to run repeatedly:
      /* Wait for the event information passed from PCNT's interrupt handler.
         * Once received, decode the event type and print it on the serial monitor.
         */
        res = xQueueReceive(pcnt_evt_queue, &evt, 1000 / portTICK_PERIOD_MS);
        if (res == pdTRUE) {
            pcnt_get_counter_value(evt.unit, &count);
            Serial.printf("Event PCNT unit[%d=%s]; cnt: %d, status: %d\n", evt.unit, chToName(evt.unit), count, evt.status);
            if (evt.status & PCNT_EVT_THRES_1) {
                Serial.printf("THRES1 EVT\n");
            }
            if (evt.status & PCNT_EVT_THRES_0) {
                Serial.printf("THRES0 EVT\n");
            }
            if (evt.status & PCNT_EVT_L_LIM) {
                Serial.printf("L_LIM EVT\n");
            }
            if (evt.status & PCNT_EVT_H_LIM) {
                Serial.printf("H_LIM EVT\n");
            }
            if (evt.status & PCNT_EVT_ZERO) {
                Serial.printf("ZERO EVT\n");
                // here we are increment liter count
            }
        } else {
            pcnt_get_counter_value(PCNT_UNIT_0, &count);
            Serial.printf("Current counter value: %s=%d,", chToName(PCNT_UNIT_0), count);
            pcnt_get_counter_value(PCNT_UNIT_1, &count);
            Serial.printf(" %s=%d\n", chToName(PCNT_UNIT_1), count);
            //pcnt_get_counter_value(PCNT_UNIT_WC_COLD, &count);
            //Serial.printf(", %d on unit: %d\n", count, PCNT_UNIT_WC_COLD);
        }

        /*
        if(user_isr_handle) {
          Serial.printf("Clearing user_isr_handle\n");
          //Free the ISR service handle.
          esp_intr_free(user_isr_handle);
          user_isr_handle = NULL;
        }*/
}

```

# Answer
> 0 votes
You can use Pulse Counter(PCNT) feature in ESP32 to count the number of pulse in background, Its also possible to configure event when number of counts reached certain threshold and had lot of options,

For get information and available Interfaces and API's for Pulse Counter(PCNT) please follow below link, https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/pcnt.html

> Initially I faced lot of issue to make **Pulse Counter(PCNT)** work in Adrino IDE for ESP-32, After multiple attempt I make it working, And same sample code is uploaded in GitHub for reference. I have not use all the API's in the official documentation but but used few of them and are working..

I have created a simple sample program for a water flow meter, there also we use to get pulse which needs to count to measure the water flow rate.

GitHub Sample code Path:- https://github.com/Embedded-Linux-Developement/Arduino\_Sample\_Programs/tree/main/ESP\_32/Water\_Flow\_Pulse\_counter\_WithOut\_Interrupt\_Using\_PCNT

I have not placing the code here, because its there in GitHub and a simile one and can use it. Its a working code I tested in ESP32 HW.

*Hopes Its helpful, Regards, Jerry James*

---
Tags: arduino-ide, interrupt, esp32
---


title: 9x servo on Arduino Nano?

text:
# Question
Title: 9x servo on Arduino Nano?
I saw this project with multiple servos: In Servo We Trust! Let's control 135 servos with a single Arduino! I wanted to miniaturize this project.

BUT instead of triangles i will use SQUARES.

:EDIT: summing UP

For now project stops, not forever. I bought 9 servos on aliexpress and im waiting for them to be delivered. Also, im making a 3D project in AutoDesk Maya 2018, planning and will sbow you the results soon how im gonna make it work. I was thinking about adding 1 more servo and hc sr06 distance sensor. I was thinking about the sensor will detect person, servos and mirrors will also follow the person. But idk if im gonna make it to the final project.

* I bought arduino nano that will be powered from the battery
* All servos will be powered with electricity from the wall 5V 5A.The servos wont be on heavy load so it will be enough i think.If any problem occurs I will use 10A.

ALSO SORRY for not editing this POST earlier.

I would like to thank everybody for giving me such a great advices, I will post my AutoDesk project soon.

# Answer
> 2 votes
> I'm afraid that with PWM controler I won't be able to do that.

Chances are that any PWM controller is going to let you control each output independently.

According the the servo library documentation, the library can handle up to 12 servos on a single Arduino, so your project should be feasible. It will however reduce the number of PWM pins available from 6 down to 4.

> Will a 9V battery power all these servos?

No! Not a chance.

Typical 9g servos consume 150 mA without any load, and stall at ~700-900 mA. A typical 9v has ~500 mAh capacity, and most data sheets show loads of ~100-150 mA max. Your 9v might be able to supply a few amps for a few seconds before they heat up and slow down.

If your load is very light 9 servos will consume ~900 mA; an ideal 9v would last at most 30 min with this load, but real batteries aren't ideal and will heat up and loose efficiency.

Near maximum load your 9 servos will draw ~7000-9000 mA, well beyond the capabilities of a 9v. However those numbers are for 5v so you could cut them all in half.

If you used an appropriate 5v step-down DC-DC supply you might be able to power all 9 servos for a few seconds before the batter overheats and gives up.

If you powered them directly, the servos will have to dissipate more heat, and will draw extra power, could damage the servos if the batter could supply enough juice.

# Answer
> 2 votes
Here are the specifications of the SG90 (from FEETECH (Fitec) FS90 9G Mini Servo with Accessories)

>

The FG90 is similar in specification to the SG90. From the website:

> The FS90 is a 9 g analog servo from FEETECH (formerly known as Fitec) which is similar in form and function to the Towerpro SG90. The specifications state that this servo has a 120° operating angle for standard servo pulses between 900 µs and 2100 µs. As with most servos, the pulse range can be expanded to achieve an expanded operating angle, but the limits of which are not specified by FEETECH.

From this answer to Power supply circuit for powering SG90 servo. How to handle high current requirements?, lets assume each servo (best case) needs 250 mA, as you state that the load per servo is relatively low.

Let's say that the Nano requires 280 mA, see this answer to What is the maximum power consumption of the Arduino Nano 3.0?

Using a single 5V supply to power both servos and Arduino. The current rating needs to need at least:

```
I = (9 x 0.25) + 0.28
I = 2.53 A

```

Or power rated

```
P = I x V = 2.53 x 5
P = 12.65 W

```

You probably want more than that, so get a 5 V 5 A supply to be on the safe side. So, no, a battery will not suffice.

# Answer
> 1 votes
You can drive upto 20 servos on an Arduino Nano - here's the EXCELLENT software for this: http://www.lamja.com/?p=504

Most servos can run well using high voltages (e.g. 9v) while still accepting PWM signals much lower (e.g. 3.3v) - here's a video showing that working fine: https://youtu.be/9ZCiQgjcx3k

See Greenonline's answer table (or servo datasheets) to work out your power budget. 9v will work, but is probably more than the servos would like: 6v is more usual.

# Answer
> 0 votes
Cheapest way is that you should buy couple of LM7805 wire it in parallel now power arduino and other servos from this 7805. Connect pwm pins of servos to the nano.

Voltage regulator built inside arduino cant provide much current to all servos.

Also connect ground of all of your power sources together.

# Answer
> 0 votes
Servos don't use PWM, not really. What they need is a pulse that is ~ 1mS wide every 20mS (50 Hz) to turn full one direction, ~ 1.5mS wide to be centered, and about 2mS wide to turn fully the other direction. Or centered, +/- ~ 60-75 degrees or so.

(0.9mS to 2.1mS per the data above).

---
Tags: arduino-nano, servo
---


title: Mounting an Arduino inside a PC

text:
# Question
Title: Mounting an Arduino inside a PC
I want to mount an Arduino Pro Micro inside my PC, hooked up to the PC's USB.

I don't want to have external cables for this, but have it neatly cabled inside.

My motherboard has USB connectors with 9 pins (5+5 grid, 10th pin key), like these:

These connectors would take a cable that looks like this:

But how would I connect this to the Arduino that has Micro USB?

I've been looking everywhere, but 9-pin USB to USB Micro does not seem to exist?

The closest I could find is a cable that goes from USB micro to a 5-pin header:

What is the preferred way to hook up an Arduino Micro with internal cabling?

Why does the 9-pin to USB-micro not exist?

# Answer
> 4 votes
@Bram, @jsotola is highlighting in the comments that the example photo you show with a 9 pin keyed two row connector has two usb cables connecting to it. USB connections often have four wires each. The standard wire color coding is:

(Source Wikipedia - USB)

Board manufacturers are often looking for a simple way to connect multiple panel mount USB ports to the PCB and this could have been a cheap and convenient way to connect two USB ports per pcb connector.

Some suggestions:

* Research the specific motherboard online to see if a schematic or connector layout is available. It’s quite likely to be laid out like this:

* Experiment by making your own connector, and use a multimeter to figure out which are the power and which are the data wires.
* If the old USB ports which used to connect to the PCB are still available, investigate further until you’re more confident about how they were wired.
* An adapter may help you experiment further to understand the PCB connections further.

---
Tags: power, usb, arduino-pro-micro
---


# Question
Title: Can I power arduino uno R3 with 9v battery through Vin?
I want to power up arduino through Vin port , what should be the input voltage ?

# Answer
> 1 votes
About 7.5V to 9V is best. A 9V battery is often not capable to supply enough current for an Arduino. Do you have a multimeter to measure the battery voltage drop when the Arduino is connected ?

# Answer
> -1 votes
Are you really sure? I must search for mine, but what i remember, that over the pins.... ok I looked, sry, Jot was right :D... on the Input Pins, you find three kinds right? 3.3, 5 an Vin, which will be a range of V for sure ;)

---
Tags: arduino-uno
---


title: Leonardo with hm-10 doesn't work

text:
# Question
Title: Leonardo with hm-10 doesn't work
I have a hm-10 module attached to Arduino Leonardo board, I'm using a bluetooth terminal app to send some text.

The problem is I can send data from the Serial monitor to my phone but when I send from my phone, there is no output in the serial monitor.

It works fine if I test it on Arduino Uno. I'm struggling with something that should be simple.

Can someone please help me?

Here is my code:-

```
#include <SoftwareSerial.h>

SoftwareSerial BTSerial(4, 5);

void setup(){
  Serial.begin(115200);
  Serial.println("Hello!");
  BTSerial.begin(115200);
}

void loop(){
  while (BTSerial.available()){
    byte data = BTSerial.read();
    Serial.write(data);
  }

  while (Serial.available()){
    byte data = Serial.read();
    BTSerial.write(data);
  }
}

```

# Answer
I GOT IT!! It was problem with the pin settings.

According to SoftwareSerial library documentation, only pins 8,9,10,11,14,15,16 can be used for RX pin. But i used pin 4 for RX.
> 1 votes

---
Tags: arduino-leonardo, ble
---


# Question
Title: how to detect when a transmitter is turned off?
Using the nrf24l01 wireless module I want to control a led with the sketch below. The transmitter automatically sends data at intervals of one second continuously and when the receiver counter reaches 2, it turns on the LED at the desired time and then turns it off. but what I want is when I turn off the power of the transmitter when 2 counts are detected from the transmitter, the led does not light up.

I want to turn the led on and off when I turn off the power of the transmitter after sending 2 signals from the transmitter.

Thank you for all the information you provide.

```
#include "nRF24L01.h"
#include "RF24.h"
#include "SPI.h"
int ReceivedMessage[1] = {000}; //  NRF24L01 tarafından alınan değeri saklamak için kullanılır
RF24 radio(3, 4); //  NRF24L01 SPI pimleri. uno'daki Pin 8 ve 9
const uint64_t pipe = 0xE6E6E6E6E6E6; // 2 NRF24L01 arasındaki iletişim için aynı olması gerekir

int led = A7;

bool flag = false;
bool ledflag  = false;
unsigned long  previous1 = 0;
unsigned long  interval1 = 5000;

unsigned long  previous2 = 0;
unsigned long  interval2  = 2000;
int button1PushCounter = 0;

void setup () {

  radio.begin(); // NRF24L01'i başlatın

  radio.openReadingPipe(1, pipe); // NRF24L01'i almaya hazır hale getirin

  radio.startListening(); // Bilginin alınıp alınmadığını görmek için dinleyin

  Serial.begin(9600);

  pinMode(led, OUTPUT);

}

void loop () {

  unsigned long currentmillis = millis();
  while (radio.available())
  {
    radio.read(ReceivedMessage, 1); // NRF24L01'den bilgileri okuyun

    if (ReceivedMessage [0] == 111) //  switch'e basıldığını gösterir
    {

      button1PushCounter++;
      Serial.println( button1PushCounter);
      delay(700);
    }

    if ( button1PushCounter == 2) {

      flag = true;
      previous1 =  currentmillis;

    }

    if ( flag ) {
      if (currentmillis - previous1 >= interval1  ) {

        digitalWrite(led, HIGH);
        ledflag  = true;
        previous2 =  currentmillis;
        flag = false;
        button1PushCounter = 0;
      }
    }

    if ( ledflag && (currentmillis - previous2 >= interval2  )) {
      digitalWrite(led,  LOW);
      ledflag  = false;

    }
  }
}

```

# Answer
> 1 votes
I found solution as below:-

```
if ( button1PushCounter == 3 ) {

  for (int i = 0; i < 5; i++)
  {
    delay(1000);
    Serial.println(i);
    a = HIGH;
  }
}

if ( a == HIGH ) {

  digitalWrite(led, HIGH);
  delay(1000);
  digitalWrite(led,  LOW);
  a = LOW;
  button1PushCounter = 0;
}

```

---
Tags: arduino-uno, led, nrf24l01+, wireless
---


title: Convert String to const unsigned char

text:
# Question
Title: Convert String to const unsigned char
```
String abc ="0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff";

const unsigned char displaydata={reinterpret_cast<const unsigned char*>(abc.c_str())};

display.drawBitmap(displaydata, startX, startY, bmpWidth, bmpHeight, GxEPD_WHITE);

```

**Get error: invalid conversion from 'const unsigned char' to 'unsigned char' \[-fpermissive\]***

**When I write like this**

```
String abc ="0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff";

display.drawBitmap(reinterpret_cast<const unsigned char*>(abc.c_str()), startX, startY, bmpWidth, bmpHeight, GxEPD_WHITE);

```

**No error but black screen no display image**

**When I write like this**

```
const unsigned char displaydata[]={ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

display.drawBitmap(displaydata, startX, startY, bmpWidth, bmpHeight, GxEPD_WHITE);

```

**It is working**

The string data coming from the server is returning to me as stirng, I am trying to reflect it on the screen. I want to convert a string data to const unsigned char with code

So I'm trying to convert

# Answer
> 1 votes
That string is literally the characters 0xff ... while the array is the bytes 0xff...

Where the string contains 4 bytes to say 0,x,f,f (followed by comma and space) the array will have 1 byte the 255 (and no need for a comma or space to delimit).

If you are looking to convert the text hex string to bytes, look at a combination of How to convert an hex string to an array of bytes? and looping through the string.

---
Tags: esp32, display
---


title: ESP32-CAM, Failed to connect to ESP32

text:
# Question
Title: ESP32-CAM, Failed to connect to ESP32
I am trying my ESP32-CAM for project but I am having problems with uploading script/code to the ESP. I am using CP2102 to connect ESP and my laptop. I tried connecting it to 3.3V and even 5V but none seem to be working as I always get the same error: "A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header"

# Answer
> 1 votes
For future references.

So after some time I was finally able to upload my code into ESP32-CAM. I don't know if I had just bad luck with "faulty" ESP but here is what helped me.

1. Don't use CP2102, it just doesn't work for me, use other programmer or Arduino as I did.
2. If you have been using scheme like this scheme and wasn't able to fix your problem try to connect all other things that need GND on some breadboard and use just one GND pin from ESP. I noticed that GNDs on ESP has (or atleast mine have ) 0.5V difference between them. Right now I am using the GND pin that was connected to IO0 as "main" GND and its works.

Hope this helps someone and thanks for all replies.

---
Tags: esp32
---


title: Why the unsigned long is overflowing?

text:
# Question
Title: Why the unsigned long is overflowing?
I want to convert hour to seconds but unsigned long is overflowing, here's the code:

```
#include <Wire.h>
#include <DS3231.h>

RTClib myRTC;
unsigned long seconds;
char timestr[9];

void setup() {
  Serial.begin(250000);
  Wire.begin();
}

void loop() {
  DateTime now = myRTC.now();

  snprintf(timestr, 9, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
  seconds = (now.hour() * 3600);
  Serial.println(timestr);
  Serial.println(seconds);
  delay(100);
}

```

And the console output is:

```
16:33:36
4294959360

```

Why is this happening?

# Answer
> 5 votes
It's not the unsigned long that's overflowing but the calculation that you're assigning to it.

3600 is a signed integer (by default), and `now.hour()` is an unsigned byte. The unsigned byte gets promoted to match the "largest" type in the calculation - a signed integer - and then the calculation is performed, resulting in a signed integer.

That signed integer is then assigned to an unsigned long and, if the result is negative (as it may well be - 10\*3600 \> 32767) you end up with a massive number.

The simple "cure" is to ensure that one value in the calculation is an unsigned long. And the best way of doing that is to make your constant an unsigned long: by appending "UL" to it:

```
seconds = (now.hour() * 3600UL);

```

---
Tags: arduino-uno, rtc, ds3231-alarms
---


title: ESP32 AP Automatic Web Page

text:
# Question
Title: ESP32 AP Automatic Web Page
I've often encountered WiFi networks that require you to sign in through a web page that automatically opens after connecting to the access point, such as hotels. I'd like to implement something similar with an ESP32, where a web page opens automatically after connecting to the AP. Is this doable? This seems to be difficult to Google, because I just get a bunch of introductory tutorials on setting up an AP.

Here's some project context in case it helps. I'm making an IoT device that needs to connect to the user's WiFi network, so the user needs to specify the login credentials. The solution I'm trying to implement is having the ESP32 set up a temporary AP, where the user can connect to that and enter their home WiFi credentials. As it stands now, the user has to manually type in the IP address of the ESP32 after connecting to the AP, but it'd be much more user friendly if the web page opened automatically like hotel WiFi networks sometimes do.

I've tinkered with this WiFi Manager library that appears to do what I want, but I'd like to implement mine from scratch.

# Answer
> 4 votes
Of course, as soon as I linked that WiFi Manager library in my question, I figured it out. The term I was missing was "captive portal" and I was able to figure it out from there. But I decided to post the question anyways, since it might help someone else stuck in the same situation.

Here's my understanding of how it works: when your device connects to a new network, it tries to ping a server to see whether it has internet access. With the ESP32, you can set up a DNS that redirects that ping to a web server running on the ESP32, which opens up the browser on the device.

I found this tutorial helpful for me to understand how that works, along with example code. This should be enough for me to get it working.

https://iotespresso.com/create-captive-portal-using-esp32/

---
Tags: arduino-ide, wifi, esp32, web-server, softap
---


# Question
Title: Arduino Micro just blinks, won't connect to PC
*Edit - Sorry it's a **Micro** not a Nano*

I have a Micro board hooked up to an EasyDriver breakout using its 5V output to power the Micro.

Today I plugged it in and instead of booting up like normal the power LEDs on the wall plug, the easy driver, and the Arduino started flashing. The Micro became very hot, but not hot enough to burn.

After that if I plug the Micro into the USB port it just rapidly blinks the pin 13 LED. The PC does not detect the device but it does receive power.

Holding or pushing the reset button doesn't seem to help at all. I've used different USB cables, and different ports on the PC as well to no effect.

Is this something it can recover from? Why did all the LEDs blink like that?

# Answer
> 2 votes
I have had a similar problem, on a Pro Micro, and the PC, in the end, could not see it, and it would not show up in Device Manager. It was, to all intents and purposes, bricked.

---

It could be just a question of timing the double resetting of the Micro correctly, in order to enter bootloader mode, see Pro Micro & Fio V3 Hookup Guide - Troubleshooting and FAQ - Reset to Bootloader:

While the Micro is in Bootloader mode, you should see it appear in Device Manager like so:

While it is temporarily in this bootloader mode, you should be able to upload a new sketch.

---

However, this did not work for me and I ended up having to burn the bootloader again, via ISP, using either a USBasp or an Arduino Uno configured as an ISP.

After a number of attempts the apparently bricked Pro Micro showed up again in Device Manager, and became fully functional:

After that, all that was required was to install the correct Windows drivers, to get rid of the yellow warning icon. From Pro Micro & Fio V3 Hookup Guide – Installing: Windows, obtain the zip file *Arduino\_Boards-Master.zip*. Then selecting the Pro Micro in Windows Device Manager, right click and “Update Driver Software”, following these instructions, from the link:

> Unzip that zip file, and don’t forget where you’ve left its contents. In that zip file, you should find an INF file, which contains all the information Windows needs to install the Pro Micro’s driver. This sparkfun.inf will be found in Arduino\_Boards-master → sparkfun → avr → signed\_driver.

Once the driver was installed, then the Pro Micro should appear correctly in Device Manager

If you haven't already done so, add the following URL to the Board Manager line in the Preferences dialog in the Arduino IDE:

```
https://raw.githubusercontent.com/sparkfun/Arduino_Boards/master/IDE_Board_Manager/package_sparkfun_index.json

```

Then opening the “Board Manager…” in the Tools/Boards menu, search for the “SparkFun AVR Boards” package and install it.

---

I have written two lengthy blogs about the whole experience:

# Answer
> 0 votes
I have something similar happen a couple of times with some atmega328s (on arduino unos). I believe it was the bootloader that some how became corrupted and so no longer responded to the computer. The only way to fix this is to reflash the bootloader using an ISP programmer. Luckily the arduino can act as an ISP programmer so all you need is another working arduino.

See https://www.arduino.cc/en/Tutorial/ArduinoISP for how to do this on an uno. The same can be done with the micro/nano as they all use the same atmega328p chip its just a matter of wiring it up correctly.

If you cannot reflash the bootloader with this method then one of the chips is probably damaged and would need to be replaced. At this point it might be easier to replace the whole board.

# Answer
> 0 votes
I've had the same problem. I fixed it through a series of resets (removing the serial cable and plugging it in again), and punching 'make upload' a few times. Eventually it accepted my upload. The problem was an invalid code upload, which caused the Arduino to reset QUICKLY after booting. As an alternative, had this not worked, I would have blanked the chip with a USBtinyISP - it will hook up easily to your Arduino.

# Answer
> 0 votes
I had similar problem to Yours. Actually I tried to run my program in Clion IDE and then something broke in Arduino. I connected my Arduino Leonardo to my second PC clicked 2 times reset button and while the Bootloader COM appeared i fastly ran blink program. (What is important that it wasnt one trial to run this blink program so i recommend to do it 5-10times if it doesnt work).

---
Tags: arduino-nano
---


title: How can I make my code Thread-Safe?

text:
# Question
Title: How can I make my code Thread-Safe?
So I made a post yesterday running into an issue on my ESP32 using both cores on the microcontroller (with wifi enabled, incase that is important).

I'm using both cores to control two Neopixel strips individually. I'm making a music visualizer, and I want the neopixels to react to the change in music as quickly as possible, so I felt like having one for every individual core was the best way for that to happen. The issue I am running into is that when audio is playing, the Music Visualizer function either in the primary core (Core 1), or secondary core (Core 0) will just completely freeze. I tried troubleshooting with some Serial.Print statements to understand where the code breaks, and it seems to happen around the **setPixelColor** command. I think my code is being thread locked, and I wanted to know what I could do to make it thread safe.

```
void musicVisualizer(void) {
  middle_strip.clear();
  upper_strip.clear();

  middle_strip.show();
  upper_strip.show();

  // Add code to tell Core 0 to wait until LED's are cleared.
  while (vu_meter) {
    tweeter_prev = tweeter;
    if (analogRead(tweeter_sample) <= 490)
      tweeter_adc = 0;
    else {
      tweeter_adc = (analogRead(tweeter_sample) - 490);
      if (tweeter_adc < 0)
        tweeter_adc = 0; // Filter for changing reference voltage
      else if (tweeter_adc > MIDDLE_LED_COUNT)
        tweeter_adc = tweeter_prev; // Filter for if there are intermittent spikes in the adc
    }
    tweeter_filter.Filter(tweeter_adc);
    tweeter = tweeter_filter.Current() * 6;  // 6 scaler is for when Alexa is at Volume Level 4

    //    /* Changing LED Number to improve efficency when turning on LED's */
    //    if (tweeter > 43)
    //      LED_COUNT = 65;
    //    else if (tweeter > 21)
    //      LED_COUNT = 43;
    //    else if (tweeter <= 21)
    //      LED_COUNT = 21;

    /* LED's turning on and off in response to audio */
    if ((tweeter > tweeter_prev) && (tweeter <= MIDDLE_LED_COUNT)) {
      for (int x = tweeter_prev; x < tweeter; x++) {
        //        middle_strip.setPixelColor(x, color);
        middle_strip.setPixelColor(x, 0, 0, middle_strip.gamma32(brightness));
        middle_strip.show();
      }
    }
    else if (tweeter_prev > tweeter) {
      for (int x = tweeter_prev; x >= tweeter; x--) {
        middle_strip.setPixelColor(x, 0, 0, 0);
        middle_strip.show();
      }
    }
  }

  /* Leaving VU Meter, returning to current lamp color set */
  if (led_on) {
    if (!color_white) {
      for (int i = 0; i < LOWER_LED_COUNT; i++) {
        lower_strip.setPixelColor(i, color);
        lower_strip.show();
      }
      for (int i = 0; i < MIDDLE_LED_COUNT; i++) {
        middle_strip.setPixelColor(i, color);
        middle_strip.show();
      }
      for (int i = 0; i < UPPER_LED_COUNT; i++) {
        upper_strip.setPixelColor(i, color);
        upper_strip.show();
      }
    }
    else {
      for (int i = 0; i < LOWER_LED_COUNT; i++) {
        lower_strip.setPixelColor(i, 0, 0, 0, lower_strip.gamma32(brightness));
        lower_strip.show();
      }
      for (int i = 0; i < MIDDLE_LED_COUNT; i++) {
        middle_strip.setPixelColor(i, 0, 0, 0, middle_strip.gamma32(brightness));
        middle_strip.show();
      }
      for (int i = 0; i < UPPER_LED_COUNT; i++) {
        upper_strip.setPixelColor(i, 0, 0, 0, upper_strip.gamma32(brightness));
        upper_strip.show();
      }
    }
  }
  else {
    upper_strip.clear();
    middle_strip.clear();
    lower_strip.clear();

    upper_strip.show();
    middle_strip.show();
    lower_strip.show();
  }
}

void vu_meter_sub(void * parameter) {
  while (true) {
    esp_task_wdt_init(30, false);
    if (vu_meter) {
      lower_strip.clear();
      lower_strip.show();
      while (vu_meter) {
        sub_prev = sub;
        sub_adc = analogRead(sub_sample);
        if (sub_adc > LOWER_LED_COUNT)
          sub_adc = LOWER_LED_COUNT-1;
        sub_filter.Filter(sub_adc);
        sub = sub_filter.Current();
        //        if (sub < 0)
        //          sub = 0;
        Serial.println(sub);
        if ((sub > sub_prev) && (sub <= LOWER_LED_COUNT)) {
          for (int x = sub_prev; x < sub; x++) {
            //            lower_strip.setPixelColor(x, color);
            lower_strip.setPixelColor(x, 0, lower_strip.gamma32(brightness), 0);
            lower_strip.show();
          }
        }
        else if (sub_prev > sub) {
          for (int x = sub_prev; x >= sub; x--) {
            lower_strip.setPixelColor(x, 0, 0, 0);
            lower_strip.show();
          }
        }
        Blynk.run();
      }
    }
  }
}

```

# Answer
I am not sure this is related to thread-safety, but you should be aware that `strip.show()` is a slow function that blocks while the data is being sent. `setPixelColor()`, in contrast, is fast, as it only updates the data in memory.

I suggest you modify `musicVisualizer()` in such a way that it only `show()`s each strip once. The bulk of the function should be about computing the colors you want and setting them with `setPixelColor()`. Then, at the very end of the function, `show()` the three strips.
> 1 votes

---
Tags: arduino-ide, esp32, neopixel, threads
---


# Question
Title: Measure voltage in 14 points 0 - 60 volts (14s LiPo battery) with single ADC
I wish to measure 14S battery voltage on each cell with single ADC. I guess I need some ADC built-in or external (I2C), voltage divider and switch chip that will allow me to select one of 14 pins to measure.

Am I correct?

Could you advice what switch chip should I use?

or Should I build that curtuit myself with 2 74HC595 and mosfets? (not sure if that will ever work)

# Answer
> 2 votes
I would do it manually (but then I am a bit sadistic like that).

The circuit for one cell is pretty simple, and you just need to replicate it 14 times. A P+N pair of MOSFETs to switch a battery channel on and off, and a pair of resistors to make a voltage divider. You can keep the "lower" of the resistors common between all channels if you like to reduce the number of components and complexity, but once you have 14 channels the complexity will become pretty silly anyway. Here's an example with just 3 channels:

simulate this circuit – Schematic created using CircuitLab

You would need to size RA|RL, RB|RL and RC|RL (etc) accordingly to get the right voltage ranges for the ADC input, and keep the output impedance low enough (\<10k) for the ADC to handle it properly. You may want a couple of different load resistors (RL) for different groups of cells.

All the N-channel MOSFETs could be replaced by a 4-to-16 decoder with open-collector outputs (such as, if you can get it, the 74xx159), which would also protect against switching on multiple channels at once, which you *never* want to do.

Note that this arrangement gives you the voltage of the first cell, the voltage of the first two cells, the voltage of the first three cells, etc. To get the voltage of just the third cell (for example) you will need to subtract the voltage of the lower cells.

---
Tags: voltage
---


title: How to power ESP32 with 230V AC

text:
# Question
Title: How to power ESP32 with 230V AC
I want to power ESP32 with 230V AC and I don’t know how to do it. The requirement is that it must never overheat. What components should i use? The ESP will be in small space with no airflow. Will it be even possible?

# Answer
> 3 votes
The folks over at Random Nerd Tutorials offer a solution for this exact scenario using a HLK-PM03 Hi-Link 100-240V AC to 3.3V 1A DC converter. They add electrical and thermal fuses to mitigate some of the possible failure modes of over-temperature or over-current.

The specifications of the HLK-PM03 are here. I suspect there will be a few alternatives available that do a similar function.

My suggestion is to be hyper-aware of the safety issues of dealing with mains power, and to be realistic about your own capabilities.

---
Tags: power, esp32, heat
---


# Question
Title: ov2640 with 18 pin and no arducam shield
I bought this ov2640 camera module with 18 pins and I don't have shield to insert it to. I am looking for a library or working code on this my camera sensor but all I kept getting was arducam examples or at most ov7670 example code. Can anybody help me out here? The image of the module is at this link https://i.stack.imgur.com/tUVg0.jpg

PS: I am using an arduino due

(Edit: Added image of camera module)

# Answer
There is a datasheet for the module at https://www.mpja.com/download/35647mpdata.pdf

It references the Arducam library at https://github.com/ArduCAM/Arduino/tree/master/ArduCAM.

The library specifically supports this camera type. By studying the camera specific code you may get a better idea of what is required. To connect the module directly to a Due, the work that was designed to be done by the intended shield would need to be replicated. Which seems non-trivial.
> -1 votes

---
Tags: arduino-due, camera
---


# Question
Title: NodeMCU with a 5V latching relay - LOW triggers relay
I am going to connect NodeMCU to a latching relay board like tis one (4 channel version): LINK

Both MCU board and relay board will be powered from the same 5V voltage regulator.

Now I have two problems to solve:

**Problem 1** \- logic levels

NodeMCU logic level is 3.3V and relays board works in 5V levels. I can either use logic level converters or simple transoptors. Because I am going to attach NodeMCU to a custom PCB, I think transoptors will be simpler to solder.

**Problem 2** \- relay triggers with low pulse on the control pin

This relay boards works like this: every time the channel pin (T1 - T4) is connected to ground for few miliseconds - the relay flips to other state. Here is the question: **when the MCU board resets/reboots on power cycle, how do I ensure that the control pins are HIGH from the beginning?** If they are not, the relay can flip randomly before my program starts and I will not know the initial state of relay.

What would be the best approch here ?

# Answer
Since ports commonly are configured as inputs at reset, you will need to add a pull-up resistor.

Then write your setup so that the pin is high before switching to output mode.

**EDIT:**

Some microcontrollers have internal pull-ups, that are even activated at reset, see the specific data sheet. (*Thanks, Juraj.* I don't know NodeMCU enough to go in details. Anyway, my answer might apply to other controllers and other loads, too.)

The value of the pull-up can be determined by the maximum input current for the relay module (or your adapting circuitry) and the respective voltages. To be sure, make it a bit smaller, for example to the next E-series value. Just an example: minimum supply voltage is 3.15V (3V minus 5%), the maximum input voltage to detect "high" is 2.4V and maximum input current is 10 µA. Then the resistor will need to be at most Rmax = (Vdd\_min - Vin\_max) / Iin\_max = (3.15V - 2.4V) / 10 µA = 75kOhm. This value is part of the E24 series, but is can be 68kOhm that is in the E6 series.

However, it seems as if the circuit of the modules contains a simple PNP BJT, a pull-up will not work here, because the input needs to be pulled up to the supply voltage of the module. You need a level converter, this could be a simple transistor. How to design that circuit, is another issue. There are lots of information in the web how to do this.
> 1 votes

---
Tags: nodemcu, relay
---


title: Second I2C on Due RTClib, can't start

text:
# Question
Title: Second I2C on Due RTClib, can't start
I am using SDA1, SCL1 for my DS3232 with RTClib on Due. It works on a Mega2560 on SDA, SCL. I ran I2c\_test with success after I inserted #define Wire Wire1 However with ds3231.ino this define doesnot work. Looking at RTClib.cpp it looks like I can pass a parameter to Wire.begin(). I have tried sda1, scl1 and Wire1. They didnot work. Thanks for the help.

# Answer
> 1 votes
The unmodified RTCLib DS3231 sample code running on Arduino Due defaults to the *Wire* I2C connection on pins 20 SDA and 21 SCL.  To enable the same sketch to connect to a device connected to the *Wire1* I2C connection on pins 70 SDA1 and 71 SCL1, I changed line 333 of RTClib.h to reference &Wire1 rather than &Wire.   Successful test output from the Wire1 connection is shown.

**Update:** OP @Marlin Turbett pointed out that adding `#define Wire Wire1` to RTClib.h also works. I agree. The modification of line 333 of RTClib.h which I suggested originally is I think the minimal change to get the desired behaviour. But using substitution to achieve the same change also works. A global change across the whole library may be a bigger hammer than might be desirable.

#define substitution works in single compilation units, so the #define needs to be in the same compilation unit as the text to be overwritten. In this case in the library, not the sketch.

The technique of using #define directives to overwrite which *Wire* port is referenced in RTClib is used selectively by the library depending on arduino architecture (see RTClib.cpp lines 46-73, below).

```
#include "RTClib.h"
#if defined(__AVR__) && !defined(TWCR) && defined(USICR)
#include <TinyWireM.h>
#define Wire TinyWireM
#else
#include <Wire.h>
#endif

#ifdef __AVR__
#include <avr/pgmspace.h>
#elif defined(ESP8266)
#include <pgmspace.h>
#elif defined(ARDUINO_ARCH_SAMD)
// nothing special needed
#elif defined(ARDUINO_SAM_DUE)
#define PROGMEM
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#define Wire Wire1
#endif

#if (ARDUINO >= 100)
#define _I2C_WRITE write ///< Modern I2C write
#define _I2C_READ read   ///< Modern I2C read
#else
#include <WProgram.h>
#define _I2C_WRITE send   ///< Legacy I2C write
#define _I2C_READ receive ///< legacy I2C read
#endif

```

I don't know why the library code at lines 60 to 64 (for ARDUINO\_SAM\_DUE) was not effective, and I hope to do some more testing. Maybe others here can shed some light?

**Update 2:** Noting the link from @Edgar Bonet in the comments to the new example sketch `customWire_DS3231onSAMD21.ino` in RTClib 1.14.1 which specifically caters for multiple i2c ports. Nice one.

---
Tags: i2c, arduino-due, rtc
---