[SOLVED] Need help with Arduino project for school (Keypad, LEDs and OLED screen)

Hi guys,
My name is Esther and right now I’m doing my graduation assignment for the bachelor Industrial Product Design. For this assignment I’m developing a phone case with a keypad and screen for use in nursing homes. The only problem is that i never learned how to code during my programme. Thats why I’m asking you for help. I started a bit but I don’t know how to properly finish the code. I wil post the code below.

For this project I am using;
• Arduino Nano IOT 33
• OLED screen 128x64
• Membrame keypad 4x4
• 3x LED

My questions for the code are as follows:
• How do I make sure only 3 numbers are entered and not more
• How do I make sure that once 3 numbers are entered, and the user types more numbers the already entered numbers are overwritten? I’m not using a ‘clear’ button
• The fourth character will be a ‘A’ or a ‘B’. If there is a ‘A’ entered and the user presses ‘A’ again the letter should disappear. How would I do that?
• Lastly, when the user hits send the led thats on should blink for a few seconds and then turn off. I can remember something about defining the led that’s on as LedStatus.True but I don’t really know how to properly use it.

I know these are a lot of questions but I really need your help.
tips are always aprecciated
Kind regards,
Esther

//OLED
#define SCREEN_WIDTH 128 // OLED display width,  in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// declare an SSD1306 display object connected to I2C
Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1)

// Led

int ledGreen = 13;
int ledYellow = 12;
int ledRed = 11;


//Keypad
#define ROWS 4
#define COLS 4

char keymap[numRows][numCols]= 
{
{'1', '2', '3', 'G'}, 
{'4', '5', '6', 'O'}, 
{'7', '8', '9', 'R'},
{'A', '0', 'B', 'S'}
};

//Code that shows the the keypad connections to the arduino terminals
byte rowPins[numRows] = {9,8,7,6}; //Rows 0 to 3
byte colPins[numCols]= {5,4,3,2}; //Columns 0 to 


void setup() {
  // put your setup code here, to run once:
  byte numDigits = 4; 
}

void loop() {
  // put your main code here, to run repeatedly:

case '0'... '9' /// invoer client nummer
{

  char key = keypad.getKey();
  if(key){
    if(key=='*'){
      keyNum = 0;
    }
    else{
      if(keyNum<=999){
        keyNum = (keyNum*10) + (int(key)-48);
      }

case 'A''B' /// invoer extra kamer v mnr,mvr 
  
  case 'G': /// geen agitatie, Groen

    digitalWrite(ledGreen, HIGH);
    digitalWrite(ledYellow, LOW);
    digitalWrite(ledRed, LOW);

  case 'O': /// milde agitatie, Oranje
    
    digitalWrite(ledGreen, LOW);
    digitalWrite(ledYellow, HIGH);
    digitalWrite(ledRed, LOW);
    
 case 'R': /// heftige agitatie, Rood
   
    digitalWrite(ledGreen, LOW);
    digitalWrite(ledYellow, LOW);
    digitalWrite(ledRed, HIGH);
    
 case 'S': // verstuur invoer

That is a fairly complex program for someone that hasn't done any programming.

Start with getting each individual component running first. The OLED screen is fairly popular so there's lot of libraries for it. That's what I would get working first if this is my project

hi,

thank you for answering. i have every component running on it's own. the trouble i'm having is with combining everthing into my product.

and yes, i totally agree. i may have bitten of more than i could chew. :sweat_smile:

Hello Esther:
Congratulations on getting to your graduation assignment; bravo.

First, there are many ways to write code, one universal way is commonly called pseudo-code, kind of a made-up set of tasks:

  • get a numeric digit
  • get another numeric digit
  • get another numeric digit
  • get an alpha character

So, that is some code. It does not fulfill all of your criterion, but gets us started.

A "state machine" is a fancy term for doing something correctly before moving to the next step. Implied in this definition is the need to handle non-correct conditions.

For example, your 4th input is a character, not a numeric digit. To a computer, a character is a very broad definition: ASCII CHART

Armed with our new information, we can rewrite the first part of the state-machine:

  • get character between ASCII 48 .and. ASCII 57, Inclusive
  • Display digit in proper position
  • number digits < 3? Get more or drop to next state
    -- get 1 character with ASCII 65 "A" .or. ASCII 97 "a" .or. ASCII 66 "B" .or. ASCII 98 "b" (lowercase optional) but if a numeric entered in 4th position clear display and start from top state

The above is a weak state description, a little pseudo-code. At this time you could continue pseudo-coding or you could get into doing some real coding - which is what I suggest.

Priority 1, get your OLED working with the Nano ... your library choice will have test examples; run them.
Priority 2, connect that keyboard and select a library. Again, you will have test code.
Priority 3, combine OLED and keyboard code.
Priority 4, add in the LEDs and write some test code: maybe press "1" for 1st LED, "2: or 2md LED, "3" for 3rd LED ... clear then all on any other keypress.

You got this coding thing.

Ray

thank you so much for responnding. i will read up on the topic and kep you posted :blush:

Good luck. Do spend a bit of time with examples... they were written to show off; you can play with edits and add/delete to 'see' what happens... if you mess it all up, a perfect copy is on the internet :slightly_smiling_face:

Work up on the logic first. Instead of getting the OLED and keypad working together, use the Serial as input for now and get the logic in place. Once that is done, all you need to do is replace the Serial input to the Keypad input and hopefully everything just works

Normally, I would agree, but the 4x4 is radically different from the serial input over USB and I believe getting the OLED and the keyboard into the sketch, both working correctly, would not distract from the coding exercise logic. Rather, IMO the logic must follow the keyboard implementation which follows the library chosen. That is, in my crude example previously, I used the ASCII chart to determine the key input value. This obviously falls apart if the [4x4 library]( Arduino Playground - Keypad Library) does not map to ASCII.

An implementation:
https://electropeak.com/learn/interfacing-4x4-membrane-keypad-with-arduino-w-sample-project/

I wanted to play around a bit, but my Arduino "bits & stuff" box did not have a membrane keypad; sure I did once but I have relatives and friends that see my old-stock stuff as excess toys; I likely gave it away for some project.
But looking at one example from the library previously linked, it does appear the lib returns a single char which is easy to test.

  char customKey = customKeypad.getKey();
  

this is the project I used as a example to set up my code.

Hi Esther,

I want to emphasize. Your project is completely doable. You could even add playing some MP-3files and connect RGB-Leds showing a moving rainbow. But I guess you won't do that.

This Caclulator-project delivers a basic structure on how to realise userinput with a membrane-keyboard and how to print to an OLED-display.

Anyway this code needs quite a lot modifications and writing these modifications requires a basic knowledge about how programming C++ with the Arduino-IDE works in general.
what is setup() for? What is loop() for? etc.

The good thing about C++-Programming is: You can divide a program into functional parts where each part can be tested on its own. After testing it is very simple to add the tested part to your main code.

So make a decision which part would you like to have support for first.
Is it

  • checking if 3 numbers are entered
  • blinking an LED for some seconds
  • printing to and clearing the display

best regards Stefan

hi Stefan,

thank you for the additional information. this is my code so far. i would love some feedback on how to put the input on to the screen. :blush:

have a wonderfull day.

kind regards,

Esther

#include <Keypad.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// oled Set up
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#if (SSD1306_LCDHEIGHT != 64)

// LEd setup

int ledGreen = 13;
int ledOrange = 12;
int ledRed = 11;

// Keypad set-up
const byte numRows= 4; //number of rows on the keypad
const byte numCols= 4; //number of columns on the keypad

char keyboardInput[5] = {0}; 
int i=0;

//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1','2','3','G'},
  {'4','5','6','O'},
  {'7','8','9','R'},
  {'A','0','B','S'}
};
byte rowPins[ROWS] = {9,8,7,6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

void setup(){

    pinMode(ledGreen, OUTPUT);    //Define LED pins
    pinMode(ledYellow, OUTPUT);
    pinMode(ledRed, OUTPUT); 
    
  Serial.begin(9600);
}

delay(2000);         // wait for initializing
  oled.clearDisplay(); // clear display

  oled.setTextSize(2);          // text size
  oled.setTextColor(WHITE);     // text color
  oled.setCursor(0, 10);        // position to display

void loop() {
  // put your main code here, to run repeatedly:

  case '0'... '9'
  //Numbers 0 till 9, saves as the firts three characters in array
  //if there are more numbers than three, it starts over
  if(i >= 3)
        { 
          memset(keyboardInput,0,sizeof(keyboardInput));
          i = 0; 
        }
        keyboardInput[i++] = customKey;


  case 'A''B'
   //Check f this is the fourth character, if yes put  in array
        if(i==3)
          keyboardInput[i++] = customKey;
        break;

  case 'G'
     digitalWrite(ledGreen, HIGH);
    digitalWrite(ledOrange, LOW);
    digitalWrite(ledRed, LOW);

  case 'O'
    digitalWrite(ledGreen, LOW);
    digitalWrite(ledOrange, HIGH);
    digitalWrite(ledRed, LOW);

  case 'R'
    digitalWrite(ledGreen, LOW);
    digitalWrite(ledOrange, LOW);
    digitalWrite(ledRed, HIGH);

  case 'S' 
  //Sending. atm only used to clear display and let a led blink for e few seconds 
        memset(keyboardInput,0,sizeof(keyboardInput));     
        break;

}

Hi Esther,

I'm willing to help. But I will not write down the whole code you.

How much did you read in the programming-course?

The code you have posted does not compile. The reason is very basic and can be seen as you still yet don't know the very very fundamentals about programming-syntax.
I'm not sure about this so I'm asking
Are you trying to make me write most of the code by posting quick & dirty added some lines?

The sure way to make a code work reliably is to test each functional part on its own
with a testcode.

Your code posted above can be seen in this way. So there is only missing one small step for checking if pressing a key on the keypad is working as expected.

This testcode shall print the pressed key to the serial monitor.
Make - at least - a suggestion how this might be coded.

best regards Stefan

Hi Stefan,

i'm not asking you to write my code. the code i posted was meant a update to let you guys know that im still working on it. im sorry if it came across otherwise.

the keypressing wokrs as expexted, it will print the key you press into the serial monitor. however it doesnt print the combines code (example; 015A) yet.

i will read up on some more information aswell.

kind regards,

Esther

The code you have posted does

not

compile
So there must have gone something wrong between copyiing and pasting the code

You should post code by using code-tags
There is an automatic function for doing this in the Arduino-IDE
just three steps

  1. press Ctrl-T for autoformatting your code
  2. do a rightclick with the mouse and choose "copy for forum"
  3. paste clipboard into write-window of a posting

best regards Stefan

Very strange use of 'case', as there is no 'switch'!? It's a good idea to at least read the syntax of the commands before trying to program.

If you break down the logic, it's fairly straight-forward. Here's a pseudo-code that uses a bunch of if-elseif-else statements instead of switches. The key is imagining the program flow as if you are the Arduino executing the code...

	char keypadInput[5] = {0};
	uint8_t i = 0;
	
	loop()
	{
		// get input from keypad
		char temp = keypad.getChar();

		// you only enter the logic is there's an input from user
		if(temp is NOT NULL)
		{
			// this section guarantees only numbers are allowed in the first three input
			// "How do I make sure only 3 numbers are entered and not more"
			if(i<3)
			{
				// check for characters '0' to '9'
				if((temp > 47) && (temp < 58))
				{
					keypadInput[i] = temp;
					i++;
				}
				// if anything else, just ignore it
				else {
					// do nothing
					asm("NOP");
				}
			}
			// check for the last character (4th at this point)
			else
			{
				// "How do I make sure that once 3 numbers are entered, and the user types more numbers the already entered numbers are overwritten? I’m not using a ‘clear’ button"
				// if user enters another number, clear the input buffer, and reset i to zero to start from the beginning
				if((temp > 47) && (temp < 58))
				{
					memset(keypadInput, 0, 5);
					i = 0;
				}
				// if this is an 'A' or 'B' instead
				// "The fourth character will be a ‘A’ or a ‘B’. If there is a ‘A’ entered and the user presses ‘A’ again the letter should disappear. How would I do that?"
				else if(temp == 'A')
				{
					// check the current value of keypadInput[3] if there's an A in there
					if(keypadInput[3] == 'A')
					{
						// clear the value
						keypadInput[3] = 0;
					}
					else {
						keypadInput[3] = temp;
					}
				}
				// same logic applies if 'B' is entered
				else if(temp == 'B')
				{
					// check the current value of keypadInput[3] if there's an B in there
					if(keypadInput[3] == 'B')
					{
						// clear the value
						keypadInput[3] = 0;
					}
					else {
						keypadInput[3] = temp;
					}
				}
				// the rest of your code goes here
				else if('G') {
					// do your LED thing
				}
				else if('O') {
					// do your LED thing
				}
				else if('R') {
					// do your LED thing
				}
				else if('S')
				{
					// clear buffer and start from the beginning
					memset(keypadInput, 0, 5);
					i = 0;
				}
				
				// update the OLED with the content of keypadInput here
				OLED.clear();
				OLED.print(keypadInput);
			}
		}
	}