Problem with 3*4 Keypad Again

#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 3;

char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};

byte rowPins[ROWS] = { 25, 35, 33, 29 };
byte colPins[COLS] = { 27, 23, 31 };

Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup()
{
Serial.begin(9600);
}

char charGain[4];
int charindex =0;
int i;

void loop(){

for(charindex == 0;charindex < 3; charindex++){

char key = kpd.getKey();
if (key != NO_KEY){
if (key = '#'){
for(charindex;charindex < 3;charindex++){ //if the user didn't enter 4 digits float from the keypad, then other char in the array is set to be 0
charGain[charindex]=0;
}
charindex=0;
}
else if (key = '*'){
int charindex =0;
}
else{ //if the user enter 0-9, then store it into array and display it
charGain[charindex]=key;
charindex++;
Serial.print(charGain[charindex]);
}
}
}
charGain[4] = '\0';
i = atoi (charGain);
Serial.print(i);
}

Can anyone tell me what's wrong here?

Well, the code was not posted using the # button.

Other than that, our crystal ball is broken, I'm afraid. You have to give us at least a tiny hint. Does the code not compile? Does it compile, but not produce the correct results?

If it compiles, but does not produce correct results, what results are you expecting, and what results are you getting?

There are some errors, like this:

if (key = '#')

That should be a == in there, I'm pretty sure.

#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 3;

char keys[ROWS][COLS] = {
 {'1','2','3'},
 {'4','5','6'},
 {'7','8','9'},
 {'*','0','#'}
};

byte rowPins[ROWS] = { 25, 35, 33, 29 };
byte colPins[COLS] = { 27, 23, 31 };

Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup()
{
 Serial.begin(9600);
}

char charGain[4];
int charindex =0;
int i;

void loop(){

for(charindex = 0;charindex < 3; charindex++){    //to compare use == to assign use =

 char key = kpd.getKey();
 if (key != NO_KEY){  
  if (key == '#'){     //to compare use == to assign use =
       for(charindex= ??;charindex < 3;charindex++){  //if the user didn't enter 4 digits float from the keypad, then other char in the array is set to be 0
//you need to say where charindex start
       charGain[charindex]=0;
       }
         charindex=0;
         }
  else if (key == '*'){   //to compare use == to assign use =
           int charindex =0;
           }
  else{      //if the user enter 0-9, then store it into array and display it
      charGain[charindex]=key;
      charindex++;
      Serial.print(charGain[charindex]);
       }
 }
}
charGain[4] = '\0';
i = atoi (charGain);
Serial.print(i);
}

Does this even compile?

It compiles correctly. The problem was I'd get whatever the input key was repeated an infinite amount of times.

Unfortunately I currently don't have a keypad to test it again, but all I'm trying to do is store a number that the user inputs that is 3 digits or less. I may have to change it to 4 digits though.

I'd also like to be able to break the code up into sections as I've seen done before for example:

void loop(){

calibrate();
...
}

void calibrate(){
...
}

but if I reference a variable from calibrate in a different part of void loop then it says that the variable is not in scope.

If you declare the variable outside of any function it is available in all functions.

I tried that, but this is what happens.

int x;
int y;

void loop(){

calibrate();
y = x *4;
Serial.print(x);
Serial.print(y);
}

void calibrate(){
x = 5;
}

and I'd get that both x and y equal zero.

Here's my version (the complete sketch made from the incomplete code in your last post):

int x;
int y;

void setup()
{
    Serial.begin(9600);
}
void loop()
{
    calibrate();
    y = x * 4;
    Serial.print("x = ");
    Serial.print(x);
    Serial.print(", y = ");
    Serial.println(y);
    Serial.println();
    delay(5000);
}

void calibrate(){
    x = 5;
}

Here's the output:


x = 5, y = 20


Now what do you get?

Regards,

Dave

Footnotes:

1: For small test cases like this, when you post code and report results, it might be more useful to people reading the thread if you would post the entire sketch, so that we know exactly what you are running.

2: Notice that I make the print statements verbose enough to tell me exactly what it is that I am seeing on the serial monitor. I mean, when you just print some digits with no separation and no identification, how can you tell what the heck the program is really doing?

It's an accelerometer.

        int ca = ca2 * 1;
        int upper = ca + 2;
        int lower = ca - 2;

In calibrate(), you are creating and manipulating local variables named ca and upper. Then, in loop(), you are printing the global (unchanged) variables. No wonder they are always 0.

Nevermind I solved the problem. I shouldn't have repeated the int. Nevertheless I still may need help with the keypad.

It's an accelerometer

What is?
A 3x4 keypad?

Firstly, you seem to want four digits inputted but your FOR loops go from 0 to less than three. Less than three is 2, so it goes 0,1,2.

Secondly, you define a string as: charGain[4]
That means it has four chars in it. Arrays start counting from 0 though, so the available characters in charGain are charGain[0], charGain[1], charGain[2] and charGain[3].
You add a character to charGain[4] which doesn't exist.

Thirdly, you have nested FOR loops using the same counter variable. I think it'll work, but it's a bad idea. It's really easy to get wrong and mess up your first loop, so you'd be better using a different variable then when complete terminate the loop.

You get the same character infinite times because you have no condition on it printing i.

Look through your LOOP: you've got a FOR loop, within which is an if (key != NO_KEY){ loop.
So, your FOR loop executes three times, if there's a keypress then it does something. If there is no keypress it doesn't executre that IF loop. It doesn't wait for there to be a keypress, it just doesn't execute that for loop.

So it keeps looping, and it loops quickly. Once you've pressed a key then it processes it, and afterwards it has a keypress in its variables so every time a key isn't pressed it doesn't do the IF A KEY HAS BEEN PRESSED bit and shoots straight to the end, where it prints the key it has.

Change that IF (key !=.. to something like (and this is a guesstimate, not guaranteed to work):

char key = kpd.getKey();
 while (key == NO_KEY){
   key = kpd.getKey();
  }
 if (key = '#'){

Then the rest of your code.

That while loop will hold the programme there until it gets a keypress and should solve your problem.

AWOL another guy asked a different question I had about an accelerometer, but I deleted most of those messages.

#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 3;

char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};

byte rowPins[ROWS] = {25, 35, 33, 29};
byte colPins[COLS] = {27, 23, 31}; 

Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup()
{
  Serial.begin(9600);
}

char charGain[4];
int charindex =0;
int i;

void loop(){

char key = kpd.getKey();
if (key != NO_KEY){ 
while (charindex < 4){
   if (key == '#'){ 
        while (charindex < 4){  //if the user didn't enter 4 digits float from the keypad, then other char in the array is set to be 0
          charGain[charindex]=0;
          ++charindex;
        }
       //   charindex=0;
          }
   else if (key == '*'){
            charindex =0;
            }
   else if (key != NO_KEY || '#' || '*'){      //if the user enter 0-9, then store it into array and display it
       charGain[charindex]=key;
       ++charindex;
        }
 }
}
 charGain[4] = '\0'; 
 i = atoi (charGain); 
 Serial.println(i);
/* for (charindex == 0;charindex < 4;charindex++){
    //lcd.print("array [" ++ charindex ++ "]"++ charGain[charindex]);
    Serial.print("array [");
    Serial.print(charindex);
    Serial.print("] ");
    Serial.print(charGain[charindex]); 
 } */
}

Well I tried it again using this code and I'll either get the same number 4 times in a row, for example, if a 1 was pressed: 1111 or just a 0.

The # seems to clear it, so idk what the problem is there with either the * key or the # key or both.

I would appreciate any help though.

You've got your IF and WHILE loops the wrong way round. The purpose of a while loop in this case is to stop the progression of the character count. You don't do that. Your code does not demand a keypress, and because it loops quicker than you can press four buttons it uses the same keypress four times.

I was playing with a keypad the other day, I've modified the cod eI used so it works the way yours should:

boolean done = false;
byte charIndex = 0;
char charGain[5];
while (!done) {  //do this loop til got number
    char key = kpd.getKey();  //get keypress
    if (key) {
      if (key=='*') { 
        charIndex=0;
      } else if (ky=='#') {
        done = true;
      } else { //is a number
        charGain[charIndex] = key;
        charIndex++;
        if (charIndex == 4) { done = true; }
      }
    }
  }
  for (byte i = charIndex; i < 4; i++) {
      charGain[charIndex] = 0;
  }
  charGain[4] = '\0';
  i = atoi(charGain);
  Serial.println(i);

I used a boolean flag, done to keep it in the loop until I've either got a four digit number or # has been pressed.
Then, I make sure the four digits are filled. You don't need an IF statement - it only inserts the 0s into empty spaces.

You do realise that it'll put the 0s at the end? So if I entered 1# it'd result in 1000.

Thank you very much! It seems to be working very well. It does seem a little sensitive. For example, it may repeat a number (1123) if the buttons are not pressed quickly and sharply. Is there anyway to fix that?

Also for curiosity's sake what does this section of code do:

for (byte i = charIndex; i < 4; i++) {
      charGain[charIndex] = 0;
  }

I got rid of it and it still seems to work fine.

Thanks again!

If # is pressed then that loop you quote fills the string with 0s.

So if you type 12# the result will be 1200 instead of 12. You seemed to be trying to do that in your original code.

EDIT: I got it wrong though! It should be:

for (byte i = charIndex; i < 4; i++) {
      charGain[i] = 0;
  }

My keypad doesn't have an auto-repeat so I haven't experienced that problem. You could put a small delay in, so:

if (key) {
  delay(200);

the new bit is the delay(200); - adding that will introduce a 2/10ths of a second delay after a keypress. You can experiment to see how big it needs to be.

Also how could I add the option not to have input at all? At this point I'd like user input to be optional.

Oh well I didn't want the zeros to be after it anyway, so this is better. The problem now is that it seems to stop the rest of the code from running.

I think it goes through the whole code and gets trapped back in the while loop.