text:
I2C_Anything String / Char Array issues
I've been working with the lovely I2C_Anything.h (thanks to the great work and support from Nick over at http://www.gammon.com.au/forum/?id=10896&reply=9#reply9).. All working great, I was using Serial communication between Teensy 3.1 & mini pro but looking to replace with I2C - I was sending a file name across that was fine, but not managing to figure it out with the I2C_Anything technique.. here's some snippets:
MASTER
const uint8_t MaxMP3Name = 13;
//====================================
// DATA STRUCTURE FOR MP3 SLAVE
//====================================
struct SEND_MP3_STRUCTURE{
  char Filename[MaxMP3Name];
  uint8_t VolLeft;
  uint8_t VolRight;
  uint8_t Command;
};
SEND_MP3_STRUCTURE txMP3;

#define MP3_SLAVE_ADDRESS 77

const uint8_t PlayFile = 1;
const uint8_t PauseFile = 2;
const uint8_t StopFile = 3;

... etc

//#################################//
//##  SEND MP3 COMMAND           ##//
//#################################//
void sendMP3Command(String MP3File, uint8_t Command) {
  char *TextArray[MaxMP3Name];
  MP3File.toCharArray(TextArray, MaxMP3Name);
  txMP3.Filename = TextArray;
  txMP3.VolLeft = VolLeft;
  txMP3.VolRight = VolRight;
  txMP3.Command = Command;
  Wire.beginTransmission(MP3_SLAVE_ADDRESS);
  I2C_writeAnything(txMP3);
  Wire.endTransmission(true);
}

...etc

... not entirely sure what i'm doing, I've tried most variations (using String in the struct vs char *Filename[] and various other attempts).
SLAVE
const uint8_t MaxMP3Name = 13;
//====================================
// RECEIVE DATA FORMAT
//====================================
struct RECEIVE_DATA_STRUCTURE{
  char Filename[MaxMP3Name];
  uint8_t VolLeft;
  uint8_t VolRight;
  uint8_t Command;
};
volatile RECEIVE_DATA_STRUCTURE RXdata;
#define SLAVE_ADDRESS 77
volatile uint8_t newData; // flag to detect I2C activity

// MAKE GLOBAL VERSIONS
String RX_Filename;
uint8_t RX_VolLeft = 30;
uint8_t RX_VolRight = 30;
uint8_t RX_Command = 0;

... etc

//#################################//
//##  MASTER SENDING US DATA     ##//
//#################################//
void onReceiveEvent(int numbytes){
  if(numbytes == 16){
    I2C_readAnything(RXdata);
    newData = 2;
  }
}

... etc

void loop(){
  if (newData==2){// I2C received Data
    RX_Filename = RXdata.Filename;
    RX_VolLeft = RXdata.VolLeft;
    RX_VolRight = RXdata.VolRight;
    RX_Command = RXdata.Command;
    newData = 0; // Clear data sent marker
  }
}

... etc

Hopefully you'll be able to see pretty quickly what i'm trying to do and the method I should be using to do it..
Thanks for any insights
Cheers
Andy

Sorry, still getting used to this comment vs editing questions business, didn't realise it would add my comment when I hit enter so it cut me off... here's full comment:

Hiya Nick, thanks for your suggestion, How you've recommended it is actually how I tried it originally (I don't like using Strings either) - which just ends up giving me the error:
"invalid conversion from 'volatile char*' to 'const char*' [-fpermissive]"
(on the Slave) - obviously the RXdata is updated during the interrupt so can't leave it out (despite the fact it compiles - but doesnt work)..
I got it working soon after I posted by breaking down the filename in the struct to separate chars, then assembling back into char array in a function I made.
That seemed to work fine, but only if I added null char at as the last char (0x00) - I can get the char Filename[MaxMP3Name]; working, but only if I lose the volatile declaration, and it skips the last char.
Thanks for any further help Nick, I really appreciate all you do for the community and I know you're the best guy to help me (not to take anything away from anyone else that wants to jump in ;)
Current solution i'm using that avoids the volatile erros
Obviously could be a for loop etc but I wrote it out this way just to debug and see where the issue was. Not perfect, but breaking it down this way seems to be overcoming the issue of trying to do anything with the volatile variable. (and i've got so much to figure out for so many other parts of the project that I was thinking i'd come back to it later once i'm done with other bits).. Cheers
//#################################//
//##  SEND MP3 COMMAND        ##//
//#################################//
void sendMP3Command(String MP3File, uint8_t Command) {
  char FileName[8];
  MP3File.toCharArray(FileName, MaxMP3Name+1);
  txMP3.File1 = FileName[0];
  txMP3.File2 = FileName[1];
  txMP3.File3 = FileName[2];
  txMP3.File4 = FileName[3];
  txMP3.File5 = FileName[4];
  txMP3.File6 = FileName[5];
  txMP3.File7 = FileName[6];
  txMP3.File8 = FileName[7];
  txMP3.VolLeft = VolLeft;
  txMP3.VolRight = VolRight;
  txMP3.Command = Command;
  StartMicros = micros();
  Wire.beginTransmission(MP3_SLAVE_ADDRESS);
  I2C_writeAnything(txMP3);
  Wire.endTransmission(true);
  EndMicros = micros();
  //Serial.print("MP3 Packet Size: "); Serial.println(sizeof(txMP3));
  //Serial.print("Sending Command To MP3: "); Serial.print(MP3File);Serial.print("   Command; "); Serial.print(txMP3.Command);Serial.print("   Time; "); Serial.print(EndMicros-StartMicros);Serial.println("uS ");
}

... Oh, and on the slave end, I changed the numbytes to be sizeof, but as you say Nick, not even any need for that, i'm not using it on any of my other I2C slaves all running in the project (5 X MCU core system). the filename is then pulled from the I2C array in a siimilar (debugging) way as the master packs them in
//##############################//
// RECONSTRUCT FILENAME
//##############################//
String getFilename(){
  char FileName[] = {
    RXdata.File1,
    RXdata.File2,
    RXdata.File3,
    RXdata.File4,
    RXdata.File5,
    RXdata.File6,
    RXdata.File7,
    RXdata.File8,
    0x00
  };
  return FileName;

}

//#################################//
//##  MASTER REQUESTING DATA     ##//
//#################################//
void onRequestEvent(void){
    I2C_singleWriteAnything(TXdata);
    newData = 1;
}

//#################################//
//##  MASTER SENDING US DATA ##//
//#################################//
void onReceiveEvent(int numbytes){
  if(numbytes == sizeof RXdata){
    I2C_readAnything(RXdata);
    newData = 2;
  }
}

I'm not sure if you are saying you got it working or not, now. if not, can you please post the exact code (edit your question) that is not working?

Hiya Nick, thanks for your help (and continued support to everyone, jeez i see your name just everywhere! lol) - so yeah, i've been off with the fairies in ESP8266 land and only just looked up ;) - in the end i just did a break down of the filename into literally seperate bytes and worked flawlessly ever since. the original issue I think must be teensy 3.1 specific as I've used char arrays all over the place with I2C with no issues, String was my final attempt. i'll post my current 'solution'.

And accept my answer? Or if my answer just pointed you in the right direction, post your own answer and accept it. So long as the question has an accepted, or upvoted, answer. Then the system doesn't nag us. :)

This part looks weird:
void sendMP3Command(String MP3File, uint8_t Command) {
  char *TextArray[MaxMP3Name];
  MP3File.toCharArray(TextArray, MaxMP3Name);
  txMP3.Filename = TextArray;

You have made an array of 13 pointers to strings. This is not what you want. You want the file name to end up into txMP3.Filename.
This would be closer:
void sendMP3Command(String MP3File, uint8_t Command) {
 MP3File.toCharArray(txMP3.Filename, MaxMP3Name);

Personally I wouldn't be using the String class at all, but that should be better.

Now:
void onReceiveEvent(int numbytes){
  if(numbytes == 16){
    I2C_readAnything(RXdata);
    newData = 2;
  }
}

Are you sure it's 16 bytes? What if you change the struct? Let the compiler do the thinking for you:
void onReceiveEvent(int numbytes){
  if(numbytes == sizeof (RXdata)){
    I2C_readAnything(RXdata);
    newData = 2;
  }
}

How you've recommended it is actually how I tried it originally (I don't like using Strings either) - which just ends up giving me the error "invalid conversion from 'volatile char*' to 'const char*' [-fpermissive]" (on the Slave)

This minimal example compiles OK:
#include <Wire.h>
#include <I2C_Anything.h>
const uint8_t MaxMP3Name = 13;
struct RECEIVE_DATA_STRUCTURE{
  char Filename[MaxMP3Name];
  uint8_t VolLeft;
  uint8_t VolRight;
  uint8_t Command;
};

volatile RECEIVE_DATA_STRUCTURE RXdata;
volatile uint8_t newData; // flag to detect I2C activity

void onReceiveEvent(int numbytes){
  if(numbytes == sizeof RXdata){
    I2C_readAnything(RXdata);
    newData = 2;
  }
}

void setup()
{
}

void loop()
{
}

Hiya Nick, thanks for your suggestion, How you've recommended it actually how I tried it originally - which just ends up giving me the error "invalid conversion from 'volatile char*' to 'const char*' [-fpermissive]" (on the Slave)

Sorry, it cut me off, please see my original question as i've added it to it, seems it wont let me add it here as a comment, cheers

You have 5 minutes after making a comment to edit it. Yes, hitting (enter) does commit the comment, but you can edit it.

hmm. it's still not compiling, got the invalid conversion from volatile to  const char error message as above. If I try type casting it I get "call of overloaded 'String(volatile char [13])' is ambiguous" . so something else is causing it to not compile since your minimal example compiles fine. i've got
#include <SPI.h>
#include <Adafruit_VS1053_NanoV3.h>
#include <SD.h>
#include <Wire.h>
#include <I2C_Anything.h>
#include <stdlib.h>
think i'll just use my original fix - breaking struct into separate chars vs array then re-build since it works. thanks again for your efforts, much appreciated

Using String is probably the reason, and I would not use String in an ISR. Since it does dynamic memory allocation you will probably find that the String library does not support re-entrant calls, and thus it will eventually fail.


text:
ESP8266 - Error: unknown opcode or format name 'jmp'
I bought a nodeMCU 8266 and I'm hoping that it can replace my bulkier UNO+WiFi 101.
I'm getting an error when I compile:
Error: unknown opcode or format name 'jmp'
I'm using it in void SoftReset() function:
void softReset() {
  delay(1000);
  asm volatile ("  jmp 0");
}

This reset works great with my Uno+101 setup but, for whatever reason, doesn't like the ESP8266.  I removed the WiFi101 library and added the ESP8266 WiFi libraries.  That has been the only change.
Can you please help me understand why I'm receiving this error?
EDIT:  I have read this SO answer but the "syntactical sugar" didn't work for me.
I am also perusing various ESP8266 sites but they are not as well managed as SE/SO and answers are tough to find.

The proper way to reset the esp8266 when using the Arduino IDE is to call ESP.reset(). You may need to #include <Esp.h>, but almost all esp8266 headers you include to use any of its functionality will have included it already.

The ESP8266 is not an Arduino Uno. It talks a completely different language.
It's like you're talking Spanish to a Chinese person. It can't understand you.
If you want to use assembly language then you have to use the assembly language of the chip you are programming for - not the assembly language of a completely different chip.
The assembly language is detailed here: http://techblog.realisaatio.fi/wp-content/uploads/2015/04/xtensalx_overview_handbook.pdf
Bear in mind, though, that jumping to 0 may not reset the device - it may do something nasty.
The only sure-fire way of resetting a chip where you don't really know what is going on inside is to connect a GPIO signal to the RESET pin and use that GPIO to pull RESET low and reset the board that way.
If you want to call address 0 and don't know how to do it in assembly there are ways of arranging it in C using a function pointer:
void (*addressZero)() = 0;

void setup() {
    addressZero(); // Call address 0
}

void loop() {
}

That way it will work on multiple different architectures without having to understand the underlying assembly language.  That, of course, is assuming that calling address 0 is a valid way of resetting the board on the target chip.
Browsing through the document I link to above it looks most likely that you would first have to load a register with 0 and then use JX to jump to the address stored in the register (i.e., zero).

source: Stack Exchange

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

sort: votes


text:
Why can I power an SD card reader from a digital pin?
I'm trying to understand the power requirements of an SD card. I have a cheap breakout board from eBay that includes built-in level shifters, so I can plug it in directly to my Arduino. I provide power from one of the digital pins, and it works. This doesn't make sense to me, as I thought an SD card reader should draw upwards of 50-100 mA, well over the capacity of an individual digital pin on the Arduino. However, at least one SD card manufacturer does this as well, so I'm not making this up.
I have checked, and the data is written no problem. I have connected an ammeter between the Arduino and the SD reader, and it never jumps above 3 mA? The only problem I have is when I switch from using the USB cable (connected to my computer) for power to a battery pack, the SD card starts acting erratically. Which makes sense, if it's not getting enough current.
What I'm wondering is why it ever works when connected to a digital output pin? Clearly I'm missing something important.
Edit: The reason why I thought they required a lot of current: I've seen comments like this on a number of tutorials:

One is that they are strictly 3.3V devices and the power draw when writing to the card can be fairly high, up to 100mA (or more)!

Edit2: @dlu answer lead me to investigate the voltage I was sending to the SD card reader, which turns out to have been the problem. I was supplying the Vin pin with 5.2V, which was regulated down to 4V, presumably too low for the 5V-3.3V step-down at the SD card. Moving the battery power to the 5V pin corrected this. This also introduces some new risk, as the board is now receiving unregulated power. But that is another problem.
Edit3: And finally, answering my original question: I found a note on the Adafruit product page for a similar breakout that indicates:

Onboard 5v->3v regulator provides 150mA for power-hungry cards

So despite only drawing 3mA of current from the Arduino pin, the actual SD card is supplied with > 100mA from the regulator.

It seems that you've verified that the power requirements are within the range of a digital pin. Is there a reason why you thought they would be higher?
So, it sounds like the real question is "why does the SD card work with USB power, but not with battery power?" The first thing that occurs to me is that the battery is not providing sufficient voltage. What kind of battery are you using and where do you connect it to the Arduino?
Almost any battery that you use will be able to provide sufficient current for a 3 mA load, but the voltage may not be adequate – especially if you are running a marginal battery (voltage wise) through the onboard regulator.

I was plugging the batter into the Vin and GND pins on the Arduino. I added a link to one reference to the high current draw of SD cards in my question.

Forgot, the battery pack is 4 AA rechargeables (1.2V), which are actually producing 5.1V at the moment (from my multi-meter), so presumably they're still well-charged

Checking the voltage drop across the SD card, when plugged in via the USB cable: 4.9; battery connected to Vin: 4.0; battery connected to Arduino 5V pin 4.9. And the SD card works when powered via USB, the 5V pin, but not the Vin pin. I didn't realize Vin and 5V weren't the same thing!

Thanks, that was the nudge I needed to chase down the problem. I've updated my question with additional info and a solution arising from your suggestion.

I just tested a SD card in an adapter (with level shifters). Without any activity the SD card is only drawing around 0.5 mA. So that is in the capability of an output pin.
Doing a directory list appears to use a maximum of 7 mA, so that is OK.
Writing a file used a maximum of 54.3 mA, which is exceeding the absolute maximum ratings for an output pin (40 mA - recommended only 20 mA for continuous current).
Now you may say that "it works" but the question is: for how long? Exceeding absolute maximum ratings is a path to damaging your processor.
If you want to turn the SD card on and off from time to time, to reduce power, I suggest you arrange to switch the 5V line (and not use a digital output). For example from this page about a low-power temperature sensor I have this schematic:

The MOSFET there switches a 5V line on and off under program control.
That particular design includes a SD card, and that particular gadget has been working for a couple of years now.
Photo of hardware:

Thanks Nick. I found your logger while I was researching this issue, it will be a very helpful resource. When I monitor the current of my SD card, it stays below 3 mA even when writing to the card. Is it possible the onboard voltage regulator is this efficient, or is it more likely my current meter is not good enough -- I'm using an INA219 current sensor board.

Measuring burst current isn't the easiest thing in the world. In my case I had my meter on "min/max" mode and hoped it would sample fast enough. My advice is, for the sake on a MOSFET and a couple of resistors: play it safe and switch the power like I showed.

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


text:
Communicating with Arduino
In this Question how does the code Processing work?
Which programming language is it written in? How to run it?

Note that you aren't required to use Processing in order to communicate with the Arduino; the Arduino uses standard serial communications, supported by almost every programming language in one form or another.

Can I use C++? If so, how? I know basics of C++, so it will be easier for me.

Can C++ support standard serial communications?

@IgnacioVazquez-Abrams , Yeah, but very long and difficult process.

"Processing" is a simplified programming language/environment based on Java. It's designed to be very easy for non-programmers to use, and is quite a popular choice for using alongside Arduino projects.
You can download it for free (and get lots of tutorials/documentation) from here:

https://processing.org

As a side note, the Arduino IDE was based on Processing, so it will probably look familiar!

how to run Processing programs alongside Arduino?

@Mathsman100 You run Processing on your PC or Mac or whatever and generally communicate with the Arduino via serial connection (USB).

So, do you first run the Processing program or do you open the Serial port before that?

@Mathsman100 Your Processing program needs to open the serial port. There are lots of tutorials online which you might find helpful. Here's one: https://learn.sparkfun.com/tutorials/connecting-arduino-to-processing


text:
Temperature sensor reading is higher than the actual temperature
// Tells the Arduino to read A2 and stores the value in “Vin”
Vin = analogRead (tempSensor);

// Converts the voltage value to temperature and stores it into the “TC” variable (in °C)
TC = 500.0 * (Vin / 1024.0);

The temperature shown is about 50.25°C, sometimes it is showing 36-38°C   degrees, but the actual temperature is about 25-26°C.
Why this is happening?
Code:
Vin = analogRead (tempSensor);
TC=(500.0*Vin)/1023.0;
TF = ((9.0*TC)/5.0)+32.0;
lcd.setCursor(0, 1);
lcd.print(TF);
lcd.print((char)223);
lcd.print("F ");
lcd.print (TC);
lcd.print((char)223);
lcd.print("C");
delay(1000);

What sensor are you using (part no.)?

LM35... @ peter

They suggest a 0.01uF bypass capacitor in the datasheet.

i use it also but still there is no change in reading

Next time please add code to your post instead of in a comment. I've edited your post for now. Thanks!

Any chance you're printing Vin, and not TC?
500*(50.25/1024) = ~24.5
If not, please post as much of your program as possible

Vin = analogRead (tempSensor);
TC=(500.0*Vin)/1023.0;
TF = ((9.0*TC)/5.0)+32.0;
lcd.setCursor(0, 1);
lcd.print(TF);
lcd.print((char)223);
lcd.print("F ");
lcd.print (TC);
lcd.print((char)223);
lcd.print("C");
delay(1000);
here is the code

@RappySaha
Thanks, I don't see anything wrong with your code. One thought I had was that the lcd.print function accepts only char,byte,int,long, or string. I'm not sure how it will handle TC and TF, if they're of type 'double'. You might want to try casting them to ints lcd.print((int)TF);
As others have said, you could have a bad sensor or a bad connection.
Your math looks right, and your code looks alright.

C++ is supposed to do implicit casting but it can sometimes break, especially with warnings disabled on Arduino. I've had issues with Serial.print() specifically, so that might be the issue.

I gave up on using a LM335, which is quite similar to your LM35. The problem is these devices self-heat due to the quiescent power they draw. The LM35 data sheet suggests you correct for this in software (footnote 5), and the LM335 datasheet dodges the bullet by quoting accuracy figures that can be achieved in an oil bath rather than free air.
But the figures you are quoting suggest you have a bigger problem, as I am talking of a few degrees inaccuracy, not tens of degrees.
I changed to a DS18B20 and never looked back - simple interface and self-heating is compensated for by the device.

if i use ds18b20 is the formula will still be same??

There is no formula. The library returns the temperature

@RappySaha more specifically the DS18B20 is a digital sensor. Depending on the library used (or not, I haven't tried them all) you can call a function to return the temperature as a float, representing the temperature in degrees Celsius or Farenheit, or as a int16_t with each single bit representing 1/128th of a degree Celsius. No extra maths is needed.

What are the variable types of TC and TF - int/float/double? Something else?
If they're integers, you may be losing some numerical precision in the calculation.
When you get 50.25°C - have you checked the Vin is correct?
Also when you write the values out, the serial.print() can take the number of decimal points as a second argument.
// Print to three decimal places
Serial.print("TF=");
Serial.println((float)TF, 3);
Serial.print("TC=");
Serial.println((float)TC, 3);
Serial.print("Vin=");
Serial.println(Vin, DEC);

"serial.print() needs the number of decimal points" : nope, a default of '2' is included within the function prototype, therefore you can skip the second parameter. The code wouldn't compile if it was needed but omitted.

@CharlieHanson - Yep! Thanks I have corrected my answer.

It sounds like your voltage to temperature calculation is wrong. Assuming the temperature voltage relationship is linear you can work out the formula. Take two measurements at two known temperatures (quite far apart, perhaps outdoors and in) and note down the value Arduino measures for Vin. Lets call these VinA & VinB for TempA and TempB.
You can calculate measures per degree with...
MeasuresPerDeg = (TempB - TempA) /(VinB - VinA)
And the a constant as...
Constant = TempA - VinA*MeasuresPerDeg
Your equation to calculate temperature should now be
TC=MeasuresPerDeg*(Vin/1024.0) + Constant;

According to the datasheet, the LM35 is supposed to output 10mV per degree C. Assuming a standard 5V AREF, the formula in the question looks correct (in theory anyway).

You're quite right. Could you post the rest of your code?

I'm not the questioner. :)


text:
deserializeJson() failed: NoMemory when sending Serial json using ArduinoJson
Hey all I have a sketch that takes up 99% of my storage space since I am using a Arduino Nano.
Although everything in my code fits as-is, there seems to be an issue with me sending a json string over Serial as its coming back saying "deserializeJson() failed: NoMemory". I've also already used the ArduinoJson Assistant.
My json string looks like this:
{"hardd": {"warrDays": "1265","temp": "102","hddST": "18TB","hddSU": "4TB","hddPB": "70","fan": "4200","date": "Fri Mar 11TH 2024","time": "10:45pm"}}
Note that the iconImages.h has just code that has images to byte code like this (there are 12 total of these):
const unsigned char hdd [] PROGMEM = {
    // 'hdd (1), 24x24px
    0x00, 0x00, 0x00, 0x3f, 0xff, 0xfc, 0x5f, 0xff, 0xfa, 0x7f, 0xff, 0xfe, 0x7f, 0x00, 0xfe, 0x7e,
    0x7e, 0x7e, 0x79, 0xcf, 0x9e, 0x7b, 0x0f, 0xde, 0x76, 0x7f, 0xee, 0x64, 0xff, 0xe6, 0x6d, 0xe7,
    0xf6, 0x69, 0x99, 0xf6, 0x69, 0xbd, 0xf6, 0x6b, 0xbd, 0xf6, 0x6f, 0x99, 0xf6, 0x6f, 0xc3, 0xf6,
    0x67, 0xff, 0xe6, 0x77, 0xff, 0xee, 0x73, 0xf3, 0xce, 0x79, 0xc7, 0x9e, 0x1c, 0x0e, 0x3e, 0x0f,
    0x00, 0xfe, 0x66, 0x07, 0xfe, 0x70, 0x3f, 0xfe, 0x72, 0x7f, 0xfe, 0x76, 0x0d, 0x5e, 0x70, 0xed,
    0x1e, 0x5f, 0xed, 0x5a, 0x3f, 0xef, 0xfc, 0x00, 0x00, 0x00
};

Here is my code - if anyone has any suggestions on how to go about shrinking the amount of storage space/memory so that it wont error out when I send the json string then that would be great!
My code:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_EMC2101.h>
#include <ArduinoJson.h>
#include "iconImages.h"

#include <Fonts/FreeSans9pt7b.h>
#include <Fonts/FreeMono9pt7b.h>
#include <Fonts/FreeSerif9pt7b.h>

#define hdd_SCREEN_ADDRESS 0x3C
#define apple_SCREEN_ADDRESS 0x3C
#define dell_SCREEN_ADDRESS 0x3C
#define TCAADDR 0x70

//                           W    H
Adafruit_SSD1306 hdd_display(128, 32, &Wire, -1);
Adafruit_SSD1306 apple_display(128, 32, &Wire, -1);
Adafruit_SSD1306 dell_display(128, 32, &Wire, -1);

Adafruit_EMC2101 emc2101;
char character;

//For timer=========================================
const long Minutes = 1;
const long _Interval = (Minutes * 60 * 1000);
unsigned long previousMillis = 0;
//==================================================

//For HDD Stats=====================================
int i = 0;
const char* hdd_warrDays  = "";
const char* hdd_temp      = "";
const char* hdd_hddST     = "";
const char* hdd_hddSU     = "";
const char* hdd_hddPB     = "";
const char* hdd_fan       = "";
//==================================================

//For Apple Stats===================================
const char* apple_os      = "";
const char* apple_hddST   = "";
const char* apple_hddSU   = "";
const char* apple_hddPB   = "";
const char* apple_ip      = "";
const char* apple_uptime  = "";
//==================================================

//For Dell Stats====================================
const char* dell_os     = "";
const char* dell_hddST  = "";
const char* dell_hddSU  = "";
const char* dell_hddPB  = "";
const char* dell_ip     = "";
const char* dell_uptime = "";
//==================================================

//For Date & Time ==================================
const char* _date = "";
const char* _time = "";
//==================================================

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

  if (!hdd_display.begin(SSD1306_SWITCHCAPVCC, hdd_SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ;
  }

  hdd_display.clearDisplay();
  hdd_display.display();
  hdd_display.setTextColor(WHITE);
  /*
    if(!apple_display.begin(SSD1306_SWITCHCAPVCC, apple_SCREEN_ADDRESS)) {
      Serial.println(F("SSD1306 allocation failed"));
      for(;;);
    }

    apple_display.clearDisplay();
    apple_display.display();
    apple_display.setTextColor(WHITE);

    if(!dell_display.begin(SSD1306_SWITCHCAPVCC, dell_SCREEN_ADDRESS)) {
      Serial.println(F("SSD1306 allocation failed"));
      for(;;);
    }

    dell_display.clearDisplay();
    dell_display.display();
    dell_display.setTextColor(WHITE);
  */
}

void loop() {
  unsigned long currentMillis = millis();

  while (Serial.available()) {
    String input_content = Serial.readString();

    if (input_content.length() > 2) {
      Serial.println(input_content);
      readAndParseJson(input_content);
      input_content = "";
    }
  }

  if (currentMillis - previousMillis >= _Interval) {
    previousMillis = currentMillis;

    Serial.println("previousMillis");

    if (i == 0 || i == 1 || i == 2 || i == 3) {
      i++;
    } else if (i == 4) {
      i = 0;
    }
  }

  doHDD(i);
  //doApple(i);
  //doDell(i);

  delay(100);
}

String getSplitValues(String data, char separator, int index) {
  int found = 0;
  int strIndex[] = { 0, -1 };
  int maxIndex = data.length() - 1;

  for (int i = 0; i <= maxIndex && found <= index; i++) {
    if (data.charAt(i) == separator || i == maxIndex) {
      found++;
      strIndex[0] = strIndex[1] + 1;
      strIndex[1] = (i == maxIndex) ? i + 1 : i;
    }
  }

  return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}

void scanI2C() {
  for (uint8_t t = 0; t < 8; t++) {
    Wire.beginTransmission(TCAADDR);
    Wire.write(1 << t);
    Wire.endTransmission();
    Serial.print("TCA Port #");
    Serial.println(t);

    for (uint8_t addr = 0; addr <= 127; addr++) {
      if (addr == TCAADDR) continue;

      Wire.beginTransmission(addr);

      if (!Wire.endTransmission()) {
        Serial.print("Found I2C 0x");
        Serial.println(addr, HEX);
      }
    }
  }
}

void readAndParseJson(String json) {
  //https://arduinojson.org/v7/assistant
  StaticJsonDocument<512> doc;
  DeserializationError error = deserializeJson(doc, json);
  json = "";

  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.f_str());

    return;
  }

  if (doc.containsKey("hardd")) {
    Serial.println("hdd");
    JsonObject hdd = doc[F("hardd")];
    hdd_warrDays = hdd[F("warrDays")];
    hdd_temp = hdd[F("temp")];
    hdd_hddST = hdd[F("hddST")];
    hdd_hddSU = hdd[F("hddSU")];
    hdd_hddPB = hdd[F("hddPB")];
    hdd_fan = hdd[F("fan")];
    _date = hdd[F("date")];
    _time = hdd[F("time")];
  } else if (doc.containsKey("apple")) {
    Serial.println("apple");
    JsonObject apple = doc[F("apple")];
    apple_os = apple[F("OS")];
    apple_hddST = apple[F("hddST")];
    apple_hddSU = apple[F("hddSU")];
    apple_hddPB = apple[F("hddPB")];
    apple_ip = apple[F("ip")];
    apple_uptime = apple[F("uptime")];
  } else if (doc.containsKey("dell")) {
    Serial.println("dell");
    JsonObject dell = doc[F("dell")];
    dell_os = dell[F("OS")];
    dell_hddST = dell[F("hddST")];
    dell_hddSU = dell[F("hddSU")];
    dell_hddPB = dell[F("hddPB")];
    dell_ip = dell[F("ip")];
    dell_uptime = dell[F("uptime")];
  }
}

void doHDD(int num) {
  hdd_display.clearDisplay();
  hdd_display.drawBitmap(0, 0, hdd, 24, 30, WHITE);

  if (num == 0) {
    //Show tempature
    hdd_display.drawBitmap(25, 0, thermometer, 24, 30, WHITE);
    hdd_display.setFont(&FreeSans9pt7b);
    hdd_display.setCursor(45, 15);
    hdd_display.print(hdd_temp);
    //hdd_display.print("100");
    hdd_display.setTextSize(1);
    hdd_display.setCursor(45, 29);
    hdd_display.print("tempature");
    hdd_display.drawBitmap(75, 0, degreesf, 24, 30, WHITE);
  } else if (num == 1) {
    //Show warranty
    hdd_display.setFont();
    hdd_display.drawBitmap(30, 1, warranty, 24, 30, WHITE);
    hdd_display.setTextSize(1);
    hdd_display.setCursor(60, 3);
    //hdd_display.print(341);
    hdd_display.print(hdd_warrDays);
    hdd_display.print(" day's");
    hdd_display.setCursor(60, 13);
    hdd_display.print("left of");
    hdd_display.setCursor(60, 23);
    hdd_display.print("warranty");
  } else if (num == 2) {
    //Show Hdd stats
    hdd_display.setFont();
    hdd_display.drawBitmap(30, 1, hddSpace, 24, 30, WHITE);
    hdd_display.setTextSize(1);
    hdd_display.setCursor(60, 3);
    //hdd_display.print("5.6TB free");
    hdd_display.print(hdd_hddST);
    hdd_display.print(" free");
    hdd_display.setCursor(60, 13);
    //hdd_display.print("of 18TB");
    hdd_display.print("of ");
    hdd_display.print(hdd_hddSU);

    //drawProgressbar(60, 25, 60, 7, atoi(hdd_hddPB));
    int progress = atoi(hdd_hddPB) > 100 ? 100 : atoi(hdd_hddPB);
    progress = progress < 0 ? 0 : progress;
    float bar = ((float)(60 - 1) / 100) * progress;
    hdd_display.drawRect(60, 25, 60, 7, WHITE);
    hdd_display.fillRect(60 + 2, 25 + 2, bar, 7 - 4, WHITE);
  } else if (num == 3) {
    //Show fan rpms
    hdd_display.setFont();
    hdd_display.drawBitmap(30, 1, fanSpeed, 24, 30, WHITE);
    hdd_display.setTextSize(1);
    hdd_display.setCursor(60, 3);
    hdd_display.print("Fan running");
    hdd_display.setCursor(60, 13);
    hdd_display.print("@ ");
    //hdd_display.print("4,102");
    hdd_display.print(hdd_fan);
    hdd_display.print(" rpm");
  } else if (num == 4) {
    //Show date/time
    hdd_display.setFont();
    hdd_display.drawBitmap(30, 1, timeAndDate, 24, 30, WHITE);
    hdd_display.setTextSize(1);
    hdd_display.setCursor(60, 3);
    //hdd_display.print("10:34pm on");
    hdd_display.print(_time);
    hdd_display.print(" on ");
    hdd_display.setCursor(60, 13);
    //hdd_display.print("Fri Sep");
    hdd_display.print(getSplitValues(_date, ' ', 0));
    hdd_display.print(" ");
    hdd_display.print(getSplitValues(_date, ' ', 1));
    hdd_display.setCursor(60, 23);
    //hdd_display.print("22nd 2024");
    hdd_display.print(getSplitValues(_date, ' ', 2));
    hdd_display.print(" ");
    hdd_display.print(getSplitValues(_date, ' ', 3));
  }

  hdd_display.display();
}

void doApple(int num) {
  String _apple_tmp[3];
  apple_display.clearDisplay();
  apple_display.drawBitmap(0, 0, apple, 24, 30, WHITE);

  if (num == 0) {
    //Show OS
    apple_display.setFont();
    apple_display.drawBitmap(30, 1, runningOS, 24, 30, WHITE);
    apple_display.setTextSize(1);
    apple_display.setCursor(60, 3);
    //apple_display.print("macOS 12.9");
    apple_display.print(getSplitValues(apple_os, ' ', 0));
    apple_display.setCursor(60, 13);
    //apple_display.print("Monterey");
    apple_display.print(getSplitValues(apple_os, ' ', 1));
    apple_display.setCursor(60, 23);
    apple_display.print(getSplitValues(apple_os, ' ', 2));
  } else if (num == 1) {
    //Show Hdd stats
    apple_display.setFont();
    apple_display.drawBitmap(30, 1, hddSpace, 24, 30, WHITE);
    apple_display.setTextSize(1);
    apple_display.setCursor(60, 3);
    //apple_display.print("5.6TB free");
    apple_display.print(apple_hddST);
    apple_display.print(" free");
    apple_display.setCursor(60, 13);
    apple_display.print("of ");
    //apple_display.print("of 18TB");
    apple_display.print(apple_hddSU);

    //drawProgressbar(60, 25, 60, 7, atoi(apple_hddPB));
    int progress = atoi(apple_hddPB) > 100 ? 100 : atoi(apple_hddPB);
    progress = progress < 0 ? 0 : progress;
    float bar = ((float)(60 - 1) / 100) * progress;
    apple_display.drawRect(60, 25, 60, 7, WHITE);
    apple_display.fillRect(60 + 2, 25 + 2, bar, 7 - 4, WHITE);
  } else if (num == 2) {
    //Show IP address
    apple_display.setFont();
    apple_display.drawBitmap(30, 1, ethernet, 24, 30, WHITE);
    apple_display.setTextSize(1);
    apple_display.setCursor(60, 3);
    //apple_display.print("192.168.1.123");
    apple_display.print("IP Address");
    apple_display.setCursor(60, 13);
    apple_display.print("...");
    apple_display.print(getSplitValues(apple_ip, '.', 2));
    apple_display.print(".");
    apple_display.print(getSplitValues(apple_ip, '.', 3));
  } else if (num == 3) {
    //Show uptime
    apple_display.setFont();
    apple_display.drawBitmap(30, 1, uptime, 24, 30, WHITE);
    apple_display.setTextSize(1);
    apple_display.setCursor(60, 3);
    //apple_display.print("35 days 17:14");
    apple_display.print("Uptime");
    apple_display.setCursor(60, 13);
    apple_display.print(getSplitValues(apple_uptime, ' ', 0));
    apple_display.print(" ");
    apple_display.print(getSplitValues(apple_uptime, ' ', 1));
    apple_display.setCursor(60, 23);
    apple_display.print(getSplitValues(apple_uptime, ' ', 2));
  } else if (num == 4) {
    //Show date/time
    apple_display.setFont();
    apple_display.drawBitmap(30, 1, timeAndDate, 24, 30, WHITE);
    apple_display.setTextSize(1);
    apple_display.setCursor(60, 3);
    //apple_display.print("10:34pm on");
    apple_display.print(_time);
    apple_display.print(" on ");
    apple_display.setCursor(60, 13);
    //apple_display.print("Fri Sep");
    apple_display.print(getSplitValues(_date, ' ', 0));
    apple_display.print(" ");
    apple_display.print(getSplitValues(_date, ' ', 1));
    apple_display.setCursor(60, 23);
    //apple_display.print("22nd 2024");
    apple_display.print(getSplitValues(_date, ' ', 2));
    apple_display.print(" ");
    apple_display.print(getSplitValues(_date, ' ', 3));
  }

  apple_display.display();
}

void doDell(int num) {
  dell_display.clearDisplay();
  dell_display.drawBitmap(0, 0, dell, 24, 30, WHITE);

  if (num == 0) {
    //Show OS
    dell_display.setFont();
    dell_display.drawBitmap(30, 1, runningOS, 24, 30, WHITE);
    dell_display.setTextSize(1);
    dell_display.setCursor(60, 3);
    //apple_display.print("Windows 11");
    dell_display.print(getSplitValues(dell_os, ' ', 0));
    dell_display.setCursor(60, 13);
    //apple_display.print("Monterey");
    dell_display.print("V. ");
    dell_display.print(getSplitValues(dell_os, ' ', 1));
    dell_display.print(dell_os);
  } else if (num == 1) {
    //Show Hdd stats
    dell_display.setFont();
    dell_display.drawBitmap(30, 1, hddSpace, 24, 30, WHITE);
    dell_display.setTextSize(1);
    dell_display.setCursor(60, 3);
    //dell_display.print("5.6TB free");
    dell_display.print(dell_hddST);
    dell_display.print(" free");
    dell_display.setCursor(60, 13);
    //dell_display.print("of 18TB");
    dell_display.print("of ");
    dell_display.print(dell_hddSU);

    //drawProgressbar(60, 25, 60, 7, atoi(dell_hddPB));
    int progress = atoi(dell_hddPB) > 100 ? 100 : atoi(dell_hddPB);
    progress = progress < 0 ? 0 : progress;
    float bar = ((float)(60 - 1) / 100) * progress;
    dell_display.drawRect(60, 25, 60, 7, WHITE);
    dell_display.fillRect(60 + 2, 25 + 2, bar, 7 - 4, WHITE);
  } else if (num == 2) {
    //Show IP address
    dell_display.setFont();
    dell_display.drawBitmap(30, 1, ethernet, 24, 30, WHITE);
    dell_display.setTextSize(1);
    dell_display.setCursor(60, 3);
    //dell_display.print("192.168.1.123");
    dell_display.print("IP Address");
    dell_display.setCursor(60, 13);
    dell_display.print("...");
    dell_display.print(getSplitValues(apple_ip, '.', 2));
    dell_display.print(".");
    dell_display.print(getSplitValues(apple_ip, '.', 3));
  } else if (num == 3) {
    //Show uptime
    dell_display.setFont();
    dell_display.drawBitmap(30, 1, uptime, 24, 30, WHITE);
    dell_display.setTextSize(1);
    dell_display.setCursor(60, 3);
    //dell_display.print("35 days 17:14");
    dell_display.print("Uptime");
    dell_display.setCursor(60, 13);
    dell_display.print(getSplitValues(apple_uptime, ' ', 0));
    dell_display.print(" ");
    dell_display.print(getSplitValues(apple_uptime, ' ', 1));
    dell_display.setCursor(60, 23);
    dell_display.print(getSplitValues(apple_uptime, ' ', 2));
  } else if (num == 4) {
    //Show date/time
    dell_display.setFont();
    dell_display.drawBitmap(30, 1, timeAndDate, 24, 30, WHITE);
    dell_display.setTextSize(1);
    dell_display.setCursor(60, 3);
    //dell_display.print("10:34pm on");
    dell_display.print(_time);
    dell_display.print(" on ");
    dell_display.setCursor(60, 13);
    //dell_display.print("Fri Sep");
    dell_display.print(getSplitValues(_date, ' ', 0));
    dell_display.print(" ");
    dell_display.print(getSplitValues(_date, ' ', 1));
    dell_display.setCursor(60, 23);
    //dell_display.print("22nd 2024");
    dell_display.print(getSplitValues(_date, ' ', 2));
    dell_display.print(" ");
    dell_display.print(getSplitValues(_date, ' ', 3));
  }

  dell_display.display();
}

Would be great if someone could look over the code and suggest areas where I could save some memory so the json works.

This line must be wrong: 'Serial.println("previousMillis");' Taking the quotes away will save a few bytes. Also I woud use the F() macro on more of your strings. There is even a case for replacing your use of Strings by char arrays. But that is a lot of work. And one more point: I have found that whenever I run close to memory limits with the Arduino IDE, code begins to behave unpredictably. I have seen this way before reaching 99% of availability.

I'm pretty sure you're using ArduinoJson 7 because ArduinoJson 6 would not return NoMemory in such conditions.
On 8-bit microcontrollers (such as the Arduino Nano), I recommend using version 6 because its fixed memory allocation strategy allows the code to be much smaller and can run without heap allocations, thanks to StaticJsonDocument.
Use the ArduinoJson Assistant to compute the right size for your StaticJsonDocument. In your case, it suggests a size of 192 bytes.
You can save a lot of RAM by passing the stream directly to deserializeJson() instead of loading it to a String.
Avoiding containsKey() can reduce the size of your program (and speed it up slightly). Instead, extract a JsonObject and check if it's null.
Beware that the F() macro doesn't duplicate strings. For this reason, you should probably use regular RAM strings when extracting from the JsonDocument.
You can find other memory-saving tricks in How to reduce memory usage?.
Finally, you can significantly reduce the program space by removing logging and replacing the repetitive patterns with loops.

Thanks for the suggestions there Benoit. I'll look into doing some of those and see if I have any success.

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


text:
Ways to turn a knob with a stepper motor and an ATMEGA32u4
Hey all I am wondering what would be the best items to purchase for me to be able to turn this know (continuous) below:

As I mentioned above, I would need the stepper motor to have a continuous rotation in order for it to work with either of these dry food dispensers above.
There is a decent tutorial HERE but really doesn't give much information about how they went about building it and the mentioned Yocto-LatchedRelay seems over priced for something that can be done with just a stepper motor and some logic behind it.
I plan on using a ATMEGA32u4 with this project. I will have a total of 6 of these to control.
So any suggestions on what would be best for this type of project would be great and I look forward in hearing them! :o)
I'm just needing to know what kind of servo torque I would need in order to turn that without issues of it getting stuck mid-ways.
update
i spoke to the original creator of that web site project that i linked to and this is what they had to say about the parts that were used:

We used a  small geared Maxon motor (great but expensive hi-tech
  stuff).
motor RE-max 13 Ø13 mm, Precious Metal Brushes CLL, 1.2 Watt, with
  cables  Part-No.: 203888
gear Planetary Gearhead GP 13 A Ø13 mm, 0.02 - 0.35 Nm, Metal version
  Part-No.: 110316
Torque was on the low side: it was enough for regular cornflakes but
  clearly insufficient for muesli  :-)
The problem is not only about finding a motor with enough torque, it's
   also about finding a motor small enough to fit in the dispenser.
Here are the files. The pulleys were 3D printed, but the bracket was
  laser cut in 3mm acrylic glass.

Are there any servos that have a hole in the middle so that i can slide it over the turning rod and screw down to tighten on it in order to spin it as if you were spinning it yourself with the handle?
Something like this:

adding vibe to the hopper will lower the required torque and increase flow speed. without gearing, about any non-slim nema24 should be able to power it, even a typical nema17 should work on the fruit loops with a vibration, if my muscle memory serves us halfway correct. calculations aside, this is the sort of thing that needs experimentation.

Are there any servos that have a hole in the middle.. if there is, it would be rare and purpose made. instead, think of a coupler.

Looks to be a screw driven by a motor through a set of greats. It doesnt matter if the motor is a regular (dc) motor or a stepper.

Updated my OP with some other info if that helps.

Unfortunately it is not possible to tell you with any reasonable degree of confidence what torque is needed. It is a function of your design, materials, and luck. And it is likely that you will not be able to avoid jam at any torque level. Best to develop some jam detection techniques and unjamming strategies.

"Are there any servos that have a hole in the middle so that i can slide it over the turning rod and screw down to tighten on it in order to spin it as if you were spinning it yourself with the handle?"
That was the question, this indeed does not seem to provide an answer to that question.


text:
Wemos D1 EEProm put/get not getting correct value
Hey all I have the following code in my Arduino IDE:
#include <EEPROM.h>
#include <ArduinoJson.h>

bool debuggin         = true;
int brightness        = 255;
int ambientLight      = 30;
struct RGBLA {
  uint8_t R;
  uint8_t G;
  uint8_t B;
  uint8_t L;
  uint8_t A;
};

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

  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  EEPROM.begin(512);
  readSavedSettings();
  updateEEProm(255,255,255,200,35,true,false);
}

RGBLA readEEProm() {
  int addr = 0;
  RGBLA customVars;

  EEPROM.get(addr, customVars);
  return customVars;
}

void readSavedSettings() {
  RGBLA returnedVars = readEEProm();
  if (debuggin) { Serial.println("START readSavedSettings"); }

  if (returnedVars.A == 00 || returnedVars.A == 0) {
    if (debuggin) { Serial.println("'A' not found! Default 30"); }
  } else {
    ambientLight = returnedVars.A;
    if (debuggin) {
      Serial.print("'A' found! ");
      Serial.println(ambientLight);
    }
  }

  for(uint8_t i = 0; i < 3/*strip.numPixels()*/; i++) {
    if (debuggin) {
      Serial.print("LED ");
      Serial.print(i);
      Serial.print(" set to: R: ");
      Serial.print((uint8_t)returnedVars.R);
      Serial.print(", G: ");
      Serial.print((uint8_t)returnedVars.G);
      Serial.print(", B: ");
      Serial.println((uint8_t)returnedVars.B);
    }
  }

  if (debuggin) {
    Serial.println("Turned off RGB LEDS");
    Serial.println("END readSavedSettings");
  }
}

void updateEEProm(uint8_t R,
                  uint8_t G,
                  uint8_t B,
                  uint8_t L,
                  uint8_t A,
                  bool saveRGBL,
                  bool saveA) {
  int addr = 0;
  RGBLA customVars;

  //Save old json before clearing EEProm
  EEPROM.get(addr, customVars);

  //Clear EEProm
  for (unsigned int i = 0; i < EEPROM.length(); i++) {
    EEPROM.write(i, 0);
  }

  if (saveRGBL) {
    //Get A value so that we can save it the same value
    DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(5));
    JsonObject& root = jsonBuffer.createObject();

    if (debuggin) {
      Serial.print("Old JSON:");
      Serial.print(" R: ");
      Serial.print((uint8_t)customVars.R);
      Serial.print(" G: ");
      Serial.print((uint8_t)customVars.G);
      Serial.print(" B: ");
      Serial.print((uint8_t)customVars.B);
      Serial.print(" L: ");
      Serial.print((uint8_t)customVars.L);
      Serial.print(" A: ");
      Serial.println((uint8_t)customVars.A);
    }

    root["R"] = (uint8_t)R;
    root["G"] = (uint8_t)G;
    root["B"] = (uint8_t)B;
    root["L"] = (uint8_t)L;
    root["A"] = (uint8_t)customVars.A;

    if (debuggin) {
      Serial.print("New JSON:");
      Serial.print(" R: ");
      Serial.print((uint8_t)root["R"]);
      Serial.print(" G: ");
      Serial.print((uint8_t)root["G"]);
      Serial.print(" B: ");
      Serial.print((uint8_t)root["B"]);
      Serial.print(" L: ");
      Serial.print((uint8_t)root["L"]);
      Serial.print(" A: ");
      Serial.println((uint8_t)root["A"]);
    }

    EEPROM.put(addr, root);
  }

  if (saveA) {
    //Get R,G,B,L values so that we can save it the same value
    DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(5));
    JsonObject& root = jsonBuffer.createObject();

    if (debuggin) {
      Serial.print("Old JSON:");
      Serial.print(" R: ");
      Serial.print((uint8_t)customVars.R);
      Serial.print(" G: ");
      Serial.print((uint8_t)customVars.G);
      Serial.print(" B: ");
      Serial.print((uint8_t)customVars.B);
      Serial.print(" L: ");
      Serial.print((uint8_t)customVars.L);
      Serial.print(" A: ");
      Serial.println((uint8_t)customVars.A);
    }

    root["R"] = (uint8_t)customVars.R;
    root["G"] = (uint8_t)customVars.G;
    root["B"] = (uint8_t)customVars.B;
    root["L"] = (uint8_t)customVars.L;
    root["A"] = (uint8_t)A;

    if (debuggin) {
      Serial.print("New JSON:");
      Serial.print(" R: ");
      Serial.print((uint8_t)root["R"]);
      Serial.print(" G: ");
      Serial.print((uint8_t)root["G"]);
      Serial.print(" B: ");
      Serial.print((uint8_t)root["B"]);
      Serial.print(" L: ");
      Serial.print((uint8_t)root["L"]);
      Serial.print(" A: ");
      Serial.println((uint8_t)root["A"]);
    }

    EEPROM.put(addr, root);
  }
}

void loop() {
}

And this is the output of that code:
START readSavedSettings
'A' found! 96
LED 0 set to: R: 48, G: 255, B: 255
LED 1 set to: R: 48, G: 255, B: 255
LED 2 set to: R: 48, G: 255, B: 255
Turned off RGB LEDS
END readSavedSettings
Old JSON: R: 48   G: 255 B: 255 L: 63   A: 96
New JSON: R: 255  G: 255 B: 255 L: 200  A: 96
Old JSON: R: 48   G: 255 B: 255 L: 63   A: 160
New JSON: R: 48   G: 255 B: 255 L: 63   A: 35

Now when I reset it this is the output:
⸮dOX⸮,R⸮X⸮4xC⸮⸮⸮START readSavedSettings
'A' found! 96
LED 0 set to: R: 48, G: 255, B: 255
LED 1 set to: R: 48, G: 255, B: 255
LED 2 set to: R: 48, G: 255, B: 255
Turned off RGB LEDS
END readSavedSettings
Old JSON: R: 48   G: 255 B: 255 L: 63   A: 96
New JSON: R: 255  G: 255 B: 255 L: 200  A: 96
Old JSON: R: 48   G: 255 B: 255 L: 63   A: 160
New JSON: R: 48   G: 255 B: 255 L: 63   A: 35

How come the Old JSON has the 'L' value as 63 again when it should be the New JSON value of 200? Why did it not save it but saved all the others? Also, Why is 'R' 48 when it should be 255 like G and B?
Is there something wrong in my code?
Update 1
This is the output after adding .end() to it:
START readSavedSettings
'A' found! 160
LED 0 set to: R: 48, G: 255, B: 255
LED 1 set to: R: 48, G: 255, B: 255
LED 2 set to: R: 48, G: 255, B: 255
Turned off RGB LEDS
END readSavedSettings
Old JSON: R: 48   G: 255  B: 255  L: 63 A: 160
New JSON: R: 255  G: 255  B: 255  L: 200 A: 160
Old JSON: R: 128  G: 12   B: 17   L: 17 A: 60
New JSON: R: 128  G: 12   B: 17   L: 17 A: 35

and the code i use:
void setup() {
  // initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  EEPROM.begin(512);
  readSavedSettings();
  updateEEProm(255,255,255,200,35,true,false); //Save all but 'A' value
  EEPROM.end();
  updateEEProm(255,255,255,200,35,false,true); //Save just 'A' value
  EEPROM.end();
}

you should try SPIFFS instead of EEPROM: ez file interface, 1-3MB of space, no slicing or delimiters needed....

@dandavis, true. the emulation library has one small advantage. it is not erased when you upload SPIFFS image

Why do you put the Json root to EEPROM at he end of updateEEProm?

@Juraj do you mean in the .put() part?

you read the RGBLA struct but you write the json to EEPROM. which is not suitable for EEPROM

@Juraj using .put() makes it compatible with strings which the JSON is in.

you write to EEPROM root and not customVars. but you read customVars and not json

@Juraj customVars are gathering whats currently in the EEProm. I then save the passed R,G,B,L values and put it into the root struct and save that as the new data for the EEProm.

root is not struct. it is a class to handle json. it can't be saved to EEPROM. and  if could, it could not be read into RGBLA

The esp8266 EEPROM emulation library requires a commit() call to save the memory image of EEPROM to flash.
Add EEPROM.commit(); or EEPROM.end(); as last line in your updateEEProm() function. Documentation link:
Second problem is that you don't write the RGBLA struct to EEPROM, instead you try to write the variable root, which is an instance of class JsonObject. Class types can't be put into EEPROM.

So this works even when using .put()?

of course. all emulating functions work with the RAM image of the emulated EEPROM. commit() or end() writes the image to flash. begin() reads the image from flash to RAM.

Hum, even doing updateEEProm(255,255,255,200,35,true,false); EEPROM.commit(); updateEEProm(255,255,255,200,35,false,true); EEPROM.commit(); still does not seem to save it?

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


text:
What electronics should I study to create something like a fridge temperature monitor?
I would like to be able to design an Arduino circuit for a fridge monitor that would have a temperature sensor, a small speaker to emit a sound when the temperature changes past a threshold and an LCD screen showing the current temperature.
I have found a few examples online, but I would like to know why components like capacitors and transistors are used in their circuits so I'd be able to design similar circuits myself.
I found this list of electronics topics:

Basic Theory
Basic Passive Components
Passive Circuits
Discrete Active Components
Active Circuits
Integrated Circuits
Digital Logic
Analog
Signals
Outputs
Inputs
Digital Electronics

Some of these things, like digital logic seem unnecessary in such a project, but obviously some others are useful, but I don't know which. I'd like to know what it would be useful to study so I can understand the reasons for the circuit design of something like a fridge monitor.

You're going to need a large portion of that in order to do more than just banging rocks against other rocks and hoping you get a useful tool.

...or you can pick a goal you want to accomplish, and learn what you need to in order to enable it (while being open to discovering that you need to alter your goal in light of practicalities you learn about)

All of the above + embedded system design

I voted to reopen this. I removed the lamp since that's a whole other question :) Feel free to ask another question if you wish to do so.

And now we get to "It depends on what pieces you want to use.". You handle a thermocouple very differently from e.g. a TMP36. A coil speaker vs. a piezo buzzer. A bare segmented LCD vs. a HD44780U-compatible module.

Why don't you pick one of the circuits you found online, the one you find most interesting, study it a little, then post your specific questions here (or at EE.SE)? Pick a simple circuit that features only one of the components you described (temp sensor or speaker or LCD). Don't forget to post the link to the circuit and make sure there's a schematic for the EE folks to look at. That's how our site works best - to answer specific questions users have.

A fridge temperature monitor (or any system that talks to world using some data) will include a sensor (temperature sensor like LM35), a controller (to do calculations, arduino ofcourse) and an output (display, like LCD). The topics you should be aware of, are digital electronics, basic passive components (working of resistor, capacitor etc). And a little arduino programming and lots of logic.


text:
Optmizing print code when writing to file, and reducing print time
First things first, I have found some solutions to this problems but they all involved for printing to serial monitor. I am trying to take the information from the sensors and write them to an sd card. Here is my code so far:
//-----Writes Data to SD Card-----//
if(!Data) {
    u8g.firstPage();
    do {
       drawFileError();
    } while( u8g.nextPage() );
    while (1);  // don't do anything more:
}

dcounter++;
if (dcounter=1){

    Data = SD.open("Data.txt", O_CREAT | O_APPEND | O_WRITE);
    Data.println(Header);
    Data.print(strutcDate + "  ");
    Data.print(strutcTime + "  ");
    Data.print(strgpsStatus + "  ");
    Data.print(strmodeIndicator + "  ");
    Data.print(strlatitude + "  ");
    Data.print(strlongitude + "  ");
    Data.print(strspeedOverGnd + "  ");
    Data.print(strcourseOverGnd + "  ");
    Data.print(t);
    Data.print("  ");
    Data.print(f);
    Data.print("  ");
    Data.print(h);
    Data.print("  ");
    Data.print(hi);
    Data.print("  ");
    Data.print(press_pKa);
    Data.print("  ");
    Data.println(str);
    Data.close();
} else{
    Data.print(strutcDate + "  ");
    Data.print(strutcTime + "  ");
    Data.print(strgpsStatus + "  ");
    Data.print(strmodeIndicator + "  ");
    Data.print(strlatitude + "  ");
    Data.print(strlongitude + "  ");
    Data.print(strspeedOverGnd + "  ");
    Data.print(strcourseOverGnd + "  ");
    Data.print(t);
    Data.print("  ");
    Data.print(f);
    Data.print("  ");
    Data.print(h);
    Data.print("  ");
    Data.print(hi);
    Data.print("  ");
    Data.print(press_pKa);
    Data.print("  ");
    Data.println(str);
    Data.close();
}

two questions: is it possible for me to reduce this chunk of code into something smaller? is there a way to decrease print time?
Edit: Ahh I see, the problem with my code is that the last few values are floats.Any way to shorten those as well, or do i need to do it individually? I do agree about the adding string parts.

Several Arduino libraries for talking to SD cards are listed at http://playground.arduino.cc/Main/InterfacingWithHardware#Storage . Perhaps one of them is faster than the library you are using now?

Edit you question to state how long it is currently taking to print and what sort of improvements you need.

First of all, the only difference between the two parts of the "if" statement is that, the first time, it prints the header. Instead of that code, you could do this:
//(Include the top part of the code here...)
dcounter++;
if (dcounter=1){
    Data = SD.open("Data.txt", O_CREAT | O_APPEND | O_WRITE);
    Data.println(Header);
}
Data.print(strutcDate + "  ");
Data.print(strutcTime + "  ");
Data.print(strgpsStatus + "  ");
Data.print(strmodeIndicator + "  ");
Data.print(strlatitude + "  ");
Data.print(strlongitude + "  ");
Data.print(strspeedOverGnd + "  ");
Data.print(strcourseOverGnd + "  ");
Data.print(t);
Data.print("  ");
Data.print(f);
Data.print("  ");
Data.print(h);
Data.print("  ");
Data.print(hi);
Data.print("  ");
Data.print(press_pKa);
Data.print("  ");
Data.println(str);
Data.close();

Like already mentioned, you can append strings with the + operator. This would be the final code then:
//(Include the top part of the code here...)
dcounter++;
if (dcounter=1){
    Data = SD.open("Data.txt", O_CREAT | O_APPEND | O_WRITE);
    Data.println(Header);
}
Data.println(strutcDate + " " + strutcTime + "  " + strgpsStatus + "  " + strmodeIndicator + "  " + strlatitude + "  " + strlongitude + "  " + strspeedOverGnd + "  " + strcourseOverGnd + "  " + t + "  " + f + "  " + h + "  " + hi + "  " + press_pKa + "  " + str);
Data.close();

FYI, it doesn't seem like you should close the stream every iteration at the end since you only open it the first time.

I would analize what I want to write, extrapolate all numeric value, then create a structure that hold numeric value. So at every write I would write the structure (it is a binary write, so use fixed byte size) followed by all others string(or even place string in different file, but may turn out harder to manipulate or fix in case of problem).
Then to read it you'll need to read back the structure, followed by eventual know number of string. If string may be of unknown number,, just put the number of following string into the struct. Outside string, as you can see, you need no special char to signal the end of chunk of data :)
Unrelated: please, remove all println in the if rather than the header as they are equal to the else; then remove the else statement (but not the else body!) That way the if will open file and add header, and then the code will always add the rest of code. It would be a shame if you edit your else branch and forgot the if, or viceversa. Code style matters, trust me

Maybe this helps with speed. It will however use more memory, so use with caution.
Data.println(Header);
Data.println(strutcDate + " " + strutcTime + "  " + strgpsStatus + "  " + strmodeIndicator + "  " + strlatitude + "  " + strlongitude + "  " + strspeedOverGnd + "  " + strcourseOverGnd + "  " + t + "  " + f + "  " + h + "  " + hi + "  " + press_pKa + "  " + str);
Data.close();

As you suggest yourself, don't ever do code like this on a microcontroller.  This is a likely to overflow the stack.


text:
Pin headers too long for the sensor i bought
https://www.amazon.co.uk/Adafruit-TCS34725-Color-Sensor-Filter/dp/B00OKCRU5M/ref=sr_1_3?keywords=adafruit+rgb+sensor&qid=1559653098&s=computers&sr=1-3
Just bought this colour sensor for a project and as you can see it comes with the pins detached. There are 8 pins but only 7 holes so how do i assemble it? I'm assuming its super obvious since i havent seen anyone else ask it so im sorry!
Thanks in advance.

Cut one pin off.
Get some wire cutters and position them in the groove between the last and next to last pins in the row. Squeeze. One pin will pop off.

Ok, will do. Why did they make it like that though? It's not just mine, you can see in the picture that all of them are like that

@ThisUsernameHasBeenTaken Simple: you can't (easily and cheaply) buy 7-pin headers, but you can buy 8-pin. They could cut them down to 7 pins for you, but that would cost more.

Didn't matter i screwed up the soldering so i need to buy a new one...


text:
Adafruit Circuit Playground Express interrupt not working
I have interrupts attached to pins 4 and 5 which correspond to the left and right inbuilt buttons on the circuit playground express (https://learn.adafruit.com/adafruit-circuit-playground-express/pinouts). For some reason the right button interrupt works perfectly however the left interrupt doesn't even trigger. Here's the code:
#include <Adafruit_Circuit_Playground.h>
#include <Adafruit_CircuitPlayground.h>

volatile bool leftState = false, rightState = false;

void left()
{
    if (CircuitPlayground.leftButton())
        leftState = !leftState;
}

void right()
{
    if (CircuitPlayground.rightButton())
        rightState = !rightState;
}

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

    attachInterrupt(digitalPinToInterrupt(4), left, CHANGE);
    attachInterrupt(digitalPinToInterrupt(5), right, CHANGE);
}

void loop()
{
    Serial.print(leftState);
    Serial.print("\t");
    Serial.print(rightState);
    Serial.print("\n");
}

Pin 4 on Zero can't be used with attachInterrupt. It is pin PA08 of the SAMD21 and this has NMI as interrupt control function in EIC and can't be used as EXTINT.
Adafruit Circuit Playground maps PA28 to pin 4, but the description of the pin is left as for Zero and doesn't declare interrupt capability.
In file arduino/hardware/samd/1.6.21/variants/circuitplay/variant.cpp change the line for pin 4 to
  { PORTA, 28, PIO_DIGITAL, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_8  },                           // GPIO D4 / Left Button

Packages are located in ~/.arduino15/packages/ on Linux and %userprofile%\AppData\Local\Arduino15\packages\ on Windows (AppData is a hidden folder).
Warning: In variant.cpp the overview comment's table describes Zero, not Circuit Playground.
Note: It is not beneficial to read a button with interrupt. You can only set some flag in interrupt and then handle it in the loop(). But then you can directlly check in loop the state of the pin, because it will be active many loops even if the user pushes it for a short time.

I have a lot of delays in my main loop (the code I posted is simplified to isolate the issue), so the button inputs wouldn't register. To be clear, what value should I put as the first parameter when I attach the interrupt for the left button?

wait, so the pinout for the playground express states that button a is an interrupt pin but you can't actually use it as an interrupt pin?

pinout where? I checked the variant.cpp for this board in Arduino SAMD boards package

https://cdn-learn.adafruit.com/assets/assets/000/049/780/original/Adafruit_Circuit_Playground_Express_Pinout.pdf Button A is labelled as an interrupt

the description in variant.cpp doesn't match the true mapping used. I rewrite the answer. you will need to patch variant.cpp

Let us continue this discussion in chat.

I changed the answer

I get compilation errors now

@JamesA, Adafruit has own SAMD boards package with Circuit Playground Express. it has the same error in variant.cpp

I made a change to the code in the repo. It should now be fixed. My issue here was that when I edited the file with vscode, it was inserting special invisible characters which gave me errors. When I changed it with notepad, all was good


text:
Having problems with running two 74HC595 as a single 16bit shift register
I'm using two of these together to create a single 16bit register which will give me access to 16 outputs. I have gotten them to work but not exactly how I imagined them to work. The code written is for a 18650 cell charger/discharger. The first 6 bits (0-5) of the shift register will be connected to 6 NPNs which will turn on or off each of their tp4056s connected in series. The next 6 bits (5-11) will be connected to 6 different constant current loads. The user selects if they want to charge or discharge their cell and depending on the mode, that particular cell's charger or current sink is turned on (but both not on the same time). In reality, I have to firstly shift 6 bits manually by selecting a mode and then pressing select for all 6 cells in the register for it to show something and even after that it misses bits randomly. btw last 4 bits (12-15) will also get used in the final product. For experimenting, I've connected LEDs to all outputs.
#include <Arduino.h>
#include <LiquidCrystal_I2C.h>
#include <Encoder.h>

//initalisation
LiquidCrystal_I2C lcd(0x27, 20, 4);
Encoder encoder(2, 3);

//software constants
const int numOfCells = 6;
const int analogInput[numOfCells] = {A0, A1, A2, A3, A6, A7};
const float arduinoPowerLine = 4.80;
const long interval = 60000; //60 seconds
const char* functions [2] = {"CHARGE   ", "DISCHARGE"}; //mode select array
const int dataPin  = 12;//DS - pin 9
const int latchPin = 11;//ST_CP --pin12
const int clockPin = 8;//SH_CP --pin11

//Encoder setup
long oldPostion = -999;
long newPostion = 0;
long prevPostion;

//making battery arrays and setting their default flags
double batteryVoltage[numOfCells];
bool noBatteryFlag[numOfCells] = {LOW, LOW, LOW, LOW, LOW, LOW};
float minimum = 3.00; //Cutoff voltage
float capacity[numOfCells];

//mode variables
int modeState[numOfCells];
int confirmedModeState[numOfCells];

//button setup
int inputPin = 5;
int inputState;
int lastInputState = LOW;
int inputFlag = LOW;

//debounce timer
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

//lcd varuables
int currentCell = -1;

//Cell timers
unsigned long prevMillis[numOfCells];
int minute[numOfCells];
unsigned long currentMillis;

//shift resister variables
word outputs = 0B0000000000000000;

void updateShiftRegister(word bits){//takes bits from the resolvemode function and sets them appropriately
  byte resisterOne  = lowByte(outputs);//right most byte
  byte resisterTwo = highByte(outputs);//left most byte
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, resisterTwo);
  shiftOut(dataPin, clockPin, MSBFIRST, resisterOne);
  digitalWrite(latchPin, HIGH);
}
void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  pinMode(inputPin, INPUT_PULLUP);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin,  OUTPUT);
  pinMode(clockPin, OUTPUT);
  updateShiftRegister(outputs);//Resets all shift resister output to LOW
}
void BatteryVoltage(){//reading each cells and converting the adc value into voltage
  for (int i = 0; i < numOfCells; i++){
    int reading = analogRead(analogInput[i]);
    batteryVoltage[i] = (reading * arduinoPowerLine) / 1023;
    //flagging stuff
    if (batteryVoltage[i] <= 0.50) {//checking if a battery is inserted in the holder
    noBatteryFlag[i] = HIGH;
    }else{
      noBatteryFlag[i] = LOW;
    }
  }
}
void ButtonDebounce(){//checking input state and flaggint button
  int reading = digitalRead(inputPin);
  if (reading != lastInputState){
    lastInputState = millis();
  }
  if ((millis() - lastInputState > debounceDelay)){//debouncing button
    if (reading != inputState){
      inputState = reading;
      if (inputState == HIGH) {
        inputFlag = HIGH;
      }
    }
  }
  lastInputState = reading;
}
void ResolveFlags(){
   if (inputFlag == HIGH){ //incrementing currentscreen
       if (currentCell == numOfCells - 1){ //if counter at its limit ,it wraps back to the start
        currentCell = 0;
      } else {
        currentCell++;
      }
      confirmedModeState[currentCell] = modeState[currentCell]; //mode selected in stored
      lcd.clear();//clears lab every time button is pressed
        inputFlag = LOW;
  }
}
void BatteryTimeKeeper(){//keeping track of battery time while it is discharging
for (int i = 0; i < numOfCells; i++){
  if (currentMillis - prevMillis[i] > interval){
    if (noBatteryFlag[i] == LOW){//if a battery is in the holder
      if (batteryVoltage[i] > minimum){//and if it is greater then 3v, it can be discharged
   minute[i]++;
   prevMillis[i] = currentMillis;
  }
  if (batteryVoltage[i] <= minimum){
    capacity[i] = (minute[i] / 60) * 500; //total time taken divided by 500mA (constant current load)
    minute[i] = 0;
    }
  }
}
    if (noBatteryFlag[i] == HIGH){//if a battery is removed, its timer is reset back to 0
      minute[i] = 0;
    }
  }
}
void EncoderFunctionNavigator(){//tracks encoder
  newPostion = encoder.read();
  if (newPostion != oldPostion){
    oldPostion = newPostion;
  }
  if(prevPostion < newPostion){
    modeState[currentCell]++;
  } else if(prevPostion > newPostion){
    modeState[currentCell]--;
  }
  if (modeState[currentCell] == 2){ //wraps back selection mode
    modeState[currentCell] = 0;
  } else if (modeState[currentCell] < 0){
    modeState[currentCell] = 1;
  }
}
void ResolveMode(){//sets shift resister output on or off depending on the mode selected
  for (int i = 0; i < numOfCells; i++){
    if (confirmedModeState[i] == 0){
      bitWrite(outputs, i, HIGH) && bitWrite(outputs, i+6, LOW);
    } else if (confirmedModeState[i] == 1){
      bitWrite(outputs, i, LOW) && bitWrite(outputs, i+6, HIGH);
    }
    updateShiftRegister(outputs);
  }
}
void PrintScreen(){//printing all the info in lcd
  lcd.home();
  int cellCounter = currentCell + 1; //this is here because I have ocd
  char buffer[25];
  sprintf(buffer, "Cell#:%d    %s", cellCounter, functions[modeState[currentCell]]);
  lcd.print(buffer);
  lcd.setCursor(0, 1);
  lcd.print("VOL:");
  lcd.setCursor(4, 1);
  lcd.print(batteryVoltage[currentCell]);
  lcd.setCursor(0, 2);
  lcd.print("Cap:");
  lcd.setCursor(4, 2);
  lcd.print(capacity[currentCell]);
}
void loop() {
 currentMillis = millis(); //main currentmillis variable
 BatteryVoltage();
 BatteryTimeKeeper();
 ButtonDebounce();
 EncoderFunctionNavigator();
 ResolveFlags();
 PrintScreen();
 ResolveMode();
 prevPostion = newPostion; //records the last postion of encoder
}

Its register, not resistor

Have you tried a simple test sketch with only the shift registers tl test, if they work as expected? Have you checked, if the data, that you want to shift out, is exactly what you expect it to be (through printing it over serial beforehand)? And why are you updating the shift registers for every bit, that you set in ResolveMode()? I would first set every bit in the data, that needs to be set, and then at the end update the shift registers only once with all new data at once

And what do you mean by "missing bits randomly"? Please explain exactly, what you were expecting and what actually happened

register* my bad.  Yes I have tried a simple sketch and I can toggle all the different bits and by missing bits I mean randomly one led stops working in the middle

That's a good idea, ill try it and report back my results. thankyou for your answer

@chrisl yep your solution worked a treat. With your solution and moving resolveMode() up made it all work.

To put the comments into an answer:
You are controlling the shift registers in this function
void ResolveMode(){//sets shift resister output on or off depending on the mode selected
  for (int i = 0; i < numOfCells; i++){
    if (confirmedModeState[i] == 0){
      bitWrite(outputs, i, HIGH) && bitWrite(outputs, i+6, LOW);
    } else if (confirmedModeState[i] == 1){
      bitWrite(outputs, i, LOW) && bitWrite(outputs, i+6, HIGH);
    }
    updateShiftRegister(outputs);
  }
}

Since the updateShiftRegister() call is inside the for loop, you are updating the shift registers for every bit, that you set. I guess this is the point, where you get your weird behavior. You don't need to update for every bit. Instead change all needed bits inside the outputs variable, and then at the end of ResolveMode() you can update the registers with all data at once.
So just move updateShiftRegister(outputs); one line down to outside of the for loop.


text:
Arduino UNO generate square wave, which is exactly the same with trigger pulse, but with a time delay
I am new in using Arduino so please forgive me if my question is too simple.
I need to generate a square wave with exactly the same duty cycle and frequency with the trigger pulse. The trigger pulse is 15 Hz with two rising edges in each cycle. Besides, I need to introduce an adjustable delay between them.
Is anyone can tell me how to do it please? Thanks in advance!

I'd forget the idea of "generating a square wave". Instead I'd just watch the incoming signal and replicate it x time in the future. If you see a rising edge then think "I need to generate a rising edge in x ms" - and the same with a falling edge.

thank you but the rising edges in triggering pulses  are not importatnt. It is for reminding when using interrupts as it will be trigger twice in one cycle.

@chris I don't understand your comment. If the triggering pulse is not important, then why should the output be exactly the same? Majenko suggested just writing code, that reads the pin (maybe through interrupts, maybe without), delaying and then outputting that value onto the output pin

how can you have two rising edges in a cycle?

I mean exactly the same in terms of duty cycle and frequency. I tried but the phase between two pulses are not stable.

Here are the main codes:
void loop() {
InputState = digitalRead(interruptPin);
if (InputState == HIGH){
delay (DelayTime);
digitalWrite (OutPin, HIGH);
delay (TriggerPeakDuration);
digitalWrite (OutPin, LOW);
delay (T - TriggerPeakDuration - DelayTime);
}

please put the explanation and the code into your question .... format the code properly

digitalWrite() and digitalRead() are extremely slow. Plus the loop() function is called in a loop, so the CPU has overhead when the function returns and is called again (jumps). This all introduces delay in the execution if your check-and-set-pin logic, thus the result you see is totally expected. See https://www.youtube.com/watch?v=D0Hr24QDD-s.

You may just want to rewrite it to use interrupts and a timer. As in, interrupt fires, you set the output, arm a timer with some expiry time, the timer interrupt fires, you unset the output. CPU can mostly sleep then, too.. If that's not possible, at least use digitalWriteFast() and friends, and unrolled loops..


text:
Custom Debounce Code Not Working
It's my custom debounce code
It keeps the led on by flipping the required threshold value when triggered after the led has turned on to keep the led in a high state and vice verse triggered again, the comments on the code explain it in more detail.
/*
 * This code is my custom debounce code, I made this but this isn't working as planned,
 * see the thing is that it turns on when I hold the button and if I release it,
 * it starts to flickers and then gradually turn off, what is wrong with my code ?
 * I can't see it.
 */

const int ledPin = 13; // led connected to pin 13
const int PushButton = 2; // a pushbutton connected to pin 2
int switcher = HIGH; // the switcher changes it's value, we require this later
int dilay = 1; // controls the delay
unsigned long lastTrigger = 0; // records the last time the led was turned on

void setup() {
  pinMode(ledPin, OUTPUT); // sets ledpin as output
  pinMode(PushButton, INPUT); // sets pushbutton pin as input
}

void loop() {
  int pushButtonState = digitalRead(PushButton); // stores the value of the pin each time the loop begins agian

  if((millis() - lastTrigger) >= dilay){ // my custom debounce code
    if(pushButtonState == switcher){ //  this is the trick, when the pushbutton pin is high it's equal to the switcher value
      digitalWrite(ledPin, HIGH); // it turns on the led
      int switcher = LOW; // now the switcher value will be low now the pushbutton pin value will also be low keeping the led on
    }else{
      digitalWrite(ledPin, LOW); // now if the led is on and pushbutton is high, then it will not be equal to the switcher because we had changed it in the previous statement
      int switcher = HIGH; // now the switcher is high and the pushbutton value low, switcher isn't equal to pushbutton so there by keeping the ledpin as low

    }

    if(pushButtonState == 1){ // if pushbutton is high
      int lastTrigger = millis(); // then  lastTrigger equals to the current time
    }
  }

}

how is the button wired? do you have a pulldown resistor?

the button is a switch which connects the 5v pin and pin 2, and no i don't use a pull down resistor

without pulldown, the pin free floats between LOW and HIGH when disconnected from 5V

Change int switcher = LOW/HIGH to just switcher = LOW/HIGH.
Otherwise you are redefining the variable, and will make it a local variable, and not change the global variable with the same name (as you are expecting).

PS you code isn't actually doing any debouncing. It negates it a bit by only polling the input pin every 1 ms. But in some switches bouncing can take up to 6ms.

now with the change you suggested, it makes the led blink now


text:
ESP8266 SPIFFS not saving correctly?
Hey all I am having some issues with the SPIFFS for this Wemos D1 mini ESP8266 controller.
This is my Arduino sketch:
#include <FS.h>
#include <ArduinoJson.h>

struct RGBLA {
  uint8_t R;
  uint8_t G;
  uint8_t B;
  uint8_t L;
  uint8_t A;
};

void setup() {
  if (!SPIFFS.begin()) {
    Serial.println("error while mounting filesystem!");
  } else {
    // put your setup code here, to run once:
    RGBLA returnedVars = readSPIFFS();

    Serial.begin(115200);
    Serial.println();
    Serial.println("Starting...");

    Serial.println("readSPIFFS 1");
    Serial.print("R: ");
    Serial.println(returnedVars.R);
    Serial.print("G: ");
    Serial.println(returnedVars.G);
    Serial.print("B: ");
    Serial.println(returnedVars.B);
    Serial.print("L: ");
    Serial.println(returnedVars.L);
    Serial.print("AmbientLight: ");
    Serial.println(returnedVars.A);

    Serial.println("==================================");

    returnedVars = saveToSPIFFS(25,77, 107, 250, 155, false);
    Serial.println("saveToSPIFFS #1");
    Serial.print("R: ");
    Serial.println(returnedVars.R);
    Serial.print("G: ");
    Serial.println(returnedVars.G);
    Serial.print("B: ");
    Serial.println(returnedVars.B);
    Serial.print("L: ");
    Serial.println(returnedVars.L);
    Serial.print("AmbientLight: ");
    Serial.println(returnedVars.A);

    Serial.println("==================================");

    returnedVars = saveToSPIFFS(205,17, 68, 50, 15, true);
    Serial.println("saveToSPIFFS #2");
    Serial.print("R: ");
    Serial.println(returnedVars.R);
    Serial.print("G: ");
    Serial.println(returnedVars.G);
    Serial.print("B: ");
    Serial.println(returnedVars.B);
    Serial.print("L: ");
    Serial.println(returnedVars.L);
    Serial.print("AmbientLight: ");
    Serial.println(returnedVars.A);

    returnedVars = readSPIFFS();
    Serial.println("readSPIFFS 2");
    Serial.print("R: ");
    Serial.println(returnedVars.R);
    Serial.print("G: ");
    Serial.println(returnedVars.G);
    Serial.print("B: ");
    Serial.println(returnedVars.B);
    Serial.print("L: ");
    Serial.println(returnedVars.L);
    Serial.print("AmbientLight: ");
    Serial.println(returnedVars.A);

    Serial.println();
    Serial.println("END!");
  }
}

void loop() {
  // put your main code here, to run repeatedly:
}

RGBLA saveToSPIFFS(uint8_t R, uint8_t G, uint8_t B, uint8_t L, uint8_t A, bool saveA) {
  File configFile = SPIFFS.open("/config.json", "w+");

  if (configFile.size() > 3072) {
    Serial.println("Config file size is too large.");
  } else {
    Serial.print("Writing json to Config file...");

    StaticJsonBuffer<200> jsonBuffer;
    JsonObject& json = jsonBuffer.createObject();

    //Get the old value and save it
    RGBLA returnedVars = readSPIFFS();

    Serial.println("Old Values?");
    Serial.print("R: ");
    Serial.println(returnedVars.R);
    Serial.print("G: ");
    Serial.println(returnedVars.G);
    Serial.print("B: ");
    Serial.println(returnedVars.B);
    Serial.print("L: ");
    Serial.println(returnedVars.L);
    Serial.print("AmbientLight: ");
    Serial.println(returnedVars.A);

    if (saveA) {
      //Save Ambient Light data
      json["R"] = returnedVars.R;
      json["G"] = returnedVars.G;
      json["B"] = returnedVars.B;
      json["L"] = returnedVars.L;
      json["A"] = A;

      //Now save the new data
      returnedVars.A = A;
    } else {
      //Save RGBL data
      json["R"] = R;
      json["G"] = G;
      json["B"] = B;
      json["L"] = L;
      json["A"] = returnedVars.A;

      //Now save the new data
      returnedVars.R = R;
      returnedVars.G = G;
      returnedVars.B = B;
      returnedVars.L = L;
    }

    json.printTo(configFile);
    configFile.close();

    //Read new saved values into struct
    //returnedVars = readSPIFFS();
    return returnedVars;
  }
}

RGBLA readSPIFFS() {
  bool exist = SPIFFS.exists("/config.json");

  if (exist) {
    Serial.println("YAY!");
  } else {
    Serial.println("Boo!");
  }

  File configFile = SPIFFS.open("/config.json", "r");
  std::unique_ptr<char[]> buf(new char[configFile.size()]);
  configFile.readBytes(buf.get(), configFile.size());
  DynamicJsonBuffer jsonBuffer;
  JsonObject& json = jsonBuffer.parseObject(buf.get());
  RGBLA returnedVars;

  String debugLogData;
  json.printTo(debugLogData);

  Serial.println("===============");
  Serial.println(debugLogData);
  Serial.println("===============");
  returnedVars.R = json["R"];
  returnedVars.G = json["G"];
  returnedVars.B = json["B"];
  returnedVars.L = json["L"];
  returnedVars.A = json["A"];

  configFile.close();

  return returnedVars;
}

And this is the console output:
Starting...
readSPIFFS 1
R: 0
G: 0
B: 0
L: 0
AmbientLight: 25
==================================
Writing json to Config file...YAY!
===============
{}
===============
Old Values?
R: 0
G: 0
B: 0
L: 0
AmbientLight: 0
saveToSPIFFS #1
R: 25
G: 77
B: 107
L: 250
AmbientLight: 0
==================================
Writing json to Config file...YAY!
===============
{}
===============
Old Values?
R: 0
G: 0
B: 0
L: 0
AmbientLight: 0
saveToSPIFFS #2
R: 0
G: 0
B: 0
L: 0
AmbientLight: 25
YAY!
===============
{"R":0,"G":0,"B":0,"L":0,"A":25}
===============
readSPIFFS 2
R: 0
G: 0
B: 0
L: 0
AmbientLight: 25

END!

As you can see, the first old values has all 0's which is incorrect. AmbientLight should be 25 at that point since readSPIFFS 1 has 25. So this should read:
Old Values?
R: 0
G: 0
B: 0
L: 0
AmbientLight: 25

saveToSPIFFS #1 is sending values 25, 77, 107, 250, 155 and false which then outputs correctly as:
R: 25
G: 77
B: 107
L: 250
AmbientLight: 0

But this time AmbientLight should still be 25 since it was sent false. It should have taken the old value (25) and placed it into the newer save.
R: 25
G: 77
B: 107
L: 250
AmbientLight: 25

Moving on to saveToSPIFFS #2 the values again are incorrect. The AmbientLight however is correct here. Instead of this output:
R: 0
G: 0
B: 0
L: 0
AmbientLight: 25

it should be gathering the 4 previous old values:
R: 25
G: 77
B: 107
L: 250
AmbientLight: 25

The json after this should not be this:
{"R":0,"G":0,"B":0,"L":0,"A":25}

It should be this:
{"R":250,"G":77,"B":107,"L":250,"A":25}

And lastly, the output of readSPIFFS 2:
R: 0
G: 0
B: 0
L: 0
AmbientLight: 25

Is incorrect. It should output:
R: 25
G: 77
B: 107
L: 250
AmbientLight: 25

Then after a reset it should have that and not the below for readSPIFFS 1:
R: 0
G: 0
B: 0
L: 0
AmbientLight: 25

So, where am I messing up here?
UPDATE
struct RGBLA {
  uint8_t R;
  uint8_t G;
  uint8_t B;
  uint8_t L;
  uint8_t A;
};

void setup() {
   RGBLA returnedValues = readSPIFFS();

   Serial.println("readSPIFFS 1");
   Serial.print("R: ");
   Serial.println(returnedVars.R);
   Serial.print("G: ");
   Serial.println(returnedVars.G);
   Serial.print("B: ");
   Serial.println(returnedVars.B);
   Serial.print("L: ");
   Serial.println(returnedVars.L);
   Serial.print("AmbientLight: ");
   Serial.println(returnedVars.A);

   returnedValues = saveToSPIFFS(205, 17, 68, 50, 15, false);

   Serial.println("saveToSPIFFS 1");
   Serial.print("R: ");
   Serial.println(returnedVars.R);
   Serial.print("G: ");
   Serial.println(returnedVars.G);
   Serial.print("B: ");
   Serial.println(returnedVars.B);
   Serial.print("L: ");
   Serial.println(returnedVars.L);
   Serial.print("AmbientLight: ");
   Serial.println(returnedVars.A);
}

RGBLA readSPIFFS() {
   RGBLA returnedVars;
   File configFile = SPIFFS.open("/config.json", "r");

   if (configFile ) {
     Serial.println("YAY!");
     configFile.readBytes((byte*) &returnedValues, sizeof(RGBLA));
     configFile.close();
   } else {
     Serial.println("Boo!");
   }

   return returnedValues;
}

RGBLA saveToSPIFFS() {
   File configFile = SPIFFS.open("/config.json", "w+");

   if (configFile.size() > 3072) {
     Serial.println("Config file size is too large.");
   } else {
     Serial.print("Writing to Config file...");

     //Get the old value and save it
     RGBLA returnedVars = readSPIFFS();

     Serial.println("Old Values:");
     Serial.print("R: ");
     Serial.println(returnedVars.R);
     Serial.print("G: ");
     Serial.println(returnedVars.G);
     Serial.print("B: ");
     Serial.println(returnedVars.B);
     Serial.print("L: ");
     Serial.println(returnedVars.L);
     Serial.print("AmbientLight: ");
     Serial.println(returnedVars.A);

     if (saveA) {
       //Save Ambient Light data
       returnedVars.A = A;
     } else {
       //Save RGBL data
       returnedVars.R = R;
       returnedVars.G = G;
       returnedVars.B = B;
       returnedVars.L = L;
     }

     configFile.write((byte*) &returnedVars, sizeof(RGBLA));
     configFile.close();

     return returnedVars;
}

why do you save it as JSON? simple file.write((byte*) rgbla, sizeof (RGBLA)) and file.read((byte*) rgbla, sizeof (RGBLA)) would work

@Juraj  can you put that as a potential answer and provide an example?

if it will be only one instance of the RGBLA struct and one file to save it, then create one global instance of the struct and rather  return a succes state from functions

You can write a struct to file as binary data. This example is from my project.
global data:
struct Stats {
  int heatingTime; // minutes
  int consumedPower; // watts
};

Stats statsData;

snippet from setup():
  File file = SPIFFS.open(STATS_FILENAME, "r");
  if (file) {
    file.readBytes((byte*) &statsData, sizeof(statsData));
    file.close();
  }

snippet from statsSave() function:
  File file = SPIFFS.open(STATS_FILENAME, "w");
  if (file) {
    file.write((byte*) &statsData, sizeof(statsData));
    file.close();
  }

your updated readSPIFFS should be:
RGBLA readSPIFFS() {

  RGBLA returnedVars;
  File configFile = SPIFFS.open("/config.json", "r");
  if (configFile ) {
    Serial.println("YAY!");
    configFile.readBytes((byte*) &returnedValues, sizeof(RGBLA));
    configFile.close();
  } else {
    Serial.println("Boo!");
  }
  return returnedValues;
}

So I can still return RGBLA like RGBLA returnedVars = readSPIFFS();?

Check out my updated OP.

configFile.readBytes((byte*) &returnedValues, sizeof(returnedValues)); or configFile.readBytes((byte*) &returnedValues, sizeof(RGBLA));

Alright corrected that in the update. Do I still need to use return returnedVars; or is it already populating the strut?

what is configFile["R"]?

Getting the value for R in the RGBLA.

you read it to the struct with readbytes. it is in returnedValues after readBytes

Alright I updated the OP again to reflect the changes. Is it correct now?

you read into local variable returnedValues and return copies the struct values into returnedValues in variable in setup

Ok I updated the OP again to reflect those changes. I also added the saveToSPIFFS but I am unsure how to save it as it has old data that needs to be saved with the new data (example: RGBL is new data while A is old data) all that needs to be saved into that config file.

Ok I think I have it now. Updated the OP update.

After finally being able to test this out i am getting the error of invalid conversion from 'byte {aka unsigned char}' to 'char*' [-fpermissive]**

invalid conversion from 'char' to 'const uint8_t {aka const unsigned char*}' [-fpermissive]**

change cast to required type. those are only different names for byte.


text:
ESP12e pin 13 won't set to output/won't work
I have an ESP12e and running a basic blink code on it. The problem is that GPIO13 of esp12e wont turn on. I have noticed that this has happened from time to time. Earlier I thought that the ESP was faulty so i just changed them. But now I have a lot of 10 ESPs and all of them have the same problem. Pin 13 wont turn on setting to HIGH.
What could be going wrong? Is there something that I am missing?
EDIT:
However, on the same piece of esp12, for some test, i tried putting the gpio12 to input and that worked.
Code:
void setup() {
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
}

void loop() {
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(2000);
}

and this is with no other hardware or libraries?

How are you determining that GPIO13 is not high?

Basic blink code uses, LED_BUILTIN ... on a generic module this is preset to 1 ... have you remembered to set LED to 13

@dandavis Ya, nothing else.

@JaromandaX umm, the led that I connect to it wont light up, nor does any reading show on a multimeter. And yes, the pin is set to gpio13.

i tried putting the gpio12 to input ... how is that relevant to gpio13 as output?

@JaromandaX, In the prodct that we are using this for, the gpio12 is working as input. I thought none of the gpios on that side were working. But the problem seems with just gpio13.

so, to summarise, you have 10 (at least) EPS12E, and not one gpio13 is working using the ESP8266 library blink code example - can you post in the question the code you are uploading to the ESP12E? I ask because it may be different with the version of arduino for esp8266 you are using compared to the one I'm using


text:
communicating with arduino over serial via terminal
I'm attempting to write data over a serial line to the arduino, however I don't want to use the arduino IDE but rather use the command line.
In order to do this I have the following commands:
$stty -F /dev/ttyACM0 cs8 9600 ignbrk -brkint -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts
$echo s123 > /dev/ttyACM0

The code on the receiving end checks whatever or not the input is s123 and if it is starts blinking. I have tested this using the arduino IDE and it worked, however this did not work.
The sketch looks like this:
    void loop(){
     if(Serial.available()==4){
       byte b1,b2,b3,b4;
      b1=Serial.read();
      b2=Serial.read();
      b3=Serial.read();
      b4=Serial.read();
        if(b1=='s'){
               digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
               delay(1000);               // wait for a second
               digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
               delay(1000);               // wait for a second
               digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
               Serial.println("the cow has landed");
          }
     }

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

the output of
stty -F /dev/ttyACM0 -a

was :
speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; flush = ^O; min = 0; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread clocal -crtscts
ignbrk -brkint -ignpar -parmrk inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo -echoe -echok -echonl noflsh -xcase -tostop -echoprt -echoctl -echoke

Thank you

can you post the sketch?

I have added the sketch

Could you post the output of stty -F /dev/ttyACM0 -a after your own stty command? That could help see some potential config issues.

I have added the output

Your code doesn't seem to have any way of getting back in sync if that is ever lost.  And it may be that you inadvertently reset the arduino when you configure/open the serial port.  If you start talking too soon thereafter, (as echo would) the first character(s) might be lost while in reset, leaving your sketch and host program out of sync.  Try putting a "Hello World" in your setup()

If you made a sketch to endlessly print something, could you see it when you read from /dev/ttyACM0?

if(Serial.available()==4) is bad code. Unless there are exactly 4 characters it will do nothing. At the least it should be >=4 but you really need to work out what you want it to do. Even if it worked it would print 1 line then do nothing.

This was fixed this morning after a reboot and upgrade command, still don't know which one of these fixed it but it seems to work now.
Ah figured it out we were using the 0 and 1 rx gates to communicate over serial rather then usb and as the used power supply turned out to be only 5V rather then 9-12V it didn't quite work as intended.

This is not a solution, as your program remains faulty.  At best you are momentarily lucking out - which is actually bad luck, because when a system is faulty, it's more helpful when it will cooperate by failing while you are paying attention to fixing it, and not some other time.


text:
Are my arrays stored in sram or in Flash?
I have the following memory allocation:
unsigned char g1[]={
  0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ....0x00 ,0x00 ,0x00 ,0x00 ,0x00 };
g2[]={
  0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ....0x00 ,0x00 ,0x00 ,0x00 ,0x00 };
...

 unsigned char* index[10] = {g1,g2,g3,g4,g5,g6,g7,g8,g9,g0};

This is accessed in the following way:
unsigned char* getMatch(int input){
  return index[input];
}

This is then futher acces using the method of
unsigned char store[1024]
unsigned char* temp = getMatch(n);
for(int i=0;i <50;i++){
 store[i]=temp[i];
}

and store is then modified and send to an external device.
As my program is randomly failing I think it might be running low on SRAM and was wondering if there is any way to force this memory to be placed in flash. Anybody got an idea?

It's stored in both the FLASH and SRAM because it's initialized array. To store in FLASH only you need use PROGMEM attribute.
const unsigned PROGMEM char g1[]= ...

You cannot access directly but using memcpy_P() function.

How would I put this in the 2nd array after this? I get a lot of error: invalid conversion from ‘const unsigned char*’ to ‘unsigned char* errors.

Never mind got it.