I’d like to make a function to that will get characters entered from a 4x3 keypad. The info is sometimes numbers, sometimes numbers and letters. I’d like to call the function by maybe passing it 2 arguments. The first is the max number of chars, the second could be a boolean set to true if it is to get numbers only. The largest size it would ever be is 20 characters.
I (think) I can work out the code for the function, but I don’t understand working with pointers and references (*, &). So I’m not sure how to pass the result back. If my function was like this:
char getInput(boolean numOnly, int maxSize) {
//code to get key events
//return the result
}
Below is a portion of my code that gets a filename from the user. But I have this repeated again and again to get numbers and other data. It’s rather clumsy, I’m just a self taught Arduino DIY.
void Add_Part() {
disp.lcd_cls(); //clear display
disp.lcd_print(F("ENTER NEW PART NAME"));
disp.lcd_rowcol(1, 3); //row, col
disp.lcd_print(F("8 LETTERS MAX"));
if (!continueMsg()) return; //wait for OK
boolean valComplete = false;
char newFileName[13]; //holder for new part name
memset(newFileName, 0, sizeof(newFileName)); //delete the previous value.
int charCount = 0; //counter for which letter we are on
int currentLetter = 65; //ascii val for the current letter we are working with
newFileName[0] = 'A'; //start with something
disp.lcd_cls(); //clear display
disp.lcd_print(F("NEW PART NAME:")); //print what ever part of the name they made so far
disp.lcd_rowcol(3, 0); //row, col
disp.lcd_print(F("* DONE CANCEL #"));
while (!valComplete) { //loop until the name is complete
disp.lcd_rowcol(1, 6); //row, col
disp.lcd_print(newFileName); //print what ever part of the name they made so far
disp.lcd_print(F(" ")); //cover up old letters
//0-9 are asci 48-57; hyphen is 45
while (1) { //get letters
byte k = checkKeyBuffer(); //get a keypress from the user
if (k == keyPound) {
cancelMsg();
return; //user canceled
}
else if (k == keyAsterisk) { //user finished
valComplete = true;
break;
}
else if (k == 2) { // = up arrow; letter step increase
currentLetter += 1;
if (currentLetter > 90) currentLetter = 45; //loop to the lowest val
if (currentLetter == 46) currentLetter = 48; //jump from hyphen up to 0
if (currentLetter == 58) currentLetter = 65; //jump from 9 up to A
newFileName[charCount] = currentLetter; //save the current letter to the name
break; //exit to refresh screen
}
else if (k == 8) { // = down arrow; letter step decrease
currentLetter -= 1;
if (currentLetter == 64) currentLetter = 57; //jump from A down to 9
if (currentLetter == 47) currentLetter = 45; //jump from 0 down to hyphen
if (currentLetter < 45) currentLetter = 90; //loop to the highest val
newFileName[charCount] = currentLetter; //save the current letter to the name
break; //exit to refresh screen
}
else if (k == 6) { // = right arrow; advance to the next letter
charCount += 1; //move to the next letter
if (charCount > 7) { //8 chars max
charCount = 7;
}
newFileName[charCount] = currentLetter; //save the current letter to the name
break;
}
else if (k == 4) { // = left arrow; advance back a letter
newFileName[charCount] = (char)0; //remove the current letter before backspacing
charCount -= 1; //move back a letter
if (charCount < 0) charCount = 0; //stop going back when we get to the first letter
break;
}
} //end of getting a letter
} //end of file name complete
if (charCount < 1) { //2 chars minimum for the filename
disp.lcd_cls(); //clear display
disp.lcd_print(F("FILENAME MUST BE"));
disp.lcd_rowcol(1, 0); //row, col
disp.lcd_print(F("3 LETTERS MINIMUM"));
continueMsg(); //wait for OK
cancelMsg();
return;
}
//now add the extension
newFileName[charCount + 1] = '.';
newFileName[charCount + 2] = 't';
newFileName[charCount + 3] = 'x';
newFileName[charCount + 4] = 't';
if (SD.exists(newFileName)) {
disp.lcd_cls(); //clear display
disp.lcd_print(F("NAME ALREADY EXISTS"));
delay(2000);
cancelMsg();
return;
}
File dataFile = SD.open(newFileName, FILE_WRITE);
dataFile.close();
void getInput(boolean numOnly, int maxSize, char *whereToStoreTheData)
{
// write not more than maxSize characters to the whereToStoreTheData array
}
I kinda understand this: So you're not really passing a string or characters back, you're just using the getInput function to put data in a variable that is in existence in the previous function. I tried making a test sketch, but I must have something wrong:
But, that is not really how your code will work, is it? Just store the data read from the keypad in the array you get the pointer to. The method really does need to know how big the array is, so it does not write beyond the end of the array.
What I’ve learned today from you, in my mind, has revolutionized the way I’ll think about functions! I’ve just always worked with global variables, but now I’m seeing how this is much better. My project is ‘sort of’ up and running - a cnc type machine with SDcard for data, roboclaw motor controller, I2C Keypad/LCD display… It was 30+ K of sketch, with 80% of my dynamic memory used up, but now I’m already down to 25K & 60% dynamic memory, and the more I rework it the better I think it’ll get.
Here’s my updated function for selecting a filename from the user. Because I can display 3 filenames at a time on the 4X20 LCD, I had three global chars[20], but now I don’t have to have any globals to do that job. And this is just one little step in the whole process, so I’m going to go thru and re-write it all again.
void getFileName(char *theData) { //selects a file from the the SD file and returns it
char fileNames[3][13]; //names of the next 3 files
char displayName[9]; //display name for the LCD (no extension)
disp.lcd_cls(); //clear display
dir = SD.open("/"); //open the main directory
while (1) { //keep looping through names until they select one
for (int a = 0; a < 3; a++) { //loop thru 3 files
File entry = dir.openNextFile();
if (!entry) { //there isn't a next file
entry.close(); //close the entry
dir.rewindDirectory(); //rewind
entry = dir.openNextFile(); //get the first file
}
strcpy(fileNames[a], entry.name());
entry.close();
int len = strlen(fileNames[a]); //how long is the file name?
memset(displayName, '\0', sizeof(displayName)); //delete the previous value.
strncpy(displayName, fileNames[a], len - 4);
//Display the name on the LCD
disp.lcd_rowcol(a, 0); //row, col
disp.lcd_print(a + 1); //the selection number
disp.lcd_print(F(": ")); //the selection number suffix
disp.lcd_print(displayName); //the filename without the extension
disp.lcd_print(F(" ")); //3 char min for name, so clear any extra 5 chars
}
disp.lcd_rowcol(4, 0); //row, col
disp.lcd_print(F("4. MORE 5. CANCEL")); //4 OR 5 TO SEE MORE FILE NAMES OF CANCEL
while (1) { //wait for key input
byte k = checkKeyBuffer(); //get a keypress from the user
if (k >= 1 && k <= 3) { //user chose 1,2 or 3
dir.close();
sprintf(theData, fileNames[k - 1]);
return;
}
else if (k == 4) {
break; //exit the key input loop to show the next 3 entries
}
else if (k == 5) { //cancel
dir.close();
theData[0] = '\0'; //add null terminator
return; //return nothing
}
} //end of wait for key stroke
} //end of while
}
so would it be better to replace
sprintf(theData, fileNames[k - 1]);
with
strcpy(theData, fileNames[k - 1]);