text:
Inconsistent results when reading input looking for spike patterns
I'm writing a library that will interface with a control unit on a refrigerator compressor pump (QDZH35G). One of the features of the control unit is that it can detect what problems it's encountering and report them via a flashing LED. Operational errors will cause the LED to flash a number of times. The number of flashes depends on what kind of operational error was recorded. Each flash will last 1/4 of a second. After the actual number of flashes, there will be a delay with no flashes, so that the sequence for each error recording is repeated every 4 seconds.
My goal (as it relates to this post) is to monitor the signal from the diagnostic lead and report what error the control unit has detected. I used my oscilloscope to monitor the diagnostic port, here are some pictures of that (fault codes 1 and 4):

(more photos here)
So the signal looked simple and clean enough. But just to be sure, I wanted to make sure Arduino was seeing it as my Oscilloscope was. I hooked the diagnostic port up to my Arduino digital port 8 and analog pin A0 (I wanted to monitor both to decide what would be the best to use for this) and uploaded the following sketch:
#define DIGITAL_DIAGNOSTIC_PIN 8
#define ANALOG_DIAGNOSTIC_PIN A0

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

  Serial.println("millis,analogRead,digitalRead");
}

void loop() {
  Serial.print(millis());
  Serial.print(",");
  int currentAnalogValue = analogRead(ANALOG_DIAGNOSTIC_PIN);
  int currentDigitalValue = digitalRead(DIGITAL_DIAGNOSTIC_PIN);

  Serial.print(currentAnalogValue);
  Serial.print(",");
  // Bump binary 1 to int 1023, to make it easier to see in the logs
  Serial.print(currentDigitalValue == 0 ? 0 : 1023);

  Serial.println();
}

And oddly enough, the signal Arduino was giving back seemed to be all over the place for both the digital and analog pins. While there was some pattern visible it's a pretty big mess.
Then I used CoolTerm to monitor and export the serial data into a CSV file which I then imported into a Google Docs spreadsheet (here) to create some graphs. I captured 10+ seconds in each of the following scenarios:

No fault/control (zero blinks)
Fault #1 (1 blink then 4-second pause)
Fault #3 (3x 0.25 second blinks separated by 0.25 seconds, then 4-second pause)

Here are the screenshots of the graphs (also in the Google spreadsheet doc and imgur gallery):

Finally - The question..
Why is the data seen by Arduino seem considerably less stable than that seen by my oscilloscope? I know that when reading a signal from some sensors (pressure transducer, thermocouple, etc) you get much more accurate and consistent results by averaging the last n readings, but the diagnostic voltage port isn't really a "sensor", it's just a voltage reading.
Additionally, it's reading from a pump powered by a DC desktop power unit, which has very stable voltages (I only say this because I know the voltage affects the level of the peaks from the diagnostic port).

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

A lot of comments, but no answers posted. If the situation is resolved please post an answer. @Justin - you can answer your own question if you think you have the solution. Thanks!

Where to start?  Your O'scope photo shows about 3 vertical divisions when the fault line is 'high'. The labelling at the bottom shows '5.00V', which I'm going to assume means '5V per vertical division'.  This would mean your 'high' voltage is about 15V, much too high for the 5V max input either analog or digital input on the Mega.
So, you need something like a 3:1 voltage divider just to start with.  The 'bottom' resistor on the divider will set the output impedance driving your analog (and digital) inputs, so this needs to be reasonably low (10K or so).
Before connecting the voltage divider to the Mega, look at the voltage divider output with your O'scope to verify the 'high' voltages are <= 5V. Then, and only then, connect the voltage divider output to the Mega with the O'scope still connected.  If you see a big drop in the 'high' voltage, it means the Mega input impedance is loading down the voltage divider output, which means the voltage divider resistor values are too high - choose lower values (same ratio of course).
The specs for the Arduino Mega show a top speed of about 10,000 readings per sec, so your loop speed should be OK as long as adjacent millisec printouts are different.
I suspect you will find that the Mega analog input is loading down the signal.

The analog input of the Mega is basically a 14 pF capacitor. Not really a high load.

Yeah, that sounds right, but even 14pf can form a low-pass filter if the output impedance of the 'diagnostic lead' is high enough.  For sure something is causing a >5V signal to read like 2V.  That's why I wanted to make sure the OP kept the O'scope connected when they connected the diagnostic lead to the Arduino analog input.

The OP's data does not look like a low-pass filtered version of the expected signal. Besides, for an RC filter to have a large effect at this time scale you would need R ≥ 200 ms / 14 pF = 14 GΩ.

I think you mean 14MegOhms?   200x10-3/14x10-9 = 14x10+6.  I don't know about you, but 14MegOhm output impedance wouldn't be out of the question for a 'diagnostic lead'.  I'm not sure how you came to the conclusion that the reported values "don't look like a low-pass output" - maybe you could elaborate on that?

I mean 14 GΩ: a picofarad is 1e-12 F. Even 14 MΩ would be unusually high for a diagnostic port. Keep in mind that a typical scope has an input impedance of 1 MΩ. Re “don't look like a low-pass output“: here is what a square wave through an RC filter looks like. Nothing like the collection of spikes in the OP's data.

Yep - you are right - I misread the link showing the prefix meanings.  However, when I looked a the OP's graph, I came to the conclusion that the 'spikes' are the instantaneous readings from the A/D converter.  If so, then drawing a line from 'spike' to 'spike' would give the analog equivalent


text:
Connecting pressure sensor to Arduino to collect pressure and time data
I'm trying to build a pressure data logger using an Arduino and Mindman MP47P-03-F1 (https://www.mindman.com.tw/proimages/pdf/E_MP47_S.pdf) pressure sensor, the sensor is connected to an outer 12-24 VDC power source.
I've connected the analog wire to the the Arduino's A0 and added another wire from the GND to the sensor. I get a stable voltage (~1V) reading but the pressure is wrong and it doesn't respond to pressure changes.
Can someone tell me what I'm doing wrong?
this is the sample code:
const int analogPin = A0;
const float slope = -0.1;
const float intercept = 0.6;
const unsigned long startTime = millis();

void setup() {
  Serial.begin(9600);
  Serial.println("Time (s)\t\tPressure (MPa)");
}

void loop() {
  unsigned long elapsedTime = millis() - startTime;
  int sensorValue = analogRead(analogPin);
  float voltage = sensorValue * (5.0 / 1023.0);
  float pressure = slope * (voltage - intercept);

  Serial.println(sensorValue);
  Serial.print(elapsedTime / 1000.0);
  Serial.print("\t\t");
  Serial.println(pressure);

  delay(1000);
}

edit: i've changed the code to as suggested by some on the arduino forum:
const int sensorPin = A0;
const int offset = 201; // zero pressure adjust
const int fullScale = 1023; // max pressure adjust
float sensorType = 1000.0; // kPa
float pressure; // final pressure
const unsigned long startTime = millis();

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

void loop() {
  unsigned long elapsedTime = millis() - startTime;
  pressure = (analogRead(sensorPin) - offset) * sensorType / (fullScale - offset);

  Serial.print(analogRead(sensorPin));
  Serial.print("\t\t");
  Serial.print(elapsedTime / 1000.0);
  Serial.print("\t\t");
  Serial.println(pressure, 4);
  delay(1000);
}

the pressure is 0 but i keep getting jumps in the readings of the pressure when no pressure is applied. here is the picture of the wiring.

the program should be responding to pressure changes ... disconnect the arduino and check the sensor output with a voltmeter

@NickS. - That's a nice comment your wrote! The "Also, your equation is wrong..." part is brilliant, and would be part of a great answer. Perhaps you are not aware that answers in the comments on Arduino SE are frowned upon.

@NickS. - Why not put your "I just gave pointers" part of your comment into an answer? I am certain that the long term members of this stack will agree that  answers and partial answers are not welcome in the question's comment section :) NG

As jsotola mentions in the comments, you should definitely verify that the pressure sensor works with a multimeter first, preferably on a bench that has a variable power supply from which you can power your sensor. Make sure that you can measure the pressure you are putting into the sensor by some other means; a simple pressure gauge could work.
Then, you'll have to correct your equation - it is flipped, since the graphs show the pressure as an input and an output as a voltage, but when you're converting a voltage to a pressure, the process is flipped, so we calculate the slope as follows: take the pressure range (output) and divide it by the voltage range (input) -> 1.1 MPA / 4.4 V = 0.25 V_in. Now, we know that at 0.6V, the pressure output is -0.1 MPA, so we set up a linear equation of the form that you did -> y = mx + b and plug in the values: -0.1 MPA = 0.25 MPA/V * (0.6V) + b. If you solve for b, you'll get -0.25.
Therefore, pressure = 0.25X - 0.25 should be the equation that you check the pressure you're putting into the sensor against the voltage that you are measuring.
If you discover that with this equation you're measuring the right pressure, but once you re-implement your Arduino program you still have no luck, I'd check that the grounds are wired together correctly - it's crucial to have all of the involved grounds at the same 'level'. As a bonus, depending on the Arduino, you could utilize the chip's differential ADC channels, but as far I know, you'd have to write directly to registers to do that.

from where i need to measure the sensor voltage? it has a LCD screen where i can see the pressure changes but the Arduino doesn't see these changes, from 0MPa to 0.008MPa for example

also, from time to time i get voltage spikes that change the pressure reading

You'd measure the voltage from the white wire to the blue wire (from analog out to DC-). Do you actually have a bigger pressure source than that minuscule (probably ambient) value? It's so small, it's less than 1% of the full scale, which is below reasonable SNR based on the +/- 2.5% FS value - it might as well be noise. Do you have a spare bicycle hand pump that you can attach the correct fitting to and try it out? Maybe with a pass-thru gauge? Either way, 1V sounds reasonable for ~0 MPA, so if you aren't applying any pressure that's bigger than ambient that looks ok. What kind of spikes?

How large are the spikes? Do you have a cap on the input to the PS (I only see a hose)? Did you try measuring the output without the Arduino in place, preferably with  a scope? Do you have a second PS you can test (for the future - you should get two next time, so you don't have to try and figure out if you're troubleshooting your connection or the sensor itself)? Did you decouple the power supply from the PS? Why do you need an extra probe to connect the analog output wire to the Arduino itself? Again, ideally you'd have a known non-zero pressure source which you can apply to the PS.

source: Stack Exchange

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

sort: votes


text:
Why does my Arduino stop uploading to the Thingspeak server after several hours?
I'm using a Maduino Zero 4G SIM7600 device to upload data from 28 sensors to a ThingSpeak IoT server. It works well for a few hours, then stops uploading the data. Sometimes it starts again after an inconsistent amount of time (an hour or two), sometimes it doesn't.
I can confirm that it's only the SIM7600 and/or Thingspeak functions that are failing, as the serial monitor demonstrates the other I2C related operations on the Arduino board are still working fine even when the server uploads fail.
Here's the relevant part of the code:
void setup(){
    SerialUSB.begin(115200);
    SerialUSB.println("Serial initialized");
    Serial1.begin(115200);
    Wire.begin();

    pinMode(LTE_PWRKEY_PIN, OUTPUT);
    digitalWrite(LTE_RESET_PIN, LOW);
    delay(100);
    digitalWrite(LTE_PWRKEY_PIN, HIGH);
    delay(2000);
    digitalWrite(LTE_PWRKEY_PIN, LOW);

    pinMode(LTE_FLIGHT_PIN, OUTPUT);
    digitalWrite(LTE_FLIGHT_PIN, LOW);//Normal Mode

    delay(5000);

    sendData("AT+CCID", 3000, DEBUG);
    sendData("AT+CREG?", 3000, DEBUG);
    sendData("AT+CGATT=1", 1000, DEBUG);
    sendData("AT+CGACT=1,1", 1000, DEBUG);
    sendData("AT+CGDCONT=1,\"IP\",\"sp.mb.com\"", 1000, DEBUG);

    delay(5000);
}

void loop(){
  getData();

  //Sensors 0-6
  http_str = "AT+HTTPPARA=\"URL\",\"https://api.thingspeak.com/update?api_key=" + Apikey1 + "&field1=" + (String)hallData[0] + "&field2=" + (String)hallData[1] + "&field3=" + (String)hallData[2] + "&field4=" + (String)hallData[3] + "&field5=" + (String)hallData[4] + "&field6=" + (String)hallData[5] + "&field7=" + (String)hallData[6] + "\"\r\n";
  SerialUSB.print("Sent to Channel 1: ");
  SerialUSB.println(http_str);
  sendData("AT+HTTPINIT\r\n", 2000, DEBUG);
  sendData(http_str, 2000, DEBUG);
  sendData("AT+HTTPACTION=1\r\n", 3000, DEBUG);
  sendData("AT+HTTPTERM\r\n", 3000, DEBUG);

  //Sensors 7-13
  http_str = "AT+HTTPPARA=\"URL\",\"https://api.thingspeak.com/update?api_key=" + Apikey2 + "&field1=" + (String)hallData[7] + "&field2=" + (String)hallData[8] + "&field3=" + (String)hallData[9] + "&field4=" + (String)hallData[10] + "&field5=" + (String)hallData[11] + "&field6=" + (String)hallData[12] + "&field7=" + (String)hallData[13] + "\"\r\n";
  SerialUSB.print("Sent to Channel 2: ");
  SerialUSB.println(http_str);
  sendData("AT+HTTPINIT\r\n", 2000, DEBUG);
  sendData(http_str, 2000, DEBUG);
  sendData("AT+HTTPACTION=1\r\n", 3000, DEBUG);
  sendData("AT+HTTPTERM\r\n", 3000, DEBUG);

  //Sensors 14-20
  http_str = "AT+HTTPPARA=\"URL\",\"https://api.thingspeak.com/update?api_key=" + Apikey3 + "&field1=" + (String)hallData[14] + "&field2=" + (String)hallData[15] + "&field3=" + (String)hallData[16] + "&field4=" + (String)hallData[17] + "&field5=" + (String)hallData[18] + "&field6=" + (String)hallData[19] + "&field7=" + (String)hallData[20] + "\"\r\n";
  SerialUSB.print("Sent to Channel 3: ");
  SerialUSB.println(http_str);
  sendData("AT+HTTPINIT\r\n", 2000, DEBUG);
  sendData(http_str, 2000, DEBUG);
  sendData("AT+HTTPACTION=1\r\n", 3000, DEBUG);
  sendData("AT+HTTPTERM\r\n", 3000, DEBUG);

  //Sensors 21-27
  http_str = "AT+HTTPPARA=\"URL\",\"https://api.thingspeak.com/update?api_key=" + Apikey4 + "&field1=" + (String)hallData[21] + "&field2=" + (String)hallData[22] + "&field3=" + (String)hallData[23] + "&field4=" + (String)hallData[24] + "&field5=" + (String)hallData[25] + "&field6=" + (String)hallData[26] + "&field7=" + (String)hallData[27] + "\"\r\n";
  SerialUSB.print("Sent to Channel 4: ");
  SerialUSB.println(http_str);
  sendData("AT+HTTPINIT\r\n", 2000, DEBUG);
  sendData(http_str, 2000, DEBUG);
  sendData("AT+HTTPACTION=1\r\n", 3000, DEBUG);
  sendData("AT+HTTPTERM\r\n", 3000, DEBUG);
}

String sendData(String command, const int timeout, boolean debug){
  String response = "";
  Serial1.println(command);

  long int time = millis();
  while ( (time + timeout) > millis()){
    while (Serial1.available()){
      char c = Serial1.read();
      response += c;
    }
  }
  if (debug){
    SerialUSB.print(response);
  }
  return response;
}

All SIM7600 related operations are taken directly from the Makerfabs examples, found on this page. One thing of note is that in their example, they use the command AT+HTTPACTION=0, which, according to this page, means READ. This does work but it sometimes returns ERROR instead of OK. I've changed it to AT+HTTPACTION=1, which means POST, which seems to work a bit better - at least there are no ERROR messages. But the same problem still persists.
UPDATE #1: The ERROR messages sometimes return even with the AT+HTTPACTION=1 adjustment. Something I've noticed is that generating new API keys for each of the Thingspeak pages (there are 4 in total, 7 sensors per page) causes it to work for a while when it didn't before. No explanation for why that is.
Any advice would be greatly appreciated.
Hardware wise, I'm powering this from an AC adapter through a DC-DC 5V converter. I'm also using a 3.7 battery for backup power.

If you are using free variant, doesn't it have some daily limit of messages? Maybe you are hitting that

Good question - I am using the free version but I haven't come across a daily limitation of messages. Everything appears to be calculated yearly (they give a "daily maximum" but it appears to be just a recommendation to optimize the number of messages you can send per year).

From the ThingSpeak License Options page:

ThingSpeak is available as a free service for non-commercial small projects (<3 million messages/year or ~8,200 messages/day).

Could you be hitting that limit?

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


text:
SoftwareSerial and HardwareSerial lost data
I need two Serial ports. One port is some sort of modified Software Serial, where I have to be listening constantly and send responses immediately if the port requires it. There is no XY problem hidden here, promise.
On the other hand I have a device on the hardware serial.
If I'm listening on the Software Serial, sometimes I lose data on the hardware serial. How can this be? Isn't the Hardware Serial "hardware", meaning independent of the CPU?

Software Serial turns off interrupts. Depending on the baud rate, they may be off for so long that the interrupt generated by the hardware serial is not serviced in time. Depending on the chip, the hardware serial may only have a buffer of a couple of bytes. Turn off interrupts long enough and one will be lost.
The external interrupts are higher priority than the UART interrupts, which won't help. I am referring to the Uno here.
It would help in future if you provide code to reproduce the situation, and also state what Arduino you are using. The lack of information about that in the question would be why you were downvoted.


text:
HardwareSerial and SoftwareSerial not compatible
The HardwareSerial requires to run an interrupt to store received bytes in the buffer. Look at this file from the Arduino Core.
If I am now constantly receiving and writing on the Software Serial, the data from the HardwareSerial cannot be buffered, since external interrupts are higher priority.
In my application, I need to constantly listen to the SoftwareSerial and respond immediately to incoming data (actually inside the receive interrupt of the SoftwareSerial, so its modified), so the SoftwareSerial has higher priority. But when I do this, I lose data on the HardwareSerial.
Is there any way to circumvent this limitation, without disabling any interrupts or getting a chip with more UART ports?
EDIT: the actual interrupt vector is here
EDIT2: This is question is not answered by the answers in my previous question. It is clearly a fact that HardwareSerial needs its receive interrupt to store data in a buffer. My question now is how I can still use the SoftwareSerial while it is constantly receiving.

Does this answer your question? SoftwareSerial and HardwareSerial lost data

This was my question which has clearly been misunderstood. People don't understand that HardwareSerial is using a receive interrupt to store bytes in a buffer. My question is how to use SoftwareSerial together with HardwareSerial, if SoftwareSerial is constantly receiving.

Duplicate of https://arduino.stackexchange.com/questions/93772/softwareserial-and-hardwareserial-lost-data

This is question is not answered by the answers in my previous question ... look again ... that question  does not have any answers

@jsotola, nervertheless, it is still the same question.

You have asked the same question twice, here and here. It is hard to know which one to close because they both have answers. Please don't do that. Don't re-ask the question just because you don't get an answer to the first one.

If you are sending something in SoftwareSerial ISR handler that means ISRs are disabled and you are blocking other ISRs being called (if needed).
If you're using some crazy slow baudrate like 9600 then it means over 1 millisecond per character sent and during that time you might be missing other interrupts calls (millis, HW serials). If there is only one character, it's not problem, it'll be handled after interrupts are enabled again, but if there will be second or more character, previous are lost, as the've never been readed out from the UDR register (that should set flag for buffer overrun or how it's called).
If your Hw serial has some nice speed like 115200, you can lose up to 12 characters during sending single characted on software serial with speed 9600
The cli() in software serial library but as you wrote it's called from ISR handler and the ISRs are disabled anyway already during whole ISR handler

"If your Hw serial has some nice speed like 115200, you can loose up to 12 characters during sending single characted on software serial with speed 9600"
This is exactly the situation I'm in, which is unfortunately required.
Thanks for your Info. I'm currently looking into AltSoftSerial, which doesn't block as much.

Go for something like Nano Every (note that Every), that has several USARTs and one connected to the USB is different from second connected to pins 0 and 1

Another solution would probably be to implement some sort of hardware flowcontrol, since the device on the HW serial supports it. This would require a modification to the receive isr of the HW serial AND a new PCB. We'll see

@LiessJemai Another solution is to swap the interfaces. Use the software serial with the higher speed (it can handle up to 115200 bits per second) and the hardware serial with the lower speed. Or, if you can choose the speeds, adjust them.


text:
ESP8266 seems to be killing a while loop
When i was testing out a program I found a strange behavior of esp8266
It seems to get out of a while loop even when there's no option of getting out on code
I don't know if these are related but here's the code
(the program is just two different visual patterns of leds toggled by a button)
#define led1 D0
#define led2 D1
#define led3 D2
#define led4 D3
#define button D7

unsigned long pressedButton;
bool change = 0;
unsigned long previousTime;
unsigned int difference;

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  pinMode(button, INPUT_PULLUP);
}

void loop(){
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);         //when the while loop change, this should delete interference
  digitalWrite(led4, LOW);
  previousTime = millis();

  while (!change){                                      //default visual pattern of leds
    difference = millis()-previousTime;

    if (!digitalRead(led1) && difference>=200){
      digitalWrite(led1, HIGH);
    }
    if (!digitalRead(led2) && difference>=400){
      digitalWrite(led2, HIGH);
    }
    if (!digitalRead(led3) && difference>=600){
      digitalWrite(led3, HIGH);
    }
    if (!digitalRead(led4) && difference>=800){         //after here, all the leds should be HIGH
      digitalWrite(led4, HIGH);
    }
    if (digitalRead(led4) && difference>=1000){
      digitalWrite(led4, LOW);
    }
    if (digitalRead(led3) && difference>=1200){
      digitalWrite(led3, LOW);
    }
    if (digitalRead(led2) && difference>=1400){
      digitalWrite(led2, LOW);
    }
    if (digitalRead(led1) && difference>=1600){        //after here, all the leds should be LOW
      digitalWrite(led1, LOW);
      previousTime = millis();
    }

    if (!digitalRead(button) && millis()-pressedButton>200){       //check if button was pressed to break while loop
      pressedButton = millis();
      break;
    }
  }

  while (change){                                         //alternative of visual pattern of leds
    difference = millis()-previousTime;

    if (!digitalRead(led1) && difference>=200){
      digitalWrite(led1, HIGH);
      digitalWrite(led4, HIGH);
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
    }
    if (digitalRead(led1) && difference>=400){
      digitalWrite(led1, LOW);
      digitalWrite(led4, LOW);
      digitalWrite(led2, HIGH);
      digitalWrite(led3, HIGH);
      previousTime = millis();
    }

    //if (!digitalRead(button) && millis()-pressedButton>=200){     //check if button was pressed to break while loop
    //  pressedButton = millis();
    //  break;
    //}
  }

  change = !change;         //after a break in one of the while loops, this will make the program go to the other while loop
 }

Is there something wrong with the code?
Here is a link of a video of the behavior for more details
https://drive.google.com/file/d/1822MHNGQn-A2-HGHhRXz_8xydz-wM4Ha/view?usp=sharing

You can't trap an ESP in a while loop like that.  There are things it needs to get back to main and do between loops.  Instead, let the loop function be your loop.  Make the while statements if statements and where you have break, that's where you change the change variable.  Put the code at the top in an if statement that checks to see if change has changed.

@Delta_G Please make an answer and not a comment.

Concerning your LED issue: Even if it happens with your current sketch, please post a separate question for it. When you do, please add a schematic of your circuit.

@NickGammon.  Done.

@the busybee all right I didn't know the problems were not related. Like that? https://arduino.stackexchange.com/questions/93807/led-doesnt-completely-turn-off-with-digitalwriteled-low

Exactly. And you have already an answer.

You can't trap an ESP in a while loop like that. There are things it needs to get back to main and do between loops. Instead, let the loop function be your loop. Make the while statements if statements and where you have break, that's where you change the change variable. Put the code at the top in an if statement that checks to see if change has changed.
#define led1 D0
#define led2 D1
#define led3 D2
#define led4 D3
#define button D7

unsigned long pressedButton;
bool change = 0;
bool oldChange = 1;
unsigned long previousTime;
unsigned int difference;

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  pinMode(button, INPUT_PULLUP);
}

void loop() {
  if (change != oldChange) {
    digitalWrite(led1, LOW);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);  //when the while loop change, this should delete interference
    digitalWrite(led4, LOW);
    previousTime = millis();
    oldChange = change;
  }

  if (!change) {  //default visual pattern of leds
    difference = millis() - previousTime;

    if (!digitalRead(led1) && difference >= 200) {
      digitalWrite(led1, HIGH);
    }
    if (!digitalRead(led2) && difference >= 400) {
      digitalWrite(led2, HIGH);
    }
    if (!digitalRead(led3) && difference >= 600) {
      digitalWrite(led3, HIGH);
    }
    if (!digitalRead(led4) && difference >= 800) {  //after here, all the leds should be HIGH
      digitalWrite(led4, HIGH);
    }
    if (digitalRead(led4) && difference >= 1000) {
      digitalWrite(led4, LOW);
    }
    if (digitalRead(led3) && difference >= 1200) {
      digitalWrite(led3, LOW);
    }
    if (digitalRead(led2) && difference >= 1400) {
      digitalWrite(led2, LOW);
    }
    if (digitalRead(led1) && difference >= 1600) {  //after here, all the leds should be LOW
      digitalWrite(led1, LOW);
      previousTime = millis();
    }

    if (!digitalRead(button) && millis() - pressedButton > 200) {  //check if button was pressed to break while loop
      pressedButton = millis();
      change = true;
    }
  }

  if (change) {  //alternative of visual pattern of leds
    difference = millis() - previousTime;

    if (!digitalRead(led1) && difference >= 200) {
      digitalWrite(led1, HIGH);
      digitalWrite(led4, HIGH);
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
    }
    if (digitalRead(led1) && difference >= 400) {
      digitalWrite(led1, LOW);
      digitalWrite(led4, LOW);
      digitalWrite(led2, HIGH);
      digitalWrite(led3, HIGH);
      previousTime = millis();
    }
  }

  change = false
}

Thank you! That resolved the unwanted break on the second pattern. But what is the reason for the while loop not working inside another loop?

The loop function is called repeatedly from main().  There are other things in main() that have to happen in between calls to loop.  You can't trap execution inside loop.  You have to let loop exit once in a while or call yield or delay(0).  In your case, you didn't need a while loop since loop is already a loop.


text:
WiFiNINA Reseting Arduino Nano IoT 33 When Powered Externally
This is puzzling me: if I power my Arduino IoT 33 Board from USB, everything runs smoothly. Now, if I power it with 5V on Vin, the board resets as soon as I call WiFiNINA's WiFi.begin(ssid, pass).
Of course, power is my first suspect as I'd imagine that wifi connections draw lots of current. But what's intriguing is that the main power source is a 5V (10A) DC source that is powered by a 24V (20A) AC/DC converter. The Arduino connects to 3 I2C components (an  128x128 monochrome OLED, an INA219, and an Adafruit PWM multiplexer). There are 2 servos connected to the multiplexer. Here's the wiring diagram:

With this setup, INA219 reads 4.8V and about 100mA when both servos are moving (85mA in rest).
An important remark: the PCA9685 multiplexer has a separate V+ just to drive the servos. I was assuming that my power source is enough to drive all of this, so I didn't bother supplying a separate power source for it (btw, there's an additional 680uF capacitor on soldered the board). Just for debugging purposes I did try a separate power source for it, but the problem persists.
Here some data sheets: 24V power source, DC-DC Converter (D24-S5), OLED, PWM Multiplexer, INA219.
Finally, here's the setup code:
void setup() {
  delay(250);
  Wire.begin();

  // Check for the screen module
  if (!display.begin(SCREEN_ADDRESS, true)) {
    // don't continue
    while (true)
      ;
  }

  // Check for the PWM module
  pwm.begin();
  pwm.setOscillatorFrequency(27000000);
  pwm.setPWMFreq(50);
  // Setting servos to midpoint
  pwm.setPWM(0, 0, SERVO_START);
  pwm.setPWM(1, 0, SERVO_START);
  display_line_2 = (String) "PWM... Ok";
  printDisplay(1);
  delay(10);

  // Check for the INA219 module
  if (!ina219.begin()) {
    display_line_3 = (String) "INA219... Fail";
    printDisplay(1);
    // don't continue
    while (true)
      ;
  }

  // Check for the internal LM module
  if (!IMU.begin()) {
    display_line_4 = (String) "IMU... Failed";
    printDisplay(1);
    // don't continue
    while (true)
      ;
  }

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    display_line_5 = (String) "Wifi... Failed";
    printDisplay(1);
    // don't continue
    while (true)
      ;
  } else {
      while (status != WL_CONNECTED) {
      // Connect to WPA/WPA2 network:
      status = WiFi.begin(ssid, pass);
      // wait 10 seconds for connection:
      delay(5000);
    }
  }
}

As I said, if I comment the line status = WiFi.begin(ssid, pass), everything works just fine. So my question is: where the problem likely is? What would be the next step to troubleshoot it?

I'd try to move that 1000uF to Vin instead (or maybe even on 3V3 - but jumper must be shorted to be available on corresponding pin). If it doesn't help, use 9V/12V Vin or skip the INA219. Check Vin and 3V3 rails with the oscilloscope (MPM3610 has operation voltages between 4.5-21V).

Also DC-DC mentions minimal output current 0.5A, and who knows what is happening when you are taking less.

Interesting: moving the 1000uF to INA219's Vin didn't change the end result, but immediately gave me a less noisy power bus (I know it because the OLED doesn't flicker anymore), meaning that my wiring is indeed screwed up. I just bought a cheap oscilloscope and it should arrive tomorrow. But considering it's my first oscilloscope, I reckon I'll need some training.
With regards to the minimum of 0.5A, that's not a problem as there are other 5V devices being powered by it and it currently measures 2A.
Thanks!


text:
Stack Mega Shield
I need to support 18 push buttons and 66 IR sensors on my Arduino Mega (model railway). I have a Mega Sensor Shield, but won't have enough pins for all the sensors. Can I get a second sensor shield and nest it some way?
https://www.aliexpress.com/item/1005004554959620.html?spm=a2g0o.order_list.order_list_main.31.1cda18022wJnOM

Can you give a link to the shield in question please? There is almost certainly more than one.

https://www.aliexpress.com/item/1005004554959620.html?spm=a2g0o.order_list.order_list_main.31.1cda18022wJnOM

No, Nick is talking about a schematic @PaulN.  At the very least some sort of specifications.  Honestly, if I were going this route, most model railway setups I have seen are room sized.  Like way over 10 feet from end to end.  With runs like that, you will likely have problems keeping noise out of longer wire runs to/from sensor. I would use multiple Arduinos w/shorter runs.  And pick communication protocols more immune to noise to mitigate any problems.

If I see it right on aliexpress the entire shield essentially consists only of wiring individual pins together, along with power, to form groups of (pin, VCC, GND) couples for each pin. There is no logic, no electronics, nothing, just connectors.
(And reset and LED)

Hi st2000 - sorry, thought Tom was asking what shield I was using. For complete transparency, I already have the Mega set up with the board, and I have 9 AdaFruit PWM Servo boards which drive 23 servos for turnouts, 106 LEDs for the mimic panel indicating turnout routes and block occupancy. The push buttons for the mimic panel are in the sensor shield. Although I can chain more servo boards on, the pins are output pins only, not input, eg, I can't read an IR sensor on them. Therefore I need them on the shield. But I don't have enough pins on the original shield to add the 66 IR sensors.

I may be interpreting your question wrong, but it seems that you're asking if you can somehow get more input pins for your sensor (general-purpose input/output), with which your sensor shield will not help with that. If you want to get more inputs for your sensors, you'll need to use shift registers.
Link to understanding how to add more digital GPIO pins

Thank you - yes that sounds about right. I will get some. Assuming as I have a number of spare GPIO ports on my shield, I can put these to multiple shift registers, if each register supports 8 addresses, I can put 8 chips on a breadboard.

For a model railway, this may not work as well as you are expecting. Sending 66 sensors values and 18 push-buttons along long cable lengths, as may be expected for a model railway, could introduce noise which would give bogus readings. The noise in long, adjacent, cables could be from one cable inducing a voltage in its neighbour, or simply from the railway operations themselves.
It may be better to use something like RS485 which is a balanced protocol. That is, of the two data wires connecting nodes, one is positive and one is negative simultaneously, for a signal to be considered genuine. Noise would tend to influence the cables in the same direction (eg. both positive) and would thus be discarded.
As described in the Wikipedia article, RS485 is used in aircraft for reliability. The wiring is minimal: two wires for data, plus an earth wire. You would also need 5V power available at the nodes.
What I would suggest here is a series of nodes, spread around your railway layout. Each node could be an inexpensive Atmeg328P processor (around $3 on eBay) with a couple of supporting resistors and capacitors. You would use 3 pins for the RS485 (transmit, receive and enable) which would leave 17 inputs for your sensors and switches per node. Thus, around 5 nodes.
You would keep the cabling for the sensors running to each node as short as possible, to reduce noise. Maybe use shielded cable.
I wrote an RS485 non-blocking library - available on Github.
There are some explanations about using it on my website most of which is also on the Github page.
Basically what you would do is give each node an address (stored in EEPROM) and then have a master query each node in turn for the values on its sensors or switches. The node would reply, and then the master could move onto the next one.

I realise this isn't directly answering the question about the Mega shield, but I am trying to answer the underlying problem of how to connect 84 sensors and switches to one Arduino reliably.

Amazing Nick - thank you for the comprehensive write up. I have heard about RS485, and will now look in to this much more. Appreciate your assistance.


text:
sim800l gsm module response isn't completed
I am using the sim800l gsm module with nodemcu esp8266 and comunicating with it using AT+ commands. The module is working correctly but I am trying to use the command AT+CLCC to get all the current calls' state but it responds with only the first call information and a part of the second call.
This is the response while there are two active calls
15:37:19.156 -> AT+CLCC
15:37:19.156 -> +CLCC: 1,0,1,0,0,"+0123456789",145,"name"
15:37:19.156 ->
15:37:19.156 -> +CLCC: 2,

I think it is the Serial buffer's problem because the size of the serial buffer is 64 bytes and the response is more than that but I don't know how to handle that
I hope someone can help.
EDIT: this is the code i am using
#include <SoftwareSerial.h>
#include <cstring>

#include <Arduino.h>

#define simTX D3
#define simRX D4

SoftwareSerial sim800l(simRX, simTX);  //RX, TX

void setup() {

  Serial.begin(115200);  //Begin serial communication with Arduino and Arduino IDE (Serial Monitor)

  sim800l.begin(115200);  //Begin serial communication with Arduino and SIM800L

}

void loop() {

  updateSerial();

}

//Start
// this method takes input from the serial monitor the pass it to sim800l via serial communication
void updateSerial() {
  delay(500);
  while (Serial.available()) {
    sim800l.write(Serial.read());  //Forward what Serial received to Software Serial Port
  }
  while (sim800l.available()) {
    Serial.write(sim800l.read());  //Forward what Software Serial received to Serial Port
  }
}
//End

Could you please share your code? Buffer size shouldn't be an issue depending on how you're fetching the response.

@NickS. i added it in the question :)

get rid of delay() ... change while to if ... see what happens

@jsotola i removed the delay() and changed the while to if as you mentioned and that was the result
`22:54:55.552 -> AT+CLCC
22:54:55.552 -> +CLCC: 1,0,0,0,1,"+0123456789",145,"name"
22:54:55.552 ->
22:54:55.552 -> +CLCC:`
still the same problem

Just for someone in the future who is having the same issue.
the problem was because of the boadrate 115200 is pretty fast for a software serial implementation so i just changed it to 9600
 sim800l.begin(9600);  //Begin serial communication with Arduino and SIM800L

good luck from the past :)


text:
Connecting Arduino to a cheap Graphics Card for VGA Output
I understand that the Arduino is generally not fast or powerful enough to generate a suitable VGA/HDMI signal with higher resolution.
However, I've noticed that there are inexpensive PC graphics cards available that can easily maintain a stable screen on a monitor.

Back in the DOS era, it was relatively straightforward to write a short program that could output text to CGA/EGA/VGA cards using BIOS calls and a few assembly instructions. The BIOS itself surely was not overly complex or large.

So my idea is to take an Arduino, use shift registers like the 74HC595 to create a sufficiently long bus, and connect it to a cheap, obsolete GPU (e.g., an NVIDIA card from a discarded PC) along with a regular monitor. I would then write Arduino code to emulate a BIOS call, such as 10h, which would shift out the "bus status" to the 74HC595s, send the signal to the GPU, and continue this process until the characters are transferred to the GPU.
The GPU can easily generate VGA/HDMI signals and work with any modern monitor. It also has enough memory to support screen resolutions like 80x25, 80x50, or even 132x60 for text-based displays. In fact, it might even be possible to run at full graphical resolutions such as 640x480 or even 2560x1440, with the Arduino slowly sending graphic primitives to display.
While the GPU's performance would be severely degraded, it would still be a better alternative than throwing it away.

My question is whether it is possible or even feasible to connect a GPU to such a slow source. If it is, I would like to know if there are any readily available and understandable documentation or even someone who has already attempted this approach.
(Or should I post it somwere else? Where?)

There were gameduinos, vgaduinos and similar but i don't think it was that popular. Currently I don't even have a monitor with VGA. Rapsberry pi with hdmi is much better. But surely you can try some old bus, but they might need all the voltages you'll never see anymore (-5, -12)

I think you will have a very hard time implementing a functional PCI(e) bus electrically and timing-wise on an Arduino.

This is the kind of project where things are going to be hard to do and the result hardly worth the effort.  But even if you completely fail you'll learn a ton in the process.  So I say go for it if you have the time.

@StarCat I had seen some projects, where processors like 6502 were driven by external clock so slow, that arduino was able emulate RAM/ROM for them. (Basically the CPU was stopped until new data was generated). So I was hoping, that some Grasphic Cards could also run in such slow/static mode. But I could not found the lower limits (how slow it can run) - all I found was upper limits, how fast it can run.

You might have more luck with interfacing an old ISA VGA card to an Arduino/AVR, but I would not use the x86 emulation as described in this project and just program the VGA registers directly.

Wow, thank you, I was looking for something like that, but had no success. (And yes, my idea was to set it directly from my code, if possible)

This doesn't answer your question about the cheap graphics card, but see https://forum.arduino.cc/t/toorums-quest-ii-atmega328p-based-retro-video-game-with-256-color-graphics/192920 for where Petri Häkkinen did an arcade-style game with an Atmega328 and the AD725 chip for generating the VGA signal.


text:
TMC2208 Stepper Motor does not change its RPM linearly
This is my first project working with stepper motors, so I may have a bit of a shaky understanding of the electronic side of the project. I'm trying to create a simple device with 4 buttons connected to a stepper motor driver/NEMA 17 motor, with the ability to increase/decrease RPM, switch motor spin direction, and run the motor with the button being held down. (LCD screen included for output as well)
I'm noticing that when changing the RPM on my motor, i.e. from 3.2 to 3.1 to 3.0, the speed of the motor is really slow, then when set to 3.0, suddenly increases a lot, but goes down when setting the RPM back down to 2.8 or so. This occurs multiple times along different intervals of RPMs that I have tested as well.
I think that there may be an issue with the method with which I am calculating the pulse delay given the RPM in my function setRPM() at the end of my code or with the way that I am micro-stepping, which I am doing because I need extremely precise movement.
Included below is the code that I used to run with my TMC2208 driver. (Sorry if it is rather long, but I included comments to document my thought process when programming the Arduino.)
Included list of RPMs and pulse delays

rpm
pulse_delay (us)

1
37500 (too fast)

2
18750 (too fast)

2.25
16666.6667 (works)

2.5
15000  (works)

3
12500  (works)

5
7500   (works)

10
3759   (works)

// Stepper motor run code with TMC2208 driver and LCD code
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Stepper.h>
// Define Pins for Step Motor Driver
#define stepPin 7  // define pin for step
#define dirPin 8   // define pin for direction
#define enPin 9    // define pin for enable ^^ Do I need this?

// Define Buttons for Speed and Direction
#define buttGo 10      // define pin for button input
#define buttSwitch 11  // define pin for button input
#define incSpeed 12    // define button for increasing speed
#define decSpeed 13    // define button for decreeasing speed

// Define LCD pinout
const int en = 2, rw = 1, rs = 0, d4 = 4, d5 = 5, d6 = 6, d7 = 7, bl = 3;  // Adapter Pinout
const int i2c_addr = 0x27;                                                 // Adapter pinout
LiquidCrystal_I2C lcd(i2c_addr, en, rw, rs, d4, d5, d6, d7, bl, POSITIVE);

/* Formulas for determining RPM
Assuming one step per pulse, delay is: wait = (μs/min)*(1/rpm)*(1/pulses per revolution) - overhead
Overhead = extra time it takes to run digitalWrite twice and loop
RPM = (steps per second)/(steps per revolution) * (60 seconds/minute)
step angle = 1.8 degrees ; 200 steps per revolution ; .005 revolutions per step
Solving for Steps Per Second: SPS = (RPM)/((REV_P_STEP)*(60 sec/min))

According to Notes:
  C0 = 15 * M_PI ; Motor X Circumference
  XSPR = 1 * (200 * 11) ; Motor X Steps per Rotation
  dVx = dS * (XSPR/C0) ; Desired X-Axis time from mm/s to x-axis steps/sec (dS represents desired x-axis speed)
  Assuming we use a button/knob, each increment/decrement would change the mm/s by 0.1
  So, to get the necessary pulse delay, increment/decrement by:
    dVx = 0.1 * (1 * (200 * 11))/(15*M_PI)

  Example: If we have an initial target rpm of 10, that gives us a dS of 10
  As such, dVx which is our speed in steps will be 10 * (1 * (200 * 11)) / (15 * M_PI)
  All of these variables are set globally
  wait = (microsecondsPminute)*(1/RPM)*(1/pulsesPrevolution) - overhead
  rpm / 60 = rps
  60 / rpm = spr
  (60 / rpm)/360 = spd
  ((60 / rpm)/360) * 1.8 = sps
***
Frequency = (RPM)/((Resolution/360)*60)
Resolution =  360/(Steps/Revolution)
For us, Resolution = 360/(200); so Resolution = 1.8**
Frequency = (RPM)/(0.005 * 60) = RPM/(0.3)
*
T_inc = incremental torque produced with each microstep
T_hfs = holding torque (full-step operation)
SDR = step division ratio (number of microsteps per full step)

T_inc = T_hfs * sin(90/SDR)
T_inc = 0.14 * sin(90/256)
T_inc = 0.00085902385
*/
float resolution = 1.8;
float rpm = 10;
float pulse_delay;  // Temporary starting value that will change after void setup
bool buttonState = false;
bool onState = false;

// Set up output types
void setup() {
  Serial.begin(9600);  // Change this baud rate to whatever rate the LCD screen runs on - should generally be 9600
  // Set up LCD screen
  pulse_delay = setRPM(rpm, resolution);
  lcd.begin(16, 2);  // set up the LCD's number of columns and rows:
  lcd.setCursor(0, 0);
  lcd.print("Current RPM: ");
  lcd.setCursor(12, 0);
  lcd.print(rpm);
  lcd.setCursor(0, 1);
  lcd.print("MOVE RIGHT");

  // Sets up buttons
  pinMode(buttSwitch, INPUT);
  pinMode(buttGo, INPUT);
  pinMode(incSpeed, INPUT);
  pinMode(decSpeed, INPUT);

  // Establish initials
  pinMode(enPin, OUTPUT);
  digitalWrite(enPin, HIGH);  // deactivate driver
  pinMode(dirPin, OUTPUT);
  digitalWrite(dirPin, HIGH);
  pinMode(stepPin, OUTPUT);
  digitalWrite(enPin, LOW);  // activates driver
}

// Revolutions per second should be able specified to the tenths
// Run code to continual
void loop() {
  // Read Buttons Being Pressed
  int pressSwitch = digitalRead(buttSwitch);
  int pressGo = digitalRead(buttGo);
  int pressInc = digitalRead(incSpeed);
  int pressDec = digitalRead(decSpeed);
  pulse_delay = setRPM(rpm, resolution);  //pulse_delay = (rpm * 200)/60;

  if (pressSwitch == HIGH)  // Moves motor Right (Counter-Clockwise)
  {
    if (buttonState == 0) {
      digitalWrite(dirPin, LOW);  // sets direction of the motor turning
      buttonState = 1;
      lcd.setCursor(0, 1);
      lcd.print("MOVE  LEFT");
      delay(500);
    }
    else {
      if (buttonState == 1) {
        digitalWrite(dirPin, HIGH);  // sets direction of the motor turning
        buttonState = 0;
        lcd.setCursor(0, 1);
        lcd.print("MOVE RIGHT");
        delay(500);
      }
    }
  }

  if (pressGo == HIGH)  // Moves motor
  {
    digitalWrite(stepPin, HIGH);  // This LOW to HIGH change is what creates the "Rising Edge" so the easydriver knows when to step.
    delayMicroseconds(pulse_delay);
    digitalWrite(stepPin, LOW);
  }

  if (pressInc == HIGH)  // Increases RPM
  {
    rpm = rpm + 0.1;
    delay(150);
    lcd.setCursor(12, 0);
    lcd.print(rpm);
  }

  if (pressDec == HIGH)  // Decreases RPM
  {
    rpm = rpm - 0.1;
    delay(150);
    lcd.setCursor(12, 0);
    lcd.print(rpm);
  }
}

// Function to get pulse delay time based off of inputted RPM value
float setRPM(float rpm, float resolution) {
  /*
  float temper = ((60 / rpm) / 360);
  float pulsetime = ((temper * resolution) * 1000000);
  1 rpm = 37500 us delay (too fast)
  2 rpm = 18750 us delay (too fast)
  2.25 rpm = 16666.6667 us delay
  2.5 rpm = 15000 us delay
  3 rpm = 12500 us delay
  5 rpm = 7500 us delay
  10 rpm = 3750 us delay
  */
  unsigned int pulsetime = (60000000 / (1600 * rpm));
  return pulsetime;  // Converts to microseconds
}

While moving (pressGo == HIGH) your high part of the pulse has a variable duration. How do you control the low part? -- Did you measure the generated signal, for example with a frequency counter or oscilloscope?

I made a quick table and it revealed that going from 3.0 to 3.1 in rpm crosses the "255/256 border" in pulse_delay. You might want to temporarily change your sketch to adjust pulse_delay directly to check this in detail.

@thebusybee I haven't been able to get my hands on a frequency counter or an oscilloscope, but I have used a multimeter just to see if there was an issue I was making with my hardware setup - which I don't think there is. I'll measure the generated signal to check that out!
What do you mean by crossing the 255/256 border? I have changed my pulse_delay directly in my pressGo if statement and it seems to work alright when changed directly.
Thank you for the quick response!

pulse_delay is a float, but you call delayMicroseconds() with it. This function expects an unsigned int according to the documentation, so the value is converted. The unsigned int uses multiple bytes, and values from 0 to 255 "use" only the least significant byte. Starting with 256, the next byte(s) carry other values than 0. That's what I mean by "255/256 border". -- Which range of values did you check concretely?

Thank you for the clarification on the byte "limit". I converted my pulse_delay variable to unsigned int since it makes sense to me that I should utilize it when using the delayMicroseconds() function. I also switched to the equation defined in my setRPM function to the one defined in this post. Using this equation I concretely checked rpms of 3, 5, and 10.

That change is fine, as it clarifies the working for the future reader, most probably your future self in some weeks. ;-) -- When I asked for the range tested, I meant the range of pulse_delay you checked out. Does the stepper run as expected? I would start with some high value (for low rpms, like 2000 µs) and decrease it down to some low value (for high rpms, like 100µs). If there is a problem with that mentioned border, you will still see this saw-tooth-like transfer function, the repetitions nicely matching multiples of 256. You might want to [edit] your question with a table.

Sorry about the confusion - I checked pulse delays from 37500 us to 3750 us and I noticed that it was running as expected up until the low value of around 18750 us delay which correlates to an rpm of 2. The stepper run stops running as expected after I start reaching lower RPMs/higher pulse delays. I also added a table of pulse delays and RPMs that I had tested to the original question as well. As for the saw-tooth-like transfer functions you are referring to the voltage displayed on an oscilloscope? I believe there is an issue with running accurately at lower speeds.

I cannot reproduce my table, I don't know where my calculations were wrong. So forget about the 255/256 border. -- Anyway, I cannot reproduce your values, too. For example, for rpm=2.5, temper=(60/rpm)/360=0.0666... and pulse_delay=(temper*1.8)*1000000=120000. But you list pulse_delay=15000. Please make sure that source and table results match, and correct.

The documentation says:

Currently, the largest value that will produce an accurate delay is 16383; larger values can produce an extremely short delay.

The value given to delayMicroseconds() seems to be processed by a modulo 16384 operation. That means that the value is divided by 16384, and the remainder of this division is the effective delay in microseconds.
If we apply this to the delays in your table, we get:

desired rpm
calculated delay (µs)
effective delay (µs)
effective rpm

1
37500
4732
7.9

2
18750
2366
15.8

2.25
16666
16666
2.25

2.5
15000
15000
2.5

3
12500
12500
3

5
7500
7500
5

10
3750
3750
10

One possible solution is presented in the same documentation:

For delays longer than a few thousand microseconds, you should use delay() instead.

You might want to consider to use both functions, depending on the necessary delay.

And then there is the other issue with the time when the output is low. Currently, it is determined by the time the code takes to quit loop(), do its internal looping, call loop() and your statements until the pin goes high again.
You might want to divide the pulse period in two halves and take control of this low phase, too.

Thank you for the response! For the second part of your answer, did you mean that I should split the pressGo motor run statement into stepPin High, (1/2 pulse delay), stepPin Low, (1/2 pulse delay)?
if (pressGo == HIGH)   {      digitalWrite(stepPin, HIGH);        delayMicroseconds(pulse_delay);      digitalWrite(stepPin, LOW);      delayMicroseconds(pulse_delay);   }
Here is my code for reference. I have also included another if statement such that if my pulse_delay is greater than that 16384 for the delayMicrosecond function, it uses delay() instead.

@jonathan Yes, you can go that route. Just be aware that the time to "turn-around" is currently and generally undetermined. You might want to measure it, for example with an oscilloscope or similar device. As long as it is small compared to the delays, you can consider to ignore it. Or you take it into account for the low phase.

For reference for any future readers who have had similar problems using a TMC2208 Stepper Motor - I have attached my annotated code to this answer for your use. In the annotation, I also include equations that can be used to determine spacings for a coiling setup.
// Stepper motor run code with A4988 driver and LCD code
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Stepper.h>
// Define Pins for Step Motor Driver
#define stepPin 7  // define pin for step
#define dirPin 8   // define pin for direction
#define enPin 9    // define pin for enable ^^ Do I need this?

// Define Buttons for Speed and Direction
#define buttGo 10      // define pin for button input
#define buttSwitch 11  // define pin for button input
#define incSpeed 12    // define button for increasing speed
#define decSpeed 13    // define button for decreeasing speed

// Define LCD pinout
const int en = 2, rw = 1, rs = 0, d4 = 4, d5 = 5, d6 = 6, d7 = 7, bl = 3;  // Adapter Pinout
const int i2c_addr = 0x27;                                                 // Adapter Pinout
LiquidCrystal_I2C lcd(i2c_addr, en, rw, rs, d4, d5, d6, d7, bl, POSITIVE);

/* Formulas for determining RPM
Assuming one step per pulse, delay is: wait = (μs/min)*(1/rpm)*(1/pulses per revolution) - overhead
Overhead = extra time it takes to run digitalWrite twice and loop
RPM = (steps per second)/(steps per revolution) * (60 seconds/minute)
step angle = 1.8 degrees ; 200 steps per revolution ; .005 revolutions per step
Solving for Steps Per Second: SPS = (RPM)/((REV_P_STEP)*(60 sec/min))

According to John Craig:
  C0 = 15 * M_PI ; Motor X Circumference
  XSPR = 1 * (200 * 11) ; Motor X Steps per Rotation
  dVx = dS * (XSPR/C0) ; Desired X-Axis time from mm/s to x-axis steps/sec (dS represents desired x-axis speed)
  Assuming we use a button/knob, each increment/decrement would change the mm/s by 0.1
  So, to get the necessary pulse delay, increment/decrement by:
    dVx = 0.1 * (1 * (200 * 11))/(15*M_PI)

  Example: If we have an initial target rpm of 10, that gives us a dS of 10
  As such, dVx which is our speed in steps will be 10 * (1 * (200 * 11)) / (15 * M_PI)
  All of these variables are set globally
  wait = (microsecondsPminute)*(1/RPM)*(1/pulsesPrevolution) - overhead
  rpm / 60 = rps
  60 / rpm = spr
  (60 / rpm)/360 = spd
  ((60 / rpm)/360) * 1.8 = sps
***
*Assume from measured diameter with calipers that it is 12 mm (Check 11.85 as well)
To get Spacings: V_extruder / RPM_rod
V_extruder = M_PI * Diam_extruder * RPM_extruder (in (mm*rev)/min)
RPM_rod = 13 rpm (set from original bought parts)
V_extruder = M_PI * 12 mm * X
Spacing = (M_PI * 12 * X) / 9.64507699 RPM
Spacing = 3.90863773 * X
For Spacings of 3 mm... 0.76753084 rev/min ~= 0.77 rev/min
For Spacings of 5 mm... 1.27921807 rev/min ~= 1.28 rev/min
For Spacings of 7 mm... 1.79090529 rev/min ~= 1.79 rev/min
*
y = 1.0715x + 2.6653
y = Voltage Setting
x = RPM
For Voltage Setting of 13, RPM = 9.64507699

T_inc = incremental torque produced with each microstep
T_hfs = holding torque (full-step operation)
SDR = step division ratio (number of microsteps per full step)

T_inc = T_hfs * sin(90/SDR)
T_inc = 0.14 * sin(90/256)
T_inc = 0.00085902385
*/
float resolution = 1.8;
float rpm = 3;
unsigned int pulse_delay;  // Temporary starting value that will change after void setup
bool buttonState = false;
bool onState = false;

// Set up output types
void setup() {
  Serial.begin(9600);  // Change this baud rate to whatever rate the LCD screen runs on - should generally be 9600
  // Set up LCD screen
  pulse_delay = setRPM(rpm);
  lcd.begin(16, 2);  // set up the LCD's number of columns and rows:
  lcd.setCursor(0, 0);
  lcd.print("Current RPM: ");
  lcd.setCursor(12, 0);
  lcd.print(rpm);
  lcd.setCursor(0, 1);
  lcd.print("MOVE RIGHT");

  // Sets up buttons
  pinMode(buttSwitch, INPUT);
  pinMode(buttGo, INPUT);
  pinMode(incSpeed, INPUT);
  pinMode(decSpeed, INPUT);

  // Establish initials
  pinMode(enPin, OUTPUT);
  digitalWrite(enPin, HIGH);  // deactivate driver
  pinMode(dirPin, OUTPUT);
  digitalWrite(dirPin, HIGH);
  pinMode(stepPin, OUTPUT);
  digitalWrite(enPin, LOW);  // activates driver
}

// Revolutions per second should be able specified to the tenths
// Run code to continual
void loop() {
  // Read Buttons Being Pressed
  int pressSwitch = digitalRead(buttSwitch);
  int pressGo = digitalRead(buttGo);
  int pressInc = digitalRead(incSpeed);
  int pressDec = digitalRead(decSpeed);
  pulse_delay = setRPM(rpm);  //pulse_delay = (rpm * 200)/60;

  if (pressSwitch == HIGH)  // Moves motor Right (Counter-Clockwise)
  {
    if (buttonState == 0) {
      digitalWrite(dirPin, LOW);  // sets direction of the motor turning
      buttonState = 1;
      lcd.setCursor(0, 1);
      lcd.print("MOVING  LEFT");
      delay(500);
    } else {
      if (buttonState == 1) {
        digitalWrite(dirPin, HIGH);  // sets direction of the motor turning
        buttonState = 0;
        lcd.setCursor(0, 1);
        lcd.print("MOVING RIGHT");
        delay(500);
      }
    }
  }
// Both of the next functions move the motor, but switches between Microseconds and Milliseconds in delay time to fit.
  if (pressGo == HIGH && pulse_delay >= 16383)  // Moves motor
  {
      digitalWrite(stepPin, HIGH);  // This LOW to HIGH change is what creates the "Rising Edge" so the easydriver knows when to step.
      delay(pulse_delay/1000);
      digitalWrite(stepPin, LOW);
  }

  if (pressGo == HIGH && pulse_delay < 16383)
  {
      digitalWrite(stepPin, HIGH);  // This LOW to HIGH change is what creates the "Rising Edge" so the easydriver knows when to step.
      delayMicroseconds(pulse_delay);
      digitalWrite(stepPin, LOW);
  }

  if (pressInc == HIGH)  // Increases RPM
  {
    rpm = rpm + 0.01;
    delay(150);
    lcd.setCursor(12, 0);
    lcd.print(rpm);
  }

  if (pressDec == HIGH)  // Decreases RPM
  {
    rpm = rpm - 0.01;
    delay(150);
    lcd.setCursor(12, 0);
    lcd.print(rpm);
  }
}

// Function to get pulse delay time based off of inputted RPM value
float setRPM(float rpm) {
  /*
  float temper = ((60 / rpm) / 360);
  float pulsetime = ((temper * resolution) * 1000000);
  1 rpm = 37500 us delay (too fast)
  2 rpm = 18750 us delay (too fast)
  2.25 rpm = 16666.6667 us delay
  2.5 rpm = 15000 us delay
  3 rpm = 12500 us delay
  5 rpm = 7500 us delay
  10 rpm = 3750 us delay
  */
  unsigned int pulsetime = (60000000 / (1600 * rpm));
  return pulsetime;  // Converts to microseconds
}


text:
How to estimate the storage room for txt file when writing data to SD card module?
I'm planning to use Arduino UNO to do some measurements and record it in a SD card module. The measurements is going to last for a year or 20 month. I need some advice on how to estimate how long can the SD card storage last without overflow. Right now I'm doing measurements every second, each second contains 13 lines of data, each line is roughly 30 characters. How big is the txt file gonna be if I left the Arduino unit recording for a year?

This is just a multiplication problem.
13 lines times 30 characters is 390 bytes per measurement.
There are 86400 seconds in one day.
86400 * 390 = 33,696,000
So that's around 34 megabytes per day.
After 1 year it would be:
365 * 33.696 = 12299 MB or a little more than 12 GB.

I just realized I put 86400 in my calculator as 68400.  I am editing to correct now.

What type of SD card are you using? Based on the capacity, you can calculate SD card storage time to overflow with data/second. Since a character has a size of one byte, the amount of data used per day should be 30 * 13 * 86400 (sec/day) = 33696000 bytes or 0.033696 gb per day.


text:
ESP8266 serial monitor spitting out garbage
I am trying to set up a weather station, and I should just have the anemometer left. This code works fine (as far as I know).
// Pin definitions
const int reedSwitchPin = 2;

// Variables
volatile unsigned long lastRotationTime = 0;
volatile float windSpeed = 0.0;
const float windSpeedFactor = 2.4; // Factor to convert rotation time to wind speed

void setup() {
  pinMode(reedSwitchPin, INPUT_PULLUP);
  // attachInterrupt(digitalPinToInterrupt(reedSwitchPin), handleRotation, FALLING);
  Serial.begin(9600);
  Serial.println("hello world!");
}

void loop() {
  // Test reed switch functionality
  int reedState = digitalRead(reedSwitchPin);
  if (reedState == HIGH) {
    Serial.println("Reed switch triggered!");
  }

  // Calculate wind speed based on the time between rotations
  unsigned long elapsedTime = micros() - lastRotationTime;
  if (elapsedTime > 0) {
   windSpeed = windSpeedFactor / (float)elapsedTime;
  }

  Serial.print("Wind Speed: ");
  Serial.print(windSpeed);
  Serial.println(" m/s");

  delay(1000); // Delay for 1 second before measuring again
}

void handleRotation() {
  // Record the time of the last rotation
  lastRotationTime = micros();

}

But when I uncomment the following line:  attachInterrupt(digitalPinToInterrupt(reedSwitchPin), handleRotation, FALLING);
it prints garbage characters on the serial monitor. Here is the full code:
    // Pin definitions
const int reedSwitchPin = 2;

// Variables
volatile unsigned long lastRotationTime = 0;
volatile float windSpeed = 0.0;
const float windSpeedFactor = 2.4; // Factor to convert rotation time to wind speed

void setup() {
  pinMode(reedSwitchPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(reedSwitchPin), handleRotation, FALLING);
  Serial.begin(9600);
  Serial.println("hello world!");
}

void loop() {
  // Test reed switch functionality
  int reedState = digitalRead(reedSwitchPin);
  if (reedState == HIGH) {
    Serial.println("Reed switch triggered!");
  }

  // Calculate wind speed based on the time between rotations
  unsigned long elapsedTime = micros() - lastRotationTime;
  if (elapsedTime > 0) {
   windSpeed = windSpeedFactor / (float)elapsedTime;
  }

  Serial.print("Wind Speed: ");
  Serial.print(windSpeed);
  Serial.println(" m/s");

  delay(1000); // Delay for 1 second before measuring again
}

void handleRotation() {
  // Record the time of the last rotation
  lastRotationTime = micros();
}

By garbage, do you mean that even if the anemometer is stopped, you get initially a high speed reading in the serial monitor which, continually reduces each second ?

by garbage, I mean random characters that make no sense

A picture is worth a thousand words. Add one to your question. If the esp8266 is continually crashing then it may write to the console at a baud rate other than the one you selected. Try changing this to 115200 or  74880 in Serial.begin() and the console to see readable output.

What happens if you remove anything else but the anemometer (hardware and source code)? What does the serial window say when you change the baudrate as suggested? Please [edit] your question and add this important information.

previously, I tried every  baud rate which got me a few things, but not what I wanted, also, I don't know what you mean to remove the anemometer, and also is this issue between the serial moniter or hardware, because if it is serial moniter, I can skip this part and try to put it directly onto the website. last thing, I don't really know what you want the picture to be of

The picture I referred to would ideally be a picture/screen dump showing the serial monitor while it is displaying these "garbage characters" or, if you have found a baud rate which shows more understandable text, that instead.

Pin 2 that is  gpio2 (D4) is not suitable for this esp8266 application because this pin must be high at boot time and your anemometer could be in either state. Try say pin 4 that is gpio4 (D2) instead or search for "best pins to use - esp8266"
A crash during boot time can result in characters being written to the serial monitor at a baud rate of 115200 or 74880.

Whoever voted down, please add a comment, why.

I wasn't the one that voted down but just saying that I thing I was using D2 not D4, at least hardware wise. should I try using D4 because D2 was the one I was using before?

@Iliketurtles   You appear to have difficulty with the two different pin numbering system in use on the nodeMcu. Search for a nodeMcu pinout diagram to see the translation between the GPIO and "D" pins. In the case here const int reedSwitchPin = 2; the 2 is a GPIO pin. On the nodeMcu board this is labeled D4. Try the suggestion I gave in my answer .

oh, so i should say in the code to use  const int reedSwitchPin = 4;

@Iliketurtles    Yes. const int reedSwitchPin = 4; is correct. So you then connect the anemometer to the pin marked D2 on your nodeMcu board. If you have anything else connected to other pins on your nodeMcu, say a led, then temporarily disconnect these. If you still have problems then select the baud rate which gives the most understandable output on the serial console and add this output to your original question.

I have a slight problem: I have kind of soldered the pins in place and that includes an analogue pin(A0(again from the pin marking on the board)), as well as its gnd and +5v pins. I am also getting this problem where the port dropdown is greyed out

@Iliketurtles It is clearly getting worse. What you are now describing is either a problem with the IDE installation or the USB functionality of your NodeMCU. It must have worked better before for you to have seen the "garbage" characters which you reported originally. Maybe open a new topic exclusively for this latest problem.


text:
Trying to resolve invalid conversion from 'byte' {aka 'unsigned char'} to
I'm trying to use an existing Arduino library on the Raspberry Pi Pico.  The library is here:
https://github.com/j-bellavance/EdgeDebounce/tree/master
It's based on some interesting insight at Jack Ganssel's blog:
http://www.ganssle.com/debouncing.htm
The library works great on an ATMega 328, but I got two errors when changing to the Raspberry Pi Pico.
The first one was resolved by editing the last line of EdgeDebounce.h like this:
//#endif;  // Arduino ATMega version
#endif   // Pico version, also works on ATMega

The second is a bit more complex.  Here's the relevant section of code, these are lines 78 - 102 in EdgeDebounce.cpp :
  byte EdgeDebounce::debounce(byte pin) {
  unsigned long pinStatus;
  do {
    pinStatus = 0xffffffff;
    for (byte i = 1; i <= MYsensitivity; i++) pinStatus = (pinStatus << 1) | digitalRead(pin);
  } while ((pinStatus != debounceDontCare) && (pinStatus != 0xffffffff));
  return byte(pinStatus & 0x00000001);
}//debounce------------------------------------------------------------------------------------------------

//updateStatus===================================================================
//After releasing EdgeDebounceLite, I realized that EdgeDebounce could do more
//With this small piece of code, EdgeDebounce can return if a switch is
//  .isclosed();  //Conducting current
//  .isopen();    //Not conducting current
//  .rose();      //Just went from open to closed
//  .fell();      //just went from closed to open
//-------------------------------------------------------------------------------
void EdgeDebounce::update() {
  byte newStatus = debounce();
  if (MYmode == PULLUP) newStatus = !newStatus;
  if (MYstatus == OPEN && newStatus == CLOSED) MYrose = true;
  else                                         MYrose = false;
  if (MYstatus == CLOSED && newStatus == OPEN) MYfell = true;
  else                                         MYfell = false;
  MYstatus = newStatus;
}//update-------------------------------------------------------------------------

When I try to compile, I get this error:
c:\Users\thisuser\Documents\Arduino\libraries\EdgeDebounce\EdgeDebounce.cpp: In member function 'void EdgeDebounce::update()':
c:\Users\thisuser\Documents\Arduino\libraries\EdgeDebounce\EdgeDebounce.cpp:102:14: error: invalid conversion from 'byte' {aka 'unsigned char'} to 'pinStatus' [-fpermissive]
  102 |   MYstatus = newStatus;
      |              ^~~~~~~~~
      |              |
      |              byte {aka unsigned char}

exit status 1

Compilation error: exit status 1

So I see that the byte of "newStatus" doesn't convert to "pinStatus" which is an unsigned long.  I've done a bunch of Google searches but can't quite figure out what the fix is.

Where is pinStatus declared? Not inside EdgeDebounce::debounce - that's a local declaration.

In C and in much pre-standard C++ nothing stops you just assigning an integer value to a variable of enumeration type.  In standard C++ (from 1998 onward) that requires an explicit type conversion (a "cast").
The AVR Arduino core
supplies
the -fpermissive option to the compiler which among other things allows the implicit
conversion they're doing despite not being standards compliant C++.  Whatever you're using (odds are this or this) for RPI Pico Arduino core does not provide the -fpermissive option. A lot of Arduino cores don't and probably shouldn't.
You could modify the RPI Pico core's platform.txt to give the -fpermissive option to g++, but it is probably better to make the code compliant.
Minimal change
There are probably dozens of ways to do this, but a combination of mimimal and pleasing to C++ nerds probably looks like:
MYstatus = static_cast<pinStatus>(newStatus);

Alternative Casts
MYstatus = static_cast<decltype(MYstatus)>(newStatus); // fancier
MYstatus = (pinStatus)newStatus;  // traditional cast
MYstatus = pinStatus(newStatus);  // function-style cast
MYstatus = (decltype(MYstatus))newStatus;  // uhhh
MYstatus = (decltype(MYstatus))(newStatus);  // sure... why not?

The static_cast declares in intent in a way that other types of cast don't. decltype would make that line survive changes to the type of MYstatus better, but decltype is not as widely understood.
Alternately not type-converting at all
You can also observe that return byte(pinStatus & 0x00000001); is the only point of return from
byte EdgeDebounce::debounce(byte pin). So you know this function returns either 0 (false) or 1 (truthy). That's just what's going to happen with applying & 1.
They've defined the enumeration type:
enum pinStatus {OPEN, CLOSED};

The rules of C and C++ (even pre-standard C++) will assign these constants
numeric values 0 and 1, where they weren't explicitly given values and were listed in that order.
So, you could replace MYstatus = newStatus; with:
{
  if (newStatus) {
      MYstatus = CLOSED;
  } else {
      MYstatus = OPEN;
  }
}

Or use the ternary operator if you want don't mind people trying to argue with you:
MYstatus = newStatus ? CLOSED : OPEN;

It's apparently also possible to use braces for the function-style cast without a narrowing conversion diagnostic, which I didn't expect for this case. But, I'm not going to edit it again just to mention that

Thank you for taking the time to write such an in-depth answer!

I am using the Earle Philhower RP2040 core.
I read (and re-read) your comments until I understood them all.
I have tested all your suggested fixes above, and they all work.

I don't mind the ternary operator, but I will go with your first suggested change.
Thanks again.

pinStatus  is an enum:
enum pinStatus {OPEN, CLOSED};

The pinStatus you posted is a local variable, nothing to do with pinStatus in the EdgeDebounce.h file.
The error is pointing out that you can't assign an unsigned char to an enum which can only hold OPEN and CLOSED. The unsigned char might hold various other values.
Whoever coded that has made some confusing code.


text:
Why this simple serial monitor code not working?
The follwoing code echoes whatever arduino recieves through reciever pin. The idea is that arduino will echo whole data in the buffer on the same line and starting from the new line while echoing the next data recieved in the buffer.
void setup()
{
    Serial.begin(9600);
}

void loop()
{
  if(Serial.available())
    {
        int count = Serial.available();
        for(int i = 0; i < count; i++)
        {
            char character = Serial.read();
            Serial.print(character);
        }
        Serial.print("\n");
    }
}

When I run the code it prints the characters line by line. for example if I enter the word "QUICK" it echoes the following
Q
U
I
C
K

Whereas I think it should be echoing
QUICK

Please help me out.

You seem to have the assumption, that the string "QUICK" is send as one package of characters, because you send it with one keypress from the Serial Monitor. But Serial (UART) is a "serial" protocol, meaning, that each byte (aka character for ASCII encoding) is send sequentially.
At 9600 baud each byte will take about 1ms to transmit. Also: small random delays can be introduced by the PC or in the USB communication (if you are communication through a USB to Serial chip, like when you connect the Uno via USB).
Your code runs faster than the data arrives at the Unos microcontroller. The first if clause is entered as soon, as there is one byte in your Serial buffer. Then you start reading the data from the buffer, but at that time no further bytes did arrive. So the loop is exited after one iteration.
If you want to process the Serial data line by line, you should send a line ending from the Serial Monitor (or whichever program you are using) via the Line ending option. The common way is to use \n aka the newline character as line ending. Then in your code you should read the data until you receive the newline character.
That can be done in multiple ways. One way is to read each arriving character into your own buffer, which is big enough to hold the maximum number of characters, that can occur in your messages. Then, when receiving the newline character you can process the data in the buffer. A variables holds the current position in the buffer:
unsigned int pos = 0;
char buffer[20] = ""; // enough space for 19 characters + the null character for terminating the string correctly

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

void loop(){
  if(Serial.available()){
    char c = Serial.read();
    if(c != '\n'){
      buffer[pos] = c; // Adding the received character to the buffer
      if(pos < sizeof(buffer) - 1){
        // incrementing the position variable to point to the next position in the buffer
        // but only, if there is enough space in the buffer left
        // otherwise this code will overwrite the last character
        pos++;
      }
    } else {
      buffer[pos] = 0; // Terminating the string correctly
      // Process the message here
      Serial.println(buffer);
      // Reset buffer by setting the position back to zero
      pos = 0;
    }
  }
}

Note: This code needs your loop() function to iterate fast enough, so that you won't miss more data, than the internal buffer of Serial can hold (I think 32 characters). So you probably don't want to use long delays (which is nearly always a bad idea anyways, see non-blocking coding and the millis() function).


text:
LED doesn't completely turn off with digitalWrite(led, LOW);
When I was testing out a program I found a strange behavior of ESP8266.
LEDs don't turn off completely in the first digitalWrite(led, LOW), just the brightness of the LED goes down, but it does turn off in the second digitalWrite(led, LOW).
I don't know if it's related to the code or the circuit, so here are both (the program is just two different visual patterns of LEDs toggled by a button)
#define led1 D0
#define led2 D1
#define led3 D2
#define led4 D3
#define button D7

unsigned long pressedButton;
bool change = 0;
unsigned long previousTime = millis();
unsigned int difference;

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  pinMode(button, INPUT_PULLUP);
}

void loop(){
  if (!digitalRead(button) && millis()-pressedButton>200){       //check if button was pressed to change visual pattern of leds
      pressedButton = millis();
      change = !change;
      digitalWrite(led1, LOW);         //here led completely turn off
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
      digitalWrite(led4, LOW);
      previousTime = millis();
  }

  difference = millis()-previousTime;

  if (!change){                                     //default visual pattern of leds
    if (!digitalRead(led1) && difference>=200){
      digitalWrite(led1, HIGH);
    }
    if (!digitalRead(led2) && difference>=400){
      digitalWrite(led2, HIGH);
    }
    if (!digitalRead(led3) && difference>=600){
      digitalWrite(led3, HIGH);
    }
    if (!digitalRead(led4) && difference>=800){
      digitalWrite(led4, HIGH);
    }
    if (difference>=1000){
      digitalWrite(led4, LOW);           //the leds just shrink here
    }
    if (difference>=1200){
      digitalWrite(led3, LOW);
    }
    if (difference>=1400){
      digitalWrite(led2, LOW);
    }
    if (difference>=1600){
      digitalWrite(led1, LOW);
      previousTime = millis();
    }
  }

  if (change){                    //alternative pattern
     if (!digitalRead(led1) && difference>=200 && change){
       digitalWrite(led1, HIGH);
       digitalWrite(led4, HIGH);
       digitalWrite(led2, LOW);
       digitalWrite(led3, LOW);
    }
    if (digitalRead(led1) && difference>=400 && change){
       digitalWrite(led1, LOW);
       digitalWrite(led4, LOW);
       digitalWrite(led2, HIGH);
       digitalWrite(led3, HIGH);
       previousTime = millis();
    }
  }
}

Actually, it's a NodeMCU Esp8266, with the pins defined on the code and a 470 ohms resistor.  (obs: resistor is not shorted, in my breadboard those rows are separated)

That resistor won't do anything with the conductor running underneath it in parallel.

Leds doesn't turn off completely ... how do you know this? ... maybe they are turning on and off very fast ... reduce your code to turn on led, delay 1 second, turn off led, delay 1 second, and repeat

have you checked the connection between wires and tried a new led?

@timemage Sorry, I forgot to mention that in my breadboard the bottom row is separated for some reason

if (!digitalRead(led3) && difference>=600){
  digitalWrite(led3, HIGH);
}
if (!digitalRead(led4) && difference>=800){
  digitalWrite(led4, HIGH);
}
if (difference>=1000){
  digitalWrite(led4, LOW);           //the leds just shrink here
}
if (difference>=1200){
  digitalWrite(led3, LOW);
}

Consider what will happen when the difference is >= 1000.
If the LED is off you turn it on (because it passes the first test, the difference is >= 600), and a moment later you turn it off. So the LEDs are being turned on and off in quick succession, which makes them look dim.
Try re-ordering the tests, and add else for each subsequent one. That seems to work for me:
  if (!change){                                     //default visual pattern of leds
    if (difference>=1600){
      digitalWrite(led1, LOW);
      previousTime = millis();
    }
    else if (difference>=1400){
      digitalWrite(led2, LOW);
    }
    else if (difference>=1200){
      digitalWrite(led3, LOW);
    }
    else if (difference>=1000){
      digitalWrite(led4, LOW);
    }
    else if (!digitalRead(led4) && difference>=800){
      digitalWrite(led4, HIGH);
    }
    else if (!digitalRead(led3) && difference>=600){
      digitalWrite(led3, HIGH);
    }
    else if (!digitalRead(led2) && difference>=400){
      digitalWrite(led2, HIGH);
    }
    else if (!digitalRead(led1) && difference>=200){
      digitalWrite(led1, HIGH);
    }
  }

Also, that resistor on the bottom row isn't achieving anything because all the pins on the bottom row are connected together so it is just shorted out. Not good for the LEDs or the processor.

Thank you! I didnt see that problem on code. And sorry, I forgot to mention that my breadboard have the bottom row separated so it's not shorted.


text:
What is the max output rating of the pins on the Arduino Mega?
I have conflicting information on the max output rating for the Arduino Mega.  Some say 200 mA and others say 800 mA like the Uno board.  I am running 8 model railroad signal devices that have (3) 3mm LEDs (Red, Yellow, and Green) in each signal.  Of the 24 LEDs, only 8 are energized at any point in time.  8*.020 = 160 mA.  I believe I am good, but confused as to why the Uno board with 13 digital output pins can handle 800 mA and the Mega board with 40 or so output pins (not including all the TX RX IO pins) can only handle 200 mA.  Lots of forum discussion on this, but most go over my head without answering the question! LOL
Simply, how many mA can all of the digital pins combined provide?

Well theory (math) is nice, and a good starting point, but reality is better.
The signals I am talking about are (model) railroad trackside warning signal devices that have a red, yellow and green light, and depending on which light is lit, tells the train's Engineer if it is safe to continue down the track.

Each of these signals are 2.1/2" in height and the LEDs use 30 gauge wires and a 1K resistor.
I connected the red LED on all 8 signal devices to my variable power supply, turned it on and lit all 8 red LEDs with 5 volts, and wow, all 8 only used .023 amps total.
I then disconnected 7 of them and a single red LED only used .002 - .003 amps.  I connected the rest of the signals one at a time, and 2 signals used .006 amps, 3 signals used .009 amps, 4 signals used .011 amps, 5 signals used .014 amps, 6 signals used .017 amps, 7 signals used .020 amps and all 8 signals again only used .023 amps.
If this is the case, that is less than the max output from a single pin.
So, my plan is to connect the signals to the Arduino Mega 2560 on at a time, monitor the total current the Arduino in using after connecting each signal, and see just how much these signals are using.

Where does it say the Uno can handle 800 mA? Link please.

Are you using resistors between the output pins and the LEDs? If not, you should be. By choosing an appropriate value resistor you can limit the current to any figure. There is an LED calculator web site to help you do that.

Sticking to your original point, please explain where you read about the Uno and 800 mA. If you want to make additional explanations please edit the question - don't make an answer.

It's possible your signals come with inbuilt resistors - looking at the datasheet for them may help.

Ah, I see you mentioned a 1k resistor. That's why they don't draw a lot of current. Based on Ohm's law, if you have a 5V supply, and a 1.8V voltage drop (approximately normal for a red LED) and a 1K resistor, then you expect to draw (5 - 1.8)/1000 amps, which is 3.2 mA.

The 1k resistor is meant to help the LED survive 12V or even slightly more. If the devices are bright enough you've got the solution: Calculate with 3 mA per led and you're fine.
If you notice they look nicer when fed by 12V I'd rather add a little transistor and 4k7 base resistor (5-0.7 / 4700 = 1mA Arduino current) to switch 12V, than exchange the 1k led resistor by a smaller one.

The answers are right there in the datasheet.
The datasheet of the ATMega2560 (and 1280 etc.), page 355, states an absolute maximum current of 200 mA for the ATMega package and 40 mA per I/O pin.
In addition (thank you for the comment, @NickGammon), there are some further restrictions that are described from page 356 of the linked datasheet:

The sum of current which can be sunk from various ports cannot exceed 100 mA, and from others, 200 mA.
The same is true for the amount of current that can be sourced from various ports.

For example, for ports A0-A7 you cannot source a total of more than 100 mA (under steady conditions) and not 40 mA * 8 like you might expect.
So, if you had 8 LEDs on at once, continuously, you would only have 12.5 mA available for each of those ports (for a total of 8 x 12.5 mA = 100 mA).
That means that the 160 mA mentioned in the question could easily be out of spec.
It's not recommended to stay at or near the Absolute Maximum values mentioned in the datasheet for an extended amount of time. It's better to design your solution so that these abolute maximum values are never approached.
For your particular situation I would look into external (TTL) buffers between your Mega and your LEDs.
Alternatively, you could reduce the amount of current through the LEDs to make sure the total amount of current will always stay well below 200 mA or the other limitations mentioned above.

You might want to mention further restrictions, from page 356 of the linked datasheet. The sum of current which can be sunk from various ports cannot exceed 100 mA, and from others, 200 mA. Ditto for the amount of current that can be sourced from various ports. So for example, for ports A0-A7 you cannot source a total of more than 100 mA (under steady conditions) not 40 mA * 8. So if you had 8 LEDs on at once, continuously, you are down to 12.5 mA each, for those ports. So, the 160 mA mentioned in the question could easily be out of spec.

Thank you, @NickGammon, I've added that information to the answer.


text:
How to turn LEDs based on voltage readings?
I am trying to turn LEDs in an LED bridge based on the voltage reading from a power source. when the Voltage is zero nothing is ON and then the LEDs gradually turn ON as increase the voltage connected to the Ao pin. ( I am using a pro trinket 3V 120 MHZ)
This is my code:
const int analogPin = A0; // the pin that the potentiometer is attached to
const int ledCount = 7; // the number of LEDs in the bar graph

int ledPins[] = { 3, 4, 5, 6, 8, 9, 10}; // an array of pin numbers to which LEDs are attached

void setup() {
    // loop over the pin array and set them all to output:
    for (int thisLed = 0; thisLed < ledCount; thisLed++) {
        pinMode(ledPins[thisLed], OUTPUT);
    }
}

void loop() {
    // read the potentiometer:
    int sensorReading = analogRead(analogPin);
    // map the result to a range from 0 to the number of LEDs:
    int ledLevel = map(sensorReading, 0, 1023, 0, ledCount);

    // loop over the LED array:
    for (int thisLed = 0; thisLed < ledCount; thisLed++) {
        // if the array element's index is less than ledLevel,
        // turn the pin for this element on:
        if (thisLed < ledLevel) {
            digitalWrite(ledPins[thisLed], HIGH);
        }
        // turn off all pins higher than the ledLevel:
        else {
            digitalWrite(ledPins[thisLed], LOW);
        }
    }
}

However, I am not getting the outcome I want. when there is 0 voltage one LED turns ON instead of nothing. when there is a voltage all connected LEDs turn ON regardless of what the voltage is
when there is no voltage connected (floating wires), I get this:

when I put any amount of Voltage as long as the power supply is ON the results is the same:

Note: What am I doing wrong?
edit: connections are something like that but with fewer digital pins.

Note: What am I doing wrong!EDIT:
I was able to get around and print the serial monitor result:

when the power source is OFF, the reading at A0 (sensorreading) is:

Note: What am I doing wrong!- when the power source is ON at any value, the reading at A0 (sensorreading) is:

(Note: What am I doing wrong!)

Try printing sensorReading and ledLevel in your program and see if they are the values  you expect.

Could you please add a schematic showing how you connected the power source? Voltage divider, protection resistor, ground connection...

@Delta_G I can not communicate with trinket pro as it does show as a port, but a USBISP

is the Trinket your only Arduino?

Currently, yeah.

Is the Arduino GND connected to the negative lead of the power supply?

yes @EdgarBonet

I can't see the connection from the negative terminal of the power supply.  Can you show that as well.  Where is it connected?

I don't see any resistors in series with the LEDs. Where are they?

You are using a Full-size breadboard, for the full-size breadboards, the power rails are divided into two half sections as shown in this picture, and you need to have jumpers to bridge the two half-sections if you want to use them as a single power trail full-size section.

So on your photo, you thought that your blue wire (for GND) is connected to the rest of GND pins, but it is actually not connected.

It makes sense. I will try it tomorrow or so. YOU ARE A GENIUS. #Observation

I can say your code is working but you need to check the wirering of your circuit .
Note that the voltage on the analogread pin should not be an oscillating voltage at low frequency like AC voltage. It should be  a direct stable voltage to get the correct output.
Here is my diagram below for you to make changes with yours .
Ive testedit on my simulation app and its working perfectly.
The code

const int analogPin = A0; // the pin that the potentiometer is attached to
const int ledCount = 7; // the number of LEDs in the bar graph
int ledPins[] = { 3, 4, 5, 6, 8, 9, 10}; // an array of pin numbers to which LEDs are attached

void setup() {
Serial.begin(9600);
// loop over the pin array and set them all to output:
for (int thisLed = 0; thisLed < ledCount; thisLed++) {
pinMode(ledPins[thisLed], OUTPUT); }
}

void loop() { // read the potentiometer:
int sensorReading = analogRead(analogPin);
Serial.print("sensor read : ");
Serial.println(sensorReading);

// map the result to a range from 0 to the number of LEDs:
int ledLevel = map(sensorReading, 0, 1023, 0, ledCount);
Serial.print("led Level : ");
Serial.println(ledLevel);

// loop over the LED array:
for (int thisLed = 0; thisLed < ledCount; thisLed++) {
// if the array element's index is less than ledLevel, // turn the pin for this element on:
if (thisLed < ledLevel) {
digitalWrite(ledPins[thisLed], HIGH);
}

// turn off all pins higher than the ledLevel:
else {
digitalWrite(ledPins[thisLed], LOW);
} }

//delay(500); //for debugging
 }

The diagram

Note that if you're tryingto measure a voltage higher than 5 volts, make sure to build the voltage divider circuit with the appropriate resistor values for you to get 5v output as that is the highest volt the arduino can carry.
measure
Example below shows a 12 volts dc battery voltage measure(note that 5 volts is the highest voltage supplied to the arduino, not the full 12 volts):


text:
ArduinoHTTPClient POST multipart/form-data from SD card returning 400 Bad Request
I have been having trouble trying to send a small txt file to my server using the following function with TinyGSM. I know I am connected to the internet and reaching the web server, however, I keep receiving a 400 Bad Request code. I think something is wrong with my PostHeader, but I have no clue where or what it could be... I know I am connecting to my server as I try a default get and return webpage text...
TinyGsm modem(SerialAT);
TinyGsmClient client2(modem);
HttpClient client(client2, server, port);

void fileUpload(String filename){
  if(!initSD()){
    return;
  }
  File dataFile = SD.open(filename.c_str());
  Serial.println("Uploading File...");
  if (!client.connect(server, port)) {
    Serial.println("Failed connecting to Server");
    return;
  }
  String fileType = "text/plain";
  String content = "--boundary1\r\n";
  content += "Content-Disposition: form-data; name=\"fileToUpload\"; filename="+String(filename)+"\r\n";  // the fileToUpload is the form parameter
  content += "Content-Type: "+fileType+"\r\n\r\n";
  //after this, post the file data.
  String closingContent = "\r\n--boundary1--";
  //Serial.println(content);
  client.println(String("POST ") + "/upload.php" +" HTTP/1.1\r\n");
  client.println(String("Host: ") + server + "\r\n");
  client.println("Content-Type: multipart/form-data; boundary=boundary1\r\n");
  client.println("Connection: close\r\n");
  client.println("Content-Length: "+String(content.length()+dataFile.size()+closingContent.length())+"\r\n");
  client.println(content);
  client.println();
  if (dataFile) {  // start sending file content
    while (dataFile.available()) {
      char c = dataFile.read();
        client.print(c);
      }
    dataFile.close();
  }
  client.println(closingContent);
  Serial.println("File Sent.");
    // read the status code and body of the response
  int statusCode = client.responseStatusCode();
  String response = client.responseBody();

  Serial.print("Status code: ");
  Serial.println(statusCode);
  Serial.print("Response: ");
  Serial.println(response);
}

remove \r\n. you have println. move client.println(); before client.println(content);

@Juraj I solved a couple issues... this was one of them. Will post solution soon. Thanks for your help :)

There were a couple issues that I finally managed to solve... I was able to get it to work by not using ArduinoHTTPClient. Here is working code for anyone else who stumbles here.
TinyGsmClient client(modem);

void fileUpload(String filename){
  File dataFile = SD.open(filename.c_str());
  Serial.println("Uploading File...");
  if (!client.connect(server, port)) {
    Serial.println("Failed connecting to Server");
    return;
  }
  String fileType = "text/plain";
  String content = "--boundary1\r\n";
  content += "Content-Disposition: form-data; name=\"fileToUpload\"; filename="+String(filename)+"\r\n";  // the fileToUpload is the form parameter
  content += "Content-Type: "+fileType+"\r\n\r\n";
  //after this, post the file data.
  String closingContent = "\r\n--boundary1--\r\n";
  //Serial.println(content);
  client.println(String("POST ") + "/upload.php" +" HTTP/1.1"); // or wherever you need to call/print to.
  client.println(String("Host: ") + server);
  client.println("Content-Length: "+String(content.length()+dataFile.size()+closingContent.length()));
  client.println("Content-Type: multipart/form-data; boundary=boundary1");
  client.println();
  client.println(content);
  if (dataFile) {  // start sending file content
    String data = "";
    while (dataFile.available()) {
      char c = dataFile.read();
      data += c;
      //write every line break...
      if(c == '\n'){
        client.write(data.c_str());
        data = "";
      }
    }
    dataFile.close();
  }
  client.print(closingContent);
  unsigned long timeout = millis();
  while (client.connected() && millis() - timeout < 50000L) {
    // Print available data
    while (client.available()) {
      char c = client.read();
      Serial.print(c);
      timeout = millis();
    }
  }
  client.stop();
}


text:
Arduino UNO Power interruption
Do you have to upload the UNO after the applied power is disconnected?
Does the UNO retain the code without any power?
And when the power is disconnected, if the code is retained, will the timers retain their values?
Thanks

Do you have to upload the UNO after the applied power is disconnected?

No.

Does the UNO retain the code without any power?

Yes.

And when the power is disconnected, if the code is retained, will the timers retain their values?

No.

This answer simply add some detail to that provided by VE7JRO to make it more generally applicable but this does look rather like a school assignment.
Program code is stored in flash memory and this is retained after a power down.  It is not necessary to reload it. The registers which hold timer values or other data from a running program are stored in RAM memory and this is lost on power off. It is possible also to save some data from a running program in EEPROM (or in some cases flash memory) which also survives after a power down.


text:
What library does the Beetle BLE utilize for BLE commands?
I am trying to pair two gloves containing beetle BLE's on each, one set to a peripheral role and one to central to control leds for kids' party jewelry.
The Arduino.BLE library does not work with this board.  Is there another BLE library that is compatible with the Beetle BLEs, that will allow me to use the NOTIFY command?

AT commands https://wiki.dfrobot.com/Bluno_SKU_DFR0267#Configure_the_BLE_through_AT_command