text:
Serial Communication - strtok() issue
I'm working on UART communication between an ESP32 (sender) and ESP8266 NodeMCU board(receiver).
The host is sending out the following character string:
Serial.println("2753192144$1&");

The 2753192144 is the payload. The $1& is the trailer of the packet - $1 signifies a particular option for the receiver and & is the termination character to signify that the packet is complete.
On the receiver end - this is what I have:
#define MAX_REC_STR_SIZE 10
#define REC_TRAILER_SIZE 4 // $1& and string terminator
#define TRUE_TRAILER_SIZE 2 // option size really

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

void loop() {
    if(Serial.available()){
    char data [MAX_REC_STR_SIZE + TRUE_TRAILER_SIZE + 1];
    Serial.readBytesUntil('&', data, MAX_REC_STR_SIZE + REC_TRAILER_SIZE); // data does not contain termination &
    data[MAX_REC_STR_SIZE + TRUE_TRAILER_SIZE + 1] = 0; // adding null terminator

    // Tokenizing
    char *payload = strtok(data, "$"); // getting payload
    char opt = strtok(NULL, "$")[0]; // getting option - 1 in our sample

    // Print
    Serial.println(payload);
    Serial.println(opt);
  }
}

This code results in a stack exception error in the serial monitor. If I remove the last line which prints opt, the payload print works fine and I get 2753192144in the serial output.
I tested this exact code out in a standard C compiler, except instead of the serial read part - I defined a character array with 2753192144$1& and used printf instead of Serial.println. See the code below
#include <stdio.h>
#include <string.h>

int main()
{
    char data[] = "2753192144$1";

    char *payload = strtok(data, "$");
    char opt = strtok(NULL, "$")[0];
    printf("Payload is %s and opt is %c", payload, opt);

    return 0;
}

This code outputs
Payload is 2753192144 and opt is 1

This works fine. Any ideas why the Arduino sketch isn't working?

There are a number of "handy" functions, for example the readBytesUntil. They have a timeout. You can use those once, when you are a beginner. But after that you have to move on and place the characters in a buffer as soon as a character is available. One character at a time for every iteration of the arduino loop. Check if the buffer has enough data en then process the data in the buffer. When you expect 16 bytes, make a buffer of 40 bytes and prevent that it overflows. Your code is dangerous in a number of ways.

println sends two additional characters that will mess with your fixed message size. Also you have a buffer for 13 character, but put a limit on readBytesUntil to 14 characters.

@gre_gor Ah yes. That REC_TRAILER_SIZE in the readBytesUntil() should be TRUE_TRAILER_SIZE since the & itself isn't meant to be read.

@Jot Yeah. I noticed that a lot of people in other threads were manually reading data and was wondering why not many people were using this readBytesUntil() function.

data[MAX_REC_STR_SIZE + TRUE_TRAILER_SIZE + 1] = 0; // adding null terminator

That line places a 0 in the byte following the array.
If you define an array of size [x] you have slices [0] to [x-1] available. If you try accessing [x] you will be altering other items on the stack after the array.
That's called a buffer overrun and is one of the most common causes of programs crashing.
If you want to put a 0 at the end of the array, you should use
data[MAX_REC_STR_SIZE + TRUE_TRAILER_SIZE] = 0; // adding null terminator

You should also check that the strtok() calls actually return a valid pointer. If the incoming string is not in the right format and strtok() can't split the string up, it will return NULL. If you then try and access that NULL pointer as if it were a valid array you will have a nasty crash.

Ah yes. My mistake sorry. Let me make some amendments to the code to take into account all the comments.

I made that change. Didn't change anything. I added a check to see if a NULL was being returned by either other of the two strtok() commands. Code runs fine I use the char opt = strtok() line without doing any operations with it. But even checking if it's NULL crashes the program.

I printed out the strlen() of data and it's 12 so that must mean that includes the 10 digit payload and the $1. Not sure why the second strtok() is giving me so much trouble. Technically, the second strtok() should only be returning 1 character - the '1'.

UPDATE: char opt = strtok(NULL, "$")[0]; to char *opt = strtok(NULL, "$") seems to have fixed it some how. Not entirely sure why the first didn't work. Any ideas?

Could be something strange in the c library for the ESP8266. I don't know which it uses, but it certainly won't be the same as your PC...

Very well could be. It's really weird. Printing it as opt[0] works too with my new line of code. For some reason, I just can't assign it like this - char opt = strtok(NULL, "$")[0]; Thanks for the help though. I appreciate it


text:
ESP8266HTTPClient conflict with other libraries?
I can successfully send a GET request with the ESP8266HTTPClient library in the first sketch. However the exactly same code won't work when used in the second sketch, which is more complex and uses other libraries too. I'm not sure why, maybe a conflict between libraries?
Sketch 1 (working)
#define DEBUG

#ifdef DEBUG
  #define SB(...) Serial.begin(__VA_ARGS__)
  #define SP(...) Serial.print(__VA_ARGS__)
  #define SPL(...) Serial.println(__VA_ARGS__)
#else
  #define SB(...)
  #define SP(...)
  #define SPL(...)
#endif

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>
const char* ssid = "TALKTALK-17409C";
const char* password = "HPHRKJYX";

void setup() {

   SB(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    SPL("Waiting to connect…");
  }

  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin("http://francescosoave.com/blind/getTime.php?pw=ciao");
    int httpCode = http.GET();
    SP("HTTP: ");
    SPL(httpCode);
    if(httpCode > 0){
      String payload = http.getString();
      SP("PAYLOAD: ");
      SPL(payload);
    }

    http.end();
  }
}

void loop() {}

Sketch 1 response in the serial monitor (Tools -> Debug port -> Serial // Tools -> Debug Level -> HTTP_CLIENT)
SDK:2.2.1(cfd48f3)/Core:2.4.1/lwIP:2.0.3(STABLE-2_0_3_RELEASE/glue:arduino-2.4.1)
scandone
scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 3
cnt
Waiting to connect…

connected with TALKTALK-17409C, channel 10
dhcp client start...
Waiting to connect…
ip:192.168.1.4,mask:255.255.255.0,gw:192.168.1.1
Waiting to connect…
[HTTP-Client][begin] url: http://francescosoave.com/blind/getTime.php?pw=ciao
[HTTP-Client][begin] host: francescosoave.com port: 80 url: /blind/getTime.php?pw=ciao
[HTTP-Client] connected to francescosoave.com:80
[HTTP-Client] sending request header
-----
GET /blind/getTime.php?pw=ciao HTTP/1.1
Host: francescosoave.com
User-Agent: ESP8266HTTPClient
Connection: close
Accept-Encoding: identity;q=1,chunked;q=0.1,*;q=0

-----
[HTTP-Client][handleHeaderResponse] RX: 'HTTP/1.1 200 OK'
[HTTP-Client][handleHeaderResponse] RX: 'Server: nginx'
[HTTP-Client][handleHeaderResponse] RX: 'Date: Wed, 08 Aug 2018 21:24:46 GMT'
[HTTP-Client][handleHeaderResponse] RX: 'Content-Type: text/html; charset=UTF-8'
[HTTP-Client][handleHeaderResponse] RX: 'Transfer-Encoding: chunked'
[HTTP-Client][handleHeaderResponse] RX: 'Connection: close'
[HTTP-Client][handleHeaderResponse] RX: 'Vary: Accept-Encoding'
[HTTP-Client][handleHeaderResponse] RX: 'X-Powered-By: PHP/5.6.32'
[HTTP-Client][handleHeaderResponse] RX: 'Vary: Accept-Encoding'
[HTTP-Client][handleHeaderResponse] RX: 'Access-Control-Allow-Origin: *'
[HTTP-Client][handleHeaderResponse] RX: ''
[HTTP-Client][handleHeaderResponse] code: 200
[HTTP-Client][handleHeaderResponse] Transfer-Encoding: chunked
HTTP: 200
[HTTP-Client] read chunk len: 11
[HTTP-Client][writeToStreamDataBlock] connection closed or file end (written: 11).
[HTTP-Client] read chunk len: 0
[HTTP-Client][end] still data in buffer (2), clean up.
[HTTP-Client][end] tcp stop
PAYLOAD: TIME: 22:24
[HTTP-Client][end] tcp is closed
pm open,type:2 0

Sketch 2 (not working)
#define DEBUG

#ifdef DEBUG
  #define SB(...) Serial.begin(__VA_ARGS__)
  #define SP(...) Serial.print(__VA_ARGS__)
  #define SPL(...) Serial.println(__VA_ARGS__)
#else
  #define SB(...)
  #define SP(...)
  #define SPL(...)
#endif

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>

const char* ssid = "TALKTALK-17409C";
const char* password = "HPHRKJYX";

ESP8266WebServer server(80);   //instantiate server at port 80 (http port)
IPAddress ip(192, 168, 1, 7);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

String pageFinal = "";
byte curPos;
boolean timerState = true; //true = on, false = off
//int[] curTime = {0, 0}; // {hour, minutes

// HTML PAGES
String page1="<!DOCTYPE html>"
""
""
"<meta charset='utf-8'/>"
"<meta name='viewport' content='width=device-width, initial-scale=1'>"
"<meta http-equiv='Content-Type' content='text/html;charset=UTF-8' />"
"<link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css' integrity='sha384-Smlep5jCw/wG7hdkwQ/Z5nLIefveQRIY9nfy6xoR1uRYBtpZgI6339F5dgvm/e9B' crossorigin='anonymous'>"
"<link rel='stylesheet' type='text/css' href='http://www.francescosoave.com/blind/style.css'>"
""
""
""
""
"
"
"
"
"
"
"
"
"
Fran's Blind
"
"
"
"
"
"
"
"<form action='/' method='get' id='manualForm'>"
"<input id='1' type='submit' class='btn btn-primary' name='manualBtn' value='1' />"
"
"
"
"
"<input id='2' type='submit' class='btn btn-primary' name='manualBtn' value='2' />"
"
"
"
"
"<input id='3' type='submit' class='btn btn-primary' name='manualBtn' value='3' />"
"
"
"
"
"<input id='4' type='submit' class='btn btn-primary' name='manualBtn' value='4' />"
"
"
"
"
"<input id='5' type='submit' class='btn btn-primary' name='manualBtn' value='5' />"
"
"
"
"
"<input id='6' type='submit' class='btn btn-primary' name='manualBtn' value='6' />"
"
"
"
"
"<input id='7' type='submit' class='btn btn-primary' name='manualBtn' value='7' />"
"</form>"
"
"
"
<form action='/' method='get'>"
"<input id='timer' name='timerBtn' value='' class='' type='submit'></form>
Timer is
"
"
"
"
"
"
"
"
"
"
"
""
"";

void setup(void){

  WiFi.config(ip, gateway, subnet);
  delay(1000);
  SB(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    SPL("Waiting to connect…");
  }

  SP("IP address: ");
  SPL(WiFi.localIP());

  //here's the same GET request as in Sketch 1 but here it doesn't work
if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin("http://francescosoave.com/blind/getTime.php?pw=ciao");
    int httpCode = http.GET();
   SP("HTTP: ");
   SPL(httpCode);
    if(httpCode > 0){
      String payload = http.getString();
      SP("PAYLOAD: ");
      SPL(payload);
    }

    http.end();
  }

  server.on("/", control);
  server.begin();
  SPL("Server listening");
}

int  i = 0;

void loop(void){
  server.handleClient();
}

void control(){

  if(server.args() > 0){ //there is something to change
    if(server.argName(0) == "timerBtn"){
      timerState = !timerState; //change timer
    }else if(server.argName(0) == "manualBtn"){
      curPos = server.arg(0).toInt(); //change current (manual)
    }
  }

  //build the page
  if(timerState)
    pageFinal = page1 + page2;
  else
    pageFinal = page1 + page2_5;

  pageFinal += page3 + curPos + page3_5 + page4;
  server.send(200, "text/html", pageFinal);
}

Sketch 2 response in the serial monitor (Tools -> Debug port -> Serial // Tools -> Debug Level -> HTTP_CLIENT)
SDK:2.2.1(cfd48f3)/Core:2.4.1/lwIP:2.0.3(STABLE-2_0_3_RELEASE/glue:arduino-2.4.1)
scandone
Waiting to connectâ€¦
IP address: 192.168.1.7
[HTTP-Client][begin] url: http://francescosoave.com/blind/getTime.php?pw=ciao
[HTTP-Client][begin] host: francescosoave.com port: 80 url: /blind/getTime.php?pw=ciao
[HTTP-Client] failed connect to francescosoave.com:80
[HTTP-Client][returnError] error(-1): connection refused
HTTP: -1
[HTTP-Client][end] tcp is closed
Server listening
pm open,type:2 0

edit: the issue was in the Wifi.config() line. It should be WiFi.config(ip, gateway, subnet, gateway);

Chances are it's that insane string you're constructing that is causing your problems.

that part works well..you can try it since it's the full code..

Humour me and replace that string with something tiny. See what the effect is. I am not at my desk to try it myself.

If you want to configure a static IP address, make sure it is unique in you LAN and outside the range managed by the DHCP server.
EDIT:
the WiFi.config() function doesn't assign the gateway address as DNS address. add 4th parameter with DNS server address.
WiFi.config(ip, gateway, subnet, gateway);

Hi, it is indeed unique in my LAN since it's working. Not sure how to check "outside the range managed by the DHCP server"?

ok so the static IP seems to be the issue. If I remove that the HTTP request will work. However I need a static IP. Any idea?

it is not working, if you can't connect. is the AP in your control? do you know the DHCP range of IPs? do you know what other devices with static IP are in your network? for start try to use the IP that was assigned by the DHCP 192.168.1.4

sorry maybe I wasn't clear. So: right now with DHCP (removing the WiFi.config() line) everything works fine: the HTTP request is sent and the html page is displayed at 192.168.1.8. If I set the static IP instead, the html page won't work and the HTTP request will return the error. BUT, for my application I need a static IP. So I need to find a solution so that both works with a static IP.

but the static address of your choice 192.168.1.7 is in conflict. then use 192.168.1.8 as a static IP if it works as lease, it will work as static. you can reserve it on the router

tried but still the same issue. It seems the conflict is something between the WiFi things and the HTTPclient. If I remove the HTTP request code completely, it will work fine both with 192.168.1.7 and 192.168.1.8

is the router a DNS server at 192.168.1.1? try to print the DNS server address assigned by the DHCP.

sorry, not sure how to do that. the default gateway in my LAN is 192.168.1.1 if that's what you're asking

WiFi.dnsIP();

with DHCP is 192.168.1.1. If I leave the WiFi.config() instead, WiFi.dnsIP() prints 0.0.0.0

WiFi.config(ip, gateway, subnet, gateway);

working!! had no idea about this. could you please explain? thanks!!!

the 4th parameter is the DNS server. your url has hostname that needs to be resolved by DNS

Comment out the WiFi.config() line in the second example. You’re probably not configuring your ESP correctly. Let it get it’s configuration from its DHCP server.

Hi, unfortunately I need a static IP address. However that part is working fine. It looks like there's a conflict somewhere.

Hi, unfortunately I need a static IP address. And that seems to be the issue. If I remove the line, the HTTP request is working. But I need the static IP. any solution? Thanks!

source: Stack Exchange

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

sort: votes


text:
Time-bound LED program
I am trying to program a sketch such that an LED will light up for as long as a push button is pressed down. I have tested the components and electronics configuration before with a simpler program, and it all works, but there seems to be a problem in the code. I wanted to know how my sketch may be altered so the code will work:
const int ledPin = 12;
const int switchPin = 2;
const int Time = 100;
int buttonState = 0;
int count = 0;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(switchPin, INPUT);
}

void loop() {
buttonState = digitalRead(switchPin);
while (buttonState == HIGH) {
    count++;
    delay(100);
  }
  count=count*10;

  if (count>1) {
    digitalWrite(ledPin, HIGH);
    delay((count*10));
    digitalWrite(ledPin, LOW);
  }

}

And how exactly this doesn't work?

@gre_gor there is no response from the LED at all, regardless of how long, or much I press the button. When I use a simpler button-light up sketch, it works perfectly, but not with this code

Why do you increase the count value? Should the led be longer on each time the button is pressed. If so, please add that to your question. Hint: nothing stops the while.

Are you also trying to see how long the button was pressed down for?

while (buttonState == HIGH) {
    count++;
    delay(100);
}

this will never exit when the button is ever high. You should also reset count after the if.
Instead you want to either do buttonState = digitalRead(switchPin); inside the loop or rejig the function to be a state machine using timestamps like blink without delay.

Try installing a 1-10k resistor to ground connected to the input pin switchPin, assuming that the pushbutton is connecting 5V to switchPin.  This will force a true logic 0 when the button is not pressed.

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


text:
exit status 1 'Time' does not name a type
#include <DS3231.h>
#include <Wire.h>  // i2C Conection Library

// Init DS3231
DS3231  rtc;
// Init a Time-data structure
Time  t;
uint32_t targetTime = 0;

uint8_t hh = 0, mm = 0, ss = 0, dd = 0, bb = 0; //variable Unsignet int 0-255
int yy = 0; //variable integer
String Day = "  "; //variable string

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

void loop() {
  t = rtc.getTime(); // gate all data time & date from RTC
  Day = rtc.getDOWStr(); //get name of day
  hh = t.hour,DEC; //pengambilan data jam
  mm = t.min,DEC; //pengambilan data menit
  ss = t.sec,DEC; //pengambilan data detik
  dd = t.date,DEC; //pengambilan data hari
  bb = t.mon,DEC; //pengambilan data bulan (dalam desimal)
  yy = t.year,DEC; //pengambilan data tahun
  //Buka Serial Monitor Arduino untuk melihat hasilnya
  Serial.print (Day);
  Serial.print (F(" Time = "));
  Serial.print (hh); Serial.print (F(" : "));
  Serial.print (mm); Serial.print (F(" : "));
  Serial.print (ss); Serial.print (F("  Date = "));
  Serial.print (dd); Serial.print (F(" . "));
  Serial.print (bb); Serial.print (F(" . "));
  Serial.println (yy);
  delay (1000);
}

When I verify the code, this error appears:

exit status 1
  'Time' does not name a type

What does it mean?

Welcome to EE.SE. Please format your code properly using the {} code button (or add >= 4 spaces on the start of each line). Make sure it is indented properly. Use the preview to check it before submitting.

Have you included the library that defines the "Time" type?

isn't it already in the library wire.h?

@Hanatsuki No - see http://playground.arduino.cc/Code/Time

You don't mention which library you are using (which library does #include <DS3231.h> refer to?)
The DS3231 library here https://github.com/NorthernWidget/DS3231 defines a DateTime object which appears to have similar elements to what you are trying to access in 't' (hour, min, sec etc).
I would try defining 't' as a DateTime object.


text:
I want to make my stepper motor work for 1 hour
I already tried code that makes the stepper motor work for a few minutes only. I'm using a clock module, a DS1302 and the stepper library already present. Also the driver I'm using is an L298n. If someone could help out it would be nice. Thanks.
#include <Stepper.h>
#include <virtuabotixRTC.h>

virtuabotixRTC myRTC(5, 6, 7);
const int stepsPerRevolution = 200;
Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

const int OnHour = 12;
const int OnMin = 52;
const int OffHour = 12;
const int OffMin = 55;

void setup() {
  Serial.begin(9600);
  myStepper.setSpeed(100);
}

void loop() {
  myRTC.updateTime();
  Serial.print(myRTC.dayofmonth); //You can switch between day and month if you're using American system
  Serial.print("/");
  Serial.print(myRTC.month);
  Serial.print("/");
  Serial.print(myRTC.year);
  Serial.print(" ");
  Serial.print(myRTC.hours);
  Serial.print(":");
  Serial.print(myRTC.minutes);
  Serial.print(":");
  Serial.println(myRTC.seconds);
  if (myRTC.hours >= OnHour && myRTC.minutes >= OnMin && myRTC.hours <= OffHour && myRTC.minutes < OffMin) {
    Serial.print(myRTC.hours);
    Serial.print(":");
    Serial.print(myRTC.minutes);
    Serial.print(":");
    Serial.println(myRTC.seconds);
    myStepper.step(stepsPerRevolution);
  }
}

The problem you have is you are treating minutes and hours separately. That won't work - they need to be combined.  As it stands your "on" time is:

Minutes greater than W, and
Hours greater than X, and
Minutes less than Y, and
Hours less than Z.

Or, to rearrange that:

Hours between X and Z, and
Minutes between W and Y.

You can see that won't work. You will only get "on" for the block of minutes between W and Y for each hour in your "ON" period.
For example, if you want ON from 9:30 to 12:45, you get:

If hours greater than or equal to 9 and less than or equal to 12, and
Minutes greater than or equal to 30 and less than or equal to 45

So, that's 9:30 to 9:45, 10:30 to 10:45, 11:30 to 11:45 and 12:30 to 12:45
Even worse if you want 9:30 to 12:00...  the second part of the IF above becomes:

Minutes greater than or equal to 30 and less than or equal to than 0.

That can never happen. There is no number that is both greater than 30 and less than 0.
So you have to combine the two values together, to create a "minutes since midnight" value. Then your ON time is decided by the number of minutes, not the hours and the minutes separately.  It's simple enough:
int minutesSinceMidnight = myRTC.hours * 60 + myRTC.minutes;

Your ON time then becomes, for 9:30, 9 * 60 + 30 = 570, to 12:00 = 12 * 60 + 0 = 720.
So:
if (minutesSinceMidnight >= 570 && minutesSinceMidnight <= 720) {
    // Do your stepping
}


text:
Keeping track of multiple actions
I have a number of LED's connected to an Arduino which receives a JSON dict.
The JSON dict determines which action the LED's follow (either a fade, a pulse, on, or off), but I'm having trouble working out how to get one LED to flash whilst another fades etc.
The important parts of the code looks like this:
int led_choice;
int led_brightness;
String pattern_name;
int pattern_length;

// Timer Setup
unsigned long led1_current_time;
unsigned long led2_current_time;
unsigned long previousFadeMillis[2];
unsigned long previousPulseMillis[2];
unsigned long current_time;

// fade setup
int fadeInterval = 50;
int fadeIncrement = 5;
int fadeDirection = 1;
int fadeValue = 0;
int maxPWM = 255;
int minPWM = 0;
int translated_pin;

// Pulse setup
int pulse_state = 0;

void setup() {
  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  Serial.begin(115200);
}

void loop() {

  current_time = millis();

  // CODE HERE TO READ SERIAL/MQTT, DECIPHER JSON AND EXTRACT VARIABLES

  if ( pattern_name == "fade"){
    fade(current_time, pattern_length, led_brightness, led_choice);
  } else if ( pattern_name == "pulse"){
    pulse(current_time, pattern_length, led_brightness, led_choice);
  }
  else if (pattern_name == "on" )
  {
    solid_running(led_choice, led_brightness);
  }
  else {
    switch_off(led_choice);
  }
}

/********** LED CONTROL FUNCTIONS *********/
void fade(unsigned long thisMillis, int fadeInterval, int maxPWM, int led_pin) {
  if (thisMillis - previousFadeMillis[led_pin] >= fadeInterval) {
    // yup, it's time!
    if (fadeDirection == 1) {
      fadeValue = fadeValue + fadeIncrement;
      if (fadeValue >= maxPWM) {
        // At max, limit and change direction
        fadeValue = maxPWM;
        fadeDirection = 0;
      }
    } else {
      //if we aren't going up, we're going down
      fadeValue = fadeValue - fadeIncrement;
      if (fadeValue <= minPWM) {
        // At min, limit and change direction
        fadeValue = minPWM;
        fadeDirection = 1;
      }
    }
    // Only need to update when it changes
    analogWrite(led_pin, fadeValue);
    // reset millis for the next iteration (fade timer only)
    previousFadeMillis[led_pin] = thisMillis;
  }
}

void pulse(unsigned long thisMillis, int on_duration, int on_speed, int led_pin){
  if (thisMillis - previousPulseMillis[led_pin] >= on_duration) {
    // save the last time you blinked the LED
    previousPulseMillis[led_pin] = thisMillis;

    // if the led is off turn it on and vice-versa:
    if (pulse_state == 0) {
      pulse_state = 1;
      // set the led with the ledState of the variable:
      analogWrite(led_pin, 255);
    } else {
      analogWrite(led_pin, 0);
      }
      pulse_state = 0;
    }
  }
}

void switch_off(int led_pin){
    analogWrite(led_pin, 0);
}

void solid_running(int led_pin, int led_brightness){
    analogWrite(led_pin, led_brightness);
}

If I send the json data telling LED 1 to pulse, as soon as I send a second string telling LED2 to fade, LED 1 stops pulsing.
I'm sure this is something obvious, but it's been driving me mad for days!
EDIT: Adding the second attempt at this
// Declare the number of LED's
const int led_count = 2;

// Setup the ENUM for the various Modes
enum EMode { Off, On, Pulse, Fade };
// Create the struct and initialise it
struct MMode {
  EMode pin_mode;
  int action_pin;
  int action_delay;
  int action_max;
  int action_min;
  int fade_direction;
  int fade_value;
  int fade_increment;
  unsigned long m_current_time;
  unsigned long previous_millis;
} leds[led_count] {
  {Fade, D4, 20, 255, 0, 1, 0, 1, 0, 0},
  {Fade, BUILTIN_LED, 20, 255, 0, 1, 0, 1, 0, 0}
};

void setup() {
  Serial.begin(9600);
  // Setup the Built-in LED
  pinMode(BUILTIN_LED, OUTPUT);
  // Setup the Red LED
  pinMode(D4, OUTPUT);
}

void loop() {
    for (int n = 0; n < led_count; n++) {
      leds[n].m_current_time = millis();
      switch(leds[n].pin_mode){
        case Fade:
          fade(leds[n]);
          break;
      }
    }
}

/********** LED CONTROL FUNCTIONS *********/
void fade(struct MMode led) {
  if (led.m_current_time - led.previous_millis >= led.action_delay) {
    // yup, it's time!
    if (led.fade_direction == 1) {
      led.fade_value = led.fade_value + led.fade_increment;
      Serial.print("Fade Up Value: ");
      Serial.print(led.fade_value);
      Serial.println("    ");
      if (led.fade_value >= led.action_max) {
        // At max, limit and change direction
        led.fade_value = led.action_max;
        led.fade_direction = 0;
      }
    } else {
      //if we aren't going up, we're going down
      led.fade_value = led.fade_value - led.fade_increment;
    //  Serial.print("Fade Down Value");
    //  Serial.print(led.fade_value);
    //  Serial.print("    ");
      if (led.fade_value <= led.action_min) {
        // At min, limit and change direction
        led.fade_value = led.action_min;
        led.fade_direction = 1;
      }
    }
    //Serial.print(led.fade_value);
    //Serial.print("  ");
    // Only need to update when it changes
    analogWrite(led.action_pin, led.fade_value);
    // reset millis for the next iteration (fade timer only)
    led.previous_millis = led.m_current_time;
    //Serial.print(led.previous_millis);
    //Serial.print("  ");
  }
}

This second iteration of the code appears to define the led's using the struct correctly, however when I upload it to the arduino, motor.fade_value gets set to 1, and never increments above this.
I get the feeling I'm missing something from the answers that I've had so far, but I'm not sure what that something is, and google isn't proving very helpful tonight...

your code has nothing to pulse or fade other led then `led_choice'

you need to call the fade/pulse function every time until the led state's change,
Start by creating full separate state for each LED,
struct LED_state{
    STATE state;

    unsigned long led1_current_time;
    unsigned long previousMillis;
    int pin;
    int fadeValue;
    int fadeDirection;
    int pulse_state = 0;
}

LED_state led[2];

STATE is an enum for each animation you do. Change the functions to take a pointer to this state. Initialize them in init().
Then create an update function which looks like:
void updateLED(LED_state* state){
    switch(state->state){
    case FADE:  fade(state);break;
    case PULSE: pulse(state);break;
    case ON:    solid_running(state);break;
    case OFF:   switch_off(state);break;
    }
}

Every time through the loop you call this update function for each LED's state.
To change what the LED does you the only need to update the state member in the struct for the LED.
  if ( pattern_name == "fade"){
    led[chosen_led]->state = FADE;
  } else if ( pattern_name == "pulse"){
    led[chosen_led]->state = PULSE;
  } else if (pattern_name == "on" ){
    led[chosen_led]->state = ON;
  } else {
    led[chosen_led]->state = OFF;
  }

So is this the same approach as @michel-keijzers (it seems to be to my eyes!), or does it differ?  If it differs, would you mind explaining what/why so I can make an informed decision? Thanks :)

it's pretty much the same, except I added more state into the per led struct

Without looking to the entire code, the best way is to use a 'mode' for each led. So for each led, keep track how it should behave (like Off, On, Blink, FadeOff, FadeOn etc) and some parameters (for the speed for fading for example). You can use a struct for this, like
enum EMode { Off, On, Pulse, FadeOff, FadeOn };
struct LedMode
{
   EMode mode;
   int fadeSpeed; // Only used when mode = fade off/on
};

LedMode ledModes[8]; // For e.g. 8 leds

When you get a JSon command, change the ledMode structure for that LED accordingly.
Than in the main loop use something like:
loop()
{
    for (int n = 0; n < 8; n++) // For each led
    {
       switch (ledModes[n].mode)
       {
       case Off:
         TurnOff(ledModes[n]);
         break;

       case On:
          TurnOn(ledModes[n]);
          break;

       case Pulse:
          Pulse(ledModes[n]);
          break;

       case FadeOn:
          FadeOn(ledModes[n]);
          break;

       ...
    }
}

To prevent going into each case all the time, add in the structure a 'Dirty' flag which is set to true by JSON and set to false after performed the change (e.g. you only have to switch a LED On or Off one time, not in every loop). For FadeOn/Off until it has reached 255 or 0. You also can use a PreviousMode and check if the mode has been changed since last time.
And for the Pulse/FadeOn/Off you need to add in the structure the last set value to be able to increase/decrease it, and the time it has changed last time.
Btw, you also can pass n and get LedModes[n] directly since it is global.

So this would move all of the code that controls the LED's out of the dedicated functions and directly into the main loop as part of the switch statement?

No, this was just the 'structure' .... PLEASE keep the separate functions, you can pass the structure for that led into the function (ledModes[n] where n is the LED that is currently handled in the loop). Use a separate function for each mode, that's very good programming practice.

That was what threw me, keeping them makes a lot of sense.
I'm used to coding in Python, but I struggle with translating things over to C!
Thanks.

You're doing a good job, it will make it easy if you use the struct with parameters, so every LED will have its own set of data, than in the mode functions (off, on, pulse etc) you can change the intensity LED depending on the parameters, independing of the other LEDs.

Unfortunately I can only accept one answer, and it was the part about referencing and setting the variables in @rachettFreak's answer that finally got this working for me.
Thanks for all the help, it really was appreciated, and if I could, I'd select your answer too!

His way is better actually, but I wanted to keep my solution simple to understand. It's good you understand his and can use it. Using struct or better: classes to keep information and functionality together is always a good idea, or better said: using structs/classes to keep different information/functionality separated is better.


text:
'dynamic_cast' not permitted with -fno-rtti
class A {
    virtual ~A();
}

class B : public A {
    public:
      int foo;
}

void bar(A *foo_){
    B* b = dynamic_cast<B*>(foo_);

    if(b != nullptr){
         cout << (*foo_)->foo << endl;
    }
}

int main(){
    B b{};
    bar(b);
}

Compiling error:
error: 'dynamic_cast' not permitted with -fno-rtti

I thank sincerely for the help.

What board are you trying to compile for?

Arduino Mega2560

What IDE version and boards package version do you have?

PlatformIO and arduino-1.8.5

It seems avr-gcc version 4.9.2 that is used by the Arduino IDE has been compiled without RTTI support. It defaults to -fno-rtti, and if you try turning it on with -frtti you just get other horrible linker error messages instead.
So it looks like you can't use dynamic_cast on AVR boards.
Googling around it looks like numerous people have tried to enable FTTI on Arduino, but they have either failed and given up, or they have succeeded and never bothered to tell anyone else how they did it (numerous forum posts of "how do you do this?", a bit of discussion, and then they tail off...)
The solution? Either don't use RTTI, or use a more capable microcontroller whose compiler has RTTI enabled.
One way to not use RTTI is to fake it yourself:
#define CLASS_A 1
#define CLASS_B 2

class A {
    public:
        virtual int classType() { return CLASS_A; }
};

class B : public A {
    public:
        virtual int classType() { return CLASS_B; }
        void bar() {
            Serial.println("Baaaah!");
        }
};

void foo(A *foo) {
    if (foo->classType() == CLASS_B) {
        B *foob = (B *)foo;
        foob->bar();
    } else {
        Serial.println("Sorry, I can't bar.");
    }
}

void setup() {
    Serial.begin(115200);
    A a;
    B b;
    foo(&a);
    foo(&b);
}

void loop() {
}

Output:
Sorry, I can't bar.
Baaaah!

You gave a band-aid solution. It is already valid.


text:
How to interface USB to custom Arduino Uno Schematic and programming atmega?
I'm fairly new to designing schematics and working with the atmega on its own and I'm designing an arduino schematic on eagle. Ive gotten to the stage where I need to incorporate a TTL USB interface in order to program the chip. I've just became aware that the arduino uses another avr chip to do so but it appears similar to the microcontroller and just need some clarification.
Since I want it all on one board like the arduino uno, my question is how is the USB-B connected to the microcontroller and how would I Incorporate it into my schematic?
Another question (out of curiosity) if I was to mass produce said PCB with one program on the atmega chip and leave out a USB module so people wouldnt be able to reprogram it (without taking the board apart obviously) How would that be done?
Heres a photo of my current schematic:

Since I want it all on one board like the arduino uno my question is how is the USB-B connected to the microcontroller and how would i Incorporate in my schematic?

The USB interface forms a bridge between the USB connector and the UART of the "master" MCU.  You don't have to use a microcontroller, but almost any UART to USB bridge chip will do the job.  Common ones are the CH340G (cheap and unstable), CP2102, FT232, etc.  The DTR signal from the USB chip is used to reset the main MCU.
You should look at the existing Uno schematics to see how the two chips are wired together.

Another question (out of curiosity) if I was to mass produce said PCB with one program on the atmega chip and leave out a USB module so people wouldnt be able to reprogram it (without taking the board apart obviously) How would that be done?

You would program the board through the ICSP pins - in the same way that you put the bootloader on.  Normally you'd invest in a proper programmer to connect up to the chip, but you can do it with an Arduino acting as the programmer.


text:
Can you use a RF remote with nRF24L01 and Arduino?
I recently bought a 10 pack of RF transceivers (nRF24L01). I wanted to know if its possible to pair one with an RC drone controller. I can't seem to find any ways to do this through google.
If this helps:
My drone and its controller is called "Sky Viper v2400" and a link to where you buy it is: https://www.amazon.com/Sky-Viper-01601-Streaming-Video/dp/B01D1HRXSK.
Thanks

Probably not. You'd have do dismantle the drone and find out what chip it uses. If it's the nRF24L01 or one of the Nordic SoCs with a built in nRF24L01, then it could be possible. Otherwise, no.

Even if you figure out that your drone uses the same proprietary protocol (/chip) you have to somehow determine the channel, pipes and every other piece of the radio's configuration for any (proper) communication to work.

The nRF24 operates in the 2.4GHz frequency and implements a proprietary protocol so, even if I don't have much information on your particular drone/controller, I strongly doubt there's a chance you can use the nRF24 module to talk to your drone.


text:
Problems with NodeMCU and Relay
I've connected the MCU to a cheap chinese 24/12v to 5v car phone charger and hooked some wires to a relay.When I try to program doesn't matter if the pin is set to high or low , as soon as I touch the "IN" wire from the relay into any of the selected pins, the relay auto actives.
here is the schematic
The charger input is hooked to a 12V drill battery for tests and the output to arduino is an usb port that I soldered wires to it's respective poles.
USB from Chinese charger Positive pole ------- NodeMcu Vin
USB from Chinese charger Negative pole ------- NodeMcu GND
USB from Chinese charger Positive pole ------- Relay   VCC
Relay Ground --------------------------------- NodeMcu Gnd
Relay DataPin -------------------------------- NodeMcu D0 or D1

And here's the code:
int port = D0;
int portB = D1;

void setup() {
Serial.begin(115200);
pinMode(port,OUTPUT);
pinMode(portB,OUTPUT);

digitalWrite(port,HIGH);
digitalWrite(portB,LOW);

}

void loop() {

}

But the result is that the relay will always be on activated ( IN pin = Low ) even connected to D0 that is high... Any ideas ?

Sorry, fixed , " it " was referring to the relay data pin

you probably have one side of the relay connected to the positive voltage .... connecting the other side of the relay to a pin overloads the pin circuitry and activates the relay

the relay might want more than 3.3v to indicate high, try feeding it 5v to the relay data pin and see if it activates. if so, it's designed for 5v arduino devices, not 3.3v. FWIW, i've bought several kinds and this is common amoung single-relay modules, bit for whatever reason, all the few kinds of 2-relay modules i've bought work fine with my nodeMCUs.

note that you can also use a logic level mosfet's S-D pins to connect the relay data line to ground, and use a 100k resisistor from 5v to relay data in to pull it up; when you set the pin high, it turns on the gate and pulls the 5v signal down ground. i like the irlz44n for most 3.3v applications.

some relays hold the coil at LOW signal and release at HIGH

I will try  the  options above then I get back with the results and I may not be able to get a irlz44n , and yes my relay holds on low, but even plugging D0 that is set to high, it holds the coil like if it is low

Oh and the charger output is 5V and its connected to the Mcu's Vin and the relay vcc

than it is clear that 3.3 V is not HIGH signal for the relay working at 5 V

Does your nodemcu directly feed the relay?
If so, 3.3v (nodemcu output high level) is not enough to activate it.
I would use a transistor like a s8050 to Power it (do not forget the freewheel diode on the relay coil)

You are right, I've completely forgot that the Mcu's digital is 3.3v instead of 5v and it wasn't able to properly control the relay, thank you very much.

@LucasMedeiros, it was in comments by dandavis

you can try to feed the esp 3.6v or 3.7v instead of 3.3v; should work fine (within/cose to ESP spec) and might be enough to trigger the relay on HIGH, since VCC (and thus D1@HIGH) will be raised.


text:
Interrupts Problem with Flow sensor
 #include <Wire.h> //I2C lib
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
 // LCD lib
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

const int pot_pin = A0;
const int pump_pwm= 3;

int press_pin =A1;

//flowmeter parameters
int flowPin = 2;  // input pin on arduino D2

double flowRate;   // value intented to calculate
double flowR; // flow value in lt
double totalFlow; // total output of flow from system

byte sensorInterrupt = 0; // interrupt 0 on D2 pin Arduino Nano

volatile int count; ////integer needs to be set as volatile to ensure it updates correctly during the interrupt process.

int pot_init= 0;
int pump_init= 0;
int percentValue =0;

void setup() {

  lcd.begin(20,4);  // A4 - A5 connection SDA - SCL
  lcd.backlight();
  Serial.begin(9600);

  pinMode( flowPin,INPUT); // Set D2 pin as an input

  attachInterrupt(sensorInterrupt,Flow,RISING); // Configures interrupt 0 ( pin D2 on Arduino Nano ) to run function "Flow"
}

void flow_control(void) {

  count = 0; // reset counter so it could start counting from 0

  interrupts(); // enables interrupts on arduino nano
  delay(1000); // wait 1000 msec
  noInterrupts(); // disable interrupts on arduino nano

  //calculation for flowmeter

  flowR = (count*8.93);   // 112 pulse/lt 423.84 pulse /gallon
  flowRate= flowR*60;     // convert seconds to minutes, new unit is ml/minutes
  flowRate= flowRate/1000; // convert ml to liters, new unit is lt/minutes

  totalFlow += flowR;

  // Print the flow rate for this second in litres / minute
    Serial.print("Flow rate: ");
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print("L/min");
    Serial.print("\t");       // Print tab space

    // Print the cumulative total of litres flowed since starting
    Serial.print("Output Liquid Quantity: ");
    Serial.print(totalFlow/1000);
    Serial.println("L");

    lcd.setCursor(0,2);
  lcd.print("Flow: ");
    lcd.setCursor(8,2);
  lcd.print(flowRate);
  lcd.print("lt/min");

  lcd.setCursor(0,3);
  lcd.print("Total: ");
  lcd.setCursor(8,2);
  lcd.print(totalFlow/1000);
  lcd.print("lt");

}

void Flow(void)
{
  count++; // every time this function is called, increment  "count" by 1
}

void loop() {

  pressure_cal();
  pump_control();
  flow_control();
  lcd_control();
}

void pressure_cal(void) {

  float sensorVoltage = analogRead(press_pin);   // sensor voltage A0
  float psi = ((sensorVoltage-102)/204)*25;  // Offset    0 PSI= 0.5V=102 unit, 50 PSI= 2.5, 100 PSI= 4.5V, 1 PSI= 0.04V

  // calibration
  float bar = psi*(0.0689475729);           // Conversion PSI to BAR

  lcd.setCursor (0,1);
  lcd.print (psi);
  lcd.print (" PSI");

  lcd.setCursor ( 10,1);
  lcd.print(bar);
  lcd.print( " BAR");

  //lcd.setCursor(17,1);
  //lcd.print(sensorVoltage);

  Serial.println (sensorVoltage);
  Serial.println(bar);
  Serial.println (psi);

  delay (100);
}

void pump_control(void)

{

  // read the analog in value:
  pot_init = analogRead(pot_pin);
  // map it to the range of the analog out:
  pump_init = map(pot_init, 0, 1023, 50, 230);  //  duty cycle between %20 - %90: speed control , duty cycle between %0 - %20: turned off  , duty cycle between %90 - %100: full speed
  // map pump speed percent of full scale
  percentValue = map (pump_init, 50, 230,0,100);
  // change the analog out value:
  analogWrite(pump_pwm, pump_init);

  // print the results to the Serial Monitor:
  Serial.print("\t Speed Input = ");
  Serial.print(pot_init);
  Serial.print("\t Speed Output = ");
  Serial.print(pump_init);
  Serial.print("\t Pump Speed Percentage = ");
  Serial.println(percentValue);

  lcd.setCursor(2,0);
  lcd.print("Speed: ");
  lcd.setCursor(8,0);
  lcd.print("%");
  lcd.setCursor(9,0);
  lcd.print(percentValue);
  lcd.print("     ");

 //  delay after the last reading:
  delay(2);

}

I try to write code including flow sensor, pressure sensor and pump. I wrote the code. But When I use interrupt , code stop. I used functions in " void loop()" . I moved the interrupt code ( flow_control) between void setup and void loop. But I can see outputs in serial monitor but I cannot see on lcd. Could you help me fix the problem ?

What happens in lcd_control()? You forgot to include that function.

I thought that I can code all lcd command in a function. But the code I added , the function is not active. I forgot to delete it.

A lot of peripheral libraries requires interrupts to be enabled, especially when they use timing or the I2C/SPI pins. Instead of disabling interrupts for the majority of the sketch, what you want to do is isolate disabling the interrupts to just reading and resetting the count variable:
noInterrupts(); // disable interrupts on arduino nano
local_count = count;
count=0;
interrupts(); // enables interrupts on arduino nano

Also all that processing takes some time which will skew the timing so it's better to use timestamp and millis:
unsigned long previous_read;
if(millis() -  previous_read > 1000){
    noInterrupts(); // disable interrupts on arduino nano
    int local_count = count;
    count=0;
    interrupts(); // enables interrupts on arduino nano
    previous_read += 1000;

    //process flowrate based on local_count

}

Should I replacey count8.93 by local_count8.93 ? When I do, Arduino says local_count  was not declared in this scope? What should I do ?
flowR = (count8.93);   // 112 pulse/lt 423.84 pulse /gallon
flowRate= flowR60;     // convert seconds to minutes, new unit is ml/minutes
flowRate= flowRate/1000; // convert ml to liters, new unit is lt/minutes

that calculation should be inside the if (where the comment is), you only need to run it when processing the new count.

Thank you so much ratchet. I want to add a button to reset only total flow on lcd
void flow_control(void)  {
if(digitalRead(resetButtonA) == LOW)
{
totalMilliLitresA = 0;
lcd.setCursor(0, 1);
lcd.print("0L");
}

Thank you so much.  I want to add a reset button to reset only total flow  on lcd. Is this code true inside void flow(void) ?
 void flow_control(void)  {

  if(digitalRead(resetButton) == LOW)
  {
    totalFlow = 0;
    lcd.setCursor(0, 3);
    lcd.print("0L");
  }


text:
Rc car which returns to middle when left or right button is not pressed
Hi i am currently working on a school project , my only problem is that i want my RC car to return to middle direction (which i have set to 66 in the servo motor) when the left or right button is not pressed . i used if statements but it doesn't work. Are there any function that i can use ?
Here is my code for the transmitter i used the RC-Switch Library (https://www.arduinolibraries.info/libraries/rc-switch)
#include <RCSwitch.h>
#include <Servo.h>

const int IN1 = 3;
const int IN2 = 4;
const int trigPin = 5;
const int echoPin = 6;
const int Buzzer = 8;
int distance = 0;
int value = 0;
long duration;
RCSwitch mySwitch = RCSwitch();
Servo myservo;

void setup () {
  mySwitch.enableReceive(0);
  myservo.attach(7);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
  pinMode(echoPin, INPUT); // Sets the echoPin as an Input
  pinMode(Buzzer,OUTPUT);
  Serial.begin (9600);    // Debugging only
  Serial.println ("Receiver Ready");
}

void loop () {

  delayMicroseconds(10);
  // Clears the trigPin
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  // Sets the trigPin on HIGH state for 10 micro seconds
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  // Reads the echoPin, returns the sound wave travel time in microseconds
  duration = pulseIn(echoPin, HIGH);
  // Calculating the distance
  distance= duration*0.034/2;
  // Prints the distance on the Serial Monitor
  //Serial.print("Distance: ");
  //Serial.println(distance); //distance is the returned integer,

 if (mySwitch.available()) {

    value = mySwitch.getReceivedValue();
    Serial.println (value);

      if(value == 1) {
        forward ();
        Serial.println (" = forward");
      }

      if(value == 2){
        backward ();
        Serial.println (" = backward");
      }

      if(value == 3) {
        left ();
        Serial.println (" = left");
      }

      if(value == 4) {
        right ();
        Serial.println (" = right");
      }
      Serial.print(" ");
    }
  mySwitch.resetAvailable();
  //myservo.write(45);
}

void forward () {
  digitalWrite (IN1, LOW);
  digitalWrite (IN2, HIGH);
}

//value = mySwitch.getReceivedValue();
void backward () {

  if ((distance < 50)&& (value == '2'))
  {
    digitalWrite (IN1, LOW);
    digitalWrite (IN2, LOW);
    digitalWrite (Buzzer, HIGH);
  }
  else if ((distance > 50)&& (value == '2'))
  {
    digitalWrite (IN1, HIGH);
    digitalWrite (IN2, LOW);
    digitalWrite (Buzzer, LOW);
  }
}
// 66 is middle

void right () {
  if (value == 4){
    myservo.write(110);
  } else
  myservo.write(66);
}

void left () {
  if (value == 3){
    myservo.write(50);
  }else
 myservo.write(66);
}

And Here is The transmitter code
// TRANSMITTER CODE

#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
// Assigning controller buttons to Digital Pins
 int forward = 11;
 int reverse = 10;
 int rightTurn = 9;
 int leftTurn = 8;

void setup () {
  pinMode (forward, INPUT_PULLUP);
  pinMode (reverse, INPUT_PULLUP);
  pinMode (rightTurn, INPUT_PULLUP);
  pinMode (leftTurn, INPUT_PULLUP);
  mySwitch.enableTransmit(7);
  Serial.begin (9600);         // Debugging only
  Serial.println ("Transmitting");
}

void loop () {
  if (digitalRead(forward) == LOW) {
    mySwitch.send(1, 24);
    Serial.println ("Forward");
  }

  if (digitalRead(reverse) == LOW) {
    mySwitch.send(2, 24);
    Serial.println ("Reverse");
  }

  if (digitalRead(leftTurn) == LOW) {
    mySwitch.send(3, 24);
    Serial.println ("Left Turn");
  }

  if (digitalRead(rightTurn) == LOW) {
    mySwitch.send(4, 24);
    Serial.println ("Right Turn");
  }
}

do not use statements such as but it doesn't work .... there is no useful information contained in such statements ...... statements such as it keeps turning left, actually describe what is happening

You send values from your transmitter when you press a button but not when you release them. The simplest solution would be sending the state of all buttons in every iteration if the transmitter has enough capacity. (I think it has for just these four values)
Add an enum to make the code more readable:
enum {
    FORWARD_ON = 0,
    FORWARD_OFF, // It will be 1.
    BACKWARD_ON, // It will be 2 and so on...
    BACKWARD_OFF,
    RIGHT_ON,
    RIGHT_OFF,
    LEFT_ON,
    LEFT_OFF
};

So a sending function will be like this:
if (digitalRead(forward) == LOW)
    mySwitch.send(FORWARD_ON, 24);
else
    mySwitch.send(FORWARD_OFF, 24);
// And so on for every button...

Then by reception you should add some state variables and store the received values:
int steer_right = 0;
int steer_left = 0;

// ...

loop() {

// ...

value = mySwitch.getReceivedValue();

switch (value) {
    case RIGHT_ON:
        steer_right = 1;
        break;
    case RIGHT_OFF:
        steer_right = 0;
        break;
    case LEFT_ON:
        steer_left = 1;
        break;
    case LEFT_OFF:
        steer_left = 0;
        break;

    // ... (throttle)

    default:
        break;
}

// ...

}

Then you evaluate what you got:
if (steer_right && !steer_left)
    right();
else if (!steer_right && steer_left)
    left();
else
    straight();

// ... (throttle)

Hi it's me again, I'm a bit confused at the switch (value) part , should i declare the RIGHT_ON and RIGHT_OFF as variables or enum them ?

and also is there anyway i can speed up the sending speed?

another question is it keeps printing when the button is off which i think is the cause why it's slow to send and receive , is there any way i can prevent this ?

keeps printing what? ..... do not print when the button is not pressed (use if statement or case statement )


text:
ESP8266 timer to trigger actions (logic issue)
so I have an application in which there are 2 specific times (eg 9AM, 6PM) where a variable curPos is updated. Everything is converted in ms since 00:00 (9AM = 32400000, 6PM = 64800000). Now, the actions (curPos updates) should be triggered every day at these times. To retrieve the current real time (always in ms) I'm sending a http request to a website. This is done only once in the setup().
The idea is that I have to access somehow (http request) the current real time in order to determine when are 9AM and 6PM in my ESP8266, since the start of the sketch. The current real time is needed only once at the beginning (in case there's an issue and the sketch restarts).
Then I can calculate the difference between the current real time and the timers.
The next step would be to translate the values into a 24hour cycle starting at the startup/reset time, so that it can repeat itself without need to request again the real time.
I'm lost in the logic on how to deal with this and with millis() to check when it's time to trigger one of the actions.
This is what I'm doing now with the HTPP GET payload in the setup() (I can successfully retrieve the 3 values in ms from the GET response)
      String payload = http.getString();

      int commaIndex = payload.indexOf(',');
      int secondCommaIndex = payload.indexOf(',', commaIndex + 1); //Search for the next comma just after the first

      mainTime = payload.substring(0, commaIndex).toInt(); //current real time in ms
      timers[0] = payload.substring(commaIndex + 1, secondCommaIndex).toInt(); //9AM in ms
      timers[1] = payload.substring(secondCommaIndex + 1).toInt()); //6PM in ms

      timers[0] = abs(mainTime - timers[0]); //the time difference before reaching the first timer (in ms)
      timers[1] = abs(mainTime - timers[1]); //the time difference before reaching the second timer (in ms)

      // my attempt to turn the time differences into a 24hrs "local" (in the sketch) time
      //dayMs is 24hrs in ms (86400000)
      if(timers[0] < 0)
        timers[0] = dayMs - timers[0];

      if(timers[1] < 0)
        timers[1] = dayMs - timers[1];

and in the loop I'd need a comparison (I think) but I'm just really lost on this
//I think millis need to be reset after 24hrs since the start of the sketch?

if(millis() == timers[0]){
      curPos = 1; //first timer expired then trigger
  }else if(millis() == timers[1]){
      curPos = 7; //second timer expired then trigger
  }

thanks!

you think that you catch the exact millisecond to trigger the event?

it would be better to set time to TimeLib and then test if it is 9AM or 6PM.

Indeed. You can also use NTP to grab the current time off the internet and feed it to TimeLib.

set up a tick variable ... increment it inside the loop() every second or every minute (even every hour ... whatever works for you) .... then simply monitor the value of tick

thanks, so: - I don't think I can catch the exact ms to trigger the event and I'm looking for suggestions on how to do this. - I tried NTP and there were issues with the timezone so the http request is a good substitute. - Ok for the tick variable but I'm still a bit confused on how to turn everything in 24hrs (since the original time). - I will check TimeLib (I assume is a Library?)

For time-keeping on a long-term basis, you are going to run up against clock drift and offsets from tick-tracking. You may be better off using a real-time-clock (RTC) such as the DS1307. This and RTCs like it are often available in breakout boards with a coin-cell battery holder built in.
You would still get the time from your HTTP or NTP source, but the RTC will be much better at keeping the "right" time as you would expect a wristwatch or desk clock to do, versus using the MCU for counting milliseconds.
You can use Ticks or millis() to set up a periodic read of the RTC every second or every 10 seconds, etc. Avoid using the MCU clock for long-term real-world time keeping.

I describe how I do it in my project. I use the Time library a.k.a TimeLib. I set the time I retrieved not by NTP but over modbus from a device which is the source of other data in my project. In your case, you have the http request.
The input to set the time to TimeLib is UNIX epoch. Epoch are seconds from 1970-01-01. If you set only the seconds of the current day, the date would stay 1970-01-01.
And then I have for example this function
boolean restHours() {

  const int BEGIN_HOUR = 9;
  const int END_HOUR = 22;

  int hourNow = hour(now());

  if (hourNow >= BEGIN_HOUR && hourNow < END_HOUR) {
    if (state == RegulatorState::REST) {
      state = RegulatorState::MONITORING;
    }
    return false;
  }
  if (state == RegulatorState::MONITORING) {
    state = RegulatorState::REST;
    clearData();
  }
  return true;
}

now() returns the 'epoch' time. hour(now()) returns the current hour.
or in other function I test if it the should be executed. it enables the execution of the rest of the function only in interval 9:00 to 10:00
void susCalibLoop() {

  const byte SUSCALIB_HOUR = 9;
  static boolean done = false;

  int hourNow = hour(now());

  if (hourNow != SUSCALIB_HOUR) {
    if (done) {
      done = false;
    }
    return;
  }
  if (done)
    return;
...


text:
Do You Put a Break after the Last case in a Switch?
The Arduino Switch Case Reference has a switch structure written two different ways:
First in the Syntax as:
switch (var) {
  case label1:
    // statements
    break;
  case label2:
    // statements
    break;
  default:
    // statements
}

and then in the Example code as:
  switch (var) {
    case 1:
      //do something when var equals 1
      break;
    case 2:
      //do something when var equals 2
      break;
    default:
      // if nothing else matches, do the default
      // default is optional
      break;
  }

Is there any reason to (or not to) add a break; in the default: case? Does the need for 'break;' change if the final case is not default:?

This isn't an Arduino specific question and it was already answered on SO.

break is an exit command, since the loop is exiting anyway, you do not need it ..... you should use it though because you may cut/paste code, or add another case statement after the last case statement, and also to form a habit to use it in case statements in general

I'd like to argue that this is Arduino specific because not all C++ rules apply to an Arduino. For example, the lack of an exception system prevents Try and catch.

You can, but you don't have to.
Should you? That's up to you.
I do. That's because it's then simple to add another case at the end of the structure in the future if you want, and you don't have to remember to add the break to the existing last case.


text:
How to upload program to custom arduino board without USB FTDI and making it read only?
If I was to mass produce a microcontroller board I have designed based around the atmega328 (very similar to an arduino uno) but for one embedded task where I want one program only to be stored on it. I want to make the program read only and impossible to access and impossible to overwrite. The board will not include a USB FTDI chip in order to prevent another program being uploaded via arduino IDE. How would I upload said program to the microcontroller?
Would I have to make use of ICSP pins (I dont know much about that) and if this is an impossible task and so a USB will have to be integrated to upload programs... How would i prevent other programs overwriting the main program and also prevent this program from being viewed?
[The main program is written in the arduino IDE]

you use pins built into the 328 to program it. 2. removing the pins will help, but ultimately, you can't.

I think you cannot prevent overwriting the firmware, neither prevent viewed by others.
However, you can detect that someone overwrites it (besides you), by reading some code from e.g. EEPROM based on the content of your firmware. If you read a different code, than you can act upon it.

You can prevent reading by setting the lock fuses


text:
Arduino Serial Writing Array Problem
I am trying to communicate Pc - Arduino Uno.
My Arduino code is here: (It is working as below)
int ndx = 0;
char pack[12];
void setup() {
Serial.begin(9600);
while(!Serial){;}
}

  void loop() {

   while(Serial.available() ){
    char rb = Serial.read();
    pack[ndx] = rb;
    ndx++;
    Serial.write(rb);
    if(ndx == 12){
        ndx=0;
      }
    }
    }

If I try in
Serial.write(rb);

Like that:
Serial.write(pack[ndx]);

Program is acting weird, I mean sending weird bytes. I do not know what is the reason. Can you help me, please? What is going on in code?
My python code:
https://github.com/mucahitkayadan/Python

A character is send as a ascii character, not the decimal value. Try to cast it to an int or try using DEC as second parameter. With such a low baudrate, should it be better to add a seperator? for example a comma between the values.

we do not see the definition of the array

@Juraj Sorry, There were some unnecessary definions. When I was posting,I deleted them, and array definion was out of sight. I fixed,edited it.

@Jot I can add comma in between every values in python list, but will it be easier? I have not understood the algorithm you are talking about.

Post the code that is not working

@Juraj What is the error? Working on me. It needs serial connection and I have. If you don't have, maybe thats why. I am not sure but it is working on me.

you replace Serial.write(rb); to Serial.write(pack[ndx]); and get?:
char rb = Serial.read();
pack[ndx] = rb;
ndx++;
Serial.write(pack[ndx]);

then you read an uninitialized array item on the next index

Actually, it is working without using array. I you use directly " Serial.write(inByte); " it is working normally.
But if you use " Serial.write(array[index]); " it is working weird. Sending 0-255 random numbers or maybe not random but I do not know reason or meaning of that weird numbers.

I changed the aswer

I have to process the data, so I need to process with array, namely 'pack[index]', thats why I don't want use Serial.write(rb); When I put "Serial.write(pack[ndx]);" program giving me different weird numbers.

do you have ndx++ before write(pack[ndx]);?

Yes, absolutely for this reason. Now it is working. So basic thing I can not believe myself, overlooked.

And, can I send data under for loop? Like that:
for(int i = 0 ; i < 12; i++){ Serial.write(pack[i]); }

yes you can do it in a for loop

The sequence:
pack[ndx] = rb;
ndx++;
Serial.write(rb);

modifies ndx before printing. So in your first case - printing 'rb' - you'll print the value you just stored in the array; in the second case printing 'pack[ndx]' - you'll print whatever happens to be in the following member of the array. Swapping the second and third statements in my excerpt will fix it.

My packs have 12 bytes and I have totally 7 pack.I tried to just send my index, namely 'ndx'. And it receives correctly. I mean, pc receives 0-11 numbers for every time for every pack. It is expected. That thing is what I could not understand, for every iteration rb and pack[rdx] are equal. Why write(rb) is working correctly but write(pack[ndx]) does not work?


text:
How we can implement the interrupt?
I want to implement the Interrupt on the Adafruit_RGBLCDShield Select button to start/stop the data logging?

There is no interrupt for the select button.
The buttons, and the LCD itself, are connected to an I2C IO expander. Reading the state of the buttons is a polling operation - the library sends a request to the IO expander to get the current state, and then returns that to you as a bitmap.
While it is true the IO expander can be configured to generate an interrupt signal on one of its IO pins when an input changes state, that pin is not connected to anything on the PCB, so you would need to physically modify the shield to connect it to an interrupt pin on the Arduino. And on top of that, the library doesn't implement the settings needed to enable the interrupt - so you'd have to resort to configuring it all manually.
If you really want to do that kind of thing, then you will have to examine the datasheet for the IO expander and learn how it works.


text:
Using external reset to trigger radio receipt
I am designing a low-power RF application using an ATTiny (Adafruit Trinket).
When the system receives a radio signal, it needs to read some sensors, and transmit with that data. Because I am short on pins, I am trying to think of creative (low-pin count) ways to design this system.
My current idea is:

Put the AVR to sleep.
Connect the radio's Rx Interrupt pin to the AVR Reset pin
When the AVR is reset, check the radio buffer

(if there's nothing in the buffer, assume this is a real power-on reset and go back to sleep)

Otherwise, read sensors, transmit
Go back to sleep

My aim here is that the AVR will use very little power while sleeping (furthermore, it will only need to wake up a few times per day).
Is it reasonable to use the AVR reset pin in this manner? Any gotchas to be aware of?

No gotchas I can think of, except for the fact that the ATtiny's memory
will be re-initialized every time you reset it. But I assume you are
aware of that.
Note that, if you want some data to be preserved across a reset, it is
possible using either the on-chip EEPROM or the .noinit
section of the RAM.

You can also use the EEARL and EEARH registers to store 2 bytes between resets, as those retain their value between resets. This behavior however isn't specified in the datasheet, so not really advised for critical/professional  applications.


text:
Arduino controlled by USB gamepad
I want to control my Arduino with USB gamepad. I know that exists library for USB keyboard for Arduino but I don't know any library for usb gamepad. I have PS3 styled gamepad. I dont want to use shield.
Any solution or help?

Does the controller act as a HID device?

Yes, Windows Device Managers says its HID-compliant game controller

If you've got a 32u4-based Arduino, I would start looking at the HID library, then.

and what model is your Arduino?

A USB host shield or mini board depending on your Arduino board should work.
https://github.com/felis/USB_Host_Shield_2.0
https://www.circuitsathome.com/usb-host-shield-hardware-manual/


text:
Can you help me trim my code?
First of all I want to be clear, I'm not very skilled in programming methods, all the C I learned was for various Arduino projects.
That being said, I just finished a project that reads some data from ELM327 via a HC-05 Bluetooth module and prints it to a 3.5 inch screen. All is working as intended, but apparently I have capped my Arduino UNO's memory because the sketch utilizes 99% of it. At the moment this is not very troublesome, but if sometime in the future I want to add more data to be read, I won't be able to do it.
With this in mind, I was looking for some advice on how I could rewrite my code in order to occupy less memory. I tried some stuff, but had little effect. As I said, I'm not familiar with advanced programming techniques.
LE: So I used all of your advice, I got rid of all the fonts, modified the MCUFRIEND library to only work with my display and got rid of some repeating code, and now the sketch got 35% smaller. Thanks to all.

Sketch uses 21216 bytes (65%) of program storage space. Maximum is 32256 bytes.
  Global variables use 642 bytes (31%) of dynamic memory, leaving 1406 bytes for local variables. Maximum is 2048 bytes.

Here's the (old) code:
#include <SoftwareSerial.h>
#include <Adafruit_GFX.h>
#include <MCUFRIEND_kbv.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#include <Fonts/FreeMonoBold12pt7b.h>
#include <Fonts/FreeMonoBold18pt7b.h>
#include <Fonts/FreeMonoBold24pt7b.h>

SoftwareSerial BTSerial(10, 11);
MCUFRIEND_kbv tft;

#define BLACK   0x0000
#define WHITE   0xFFFF
#define GREY    0x8410

byte inData;
char inChar;
String constructor="";
String deconstructor="";
int A;
int B;
bool busy = false;

void setup()
{
    Retry:
    Serial.begin(9600);
    BTSerial.begin(38400);
    delay(1000);

    BTSerial.println("0100");
    while(BTSerial.available()>0)
    {
      inData=0;
      inChar=0;
      inData = BTSerial.read();
      inChar=char(inData);
      constructor = constructor + inChar;
      delay(20);
   }
    if (constructor.length()>0)
    {
      Serial.println("Conectat");
    }
    else {
      goto Retry;
      Serial.println("retry");
    }
    delay(5000);
    ReadData();
    basicConditions();

    tft.reset();
    uint16_t identifier = tft.readID();
    if (identifier == 0xEFEF) identifier = 0x9486;
    tft.begin(identifier);

    tft.fillScreen(BLACK);
    tft.setRotation(1);
    tft.setTextColor(WHITE);

    tft.fillRect(10, 40, 70, 40, GREY);
    tft.fillRect(10, 140, 70, 40, GREY);
    tft.fillRect(10, 240, 70, 40, GREY);
    tft.fillRect(140, 70, 200, 100, GREY);
    tft.fillRect(150, 220, 180, 60, GREY);
    tft.fillRect(370, 40, 70, 40, GREY);
    tft.fillRect(370, 140, 70, 40, GREY);
    tft.fillRect(370, 240, 70, 40, GREY);

    tft.setCursor(170,10);
    tft.setFont(&FreeMonoBold12pt7b);
    tft.print("Dacia 4X4");

    tft.setCursor(30,35);
    tft.setFont(&FreeMonoBold9pt7b);
    tft.print("Cuplu");
    tft.setCursor(80,70);
    tft.setFont(&FreeMonoBold18pt7b);
    tft.print("%");

    tft.setCursor(15,120);
    tft.setFont(&FreeMonoBold9pt7b);
    tft.print("Presiune");
    tft.setCursor(15,135);
    tft.print("motorina");
    tft.setCursor(82,170);
    tft.setFont(&FreeMonoBold12pt7b);
    tft.print("bar");

    tft.setCursor(15,220);
    tft.setFont(&FreeMonoBold9pt7b);
    tft.print("Presiune");
    tft.setCursor(20,235);
    tft.print("admisie");
    tft.setCursor(82,270);
    tft.setFont(&FreeMonoBold12pt7b);
    tft.print("bar");

    tft.setCursor(395,20);
    tft.setFont(&FreeMonoBold9pt7b);
    tft.print("Temp.");
    tft.setCursor(382,35);
    tft.print("Antigel");
    tft.setCursor(450,70);
    tft.setFont(&FreeMonoBold12pt7b);
    tft.print("C");

    tft.setCursor(395,120);
    tft.setFont(&FreeMonoBold9pt7b);
    tft.print("Temp.");
    tft.setCursor(382,135);
    tft.print("Admisie");
    tft.setCursor(450,170);
    tft.setFont(&FreeMonoBold12pt7b);
    tft.print("C");

    tft.setFont(&FreeMonoBold9pt7b);
    tft.setCursor(370,235);
    tft.print("Debit Aer");
    tft.setCursor(445,270);
    tft.setFont(&FreeMonoBold9pt7b);
    tft.print("g/s");

    tft.setFont(&FreeMonoBold12pt7b);
    tft.setCursor(150, 62);
    tft.print("Turatie (RPM)");

    tft.setFont(&FreeMonoBold12pt7b);
    tft.setCursor(152, 212);
    tft.print("Viteza (KM/H)");

}

void loop()
{
  cuplu();
  PresMot();
  PresAdm();
  TempAntig();
  TempAdm();
  MAF();
  RPM();
  viteza();
}
void basicConditions(){
    if(constructor.indexOf(">")>0)  {
    busy=false;
    constructor="";
  }
}
void ReadData()
{
  if (BTSerial.available()>0)
    busy = true;
  while(busy = true && constructor.indexOf(">")<0)
  {
    if (BTSerial.available()>0){
    inData=0;
    inChar=0;
    inData = BTSerial.read();
    inChar=char(inData);
    constructor = constructor + inChar;
    //Serial.println(constructor);
    //Serial.println(busy);
  }
  }
  //Serial.println("done");

  if (constructor.indexOf(">")>0){
    deconstructor=constructor.substring(11,13);
    A = strtol(deconstructor.c_str(),NULL,16);
    if (constructor.length()>15) {
        deconstructor = constructor.substring(14,16);
            B = strtol(deconstructor.c_str(),NULL,16);
    }
    else B = 0;
  }
}
void cuplu() {
  if (busy == false){
    BTSerial.println("01041");
      ReadData();
    tft.setTextSize(1);
    tft.setFont(&FreeMonoBold18pt7b);
    tft.setCursor(10, 70);
    tft.fillRect(10, 40, 70, 40, GREY);
    tft.print(A/2.55, 0);
  }
  basicConditions();
}
void PresMot() {
  if (busy == false){
      BTSerial.println("010A1");
      ReadData();
      tft.setTextSize(1);
      tft.setFont(&FreeMonoBold18pt7b);
      tft.setCursor(10, 170);
    tft.fillRect(10, 140, 70, 40, GREY);
    tft.print((3*A)/100.0, 1);
  }
  basicConditions();
}
void PresAdm() {
  if (busy == false){
      BTSerial.println("010B1");
      ReadData();
      tft.setTextSize(1);
      tft.setFont(&FreeMonoBold18pt7b);
      tft.setCursor(10, 270);
    tft.fillRect(10, 240, 70, 40, GREY);
    tft.print((A/100.0), 1);
  }
  basicConditions();
}
void TempAntig() {
    if (busy == false){
      BTSerial.println("01051");
      ReadData();
      tft.setTextSize(1);
      tft.setFont(&FreeMonoBold18pt7b);
      tft.fillRect(370, 40, 70, 40, GREY);
    tft.setCursor(370, 70);
    tft.print(A-40);
    }
  basicConditions();
}
void TempAdm() {
    if (busy == false){
      BTSerial.println("010F1");
      ReadData();
      tft.setTextSize(1);
      tft.setFont(&FreeMonoBold18pt7b);
      tft.fillRect(370, 140, 70, 40, GREY);
    tft.setCursor(370, 170);
    tft.print(A-40);
    }
  basicConditions();
}
void MAF() {
  if (busy == false){
      BTSerial.println("01101");
      ReadData();
      tft.setTextSize(1);
      tft.setFont(&FreeMonoBold18pt7b);
      tft.fillRect(370, 240, 70, 40, GREY);
    tft.setCursor(370, 270);
    tft.print(((256*A)+B)/4.0, 0);
  }
  basicConditions();
}
void RPM() {
  if (busy == false){
      BTSerial.println("010C1");
      ReadData();
      tft.setFont(&FreeMonoBold18pt7b);
    tft.setTextSize(2);
    tft.fillRect(140, 70, 200, 100, GREY);
    tft.setCursor(150, 140);
    tft.print(A/4.0, 0);
  }
  basicConditions();
}
void viteza() {
  if (busy == false){
      BTSerial.println("010D1");
      ReadData();
      tft.setFont(&FreeMonoBold18pt7b);
    tft.setTextSize(2);
      tft.fillRect(150, 220, 180, 60, GREY);
    tft.setCursor(180, 270);
    tft.print(A);
  }
  basicConditions();
}

99% of code is no problem, 80% dynamic ram can be a problem. What is the percentage of the used dynamic ram? The gfx library and the fonts use a lot of memory. You can upgrade to a arduino mega for more ram and extra hardware serial ports, or upgrage to arduino zero or one of the mkr boards for a faster processor, more ram and extra hardware serial port.

Are you trying to reduce Flash (code-space) or RAM (data-space) use? Which one is at 99%? The techniques for reducing either are different.

It says that the sketch size is at 99% and the dynamic memory is at 30%. So I’m guessing that the code size is problematic.

the code for drawing the gray rectangles is in your sketch twice

I assume you mean that are running short of flash memory, rather than
RAM. I base this assumption on the fact that you say that it's 99%
full, and that this “is not very troublesome”. Filling 99% of the RAM
with statically allocated data would certainly be troublesome. But
please note that it as always better to make your question clear and
explicit, rather than expect the respondents to make guesses.
Now, look at your font files. Each one of them ends with a comment
similar to this:
// Approx. 1672 bytes

Just adding those numbers we get:
FreeMonoBold9pt7b   1672 bytes
FreeMonoBold12pt7b  2402 bytes
FreeMonoBold18pt7b  4485 bytes
FreeMonoBold24pt7b  7469 bytes
------------------------------
TOTAL              16028 bytes

That's about 49% of your Arduino's flash. So that's the first place you
should be looking to if you want to save flash. Do you really need
these four different font sizes? And more specifically, do you really
need the (very flash hungry) largest sizes? Getting rid of some of them
is the easiest way to save flash.
If you really want to keep them all, your next option is to trim the
fonts in order to have only the characters you are actually using. This
can be a lot of work, but it should be a very effective way of
significantly reducing their flash footprint.
If you decide to take this path, the first step is to take note of what
characters you need at each font size. From a cursory look at your
source, it seems to me that the 18 pt font is only used for
printing “%”, “.”, the ten digits, and possibly “-”. That's a lot less
than the full ASCII repertoire the font supports. And I can't see where
you are using the 24 pt font. Look into an ASCII table and take
note of the smallest continuous range that contains all the characters
you use at one font size. Then trim the Glyphs array of the font to
keep only that range, and fix the first and last fields of the
GFXfont struct accordingly.
Next step is what will take most of the work. For each character you
actually need, take note of the bitmapOffset field of its glyph and
the next one. This way you know the range of offsets that are used by
that character. Then remove from the font's Bitmaps array all the
bytes that are at offsets you don't need. While doing this, you will be
changing the offsets of the bytes you keep, so you should update the
bitmapOffset fields on the Glyphs array accordingly.
Yes, that's quite some work, but you should end up with custom fonts
that are a lot lighter than the original ones, and yet capable of
displaying everything you are displaying now. Maybe you could write a
program to automate all this. Maybe someone already did that and you can
find it through a Web search...

Thanks for the advice and sorry I wasn’t very clear about the problem. First thing I’ll do is to get rid of the fonts permanently and go from there.

The documentation for the MCUFRIEND_kbv project has a file describing how to use.
This document has the statement:
Most of these controllers are #define SUPPORT_xxxx by default.
You can save Flash memory on a Uno by commenting out the macro(s) in MCUFRIEND_kbv.cpp

So you open MCUFRIEND_kbv.cpp and comment out support for the controllers you aren't using.
You can also reduce the number of different fonts you use to save Flash space.

Strings get allocated, reallocated, and deallocated as you use them, which can leave the heap - the bottom end of RAM memory - fragmented and the fragments essentially unusable. The memory report from the compiler can't show this; it happens at runtime.
If instead, you pre-allocate character arrays of a sufficient size for the eventual maximum text you want to put in them, they will stay in one place, neither growing nor shrinking, but also won't create those unused but unusable "holes" in the RAM.
Update:
Instead of:
String xyz;
xyz = "Hello";
xyz = xyz + ',';
xyz = xyz + "World!\n";

, you'd write:
#define XYZ_MAX  25    // or whatever size you need

char xyz[XYZ_MAX+1];
strcpy(xyz, "Hello";      // overwrites whatever is there
strcat(xyz, ", World!\n"; // appends whatever is there

You can further optimize RAM by directing the compiler to store the string literal ("Hello", etc.) in Flash. That's another topic, but here is a link to an article about it in the Arduino Playground, to get you started.

This is something I wasn't aware of. Maybe you could give me a short example on how to do it exactly.

you are repeating the same code in the 8 functions at the end of your sketch (note: the code is badly indented and the command sequence is inconsistent between functions)
similar thing is occurring at the middle of your sketch
here is the data that repeats
you could use one function and a lookup table (array)
this is the repeating data
+---------------+-------+-------------------------------+---------------+-----------------------+
|  println     setTextSize        fillRect                 setCursor          print             |
+---------------+-------+-------------------------------+---------------+-----------------------+
|   "01041"     |   1   |    10,  40,  70,  40, GREY    |    10,  70    |   A/2.55         , 0  |
|   "010A1"     |   1   |    10, 140,  70,  40, GREY    |    10, 170    |   (3*A)/100.0    , 1  |
|   "010B1"     |   1   |    10, 240,  70,  40, GREY    |    10, 270    |   (A/100.0)      , 1  |
|   "01051"     |   1   |   370,  40,  70,  40, GREY    |   370,  70    |   A-40                |
|   "010F1"     |   1   |   370, 140,  70,  40, GREY    |   370, 170    |   A-40                |
|   "01101"     |   1   |   370, 240,  70,  40, GREY    |   370, 270    |   ((256*A)+B)/4.0, 0  |
|   "010C1"     |   2   |   140,  70, 200, 100, GREY    |   150, 140    |   A/4.0          , 0  |
|   "010D1"     |   2   |   150, 220, 180,  60, GREY    |   180, 270    |   A                   |
+---------------+-------+-------------------------------+---------------+-----------------------+

you could also calculate some of the values in the first 6 functions


text:
Need help with a program for a button to change the display on an OLED display
So I am programming an OLED display from my Arduino Uno. I am trying to have a button that switches the different words on the display. (The words are just placeholders for programs as of now.) My program has a button that changes a counter, and an if test to see what the counter is so it can display the appropriate word. The problem is, whenever I press the button, the display turns black and doesn't do anything anymore. When I start/reset the Arduino, it displays TEMPERATURE, but it should say TIME.
#include <OLED_I2C.h>

OLED  myOLED(SDA, SCL, 8);

extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];
extern uint8_t BigNumbers[];

//constants:
const int buttonPin = 2;

//variables:
byte oldButtonState = HIGH;
int screenNumber = 0;
byte buttonState = 0;

void setup()
{
  myOLED.begin();
  myOLED.setFont(SmallFont);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() { //myOLED.print formats with (string, text_placement,     pixel_location)
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // Test if the button is being pressed
  if (buttonState == HIGH) {
    myOLED.clrScr();
    myOLED.update();
    oldButtonState = buttonState;
    if (screenNumber != 2) {
      ++screenNumber;
    }
    else {
      screenNumber = 0;
    }
    //delay a little to avoid bouncing
    delay(200);
    }

  //Test for the screenNumber variable and change to the
  //according screen
  if (screenNumber == 0) {
    myOLED.print("TIME", CENTER, 16);
    myOLED.update();
  }
  else if (screenNumber == 1) {
    myOLED.print("TEMPERATURE", CENTER, 16);
    myOLED.update();
  }
  else if (screenNumber == 2) {
    myOLED.print("DIRECTION", CENTER, 16);
    myOLED.update();
  }
  else {
    myOLED.print("ERROR", CENTER, 16);
    myOLED.update();
  }
}

What is your question? What is your sketch doing that it's not suppose to be doing?

have a close look at your code and try to figure out why it is displaying screen #1

I didn't see a problem in the code - but maybe I overlooked something.
Maybe your code is not the problem but your hardware. Did you make sure the input is connected to GND if it the button is not pressed?
Notes and Warnings
If the pin isn’t connected to anything, digitalRead() can return either HIGH or LOW (and this can change randomly).
https://www.arduino.cc/reference/en/language/functions/digital-io/digitalread/
I suggest you use serial to show the value of buttonState after this line
buttonState = digitalRead(buttonPin);

Maybe it is not what you expect it to be.

this doesn't apply. he has INPUT_PULLUP

I changed the input mode to INPUT and added the Serial.print(buttonState); but it only prints 0 even when I am pressing the button. Any clue why that might be?

So I switched the side that the wire connecting to PIN 2 was and now it says 1 when I am not pressing it and 0 when I am.

Good that you found the problem. Sometimes we forget to double check the little things (they connections) and concentrate only on the code...

You have pinMode(buttonPin, INPUT_PULLUP); so I assume, you connected the button between pin and ground. With pull-up the pin will read HIGH if it is not grounded. If the button is pushed, grounding the button pulls it LOW. So you should test if the button is pressed with comparing to LOW.
We have this misleading idea in our heads that active is HIGH and not active is LOW. But you can see it this way:

button pushed down (low) is LOW
button not pushed is up (high) reading HIGH

I fixed the problem. It turned out that the value being returned by the button was 1 when it was not being pressed and 0 when it was being pressed. My new code is:
#include <OLED_I2C.h>

OLED  myOLED(SDA, SCL, 8);

extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];
extern uint8_t BigNumbers[];

//constants:
const int buttonPin = 2;
const int debug = 0;

//variables:
int screenNumber = 0;
byte buttonState = 0;

void setup()
{
  myOLED.begin();
  myOLED.setFont(SmallFont);
  pinMode(buttonPin, INPUT);
  myOLED.clrScr();
  myOLED.print("TIME", CENTER, 16);
  myOLED.update();
  Serial.begin(9600);
}

void loop() { //myOLED.print() formats with (string, text_placement, pixel_location)
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);
  Serial.println(buttonState);
  if (debug == 1) {
    myOLED.clrScr();
    myOLED.print("Start", CENTER, 16);
    myOLED.update();
    delay(debugDelay);
  }
  // compare the buttonState to its previous state
  if (buttonState == 0) {
    if (screenNumber < 2) {
      screenNumber = screenNumber + 1;
    }
    else {
      screenNumber = 0;
      }
    //delay a little to avoid bouncing
    delay(100);
    }

  //Test for the screenNumber variable and change to the
  //according screen

  if (screenNumber == 0) {
    myOLED.clrScr();
    myOLED.print("TIME", CENTER, 16);
    myOLED.update();
  }
  else if (screenNumber == 1) {
    myOLED.clrScr();
    myOLED.print("TEMPERATURE", CENTER, 16);
    myOLED.update();
  }
  else if (screenNumber == 2) {
    myOLED.clrScr();
    myOLED.print("DIRECTION", CENTER, 16);
    myOLED.update();
  }
  else {
    myOLED.clrScr();
    myOLED.print("ERROR", CENTER, 16);
    myOLED.update();
  }
}

and what did I write in my answer? you accepted the wrong answer

Edgar told me to use the Serial.print() to find out what the value of the button was. That helped me more. If you had just said it is the inverse of what I expected it would have made more sense.


text:
Second SD not writing
simple problem I can't see the reason behind, the sd card writes the first file fine, but the second doesn't write at all. Can any one see why?
    #include <SPI.h>
    #include <SD.h>
    const int chipSelect = BUILTIN_SDCARD;
    File datafile;
    void setup()
    {
      Serial.begin(38400);
      analogReadResolution(13);
      //Initialize SPI pins to avoid errors
      //USB host SS pin
      pinMode(9, OUTPUT);
      delay(200);
      digitalWrite(9, HIGH);
      delay(200);
      pinMode(chipSelect, OUTPUT);
      delay(200);
      digitalWrite(chipSelect, HIGH);
      delay(200);

      Serial.print("Initializing SD card...");

      // see if the card is present and can be initialized:
      if (!SD.begin(chipSelect)) {
       Serial.println("Card failed, or not present");
  }
  Serial.println("card initialized.");
  File dFile = SD.open("datalog.txt", FILE_WRITE);
  dFile.println("BORK");
  dFile.close();
  char filename[] = "LOGGER00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i / 10 + '0';
    filename[7] = i % 10 + '0';
    if (! SD.exists(filename)) {
      datafile = SD.open(filename, FILE_WRITE);
      break;  // leave the loop!
    }
  }
  Serial.println(filename);
  datafile.print("A0,");
  datafile.println("A1");
  if (!datafile){
    Serial.println("oopsydaisy");
  }
}

void loop()
{
  Serial.print("analog 0 is: ");
  Serial.println(analogRead(0));
  Serial.print("analog 1 is: ");
  Serial.println(analogRead(1));

  datafile.print(String(analogRead(0)));
  datafile.print(",");
  datafile.print(String(analogRead(1)));
  datafile.println();
  delay(1000);
}

please correct the title of your post .... right now it says that the second SD card does not work .... anyone searching for solution to issues with writing  multiple files will miss your post

You should cut your code down to the bare minimum.  You need to work out if:

It's the fact that it's the second file you're opening that causes it to fail, or
It's the way you're building up the filename in your loop, or
It's the way you're handling the file once it's been opened.

You should add extra debugging to your program so you know how your loop is operating. Is it checking for the existence of the files correctly? Is it looping too far? Not at all? Is the filename being created properly?
You haven't properly described your symptoms. Does the file actually get created? If so, is it just that it is empty? (I suspect so).
Why do I suspect that?  Simple:
The SD library uses a certain amount of crude caching. Nothing gets written to the SD card itself until either a whole block of data (512 bytes) has been written, or you close the file. Or manually flush the data to the card.
When doing periodic writing to a file like that it is better to open the file as (O_READ | O_WRITE | O_APPEND) before each block of writes, then close it afterwards. This ensures that the file is in a good state between each sampling period and all the data is written and the FAT updated properly.
So your method should be:

Find your unused filename.
Open the file FILE_WRITE (or (O_READ | O_WRITE | O_CREAT) - different versions of the library define it slightly differently) to make the file.
Close the file.

Then on each loop iteration where you want to write:

Open the file again as (O_READ | O_WRITE | O_APPEND)
Write your data.
Close the file.

@Juraj Regardless of whether it has append or not, it has O_CREAT, so it will make the file if it's not there - so it will always succeed on the first file whether it exists or not.

but I see no such operation in his code. and it was not edited

@Juraj Oh, hang on... All that extra irrelevant code was blinding me with extraneous file opens. Buried deep in there is actually an "exists" that I didn't see before... woods... trees... just goes to show the importance of the SSCCE concept instead of just dumping reams of irrelevant code on us.

@trinityalps, what was the problem? What from Majenko's answer helped?

You do not close the second file.
The examples show that you should close the file after every write and open it again before next write. Opening the file with SD library using FILE_WRITE flags, opens it for append if the file exists.
In my project I have a MCU with enough RAM (Mega, esp8266 or M0) so I cache the rows into 2000 bytes buffer and write them to file if the memory cache is full.


text:
sending and recieving data from esp8266
We're trying to make an network of connected cars in which the status of one car is continuously updated to the nearby cars (for example, speed, gear, brakes, etc.).
Can I continuously send out sensor data via ESP8266 and and any nearby ESP8266 can pick it up? Is it possible? Or if there's any other method?

yes, that's completely possible. you can go ESPNOW or mesh or a pre-setup LAN.

Yes, you can - if all the "cars" are on the same WiFi network.
If that is the case, then I'd recommend using UDP as your transport layer, and either broadcast or multicast the packets.
I use UDP and Multicast to send sensor data from multiple sensors to multiple receivers on my network. All nodes subscribe to the same multicast address, and the sensors include their own ID in the packet to identify them. A sensor sends out one packet, and all the other nodes can receive it.
However, if there is no active WiFi network already established between the "cars" then no, there's not a lot you can do with an ESP8266. It communicates using IP, and that relies on there being an established layer 2 network (WiFi / Ethernet, etc) already in existence. You should instead investigate more peer-to-peer communication technologies, or communication technologies that don't rely on establishing a connection to a network of any form.  Maybe the nRF24L01+ would be a better fit?

ESP-NOW fits the problem better than wifi, which has to maintain a connection. ESPNOW also allows encryption (nrf doesn't) and has a nice built-in encoder, with error detection, sender ID, etc.


text:
How can I prepare for a short circuit between 5V and GND pins?
My Arduino Uno controls a couple of LEDs in a watertight enclosure. I'm running wires from ground, a data pin, and the 5 V pin into the enclosure. The Arduino is powered through the DC jack.
What measures can I take to handle failure of the watertight enclosure, which would short-circuit the wires? Can I protect the Arduino, or at least prevent a fire?

simply put a fuse inline with the power jack, say 1 amp (if the LEDs aren't powerful). Also, water won't cause a dead-short, and with only 5v, you don't really have to worry about a fire, unless you're doing something weird you didn't mention.

Nothing weird! Thank you. Do you mean to put the fuse right after the 5V pin? What would be an appropriate fuse for this?

Se this WONDERFULL vid  (is just 8 mins!!!)

they make pre-assembled DC inline fuses (like these) if you don't want to solder in a fuse holder. The fuse should be sized as 1.5-2X your expected load in amps.

@k.Cyborg Thank you, seems I hade several misconception about water.

@dandavis Thanks a lot! Can I just ask, what is the reason to put the fuse between the power supply and Arduino, as opposed to between the Arduino and the potential short?

well you can do both; i'm evidently not sure of your exact setup, i thought everything was in the enclosure, so putting it up-front made sense in terms of preventing a fire. The MCU should not be in a position to blow out if shorted; GPIOs can be pulled to ground or VCC without issue...

What are you using to supply power to the DC jack? The problem with a fuse could be that the power supply can’t provide enough current to blow the fuse, making it useless.

Shoutout to @k.Cyborg who gave a very nice pointer in the comments to a YouTube video on the effects of water on electronics!
One of the things you can do to handle failure of the watertight enclosure better is to use nail polish clear coat and apply that over your board - it will form a protective layer. I use this technique on protoboards with solder bridges on the bottom - adding a layer of clear coat seals them and prevents any shorts due to placing the bottom of the board on a conductive surface, or from fingers touching and shorting things. This would work with water too, to prevent any electrolytic reaction and corrosion, which the video talks about. The video also briefly shows a nail polish clear coat (but doesn't elaborate and says it's a topic for another video).
Another point to consider when talking about shorts. In my case, I was powering my Arduino Pro Mini through the Vin , connected to a 9v battery. I fried the LDO on it by briefly reversing the polarity by switching the terminals by mistake (nice puff of magic smoke!). I added a reverse polarity protection diode in series with the + to prevent a repeat on my next Pro Mini. Since you are powering your Uno through the DC jack (which has a reverse polarity protection diode), it is not an issue for you, but thought I'd mention it if you plan to move to Vin.