I am using nodemcu ESP8266 and write a program to store some values to EEPROM (assign buffer address 115 to 150 to store USERNAME).
When I am reading EEPROM data using for loop from 115 to 150 then it will return unknown characters with string. As I am checking for null values to determine when the string ends the code doesn't work.
My code:
//My Code for store username
String consumername = obj [String("USERNAME")] ;
Serial.println("writing eeprom > Consumer Name:");
for (int i = 0; i < consumername.length(); ++i)
{
EEPROM.write(115 + i, consumername[i]);
Serial.print("Wrote: ");
Serial.println(consumername[i]);
}
//My Code for reading username
for (int i = 115; i < 150; ++i)
{
ch = char(EEPROM.read(i));
if(ch!='\0'){
oname+= char(EEPROM.read(i));
}
}
Serial .print("Name=");
Serial .println(oname);
Looks to me like you are not including the string terminator in the writing to the EEPROM. Change the i < consumername.length() to i <= consumername.length() to include the string terminator.
for (int i = 0; i <= consumername.length(); ++i)
{
EEPROM.write(115 + i, consumername[i]);
Serial.print("Wrote: ");
Serial.println(consumername[i]);
}
As pointed out in a comment below, your read loop needs a modification. In the following I assume oname is an empty string to which you are adding the characters. So you need to read the characters from EEPROM until you read the end of string at which point you are done reading.
for (int i = 115; i < 150; ++i)
{
ch = char(EEPROM.read(i));
if(ch == '\0') break; // if end of string found, break out of read loop.
oname += ch;
}
Related
I want to save the SSID and password in the EEPROM in my Arduino Sketch Wlan.
Actually everything works so far, except that the commit () returns a false. And that's why the memory is empty again after a restart.
My code:
void writePROM()
{
EEPROM.begin(0);
EEPROM.write(0, 0xAA);
byte ssidLength = ssid.length();
byte passLength = pass.length();
int adress = 2;
EEPROM.write(1, (byte)ssidLength);
for(int i = 0; i < ssidLength; i++)
{
EEPROM.write(adress + i, (byte)ssid[i]);
}
adress += ssidLength + 1;
EEPROM.write(adress++, passLength);
for(int i = 0; i < passLength; i++)
{
EEPROM.write(adress + i, pass[i]);
}
bool bRc = EEPROM.commit();
if(bRc)
{
Serial.println("Write successfully");
}
else
{
Serial.println("Write error");
}
Serial.println("Write name to EEPROM = " + ssid);
Serial.println("Write password to EEPROM = " + pass);
}
What I am doing wrong?
First of all, good on you for checking the result of the commit() call.
You're passing 0 when you initialize the EEPROM library:
EEPROM.begin(0);
You need to pass it the number of bytes that you're looking to store using it.
You can read the code for the EEPROM library to confirm this:
void EEPROMClass::begin(size_t size) {
if (size <= 0) {
DEBUGV("EEPROMClass::begin error, size == 0\n");
return;
}
If you pass 0 it simply returns without doing any setup. You can also see that commit() will do nothing in this case:
bool EEPROMClass::commit() {
if (!_size)
return false;
In your case you should call EEPROM.begin() with at least the maximum size of an SSID and password plus one each for the zero terminating bytes (so, 32 characters for the SSID, 63 for the password, plus 2 for 97).
But, as #Juraj pointed out in the comments, you don't need to do any of this as the ESP8266 will automatically persist the Wifi credentials.
The base of the problem: I have an Arduino Due and a MPU6050 accelerometer and an 23lcv512. MPU gives me 16bit signed integer. I would like to save the datas to the SRAM and after the measurement read them back and via Serial send it to PC. Sending to PC is not a problem. The problem is that this SRAM has 128k pcs 8bit address. My numbers are 16 bit. I can't write them directly. Here is my code. I tested the RAM with this code:
`
void loop() {
int i = 0;
Serial.print("Write Byte: ");
for (i = 0; i < 70000; i++) {
//Serial.print("Write Byte: ");
//Serial.print(i);
//Serial.println();
SRAM.writeByte(START_ADDRESS, i);
START_ADDRESS = START_ADDRESS + 1;
}
Serial.print("Write End");
i = 0;
START_ADDRESS = 0;
for (i = 0; i < 300; i++) {
Serial.print("Read Byte: ");
Serial.print(SRAM.readByte(START_ADDRESS));
Serial.println();
Serial.println();
START_ADDRESS = START_ADDRESS + 1;
delay(100);
}
}`
I added the 23LC library. If it's run reads back the numbers from the RAM but after 255 it starts to read 0 again. I know why does it happen. But I don't know howto solve the problem.
I tried to use the writeBlock command but it only works for me with char variables. Char variable requires more space than integers. I have not too much.
Is there anyone who can write a sample code which can write 16 bit signed integer to sram?
I've commented the most obvious problems in your original code below:
void loop() {
int i = 0;
Serial.print("Write Byte: ");
for (i = 0; i < 70000; i++) { // since i is a 16bit int, 70,000 is out of range.
SRAM.writeByte(START_ADDRESS, i); // cool you wrote 1 byte, where is the other write?
START_ADDRESS = START_ADDRESS + 1; // try to keep all caps names for constants.
// this will make your code easier to read, trust me!
}
Serial.print("Write End");
i = 0;
START_ADDRESS = 0;
for (i = 0; i < 300; i++) {
Serial.print("Read Byte: ");
Serial.print(SRAM.readByte(START_ADDRESS)); // you read 1 byte, you can't expect a 16 bit
// value out of that.
Serial.println();
Serial.println();
START_ADDRESS = START_ADDRESS + 1;
delay(100);
}
}
Here's a more sound approach, it stores unsigned ints, but that can easily be changed to signed ints.
#define SRAM_SIZE (128UL << 10) // we have 128K of SRAM available.
// The U and L make this value an unsigned long.
// ALWAYS use unsigned values for addresses.
void loop()
{
Serial.print(F("Writing sequential numbers into SRAM...")); // _always_ store string constants in flash.
// save your RAM for more interesting stuff.
for (unsigned long i = 0; i < SRAM_SIZE; i += 2) // filling SRAM
{
// this is the (truncated from 0-65535) value we'll write.
unsigned int value = static_cast<unsigned int>(i & 0xFFFF);
SRAM.writeByte(i, value & 0xFF); // write lowest 8 bits
SRAM.writeByte(i + 1, (value >> 8) & 0xFF); // write next 8 bits.
}
Serial.println(F("done."));
// read back
Serial.println(F("SRAM contents (16-bits unsigned values):"));
for (unsigned long i = 0; i < SRAM_SIZE; i += 2) // reading all SRAM in 16-bit chunks.
{
Serial.print(i, HEX);
Serial.print(F(": "));
// read two consecutive bytes and pack them into a 16-bit integer.
unsigned int value = SRAM.readByte(i) + (static_cast<unsigned int>(SRAM.readByte(i+1)) << 8); // the cast is necessary.
Serial.println(value);
}
delay(100);
}
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() {
}
I'm trying to get up to 64 lines of max 16 characters to display on an LCD screen via serial. These lines have to be given during startup. I've got the following, which works in most cases:
unsigned char textMatrix[64][17];
unsigned char lineCount = 0;
void readLines(){
Serial.println("Send up to 64 lines of up to 16 characters. Send an empty line to stop sending lines. Make sure to use \\n (newline) as line terminator!");
Serial.setTimeout(10000);
bool receiving = true;
while (receiving){
if(Serial.available() > 0) {
textMatrix[lineCount][0] = '\0';
char res = Serial.readBytesUntil('\n',textMatrix[lineCount],16);
if (res == 0){
if (textMatrix[lineCount][0] != '\0'){
continue;
}
Serial.println("Received empty line");
receiving = false;
break;
}
textMatrix[lineCount][16] = '\0';
Serial.print("Received line: ");
Serial.println((const char*)textMatrix[lineCount]);
lineCount++;
if (lineCount >= 63){
receiving = false;
}
}
}
}
The problem occurs when I send the following line:
Okay, that's one
This line is exactly 16 characters long. I'm assuming that this causes readBytesUntil to trigger twice, causing it to be the same as pressing enter twice. I don't seem to be able to find a difference between seriously sending an empty line or sending a line of exactly 16 characters. What would be the best way to resolve this?
When you send the line
Okay, that's one
That's not 16 character but 17, because there is \n character in the end. What Serial.readBytesUntil('\n',textMatrix[lineCount],16); does in this case is it takes out first 16 characters out of the buffer. After that operation, the only thing left there, is the new line \n, which in the next iteration of the loop is read as an empty line.
To counter that, you can check res variable, and if you see that it equals 16, discard the next read. Or do some more checks in case there is a string longer than 16 + new line.
Here's one way... just read the chars yourself:
unsigned char textMatrix[64][17];
const uint8_t MAX_WIDTH = sizeof( textMatrix[0] );
const uint8_t MAX_LINES = sizeof( textMatrix ) / MAX_WIDTH;
unsigned char lineCount = 0;
void readLines(){
uint32_t startTime = millis();
uint8_t column = 0;
do {
if (Serial.available()) {
char c = Serial.read();
if (c == '\n') {
if ((lineCount >= MAX_LINES) || (column == 0))
break; // too many lines or empty line
textMatrix[ lineCount ] [ column ] = '\0'; // NUL-terminate
lineCount++; // start accumulating a new line
column = 0;
} else if (column < MAX_WIDTH-1) {
// room for another char on this line
textMatrix[ lineCount ] [ column ] = c;
column++;
} // else
// ignore rest of line
}
} while (millis() - startTime < 10000UL); // TIMEOUT == 10s
} // readLines
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.