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

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

```

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

int updateAudio() {
 switch (wave) {

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

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

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

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

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

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

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

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

 }
}
void loop() {
 audioHook(); // required here
}

```

(Yeah, it's still a lot...)

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

# Answer
I don't get a compilation error with your sketch with the latest git version.

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

---
Tags: compilation-errors
---


# Question
Title: CH340G based USB to UART adapter - Pinouts - Can't find schematics
This is the board I will be referring to.

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

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

# Answer
> 3 votes
This module appears to be designed for communicating with the ESP8266 ESP-01 board. The pinout for the ESP-01 is shown below, taken from a typical datasheet:

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

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

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

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

---
Tags: serial, uart, ch340
---


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

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

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

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

void setup() {
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);

  stopWDT();

  pinMode(LED_BUILTIN, OUTPUT);

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

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

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

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

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

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

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

```

# Answer
> 1 votes
Try changing this:

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

```

to:

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

```

It appears that your construct violates the 4 clock cycle window that the WDCE Watchdog Change Enable bit allows for updates to the WDE bit.

---
Tags: arduino-uno, interrupt, atmega328, sleep, watchdog
---


# Question
Title: Arduino OTA port not updating in Arduino IDE
The OTA (from the ArduinoOTA library) on my ESP8266 does not show up in the programming ports on the Arduino IDE unless I restart the IDE. Even when I plug in a usb cable and the ports list updates to show that device, it does not show the network port without a restart. Does anyone know why this would happen or how to solve it?

I downloaded the newest version of the IDE and this is still the case.

# Answer
> 1 votes
I found an workaround for Windows:

* disable IPv6 from Network Configuration
* disable/enable network interface
* restart Arduino IDE

You should see your OTA device in port list, in Arduino IDE.

# Answer
> 0 votes
For some reason you have to close and reopen the Arduino IDE for it to discover all available OTA ports. Not sure why this is -- if anyone knows I would be glad to learn.

EDIT: keeping this answer just for comments -- it's not a real answer.

# Answer
> 0 votes
I have the exact problem on various flavours of Linux with last Arduino IDE and rebooting the router seems to be the only thing I've found that can make the IP address port appear.

---
Tags: programming, esp8266
---


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

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

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

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

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

Here is my test code:

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

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

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

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

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

void loop() {}

```

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

And here is the resulting histogram:

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

```

All other histogram bins were empty (no outliers).

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

I can hardly imagine anything more stable than this.

# Answer
> 1 votes
Schematics even for such a question are indispensable.

Assuming from the following:

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

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

simulate this circuit – Schematic created using CircuitLab

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

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

---
Tags: arduino-uno, breadboard
---


title: About the FFT library on Arduino

text:
# Question
Title: About the FFT library on Arduino
From the output results, i see that the arduinoFFT returns only positive frequencies, thus i think it self removes the negative sided values and compensates the lost energy by multiplying by 2. Is this correct?Ar

# Answer
I don't know what you mean by a "negative" frequency.

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

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

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

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

---
Tags: signal-processing
---


# Question
Title: Safe to solder a slide switch to unused GPIO pins?
I have a Digispark Rev.3 Kickstarter with ATTiny85 (see pinout below) and a three pin slide switch (see example below). I want to use the slide switch to control a task running on the Digispark, with the example code below.

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

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

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

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

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

```

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

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

---
Tags: pins, switch, digispark, pinmode
---


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

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

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

```

code

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

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

void loop() {

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

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

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

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

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

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

```

# Answer
> 1 votes
From my post about interrupts:

---

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

## Example (not recommended):

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

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

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

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

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

```

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

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

## Improved sketch:

```
volatile bool counting;
volatile unsigned long events;

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

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

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

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

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

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

```

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

If the time is up we display the count.

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

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

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

---

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

---
Tags: interrupt, pulsein
---


# Question
Title: How to shift binary into a shift register (serial in, parallel out) sequentially
I'm trying to make a continuity tester at work where I connect the input and output of a harness into a test fixture powered by an Arduino. This tester tests whether the position of the connects are pinned correctly.

Here is the diagram of my initial idea:

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

Here is my loop that attempts to perform the above:

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

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

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

```

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

Is there something I'm missing here? thanks!

# Answer
> 2 votes
Do not use `pow()`. This is a function that works with floating point numbers. It is roughly equivalent (for y \> 0) to

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

```

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

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

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

```
shift_SIPO(1 << i);

```

---
Tags: arduino-mega, c++
---


title: Non-blocking MQTT library

text:
# Question
Title: Non-blocking MQTT library
Are there any MQTT libraries that do not block while connecting?

I'm currently using PubSubClient, and the connection part contains this code: https://github.com/knolleary/pubsubclient/blob/master/src/PubSubClient.cpp

```
        while (!_client->available()) {
            unsigned long t = millis();
            if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) {
                _state = MQTT_CONNECTION_TIMEOUT;
                _client->stop();
                return false;
            }
        }

```

I'd like my main loop to continue, or a callback to be called, while the MQTT connection is established, rather than waiting for ages if the MQTT server is unavailable.

**Update:**

I wrote a modification to take a callback function, and called it in an else clause added to that if statement, and discovered that the blocking delay is not this while loop. I think it's in the \_client-\>connect at the start of the method.

# Answer
I had the same question and found an mqtt library that is completely non-blocking.

You need to manually install it and the docs give instructions:

It requires one additional library:

I also liked the example's use of the Ticker library as a general tool for non-blocking code.
> 4 votes

---
Tags: esp8266, callbacks
---


title: Connecting multiple topics- MQTT

text:
# Question
Title: Connecting multiple topics- MQTT
I'm configuring an ESP8266 using Arduino Uno.

I have several MQTT topics I wish it to subscribe, and I do not want to repeat code 3 or 4 times ( in `Python` I would have created a list - and make a for loop to subscribe all )

These are my topics:

```
//MQTT topic
const char* deviceName = "Sonoff1";
const char* deviceTopic = "HomePi/Switches/Sonoff1";
const char* msgTopic = "HomePi/Messages";
const char* groupTopic = "HomePi/All";

```

This is the function registering a single topic:

```
void reconnect() {
        // Loop until we're reconnected
        while (!client.connected()) {
                Serial.print("Attempting MQTT connection...");
                // Attempt to connect
                if (client.connect(deviceName,user, passw)) {
                        Serial.println("connected");
                        pub_msg("Power On");
                        client.subscribe(deviceTopic);
                } else {
                        Serial.print("failed, rc=");
                        Serial.print(client.state());
                        Serial.println(" try again in 5 seconds");
                        // Wait 5 seconds before retrying
                        delay(5000);
                }
        }
}

```

Appriciate you kind help,

Guy

# Answer
just for a closure:

added an array (thank to Juraj):`const char* topicsArry[]={deviceTopic, msgTopic, groupTopic, "HomePi/Dvir/Clock", "HomePi/Dvir/Alerts"};`

a for loop to over this that loop, and using `sizeof` ( which was not trivial for me ), led to :

```
void reconnect() {
        // Loop until we're reconnected
        while (!client.connected()) {
                Serial.print("Attempting MQTT connection...");
                // Attempt to connect
                if (client.connect(deviceName,user, passw)) {
                        Serial.println("connected");
                        pub_msg("Power On");
                        for (int i=0; i<=sizeof(topicsArry)/sizeof(char *); i++){
                          client.subscribe(topicsArry[i]);
                          char msg[50];
                          sprintf(msg, "Subscribed to %s",topicsArry[i]);
                          pub_msg(msg);
                        }
                } else {
                        Serial.print("failed, rc=");
                        Serial.print(client.state());
                        Serial.println(" try again in 5 seconds");
                        // Wait 5 seconds before retrying
                        delay(5000);
                }
        }
}

```
> 1 votes

# Answer
You can make life easier if you arrange your topic names hierarchically. As an example suppose we have a multimedia controller that accepts various commmands:

* mediaserver/set/volume
* mediaserver/set/pause
* mediaserver/set/audio/source
* mediaserver/set/video/subtitles
* etc...

You can then subscribe to "mediaserver/set/#"

For looping over the array of topics, you can take advantage of modern C++'s range-based for loop:

Example code:

```
const char *topicArry[] = {
    deviceTopic, msgTopic, groupTopic,
    "HomePi/Dvir/Clock", "HomePi/Dvir/Alerts"
};
void reconnect() {
    // Loop until we're reconnected
    while (!client.connected()) {
        Serial.print("Attempting MQTT connection...");
        // Attempt to connect
        if (client.connect(deviceName,user, passw)) {
            Serial.println("connected");
            pub_msg("Power On");
            for (const char *topic : topicsArry) {
                client.subscribe(topic);
                char msg[50];
                sprintf(msg, "Subscribed to %s",topic);
                pub_msg(msg);
            }
        } else {
            Serial.print("failed, rc=");
            Serial.print(client.state());
            Serial.println(" try again in 5 seconds");
            // Wait 5 seconds before retrying
            delay(5000);
        }
    }
}

```
> 5 votes

---
Tags: esp8266
---


# Question
Title: Unpredictable behavior of a 74HC595, Q0 has no output and LED flickering
Below is my schematics:

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

Here is my code:

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

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

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

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

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

```

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

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

Some easy checks:

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

---
Tags: arduino-mega
---


title: How to toggle a pin (LED) simply

text:
# Question
Title: How to toggle a pin (LED) simply
I am not a programmer but rather a hardware guy. In the good old machine code days, you could 'read' the status of the port and flip it.. admittedly a much simpler processor. Is it not possible to do this with the 328 without many lines of code?

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

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

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

# Answer
> 2 votes
To toggle a pin, just read the pjn and invert the value:

```
#define LEDPIN 2

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

```

You can also just "remember" the last value:

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

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

```

---
Tags: pins
---


# Question
Title: How to perform multitask using arduino such as update data as well as check condition?
Here data is updated after every 2 seconds. But when the condition is true then the valve and motor process starts and data is updated only after completion of that part (i.e., data is updated after 25 seconds). I want data updation and condition checking simultaneously.

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

#define ONE_WIRE_BUS 4
#define TEMPERATURE_PRECISION 9

#define motor 6
#define valve 7

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

const float thld = 35;

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

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

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

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

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

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

delay (2000);
 }

```

# Answer
You need to think about this with a real-world analogue.

I like to use boiling an egg...

There are three ways you can boil an egg:

## Blocking operation

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

## Timer operation

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

## Time polling

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

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

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

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

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

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

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

```

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

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

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

```
(later_time - earlier_time) compared-with duration

```

There is a library I like that makes all of this so easy: "Ticker"

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

The default is to use microsecond resolution with millisecond specification:

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

```

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

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

```

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

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

```

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

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

```

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

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

#define ONE_WIRE_BUS 4
#define TEMPERATURE_PRECISION 9

#define motor 6
#define valve 7

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

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

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

void check_sensors();

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

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

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

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

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

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

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

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

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

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

```
> 0 votes

# Answer
Not all processes are time-based, so for completeness

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

```
> 0 votes

---
Tags: relay, temperature-sensor, home-automation
---


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

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

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

}

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

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

void loop() {

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

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

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

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

    }

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

```

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

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

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

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

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

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

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

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

  Serial.begin(9600);
}

void loop() {

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

  if ( PhotoValue < 100 ) {

    if ( !car_detected ) {
      car_detected = true ;

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

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

```

---
Tags: sensors, led
---


title: Arduino array error

text:
# Question
Title: Arduino array error
I'm writing a program that has a sub program that saves values to an array, but the sub program that saves the values to the array comes back with an error telling me that the array isnt declared in that scope.

I'm fairly new to this and self taught but even when I try and pass the array into the sub program I get the same error. I'm sure its a fairly simple obvious error I'm making but I just cant get it to work.

If anyone sees any other errors or better ways for me to write any of this any help would be greatly valued as I'm still not confident on what I'm supposed to be doing.

```
#include <HX711.h>

#include <Wire.h>  // IC2 communication

#include <LiquidCrystal_I2C.h>  //LCD
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4); // Change to (0x27,16,2) for 16x2 LCD.

int max_load;
int interval;
int max_load_prev;
int interval_prev;
int mode;
int handle_weight;
int tip_weight;
int stop1;
int mode_previous;
int interval_sum;

int mode1 = 53;
int mode2 = 51;
int mode3 = 49;
int start1 = 39;
int start2 = 37;
int increment = 47;
float potentiometer1 = A0;
float potentiometer2 = A1;
int tare_1 = 45;
int tare_2 = 43;

//stepper motor controller
int stepPin = 12;
int dirPin = 13;

//sensor readings
  HX711 tip_read;
  HX711 handle_read;
  int DOUT_tip = 6;
  int DOUT_handle = 5;
  int CLK_tip = 4;
  int CLK_handle = 3;

void setup() {
  // put your setup code here, to run once:

  lcd.init();
  lcd.backlight();

  //saving to array//
  float data_storage_array[600][3];

  pinMode(mode1, INPUT);
  pinMode(mode2, INPUT);
  pinMode(mode3, INPUT);
  pinMode(start1, INPUT);
  pinMode(start2, INPUT);
  pinMode(increment, INPUT);
  pinMode(stop1, INPUT);
  pinMode(potentiometer1, INPUT);
  pinMode(potentiometer2, INPUT);

  //sesnor readings
  tip_read.begin(DOUT_tip, CLK_tip);
  tip_read.set_scale(55);// change to calibration factor
  handle_read.begin(CLK_tip,CLK_handle);
  handle_read.set_scale(55);// change to calibration factor

  pinMode(tare_1, INPUT);
  pinMode(tare_2, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  mode_previous = 0;
  interval = 25;
  max_load_prev = 0;
  interval_prev = 0;
  interval_sum = 0;
  while (digitalRead(start1) == 0) {
    if (digitalRead(mode1) == 1) {
      mode = 1;
    }
    if (digitalRead(mode2) == 1) {
      mode = 2;
    }
    if (digitalRead(mode3) == 1) {
      mode = 3;
    }
    if (mode_previous != mode) {
      Display_mode_set_up(mode);
      mode_previous = mode;
    }
    if (digitalRead(increment) == 1) {
      delay(500);
      if (interval >= 1000) {
         interval = 25;
      }
      else if (interval < 1000) {
        interval = interval + 25;
      }
    }
    max_load = max_load_reading();
    if (max_load_prev != max_load or interval_prev != interval){
      Display_value_set_up(max_load, interval, mode);
      max_load_prev = max_load;
      interval_prev = interval;
    }
    Display_output(handle_weight, tip_weight);

  tare_one();
  }
  if (mode == 1) {
    mode_one(max_load, tip_weight);
  }
  else if (mode == 2) {
    mode_two(max_load, interval, handle_weight, tip_weight);
  }
  else if (mode ==3) {
    mode_three(max_load, interval, handle_weight, tip_weight);
  }
  Pause_stop();
}

//---SUB ROUTINES---

void mode_one(int max_load, int tip_weight) {
  tip_weight = read_tip();
  while (tip_weight < max_load) {
    tip_weight = read_tip();
    turn_motor();
    Pause_stop();
    Display_output(handle_weight, tip_weight);
  }
}

void mode_two(int max_load, int interval, int handle_weight, int tip_weight) {
  int aim_value;
  aim_value = 0 + interval;
  tip_weight = read_tip;
  while (tip_weight < max_load){
    while (tip_weight < aim_value){
      turn_motor();
      Pause_stop();
      Display_output(handle_weight, tip_weight);
      tip_weight = read_tip();
    }
    save_to_array(interval_sum);
    aim_value = aim_value + interval;
    while (digitalRead(start2) == 0) {
      delay(1);
    }
  }
  send_values_to_pc();
}

void mode_three(int max_load, int interval, int handle_weight, int tip_weight) {
  int aim_value;
  aim_value = 0 + interval;
  tip_weight = read_tip();
  while (tip_weight < max_load) {
    while (tip_weight < aim_value) {
      turn_motor();
      Pause_stop();
      Display_output(handle_weight, tip_weight);
      tip_weight = read_tip();
    }
    save_to_array(interval_sum);
    aim_value = aim_value + interval;
    delay(10000);
  }
  send_values_to_pc();
}

void tare_one() {
  if (tare_1 == HIGH) {
    tip_read.tare();
  }
  if (tare_2 == HIGH) {
    handle_read.tare();
  }
}

void turn_motor() {
  digitalWrite(dirPin, HIGH);
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(500);
  digitalWrite(stepPin, LOW);
  delayMicroseconds(500);
}

int read_tip() {
  int weight;
  weight = tip_read.get_units();
  return weight;
}

int read_handle() {
  int weight;
  weight = handle_read.get_units();
  return weight;
}

void save_to_array(int interval_sum) {
  data_storage_array[interval_sum][0] = interval_sum;
  data_storage_array[interval_sum][1] = tip_read.get_units();
  data_storage_array[interval_sum][2] = handle_read.get_units();
  interval_sum = interval_sum + 1;
}

void send_values_to_pc() {
}

int max_load_reading() {
  int KG_value;
  int g_value;
  int load_max;
  KG_value = analogRead(potentiometer1);
  g_value = analogRead(potentiometer2);
  KG_value = KG_value * 2;
  KG_value = KG_value/ 100;
  KG_value = round(KG_value);
  KG_value = KG_value* 100;
  g_value = g_value/ 10;
  g_value = round(g_value);
  if (g_value >= 100){
    g_value = 99;
  }
  load_max = KG_value + g_value;
  return load_max;
}

void Pause_stop() {
  if (digitalRead(stop1) == 1){
    delay(1000);
    while (digitalRead(start1) == 0){
      if (digitalRead(stop1) == 1){
        motor_unwind();
      }
      else{
        delay(100);
        lcd.setCursor(0, 2);
        lcd.print("Program Paused");
      }
    }
    lcd.setCursor(0, 2);
    lcd.print("                    ");
  }
}

void motor_unwind() {
  tip_weight = read_tip();
  while (tip_weight < 100) {
    digitalWrite(dirPin, LOW);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
  }
  int count = 100;
  while (count > 0) {
    digitalWrite(dirPin, LOW);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
    count = count -1;
  }
}

void Display_mode_set_up(int mode) {
  lcd.setCursor(0, 0);
  if (mode == 1) {
    lcd.print("Mode: Max           ");
    lcd.setCursor(0, 1);
    lcd.print("MLoad:");
    lcd.setCursor(12, 1);
    lcd.print("inti:---");
  }
  if (mode == 2) {
    lcd.print("Mode: Incrimental    ");
    lcd.setCursor(0, 1);
    lcd.print("MLoad:");
    lcd.setCursor(12, 1);
    lcd.print("inti:   ");
  }
  if (mode == 3) {
    lcd.print("Mode: Automatic      ");
    lcd.setCursor(0, 1);
    lcd.print("MLoad:");
    lcd.setCursor(12, 1);
    lcd.print("inti:   ");
  }
  lcd.setCursor(0, 3);
  lcd.print("Tip:");
  lcd.setCursor(9, 3);
  lcd.print("Handle:");
}

void Display_value_set_up(int max_load, int interval, int mode) {
  if (mode == 1) {
    lcd.setCursor(6, 1);
    lcd.print("      ");
    lcd.setCursor(6, 1);
    lcd.print(max_load);
  }
  if (mode == 2 or mode == 3) {

    lcd.setCursor(6, 1);
    lcd.print("      ");
    lcd.setCursor(6, 1);
    lcd.print(max_load);

    lcd.setCursor(17, 1);
    lcd.print("   ");
    lcd.setCursor(17, 1);
    lcd.print(interval);
  }
}

void Display_output(int handle_weight, int tip_weight) {
  tip_weight = read_tip();
  handle_weight = read_handle();
  lcd.setCursor(4, 3);
  lcd.print(tip_weight);
  lcd.setCursor(16, 3);
  lcd.print(handle_weight);
}

```

# Answer
You are declaring `float data_storage_array[600][3]` in `setup()`, and using it in another function, that can't "see" it.

The simplest way of making it work is making your array global by declaring it at the top in the section where you declare other variables like `max_load`.
> 1 votes

# Answer
As others have mentioned, your array is out of scope and can only be used in the `setup()` function. I have moved this out of the `setup()` function and into the global variable section.

I am also cautious of how much SRAM you were using with your (600 x 3 =) 1800 float elements. So I have changed it to ints and reduced it to 250 x 3. You have put down that you are using the Arduino Mega, so this could be expanded further if necessary.

Your variable `interval_sum` was set to increment with no upper limit. This means you would end up going beyond the limits of the array. I have fixed this.

I have reviewed your code briefly and added some fixes and some comments. It is untested. I hope this helps you.

```
#include <HX711.h>
#include <Wire.h>  // IC2 communication
#include <LiquidCrystal_I2C.h>  //LCD

LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4); // Change to (0x27,16,2) for 16x2 LCD.

int max_load;
int interval;
int max_load_prev;
int interval_prev;
int mode;
int handle_weight;
int tip_weight;
int stop1;
int mode_previous;
int interval_sum;

const int mode1 = 53;    // <-- added the const keyword to all pin definitions as they dont change
const int mode2 = 51;
const int mode3 = 49;
const int start1 = 39;
const int start2 = 37;
const int increment = 47;
const int potentiometer1 = A0;    // <-- Changed to int as it is only a pin definition
const int potentiometer2 = A1;    // <-- Changed to int as it is only a pin definition
const int tare_1 = 45;
const int tare_2 = 43;

//stepper motor controller
const int stepPin = 12;
const int dirPin = 13;

//sensor readings
HX711 tip_read;
HX711 handle_read;
int DOUT_tip = 6;
int DOUT_handle = 5;
int CLK_tip = 4;
int CLK_handle = 3;

//saving to array//
int data_storage_array[250][3];    // <-- Moved before setup(). Changed to int. Reduced to 250x3 elements.

void setup() {
  // put your setup code here, to run once:
  lcd.init();
  lcd.backlight();

  pinMode(mode1, INPUT);
  pinMode(mode2, INPUT);
  pinMode(mode3, INPUT);
  pinMode(start1, INPUT);
  pinMode(start2, INPUT);
  pinMode(increment, INPUT);
  pinMode(stop1, INPUT);
  pinMode(potentiometer1, INPUT);
  pinMode(potentiometer2, INPUT);

  //sesnor readings
  tip_read.begin(DOUT_tip, CLK_tip);
  tip_read.set_scale(55);// change to calibration factor

  handle_read.begin(CLK_tip,CLK_handle);
  handle_read.set_scale(55);// change to calibration factor

  pinMode(tare_1, INPUT);
  pinMode(tare_2, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  mode_previous = 0;
  interval = 25;
  max_load_prev = 0;
  interval_prev = 0;
  interval_sum = 0;
  while (digitalRead(start1) == 0){
    if (digitalRead(mode1) == 1){
      mode = 1;
    }
    if (digitalRead(mode2) == 1){
      mode = 2;
    }
    if (digitalRead(mode3) == 1){
      mode = 3;
    }
    if (mode_previous != mode){
      Display_mode_set_up(mode);
      mode_previous = mode;
    }
    if (digitalRead(increment) == 1){
      delay(500);
      if (interval >= 1000){
         interval = 25;
      }
      else if (interval < 1000){
        interval = interval + 25;
      }
    }
    max_load = max_load_reading();
    if (max_load_prev != max_load or interval_prev != interval){
      Display_value_set_up(max_load, interval, mode);
      max_load_prev = max_load;
      interval_prev = interval;
    }
    Display_output(handle_weight, tip_weight);
    tare_one();
  }
  if (mode == 1){
    mode_one(max_load, tip_weight);
  }
  else if (mode == 2){
    mode_two(max_load, interval, handle_weight, tip_weight);
  }
  else if (mode ==3){
    mode_three(max_load, interval, handle_weight, tip_weight);
  }
  Pause_stop();
}

//---SUB ROUTINES---

void mode_one(int max_load, int tip_weight){
  tip_weight = read_tip();
  while (tip_weight < max_load){
    tip_weight = read_tip();
    turn_motor();
    Pause_stop();
    Display_output(handle_weight, tip_weight);
  }
}

void mode_two(int max_load, int interval, int handle_weight, int tip_weight){
  int aim_value;
  aim_value = 0 + interval;
  tip_weight = read_tip;
  while (tip_weight < max_load){
    while (tip_weight < aim_value){
      turn_motor();
      Pause_stop();
      Display_output(handle_weight, tip_weight);
      tip_weight = read_tip();
    }
    save_to_array();    // <-- Global variable removed
    aim_value = aim_value + interval;
    while (digitalRead(start2) == 0){
      delay(1);
    }
  }
  send_values_to_pc();
}

void mode_three(int max_load, int interval, int handle_weight, int tip_weight){
  int aim_value;
  aim_value = 0 + interval;
  tip_weight = read_tip();
  while (tip_weight < max_load){
    while (tip_weight < aim_value){
      turn_motor();
      Pause_stop();
      Display_output(handle_weight, tip_weight);
      tip_weight = read_tip();
    }
    save_to_array();    // <-- Global variable removed
    aim_value = aim_value + interval;
    delay(10000);
  }
  send_values_to_pc();
}

void tare_one(){
  if (tare_1 == HIGH) {
    tip_read.tare();
  }
  if (tare_2 == HIGH) {
    handle_read.tare();
  }
}

void turn_motor(){
  digitalWrite(dirPin, HIGH);
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(500);
  digitalWrite(stepPin, LOW);
  delayMicroseconds(500);
}

int read_tip(){
  int weight;
  weight = tip_read.get_units();
  return weight;
}
int read_handle(){
  int weight;
  weight = handle_read.get_units();
  return weight;
}

void save_to_array(){    // <-- Global variable removed
  data_storage_array[interval_sum][0] = interval_sum;
  data_storage_array[interval_sum][1] = tip_read.get_units();
  data_storage_array[interval_sum][2] = handle_read.get_units();
  if (interval_sum >= 249){   // <-- Added this if statement as there was no way to cap this number
      interval_sum = 0;
  }
  else{
      interval_sum = interval_sum + 1;
  }
}

void send_values_to_pc(){

}

int max_load_reading(){
  int KG_value;
  int g_value;
  int load_max;
  KG_value = analogRead(potentiometer1);
  g_value = analogRead(potentiometer2);
  KG_value = KG_value * 2;
  KG_value = KG_value/ 100;
  KG_value = round(KG_value);
  KG_value = KG_value* 100;
  g_value = g_value/ 10;
  g_value = round(g_value);
  if (g_value >= 100){
    g_value = 99;
  }
  load_max = KG_value + g_value;
  return load_max;
}

void Pause_stop(){
  if (digitalRead(stop1) == 1){
    delay(1000);
    while (digitalRead(start1) == 0){
      if (digitalRead(stop1) == 1){
        motor_unwind();
      }
      else{
        delay(100);
        lcd.setCursor(0, 2);
        lcd.print("Program Paused");
      }
    }
    lcd.setCursor(0, 2);
    lcd.print("                    ");
  }
}

void motor_unwind(){
  tip_weight = read_tip();
  while (tip_weight < 100){
    digitalWrite(dirPin, LOW);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
  }
  int count = 100;
  while (count > 0){
    digitalWrite(dirPin, LOW);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
    count = count -1;
  }
}

void Display_mode_set_up(int mode){
  lcd.setCursor(0, 0);
  if (mode == 1){
    lcd.print("Mode: Max           ");
    lcd.setCursor(0, 1);
    lcd.print("MLoad:");
    lcd.setCursor(12, 1);
    lcd.print("inti:---");
  }
  if (mode == 2){
    lcd.print("Mode: Incrimental    ");
    lcd.setCursor(0, 1);
    lcd.print("MLoad:");
    lcd.setCursor(12, 1);
    lcd.print("inti:   ");
  }
  if (mode == 3){
    lcd.print("Mode: Automatic      ");
    lcd.setCursor(0, 1);
    lcd.print("MLoad:");
    lcd.setCursor(12, 1);
    lcd.print("inti:   ");
  }
  lcd.setCursor(0, 3);
  lcd.print("Tip:");
  lcd.setCursor(9, 3);
  lcd.print("Handle:");
}

void Display_value_set_up(int max_load, int interval, int mode){
  if (mode == 1){
    lcd.setCursor(6, 1);
    lcd.print("      ");
    lcd.setCursor(6, 1);
    lcd.print(max_load);
  }
  if (mode == 2 or mode == 3){

    lcd.setCursor(6, 1);
    lcd.print("      ");
    lcd.setCursor(6, 1);
    lcd.print(max_load);

    lcd.setCursor(17, 1);
    lcd.print("   ");
    lcd.setCursor(17, 1);
    lcd.print(interval);
  }
}

void Display_output(int handle_weight, int tip_weight){
  tip_weight = read_tip();
  handle_weight = read_handle();
  lcd.setCursor(4, 3);
  lcd.print(tip_weight);
  lcd.setCursor(16, 3);
  lcd.print(handle_weight);
}

```
> 0 votes

---
Tags: arduino-mega, array
---


# Question
Title: How to efficiently code a long duration timer
I'm working on a battery-powered project. I'm trying to write code, which checks the battery voltage every 30 minutes and changes the color of a LED accordingly. Should I still be using `millis()` or is there a more efficient way to create a timer which tracks these longer time periods? Should I be concerned that the value of millis resets every 50 days, with an example timer like this:

```
bool timer(unsigned long &last_time, unsigned long period)
{
  unsigned long now = millis();
  if (now - last_time >= period) {
    last_time = now;
    return true;
  }
  return false;
}

```

# Answer
> Should I still be using millis() or is there a more efficient way to create a timer which tracks these longer time periods?

For longer time periods you really should use an RTC. You will get much better accuracy (assuming accuracy is what you want). You can also use an alarm on the RTC and use it to trigger an interrupt every 30 minutes and wake the MCU from sleep (so as to save precious battery power) to check the voltage.

> Should I be concerned that the value of millis resets every 50 days, with an example timer like this:

Using that method, where you subtract the previous time from the current time, no, there is nothing to worry about. That is the recommended method to work around the wrapping of the millis() count.
> 4 votes

# Answer
There are various notions of efficiency, depending on what resource you want to optimize for. For a battery-powered project, the most relevant is likely to be *energy*-efficiency. Then, your code may not be the main issue.

If you plan for your LED to be turned on continuously, this is going to significantly tax your battery. Your first concern should then be to minimize the power drain of the LED itself: make the current through it as low as convenient, and maybe consider powering it through a DC-DC converter in order to avoid wasting too much energy in the series resistor. If your Arduino has a power-indicator LED, you should also unsolder it. If it has a second microcontroller that it always on (like the Uno), you should find a way to disable it.

Regarding the energy consumption of the CPU running your code, the only way to be energy-efficient is to have it sleep most of the time, and wake it up only when there is useful job to do. Unfortunately, the Arduino core provides no standard way to sleep. You may have to look into architecture-specific solutions, or search for a library that abstracts this for you. On an AVR, for example, you may be able to significantly lower the consumption by calling `sleep_mode()` once within your `loop()`. This will put your device in a “shallow” sleep mode, and it will be woken up by the next timer interrupt (these happen every 1.024 ms). If you want to go to deep sleep, you will have to arrange a wake-up source other than the timer interrupt. An RTC could be an option. However, if you do not need the 30 minute period to be accurate, you may as well use the watchdog timer (which is ultra-low power) as an interrupt source.

There are many other things to be aware of when you care about power consumption. I recommend reading Power saving techniques for microprocessors, by Nick Gammon, which covers most of the relevant issues. Note, however, that it discusses mostly AVR.
> 2 votes

# Answer
A library I like for this kind of task is Ticker

```
#include <Ticker.h>

void batterycheck() {
    // called by battcheck ticker every 30 minutes
    // read_voltage...
    // set_led_color...
}

Ticker battcheck(batterycheck, 30*60*1000, 0);

setup() {
    battcheck.start();
}

loop() {
    battcheck.update();
}

```

There's no advantage over doing it manually but I found this library after writing almost exactly the same code for a project that had a bunch of timers running concurrently.
> 2 votes

# Answer
Your posted code **will never fail**.

See http://gammon.com.au/millis

Let me put it this way. Does your clock "fail" at midnight?

Subtracting the *start time* from *time now* always works (even after 50 days) because of the way unsigned integers work.
> 1 votes

---
Tags: timers, time
---


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

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

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

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

  Serial.begin(9600);

}

void loop() {

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

int redValue;
int greenValue;
int blueValue;

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

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

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

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

}

```

# Answer
As I said, you MUST either

* know the spectrum of the light source that exposes your sample or
* calibrate the sensor under the exact same light you use for detection later on.

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

---
Tags: arduino-uno, arduino-ide, sensors, rgb-led, calibration
---


# Question
Title: How to get the name of connected device over BLE?
I am implementing a BLE peripheral in my firmware with Arduino ESP32.

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

How can I do that?

```
#include <BLEServer.h>

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

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

        ble.deviceConnected = true;

        #if SUPPORT_LEDS_INDICATOR

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

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

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

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

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

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

```

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

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

There is a function in the `BLEServer` class:

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

```

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

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

```

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

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

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

---
Tags: esp32, ble
---


# Question
Title: How to automatically reset the NRF24L01 module
For my home-automation project I'm using several arduino nano's with each a NRF24L01+ module. Each module is able to both receive and transmit with one another. Everything seemed to be flawless for a couple of hours, but after a couple of hours it either stops transmission (completely frozen) of receives the last data repeatedly. In my design I'm using the RF24 and RF24Network libraries, I was wondering whether someone managed to automatically reset the NRF24L01 module using code, when one of these errors occured, and could share his/her code?

I already found this form, but this is only using the standard RF24 library, whereas I'm also using the RF24Network library. Furthermore, in this form it is having a seperate TX and RX side, whereas I like to have each module to be able to both send and receive.

Some extra side information, I use a stable power supply with a capacitor connected to the module, also the wires are soldered to the module.

I hope somebody can help me with this,

Guido

# Answer
This is a known problem with those chips (especially Chinese clones). It is caused when a chip gets stuck in TX mode waiting for an ACK that never arrives back.

The chips don't have a "reset", but switching them into low power mode and then back on again, which doesn't affect any register settings, aborts the current TX operation.

`RF24Network` is merely a protocol layer on top of the `RF24` library. That `RF24` library has `powerDown()` and `powerUp()` methods. Simply call powerDown followed by powerUp on your RF24 driver object.
> 4 votes

# Answer
Same issue; Simple work-around did it for me: (1) supply +3.3V power the nRF24L01 from a digital pin, using a forward bias diode/LED (with Vf in range 1.7-2.3V) to reduce voltage to compliant range (2.7-3.3V), then (2) in **setup** say, switch the pin to OUT/HIGH

pinMode(NRFPIN, OUTPUT); digitalWrite(NRFPIN, HIGH);

Notes:

A) If you have 3.3V device then you can skip voltage reduction in (2)

B) nRF24L01 power consumption peaks at 13mA (quiescent is miniscule) so well within spec for output pin

C) Of course you can do (1) with a voltage divider, or a level converter chip, etc, but the appeal of the LED (I checked Vf across 100 ohm @5V to find a decent match) is that it is simple, passive and in-line and has the nice added advantage of a faint flash when transmitting or receiving!

Look here also nRF24L01 reset
> 2 votes

# Answer
@Majenko thank you for your suggestion, I have been playing around a little bit with the powerDown() and powerUp() functions but unfortunately I haven't got it to work yet. Again, it seemed to work for a couple of hours and then again seem to get stuck. Therefore, I also included my code to see if I maybe made some major mistakes. Furthermore, I assume that I'm having such Chinese clones of the NRF24L01+, as I have bought mine on Aliexpress.

I have included several parts of my code, the following part resets the NRF24L01+ module once a failure is detected. In here I also included the suggested powerDown and powerUp functions.

```
void NetworkReconnect()
{
  pinMode(CE_PIN, OUTPUT); digitalWrite(CE_PIN, HIGH);
  pinMode(CS_PIN, OUTPUT); digitalWrite(CS_PIN, HIGH);

  radio.powerDown();

  radio.begin();

  radio.powerDown();

  Network.begin(90, thisNode);

  delay(100);

  radio.setPALevel(RF24_PA_MAX);
  radio.setDataRate(RF24_1MBPS);

  radio.powerUp();
}

```

The following code I have in my **void.loop()**, every 5 seconds I check the network connection, by calling **NetworkCheckConnection()** (see last part of included code). Which tries to figure out whether the module has crashed, I found this failure detection as a suggestion at a discussion form on the RF24 library on GitHub Discussion. Furthermore, the while loop is limited to only 500ms to avoid being in an infinite loop, if this is exceed, the function **NetworkReconnect()** is called again.

```
void loop()
{

  Network.update();

  if (millis() - Timer > 5000)
  {
    NetworkCheckConnection();
    Timer = millis();
  }

  if(radio.failureDetected){
    radio.failureDetected = false;
    delay(250);
    Serial.println("Radio failure detected, restarting radio");
    NetworkReconnect();
  }

  if (Network.available())
  {
    uint32_t failTimer = millis();
    while (Network.available())
    {
      if(millis() - failTimer > 500)
      {
        radio.failureDetected = true;
        Serial.println("Radio available failure detected");
        break;
      }

      ... The usual Network.read stuff ...

    }
  }

  ... Remainder of code ...

}

```

And lastly the **NetworkCheckConnection()** code, this code is based on the RF24 Failure handling example and the principles used for checking connectivity of the RF24Mesh network link (see line 140).

```
void NetworkCheckConnection()
{
  if (radio.getDataRate() != RF24_1MBPS)
  {
    radio.failureDetected = true;
    Serial.println("CheckConnection FailureDetected");
    return;
  }
  // see line 140 of: https://github.com/nRF24/RF24Mesh/blob/master/RF24Mesh.cpp
  bool ok = 0;
  if(radio.rxFifoFull() || (Network.networkFlags & 1))
  {
    return;
  }
  RF24NetworkHeader header(otherNode, NETWORK_PING);
  ok = Network.write(header,0,0);
  if(ok) { Serial.println("Network Connected");       return;}
  if(!ok){ radio.stopListening(); NetworkReconnect(); return;}
}

```

Lastly, I also call the **NetworkReconnect()** function if any of my Network.write functions fails.

I hope that you can give me some suggestions on how to get this module to work more reliable, any suggestion is welcome!

Thanks in advance :)
> 0 votes

---
Tags: programming, arduino-nano, communication, nrf24l01+, software
---


title: SIM800L stays in 1sec-blink-state

text:
# Question
Title: SIM800L stays in 1sec-blink-state
I've bought such on Amazon. My main problem is that it stays in 1sec-blink, meaning it can't registrer cellular network.

First I tried with all anntennas possiblities (one of each, both, none) - failed.

Using NodeMCU (for 3.3 TxRx) and `SoftwareSerial.h` to communicate. It answers all AT command as expected.

I tried several powering possibilities (as noted extensively about 2A on the internet), including 18650 , 2000mAh battery connected only to SIM800L module with no MCU connected, still same state.

What Can be done else?

SEE PELEPHONE:

# Answer
> 1 votes
Your mobile network provider does not provide a 2G (GPRS / GSM) network.

2G is graduallly being phased out around the globe, so switching to an LTE modem is really the way forward.

If you still want to use the SIM800L then you need a network provider that gives 2G services. Fortunately the SIM800L is a "quad band" modem, so it will work with pretty much any 2G provider (it works on 850/900/1800/1900MHz, hence the "quad" of "quad band").

---
Tags: sim800
---