Well here's my code for my project.
I've got an 8-digit 7-segment display to show the numbers. I could have used a 1-digit 7-segment but I want my eventual project to contain quite a few 7-segment displays. Plus a 5x3 keypad connected via a PCF8574 IC.
keypad_test.ino:
#include "Display.h"
#include "Keypad.h"
#define DIN_PIN 5
#define CS_PIN 6
#define CLK_PIN 7
#define NUM_DISPLAYS 1
#define KEYPAD_ADDR 0x20 // PCF8574 A0, A1, and A2 all grounded
CDisplay m_display(DIN_PIN, CLK_PIN, CS_PIN, NUM_DISPLAYS);
CKeypad m_keypad(KEYPAD_ADDR);
void setup()
{
m_display.Init();
m_keypad.Init();
for (long num = 0; num < 10; ++num)
{
m_display.ShowNumber(1, num);
delay(500);
}
}
void loop()
{
/*for (long num = 0; num < 1000000; ++num)
{
m_display.ShowNumber(1, num);
delay(500);
}
m_display.ClearDisplay(1);*/
char key = m_keypad.GetKey();
if (key)
{
if (isdigit(key))
{
long number = atol(key);
m_display.ShowNumber(1, number);
}
}
}
Display.h:
class LedControl;
class CDisplay
{
public:
CDisplay(const int dataPin, const int clkPin, const int csPin, const int numDevices);
~CDisplay();
void Init();
void ShowNumber(int deviceId, unsigned long number);
void ClearDisplay(int deviceId);
private:
void printNumber(int addr, unsigned long number);
unsigned int didgitCount(const unsigned long num, const unsigned int max);
const int m_nDataPin;
const int m_nClkPin;
const int m_nCsPin;
const int m_nNumDevices;
LedControl* m_pLC;
};
Display.cpp:
#include "Display.h"
#include <LedControl.h>
CDisplay::CDisplay(int dataPin, int clkPin, int csPin, int numDevices)
: m_nDataPin(dataPin)
, m_nClkPin(clkPin)
, m_nCsPin(csPin)
, m_nNumDevices(numDevices)
{
m_pLC = new LedControl(dataPin, clkPin, csPin, numDevices);
}
CDisplay::~CDisplay()
{
delete m_pLC;
}
void CDisplay::Init()
{
for (int addr = 0; addr < m_pLC->getDeviceCount(); ++addr)
{
// Initialize the module
m_pLC->shutdown(addr , false);
// display brightness adjustment
m_pLC->setIntensity(addr , 0x06);
// Delete the display
m_pLC->clearDisplay(addr);
}
}
void CDisplay::ShowNumber(int deviceId, unsigned long number)
{
printNumber(deviceId-1, number);
}
void CDisplay::ClearDisplay(int deviceId)
{
m_pLC->clearDisplay(deviceId-1);
}
void CDisplay::printNumber(int addr, unsigned long number)
{
unsigned int digits = didgitCount(number, 8);
// Calculate the value of each digit
int digit1 = number % 10 ;
int digit2 = (number / 10)% 10 ;
int digit3 = (number / 100)% 10 ;
int digit4 = (number / 1000)% 10 ;
int digit5 = (number / 10000)% 10 ;
int digit6 = (number / 100000)% 10 ;
int digit7 = (number / 1000000)% 10 ;
int digit8 = (number / 10000000)% 10 ;
// Display the value of each digit in the display
switch (digits)
{
case 8:
m_pLC->setDigit(addr, 7, (byte)digit8, false);
case 7:
m_pLC->setDigit(addr, 6, (byte)digit7, false);
case 6:
m_pLC->setDigit(addr, 5, (byte)digit6, false);
case 5:
m_pLC->setDigit(addr, 4, (byte)digit5, false);
case 4:
m_pLC->setDigit(addr, 3, (byte)digit4, false);
case 3:
m_pLC->setDigit(addr, 2, (byte)digit3, false);
case 2:
m_pLC->setDigit(addr, 1, (byte)digit2, false);
case 1:
m_pLC->setDigit(addr, 0, (byte)digit1, false);
}
}
//
// Returns the number of digits that need to
// be lit up on the LED, to show num
//
unsigned int CDisplay::didgitCount(const unsigned long num, const unsigned int max)
{
if (num == 0 || num == 1) return 1;
if (num == 10) return 2;
unsigned int count(max);
for (; count > 0; --count)
{
if (pow((double)10, (double)(count - 1)) < num)
break;
}
return count;
}
Keypad.h:
#include <Arduino.h>
#define ROWS 5
#define COLS 3
class CKeypad
{
public:
CKeypad(const byte address);
~CKeypad();
void Init();
char GetKey();
private:
byte Read();
void Write(byte);
const byte m_addr;
byte m_rows[ROWS];
byte m_cols[COLS];
char m_keypad[ROWS][COLS];
};
Keypad.cpp:
#include "Keypad.h"
#include <Wire.h>
CKeypad::CKeypad(const byte address)
: m_addr(address)
{
m_rows[0] = B11110111;
m_rows[1] = B11101111;
m_rows[2] = B11011111;
m_rows[3] = B10111111;
m_rows[4] = B01111111;
m_cols[0] = B00000001;
m_cols[1] = B00000010;
m_cols[2] = B00000100;
m_keypad[0][0] = 'C';
m_keypad[0][1] = 'M';
m_keypad[0][2] = 'N';
m_keypad[1][0] = '7';
m_keypad[1][1] = '8';
m_keypad[1][2] = '9';
m_keypad[2][0] = '4';
m_keypad[2][1] = '5';
m_keypad[2][2] = '6';
m_keypad[3][0] = '1';
m_keypad[3][1] = '2';
m_keypad[3][2] = '3';
m_keypad[4][0] = '*';
m_keypad[4][1] = '0';
m_keypad[4][2] = '-';
}
CKeypad::~CKeypad()
{
}
void CKeypad::Init()
{
Wire.begin();
}
char CKeypad::GetKey()
{
char key = '\0';
for (int row = 0; row < ROWS && !key; ++row)
{
Write(m_rows[row]);
byte receive = Read();
if (receive != m_rows[row])
{
for (int col = 0; col < COLS && !key ; ++col)
{
if (m_cols[col] & receive == 0)
{
key = m_keypad[row][col];
}
}
}
}
return key;
}
byte CKeypad::Read()
{
byte data;
Wire.requestFrom(m_addr, 1);
if (Wire.available())
{
data = Wire.read();
}
return data;
}
void CKeypad::Write(byte data)
{
Wire.beginTransmission(m_addr);
Wire.write(data);
Wire.endTransmission();
}
If I just run the code without connecting the breadboard with the PCF8574 and keypad connected, and enable the code to loop through numbers 0 to 1000000, the 7-segment will happily show the numbers. But if I then disable that part of the program and enable the program to read the key press and display the number accordingly and connect the 7-segment to the breadboard and the Arduino to the breadboard then the display will just show complete random data!! This is why a year or so back when I last looked at creating this project I started to use the 74C922 keypad decoder.
I'll draw up a schematic and post that here if that helps. I'm at a loss at the moment again.