====== Voice Shield Slim Review ====== === im Aufbau ... === Geliefert wurde ein Bausatz mit einer Platine (PCB) und vielen Bauteilen. Auf der Verpackung aufgedruckt ist die Materialliste und es waren alle Bauteile da. Hier ein Bild: {{:reviews:bauteile_s.png?200|}} Oben links sieht man die Tantalkondensatoren (8), daneben eine LED, fünf Elkos und die Header. Darunter die Platine, die Audiostecker und der Poti. Daneben der Soundchip und der kleine Verstärkerchip. Zuletzt noch die Dioden und Widerstände. Beim Löten muss man nicht Besonderes beachten, und wenn man der sehr schönen [[http://www.spikenzielabs.com/SpikenzieLabs/VoiceShield_Build.html|Anleitung]] folgt, kann eigentlich nichts schief gehen. {{:reviews:voiceshieldfertig.png?200|}} Auf zur Software: Die findet man bei [[http://www.spikenzielabs.com/SpikenzieLabs/VoiceShield_Software.html|SpikenzieLabs]], wobei man bis ans Ende scrollen muss. Geladen habe ich die Library, die Sound Dateien und den programmer sowie die Lite Version, alles für Windows. Die Anleitung empfiehlt, die Library unter Arduino\Hardware\Libraries zu installieren. Ich nehme lieber das Standardverzeichnis unter c:\Users\//userid//\Documente\Arduino\libraries. Danach soll man das Sketch VSLoader laden, was problemlos klappt. Jetzt soll man den Programmer installiern, was auch kein Problem ist. Die Sounddateien werden in den entsprechenden Ordner kopiert. Dabei sollte man die Schritte der [[http://www.spikenzielabs.com/SpikenzieLabs/VoiceShield_Software.html|Anleitung]] beachten. Nach dem Start des Programms konnte ich mich ohne Probleme mit dem Arduino, der das Shield trägt, verbinden. Dann habe ich die Sounddateien hoch geladen. Dazu braucht es ein Audiokabel mit 3.75 Klinkesteckern, das ich zum Glück hatte. Das Laden hat geklappt und mit einem angeschlossenen Lautsprecher kann man die einzelnen Sounds abspielen. === Zwischenfazit === Das VoiceShield ist einfach zu löten und genauso einfach in Betrieb zu nehmendes Shield. Es macht Spaß, es zu löten und die Worte aus dem Lautsprecher zu hören als Bestätigung, dass man alles richtig gemacht hat. Jetzt geht es an die Programmierung (also die Beispiele der Library). === Beispiel BasicPhraseTalk === Ich habe den Sketch geladen, übersetzt und in den Arduino geladen. Der Code ist klar verständlich und vor allem richtig. Ich habe "upload" geklickt und das Shield fing an zu sprechen! Alles in Allem ein sehr einfaches und tolles Shield! === Sprechende Uhr === Ich habe den Code der TextClock meines Vaters geladen, der eine Wortuhr auf einem TFT Display darstellt und als neuen Sketch abgespeichert. Dann habe ich alle Verweise entfernt, was mit dem LCD zu tun hat, da ich ja eine sprechende Uhr haben will und nicht eine zeichnende. Außerdem braucht das TFT Display alle Pins des Arduinos und daher kann ich das VoiceShield nicht zusammen mit einem TFT betreiben. Bei der Gelegenheit frage ich mich, welche Pins das Shield eigentlich belegt. Laut [[http://shieldlist.org/spikenzie/voiceshieldslim|Arduino Shield List: VoiceShield Slim]] belegt das Shield die Pins D2, D3, D4 und D5. Dann habe ich die Wörter mit den Soundbytes der VoiceShield Software verbunden, genau so, wie im Beispielprogramm angegeben. Dabei hat mir mein Vater geholfen. Die TextClock wechselt alle 5 Minuten die Anzeige. Diesen Moment habe ich dazu verwendet, um die Uhrzeit als Sound auszugeben. Zum Testen, haben wir aber die Minuten an die Sekunden gekoppelt, so dass alle 5 Sekunden die Uhrzeit als Sprache ausgegeben wurde. Leider habe wir für die Worte "half", "quarter", "past" und "minute" keine passenden Sounds gefunden. Also muss als nächstes ausprobiert werden, wie man Soundfile aufnimmt. Dabei werde ich auch gleich eine deutsche Version aufnehmen. === Soundfiles aufnehmen: Balabolka === Ich habe mit meinem Vater lange im Internet gesucht und wir sind auf ein nettes Programm gestoßen: [[http://www.cross-plus-a.com/de/balabolka.htm|Balabolka]]. Das ist russisch und bedeutet "Schwätzer" ;-) Man gibt den Text, den man vorgelesen haben will im Fenster ein und setzt den Cursor an den Anfang. Dann kann man sich den Text anhören. Dabei fällt auf, dass der Text mit einem schrecklichen amerikanischen Akzent vorgelesen wird. Das liegt daran, dass unser Windowssystem nur diese Stimme ausliefert. Man kann aber eine deutsche Stimme nachinstallieren. Die entsprechenden Links sind auf der Homepage von [[http://www.cross-plus-a.com/de/balabolka.htm|Balabolka]] zu finden. Mit diesem Programm haben wir die einzelnen Soundbytes zusammen gestellt. Da die VoiceShield Software mp3 versteht muss man die Audiodateien als solche abspeichern oder umwandeln. Balabolka bietet mp3 direkt an. Nun müssen die Soundbytes der VoiceShield Software durch die neuen Files ersetzt werden. Lange haben mein Vater und ich versucht, das Programm mit den neuen Dateien zu starten und erst nach einiger zeit haben wir heraus gefunden, dass das Programm immer die Datei Monkey2.aiff sucht und ohne diese Datei im Soundbyte Verzeichnis nicht starten will. Das zugehörige Definitionsfile soundscore.txt sieht dann so aus: 0 esist.mp3 1 fuenfnach.mp3 2 zehnnach.mp3 3 viertelnach.mp3 4 zwanzignach.mp3 5 fuenfundzwanzignach.mp3 6 halb.mp3 7 fuenfnachhalb.mp3 8 zwanzigvor.mp3 9 viertelvor.mp3 10 zehnvor.mp3 11 fuenfvor.mp3 12 einuhr.mp3 13 zweiuhr.mp3 14 dreiuhr.mp3 15 vieruhr.mp3 16 fuenfuhr.mp3 17 sechsuhr.mp3 18 siebenuhr.mp3 19 achtuhr.mp3 20 neunuhr.mp3 21 zehnuhr.mp3 22 elfuhr.mp3 23 zwoelfuhr.mp3 24 willkommen.mp3 Im arduino code kann man das entsprechende Soundbyte durch den Aufruf: vs.ISDPLAY_to_EOM(24); abspielen. Die 24 spielt also den Willkommensgruß ab. Die Soundfiles werden von der Software in den Soundchip dadurch geladen, dass der Kopfhörerausgang des PCs mit Audio-In des VoiceShields verbunden wird. Das Programm spielt dann die entsprechenden Dateien ab und nimmt sie in den Soundchip auf. Dabei haben wir entdeckt, dass Dateien größer als 43 kB nicht richtig geladen werden und dann später auch nicht richtig abgespielt werden. Zu lange Dateien erkennt man daran, dass das Programm flackert. Außerdem habe ich die Lautstärke auf 25% herunter geregelt, da sonst die Sounds übersteuert sind. Hier noch der Code für das SpeakClock: /* SpeakClock.ino - Clock using an Arduino and the Spikenzielabs VoiceShield http://www.spikenzielabs.com/Catalog/index.php?main_page=product_info&cPath=27&products_id=211 Copyright (C)2013 Dr. Mathias Wilhelm. All right reserved If you make any modifications or improvements to the code, I would appreciate that you share the code with me so that I might include it in the next release. I can be contacted through http://www.mathias-wilhelm.de/arduino This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. */ #include VoiceShield vs(80); #include #define StartTag 83 // S-Zeichen #define EndTag 69 // E-Zeichen DS1307 rtc(4, 5); // define your RTC here boolean c_debug = true; boolean c_demo = true; //boolean c_rtc=true; // use rtc clock boolean c_rtc = false; // do not use rtc clock long t_ms; Time t; int lastsec=0; int lastmin=0; boolean sec_highlight=false; boolean min_highlight=false; boolean initialized=false; int bufferCount; // Anzahl der eingelesenen Zeichen char buffer[20]; // Serial Input-Buffer /******************************************************** * standard setup routine ********************************************************/ void setup() { t.hour = 0; t.min = 0; t.sec = 0; t.date = 0; t.mon = 0; t.year = 0; t.dow = 0; // Set the clock to run-mode rtc.halt(false); // wait for time set to initialize Serial.begin(9600); Serial.println("Enter time ticket to set time"); Serial.println("Format: ShhmmssddmmyyyyE"); Serial.println("SDEMOE to toggle demo mode"); Serial.println("SRTCE to toggle RTC mode"); Serial.println("SDEBUGE to toggle debug mode"); t_ms = millis(); delay(1000); if (c_debug) Serial.println("SpeakClock started"); vs.ISDPLAY_to_EOM(24); } /******************************************************** * standard loop routine ********************************************************/ void loop() { int speak; c_update(); if (t.sec != lastsec){ lastsec = t.sec; speak = t.min %5; if (speak==0) c_setMatrix(); if (c_debug){ if(t.hour<10) Serial.print('0'); Serial.print(t.hour); Serial.print(":"); if(t.min<10) Serial.print('0'); Serial.print(t.min); Serial.print(":"); if(t.sec<10) Serial.print('0'); Serial.print(t.sec); Serial.println(" "); } } if (t.min != lastmin){ lastmin = t.min; } } /******************************************************** * serial event routine ********************************************************/ void serialEvent(){ char ch = Serial.read(); buffer[bufferCount] = ch; bufferCount++; if(ch == 13) evalSerialData(); } /******************************************************** * parse serial input ********************************************************/ void evalSerialData(){ boolean sok = false; // toggle debug mode if((buffer[0] == StartTag) && (buffer[6] == EndTag)) { if ((buffer[1] == 'D') && (buffer[2] == 'E') && (buffer[3] == 'B') && (buffer[4] == 'U') && (buffer[5] == 'G')) { sok = true; c_debug = !c_debug; if (c_debug) { Serial.println("Switched to DEBUG mode"); } else { Serial.println("Switched back to normal mode"); } } } // toggle RTC mode if((buffer[0] == StartTag) && (buffer[4] == EndTag)) { if ((buffer[1] == 'R') && (buffer[2] == 'T') && (buffer[3] == 'C')) { sok = true; c_rtc = !c_rtc; if (c_rtc) { Serial.println("Using RTC clock"); t = rtc.getTime(); } else { Serial.println("Using Arduino clock"); } } } // toggle demo mode if((buffer[0] == StartTag) && (buffer[5] == EndTag)) { if ((buffer[1] == 'D') && (buffer[2] == 'E') && (buffer[3] == 'M') && (buffer[4] == 'O')) { sok = true; c_demo = !c_demo; if (c_demo) { if (c_rtc) c_rtc=false; Serial.println("Minutes linked to seconds for Demo"); Serial.println("RTC reading switched off for Demo"); } else { Serial.println("Switched to normal time mode"); Serial.println("Remember to switch clock back to RTC"); } } } // serial time ticket: ShhmmssddmmyyyyE // 0123456789012345 // 111111 // i.e. S15364318092012E if((buffer[0] == StartTag) && (buffer[15] == EndTag)) { sok = true; t.hour = (buffer[ 1] - 48) * 10 + (buffer[2] - 48); t.min = (buffer[ 3] - 48) * 10 + (buffer[4] - 48); t.sec = (buffer[ 5] - 48) * 10 + (buffer[6] - 48); t.date = (buffer[ 7] - 48) * 10 + (buffer[8] - 48); t.mon = (buffer[ 9] - 48) * 10 + (buffer[10] - 48); t.year = (buffer[11] - 48) * 1000 + (buffer[12] - 48) * 100 + (buffer[13] - 48) * 10 + (buffer[14] - 48); t.hour = constrain(t.hour,0,23); t.min = constrain(t.min ,0,59); t.sec = constrain(t.sec ,0,59); t.date = constrain(t.date,0,31); t.mon = constrain(t.mon ,0,12); t.year = constrain(t.year,0,9999); Serial.print("Time set to : "); if(t.hour<10) Serial.print('0'); Serial.print(t.hour); Serial.print(":"); if(t.min<10) Serial.print('0'); Serial.print(t.min); Serial.print(":"); if(t.sec<10) Serial.print('0'); Serial.print(t.sec); Serial.print(" - "); if(t.date<10) Serial.print('0'); Serial.print(t.date); Serial.print("."); if(t.mon<10) Serial.print('0'); Serial.print(t.mon); Serial.print("."); Serial.print(t.year); Serial.println(" "); if (c_rtc) { rtc.setTime(t.hour,t.min,t.sec); rtc.setDate(t.date,t.mon,t.year); } } if (!sok) { Serial.print("Invalid Serial Command :"); for (int i=0; i11) c_hour=0; switch (c_hour) { case 0: case 12: vs.ISDPLAY_to_EOM(23); break; case 1: vs.ISDPLAY_to_EOM(12); break; case 2: vs.ISDPLAY_to_EOM(13); break; case 3: vs.ISDPLAY_to_EOM(14); break; case 4: vs.ISDPLAY_to_EOM(15); break; case 5: vs.ISDPLAY_to_EOM(16); break; case 6: vs.ISDPLAY_to_EOM(17); break; case 7: vs.ISDPLAY_to_EOM(18); break; case 8: vs.ISDPLAY_to_EOM(19); break; case 9: vs.ISDPLAY_to_EOM(20); break; case 10: vs.ISDPLAY_to_EOM(21); break; case 11: vs.ISDPLAY_to_EOM(22); break; } } /******************************************************** * clock update routines ********************************************************/ void c_update(){ long ctime; int elapsed; int daypermonth[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; if (!c_rtc){ ctime = millis(); elapsed= (ctime - t_ms)/1000; if (elapsed>0) { t_ms = ctime; t.sec = t.sec + elapsed; if (c_demo) t.min++; // DEBUG ONLY ADVANCE TIME FASTER if (t.sec>59){ t.sec = 0; t.min++; } if (t.min>59){ t.min = 0; t.hour++; } if (t.hour>23){ t.hour = 0; t.date++; t.dow++; } if (t.date>daypermonth[t.mon-1]){ t.mon = 1; t.year++; } if (t.dow>6) t.dow=0; } } else { t = rtc.getTime(); } }