Arduino matrix Keypad & array

GautamD:
PaulS could you help me with the 'atoi' function with respect to my current code that I have got working. Thanks for helping so far.

enlarge your buffer by one to allow space for the trailing NULL character
add the '\0' at the x position when the user validates and then you could call the atoi() function directly on your array as it will be a well formed c-string

(careful, there is a catch with the size of an int and 5 digits)

So now, as I need to make use of a null terminator to implement the 'atoi' function, I must not use the for loop to print the digits right, which you had pointed out earlier? @ J-M-L

You can

  • use the for loop and print each digit, just make sure you don't print the null char (harmless but useless)

  • use print directly on your bufffer, it will do the right thing

  • convert to a number and print the number

Suggest you look beyond atoi() and use atol() and a long to get your number. These functions have a catch because they return 0 if your input does not start with a number and you can't tell if the number was 0 or it's an error (without looking at the first digit) but in your case if you exclude (in your switch/case) the letters then you know your buffer will have only digits

  • you can also use a for loop to build the long int doing in the loop v = 10*v + (digit[index]-'0'); with index going through your array

The thing is I want to store this number in the EEPROM and display it as set count after pressing enter key. I want each digit to to go into 5 different locations but reading them as a single 5 digit number.

GautamD:
The thing is I want to store this number in the EEPROM and display it as set count after pressing enter key. I want each digit to to go into 5 different locations but reading them as a single 5 digit number.

why and where is the problem?

I think I must approach the storing to EEPROM issue later, first I'll implement the atoi function. How do I get the digits to print one by one as I enter them? I am getting the entire number only after I press the enter key. I also want to implement a delete/ backspace function for the count. Or clear the count directly if the user thinks he has entered an undesired count.

How do I get the digits to print one by one as I enter them?

print them as you add them to the array....

I am getting the entire number only after I press the enter key.

Yes, because that's the only part of the code where you print them...

first I'll implement the atoi function

As discussed don't use atoi(), use a long and the atol() as an int won't be enough to represent 99999 (On the Arduino Uno (and other ATMega based boards) an int stores a 16-bit (2 bytes) value. This yields a range of -32,768 to 32,767 (minimum value of -215 and a maximum value of (215 - 1) --> cf the documentation)

I also want to implement a delete/ backspace function for the count. Or clear the count directly if the user thinks he has entered an undesired count.

that's a good idea. you have other characters like * # A B C D to do things like this. it's all just about dealing with the index in your array to decide where things go

Thanks for the valuable suggestions. I'll post the updates and corrections I make to the code. Cheers!!

I wanted to clarify a few things before I make the changes.

no problem - post your final version

I want to store the 5 digit count byte by byte into 5 different locations of the intenal EEPROM. And then read them as an integer. Each location is of one byte so is it possible to store those digits individually but read them as an integer?

Not directly if you store an ASCII representation of a number in memory: ASCII provides a coding on one byte for each common symbol


(image source/credit)

So the string you capture as "12345" for example is represented in memory by 0x31 0x32 0x33 0x34 0x35 (and possibly the trailing null character) whereas the decimal number 12345dec or 0x3039hex in hexadecimal would be coded as an long int (on four bytes) as 0x00 0x00 0x30 0x39 (or reverse way depending on little or big endian architecture)

--> if you store the ASCII character representation in EEPROM, then you need to read each byte and use atol() to rebuilt the number as you will do now in your code.

--> if you store (with the put() method) the number representation in EEPROM, then you can use the get() function to read directly that value

You need to decide for one or the other and once you have a representation it's always possible to generate the other one (going from string to number with atol() and from number to string with strol())

makes sense?

What kind of representation do you suggest I must go with? I want it to be highly efficient since my project will be dealing with real time constraints. I wish to go ahead with the best way possible. Thanks for the help so far.

if you want to do math with the number, then store it as a number because display functions know also how to print a number if you need to display it...

to be honest you'll probably read that only once at setup or upon user action so you won't be in the "real time" part of your code anyway

I guess I might have to explain my project in detail to you. You are giving the best advice but as I have not been clear regarding what my project requires, I am not able to get ahead with it.

No you don't need to. I get what you want to do. there is a part of your project where user can enter a value and that value needs to be stored in EEPROM to be read next time you start the arduino.

my recommendation = store the value as a number, keep it simple. (see the EEPROM lib examples)

The value stored is a 5 digit count to which an external IR count is continuously compared, once they are equal a specific operation that was being performed stops. The user can at any point of time might edit the count in the EEPROM. But again efficiency of EEPROM comes into question. Due to the 1,00,000 read/write cycles that are allowed for each location, I wanted to put those 5 digits at 5 different locations. But now you suggest that I write the number directly. I am totally confused how to go ahead from here on.

  • Declare a global long variable IRcount
  • in setup, initialize IRCount by reading EEPROM; if 0 (means EEPROM was not initialized previously most likely), set IRcount to something that makes sense, store in EEPROM or possibly prompt the user for entry

overtime user gets to the data entry, store in EEPROM and update your IRcount variable to match user input

--> You only write the number in EEPROM when the user changes it. otherwise read it at the start of the arduino. The 100,000 count limit is for writing not for reading so unless you foresee the end user changing that value 100,000 times you probably have a fair amount of time ahead of you before you trash your EEPROM... but there is no necessity to always read from EEPROM in your code. reading once is enough.

writing at a different place in EEPROM means you need a way to remember where it is, which means writing in a known location in EEPROM.. so not helpful

Would you help me with the code for once, I am not able to write it by myself?

Here is a basic example

upload that code to your arduino with serial console set à 115200 bauds

the way this code works is in the setup (there is no loop)

it reads the EEPROM starting from address 0 (eepromStartAddress in the code) and stores whatever was read in a struct composed of 3 elements

  • a flag (sentinel)
  • a long number
  • a char buffer

If that flag sentinel is the magic code 0xBADCAFE :grin: then it means you can trust the data in EEPROM to have been set (based on the likelihood that the first 4 bytes of memory would be set at this value randomly is very very very low)

So the code tests the sentinel flag against our magic key.
--> if it's OK then the code proceed after telling you what it read in memory.
--> if it's not OK, then it means this is the first time you use that Arduino (or data was corrupted), so you initialize the parameters to some default values and store them for next time in EEPROM.

so the first time you run this program the console will say

Data in EEPROM was not OK, setting default Value :
Saved Data
Parameters are: 
IR Count = 12345
Message  = Hello World

every time you press reset now on your Arduino you'll see

[color=green]Data OK in EEPROM: 
Parameters are: 
IR Count = 12345
Message  = Hello World
[/color]

showing that the magic key was recognized

if you change the values in the Parameters structure and call the function storeParametersInEEPROM() then your new values will become the default for next time (don't do that in the loop without control otherwise you'll kill your 100,000 cycles quickly. Only write in EEPROM when user has changed the params you want to save)

I added at the end of the program (commented out) a few lines to empty the EEPROM (write a wrong magic key) so that if you want to be back in a state where the memory is not OK, just uncomment that part and run the program.

hope this helps

#include <EEPROM.h>

const unsigned long magicKey = 0xBADCAFE; // likelyhood of this being in EEPROM is very low

struct savedInEEPROM
{
  unsigned long sentinel; // will be our magicKey if memory already set otherwise don't assume it's correct
  unsigned long IRCount;
  char message[20]; // enough space to store what you need. Careful don't overflow!
} parameters;

unsigned int eepromStartAddress = 0; //EEPROM address to start reading from

void storeParametersInEEPROM()
{
  parameters.sentinel = magicKey;             // ensure we have the magic key set up
  EEPROM.put(eepromStartAddress, parameters); // save the current parameters
  Serial.println("Saved Data");               // notify end user it's done
}

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

  // Read EEPROM memory to initialize our parameters
  EEPROM.get(eepromStartAddress, parameters);

  // verify if we read garbage or good data
  if (parameters.sentinel == magicKey) {
    // we fond the magic key, we can assume that the rest of the data is OK
    Serial.println(F("Data OK in EEPROM: "));
  } else {
    // data in memory is likely not good, initialize our data structure with defaut value
    // or ask the end user to enter a value from the keypad
    Serial.println(F("Data in EEPROM was not OK, setting default Value :"));

    // define the default values you want the first time
    parameters.IRCount = 12345l;
    strcpy(parameters.message, "Hello World"); // ensure it fits in the buffer, including the trailing '\0'

    // and store it in memory for next time
    storeParametersInEEPROM();
  }

  Serial.println(F("Parameters are: "));
  Serial.print(F("IR Count = ")); Serial.println(parameters.IRCount);
  Serial.print(F("Message  = ")); Serial.println(parameters.message);

  // -------------------------------------------
  // uncomment those lines if you want to leave the memory in a state where the sentinel is wrong
  // put garbage in EEPROM at start address for the sentinel and empty the rest
  // -------------------------------------------
  // -------------------------------------------

  //    parameters.sentinel = 0xDEADBEEF; // wrong sentinel
  //    parameters.IRCount = 0l;
  //    memset (parameters.message, 0, sizeof(parameters.message)); // http://www.cplusplus.com/reference/cstring/memset/?kw=memset
  //    EEPROM.put(eepromStartAddress, parameters);

  // -------------------------------------------
  // -------------------------------------------
}

void loop() {}