text:
Unexpected negative values from abs() function inline with analogRead
When sampling from A0 with a 0-5V signal on an arduino micro with the code below I get some negative values.
int sensor = 0;
sensor = abs(analogRead(A0) - 512);

Values:
77
25
-74
-58
46
113
-74
102
-91
-51
-126
47
31

When running the (apparently) mathematically equivalent code below I get exclusively positive values.
int sensor = 0;
sensor = analogRead(A0);
sensor = sensor - 512;
sensor = abs(sensor);

I don't think this is an integer overflow as in this post because when I switch to long sensor = 0 I get the same negative results.
What's going on here?

abs() is defined in Arduino.h as a macro:
 #define abs(x) ((x)>0?(x):-(x))

A macro does not evaluate in the same way as a function.
 sensor = abs(analogRead(A0) - 512);

This statement will be expanded at compile-time to:
 sensor = ((analogRead(A0) - 512)>0?(analogRead(A0) - 512):-(analogRead(A0) - 512));

Now the "error" is easy to understand. The analog pin is read twice. The "error" can be avoided by adding the following line first in your sketch:
#undef abs

This will remove the macro abs() and the standard library function will be used instead.
Cheers!

The error is the abs() macro in Arduino.h

Thanks for the clear answer. I had no idea that macros even existed in the Arduino world. I found a post from 2011 discussing this and a short list of other macros. Do you know of a definitive list? Is it just more "Arduinoesque" and better practice to avoid multiple assignments in a line and stick to one operation per line?

No, it is not more Arduinoesque to use only one operation in one assignment. Sometimes this is done to make it easier to read. Your problem with macros does not have to do much with Arduino. It is more generally about how macros are evaluated by the compiler. The compiler replaces the macro with what is written in it's definition (and puts in the argument). It is not a function. And this is not Arduino specific, but depends on the compiler. You can also use  macros, when programming with other compilers. Macros can be useful, but you have to use them with caution.

@chrisl, there is already a abs and labs function. The arduino abs macro is a ludicrous blunder by arduino. Aaron Ciuffo, click on the link to Arduino.h in the answer by Mikael Patel, there you see the other macros. Another thing is not to use a variable with the name "B1".


text:
Arduino Nano stucks on uploading
I'm trying to upload an simple blink sketch to my Arduino Nano, which not used for a while.
As I remember, I uploaded an sketch to control RF module, at the last time I used. Now, when I connect my Arduino Nano, I 'm getting error message every second, from my serial monitor saying the the RF communication cant start, because I have disconnected all connections to the RF module.
It seems the Nano is working, and the Nano driver is working properly. I tried resetting manually, and uploading many times with random timings. But up to now, the sketch not uploaded, and waiting. When I press reset button while uploading, Arduino shows me the error it cant communicate.
I think the Arduino IDE not getting enough time to upload from serial, because it's busy all the time.
Is there any way to wipe out the existing sketch from Nano? or any working solution to upload my new empty sketch or simple blink sample? It's a big help if anyone can shed me some light to make my Nano work again.

select "Old bootloader" in Tools menu

@Juraj, I'm unable to find 'Old bootloader' in tools menu. You mean 'Burn bootloader'?

@Juraj, Ok I found it on sub menu and worked great! Thank you so much.

@Juraj I solved it thank you

You should use the "That solved my problem" button, not write an answer

@Juraj, There is no button available to me?

it should be in the box above the question

Edit and delete buttons are available, nothing else?

https://meta.stackexchange.com/questions/250922/can-we-clarify-to-the-op-that-their-question-is-not-yet-closed-and-the-duplicate/250930#250930

I have solved the issue by selecting,
Tools > Processor > ATMega (Old bootloader)
@Juraj, Thank you for suggestion.

source: Stack Exchange

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

sort: votes


text:
Why do we use bitwise operators to assign PORTx, DDRx and Pinx?
I have come accross a lot of examples using ways similar to the ones shown below to assign values to the pins.

PORTB |= (1<<PORTB2); //set bit 2

PORTB &= ~(1<<PORTB1); //clear bit 1

DDRD = DDRD | B11111100;  //Sets up the pins for output

My question is why do we need to use bitwise operations to make assignements?

You have "set bit 2" in comment, not "set bit 2 and clear all others"

@KIIV that is a bitwise OR operator ... it cannot clear bits

@jsotola exactly my point. PORTB |= (1<<PORTB2); //set bit 2 and keep the rest unchanged and PORTB = (1<<PORTB2); //set bit 2 and clear everything else.

Take a look at the LPC3250 User Manual on page 64 (Table 20. HCLK PLL Control register (HCLKPLL_CTRL - 0x4000 4058)). Now tell me, how would you put the PLL in power down mode, and later power it up again, without changing anything else? :) You need to only change bit 16, in a 32-bit register. The C language doesn't have an explicit "Set/change/read only this specific bit" (although, you can do some cool struct/bit member mask stuff with "bitfields"), so you have to be creative and use available operations to modify a subset of bits.

My question is why do we need to use bitwise operations to make assignements?

Because you're not assigning, you're modifying.
If you want to turn on just pin 3 (for example) you need to only control bit 3 of PORTB and leave the others alone.
That means you need to "or" the value of just bit 3 being on with the existing PORTB to turn the bit on, or AND it with the inverse (all pins on except bit 3) to turn it off.
To get the value of bit 3 you can remember that it's 4, or you can just use 1<<3 to say "Bit 3" - or use the macro PORTB3 to make it more readable instead of just the number 3.
The operation is commonly known as "Read Modify Write" and in some low-end microcontrollers you have to take special care when doing it.
For example, if you want to control the output pin 3 and currently you have pins 2, 5 and 6 on and the rest of pins 0-7 off (those are the ones on port B on the Uno) the sequence may be like:
Turn on:

Calculate bit value 1<<3    => 0b00001000
Read PORTB                  => 0b01100100
OR the two values together  => 0b01101100
Write to PORTB              <= 0b01101100

Turn off:

Calculate bit value 1<<3    => 0b00001000
Invert it                   => 0b11110111
Read PORTB                  => 0b01101100
AND the two values together => 0b01100100
Write to PORTB              <= 0b01100100

Could you put examples into your answer as you write (refer) to them?
I have learned from your and &Gerbens answer, but it would make things easier to understand if reference and example are seen simultaneously. Thanks

@Tomas Does that help you?

Thanks. That just become one of the posts to read when learning Arduino

Possibly worth noting that some chips (including the AVR) have specific "set bit" instructions, and at least gcc-avr will recognize this idiom and use the single instruction.

If you want to change all pins on a port at once, you don't have to.
The point isn't just that you want to set/clear the pins you want, it's that you want to not change the state of the other pins.  To do that, you need to modify only the bits for the pins to be changed, and leave all the other bits as they are.  The only way to do this is with bitwise operators.
But if you do want to change all the pins at once, then you can perfectly well just set the port register to a value.  Outputting a value on an 8-bit bus would be a classic case where you'd do this.
I do need to pick you up on one thing in your question though.  In many cases, it is a bad idea to read the state of the port, modify the bits, and write the value back.  The reason is that almost all microcontrollers use the same port address for setting the output state and reading the input state.  So by reading back the port state, you aren't necessarily reading the actual outputs you set.  Logic-high outputs are generally weaker than logic-low, so it's entirely possible for your connected electronics to pull down a logic-high.  The sequence of faults for the bug goes:-

Your program sets a bit (pin) to 1.
Another component pulls that pin down to logic-low.
The next time you read that port back to change another pin, the input for the pin reads 0.
You modify the value for the pin you intended to change.
You write the value back.  Now not only has the intended pin changed state, but so has the pulled-down output.
The other component stops pulling the pin down.  But your micro keeps outputting 0 (logic-low) for that pin.

The solution is that you don't do bitwise operations directly on the register.  Instead, you keep a "shadow" variable containing the state you want the outputs to be.  You do all your bitwise operations on that shadow variable, and then you write the shadow variable directly to the register.  And the bug goes away.

It makes code easier to write and re-use.
Let's say your program needs to do 3 unrelated things on different pins. Control a motor, flash a light, count some input pulses.
Since this bitwise technique allows you to read/change only the bits you need to, and leave the others alone, you can totally separate the code for the 3 tasks. It can even be written in separate files by separate people, and without knowing what other pins in the project are being used for. The code for one of the 3 tasks could be copy-pasted into a separate project, without needing to untangle it from project 1 nor make major changes to project 2. In software engineering lingo this is called making code "more maintainable" and also "modular."

The registers are 8 bits in size. And in the above two cases you want to set/clear 1 bit, while leaving the others the same.
In the last example you want to set pins D2-D7 to output, while leaving pins D0 and D1 unchanged.

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


text:
Arduino communication
I want to message and call arduino board. I want some type of automation. But where should I get started I don't know I've tried sim900a module which was disappointing experience for me. Then I found out that this module was designed for asian regions and needed some type of firmware update. I wonder if there are another methods to make calls and send messages to arduino board. Any answers will be appreciated.

Choose a modem that is suitable for your region. You should be looking for an LTE modem not a GSM/GPRS modem these days. GSM/GPRS is gradually being phased out.

SIM900A is not just for Asia, it is supports dual band GSM/GPRS 900/1800MHz which works in Asia, Europe except North America. You should get SIM900B which is a quad-band supporting GSM/GPRS 850/900/1800/1900MHz.


text:
arduino usb host shield hard drive
Greeting to all,
i have a mega2560( NOT AN ADK ), and usb host shield 2.0, and the following
a) 1 pendrive( 8GB) formatted as fat32
b) 1 300GB usb hard drive formatted as fat32
c) 1 1TB usb hard drive also formatted as fat32
i know, there is a limit on fat32 that the maximum
drive/partition size must be 32GB, and i have found
a disk utility that can format such big drive as fat32(
if you want to know what it is, please ask)
after formatting all these drives( a)+b)+c) ), i have
created folders+files on them, no access problem when
using them in linux, mac, win?;
so i have wrote a sketch in arduino and was successful
in create+write to the pendrive, but when i use the
identical sketch to write to the other two drives, the
sketch died at usb init;
all these were using the same+identical arduino+usb
host shield 2.0, and the operation of the hard drive(
one at a time ) was power with external adapter,
after b) and c) failed, again i used the same pendrive,
and wrote successfully;
then i reformatted those two large drives as fat32(this
time both with size 30GB)...again failed at usb  init;
any advice/suggestion would be greatly appreciated ,
thanks for reading and STAY HEALTHY !!!

I have no direct experience with that, but using a drive as big as 300GB or 1TB seems rather off limits with an Arduino. For what do you ever need that much space with a small and slow AVR Arduino?

thanks for your comment, what you have said about the size is TRUE+CORRECT, the 300GB and the 1TB was just laying around, and i wanted  to test out the limits, since i have 5 sensors in a robot, and by each write size is 100bytes and over 720 minutes...you get the picture...

Ok, that sparks the question how often you read per minute. To fill up 300GB in 720 minutes you would need to write the sensor data for all 5 sensors every 72us. I think the writing itself will take way way longer than that. With the 30GB from the stick you are still at a rate of every 720us. I mean, I don't want to invalidate your question, since it is a good question. Just wondering about the closeness to reality here.

the 300gb was just laying around, i used it to test out 00) this fat32 will work on drive/partition larger than 32gb, 01) the test i did with 5 sensors, for 3 hours each sensor took 1GB...so for 5 sensors over 12  hours that would be 20gb+(???) and if i run those sensors in a 24 hours that will go over the fat32 limit of 32gb

You are dealing with an MCU without an OS, if you want to have a hard disk, get a Raspberry Pi which run Linux with proper hardware driver. 2) Do you really need to read the sensor that frequent? I don't know your application, normally if you need that kind of data, you would process the data immediately rather than storing it in storage for later to process, I would suggest to understand the concept of edge computing if you need to process such intensive data acquisition.

thanks to all, yes i do understand my case is a mcu without an os, and yes, i have considered among raspberry pi( 3+4), and udoo, udoo is the only one that has a leonardo mounted...but with very limited  digital+pwm capable pins, so without exception, ALL operates on 3v, and all my sensors operate( meaning giving feedback to arduino ) at 5v...as to why am i collecting this amount of data, that is an assumption on your part, in worse case scenario, as i have stated can be over 40GB, since it worked with a 8GB pendrive, next i will try with a 64gb pendrive,

if that works,  then pcb inside these usb hard drives are over  8 years old...thus speed ,any comment would be appreciated, thanks again

ok, folks, i am sure i have this solved, after i used 2 64GB pendrives, 1 is with usb 3.0, 1 with 2,0... the 1 with a 2.0 worked and the one with 3.0 did not...and i found out that  i was attaching those hard drives to the usb host shield 2.0 with a usb 3.0 adapter...so consider this closed


text:
problem with char array iteration and strcmp
New to Arduino and programming so forgive me if this is trivial but I've searched and can't find an answer...
Goal: I want to convert decimal values to their equivalent fraction... eg: 0.125=1/8. I think I came up with a simple solution, having one array of decimal values and one array of fraction values and when the input value matches a decimal value return the corresponding fraction value and display it on a tft screen...
Problem: well my simple solution doesn't work for some reason and as stated previously I searched and can't figure out why... I tried declaring the arrays in many ways but with the same result, here is the relevant code but it's only a small fraction of the complete code... the line that is commented out is the one giving me the problem...
//Serial.print("decimal test result: ");Serial.print(fracarray[i]);Serial.println(" match");

when I use that line a random smiley face character appears on the tft screen and keeps the code from running properly.
int checkformatting(char *input, int button){
  char *decarray[]={"0.015625", "0.03125", "0.046875", "0.0625", "0.078125", "0.09375", "0.109375", "0.125", "0.140625", "0.15625", "0.171875", "0.1875", "0.203125", "0.21875",
                  "0.234375", "0.250", "0.265625", "0.28125", "0.296875", "0.3125", "0.328125", "0.34375", "0.359375", "0.375", "0.390625", "0.40625", "0.421875", "0.4375", "0.453125",
                  "0.46875", "0.484375", "0.5", "0.515625", "0.53125", "0.546875", "0.5625", "0.578125", "0.59375", "0.609375", "0.625", "0.640625", "0.65625", "0.671875", "0.6875",
                  "0.703125", "0.71875", "0.734375", "0.75", "0.765625", "0.78125", "0.796875", "0.8125", "0.828125", "0.84375", "0.859375", "0.875", "0.890625", "0.90625", "0.921875",
                  "0.9375", "0.953125", "0.96875", "0.984375"};
  char *fracarray[]={"1/64", "1/32", "3/64", "1/16", "5/64", "3/32", "7/64", "1/8", "9/64", "5/32", "11/64", "3/16", "13/64", "7/32",
                  "15/64", "1/4", "17/64", "9/32", "19/64", "5/16", "21/64", "11/32", "23/64", "3/8", "25/64", "13/32", "27/64", "7/16", "29/64",
                  "15/32", "31/64", "1/2", "33/64", "17/32", "35/64", "9/16", "37/64", "19/32", "39/64", "5/8", "41/64", "21/32", "43/64", "11/16",
                  "45/64", "23/32", "47/64", "3/4", "49/64", "25/32", "51/64", "13/16", "53/64", "27/32", "55/64", "7/8", "57/64", "29/32", "59/64",
                  "15/16", "61/64", "32/32", "63/64"};
    for (int i=0; i<63; i++){
      if (strcmp(decarray[i], input)==0){
        //Serial.print("decimal test fracarray: ");Serial.print(fracarray[i]);Serial.println(" match");
       Serial.print("decimal test result: ");Serial.println(decarray[i]);Serial.println(" match");
      }
    }

    Serial.print(("result mm= ")); Serial.println(conversionresult, 6);
  }
}

Thanks in advance for any help...

This is not the reason for the error, but your arrays should be declared as static const char *const decarray[] = { .... (Even better: relocate the string literals to PROGMEM). As for the actual problem... Apparently something else happens in the rest of the code. You said this is just a fraction of it. BTW, what is conversionresult? Where is it initialized?

@AnT thanks, I'll change the array declaration and look into what relocating to PROGMEM means... like I said very new at this. conversionresult is a global variable float conversionresult; I use it to return the results when converting inches to mm.

Otherwise there seems to be nothing wrong with the code you posted.

@Ant just had time to look into your suggestion that something else was causing the problem... and found it, it was a global float causing the problem... can't actually explain why but it works without that line of code that I originally thought was the problem and doesn't with it.... thanks for the help

It is highly unlikely that "a global float" by itself would cause such problem. Most likely that somewhere else in your code you have undefined behavior. It can be temporarily "spooked"/"swept under the carpet" by making random unrelated changes in the code (like your "global float"), but it will reappear eventually in some other form.

Ok I think I figured out what it was and I'll try and explain here with generic variable names... hopefully it makes sense to you... I have a global float 'float a; then I have 2 other global floats that I use for displaying stuff to the tft… 'float b; float c; then later I need both b and c to equal a... I wrote the code on separate lines... b=a; and c=a;... so to fix it I created a new float called float d; which works fine but messes up a reference to c somewhere else... so I tried to write b=c=a and b, c=a... both work but again no idea if there's a difference or not

b, c=a is equivalent to just c=a, which is not the same as b=c=a.

Ah ok... So b=c=a makes b and c equal a?

Yes, b=c=a; is the same as c = a; and b = a; together. Which means that there was no reason to change your original c = a; and b = a; variant,

I did find it strange that making that change fixed it... I'll do more testing, as you said something might show up later... And that wasn't my true problem...


text:
Teensy not pulling down despite digitalWrite(x,LOW)
I'm trying to switch a ATX PSU on and off by serial command. My code is as follows:
#include <Arduino.h>
#define PIN_LOW_FOR_POWER PIN_F0

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

void loop() {
  String sCode = Serial.readStringUntil('\n');
  if (sCode == "M80"){
    digitalWrite(PIN_LOW_FOR_POWER, LOW);
  }
  else if (sCode == "M81"){
    digitalWrite(PIN_LOW_FOR_POWER, HIGH);
  }
  else{
    Serial.println("Unknown command");
    return;
  }
  Serial.println("OK");
}

I'm getting "OK" back, and the power switches. After sending M81 I read 5V across the pin and ground, but after sending M80 for some reason I read 2.37V and not 0V. If I switch to "F1" (keep the wire connected to F0) I do read 0V.
The ATX PSU needs F0 to be pulled down in order to turn on. I soldered the ground of the ATX PSU to the Teensy ground, and the wire to be pulled down (green) to F0. I supply the 5V to the Teensy through USB, so the VCC pin is left unconnected.
The PSU does turn on if I manually create a short between F0 and ground.
Why doesn't the Teensy pull F0 down, and how do I resolve this? (All I could come up with is something of internal resistance within the Teensy being too high, which seems unlikely to me. (If the resistance within the PSU and wires between "green" and ground is equal to the resistance within the Teensy this would happen, right?))
PS: It turns out I bought a fake Teensy from China, if it's related. Ordered a new one for a different project, but still had this one laying around.

You forgot to set the IO pin to OUTPUT. Unless you do so all you are doing (if the Teensy core follows the Arduino API to the letter) is controlling the internal pullup.
pinMode(PIN_LOW_FOR_POWER, OUTPUT);

Okay, that was stupid... I'll accept your answer in 3 minutes.

Easilly done. It's called "code blindless" and we all suffer from it at some time or other. You have been looking at the code so long that you stop being able to see the code. A fresh pair of eyes always helps.


text:
Teensy 2.0 with MCP23017-E
I've recently bought two more MCP23017-E's for a project, but after hooking them up to my Teensy 2.0 I couldn't get them to react to anything. Suspecting faulty hardware, I hooked them up to an old LCP1114, and got them running just fine. I've tried porting the code I used, which still gave no result.
I'm using the following code:
#include "Wire.h"
const byte device=0b01000000; //default addrress of IO chip

const byte IODIRA=0x00;
const byte IODIRB=0x01;

const byte GPIOA=0x12; //IO pins, port A
const byte GPIOB=0x13; //IO pins, port B
const byte OLATA=0x14;//O pins A
const byte OLATB=0x15;//O pins B

const byte GPPUA=0x0C; //pull up resistors ,port A
const byte GPPUB=0x0D; //pull up resistors ,port B

char iCounter = 0;

void setup() {
  Wire.begin();
  seti2cbyte(device,IODIRA,0x00);
  seti2cbyte(device,IODIRB,0xFF);
  seti2cbyte(device,GPPUB,0xFF);  //enable pull-up resistors on port B
}

byte geti2cbyte(byte address, byte ptr) {
  Wire.beginTransmission(address);
  Wire.write(ptr);
  Wire.endTransmission();
  Wire.requestFrom(address, 1); // request one byte of data from MCP20317
  byte inputs=Wire.read();
  return inputs;
}

void seti2cbyte(byte address, byte ptr, byte value) {
  Wire.beginTransmission(address);
  Wire.write(ptr); // set MCP23017 memory pointer to GPPUA address
  Wire.write(value); // enable pull up resistors
  Wire.endTransmission();
}

void loop() {
  seti2cbyte(device,OLATA,iCounter);
  byte port_b = geti2cbyte(device,GPIOB); //get status of pins 21-28
  Serial.print(iCounter++);Serial.println(port_b);
  delay(500);
}

I don't see a blinking LED, and port_b stays at 255 (or -1 I figured after reading the Wire.cpp)
I've tried different methods, even running SPI myself (setting pins high and low manually). The only difference I see is that the Teensy 2.0 is 5V, and the LCP1114 runs at 3.3V. The data sheet for the MCP23017-E states that it is also rated for 5V though.
Why does it seem like my MCP23017-E's won't work at 5V, while the data sheet states they should?
MCP23017-E datasheet

• Operating Voltage:
  - 1.8V to 5.5V @ -40°C to +85°C
  - 2.7V to 5.5V @ -40°C to +85°C
  - 4.5V to 5.5V @ -40°C to +125°C

Those solder connections look really bad in the last picture. On D1 you can see that half of the hole isn't even filled with solder. You should first try to resolder all pins and check continuity between GND,VCC,D0 and D1 to your chips.

@Maximilian Gerhardt I've checked the connections, they're fully functional. They're indeed not filled, since it's temporary, but there is no measurable resistance over the connections.

No I2C pullup resistors? Also did you run an I2C scanner sketch?

The I2C scanner will help determine if the device is connected correctly and verify the address. The address in the code seems to be a "bit" off.

You have the wrong device address. You've included the R/W bit in the address, which you shouldn't.  An I2C address is only 7 bits, not 8.  Drop one bit:
const byte device=0b0100000; //default addrress of IO chip

HA!!! Thank you! I'm used to it just getting OR'd by libraries.

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


text:
NodeMcu 1.0 resets automatically after sometime
I want to show some digits in a 3x3 p10 red led pannel where the number will come from the cloud and the number keeps updating. For this I have used esp8266 based Nodemcu. I have used WiFi Manager library and DMD2 library for this and I am requesting the server every 5 seconds to get the number in response. Everything is working fine but it keeps restarting after some time and there is no fixed timing for this but it keeps restarting. It provides a message that "reset cause 4 boot mode(3,6)" wdt reset... I have tried different hardware and esp board version but nothing is working. I am currently using arduino 1.8.9 and esp8266 board version 2.5.2
please look into my code and suggest me what is wrong....
#include <Arduino.h>

#include <WiFiManager.h>
#include <math.h>
#include <WiFiClient.h>
#include <ESP8266HTTPClient.h>
#include <EEPROM.h>
#include <ESP8266WiFi.h>
WiFiManager wifiManager;
int countT;
HTTPClient http;
String svrHost = "";
unsigned int svrPort = 80;
String svrURL = "";
//DMD
#include <SPI.h>
#include <DMD2.h>
#include <fonts/Arial_Black_16.h>
#include <fonts/Droid_Sans_36.h>
#include <fonts/Droid_Sans_12.h>
#include <fonts/Arial_New_56.h>
//#include <fonts/Dmd13x20ClockX.h>
//DMD PIN
#define pin_A 16
#define pin_B 12
#define pin_sclk 0
#define pin_clk 14
#define pin_r 13
#define pin_noe 15
int respin = D2;
int btnstt = 0;
int wlcmgs = 1;
String ssid;
String dmdText = "0";
SPIDMD dmd(3, 3, pin_noe, pin_A, pin_B, pin_sclk);
// Number of P10 panels used X, Y
//DMD_TextBox box(dmd,0,0,32,5);
// Set Box (dmd, x, y, Height, Width)
//const char *MESSAGE = "iTrack LIVE InWard";
void setup(){
Serial.begin(115200);
EEPROM.begin(512);
pinMode(respin, INPUT);
//Reset Val
String doResetWifi = "0";
doResetWifi = readESP(257,1);

if(doResetWifi == "1"){
    writeESP(257,1,"0");
    wifiManager.resetSettings();
}

Serial.println("\nReset Val "+doResetWifi);
//wifiManager.resetSettings();
countT = 0;
wifiManager.autoConnect("LED-1");
Serial.println("connected...yeey :)");

//Read/Write EPROM
if(wifiManager.svrURL != ""){
    svrHost = wifiManager.svrHost;
    svrPort = wifiManager.svrPort;
    svrURL = wifiManager.svrURL;
    //HOST
writeESP(0,50,svrHost);

    //PORT
writeESP(51,5,String(svrPort));

    //URL
    writeESP(56,200,svrURL);

}else{
    //HOST
    svrHost = readESP(0,50);

    //PORT
    svrPort = readESP(51,25).toInt();

    //URL
    svrURL = readESP(56,200);
}

//DMD Setup
    dmd.setBrightness(255); // Set brightness 0 - 255
    //dmd.selectFont(Droid_Sans_36); // Font used
    dmd.begin();     // Start DMD

}
void loop(){
btnstt = digitalRead(respin);

if (btnstt == 1){
flashESP();
ESP.reset();
}
doRequest();
  //box.print(dmdText);

if(wlcmgs==1){
dmd.selectFont(Droid_Sans_12);
dmd.drawString(0,0,"Connected");
delay(5000);
dmd.clearScreen();
//scrlssid();
delay(5000);
wlcmgs=0;
}
dmd.clearScreen();
dmd.selectFont(Arial_New_56);
int padingTop = 2;
dmd.drawString(round((96 - (dmdText.length() * 24)) / 2), padingTop, dmdText);
delay(1000 * 5);
//dmd.selectFont(Arial_Black_16);
//scrtxt();
}
void doRequest(){
Serial.print("[HTTP] begin: "+svrHost+" "+svrPort+" "+svrURL+"\n");
String response;
if (httpRequest(svrHost, svrPort, String("GET /") + svrURL, "", response)) {
if (response.length() != 0) {
        response.trim();
        dmdText = response;
        Serial.println(response);
        Serial.println(countT);
        countT++;
    }
}

}
bool httpRequest(const String svrHOST,
unsigned int svrPORT,
const String& method,
const String& request,
String&       response)
{
WiFiClient client;
if (client.connect(svrHOST, svrPORT)) {
    Serial.println("HTTP Connected");
} else {
    Serial.println("failed");
    return false;
}

client.print(method);
client.println(F(" HTTP/1.1"));
client.print(F("Host: "));
client.println(svrHOST);
client.println(F("Connection: close"));
if (request.length()) {
    client.println(F("Content-Type: application/json"));
    client.print(F("Content-Length: "));
    client.println(request.length());
    client.println();
    client.print(request);
} else {
    client.println();
}

//Serial.println("Waiting response");
int timeout = millis() + 5000;
while (client.available() == 0) {
    if (timeout - millis() < 0) {
        Serial.println(">>> Client Timeout !");
        client.stop();
        return false;
    }
}

//Serial.println("Reading response");
int contentLength = -1;
while (client.available()) {
    String line = client.readStringUntil('\n');
    line.trim();
    line.toLowerCase();
    if (line.startsWith("content-length:")) {
        contentLength = line.substring(line.lastIndexOf(':') + 1).toInt();
    } else if (line.length() == 0) {
        break;
    }
}

//Serial.println("Reading response body");
response = "";
response.reserve(contentLength + 1);
while (response.length() < contentLength && client.connected()) {
    while (client.available()) {
        char c = client.read();
        response += c;
    }
}
client.stop();
return true;

}
void writeESP(int start, int len, String text){
EEPROM.begin(512);
int ind;
for(ind = 0; ind < len; ind++){
EEPROM.write(ind+start,text[ind]);
}
EEPROM.write(ind+start+text.length(),'\0');
EEPROM.commit();

EEPROM.end();
}
String readESP(int start, int len){
EEPROM.begin(512);
char dataS[len];
int ind;
for(ind = 0; ind < len; ind++){
if(EEPROM.read(ind+start) != '\0'){
dataS[ind] = EEPROM.read(ind+start);
}else{
break;
}
}
dataS[ind]='\0';
EEPROM.end();
return String(dataS);
}
void flashESP(){
Serial.print("\nResetting ESP\n");
writeESP(257,1,"1");
ESP.reset();
delay(2000);
}
/*
void scrtxt(){
const char *next = MESSAGE;
while(*next) {
Serial.print(*next);
box.print(*next);
delay(200);
next++;
}
}
/
/
void scrlssid(){
dmd.drawString(5,0,"Connected With");
DMD_TextBox box(dmd,0,20,96,16);
ssid = WiFi.SSID();
const char *ssidNext= ssid.c_str();
int len = 0;
while(ssidNext && len < ssid.length()){
Serial.print(*ssidNext);
box.print(*ssidNext);
delay(200);
ssidNext++;
len++;
}
}
*/

Welcome Angkon. Align your code (select and ctrl-k), and remove any code that doesn't cause the reset (try removing parts until it doesn't reset anymore, so you also can find out yourself what is the problem).

You have a watchdog timeout. That is caused by your code blocking and not "kicking the dog" enough. You should check for parts of your code that do nothing for long periods of time and regularly yield() so that the IP stack can do its work.

From your description it sounds like a Watchdog Timer reset.
The ESP8266 needs to regularly run internal householding tasks outside of your own code, such as Wifi/network related tasks. It will normally take some processing time for those tasks with every loop() iteration and with every delay() command.
If your code is doing things that take longer than about 3.2 seconds, the internal "watchdog timer" will time out and reset the ESP, which is what you observed.
To ensure this does not happen, you should put a yield(); command inside pieces of your code that can potentially take longer than 3 seconds, like waiting loops (for example the "Waiting response" while() loop and similar pieces of your code). Try this and see if this solves your problem.


text:
Is there any way to catch the response of SIM800L after sending the at command?
I am using sim 800l with arduino. I am successfully sending AT command from arduino, not in serial monitor but I am unable to catch the response after each successful command execution if its ok or not. I want to do that because, if there is an error in a certain command the next command will not be executed unless its successful. Can you tell me is there any way to do so?

use readBytesUntil

Read Nick Gammon's How to process incoming serial data without blocking. Once you understand it, you can build your own parser.

for a polling serial read I use this method :
bool tSim8_sendCommand(uint8_t sim_cmd[])
{
    uint8_t simOK[2] = {0}, i=20;
    tSoftSerial1_write(sim_cmd);
    tSoftSerial1_write("\r\n");
    while (i--)
    {
        simOK[0] = simOK[1];
        simOK[1] = tSoftSerial1_readChar();
        if(simOK[0] == 'O' || simOK[1] =='K')
        {
            return true;
        }
    }
    return false;
}

the variable i i the while loop, is used just for retries, so the program doesn't get trapped in an infinite loop. the code is self-explanatory. the incoming characters are "pushed" into an array till the array reads "OK".
for a non-blocking one, it's a bit complicated as you have to define state-machines and concurret loops. here is a method I use for finding out if the last transmission was OK:
void tsim_phase_ok_routine(uint8_t inChar)
{
    if(tsim_aux_buff[0] == 'O' && tsim_aux_buff[1] =='K' && tsim_aux_buff[2] =='\r')
    {
        tsim_status_flag |= (1<<PHASE_OK);
        tsim_status_flag &=~(1<<PHASE_CON_ERR);
        return;
    }
    else
    {
        tsim_aux_buff[0] = tsim_aux_buff[1];
        tsim_aux_buff[1] = tsim_aux_buff[2];
        tsim_aux_buff[2] = inChar;
        err_timeout--;
    }
    if(!(tsim_status_flag & (1<<PHASE_OK)) && !err_timeout)
    {
        tsim_status_flag &=~(1<<PHASE_OK);
        tsim_status_flag |= (1<<PHASE_CON_ERR);
    }

}

I define "PHASES" to find out which phase is sim800 in. the whole function would be written in RX interrupt service routine and the input character would be fed to it.

what is tSoftSerial1_readChar?

@Juraj it was a software serial handler for reading chars

do you know the readBytesUntil functions? https://www.arduino.cc/reference/en/language/functions/communication/stream/streamreadbytesuntil/

@Juraj actually, the code I wrote is in C99 so I could use it on any platform. I the link, yes it does the same job

and why do you confuse a newbie with it?

@Juraj it's an answer anyway. that's why many question here have multiple answers. there would be people who just google the same question and may or may not be newbie or using the exact platform. and my answer is pure C so it can be used on arduino "as is" and many other platforms. we can't also deduce the OP is newbie because he wasn't aware of the method.


text:
Running commands from string
I have a string:
string s="digitalWrite(8,LOW);"

Is there any way to run it as a code?

Not an easy way, since you basically would need to write a C/C++ interpreter library for this. I don't know of such a library. Why do you need to do this? What are you trying to achieve?

To run commands that will be saved in external eeprom

Do you really have such complex programs to save there, that you need C syntax text there? Instead you could build your own command structure, which can be way easier to interpret. What commands do you need to save in the EEPROM?

@chrisl thank you, I forgot that I can do it like this

This is actually pretty simple:
if (s == "digitalWrite(8,LOW);") {
    digitalWrite(8,LOW);
}

Obviously, it will not work is s contains any other string... If you
want something more general, that is able to interpret a wide range of
possible commands, you will have to define a language, and write an
interpreter for that language. From the example you give, it seems you
would like your language to look like C++. This is most likely a bad
design choice. If you want an interpreter that understands the whole C++
language: forget it. You will never fit something this big into an
Arduino Uno.
Here is, for inspiration, a very simple interpreter I
wrote that understand the following commands:
mode <pin> <mode>: pinMode()
read <pin>: digitalRead()
aread <pin>: analogRead()
write <pin> <value>: digitalWrite()
awrite <pin> <value>: analogWrite()
echo <value>: set echo off (0) or on (1)

You can use it a basis for writing your custom interpreter. Otherwise
you can do a Web search for “Arduino interpreter”: you should be able to
find interpreters implementing a wide variety of languages, including
compact binary languages (Firmata), Forth (another one),
Lisp, Basic, and even a C-like language.


text:
green house vent servo based reading a sensor wrong
I am trying to make a green house vent that will open based on the temperature, however in my code the thermometer is not reading correctly, I've been designing it  in tinkercad and heres the link
https://www.tinkercad.com/things/fxhHvZCoqmQ
when the thermometer is on A0 i9t reads 14, if its on A3 it is 17.
I am very new at this so please help.

post your code in the question directly.

what is your question?

What is the problem with the code, because I can't see any problems.


text:
OTA updating the ESP32 from a separate server
I have an ESP32 project which I'd like to be able to update OTA. The trouble is that it is in deep sleep for approximately 15 minutes before waking up, connecting to WiFi sending an MQTT packet then going back to sleep.
I would like to be able to have a webpage hosted on a Raspberry Pi with a repository of datestamped .bin files that the ESP32 can connect to, check it's current version against the available options, if there is an applicable update, go through the standard OTA update protocol, or if there is no new available version, don't check again for 24 hrs.
How do I go about this?

HttpUpdate library. the esp32 version is without a documentation, but here is the similar esp8266 HttpUpdate library doc https://arduino-esp8266.readthedocs.io/en/latest/ota_updates/readme.html#http-server

I remember seeing something about this a while ago and it must have stuck in my head, but I hadn't thought about using it for ESP32.
Do you know if the ESP32 version will work by using the ESP8266 documentation?
I can't imagine they'd be too different

the esp32 version has examples too

I used the library mentioned by Juraj some time ago on an ESP32 in the exact way you described. I remember that it was straight forward to use. Looking at examples is all you need to do

Thank you very much :) I will try it all out


text:
What methods are there for tracking presence in rooms?
Im wanting to automate the lighting in my house, e.g. turn on lights when entering a room without having to fumble around with my phone or switches.
I have looked at audio, PIR and radar sensors, are there any more alternatives? For example using a wifi mesh to triangulate which room a phone is in.
Any suggestions welcome.
P.s. I may end up with one of the earlier options, I just want to see what is out there.

check out opencv

Jsotola OpenCV seems a bit excessive for the number of rooms I need to monitor, but for a single location could work

Maybe a combination of PIR and door-switch (like those used in alarm systems). By combining both you know not to turn of the lights, even if the PIR hasn't picked up any movement for a few minutes, which you're sitting on the couch. I personally really like light-switches. I'm only half joking here. An automated system only rarely has to malfunction for it to be more annoying that having to flick a switch.

what's wrong with pir and radar?


text:
Fail to upload sketch when Arduino Nano is connected to breakout board
When I upload a sketch from Arduino IDE to my Arduino Nano (not yet connected to breakout board) via USB, it works. I can then plug the Nano back to the breakout board and let it do its thing.
However, if the same Nano is already connected to the breakout board (which is in turn connected to some other things), and I try to upload a sketch via USB, it does not work.
The error message is:
Arduino: 1.8.13 (Windows 7), Board: "Arduino Nano, ATmega328P (Old Bootloader)"

Sketch uses 3844 bytes (12%) of program storage space. Maximum is 30720 bytes.

Global variables use 204 bytes (9%) of dynamic memory, leaving 1844 bytes for local variables. Maximum is 2048 bytes.

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x1c

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x1c

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x1c

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x1c

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0x1c

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0x1c

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0x1c

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0x1c

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0x1c

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x1c

Problem uploading to board.  See http://www.arduino.cc/en/Guide/Troubleshooting#upload for suggestions.

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

What's wrong? How do I solve it?

What breakout board do you have? Does it use the serial interface? Upload is done via serial. So if you block the serial interface with some other device, you cannot upload

Thanks chrisl
I think it's this one: https://www.jvzdigitalsourcing.com/products/arduino-nano-breakout-board
I think it's supposed to work with serial interface though, because the school provided all the hardware I'm using (it's for a course), and one of the things we need to do in this course is to control some motors via serial interface.

Have you pins 0 and 1 connected to anything?

Nope, 0 and 1 not connected to anything

!!!! I realised the RXN and TXN pins connecting to the bluetooth module are 0 and 1 pins! Oh god!

I unplugged them and now it's okay :) Thanks!


text:
Fio Keyboard program out of control, how to reset?
My question involves a Sparkfun Fio v3, similar to the Arduino Fio.
I had a student who was testing his understanding of the Keyboard library.  He uploaded a sketch that continuously sends output, emulating a keyboard, saying "Hello!If you're reading this, then you did things right!" (I don't have his code, unfortunately, so I can't post it.)
So, now, whenever I connect it via the USB, I can't upload a new sketch because the Serial channel is clogged with this output.  (Error Message: "avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x00" and so on)
I've tried putting the cursor inside the header comment in 'Blink', so that the new characters that are being spammed to my code are all inside a comment, and this makes it possible to compile, but it won't sync and upload.  I've tried burning a new bootloader, and this fails as well (Message: "Error while burning bootloader.").
It seems to me that the only way to get this device back is to reset the memory without connecting to a computer, but I can't find any way to do this.
Is there any way to rescue this device?

Hehe... This is a fun one to try and get out of. The normal way is to reflash the bootloader...
If it's the same as the Leonardo you get about 8 seconds after a reset while just the bootloader runs before it starts to spam everything with text. So you can try:

Open notepad or something similar
Plug in the board
Press and hold the RESET button (or connect the RESET pin to GND with wire)
Open the IDE and load Blink.ino

Now the tricky bit.  If the correct serial port isn't selected, you need to, within the space of 8 seconds:

Release the reset button.
Let the PC enumerate the device
Open the serial ports menu and select the right port
Press and hold the RESET button again.

Now you can program it, in a similar way:

Press UPLOAD in the IDE.
Just before it finishes compiling (turn on verbose output can help you time it better) release the RESET button.

If you timed it right the bootloader should run and accept the new program before the existing sketch runs and starts spamming everything.

I tried this many times, and couldn't get anything to work. Thanks, though.

Majenko's suggestion should work - the bootloader should give you a few seconds in which to upload the new sketch, although timing it can be critical.
If that fails, you can reburn the bootloader which will erase the existing sketch. I have a sketch which uploads various bootloaders, the ATmega32U4 being one of them.
Judging by the schematic and also a photo of the board, you would need to solder on a 6-pin header (circled).

Then run 6 wires as described on my page above to another Arduino (see "Wiring for Leonardo") and burn the bootloader. That only takes a couple of seconds. You could make up a suitable cable with a 6-pin socket to make it easier next time a student does the same thing. :)
This will definitely work (if you get the wiring right) because it uses ICSP programming, which means the sketch on the board doesn't have a chance to run. In fact the programming is not via the USB interface at all.
The bootloader uploading starts with a chip erase, which therefore removes any existing sketches.

Thank you twice!  I discovered that I had already downloaded your sketch before, I think this helped me rescue a Mega some time ago.

Your sketch successfully identified the SF Fio V3 as an ATmega32U4, and transferred the bootloader.  It took a little fiddling because SF didn't put a dot to tell me which end is up on the ICSP header, and it is upside-down compared to the Uno I was using to send it.  However, now my Mac won't recognize the Fio at all when I connect it to the USB.  When I look in /dev/, I see a new device, so linux is picking it up, but the Mac isn't recognizing it as anything interesting.  I'll do a little more playing.  I realized that this computer is new so I might just not have all the drivers installed.

A Leonardo driver should do it.

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


text:
Want criticism on my code
The code is controlling 3 blinds. There are 2 buttons for each blind for going each way and 2 buttons controlling all of them at the same time. The motorSerial is a way to control all of the blinds through the serial monitor where sending 1 goes one way and 2 the other way.
What I'm most concerned about is when pressing a button, it turns on the motor, waits for 0.2 seconds and turns the off. But if I'm holding the button down it will continuously keep turning it on and off. Does anyone have a better way of doing this?
const int PWMA = 13;
const int AI2_left = 12;
const int AI1_left = 11;
const int PWMB = 18;
const int BI1_middle = 10;
const int BI2_middle = 9;

const int PWMA2 = 8;
const int AI2_right = 7;
const int AI1_right = 6;

const int greenLeft1 = 5;
const int greenLeft2 = 4;
const int redMiddle1 = 3;
const int redMiddle2 = 2;
const int yellowRight1 = 14;
const int yellowRight2 = 15;
const int blueAll1 = 16;
const int blueAll2 = 17;

int motorSpeed_left = 0;
int motorSpeed_middle = 0;
int motorSpeed_right = 0;
int motorSpeed_all = 0;
int motorSerial = 0;

void setup() {
  pinMode(PWMA, OUTPUT);
  pinMode(AI2_left, OUTPUT);
  pinMode(AI1_left, OUTPUT);
  pinMode(BI1_middle, OUTPUT);
  pinMode(BI2_middle, OUTPUT);
  pinMode(PWMA2, OUTPUT);
  pinMode(AI2_right, OUTPUT);
  pinMode(AI1_right, OUTPUT);

  pinMode(greenLeft1, INPUT_PULLUP);
  pinMode(greenLeft2, INPUT_PULLUP);
  pinMode(redMiddle1, INPUT_PULLUP);
  pinMode(redMiddle2, INPUT_PULLUP);
  pinMode(yellowRight1, INPUT_PULLUP);
  pinMode(yellowRight2, INPUT_PULLUP);
  pinMode(blueAll1, INPUT_PULLUP);
  pinMode(blueAll2, INPUT_PULLUP);

  Serial.begin(9600);
}

void loop() {

  if(Serial.available() > 0) {
    motorSerial = Serial.parseInt();
  }

  if(digitalRead(greenLeft1) == LOW) {
    motorSpeed_left = 200;
    spinMotor_left(motorSpeed_left);
    delay(200);
    motorSpeed_left = 0;
    spinMotor_left(motorSpeed_left);
  }
  else if(digitalRead(greenLeft2) == LOW) {
    motorSpeed_left = -200;
    spinMotor_left(motorSpeed_left);
    delay(200);
    motorSpeed_left = 0;
    spinMotor_left(motorSpeed_left);
  }
  else if(digitalRead(redMiddle1) == LOW) {
    motorSpeed_middle = 200;
    spinMotor_middle(motorSpeed_middle);
    delay(200);
    motorSpeed_middle = 0;
    spinMotor_middle(motorSpeed_middle);
  }
  else if(digitalRead(redMiddle2) == LOW) {
    motorSpeed_middle = -200;
    spinMotor_middle(motorSpeed_middle);
    delay(200);
    motorSpeed_middle = 0;
    spinMotor_middle(motorSpeed_middle);
  }
  else if(digitalRead(yellowRight1) == LOW) {
    motorSpeed_right = 200;
    spinMotor_right(motorSpeed_right);
    delay(200);
    motorSpeed_right = 0;
    spinMotor_right(motorSpeed_right);
  }
  else if(digitalRead(yellowRight2) == LOW) {
    motorSpeed_right = -200;
    spinMotor_right(motorSpeed_right);
    delay(200);
    motorSpeed_right = 0;
    spinMotor_right(motorSpeed_right);
  }
  else if(digitalRead(blueAll1) == LOW) {
    motorSpeed_left = 200;
    motorSpeed_middle = 200;
    motorSpeed_right = 200;
    spinMotor_left(motorSpeed_left);
    spinMotor_middle(motorSpeed_middle);
    spinMotor_right(motorSpeed_right);
    delay(200);
    motorSpeed_left = 0;
    motorSpeed_middle = 0;
    motorSpeed_right = 0;
    spinMotor_left(motorSpeed_left);
    spinMotor_middle(motorSpeed_middle);
    spinMotor_right(motorSpeed_right);
  }
  else if(digitalRead(blueAll2) == LOW) {
    motorSpeed_left = -200;
    motorSpeed_middle = -200;
    motorSpeed_right = -200;
    spinMotor_left(motorSpeed_left);
    spinMotor_middle(motorSpeed_middle);
    spinMotor_right(motorSpeed_right);
    delay(200);
    motorSpeed_left = 0;
    motorSpeed_middle = 0;
    motorSpeed_right = 0;
    spinMotor_left(motorSpeed_left);
    spinMotor_middle(motorSpeed_middle);
    spinMotor_right(motorSpeed_right);
  }
  else if(motorSerial == 1) {
    motorSpeed_left = 200;
    motorSpeed_middle = 200;
    motorSpeed_right = 200;
    spinMotor_left(motorSpeed_left);
    spinMotor_middle(motorSpeed_middle);
    spinMotor_right(motorSpeed_right);
    delay(2500);
    motorSpeed_left = 0;
    motorSpeed_middle = 0;
    motorSpeed_right = 0;
    spinMotor_left(motorSpeed_left);
    spinMotor_middle(motorSpeed_middle);
    spinMotor_right(motorSpeed_right);
    motorSerial = 0;
  }
  else if(motorSerial == 2) {
    motorSpeed_left = -200;
    motorSpeed_middle = -200;
    motorSpeed_right = -200;
    spinMotor_left(motorSpeed_left);
    spinMotor_middle(motorSpeed_middle);
    spinMotor_right(motorSpeed_right);
    delay(2500);
    motorSpeed_left = 0;
    motorSpeed_middle = 0;
    motorSpeed_right = 0;
    spinMotor_left(motorSpeed_left);
    spinMotor_middle(motorSpeed_middle);
    spinMotor_right(motorSpeed_right);
    motorSerial = 0;
  }

}

/*****************************************************/
void spinMotor_left(int motorSpeed_left)
{
  if (motorSpeed_left > 0)
  {
    digitalWrite(AI1_left, HIGH);
    digitalWrite(AI2_left, LOW);
  }
  else if (motorSpeed_left < 0)
  {
    digitalWrite(AI1_left, LOW);
    digitalWrite(AI2_left, HIGH);
  }
  else
  {
    digitalWrite(AI1_left, LOW);
    digitalWrite(AI2_left, LOW);
  }
  analogWrite(PWMA, abs(motorSpeed_left));
}

void spinMotor_middle(int motorSpeed_middle)
{
  if (motorSpeed_middle > 0)
  {
    digitalWrite(BI1_middle, HIGH);
    digitalWrite(BI2_middle, LOW);
  }
  else if (motorSpeed_middle < 0)
  {
    digitalWrite(BI1_middle, LOW);
    digitalWrite(BI2_middle, HIGH);
  }
  else
  {
    digitalWrite(BI1_middle, LOW);
    digitalWrite(BI2_middle, LOW);
  }
  analogWrite(PWMB, abs(motorSpeed_middle));
}

void spinMotor_right(int motorSpeed_right)
{
  if (motorSpeed_right > 0)
  {
    digitalWrite(AI1_right, HIGH);
    digitalWrite(AI2_right, LOW);
  }
  else if (motorSpeed_right < 0)
  {
    digitalWrite(AI1_right, LOW);
    digitalWrite(AI2_right, HIGH);
  }
  else
  {
    digitalWrite(AI1_right, LOW);
    digitalWrite(AI2_right, LOW);
  }
  analogWrite(PWMA2, abs(motorSpeed_right));
}

ratchet freak's long answer has many good points. I would also agree
with Code Gorilla's suggestion to add a constructor to the struct.
However, once you have a constructor, it pretty much looks like a
regular C++ class¹, so it would make sense to add the motor-related
functions as members of the class. Thus I would start by building a
class that abstracts out the details of driving the motors:
class Motor {
public:
    Motor(uint8_t pin_1, uint8_t pin_2, uint8_t pin_pwm)
    : pin_1(pin_1), pin_2(pin_2), pin_pwm(pin_pwm) {}

    void begin() {
        pinMode(pin_1, OUTPUT);
        pinMode(pin_2, OUTPUT);
        pinMode(pin_pwm, OUTPUT);
    }

    void spin(int speed) {
        digitalWrite(pin_1, speed > 0 ? HIGH : LOW);
        digitalWrite(pin_2, speed < 0 ? HIGH : LOW);
        analogWrite(pin_pwm, abs(speed));
    }

private:
    const uint8_t pin_1, pin_2, pin_pwm;
};

I have left the buttons out of the class, because you have those blue
“all motors” buttons that do not fit well with the notion that each
button “belongs” to a particular motor.
Then, I would use some other abstraction for representing the buttons.
Maybe from a debouncing library. If button bounces are not problematic
in this application, then the “abstraction” would simply be:
// Is that button pressed?
static inline bool pressed(uint8_t pin) {
    return digitalRead(pin) == LOW;
}

Of course, as an abstraction, this does not provide a lot of value. It
can be seen as a small bit of “syntactic sugar” that makes writing (and
reading) the rest of the code easier.
With those in place, the program would look like:
// Pinout.
const uint8_t left_1   = 5;
const uint8_t left_2   = 4;
const uint8_t middle_1 = 3;
const uint8_t middle_2 = 2;
const uint8_t right_1  = 14;
const uint8_t right_2  = 15;
const uint8_t all_1    = 16;
const uint8_t all_2    = 17;
const int button_count = 8;
const uint8_t buttons[button_count] = {
    left_1, left_2, middle_1, middle_2, right_1, right_2, all_1, all_2
};

// Motors.
const int SPEED = 200;
Motor motor_left(11, 12, 13);
Motor motor_middle(10, 9, 18);
Motor motor_right(6, 7, 8);

void setup() {
    motor_left.begin();
    motor_middle.begin();
    motor_right.begin();
    for (int i = 0; i < button_count; i++)
        pinMode(buttons[i], INPUT_PULLUP);
    Serial.begin(9600);
}

void loop() {
    // Read the serial command, if any.
    int serial_command = Serial.read();  // is -1 if there is no input
    bool serial_1 = serial_command == '1',  // serial request for '1'
         serial_2 = serial_command == '2';  // serial request for '2'

    // Operate the motors.
    if      (pressed(left_1))   motor_left.spin(SPEED);
    else if (pressed(left_2))   motor_left.spin(-SPEED);
    else if (pressed(middle_1)) motor_middle.spin(SPEED);
    else if (pressed(middle_2)) motor_middle.spin(-SPEED);
    else if (pressed(right_1))  motor_right.spin(SPEED);
    else if (pressed(right_2))  motor_right.spin(-SPEED);
    else if (pressed(all_1) || serial_1) {
        motor_left.spin(SPEED);
        motor_middle.spin(SPEED);
        motor_right.spin(SPEED);
        if (serial_1) delay(2500);
    } else if (pressed(all_2) || serial_2) {
        motor_left.spin(-SPEED);
        motor_middle.spin(-SPEED);
        motor_right.spin(-SPEED);
        if (serial_2) delay(2500);
    } else {
        motor_left.spin(0);
        motor_middle.spin(0);
        motor_right.spin(0);
    }
}

¹ The struct keyword in C++ actually declares a class.

if(digitalRead(greenLeft1) == LOW) {
    motorSpeed_left = 200;
    spinMotor_left(motorSpeed_left);
    delay(200);
    motorSpeed_left = 0;
    spinMotor_left(motorSpeed_left);
}
else if(digitalRead(greenLeft2) == LOW) {
    motorSpeed_left = -200;
    spinMotor_left(motorSpeed_left);
    delay(200);
    motorSpeed_left = 0;
    spinMotor_left(motorSpeed_left);
}

Doesn't quite do what you want it to do.
Instead you want something like:
if(digitalRead(greenLeft1) == LOW) {
    motorSpeed_left = 200;
    spinMotor_left(motorSpeed_left);

} else if(digitalRead(greenLeft2) == LOW) {
    motorSpeed_left = -200;
    spinMotor_left(motorSpeed_left);
} else {
    motorSpeed_left = 0;
    spinMotor_left(motorSpeed_left);
}

However because you also want a master switch and control through serial. You can pull out the tests on each button to a variable and then make the master switch override those:
int motor_left = 0;
if(digitalRead(greenLeft1) == LOW) {
    motor_left = 1;
} else if(digitalRead(greenLeft2) == LOW) {
    motor_left = -1;
} else {
    motor_left = 0;
}

//...

if(digitalRead(blueAll1) == LOW){
    motor_left   = 1;
    motor_center = 1;
    motor_right  = 1;
} else if(digitalRead(greenLeft2) == LOW) {
    motor_left   = -1;
    motor_center = -1;
    motor_right  = -1;
}

if(motor_left > 0) {
    motorSpeed_left = 200;
    spinMotor_left(motorSpeed_left);

} else if(motor_left < 0) {
    motorSpeed_left = -200;
    spinMotor_left(motorSpeed_left);
} else {
    motorSpeed_left = 0;
    spinMotor_left(motorSpeed_left);
}

Also the pin number is just and int so you can pull those out as a parameter as well and have only one copy of the spinMotor function.
void spinMotor(int motor_pin1, int motor_pin2, int motorSpeed)
{
  if (motorSpeed > 0)
  {
    digitalWrite(motor_pin1, HIGH);
    digitalWrite(motor_pin2, LOW);
  }
  else if (motorSpeed < 0)
  {
    digitalWrite(motor_pin1, LOW);
    digitalWrite(motor_pin2, HIGH);
  }
  else
  {
    digitalWrite(motor_pin1, LOW);
    digitalWrite(motor_pin2, LOW);
  }
  analogWrite(PWMA, abs(motorSpeed));
}

To reduce the number of globals you can group the state for each motor into a struct and initialize them in init():
struct motorState {
   int motor_pin1, motor_pin2;
   int pwm_pin;
   int button1, button2;
   int direction;
   int speed;
}

motorState motor_left;
motorState motor_center;
motorState motor_right;

then pass the globals by pointer or ref to the functions doing the input and output.
void readMotorButton(motorState *motor){
    if(digitalRead(motor->button1) == LOW) {
        motor->direction = 1;
        motor->speed = 200;
    } else if(digitalRead(motor->button2) == LOW) {
        motor->direction = -1;
        motor->speed = 200;
    } else {
        motor->direction = 0;
        motor->speed = 0;
    }
}

void spinMotor(motorState *motor)
{
  if (motor->direction > 0)
  {
    digitalWrite(motor->motor_pin1, HIGH);
    digitalWrite(motor->motor_pin2, LOW);
  }
  else if (motor->direction < 0)
  {
    digitalWrite(motor->motor_pin1, LOW);
    digitalWrite(motor->motor_pin2, HIGH);
  }
  else
  {
    digitalWrite(motor->motor_pin1, LOW);
    digitalWrite(motor->motor_pin2, LOW);
  }
  analogWrite(motor->pwm_pin, abs(motor->speed));
}

If neither blueAll1 nor greenLeft2 are pressed, your else clause will prevent the other button from affecting the motors. 2. By motor_left > 1 you probably mean motor_left > 0. 3. The PWM pin should also be a parameter of spinMotor(). 4. readMotorButton() and spinMotor() look like they want to be methods of motorState.

1&2 yeah mistake; 3. I didn't realize that each motor had its own PWM pin; another argument in favor of grouping the motor states like that; 4. I'm not that much of a fan of creating member functions for simple stuff like this. YYMV though

There is a code review group on here where you will get a more generic code review if you want.
First thing I noticed is there are no comments.  You have written a paragraph explaining what the code does, but that should be in the code where you will be able to read it when you find the code 12 months down the line.
Rachet Freak has covered loads of good points, but one point I would disagree with is passing globals to functions using pointers.  I would use references instead, the only reason for this is IF you mess up references can't be NULL, so you don't need to check within the function to see if they are NULL.  Of course it will never happen, you never pass a NULL pointer to one of these functions, but as you code grows in size the chances of you doing that will increase and should you ever write a library, the chances of someone else passing a NULL pointer to your library is very high, and then you have got "a problem in your library".
Moving on from that if the parameter's value will not be modified during the life of a function pass it in as a const reference.  The main reason for this is it explains to the reader that the value won't change in the function, its a simple way of documenting your intention without having to write a comment.  So
void spinMotor(int motor_pin1, int motor_pin2, int motorSpeed){...}

would become
void spinMotor(const int& motor_pin1, const int& motor_pin2, const int& motorSpeed) {...}

Personally I would always add a constructor to structures.  This way you know that every field has the correct value to start with.  (I believe the Arduino compiler will initialise everything, but not all compilers are so kind.)  Also it allows you to write neater code, i.e.
struct motorState {
   int motor_pin1;
   int motor_pin2;
   int button1;
   int button2;
   int direction;

  // Parameterised constructor can be called either:
  //    motorState mState;
  //    motorState mState2 = motorState (2, 3, 4, 5, -1);
  motorState (const int& pin1 = 5, const int& pin2 = 6, const int& b1 = 7, const int& b2 = 8, const int& dir = 1)
  : motor_pin1(pin1)
  , motor_pin2(pin2)
  , button1(b1)
  , button2(b2)
  , direction(dir)
{}

}
Finally, I have always been told to never put two declarations on the same line.
int motor_pin1, motor_pin2;

There is no difference between the above and this as far as the compiler is concerned.
int motor_pin1;
int motor_pin2;

It is purely for readability you don't realise you are doing it, taking longer to read the first case than the second because your brain is more attuned to seeing a type, variable name and optional value.
int
motor_pin1,
motor_pin2;

The above is legal, but what type in motor_pin2?  It is just a convention that is widely used and makes code easier to read, even though it is harder to write, in the same way that code has to be indented by 4 spaces on here.  If it isn't indented it has the same text, but is virtually unreadable.
Finally, if you find yourself copy and pasting lines, it should probably be a function or an array or both.

You don't want to pass an int as a reference unless the intention is for the function to change the original value. Ints are too small, and the overhead of passing a reference is larger than the overhead of copying the int. And if you do want the original value to be modified, your intention may be clearer with a pointer (though there is more potential for a crash).

I see what you mean but it may depend on the platform you are targeting.

Very good point. Though I don't think a reference could possibly have less overhead than a small primitive type.


text:
Set variable value with serial?
so I need to make a arduino program, generates 2 random numbers, makes a + calculation with them and asks user the right answer. If the answer is right AKA Calculation==User Answer, then led is set to LOW, and serialprint sent. If its wrong, Led lights up and serialprint sent again. It works if i set the variables manually etc. But the I think the problem is with my serialRead, somehow it doesnt set the value it got from the user as the value of the variable (Luku4)
Here is the code, I hope you can help me.
int Luku1 = 0;
int Luku2 = 0;
int Luku3 = 0;  //Summa
int Luku4 = 0; //Vastaus
const int ledPin = 13;
byte i = 0;

void setup() {

  for (i=0; i<4; i++){
pinMode(ledPin, OUTPUT);
}

randomSeed(analogRead(0));
Serial.begin(9600);
Serial.println("Arvotaan 2 satunnaislukua ja summataan ne yhteen. Kerro oikea vastaus");
}

void loop() {
  Serial.println("Arvotaan 2 satunnaislukua");
  Luku1 = random(1,5);
  Luku2 = random(1,5);
  Serial.println(Luku1);
  Serial.println("+");
  Serial.println(Luku2);
  Luku3 = Luku1 + Luku2;
  delay(100);
  Serial.println("Mika on vastaus?");
  Luku4 = Serial.read();
    while(Serial.available() == 0){}

  if (Luku4==Luku3) {
    digitalWrite(ledPin, LOW);
    Serial.println("Oikea vastaus");
    delay(2000);
  }

  else{
    digitalWrite(ledPin, HIGH);
    Serial.println("Vaarin");
    delay(2000);
    digitalWrite(ledPin, LOW);

  }
}

You should move the Serial.read to after the  "wait for serial input"-line. Secondly. Serial.read will return a character, not a number. So you have to convert the ascii value of the letters "0"-"9" to the integer value of 0-9. This can be done by subtracting 48, as "0" is ascii code nr 48.

Oh, never heard of that. Thanks alot, it worked!

but it still works only for one digit and not for a number. use parseInt https://www.arduino.cc/reference/en/language/functions/communication/serial/parseint/

These could all by byte, vs int, as they will not be more than 255:int Luku1 = 0;
int Luku2 = 0;
int Luku3 = 0;  //Summa
int Luku4 = 0; //Vastaus
const int ledPin = 13;

And why do you need to set this pin to an  output 4 times? Once is enough   for (i=0; i<4; i++){
pinMode(ledPin, OUTPUT);
}

You are comparing a byte which was read through uart with a number. If you send number '5' through uart, you won't get number 5, but character '5'. To convert single character to number, you can do following:
Luku4 = Serial.read(); // '0' .. '9'
Luku4 = Luku4 - '0'; // 0..9

But this will work only for single digit numbers, for more robust solution please refer to readString function to see how you can read strings from UART and to function atoi which converts string to number.

You are reading Serial before you check that there is anything valid to read:
Luku4 = Serial.read();
while(Serial.available() == 0){}

Try swapping those two lines.

Swapped, Still not working. Only gives the "else", no matter what I input. Thanks for the help still.

Try changing these lines
Luku4 = Serial.read();
while(Serial.available() == 0){}

to these lines
while(Serial.available() == 0){}
Luku4 = Serial.parseInt();

As shown in the Arduino documentation, Serial.parseInt() will read a number from Serial. If a non-number character is entered it will return 0.


text:
MEGA2560 only starts program after pressing RESET button multiple times
I am working on a program where I am controlling an MP3 player by using UART between my MEGA2560 and the MP3 player. The MEGA2560 sends serial commands to the MP3 player when external interrupts are generated on INT4 and INT5 and it all seems to work fine.
When I want to test my program I press the RESET button on the Arduino in order to start the program. However, sometimes the program only starts after pressing the RESET button multiple times. This happens often but not all the time, which is weird.
What do you think could be the reason for this?

Does keeping the RESET button pressed for at least 1 second change the behavior?

Are you using Serial inside the interrupt handlers?

What causes the signals to switch on INT4 & 5? Normally, one would have the pins connect to Gnd when a button is pressed, and the lines are held high when not pressed by a Pullup resistor, typically the internal pullup is enough. For long wires, an external pullup may be needed.

@CrossRoads
I have two sensors (one for INT4 and one for INT5). When the sensors are turned on, they send 5V on the output. I measured the output with a scope and it works.


text:
Serial communication questions
I have to arduino's which are communicate using rx/tx. Arduino1 (A1) send data over serial to Arduino2 (A2). My questions are:
1 - If A1 do Serial.print each 50ms and A2 reading serial each 100ms which value will get A2? For example A1 send "1" and after 50ms send "2". Considering A2 will read serial after 100+ ms it will get "2" ?
2 - If A1 send data each 100+ms and A2 read at 50ms which value will get A2 between? For example A1 send "1" and A2 read "1" when read at 50ms but when it read again after 50ms (during that time A1 didn t sent anything ) will read again "1" ?
Thank you

1 - If A1 do Serial.print each 50ms and A2 reading serial each 100ms which value will get A2? For example A1 send "1" and after 50ms send "2". Considering A2 will read serial after 100+ ms it will get "2" ?

The Arduino has a 64 byte (software) buffer.  You will get the numbers in sequence up until that buffer overflows. Then it's not easy to predict what the results will be.
Probably something like:
121212121[...]2121212121212111111111111111

2 - If A1 send data each 100+ms and A2 read at 50ms which value will get A2 between? For example A1 send "1" and A2 read "1" when read at 50ms but when it read again after 50ms (during that time A1 didn t sent anything ) will read again "1" ?

If there is nothing in the buffer the read function returns -1.  That can be mapped (IIRC) into ASCII (depending on your software) as ÿ so you would get:
1ÿ1ÿ1ÿ1ÿ1ÿ...

You should read my tutorial on reading serial on the Arduino.

thank you very much


text:
How is better to store html / java script / in code or in flash on esp32
I have an esp32 which is running a web page together with a java script and using socket I update some values on the web page. I am doing this very fast (like each 50ms). Now I am serving all the html/java script code stored in a string variable but I am wondering which is the best? To store this html in spiff or in code ? and why?
Thank you very much

SRAM is typically an order of magnitude faster than NVRAM.

why do you need to update a web page every 50 ms?

I am displaying rpm of an engine which is read through obd port and I want see it as "real time" as possible

Best is to store static files in SPIFFS and serve them with Expires header set, to let the browser cache the html, css, js files and pictures files.
How to build the Expires header:
unsigned long expires = now() + SECS_PER_YEAR;
bp.printf(F("Expires: %s, "), dayShortStr(weekday(expires))); // two printfs because ShortStr functions share the buffer
bp.printf(F("%d %s %d 00:00:00 GMT"), day(expires), monthShortStr(month(expires)), year(expires));

And use AJAX method to show data on the page. Make the request with XMLHttpRequest object:
function getData(cmd) {
  var xhr = new XMLHttpRequest();
  xhr.onerror = function(e) {
    alert(xhr.status + " " + xhr.statusText);
  }
  xhr.onload = function(e) {
    showValues(xhr.responseText);
  };
  xhr.open("GET", "http://" + host + ":" + restPort + "/" + cmd, true);
  xhr.send();
}

showValues would be your function to fill the data into page
In ESP32 build the response as JSON for simple handling of the data in JavaScript.
Here is the WebServer in my project. It uses the basic Arduino Server class, not the esp WebServer. It has #ifdefs for SD or SPIFFS. The static files of my project including the js file are here.

It depends on your definition of "better".
Directly inlined in your code will probably be faster - it will be subject to the caching mechanisms of the execution pipeline, whereas SPIFFS will have to make specific SPI calls to read the data from the flash chip at the time it's required.  However SPIFFS will be easier to maintain since you are just working with files.
I would probably choose SPIFFS for larger files like graphics or big chunks of Javascript. Things that the client can download once and then cache (as long as your web server supports that kind of functionality - not sure what facilities the default ESP32 web server code has). The rest, the more dynamic things that change often, have as inline string literals.


text:
Getting "spikes" from an array of values - measure rpm using accelerometter
For a project where I intend to use an arduino and an accelerometer to get rpm of an diesel / gasoline engine i intend to use following solution.
I glued an mma8453 accelerometer to a neodium magnet which will be placed on a metallic part of the engine.
Using an arduino I am reading values from accelerometter and calculate one final value which is sqrt (acc.x^2 + acc.y^2 + acc.z^2), and also get millis for each value.
The values looks like this:
First column = millis, second acc value and third I identified maximums and millis since last maximum for them. Assuming that for an engine you have to max's per revolution I can calculate rpm of the engine.
My issue is that I have no idea how to write a function to do that.
Any help really appreciated
Thanks
269503  310
269504  303
269506  334
269507  326
269509  331
269510  330
269512  380
269513  377
269514  392
269516  400
269517  339
269519  393
269520  368
269521  353
269523  346
269524  316
269527  330
269528  281
269530  196
269531  195
269532  162
269534  119
269535  140
269537  132
269538  90
269539  99
269541  122
269542  168
269544  224
269545  219
269546  211
269548  268
269549  301
269551  334
269552  332
269554  316
269555  329
269556  379
269558  363
269559  381
269561  388
269562  403
269564  400
269565  420 49
269566  388
269569  360
269570  346
269572  259
269573  276
269574  284
269576  242
269577  207
269579  192
269580  145
269582  119
269583  113
269584  45
269586  125
269587  142
269589  123
269590  205
269591  243
269593  304
269594  308
269596  305
269597  298
269599  321
269600  340
269601  360
269603  380
269604  384
269606  370
269607  372
269608  413
269611  441 46
269612  395
269614  355
269615  332
269617  290
269618  317
269619  286
269621  227
269622  190
269624  172
269625  199
269627  146
269628  154
269629  177
269631  176
269632  156
269634  136
269635  174
269636  212
269638  260
269639  318
269641  291
269642  321
269644  304
269645  315
269646  343
269648  339
269649  360
269651  393
269652  390
269654  305
269656  405
269657  458 46
269659  358
269660  372
269662  339
269663  277
269664  298
269666  241
269667  203
269669  208
269670  185
269672  130
269673  165
269674  105
269676  87
269677  109
269679  128
269680  176
269681  229
269683  226
269684  271
269686  343
269687  307
269688  320
269690  318
269691  322
269693  322
269694  369
269697  363
269698  413
269699  399
269701  388
269702  426 45
269704  395
269705  380
269707  342
269708  311
269709  309
269711  315
269712  221
269714  227
269715  198
269716  113
269718  111
269719  88
269721  44
269722  69
269723  107
269725  158
269726  200
269728  232
269729  247
269731  313
269732  338
269733  348
269735  366
269736  339
269739  348
269740  377
269741  378
269743  385
269744  394
269746  403
269747  447
269749  454 47
269750  398
269751  380
269753  302
269754  245
269756  299
269757  310
269758  238
269760  206
269761  180
269763  108
269764  81
269766  83
269767  11
269768  119
269770  106
269771  169
269773  245
269774  270
269775  311
269777  338
269778  341
269780  332
269782  337
269783  337
269785  380
269786  387
269788  382
269789  373
269791  398
269792  414 43
269793  408
269795  387
269796  374
269798  285
269799  290
269801  326
269802  266
269803  211
269805  221
269806  191
269808  120
269809  175
269810  63
269812  147
269813  59
269815  120
269816  183
269817  196
269819  252
269820  301
269822  334
269824  325
269826  334
269827  310
269828  351
269830  354
269831  358
269833  373
269834  379
269835  332
269837  386
269838  404 46
269840  383
269841  385
269843  332
269844  266
269845  301
269847  282
269848  188
269850  199
269851  182
269852  128
269854  163
269855  119
269857  120
269858  140
269860  120
269861  129
269862  212
269864  230
269865  241
269868  290
269869  304
269871  340
269872  350
269873  327
269875  323
269876  351
269878  369
269879  387
269880  379
269882  380
269883  421 45
269885  373
269886  364
269888  360
269889  305
269890  302
269892  266
269893  249
269895  202
269896  229
269897  136
269899  122
269900  128
269902  49
269903  98
269904  107
269906  158
269907  211
269910  235
269911  225
269913  269
269914  314
269915  341
269917  335
269918  325
269920  348
269921  410
269923  375
269924  404
269925  419
269927  425
269928  442 45
269930  436
269931  400
269932  393
269934  326
269935  259
269937  307
269938  265
269940  220
269941  199
269942  183
269944  86
269945  83
269947  98
269948  23
269949  65
269952  124
269953  152
269955  221
269956  249
269957  287
269959  350
269960  331
269962  323
269963  341
269964  338
269966  389
269967  388
269969  380
269970  370
269972  358
269973  415 45
269974  403
269976  377
269977  381
269979  338
269980  328
269982  284
269983  246
269984  197
269986  178
269987  230
269989  162
269990  171
269991  141
269993  258
269995  138
269997  111
269998  163
270000  212
270001  192
270002  304
270004  287
270005  294
270007  349
270008  309
270009  334
270011  332
270012  364
270014  361
270015  408
270017  336
270018  421
270019  432 46
270021  361
270022  361
270024  342
270025  271
270027  288
270028  310
270029  235
270031  218
270032  166
270034  136
270035  146
270036  102
270039  78
270040  99
270042  122
270043  105
270044  181
270046  222
270047  293
270049  299
270050  299
270052  318
270053  349
270054  344
270056  349
270057  382
270059  381
270060  412
270062  380
270063  397
270064  425 45
270066  381
270067  367
270069  332
270070  272
270071  291
270073  296
270074  178
270076  177
270077  190
270080  123
270081  146
270082  107
270084  85
270085  108
270087  117
270088  148
270089  234
270091  223
270092  238
270094  283
270095  301
270097  332
270098  331

(Is this homework or are you really designing something?) You are leaving out stuff like why are you using a magnet?  Where are you placing the NXP part? That leaves us with having to guess at what is going on.  Calculating based on guessing, I'd say your engine is running at about 1304.3 rpms.

Is a mix actually between homework and design. The accelerometter is fixed on a magned and together attached to engine. Actually measure vibrations of the engine. When there is a detonation, then I have a high value. I don t know what you mean by NXP.

NXP (aka Motorola, Freescale & maybe Qualcomm) is the OEM for the chip you specified.

A simple approach would be to filter the signal using a low-pass filter, and then just calculate the time between two zero crossings.
Here's an example that works on your data. It's written in Python for easy testing and plotting, but trans-coding it to C++ should be trivial.

I used an Exponential Moving Average low-pass filter to get rid of the noise. Depending on the frequencies involved, you can change the shift factor. The higher this factor, the lower the cut-off frequency, and the greater the phase shift.
I chose a fixed DC offset, but if necessary, you could use another (very slow) filter to get rid of it before applying the zero-cross detection.
If you want to, you could use both zero crossings. Use the average of the two last RPM measurements in that case, to compensate for asymmetric waveforms.
You could add another EMA to smooth out the RPM measurements.
class ZeroCrossRPMCounter:
    def __init__(self,
                 max_rpm: float):
        self.min_distance = int(round(60_000 / max_rpm))

        self.first_crossing = True
        self.time_of_last_crossing = 0
        self.rpm = float('nan')
        self.previous_value = 0

    def __call__(self, time_ms: int, value: int):
        new_crossing = self.previous_value >= 0 and value < 0
        if new_crossing:
            if self.first_crossing:
                self.time_of_last_crossing = time_ms
                self.first_crossing = False
            elif (time_ms - self.time_of_last_crossing) >= self.min_distance:
                self.rpm = 60_000 / (time_ms - self.time_of_last_crossing)
                self.time_of_last_crossing = time_ms
            else:
                new_crossing = False
        self.previous_value = value
        return new_crossing

class EMA_shift_round:
    def __init__(self, shiftfac: int, initial: int = 0):
        self.shiftfac = shiftfac
        self.fixedPointOneHalf = 1 << (shiftfac - 1)
        self.z = initial << shiftfac

    def __call__(self, x: int):
        self.z += x
        shifted = (self.z + self.fixedPointOneHalf) >> self.shiftfac
        self.z -= shifted
        return shifted

if __name__ == '__main__':
    import numpy as np
    from matplotlib import pyplot as plt

    # Load the data
    data = np.genfromtxt('rpm-ctr-data.csv', delimiter='\t', dtype=np.int)
    time, signal = data[:, 0], data[:, 1]
    t_start, t_end = time[0] * 1e-3, time[-1] * 1e-3

    # Find the DC offset
    offset = int(round(np.mean(signal)))
    print(offset)

    # Initialize the filter and RPM counter
    lp_filter = EMA_shift_round(3)
    counter = ZeroCrossRPMCounter(2000)

    # Iterate over the data, filter it, and count the RPM
    peaks = []
    rpms = []
    filtered = np.zeros(len(time))
    for n in range(len(time)):
        filtered[n] = lp_filter(signal[n] - offset)
        new_crossing = counter(time[n], filtered[n])
        if new_crossing:
            peaks.append(time[n] * 1e-3)
            rpms.append(counter.rpm)

    # Plot the results
    plt.figure(figsize=(10, 6))
    plt.subplot(3, 1, 1)
    plt.title('Original signal')
    plt.plot(time * 1e-3, signal)
    for peak in peaks:
        plt.axvline(peak, color='red')
    plt.xlim((t_start, t_end))
    plt.subplot(3, 1, 2)
    plt.title('Filtered signal')
    plt.plot(time * 1e-3, filtered)
    for peak in peaks:
        plt.axvline(peak, color='red')
    plt.axhline(0, color='black', linestyle=':')
    plt.xlim((t_start, t_end))
    plt.subplot(3, 1, 3)
    plt.title('RPM measurements')
    plt.plot(peaks, rpms, '-o')
    plt.axhline(np.mean(rpms[1:]), color='red', linestyle=':')
    plt.xlim((t_start, t_end))
    plt.xlabel("Time [s]")
    plt.tight_layout()
    plt.show()

Those values are retrieved using i2c from accelerometer (mma8453). Not sure how can I add that filter. Also the rpm is around 670-680 rpm. I take actually time from each max and I have around 45-47 ms between each detonation. The issue is that the max is not always the same of course and somehow I try to get these points.

@lucian_v You just call counter(millis(), lp_filter(new_value)) every time you get a new measurement. It doesn't matter where the new value comes from. Finding the maximum is less accurate than using the zero crossings, because in the maximum, the slope is close to zero, resulting in a larger error on the time axis.

I think most cars use a magnetic pickup next to the fly wheel to derive engine timing.  The method picked here is likely to have several problems.  For example, how to avoid picking up the shock of more than one cylinder compressing and exploding.  Or, perhaps the motor developed on is out of balance.  And a more nominal motor vibrates less making the project difficult to apply universally.
That said, using FFTs (Fast Fourier Transforms) is an alternative but fundamentally similar approach to detecting zero crossings for finding fundamental frequencies, and hence the engine's RPM.
This "FFT on an Arduino" article describes how to implement Fast Fourier Transforms on an Arduino.  It uses the FFT libraries hosted here on github.

This being "partly" school, I think you will gain some points if you walk in knowing the basics of Fast Fourier Transforms.

The approach suggested by tttapa is an excellent suggestion. But just to
give you more options, you can consider using an hysteretic crossing
detector instead of a filter. The hysteresis in a comparator consists of
having one threshold value for detecting the high → low transition, and
another, higher value, for the low → high transition. This tends to
provide good immunity against noise, as noise spikes will not be able to
trigger false transitions as long as they are smaller than the
hysteresis (i.e. the difference between the thresholds).
Here is an example function that performs this detection. If you feed it
all your data samples, it will always return false, except exactly
once per signal period.
const int LOW_THRESHOLD = 220;
const int HIGH_THRESHOLD = 300;

/* Returns true when a high threshold crossing is detected. */
void crossing_detector(int x)
{
    static enum { BELOW, ABOVE } state;
    if (state == BELOW && x >= HIGH_THRESHOLD) {
        state = ABOVE;
        return true;
    }
    if (state == ABOVE && x < LOW_THRESHOLD) {
        state = BELOW;
    }
    return false;
}

Now, it is perfectly possible to combine tttapa's filter idea with this
hysteretic crossing detector. The issue with the low pass filter is that
it is tricky to find the right time constant. If you filter too
aggressively, you may kill the signal at high RPMs. If you don't filter
enough, you may end up keeping enough noise to trigger false zero
crossings. If you use an hysteretic detector instead of a plain
zero-crossing detector, then you will be able to use less aggressive
filtering, as you will not be sensitive to the small residual noise.

how did you choose 220 and 300 values?

@lucian_v: By looking at your data. Every oscillation goes well below 220 and above 300. No noise spikes cover that range.


text:
Store and processing about 30000 values read in 30 seconds
I am reading an accelerometer using an esp32.

interval = 30000; (30 sec)
offsetx, offsety and offsetz are values calculated on another function which I am using to calibrate it.

If I do like this I get about 28000 readings ( value of i-1)
void reading_mpu(){
  Serial.println("Start reading mpu:");
  unsigned long StartTime = millis();

  int i = 0;

  while(1){
    unsigned long CurrentTime = millis();

    if (CurrentTime - StartTime < interval) {  //interval is 30000
      mpu.update();

      float total_acc = sqrt((pow((mpu.getAccX() - offsetx), 2) + pow((mpu.getAccY() - offsety), 2) + pow((mpu.getAccZ() - offsetz), 2) ));
      i++;
    }
    else if (CurrentTime - StartTime > interval) {
      Serial.println("Time end");
      Serial.println(i-1);
      break;
    }
  }
}

If I add before "i++"
Serial.println(total_acc);

I get around 4800 values so much less values , probably because of the time that serial print is take.
If I add before "i++"
file_acc.println(total_acc);

(try to store values in a txt file on spiffs) I get around 16700 values. Much more than on serial print but still less that what is in first try.
My project consists in calculate average and max of this array of values.
I also tried define an array to store them but esp32 is crashing (probably memory :) )
Any idea of how can I get those values (hopefully a number of values as close of 28000) stored and be able to calculate average and max ?
Thank you very much

calculating and printing are very different things.  accelerometers also need filtering (in your case max and average).  It's often pointless to store all the values.  for the max, just store the max so far.
for average consider only keeping something akin to a total or better yet- a low pass filtered value.  Then only print something for a very large number of values

You are partially right, but maybe I was not clear enough, except calculate average and max which can be done without storing them, I need to store them as well...

to store: allocate sufficient memory before even beginning the sampling.  do you need to store x,y,z, and magnitude or just that float total_acc magnitude?

What kind of processing, other than average and max, do you need to do with those values? Are you absolutely sure you need to store all the data? If you really have to store all that, and have not enough RAM, the only solution will be to find an MCU with more RAM.

You don't need to store values to know average and max. All you need is the total of all values, which you divide by the number of values, for the average, and the current max which you update if a sample exceeds it.

As sqrt() and pow() need some time, too, you might want to calculate the square by multiplication (probably faster than pow(..., 2)), and perhaps you don't need the sqrt() depending on the evaluation. However, check what you gain from this before using it in production code.


text:
Return mean of observations for a given sample time
new to this StackExchange site. I have an experimental setup with three inputs - two from a laser distance sensor to measure planar distance and one digital input from a set of callipers.
All sensors readings fluctuate over a small range (which is acceptable for my use case). Is it possible to have the Arduino record all inputs for a given period of time and output only the mean value for each sensor?

Just use an array. There's a tutorial on Smoothing on the Arduino site that may help.

To make life easy: https://github.com/MajenkoLibraries/Average

@Majenko That's pretty neat. Is there anything you don't have a library for?

@sempaiscuba I don't have one for making money :(

@Majenko That's a shame. I could really use one of them too. :)

https://stackoverflow.com/questions/4611599/smoothing-data-from-a-sensor?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa

I have this:
int readElSens() {
  long sum = 0;
  int n = 0;
  long start_time = millis();
  while(millis() - start_time < 400) {
    sum += analogRead(ELSENS_PIN);
    n++;
  }
  return sum / n;
}