Pages: [1]   Go Down
Author Topic: Fairy Tale Phone  (Read 1562 times)
0 Members and 1 Guest are viewing this topic.
Switzerland
Offline Offline
Newbie
*
Karma: 5
Posts: 34
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello Arduino Community

Here's my recent project as a X-Mas gift for my daughters. Using an old telephone with dial wheel and build in a Pro Mini with SD Card to play fairy tales over the ear phone.
I am not yet finished since I am waiting for the SD break out. Until now I soldered some pins on a MicroSD Adapter and a L78L33 regulator to get the stuff working properly

Here's some impressions:




Fist try to catch the impulse signal from the dial wheel and count them. Also playing with tone().


Prototype with all components


And here's the code with the TMRpcm library
Code:
/*
=============================================================================================
Fairy Tale Phone 1.0
by ReDiculum (Oct. - Dez. 2013)
-------------------------------
X-Mas 2013 Arduino project.
Using an old Zellweger Modell 70 (anno 1982) telephone with dial wheel.
The wheel can be spinned to count impulses and then playing one of ten different
audio fairies stored as 8bit 16.000khz mono WAV files named from 1.wav to 10.wav

SD Card > Arduino pinout:

CS (1)   -> Pin 4 (Chip select)
MOSI (2) -> Pin 11
MISO (7) -> Pin 12
SCK  (5) -> Pin 13

Ear phone  -> Pin 9 (protect with Diode against Pin 3) and GND
Dial wheel -> Pin 2 and GND
 
=============================================================================================

TMRh20's pcm library for Arduino
https://github.com/TMRh20/TMRpcm
*/
#include <SD.h>
#include <TMRpcm.h>
#include <SPI.h>

#define IMPULSE_PIN 2 // Digital Pin 2
#define PHONE_PIN 3 // Digital Pin 3 (PWM)
#define SD_CHIPSELECT_PIN 4  // SD
#define LED_PIN 13 // Digital Pin 13
#define TIME_WAIT 2000 // Waiting 2sec during dial wheel turns. Sufficient to catch 10 impulses
int countImpulse = 0;
unsigned long timeWait = 0;

TMRpcm music;  // Create object "music" from class "TMRpcm"

/* Sum of running millis and TIME_WAIT.
Must be long integer if kids are not dialing quickly :)
*/
unsigned long timeWaitEnd = 0;

void setup() {
  Serial.begin(57600); // Set console to 57600 baud
  Serial.println("=== FairyTalePhone based on TMRpcm ===");  

  pinMode(LED_PIN, OUTPUT); // onboard LED
  
  music.speakerPin = 9; // Set Pin for SD card audio output

  /* Turn on internal pullup resistor, because we pull the pin to ground.
  When the wheel gives impulse, the contact is opened (no current). That's
  when we have a digitalRead = 1.
  */
  digitalWrite(IMPULSE_PIN, HIGH);

  Serial.println("Ready to dial ...");

  // Play tone and wait here until the dial wheel has sent his first impulse
  tone(PHONE_PIN,420);
  while (digitalRead(IMPULSE_PIN) == 0) {
    delay(1);
  }
  noTone(PHONE_PIN); // Pssht! Here we go!

  Serial.print("Counting impulses ");
  timeWaitEnd = millis() + TIME_WAIT; // Summarize already passed millis since Arduino runs and TIME_WAIT.

  // Count all the dialed impulses until timeWaitEnd has reached
  while (millis() < timeWaitEnd ) {      
    if (digitalRead(IMPULSE_PIN) == 1) {
      /* Increment the amount of impulses if the contacts are opened.
      The wheel pulses with an interval of approx 70ms
      */
      countImpulse++;
      Serial.print(".");
      digitalWrite(LED_PIN, HIGH); // Blink LED ...
      tone(PHONE_PIN,1000); // ... and short tone (70ms) of 1khz to fill the gap
      delay(70);
      digitalWrite(LED_PIN,LOW);
      noTone(PHONE_PIN);
    }
  }

  Serial.println(" "); // New line

  /* If the dial wheel has been turned more than once by nervous kids
  and the amount of counted impulses exceeds 10, we just restart Arduino
  */
  if (countImpulse > 10) {
    Serial.print("Count exceeded 10 ("); Serial.print(countImpulse); Serial.println("), restarting");
    hangOff();
    asm volatile ("  jmp 0"); // Soft Reset
  } else {    
    Serial.print("Preparing fairy tale number "); Serial.println(countImpulse);
    
    // Initialize SD Card with library SimpleSDAudio
    if (!SD.begin(SD_CHIPSELECT_PIN)) {
      tone(PHONE_PIN,100); delay(250); noTone(PHONE_PIN); delay(400);
      tone(PHONE_PIN,80); delay(600); noTone(PHONE_PIN);
      Serial.println("Error initializing SD Card");
      while(1);
    }

    /* define a char array with an index size of 6 and convert
    integer "countImpulse" to char "track" using utoa() function
    http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html
    */
    char track[6];
    utoa(countImpulse,track,10);
    // Append the suffix .wav to the char array
    strcat(track, ".wav");
    
    // Play the audio file
    music.play(track);
    Serial.print("Playing..."); Serial.println(track);
    while (music.isPlaying() == 1) {
      true; // play WAV file number and wait until it's finished
    }
    hangOff(); // That's it, we jump into loop() function    
  }
}

void loop() {
  ;// Nothing to do
  //asm volatile ("  jmp 0"); // Soft Reset
}

void hangOff(){
  // Hang off tone 5x
  delay(1000);
  tone(PHONE_PIN,450); delay(250);
  noTone(PHONE_PIN); delay(250);
  tone(PHONE_PIN,450); delay(250);
  noTone(PHONE_PIN); delay(250);
  tone(PHONE_PIN,450); delay(250);
  noTone(PHONE_PIN); delay(250);
  tone(PHONE_PIN,450); delay(250);
  noTone(PHONE_PIN); delay(250);
  tone(PHONE_PIN,450); delay(250);
  noTone(PHONE_PIN); delay(250);
}
« Last Edit: December 13, 2013, 02:21:00 am by rediculum » Logged

Regards
ReDiculum

Project:
LASERino

NSW Australia
Offline Offline
Faraday Member
**
Karma: 84
Posts: 3449
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You say "fairy tales"; unless they are very short, are you including a function to remember the present position (and rewind a couple of seconds) when it goes on-hook?
Logged

Switzerland
Offline Offline
Newbie
*
Karma: 5
Posts: 34
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You say "fairy tales"; unless they are very short, are you including a function to remember the present position (and rewind a couple of seconds) when it goes on-hook?
I will upload max 5min swiss fairy tales which I ripped form old compact cassettes (tapes).
By hooking on, the power will interrupt the Pro Mini. Hooking off will power on the board. No store of current playing position.
Logged

Regards
ReDiculum

Project:
LASERino

Valencia, Spain
Offline Offline
Faraday Member
**
Karma: 145
Posts: 5460
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is a cool project...
Logged

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Switzerland
Offline Offline
Newbie
*
Karma: 5
Posts: 34
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Finally I also used the SimpleSDAudio library and finished the project. Here's the final code and some pictures
Code:
/*
=============================================================================================
Fairy Tale Phone 1.0
by ReDiculum (Oct. - Dez. 2013)
-------------------------------
X-Mas 2013 Arduino project.
Using an old Zellweger Modell 70 (anno 1982) telephone with dial wheel.
The wheel can be spinned to count impulses and then playing one of ten different
audio fairies stored as 8bit full-rate (62500) mono PCM files named from 1.PCM to 10.PCM

SD Card > Arduino pinout:

CS (1)   -> Pin 10 (Chip select)
MOSI (2) -> Pin 11
MISO (7) -> Pin 12
SCK  (5) -> Pin 13

Ear phone  -> Pin 9 (protect with Diode against Pin 3) and GND
Dial wheel -> Pin 2 and GND
 
=============================================================================================

SimpleSDAudio library for audio playback from SD card
http://www.hackerspace-ffm.de/wiki/index.php?title=SimpleSDAudio
*/
#include <SimpleSDAudio.h>

#define IMPULSE_PIN 2 // Digital Pin 2. Read impulses
#define PHONE_PIN 3 // Digital Pin 3 (PWM) for phone tone output (protect with Diode against Pin 9)
#define SD_CHIPSELECT_PIN 10  // Digital Pin 10. SD Card chip select.
#define LED_PIN 13 // Digital Pin 13
#define TIME_WAIT 2000 // Waiting 2sec during dial wheel turns. Sufficient to catch 10 impulses
int countImpulse = 0; // The magic number to "dial" the music track number.

/* Sum of running millis and TIME_WAIT.
Must be long integer if kids are not dialing quickly :)
*/
unsigned long timeWaitEnd = 0;

void setup() {
  Serial.begin(57600); // Set console to 57600 baud
  Serial.println("=== FairyTalePhone based on SSDA ===");  

  pinMode(LED_PIN, OUTPUT); // onboard LED

  /* Turn on internal pullup resistor, because we pull the pin to ground.
  When the wheel gives impulse, the contact is opened (no current). That's
  when we have a digitalRead = 1.
  */
  digitalWrite(IMPULSE_PIN, HIGH);

  Serial.println("Ready to dial ...");

  // Play tone and wait here until the dial wheel has sent his first impulse
  tone(PHONE_PIN,420);
  while (digitalRead(IMPULSE_PIN) == 0) {
    delay(1);
  }
  noTone(PHONE_PIN); // Pssht! Here we go!

  Serial.print("Counting impulses ");
  timeWaitEnd = millis() + TIME_WAIT; // Summarize already passed millis since Arduino runs and TIME_WAIT.

  // Count all the dialed impulses until timeWaitEnd has reached
  while (millis() < timeWaitEnd ) {      
    if (digitalRead(IMPULSE_PIN) == 1) {
      /* Increment the amount of impulses if the contacts are opened.
      The wheel pulses with an interval of approx 70ms
      */
      countImpulse++;
      Serial.print(".");
      digitalWrite(LED_PIN, HIGH); // Blink LED ...
      tone(PHONE_PIN,1000); // ... and short tone (70ms) of 1khz to fill the gap
      delay(70);
      digitalWrite(LED_PIN,LOW);
      noTone(PHONE_PIN);
    }
  }

  Serial.println(" "); // New line

  /* If the dial wheel has been turned more than once by nervous kids
  and the amount of counted impulses exceeds 10, we just restart Arduino
  */
  if (countImpulse > 10) {
    Serial.print("Count exceeded 10 ("); Serial.print(countImpulse); Serial.println("), restarting");
    hangOff();
    asm volatile ("  jmp 0"); // Soft Reset
  } else {
    Serial.print("Preparing fairy tale number "); Serial.println(countImpulse);
    

    // Set Chip Select Pin
    SdPlay.setSDCSPin(SD_CHIPSELECT_PIN);
    // Initialize SD Card with library SimpleSDAudio
    if (!SdPlay.init(SSDA_MODE_FULLRATE | SSDA_MODE_MONO | SSDA_MODE_AUTOWORKER)) {
      tone(PHONE_PIN,100); delay(250); noTone(PHONE_PIN); delay(400);
      tone(PHONE_PIN,80); delay(600); noTone(PHONE_PIN);
      Serial.println("Error initializing SD Card");
      while(1);
    }

    /* define a char array with an index size of 6 and convert
    integer "countImpulse" to char "track" using utoa() function
    http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html
    */
    char track[6];
    utoa(countImpulse,track,10);
    // Append the suffix .PCM to the char array
    strcat(track, ".PCM");
    
    // Set the audio file if it exists and play it
    if (SdPlay.setFile(track)) {
      Serial.print("Playing..."); Serial.println(track);
      SdPlay.play();
      while(!SdPlay.isStopped()) {
        ;
      }
      SdPlay.deInit();
      hangOff();
      // That's it, we jump into loop() function
    } else {
      SdPlay.deInit();
      Serial.print("File "); Serial.print(track); Serial.println(" not found");
      tone(PHONE_PIN,80); delay(250); noTone(PHONE_PIN); delay(400);
      tone(PHONE_PIN,120); delay(600); noTone(PHONE_PIN);
    }
  }
}

void loop(void) {
    ; // Nothing to do here
    //asm volatile ("  jmp 0"); // or Soft Reset?
}

void hangOff(){
  // Hang off tone 5x
  delay(1000);
  tone(PHONE_PIN,450); delay(250);
  noTone(PHONE_PIN); delay(250);
  tone(PHONE_PIN,450); delay(250);
  noTone(PHONE_PIN); delay(250);
  tone(PHONE_PIN,450); delay(250);
  noTone(PHONE_PIN); delay(250);
  tone(PHONE_PIN,450); delay(250);
  noTone(PHONE_PIN); delay(250);
  tone(PHONE_PIN,450); delay(250);
  noTone(PHONE_PIN); delay(250);
}

Fritzing Layout






« Last Edit: January 06, 2014, 05:35:08 am by rediculum » Logged

Regards
ReDiculum

Project:
LASERino

Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for sharing, this is an absolutely awesome project.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 216
Posts: 13664
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Superb!
deep bow
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pages: [1]   Go Up
Jump to: