Arduino Kitchen Timer

Arduino Kitchen Timer is made of 4-digit 7-segment LED, and 12-key keypad, 8-bit shift register 74HC164, and some resistors, decoupling capacitor, and Piezo speaker for the sound output.

* Do not imagine I am using this timer in my kitchen because I don’t. :) It’s just the name of device…

Feature:
Kitchen Timer. Maximum duration is 99 minutes and 99 sec. Beep when it’s done.

Parts:
1 x Keypad 12 Button
1 x 7-Segment Yellow 4 Digit LED
1 x 74AC164
8 x 470 ohm Resistor (LED)
* 220 ohm may work but it’s a little bit brighter. I used 470 ohm resistor array.
3 x 4.7K ohm Resistor (Keypad pullup resistors)
1 x Piezo Speaker taken out from old PC.

Pin Assignment:
Digital 02-05 Common Cathode of LED
Digital 06-12 Keypad Scanning
Digital 13 Piezo Speaker Output
Analog 0 74AC164 Data
Analog 1 74AC164 Clock
Analog 3-5 Not Used.

Video and Semantic in eagle format will be added soon.
Porting to Arduino Kitchen Timer Shield is on the way, but I will replace the keypad with just three or four buttons.

#include   <GenKeypad.h> //My keypad library
#include   <MsTimer2.h> //download this library at http://www.arduino.cc/playground/Main/MsTimer2

#define SHIFT_DATA 15     // 74AC164 data pin
#define SHIFT_CLOCK  14   // clock pin
#define SPEAKER_PIN 13

int NumPins[4] = {2, 3, 4, 5};
int SS = 0;
int MM = 0;
int start = 0;
char input[4] = {0, 0, 0, 0};
int inputIndex = 0;
int length = 15; // the number of notes
char notes[] = "ccccccccccccccc";
int beats[] = { 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1 };

int tempo = 300;
int beeping = 0;

/**
   Keypad 
 **/
GenKeypad keypad;

//Key Input Callback Functions 

void keyUP(char key)
{
  //Serial.print("keyUP: ");  
  //Serial.println(key);  
}  

int atoi(char c)
{
  if (c == 0)
    return 0;
  else
    return (c - '0');
}

void keyDOWN(char key)
{
  Serial.print("keyDOWN: ");
  Serial.println(key);  

  if (key == '#' && start == 0)
  {
    //Convert input chars into MM:SS
    MM = atoi(input[0]) * 10 + atoi(input[1]);
    SS = atoi(input[2]) * 10 + atoi(input[3]);

    if (MM + SS > 0)
      start = 1;
    return;
  }
  else if (key == '#' && start == 1)
  {
    start = 0;
    return;
  }

  if (key == '*')
  {
    if (beeping == 0)
    {
      for (int i = 0; i < 4; i++)
        input[i] = 0;
    }

    inputIndex = 0;
    start = 0;
    beeping = 0;
    digitalWrite(SPEAKER_PIN, LOW);
  }
  else
  {
    shiftDigit(input);
    input[3] = key;      

    inputIndex++;
    inputIndex %= 4;
  }
}  

void shiftDigit(char input[4])
{
  input[0] = input[1];
  input[1] = input[2];
  input[2] = input[3];
}

void keyPRESSING(char key)
{
  //Serial.print("keyPressed: ");  
  //Serial.println(key);  
}

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

  //Digital pins parameter order matters!!
  keypad.setRowPins(11, 6, 7, 9);  //These pins are used as OUTPUT pins.
  keypad.setColPins(10, 12, 8);    //These pins are used as INPUT pins.  
  keypad.setFunction(GenKeypad::EVENT_KEY_UP,       keyUP);
  keypad.setFunction(GenKeypad::EVENT_KEY_DOWN,     keyDOWN);
  keypad.setFunction(GenKeypad::EVENT_KEY_PRESSING, keyPRESSING);

  pinMode(SPEAKER_PIN, OUTPUT);

  pinMode(SHIFT_DATA, OUTPUT);
  pinMode(SHIFT_CLOCK, OUTPUT);

  pinMode(NumPins[0], OUTPUT);
  pinMode(NumPins[1], OUTPUT);
  pinMode(NumPins[2], OUTPUT);
  pinMode(NumPins[3], OUTPUT);

  digitalWrite(NumPins[0], HIGH);
  digitalWrite(NumPins[1], HIGH);
  digitalWrite(NumPins[2], HIGH);
  digitalWrite(NumPins[3], HIGH);

  // writing default values (from the datasheet)

  MsTimer2::set(1000, secPulse);
  MsTimer2::start();
}

int digitSS = 0;
int digitMM = 0;
int digit = 0;

  byte font[10] = {
	//abcdefg.
    0b11111100,
    0b01100000,
    0b11011010,
    0b11110010,
    0b01100110,
    0b10110110,
    0b10111110,
    0b11100100,
    0b11111110,
    0b11100110
  };

byte c2font(char c)
{
  const byte blank = 0b00000000;

  if (c == 0)
    return blank;
  else
    return font[c-'0'];
}

void setChars(char input[4], int delaymsec)
{
  digitalWrite(NumPins[0], LOW);
  shiftOut(SHIFT_DATA, SHIFT_CLOCK, LSBFIRST, c2font(input[3]));
  delay(delaymsec);
  digitalWrite(NumPins[0], HIGH);

  digitalWrite(NumPins[1], LOW);
  shiftOut(SHIFT_DATA, SHIFT_CLOCK, LSBFIRST, c2font(input[2]));
  delay(delaymsec);
  digitalWrite(NumPins[1], HIGH);

  digitalWrite(NumPins[2], LOW);
  shiftOut(SHIFT_DATA, SHIFT_CLOCK, LSBFIRST, c2font(input[1]));
  delay(delaymsec);
  digitalWrite(NumPins[2], HIGH);

  digitalWrite(NumPins[3], LOW);
  shiftOut(SHIFT_DATA, SHIFT_CLOCK, LSBFIRST, c2font(input[0]));
  delay(delaymsec);
  digitalWrite(NumPins[3], HIGH);

  delay(delaymsec);
}

void beep()
{
  if (start)
  {
    digitalWrite(SPEAKER_PIN, HIGH);
    beeping = 1;
    start = 0;
  }
  else
    digitalWrite(SPEAKER_PIN, LOW);
}

void secPulse()
{
  if (start)
  {
    SS--;
    if (SS == 0 && MM == 0)
    {
      beep();
      start = 0;
      return;
    }

    if (SS == -1 && MM > 0)
    {
      MM--;
      SS = 59;
    }

  }
}
void playTone(int tone, int duration) {
  for (long i = 0; i < duration * 1000L; i += tone * 2)
  {
    digitalWrite(SPEAKER_PIN, HIGH);
    delayMicroseconds(tone);
    digitalWrite(SPEAKER_PIN, LOW);
    delayMicroseconds(tone);
  }
}

void playNote(char note, int duration) {
  char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C', 'F', 'G'};
  int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 473, 478};

  // play the tone corresponding to the note name
  for (int i = 0; i < 10; i++) {
    if (names[i] == note)
    {
      playTone(tones[i], duration);
    }
  }
}

char * clearLeadingZero(char input[4])
{
  if (input[0] == '0')
  {
    input[0] = 0;
    if (input[1] == '0')
    {
      input[1] = 0;
      if (input[2] == '0')
        input[2] = 0;
    }
  }

  return input;
}

void processLCD()
{
  static char chs[4] = {'0', '0', '0', '0'};

  if (start)
  {
    chs[3] = SS%10 + '0';
    chs[2] = SS/10 + '0';
    chs[1] = MM%10 + '0';
    chs[0] = MM/10 + '0';

    setChars(clearLeadingZero(chs), 2);
  }
  else
  {
    setChars(input, 2);
  }
}

void loop()
{
  int someKeyDown = keypad.scanKeys(0);
  keypad.handlePostEvents(someKeyDown);      

  processLCD();

  if (beeping = 1)
  {
     beeping++;
     beeping %=3;

     for (int i = 0; i < length; i++)
     {
       someKeyDown = keypad.scanKeys(0);
       keypad.handlePostEvents(someKeyDown);      

       processLCD();
       if (beeping != 0)
         playNote(notes[i], beats[i] * tempo/2);

       // pause between notes
       delay(tempo / 2);
     }
  }
}

NTSC on Arduino

I switched to NTSC signal. I think it’s much simpler and easier, but it’s monochrome.
I’ve managed to get around 40 pixels width and working to increase vertical resolution.
It’s a very good idea to use constant length of interrupt to send NTSC signal apart from your pixel manipulation.

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1188261175/0

I am trying to build VGA (analog RGB) signal output on Arduino.
I found out that H/V Sync can be done by the built-in timer interrupt.

1. Arduino Pin-out assignment.

02: Red
03: Green
04: Blue
(05: SyncFlag)
06: VSync
07: HSync
10-13: SPI for EEPROM

(On going memo)

* Memory?
Frame buffer: 640 x 480 pixels x 3 bytes per pixel = 900KB
External EEPROM 2MB AT45DB161D may be needed.

* Find out the maximum transmission rate.

* Double buffering with two Atmega chips and one 2MB AT45DB161D? possible?

* Any suggestions?

References:
http://avga.prometheus4.com/index.php?p=2-0 (AVR but not written for Arduino)
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1228264461/all (Implementation issues discussed here.)
H/V Sync code using ISR timer: http://olb7.free.fr/arduino/syncInterrupt.pde
EEPROM:
http://blog.blockos.org/?p=27
http://todotani.cocolog-nifty.com/blog/2009/07/arduino-4cf4.html

Breadboard Arduino

You can build DIY arduino in your breadboard. The best site I found is: http://itp.nyu.edu/physcomp/Tutorials/ArduinoBreadboard

I have not managed the USB part yet, but I am sure you can add the Arduino Serial USB Board

So far, the LED blinking works good on my breadboard.
Eventually I am planning to do some VGA signal experiment on the breadboard.

Digit Counter with 7-segment LED + Arduino

It just counts 0 to 9 with 7-segment LED. Only digit 1 side has been used since the digit 2 is burned out…
Adjust output pins for your environment. For simplicity, you need 7 pins for output in this example.
I am sure I can reduce the number of pins with demux. That’s gonna be the next project.

Parts: Arduino Duemilanove, Breadboard, a register and LTD-5523AB (Datasheet)

The LED-facing-upright LTD-5523AB pin-order is:

18, 17, 16, 15, 14, 13, 12, 11, 10pin 
[------------LTD-5523AB------------]
     | - A - |       | - A - |
     F       B       F       B
     | - G - |       | - G - |
     E       C       E       C
     | - D - |       | - D - |
[------------LTD-5523AB------------]
01, 02, 03, 04, 05, 06, 07, 08, 09pin

[7-segment LED for digit 1]
A = 16pin, B = 15pin, C = 03pin, D = 02pin, E = 01pin, F = 18pin, DP = 04pin
14pin is common cathode for digit 1 (it means it should be GNDed all the time.)

For example, to make the digit 3, just turn on A, B, C, D and G.

[7segment.pde]
//Output Pins
//* Adjust this for your pin outputs.
int ledPin[8] = {4, 5, 6, 7, 9, 10, 11, 12};  

//Segment to Pin
//* Adjust this for your 7 segment LED spec.
//                 A,  B, C, D, E,  F,  G, DP
int Seg2Pin[8] = {11, 10, 5, 6, 7, 9, 12, 4};

//Digit to Segment
// * You don't need modify this unless you want to change digits.
int Dec2Seg[11] =
{
//A(125), B(64), C(32), D(16), E(8), F(4), G(2), DP(1)
  0x07E, //Digit 0
  0x00C, //Digit 1
  0x0B6, //Digit 2
  0x09E, //Digit 3
  0x0CC, //Digit 4
  0x0DA, //Digit 5
  0x0FB, //Digit 6
  0x00E, //Digit 7
  0x0FF, //Digit 8
  0x0DF, //Digit 9
  0x100 //DP
};

void setup()                    // run once, when the sketch starts
{
  for (int i = 0; i < 8; i++)
    pinMode(ledPin[i], OUTPUT);      // sets the digital pin as output
}

void clearAllSegments()
{
  //Turn off all segments
  for (int i = 0; i  0)
  {
    seg /= 2;
    if (seg & 0x1)
      digitalWrite(Seg2Pin[pin], HIGH);   // sets the LED on
    pin++;
  }
}

void loop()                     // run over and over again
{
  //Count 0 to 9
  for( int digit = 0; digit <= 10; digit++)
  {
    drawDigit(digit);
    delay(1000);                  // waits for a second
    clearAllSegments();
  }
}

Update 1: I change the 13pin to 9pin for output since 13pin has some builtin register.
Update 2: I implemented a bit mask to select segments.n