I am currently trying to write a function to store data to the EEPROM on my Arduino. So far I am just writing a specified string and then reading it back when the program first runs. I am trying to store the length of the string as the first byte and my code is as follows;
#include <EEPROM.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7);
char string[] = "Test";
void setup() {
lcd.begin( 16, 2 );
for (int i = 1; i <= EEPROM.read(0); i++){ // Here is my error
lcd.write(EEPROM.read(i));
}
delay(5000);
EEPROM_write(string);
}
void loop() {
}
void EEPROM_write(char data[])
{
lcd.clear();
int length = sizeof(data); // I think my problem originates here!
for (int i = 0; i <= length + 2; i++){
if (i == 0){
EEPROM.write(i, length); // Am I storing the length correctly?
lcd.write(length);
}
else{
byte character = data[i - 1];
EEPROM.write(i, character);
lcd.write(character);
}
}
}
The problem I am having is when I read the first byte of the EEPROM, I get the supposed length value. However, the loop only runs three times. I have commented some points of interest in my code, but where is the error?
You are indeed correct, on many counts, I think. Try this for writing:
// Function takes a void pointer to data, and how much to write (no other way to know)
// Could also take a starting address, and return the size of the reach chunk, to be more generic
void EEPROM_write(void * data, byte datasize) {
int addr = 0;
EEPROM.write(addr++, datasize);
for (int i=0; i<datasize; i++) {
EEPROM.write(addr++, data[i]);
}
}
You would call it like this:
char[] stringToWrite = "Test";
EEPROM_write(stringToWrite, strlen(stringToWrite));
To read then:
int addr = 0;
byte datasize = EEPROM.read(addr++);
char stringToRead[0x20]; // allocate enough space for the string here!
char * readLoc = stringToRead;
for (int i=0;i<datasize; i++) {
readLoc = EEPROM.read(addr++);
readLoc++;
}
Note that this is not using the String class developed for Arduino: reading and writing that would be different. But the above should work for char array strings.
Note however, that while EEPROM_write() looks generic now, it isn't really, since addr is harcoded. It can only write data to the beginning of EEPROM.
Related
I am trying to read EEPROM first and then write particular data to EEPROM. I am expecting previous data from EEPROM at first but it prints the data I am trying to write to EEPROM. But if I add a delay between the read and write everything works as expected. I am using an ESP32( Arduino framework) clocked at 240 Mhz. I am very suspicious about the clock frequency. I think this issue happens because the instruction speed of the controller is much higher than the baud rate. Am I right?
#include <Arduino.h>
#include <EEPROM.h>
#define config_ver "pppp"
void saveconfig();
typedef struct {
char version[10];
char ssid[10];
char pass[10];
int settings;
} configuration_type;
configuration_type configuration = {config_ver,"lol","dk",50};
void setup() {
Serial.begin(115200);
EEPROM.begin(128);
for(int i = 0; i <= 50; i++) {
Serial.print((char)EEPROM.read(i)); // "pppp" is printed instead of values already in eeprom.
}
Serial.println("\n");
//delay(10000); // delay
saveconfig(); // "pppp" is about to write to epprom
for(int i = 0; i <= 50; i++) {
Serial.print((char)EEPROM.read(i));
}
Serial.println("\n");
}
void loop() {
}
void saveconfig() {
Serial.println("################Saving configuration################!!");
for(int i = 0; i < sizeof(configuration); i++) {
char data = *((char*)&configuration + i);
EEPROM.write(i,data);
}
EEPROM.commit();
}
Output:
pppp␀␀␀␀␀␀lol␀␀␀␀␀␀␀dk␀␀␀␀␀␀␀␀␀␀2␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀2␀␀
################Saving configuration################!!
pppp␀␀␀␀␀␀lol␀␀␀␀␀␀␀dk␀␀␀␀␀␀␀␀␀␀2␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀2␀␀
Output after adding delay:
pppp␀␀␀␀␀␀lol␀␀␀␀␀␀␀dk␀␀␀␀␀␀␀␀␀␀2␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀2␀␀
################Saving configuration################!!
aaaa␀␀␀␀␀␀lol␀␀␀␀␀␀␀dk␀␀␀␀␀␀␀␀␀␀2␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀2␀␀
I want to write some text into the flash memory of an Arduino ESP32. It works kinda but not as I want it to.
void writeString(const char* toStore, int startAddr) {
int i = 0;
for (; i < LENGTH(toStore); i++) {
EEPROM.write(startAddr + i, toStore[i]);
}
EEPROM.write(startAddr + i, '\0');
EEPROM.commit();
}
My call
writeString("TEST_STRING_TO_WRITE", 0);
only writes TEST into the memory. I do not understand why. Is that because of the _? Or am I missing something different?
Here is the used LENGTH macro
#define LENGTH(x) (sizeof(x)/sizeof(x[0]))
and the method I use to read the string from the memory again (which seems to work correctly):
String readStringFromFlash(int startAddr) {
char in[128];
char curIn;
int i = 0;
curIn = EEPROM.read(startAddr);
for (; i < 128; i++) {
curIn = EEPROM.read(startAddr + i);
in[i] = curIn;
}
return String(in);
}
Where on earth did you get that LENGTH macro from? It’s surreal.
sizeof will not do what you want here. It’s a compile-time function that computes the storage requirements of its argument. In this case it should return the length in bytes of a character pointer, not the string it points to.
You want to use strlen(), assuming your char* is a properly terminated C string. Add one to make sure the ‘\0’ at the end gets stored, too.
#define LENGTH(x) (strlen(x) + 1)
Below is the code to demonstrate the storing as well as retrieving of the string ssid in the EEPROM (permanent storage).
#include "EEPROM.h"
int addr = 0;
#define EEPROM_SIZE 64
// the sample text which we are storing in EEPROM
char ssid[64] = "CARNIVAL OF RUST";
void setup() {
Serial.begin(115200);
Serial.println("starting now...");
if (!EEPROM.begin(EEPROM_SIZE)) {
Serial.println("failed to init EEPROM");
while(1);
}
// writing byte-by-byte to EEPROM
for (int i = 0; i < EEPROM_SIZE; i++) {
EEPROM.write(addr, ssid[i]);
addr += 1;
}
EEPROM.commit();
// reading byte-by-byte from EEPROM
for (int i = 0; i < EEPROM_SIZE; i++) {
byte readValue = EEPROM.read(i);
if (readValue == 0) {
break;
}
char readValueChar = char(readValue);
Serial.print(readValueChar);
}
}
void loop() {
}
Appreciate your time.
I am trying to convert "String" read from serial port in serialEvent() of Arduino IDE to integer values with exact representation.
For eg, if String myString = 200 then int myInt should be 200.
I have been somewhat successful but unable to convert String to exact int representation beyond 255.
Solutions I have tried:
1) used .toInt() function in Arduino.
2) used "atoi" and "atol" functions.
3) Serial.parseInt() in loop().
All of these methods start recounting from 0 after every 255 values.
I can't use parseInt since it only works inside loop(). My application requires to store variable value permanently until another value is given through port. For this Arduino Due's flash memory has been used.
The memory storing code seems to work only inside serialEvent().
Code snippet is as below:
#include <stdlib.h>
#include <DueFlashStorage.h>
DueFlashStorage memory;
String x = " ";
int x_size;
int threshold;
void setup(){
Serial.begin(115200);
}
void loop{
Serial.println(memory.read(0));
}
void serialEvent(){
while(Serial.available()){
x = Serial.readStringUntil('\n');
x_size = x.length();
char a[x_size+1];
x.toCharArray(a, x_size+1);
threshold = atoi(a);
memory.write(0, threshold);
}
}
1) Function .toInt() returns LONG and you want INT (I don't know why honestly but it is in documentation)... you need to cast it like this (tried on Arduino ATMEGA and it worked):
#include <stdlib.h>
String x = "1000";
int x_ = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
x_ = (int) x.toInt();
Serial.println(x_);
delay(1000);
}
2) I’m not professional ... but serilEvent() is really old way of doing things and it isn't recommended to use it. You can do it "manually" in the loop() function.
You're only converting 1 character a time, that's why the limit is 255.
If you're not doing anything else, you could stay in a serial.read-loop until all characters are read. For example:
void loop() {
if(Serial.available()) {
byte count = 0;
char number[10]; // determine max size of array
bool wait = true;
while(wait) { // stay in this loop until newline is read
if(Serial.available()) {
number[count] = Serial.read();
if (number[count] == '\n') {
wait = false; // exit while loop
}
count++;
}
}
int threshold = atoi(number);
memory.write(0, threshold);
}
}
For the lack of a good function in Arduino IDE for char/String type to int type conversion (has a limit of 255), I wrote my own conversion code which seems to work perfectly.
int finalcount=0;
void setup(){
Serial.begin(115200);
}
void loop(){
if(Serial.available()) {
int count = 0;
char number[5]; // determine max size of array as 5
bool wait = true;
while(wait) { // stay in this loop until newline is read
if(Serial.available()) {
number[count] = Serial.read();
if (number[count] == '\n') {
finalcount = count; //max array size for integer; could be less than 5
wait = false; // exit while loop
}
count++;
}
}
int val[finalcount]; //array size determined for integer
int placeValue;
int finalval[finalcount];
int temp=0;
int threshold;
for(int i = 0; i<finalcount; i++){
val[i] = (int)number[i]-48; //convert each char to integer separately
placeValue = pow(10,(finalcount-1)-i); //calculate place value with a base of 10
finalval[i] = val[i]*placeValue; //update integers with their place value
temp += finalval[i] ; //add all integers
threshold = temp; //resulting number stored as threshold
}
Serial.println(threshold); //prints beyond 255 successfully !
}
}
I solved the problem using highByte and lowByte functions of Arduino. Works flawlessly.
#include <DueFlashStorage.h>
DueFlashStorage m;
byte a1,a2;
int val;
void setup() {
Serial.begin(115200); //start the serial communication
}
void loop()
{
if (Serial.available()>0)
{
val = Serial.parseInt(); //read the integer value from series
if(val>0){
a1 = highByte(val); //get the higher order or leftmost byte
a2 = lowByte(val); //get the lower order or rightmost byte
m.write(0,a1); //save in arduino due flash memory address 0
m.write(1,a2); //save in arduino due flash memory address 1
}
int myInteger;
myInteger = (m.read(0)*256)+m.read(1); //convert into the true integer value
Serial.println(myInteger);
}
I want to do project which will use GPS & GSM module, use Arduino, take data from GPS(GY-GPS/NEO6MV2) and send by GSM(SIM900 GSM/GPRS Module ) to my phone. I am using separate GPS module
I try this code but still have problem.
#include <SoftwareSerial.h>
#include "SIM900.h"
#include <TinyGPS.h>
#include "sms.h"
SMSGSM sms;
TinyGPS gps;
SoftwareSerial ss(4, 3);
SoftwareSerial SIM900(7, 8);
static void smartdelay(unsigned long ms);
static void print_float(float val, float invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);
String strL, strN, message, textForSMS;
char charL[10], charN[10], text[200];
int m = 1;
boolean started = false;
void setup()
{
Serial.begin(9600);
ss.begin(9600);
gsm.begin(9600);
}
void loop()
{
float flat, flon;
unsigned long age, date, time, chars = 0;
unsigned short sentences = 0, failed = 0;
gps.f_get_position(&flat, &flon, &age);
textForSMS = "Moosa Home"; //testing gps from here
Serial.println(textForSMS);
Serial.println(flat, 6);
Serial.println(flon, 6);
Serial.print("longitude: ");
print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 10, 6);
Serial.println("");
Serial.print("latitude : ");
print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 10, 6);
smartdelay(1000);
Serial.println(""); //till here
delay(1000);
if (m == 5) //send sms on third reading
{
Serial.println("XXXXXXXXX"); //to check whether 'if' works
dtostrf(flat, 4, 6, charL);
for (int i = 0; i < 10; i++)
{
strL += charL[i];
}
dtostrf(flon, 4, 6, charN);
for (int i = 0; i < 10; i++)
{
strN += charN[i];
}
message = "Home";
message = message + "/nLat: ";
message = message + strL;
message = message + "/nLon: ";
message = message + strN;
message.toCharArray(text, 250);
Serial.println(text);
if (sms.SendSMS("+999999999999999", text))
{
Serial.println("\nSMS sent OK.");
}
else
{
Serial.println("\nError sending SMS.");
}
do {} while (1);
}
m++;
}
static void smartdelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}
static void print_float(float val, float invalid, int len, int prec)
{
if (val == invalid)
{
while (len-- > 1)
Serial.print('*');
Serial.print(' ');
}
else
{
Serial.print(val, prec);
int vi = abs( val);
int flen = prec + (val < 0.0 ? 2 : 1); // . and -
flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
for (int i = flen; i < len; ++i)
Serial.print(' ');
}
smartdelay(0);
}
static void print_str(const char *str, int len)
{
int slen = strlen(str);
for (int i = 0; i < len; ++i)
Serial.print(i < slen ? str[i] : ' ');
smartdelay(0);
}
I receive SMS
Home/nLat:1000.00000/nLon:1000.00000`
where is my mistake in this code?
I am sure Gps & gsm work properly
Using TinyGPS on SoftwareSerial + a loop() structure using delay(1000), has very low odds of working. The m counter is really useless here, because loop() will execute 1000's of times while the GPS characters are arriving. And doing a get_position is useless, because you may not have any GPS data yet.
Basically, loop() should be constantly running, without delays. When something important happens (like getting all of a GPS sentence, or enough time has passed), that's when you do your other work (like send an SMS message). The TinyGPS smartDelay is not smart.
You should restructure the loop to look more like this example from the NeoGPS library. All the non-GPS work should be performed where the digitalWrite is in that example (line 62). That's where you would take the time to send an SMS.
The TinyGPS examples would require a complete rewrite to do what you want. They are fine by themselves, but it is difficult to extend them to do other things, like send an SMS. As I said, the loop structure must change.
I suggest taking a look at the NeoGPS library I wrote, as the examples are more robust. The library also uses much less RAM and CPU time, but that isn't a big problem if all you need to do is send an SMS message. If you do want to try it, be sure to review the default SoftwareSerial choice.
If you get the simple NMEAblink.ino example to work, I would suggest trying NMEA.ino. Then insert your code into the doSomeWork function. Most of what you have in loop needs to go in the doSomeWork function, which is called only when a complete RMC sentence is received.
Regardless of which library you use, you also need to check whether the data is valid. What if your GPS isn't receiving any satellites? It may still send an RMC sentence, but there won't be any lat/lon data. You probably shouldn't send an SMS if the location field is not valid.
I have an arduino taking serial input and will turn on the leds. The code is below.
I have a strange problem that when I send multiples of 120x bytes e.g., 240, 480 the last 120 bytes never get read completely.
I see on the serial monitor 120 120 120 81 if I send 480 bytes of data. Could anyone point out the mistake?
#include "FastLED.h"
#define DATA_PIN 6
#define NUM_LEDS 40
byte colors[120];
CRGB leds[NUM_LEDS];
void setup(){
FastLED.addLeds<NEOPIXEL, DATA_PIN, RGB>(leds, NUM_LEDS);
Serial.begin(115200);
}
void loop(){
if (Serial.available()){
int i =0;
char incomingByte;
while(1) {
incomingByte = Serial.readBytes((char *)colors,120);
break;
}
Serial.print(incomingByte);
for(i=0;i<NUM_LEDS ;i++){
leds[i].green = colors[i];
leds[i].red = colors[i+1];
leds[i].blue = colors[i+2];
}
if(incomingByte==0x78){
FastLED.show();
}
}
}
your code is flawed in different ways.
First, please remove the useless use of while(1) {…; break;}, it's just adding an overhead and adds nothing to your algorithm.
Otherwise, your code is not working well because, I guess, at some point there's a lag happening in the serial communication that causes the read to timeout. Let's have a look at source code.
First, you take the readBytes() function. All it does is:
size_t Stream::readBytes(char *buffer, size_t length)
{
size_t count = 0;
while (count < length) {
int c = timedRead();
if (c < 0) break;
*buffer++ = (char)c;
count++;
}
return count;
}
i.e. it iterates length times over the blocking read function. But it breaks if that function's return value is less than zero, returning less than length bytes. So that what's happening to get less than length, so let's have a look at timedRead():
int Stream::timedRead()
{
int c;
_startMillis = millis();
do {
c = read();
if (c >= 0) return c;
} while(millis() - _startMillis < _timeout);
return -1; // -1 indicates timeout
}
what happens here, is that if the read succeeds, it returns the read value, otherwise it loops until timeout has passed, and returns -1, which will end readBytes immediately. The default value for the timeout is 1000ms, though you can make that value higher by using Serial.setTimeout(5000); in your setup() function.
Though you have nothing to earn by using the blocking readBytes() function. So you'd better instead write your loop so you read the values, and trigger an event only once all values have been read:
#define NB_COLORS 120
void loop() {
static byte colors[NB_COLORS];
static int colors_index=0;
if (colors_index < NB_COLORS) {
// let's read only one byte
colors[colors_index] = Serial.read();
// if a byte has been read, increment the index
if (colors[colors_index] != -1)
++colors_index;
} else {
// reset the index to start over
colors_index = 0;
// should'nt you iterate 3 by 3, i.e. having i=i+3 instead of i++ ?
for(i=0;i<NUM_LEDS ;i++){
leds[i].green = colors[i];
leds[i].red = colors[i+1];
leds[i].blue = colors[i+2];
}
FastLED.show();
}
}
HTH