Search code examples
c++arduinokeypad

Alpha-numeric Telephone Keypad with Arduino


I'm trying to make a capacitive touch keypad to take input from a user, and output a string of characters generated by this input. Each pad returns its value, with the first being 1, the second being 2, the third 4, 8, 16 up until 2^12. (If multiple keys are touched, their ids are added up, but this won't happen.)

Imagine you're using your old Nokia phone and typing a message to a friend, you press 2 twice for 'b' and 9 three times for 'y'. I need code for something like this.

My biggest hurdle is that I have very limited knowledge of C, and what I have done so far has gone well, with the occasional hiccup, however this is far beyond my knowledge.

Here's my current code, it's not pretty, but it's my current attempt at this.

//import all packages
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1351.h>
#include <Adafruit_MPR121.h>
#include <Adafruit_NeoPixel.h>
#include <SPI.h>
//define pins for OLED display
#define sclk SCK
#define mosi MOSI
#define dc   A1
#define cs   A2
#define rst  A3
//define pins for indicator lights
#define neo_pin A4
//define basic colours
#define BLACK           0x0000
#define BLUE            0x001F
#define RED             0xF800
#define GREEN           0x07E0
#define CYAN            0x07FF
#define MAGENTA         0xF81F
#define YELLOW          0xFFE0 
#define WHITE           0xFFFF
//create the screen
Adafruit_SSD1351 screen = Adafruit_SSD1351(cs, dc, mosi, sclk, rst);
//create the cap. sensor
Adafruit_MPR121 cap = Adafruit_MPR121();
//initialize the variables used by the cap. sensor
uint16_t lastTouched = 0;
uint16_t currTouched = 0;
int delayPress = -1;
int buttonIndex = 0;
int padTouched = 0;
//create the neopixel indicator light
Adafruit_NeoPixel indicator = Adafruit_NeoPixel(1, neo_pin, NEO_GRB + NEO_KHZ800);
//initialize functional variables
char string[32];
//level 0 functions
void flash(int dly = 100)
{
  digitalWrite(13,HIGH);
  delay(dly);
  digitalWrite(13,LOW);
  delay(dly);
}
void flashIndicator(int dly = 100)
{
  setColour(255,255,255);
  delay(dly);
  setColour(0,0,0);
  delay(dly);
}
void setColour(int r, int g, int b)
{
  indicator.setPixelColor(0,r,g,b);
  indicator.show();
}
void resetDrawText(char *text,uint16_t textColour = WHITE, uint16_t backColour = BLACK)
{
  screen.fillScreen(backColour);
  screen.setCursor(0,0);
  screen.setTextColor(textColour);
  screen.print(text);
}
void drawText(char *text,uint16_t textColour = WHITE)
{
  screen.setCursor(0,0);
  screen.setTextColor(textColour);
  screen.print(text);
}

//component startup functions (level 1)
void startIndicator()
{
  indicator.begin();
  indicator.setBrightness(64);
  setColour(0,0,0);
  setColour(0,255,0);
}
void startCap()
{
  cap.begin(0x5A);
}
void startScreen()
{
  screen.begin();
  screen.fillScreen(BLACK);
}

void setup() {
  // start all components
  startIndicator();
  startCap();
  startScreen(); 
  Serial.begin(9600);
  Serial.println("init");
  setColour(255,0,255);
}

void keyIn()
{
  flashIndicator(100);
  flashIndicator(100);

  char catChar[] = " ";
  Serial.println("pad index");
  Serial.println(currTouched);
  switch (currTouched)
  {
    case 1:
    catChar[1] = "A";
    break;

    case 2:
    catChar[1] = "B";
    break;

    case 4:
    catChar[1] = "C";
    break;
  }
  //Serial.println("char group");
  //Serial.println(catGroup);


  //strcpy(catChar, catGroup);
  //char catChar = catGroup[buttonIndex];
  Serial.println("new char");
  Serial.println(catChar);

  strcat(string, catChar);
  drawText(string);
  Serial.println("draw text");
  Serial.println(string);
  delayPress = -1;
  buttonIndex = 0;
  padTouched = 0;
}

void loop() {
  currTouched = cap.touched();

  if ((currTouched > 0) and (not currTouched == lastTouched))
  {
    Serial.println("pad touched");
    Serial.println(currTouched);
    flashIndicator(200);
    if ((padTouched == currTouched) or (padTouched == 0))
    {
    delayPress = 50;

    buttonIndex++;
    if (buttonIndex > 2)
    {
        buttonIndex = 0;
    }
    Serial.println("button index");
    Serial.println(buttonIndex);
    }
    else if (not currTouched == 0)
    {
    keyIn();
    }
    padTouched = currTouched;
  }
  if (delayPress > 0)
  {
    delayPress--;
  }
  else if (delayPress == 0)
  { 
    keyIn();
  }
  lastTouched = currTouched;

  flash(50);//delay(100);
}

Please feel free to ask for clarity, and if you do know the solution, please explain what each line and statement is doing so that I can gain some insight into the language.


Solution

  • This demonstrates the concept of alphanumeric keypad typing:

    const int max_delay_between_keys = 300; // Time in milliseconds to allow between keypresses
    
    String text = "";
    char current_char = '\0';
    int last_pressed = -1;
    int times_pressed = 0;
    int time_last_pressed = 0;
    
    char lookup_value(int key, int count) {
        const char* const characters[12] = {"1", "abc2", "def3", "ghi4", "jkl5", "mno6", "pqrs7", "tuv8", "wxyz9", "*", "0 ", "#"}; //Change this to match the characters on your keypad.
        const char* sequence = characters[key];
        return sequence[count % strlen(sequence)];
    }
    
    String process_keystream(int key_code) {
        int new_time = millis();
        bool time_over = (new_time - time_last_pressed > max_delay_between_keys);
    
        time_last_pressed = new_time;
    
        key_code = log((float)key_code) / log(2.0) - 1;
        if (key_code == last_pressed && !time_over) {
            times_pressed += 1;
        }
        else {
            if (last_pressed != -1) {
                text += current_char;
            }
    
            last_pressed = key_code;
            times_pressed = 0;
        }
        current_char = lookup_value(key_code, times_pressed);
    
        return text + current_char;
    }
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(115200);
    
      // Serial.println() is what you'd send to your screen.
      Serial.println(process_keystream(16)); // Pressed the 4 key
      Serial.println(process_keystream(16)); // Pressed the 4 key
      Serial.println(process_keystream(8));  // Pressed the 3 key
      Serial.println(process_keystream(8));  // Pressed the 3 key
      Serial.println(process_keystream(32)); // Pressed the 5 key
      Serial.println(process_keystream(32)); // Pressed the 5 key
      Serial.println(process_keystream(32)); // Pressed the 5 key
      delay(500);                            // Wait a while so the current letter is set.
      Serial.println(process_keystream(32)); // Pressed the 5 key
      Serial.println(process_keystream(32)); // Pressed the 5 key
      Serial.println(process_keystream(32)); // Pressed the 5 key
      Serial.println(process_keystream(64)); // Pressed the 6 key
      Serial.println(process_keystream(64)); // Pressed the 6 key
      Serial.println(process_keystream(64)); // Pressed the 6 key
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
    
    }
    

    Result:

    g
    h
    hd
    he
    hej
    hek
    hel
    helj
    helk
    hell
    hellm
    helln
    hello