*This is a followup to my Write String to Arduino EEPROM article.*
As it goes, sometimes you find one thing when looking for another. In this case, I was doing some research on a project I’m planing to make in the near future. This is when I came across a line of code that would make turning a Char Array into a String much easier and faster then the method I was using for both my EEPROM and FRAM read_String functions.
When I was reading information back from memory and returning a String, the first operation I needed to do was convert a Char Array into a String. Each character was returned one at a time and then needed to be reconstructed into a String type variable. To do this I used the concat, which would append to a String variable. To use concat, I needed to loop through a Char array, this would add each new character to the String (See Below).
1 2 3 4 5 6 7 8 9 |
String stemp=""; char cbuff[length]; eeprom_read_string(Addr,cbuff,length); for(int i=0;i<length-1;i++) { stemp.concat(cbuff[i]); delay(100); } return stemp; |
This code does work well, though it is not fast. Concat by itself is slow, and if you look in the loop above you can see a delay statement. I found when testing the code, that due to the speed in which concat works, if you don’t delay between uses it can cause garbage data. The time penalty in the code might not seem too bad, but makes it self very noticeable when reading long or many Strings. At the time I wrote this function, I did not know of another way of doing this operation but was always unhappy with its performance. Now I have fixed it.
While I was reading up on some info for a future project (Was reading this) I found that you can typecast a Char array into a String.
Quickly, typecasting is making a variable of one type work like another. For example you could typecast a character variable as an integer and then preform a math operation on it.
1 2 3 4 5 |
char letter = 'a'; int x = 16 + (int)letter; //This is an example, I don't know why you would want to do this. But you could! |
In this case I can typeset the Char array as a String which would mean I would not need the for loop nor the time delays. The resulting code is as follows:
1 2 3 4 5 |
char cbuff[length+1]; eeprom_read_string(Addr, cbuff, length+1); String stemp(cbuff); return stemp; |
This code is a little bit smaller and much faster. There is no need for the delay anymore which means no more hang when reading large Strings of data.
Here is an example code of writing and reading back a string to the EEPROM.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
/* Test code for writing a String to the EEPROM and then reading it Back Written by Mario Avenoso, M-tech Creations 4/10/16 */ #include const int EEPROM_MIN_ADDR = 0; const int EEPROM_MAX_ADDR = 511; //http://ediy.com.my/index.php/tutorials/item/68-arduino-reading-and-writing-string-to-eeprom // Returns true if the address is between the // minimum and maximum allowed values, false otherwise. // // This function is used by the other, higher-level functions // to prevent bugs and runtime errors due to invalid addresses. boolean eeprom_is_addr_ok(int addr) { return ((addr >= EEPROM_MIN_ADDR) && (addr <= EEPROM_MAX_ADDR)); } // Writes a sequence of bytes to eeprom starting at the specified address. // Returns true if the whole array is successfully written. // Returns false if the start or end addresses aren't between // the minimum and maximum allowed values. // When returning false, nothing gets written to eeprom. boolean eeprom_write_bytes(int startAddr, const byte* array, int numBytes) { // counter int i; // both first byte and last byte addresses must fall within // the allowed range if (!eeprom_is_addr_ok(startAddr) || !eeprom_is_addr_ok(startAddr + numBytes)) { return false; } for (i = 0; i < numBytes; i++) { EEPROM.write(startAddr + i, array[i]); } return true; } // Writes a string starting at the specified address. // Returns true if the whole string is successfully written. // Returns false if the address of one or more bytes fall outside the allowed range. // If false is returned, nothing gets written to the eeprom. boolean eeprom_write_string(int addr, const char* string) { int numBytes; // actual number of bytes to be written //write the string contents plus the string terminator byte (0x00) numBytes = strlen(string) + 1; return eeprom_write_bytes(addr, (const byte*)string, numBytes); } // Reads a string starting from the specified address. // Returns true if at least one byte (even only the string terminator one) is read. // Returns false if the start address falls outside the allowed range or declare buffer size is zero. // // The reading might stop for several reasons: // - no more space in the provided buffer // - last eeprom address reached // - string terminator byte (0x00) encountered. boolean eeprom_read_string(int addr, char* buffer, int bufSize) { byte ch; // byte read from eeprom int bytesRead; // number of bytes read so far if (!eeprom_is_addr_ok(addr)) { // check start address return false; } if (bufSize == 0) { // how can we store bytes in an empty buffer ? return false; } // is there is room for the string terminator only, no reason to go further if (bufSize == 1) { buffer[0] = 0; return true; } bytesRead = 0; // initialize byte counter ch = EEPROM.read(addr + bytesRead); // read next byte from eeprom buffer[bytesRead] = ch; // store it into the user buffer bytesRead++; // increment byte counter // stop conditions: // - the character just read is the string terminator one (0x00) // - we have filled the user buffer // - we have reached the last eeprom address while ((ch != 0x00) && (bytesRead < bufSize) && ((addr + bytesRead) <= EEPROM_MAX_ADDR)) { // if no stop condition is met, read the next byte from eeprom ch = EEPROM.read(addr + bytesRead); buffer[bytesRead] = ch; // store it into the user buffer bytesRead++; // increment byte counter } // make sure the user buffer has a string terminator, (0x00) as its last byte if ((ch != 0x00) && (bytesRead >= 1)) { buffer[bytesRead - 1] = 0; } return true; } //Takes in a String and converts it to be used with the EEPROM Functions // bool write_StringEE(int Addr, String input) { char cbuff[input.length() + 1]; input.toCharArray(cbuff, input.length() + 1); return eeprom_write_string(Addr, cbuff); } //Given the starting address, and the length, this function will return //a String and not a Char array String read_StringEE(int Addr, int length) { char cbuff[length+1]; eeprom_read_string(Addr, cbuff, length+1); String stemp(cbuff); return stemp; } void setup() { Serial.begin(9600); Serial.println("Starting...");//Say hello String text = "Hello World!!";//String to write Serial.print("Writting: "); Serial.println(text); write_StringEE(0, text);//Write string starting at address 0 Serial.print("Reading: "); Serial.println(read_StringEE(0,text.length()));//Read String starting a address 0 with given lenth of String } void loop() { /* add main program code here */ } |