oklima
Published © GPL3+

Morse Code Kitchen Timer

Don't buy a kitchen timer, they are all boring. Make one like this.

IntermediateShowcase (no instructions)2,862
Morse Code Kitchen Timer

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
Peizo transducer
×1
Rotary Encoder with Push-Button
Rotary Encoder with Push-Button
×2
Switch
×1
SparkFun 7-Segment Serial Display - Red
SparkFun 7-Segment Serial Display - Red
×1
Morse Code Key
×1

Hand tools and fabrication machines

dremel
Soldering iron (generic)
Soldering iron (generic)
Hot glue gun (generic)
Hot glue gun (generic)

Story

Read more

Schematics

Schematic

Here is the kitchen timer breadboard

Breadboard image

Vero board version

Code

Kitchen timer code

Arduino
Handle 2 encoders, peizo beeper, and 4x 7 segment displays
/* 
jjn timer
20161022
*/
#include <Wire.h> // Include the Arduino SPI library
bool showColon=0;

/*start encoders*/
int val; 
int encoder0PinA = 2;
int encoder0PinB = 3;
int encoder0Pos = 0;
int encoder0PinALast = LOW;
int encoder1PinA = 7;
int encoder1PinB = 8;
int encoder1Pos = 0;
int encoder1PinALast = LOW;
int n = LOW;
bool startup = true;
bool doBeeper=false;
int mins=0;
int secs=0;
/*end encoders*/

/*beep*/
int SPKR=9;
/*end beep*/

/*toggle button*/
  
// constants won't change. They're used here to
// set pin numbers:
const int buttonPin = 5;    // the number of the pushbutton pin
const int ledPin = 13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers
/*end toggle button*/


// Here we'll define the I2C address of our S7S. By default it
//  should be 0x71. This can be changed, though.
const byte s7sAddress = 0x71;

unsigned int counter = 0;  // This variable will count up to 65k
char tempString[10];  // Will be used with sprintf to create strings
int scan=1;
bool doCountdown=true;


void setup(){
  Serial.begin(9600);
  Wire.begin();  // Initialize hardware I2C pins

  /*start encoder pins*/
   pinMode (encoder0PinA,INPUT);
   pinMode (encoder0PinB,INPUT);
   pinMode (encoder1PinA,INPUT);
   pinMode (encoder1PinB,INPUT);  
  /*end encoder pins*/
  

  // Clear the display, and then turn on all segments and decimals
  clearDisplayI2C();  // Clears display, resets cursor

  // Custom function to send four bytes via I2C
  //  The I2C.write function only allows sending of a single
  //  byte at a time.
  //s7sSendStringI2C("TIMR");
  //setDecimalsI2C(0b111111);  // Turn on all decimals, colon, apos

  // Flash brightness values at the beginning
  //setBrightnessI2C(0);  // Lowest brightness
  //delay(130);
  setBrightnessI2C(255);  // High brightness
  //  setBrightnessI2C(105);  // med brightness
  //delay(150);
  //s7sSendStringI2C("TIMR");
  //delay(150);
  // Clear the display before jumping into loop
  //clearDisplayI2C();  

  /*toggle button*/
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  //pinMode (SPKR,OUTPUT);  

  // set initial LED state
  //digitalWrite(ledPin, ledState);
  /*end toggle button*/
}


void loop(){
   /*read encoders*/
   int delta=0;
   n = digitalRead(encoder0PinA);
   if ((encoder0PinALast == LOW) && (n == HIGH)) {
     if (digitalRead(encoder0PinB) == LOW) {
       encoder0Pos++;
       delta=1;
     } else {
       encoder0Pos--;
       delta=-1;
     }
     Serial.print ("B");
     Serial.print (encoder0Pos);
     Serial.print ("/");
   } 
   if(encoder0PinALast != n) {
     StopBeeperAndCountdown();
     mins+=delta;//=encoder0Pos;
   }
   encoder0PinALast = n;
   
   n = digitalRead(encoder1PinA);
   if ((encoder1PinALast == LOW) && (n == HIGH)) {
     if (digitalRead(encoder1PinB) == LOW) {
       encoder1Pos++;
       delta = 5;
     } else {
       encoder1Pos--;
       delta = -5;
     }
     Serial.print ("A");
     Serial.print (encoder1Pos);
     Serial.print ("/");
   } 
   if(encoder1PinALast != n){
     StopBeeperAndCountdown();
     secs+=delta;//encoder1Pos*5;
   }
   encoder1PinALast = n;

   if(mins>99)mins=0;  //mins
   if(mins<0)mins=99;
   if(secs>59)secs=0;  //secs 
   if(secs<0)secs=55;
     
   /*read encoders end*/
   if(startup){
     startup = false;
     encoder0Pos = 0;
     encoder1Pos = 0;
     mins = 0;
     secs = 0;
   }
  
  // Magical sprintf creates a string for us to send to the s7s.
  //  The %4d option creates a 4-digit integer.
  //sprintf(tempString, "%4d", counter);
  //sprintf(tempString, "%s%2d%s%2d",(mins<10)?"":"0", mins,(secs<10)?"":"0",secs);
  if(mins>9&&secs>9)sprintf(tempString, "%2d%2d", mins,secs);
  if(mins<=9&&secs>9)sprintf(tempString, "0%d%2d", mins,secs);
  if(mins>9&&secs<=9)sprintf(tempString, "%2d0%d", mins,secs);
  if(mins<9&&secs<=9)sprintf(tempString, "%02d0%d", mins,secs);
  
  if(scan%1000==0){  //only update every so many cycles
    // This will output the tempString to the S7S
    s7sSendStringI2C(tempString);
  }
  // Print the decimal at the proper spot
  /* 
  setDecimalsI2C(0b00000100);  // Sets digit 3 decimal on
  */
    
  //delay(50);  // This will make the display update at 10Hz.*/

  scan++;
  if(scan > 60000){scan=0;}
  
  if(doCountdown){
    if(scan % 5000==0 && !doBeeper){
      if(secs >= 0)secs--;
      if(secs < 0){
        secs = 59;
        mins--;
      }
      if(mins < 0){
        secs = 0;
        mins = 0;
        doCountdown = false;
        doBeeper = true;
      }
    }
  }
  
  if(scan % 3000 == 0){
    showColon=!showColon;
    //  [MSB] (X)(X)(Apos)(Colon)(Digit 4)(Digit 3)(Digit2)(Digit1)
    if(doCountdown && showColon){//showColon
      setDecimalsI2C(0b010000);  // Turn on colon
    }else{
      setDecimalsI2C(0b000000);  // hide colon
    }
    if(doBeeper){
      alarm();
    }
  }
  
  CheckToggleButton();
}

void CheckToggleButton(){
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      snick();
      if(doCountdown&&doBeeper)StopBeeperAndCountdown();
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        //ledState = !ledState;
        
     
        doCountdown=!doCountdown;
      }
    }
  }

  // set the LED:
  //digitalWrite(ledPin, ledState);

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
}

// This custom function works somewhat like a serial.print.
//  You can send it an array of chars (string) and it'll print
//  the first 4 characters in the array.
void s7sSendStringI2C(String toSend){
  Wire.beginTransmission(s7sAddress);
  for (int i=0; i<4; i++)
  {
    Wire.write(toSend[i]);
  }
  Wire.endTransmission();
}

// Send the clear display command (0x76)
//  This will clear the display and reset the cursor
void clearDisplayI2C(){
  Wire.beginTransmission(s7sAddress);
  Wire.write(0x76);  // Clear display command
  Wire.endTransmission();
}

// Set the displays brightness. Should receive byte with the value
//  to set the brightness to
//  dimmest------------->brightest
//     0--------127--------255
void setBrightnessI2C(byte value){
  Wire.beginTransmission(s7sAddress);
  Wire.write(0x7A);  // Set brightness command byte
  Wire.write(value);  // brightness data byte
  Wire.endTransmission();
}

// Turn on any, none, or all of the decimals.
//  The six lowest bits in the decimals parameter sets a decimal 
//  (or colon, or apostrophe) on or off. A 1 indicates on, 0 off.
//  [MSB] (X)(X)(Apos)(Colon)(Digit 4)(Digit 3)(Digit2)(Digit1)
void setDecimalsI2C(byte decimals){
  Wire.beginTransmission(s7sAddress);
  Wire.write(0x77);
  Wire.write(decimals);
  Wire.endTransmission();
}

void snick(){
  // put your setup code here, to run once:
  pinMode (SPKR,OUTPUT);
  
  for (int i=0; i<300; i++) {  // generate a 1KHz tone for 1/2 second
    digitalWrite(SPKR, HIGH);
    delayMicroseconds(100);
    digitalWrite(SPKR, LOW);
    delayMicroseconds(100);
  }
  pinMode (SPKR,INPUT);
  //delay(1000);
}

void alarm(){
  //return;
  // put your setup code here, to run once:
  pinMode (SPKR,OUTPUT);
  
  for (int i=0; i<350; i++) { 
    digitalWrite(SPKR, HIGH);
    delayMicroseconds(120);
    digitalWrite(SPKR, LOW);
    delayMicroseconds(50);
    digitalWrite(SPKR, HIGH);
    delayMicroseconds(60);
  }
  pinMode (SPKR,INPUT);
  //delay(1000);
}

void StopBeeperAndCountdown(){
  doBeeper=false;
  doCountdown=false;
  //secs=30;
  //mins=encoder1Pos*5;
  //secs=encoder0Pos*5;
}

Credits

oklima

oklima

0 projects • 1 follower

Comments