text:
Clarification of power-up behaviour of MAX7219 display driver
What is the exact meaning of the Initial Power-Up Section of the MAX7219 data sheet to be found on Page 7?
It says:

On initial power-up, all control registers are reset, the display is blanked, and the MAX7219/MAX7221 enter shutdown mode. Program the display driver prior to display use. Otherwise, it will initially be set to scan one digit, it will not decode data in the data registers, and the intensity register will be set to its minimum value.

Most of this is clear. But specifically, what does the "the display is blanked" mean? Does it mean that the MAX7219 internal SRAM is cleared as part of the power-up sequence or does it mean that because the display is set to shutdown mode by power-up the display will be blank.
I have sought widely and cannot find a definitive statement. Which of these interpretations is correct, or perhaps is there another interpretation?
Why does it matter? Idle curiosity really. My read of the datasheet was that the RAM was cleared and hence did not expect to have to manually clear it.
So I didn't, and was wondering where the flash of random data at power up in my bank of displays was coming from, prior to the first display data write. And I was a bit too slow in accepting I got reading the datasheet wrong, or the datasheet didn't apply to the clone I was using.
I was wondering if someone had a definitive answer from some deep investigation or perhaps insider information. It seems not, and it may not be consistent anyway.
For the clone MAX7219s in my collection, the SRAM is not cleared on power-up. I don't know if that is the case for genuine MAX7219 or for different clones for that matter. In future, I will just assume not and zero out the SRAM manually.
That point about a pull-up resistor on the chip select(CS) line to mitigate erratic behaviour is an excellent one. Random noise here can easily generate unexpected results.
It should be noted though that if the CS line is not the default Slave Select (SS) of the SPI pin group, it is not enough to use a pull-up resistor alone.
The SPI begin function takes care of the case that the default SS pin will glitch low as it is made an output if the corresponding bit in the output register is not set to 1 prior to setting the pin to output mode.
For the default SS pin, begin() does a digitalWrite HIGH first, setting the internal pullup resistor on (and the output register bit to 1) then a pinMode to OUTPUT, thus if the SS pin is already pulled high by a resistor there are no glitches.
However, if the CS pin is a pin other than the designated SS, then the same process must be undertaken by user code. If forgotten, even a pulled up pin will glitch low as the output register, with the bit set to 0, is transferred through to the pin when it is configured as output.
It is easily fixed using the same method as the SPI library uses, digitalWrite a HIGH to the CS pin, then set that pin to OUTPUT. And pull it up, of course.

I'm a little confused. There doesn't appear to be any way for you read the RAM in the the device. So if there were a distinction between the display being blanked and the RAM being cleared (I suspect there isn't) how would you observe that or why would you care? Your question as written is probably better suited to ESE.

If the mechanism is not described in the datasheet then it will be difficult to determine how the blanking is achieved and may even differ between various clones / fakes. However,  if you are asking because you have experienced erratic/random behaviour  at system start then putting a 10k pullup resistor on the load/cs pin may help.

You've edited your initial post extensively so it is not now clear if there is an issue remaining. However,  the point about the external pullup resistor on the load/cs pin is that it minimises the risk of instability at system start, to which these MAX7219 chips are prone, while the MCU pins are still floating. That is, before the internal pullup has been activated.

I think it's pretty clear from the datasheet.

all control registers are reset

The digit displays are registers, and therefore they will contain zeroes.
Displaying one digit, being in shutdown mode, and minimum intensity are all what would happen if all registers were set to zero.

I have sought widely and cannot find a definitive statement.

Why is this important to know? When powered on it will be blank, as stated. Presumably you will configure it to the way you want it before leaving shutdown mode.

the datasheet contains the phrase Table 2 lists the 14 addressable digit and control registers. ... it is unclear if all control registers are reset includes the digit registers ... like you said, does it really matter?


text:
Direct port manipulation takes 300 nanoseconds to execute for some reason
I have this code
#include <Arduino.h>

void setup() {

  DDRD  = B00001000;

}
void delayNanoSeconds(int time){
    int ans = (float)time / 62.5;
    for(int i = 0; i < ans; i++){
        _NOP();

    }

}
#define delay250 _NOP(); _NOP();_NOP(); _NOP();
#define delay1000 delay250 delay250 delay250 delay250
void loop() {
  while(1){
       PORTD ^= B00001000;
       delay1000; delay1000;
  }

  }

but I am getting delay of 2300 us
here is a picture of the logic analyzer
and when I change delay to 250 or 1000 I am still getting this extra 300ns so why

Remember: every single thing the CPU does takes time. Here is a
disassembly of your loop():
    ldi  r25, 0b00001000 ; r25 = B00001000
1:  in   r24, PORTD      ; r24 = PORTD
    eor  r24, r25        ; r24 ^= r25
    out  PORTD, r24      ; PORTD = r24
    nop
    nop
    ...
    nop
    rjmp 1b              ; goto previous label 1

As you see, besides your series of nop, there are four instructions in
the loop:

in, eor and out take one cycle each
rjmp takes two cycles.

That is a total overhead of 5 CPU cycles, or 312.5 ns when
running at 16 MHz. Pretty close to what you are seeing.
If you want an exact timings, you will have to disassemble your code and
count the overhead cycles, as I did here. Then, I suggest this simpler
approach:
#define OVERHEAD_CYCLES 5

void loop() {
    for (;;) {
        PORTD ^= _BV(PD3);
        _delay_us(2 - OVERHEAD_CYCLES / (F_CPU / 1e6));
    }
}

Ok thanks for help

By the way how did you see the assymbly code

@Abdrlrahman: Re “how did you see the assymbly code”: avr-objdump -SCz sketch.elf > sketch.lss. You should see the location of the ELF file if you enable verbose compilation. The avr-objdump tool is somewhere in your Arduino installation, but the exact location may depend on your OS and the installed version of Arduino. You may have to search for it.

By the way shouldnt it be _delay_us(2 - OVERHEAD_CYCLES  * (F_CPU / 1e6)); instead of /

@Abdrlrahman: No, it's really a division. It ends up being 2 − 5/16.0 = 1.6875 µs.

2 - OVERHEAD_CYCLES / (F_CPU / 1e6) must be evaluated at compile time, of course. Thus the 2 cannot be added at runtime. Interesting that _delay_us has a float parameter, compared to the Arduino delayMicroseconds(unsigned int)

source: Stack Exchange

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

sort: votes


text:
How do I properly use an ISR inside a class definition?
I want to write a class for a model bike.
For controlling the steering I use a DC motor with two encoders.
To get the steering angle stAng of the bike, I attach a interrupt to the pin ST_ENC_A where one of the encoders is connected to. This interrupt is attached when the bike is initialized with the function bike.begin(). When the interrupt is triggerd, the increment-steering-angle-function incStAng is triggerd.
Said function is member of the class Bike. To make the whole code compile and upload I had to make the increment-steering-angle-function static void incStAng() and the steering-angle-variable volatile static float stAng static.
The code is running, there are no errors or warnings.
Now, when I provide pin ST_ENC_A with 3.3V the interrupt should be triggerd and I should see the printed value of stAng increse in the Serial Monitor. This is not the case. It stays at 0.00.
This is my first real class I am writing. I only want to create one instance of my bike so the static definition of stAng and incStAng should be no problem.
So far I found the following websites helpful for information on 'static' and ISR.
I would be glad if someone could help me and give me a hint why the steering angle is not increasing when I give said pin 3.3V!
Board: Arduino Nano RP2040 Connect
Below you will see the .ino, .h, .cpp files in this order.
// myBike.ino - main file

#include "Bike.h"

Bike bike;

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

void loop() {
  float val = bike.getStAng();
  Serial.println(val);
}

// Bike.h - header file for the Bike library

#ifndef Bike_h
#define Bike_h

#include "Arduino.h"

class Bike {
  public:
    Bike();
    void begin();
    float getStAng();
  private:
    volatile static float stAng;
    static void incStAng();
};

#endif

// Bike.cpp - implementation file for the Bike library

#include "Bike.h"

#define ST_ENC_A      12
#define ST_ENC_B      11

#define DEG_PER_CNT   0.51428571428

Bike::Bike() {
  pinMode(ST_ENC_A, INPUT);
  pinMode(ST_ENC_B, INPUT);
}

void Bike::begin() {
  attachInterrupt(digitalPinToInterrupt(ST_ENC_A),incStAng,RISING);
}

void Bike::incStAng() {
  volatile float stAng;
  int b = digitalRead(ST_ENC_B);
  if(b==HIGH){
    stAng = stAng - DEG_PER_CNT;
  }else{
    stAng = stAng - DEG_PER_CNT;
  }
}

float Bike::getStAng() {
  volatile float stAng;
  return stAng;
}

Did you connect that pin to ground previosly before changing to 3.3V? Do you use external pullup or pulldown resistors? The pin might already have been at 3.3V, thus connecting it to 3.3V would not generate a rising edge. Have you tried connecting and rotating the actual encoder?

You have three different variables named stAng here:

a static member of the Bike class, which has been declared but not
defined, and is never used
a local variable of the Bike::incStAng() method
a local variable of the Bike::getStAng() method

There should be only one such variable. For this, you should define the
first one: in Bike.cpp
volatile float Bike::stAng;

and get rid of the other two.
Side note: I would recommend avoiding floating point computations within
an ISR, as these can be quite slow. Instead, count the integer number
of encoder steps in the ISR, and convert to an angle within
Bike::getStAng().

Thank you for this quick help, it works like I want it to!
I am still wondering why it has to be like this though.
Adding these two local variables you mentioned made the code compile, this is why I did it.  So, in the class I only declare stAng as a static member but with volatile float Bike::stAng; in Bike.cpp I define it, right? I do not get the underlying rule why I have to do it this way. Could you give me a short explanation? If I add a non-static variable to the class and want to access and modify it using a method of Bike I do not have to add such a definition in Bike.cpp.

@Ole: The class definition in Bike.h defines a type only. No data. The line Bike bike; in myBike.ino defines a Bike object, and thus all the data belonging to that object (which in this case just happens to be none). A static data member does not belong to any object, and thus has to de defined elsewhere. It has also to be defined only once, so a .h file, which could potentially be included in multiple other files, would not be appropriate.

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


text:
Passing function as argument, with capture, what type to declare in function?
This probably has a simple resolution, but can't find the right combination.
I'm trying to setup a function (setupScreen) to take as an argument a function to do the actual setup:
void ScreenHelpers::setupScreen(void (*setupFunc)(ThinkInk_290_Tricolor_Z10*)){
    ScreenHelpers::waitTilCanRefreshScreen();

    (* setupFunc)(&display_two);

    lastUpdateTime = millis();
}
//...
void ScreenHelpers::displayErrorMessage(const String message){
    const char* text = message.c_str();
    ScreenHelpers::setupScreen([text](ThinkInk_290_Tricolor_Z10* screen) {
        screen->clearBuffer();
        ScreenHelpers::simpleDisplayText(
            screen,
            text,
            EPD_RED
        );
     });
}

This works, until I added the [text] to capture the text variable in the lambda, where it resulted in:
ScreenHelpers.cpp: In static member function 'static void ScreenHelpers::displayErrorMessage(String)':
ScreenHelpers.cpp:45:4: error: no matching function for call to 'ScreenHelpers::setupScreen(ScreenHelpers::displayErrorMessage(String)::<lambda(ThinkInk_290_Tricolor_Z10*)>)'
   });
    ^
ScreenHelpers.cpp:21:6: note: candidate: 'static void ScreenHelpers::setupScreen(void (*)(ThinkInk_290_Tricolor_Z10*))'
 void ScreenHelpers::setupScreen(void (*setupFunc)(ThinkInk_290_Tricolor_Z10*)){
      ^~~~~~~~~~~~~

What should my function declaration look like to accept this?

This is not an Arduino specific question, it is a pure C++ issue. Please ask this at [so], if you still don't know how to do it, after doing the necessary research.

I have to disagree, Arduino's C++ is an odd subset of the language. I'd argue it is reasonable to look to Arduino-specific places for advanced language features.

The compiler used by the Arduino is a standard GNU C++ compiler targeting the AVR or ARM processor. As such it is not really limited in the language, and we program in standard C++. But the accompanied C++ libraries can be incomplete, for example <functional> might be missing, granted. -- So it had helped if you had mentioned your specific Arduino target.

ScreenHelpers::setupScreen() expects its argument to be a plain
function. A capturing lambda is not a plain function: it is rather a
functor, i.e. an object that is callable like a function.
The standard way of passing such a lambda in C++ is to declare the
parameter to be of type std::function:
#include <functional>

void ScreenHelpers::setupScreen(std::function<void(ThinkInk_290_Tricolor_Z10*)> setupFunc) {
    ...
}

This may or may not work depending on the Arduino board you are using.
AVR-based boards rely on a C library that only minimally supports C++.
You cannot use <functional> on those boards. If you are using one of
those boards, your options are:

Try to find an implementation of of the C++ STL for AVR-based boards.
I have seen at least one floating around in the Net.

Use the standard C idiom for defining a callback with a void*
parameter:

void ScreenHelpers::setupScreen(
      void (*setupFunc)(ThinkInk_290_Tricolor_Z10*, void*),
      void *callback_data) {
   setupFunc(&display_two, callback_data);
   //...
}

// elsewhere:
ScreenHelpers::setupScreen([](ThinkInk_290_Tricolor_Z10 *screen, void *data) {
   const char *text = (const char *) data;
   // ...
}, (void *) text);

Thanks! Looks like my board supports the lambdas, making things easy!
The second option crossed my mind too, was also thinking maybe making the *data param a varargs.


text:
Carbon dioxide sensor MG 811
I am using MG811 carbon dioxide sensor with ESP8266 module. CO2 values is being read inside closed room. The value comes around 400 ppm. Using CO2 generator does not make increase in reading. Checked with pSense RH co2 Temp handheld meter. It shows around 750-800 ppm. But ESP8266 still shows around 420 ppm on oled display.
#include "CO2Sensor.h"
CO2Sensor co2Sensor(A0, 0.99, 100);

void setup() {
Serial.begin(9600);
Serial.println("=== Initialized ===");
co2Sensor.calibrate();
}

void loop() {
int val = co2Sensor.read();
Serial.print("CO2 value: ");
Serial.println(val);
delay(1000);
}

What is the meaning of (A0, 0.99, 100) in second line of code. Is any calibration needs to be done for correct value ?

You will probably need to show this thing is wired and what source you are using to power the heating element.

check the library documentation

Your code appears to come from an example in the library you are using https://github.com/solvek/CO2Sensor/blob/master/examples/ReadCO2/ReadCO2.ino
To answer your questions:
What is the meaning of (A0, 0.99, 100) in second line of code.
Inspection of the library source code shows:
CO2Sensor::CO2Sensor(int analogPin, float inertia, int tries)
Of course, if you don't understand how the library is using the variables inertia and tries, this alone will make no sense to you.
Is any calibration needs to be done for correct value ?
In my opinion, the answer is YES. Furthermore, I think that calibration is necessary but not sufficient to appropriately use the sensor to the extent that you can have a good idea about what a "correct value" means.
I like that you get the fundamental idea of testing, or validating, a sensor. I like the idea that you are using another monitor (assuming it is a good one) as a "standard" and I like that you use a CO2 generator - assuming you are doing that safely.
What is lacking, again, in my opinion, is any understanding of how the sensor works. It is not that I am an expert on this particular sensor, but even a brief look at what passes as a data sheet https://sandboxelectronics.com/files/SEN-000007/MG811.pdf and the text of the library usage https://github.com/solvek/CO2Sensor and a few other sources that are freely available; makes it clear to me that you need to dig into this much more before you will have success understanding and appropriately using this sensor.
It is complicated. I hope that my response is not off putting and instead points you in the right direction.


text:
Can I power Lilygo TTGo T-display from 5v and still use USB for communication?
I have a project which needs a 7-9V power source.  I use a battery, and plan to use a small regulator to supply 5V to a Lilygo TTGO T-Display V1.1 (1.14 inch display) via the 5V and GND pins.
I need to connect the Lilygo to USB from time-to-time to upload data.  Will there be any conflict between the USB power and the 5V supply ?
I have peered for a long time at the schematic, and I see that there are MOSFETs doing some kind of protection, but I do not understand it well enough to be sure.
Schematic: here

Q5 appears to disconnect the battery (VBAT) from +5V when the USB is
connected.
Q4 also seems to disconnect the battery (BAT) from +5V when the USB
is connected.  What is the difference between VBAT and BAT ?
VBUS (the USB power) is connected to +5V via a Zener diode.  This
appears to allow the USB to supply 5V, but prevent current flowing
back to the PC.  I think there could be an issue with high current
through the Zener if my 5V regulator gave a voltage that was lower
than the USB.

is that the official schematic diagram? ... it is sloppily drawn

What do you mean "via the 5V and GND pins"? Do you mean directly to the traces or do you mean by hooking up the regulated battery voltage to the battery input pins? Do note that the board expects a 3.7-4.2V input for the battery, 5V is too much; take a look at the charger datasheet (TP4054). Also, next time use the Electrical Engineering SE as it's more relevant to these kinds of questions, rather than the Arduino one.

a zener between usb and 5v doesn't makes sense, sure it's not a Schottky? How do you even upload data over the USB connector anyway? Why not just use wifi so you don't risk your device or computer?

@dandavis it is a Schottky, yeah, even after reading the datasheet I came back to the post to write "Zener" in my answer hahaha. The USB is connected to the USB-UART chip, which in turn is connected to the ESP32's UART #0. Using WiFi would be fine, but you still have to power it and looking at the company's website and the schematic, they did not design the board with the intention of it being powered by anything other than the USB or the battery.

I just looked at datasheet for the charger, TP4054.  I see that Vin is given as 4.5 - 6.5V (with absolute max rating of -0.3 - 10V).  It is connected to VBUS in the schematic,  which I believe is nominally 5V.  BAT is rated as -0.3 - 7V, so I am thinking applying 5V to the battery input should be safe. Maybe I am looking at the wrong datasheet.

@elpidiovaldez5 huh, okay, for some reason I thought it said Vcc-0.6 for the input battery; either I was looking at a different part yesterday or I made it up :) Glancing at it again, yeah, applying the 5V to the battery input should be a viable way to do what you're looking to do. Just make sure that the current that the regulator provides isn't over the specs and if you do connect the USB while powering it from the 5V regulator, just double-check that it can potentially sink the current from the charger. It shouldn't initiate the charging sequence because Vbat > Vfloat, but just in case :)

What are you trying to achieve? For how long is the board supposed to function? The simplest solution in this case is to simply get a 4.2V battery for the LilyGO board itself, most likely not just in terms of effort, but economically.
From your edits, I (now) assume you want to use the 5V pin on the board? I don't think that'll work the way you'd want it to, as it doesn't seem that it was intended for that (if it was, the VIN pin would've been brought out).

Q5 appears to disconnect the battery (VBAT) from +5V when the USB is connected.

Yeah, that makes sense to me as well.

Q4 also seems to disconnect the battery (BAT) from +5V when the USB is connected. What is the difference between VBAT and BAT ?

Yes, looking at the datasheet for the battery charger and the schematic for the LilyGO board, VBAT is the batteries voltage, while the BAT terminal is the one coming out of the charger and the one that usually supplies the current to both charge the battery and to possibly drive the system load.

VBUS (the USB power) is connected to +5V via a Zener diode. This appears to allow the USB to supply 5V, but prevent current flowing back to the PC. I think there could be an issue with high current through the Zener if my 5V regulator gave a voltage that was lower than the USB.

Yeah, it prevents the current going back into the USB port if you have the battery connected. You need a pretty substantial voltage to overcome that Schottky* barrier.
One issue you'll probably encounter is that if you connect a 5V source to that pin, the system will think it's powered on by a battery and you can damage the BAT terminal. If you have more than 1 of those boards and you're willing to experiment, you could try cutting the trace to BAT terminal altogether and connecting the 5V source and seeing if that works.
Another issue is that for safety reasons, it'd be prudent to switch that source off when you're connecting the USB; you'd also want to protect that 5V source from being damaged by the VUSB once it's on. There are probably ways you could keep the 5V on if you desolder the USBC connector and try to manually attach a probe to the datalines and ground the two together, but dealing with USBC is not easy and you're rapidly venturing into territory where it's just easier to get a different board and the screen separately or just use a LiPo battery to power the board in the first place (you could probably find a way to use multiple LiPo packs if you need your application to last longer as well).
Note: I didn't spend too much time looking at the schematic and it is a bit confusing, so a possible good exercise would be to simulate those two circuits in a SPICE program. And again, these types of questions are covered more-so by the EE SE. If you'd have posted it there, I'm sure you'd get more (and most likely, better) answers.

Thanks for putting in so much effort.  My project needs 9V to power some other equipment, so I want to power the ESP32 from the same battery - hence the idea of using a 5V regulator.  Sorry about mix-up over Zener/Schottky - I checked Google and a lot of sources use the same symbol for Zener.  The circuit diagram is not 'official'.  I have not been able to find any official documentation for this board. I will post another question on the other site you mentioned.

@elpidiovaldez5 that's okay, that's why looking at the datasheets helps - that one is a Schottky indeed!


text:
Arduino Timer Drift Issue
I have two Arduinos that communicate over serial. Each arduino runs a TDMA algorithm where each arduino is assigned one timeslot. The arduinos should transmit during their timeslot, which does work fine. However, over time, say 10-15 minutes the arduinos start to overlap their timeslots. To keep time I am using the millis() function to determine when to send a message. I have tried both delay() and manually setting up counters but getting the same drifting behavior. On one of the iterations of the code I had a Serial.readStringUntil() function that was being called during every timeslot and the arduinos stayed in sync for over 13 hours with no detected drift, with an exact timeslot of 1000ms. I now am aware that the delay I was seeing is caused by the timeout parameter, which defaults to 1000ms, in the readStringUntil function, but it does not make sense that there would be no drift when the arduino was delayed in this way. I know that the stability of the ceramic resonator on each arduino would cause drift.
Why would delay(), millis(), and manually configuring timer1 cause drift, but the timeout functionality of the readStringUntil function seemingly does not drift?
Also, is there a better way to setup the timing functionality, the goal is to have the nodes go as long as possible without needing a resync?
The following psuedo is how the timing is currently setup.
count = 0;

if(millis() - previous_action >= TIME_SLOT) {
   count++;
   if(correct timeslot) {
       TRANSMIT();
   }
   previous_action = millis();
   loop_back_to_check;
}

EDIT:
RTC and other devices that can keep the devices sync'd are not in the scope of the project.

what device do the arduinos communicate to?

@jsotola they send messages to a receiver which collects packets and prints to a file.

What kind of Arduino are you using? Is it clocked off a crystal or a ceramic resonator?

Similar to @NickS below. Modify the TDM algorithm running on both devices so that the transmissions can be used also to keep the devices in sync. For example, if each transmission starts exactly 100ms into the timeslot, the other side can adjust its clock to match. In this case, the next full second rollover should be in 900ms.

Any fee-running clock will drift. Worse yet: its drift rate will not be
constant. This is a fact of life, and there is nothing you can do about
it. There is no software solution, although your software can certainly
make things worse. What you can do is:

Synchronize the clocks of both Arduinos to an external time source.
The time source doesn't have be accurate if you only care about the
relative drift between the Arduinos. This could be the receiver of
the messages sending an acknowledgement at a specific time, or the
same receiver sending a pulse on a dedicated line, or an NTP server
if your Arduinos are networked, or a radio-broadcast time signal, or
a GPS receiver...

Use clocks that are so good that their drift becomes irrelevant. The
drift rate has to be less than the timing tolerance of your TDMA
protocol divided by the expected service life of your devices. A good
RTC can give you a drift rate less than about 2 ppm (i.e.
2×10−6). If that is not good enough, you may consider an
OCXO (oven-controlled crystal oscillator) or an atomic clock (the
rubidium-based ones are the most affordable).

Calibrate your clocks. As the variations of the drift rate are
typically much less than the average drift rate, you can remove most
of the drift by first measuring it and then removing in software the
value you measured. You are then left with the random variations of
the drift rate (“frequency wander”). I suggest you read Arduino
clock frequency accuracy to get an idea of the kind of
accuracy you can expect.

Use temperature control: keep you clocks at constant temperature, as
temperature variations are often the main cause of frequency wander.
Alternatively, use temperature compensation: measure the drift rate
at multiple temperatures, fit a continuous curve through these
measurements and use this curve (and continuous temperature
measurements) to correct the drift in software.

Avoid making things worse with your software: update
previous_action with
previous_action += TIME_SLOT;

rather than assigning millis() to it, as this approach is
guaranteed to cause drift.

Why [...] the timeout functionality of the readStringUntil function
seemingly does not drift?

Nobody can answer this question without a careful examination of both
the specific version of the software you used and the physical setup. It
could be that you accidentally implemented a synchronization mechanism.
It could be that your measurements were not accurate enough to reveal
the drift.

You can use one of the many RTC (Real Time Clock) modules, they are crystal controlled where your Arduino is not. There are several varieties, pick the one you like. There is a large difference in stability between the Arduino timing and the RTC timing. You can update the clocks on a regular basis. Using NTP (Network Time Protocol) which would be very accurate and reliable. You can do the NTP on a regular basis on one unit and have it update the others. Side benefit they will not drift much as the temperature changes.

See edit. The goal of this is to avoid RTC and only use the internal clock of the arduino to keep time of the device

@roberthayek then it sounds like you'll have to expand on your TDMA algorithm and have the two devices generate overhead and maybe have one be the "server" and the other a "client" - the client device will be doing all the scheduling and the server device will have to adjust its time slots based on the information provided by the client. The two devices have different clocks and thus different drifts, you really can't just fix that.

According to my experience, they are the clients that should follow the server's timing.
On the client side:

On each server transmission, calculate the ETA (Estimated Time of Arrival and ATA (Actual Time of Arrival) of the message, based on your time slot scheduling and adjust your local clock accordingly.
It would be nice to treat all transmissions as timing messages, no matter the destination, just ignore the payload.
It is obvious that the client should be a little overhead timed, in case the server's clock is a little faster.
For long inactive periods, the server should broadcast a periodic timing message, so that the error will be kept to a minimum.
It would be convenient to add a "timing preamble" in each transmission.

With all that in mind, the readStringUntil function is your friend in many ways. By waiting for the timing preamble, you can determine easily the timing error. By waiting for a known postamble, you read "late" messages (don't forget the timeout value!).
Use a bi-numbering scheme for each transmission, one for each client's message and one for each broadcast (total transmissions). Calculate the minimum convenient modulo (overflow) values. Each client will know if there's something missing. (usually, a too-early transmission or a collision)
Although it is communications-medium agile, I would recommend a preamble like:
$FF $00 $FF $00 AA BB CC DD EE $FF $FF FF with PAYLOAD following, where:

AA = 1 byte, the destination addr, $00 = Broadcast

BB = 1 byte, message type (optional, $00 for timing msg)

CC = 1..2 bytes, msg no. to this dest.

DD = 1..2 (3?) bytes, total msg no., no matter the dest.

EE = 1 byte, payload length, if variable. (EE<$FF, $00 for timing msg)

FF = 1 byte checksum (optional). (Why should you place it AFTER the "$FF
$FF" combination?)

Use the time you receive the "$FF $FF" combination as a time-mark to calculate ATA & ETA. (It is common sense to treat your values so that this combination cannot show before the end of the preamble)
Consider using a postamble, with redundant info & End-Of-Message mark.


text:
DS3231 with Arduino Nano for Timing precision
I am in need to synchronize two separate circuit boards working with Arduino nano. The need is to activate one relay using Arduino-1 after 45 min and another relay using Arduino-2 after 45.36 seconds. The time starts from the point of reception of input from an external switch common to both.
with ref to This question and from the advice of edgar-bonet I have used one temperature-compensated RTC for timing the Arduino s externally (DS3231). I am using its 32kHz pin from the chip for counting the ticks and in the Arduino using the interrupt to count the ticks.
The program is shown below.

float _sec = 1;

float secTime =  _sec * 1000UL; // second->millis
uint32_t coilTime = 5 * 1000UL; // second->millis

volatile uint32_t count = 0;
/*
 * 32768 ticks in 1 sec
 * 0.032768 tick in 1 us
 */

float _multiplier = 0.032768; // 32768 Hz

uint32_t _delay = secTime * _multiplier * 1000UL ;

volatile bool onFlag = false;

ISR(INT1_vect, ISR_NOBLOCK) {
  count = count + 1UL;
  if (_delay == count) {
    PORTC |= (1 << 5);
    onFlag = true;
    EIMSK = 0;
  }
}

ISR(INT0_vect) {
  /* INTERRUPT re-initalization */
  EIMSK = 0;
  EICRA = B00001100; // INT0 - clear ; INT1 -  set
  EIFR  = 0;
  PORTB ^=  (1 << 0) | (1 << 1); // setting Green off and red on
  count = 0;
  EIMSK = B00000010; // INT0 - inactive ; INT1 - active
}

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

  /* PIN initialization */
  DDRB |= (1 << 0) | (1 << 1); // red led and green led

  pinMode(3, INPUT_PULLUP); // timer unit
  pinMode(2, INPUT); // interrupt unit

  DDRC |= (1 << 3) | (1 << 4) | (1 << 5); // relay, OUT_1, OUT_2

  /* LEDs state update */
  PORTB &=  ~(1 << 1); // red off.
  PORTB |= (1 << 0); // green on.

  PORTC &= ~(1 << 3); // A3-off

  /* INTERRUPT initalization */
  EICRA = B00000011; // INT0 - set ; INT1 - not set
  EIMSK = B00000001; // INT0 - active ; INT1 - inactive
  EIFR  = 0;
}

void loop() {

  if (onFlag) {

    PORTB |= (1 << 0); // setting green on

    delay(500);
    PORTC ^= (1 << 5);
    //    PORTB ^= (1 << 0) | (1 << 1);
    PORTB ^= (1 << 1); // setting red off
    while (true) {
      TCCR2B = 0;
      count = 0;
      PORTB ^= (1 << 0);
      delay(500);
    }
  }
}

when running the program The result I am expecting the accuracy of microseconds
but
for
input -> Measured value
1 sec -> 1.000387792
2 sec -> 2.000784208
50 sec -> 50.020926833
250 sec -> 250.104557792
How to make the clock more precise, In the datasheet it is said that the clock is accurate to +- 2ppm.
datasheet-ds3231

I'm not completely sure I understand your use case because, at least for the initial synchronisation, there is a connection between the 2 devices.
volatile uint32_t count . . . count = 0; beware of asynchronous non-atomic operations on multi-byte variables on an 8bit MCU. For high precision calculations, float may have limitations: float _multiplier = 0.032768; 2ppm is about one second every five days.

Can you please advise me on the correct variables to be used? In the initial case, I have a common switch connected to my devices and I use that as the interrupt signal.

1.0000000 / (1.000387792 / 32768 ) = 32755.29776 .... that makes 32755 ticks in 1 second

after 45 min and another relay using Arduino-2 after 45.36 seconds does not declare the necessary precision ... for example, 45.36 can be anywhere between 44.355000... and 45.364999...

@jsotola, If i am okay with that much dispersion what modifications to be done.?

Instead of using floats to specify the time interval,  why not  specify say 1 second as 32768? At a quick glance, the loss of ticks (in comparison to your reference) seems linear at around 13 per second. Maybe try switching off timer 0 to inhibit its possibly clashing interrupts and then you'll have to find another solution for delay().

I cannot understand what your code is trying to do, and I do not see how the code relates to the “input -> measured value” part of the question. I suggest you follow the advice in How to create a Minimal, Reproducible Example. 2. You have a very contrived way of writing _delay = 32768. Please, note that 0.032768 cannot be represented as a float, and will be rounded to the nearest representable number, which is 0.0327679999172687530517578125

This may not be a proper answer to your question. Instead of telling you
how to improve the accuracy, I will show you how to measure it. The
issue is that the code you posted is doing too much stuff, and it is not
clear how it could be measuring the clock accuracy. So, instead I
suggest you try the code below:

connect a push button between pin 2 and GND
connect the 32768 Hz signal to pin 5
watch the built-in LED blink

const uint8_t input_pin = 5;  // 32768 Hz on digital 5 = T1
const uint8_t clear_pin = 2;  // button to clear timer

void setup() {
    pinMode(input_pin, INPUT_PULLUP);
    pinMode(clear_pin, INPUT_PULLUP);
    pinMode(LED_BUILTIN, OUTPUT);

    // Configure Timer 1 as a counter.
    TCCR1A = 0;
    TCCR1B = _BV(CS11) | _BV(CS12);  // count falling edges of T1
}

void loop() {
    // Display bit 14 of the counter on the builtin LED.
    if (TCNT1 & (1 << 14)) {
        digitalWrite(LED_BUILTIN, HIGH);
    } else {
        digitalWrite(LED_BUILTIN, LOW);
    }

    // Clear the counter on button press.
    if (digitalRead(clear_pin) == LOW) {
        TCNT1 = 0;
    }
}

What this sketch does is use Timer/counter 1 as a counter in order to
count the falling edges of the 32768 Hz signal. Bit 14 of the counter
should then toggle at 1 Hz. This bit is output on the built-in LED to
let you check its frequency. You can use the push button to reset the
phase of the blinks.
If you have a very accurate clock at hand, you can use the push button
to synchronize the blinks with the ticks of that clock, and then see how
long it takes to get visibly out of phase. You can also synchronise the
blinks of two Arduinos and see for how long they stay in sync. If you
have a scope, you could measure a tiny offset between the edges of the
two Arduino's LEDs, then see how this offset evolves with time.


text:
Is ESP8266 dropping an interrupt?
I want to use interrupts on my ESP 8266 to monitor the digital outputs of a power meter and water meter.
The idea is to increment a counter in the ISRs and at some point to take the value of the counter and to set the counter back to 0 in the loop() function.
I've red about critical sections, noInterrupts() and interrupts() and then I started to wonder if an ISR will be executed while the code is between noInterrupts() and interrupts(). On theory it should be because the interrupt flag in the chip will be raised and the ISR will be invoked after the code exits the critical section. I wrote a program to test it, but my findings prove the opposite.
#include <Arduino.h>

#define REPORT_TIME 5000
#define INTERRUPT_PIN D1

unsigned long base_time;

volatile unsigned int interrupt_counter = 0;

void IRAM_ATTR isr() {
  interrupt_counter++;
}

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

  // The interrupt will be FALLING EDGE
  pinMode(INTERRUPT_PIN, INPUT_PULLUP);
  pinMode(LED_BUILTIN_AUX, OUTPUT);
  digitalWrite(LED_BUILTIN_AUX, HIGH);
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), isr, FALLING);

  base_time = millis();
}

bool written = false;

void loop() {

  if (!written)
  {
    written = true;
    for (int i = 0; i < 100; i++)
    {
      digitalWrite(LED_BUILTIN_AUX, LOW);
      digitalWrite(LED_BUILTIN_AUX, HIGH);
    }
  }

  unsigned long time_now = millis();
  if (time_now - base_time >= REPORT_TIME)
  {

    written = false;

    base_time = time_now;

    unsigned int interrupt_counter_local;

    //Guard the critical section
    noInterrupts();
    interrupt_counter_local = interrupt_counter;
    interrupts();

    digitalWrite(LED_BUILTIN_AUX, LOW);
    digitalWrite(LED_BUILTIN_AUX, HIGH);

    Serial.print("counter ");
    Serial.println(interrupt_counter_local);
    Serial.println();
  }
}

Using a wire I attached the pin of the builtin led to the interrupt pin and in the serial monitor I could see the values are:
counter 100
counter 201
counter 302

When I modify the critical section to be like:
noInterrupts();
interrupt_counter_local = interrupt_counter;
digitalWrite(LED_BUILTIN_AUX, LOW);
digitalWrite(LED_BUILTIN_AUX, HIGH);
interrupts();

I expect the same output as above but the values are:
counter 100
counter 200
counter 300

Am I missing something or the interrupts doesn't work as I expect?

After some additional experiments I found that moving
digitalWrite(LED_BUILTIN_AUX, HIGH);

utside the critical section gives me the expected result, so I'm not blocked anymore and more importantly the chip will not drop an interrupt.
If someone knows why it doesn't work with my initial version I will be happy to hear the answer.


text:
UDPSendReceiveString example using Arduino Due with ENC28J60 Ethernet Module
I was trying to learn how to use UDP protocol to use in my automation project to send commands to an Arduino Due on ethernet with an ENC28J60 breakout board which I have connected to the Due from SPI pins. I had to use another library called EthernetENC.h to use this module with the Due.
Arduino Code:
#include <EthernetENC.h>
#include <EthernetUdp.h>

#define UDP_TX_PACKET_MAX_SIZE 256

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xA0, 0x36, 0xBC, 0x30, 0xC1, 0x16
};
IPAddress ip(192, 168, 137, 205);

unsigned int localPort = 8888;      // local port to listen on

// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];  // buffer to hold incoming packet,
char ReplyBuffer[] = "acknowledged";        // a string to send back

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

void setup() {
  // You can use Ethernet.init(pin) to configure the CS pin
Ethernet.init(10);  // Most Arduino shields
  //Ethernet.init(5);   // MKR ETH Shield
  //Ethernet.init(0);   // Teensy 2.0
  //Ethernet.init(20);  // Teensy++ 2.0
  //Ethernet.init(15);  // ESP8266 with Adafruit FeatherWing Ethernet
  //Ethernet.init(33);  // ESP32 with Adafruit FeatherWing Ethernet

  // start the Ethernet
  Ethernet.begin(mac, ip);

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }

  // start UDP
  Udp.begin(localPort);
}

void loop() {
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remote = Udp.remoteIP();
    for (int i=0; i < 4; i++) {
      Serial.print(remote[i], DEC);
      if (i < 3) {
        Serial.print(".");
      }
    }
    Serial.print(", port ");
    Serial.println(Udp.remotePort());

    // read the packet into packetBuffer
    Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    Serial.println("Contents:");
    Serial.println(packetBuffer);

    // send a reply to the IP address and port that sent us the packet we received
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(ReplyBuffer);
    Udp.endPacket();
  }
  delay(10);
}

Processing 3 Code:
 import hypermedia.net.*;

 UDP udp;  // define the UDP object

 void setup() {
 udp = new UDP( this, 6000 );  // create a new datagram connection on port 6000
 //udp.log( true );     // <-- printout the connection activity
 udp.listen( true );           // and wait for incoming message
 }

 void draw()
 {
 }

 void keyPressed() {
 String ip       = "192, 168, 137, 205";  // the remote IP address
 int port        = 8888;    // the destination port

 udp.send("Hello World", ip, port );   // the message to send

 }

 void receive( byte[] data ) {       // <-- default handler
 //void receive( byte[] data, String ip, int port ) {  // <-- extended handler

 for(int i=0; i < data.length; i++)
 print(char(data[i]));
 println();
 }

And this is my test setup:

After I upload the code to the Due the LinkOFF command immediately triggers and Serial.print() prints that "Ethernet cable is not connected." but this is indeed incorrect since this setup worked in other ethernet examples. But other than this message there is nothing on the Serial monitor. On the processing side, the story is even more depressing because simply nothing happens. There is just a small window opening and no matter where a click or press any key on my keyboard no string is being sent or received. I seriously don't know what to do I don't have much experience with UDP and I am trying to learn but the only responsive example in the Arduino library isn't working.
Edit:
I have connected the ENC28J60 directly to my laptop ethernet port and I chose the IP from there which was IPv4 Adress = 192.168.137.1
I also remove the linkOFF() from the original example since it was just using serial monitor for no good.

do you use a crossed Ethernet cable? try to connect to router and try the basic examples of the Ethernet library (with #include <EthernetENC.h>). best to try as first is the WebClient example

from https://github.com/JAndrassy/EthernetENC/wiki/Examples

If the Ethernet.linkStatus() is invoked too soon, it may return LinkOFF. You can do the check in setup() this way:

  if (Ethernet.linkStatus() == LinkOFF) {
    delay(500);
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected.");
    }
  }


text:
Arduino Nano R3 & Deek-Robot datalogging shield
Whilst I am much more at home programming PIC ISR's in assembler, I am building a data logger using a DS1307 to interrupt every second to write data to a USB SD card.
There does not appear to be a connection or even a pad from the DS1307 SQW for interrupts and feel I must be missing something, as this would be a remarkable designer/manufacturer oversight?

what is your question? ... are you asking if it would be a remarkable oversight?

is it so important to track the real time seconds in your project? using millis() function is not good enough?

Thanks and no worries.

I can't find any official source for information about "Deek-Robot datalogging shield" but what I do find indicates it is the same or similar design as an Adafruit Datalogging shield. The DS1307 (or other RTC) square wave out signal is routed to a through-hole on the interior of the board indicated in this image:

It does not appear to be routed anywhere else an any of these boards. Note: the picture here is of a board (Current Adafruit logging shield apparently) that uses an NXP RTC that has the same pinout as the DS1307, but uses a different register layout. But in any case places the SQ output on a header in the same basic location. So you would need to solder a header to accept a jumper. Or solder a wire from there to one of the through holes for a digital pin, probably pin 2 or 3 if you're on an UNO (you have tagged) since those are the pins compatible with attachInterrupt()

Thanks, once I put my glasses on I was able to find it.


text:
Controll the dc motor that works with 2xAA bateries using 5v
I have a toy that has a dc motor and is runing with 2xAA bateries ( i think it is 3v motor)
So i want to run it with 5v power supply.
First question: Can 5v damage the motor
Second question: i think i need to add diode but dont know what diode to add and how to determine what i need
Third question: is there a combination that i can add series of diode so i can drop voltage to 3v

yes ... 2) research motor control with arduino ... 3) yes

can drop current tl 3v ...  current is not measured in volts ... it is measured in amps

DC electric motors are usually rated to run over a range of voltages.  If you are unsure of the specifications of the DC electric motors you have, consider buying new motors which are specified to operate in a rage that includes 5VDC.
Consider not running both the processor (Arduino) and any high current demanding device off the same power source.  Such as solenoids or motors.  This is especially true for mobile devices supplied by battery voltage.  Often is the case the processor will reset (behave unexpectedly) should the supply voltage drop because of activating a solenoid or motor.
Diodes and other components are added to suppress or mitigate undesired effects of a solenoid or motor.  Inductive loads such as solenoids or motors resist changes in current flow and can damage connected components if the undesired current flow is beyond the connected component's abilities.  Read this stackexchange question/answer for more about this.
A silicon diode has a forward bias voltage drop of about 0.6 volts.  Other diodes have different forward bias voltage drops.  This wikipedia article lists a few different diodes. It may be possible to arrange enough diodes in series to drop 5 volts to 3 volts.
Consider searching for a 5VDC controllable Arduino relay module.  There are plenty on the web.  Such a device should include the circuitry to safely control the relay and the relay should provide more than adequate isolation from the DC motor.
For a learning experience, consider following this Arduino / Motor tutorial provided by Adafruit.


text:
I don't understand what's wrong with this code
int ledy = 5 ;
int leds = 4 ;
int ledk = 3;
int button = 2 ;
int count = 0 ;

void setup()
{
  pinMode(ledy, OUTPUT);
  pinMode(leds, OUTPUT);
  pinMode(ledk, OUTPUT);
  pinMode(button,INPUT);
  randomSeed(analogRead(A0));
}

void loop()
{
  if(digitalRead(button)== HIGH)
  {
  count = count++ ;
  }
    if (count==1)
  {
    digitalWrite(ledk, HIGH);
    digitalWrite(leds, LOW);
    digitalWrite(ledy, LOW);

   }
    else if (count==2)
   {
    digitalWrite(ledk, LOW);
    digitalWrite(leds, HIGH);
    digitalWrite(ledy, LOW);

    }

   else if (count==3)
   {
    digitalWrite(ledk, LOW);
    digitalWrite(leds, LOW);
    digitalWrite(ledy, HIGH);
   }

     delay(1000);

}

I don't undertstand why it isn't working.
I want it three leds to light up one by one as loop. But none of them lights up.

Please tell us what you want to achieve and what happens instead.

I want it three leds to light up one by one as loop. But none of them lights up.

You also could use the serial port to print some messages to the arduino serial monitor to see if the button press is detected and the right if-condition gets triggered. Also show your circuit - there could also be something wrong. Depending on how your button is wired a pull-down resistor might be needed. If the button pulls the pin to GND you could use pinMode(button,INPUT_PULLUP); and then need to test for digitalRead(button)== LOW...

@gruesome, please add that information to your question. This is probably caused by count = count++ which (I guess) does not do what you think it does. Replace it with either count++ or count = count + 1. It might also be a good idea to reset the counter after it reaches 3.

@gruesome Please "edit" your original question and add additional information there and not to the comments.

forget your code for now ... write a simple sketch that lights one of the LEDs for one second, turns off LED for one second, and repeats ... test all three LEDs this way ... update your question with results of the test

One thing that jumps out to me as a possible cause of your issue here is that many push buttons require a pull-up resistor, which is provided as an internal component of most microcontrollers, but needs to be specifically requested in the pinMode instantiation of the button. Try changing your setup() function to the following:
void setup()
{
  pinMode(ledy, OUTPUT);
  pinMode(leds, OUTPUT);
  pinMode(ledk, OUTPUT);
  pinMode(button,INPUT_PULLUP);
  randomSeed(analogRead(A0));
}

however if you do this, you must also change your if statement to if(digitalRead(button) == LOW), as a pullup resistor will make it so that when the button is not pressed, the pin is pulled high, and vice-versa.
Another way to troubleshoot this is to see if the LEDs light up when you remove the reliance on the button altogether by removing the
if(digitalRead(button)== HIGH)
  {
  count = count++ ;
  }

and changing it to
count++;
delay(1000);

and see if the LED changes every 1 second (delay requires a millisecond value). I agree with @StarCat that count = count++; possibly isn't doing what you think it is.


text:
How to pass Strem object to my class
I'm trying to creaper class wraper to use an Streamobject but I've an error when I try to compile.
My .hfile :
#include <Arduino.h>

class TestSerialListener {
public:
  TestSerialListener(Stream &serial);
  void testPrint(void);
private:
  bool _listener_start;
  Stream &_serial;

  void startListener(void);

};

my cppfile
#include "TestSerialListener.h"
#include <Arduino.h>

TestSerialListener::TestSerialListener(Stream &serial) : _serial(serial)
{
}

void TestSerialListener::testPrint(){
    _serial.begin(115200);      <---------- error compilation
    _serial.println("test");
}

void TestSerialListener::startListener(void)
{
    if(!_listener_start){
        _listener_start = true;
    }
}

And when i try to compile it I got this error : error: 'class Stream' has no member named 'begin'Why I can't use begin()in my classe ?

The compiler said: “you can't because the Stream class has no method named begin”. Does this answer your question?

Ok but why I can do SerialUSB.begin(115200)in my sketch ? @EdgarBonet

Because, SerialUSB does have a method named begin. Some Stream-derived classes can have such a method, It's just not something you can expect from any Stream object.

see https://arduino.stackexchange.com/questions/78719/can-you-use-serial-port-as-a-variable/78725#78725

the begin() method is defined in the HardwareSerial class, not in Stream. You can look that up yourself in your Arduino installation. For me these files are placed under ~/.arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino/ and are named Stream.h and HardwareSerial.h.
And if you  think about it, this is quite logical. The Stream class can represent any object, that can stream data. It doesn't know anything about how exactly the data is streamed on a hardware level. It just provides the convenient functions for handling the data. The HardwareSerial class then derives from Stream to get those data handling methods and adds its own methods to handle the hardware side of the problem, including setting a baudrate.
When providing a Stream reference to a class constructor you want to begin() the corresponding object outside of the class, before you start to stream any data through it. Doing it this way makes your class widely usable, since you could use any Stream object, even a file on an SD card.
So move the begin() line from your class to the setup() function in your main code.

For reference: Juraj showed the inheritance between the classes in his answer to this question. Have a look at it, since it is quite enlightening.


text:
Arduino 3.3v pro mini, most efficient use of AA batteries for power
I want to use a 3.3V pro mini that uses a BME 280 to take temp/pressure/humidity, and nRF24L01 module to transmit the data, at ?10 minute intervals. I want to use 1, 2,3 or 4  AA batteries to power it. I've read all about the techniques to reduce power consumption, by removing the power LED and using sleep functions.
But I would like to know the most efficient combination of batteries to use. If I can get a year out of 1 battery and a step-up converter, I would be happiest with that. But perhaps 3 duracell or 4 (rechargeable) batteries  connected directly to the Vcc pin (ie no regulator) might be better. Does anyone have first-hand experience to know what works best?

You can definitely do better with another regulator that the on-board ones, which are not energy efficient because they drop the supply voltage through a resistance, wasting the excess current as heat. An external boost regulator would waste much less current (charge, really, since we're trying to make maximum use of the battery capacity, or equivalently, trying to minimize the capacity & space needed to run your system for a year).
So you need two things:

The most space-efficient way (I assume...) to store a year's energy needs; and
A pretty good idea of what the energy requirement will be.

For (2.), you'll need an energy budget for your system:

How much current your system draws when it is awake;
How much current your system draws when it is asleep;
It's duty cycle (e.g.: 3% awake time, 97% sleep time), and use that to calculate the total charge in milliAmp-hours the system draws during the 1 year.

Don't forget to account for the batteries' inefficiency when they're cold, if that will be an issue, and add in a safety factor so it won't die before you arrive a year hence to change the batteries.
You'll need to consider powering down the sensor(s) and radio(s) during CPU sleep; their idle draw would make sleeping the CPU ineffective (as far as saving battery is concerned).
Once you have an energy budget, you can look at the available ways to store and deliver a year's worth - regulator type, size and efficiency; battery size and count) to see what combination will meet your needs for cost, simplicity, and space limitations.


text:
Arduino Nano BLE 33 Sense receives but not able to transmit data to XBEE Pro S2C
This is my first time asking a question so I will try my best to be precise and detailed.
I had recently started to work on a project that requires me to establish a wireless communication between two XBEE Pro S2C modules for the purpose of sending data of the sensors present on the Arduino Nano BLE 33 Sense.
What I did so far:
One of the XBEE (XBEE 1) is connected to my laptop using one of the USB-port, and the other (XBEE 2) to Arduino. The Arduino is also connected to the same laptop using another one of the USB ports. Using the XBEE and Arduino pinout diagrams, I connected Vcc, Dout, Din and GND of XBEE 2 to 3.3V, D3, D4 and GND pins of the Arduino respectively. Both the XBEES have been configured using XCTU software and are operating in AT mode. The XBEES are able to talk to each other on the XCTU console if I directly plug both of them into the laptop using the USB ports.
To check and establish a serial communication between the XBEE 2 and Arduino, I wrote the following sketch on Arduino IDE and uploaded it:
int received = 0;
#include<HardwareSerial.h>
UART mySerial(digitalPinToPinName(4), digitalPinToPinName(3), NC, NC);
void setup() {
  mySerial.begin(9600);
  Serial.begin(9600);
}

void loop() {
  while(mySerial.available())
  {
    received =mySerial.read();
    if(received == 'a')
    {
      Serial.println("Character Received");
    }
  }
}

Now, when I type the character 'a' in the XCTU console of XBEE 1, the XBEE 2 is able to receive it wirelessly and Arduino prints - "Character Received", on the serial monitor as expected. The TX of the adapter for XBEE 1 and the RX of the adapter for XBEE 2 also blinks at the same moment, confirming that the character is being sent by the XBEE 1 and it is being received by XBEE 2 for the Arduino to print.
The Problem:
Now, I uploaded the following sketch to do the reverse job, so that XBEE 2 sends the data and it appears on the XCTU console of XBEE 1:
#include<HardwareSerial.h>
UART mySerial(digitalPinToPinName(4), digitalPinToPinName(3), NC, NC);

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

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

This sketch does not print anything on the XCTU console of XBEE 1. I checked the connections and re-uploaded the sketch but it still showed nothing. I included the printing line inside a while-loop,
while(Serial.available()){
   mySerial.print("a");
}

so that I can manually type in a character into the serial monitor using Arduino IDE, but that also did not work. I also noticed that the respective TX and RX of the adapters also did not blink, meaning that XBEE 2 is not able to transmit the character only.
I cannot figure out what I am doing wrong and I spent hours to resolve this issue. I also tried changing the Din and Dout pins of XBEE 2 to RX and TX pins of the Arduino but that also did not work, although I think that's because the RX and TX are already being used by the Serial Connection between Arduino and laptop.
Any help to point me into the right direction would be greatly appreciated.
Thanks a lot!
Some points:
I came to know that SoftwareSerial library isn't available for the version of Arduino that I am using and for this reason I am using the UART instruction:
UART mySerial(digitalPinToPinName(4), digitalPinToPinName(3), NC, NC);
based on the discussion in this forum. I also use CP2012 XBEE explorer as adapters for XBEES.

Comments have been moved to chat; please do not continue the discussion here. Before posting a comment below this one, please review the purposes of comments. Comments that do not request clarification or suggest improvements usually belong as an answer, on [meta], or in [chat]. Comments continuing discussion may be removed.


text:
Unable to flash arduino pro micro from Terminal
I am trying to upload an hex file to my arduino pro micro using Avrdude . The thing is that I cannot upload any code using the Avrdude terminal commands , but when I use arduino IDE to upload any code it perfectly uploads the code to Arduino.
The command I am using on the terminal:
avrdude -C C:\Users\santi\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf -v -V -patmega32u4 -cavr109 -PCOM15 -b57600 -D -U flash:w:C:\Users\santi\Documents\keyboard\corne\crkbd_rev1_layout_split_3x6_3_mine.hex:i

I already have avrdude on the environment variables on my windows 10 machine.
Output:
avrdude: Version 6.3-20190619
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "C:\Users\santi\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf"

         Using Port                    : COM15
         Using Programmer              : avr109
         Overriding Baud Rate          : 57600
         AVR Part                      : ATmega32U4
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PA0
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  9000  9000 0x00 0x00
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0x00 0x00
           lfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           lock           0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : butterfly
         Description     : Atmel AppNote AVR109 Boot Loader

Connecting to programmer: .avrdude: butterfly_recv(): programmer is not responding

avrdude: butterfly_recv(): programmer is not responding

I keep waiting but it does not upload the code.
I added a push button for RST and GND pins to enter bootloader mode, and I am pressing the reset button. I even tried resetting twice quickly, but I get the same result.
I tried using the Arduino and the code gets uploaded.
I uploaded the following code:
int RXLED = 17;
void setup(){
  pinMode(RXLED, OUTPUT);
}

void loop() {
  digitalWrite(RXLED, LOW);
  delay(1500);
  digitalWrite(RXLED, HIGH);
  delay(1500);
}

The command ran in the IDE is:
"C:\Users\santi\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/bin/avrdude" "-CC:\Users\santi\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf" -v -V -patmega32u4 -cavr109 -PCOM16 -b57600 -D "-Uflash:w:C:\Users\santi\AppData\Local\Temp\arduino-sketch-F0563C64AD4C1F392D3E71AA32E4F874/blink_nano.ino.hex:i"

Arduino IDE output:
avrdude: Version 6.3-20190619
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "C:\Users\santi\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf"

         Using Port                    : COM16
         Using Programmer              : avr109
         Overriding Baud Rate          : 57600
         AVR Part                      : ATmega32U4
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PA0
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  9000  9000 0x00 0x00
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0x00 0x00
           lfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           lock           0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : butterfly
         Description     : Atmel AppNote AVR109 Boot Loader

Connecting to programmer: .
Found programmer: Id = "CATERIN"; type = S
    Software Version = 1.0; No Hardware Version given.
Programmer supports auto addr increment.
Programmer supports buffered memory access with buffersize=128 bytes.

Programmer supports the following devices:
    Device code: 0x44

avrdude: devcode selected: 0x44
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9587 (probably m32u4)
avrdude: reading input file "C:\Users\santi\AppData\Local\Temp\arduino-sketch-F0563C64AD4C1F392D3E71AA32E4F874/blink_nano.ino.hex"
avrdude: writing flash (3852 bytes):

Writing | ################################################## | 100% 0.29s

avrdude: 3852 bytes of flash written

avrdude done.  Thank you.

I tried using the same Avrdude command in the terminal.
"C:\Users\santi\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/bin/avrdude" "-CC:\Users\santi\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf" -v -V -patmega32u4 -cavr109 -PCOM16 -b57600 -D "-Uflash:w:C:\Users\santi\AppData\Local\Temp\arduino-sketch-F0563C64AD4C1F392D3E71AA32E4F874/blink_nano.ino.hex:i"

Output:
avrdude: Version 6.3-20190619
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "C:\Users\santi\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf"

         Using Port                    : COM16
         Using Programmer              : avr109
         Overriding Baud Rate          : 57600
avrdude: ser_open(): can't open device "\\.\COM16": El sistema no puede encontrar el archivo especificado.

I don´t know why it uses a different port.
I tried changing the port in that command but I get the same result as before
avrdude: Version 6.3-20190619
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "C:\Users\santi\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf"

         Using Port                    : COM15
         Using Programmer              : avr109
         Overriding Baud Rate          : 57600
         AVR Part                      : ATmega32U4
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PA0
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  9000  9000 0x00 0x00
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0x00 0x00
           lfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           lock           0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : butterfly
         Description     : Atmel AppNote AVR109 Boot Loader

Connecting to programmer: .avrdude: butterfly_recv(): programmer is not responding

I could just use the arduino IDE to flash my device but the problem is that I only have the hex file. I am trying to flash my device with a hex file from QMK Configurator. I am trying to build a custom keyboard.

When you tried the same command as the IDE, did you close the IDE? There is a possibility that it has the port open, which will block other programs from accessing it.

You have to reset the Arduino using a very special procedure in order
for it to accept being programmed. This involves opening the port at
1200 bps, toggling some control lines, and closing the port again.
You may try using this ard-reset-arduino Python script with the
option --caterina.
By the way, this script belongs a project called “Arduino-Makefile”. You
may want to take a look if you want to program your Arduino from the
command line. Alternatively, you can use arduino-cli.

"I am trying to flash my device with a hex file from QMK Configurator." The arduino-cli does the 1200baud touch as part of the upload process, but it might not apply or may need clarification on how to apply. I'm not sure how you'd make use of it unless it has the ability to be supplied arbitrary hex files to upload, or has a stand-alone command for issuing a 1200 baud touch, or unless you can sneak your hex file over top of one the compile command had created.  "I even tried resetting twice quickly" This should have given them 8 seconds of bootloader time, though the tool would help.


text:
What is the difference between ":i" and ":a" in avrdude command?
What is the difference between :i and :a after my hex file path in avrdude command.
avrdude -C C:\Users\santi\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf -v -V -pm32u4 -c avr109 -P COM8 -b 57600 -D -U flash:w:\Users\santi\AppData\Local\Temp\arduino-sketch-35CC2EF472BAA882EB5508D7552111AD/blink_RX_Led_ProMicro.ino.hex:i

and
avrdude -C C:\Users\santi\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf -v -V -pm32u4 -c avr109 -P COM15 -b 57600 -D -U flash:w:\Users\santi\AppData\Local\Temp\arduino-sketch-35CC2EF472BAA882EB5508D7552111AD/blink_RX_Led_ProMicro.ino.hex:a

:-( The art of reading manuals is being lost more and more.

These are Avrdude file format specifiers.
avrdude -C C:\Users\santi\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf -v -V -pm32u4 -c avr109 -P COM15 -b 57600 -D -U flash:w:\Users\santi\AppData\Local\Temp\arduino-sketch-35CC2EF472BAA882EB5508D7552111AD/blink_RX_Led_ProMicro.ino.hex:a

The final :a in this case is a format specifier meaning "auto detect; valid for input only, and only if the input is not provided at stdin."
An :i in the same position means "Intel Hex"
A complete list can be found here: https://www.nongnu.org/avrdude/user-manual/avrdude_3.html#Option-Descriptions

It is worth noting that :a is the default, and can thus be omitted. Also, if this version of avrdude is not too old, it can understand the ELF file: no need to convert it to hex.


text:
Serial port stops receiving data after random amount of time
EDIT: Things I have tried so far:

Increasing the baud rate, but this didn't make any difference as it still continued to stop receiving data after random amount of time.

I tried testing one sensor and reducing the sketch to something that only prints in a sketch. I can get the sketch to work up to 2 sensors where it prints the results continuously. 3 or 4 sensors and I get the issue mentioned.

Link to the VL53L4CD library: https://github.com/stm32duino/VL53L4CD
Datasheets:
https://cdn-learn.adafruit.com/downloads/pdf/adafruit-vl53l4cd-time-of-flight-distance-sensor.pdf
https://www.st.com/resource/en/datasheet/vl53l4cd.pdf

I'm currently working on a project where I need to measure distances at two different points using distance sensors (I'm currently using VL53L4CD laser distance sensors). However, this project requires a high sampling rate of 100Hz. To achieve this, I have 4 distance sensors arranged into 2 sensor sets. Each sensor set consists of 2 distance sensors (So for example, sensor set 1 consists of distance sensor 2&3 and sensor set 2 consists of distance sensor 1&4) and I would alternate between reading each sensor set.
This seemed to work at first, I did get a new distance reading every 8ms. However, the serial port stops receiving the distance readings after a very random amount of time. Sometimes the serial port stops receiving new data after 5 seconds, sometimes 30s, sometimes 60 and even 180s.
I'm not sure what's causing this issue what I can do to fix it. Any help is appreciated
(I'm using the Arduino Nano 33 IOT)
Thanks!
Here is my code below:
// Included libraries
#include <Arduino.h>
#include <Wire.h>

// Libraries required for VL53L4CD sensors
#include <vl53l4cd_class.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>

// Definitions
#define DEV_I2C Wire
#define SerialPort Serial

// variables
int alternate = 0; // Variable used to alternate between sensor sets

// Components.
VL53L4CD sensor_vl53l4cd_1(&DEV_I2C, 2); // xshut pin of distance sensor 1 connected to pin 2
VL53L4CD sensor_vl53l4cd_2(&DEV_I2C, 3); // xshut pin of distance sensor 2 connected to pin 3
VL53L4CD sensor_vl53l4cd_3(&DEV_I2C, 5); // xshut pin of distance sensor 3 connected to pin 5
VL53L4CD sensor_vl53l4cd_4(&DEV_I2C, 6); // xshut pin of distance sensor 4 connected to pin 6

/* Setup ---------------------------------------------------------------------*/

void setup()
{
  // DISTANCE SENSOR SETUP
  // Initialize serial for output.
  SerialPort.begin(9600);
  SerialPort.println("Starting...");

  // Initialize I2C bus.
  DEV_I2C.begin();

  // Configure VL53L4CD number 1
  Serial.println("Configuring distance sensor 1");
  sensor_vl53l4cd_1.begin();
  sensor_vl53l4cd_1.VL53L4CD_Off();
  sensor_vl53l4cd_1.InitSensor();
  sensor_vl53l4cd_1.VL53L4CD_SetI2CAddress(0x40);
  sensor_vl53l4cd_1.VL53L4CD_SetRangeTiming(10, 0);

  // Configure VL53L4CD number 2
  Serial.println("Configuring distance sensor 2");
  sensor_vl53l4cd_2.begin();
  sensor_vl53l4cd_2.VL53L4CD_Off();
  sensor_vl53l4cd_2.InitSensor();
  sensor_vl53l4cd_2.VL53L4CD_SetI2CAddress(0x42);
  sensor_vl53l4cd_2.VL53L4CD_SetRangeTiming(10, 0);

  // Configure VL53L4CD number 3
  Serial.println("Configuring distance sensor 3");
  sensor_vl53l4cd_3.begin();
  sensor_vl53l4cd_3.VL53L4CD_Off();
  sensor_vl53l4cd_3.InitSensor();
  sensor_vl53l4cd_3.VL53L4CD_SetI2CAddress(0x44);
  sensor_vl53l4cd_3.VL53L4CD_SetRangeTiming(10, 0);

  // Configure VL53L4CD number 4
  Serial.println("Configuring distance sensor 4");
  sensor_vl53l4cd_4.begin();
  sensor_vl53l4cd_4.VL53L4CD_Off();
  sensor_vl53l4cd_4.InitSensor();
  sensor_vl53l4cd_4.VL53L4CD_SetI2CAddress(0x46);
  sensor_vl53l4cd_4.VL53L4CD_SetRangeTiming(10, 0);

  // Start Measurements
  sensor_vl53l4cd_1.VL53L4CD_StartRanging();
  sensor_vl53l4cd_2.VL53L4CD_StartRanging();
  sensor_vl53l4cd_3.VL53L4CD_StartRanging();
  sensor_vl53l4cd_4.VL53L4CD_StartRanging();
}

void loop()
{
  // Read results from sensor set 1
  if (alternate == 0){
    VL53L4CD_Result_t results2;
    VL53L4CD_Result_t results3;

    // Read results from sensor set 1 (Sensors 2 and 3)
    sensor_vl53l4cd_2.VL53L4CD_ClearInterrupt();
    sensor_vl53l4cd_2.VL53L4CD_GetResult(&results2);
    sensor_vl53l4cd_3.VL53L4CD_ClearInterrupt();
    sensor_vl53l4cd_3.VL53L4CD_GetResult(&results3);

    Serial.print("Distance 1-1 = ");
    Serial.print(results2.distance_mm);
    Serial.println(" ");
    Serial.print("Distance 1-2 = ");
    Serial.print(results3.distance_mm);
    Serial.println(" ");

    alternate = 1; // Change value so sensor set 2 is read in the following loop
  }

  // Read results from sensor set 2
  else if (alternate == 1){
    VL53L4CD_Result_t results1;
    VL53L4CD_Result_t results4;

    // Read results from sensor set 1 (Sensors 1 and 4)
    sensor_vl53l4cd_1.VL53L4CD_ClearInterrupt();
    sensor_vl53l4cd_1.VL53L4CD_GetResult(&results1);
    sensor_vl53l4cd_4.VL53L4CD_ClearInterrupt();
    sensor_vl53l4cd_4.VL53L4CD_GetResult(&results4);

    Serial.print("Distance 2-1 = ");
    Serial.print(results1.distance_mm);
    Serial.println(" ");
    Serial.print("Distance 2-2 = ");
    Serial.print(results4.distance_mm);
    Serial.println(" ");

    alternate = 0; // Change value so sensor set 2 is read in the following loop
   }
   Serial.println(millis());
}

I'm unfamiliar with the VL53L4CDs, but for us to help you, do you mind linking the library that you've used in the post (and a link to the datasheet wouldn't hurt either)? Also, how does adding sensors help with the sampling rate? My hunch here is to say that you might be overflowing your I2C buffer, but I say test one sensor first, then a set of sensors, and IF that works alright, I'd start looking at two sets again and thinking about a more sophisticated flow control implementation. Do you know how much data each sensor (not set!) provides per reading? Also, try increasing the baud rate.

You might increase the baudrate so the serial buffer is less likely to overflow. Does it work without all the printing (use a LED for debug-blinking)?

Adding to @datenheim's comment: With 9600 baud you can transmit at most a bit less than 1000 bytes per second. With your sample rate of 100 Hz equaling a period of 10 ms, only 9 to 10 characters per sample are possible. -- A virtual serial connection via USB is much faster, though. The set baudrate matters only, if at least on one end a real serial line is involved. Using your PC and the Arduino built-in USB module, this is not the case, AFAIK.

Anyway, since you have no timing control in the provided sketch, I don't see how a serial buffer can overflow. All printing methods should block if their buffer is full. This way, your loop is timed by the speed of the serial transmission.

To make the problem smaller, reduce your sketch to something that only prints in a loop. If this runs long without problems, it is not the printing. Then do the same with only the sensor reading. [Edit] your question and add the findings, please.

Hi all, thanks for the replies and suggestions. @Nick, regarding the sampling rate of each sensor, each sensor has a maximum sampling rate of 100Hz. However at this high of a sampling rate the readings are quite inaccurate. The idea is to set the sensor to operate at a slightly lower frequency to increase the accuracy and by using two sets of sensors, I can read one set of sensor while the other set is measuring, therefore increasing the sampling rate while maintaining the accuracy (at least that's what my FYP supervisor suggested). I have also edited my post to include what I've tried so far.

Right now I suspect it could be because the USB port on my laptop cannot provide the required amount of current. I've read somewhere that the USB port on laptops only provide 100milliAmps? According to the datasheet, the peak current for a sensor can reach a maximum of 40mA. Could it be that this is why I can only use a maximum of two sensors before the problem manifests itself?

@JinYuan I doubt it's the laptop, since usually USB ports can provide up to 500mA, which should be plenty for your Arduino and the sensors. I'm not sure what's exactly going on at the moment, but your control flow should be a bit different; you can either use STM's VL53L4CD_CheckForDataReady() function or actually instantiate interrupts for all 4 sensors and process them as sets on a set interval. I don't think of 100 Hz as a high sampling rate as your loop probably runs at 100 times faster than that...well, or at least, could, as I don't know if those functions are blocking are not.

@JinYuan You can also use Adafruit's library as well and you could also try powering the a set of sensors (two sensors) from a different source than your laptop. If you  have a logic analyzer,  you could put that up just to see how the data transfer is happening when you have all 4 hooked up at the same time.

@NickS. I tried powering all of the sensors using an external source and this seems to fix the problem. I was receiving all of the distance readings consistently and the serial port did not stop receiving data.

@JinYuan sounds good, you should post your own answer then! Also, it does depend on the USB port of the laptop on how much power it can provide - some indeed are limited to only 500-750 mW (or 100-150 mA), while other can provide up to 1.5A (charging ports). Still a bit weird you saw the issue as you saw it, since the Nano 33 should be pulling on average around 50-60, if not about 100 mA just by itself (which depends on whether you are using BLE/BT/WiFi and how), but hey, if it works it works!

I tried powering all of the sensors with an external power source and this seems to solve the issue, I got consistent readings from all the distance sensors and the serial port did not stop receiving data. It might have been the USB port on my laptop that was causing these issues.


text:
Arduino MEGA - How to send and receive data asynchronously?
i am newbie to this so i hope i can explain my problem clearly;
Arduino MEGA connected to PC via USB port.
I am using an encoder to trigger function to send data to pc, data is a simple string "A01" or "A02" when i turn encoder to opposite direction, when arduino sends that string to serial port PC answers with another string from serial and its something like "MCPHDGxxx" and arduino does if serial available gets the string and filter it to get and show that number on my 7-segment display.
(xxx is a number between 000 and 359, and that number changes on PC screen when arduino send "A01" or "A02" string to PC)
When i don't send display data from PC to arduino, encoder function works as intended, changes numbers up and down rapidly on PC screen but when i try to send that "number" data to Arduino from serial port number on the PC screen changes so slowly like 1 point up/down per 2 sec even if i turn encoder continuously. Seems like receiving data from PC blocking my send data function until it's done.
Is it possible to make it work asynchronously?
Here is my sketch:
#include "DigitLedDisplay.h"
 #define outputA 24
 #define outputB 25

 int aState;
 int aLastState;
 unsigned long lastButtonPress = 0;
 long finalMCPHDGLong;
 String ReceivedSerialString;

 DigitLedDisplay ld = DigitLedDisplay(21, 22, 23);

 void setup() {
   pinMode (outputA,INPUT);
   pinMode (outputB,INPUT);

   Serial.begin (115200);
   // Reads the initial state of the outputA
   aLastState = digitalRead(outputA);

     /* Set the brightness min:1, max:15 */
  ld.setBright(10);

  /* Set the digit count */
  ld.setDigitLimit(8);

 }

 void loop() {
   aState = digitalRead(outputA); // Reads the "current" state of the outputA
   // If the previous and the current state of the outputA are different, that means a Pulse has occured
   if (aState != aLastState){
     // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
     if (digitalRead(outputB) != aState) {
       if (millis() - lastButtonPress > 25) {
         Serial.println("A01");
        }

        // Remember last button press event
        lastButtonPress = millis();

     } else {
       if (millis() - lastButtonPress > 25) {
         Serial.println("A02");
        }

        // Remember last button press event
          lastButtonPress = millis();

     }

   }
   aLastState = aState;

    while (Serial.available() > 0){
      ReceivedSerialString = Serial.readString();
      if (ReceivedSerialString.substring(0,6) == "MCPHDG"){
        String value = ReceivedSerialString.substring(6,9);
          long val = value.toInt();
          finalMCPHDGLong = val;
          if((finalMCPHDGLong <= 99)){
              ld.printDigit(0,7);
            }if((finalMCPHDGLong <= 9)){
              ld.printDigit(0,6);
            }
          ld.printDigit(val, 5);
      }
    }
 }

Seems like receiving data from PC blocking my send data function until it's done.

You may be saying the same thing, but I'd put it that it's waiting for more data to arrive that isn't going to.

Is it possible to make it work asynchronously?

Depending on how you're defining "asynchronously" that may be unnecessary.
while (Serial.available() > 0){
  if (ReceivedSerialString.substring(0,6) == "MCPHDG"){
    String value = ReceivedSerialString.substring(6,9);

There's a lot that could be said about using String and conversion to int and choosing a simple message format and so forth, but I'll elide most of that. Finding a good approach to what you're doing would require understanding a lot more about what you're doing and why. But, taking your code and question as written, the main thing is that readString() here is terminating based on the value of Serial.setTimeout(), which by default is 1000 or 1 second.  So you are spending a lot of time doing nothing following receipt of your command from the PC. So during that 1 second you are not tending to the "encoder".
You could play with setTimeout, but it would be better to avoid a timeout altogether by not attempting to read when there's no more command to be read. If this protocol you're using is line-oriented then you have a terminator you can use in the form of '\r' or '\n'. This can be done with Serial.readStringUntil(whatever_your_terminator_is); If you have both '\r' and '\n' you will need to read other part of the termination sequence and then throw it away. Either it will come in as part of the read string or it will not and you will need to do a second read to discard it. There are more sophisticated ways to go about this, but that maybe sufficient for what you're doing.
When it comes to not blocking (or significant blocking) of serial reads, you have to assure that the data is there to be read. Either because you know it's sent (and are willing to trust that it was received okay). Or you use Serial.setTimeout with a 0 or sufficiently small number, .read() indicates no data with a negative return value, or by checking .available(), and it all of these cases deciding what to do when you have not received everything, or everything... yet. Doing it well, manually, is a bit of a pain.
For writing/printing to serial there's a counterpart .availableForWrite() which
you can use to determine ahead of time whether or not you're going to be stuck in waiting (in .print()/.println()/.write()) for the serial data to go out, in turn not tending to the encoder. Basically you can choose where and how to throttle your writing to serial so as not overly interfere checking the encoder rather than causing throttle to happen within Serial.write. With the way your code is currently written, with events coming in at the rate they apparently are (according to your debouncing code) this is probably not currently a problem for you. But it's worth keeping in mind if you begin handling events at a higher rate. Placing a character in the outbound serial buffer is significantly faster than waiting for space for a character to become available in the serial buffer.

Serial.setTimeout(25) solved the problem. Also other advices helped a lot, thanks.

Is not easy, but you can implement two modification.
The first one is handling encoder via interrupt, the second one, is change the while to an if, with the while you force the code to loop inside the while serial aviable loosing eventually encoders state change, to avoid this, you shuold take continusly the strings coming from PC and create a command queue and proces it cycle by cicle, unfortunatly arduino mega is single processor, so it can't handle different process at the same time.
You should olso to consider, and run a benckmark to test how much is the refresh rate of your display


text:
Error coming from specified code
Error
Arduino: 1.8.19 (Windows 10), Board: "Arduino Uno"

AnalogInOutSerial:8:56: error: no matching function for call to 'PID::PID(int*, int*, double*, double&, double&, double&, int)'
 PID pid(&Rawval, &Rawval, &setpoint, kp, ki, kd, DIRECT);
                                                        ^
In file included from C:\Users\USER\AppData\Local\Temp\arduino_modified_sketch_407168\AnalogInOutSerial.ino:1:0:
C:\Users\USER\Documents\Arduino\libraries\Arduino-PID-Library-master/PID_v1.h:24:5: note: candidate: PID::PID(double*, double*, double*, double, double, double, int)
     PID(double*, double*, double*,        // * constructor.  links the PID to the Input, Output, and
     ^~~
C:\Users\USER\Documents\Arduino\libraries\Arduino-PID-Library-master/PID_v1.h:24:5: note:   no known conversion for argument 1 from 'int*' to 'double*'
C:\Users\USER\Documents\Arduino\libraries\Arduino-PID-Library-master/PID_v1.h:20:5: note: candidate: PID::PID(double*, double*, double*, double, double, double, int, int)
     PID(double*, double*, double*,        // * constructor.  links the PID to the Input, Output, and
     ^~~
C:\Users\USER\Documents\Arduino\libraries\Arduino-PID-Library-master/PID_v1.h:20:5: note:   candidate expects 8 arguments, 7 provided
C:\Users\USER\Documents\Arduino\libraries\Arduino-PID-Library-master/PID_v1.h:5:7: note: candidate: constexpr PID::PID(const PID&)
 class PID
       ^~~
C:\Users\USER\Documents\Arduino\libraries\Arduino-PID-Library-master/PID_v1.h:5:7: note:   candidate expects 1 argument, 7 provided
C:\Users\USER\Documents\Arduino\libraries\Arduino-PID-Library-master/PID_v1.h:5:7: note: candidate: constexpr PID::PID(PID&&)
C:\Users\USER\Documents\Arduino\libraries\Arduino-PID-Library-master/PID_v1.h:5:7: note:   candidate expects 1 argument, 7 provided
exit status 1
no matching function for call to 'PID::PID(int*, int*, double*, double&, double&, double&, int)'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Actual Code
#include <PID_v1.h>

int analogPin = A3;
int Rawval ;  // variable to store the value read
double setpoint = 169; // target value for the system is set to 169
double kp = 1, ki = 0.1, kd = 0.01; // PID constants
int RELAY_pin = 10;    // Relay is connected to pin D10
PID pid(&Rawval, &Rawval, &setpoint, kp, ki, kd, DIRECT);

void setup()
{
  Serial.begin(9600);           //  setup serial
  pinMode(RELAY_pin, OUTPUT);
  pid.SetMode(AUTOMATIC);
}

void loop()
{
  Rawval = analogRead(analogPin);
  Serial.print("Rawvalue from Analog input  =");
  Serial.println(Rawval);
  pid.Compute();
  digitalWrite(RELAY_pin, Rawval < setpoint ? HIGH : LOW);
}

The error message is quite clear about the problem (extracted and formatted for clarity):

no matching function for call to
PID::PID(int*, int*, double*, double&, double&, double&, int)
[...]
candidate:
PID::PID(double*, double*, double*, double, double, double, int)
[...]
no known conversion for argument 1 from 'int*' to 'double*'
[other candidates left out due to non-matching number of arguments]

You need to provide pointers to double as the first two arguments, and the candidate will match.

EDIT:
I hesitated a while to provide your this, because you learn much better by doing it yourself. Anyway, here it is.
Your original variable declaration is:
int Rawval ;  // variable to store the value read

Replace the data type int by double, as the called constructor expects:
double Rawval ;  // variable to store the value read

Now there is this line, assigning an int to a double:
Rawval = analogRead(analogPin);

And you might ask yourself, is this OK? Well, try it. You will find that the compiler implicitly converts the value. If you want to make it explicitly, change the line to:
Rawval = static_cast<double>(analogRead(analogPin));

A final point, as datenheim states: Read and learn about the PID. It is for sure an error to use the same variable for input and output.

Can you kindly modify the portion & provide it here accordingly so that I can execute without any further error.Thanks in advance

My code is fine?? I will integrate yours as per modification..Till it will give error?
The code is to integrate PID in to arduino to an analogous sensor based on threshold value like 169 for raw value. If the value is less than the relay will be operational.
Target rawvalue =169
Target scaleval =5
Setpoint also
What would be the ka, kp, ki value for fully functional as described. Please guide. Thanks!

@Rocky, That is not how this site works. Your code is yours. You have been given enough information to fix the error in your code and now it's up to you to integrate the solution and fix your code so it does what you want.

I do understand the importance of. Highly obliged but it would be great for me if you kindly guide what would be the values for kp,ka,ki

@Rocky I have no idea. This is a completely different question, and certainly not one about programming. Since your course seems to involve control engineering, you should repeat the material you have.

Set value or target value is 169 as raw & 5% as scaled value. Current value -4&8 .So accordingly..Kp,ka, ki?

@Rocky, that makes no sense and this site is not a free homework service.

The first two parameters need to be of type double.
PID pid(&Rawval, &Rawval, &setpoint, kp, ki, kd, DIRECT);
        ^^^^^^^  ^^^^^^^

It also makes probably no sense to have input and output both wired to &Rawval.
Take a look on this example.

Can you kindly modify the portion & provide it here accordingly so that I can execute without any further error.Thanks in advance

No, sorry, learning is by doing. Try it, you will see :-)