text:
Why does Serial.write() work but Serial.print() doesn't?
I am testing my GPS module with an ESP32 using the Arduino IDE. I'm asking because I usually don't fully understand the difference between Serial.write() and Serial.print().
This code is working perfectly with Serial.write() and the output is meaningful:
void loop() {
  while (Serial2.available() > 0) {
    Serial.write(Serial2.read());
  }

  Serial.println("-------------------------------------");
}

Output:
13:28:05.173 -> -------------------------------------
13:28:05.206 -> $GPRMC,,V,,,,,,,,,,N*53
13:28:05.238 -> $GPVTG,,,,,,,,,N*30
13:28:05.238 -> $GPGGA,,,,,,0,00,99.99,,,,,,*48
13:28:05.270 -> $GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
13:28:05.334 -> $GPGSV,1,1,00*79
13:28:05.334 -> $GPGLL,,,,,,V,N*64
13:28:05.366 -> -------------------------------------

When I convert this code to Serial.print() the output looks strange:
void loop() {
  while (Serial2.available() > 0) {
    Serial.print(String(Serial2.read()));
  }

  Serial.println("-------------------------------------");
}

Output:
13:26:43.118 -> -------------------------------------
13:26:43.150 -> -------------------------------------
13:26:43.214 -> 367180827767444486444444444444444444447842535113103671808684714444444444444444447842514813103671807171654444444444444844484844575746575744444444444442525613103671807183654465444944444444444444444444444444575746575744575746575744575746575742514813103671807183864449444944484842555713103671807176764444444444448644784254521310-------------------------------------
13:26:43.566 -> -------------------------------------
13:26:43.629 -> -------------------------------------

Why does Serial.write work, but Serial.print doesn't? Or: how to write the same code with Serial.print()?

Why does Serial.write work, but Serial.print doesn't?

Serial.read() returns an integer for each byte from the serial port.
String converts each integer to its decimal ASCII representation (e.g. $ = "36", G = "71" etc), so Serial.print() receives an ASCII string with the decimal values of each input byte, which were already ASCII. This is probably not what you want.

Well, @devnull gave a good and helpfull answer. I'll present another method of using Arduino to test the GPS module.

Here is an example of test code that you can use to test a GPS module with an ESP32 using the Arduino IDE and the Serial.print() function:
#include <TinyGPS++.h>
#include <HardwareSerial.h>

// Set up a serial connection for the GPS module
HardwareSerial GPSSerial(2);
TinyGPSPlus gps;

void setup() {
  // Initialize serial communication with the computer
  Serial.begin(115200);

  // Initialize serial communication with the GPS module
  GPSSerial.begin(9600, SERIAL_8N1, 16, 17);
}

void loop() {
  // Read data from the GPS module
  while (GPSSerial.available() > 0) {
    gps.encode(GPSSerial.read());
  }

  // Print the GPS data to the serial monitor
  Serial.print("Latitude: ");
  Serial.print(gps.location.lat(), 6);
  Serial.print(" Longitude: ");
  Serial.println(gps.location.lng(), 6);
  Serial.print("Altitude: ");
  Serial.print(gps.altitude.meters());
  Serial.println(" meters");
  Serial.print("Date: ");
  Serial.print(gps.date.month());
  Serial.print("/");
  Serial.print(gps.date.day());
  Serial.print("/");
  Serial.println(gps.date.year());
  Serial.print("Time: ");
  Serial.print(gps.time.hour());
  Serial.print(":");
  Serial.print(gps.time.minute());
  Serial.print(":");
  Serial.println(gps.time.second());
  Serial.println();

  // Wait a second before printing the data again
  delay(1000);
}

This code initializes a serial connection with the GPS module using the HardwareSerial library and the TinyGPS++ library to parse the GPS data. The loop() function reads data from the GPS module and prints the latitude, longitude, altitude, date, and time to the serial monitor using the Serial.print() function.
You may need to adjust the serial port and baud rate settings to match your specific GPS module. You may also want to add additional code to handle errors or check for valid GPS data.

This isn't really answering the question, as asked.

i only use this to get data from the GPS module, no need for library
you need to declare an array, say gps_rawData[200] = {0};
while (SerialGPS.available()) {
size_t byteCount = SerialGPS.readBytesUntil('\n', gps_rawData,
sizeof(gps_rawData) - 1);
gps_rawData[byteCount] = NULL;
String gps_rawDataString = String(gps_rawData);
SerialMon.println(gps_rawDataString);
}
this way you have the data in an array to be manipulated whenever or wherever required.

They're asking about why Serial.write behaves one way and Serial.print behaves a different way, which is answered by devnull.


text:
is there Raw RTC output?
I have an I2C Real Time Clock, DS3231 RTC module , and I just want something like Unix Time.
I'm using the uRTCLib, looking at the class methods
but dont see anything like that. I'm thinking there must be a raw read that would return all the digits. Is there an easy way to do that?

The DS3231 doesn't report the Unix time. It reports the current time in
broken-down form (year, month... second). If you need Unix time, you
have to compute it.
I suggest using Adafruit's RTClib. This library implements the
computation of Unix time, e.g.
uint32_t unix_time = rtc.now().unixtime();

source: Stack Exchange

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

sort: votes


text:
Recognizing fake NEO-M8N gps module?
I bout a NEO-M8N gps module but I can't connect to u-blox softwares (both u-center2 & u-center_v22.07)
It seems to be one of the junk modules that China mass-produces
Module's pictures :

I tried TinyGPSPlus, Sparkfun u-blox and some other libraries to connect it to my ESP32 Dev. Board (30 pin board) but i cant programme it,
Also i connected to my laptop USB port directly but i even can't see  it coming up to my device manager list (not even as unknow device)
All i can see is the onboard LED turning On when i connect it
Is there any Arduino sketch to recognise it (recognise it's core) to find it's library? Or is there any free windows software to recognise all gps modules?
And then, how can i programme it to connect esp32 and give me lat, long & alt as float numbers?
Note : i have ESP32 Dev. Kit (30 pin) as my only controller so, any suggestion sketch must be compatible with the board

sounds like the module has failed

There is a very simple Arduino program you can try here: https://randomnerdtutorials.com/guide-to-neo-6m-gps-module-with-arduino/ . You'll have to adapt it for the ESP32 to use one of the ESP32's other serial ports instead of using the SoftwareSerial library. Note that TX and RX are crossed. This may help if there is a problem only with the device's USB interface.

I'm using Neo-M8N-0-10 not Neo-6m

just plug the unit to terminal software, set the baud to 9600 and see what is coming out.
you can even use Arduino IDE, if the unit is not faulty, you should be able to see data coming out.
I use Neo8M & Neo6M, all bought from AliXpress, not a single failed so far.

didn't get anything

and about connecting and getting data from Arduino IDE, it's not make sense because in the IDE you have to select the board and it doesn't support any gps module as far as i know

I am using Arduino IDE to test the serial data from GPS.  just plug in the GPS module, if windows(I assume you are using windows) detects the port, that particular port will appear in the port list on the arduino ide. just select the port and open the serial monitor.  data should be flowing in.  if the port does not appear in your IDE, most likely windows does not recognise the port, ie port is faulty or the gps module is faulty.  hope this helps.

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


text:
Temperature is not updated on OLED screen - Grove components
I am using 2 grove components in order to display a temperature. I use an I2C High Accuracy Temperature Sensor - MCP9808 and an OLED Screen using this script:
#include <U8g2lib.h>
#include <SPI.h>
#include <Wire.h>
#include "Seeed_MCP9808.h"

MCP9808 sensor;
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/SCL, /* data=*/SDA, /* reset=*/U8X8_PIN_NONE);  //Software I2C

char strTemp\[16\];
float temp;

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

  if (sensor.init()) {
    Serial.println("sensor init failed!!");
  }
  sensor.set_config(SET_CONFIG_ADDR, 0x0008);
  Serial.println("sensor init!!");
}

void loop() {
  sensor.get_temp(&temp);
  Serial.print("temperature value is: ");
  Serial.println(temp);
  delay(1000);

  dtostrf(temp, 7, 2, strTemp);

  u8g2.clearBuffer();                   // clear the internal memory
  u8g2.setFont(u8g2_font_luBIS08_tf);   // choose a suitable font
  u8g2.drawStr(0, 10, "Hello Seeed!");  // write something to the internal memory
  u8g2.drawStr(0, 30, "Temp. value:");  // write something to the internal memory
  u8g2.drawStr(0, 50, strTemp);         // write something to the internal memory
  u8g2.sendBuffer();                    // transfer internal memory to the display
}

The temperature output is not updated on the screen and I think it might be related to I2C addresses. Is it possible?
I run an I2C scanner and I think that the OLED address is 0x3C and the temp. sensor is 0x18. How can I assign them correctly. I never done something like that so any help is welcome.
Thanks a lot.

Simplify the problem.  Try making a copy of your software w/o the OLED code and simply print the temperature out to the serial monitor already part of the IDE.  If that works, then it may be the I2C addressing.  If it does not then it's likely how you are sampling the temperature sensor.

Thanks for the reply and recommendation. Without the OLED code it prints the temperature out to the serial monitor, Any idea how to proceed?

does "Hello Seeed!" show on the display?

@jsotola: Yes, it does appear on the display

... oh, I see you are already printing out the temperature.  I'd still comment out all the u8g2 lines and maybe even remove the OLED hardware and see if you see new temperature data ever second.

"...Without the OLED code it prints the temperature out to the serial monitor...", yes, but does it print out a new temperature every second?  If so, my guess is that the libraries are not working well w/each other.  Likely they are trying to use the same I2C processor hardware and braking it for the other library.

@st2000: When removing all the u8g2 lines I see in the serial monitor the temp. When  the u8g2 lines are in the code  even the serial monitor is not working

st2000: I suspect as well that there is I2C interference. Any idea how to change one or both of them?

You can look at the MPC9808 and  U8G2 code on github (not sure about if I got the correct U8G2 web page) and try to design a version of code that are compatible w/one another.  But 1st I'd look for other's w/similar problems.  For all we know, maybe the U8G2 libaray has an option to skip I2C initialization already built in.

Or, you could check if your specific Arduino platform has a second I2C port and use it for the U8G2 display.  Or you could buy an Arduino w/2 or more I2C ports (but check to make sure the libraries you are using are compatible with the new Arduino).

You mix software I2C with hardware I2C on the hardware I2C pins.
To use hw I2C with the display use the U8G2_SSD1306_128X64_NONAME_F_HW_I2C constructor.
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);

Or use a different pair of pins for the software I2C display control.


text:
GCRduino shows up briefly in the IDE and then disappears
I have two UNO boards from a few years ago. They look the same as far as chip placement goes.
I can plug both in and get flashing lights on them, and when I hit the reset (2x the on-off) button, they both make the same LED "noises".  Since the LEDs on the non-detected board flash the same start-up sequence as a board that is detected, I assume both boards are working.
One of them has "UNO" printed on the circuit board and the other has "GCRduino Rev 1.0" printed on the circuit board. (edited according the comments for clarification)
I'm using Linux Mint 21 and Arduino IDE 2.0.3.
On hardinfo (the linux program), both of them are listed in Devices->USB Devices as "QinHeng Electronics CH340 serial converter."
The one that has UNO printed on the board is detected and I can load software onto it. The one that say GCRduino is not detected by the IDE and no new entry shows up in /dev.
The GCRduino is detected for a split second and then disappears again.  check this video: http://100wires.com/arduino.mp4

Welcome to SE/Arduino! Please take the [tour] to learn how these SE sites work. -- Are you sure that the GCRduino has a compatible boot loader? Please [edit] your question and tell us what your research on the device has revealed so far.

Arduino clones that use the CH34x chips generally do not show list the IDE or hardware lists as being a particular board, because the necessary information to positively identify them is not provided by the CH34x chip.
So, I'm skeptical that "one says UNO is detected" and "both of them are listed as...CH340...". are both true. Make sure the information in your question is correct.

@timemage Presumably "says UNO" means that the word "UNO" is printed somewhere on its circuit board. ;-) Therefore I don't think the OP wanted to say that Linux reports "UNO". Technical terms are difficult for casual users.

Yeah, I'm stumbling on the grammar I guess. Anyway, I take your point.

i've updated the post for accuracy.

did you try it on a different computer?

No.  same computer.  see my answer.

so yes I see you answer. and you didn't try it on a different computer before asking a question here. and the problem is with the computer not with the arduino

yes, that's why i mentioned the LED noises, although i didn't specify that the noises seem to indicate that it's working.  i've updated my question again for clarity.

I found the problem with dmesg.  When I insert the card and it shows up very briefly, it gets kicked by another device:
[  167.032321] input: BRLTTY 6.4 Linux Screen Driver Keyboard as /devices/virtual/input/input25
[  172.660038] usb 3-3: new full-speed USB device number 9 using xhci_hcd
[  172.809032] usb 3-3: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice= 2.62
[  172.809038] usb 3-3: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[  172.809041] usb 3-3: Product: USB2.0-Serial
[  172.810938] ch341 3-3:1.0: ch341-uart converter detected
[  172.811372] usb 3-3: ch341-uart converter now attached to ttyUSB0
[  173.349731] input: BRLTTY 6.4 Linux Screen Driver Keyboard as /devices/virtual/input/input26
[  173.655257] usb 3-3: usbfs: interface 0 claimed by ch341 while 'brltty' sets config #1
[  173.656203] ch341-uart ttyUSB0: ch341-uart converter now disconnected from ttyUSB0
[  173.656275] ch341 3-3:1.0: device disconnected

I can see the device on lsusb:
Bus 003 Device 008: ID 1a86:7523 QinHeng Electronics CH340 serial converter
That same device serial number is listed in
grep 1a86 /usr/lib/udev/rules.d/85-brltty.rules
ENV{PRODUCT}=="1a86/7523/*", ENV{BRLTTY_BRAILLE_DRIVER}="bm", GOTO="brltty_usb_run"

So when it connects, it gets kicked off by it being detected as another device.
So I just comment out that line in /usr/lib/udev/rules.d/85-brltty.rules, restart, and the board can now be detected.

Seems to be the same as this issue.

It is, thanks.  I've updated my question with more keywords/descriptions so maybe other's can more easily find the problem.


text:
How to abort compilation based on a "wrong" value in a variable
I looking for some code that can generate a compile time error when a variable contains a wrong value.
I once started with this code in a c program:
#define FIFO_BUFFER_SIZE 8

#define FIFO_BUFFER_MASK ( FIFO_BUFFER_SIZE - 1 )

#if ( FIFO_BUFFER_SIZE & FIFO_BUFFER_MASK )
#error Fifo buffer size is not a power of 2
#endif

Rewrote that in C++ for a PC console application:
MovingAVG::MovingAVG( const unsigned long element_count ) {
    ptr = 0;
    siz = element_count;
    buf = new long[siz];
    msk = siz - 1;
    if( siz & msk ) {
        //std::cerr << "Buffer size is not a power of 2" << std::endl;
        //exit( -1 );
    }
}

Now I want to use something similar in an Arduino sketch.
Because there is not always a terminal connected to the serial port and exit() is useless in a microcontroller, I am looking for a way to abort compilation based on a value in a variable.
I don't give myself much chance to find anything but to be absolutely sure that there is really no way, I am dropping the question here.
I want to abort compiling (preferably with a message) when the parameter of a class-constructor contains an invalid value. Is that possible at all?
Actually I want to see a message before I start programming the device. I have posted a possible solution below, that will throw a message during linking, but that only works when I declare the class with a constant parameter:
class MovingAVG avg( 32 );

I'm not sure what to do with this, because it's probably better asked and answered on stackoverflow. It almost certainly has been. You are sort of looking for  static_assert. However, to make use of that you have actually have a constant expression (compile-time knowable calculation) and siz & msk isn't knowable at compile-time. So the better part trying to answer this would seem to be about transforming your rewrite into something that could be evaluated at compile time which is something you'd probably have make decisions about that we can't.

The second code throws the error at execution time, not at compilation time, thus not want to asked for. The first code snippet would do that. What exactly is the reason that you don't want to use it?

As suggested by timemage, I think static_assert() is the right
solution to your problem: it is the clearest and most semantically
correct. The problem is, you cannot plug static_assert() directly into
your code, as the expression you are testing is not a compile-time
constant.
I suggest you turn the argument of the constructor into a template
argument. This will guarantee it is a compile-time constant. As a bonus,
you will be able to use a statically-allocated buffer, which is nicer on
the RAM than dynamic allocation:
template <int siz> class MovingAVG {
    static const int msk = siz - 1;
    long buf[siz];
    int ptr = 0;
public:
    MovingAVG()
    {
        static_assert((siz & msk) == 0,
                "Element count should be a power of two.");
    }
};

This works:
MovingAVG<32> filter;

but this fails with “error: static assertion failed: Element count
should be a power of two.”:
MovingAVG<33> filter;

Yeah. If this is a design decision they can take, it's what I'd go with. Where we're not getting them to clarify, I'm voting this up.

Excellent coding. I like it!
Thank you.

Because element_count is a method's parameter, it is by definition variable. Therefore, its value is generally not known at compile time.
Since the value of element_count is not known at compile time, you cannot get a compile time error for a wrong value.

Only if you use the method (here: a constructor) in the same translation unit as its definition, and if the arguments of all calls are known to the compiler (they are constants), the compiler will be able to evaluate siz & msk as a constant. Please note that some compilers need to receive optimization options for this.
Then you can use any approach that triggers a compiler diagnostic, for example like this one in C.

This will do the trick, a very dirty trick but it will generate an error before I program/test the device.
That might save a few program cycles of the device, but more important it will not waste my time.
extern void ElementCountShouldBeAPowerOfTwo(void);

MovingAVG::MovingAVG( const unsigned long element_count ) {
    ptr = 0;
    siz = element_count;
    buf = new long[siz];
    msk = siz - 1;
    if( siz & msk ) {
        // This function will be removed by the optimiser
        // when the buffer size is a power of 2
        ElementCountShouldBeAPowerOfTwo();
    }
}

The compiler will not complain about the function "ElementCountShouldBeAPowerOfTwo" because it is marked as external. The linker will throw an error when the optimizer leaves the call in place.
In case the linker throws an error it will show:
undefined reference to `ElementCountShouldBeAPowerOfTwo()'

@chrisl
I've used both code in C and in C++ and I don't want to rewrite the C++ part.
You and @the_busybee were both right when you wrote that the error will not be shown at compile time.
I should have asked my question differently, I want to see a warning before I program the device :-)
I do not mark an answer because I expect this to fail in the future when the compiler is updated. For the moment, with Arduino 1.8.19, it does what I want.

It does not matter how you turn it, like any other method, this can work only if the value is known at compile time. And this is true only if the compiler sees all calls (in this case of the constructor) and their arguments are constant. So the usability is really very small. It would be good to add this to your question.


text:
Curious Collision between OneWire and RadioHead
The code below runs on an Arduino Pro Mini (8MHz 328p) sending temperature readings using an inexpensive ASK transmitter. I use OneWire to read the DS18B20s, and RadioHead to manage the radio.
The original problem was the send() calls at the top of the loop always worked, but the send() call in the temperature-reading loop never did.
The fix was to insert a call to setModeTx() ahead of the send() call. I'm pleased it works, but it's a hollow victory because I can't figure out why it works.
OneWire uses no timers and no interrupts. I wait for the temperature conversion using _delay_ms() which is a spin delay.
I've read and re-read the OneWire and RH_ASK code and am still puzzled. Can anyone explain?
Many thanks
Here's the gist of the code…
RH_ASK radio(1024, 0, 10, 0, false);
OneWire ow(2);

void loop()
{
    radio.send(/* build info */);     // always works
    radio.send(/* battery health */); // always works
    ow.reset_search();
    while (ow.search(addr))
    {
        read_thermometer(addr);

        // the following send() works ONLY
        // when preceded by setModeTx()
        // It *never* works without it
        radio.setModeTx();
        radio.send(/* one temp reading */);
    }
}

UPDATE
@timemage was correct in that there are also calls to Serial (which resolve to HardwareSerial) interspersed. I'm no closer to solving it; however, by rearranging calls I can get the failure to happen more- or less often.
In a way this highlights the distinction between diagnosis and repair. I may in the end discover an ordering of the calls that makes the failure exceedingly rare, and in this case the problem will have been repaired; though not diagnosed.

I would expect RH_ASK radio(1024, 0, 10, 0, false); to interfere with Serial, but I have no way of testing that. But, you don't appear to be using Serial, but then you indicate it's not the complete code. But then... I don't know why .setModeTx() would have the effect it's having. In any case, it's not clear to me that 0 can mean "unused" there and is maybe something to fix regardless.

@timemage you're on to something. I had earlier dismissed interaction with Serial, which as you surmise I am using. Still looking…

I'm not even sure I'd go that far. I've seen some libraries use -1 as an indicator of "not used" or "not applicable". What I did was look the RadioHead library to see how it would interpret it. For the benefit of anyone that thinks this is an "answer" I feel the need to spell this out: No it's not. At it's an observation of something that should probably be fixed regardless and may or may not have any bearing at all on the actual problem as stated in the question. I'm not going to write it an an answer because there's no particularly good reason to think it is the answer or even an answer.

If you find out that it helps and why, you can write your own answer, because you'll actually know that it's the answer and ideally why.

I could imagine two thngs that might happen (or not ;-)). First there is a code line somewhere in your code that configures the ASk driver for RX. Second the first two sends fill the write buffer and the third send does not work, because there is not enough place in the buffer to add the new data. The setModeTx might clean the buffer or simply needs some time the ASK driver needs to send the remaining data. Isn't there a waitPacketSent() method to wait before new data can be written? Perhaps worth I try???

I think @PeterPaulKiefer is onto something. The setModeTx() does clear _txIndex, _txBit, _txSample. And the transmitTimer() has a check if (_txIndex >= _txBufLen). Of course I am spitballing. But worth an investigation there.

If I am not mistaken, radiohead will use manchester encoding. This ensures there is always a transition. 0 is low to high and 1 is high to low. An unlucky series of 1's or 0's will not create a "flat" zone. Your signal trace looks like a proper Manchester encoded signal. Sorry I dont know the root cause of your problem. Is this packet longer than the other two that are usually successful? Sometimes the radio receivers are temperature sensitive. Try to put them in the freezer or near an oven and see if they get better or worse.
But it doesnt answer why a call to setModeTx() would fix the issue.

What if you do a similar trace again but this time with the call to setModeTx() before the actual send.

Finally had time to get back to this. I connected the data-out line from the sender to the data-in line of the receiver, and discovered it always works. So it's not any sort of collision between OneWire and RadioHead, curious or otherwise. There's something amiss with the radio link… but what?
Have a look at the following oscilloscope traces. The magenta line is the input to the transmitter. Cyan is the output from the receiver (an SYN480R if you're curious). Yellow is just there to trigger the scope (a digitalWrite() just before sending the problem message).
The packet from the transmitter begins with a series of training pulses for the receiver to establish things like gain and threshold for the demodulator. Thereafter, the data is encoded in a series of long and short pulses.
Note how the receiver (cyan line) syncs up with the training pulses, and is in lock-step with the transmitter... until ... IT GETS LOST and thinks everything is a zero for awhile. It eventually re-syncs with the transmitter, but by this point the packet is corrupt, gets rejected by the decoder, and that is why I'm losing the packet at the receiver.

But, one wonders, why this particular packet and not any of the others? The answer to that question is pretty much out of band for a software forum, but here goes. Let's add a trace to the scope display.
The following image includes the demodulator threshold in blue. That's an analog value that the demodulator uses to decide if it's looking at a one or a zero. For the SYN480R chip, it's the output of a low pass filter, which produces an average over the recent bits.
In this case, notice how the threshold rises during the early part of the packet, then settles down. My conjecture is there are too many ones in the packet encoding thus far (i.e. many more ones than zeroes), and this shifts the threshold high enough that the demodulator thinks everything it sees is a zero. This is confirmed in the previous image. Seeing all zeroes, the threshold settles down and the demodulator can sync up again.
Interestingly, just touching the scope probe to the threshold capacitor (to get the blue trace) disturbs the threshold enough to slow the rise and keep the packets working.
Thus, OneWire is definitely off the hook, as is any interaction with RadioHead. Moving on, I either need to make some tweaks to the RadioHead RH_ASK driver packet encoder, or change out the threshold capacitor in the receiver. That in itself is a balance, because you want it to be able to track changes in the received signal, yet not be so sensitive to packet encoding.
Hope you found this interesting. Many thanks to everyone who took a look and offered your insight.


text:
Arduino code giving error while compiling
I am a beginner, and I'm trying to make code to control a servo using two ultrasonic sensors.
I've tried to make the code, but when I tried to compile it using my simulation app, it gives this error:
sketch.ino: In function 'void value2()':
sketch.ino:123:19: error: expected ')' before '!' token
 if((L < R)>=6 & L !> normal){
                   ^
sketch.ino: In function 'void value3()':
sketch.ino:131:19: error: expected ')' before '!' token
 if ((R< L)>=6 & R !> normal){
                   ^

Error during build: exit status 1

How do I go about fixing this?
I'm using the Wokwi simulator website, and here is the link to the simulation.
Here is where the problem is in my code:
void value2() {
  /* I'm using L !> normal to make sure it doesn't run when L is greater than 750, and this is where the problem comes */
  if ((L < R) >= 6 & L !> normal) {
    servo.write(120);
    //goto
    loop();
  }
}

void value3() {
  /* I'm using R !> normal to make sure it doesn't run when R is greater than 750, this is also where the problem comes */
  if ((R < L) >= 6 & R !> normal) {
    servo.write(60);
    //goto
    loop();
  }
}

And here is my complete code:
#include <Servo.h>
#include <Stepper.h>
#define STEPS 100 // stepper steps
#define speed 30 // stepper speed
#define Lechopin 10 // ultrasonic sound sensor left
#define Ltrigpin 11 // ultrasonic sound sensor left
#define Rechopin 12 // ultrasonic sound sensor right
#define Rtrigpin 13 // ultrasonic sound sensor right
long Lduration;
long Ldistance;
long Rduration;
long Rdistance;
int  L;
int  R;
int dt1 = 100; //delay
int dt2 = 1;   //delay
int dt3 = 2;   //delay
int dt4 = 10;  //delay
int serv = 9;  //servo pin
Servo servo;
Stepper stepper(STEPS, 5, 6, 7, 8);
/* Assuming distance of 4 feet measured by sensor is between 100 to 1000, let's set 750 as the normal distance between
sensor and object in which will be anything in 4feet upward far
away from sensor won't be detected by the code. you can edit it with real time measurement, I just assume this */
int normal=750;
int minn=250;

void setup() {
  Serial.begin(9600);
  stepper.setSpeed(speed);
  servo.attach(serv);
  pinMode(Lechopin,INPUT);
  pinMode(Ltrigpin,OUTPUT);
  pinMode(Rechopin,INPUT);
  pinMode(Rtrigpin,OUTPUT);
}

void loop() {
  get_L_dist();
  L = get_L_dist();
  get_R_dist();
  R = get_R_dist();

  normalp();
  value1();
  value2();
  value3();

  //bailout;
}

//print sensors
/*
Serial.print("L is:");
Serial.println(L);
Serial.print("R is:");
Serial.println(R);
*/

/* read left sensor and calculate the distance */
long get_L_dist() {
  digitalWrite(Ltrigpin, LOW);
  delayMicroseconds(dt3);
  digitalWrite(Ltrigpin, HIGH);
  delayMicroseconds(dt4);
  digitalWrite(Ltrigpin, LOW);
  Lduration=pulseIn(Lechopin, HIGH);
  Ldistance=Lduration / 58.2;
  return Ldistance;
}

/* read right sensor and calculate the distance */
long get_R_dist() {
  digitalWrite(Rtrigpin, LOW);
  delayMicroseconds(dt3);
  digitalWrite(Rtrigpin, HIGH);
  delayMicroseconds(dt4);
  digitalWrite(Rtrigpin, LOW);
  Rduration=pulseIn(Rechopin, HIGH);
  Rdistance=Rduration / 58.2;
  return Rdistance;
}

//normal position of servo
void normalp() {
  if (L >= normal & R >= normal) {
    servo.write(90);
    //goto
    loop();
  }
}

void value1() {
  if ((L < minn) >= 2 & (R < minn) >= 2) {
    int ran = random(2);
    if (ran == 0) {
      servo.write(30);
      //goto
      loop();
    }
    if (ran == 1) {
      servo.write(150);
      //goto
      loop();
    }
  }
}

void value2() {
  /* I'm using L !> normal to make sure it doesn't run when L is greater than 750, and this is where the problem comes */
  if ((L < R) >= 6 & L !> normal) {
    servo.write(120);
    //goto
    loop();
  }
}

void value3() {
  /* I'm using R !> normal to make sure it doesn't run when R is greater than 750, this is also where the problem comes */
  if ((R < L) >= 6 & R !> normal) {
    servo.write(60);
    //goto
    loop();
  }
}

Use <= instead of !>. The latter is not proper C++ syntax.
Also, if (L < R) >= 6 probably doesn't do what you want. Did you mean if (L - R) >= 6 maybe?

It really can't do what they want. Because L < R in C++ will be either true or false, which will be considered 1 or 0 when when evaluated against >= 6. Taken as a whole (L < R) >= 6 is always false. They also probably wanted && rather than & although it may not exactly matter in this case. Ancient C didn't actually have && and used & this way. Still probably not a good idea.

Please put these helpful answers as actual answers and not comments on the question. Thank you,

If you answer in comments, then this question will show up a year later with "no answers" because you answered in the comments. And that just annoys everyone.

@timemage See above.

@NickGammon, the bot bumps only answered questions (which have an answer without vote). We usually don't answer syntax error questions so let's see if this one gets closed.

@NickGammon it may be helpful. I'm not sure it constitutes answer. If I thought it did, it would be an answer.

@NickGammon let me put it this way. If you take what I'd written and posted it as an "answer", I will vote it down. Because it is not an answer to the question. For thing it's describing code that compiles. It also does not having to do with that they should do; it represents no part of a solution. It is hopefully dispelling some idea about what they think code is going to do. Anyway, you guys need to figure out what you actually want people to do. At a minimum, it would be helpful if you weren't calling people out for things they're not doing. Thank you.

@Juraj It's unlikely to get closed now. I'm not going to fault the answerer for doing what a mod was asking them to do. Particularly now that it's an accepted answer. It at least does attempt to address the compilation issue. I don't think addressing them is such a bad thing, particularly if there's anything arduino-related about either the question on answer, and is based on something that isn't just a typo. Either way, it would help to know what is supposed to be done. Or again, at a minimum, not to be getting crap for it.

@timemage it would be helpful if you weren't calling people out for things they're not doing - this is a Q&A site. People ask questions. You are supposed to answer them in the answer box. Comments under questions are for clarifying the question (eg. "what sort of Arduino do you have"). Not putting your answer into an answer box is a pretty big thing. I think I can occasionally "call it out". Personally I thought what you wrote was very good, and it deserved to be in an answer box. Then, people can vote it up or down. And you get credit for making the answer.

I'd be very surprised if Juraj considers what I'd said an answer to the question. Either way, I don't care what you decide, but you and he and whoever else needs to figure out what is and isn't an answer and what is and isn't off topic. If everyone wants to define "answer" as anything that is "good" (or "helpful" as I said) irrespective of whether it actually answers the question that was asked, then I'm okay with that.

Use <= instead of !>; the latter is not proper C++ syntax.
Also, if (L < R) >= 6 doesn't do what you may think: (L < R) evaluates to true or false, so the whole expression will always evaluate to false. Did you mean if (L - R) >= 6 maybe?
Also, you use & as an "and" in your if statements, which should be &&.

Thanks a lot @ocrdu , I have modified it I use <= instead of !>, and I also changed ((L < minn)>= 2) to ((minn - L)>=2) and it is working on my simulation exactly as I need it to. Thanks to you all for helping me.


text:
how to transfer json to string?
I am getting a json object from aws iot MQTT. Assuming that json from aws is {status:opened}.
Here is my code.
#include <ArduinoJson.h>
void messageHandler(char *topic, byte *payload, unsigned int length)
{
  StaticJsonDocument<32> doc;
  deserializeJson(doc, payload);
  const char *status = doc["status"];
  Serial.println(status);//opened
  if (status == "opened")
  {
    Serial.println("door is opened");//not excute
  }
  else if (status == "closed")
  {
    Serial.println("door is closed");
  }
}

Why the if condition is not being excute?

what's printed in the serial monitor?

That's one of the peculiarities of the C language: the == operator compares the string addresses, not their content. It makes sense when you think of them as pointers, but it can be confusing for beginners.
To fix this, you can use strcmp() like so:
if (strcmp(status,"opened") == 0)
Alternatively, you can change the type of status to JsonVariant, like so:
JsonVariant status = doc["status"]
It works with JsonVariant because I overloaded the == operator to support string comparison.

if (strcmp(status,"opened") == 0)  You know probably knew this and just forgot, but for the benefit of anyone else, strcmp returns 0 for equality, and some negative and positive numbers for the other relative orderings. So, you'll want the == 0. Upvote.

Thanks, I updated the answer.

Disclaimer: I appreciate your work on this library. This and your answer are good and helpful. -- However, overloading operators in such a way is one of the many reasons I still dislike C++ after 40+ years of software development in many languages. It hides a lot of things up-front and (mis)leads to weird constructs, making it hard for non-experts to grasp good programming. C++ is therefore not an adequate programming language for beginners.


text:
esp_now.h: No such file or directory
Arduino: 1.8.19 (Windows 10), Board: "NodeMCU 1.0 (ESP-12E Module), 80 MHz, 4M (1M SPIFFS), v2 Lower Memory, Disabled, None, Only Sketch, 115200"
esp_now_testing:3:21: fatal error: esp_now.h: No such file or directory
 #include <esp_now.h>
                     ^
compilation terminated.
exit status 1
esp_now.h: No such file or directory
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Couldnt compile for a node mcu esp8266 board. Have installed esp8266 library from boards manager
#include <ESP8266WiFi.h>
#include <esp_now.h>

// Variables for test data
int int_value;
float float_value;
bool bool_value = true;

// MAC Address of responder - edit as required
uint8_t broadcastAddress[] = {0x24, 0x6F, 0x28, 0x7A, 0xAE, 0x7C};

// Define a data structure
typedef struct struct_message {
 char a[32];
 int b;
 float c;
 bool d;
} struct_message;

// Create a structured object
struct_message myData;

// Peer info
esp_now_peer_info_t peerInfo;

// Callback function called when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
 Serial.print("\r\nLast Packet Send Status:\t");
 Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void setup() {

 // Set up Serial Monitor
 Serial.begin(115200);

 // Set ESP32 as a Wi-Fi Station
 WiFi.mode(WIFI_STA);

 // Initilize ESP-NOW
 if (esp_now_init() != ESP_OK) {
   Serial.println("Error initializing ESP-NOW");
   return;
 }

 // Register the send callback
 esp_now_register_send_cb(OnDataSent);

 // Register peer
 memcpy(peerInfo.peer_addr, broadcastAddress, 6);
 peerInfo.channel = 0;
 peerInfo.encrypt = false;

 // Add peer
 if (esp_now_add_peer(&peerInfo) != ESP_OK){
   Serial.println("Failed to add peer");
   return;
 }
}

void loop() {

 // Create test data

 // Generate a random integer
 int_value = random(1,20);

 // Use integer to make a new float
 float_value = 1.3 * int_value;

 // Invert the boolean value
 bool_value = !bool_value;

 // Format structured data
 strcpy(myData.a, "Welcome");
 myData.b = int_value;
 myData.c = float_value;
 myData.d = bool_value;

 // Send message via ESP-NOW
 esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));

 if (result == ESP_OK) {
   Serial.println("Sending confirmed");
 }
 else {
   Serial.println("Sending error");
 }
 delay(2000);
}

Where did you get this code from? Although it does load <ESP8266WiFi.h>, the rest of this code seems to be for an ESP32 and not an ESP8266/NodeMCU.

To use ESP-NOW with ESP8266 and Arduino IDE, you must use the "espnow.h" header file. In this case, the error codes change and only need to use int values for success(0). esp_now_peer_info_t is not required to add peers. Here is the code:
#include <ESP8266WiFi.h>
#include <espnow.h>

// Variables for test data
int int_value;
float float_value;
bool bool_value = true;

// MAC Address of responder - edit as required
uint8_t broadcastAddress[] = {0x24, 0x6F, 0x28, 0x7A, 0xAE, 0x7C};

// Define a data structure
typedef struct struct_message {
 char a[32];
 int b;
 float c;
 bool d;
} struct_message;

// Create a structured object
struct_message myData;

// Callback function called when data is sent
void OnDataSent(uint8_t *mac_addr, uint8_t status) {
 Serial.print("\r\nLast Packet Send Status:\t");
 Serial.println(status == 0 ? "Delivery Success" : "Delivery Fail");
}

void setup() {

 // Set up Serial Monitor
 Serial.begin(115200);

 // Set ESP32 as a Wi-Fi Station
 WiFi.mode(WIFI_STA);

 // Initilize ESP-NOW
 if (esp_now_init() != 0) {
   Serial.println("Error initializing ESP-NOW");
   return;
 }

 // Register the send callback
 esp_now_register_send_cb(OnDataSent);

 // Add peer
 if (esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 0, NULL, 0) != 0){
   Serial.println("Failed to add peer");
   return;
 }
}

void loop() {

 // Create test data

 // Generate a random integer
 int_value = random(1,20);

 // Use integer to make a new float
 float_value = 1.3 * int_value;

 // Invert the boolean value
 bool_value = !bool_value;

 // Format structured data
 strcpy(myData.a, "Welcome");
 myData.b = int_value;
 myData.c = float_value;
 myData.d = bool_value;

 // Send message via ESP-NOW
 int result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));

 if (result == 0) {
   Serial.println("Sending confirmed");
 }
 else {
   Serial.println("Sending error");
 }
 delay(2000);
}

Your description of what needed to be changed is not complete. You have changed more than just the header file.


text:
Alternate full speed usb library for ATTINY85?
I'm currently working on a project using the ATTINY85 for USB communication. After some research, it turns out that the V-USB library only supports usb 1.1, which only supports a 125hz polling rate. I would like to be able to have a polling rate of 1000hz, or close to it, which requires usb 2.0 or faster. I was hoping that someone could help point me to a library which supports usb 2.0, or suggest an alternative. Any help would be greatly appreciated, thanks in advance!

you need a dedicated USB controller for that

Since an ATtiny85 has no built-in USB hardware module, you use a software solution like V-USB. Unfortunately bit-banging software cannot be as fast as hardware, so you are out of luck here. (Reading the documentation of V-USB is enlightened and explains the difficulties and limits of such a solution.)
You cannot have USB 2.0 with an ATtiny85 alone.
Possible solutions:

an external USB module
another microcontroller


text:
Rotary encoder weird values
I am trying to understand this rotary encoder I have, but it makes no sense to me.
I am using this rotary encoder:
https://www.amazon.com/gp/product/B07DM2YMT4/
CYT1100 aka CY110 aka EC11
I am using this wiring:
https://i.stack.imgur.com/aMyR5.png
P2 is the "push button" and it gives continuity when pressed.
I am using a knock off arduino nano and this is my simple script:
#define PIN_CLK 2

void setup()
{
    Serial.begin(9600);
    pinMode(PIN_CLK, INPUT);
}

void loop()
{
    auto val = digitalRead(PIN_CLK);

    Serial.println("CLK:" + String(val));
}

Where PIN_CLK is connected to A (DW) or B (CLK) in the diagram.
My expectation is that A and B should be either a constant HIGH or LOW depending on where the brushes are internally. Not switching to HIGH or LOW for a moment and then returning to what it was before.
When I check them with my multimeter, they are both always 5v (when its not making loose contact on the breadboard).
The serial plotter says its switching between HIGH and LOW repeated:
https://i.stack.imgur.com/6VC3z.png
Same with the Serial monitor:
https://i.stack.imgur.com/wAk0v.png
When I spin the encoder, it gives me gaps of LOW in the output like this:
https://i.stack.imgur.com/lOUmx.png
If I hold my index and thumb against P1 (5v) and A (CLK) while spinning the encoder. I get constant stream of HIGH with a LOW on every notch spin:
https://i.stack.imgur.com/CzUwV.png
Can someone explain this behavior and how this encoder is suppose to work?
Edit: I tried this schematic:
https://i.stack.imgur.com/Mlj1l.png
Whenever I turn the encoder. The LED blinks for a few milliseconds. Then turns off.
Is it suppose to stay solid depending on the 2 bit states?
Edit2: If I turn it extremely slowly. It turns the leds on in the order of left right or right left depending on the direction.
So the led diagram above works, but its weird to me.

P1 and P2 is probably the switch ... connect one to GND and the other to IO pin ... enable the pullup resistor on the IO pin ... do the same with B and A ... do not connect any pins to 5 V

@jsotola I disconnected P1 from 5V and connected G to ground, A to D2, B to D3. The values jitter between HIGH and LOW. Then both go low for a few ticks when spinning the encoder. Same result as before.

did you enable the pullup resistors?

@jsotola I did now

This is just quadrature encoding / decoding. There are tutorial all over the internet for this.  It's how old mice work.  Followup on this comment if you need to know more and I'll create another answer based on this approach.

There are several problems happening here. Since your code only covers one input pin, I'm going to talk about input A. This pin is left floating! When you turn the dial, the brush connects A and/or B to G in your photo, or in other words, pins A/B to ground. But if A/B is not connected to ground, there is no other voltage state - it's just left floating. You need to have a logic LOW 0V and a logic HIGH (either 3.3V or 5V depending on your Arduino board) for the Arduino to be able to distinguish between the LOW and HIGH states. You can solve this by changing your code to:
pinMode(PIN_CLK, INPUT_PULLUP);

This way when the pin (A) is not connected to GND via (G), it is held at a logic HIGH state.
P1 & P2 are the for the button, so you can't ignore one of the pins. To wire that correctly using an input pullup, P1 needs to connect to GND. P2 needs to connect to an input pin with another input_pullup. When the button is unpressed, the state will default to HIGH. When it's pressed, it will be connected to GND and show as LOW.
You are most likely following the images online for wiring the encoders that are already on a PCB. That PCB has 3 pullup resistors on it. Regardless if you are using code to do it or hardware, the circuit needs to look like this. input_pullup on the Arduino will act just like resistors shown in the circuit.
Here is a great resource: https://lastminuteengineers.com/rotary-encoder-arduino-tutorial/

I got it working after I used the LED example to realize that the current is only flowing in between notches and not all the time. The pull up requirement was also something that I was missing. The only difference between yours and mine is that I'm not connecting the 5v at all. I do have some more questions if you can answer them. For CLK and DT. Why use two resistors on the signal paths instead of just 1 resistor on the ground path? That seems to work ok so far. Also, are resistors even needed if connecting a arduino pin to ground?

If you combined resistors both CLK & DT would go LOW at the same time, which means you won't be able to use the encoder properly, if you are trying to do CW and CCW. You should really look up an Arduino button tutorial and get familiar with what input pullup/pulldown resistors do, that will answer all your questions.

It doesn't look like this encoder ever has both CLK and DT on at the same time. If I try to edge it. It flickers between them, but they're never both on. Edit: I tested it and both single resistor and double resistor ended up having double LOW readings when rotating the encoder.

Spend some time reading that tutorial I linked :)

When encountering weird values from a rotary encoder, there are a few possible reasons and troubleshooting steps you can take:
Mechanical issues: Check if there is any physical damage or obstruction affecting the rotary encoder's movement. Ensure that it rotates smoothly without any unusual resistance or skips.
Loose connections: Verify the wiring connections between the rotary encoder and the device it is connected to. Ensure that the connections are secure and properly seated.
Electrical noise: Electrical noise or interference can sometimes cause erratic readings. Try using shielded cables for the connections and consider adding capacitors or ferrite beads to filter out noise.
Incorrect configuration: Review the setup and configuration of the rotary encoder in your code or software. Make sure that you have selected the correct type of encoder (incremental or absolute) and that the signal processing is correctly implemented.
Debouncing: If you are using an incremental rotary encoder, it may produce multiple pulses or bouncing signals when rotating. Implementing debouncing techniques in your code can help filter out these erroneous readings.
Resolution and speed settings: Check if the resolution and speed settings in your code or software match the specifications of your rotary encoder. Incorrect settings can lead to unexpected values.
Compatibility issues: Ensure that the rotary encoder you are using is compatible with the device or system you are connecting it to. Check the specifications and requirements of both the encoder and the device to ensure compatibility.
If you have gone through these troubleshooting steps and are still experiencing weird values from your rotary encoder, it might be worth considering a replacement or consulting the manufacturer's support for further assistance.


text:
Making library for arduino
I'm learning library making on arduino , I want to make a library that works with arrays a user sets, e.g:
User sets array of int,
when  a certain function is been called the library will check if some instance are true or not ann set the return function accordingly as the array.
Code example:

    //in project example

#include <Keyss.h>

int rows=4;
int cols=2;
int a=0;
int b=1;
int c=2;
int inp=3;
int keyss[4][2]={
{0,1},,
{2,3},
{4,5},
{6,7}
};

Key key((keyss),rows,cols,inp,a,b,c);

void setup(){
Serial.begin(9600);
int keyprint=key.getkey();
Serial.println(key print);
}
void loop(){
}

And this will be the library files
Keys.h

#ifndef KEYSS_H
#define KEYSS_H
#include <Arduino.h>

class Key {

public:

Key(int (*keys)[4],int rows,int cols,int inp,int t1,int t2,int t3);
int getkey();
int waitforkey();

private:

int *_keys;
int _rows;
int _cols;
int _inp;
int _t1;
int _t2;
int _t3;

};

#endif

And
Keys.CPP

#include <Keyss.h>

//initialization

Key::Key(int (*keys)[4],int rows,int cols,int inp,int t1,int t2,int t3){

 _keys=keys[4];
 _rows=rows;
 _cols=cols;
 _inp=inp;
 _t1=t1;
 _t2=t2;
 _t3=t3;

 pinMode(_inp,INPUT);
 pinMode(_t1,OUTPUT);
 pinMode(_t2,OUTPUT);
 pinMode(_t3,OUTPUT);

}

//getkey()

int Key::getkey(){

int _a;
int _b;
int _i=0;
int _keymap=false;
int _val;
int _dt=500;
int _s1;
int _input;

for(_a=0;_a<_rows;_a++){

 for(_b=0;_b<_cols;_b++){

  _s1=_i;
  digitalWrite(_t1,(_s1>>0)&1);
  digitalWrite(_t2,(_s1>>1)&1);
  digitalWrite(_t3,(_s1>>2)&1);
  delayMicroseconds(_dt);

  _input=digitalRead(_inp);

  if(_input==true && _keymap==false){

   _val=_keys[_a*_cols+_b];
   _keymap=true;
}

  _i++;

}
}

if(_keymap==false){
   _val=-1;
}

return _val;

}

//waitforkey()

int Key::waitforkey(){

int _waitfor=getkey();

while(_waitfor<0){

_waitfor=getkey();

}

return _waitfor;

}

Where I have problem now is I don't know how to
use or assign an array in a library
I don't know how to use functions to refer to an array a user inputes, like here
int keyss[4][2]={
{0,1},
{2,3},
{4,5},
{6,7}
};

How do I use a function or inside the library to refer to the array a user sets?
Please how do I achieve that?
Its giving this error

Your keys variable is a 2D array of int, i.e. it is an array of
arrays. In C++, when an array is assigned to a variable or passed as an
argument, it implicitly decays to a pointer to its first element.
Note, however, that the decay-to-pointer behavior is not recursive.
In this case you end up with a pointer to an array of three int.
Your code should work if you give the proper type to the _keys class
member and the keys constructor parameter:
class Key {
public:
    Key(int (*keys)[3], int trig1, int trig2, int trig3, int inpin);
    int getkey();

private:
    int (*_keys)[3];  // pointer to array of 3 int.
    int _trig1;
    int _trig2;
    int _trig3;
    int _inpin;
    int _keye;
};

Edit: You have completely changed the question, to the point that my
answer may not be relevant anymore. In the previous version of the
question, it looked like you wanted to use a 3×3 2D array of numbers in
the class. In the current version, you are using an array of arbitrary
sizes represented as a flattened 1D array. These are quite different
approaches.
If you want to use a 2D array, the number of columns has to be a
compile-time constant. You have to declare the member variable as a
pointer-to-array like this:
int (*_keys)[2];  // there are two columns, not four!

assign it like this:
_keys = keys;  // do NOT subscript keys

and use it like this:
_val = _keys[_a][_b];  // it is a 2D array

This approach cannot work if you do not know the number of columns
beforehand.
If you want to use a flattened (1D) array, then the parameter of the
constructor has to be a simple int*, and you have to give it the
address of the first element of the original 2D array:
Key key(&keyss[0][0], rows, cols, inp, a, b, c);

The drawback of using a flattened array is that, in order to access the
elements, you have to perform explicit index calculations:
_val = _keys[_a*_cols + _b];

I tried it but I don't know the correct way to do it

Thanks bro  I didn't understand it that much earlier and also I am   new to  programming, but now I have understand it more


text:
How to trigger a function by detecting voltage change?
#define monitor_pin 14

void setup()
{
  pinMode(monitor_pin , INPUT);
}

void loop()
{
    unsigned long d1 = pulseIn(14, HIGH);
    if (d1>0){//trigger function}
}

I know there is a function pulseIn(), but it doesnt really solve my problem. I just want to trigger a function when voltage change from LOW to HIGH/HIGH to LOW. pulseIn() need to wait for the voltage to back to original level which in my case will exceed 3 minutes and cause timeout.
How can  I detect a voltage change other than pulseIn()?

The length of the pulse is of no interest to you at all?

@timemage yes, i dont need the pulse length at all.

You can save the previous state of the pin and then trigger the function when the current state is different from the previous state:
#define monitor_pin 14
int previous_state;

void setup()
{
  pinMode(monitor_pin , INPUT);
  previous_state = digitalRead(monitor_pin); // Initialize previous state with initial reading of the pin
}

void loop()
{
  int current_state = digitalRead(monitor_pin);
  if(current_state != previous_state){
    // Execute your code here
    previous_state = current_state; // update previous state
  }
}


text:
Compilation error with MMA8451 accelerometer and attiny85 using ATTinyCore
I am trying to use the Adafruit MMA8451 accelerometer with an attiny85. The Adafruit library uses Wire which doesn't work on the attiny so I used the ATTinyCore board files which have been modified to use a working version of Wire (github link: https://github.com/SpenceKonde/ATTinyCore).
I'm just trying to get the MMA8451 example to compile but here is the following error output:

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp: In static member function 'static void SPIClass::begin()':

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:259:5: error: 'USI_SCK_PORT' was not declared in this scope

     USI_SCK_PORT |= _BV(USCK_DD_PIN);   //set the USCK pin as output

     ^~~~~~~~~~~~

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:259:5: note: suggested alternative: 'USI_CLOCK_PORT'

     USI_SCK_PORT |= _BV(USCK_DD_PIN);   //set the USCK pin as output

     ^~~~~~~~~~~~

     USI_CLOCK_PORT

In file included from c:\users\sglaw\appdata\local\arduino15\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7\avr\include\avr\io.h:99:0,

                 from C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.h:27,

                 from C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:20:

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:259:25: error: 'USCK_DD_PIN' was not declared in this scope

     USI_SCK_PORT |= _BV(USCK_DD_PIN);   //set the USCK pin as output

                         ^

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:259:25: note: suggested alternative: 'USI_PIN'

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:260:5: error: 'USI_DDR_PORT' was not declared in this scope

     USI_DDR_PORT |= _BV(DO_DD_PIN);     //set the DO pin as output

     ^~~~~~~~~~~~

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:260:5: note: suggested alternative: 'USI_PORT'

     USI_DDR_PORT |= _BV(DO_DD_PIN);     //set the DO pin as output

     ^~~~~~~~~~~~

     USI_PORT

In file included from c:\users\sglaw\appdata\local\arduino15\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7\avr\include\avr\io.h:99:0,

                 from C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.h:27,

                 from C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:20:

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:260:25: error: 'DO_DD_PIN' was not declared in this scope

     USI_DDR_PORT |= _BV(DO_DD_PIN);     //set the DO pin as output

                         ^

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:260:25: note: suggested alternative: 'NOT_A_PIN'

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:261:26: error: 'DI_DD_PIN' was not declared in this scope

     USI_DDR_PORT &= ~_BV(DI_DD_PIN);    //set the DI pin as input

                          ^

Using library Wire at version 2.0.0 in folder: C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\Wire
Using library Adafruit_MMA8451_Library at version 1.2.1 in folder: C:\Users\sglaw\Documents\Arduino\libraries\Adafruit_MMA8451_Library
Using library Adafruit_BusIO at version 1.14.1 in folder: C:\Users\sglaw\Documents\Arduino\libraries\Adafruit_BusIO
Using library Adafruit_Unified_Sensor at version 1.1.7 in folder: C:\Users\sglaw\Documents\Arduino\libraries\Adafruit_Unified_Sensor
Using library SPI at version 2.0.0 in folder: C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI
exit status 1
Error compiling for board ATtiny85/45/25 (No Bootloader).

Any help much appreciated

I'm pretty sure I know what this is, but I can't replicate your problem exactly.

I guess this is a problem with the 2.0.0 version of core. I installed version 1.5.2 through the boards manager and the example of the library compiles without errors

I'll try the 1.5.2 version

@chrisl Did you also not get their exact error?

@timemage In fact I got no error. Only the warning, that like 85% of memory is used globally. Compiled without problems. OP: Maybe you can report this at the cores github repository. They are asking for feedback on the 2.0.0 version.

@chrisl no errors with 1.5.2 (apart from same global variables warning), thanks for the help! I'll try report it on the github for 2.0.0


text:
Arduino Nano 33 BLE Sense's BMI270 accelerometer rev 2
I'm trying to figure out how to use interrupts to get BMI270 acceleration data at high rate, but can't find any info on it. Already spent a few hours looking for some sample code and found nothing. Anyone knows where can I find more info or sample code on this?
EDIT:
its the rev 2 and it has a BMI270

By BMI270 do you mean LSM9DS1?

Sorry, I forgot to mention its rev 2 (https://docs.arduino.cc/hardware/nano-33-ble-sense-rev2)


text:
Adding RTC Library for Arduino Project in Visual Studio
I am working in an Arduino project in visual studio. I need to get and set time to a RTC clock. That's why I am adding a ds3231 header file in my project from GitHub. When I want to build "it's showing me linking error.
cccSeqVu.ltrans0.o*: (.text.startup+0x1ea): undefined reference to DS3231_init(unsigned char)

My code is given below.
   #include <Wire.h>
   #include "ds3231.h"

    void setup(){
        Wire.begin();
        DS3231_init(0x4);
    }

    void loop(){
    }

Can anyone please help me to find out what I have missed.

add the whole library, not just the header file

How to add the whole library in visual studio?

I don't know. I don't use platformio


text:
Is it possible to program an AVR chip (atmega328p) via i2c?
Currently I am using avrdude and I'm programming my atmega328p chip via the spi pins by pulling the RESET pin low (spidev programmer).
In my project I'm using predominantly i2c and this the only place where spi is used. I was wondering whether it is possible to program the chip via the i2c protocol and remove the spi connections altogether?
My searches were unsuccessful.

Are you really programming over SPI (communicating via SPI with a bootloader) or are you programming via ISP (same pins)?

@chrisl I thought I was using SPI, but now I'm not sure, lol. I'm using avrdude (-c linuxspi) to flash a .hex file over the spi pins and using the reset pin as slave select.

If you haven't changed the bootloader via ISP before doing that, I think you were using ISP, which means you were communicating with the ISP hardware of the Atmega328p directly, not with a bootloader running on it. Though I would ask, why you want to eliminate the SPI/ISP connection? Normally you use this only while developing and once for programming on production. You can even program the controller outside of your project and only put it into the target circuit after programming. That way your project circuit doesn't need any SPI/ISP connection headers.

@chrisl Well then, I suppose I'm using ISP. I want to be able to flash new firmware to my controller at any time, thus I need the programming connections, it was just going to be nice if I could reduce the number of connections if there was a simple way but it seems like too much work.

From section 27.2(*) of the Atmega328xx data sheet (emphasis mine):

In ATmega88A/88PA/168A/168PA/328/328P the Boot Loader Support provides
a real Read-While-Write Self- Programming mechanism for downloading
and uploading program code by the MCU itself. This feature allows
flexible application software updates controlled by the MCU using a
Flash-resident Boot Loader program. The Boot Loader program can use
any available data interface and associated protocol to read code and
write (program) that code into the Flash memory, or read the code from
the program memory. The program code within the Boot Loader section
has the capability to write into the entire Flash, including the Boot
Loader memory. The Boot Loader can thus even modify itself, and it can
also erase itself from the code if the feature is not needed anymore.
The size of the Boot Loader memory is configurable with fuses and the
Boot Loader has two separate sets of Boot Lock bits which can be set
independently. This gives the user a unique flexibility to select
different levels of protection.

You may need to re-write the input section of the bootloader, but it sure sounds like Atmel intended it to be doable.
[*] My data-sheet is dated 2018; the relevant section, Section 27, is titled "Boot Loader Support – Read-While-Write Self-Programming", in case a later revision has different section numbers.

Yes, as JRobert pointed out, I have no doubt - it is possible!
You need just 3 things:

a Bootloader that supports uploading the firmware via I2C
an Upload-Software that supports uploading the firmware to the bootloader mentioned in 1.)
an physical connection from the system the upload software is running on to the actual I2C bus of your device

Actually the physical interface is not the problem - there are USB<>I2C interfaces available widely, you can also re-use an arduino itself to be such.
Let's look at the bootloader.
Actually I found a german site that claims having a working I2C bootloader for Atmega8 including an upload tool (use Deepl.com to translate it). It may or may not work for other Atmegas as is.
There is also another project at github.
There will be more if you google for it. Actually I have not investigated any of them.
But chances are good than any of those might work for you.


text:
SoftwareSerial will not read all of the printed string when calling readString()
I have an Arduino UNO and an ESP32 that need to communicate to each other using SoftwareSerial. The problem I am coming across is that when I call readString and print it out using Serial, it will not give me everything that has been printed out from my ESP32.
I have my Arduino RX Pin hooked up to 4 and TX hooked up to 5
I have my ESP32 RX2 Pin hooked up to 16 and TX2 pin hooked up to 17, with the GND hooked up to directly to the Arduino GND
I am not using any resistors, straight up 5v of pure power
Arduino UNO Code:
// C-standard library
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <SoftwareSerial.h>

#define RX_PIN 4
#define TX_PIN 5

SoftwareSerial ardSerial(RX_PIN, TX_PIN);

void setup(void) {
  // Get access to network
  pinMode(RX_PIN, INPUT);
  pinMode(TX_PIN, OUTPUT);
  Serial.begin(9600);
  while(!Serial) {}
  ardSerial.begin(9600);
  while(!ardSerial) {}
}

void loop(void) {
  while (ardSerial.available() > 0) {
    String payload = ardSerial.readString();
    Serial.println(payload);
  }
  delay(1000);

}

ESP32 Code
#include <stdlib.h>
#include <string.h>

#include <SoftwareSerial.h>

SoftwareSerial ardSerial;

void setup(void) {
  // Begin connections
  Serial.begin(115200);
  while (!Serial) {}

  ardSerial.begin(9600, SWSERIAL_8N1, RX2_PIN, TX2_PIN);
  while (!ardSerial) {}
  return;
}

void loop(void) {
  {
    String spotData = "Huge JSON File that needs transferred";
    ardSerial.print(spotData);
  }

  delay(5000);
}

Expected result:

Able to retrieve every little bit of the JSON file that was printed out

Actual result:

Only receive like half of the JSON file

How big is the JSON file? How many bytes did the Uno manage to retrieve?

@EdgarBonet it's a huge JSON file, can't tell you exactly how many bytes the JSON holds since it is random each time. I grab it from the Spotify API if that tells you anything. It retrieves from the beginning of the JSON to a random part near the middle, then it just cuts communication until the JSON is sent again

does it fit into the RAM of the Uno?

I see 2 problems with your code:

You wrote in the comments, that the JSON file is huge. The Uno has only 2kB of RAM and you are trying to lead the complete file into RAM at once. Such a JSON file from Spotify will easily exceed the 2kB (in fact you have even less, because the Arduino framework and SoftwareSerial also use some of the RAM). So you just cannot handle the complete file at once with an Uno.

You use readString(). This function is sure easy, but also has some pitfalls. It uses the String class, which utilizes dynamic memory allocation. It allocates a bigger character array in RAM, if the current array is not big enough. That means, that you would need up to 2 versions of your String fitting into RAM while receiving, leaving only about 1kB. Also it will read from the SoftwareSerial interface, until a timeout is hit (1s by default I think). For building a robust communication between the two devices you should read until you reach a special character, for example via readStringUntil(). That special character is often the newline character '\n'.

Possible solution: First we should talk about the limited RAM problem. As stated above you cannot handle the full file at once. You need to handle it in chunks. Whatever you want to do with the data in the end, the Uno will need some time handling the current chunk of data. So you need to pause the transmission of data at the ESP, until the Uno is ready to receive more. Here you can go two ways:

Send the data in chunks of predefined size (small enough for the Uno to hold at once in its RAM) and wait a predefined time between each chunk, that is long enough for the Uno to handle every data it might have gotten in that chunk. This is the easiest to program, but will necessarily take more execution time.
Let the Uno signal to the ESP, that its buffer is full, for example by sending a special character to the ESP. The ESP should then stop sending, until it gets the OK from the Uno to proceed the transmission. To send without loosing data the Uno should probably also send the number of bytes received in that chunk. That way the ESP knows exactly, where in the data String the Uno is currently. This is a bit more difficult, though still easy enough and robust.

To handle the sending in chunks I would use the write(const uint8_t *buffer, size_t size) method of SoftwareSerial (actually this function comes from the Print class, from which SoftwareSerial inherits). The buffer is the pointer to the first element of the current chunk in the char array with the data. You can get the char array via spotData.c_str() and you can get the pointer to the n-th element of it via &(spotData.c_str()[n]). The second parameter is the size of the chunk in bytes. This needs to be small enough, that the data will fit into the RAM of the UNO, together with all the RAM needed for processing the data.
On the Uno I would then do the reading bytewise. Something like this:
char data[BUFFER_SIZE]="";
int pos=0;

void loop(){
    if(ardSerial.available()){
        data[pos] = ardSerial.read();
        if(pos == BUFFER_SIZE - 1){
            // Handle chunk of data
            pos = 0; // reset position to reuse buffer
        } else {
            pos++;
        }
    }
}

I have left out some parts to only demonstrate the principle. Also you need to define BUFFER_SIZE yourself, depending on the available RAM.
Obviously this does not implement the second option with the pause signal, which is more complex.

Apart from sending and receiving you will need to think about how to process the chunks of data. This depends largely on what exactly you want to do with that data. Just sending them via Serial is easy. Interpreting the data in chunks is more difficult.

There are two ways to implement a parser for a language like JSON or
XML:

Have the parser swallow the whole document at once, and produce an
in-memory representation of the same data.

Have the parser return control to the caller for each “event” it
detects, where an “event” is typically a primitive data item, or the
start or the end of a container.

Parsers of the first kind are much easier to use, but this can be
expensive in RAM usage if you want to parse a alrge document. The second
kind of parsers are harder to use, but they are able to parse huge
documents using a minimal amount of memory.
On an Arduino, you would typically use ArduinoJson, which is a parser of
the first kind, not ideal for parsing huge documents on little memory. A
quick search for “event driven C++ JSON parser” got me JsonReader. I
did not try it, and do not know whether that would work on Arduino, but
it shows that at least this kind of parsers do exist for JSON in C++.
You may want to search further along this way.
Before you dig into this, however, I suggest you give ArduinoJson a
second chance. ArduinoJson has a couple of tricks that can help dealing
with large documents:

You can ask it to filter the data as it reads it, in order to only
keep in memory the items you are actually interested in.

You can deserialize in chunks, and use the data extracted from one
chunk at a time.

Both techniques are explained in the tutorial How to deserialize a very
large document?.
Also, let's not forget the obvious: you should not attempt to store the
raw JSON document in memory. Instead, you should give ArduinoJson a
reference to your stream (namely ardSerial), and let it directly pull
the bytes as it parses.


text:
Just installed Arduino 2.0.3 - what is windows path to associated libraries?
Just installed Arduino 2.0.3 and I attempted to build a sketch which includes a library that I manually installed in version 1.8.19 and it can't be found:
In my program I have
#include <DS3231.h>
Now, attempting to compile it cannot find the library.
What is the path to the basic libraries in Arduino 2.0.3?

as in IDE1, it is the libraries folder in the sketchbook folder. the location of the sketchbook folder is in the Preferences dialog in the IDE

I found the location by examining the app while it was running.
The associated libraries are at:
%localappdata%\arduino15\Libraries
That will look like : C:\Users\<username>\AppData\Local\Arduino15\libraries
I created a new folder named DS3231 dropped in the .cpp, .h and .config files and now my sketch compiles with the #include <DS3231.h>
Kind of blows my mind that the Arduino 2.0.3 Libraries are found in a directory named Arduino15.  Is that an old version or something?
Here's what I see in preferences -- don't see a location for user libraries:

The best location will be your sketchbook location + a folder named libraries.
For example, in my case my sketchbook location is :
c:\users\<username>\dev\arduino
so my library folder should be:
c:\users\<username>\dev\arduino\libraries

"in a directory named Arduino15. Is that an old version or something?" The 15 comes from the the 1.5.x series IDE which first introduced support for boards other than the original set of AVR boards, was carried into arduino-builder, and arduino-cli were it remains relevant to current day IDEs. It is not a normal place to add user libraries.

@timemage Where would the place be to add user libraries?  I've added an image to the answer showing the Arduino 2.0.3 preferences but I don't see any location that would work.  Do you have an alternative path in mind that works for 2.0.3?  Thanks

do you see the location of the sketchbook folder in the Preferences dialog? then read my comment again and slow


text:
Arduino nano timing precision
How precisely can an Arduino nano be timed? The project I am working on needs two Arduino nano to work synchronously. Arduino one have to activate a relay after 2700 sec and Arduino two have to activate a second relay after 2700.360 sec (360 milli seconds after )
With the code given below the required accuracy is not achieved.
volatile uint32_t ovfCount = 0UL;
volatile uint32_t currentTime = 0UL;
volatile unsigned long time_prev = 0UL;
volatile unsigned long dT = 0UL;

unsigned long delayTime = 2700UL;     //Seconds
unsigned long coilActivateTime = 5UL;  // seconds

volatile unsigned long _waitTime = delayTime * 1000UL + 360UL;
uint32_t _burnTime = coilActivateTime * 1000UL;

volatile bool coilOn_flag = false;

ISR(INT0_vect) {

  EIMSK = 0b00000000;

  TCCR1B = B00011100;
  PORTB ^= (1<<0);
  ovfCount = 0;
  TIFR2 = 0;
  TCNT2 = 0;

}

ISR(TIMER2_OVF_vect) {
  ovfCount++;
}

ISR(TIMER1_OVF_vect) {
  //pass
}

ISR(TIMER1_COMPA_vect) {
  //pass
}

ISR(TIMER1_COMPB_vect) {
  uint8_t tcnt2 = TCNT2;
  uint32_t ovf_count = ovfCount;

  if (bit_is_set(TIFR2, TOV2) && tcnt2 < 128) {
    ovf_count++;
  }

  uint32_t totalCount = ovf_count << 8 | tcnt2;  // raw count
  // uint32_t currentTime = totalCount * 0.004;     // milli second
  currentTime = totalCount * 4UL/1000UL;  // milli second

  if (currentTime >= _waitTime) {
    PORTC ^= (1 << 5);   // relay Switch
    TCCR1A = B00000010;
    TIMSK1 = B00000101;
    PORTB |= (1<<1);
    if (coilOn_flag) {
      TCCR1B = 0;
      PORTB ^= (1 << 1) | (1<<0);
    }
    coilOn_flag = true;
    _waitTime = _burnTime;
    ovfCount = 0;
    TCNT2 = 0;
  }
}

void setup() {
  Serial.begin(115200);
  /*setting the pin directions*/
  DDRB |= (1 << 1) | (1 << 0); // gL, rL
  DDRC |= (1 << 5);  // relay
  DDRD &= B11111011; // interrupt- interrupt

  /* INITIAL STATE SETTING FOR THE PINS */
  PORTB &= B11111100; // rL, gL
  PORTC &= B11011111; // relay

  /* 8Bit Timer*/
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = B00000011;
  TCCR2B = B00001100;
  OCR2A = 250;
  TCNT2 = 0;
  TIFR2 = 0;
  TIMSK2 = B00000001;

  /* 16 bit timer */
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1A = B10000010;
  // TCCR1B = B00011100;
  TCCR1B = 0;
  ICR1 = 62461;
  OCR1A = 6206;
  OCR1B = 624;
  TCNT1 = 0;
  TIFR1 = 0;
  TIMSK1 = B00000111;

  /* External INTERRUPT */
  EICRA = 0b00000010;
  EIFR = 0;
  EIMSK = 0b00000001;

  PORTB ^= (1<<0);
}

void loop() {

}

How to correct the code.?

you said nothing about the required precision of the two values ... you also did not say if there is anything wrong with the code

The internal clock of an Arduino is not really good for timing long durations with high precision (due to manufacturing differences and clock drift with temperature). For that a RTC (Real Time Clock) would be needed. Though: If you only need precision in the time difference between the two relay activations, then you could trigger the second Arduino from the first to start the timing there. Millisecond range is normally easily reached with Arduinos

why can't one Arduino control both relays?

both are going to be inside 2 different systems. I do start the clock on both at the same time using a common interrupt signal.

The Arduino Nano is nowhere accurate enough for your application, and
this has nothing to do with your code: it is a hardware limitation. 360
extra milliseconds after 2,700 seconds is a difference of only
133 ppm (parts per million). The Arduino Nano is clocked off a
ceramic resonator, and these time sources carry a typical error of the
order of 1,000 ppm. The best thing the code can do is count the
clock cycles with perfect accuracy, which makes the software timing as
good as the underlying hardware, but never better.
Some options you may try:

The one that seems most obvious is to have the first Arduino somehow
send a trigger signal to the second one when it activates the first
relay. Or have the second Arduino sense the state of that relay.
Then, all the second Arduino has to do is wait for 360 ms, which
it can easily do with reasonable accuracy.

If there is no way the Arduinos can communicate, then you could try
to add external time sources to the Arduinos. Some RTC modules can
output a 32,768 Hz signal that could be accurate enough for your
needs. Look for a temperature-compensated RTC, as those are more
accurate.

If you cannot add extra hardware, you could try to calibrate the
clocks of your Arduinos in order to compensate for their relative
drift. Keep in mind though that the drift rate is
temperature-dependent, and wanders randomly even at constant
temperature. First read the article Arduino clock frequency
accuracy, by Joris_VR, to get an idea of the accuracy you
could expect from such calibration.


text:
avrdude: usbdev_open(): cannot open device: Permission denied
I'm trying to upload anything to my Arduino Uno Wifi Rev2, I'm on Arch Linux, but I'm failing with the following error be it via IDEv2 or arduino-cli:

avrdude: usbdev_open(): cannot open device: Permission denied
avrdude: jtag3_open_common(): Did not find any device matching VID 0x03eb and PID list: 0x2145

The device permissions:
crw-rw-rw- 166,0 root uucp  9 Jan 23:22 /dev/ttyACM0

My udev rule:
KERNEL=="ttyACM[0-9]",MODE="0666",GROUP="uucp",TAG+="uaccess"

lsusb:
Bus 001 Device 005: ID 03eb:2145 Atmel Corp. ATMEGA328P-XMINI (CDC ACM)

First two entries from udevadm info -a -n /dev/ttyACM0:
  looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.1/tty/ttyACM0':
    KERNEL=="ttyACM0"
    SUBSYSTEM=="tty"
    DRIVER==""
    ATTR{power/control}=="auto"
    ATTR{power/runtime_active_time}=="0"
    ATTR{power/runtime_status}=="unsupported"
    ATTR{power/runtime_suspended_time}=="0"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.1':
    KERNELS=="1-3:1.1"
    SUBSYSTEMS=="usb"
    DRIVERS=="cdc_acm"
    ATTRS{authorized}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceClass}=="02"
    ATTRS{bInterfaceNumber}=="01"
    ATTRS{bInterfaceProtocol}=="01"
    ATTRS{bInterfaceSubClass}=="02"
    ATTRS{bNumEndpoints}=="01"
    ATTRS{bmCapabilities}=="6"
    ATTRS{iad_bFirstInterface}=="01"
    ATTRS{iad_bFunctionClass}=="02"
    ATTRS{iad_bFunctionProtocol}=="01"
    ATTRS{iad_bFunctionSubClass}=="02"
    ATTRS{iad_bInterfaceCount}=="02"
    ATTRS{physical_location/dock}=="no"
    ATTRS{physical_location/horizontal_position}=="left"
    ATTRS{physical_location/lid}=="no"
    ATTRS{physical_location/panel}=="top"
    ATTRS{physical_location/vertical_position}=="upper"
    ATTRS{supports_autosuspend}=="1"

I feel like I've tried everything so far:

sudo chmod a+rw /dev/ttyACM0
sudo usermod -a -G uucp $USER
adding udev rule with all different configs (although if chown/chmod doesn't work what will it change??)
changing ownership to my user...
I checked the process for the IDE to make sure it runs on my user and it does
After all these steps I always either restarted and/or reloaded everything with sudo udevadm control --reload-rules && sudo udevadm trigger
Went through plethora of similar topics, no clues

I feel like I must be doing something awfully stupid here, it doesn't make any sense to me why it wouldn't work even after I chown'ed it to my user...

Looking at the board definition for the UNO WIFI R2, it doesn't use the serial port for upload. It's using an mdbg chip that it speaks to over a non-cdcacm USB protocol. Getting yourself into the group-owner for the serial device is good for communicating to the board through the serial monitor though.
The megaavr board package seems to come with a file for creating your udev rules that you should find at:
"${USER}/.arduino15/packages/arduino/hardware/megaavr/1.8.8/scripts/create_dfu_udev_rule"

The 1.8.8 subdirectory of megaavr is current as of writing. It will no doubt change. I still have 1.8.7 on my system.
Running it should create the necessary udev rule for allowing avrdude to speak directly to the USB device. Specifically they're adding this:
SUBSYSTEM=="usb", ATTR{idVendor}=="03eb", ATTR{idProduct}=="2145", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"

They seem to be creating a udev rule for the tty device as well, though that shouldn't strictly be necessary given what you've already done with becoming a member of the serial device's group. Basically you're doing it by becoming a member of the owning group where what they did was just open the device up to RW permissions for everyone.

It worked! Thank you so much for that insight, I wouldn't have figured it out in a reasonable time on my own for sure, I just ran the script to add both tty and usb rules, and removed the one I made previously. I haven't tested if adding just the usb rule works but afair the perms on the tty device were alright (rw for the owner group)

could u send the exact commands u used to fix the error?
@nieomylnieja

You can try sudo "${USER}/.arduino15/packages/arduino/hardware/megaavr/1.8.8/scripts/create_dfu_udev_rule" It may work. I can't practically do that for every version of every distribution of Linux in combination with every core version and executed from every command shell. In case this isn't clear, "${USER}" will evaluate to your user name. Or rather it will in bash. 1.8.8 is current as of this comment.


text:
Is it possible to know how long an ESP8266 was in deep sleep?
I'm working on a low power device that implements an ESP8266 MCU and uses it's deep sleep feature. The firmware uses the Arduino C++ library.
Part of the functionality requires knowing the time. To do this, I am using configTime to get the time (i.e. NTP). But, to reduce power consumption, I only connect to WiFi every 24 hours. The ESP8266 wakes every hour (to decide if it should do something or go back to sleep). To keep time, I record the last known unix timestamp to RTC memory and upon waking add the amount of time that the device was told to deep sleep (i.e. 1 hour).
The flaw in this design: Part of the requirement is that the user needs to be able to wake the device manually with a button press and interrupt the normal sleep pattern, but if the device is woken with the reset button, it adds an hour to the time and the time becomes completely inaccurate (because an hour was added, even though it could be seconds since deep sleep started).
Is there a way, using the ESP8266 API, to tell how long the device was actually in deep sleep? That way, on wake, instead of blindly adding 1 hour to the RTC-saved unix timestamp, I can add the amount of time that the MCU was in deep sleep. The datasheet seems to only mention the RTC a few times in not much detail.
If no firmware solution exists, what hardware solution could I use?
Thinking out loud: I think a compromise could be to detect if the reset button was pressed (latch/flip flop/register, maybe?). In this case I still wouldn't be able to tell how long the MCU was asleep, but at least I'd be able to tell if I should add time. I found that system_get_rst_info is based on how the device went to sleep (i.e. if woken from deep sleep by pressing the reset button, the reason is REANSON_DEEP_SLEEP_AWAKE), so I couldn't see how to make use of that in this case. I suppose I could add an external RTC, negating the need to calculate how long the MCU was in deep sleep, and just use that external IC for time keeping.
Edit: Apparently, rtctime.dsleep() provides time keeping across deep sleep, but it's LUA only so not useful to me. The source is written in C, but I can't see anything that would help.

Time is kept across the deep sleep. I.e. rtctime.get() will keep working (provided time was available before the sleep).

The hardware solution could be a flip/flop or scr or latching bjt thingie that's clamped by a physical button press that also uses a fet to pull down rst. You can then quickly query that one bit of state on boot to determine if a button did it. You then reset the latch/JK/SCR with another GPIO. So, it burns two GPIOs but works well.

@dandavis Good idea, I'll give that a try.

I believe the answer is no (you cannot tell exactly how long an ESP8266 was asleep), given these constraints:

If an external RTC cannot be used.
If the MCU does not connect to Wi-Fi every time it wakes.
If the MCU can be woken arbitrarily by the user pressing the reset button.

In other words, if the ESP8266 does not connect to Wi-Fi every time it wakes, you can only estimate the time based on how long it should have been in deep sleep, but you can't know for sure without either going online or using an external RTC.

save timestamp in NVRAM, the time before sleep. once wakeup, simply subtract the the data saved in NVRAM from the current time.

What if I sleep for 1 hour, but then press the reset button 1 second later? The time would be 59 mins and 59 seconds out, as I mentioned in my question.

I always use unix timestamp in millisecond ie...      gettimeofday(&tv,NULL);
time_stamp[ptr] = (int64_t)(tv.tv_sec*1000LL + tv.tv_usec /(1000LL));