text:
AT command validation does not appear on the serial monitor
I can't validate an AT command. Would anyone have any suggestions as to what I might be doing wrong? It should be printing "Sending successful! or "Sending failed!", but it doesn't show any text.
if (httpReadResponse.indexOf("OK") != -1) {
  Serial.println("Envio bem-sucedido!");
} else {
  Serial.println("Falha no envio!");
}

My serial monitor is printing this:

AT+HTTPDATA=192,5000\
DOWNLOAD\
OK\
AT+HTTPACTION=0\
OK\
AT+HTTPREAD

Full function:
void sendHttpRequest(int distance_cm) {
  gsm_send_serial("AT+HTTPINIT");
  gsm_send_serial("AT+HTTPPARA=CID,1");
  gsm_send_serial("AT+HTTPSSL=1");
  gsm_send_serial("AT+HTTPPARA=URL," + url2 + "/" + distance_cm + "/" + id_cliente + "/" + id_caixa + "/" + ipadd1 + "/" + sinal + "/" + totalMilliLitres + "/" + vazao_atual + "/" + apikey);
  gsm_send_serial("AT+HTTPPARA=CONTENT,application/x-www-form-urlencoded");
  gsm_send_serial("AT+HTTPDATA=192,5000");
  gsm_send_serial("param=Aqualizar");
  gsm_send_serial("AT+HTTPACTION=0");

  String httpReadResponse = gsm_send_serial("AT+HTTPREAD");

  gsm_send_serial("AT+HTTPTERM");

  if (httpReadResponse.indexOf("OK") != -1) {
    Serial.println("Sending successful!");
  } else {
    Serial.println("Sending failed!");
  }
}

The declaration of url2 may be important to interpreting gsm_send_serial("AT+HTTPPARA=URL," + url2... It would be better to provide all the variable declaration involved, if not compilable and testable code.

what is the value  of httpReadResponse.indexOf("OK")?

THE VALUE IS "OK" IN THE SERIAL

Print the value of the response,  ie. Serial.println(httpReadResponse);

String httpReadResponse = gsm_send_serial ("AT+HTTPREAD"); How is function gsm_send_serial() defined ? You are clearly expecting it to return a String under the circumstances that you are using it. Also, which Serial instance is connected to the serial monitor? Does, for example, Serial.println("Hello World") work? Which serial instance is connected to the GSM device?

It would help, if you provide a minimal compilable example code, that demonstrates your problem. How is the SIM800 connected, that the Serial Monitor and the Arduino both see the modules AT answer?

AT+HTTPACTION=0

AT+HTTPACTION=0 starts a GET session. Based on your code, you are supposed to create a POST session, which should be AT+HTTPACTION=1.
Read SIM800 Series_IP_Application Note which provides the examples for both GET and POST request based on the SIMCOM HTTP AT-command set. The application note can be found at SIMCOM's website (requires registration for free download) or simply google "SIM800 Series_IP_Application Note" as there are many sites that have the document available without the need for registration.


text:
PCA9685 servo not working

I am working on a project where I want to connect 12 servos together.
I got:

Arduino Nano Every
PCA9685 16-channel, 12-bit PWM/servo shield
Power supply 5 V, 10 A

I got a PCA9685 16-channel, 12-bit PWM/servo shield from Adafruit. I connected all the wires as they are supposed to be and I connected the shield to an external power supply, but the servos are not moving.
I don't know where the problem comes from.
I'm using the Adafruit library. It's not even moving one servo (although the servo moves when connected directly to the Arduino).
I have another wire connected to add a button. Here is my wiring diagram:

I am using code from the original project, so that shouldn't be the problem.

First, you should solder the connections to the Arduino properly, and check you haven't shorted reset to ground with stray wire strands sticking out.

Maybe use more flux when soldering, sl that you get nice smooth connections. The green while doesn't look like it is actually connected to the solder pad

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Where can I store secret keys?
I want to store a password in my ESP8266 program, but I can't figure out a way to do it that makes it inaccessible to hackers. Even if I encrypt it, I'd still need to store the private key for the encryption process somewhere. I only have two ideas and both have issues:

As a const in program code
The compiled binary will be publicly available, so anyone who is able to spend some time interpreting the compiled file would eventually be able to find the password stored in it.
In EEPROM
This is at least safe from people who aren't users, but any user would still be able to upload their own program and read the EEPROM to find the password.

Surely this is a common issue, especially in commercial products. What is the solution that I'm not thinking of?

Maybe you should tell us what you are trying to do that requires you to store a password.

If it is that important, then you probably need a TPM module/chip for storing and using the private key. Though you then should only send the password in encrypted form. If you just decrypt the password with the TPM and then use it directly, someone might be able to extract it. This seems to be a use case of public key authentication involving a TPM.

The ESP8266 is the wrong device for this. You cannot store anything inside it with protection against read-out.
Any user software is in external memory, so even hobbyists can read all of it. If you provide the binary for download (because of updates, or a DIY build), it even simplifies the read-out.
If you apply asymmetric encryption, for example via a key from an external server, you cannot stop a hacker to apply the same algorithm.
Final note: There is no such thing as absolute security. You can reach some degree, but it is hard.

As @the busybee already said, the ESP8266 is the wrong chip for such applications. Since you always have the possibility to change the firmware. You could write your own bootloader that only accepts your firmware, but this is a huge project by itself.
Encrypting the data should normally be totally ok, if the encryption algorithm is sufficiently strong.
But since you have a ESP8266, you could also transfer the data encrypted to a cloud server which manages/holds the data for you.
But with the hardware you have, it's going to be difficult to lock or hide the data in the EEPROM.
Regards
Dario

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Why doesn't this code for an 8x8 LED matrix work properly?
There's an Arduino Uno (Keyestudio KS0078) and a 788BS 8x8 LED matrix.
I built the circuit as on the image and ran this program:
#define MY_PERIOD 200

int displayColumn = 0;
uint32_t tmr1;

unsigned char Text[] = { 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c };

void Draw_point(unsigned char x, unsigned char y) {
  clear();
  digitalWrite(x + 2, HIGH);
  digitalWrite(y + 10, LOW);
  delay(1);
}

void show_num(void) {
  unsigned char i, j, data;
  for (i = 0; i < 8; i++) {
    data = Text[i];
    data <<= displayColumn;
    for (j = 0; j < 8; j++) {
      if (data & 0x01) {
        Draw_point(j, i);
      }
      data >>= 1;
    }
  }
}

void setup() {
  Serial.begin(9600);
  int i = 0;
  for (i = 2; i < 18; i++) {
    pinMode(i, OUTPUT);
  }
  clear();
}

void loop() {
  show_num();
  if (millis() - tmr1 >= MY_PERIOD) {
    tmr1 = millis();
    displayColumn++;
    if (displayColumn > 7) {
      displayColumn = 0;
    }
  }
}

void clear() {
  for (int i = 2; i < 10; i++)
    digitalWrite(i, LOW);
  for (int i = 10; i < 18; i++)
    digitalWrite(i, HIGH);
}

I got the code from the Keyestudio examples wiki and added a part with displayColumn and shifting to the left every 0.2 sec. But instead of fading out fully on the 7th step, one LED (x=0, y=6) stays on. Even if I stop executing show_num when displayColumn > 7 it stays on as long as there is power. Why?
UPD: I removed dynamic shifting in loop and set displayColumn in 5, 6 and 7 - the display showed correct result and was empty when displayColumn was equal to 7. Obviously the bug hides between "transitions".
UPD2: If I try the programm with other symbol, the bug on the step 7 always repeats with other LED which was the last lighted one on the step 6.
UPD3: Debug data by request of @thebusybee (repeated blocks removed)
x,y:2,1 x,y:3,1 x,y:4,1
x,y:1,2 x,y:5,2
x,y:1,3 x,y:5,3
x,y:1,4 x,y:5,4
x,y:1,5 x,y:5,5
x,y:1,6 x,y:5,6
x,y:2,7 x,y:3,7 x,y:4,7
displayColumn: 1
x,y:3,1 x,y:4,1 x,y:5,1
x,y:2,2 x,y:6,2
x,y:2,3 x,y:6,3
x,y:2,4 x,y:6,4
x,y:2,5 x,y:6,5
x,y:2,6 x,y:6,6
x,y:3,7 x,y:4,7 x,y:5,7
displayColumn: 2
x,y:4,1 x,y:5,1 x,y:6,1
x,y:3,2 x,y:7,2
x,y:3,3 x,y:7,3
x,y:3,4 x,y:7,4
x,y:3,5 x,y:7,5
x,y:3,6 x,y:7,6
x,y:4,7 x,y:5,7 x,y:6,7
displayColumn: 3
x,y:5,1 x,y:6,1 x,y:7,1
x,y:4,2
x,y:4,3
x,y:4,4
x,y:4,5
x,y:4,6
x,y:5,7 x,y:6,7 x,y:7,7
displayColumn: 4
x,y:6,1 x,y:7,1
x,y:5,2
x,y:5,3
x,y:5,4
x,y:5,5
x,y:5,6
x,y:6,7 x,y:7,7
displayColumn: 5
x,y:7,1
x,y:6,2
x,y:6,3
x,y:6,4
x,y:6,5
x,y:6,6
x,y:7,7
displayColumn: 6

x,y:7,2
x,y:7,3
x,y:7,4
x,y:7,5
x,y:7,6

displayColumn: 7

//many many empty strings
displayColumn: 8

add debugging code to your program

@jsotola I'v tried to get print of x, y from some code parts in some times and I have no idea anymore. After step 6 I found nothing activating the pixel. So seems the pixel still acive after previous teps but why so and why one? My experience is too poor to get it.

This can't be correct: data = Text[i];  data <<= displayColumn;. The first assignment will be overwritten by the second. It also looks odd that you are also incrementing  displayColumn  in the loop() as well as left shifting it in function shownum(). It will get some weird values in it. The original code, if it worked,  would have shown a '0'. What are you attempting to do, scroll the '0' from right to left across the display?

@6v6gt The second statement shifts the value in data. It is not a simple assignment overwriting the first. In contrast, the first statement is necessary to set a defined value in data.

@6v6gt yes, kinda. I don't know it looks odd or not cause I'm newbee in Arduino. But I see no logical contradictions in the order of assignment and besides it works strange but almost properly. The first assignment sets next byte ("the display line") in data, the second shifts it to left, and every 0.2 sec displayColumn increases by 1 ("one display column"). I try to animate original code slightly to understand better how to cook displays

Oops. I did not look at the the operator too closely. To me the code looks OK. You could try slowing the multiplexing down and look for any odd effects. When I work with a matrix display, I find it easier to define an array which matches the display, load the array, then write it out. This way, there is an intermediate state you can check.

Your code looks fine to me, I checked the algorithm with debug prints, but no output to an LED matrix. -- Your wiring according to the drawing looks fine, too. -- Please [edit] your question to clarify: How long does this single erroneous LED light? Your code repeats endlessly. Does this happen?

@thebusybee done.

@6v6gt I'll try it but I found this way too verbose. I ran same code as you said for a 7-segments display experiment but the method with byte sequence looks more interesting and laconic for me, so I intend to figure out why I encountered the bug.

Does this phenomenon of the unwanted led remaining on show when the code is continually scrolling? Obviously, you stopped the cycle to make the pictures. With the way function Draw_point() is written, where the display is cleared and then a led is switched on, it is inevitable that if there is a pause anywhere, the last led switched on will remain on. As a crude test, you could add another clear() after the delay(1) in function Draw_point() or perhaps after show_num()  in the loop().

Please add debug prints like that: 1) For x and y in Draw_point() without line break. 2) println() after the for loop over j in show_num(). 3) For displayColumn after increment and rollover in loop() with line break. -- In my reproduction I added also a flag that avoids multiple outputs when displayColumn did not change, but the room here is limited. You might try to insert the same. -- Check that in the last round with displayColumn = 7 no output happens. It should be like that because your pattern has no bit 0 set.

Commonly you don't drive LEDs in reverse to switch them off. Instead you disable their driver, in case of the Arduino you will change the pin mode to input. However, I don't see how this could be an explanation to the effect you observe.

@thebusybee added and there's really no output after the seventh step. I also tried the flag as you said but this way cant draw symbol normally: LEDs just flash for a moment after every displayColumn chsnging. Looks like pin's state resets every loop iteration

@6v6gt the phenomenon is present when the scrilling stops at the final step too, no only when the scrolling is contineous. And yes, final clear() inside Draw_point turns the LED off, and now the code works as needed. Seems I understand your assertion about clear(), this function must be called before any row rendering. The original code draws static symbol so there clear() placed right. I just move it in show_num into first for as first line and now scrolling works correctly. You can write your comment as an answer little more detailed and I'll check it as correct

Good. I'm pleased it works now and it was an interesting puzzle. Maybe even another solution is simply to move the clear() from the beginning of Draw_point() to the end. That should also stop the unwanted led "lingering" for 200ms during the scroll. Anyway, I can't test it so I'll leave you to write up an answer and include the code in it that works best for you. Also note what @thebusybee  implied about making clear() more efficient. Feel free to mention my name in the answer.

I loaded your initial code into a simulator to try it. Unfortunately, the simulator does not have a raw 8x8 dot matrix and I can't spend too long creating one out of individual leds.
What I have done is modified Draw_point() to print out the time (ms) the last led was lit for (if > 5ms). It gives results like "xLast=7, yLast=6, on for 202 ms" and only that led which does not agree exactly with your statement "one LED (x=0, y=6) stays on.". Anyway, it is here: https://wokwi.com/projects/389152026616860673

@6v6gt seems in the original example circuit the display used in "landscape orientation" instead of "portrait" and its coordinate system is overturned. Thank you for helping very much!

As found out during the discussion,
the display must be cleaned before drawing any new row. And since the clear() calling was at the beginning of the Draw_point() and this function was not used in the last step, cleaning was not executed before the last step. This is correct for static rendering but for scrolling it will be correct to move the clear() to the end of the Draw_point() then the project works correctly.
#define MY_PERIOD 200

int displayColumn = 0;
uint32_t tmr1;

unsigned char Text[] = { 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c };

void Draw_point(unsigned char x, unsigned char y) {
  digitalWrite(x + 2, HIGH);
  digitalWrite(y + 10, LOW);
  delay(1);
  clear();
}

void show_num(void) {
  unsigned char i, j, data;
  for (i = 0; i < 8; i++) {
    data = Text[i];
    data <<= displayColumn;
    for (j = 0; j < 8; j++) {
      if (data & 0x01) {
        Draw_point(j, i);
      }
      data >>= 1;
    }
  }
}

void setup() {
  Serial.begin(9600);
  int i = 0;
  for (i = 2; i < 18; i++) {
    pinMode(i, OUTPUT);
  }
}

void loop() {
  show_num();
  if (millis() - tmr1 >= MY_PERIOD) {
    tmr1 = millis();
    displayColumn++;
    if (displayColumn > 7) {
      displayColumn = 0;
    }
  }
}

void clear() {
  for (int i = 2; i < 10; i++)
    digitalWrite(i, LOW);
  for (int i = 10; i < 18; i++)
    digitalWrite(i, HIGH);
}

Thanks to users @6v6gt and @thebusybee for their help in finding the solution.

As an addition to your answer, this is for future visitors who want to learn more.
1. Programming by Accident
Your analysis is correct, mine in an early comment is wrong.
The last LED of the second last "picture" is not cleared when the last "picture" is drawn. This is because you clear the matrix only, if you switch on an LED.
This is your original code:
void Draw_point(unsigned char x, unsigned char y) {
  clear();
  digitalWrite(x + 2, HIGH);
  digitalWrite(y + 10, LOW);
  delay(1);
}

In your solution you clear the complete matrix after the delay, which results in the expected effect.
However, you did not analyze the underlying to the end. You changed something after a random suggestion, and it "works." I have seen this so many times.
We know that Draw_point() handles only one LED. So we do not need to reset all pins to their respective off levels, 14 of the 16 are already fine. It suffices to do this for the single LED just switched on.
void Draw_point(unsigned char x, unsigned char y) {
  digitalWrite(x + 2, HIGH);
  digitalWrite(y + 10, LOW);
  delay(1);
  digitalWrite(x + 2, LOW);
  digitalWrite(y + 10, HIGH);
}

2. Driving the LEDs in Reverse
As I mentioned in a comment, you drive the LEDs of the matrix in reverse, when they are off. We all know that comments will not be read, mostly. So I add this here. ;-)
Most LEDs stand some voltage in reverse. According to the 788BS' data sheet it has 5V as absolute maximum rating. I would not dare to apply that really.
All professionals drive their LED matrices such that only forward current is applied. All other LEDs are not driven at all.
The solution here is to change the pin mode of the pins.
#define MY_PERIOD 200

int displayColumn = 0;
uint32_t tmr1;

unsigned char Text[] = { 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c };

void Draw_point(unsigned char x, unsigned char y) {
  pinMode(x + 2, OUTPUT);
  digitalWrite(x + 2, HIGH);
  pinMode(y + 10, OUTPUT);
  digitalWrite(y + 10, LOW);
  delay(1);
  pinMode(x + 2, INPUT);
  pinMode(y + 10, INPUT);
}

void show_num(void) {
  unsigned char i, j, data;
  for (i = 0; i < 8; i++) {
    data = Text[i];
    data <<= displayColumn;
    for (j = 0; j < 8; j++) {
      if (data & 0x01) {
        Draw_point(j, i);
      }
      data >>= 1;
    }
  }
}

void setup() {
}

void loop() {
  show_num();
  if (millis() - tmr1 >= MY_PERIOD) {
    tmr1 = millis();
    displayColumn++;
    if (displayColumn > 7) {
      displayColumn = 0;
    }
  }
}

You don't need to clear() in setup(), because all pins are initially in "input" mode already.
3. About Flicker
You tried with no delay() and see only a dim display. This is correct as the time the LED is on is short compared to the time of the rest of the program.
With delay(2) you experience flicker. Let's think about the timing here.
There are different "pictures" during the scroll, with the listed number of LEDs switch on:

displayColumn
Number of LEDs switched on

0
16

1
16

2
16

3
11

4
9

5
7

6
5

7
0

Because the Arduino is quite fast, we came approximate the calculations by neglecting the rest of the program.
Each single LED is shown for 2 ms according to delay(2), so a complete picture sums up to repetition periods between (nearly) 0 ms (displayColumn = 7) and 32 ms (displayColumn = 0 to 2). The reciprocal gives us the display frequency, many know the term "frames per second" or frame rate. The lowest frame rate is with the longest period: 1 / 0.032 s = 31.25 Hz. Our eyes see this as flickering. BTW, as soon as the "picture" has fewer LEDs, the display will stop flickering.
Commonly human eyes see no flicker if the frame rate exceeds about 50 to 60 Hz. With delay(1) the periods are only half as long as with delay(2), of course. The lowest frame rate is therefore 62.5 Hz, good enough for no flicker experience.
Please be aware that the frame rate drops with the number of LEDs switched on. If you want to have at least 50 Hz with delay(1), you cannot have more than 20 LEDs: 1 / 50 Hz = 20 ms, which corresponds to 20 LEDs.
The solution here is to show a complete row at the same time. Because then there are just 8 rows to sequence, you can raise to delay(2) again: 8 rows * 2 ms < 20 ms. The specific code is left as an exercise to the reader. Please be aware that you need to take electrical maximum ratings into account. The MCU of the Arduino has limits to the sourced current.
4. Final Note
You might wonder why the linked resource (the Keyestudio examples wiki) shows this "not-so-perfect" source code. Well, as we can see from the bad formatting of the example, it was hacked down in a hurry and without being aware that beginners will be misguided.
Take all such resources with a lot of caution. Unfortunately, this is absolutely necessary. (This includes my answer here, too.)

Just like that, I thought whatever my programm was far from optimum. I read your comment about mode switch but decided to search for materials on this topic because I never saw this method before, so thank you for the explaining with working example!
I also should to note that your first variant needs the clear() executed in the setup().
And one final question - why exactly does delay(1) work as it should? No delay - symbol is dim because we switch it on and off instantly, it's too little time. But the display begins to flicker when delay = 2 or higher. Why 1?


text:
Incremental Rotary Encoder sends data when shaft is untouched
I'm trying to build an Arduino project that counts pulses sent by an encoder.
I've bought an Omron E6B2-CWZ5B-2 2000P/R and face the issue of it sending pulses non-stop, even when I'm not touching it. The code I use is from this video.
I thought that the encoder itself was the problem and bought two encoders like in the video above (LPD3806-400BM-G5-24C), but I faced the exact same problem.
When I connect the encoder to the Arduino 5 V and GND ports, the encoder doesn't seem to work at all (in the video it does without any resistors, etc.). I had to use a different power source, which was a laboratory power supply, which I set to around 6 V.
I connected the A output to digital pin 2 and the B output to digital pin 3 of my Arduino Uno. The problem is - the values just start going up and down at an insane speed without me touching the encoder. If I only connect output A, they go like I'm spinning it hard left, if I connect only the B output, they go like I'm spinning it hard right. If I connect both of them, it's just a massacre of data, like I'm spinning it left and right insanely fast.
The other thing I noticed - if I power up my Laboratory power supply to 12 V and more it seems that the encoder sends even more data per sec.
I only managed to get it working properly once and can not repeat it now. I did the following:
I powered the LPD3806 with 5.5 V externally (lab power supply), took the ground shield of encoder and held it really tight to Arduino Uno USB port. Data spam stopped and the encoder worked properly when I'm twisting the shaft. But I can't repeat this thing now.
It's clear the problem is with grounding, but I wonder how I can fix it to use it in an okay way. And I still wonder how the author of the video above got results with no use of the ground shield at all.
So the question is - how do I fix it and where did I go wrong?
Here are some schematics. I don't know how to do them properly, so I did them with Wokwi. So to read it keep in mind that:

I marked A and B output cables of my LPD3806 encoder as CLK and DT on the rotary encoder from wokwi.com

The VCC and GND symbols at the very top of some schemas here are + and - of my laboratory power supply

I marked my ground shield as SW on the third schema to show where I held it to get it working.

Here's how I tried to power it from the Arduino itself. It just didn't start. No signal; nothing.

So I powered it from the lab power supply. Now the encoder started, but it was just spamming numbers. When I increased the voltage, the number-spamming got faster.

And here's how I got it working once by pulling the ground shield tight to the Arduino USB port (keep in mind in my schema I marked ground shield as SW on the encoder).

Here's the code I use:
volatile unsigned int temp, counter = 0; // This variable will increase or decrease depending on the rotation of encoder

void setup() {
  Serial.begin (9600);
  pinMode(2, INPUT_PULLUP); // internal pullup input pin 2
  pinMode(3, INPUT_PULLUP); // internal pullup input pin 3
  // Setting up interrupt
  //A rising pulse from encoder activates ai0(). AttachInterrupt 0 is digital pin nr 2 on most Arduinos.

  attachInterrupt(0, ai0, RISING);

  // B rising pulse from encoder activates ai1(). AttachInterrupt 1 is digital pin nr 3 on most Arduinos.

  attachInterrupt(1, ai1, RISING);
}

void loop() {
  // Send the value of counter
  if (counter != temp) {
    Serial.println (counter);
    temp = counter;
  }
}

void ai0() {
  // ai0 is activated if digital pin nr 2 is going from LOW to HIGH
  // Check pin 3 to determine the direction
  if (digitalRead(3)==LOW) {
    counter++;
  } else {
    counter--;
  }
}

void ai1() {
  // ai0 is activated if digital pin nr 3 is going from LOW to HIGH
  // Check with pin 2 to determine the direction
  if (digitalRead(2)==LOW) {
    counter--;
  } else {
   counter++;
  }
}

Looking forward for your answers and thanks in advance!

please add the wiring diagram

From the description that sounds like a floating pin, though you already have the internal pullups activated. You wrote, that you use an external power supply for the encoder. Did you connect the grounds of that supply and the Arduino? Have you tried adding stronger external pullup resistors (like 1 to 4.7kOhm)? The seller site, that I found with this encoder claims, that you can connect it directly to Arduino 5V pin. Though it might, that your voltage is right at the lower end of the valid power voltage range of the encoder (4.8V). USB voltage can easily get as low as 4.5V

@chrisl I did try it with external pull-up resistors - no help. But I moved forward a little bit! I did everything like before - I powered LPD3806 with 5.5v externally and got it working properly once.
How I did it - I took the ground shield of encoder and held it really tight to Arduino Uno USB port. Data stopped and encoder only worked properly when I'm twisting the shaft. But I can't repeat this thing now. It's clear the problem is with grounding, but I wonder how can I fix it to use it in an okay way. And I still wonder how the author of the video got results without ground shield at all.

You absolutely need to connect all grounds. Your wiring diagram is missing the connection between external power supply ground and Arduino ground

From the datasheet: the E6B2-CWZ5B 2000P/R 0.5M encoder has an output circuit which is described as PNP open collector. That is, the output swings from whatever voltage you are running the encoder at (12 V to 24 V) to high impedance:

You probably want to wire it to your (5 V?) Arduino in this manner. The resistor divider is balanced for ~12 V:

Your loop() could be better structured to avoid non-atomic reads because it appears that you are using an 8-bit Arduino and an int is 16-bit. There is, therefore, a risk that an ISR will corrupt the variable counter while you are attempting to read it in the loop():
void loop() {
  // Send the value of counter
  noInterrupts() ;
  int counter_copy = counter ;
  interrupts() ;
  if (counter_copy != temp) {
    Serial.println (counter_copy);
    temp = counter_copy;
  }
}

Thanks for your answer! But the thing is - I tried it with Omron before, powering it with 12v adapter. Now I'm trying it with LPD3806-400BM-G5-24C, which is 5-24V. As the video above shows, it can be powered with Arduino but it doesn't seem to work that way.
What I did now - I powered it with 5.5v externally and got it working properly once. How I did it - I took the ground shield and held it really tight to Arduino Uno USB port. Data stopped and only worked when I'm twisting the shaft. But I can't repeat this thing now. It's clear the problem is with grounding, but I wonder how can I fix it.

@DoICare . OK. The second device you have LPD3806-400BM-G5-24C has apparently an open collector (NPN) output so that is wired in a different way to the first so connecting it to an Arduino pin (per phase) and using the internal pullup is correct. The encoder can be driven still at a higher voltage that the the Arduino. However, it is also important that there is a common ground between the Arduino and the encoder. Anyway, show your wiring diagram. This is the nearest I have found to a data sheet with a quick search: domoticx.com/sensor-lpd3806-optical-rotary-encoder

I've just looked at the video. The red wire from the encoder can only be connected to the Arduino if you are powering the encoder at 5v from the Arduino only. Otherwise the encoder red wire should go to an external power supply and again all grounds should be common.

Thanks for your answer once again! I've updated my question with some schemas, would be great if you check it out. I'm pretty new to electronics and I struggle understanding how to set common ground. Again - when I tried to do this with ground shield held tight to Uno USB port, it did work but only for a while

Even when you use a lab power supply, all the grounds must be connected together. That is, the power supply ground, the arduino ground and the encoder ground (and 0v and shield if the encoder has these). So your last 2 pictures of the Uno setup are clearly wrong because there is no shared ground. Can you find a better data sheet for that LPD3806-400BM-G5-24C encoder?


text:
USB Driver for LGT8F328P Arduino clone
Where is the USB driver for LGT8F328P Arduino Nano clone downloaded from for Windows 10 64-bit?
When I plug in the LGT8F328P into USB, using IDE 1.8.13, it does not detect it. I think it is because there is no HOLTEK driver - wherever that is.
If you got this clone working on Windows 10 can you also mention what version of the Arduino IDE and what boards package (there's more than one for the LGT8F328P) you used and what Windows version you used.
The USB chip on the LGT8F328P clone board is a Holtek HT42B534 which is used as a  USB to serial interface

I don't have one of these, but I found a tutorial about them (though only in german), which used this board package.

the USB is not in the 328p. as with ATmega, there must be an USB chip on board. I guess it is the CH340 as on clones with ATmega

@Juraj it uses a holtek for the USB to serial interface-I added a bit more info to the question regarding your comment

So you need a driver for the HT42B534 for Windows 10? Doesn't the OS detect the chip automatically? (I would expect this from a serious OS.) What does the hardware manager say?


text:
Machine learning on Arduino Nano RP2040
I am trying to use the Arduino Nano RP2040 to recognize gestures using an IMU. This board has the possibility of machine learning core features provided by the LSM6DSOX.
I tested the example provided by the manufacturer and everything works fine. I now want to create a new ML model to recognize custom gestures.
I found this STM tutorial, which is very helpful, but I can't find the code presented at 5:48, to record the movements.
Does anyone know where I can find all the code or how I should do it?

I answer the question myself, for those who have the same problem as me.
Source code
#include "PluggableUSBMSD.h"
#include "FlashIAPBlockDevice.h"
#include "WiFiNINA.h"
#include "LSM6DSOXSensor.h"

#define INT_1 INT_IMU
#define SENSOR_ODR 104.0f // In Hertz
#define ACC_FS 2 // In g
#define GYR_FS 2000 // In dps
#define MEASUREMENT_TIME_INTERVAL (1000.0f/SENSOR_ODR) // In ms
#define FIFO_SAMPLE_THRESHOLD 199
#define FLASH_BUFF_LEN 8192

typedef enum {
  DATA_STORAGE_STATE,
  DATA_LOGGER_IDLE_STATE,
  DATA_LOGGER_RUNNING_STATE
} demo_state_e;

volatile demo_state_e demo_state = DATA_STORAGE_STATE;
volatile int mems_event = 0;
uint32_t file_count = 0;
unsigned long timestamp_count = 0;
bool acc_available = false;
bool gyr_available = false;
int32_t acc_value[3];
int32_t gyr_value[3];
char buff[FLASH_BUFF_LEN];
uint32_t pos = 0;

static FlashIAPBlockDevice bd(XIP_BASE + 0x100000, 0x100000);

LSM6DSOXSensor AccGyr(&Wire, LSM6DSOX_I2C_ADD_L);

USBMSD MassStorage(&bd);

rtos::Thread acquisition_th;

FILE *f = nullptr;

void INT1Event_cb()
{
  mems_event = 1;
}

void USBMSD::begin()
{
  int err = getFileSystem().mount(&bd);
  if (err) {
    err = getFileSystem().reformat(&bd);
  }
}

mbed::FATFileSystem &USBMSD::getFileSystem()
{
  static mbed::FATFileSystem fs("fs");
  return fs;
}

void led_green_thd()
{
  while (1) {
    if (demo_state == DATA_LOGGER_RUNNING_STATE) {
      digitalWrite(LEDG, HIGH);
      delay(100);
      digitalWrite(LEDG, LOW);
      delay(100);
    }
  }
}

void Read_FIFO_Data(uint16_t samples_to_read)
{
  uint16_t i;

  for (i = 0; i < samples_to_read; i++) {
    uint8_t tag;
    // Check the FIFO tag
    AccGyr.Get_FIFO_Tag(&tag);
    switch (tag) {
      // If we have a gyro tag, read the gyro data
      case LSM6DSOX_GYRO_NC_TAG: {
          AccGyr.Get_FIFO_G_Axes(gyr_value);
          gyr_available = true;
          break;
        }
      // If we have an acc tag, read the acc data
      case LSM6DSOX_XL_NC_TAG: {
          AccGyr.Get_FIFO_X_Axes(acc_value);
          acc_available = true;
          break;
        }
      // We can discard other tags
      default: {
          break;
        }
    }
    // If we have the measurements of both acc and gyro, we can store them with timestamp
    if (acc_available && gyr_available) {
      int num_bytes;
      num_bytes = snprintf(&buff[pos], (FLASH_BUFF_LEN - pos), "%lu %d %d %d %d %d %d\n", (unsigned long)((float)timestamp_count * MEASUREMENT_TIME_INTERVAL), (int)acc_value[0], (int)acc_value[1], (int)acc_value[2], (int)gyr_value[0], (int)gyr_value[1], (int)gyr_value[2]);
      pos += num_bytes;
      timestamp_count++;
      acc_available = false;
      gyr_available = false;
    }
  }
  // We can add the termination character to the string, so we are ready to save it in flash
  buff[pos] = '\0';
  pos = 0;
}

void setup()
{
  Serial.begin(115200);
  MassStorage.begin();
  pinMode(LEDB, OUTPUT);
  pinMode(LEDG, OUTPUT);
  digitalWrite(LEDB, LOW);
  digitalWrite(LEDG, LOW);

  // Initialize I2C bus.
  Wire.begin();
  Wire.setClock(400000);

  //Interrupts.
  attachInterrupt(INT_1, INT1Event_cb, RISING);

  // Initialize IMU.
  AccGyr.begin();
  AccGyr.Enable_X();
  AccGyr.Enable_G();
  // Configure ODR and FS of the acc and gyro
  AccGyr.Set_X_ODR(SENSOR_ODR);
  AccGyr.Set_X_FS(ACC_FS);
  AccGyr.Set_G_ODR(SENSOR_ODR);
  AccGyr.Set_G_FS(GYR_FS);
  // Enable the Double Tap event
  AccGyr.Enable_Double_Tap_Detection(LSM6DSOX_INT1_PIN);
  // Configure FIFO BDR for acc and gyro
  AccGyr.Set_FIFO_X_BDR(SENSOR_ODR);
  AccGyr.Set_FIFO_G_BDR(SENSOR_ODR);
  // Start Led blinking thread
  acquisition_th.start(led_green_thd);
}

void loop()
{
  if (mems_event) {
    mems_event = 0;
    LSM6DSOX_Event_Status_t status;
    AccGyr.Get_X_Event_Status(&status);
    if (status.DoubleTapStatus) {
      switch (demo_state) {
        case DATA_STORAGE_STATE: {
            // Go to DATA_LOGGER_IDLE_STATE state
            demo_state = DATA_LOGGER_IDLE_STATE;
            digitalWrite(LEDG, HIGH);
            Serial.println("From DATA_STORAGE_STATE To DATA_LOGGER_IDLE_STATE");
            break;
          }
        case DATA_LOGGER_IDLE_STATE: {
            char filename[32];
            // Go to DATA_LOGGER_RUNNING_STATE state
            snprintf(filename, 32, "/fs/data_%lu.txt", file_count);
            Serial.print("Start writing file ");
            Serial.println(filename);
            // open a file to write some data
            // w+ means overwrite, so every time the board is rebooted the file will be overwritten
            f = fopen(filename, "w+");
            if (f != nullptr) {
              // write header
              fprintf(f, "Timestamp[ms] A_X [mg] A_Y [mg] A_Z [mg] G_X [mdps] G_Y [mdps] G_Z [mdps]\n");
              fflush(f);
              Serial.println("From DATA_LOGGER_IDLE_STATE To DATA_LOGGER_RUNNING_STATE");
              demo_state = DATA_LOGGER_RUNNING_STATE;
              digitalWrite(LEDG, LOW);
              timestamp_count = 0;
              pos = 0;
              acc_available = false;
              gyr_available = false;
              // Set FIFO in Continuous mode
              AccGyr.Set_FIFO_Mode(LSM6DSOX_STREAM_MODE);
            }
            break;
          }
        case DATA_LOGGER_RUNNING_STATE: {
            // Empty the FIFO
            uint16_t fifo_samples;
            AccGyr.Get_FIFO_Num_Samples(&fifo_samples);
            Read_FIFO_Data(fifo_samples);
            // Store the string in flash
            fprintf(f, "%s", buff);
            fflush(f);

            // Close the log file and increase the counter
            fclose(f);
            file_count++;
            // Set FIFO in Bypass mode
            AccGyr.Set_FIFO_Mode(LSM6DSOX_BYPASS_MODE);
            // Go to DATA_LOGGER_IDLE_STATE state
            demo_state = DATA_LOGGER_IDLE_STATE;
            // Wait for the led thread ends the blinking
            delay(250);
            digitalWrite(LEDG, HIGH);
            Serial.println("From DATA_LOGGER_RUNNING_STATE To DATA_LOGGER_IDLE_STATE");
            break;
          }
        default:
          Serial.println("Error! Invalid state");
      }
    }
  }

  if (demo_state == DATA_LOGGER_RUNNING_STATE) {
    uint16_t fifo_samples;

    // Check the number of samples inside FIFO
    AccGyr.Get_FIFO_Num_Samples(&fifo_samples);

    // If we reach the threshold we can empty the FIFO
    if (fifo_samples > FIFO_SAMPLE_THRESHOLD) {
      // Empty the FIFO
      Read_FIFO_Data(fifo_samples);
      // Store the string in flash
      fprintf(f, "%s", buff);
      fflush(f);
    }
  }

  if (demo_state == DATA_STORAGE_STATE && millis() > 10000) {
    // Disable the sensor and go to Mass Storage mode
    AccGyr.Disable_Double_Tap_Detection();
    AccGyr.Disable_X();
    AccGyr.Disable_G();
    while (1) {
      digitalWrite(LEDB, HIGH);
      delay(100);
      digitalWrite(LEDB, LOW);
      delay(100);
    }
  }
}


text:
Why 0 devices, but not 1?
I have found a sketch in Wokwi where a MAX7219 LED matrix is used. The sketch subject is to display 0 using <LedControl.h>. I don't understand why it's nessesary to send 0 unlike 1 in fourth parameter in library-object initialization.
LedControl(int dataPin, int clkPin, int csPin, int numDevices=1);
It seems it should be 1 there, but the sketch isn't working in that way.
#include <LedControl.h>

int DIN = 12;
int CS =  11;
int CLK = 10;
LedControl lc=LedControl(DIN,CLK,CS,0);

void setup(){
  lc.shutdown(0,false);
  lc.setIntensity(0,15);
}

void loop(){
  byte zero[8]= {0x00,0x1c,0x22,0x22,0x22,0x22,0x22,0x1c};
  printByte(zero);
}

void printByte(byte character []) {
  int i = 0;
  for (i=0;i<8;i++) {
    lc.setRow(0,i,character[i]);
  }
}

Yes, I agree 0 is not correct. On this page it says: "The fourth argument to LedControl(dataPin,clockPin,csPin,numDevices) is the number of cascaded MAX72XX devices ... only values between 1..8 are allowed here.".  Please add a link to the source of your code. Perhaps there is an explanation there why 0 was chosen.

https://wokwi.com/projects/373210641309244417
Here is that project.
It's working with 1.

On this page it says: "The fourth argument to LedControl(dataPin,clockPin,csPin,numDevices) is the number of cascaded MAX72XX devices ... only values between 1..8 are allowed here.".
Examining the LedControl source code at GITHUB, we see in file LedControl.cpp in function LedControl() code which checks for unexpected values for the number of MAX7219 LED Matrix devices used:
LedControl::LedControl(int dataPin, int clkPin, int csPin, int numDevices) {
...
  if(numDevices<=0 || numDevices>8 )
    numDevices=8;

We can see if the number is less than or equal to 0 or is greater than 8 the code defaults to 8 devices.  So when passing a 0 the code will detect an unexpected value and create 8 devices by default.

Thanks. Now it's clear.
Unfortunately, I don't understand why the project isn't working with 1 device.

Make sure you have the latest version of the LedControl code.  Check for updated in your Arduino IDE.

The problem was when I put 1 device in initialization and then in shutdown, setIntensity, setRow also used 1. But there must be 0, because it's the address of the 1 device.
Thank you so much for help


text:
Fixing a pedestrian traffic light sequence pattern in a cycle using millis and without delay
I was emulating the pedestrian traffic light cyclic pattern (red, green, green flashing) in the next Arduino code. But when I run this code with my ESP8266 Wemos D1 mini controller, it appears the pattern (red, red and (green flashing) at the same time, green). I do not know why this strange pattern appeared and I was trying to fix it, but I did not get anything. How to fix this code to replicate the (red, green, green flashing) sequence pattern?
// Define pin assignments
const int redLED = D1;
const int greenLED = D2;
const int pedestrianButton = D3;
const int potentiometer = A0;

// Define variables
unsigned long lastStateChangeTime = 0;
unsigned long greenFlashingDuration = 3000; // 3 seconds
unsigned long redGreenDuration = 5000; // Initial duration
bool pedestrianRequest = false;

void setup() {
  // Initialize pins
  pinMode(greenLED, OUTPUT);
  pinMode(redLED, OUTPUT);
  pinMode(pedestrianButton, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(pedestrianButton), pedestrianInterrupt, FALLING);
}

void loop() {
  updateTiming(); // Read potentiometer/LDR and update timings
  manageTrafficLights(); // Manage traffic light states
}

void manageTrafficLights() {
  unsigned long currentTime = millis();

  if (pedestrianRequest==true) {
    // Pedestrian request prioritized
    digitalWrite(greenLED, HIGH);
    digitalWrite(redLED, LOW);

    pedestrianRequest = false;
  }

  // Determine the state based on the timing

  if ( (currentTime-lastStateChangeTime) >= (2 * redGreenDuration) ) {
    lastStateChangeTime = currentTime; // Reset cycle
  }
  else {
    if ( (currentTime-lastStateChangeTime) < redGreenDuration ) {
      digitalWrite(greenLED, LOW);
      digitalWrite(redLED, HIGH); // Red state
    } else if ( (currentTime-lastStateChangeTime) < (2*redGreenDuration-greenFlashingDuration) ) {
      digitalWrite(redLED, LOW);
      digitalWrite(greenLED, HIGH); // Green state
    } else {
      digitalWrite(redLED, LOW);

      if ( ( (currentTime-lastStateChangeTime) >= (2*redGreenDuration-greenFlashingDuration) )
      && ( (currentTime-lastStateChangeTime) % (greenFlashingDuration/3) < (greenFlashingDuration/6) ) ){
        digitalWrite(greenLED, LOW);
      } else {
        digitalWrite(greenLED, HIGH);
      }

    }
  }

}

void updateTiming() {
  // Read potentiometer/LDR values and map to timings
  // Update redGreenDuration and greenFlashingDuration accordingly
  redGreenDuration = map(analogRead(potentiometer), 0, 1023, 5000, 10000);
}

void pedestrianInterrupt() {
  pedestrianRequest = true;
  // Quickly change to green if in red state
  if (digitalRead(redLED) == HIGH) {
    digitalWrite(greenLED, HIGH);
    digitalWrite(redLED, LOW);
    lastStateChangeTime = millis(); // Reset the cycle
  }

}

Here is some simplified example code that might be useful to you.
It keeps the logic and the LED control separated by the use of flags.
Simulation is at https://wokwi.com/projects/389132610627050497

// https://arduino.stackexchange.com/questions/95476/fixing-a-pedestrian-traffic-light-sequence-pattern-in-a-cycle-using-millis-and-w

// for simulation, see https://wokwi.com/projects/389127817478781953

const int redLED   = 2;
const int greenLED = 3;

unsigned int timeInterval  [4] = {  5,  3,  4,  0};             // timers reload with these values
unsigned int timeCounter   [4] = {  0,  0,  0,  0};             // these are the actual timers

//boolean    reloadable    [4] = {true, true, false, false};    // this determines if the timer will restart upon reaching end
                                                                // put value in <timeCounter> for oneshot event
                                                                // 3rd and 4th timers are not used in this example sketch

boolean       tick [4]  = {false, false, false, false};         // countdown timers flags
boolean       mainTick  = false;
boolean       subTick   = false;

boolean       red       = false;
boolean       green     = false;
boolean       blink     = false;

unsigned long previousMillis = 0;

void setup() {

  Serial.begin(115200);

//memcpy(timeCounter, timeInterval, 4 * sizeof(long));           // preload timers

  green = true;                                                  // start with green
  timeCounter[0] = 1;                                            // load the first counter

}

void loop() {

  unsigned long currentMillis = millis();

// -------------------------------------------------------------------

  if (currentMillis - previousMillis >= 500) {                    // 0.5 s tick
    previousMillis = currentMillis;
    subTick = !subTick;                                           // alternate the value

    if (subTick) {
      mainTick = true;                                            // 1 s tick

  //  Serial.println("tick");                                     // debugging code

      for (int i = 0; i < 4; i++) {                               // keep track of 4 time intervals

        timeCounter[i]-- ;                                        // decrement counter

        if (timeCounter[i] == 0) {
  //      if (reloadable[i])  timeCounter[i] = timeInterval[i];   // reached zero, reload counter if it is reloadable
          tick[i] = true;                                         // emit a "tick"
        }
      }
    }
  }

// -------------------------------------------------------------------

  if (mainTick) {                                         // 1 s tick
  }

// -------------------------------------------------------------------

  if (tick[0]) {                                          //
    tick[0] = false;
    timeCounter[1] = timeInterval[1];                     // setup the next tick

    red   = false;                                        // setup flags
    green = true;
    blink = false;
  }

// -------------------------------------------------------------------

  if (tick[1]) {                                          //
    tick[1] = false;                                      // clear flag so that code runs only once every tick
    timeCounter[2] = timeInterval[2];                     // setup the next tick

    red   = true;
    green = false;
    blink = false;
  }

// -------------------------------------------------------------------

  if (tick[2]) {                                          //
    tick[2] = false;                                      // clear flag so that code runs only once every tick
    timeCounter[0] = timeInterval[0];                     // setup the next tick

    red   = false;
    green = false;
    blink = true;
  }

// -------------------------------------------------------------------

  if (mainTick) {                                         // can have multiples of these
    mainTick = false;                                     // clear the flag in the last one
  }

// -------------------------------------------------------------------

  digitalWrite(redLED  , red             ? HIGH:LOW);     // C++ ternary operator
  digitalWrite(greenLED, green           ? HIGH:LOW);
  digitalWrite(redLED  , blink && subTick? HIGH:LOW);     // subTick changes every 500 ms
}

Your Wokwi link is broken.

@RussellMcMahon I tested the link on multiple devices, none of which were logged into Wokwi ... they all worked ... are you able to reach https://wokwi.com/ ?

It works for me now. I was able to access Wokwi. I tried accessing it only a few minutes after you posted the link. Mayhaps there was some setup time. || They need an NRF24L01 peripheral, or better still, a mesh of them :-). (That would be useful to me at present).

@RussellMcMahon they have a "custom chip" available ... it can be programmed with C++, Rust and Verilog ... perhaps it could be made to emulate an NRF24L01


text:
Arduino works indefinitely without PC contact
I'm studying H-Bridge for DC motors. I have a 9V battery, DC motor (9v), Arduino Nano and L293D. I'm following Jeremy Bloom's book about Arduino. Well, the system works perfectly with a PC connected. When I turn off the PC and connect the battery only, it doesn't work at all. The system should work only with a 9V battery.
const uint8_t MC1 = 8;
const uint8_t MC2 = 7;
const uint8_t POT = 0;

uint16_t velocity = 0;
uint16_t PWM = 0;

void forward(uint16_t);
void reverse(uint16_t);
void brake();

void setup(){
  Serial.begin(9600);
  pinMode(EN, OUTPUT);
  pinMode(MC1, OUTPUT);
  pinMode(MC2, OUTPUT);
  brake();
}

void loop(){
  Serial.println(PWM);
  PWM = analogRead(POT);
    if (PWM > 562){
    velocity = map(PWM, 563, 1023, 0, 255);
    forward(velocity);
  }
  if (PWM < 462){
    velocity = map(PWM, 461, 0, 0, 255);
    reverse(velocity);
  }
}

void forward(uint16_t speedValue){
  digitalWrite(EN, LOW);
  digitalWrite(MC1, HIGH);
  digitalWrite(MC2, LOW);
  analogWrite(EN, speedValue);
}

void reverse(uint16_t speedValue){
  digitalWrite(EN, LOW);
  digitalWrite(MC1, LOW);
  digitalWrite(MC2, HIGH);
  analogWrite(EN, speedValue);
}

void brake(){
  digitalWrite(EN, LOW);
  digitalWrite(MC1, LOW);
  digitalWrite(MC2, LOW);
  digitalWrite(EN, HIGH);
}```

The A0 pin is used to rotate the sensor (PWM).

[![The circuit][1]][1]

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

Did you use this type of 9 Volt battery? These types of battery do not have enough current capacity to run most type of motors. Consider using batteries with more current capacity. Likely the type used in older flashlights would work better.

Yes, i did. Which one should I use?

Well, I connected 7.4V 1500mAh Li-ion battery and... it's working. Could you explain why??

Well, I connected 7.4V 1500mAh Li-ion battery and... it's working. Could you explain why??

The PP3 batteries (rectangular 9v battery with snap-on terminals) can supply only a very limited amount of current; barely enough to run an Arduino at all, and none left over to run a motor or other higher current devices.
The best application for PP3s is in low-current, standby devices like smoke detectors, which need very little current under normal circumstances (no smoke) but can draw enough current to make a lot of noise for long enough to wake you up and alert you to the danger, when they detect smoke.
For your application you need a larger capacity battery that can supply more current. Carbon, Alkaline, and nickel chemistries could all work, provided the battery is large enough to supply the current you need; the PP3's form factor is its limitation. Li-ion's big advantage over the other chemistries is, of course, it's rechargeability, and with less degradation than Nickel-based rechargeables.


text:
Updating multiple Arduino Nanos with same INO file
BTW - I have, unsuccessfully, searched for an answer before posting.
I have an NodeMCU connected to a bunch of Arduino Nanos over the I2C bus. The WiFi-enabled NodeMCU has the capability to do OTA updates on itself, which I've mastered but I want to update the same code into all of the slave Nano devices.
Is this possible? If so, what is the easiest way? The devices will be installed on a wall, so I don't want a bunch of USB cables trailing out of it.
Can I use/share the WiFi connection on the NodeMCU, with the Nanos, via the I2C bus? Or is there a better way?
PS - I have read about compiling the .INO file into a hex or bin file but still don't understand the process properly.
PPS - updating .INO files OTA on an ESP8266/WiFi enabled NodeMCU is great but they are bigger (wider) that a Nano and would cost a lot of money as I would need about 30 or so.

The compilation and linking process turns the .INO file into a .HEX file which is basically the machine-code that gets loaded into the processor. It is easy enough to get hold of that file as part of the compilation process.
To update the firmware in your Nanos, you basically need to replace the existing bootloader (which updates via the serial interface) with one which updates via I2C.
I see such a bootloader exists here on Github.

Is this possible?

Sounds like it.

If so, what is the easiest way?

Depends what you mean by "easiest". If the devices are mounted on a wall, that may be the easiest way.
What you might do is, after booting up, each device would query the master to see if an update was available*. If it was, they would take turns to get the update supplied to them via I2C. If the update failed half-way through it might be hard to recover. You might want to have some sort of system where the bootloader checks if the main code is valid (eg. by a sumcheck) and if not, request another update.
I think it could be done, the mechanics could provide an interesting challenge. Have fun with it!

* One possibility would be for the master to make an I2C broadcast (maybe every 10 minutes) of what the current software version is, and if the slave finds that it doesn't have the latest version, request an update. If the master was busy (perhaps because it was updating another slave) the slave might wait 5 minutes and try again.


text:
Issue with uploading Arduino sketch on Ubuntu 20.04
I'm encountering an issue while attempting to upload an Arduino sketch on my Ubuntu 20.04 system. Despite ensuring that the correct board is selected and the USB port is recognized properly, I consistently encounter the following error message:
Sketch uses 444 bytes (1%) of program storage space. Maximum is 32256 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.

avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x00
Failed uploading: uploading error: exit status 1

I have tried various troubleshooting steps, including changing the board, reinstalling the IDE, and resetting the settings, but none of them have resolved the issue.
Could anyone please provide guidance on how to troubleshoot and resolve this problem? Any assistance would be greatly appreciated.

Which Arduino model do you use?

When I have this problem, holding down reset on the board until uploading starts often works


text:
Unable to find PCA9685 module when using the I2CScanner library: no servo movement
I am trying to use an Adafruit PCA9685 servo driver module with an ELEGOO Mega 2560 board.
I am supplying the servo driver board with 5 V and tested all the wires to make sure. I tested the servo without the board and it works fine.

I2CScanner code:
#include "I2CScanner.h"

I2CScanner scanner;

void setup()
{
    Serial.begin(9600);
    while (!Serial) {};

    scanner.Init();
}

void loop()
{
    scanner.Scan();
    delay(5000);
}

What exact board is this? Looks like an Arduino Due, in which case you would be using the wrong pins. Try to use the pins labeled "SCL" and "SDA".

@PMF the exact board i am using is the elegoo mega 2560 and have put the pins in the "SCL" and "SDA" near the "AREF"

I'm not exactly sure about this board, but have you tried the other pins marked "SCL" and "SDA" (Pin 20/21 I think, near the green Led)

@PMF It should be the exact same as the Arduino Mega 2560, I have tried those pins also the older version "A4" and "A5" pins but it still didn't detect anything. Thx for helping btw.

what is the result when you run the code? ... please copy and paste into your post... no pictures please

@jsotola --- Scan started ---
No I2C devices found
--- Scan finished ---

The library you're using there looks ok, but just to be safe: Have you tried to use the standard I2C sample program instead? It's under Examples->Wire->WireScan. Try also with Wire1 instead of Wire.

Insert Wire.setClock(31304); after scanner.Init(); and say whether or not that makes any difference to output. You say "I am supplying the servo driver board with 5 V". Is that what the orange wire is plugged into? I can't tell from the picture.

The I2C bus needs a set of pull up resistors. When buying assembled I2C devices, the designer may include I2C pull up resistors but not connect them. This is because, according to this sparkfun.com tutorial, you only need about 4.7K Ohms of pull up resistance. Adding multiple I2C boards to the same bus all with their own pull up resistors will lower this resistance and may damage I2C drivers. So, it is up to the end-user to decide which I2C board to connect the pull up resistors on.

The breakout manufacturer (Adafruit in this case, I think) would write if that was necessary. But they explicitly state that it already has pullups.


text:
Multiple symbol definition related to USART_RX_vect from Serial
When trying to compile the sketch below, I get this error when using either the IDE or the CLI:
HardwareSerial0.cpp.o (symbol from plugin):
In function `Serial':
(.text+0x0): multiple definition of `__vector_18'

This seems to have something to do with multiple definitions of  USART_RX_vect.
Since I'm not using any extra libraries, that doesn't seem to be the source of the problem (though library conflicts are the source of many similar problems I've seen on here and elsewhere).  Any suggestions on how to fix this?
Sketch:
// Listen to the Serial Port for Instructions and Print Register Values

volatile boolean start = false;  // flag to start register inspection; global

void setup() {
  Serial.begin(9600);
  if (Serial) {
    Serial.println("Arduino listening...");
    Serial.println("Enter g or s at any time");  // g = go, s = stop
  }
}

void loop() {
  while (start) {
    // print the values of some ADC registers
    Serial.print("ADMUX  register: ");
    print_bin(ADMUX);
    Serial.print("ADCSRA register: ");
    print_bin(ADCSRA);
    Serial.println(" ");
    delay(1000);
  }
}

ISR(USART_RX_vect) {
  unsigned char data;
  data = UDR0;
  if (data == 'g') {
    start = true;
  }
  if (data == 's') {
    start = false;
  }
}

void print_bin(byte aByte) {
  for (int8_t aBit = 7; aBit >= 0; aBit--) {
    if (aBit == 3) {
      Serial.print(" ");
    }
    Serial.print(bitRead(aByte, aBit) ? '1' : '0');
  }
  Serial.println(" ");
}

Using the Arduino IDE as follows:
Version: 2.3.0
Date: 2024-02-07T13:40:21.377Z
CLI Version: 0.35.2

Well the Serial is probably using the same ISR. (may differ for different boards, however Arduino Core usually occupy all related ISRs for all serial ports)

USART_RX_vect is defined by the Arduino core library. It is part of
the implementation of the Serial object. Your sketch has a second
definition of the same ISR, thus the conflict.
Basically you have two choices: either you write your own code to handle
the serial port at the I/O register level (like in your ISR above), or
you rely on the Serial implementation of the Arduino core
(Serial.available() and Serial.read() to read data). You cannot mix
the approaches like you are trying to do here.

Thanks, self-inflicted wound.  In another sketch I used ISR(ADC_vect) without such a conflict but I guess that one is not implemented in the core library.  Live and learn.

@BryanHanson: Indeed. The core busy-waits for the ADC (in analogRead()) instead of using the interrupt.


text:
ESP32 Preferences on partition `app1`
My Arduino ESP32 project needs a lot of space for on-device string storage and the default nvs partition is not enough. I'd like to use app1 partition for preferences via pref.begin("ns1", false, "app1") but the device doesn't boot if I do that:
21:01:54.643 -> ESP-ROM:esp32s3-20210327
21:01:54.643 -> Build:Mar 27 2021
21:01:54.643 -> rst:0x3 (RTC_SW_SYS_RST),boot:0x2b (SPI_FAST_FLASH_BOOT)
21:01:54.643 -> Saved PC:0x403cdada
21:01:54.643 -> SPIWP:0xee
21:01:54.643 -> mode:DIO, clock div:1
21:01:54.643 -> load:0x3fce3808,len:0x44c
21:01:54.643 -> load:0x403c9700,len:0xbd8
21:01:54.660 -> load:0x403cc700,len:0x2a80
21:01:54.660 -> entry 0x403c98d0
21:01:54.660 -> ESP-ROM:esp32s3-20210327
... repeats

Any ideas on how to make it work?
I'd like to avoid defining a new partition since the code will be used by other people and ideally I'd avoid having them deal with another piece of complexity of redefining partitions.


text:
Can't get serial port's attention once sketch is running
This sketch is supposed to listen for a single character sent to the serial port, as a means of starting and stopping data collection (which in this example is mocked by printing some register values).  It reacts to the first character sent (g), and the while loop begins executing.  But it doesn't react to a subsequent s character, it seems I can't get Arduino's attention.
Perhaps this is related to this answer but I'm not sure.  If that's the problem, I could use some general suggestions about how to work around the limitations.  If it's something else, well obviously I need a suggestion for that as well!
// Listen to the Serial Port for Instructions and Print Register Values

volatile boolean start = false;  // flag to start register inspection; global

void setup() {
  Serial.begin(9600);
  if (Serial) {
    Serial.println("Arduino listening...");
    Serial.println("Enter g or s at any time");  // g = go, s = stop
  }
}

void loop() {
  unsigned char data;
  if (Serial.available()) {
    data = Serial.read();
    Serial.println(data); // only for troubleshooting
    if (data == 'g') {
      start = true;
    }
    else  if (data == 's') {
      start = false;
    }
  }

  while (start) {
    // print the values of some ADC registers
    Serial.print("ADMUX  register: ");
    print_bin(ADMUX);
    Serial.print("ADCSRA register: ");
    print_bin(ADCSRA);
    Serial.println(" ");
    delay(1000);
  }
}

void print_bin(byte aByte) {
  for (int8_t aBit = 7; aBit >= 0; aBit--) {
    if (aBit == 3) {
      Serial.print(" ");
    }
    Serial.print(bitRead(aByte, aBit) ? '1' : '0');
  }
  Serial.println(" ");
}

Environment:
Version: 2.3.0
Date: 2024-02-07T13:40:21.377Z
CLI Version: 0.35.2

There is nothing in your while (start) { loop that would allow start to become false.
  while (start) {
    // print the values of some ADC registers
    Serial.print("ADMUX  register: ");
    print_bin(ADMUX);
    Serial.print("ADCSRA register: ");
    print_bin(ADCSRA);
    Serial.println(" ");
    delay(1000);
  }

...and so your loop continues while data is piling up in Serial's input buffer.
loop() is already a functional loop. Changing while (start) { to if (start) { seems to be what you're looking for.
void loop() { // <-- existing loop
  unsigned char data;
  if (Serial.available()) {
    // stuff that can change start
  }

  if (start) {
    // stuff that happens if start is true
  }
}

You may want to look at the blink without delay example for handling your delay(1000) differently.

Dang, I set up a loop inside a loop with no escape from the inner loop once it was going!  Thanks for the second set of eyes!  Just couldn't see that for some reason.

And thanks for the link to the blink nuances.  I don't actually need that delay in there, but I need to keep learning about Arduino blocking, interrupts etc.  Many details are not readily apparent when one is already learning a lot of new stuff.


text:
ESP32 with static IP address acting as client connecting to ESP32 acting as access point
I have an ESP32 board as a client with a static IP address. The client with the static IP address connects to a second ESP32 that is acting as an access point. The connection is established and the access point recognizes the new connected device.
The problem is, with the client having a static IP address the access point displays the client IP as 0.0.0.0. If the client does not have the IP address set as static, the access point displays the correct IP address.
The code for the client:
#include <WiFi.h>

const char* ssid = "ESP32-AP";
const char* password = "123456789";
IPAddress ip(192, 168, 0, 101);
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  // Configure the static IP address
  WiFi.config(ip, gateway, subnet);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("Connected to WiFi network");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  static long general_t1 = 0;

  if (millis() - general_t1 > 2000) {
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    general_t1 = millis();
  }
}

The code for the access point:
#include <Arduino.h>
#include <WiFi.h>
#include "esp_wifi.h"
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const char *ssid = "ESP32-AP";      // SSID Name
const char *password = "123456789"; // SSID Password - Set to NULL to have an open AP
const int channel = 10;             // WiFi Channel number between 1 and 13
const bool hide_SSID = false;       // To disable SSID broadcast -> SSID will not appear in a basic WiFi scan
const int max_connection = 5;       // Maximum simultaneous connected clients on the AP

IPAddress local_ip(192, 168, 0, 1);
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);

//*** void display_connected_devices() **************************************************************
void display_connected_devices() {
  wifi_sta_list_t wifi_sta_list;
  tcpip_adapter_sta_list_t adapter_sta_list;
  esp_wifi_ap_get_sta_list(&wifi_sta_list);
  tcpip_adapter_get_sta_list(&wifi_sta_list, &adapter_sta_list);
  String deviceInfo = "";

  if (adapter_sta_list.num == 0) {
    deviceInfo = "No Device connected";
  }
  else {
    for (int i = 0; i < adapter_sta_list.num; i++) {
      tcpip_adapter_sta_info_t station = adapter_sta_list.sta[i];
      deviceInfo += "Device " + String(i) + " = ";
      deviceInfo += IPAddress((&station.ip)->addr).toString();
      deviceInfo += "\n";
    }
  }

  // Display accumulated device information
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.println("AP IP: " + WiFi.softAPIP().toString());
  display.setCursor(0, 20);
  display.println(deviceInfo);
  display.display();
  display.clearDisplay();
}

//***********************************************************************************************
//**                                   void setup()
//***********************************************************************************************
void setup() {
  Serial.begin(115200);

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

  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(25, 10);
  display.println(F("ESP-32"));
  display.setCursor(25, 30);
  display.println(F("Router"));
  display.display();
  delay(2000);

  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(local_ip, gateway, subnet);
  WiFi.softAP(ssid, password, channel, hide_SSID, max_connection);
  Serial.print("[+] AP Created with IP Gateway ");
  Serial.println(WiFi.softAPIP());
}

//***********************************************************************************************
//**                                  void loop()
//***********************************************************************************************
void loop() {
  display_connected_devices();
  delay(5000);
}

there are no IP addresses in WiFi. the SoftAP device can only display the IP from DHCP server records or maybe from ARP table after the client does some TCP/IP communication with the SoftAP device.

Thanks for the reply. Is there any way to get the Ip?

Not digging deep in API, as @Jurai says, it lists IP from DHCP server on AP, which know nothing about static IPs.

As you set static IP to "Client" - just use it (192.168.0.101) (KISS rule)
On AP implement web API which allow client to register itself
Use mDNS (aka Avahi, aka Bonjour) multicast discovery espressif-skd doc arduino-esp32 ESPmDNS library

What is Your goal in using static IP on Client?

There are some testbench who are controlled by esp32. Every testbench has a number and the idea is to have the same correspondent number inside the ip-address. The fourt octets of the ip-address would be the same as the testbench number. I managed this situation with having the client send its IP address to the Access Point upon establishing the connection. Thanks for the help.


text:
Problem installing RPLidar library
I'm trying to add the RPLidar library. I've already checked this solution, but it's not working for me, I get this error :
Error: 13 INTERNAL: Library install failed: extracting archive: Not a supported archive
Do you have a solution ?

Are you trying to install this library through the Arduino IDE? Then maybe it doesn't work, because this library doesn't conform to the normal library structure for Arduino.
You can install it manually.

Download the library from Github

either by downloading the ZIP-file and extracting it
or by using git clone on your machine, if you have git installed.

Move the folder RPLidarDriver into the libraries folder. You can normally find this in Arduino/libraries in your home directory. If you cannot find it, look in the Arduino IDE in the preferences dialog. There the sketchbook location should be mentioned. libraries is a folder inside the sketchbook location.

Then you should be able to compile your code. I've tested this with the examples provided by the library.


text:
Generation of TTL Signal
I would like to generate a TTL signal using an Arduino.
As far as I understand, a TTL signal is just a predefined controlled signal that repeats at a certain interval (e.g. 2 μs).
An Arduino circuit arguably has a very fast clock (e.g. 16 MHz), so what I thought is I can basically just draw a square signal for whatever desirable interval (important to be down to the microsecond).
I used the following code, choosing a pin and changing its signal state between 0 and 1 and then using Serial.println to draw the signal out. Everything is inside a while loop that times everything to be generated exactly within 1 second.
#include <arduino-timer.h>

// Variables
unsigned long v = -1;
int freq = 100.0; // Hz
unsigned long d = floor(1.0/freq*1000000.0) ; // us
Timer<1, micros> timer; // create a timer with 1 task and microsecond resolution

void setup() {
  unsigned long repeatEvery = 5000000; // Microseconds
  Serial.begin(9600);
  pinMode(3, OUTPUT);
  timer.every(repeatEvery, func1); // XXXXX microsec
}

void func1() {
  unsigned long uSec = 1000000; // Microseconds (= 1 sec)

  PORTD = B00000000;
  v = digitalRead(3);

  unsigned long counter = 0, i = 0;

  auto currentTime = micros();
  auto prevTime = currentTime;
  d = 0; // no delay to check the speed of the execution

  do {
    PORTD = B00001000;
    v = digitalRead(3);
    // Serial.println(v);
    PORTD = B00001000;
    v = digitalRead(3);
    // Serial.println(v);
    delayMicroseconds(d); // first frame

    PORTD = B00000000;
    v = digitalRead(3);
    // Serial.println(v);
    PORTD = B00000000;
    v = digitalRead(3);
    // Serial.println(v);
    delayMicroseconds(d); // second frame

    currentTime = micros();
    i = (unsigned long)(currentTime - prevTime);
    counter++;
  } while(i < uSec);

  Serial.print(">>>Counter:");
  Serial.println(counter);
  Serial.print(">>>delay (ms):");
  Serial.println(d);
}

void loop() {
  timer.tick();
}

The code above will give output as counter = 47620 // how many times the instructions were repeated
and if the Serial.println lines were uncommented to draw the signal then the execution time slows down to counter = 86

I am not sure if the whole train of thought is wrong and I should do something else or use a different circuit.
Any hint or help would be highly appreciated.
PS: my Arduino by the way is a UNIROI that is supposed to be the same as an Arduino R3.

Describing your code makes it rather difficult to understand. Could you just post the code instead?

TTL signal is just a predefined controlled signal that repeats at a certain interval ... no TTL is a logic level that is 5 V when high and 0 V when low ... it does not necessarily repeat ... it could easily always be high

The 1u/2us are pretty fast - you have 16 or 32 instruction cycles @16MHz.
And now you have digitalRead that usually takes around 70 instruction cycles (several times), after that 32b arithmetics (hundreds instructios).
When you uncomment Serial.printlns that starts being blocking after the internal buffer is filled plus you even use 9600bauds speed (960 characters per second max speed), each println means 3 characters and it's there 4 times -> 960/12 = around 80 loops per second. Do you see the pattern?
The only way to generate jitter free signals are timers (probably fast PWM with prescaler=1 and top value according to your desired period).

I see the problem already yeah and thanks for the answer. The thing is that, I am not too familiar yet with all these electronic circuits (instructions). So I would appreciate a link or more details that could help putting me on the right track.

It'd be "AVR instruction set manual", however for the Timer setting the "Atmega328p datasheet" will be more interesting

I will look that up, thanks for the tip


text:
Reading MAX31888 works with Nano, but not with ATtiny85
I'm using the OneWire library to try and read temperatures from a MAX31888 sensor using this Arduino program:
#include <SoftwareSerial.h>
#include <OneWire.h>

#define RX PB4
#define TX PB3
#define OW PB0

SoftwareSerial serial(RX, TX);
OneWire ds(OW);

void setup() {
  serial.begin(19200);
  delay(1000);
  serial.println("TX_INIT");
}

void loop() {
  byte addr[8];
  if (!ds.search(addr)) {
    serial.println("No more addresses.");
    serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
  serial.print("ROM =");
  for (byte i = 0; i < 8; i++) {
    serial.write(' ');
    serial.print(addr[i], HEX);
  }
  delay(5E3);
}

When I test this on an Arduino Nano, with hardware serial instead of software, I get the output I expect:
ROM = 54 36 25 5 0 0 0 3C
No more addresses.

But when I compile and burn the same program to an Attiny85, using the internal 8 MHz clock bootloader, all I get is:
No more addresses.

What could be the issue here? I've read DS18B20 sensors just fine with the 8 MHz internal clock bootloader before.
Software & library versions used:

Arduino IDE ver. 2.2.1
Arduino AVR Boards core for Nano, ver. 1.8.6
ATTiny core ver. 1.0.2
Onewire library ver. 2.3.7

Wiring diagram for ATTiny setup:

Diagram legend:

U1: USB
U2: ATTiny85
U3: MCP2221
J1: OneWire header

Please note that the VUSB pin of the MCP2221 outputs a regulated 3.3V.

If your code shown also doesn't work as shown with a DS18B20 you're likely to get more help. The name and version of the Arduino core in use would help. Same for OneWire, there is not just one of these now, and there are forks of all of them. Same of SoftwareSerial assuming it isn't just part of the core you're using.

@timemage I've added version numbers and sources to my initial post for applicable software and library versions. SoftSerial is indeed part of the core in this case. The DS18B20's work just fine with this on both ATTiny and Nano, the same code reports the DS18B20's ROM just fine on both. But only the Nano reports the MAX31888 ROM, and not the ATTiny for some reason. Response on DS18B20: ROM = 28 AD 45 73 E 0 0 E7 No more addresses. Which seems to be correct, since the family code for DS18B20 is 0x28.

It looks like you have good details now.  Unfortunately I don't believe I have a MAX31888 to test with.  But, I'm voting it up. That is appears to top out at 3.6V makes me wonder how you've been wiring it.

@timemage Both on the ATTiny and Nano, I use 3.3V for powering the sensor. Though both microcontrollers are powered off of 5V from USB. On the Nano I use the 3.3V regulated output and on the nano I have a separate regulator for 3.3V

Does it work if you also use SoftwareSerial on the Nano?

@EdgarBonet I can try, I don't see how that would change anything since I get a serial response with SoftSerial on ATTiny when using a DS18B20, and also a failure message when either nothing, or a MAX31888 is connected.

@EdgarBonet SoftSerial works fine on Nano


text:
Difficulties acquiring angle values from MPU6050
I'm attempting to acquire angle values from an MPU6050 IMU sensor using an ESP32-DevKitM-1 microcontroller.
My setup contains the ESP32 board, the MPU6050 board, and an SD card reader to save the readings from the sensor:

I'm using the Arduino IDE v2.3.0.
I adapted the following testing code excerpt from another post about sensor, using the newer Adafruit_MPU6050 library and the SD functions:
#include <Wire.h>
#include "SPI.h"

#include <Adafruit_Sensor.h>
#include <Adafruit_MPU6050.h>

#include "SD.h"

const int PIN_IMU_SCL = 22;
const int PIN_IMU_SDA = 21;
const int PIN_SD_CS = 23;
const int PIN_SD_MISO = 10;
const int PIN_SD_MOSI = 18;
const int PIN_SD_CLK = 5;

const int IMU_GyroScale = 131;

Adafruit_MPU6050 IMU;
double IMU_Time;
double IMU_TimePrev = -1;
double IMU_GyroRotX;
double IMU_GyroRotY;
double IMU_GyroRotZ;

File DataFile;

void IMU_GetData(double& angleX, double& angleY, double& angleZ, double& temp)
{
  bool firstTime = false;

  if (IMU_TimePrev == -1)
    firstTime = true;

  // Calculating the elapsed time...
  IMU_TimePrev = IMU_Time;
  IMU_Time = millis();
  double timeDelta = (IMU_Time - IMU_TimePrev) / 1000;

  // Acquiring the readings from the accelerometer & gyroscope...
  sensors_event_t accelData;
  sensors_event_t gyroData;
  sensors_event_t tempData;
  IMU.getEvent(&accelData, &gyroData, &tempData);

  // Calculating the accelerometer angle...
  double accelRotX = (180 / PI) * atan(accelData.acceleration.x / sqrt(pow(accelData.acceleration.y, 2) + pow(accelData.acceleration.z, 2)));
  double accelRotY = (180 / PI) * atan(accelData.acceleration.y / sqrt(pow(accelData.acceleration.x, 2) + pow(accelData.acceleration.z, 2)));
  double accelRotZ = (180 / PI) * atan(sqrt(pow(accelData.acceleration.x, 2) + pow(accelData.acceleration.y, 2)) / accelData.acceleration.z);

  // Calculating the gyroscope angle...
  double gyroRotX = (gyroData.gyro.x / IMU_GyroScale);
  double gyroRotY = (gyroData.gyro.y / IMU_GyroScale);
  double gyroRotZ = (gyroData.gyro.z / IMU_GyroScale);

  // Combining the two (complementary filter)...
  if (firstTime)
  {
    IMU_GyroRotX = accelRotX;
    IMU_GyroRotY = accelRotY;
    IMU_GyroRotZ = accelRotZ;
  }
  else
  {
    IMU_GyroRotX += timeDelta * gyroRotX;
    IMU_GyroRotY += timeDelta * gyroRotY;
    IMU_GyroRotZ += timeDelta * gyroRotZ;
  }

  angleX = (0.96 * accelRotX) + (0.04 * IMU_GyroRotX);
  angleY = (0.96 * accelRotY) + (0.04 * IMU_GyroRotY);
  angleZ = (0.96 * accelRotZ) + (0.04 * IMU_GyroRotZ);

  temp = tempData.temperature;
}

bool IMU_Init()
{
  bool status = IMU.begin();

  if (status)
  {
    IMU.setAccelerometerRange(MPU6050_RANGE_8_G);
    IMU.setGyroRange(MPU6050_RANGE_500_DEG);
    IMU.setFilterBandwidth(MPU6050_BAND_21_HZ);
  }

  IMU_Time = millis();

  delay(100);

  return status;
}

void setup()
{
  Serial.begin(9600);
  Serial.println("Initializing...");

  Wire.begin(PIN_IMU_SDA, PIN_IMU_SCL);
  IMU_Init();

  SPI.begin(PIN_SD_CLK, PIN_SD_MISO, PIN_SD_MOSI, PIN_SD_CS);

  while (!SD.begin(PIN_SD_CS))
  {
    Serial.println("Unable to open SD!");
    delay(500);
  }

  DataFile = SD.open("/angles.txt", FILE_WRITE);
  DataFile.close();

  delay(100);
  Serial.println("Initialized!");
}

void loop()
{
  double angleX;
  double angleY;
  double angleZ;
  double temp;
  IMU_GetData(angleX, angleY, angleZ, temp);
  String anglesStr = String(angleX) + ":" + String(angleY) + ":" + String(angleZ);

  DataFile = SD.open("/angles.txt", FILE_APPEND);
  DataFile.println(anglesStr);
  DataFile.close();

  Serial.println(anglesStr);

  delay(200);
}

Where IMU_GetData is the function responsible for acquiring the angle data from the gyroscope and the accelerator sensors on the MPU6050 board, and implementing a filter to attain a set of filtered angle values.
I then simply save the filtered angle values to the SD card. I communicate with the sensor using the Wire I2C library, and with the SD card using the SPI library.
The main issue I'm running into is the fact that the resultant angle values do not appear to accurately represent the rotation of the sensor.
As a test, I rotated the sensor 360° slowly around each one of the 3 axes, and saved the continuous angle readings during each rotation:

The time interval between each reading in the plots above is ~0.2 s.
The first issue is that a rotation about the Z-axis visible in the last graph above appears to not cause any appreciable change in any of the angle readings.
I initally assumed that could be caused by the value of the IMU_GyroScale constant that the gyroscope angle values get multiplied by during the calculations carried out in the IMU_GetData function. I assumed that all MPU6050 chips will use that same scaling factor, but then I tried several of the other listed scaling factors listed in the datasheet, with no appreciable difference.
Is there something visibly wrong in my code with the angle calculations for the Z-axis? Could this be a sign of a defective sensor board?
The second thing I was curious about was the format of the filtered angle values.
I initially assumed that the filtered angle values I would be getting from the sensor would be the Euler angles; Roll, Pitch & Yaw. However, these appear to not represent those.
In fact, one of the main sources listed in the original posting that describes in detail the process of calculating the filtered angle values, also provides a visualization of the angle values acquired from the sensor:

Are these "tilt" values related to Euler angles? Is it possible to convert between the two?

The formulas you are using look plain wrong. There are a few issues that
stick out:

Rotating along z has no effect on the accelerometers. Any formula
that pretends to give you the three Euler angles out of accelerometer
data can only be wrong. You need a magnetic compass to get the yaw
angle, otherwise you would have to rely solely on the gyros, which are
prone to long-term drift.

The formulas for updating angles from gyro data are awfully complex.
You don't want to do that. You want to instead keep track of you
attitude using quaternions, which give much nicer maths.

If you look at the formulas that update IMU_GyroRot*, you should
notice that they are prone to unbounded drift, which is then inherited
by angle*. Obviously, the author of these formulas completely missed
the point of a complementary filter.

I suggest you look at this old answer to a very similar question.

Thanks for your comment;
Since gyroscopes drift their Yaw measurement, does that mean I'd strichtly need to use a magnetometer to measure the Yaw?
As for the angle formulas, it does indeed appear that the author of the original article from 2013 may have missed a couple of things. I didn't actually know this, but the MPU6050 contains a Digital Motion Processor (DMP), that apparently handles a lot of the calculations for you. Using the i2cdev library from jrowberg, I was able to get some readings. Unfortunately, the Yaw still appears to drift, both in Euler and Quaternions...

@Runsva: Good that you found a way to get the DMP-computed rotation! Yes, you need a magnetometer to measure yaw, I do not know of any other easy way to get it. If you only have accelerometers and gyros, your only option is to calibrate the gyros as accurately as you can, and hope it is good enough to get an acceptable drift rate.

Make sure that the sensor is correctly orientated and calibrated, verify gyro scaling and range settings, and consider the application requirements when choosing between tilt angles and Euler angles. If Euler angles are necessary, you'll need to implement a different algorithm to calculate them accurately.


text:
Sketch halts if button is pressed on boot
I have a KY-040 rotary encoder with a push button wired to an ESP8266. My objective is to be able to detect if the button is pressed or not on boot.
In the below code, if I hold the button down and power on the ESP8266, neither "IT'S STARTED" or "IT'S LOOPING" is printed in the serial monitor, even if I release the button. If I don't press the button, the code works as expected and prints "IT'S STARTED" followed by "IT'S LOOPING". It's as though the code gets stuck/halted if I press the button on boot.
Can someone explain why this is happening?
I would also appreciate suggestions on how I can detect the status (pressed/not pressed) of the button when the ESP8266 is powered up.
Here is my code:
void setup() {
  pinMode(D3, INPUT_PULLUP);
  Serial.begin(115200);
  Serial.println("IT'S STARTED");
}

void loop() {
  Serial.println("IT'S LOOPING");
  delay(1000);
}

D3 is io 0 the boot mode pin. https://arduino.stackexchange.com/questions/75704/what-are-the-best-gpio-pins-to-use-for-my-project/75706#75706

Description of pin D3 from this ESP8266 pinout reference:

connected to FLASH button, boot fails if pulled LOW

So you cannot pull this pin to LOW during boot, as it will keep the ESP in flash mode. You need to use a pin, that doesn't have this limitation, like D1, D2, D5, D6 or D7.

Thanks for the answer @chrisl. Of all the pins I could pick from!


text:
Physically passing through a pin to access another
I would like to know about physically passing through a pin in order to get to another. For instance, if I have a sensor on one side of an ATMEGA328P or ESP8266 (Wemos D1 Mini) yet need to connect to a pin on the other side, would I be able to simply go through an unused pin instead of worrying about going around or using a jumper wire? If so, would I need to set the unused pin in a certain way, for example as an input (with or without pull-up)?
PS: The diagram  of the first answer illustrates my question exactly and the answer has been accepted as the solution.

It is unclear to me, what exactly your problem is. Why would you need to "go through a pin" (whatever that means) to access another pin? The pins are all spaced out. Why are you not able to reach the pin, that you want to connect?

No.  If you want to connect to a certain pin then you need to connect to that pin.  The pins are physically connected to certain parts of the chip.  They're not re-routable.

Let me see if I understand what you are asking. You want to connect both the relevant pin and an unrelated one, like in this DIP footprint:

If this is the case, the answer is yes, provided that the pass-through pin is always held in a high-impedance (i.e. INPUT) state.

This is exactly the answer to the question at hand. Thank you.

Make sure that the unused pin isn't configured for any conflicting functions like SPI, I2C, or UART communication, as this could interfere with the signal you're routing.

Thanks. I thought as much that is why I referred to the pin as unused, but I guess I didn't clarify p0roperly.


text:
Code review for timer using RTC and OLED screen
I am building a small art project to display my current age with an accuracy of 1/100th of a second. I am using a XIAO SAMD21, a DS3231 RTC, and a 128x32 OLED screen. Here is what it looks like right now without the battery:

My aim is to fit this and a battery into a locket / necklace. I want to make as low-power as possible so that it can last at least an hour or two on a 75 mAh Li-po. I can't use a bigger battery since it wouldn't fit in the necklace.
I wrote the code to the best of my ability and it looks like it works really well. I just want a sanity check to make sure there isn't a simpler way of doing things. In particular I feel like the calculation of the age in the main loop, the syncing with RTC, and maybe the display updates, could be done in a better way. Maybe there are some things I do with interrupts and the 'alarms' in the RTC? Just power on the display every other second maybe. I am also considering using an epaper display and removing the power LED.
The code is attached here. I use the Adafruit libraries to drive the SSD1306 on the OLED screen, and one of the DS3231 libraries to interface with the RTC. Parts of it are adapted from examples, so there may be some extraneous imports or declarations I don't need.
// TUNIO 2024
// Age Pendant

// TO DO:
// current loop is 17 to 18 milliseconds long - need less than 5 for accurate centi-second counting

// Libraries
#include <SPI.h>
#include <Wire.h>
#include <DS3231.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// OLED Setup ~ copied from example
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C // See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// RTC Setup
RTClib myRTC;

// Initializations for periodic sync with RTC
uint32_t remote_time = 0;
uint32_t sync_interval_ms = 1800000; // sync with RTC every sync_interval_ms milliseconds // about an hour is good
uint32_t last_millis_synced = 0; // the last time we synced with RTC
uint32_t system_time = 0; // the local system time

// Initializations for age calcs
// QUESTION us 32 bit enough to store the age of someone? What if they live to 100?
uint32_t born_utime = 788888888; // date of birth in unixtime // 788888888
uint32_t total_age_secs = 0;
uint32_t sec_remainder = 0;
uint8_t age_years = 0;
uint8_t age_months = 0;
uint8_t age_days = 0;
uint8_t age_hours = 0;
uint8_t age_mins = 0;
uint8_t age_secs = 0;

// initializations for centi-second counting
uint8_t oldsec = -1;
uint8_t newsec = -1;
uint32_t offset = 0;
uint8_t age_cs = 0;

// screen saving vars
bool invert = false;

//// debug
//uint32_t start_millis=0;
//uint32_t end_millis=0;

void setup() {
  Serial.begin(57600);
  Wire.begin();
  delay(250);

  // display setup
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.dim(true);
  display.setTextColor(SSD1306_WHITE);
  display.clearDisplay();
  display.setTextSize(2); // 1 default
  display.setRotation(3); //0 default, 1, 2, 3

  // turn off built in LED
  pinMode(LED_BUILTIN , OUTPUT);
  digitalWrite(LED_BUILTIN , HIGH);

  // do first sync
  sync_time_with_rtc();
}

void loop() {
//  //debug
//  start_millis = millis();

  // sync every sync_interval_ms with RTC
  if (millis() - last_millis_synced >= sync_interval_ms) {
    sync_time_with_rtc();
  }

  // Calculate time elapsed since birth in years, months, etc.
  system_time = local_time_now();
  total_age_secs = system_time - born_utime; // age in seconds
  age_years = num_time_units(total_age_secs, 31558149.756); // second arg is num of: secs in a year
  age_months = num_time_units(sec_remainder, 2629745.568); // ... secs in a month
  age_days = num_time_units(sec_remainder, 86401.505); // ... secs in day
  age_hours = num_time_units(sec_remainder, 3600); // ... in an hour
  age_mins = num_time_units(sec_remainder, 60); // ... in an minute
  age_secs = sec_remainder;

  // display the age calculated
  show_age_on_display(5, 3); // input top left coordinates of where the age will be displayed

//  //debug
//  end_millis = millis();
//  Serial.println(end_millis - start_millis,DEC);
}

// Prints the provided age to the LCD with the correct formatting
void show_age_on_display(int col, int line) {
  newsec = age_secs;
  if (newsec != oldsec) {
    offset = -1 * (millis() % 1000);
    if (age_secs % 11 == 0) {invert = ! invert;} // invert display to save pixels burning every 11 secs
    oldsec = age_secs;
  }

  display.clearDisplay();
  display_at_location(age_years, col, line);
  display_at_location(age_months, col, line + (13 + 5) * 1);
  display_at_location(age_days, col, line + (13 + 5) * 2);
  display_at_location(age_hours, col, line + (13 + 5) * 3);
  display_at_location(age_mins, col, line + (13 + 5) * 4);
  display_at_location(age_secs, col, line + (13 + 5) * 5);
  age_cs = floor(((millis() + offset) % 1000) / 10);
  display_at_location(age_cs, col, line + (13 + 5) * 6);

  display.fillRect(0, display.height() - 18, display.width(), 18 - ((18 * age_cs) / 100), SSD1306_INVERSE); // progress bar completes every second

  display.invertDisplay(invert);
  display.display();
}

// display integer value <100 at given location with "0" padding
void display_at_location(uint8_t value, uint8_t this_col, uint8_t this_line){
  display.setCursor(this_col, this_line);
  if (value < 10) display.print(F("0"));
  display.print(value, DEC);
}

// input seconds and returns number of whole time unit, sets remainder variable
uint32_t num_time_units( uint32_t secs, float time_unit) {
  int num_units = floor(secs / time_unit);
  sec_remainder = secs - round(num_units * time_unit);
  return num_units;
}

// syncs time with the RTC: call on sync_interval, power ons, AND when wake from sleep
void sync_time_with_rtc() {
  digitalWrite(LED_BUILTIN , LOW); // briefly flash the LED every sync with the RTC
  remote_time = myRTC.now().unixtime();
  last_millis_synced = millis();
  system_time = local_time_now();
  digitalWrite(LED_BUILTIN , HIGH);
}

// fetches the unixtime according to Arduino
uint32_t local_time_now() {
  return remote_time + floor((millis() - last_millis_synced) / 1000);
}

use a function to replace repeating code

One thing I discovered: millis() will roll over every ~49 days if for some reason the Arduino doesn't have a power cycle. So I follow this and update the code https://arduino.stackexchange.com/questions/12587/how-can-i-handle-the-millis-rollover

I see quite a bit of floating point computations here. Since the SAMD21
doesn't have a floating point unit, all float operations are implemented
in software, which can be quite expensive. As an optimization, I suggest
to stay as much as possible in the integer realm. For example:
uint32_t total_minutes = total_age_secs / 60;
age_secs = total_seconds - total_minutes * 60;
uint32_t total_hours = total_minutes / 60;
age_mins = total_minutes - total_hours * 60;
uint16_t total_days = total_hours / 24;
age_hours = total_hours - total_days * 24;
age_years = total_days / 365;
uint16_t remaining_days = total_days - age_years * 365;
age_months = remaining_days * 12 / 365;
age_days = remaining_days - age_months * 365 / 12;

Note that there is some rounding here: a day is assumed to be exactly
86400 seconds instead of 86399.9999 (I don't know where you found the
number 86401.505), a year is assumed to be 365 days, and all months are
assumed to be equal. If you found this approximations too rough (mostly
the year), you may use 365.25 = 1461 / 4 days per year and
1461 / 48 days per month. You can do this by replacing the last four
lines with:
age_years = total_days * 4 / 1461;
uint16_t remaining_days = total_days - age_years * 1461 / 4;
age_months = remaining_days * 48 / 1461;
age_days = remaining_days - age_months * 1461 / 48;

I'm almost done updating the code, you may be interested to see it. I am removing all floating point operations and attempting to max out the resolution using only 32 bit integers and a few correction factors.
I think I got the "86401.505" by naively dividing the length of sidereal year in seconds by 365.25 days, I fix that in the next version. I got a bit confused with the several different definitions of a year I guess.