title: LSM303 unable to compensate tilt

text:
# Question
Title: LSM303 unable to compensate tilt
I am working on a tilt compensated compass with the LSM303DLHC. I manage to calibrate the magnetic and accelero part. I managed to calculate pitch and roll. But when it comes to calculate tilt compensation for the compass something goes wrong. My values on the serial monitor just don't make sense...If I calculate compass heading from calibrated magneto values it works using the Y axis as the magnetic vector. How would I be able to change that to the X-axis?

```
   LSM303DLHC including accelerometer to correct for position

*/
#include <Wire.h>

const int LSM303_ADDR = 0x19;
const int LSM303_ADDR_MAG = 0x1E;

//control register addresses
const int CTRL_REG1_ADDR = 0x20;
const int CTRL_REG2_ADDR = 0x21;
const int CTRL_REG3_ADDR = 0x22;
const int CTRL_REG4_ADDR = 0x23;
const int CTRL_REG5_ADDR = 0x24;
const int CTRL_REG6_ADDR = 0x25;

const int CRA_REG_M_ADDR = 0x00;
const int CRB_REG_M_ADDR = 0x01;
const int MR_REG_M_ADDR = 0x02;

//data register addresses LSB first for accelero, MSB first for magneto
const int Accelero_First_data_addr = 0x28;
const int Magneto_First_data_addr = 0x03;
const int Temp_out_data_addr = 0x31;//MSB first 12 bits

int CTRL_REG1_A_value = 0x47; //50Hz Low Power disable, all axes enabled
int CTRL_REG2_A_value = 0x00; //
int CTRL_REG3_A_value = 0x00; //no interrupt or watermark enabled
int CTRL_REG4_A_value = 0x00; // 2G full scale, high resolution, no SPI mode selected
int CTRL_REG5_A_value = 0x00; // nothing enabled
int CTRL_REG6_A_value = 0x00; // nothing enabled

int CRA_REG_M_value = 0x14; // Temp sens enabled, 15Hz data rate output
int CRB_REG_M_value = 0x20; // 2G is data 1100 - 980 G/LSB

int MR_REG_M_value = 0x00;

int16_t MagRaw_X_axis_value, MagRaw_Y_axis_value, MagRaw_Z_axis_value;
int16_t AccRaw_X_axis_value, AccRaw_Y_axis_value, AccRaw_Z_axis_value;

float pitch, roll;
float Xm_calibrated, Ym_calibrated, Zm_calibrated;
float Xm_norm, Ym_norm, Zm_norm, Xa_norm, Ya_norm, Za_norm;
float norm_a, norm_m;

void setup() {// put your setup code here, to run once:
  Serial.begin(9600);
  Wire.begin();
  setupLSM303();
  Serial.println("Setup complete..");
}

void loop() {// put your main code here, to run repeatedly:
  MagnetoDataRead();
  AcceleroDataRead();

}

void setupLSM303() {
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(CTRL_REG1_ADDR);
  Wire.write(CTRL_REG1_A_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(CTRL_REG2_ADDR);
  Wire.write(CTRL_REG2_A_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(CTRL_REG3_ADDR);
  Wire.write(CTRL_REG3_A_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(CTRL_REG4_ADDR);
  Wire.write(CTRL_REG4_A_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(CTRL_REG5_ADDR);
  Wire.write(CTRL_REG5_A_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(CTRL_REG6_ADDR);
  Wire.write(CTRL_REG6_A_value);
  Wire.endTransmission();
  //magneto register setup
  Wire.beginTransmission(LSM303_ADDR_MAG);
  Wire.write(CRA_REG_M_ADDR);
  Wire.write(CRA_REG_M_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR_MAG);
  Wire.write(CRB_REG_M_ADDR);
  Wire.write(CRB_REG_M_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR_MAG);
  Wire.write(MR_REG_M_ADDR);
  Wire.write(MR_REG_M_value);
  Wire.endTransmission();
}

void MagnetoDataRead() {
  Wire.beginTransmission(LSM303_ADDR_MAG );
  Wire.write(Magneto_First_data_addr);
  Wire.endTransmission();

  Wire.requestFrom(LSM303_ADDR_MAG , 6);
  if (Wire.available() <= 6) {
    MagRaw_X_axis_value = (Wire.read() << 8) | (Wire.read());
    MagRaw_Y_axis_value = (Wire.read() << 8) | (Wire.read());
    MagRaw_Z_axis_value = (Wire.read() << 8) | (Wire.read());

    float X_mag_cal = MagRaw_X_axis_value / 1100.0;
    float Y_mag_cal = MagRaw_Y_axis_value / 1100.0;
    float Z_mag_cal = MagRaw_Z_axis_value / 980.0;

    //input calibration factors
    float Xm_offset_corrected = MagRaw_X_axis_value - 0.041423;
    float Ym_offset_corrected = MagRaw_Y_axis_value + 0.022448;
    float Zm_offset_corrected = MagRaw_Z_axis_value + 0.078354;

    Xm_calibrated = 94.622065 * Xm_offset_corrected + 0.831029 * Ym_offset_corrected + 1.647934 * Zm_offset_corrected;
    Ym_calibrated = 0.831029 * Xm_offset_corrected + 93.462985 * Ym_offset_corrected + 3.416885 * Zm_offset_corrected;
    Zm_calibrated = 1.647934 * Xm_offset_corrected + 3.416885 * Ym_offset_corrected + 76.477691 * Zm_offset_corrected;

    //normalization formula
    norm_m = sqrt(sq(Xm_calibrated) + sq(Ym_calibrated) + sq(Zm_calibrated));
    Xm_norm = Xm_calibrated / norm_m;
    Ym_norm = Ym_calibrated / norm_m;
    Zm_norm = Zm_calibrated / norm_m;

    //float Heading = ((atan2(Ym_calibrated, Xm_calibrated)) * 180 ) / PI;
    //if (Heading < 0) {
    //  Heading = 360 + Heading;
    //}
    /*
        Serial.print(X_mag_cal, 10);
        Serial.print("\t");
        Serial.print(Y_mag_cal, 10);
        Serial.print("\t");
        Serial.print(Z_mag_cal, 10);
        Serial.println("\t");
    */

    delay(50);

  }
}

void AcceleroDataRead() {
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(Accelero_First_data_addr | 0x80);
  Wire.endTransmission();

  Wire.requestFrom(LSM303_ADDR, 6);
  if (Wire.available() <= 6) {
    AccRaw_X_axis_value = (Wire.read()) | (Wire.read() << 8);
    AccRaw_Y_axis_value = (Wire.read()) | (Wire.read() << 8);
    AccRaw_Z_axis_value = (Wire.read()) | (Wire.read() << 8);

    float X_Acc =  (AccRaw_X_axis_value >> 4);
    float Y_Acc =  (AccRaw_Y_axis_value >> 4);
    float Z_Acc =  (AccRaw_Z_axis_value >> 4);
//calibrate offset
    float X_acc_offset_corrected = X_Acc + 6.676443;
    float Y_acc_offset_corrected = Y_Acc - 6.622381;
    float Z_acc_offset_corrected = Z_Acc + 55.408804;
//calibrate
    float X_acc_calibrated = 0.977273 * X_acc_offset_corrected - 0.003458 * Y_acc_offset_corrected + 0.012639 * Z_acc_offset_corrected;
    float Y_acc_calibrated = -0.003458 * X_acc_offset_corrected + 0.979674 * Y_acc_offset_corrected - 0.001130 * Z_acc_offset_corrected;
    float Z_acc_calibrated = 0.012639 * X_acc_offset_corrected - 0.001130 * Y_acc_offset_corrected + 0.897083 * Z_acc_offset_corrected;
//normalize
    norm_a = sqrt(sq(X_acc_calibrated) + sq(Y_acc_calibrated) + sq(Z_acc_calibrated));
    Xa_norm = X_acc_calibrated / norm_a;
    Ya_norm = Y_acc_calibrated / norm_a;
    Za_norm = Z_acc_calibrated / norm_a;

//calculate pitch and roll
    pitch = asin(-Xa_norm) * 180 / PI;
    roll = (atan2(Ya_norm, Za_norm) * 180) / PI;
//calculate vectors fo tilt compensation
    float Xh = Xm_norm * cos(pitch * PI / 180) + Zm_norm * sin(pitch * PI / 180);
    float Yh = Xm_norm * sin(roll * PI / 180) * sin(pitch * PI / 180) + Ym_norm * cos(roll * PI / 180) - Zm_norm * sin(roll * PI / 180) * cos(pitch * PI / 180);
//calculate tilt compensated heading
    float Heading = ((atan2(Yh, Xh)) * 180.0 ) / PI;
    if (Heading < 0) {
      Heading = 360 + Heading;
    }

    Serial.print("Pitch \t");
    Serial.print(pitch);
    Serial.print("\t roll \t");
    Serial.print(roll);
    Serial.print("\t");
    Serial.println(Heading);

    delay(50);
  }
}

```

I have been stuck on this for a few days now. Any help is appreciated!

# Answer
It seems I got it working! Thanks a lot for your help, I owe you a few beers. For anyone following and interested here is my code:

```
   LSM303DLHC including accelerometer to correct for position
  Vector calculation to be implemented
*/
#include <Wire.h>
#include <Math.h>

const int LSM303_ADDR = 0x19;
const int LSM303_ADDR_MAG = 0x1E;

//control register addresses
const int CTRL_REG1_ADDR = 0x20;
const int CTRL_REG2_ADDR = 0x21;
const int CTRL_REG3_ADDR = 0x22;
const int CTRL_REG4_ADDR = 0x23;
const int CTRL_REG5_ADDR = 0x24;
const int CTRL_REG6_ADDR = 0x25;

const int CRA_REG_M_ADDR = 0x00;
const int CRB_REG_M_ADDR = 0x01;
const int MR_REG_M_ADDR = 0x02;

//data register addresses LSB first for accelero, MSB first for magneto
const int Accelero_First_data_addr = 0x28;
const int Magneto_First_data_addr = 0x03;
const int Temp_out_data_addr = 0x31;//MSB first 12 bits

int CTRL_REG1_A_value = 0x47; //50Hz Low Power disable, all axes enabled
int CTRL_REG2_A_value = 0x00; //
int CTRL_REG3_A_value = 0x00; //no interrupt or watermark enabled
int CTRL_REG4_A_value = 0x00; // 2G full scale, high resolution, no SPI mode selected
int CTRL_REG5_A_value = 0x00; // nothing enabled
int CTRL_REG6_A_value = 0x00; // nothing enabled

int CRA_REG_M_value = 0x14; // Temp sens enabled, 15Hz data rate output
int CRB_REG_M_value = 0x20; // 2G is data 1100 - 980 G/LSB

int MR_REG_M_value = 0x00;

int16_t MagRaw_X_axis_value, MagRaw_Y_axis_value, MagRaw_Z_axis_value;
int16_t AccRaw_X_axis_value, AccRaw_Y_axis_value, AccRaw_Z_axis_value;

float pitch, roll;
float Xm_calibrated, Ym_calibrated, Zm_calibrated;
float Xm_norm, Ym_norm, Zm_norm, Xa_norm, Ya_norm, Za_norm;
float norm_a, norm_m;

void setup() {// put your setup code here, to run once:
  Serial.begin(9600);
  Wire.begin();
  setupLSM303();
  Serial.println("Setup complete..");
}

void loop() {// put your main code here, to run repeatedly:
  MagnetoDataRead();
  AcceleroDataRead();

}

void setupLSM303() {
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(CTRL_REG1_ADDR);
  Wire.write(CTRL_REG1_A_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(CTRL_REG2_ADDR);
  Wire.write(CTRL_REG2_A_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(CTRL_REG3_ADDR);
  Wire.write(CTRL_REG3_A_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(CTRL_REG4_ADDR);
  Wire.write(CTRL_REG4_A_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(CTRL_REG5_ADDR);
  Wire.write(CTRL_REG5_A_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(CTRL_REG6_ADDR);
  Wire.write(CTRL_REG6_A_value);
  Wire.endTransmission();
  //magneto register setup
  Wire.beginTransmission(LSM303_ADDR_MAG);
  Wire.write(CRA_REG_M_ADDR);
  Wire.write(CRA_REG_M_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR_MAG);
  Wire.write(CRB_REG_M_ADDR);
  Wire.write(CRB_REG_M_value);
  Wire.endTransmission();
  Wire.beginTransmission(LSM303_ADDR_MAG);
  Wire.write(MR_REG_M_ADDR);
  Wire.write(MR_REG_M_value);
  Wire.endTransmission();
}

void MagnetoDataRead() {
  Wire.beginTransmission(LSM303_ADDR_MAG );
  Wire.write(Magneto_First_data_addr);
  Wire.endTransmission();

  Wire.requestFrom(LSM303_ADDR_MAG , 6);
  if (Wire.available() <= 6) {
    MagRaw_X_axis_value = (Wire.read() << 8) | (Wire.read());
    MagRaw_Z_axis_value = (Wire.read() << 8) | (Wire.read());
    MagRaw_Y_axis_value = (Wire.read() << 8) | (Wire.read());

    float X_mag_cal = MagRaw_X_axis_value / 1100.0;
    float Y_mag_cal = MagRaw_Y_axis_value / 1100.0;
    float Z_mag_cal = MagRaw_Z_axis_value / 980.0;

    //input calibration factors
    float Xm_offset_corrected = X_mag_cal - 0.032874;
    float Ym_offset_corrected = Y_mag_cal + 0.047876;
    float Zm_offset_corrected = Z_mag_cal + 0.039649;

    Xm_calibrated = 92.387197 * Xm_offset_corrected - 0.307374 * Ym_offset_corrected + 1.151625 * Zm_offset_corrected;
    Ym_calibrated = -0.307374 * Xm_offset_corrected + 85.002110 * Ym_offset_corrected + 1.169755 * Zm_offset_corrected;
    Zm_calibrated = 1.151625 * Xm_offset_corrected + 1.169755 * Ym_offset_corrected + 80.276037 * Zm_offset_corrected;

    //normalization formula
    norm_m = sqrt(sq(Xm_calibrated) + sq(Ym_calibrated) + sq(Zm_calibrated));
    Xm_norm = Xm_calibrated / norm_m;
    Ym_norm = Ym_calibrated / norm_m;
    Zm_norm = Zm_calibrated / norm_m;

    /*
        Serial.print(X_mag_cal, 10);
        Serial.print("\t");
        Serial.print(Y_mag_cal, 10);
        Serial.print("\t");
        Serial.print(Z_mag_cal, 10);
        Serial.println("\t");
    */

    //float Heading = ((atan2(Ym_norm, Xm_norm)) * 180.0 ) / PI;
    //if (Heading < 0) {
    // Heading = 360 + Heading;
    //}
    //Serial.println(Heading);
    //delay(50);

  }
}

void AcceleroDataRead() {
  Wire.beginTransmission(LSM303_ADDR);
  Wire.write(Accelero_First_data_addr | 0x80);
  Wire.endTransmission();

  Wire.requestFrom(LSM303_ADDR, 6);
  if (Wire.available() <= 6) {
    AccRaw_X_axis_value = (Wire.read()) | (Wire.read() << 8);
    AccRaw_Y_axis_value = (Wire.read()) | (Wire.read() << 8);
    AccRaw_Z_axis_value = (Wire.read()) | (Wire.read() << 8);

    float X_Acc =  (AccRaw_X_axis_value >> 4);
    float Y_Acc =  (AccRaw_Y_axis_value >> 4);
    float Z_Acc =  (AccRaw_Z_axis_value >> 4);

    //calibrate offset
    float X_acc_offset_corrected = X_Acc + 6.676443;
    float Y_acc_offset_corrected = Y_Acc - 6.622381;
    float Z_acc_offset_corrected = Z_Acc + 55.408804;

    //calibrate
    float X_acc_calibrated = 0.977273 * X_acc_offset_corrected - 0.003458 * Y_acc_offset_corrected + 0.012639 * Z_acc_offset_corrected;
    float Y_acc_calibrated = -0.003458 * X_acc_offset_corrected + 0.979674 * Y_acc_offset_corrected - 0.001130 * Z_acc_offset_corrected;
    float Z_acc_calibrated = 0.012639 * X_acc_offset_corrected - 0.001130 * Y_acc_offset_corrected + 0.897083 * Z_acc_offset_corrected;
    //normalize
    norm_a = sqrt(sq(X_acc_calibrated) + sq(Y_acc_calibrated) + sq(Z_acc_calibrated));
    Xa_norm = X_acc_calibrated / norm_a;
    Ya_norm = Y_acc_calibrated / norm_a;
    Za_norm = Z_acc_calibrated / norm_a;

    //calculate pitch and roll
    /*
      pitch = asin(-Xa_norm) * 180 / PI;
      roll = asin(Ya_norm / cos(pitch * PI / 180)) * 180 / PI;
    */
    roll = atan2(Ya_norm, Za_norm);
    float  Gz2 = Ya_norm * sin(roll) + Za_norm * cos(roll);
    pitch = atan(-Xa_norm / Gz2);
    float By2 = Zm_norm * sin(roll) - Ym_norm * cos(roll);
    float Bz2 = Ym_norm * sin(roll) + Zm_norm * cos(roll);
    float Bx3 = Xm_norm * cos(pitch) + Bz2 * sin(pitch);
    float yaw = (atan2(By2, Bx3)*180)/PI;
    if (yaw < 0) {
      yaw = 360 + yaw;
    }

    float tilt = atan2(sqrt((sq(Xa_norm)+(sq(Ya_norm)))),Za_norm);

    //calculate vectors fo tilt compensation
    float Xh = Xm_norm * cos(pitch) + Zm_norm * sin(pitch);
    float Yh = Xm_norm * sin(roll ) * sin(pitch) + Ym_norm * cos(roll) - Zm_norm * sin(roll) * cos(pitch);

        // calculate tilt compensated heading
        float Heading = ((atan2(Yh, Xh)) * 180.0 ) / PI;
        if (Heading < 0) {
          Heading = 360 + Heading;
        }

    Serial.print("Pitch \t");
    Serial.print(pitch * 180 / PI);
    Serial.print("\t roll \t");
    Serial.print(roll * 180 / PI);
    Serial.print("\t tilt \t");
    Serial.print(tilt*180/PI);
    Serial.print("\t");
    Serial.println(Heading);
    delay(500);
  }
}

```
> 0 votes

# Answer
Found it...Magneto data is coming out XZY not XYZ...when I changed this it works! Sorry, RTFMA would have given me the answer straight away.
> 0 votes

---
Tags: esp8266, sensors, magnetometer, calibration
---


# Question
Title: How do I configure WEMOS D1 R2 Vin pin to output max voltage?
I am in need of 12VDC from my Wemos D1 R2. How do I configure the Vin pin to output the max (I think its 12VDC)?

board: Wemos D1 R2 V2.1.0 - ESP8266 (LOLIN D1 R2)

Pinout here in pictures below

# Answer
> 0 votes
After looking into it and seeing all the previous answers, I noticed the Vin pin can be used as an output but only up to the input from the barrel connector.

When using a 9V input to the barrel jack, the voltage difference between the ground pin and Vin pin was just under 9V. Similarly, when measuring the voltage difference when using a 12V supply, the multimeter reported just under 12V.

This is in line with @StarCat comment.

# Answer
> 0 votes
You cannot. You are misunderstanding, what that pin is. Vin means Voltage In. It's a voltage input, connected to a voltage regulator, which will regulate the provided voltage at that pin down to 3.3V for the Wemos to work with. It is **not** an output. The regulator cannot convert the 3.3V from the Wemos to 12V. That is not, what it is build for.

To get 12V you either need a separate 12V power source, or you need to buy a stepup/boost converter, which brings the 3.3V (or 5V, if you are powering from USB) up to 12V. For the latter, be sure, that the converter and the source, where you get the input voltage of the converter, can provide enough current for your use case.

---
Tags: esp8266, voltage-level
---


# Question
Title: Vin pin vs USB vs Barrel connector: Wemos D1 R2
@Majenko says in the leading (19 Upvote) answer here not to use VIN and USB socket at the same time.

> You must never ever connect VIN to a power source and connect the USB socket. That can destroy the USB port in your computer. There is zero back-powering protection on \[LoLin v3 board\] board.

I need to do diagnostics on my Wemos (LOLIN) D1 R2 V2.1.0 while it's connected via 9-12V barrel jack and the Vin pin connected to an L9110H H-bridge as an output (bridge input).

Does the Wemos (LOLIN) D1 R2 V2.1.0 (ESP8266) work like this as well? Would I be able to run diagnosics with Serial through my USB socket while running this setup?

# Answer
> 0 votes
The D1 R2 uses the same power supply arrangement as the Arduino Uno (albeit with a better switching regulator for the 5V instead of the Arduino's basic linear regulator).

So it should be safe to use both the USB and the barrel jack at the same time.

The NodeMCU *doesn't include a 5V regulator* and doesn't have the power switching circuitry of the Uno / D1 R2, and thus is a completely different arrangement.

---
Tags: esp8266, power, voltage-level, voltage-protection
---


# Question
Title: Trying to move servo motor via 3 buttons
I am having some difficulties in trying to make my servo motor move to a specific angle based on the button pressed.

For example, having the motor start at 0 degrees and then having it move to 180 when the 3rd button is pressed, have it return to 0 degrees when the first button is pressed, and have it go to 90 degrees when the second button is pressed, etc, etc.

I can't tell if I am going about this all wrong or not with my code, so if anyone could provide some assistance with this it would be a great help

EDIT: Added the wiring as a just in case

```
#include <Servo.h>

Servo myservo;
int angle = 0;
int anglestep = 10;

#define FIRST 2 // pin 2 is connected to 1st floor button
#define SECOND 3 // pin 3 is connected to 2nd floor button
#define THIRD 4 // pin 4 is connected to 3rd floor button
#define SIGNAL 10

void setup()
{
Serial.begin(9600);
myservo.attach(10);
myservo.write(angle);
pinMode(2,INPUT_PULLUP);
pinMode(3,INPUT_PULLUP);
pinMode(4,INPUT_PULLUP);
Serial.println("Lift/Descend");
}

void loop()
{
while (digitalRead(FIRST) == LOW)
    {
    if (angle > 0 && angle <= 90) //2to1
        {
        angle = angle - anglestep;
            if (angle < 0)
            {
            angle = 0;
            }
            else
            {
            myservo.write(angle);
            Serial.print("Moved to: ");
            Serial.print(angle);
            Serial.println(" degree");
            }
        }
    else if (angle > 90 && angle <= 180) //3to1
    {
        angle = angle - anglestep;
            if (angle < 0)
            {
            angle = 0;
            }
            else
            {
            myservo.write(angle);
            Serial.print("Moved to: ");
            Serial.print(angle);
            Serial.println(" degree");
            }
    }
    else //1on1
    {
        angle = 0;
    }

}
while (digitalRead(SECOND) == LOW)
    {
    if (angle > 90 && angle <= 180) //3to2
        {
        angle = angle - anglestep;
        if (angle > 90)
            {
            angle = 90;
            }
        else
        {
        myservo.write(angle);
        Serial.print("Moved to: ");
        Serial.print(angle);
        Serial.println(" degree");
        }
    }
    else if (angle > 0 && angle < 90) //1to2
        {
        angle = angle + anglestep;
        if (angle < 90)
            {
            angle = 90;
            }
        else
        {
        myservo.write(angle);
        Serial.print("Moved to: ");
        Serial.print(angle);
        Serial.println(" degree");
        }
    }
    else
    {//2on2//
    angle = 90;
    }
}

while (digitalRead(THIRD) == LOW)
{
    if (angle > 0 && angle <= 90) //1to3
    {
        angle = angle + anglestep;
        if (angle > 180)
            {
            angle = 180;
            }
        else
        {
        myservo.write(angle);
        Serial.print("Moved to: ");
        Serial.print(angle);
        Serial.println(" degree");
        }
    }
    else if (angle > 90 && angle < 180)
    {//2to3
        angle = angle + anglestep;
        if (angle > 180)
            {
            angle = 180;
            }
        else
        {
        myservo.write(angle);
        Serial.print("Moved to: ");
        Serial.print(angle);
        Serial.println(" degree");
        }
    }
    else
        {
        angle = 180;
        }
    }
}

```

# Answer
> 1 votes
You are really overthinking things there. A servo will move to an angle if you just give it the final angle to move to. You don't need to nudge it to the final angle by visiting every angle in between, and you don't need to know what angle it's at currently.

You can simply do:

```
if (digitalRead(FIRST) == LOW) {
    myservo.write(0);
}

if (digitalRead(SECOND) == LOW) {
    myservo.write(90);
}

if (digitalRead(THIRD) == LOW) {
    myservo.write(180);
}

```

However if you wanted to slow the movement down, which would entail moving the servo in smaller steps, I would separate out the current angle and positioning from the buttons, which would set a *desired* angle. Something more like:

```
static uint8_t desiredAngle = 0;
static uint8_t currentAngle = 0;
static uint32_t timestamp = millis();

// Choose a new desired angle
if (digitalRead(FIRST) == LOW) {
    desiredAngle = 0;
}

if (digitalRead(SECOND) == LOW) {
    desiredAngle = 90;
}

if (digitalRead(THIRD) == LOW) {
    desiredAngle = 180;
}

// Every 10ms "tick" the servo towards the desired
// angle by 1 degree
if (millis() - timestamp >= 10) {
    timestamp = millis();
    if (desiredAngle > currentAngle) {
        currentAngle++;
        myservo.write(currentAngle);
    } else if (desiredAngle < currentAngle) {
        currentAngle--;
        myservo.write(currentAngle);
    }
}

```

---
Tags: arduino-uno, servo, button
---


title: Macbook Pro CH340 Nano 14201 error

text:
# Question
Title: Macbook Pro CH340 Nano 14201 error
I'm using a MacBook Pro Mojave 10.14.6 to code genuine Arduinos. Been working with multiple Uno R3s, no issue. Got a genuine Nano and get the following error: ser\_open(): can't open device "/dev/cu.usbmodem14201": No such file or directory

The USB cable I'm using works fine with a cheap Chinese Uno clone, so there are data pins in the cable.

I followed instructions to delete the kext file, rebooted, installed CH341SER\_MAC file and rebooted. Still getting the error message. I notice that others have asked this question; where are the answers? Thanks in advance.

# Answer
Timekeeping isn't exact with any of the boards, though .05% - just over 7 minutes/day - doesn't sound like too high an expectation.

Restarting when you connect it to your computer is by design and doesn't indicate a fault. Opening the IDE's terminal or connecting another terminal program to a connected and running Arduino will - and is supposed to - reset it. Here is a forum discussion on how to disable the auto-reset function (Uno-specific) if you want to. Note that it involves modifying the board.

It's quite possible that this one board has a fault, though it still could be the cable. A couple of swaps should confirm it one way or the other.

I'm still not clear on where the error message,

> ser\_open(): can't open device "/dev/cu.usbmodem14201"

came from, but I'm guess it's from AVRdude, the uploader application on your Mac, and still I'm wondering if the correct port is selected in the IDE's Tools | Port menu? For some reason, a USB device called "cu.usbmodem14201" is expected but not found. Since neither the Mac nor the IDE inherently knows this name - a USB device announces its name when you connect it - could this selection be left over from having previously used the genuine Arduino? Another reason to check the Ports menu. Also note that the Ports menu doesn't update its list spontaneously - only when you open it (and maybe only when you open the top-level, Tools, menu; I don't remember exactly).

Update:

> The regular Arduino at 0.5% is pretty crude, I'd pay more for a more accurate crystal, but I was able to develop a sketch that adjusts for the Arduino's inaccuracy.

You could try putting the Arduino in an "oven" - and I emphasize the quotes. This is not a heating chamber per-se but a temperature controlled chamber. If you're getting good results by adjusting the count, adding the oven should get you even better results, especially as the seasons change and if that makes enough difference where you are.
> -1 votes

---
Tags: arduino-nano
---


# Question
Title: Using the same variable between if-statements within loop()
I wonder if there is a good way to use the same variable value between two different if-statements within the loop().

Within the Servomotor section of the code, I want to use the value from the first if-statement's RewardTime within the next if-statement's RewardTime. Thus far, I cannot find a way to do it. (Since there is no communication between these variables right now, the RewardTime remains 0).

I'd appreciate a certain guidance in this matter.

```
#include <Servo.h> // Library required for the servomotor (Make sure to download if not in the library)
#include <Button.h> // Library required for the microswitch (Make sure to download if not in the lbrary)

// PARAMETERS
// COPY THESE VALUES IN PROCESSING CODE MANUALLY
// Explanation: To prevent possible Arduino-Processing overflow. Do not want too much information flow between Arduino and Processing.
const float Scale = 1 * 1000; // milliseconds
const float Base = 1 * 1000; // milliseconds

Servo Servo1;
int servoPin = 9; // Declare the Servo pin
Button button(7); // Declare the microswitch pin (Can be varied from setup to setup)

unsigned long previousMillis = 0;
bool switching = false;
int State = LOW;

char BirdSings = 0;
//static float RewardTime = 0;

void setup() {
   Servo1.attach(servoPin);
   analogWrite(9, 0);
   Serial.begin(9600);
   button.setDebounceTime(100); // set debounce time to 100 milliseconds
}

void loop(){
   // MICROSWITCH
   // Get onset and offset times of when the bird arrives and leaves the perch
   button.loop();
   if(button.isPressed())
    Serial.println(1);
   if(button.isReleased())
    Serial.println(0);

   // SERVOMOTOR
   // Get times when the feeder is covered (food present) and uncovered (food not present)
    unsigned long currentMillis = millis();
    while (Serial.available() > 0) {
    unsigned long currentMillis = millis();
   if (Serial.read() == '\n') { // When there is a song
     //Serial.println(2); // Food is uncovered
     previousMillis = currentMillis; // 0 becomes the current milli
     static float RewardTime = (Serial.parseFloat() * Scale) + Base; // CALCULATE THE RewardTime HERE
     Serial.println(RewardTime);
     if (State == LOW)
      State = HIGH;
     else
      State = LOW;
    }
   }

  if (State == HIGH && switching == false){
    Servo1.write(0); // 0 degree
    unsigned long secondCurrentMillis = millis();
    if (secondCurrentMillis - previousMillis > RewardTime) { // USE THE ABOVE RewardTime HERE
      switching = true;
      previousMillis = secondCurrentMillis;
      if (State == LOW)
        State = HIGH;
      else
        State = LOW;
    }
  }
  if(State == LOW && switching == true){
    Servo1.write(90); // 90 degrees
    switching = false;
    //Serial.println(3); // Food is covered
    }
}

```

# Answer
> 1 votes
Make the variable global, thus put it outside the `loop` function; also you don't need the `static` keyword anymore.

```
float RewardTime = 0;

```

Than inside your first `if` statement, remove the `static float` keywords:

```
RewardTime = (Serial.parseFloat() * Scale) + Base;

```

Some other tips:

* normally local variables do not start with a capital (so `rewardTime` is like most coding conventions)
* Always use brackets.

if (State == LOW) State = HIGH; else State = LOW;

Change to:

```
  if (State == LOW)
  {
    State = HIGH;
  }
  else
  {
    State = LOW;
  }

```
* However, to make it more simpler, use the ternary operator, you can change it to:

State = (State == LOW ? HIGH : LOW);

Which means: if some condition ? Do this : Else do this;

# Answer
> 1 votes
Since you defined it within the first `if` statement, it is only "in-scope" or defined within that block. To make it visible to both if statements, define it in the next outer block that contains both `if` statements - in this case, somewhere between `void loop(){` and `if (Serial.read()...`

---
Tags: arduino-uno, variables, loop
---


title: Arduino Hardlid Unlocker

text:
# Question
Title: Arduino Hardlid Unlocker
I am trying to build a unlocker on my hardlid for my ute. I have replaced the manual unlocking mechanism with 2 of these https://www.jaycar.com.au/slave-door-lock-actuator/p/LR8813.

Now my code below works sometimes and I cannot work out why. The way the code should work is

1. Press Unlock Button (Count increments)
2. Press Unlock Button again
3. When count = 2 turn relay on for 4 seconds then turn off
4. reset count to 0
5. If time between presses is longer than 10 seconds reset count to 0

Basic diagram below. Please note the push button is actually wired to a relay which is triggered by the car unlock remote and the LED is the actuators.

This is my code

```
int switchPin = 2; // choose the input pin (for a pushbutton)
int relayPin = 4; // choose the input pin (for a pushbutton)
int val = 0; // variable for reading the pin status
int counter = 0;
int currentState = 0;
int previousState = 0;
bool lockOn = false;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;

unsigned long LockcurrentMillis = 0;
unsigned long LockpreviousMillis = 0;

const long interval = 10000;
const long Lockinterval = 4000;

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

  pinMode(switchPin, INPUT); // declare pushbutton as input
  pinMode(relayPin, OUTPUT); // declare pushbutton as input

  Serial.println("Ready");
  Serial.print("IP address: ");

}

void loop() {

  currentMillis = millis();
  LockcurrentMillis = millis();
/*
  Serial.print("Current ");
  Serial.print(currentMillis);
  Serial.print(" | Previous ");
  Serial.println(previousMillis);
    //Serial.println(lockOn);

  Serial.print("Lock Current ");
  Serial.print(LockcurrentMillis);
  Serial.print(" | Lock Previous ");
  Serial.println(LockpreviousMillis);
  */
  if (lockOn == true){

    if (LockcurrentMillis - LockpreviousMillis >= Lockinterval) {
      // save the last time you blinked the LED
      LockpreviousMillis = LockcurrentMillis;
      digitalWrite(relayPin, LOW); // turn relayPin off
      lockOn = false;
      Serial.println("relay off");
    }
  }

  val = digitalRead(switchPin); // read input value
  if (val == HIGH) { // check if the input is HIGH (button released)
    currentState = 1;
  }
  else {
    currentState = 0;
  }
  if (currentState != previousState) {
    if (currentState == 1) {
      counter = counter + 1;
      previousMillis = currentMillis;   //reset timer
      Serial.println(counter);
    }
  }
  if (counter == 2) {
    counter = 0;
    digitalWrite(relayPin, HIGH); // turn relayPin on
    //delay(4000);
    //digitalWrite(relayPin, LOW); // turn relayPin off
    lockOn = true;
          LockpreviousMillis = LockcurrentMillis;

    Serial.println("relay on");
  }

  previousState = currentState;
  //delay(250);
  if (currentMillis - previousMillis >= interval) {
    // save the last time you presse the button
    previousMillis = currentMillis;
    //LockpreviousMillis = LockcurrentMillis;
    //if (counter >= 1) {
    Serial.println("Took too long reset count");
    counter = 0;
    lockOn = false;
    //}
  }
}

```

Any Help would be highly appreciated

Thanks

# Answer
Your circuit drawing seems very wrong, but it is not helpful since, as you say, it doesn't represent the real circuit. Please, add a proper diagram of the actual circuit.

As for your reliability problem, I did not dig into the logic of the code you posted, but I suspect it may be caused by the lack of debouncing. You could add you own debouncing code but, for the sake of simplicity, I suggest you instead use a ready-made library, like Bounce2.

For the kind of program you are trying to write, I find that the logic becomes way easier to grasp if you think think of it as a finite state machine. This is program construct based on the idea that the system can be in any of a predefined set of possible states, and that its behavior and the possible state transitions depend on what particular state it is in. In this specific case, I would use three states:

* In the `LOCKED` state, the lid is locked and you need to press the button twice in order to unlock it. Once you press the button once, it transitions to the `WAITING` state.
* In the `WAITING` state, the lid is still locked, but the first button press has already been registered. If you press the button again, the system transitions to the `UNLOCKED` state. If not, after a timeout it transitions back to `LOCKED`.
* In the `UNLOCKED` state the lid is unlocked. After another timeout it transitions back to the `LOCKED` state.

Once you have this logic written down, it can be translated into code in a very straightforward way:

```
#include <Bounce2.h>

const uint8_t  switch_pin = 2;
const uint8_t  relay_pin  = 4;
const uint32_t wait_interval = 10000;  // 10 s
const uint32_t lock_interval =  4000;  //  4 s

Bounce button;

void setup() {
    button.attach(switch_pin, INPUT_PULLUP);
    pinMode(relay_pin, OUTPUT);
    Serial.begin(9600);
    Serial.println("Ready.");
}

void loop() {
    static enum { LOCKED, WAITING, UNLOCKED } state = LOCKED;
    static uint32_t last_change;  // not used in the LOCKED state

    button.update();
    uint32_t now = millis();
    switch (state) {
    case LOCKED:
        if (button.fell()) {
            Serial.println(F("Waiting for second button press."));
            state = WAITING;
            last_change = now;
        }
        break;
    case WAITING:
        if (button.fell()) {
            Serial.println(F("Unlocking."));
            digitalWrite(relay_pin, HIGH);
            state = UNLOCKED;
            last_change = now;
        } else if (now - last_change >= wait_interval) {
            Serial.println(F("Wait time out."));
            state = LOCKED;
        }
        break;
    case UNLOCKED:
        if (now - last_change >= lock_interval) {
            Serial.println(F("Locking."));
            digitalWrite(relay_pin, LOW);
            state = LOCKED;
        }
        break;
    }
}

```
> 2 votes

---
Tags: esp8266
---


# Question
Title: HTU21 on GY-21 breakout board I2C problem
I am interfacing the HTU21D sensor with my nodeMCU v3. All good! I managed to get some readings etc. But when I re-upload my code the device does not respond. If I remove the power supply from the pin and hard reset it, it works again. I have exactly the same problem using the Sparkfun library, so it seems more of a hardware problem. Anyone else had the same problem? link to the sparkfun library https://github.com/sparkfun/SparkFun\_HTU21D\_Breakout\_Arduino\_Library for reference, here is my code

<pre><code>   This program interfaces the HTU21 temp/humidity sensor via I2C
*/

#include <Wire.h>
#include <Math.h>

const int HTU21_ADDR = 0x40;
const int Trigger_Temp_Measurement = 0xE3;// hold master
const int Trigger_Hum_Measurement = 0xE5; // hold master
const int Trigger_Temp = 0xF3; //No Hold Master
const int Trigger_Hum = 0xF5; //No Hold Master

int16_t Temp, Hum;//variables to store temp and humidity
int8_t TmpCrc, HumCrC;

void setup() {// put your setup code here, to run once:
  Serial.begin(9600);
  Wire.begin();
  Wire.beginTransmission(HTU21_ADDR);
  Wire.write(0xFE);
  Wire.endTransmission(true);

}

void loop() {// put your main code here, to run repeatedly:
  TempReading();
  HumReading();

}

void TempReading() {

  Wire.beginTransmission(HTU21_ADDR);
  Wire.write(Trigger_Temp_Measurement);
  Wire.endTransmission();

  Wire.requestFrom(HTU21_ADDR, 3, true);
  if (Wire.available() <= 3) {
    Temp = (Wire.read() << 8) | (Wire.read() );
    TmpCrc = Wire.read();
  }
  float TempCalc = -46.85 + (175.72 * ((float)Temp / (pow(2, 16))));
  Serial.print("Temperature \t");
  Serial.print(TempCalc);
  //Serial.println(TmpCrc, HEX);

}

void HumReading() {
  Wire.beginTransmission(HTU21_ADDR);
  Wire.write(Trigger_Hum_Measurement);
  Wire.endTransmission();

  Wire.requestFrom(HTU21_ADDR, 3, true);
  if (Wire.available() <= 3) {
    Hum = (Wire.read() << 8) | (Wire.read());
    HumCrC = Wire.read();
  }

  float HumCalc = -6 + 125 * (Hum / (pow(2, 16)));
  Serial.print("\t Humidity \t");
  Serial.println(HumCalc);
  //Serial.println(HumCrC, HEX);

}```

</code></pre>

# Answer
Yes the setup runs completely. I found out that the bus hangs if I terminate communication by uploading new code to the board. I found a piece of code that releases the bus which works. See below:

```
#if defined(TWCR) && defined(TWEN)
  TWCR &= ~(_BV(TWEN)); //Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly
#endif

  pinMode(SDA, INPUT_PULLUP); // Make SDA (data) and SCL (clock) pins Inputs with pullup.
  pinMode(SCL, INPUT_PULLUP);

  boolean SCL_LOW = (digitalRead(SCL) == LOW); // Check is SCL is Low.
  if (SCL_LOW) { //If it is held low Arduno cannot become the I2C master.
    return 1; //I2C bus error. Could not clear SCL clock line held low
  }

  boolean SDA_LOW = (digitalRead(SDA) == LOW);  // vi. Check SDA input.
  int clockCount = 20; // > 2x9 clock

  while (SDA_LOW && (clockCount > 0)) { //  vii. If SDA is Low,
    clockCount--;
    // Note: I2C bus is open collector so do NOT drive SCL or SDA high.
    pinMode(SCL, INPUT); // release SCL pullup so that when made output it will be LOW
    pinMode(SCL, OUTPUT); // then clock SCL Low
    delayMicroseconds(10); //  for >5uS
    pinMode(SCL, INPUT); // release SCL LOW
    pinMode(SCL, INPUT_PULLUP); // turn on pullup resistors again
    // do not force high as slave may be holding it low for clock stretching.
    delayMicroseconds(10); //  for >5uS
    // The >5uS is so that even the slowest I2C devices are handled.
    SCL_LOW = (digitalRead(SCL) == LOW); // Check if SCL is Low.
    int counter = 20;
    while (SCL_LOW && (counter > 0)) {  //  loop waiting for SCL to become High only wait 2sec.
      counter--;
      delay(100);
      SCL_LOW = (digitalRead(SCL) == LOW);
    }
    if (SCL_LOW) { // still low after 2 sec error
      return 2; // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec
    }
    SDA_LOW = (digitalRead(SDA) == LOW); //   and check SDA input again and loop
  }
  if (SDA_LOW) { // still low
    return 3; // I2C bus error. Could not clear. SDA data line held low
  }

  // else pull SDA line low for Start or Repeated Start
  pinMode(SDA, INPUT); // remove pullup.
  pinMode(SDA, OUTPUT);  // and then make it LOW i.e. send an I2C Start or Repeated start control.
  // When there is only one I2C master a Start or Repeat Start has the same function as a Stop and clears the bus.
  /// A Repeat Start is a Start occurring after a Start with no intervening Stop.
  delayMicroseconds(10); // wait >5uS
  pinMode(SDA, INPUT); // remove output low
  pinMode(SDA, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control.
  delayMicroseconds(10); // x. wait >5uS
  pinMode(SDA, INPUT); // and reset pins as tri-state inputs which is the default state on reset
  pinMode(SCL, INPUT);
  return 0; // all ok
}

```

Thanks for pointing me in the right direction!
> 1 votes

---
Tags: i2c, nodemcu, hardware, temperature-sensor
---


# Question
Title: guidance on Mikrobus NFC tag and connecting to arduino
I've recently purchased an NFC tag reader from MikroE and ive been a little lost on connecting the reader to my arduino board.

I've also been looking online for a library that i could use for this device, and have found little to nothing, though i maybe looking in the wrong place. If you could provide any guidance to the matter please respond.

any help would be much appreciated.

link to the tag: https://www.mikroe.com/nfc-tag-click

# Answer
To find an Arduino library for a device, you can search for the term combination

```
Arduino github <devicename>

```

because most libraries are hosted on github. The devicename here means the chip on the product, not the product itself. You won't find much for "Mikrobus NFC", but when you search for the chip on it - the M24SR64 - you can find some promising results.

For example this library, which looks good to me. It was used for this blog article, which is where I found it (though that is a german site. I just wanted to link as reference for the german speakers). It has some examples, that show the usage of the library.

---

In general: Sometimes there might be no ready to use library for a chip or product to use with Arduino. In that case you need to write that code yourself. Let's take this product as example. It uses the I2C interface and the seller also links to the datasheet of the used chip. In the datasheet you can read, how the chip is used, including the communication protocol, that is imposes on the I2C interface. You could then write the corresponding I2C code using the `Wire` library.

Fortunate for you there already is a library, so you can first try that.
> 0 votes

---
Tags: arduino-uno, nfc
---


title: Arduino Project Interrupt Error?

text:
# Question
Title: Arduino Project Interrupt Error?
I have a project to be made i.e. water Billing System using RFID(Mfrc522) on Arduino NANO. There is one difficulty that I haven't been able to overcome. I hope someone could help me out. Project flow:

1. water or any liquid flows through the sensor and quantity of water gets recorded
2. now according to quantity of water flown there is price decided
3. this price needs to be deducted by swiping rfid card issue:
4. i haven't been able to control interrupts
5. my program calculates the water flown required:
6. edit code such that it as soon as water flows through it, it calculates and ask user to swipe card and as user swipes a amount deductes and process continues.

if not clear please ask and help me out

```
#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9          // Configurable, see typical pin layout above
#define SS_PIN          10         // Configurable, see typical pin layout above
MFRC522 mfrc522(SS_PIN, RST_PIN);
String tagUID = "10 90 70 38";  // String to store UID of tag. Change it with your tag's UID
int bal =1000;

byte statusLed    = 13;
byte sensorInterrupt = 0;  // 0 = digital pin 2
byte sensorPin       = 2;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
// litre/minute of flow.
float calibrationFactor = 4.5;

volatile byte pulseCount;

float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;

unsigned long oldTime;

void setup()
{

  // Initialize a serial connection for reporting values to the host
  Serial.begin(9600);
  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);

  pulseCount        = 0;
  flowRate          = 0.0;
  flowMilliLitres   = 0;
  totalMilliLitres  = 0;
  oldTime           = 0;
  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
  Serial.begin(9600);    // Initialize serial communications with the PC
  while (!Serial);
  SPI.begin();      // Init SPI bus
  mfrc522.PCD_Init();   // Init MFRC522
}

/**
 * Main program loop
 */
void loop()
{

   if((millis() - oldTime) > 2000)    // Only process counters once per second
  {
    // Disable the interrupt while calculating flow rate and sending the value to
    // the host
    detachInterrupt(sensorInterrupt);

    // Because this loop may not complete in exactly 1 second intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output. We also apply the calibrationFactor to scale the output
    // based on the number of pulses per second per units of measure (litres/minute in
    // this case) coming from the sensor.
    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;

    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.
    oldTime = millis();

    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.
    flowMilliLitres = (flowRate / 60) * 1000;

    // Add the millilitres passed in this second to the cumulative total
    totalMilliLitres += flowMilliLitres;

    unsigned int frac;

    // Print the flow rate for this second in litres / minute
    Serial.print("Flow rate: ");
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print("L/min");
    Serial.print("\t");       // Print tab space

    // Print the cumulative total of litres flowed since starting
    Serial.print("Output Liquid Quantity: ");
    Serial.print(totalMilliLitres);
    Serial.println("mL");
    Serial.print("\t");       // Print tab space
    Serial.print(totalMilliLitres/1000);
    Serial.print("L");
    rfid();

    // Reset the pulse counter so we can start incrementing again
    pulseCount = 0;

    // Enable the interrupt again now that we've finished sending output
    attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
  }
}

/*
Insterrupt Service Routine
 */
void pulseCounter()
{
  // Increment the pulse counter
  pulseCount++;
}

void rfid()
{
   // put your main code here, to run repeatedly:

  Serial.println("In Rfid Loop");
  delay(3000);
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
        return;
      }
      // Select one of the cards
      if ( ! mfrc522.PICC_ReadCardSerial()) {
        return;
      }
  //Reading from the card
      String tag = "";
      for (byte j = 0; j < mfrc522.uid.size; j++)
      {
        tag.concat(String(mfrc522.uid.uidByte[j] < 0x10 ? " 0" : " "));
        tag.concat(String(mfrc522.uid.uidByte[j], HEX));
      }
      tag.toUpperCase();
       if (tag.substring(1) == tagUID)
      {
        bal=bal-20;
        delay(100);
        if(bal>=30)
        {
          Serial.println(bal);
          Serial.println("YOUR BALANCE");
          delay(400);

          // Reset the pulse counter so we can start incrementing again
          //pulseCount = 0;

          // Enable the interrupt again now that we've finished sending output
          //attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
        }
       else
        {
          Serial.println("INSUFFICIENT BALANCE PLEASE RECHARGE");
         }
        delay(100);

      }
      else
      {
        Serial.println("WRONG CARD ENTERED");

       }
}

```

# Answer
> 1 votes
You are disabling interrupts for way too long. Interrupts are meant for handling time-critical tasks that cannot wait for a full loop iteration. If you ever disable them, it should be for a time as short as possible. In your case, you only need to disable interrupts while accessing the `pulseCount` variable, as this variable is shared between the ISR and the regular code. This can be done in a very short "critical section" as follows:

```
noInterrupts();
uint8_t pulseCountCopy = pulseCount;
pulseCount = 0;
interrupts();

```

In the rest of the loop you then only access `pulseCountCopy`. Note that you don't really need to reset `pulseCount` to zero. Since it is incremented using the rules of modular arithmetic, you can just compute the differences between consecutive readings. You will get the correct result even when it rolls over. This makes the critical section even shorter:

```
static byte oldPulseCount;
noInterrupts();
uint8_t pulseCountCopy = pulseCount;
interrupts();
uint8_t pulseIncrement = pulseCountCopy - oldPulseCount;
oldPulseCount = pulseCountCopy;

```

And then note that, since reading a single byte is an atomic operation (a single machine instruction), you do not even need to disable interrupts *al all*! However, if the flow can ever be larger than 0.47 L/s, then 8 bits will not be enough for `pulseCount`. You will have to use a 16-bit variable (`uint16_t`) and keep the critical section.

As a side note, you are calling `millis()` several times per loop iteration. This is bad practice, as there is no guarantee that you will always get the same value, so you end up with your timing calculations being somewhat sloppy. You should rather do something like

```
uint32_t now = millis();

```

at the start of `loop()`, and use the same value for the whole iteration.

Another side note: you are differentiating the pulse count in order to get a flow rate, then integrating the flow rate to get a total volume. This is completely useless. The pulse count is already a measure of the total volume. Basic arithmetics shows you that the calibration factor is

4.5 (pulses/s) / (L/min) = 270 pulses/L

Your calculations will be less sloppy (having less accumulated error) if you just divide the total pulse count by 270 to get the total volume in liters.

---
Tags: programming, arduino-nano, interrupt, rfid
---


# Question
Title: Arduino AES encryption, working example or tutorial
I am quite new to idea of encryption and am trying to use aes-256-ecb encryption.
I am using library called "Arduino cryptography". Unfortunately I could not find any tutorial that would explain how to encrypt a json string (and other things latter) using a key.
I have a function that generates same key on both sides of Arduino and php script on a server side, but I could not find a working tutorial (except the case of obsolete buggy library with instruction like : "copy this text" and even that doesn't work. Unfortunately libraries examples do not bother to show how to retrieve encrypted string or explain what is what and instead just focus on checking how long encryption takes.
Does any of you know of some tutorial or an example from which I could engineer a solution? library link:The library
in buioltin example there is a code of:

```
cipher->decryptBlock(buffer, test->ciphertext);

```

But I do not understand where is the output and where the input here

Second question would be if I can use other modes like the mentioned GCM simply by changing the value in

```
static TestVector const testVectorAES256 = {
    .name        = "AES-256-ECB",
    .key         = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
                    0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F},
    .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                    0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
    .ciphertext  = {0x8E, 0xA2, 0xB7, 0xCA, 0x51, 0x67, 0x45, 0xBF,
                    0xEA, 0xFC, 0x49, 0x90, 0x4B, 0x49, 0x60, 0x89}
};

```

or how?

After bits and strougles I have managed to get this working, but next step is how to make it take a string:

```
/*Skúška kódovania GCM-AES256#*/

#include <Crypto.h>
#include <AES.h>
#include <GCM.h>
//#include <pgmspace.h>

struct TestVector
{
    const char *name;
    uint8_t key[32];
    uint8_t plaintext[60];
    uint8_t ciphertext[60];
    uint8_t authdata[20];
    uint8_t iv[12];
    uint8_t tag[16];
    size_t authsize;
    size_t datasize;
    size_t tagsize;
    size_t ivsize;
};

static TestVector const testVectorGCM PROGMEM = {
    .name        = "AES-256 GCM",
    .key         = {0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
                    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
                    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
                    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08},
    .plaintext   = {0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
                    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
                    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
                    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
                    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
                    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
                    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
                    0xba, 0x63, 0x7b, 0x39},
    .ciphertext  = {0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
                    0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
                    0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
                    0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
                    0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
                    0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
                    0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
                    0xbc, 0xc9, 0xf6, 0x62},
    .authdata    = {0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
                    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
                    0xab, 0xad, 0xda, 0xd2},
    .iv          = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
                    0xde, 0xca, 0xf8, 0x88},
    .tag         = {0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
                    0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b},
    .authsize    = 20,
    .datasize    = 60,
    .tagsize     = 16,
    .ivsize      = 12
};

TestVector testVector;
byte buffer[128];

bool testCipher_N(AuthenticatedCipher *cipher, const struct TestVector *test, size_t inc)
{
    size_t posn, len;
    uint8_t tag[16];

    crypto_feed_watchdog();

    cipher->clear();
    if (!cipher->setKey(test->key, cipher->keySize())) {
        Serial.print("setKey ");
        return false;
    }
    if (!cipher->setIV(test->iv, test->ivsize)) {
        Serial.print("setIV ");
        return false;
    }

    memset(buffer, 0xBA, sizeof(buffer));

    for (posn = 0; posn < test->authsize; posn += inc) {
        len = test->authsize - posn;
        if (len > inc)
            len = inc;
        cipher->addAuthData(test->authdata + posn, len);
    }

    for (posn = 0; posn < test->datasize; posn += inc) {
        len = test->datasize - posn;
        if (len > inc)
            len = inc;
        cipher->encrypt(buffer + posn, test->plaintext + posn, len);
    }

    Serial.println("Vystup:\n");
    for(uint8_t i=0; i<sizeof(buffer); i++) printf("0x%X,",buffer[i]);

    return true;
}

void testCipher(AuthenticatedCipher *cipher, const struct TestVector *test)
{
    bool ok;

    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;

    Serial.print(test->name);
    Serial.print(" ... ");

    ok  = testCipher_N(cipher, test, test->datasize);
    /*ok &= testCipher_N(cipher, test, 1);
    ok &= testCipher_N(cipher, test, 2);
    ok &= testCipher_N(cipher, test, 5);
    ok &= testCipher_N(cipher, test, 8);
    ok &= testCipher_N(cipher, test, 13);
    ok &= testCipher_N(cipher, test, 16);*/

    if (ok)
        Serial.println("Passed");
    else
        Serial.println("Failed");
}

void perfCipherSetKey(AuthenticatedCipher *cipher, const struct TestVector *test, const char *name)
{
    unsigned long start;
    unsigned long elapsed;
    int count;

    crypto_feed_watchdog();

    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;

    Serial.print(name);
    Serial.print(" SetKey ... ");

    start = micros();
    for (count = 0; count < 1000; ++count) {
        cipher->setKey(test->key, cipher->keySize());
        cipher->setIV(test->iv, test->ivsize);
    }
    elapsed = micros() - start;

    Serial.print(elapsed / 1000.0);
    Serial.print("us per operation, ");
    Serial.print((1000.0 * 1000000.0) / elapsed);
    Serial.println(" per second");
}

void perfCipherEncrypt(AuthenticatedCipher *cipher, const struct TestVector *test, const char *name)
{
    unsigned long start;
    unsigned long elapsed;
    int count;

    crypto_feed_watchdog();

    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;

    Serial.print(name);
    Serial.print(" Encrypt ... ");

    cipher->setKey(test->key, cipher->keySize());
    cipher->setIV(test->iv, test->ivsize);
    start = micros();
    for (count = 0; count < 500; ++count) {
        cipher->encrypt(buffer, buffer, 128);
    }
    elapsed = micros() - start;

    Serial.print(elapsed / (128.0 * 500.0));
    Serial.print("us per byte, ");
    Serial.print((128.0 * 500.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
}

void setup(){
    Serial.begin(115200);
    Serial.println("Začínam\n");
    GCM <AES256> *gcm=0;
    gcm= new GCM<AES256>();
    gcm->setKey(testVectorGCM.key, 32);
    gcm->setIV(testVectorGCM.iv,testVectorGCM.ivsize);
    crypto_feed_watchdog();
    //gcm->encrypt(buffer,testVectorGCM.plaintext,60);
    testCipher(gcm,&testVectorGCM);
    delete gcm;
    //gcm.encrypt(&vstupny,&vystup,49);
    crypto_feed_watchdog();
    Serial.println("Vystup: \n");
    for(uint8_t i=0; i<50;i++) Serial.print(buffer[i]);
}

void loop(){
    delay(1000);
    Serial.print(".");
}

```

I need to be able to get the text on PHP side

# Answer
Kind of an answer. After the advise from @Kwasmich I have converted to aes-256-gcm.
Upgraded to UTF-8 thanks to Edgar Bonet
Based mostly on GCMTest example comming with Arduino Cryptograhy libraries:
-----------------------------------------------
**Shared between Encryption and decrition**
First need to define parts which will not change:

```
#include <Crypto.h>
#include <AES.h>
#include <GCM.h>

struct TestVector
{
    const char *name;
    uint8_t key[32];
    uint8_t authdata[20];
    uint8_t iv[12];
    uint8_t tag[16];
    size_t authsize;
    size_t tagsize;
    size_t ivsize;
};

static TestVector const testVectorGCM PROGMEM = {   //Dont forget to change the Values here
    .name        = "AES-256 GCM",
    .key         = {0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
                    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
                    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
                    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08},
    .authdata    = {0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
                    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
                    0xab, 0xad, 0xda, 0xd2},
    .iv          = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
                    0xde, 0xca, 0xf8, 0x88},
    .tag         = {0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
                    0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b},
    .authsize    = 20,
    .tagsize     = 16,
    .ivsize      = 12
};

```

Now create a global buffer (easier to understand then pointers)

```
TestVector testVector;
byte buffer[128];

```

**Encrytpion**

```
{
    memcpy_P(&testVector, test, sizeof(TestVector));   //Load into memory
    test = &testVector;
    size_t posn, len;
    uint8_t tag[16];
    crypto_feed_watchdog();    //To protect from Watchdog reseting this function

```

It is important to clear memory of any ciphering before doing one:

```
    cipher->clear();

```

```
    cipher->setKey(test->key, cipher->keySize());    //Setting key
    cipher->setIV(test->iv, test->ivsize);     //vector
    for (posn = 0; posn < test->authsize; posn += datasize) {
        len = test->authsize - posn;
        if (len > datasize)
            len = datasize;
        cipher->addAuthData(test->authdata + posn, len);   //To make hack even more confusing
    }
    Serial.print("input numbers ");
    for(uint8_t i=0; i<60; i++) Serial.printf("%X",buffer[i]);
    Serial.println();

    for (posn = 0; posn < datasize; posn += datasize) {
        len = datasize - posn;
        if (len > datasize) len = datasize;
        crypto_feed_watchdog();
        cipher->encrypt((uint8_t*)buffer + posn, buffer + posn, len); //This is why we are here
        crypto_feed_watchdog();
    }
    Serial.println("Vystup:\n");
    for(uint8_t i=0; i<sizeof(buffer); i++) printf("0x%X,",buffer[i]);
}

```

**Decryption**

```
void decrypt(AuthenticatedCipher *cipher, const struct TestVector *test, size_t datasize){
    bool ok;

    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    size_t posn, len;
    uint8_t tag[16];
    crypto_feed_watchdog();
    cipher->clear();
    cipher->setKey(test->key, cipher->keySize());
    cipher->setIV(test->iv, test->ivsize);
    for (posn = 0; posn < test->authsize; posn += datasize) {
        len = test->authsize - posn;
        if (len > datasize)
            len = datasize;
        cipher->addAuthData(test->authdata + posn, len);
    }

    for (posn = 0; posn < datasize; posn += datasize) {
        len = datasize - posn;
        if (len > datasize)
            len = datasize;
        cipher->decrypt((uint8_t*)buffer + posn, buffer + posn, len);
    }

    Serial.print("\nVystup: ");
    for(uint8_t i=0; i<60;i++) Serial.printf("%c",(char)buffer[i]);
    Serial.println();

}

```

-----------------------------------------------
full example:

```
/*Skúška kódovania GCM-AES256#*/

#include <Crypto.h>
#include <AES.h>
#include <GCM.h>

struct TestVector
{
    const char *name;
    uint8_t key[32];
    uint8_t authdata[20];
    uint8_t iv[12];
    uint8_t tag[16];
    size_t authsize;
    size_t tagsize;
    size_t ivsize;
};

static TestVector const testVectorGCM PROGMEM = {
    .name        = "AES-256 GCM",
    .key         = {0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
                    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
                    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
                    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08},
    .authdata    = {0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
                    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
                    0xab, 0xad, 0xda, 0xd2},
    .iv          = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
                    0xde, 0xca, 0xf8, 0x88},
    .tag         = {0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
                    0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b},
    .authsize    = 20,
    .tagsize     = 16,
    .ivsize      = 12
};

TestVector testVector;
byte buffer[128];

void encrypt(AuthenticatedCipher *cipher, const struct TestVector *test, size_t datasize)
{
    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    size_t posn, len;
    uint8_t tag[16];
    crypto_feed_watchdog();

    cipher->clear();
    cipher->setKey(test->key, cipher->keySize());
    cipher->setIV(test->iv, test->ivsize);
    for (posn = 0; posn < test->authsize; posn += datasize) {
        len = test->authsize - posn;
        if (len > datasize)
            len = datasize;
        cipher->addAuthData(test->authdata + posn, len);
    }
    Serial.print("Cisla: ");
    for(uint8_t i=0; i<60; i++) Serial.printf("%X",buffer[i]);
    Serial.println();

    for (posn = 0; posn < datasize; posn += datasize) {
        len = datasize - posn;
        if (len > datasize) len = datasize;
        crypto_feed_watchdog();
        cipher->encrypt((uint8_t*)buffer + posn, buffer + posn, len);
        crypto_feed_watchdog();
    }
    Serial.println("Vystup:\n");
    //      Decrypt
    for(uint8_t i=0; i<sizeof(buffer); i++) printf("0x%X,",buffer[i]);
}

void decrypt(AuthenticatedCipher *cipher, const struct TestVector *test, size_t datasize){
    bool ok;

    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    size_t posn, len;
    uint8_t tag[16];
    crypto_feed_watchdog();
    cipher->clear();
    cipher->setKey(test->key, cipher->keySize());
    cipher->setIV(test->iv, test->ivsize);
    for (posn = 0; posn < test->authsize; posn += datasize) {
        len = test->authsize - posn;
        if (len > datasize)
            len = datasize;
        cipher->addAuthData(test->authdata + posn, len);
    }

    for (posn = 0; posn < datasize; posn += datasize) {
        len = datasize - posn;
        if (len > datasize)
            len = datasize;
        cipher->decrypt((uint8_t*)buffer + posn, buffer + posn, len);
    }

    Serial.print("\nVystup: ");
    for(uint8_t i=0; i<60;i++) Serial.printf("%c",(char)buffer[i]);
    Serial.println();

}

void setup(){
    Serial.begin(115200);
    Serial.println("Začínam\n");
    GCM <AES256> *gcm=0;
    gcm= new GCM<AES256>();
    gcm->setKey(testVectorGCM.key, 32);
    gcm->setIV(testVectorGCM.iv,testVectorGCM.ivsize);
    crypto_feed_watchdog();
    memset(buffer, (int)'\0', sizeof(buffer));
    char vstup[30]="Tak to netuším";     //String containing Non-Asci characters
    for(uint8_t i=0; i<30; i++) buffer[i]=vstup[i];
    encrypt(gcm,&testVectorGCM,30);
    decrypt(gcm,&testVectorGCM,30);
    delete gcm;
}

void loop(){
    delay(1000);
    Serial.print(".");
}

```

simple key generator in PHP:

```
<?php
for($i=0;$i<31;$i++) printf("0x%X,",random_int(0,0xFF));
printf("0x%X\n",random_int(0,0xFF));
?>

```
> 2 votes

---
Tags: communication
---


# Question
Title: Does toCharArray prevent a String being created on the heap?
I know it's bad to use Strings due to the memory problems that can occur. I've tried to remove all instances of strings from my code. But I'm not sure about this line:

```
http.getString().toCharArray(ipAddressBuffer, lengthOfIPAddress);

```

Is calling `toCharArray()` enough to prevent memory problems? Or is there a string still being created on the heap?

If it's still created on the heap, how can I modify the code so it only deals with cstrings?

Here's my code:

```
void setIPAddress(char* ipAddressBuffer){
  HTTPClient http;
  http.begin("http://bot.whatismyipaddress.com/"); //Only allowed to call once per 5 mins.
  http.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36");
  int httpCode = http.GET();
  if (httpCode > 0) {
    http.getString().toCharArray(ipAddressBuffer, lengthOfIPAddress);
  }
  else {
    Serial.println("Error on HTTP request");
  }
  http.end();
}

```

I'm using the HTTPClient.h library btw.

# Answer
The return value of getString allocates and the deletes a char array in heap for a temporary String object.

For ESP8266HTTPClient and ESP32 HTTPClient library you can use `writeToStream` or `getStream()`to read the response without using String class with `getString()`, where `stream` is `WiFiClient& stream = client.getStream();`

`getStream`, returns the underlying WiFiClient. You can read the data with classic `while (stream.available()) { char c = stream.read; ... }`

`writeToStream` copies the data to a stream. My StreamLib library has a stream wrapper over a char array. It is called CStringBuilder.
> 3 votes

# Answer
`http.getString()` creates a temporary Arduino String object and fills text into dynamic memory on the heap. Calling the method `.toCharArray`copies this text to a char array, wherever you defined it. Immediately after that, the temporary String gets out of scope and the text on the heap is deleted again.
> 0 votes

---
Tags: esp32, string, memory-usage, c-string
---


title: HC-05 TX,RX divider rule

text:
# Question
Title: HC-05 TX,RX divider rule
I'm using the HC-05 Bluetooth module but I'm confused about the TX,RX pins. I want to know when should I connect the RX to a divider circuit to convert 5v to 3.3v. Because while searching, I saw both of the following:

1. either RX is connected to TX of the UNO and TX is connected to RX of the UNO without a divider circuit.
2. or RX is connected to a divider circuit and then connected to any digital pin , TX is connected to any digital pin as well.

So can you give me a thought about both the situations? my thought is that only digital pins needs a divider rule, but the TX,RX pins can be connected directly and operates without any problems but if so, then what's the difference between both?? Note that I'm using HC-05 to turn on a LED. Hope to see some good explanation that suits a new Arduino learner. Thank you..

# Answer
You need a logic level translator of some form (such as a resistive divider) if the Arduino runs at 5V. If it's a 3.3V Arduino then you don't need one since the logic levels will match.

You connect to the TX and RX pins (or TX1/RX1 etc) of the Arduino if you want to use a hardware UART (Serial, Serial1, etc). You connect to *any* pins you like (with certain exceptions for the Mega) if you use `SoftwareSerial` instead of a hardware UART.
> -1 votes

# Answer
While you *should* use a voltage divider on the Arduino TX --\> BT RX signal, you honestly don't need to. Many people, including myself, have used HC-05s without voltage dividers and haven't let "the magic smoke" out of the device. Adding a voltage divider may, though, may increase the lifespan of the HC-05.
> -1 votes

---
Tags: serial
---


# Question
Title: How can a function/method determine if a const array passed in is PROGMEM (flash) or not (RAM)?
Is it possible for a function/method to know if a constant array that has been passed in is in flash or RAM?

If I have a method or function that receives a constant array that is in RAM, the array is declared like this: `const uint8_t MY_ARRAY[] = { 1, 2, 3, 4 };`

gets passed into a method or function like this: `MyFunction(MY_ARRAY);`

and the method or function can handle it like this:

```
void MyFunction(const uint8_t *MY_ARRAY) {
     uint8_t secondElement = MY_ARRAY[1];
     ...

```

However, if the array is in Flash (because it's a constant array, so that's where it should go), then the declaration adds PROGMEM: `const uint8_t PROGMEM MY_ARRAY[] = { 1, 2, 3, 4 };`

The pass looks the same: `MyFunction(MY_ARRAY);`

And the function declaration looks the same but it needs to use pgm\_read\_byte\_near to get the correct values back:

```
void MyFunction(const uint8_t *MY_ARRAY) {
     uint8_t secondElement = pgm_read_byte_near(MY_ARRAY+1);
     ...

```

How can the receiving method know if the array is in flash (PROGMEM) or RAM (no PROGMEM) so it knows to use pgm\_read\_byte\_near or not? Ideally I'd like a compiler error, but the type is the same (both are const arrays of uint8\_t).

If pgm\_read\_byte\_near is used when it shouldn't be, or it's not used when it should be, the results are garbage.

Some relevant questions: How to pass a static const (progmem) array to a function

RAM usage question: PROGMEM vs const vs #define

Storing array in PROGMEM

PROGMEM: do I have to copy data from flash to RAM for reading?

UPDATE: It looks like what I want to do is not possible. The responses below are very interesting options though: using \__flash in plain C, using OOP to make PROGMEM and non-PROGMEM data holders or trying to (somehow?) use non-deprecated progmem specific data types from avr/gpmspace.h.

The best answer to my original question is that the method can not make this determination. The best solution, from a comment by Delta\_G, is to create regular (ram) and "\_P" (flash/ progmem) versions of the functions and to be as obvious as possible in the naming of those functions.

# Answer
> 7 votes
I am afraid there is no good solution to this problem. One option I do like is to use the `__flash` qualifier instead of `PROGMEM`:

```
const uint8_t ram_array[] = { 1, 2, 3, 4 };
__flash const uint8_t flash_array[] = { 5, 6, 7, 8 };

void function_reading_ram(const uint8_t *array)
{
    uint8_t secondElement = array[1];
    // ...
}

void function_reading_flash(__flash const uint8_t *array)
{
    uint8_t secondElement = array[1];
    // ...
}

int main(void)
{
    function_reading_ram(ram_array);      // OK
    function_reading_flash(flash_array);  // OK
    function_reading_ram(flash_array);    // Warning
    function_reading_flash(ram_array);    // Warning
}

```

Note that, with `__flash`, you don't need `pgm_read_byte_near()` or anything similar. You just use the array like you would use any regular array, and the compiler is smart enough to generate the code required to access the Flash memory.

The warnings generated by gcc are:

```
warning: conversion from address space ‘__flash’ to address space ‘generic’ [-Waddr-space-convert]
     function_reading_ram(flash_array);
     ^
warning: conversion from address space ‘generic’ to address space ‘__flash’ [-Waddr-space-convert]
     function_reading_flash(ram_array);
     ^

```

Given how nice this solution is, you may wonder why I wrote “there is no good solution”. Well, this comes with two caveats, one small and one huge. The small caveat is that you need to explicitly pass the option `-Waddr-space-convert` to the compiler if you want it to generate the warnings. It is not implied even with `-Wall -Wextra`. The huge caveat is that *this only works in plain C*. If you try to use this trick in C++ you get:

```
error: ‘__flash’ does not name a type

```

This is an implementation of the “named address spaces” extension to the standard C. Since nothing like this is standardized in C++, the authors of gcc assumed it would not be useful to users of C++. :-( You can mix C and C++ sources in Arduino, but you can't call class methods from C.

# Answer
> 5 votes
I will expand on KIIV's comment here.

This is a known issue to the people who wrote the Arduino framework. Essentially, the pointers to PROGMEM and RAM are both data pointers (think of a pointer like an array index, but for the entire RAM/Flash itself rather than one chunk of it that you manage) of the same size and type. They cannot be told apart since pointer types are only determined by the size of the data, not where the data is.

So, they used a clever solution: Make the pointer into a *different* pointer that *isn't* compatible with the regular RAM pointer. This is done by casting to the \__FlashStringHelper class (and then casting back when it must be read). The FSH class doesn't actually have any methods or do anything; it's simply used to define a custom pointer type that is different from the normal const \*.

You can directly go read one of the better guides I've seen on it here (Note that it's for the ESP8266, but this part works the same), or I can try to explain it. I suggest reading it anyway, since it has a lot of other info that's useful but not relevant to this question. Do note that they have a few examples near the end which don't de-allocate memory when they are done using it, though, so copying them directly could cause a memory leak (see my string processing example to see the proper method).

First, you need to cast the array to the FSH class:

```
const byte MyProgmemArray[] PROGMEM = {4,4,4,4,4,4,4,4}; //Fixes issue #82 (add randomness); see https://xkcd.com/221/ for details :D
__FlashStringHelper * MyArray = (__FlashStringHelper *) MyProgmemArray;

```

I am unaware if there is any method (and I did look) to declare these in-place, i.e. to make the original array declaration into a \__FlashStringHelper * directly. So you still need, as the programmer/user, to know which strings are in flash when you add them, and add the conversion line. This means that what you wanted (fully automatic RAM/Flash detection) isn't *quite* possible, but this is as close as I think it gets. A further warning is that the original array still exists, meaning that it could accidentally be used instead (will still cause the original mismatch issue) and the new definition takes up *slightly* more memory for the additional pointer (if the compiler does not optimize it out?).

Oddly, it works fine if your want to store a string:

```
__FlashStringHelper * MyString = PSTR("yaddayaddayadda...");

```

Strings *can* be inlined, but I think it's because of both the PSTR macro *and* because string definitions might be treated differently than an array of values (even though they are physically the same thing). Perhaps you could experiment with however PSTR works (it's actually a macro that does something, and isn't just a keyword) and see if you can implement this in your own code after all.

---

Now, you still need to get the data OUT of the array in that function you mentioned. To do that, we actually use two versions of that function. This is called overloading (and I think it's C++ only, but this is Arduino, which is by definition C++, so it's safe).

The RAM function you declare as normal:

```
void MyFunction(const uint8_t *MY_ARRAY){
  byte index_two = MY_ARRAY[1];
  ...
}

```

The PROGMEM function you declare as follows (assuming that pgm\_read\_byte\_near IS the right function. Also note that it gets more complicated if you need multi-byte values, like `int` or something...):

```
void MyFunction(__FlashStringHelper *MY_PROGMEM_ARRAY){
  const byte *MY_ARRAY = (const byte *)MY_PROGMEM_ARRAY; //convert back to normal
  byte index_two = pgm_read_byte_near(MY_ARRAY+1); //still have to read it as flash, of course
  ...
}

```

---

As a bonus bit of info that is **unrelated** to the question *as asked*, but that may interest you/be relevant later:

There are a few more notes if you use this for string data (or pretend it's a string for this part, which works if your data contains no zeros and ends in one). By the latter, I refer to the fact that strings in C (NOT the C++ `std::string` or Arduino `String`, though, so keep this in mind) are basically char arrays with a 0 tacked on the end. All string-processing functions run an infinite loop until they read a 0 at their current index, which allows them to work with strings of any length but still know when they are done. As a result, when reading it, you can treat your data like a string, with three caveats:

1. It can never contain a 0, except for the very last item, which won't be read.
2. When defining it, you'd need to still use {} instead of "" since most values don't have printable ASCII characters. (And even so, you'd have to write `" "` for 32, for instance.)
3. You can't actually print the alleged string, since the data won't actually contain printable characters. You'll get any mix of numbers, letters, punctuation, and fun things like backspace and newline all jumbled together. You would need to read each character and convert it (via, say, `String num = <your value here>;` or `itoa()` etc).

If you want to print it using an existing Arduino function, like Serial.print, and it is *actually* a string (and not data pretending to be a string), it will natively support \__FlashStringHelper \*, so you don't need the conversion step (this lets you do `Serial.print(F("No static RAM used here!"));` and similar).

There are two ways to read the data if it is for your own string-processing function, however. The first, the simple one, is not memory efficient and creates a full copy of the data or string in RAM while it's being used. As a result, it is not capable of processing strings that are too large for RAM and may have issues if it's called while a lot of RAM is already in use or it is called deep down a set of nested functions. It is very convenient, however:

```
//convert from __FlashStringHelper * as above, but let's assume it's a char* here
int size = strlen_P(MY_ARRAY);
if (size!=0){
  char * data = new char[size];
  if (data!=NULL){
    strcpy_P(data,MY_ARRAY);
    //do stuff with the string
    delete data;
  }
}

```

The second method is more annoying to actually do, and requires more control over how the data is processed, but you can also read out the data byte-by-byte as shown in my first decoding example above using pgm\_read\_byte\_near. This lets you work with data that is too large to fit in RAM and keeps a constant stack size too. The downside is that it requires that you are actually able to stream the data byte-by-byte in all places that it's then used (or that you re-read it when it needs to be accessed out-of-order).

# Answer
> 4 votes
There is also an OO solution possible, using the strategy design pattern, but this comes with some (slight) memory and performance penalties. You need to use C++ for this.

* Put each array you want to differ between flash/SRAM in a separate class (one per type). You get data hiding and possible separation of concerns for free.
* Instead of putting the array in each class, put a reference/pointer or use it directly.
* You can use inheritance:
    + Create a Flash Array class with a SRAM array reader/writer
    + Create an SRAM Array class with a Flash array reader/writer
    + Inherit each of the array types you use from one of these classes where the base class takes care of reading/writing.
* Alternative solution: use the strategy pattern; involves a bit more work, but you can prevent multiple inheritance (although since you use C now, you don't use inheritance (yet)). This would involve roughly:
    + Create a Flash and SRAM Array class reader as above.
    + Instead of inheritance, create a pointer to one of these classes which suits the type of the array.

Although I can imagine this will mean quite some changes in your sketch.

**Explanation using Inheritance**

(requested by comment)

@Casey I assume you mean the Inheritance way. Assume in a class you have `x_array` which is of type `FlashArray`. You just call `x_array.Read(...)`. This method is implemented in `FlashArray`, but also with the same parameters in `RamArray`. You can enforce this by inheriting both `FlashArray` and `RamArray` by a base class (e.g. `ArduinoArray` and create a (pure) virtual function `Read` with the same arguments. Anyway, the implementation of `Read` method in `FlashArray` should read from Flash and the same method in `RamArray` should read from RAM.

When you change the type of `x_array` from `FlashArray` to `RamArray` or vice versa, you don't need to change anything (except the types). To make this easier consider defining a type for `x_array`, so when you later need to change it, you only need to do this in one location.

# Answer
> 2 votes
The classic avr-gcc way is to have dedicated functions with different names

e.g. `void* memcpy(void* dest, const void* src, size_t n);` // Only works if src is RAM

vs. `void* memcpy_P(void *dest, PGM_VOID_P src, size_t n);` // Only works if src is PROGMEM

BTW: That's mentioned in a comment to the question already by @Delta\_G. More about the example memcpy\_P here

---
Tags: avr, memory-usage, flash, memory, progmem
---


# Question
Title: What happens to the board if you connect the +5V pin directly to a digital input configured as input
I have maybe a very stupid question but connecting the +5V pin to a digital input pin programmed as input ( let's say pin2) . Will it destroy the board? Cause after i did this my board doesn't work anymore and i can also not upload a sketch to it. it does nothing anymore, yet nothing has burned or no smoke.

??

Thanks

# Answer
> Will it destroy the board?

No, it will just read HIGH. That's what HIGH is - 5V.

> Cause after i did this my board doesn't work anymore

Then you probably did *something else*.
> 0 votes

---
Tags: arduino-uno
---


# Question
Title: Arduino doesnt seem to be reading my pin states
I seem to have an unbelievable thing. My code was working perfectly on one arduino, when i upload the same sketch to another one, it is behaving strangely, it seems like it is not reading any of my pin states:

The code is ment to drive a simple stepper motor with driver. depending on the state of several pins in which direction it moves or moves at all.

What is happening now is when i upload the sketch the motor starts to turn, nomatter what pinstate any of the input pins have, the motor just turns on uploading and even if i apply 5v to any of the pins, it just keeps turning the same direction.

Following the code. I hope someone could tell me what i am doing wrong, i am a newbie to programming:

```
int PUL=7; //define Pulse pin
int DIR=8; //define Direction pin
//int ENA=5; //define Enable Pin
int up = 2;
int down = 3;
int limitpin=1;
int limitpinup=4;
int i=0;

int buttonupstate = 0;
int buttondownstate = 0;
int limitstate=0;
int limitstateup=0;

void setup() {
  pinMode(PUL, OUTPUT);
  pinMode(DIR, OUTPUT);
  pinMode(up, INPUT);
  pinMode(down, INPUT);
  pinMode(limitpin, INPUT);
  pinMode(limitpinup, INPUT);
}

void loop() {
  buttonupstate = digitalRead(up);
  buttondownstate = digitalRead(down);
  limitstate = digitalRead(limitpin);
  limitstateup = digitalRead(limitpinup);
  i = 0;
  switch (limitstateup){
  case LOW:
    switch (limitstate){
    case LOW:
      if (buttondownstate==HIGH){
        do
        {
          digitalWrite(DIR,LOW);
          // digitalWrite(ENA,HIGH);
          digitalWrite(PUL,HIGH);
          delayMicroseconds(20);
          digitalWrite(PUL,LOW);
          delayMicroseconds(20);

          buttondownstate = 0;
          buttondownstate = digitalRead(down);
          limitstate == 0;
          limitstate = digitalRead(limitpin);
          limitstateup == 0;
          limitstateup = digitalRead(limitpinup);
        } while (buttondownstate == HIGH && limitstate == 0 && limitstateup == 0);
      }
      if (buttonupstate == HIGH){
        do
        {
          digitalWrite(DIR,HIGH);
          // digitalWrite(ENA,HIGH);
          digitalWrite(PUL,HIGH);
          delayMicroseconds(20);
          digitalWrite(PUL,LOW);
          delayMicroseconds(20);

          buttonupstate = 0;
          buttonupstate = digitalRead(up);
          limitstate == 0;
          limitstate = digitalRead(limitpin);
          limitstateup == 0;
          limitstateup = digitalRead(limitpinup);
        } while (buttonupstate == HIGH && limitstate == 0 && limitstateup == 0);
      }
      break;
    case HIGH:
      do{
        digitalWrite(DIR,HIGH);
        digitalWrite(PUL,HIGH);
        delayMicroseconds(20);
        digitalWrite(PUL,LOW);
        delayMicroseconds(20);
        limitstate = 0;
        limitstate = digitalRead(limitpin);
      }while (limitstate == HIGH );
      break;
    }
    break;
  case HIGH:
    do{
      digitalWrite(DIR,LOW);
      digitalWrite(PUL,HIGH);
      delayMicroseconds(20);
      digitalWrite(PUL,LOW);
      delayMicroseconds(20);
      limitstateup = 0;
      limitstateup = digitalRead(limitpinup);
    }while (limitstateup == HIGH );
    break;
  }
}

```

# Answer
> 2 votes
Thanks all of you,

Indeed there is nothing wrong with my code. The problem is indeed in the pull-down resistors, I rebuild the connection on a breadboard and works perfectly. I will have to check my PCB that contains all relays and resistors, the problem has to be on that board, bad connection or something like that.

However I would like to state that on the Osoyoo Uno board, the whole thing worked perfectly, so there has to be something different between Osoyoo Uno board and another Arduino board.

---

Here is the schematic to my PCB board. I checked it again, but i think all the digital pins have actually pull-down resistors active.

---
Tags: pins, stepper
---


title: Custom build of arduino on a pcb

text:
# Question
Title: Custom build of arduino on a pcb
I am running my Arduino based from the ATMEGA328P-PU chip from a 4v battery with this setup:

Everything works great and now I will like to make my project permanent building a custom PCB from easyeda.com. Anyways this question is not about how to create the custom PCB I have already made one and it works great. This is the PCB that I created:

Because I liked it so much now I want to build it even better. For example now I will like to combine the crystal with the 22pf ceramic capacitors into one small part.

**Question**

Can I use ----THIS---- part instead of the basic 22pf capacitor and the big 16Mhz crystal? In other words I want to replace the left picture with the right picture:

If its possible to use part 7325-1600A2210-00 then where can I find information on what pins to connect to the atmega328 chip and what pins to connect to ground? 7325-1600A2210-00 has 4 pins. To me it makes sense to connect 2 of the pins to pins 9 and 10 and the other 2 pins to ground. Will this work?

# Answer
> 1 votes
> Can I use ----THIS---- part instead of the basic 22pf capacitor and the big 16Mhz crystal?

No. That is just a crystal. You still need the capacitors. If you want a single device then you need a *ceramic resonator*.

Also you're lacking any decoupling capacitors in your circuit. You may find it works for now, but it will become flaky when you start getting it to do things.

---
Tags: arduino-uno-smd
---


title: How to do with fzz file

text:
# Question
Title: How to do with fzz file
I have a file YunConfig.fzz file for arduino yun for map maker project with ultrasonic sensor. How can I open or do with that file? please answer me.

# Answer
> 5 votes
Download and install the open-source, Fritzing CAD software for electronics hobbyist and open the .fzz file with that.

Versions are available for Linux, Mac, and Windows.

Installation instructions are on the downloads page.

# Answer
> 0 votes
You can get the latest version here: fritzing(dot)org/download/api/1.0/update/344 or find a version on softpedia

---
Tags: arduino-yun
---


# Question
Title: How can I increase the responsiveness/speed of my stepper motor?
I'm trying to control the positioning of a NEMA17 bipolar stepper motor by turning the knob of a potentiometer, using an EasyDriver board. The control part is solved. My problem is that if I quickly turn the knob to one end of its range and then back, the stepper motor lags behind by about 1/5 of a second.

All the spec sheets for the motor says I should be able to expect a lot more responsiveness (based on max RPM, acceleration, etc...). I'd like to speed up the responsiveness of the motor to shorten the lag. My code is as follows:

```
//Declare pin functions on Arduino
#define stp 2
#define dir 3  //LOW => forward, HIGH => backward
#define MS1 4
#define MS2 5
#define EN  6

//Declare variables for functions
int x;
int const potPin = A0;
long potval; // current analog read of A0 voltage
int potrotsteps = 166; //num of stepper motor steps for 300-degree rotation
int cur_step_pos = 0; //current position in terms of stepper steps
long cmd_step_pos = 0; //step-position to command stepper motor to go to
int tomove; //num steps to move

void setup() {
  //stepper motor setup
  pinMode(stp, OUTPUT);
  pinMode(dir, OUTPUT);
  pinMode(MS1, OUTPUT);
  pinMode(MS2, OUTPUT);
  pinMode(EN, OUTPUT);
  resetEDPins(); //Set step, direction, microstep and enable pins to default states
  Serial.begin(9600); // initialize serial communication at 9600 bits per second
  Serial.println("\n\n\n#################    setup completed     #################");
}

void loop() {

  //map analog voltage read from pot to a step-position (0-166) of the stepper motor
  potval = analogRead(potPin);
  cmd_step_pos = potval * potrotsteps / 1023; // find where stepper motor should be in terms of step-position
  tomove = abs(cur_step_pos - cmd_step_pos);

  if (cmd_step_pos > cur_step_pos) { //if should-be position greater than current position
    digitalWrite(dir, LOW); // move forward
    CommandStepperMotor(tomove); //move forward by the diff in position
  } else { //if should-be position is lower
    digitalWrite(dir, HIGH); //move backward
    CommandStepperMotor(tomove); //move backward by diff in position
  }
  cur_step_pos = cmd_step_pos; //current position is now former should-be position

}

//GLOBAL FUNCTIONS

//Reset Easy Driver pins to default states
void resetEDPins() {
  digitalWrite(stp, LOW);
  digitalWrite(dir, LOW);  //default "forward" movement
  digitalWrite(MS1, LOW); // L-L => full steps, H-L => 1/2 step
  digitalWrite(MS2, LOW); // L-H => 1/4 steps, H-H => 1/8 step
  digitalWrite(EN, LOW); //Enable motor control
}

void CommandStepperMotor(int numsteps) {
  for (x = 0; x < numsteps; x++) {
    digitalWrite(stp, HIGH); //Trigger one step forward
    delay(1);
    digitalWrite(stp, LOW); //Pull step pin low so it can be triggered again
    delay(1);
  }
}

```

I understand that changing delay(1) to delayMicroseconds(100) in the **CommandStepperMotor** function should help, but as it turns out, anything smaller than a delay of 1 millisecond stalls the motor. I've tried to Google other's solutions to the problem, but it seems they had no problem at all lowering the delay in sending the HIGH/LOW signals to the stepper pin to \<1 ms.

Any ideas? Thanks in advance!

# Answer
Your problem is that you want to go from a standstill to full speed instantly. That just isn't going to happen. As you have seen there is a limit to how fast you can go from stationary.

If you want to go faster you will have to *accelerate* up to that speed.

The simplest way to do that is to use a library that is designed for it, such as the popular AccelStepper.h library.
> 1 votes

---
Tags: arduino-uno, stepper-motor
---


# Question
Title: What do the TinyGPS++ output parameters mean?
TinyGPS++ give many output parameters. Where can I find explanation what do all output parameters mean? I don't understand what is the meaning of the following parameters:

> Course Speed Card Distance Course Car

UPD

**2365** is distance to London

**wnw** is the direction to London: https://en.wikipedia.org/wiki/Points\_of\_the\_compass#Compass\_point\_names

**0.00** \- Vertical speed?

**0.06** \- Horizontal speed?

**294.06** \- ???

# Answer
As you can see when you look at the source code of the FullExample.ino that is part of the TinyGPS++ library, the values you marked are:

1. Course Speed Card\*: The current speed (in km/h), course (in degrees) and cardinal course (which is the course translated to a cardinal direction on a compass, i.e. N,S,E,W, NE, NNW, etc.) of the GPS receiver (i.e. you).
2. Distance Course Card\**: The distance (in km) and course and cardinal course to some location or waypoint (London in this example).

After the information you added in your edit, this means the following:

* 0.00 is your current course over ground (i.e. due North)
* 0.06 is current current speed over ground (i.e. as good as stationary)
* N is your current cardinal course
* 2365 is the distance to London (km)
* 294.06 is the bearing to London from your location
* WNW is the cardinal bearing to London

* this is also known as SOG (Speed Over Ground) and COG (Course Over Ground, which is used in (aero)nautical navigation) or Bearing.

\** this is also known as DTG and CTS (Distance to Go and Course to Steer) when navigating to a GPS waypoint.
> 1 votes

---
Tags: gps, tinygps
---


# Question
Title: How are libraries added to the Arduino library manager?
Who curates the list of libraries in the `Tools / Manage Libraries` menu, and what is the procedure for submitting code for consideration?

# Answer
> 1 votes
You have to submit a ticket to the Arduino GitHub page. If you want to do this in an automated fashion, you can use this python program. Make sure beforehand that your library fits the Arduino library specification.

---
Tags: arduino-ide, library
---


title: Why HDOP in TinyGPS++ is less than 1?

text:
# Question
Title: Why HDOP in TinyGPS++ is less than 1?
HDOP is supposed to be greater than 1: https://en.wikipedia.org/wiki/Dilution\_of\_precision\_(navigation) But I get HDOP about 0.7. What does it mean?

Where can I found explanation of the output parameters?

# Answer
HDOP can be less than 1 according to this article.. I am no expert in this area, but according to the article, the `HDOP=1` limit is based on 4 satellites; visibility *and use* of more than 4 satellites can reduce HDOP below this limit. When you think on it, this makes sense.

GPS specifications limit the inherent accuracy of a *position solution* through timing errors and vagaries in rf propagation through our atmosphere. Imagine drawing a vector from a GPS satellite to your receiver. The length of that vector represents the distance from the satellite to your receiver, but we depend on *signal timing* to *infer* distance/vector magnitude. In other words, we can only measure distance as accurately as we can measure time.

Now think about the accuracy of a position solution based on a single satellite. If we assume the receiver is confined to the surface of the earth (and the satellite is *geostationary*), the single vector of length **L1** will intersect the surface of the earth forming a circle. Your position could be anywhere on that circle - which could be quite a large range of values!

Now imagine a 2nd satellite, a 2nd vector of length **L2** tracing a second circle. Now your position is constrained to be those points where the two circles intersect - two points! With a third satellite, a 3rd vector of length **L3**, one of these two points will be eliminated.

Now replace those sharp lines with bands or swaths of some width **D**. In this case, the intersection describes a polygon instead of a point. We know our position is within the polygon, but with only three satellites that is the best we can do.

As you can see, adding more satellites will begin to "slice off" sections of the original polygon, making it progressively smaller. So: `HDOP=1` represents the limit with 4 satellites; more satellites yield a smaller polygon, and smaller HDOP.

---

While writing this, I found a video that does a far better job than my words at describing the position solution process with multiple satellites.

This video is quite good also!
> 1 votes

---
Tags: gps, tinygps
---