DFRobot DFPlayer mini mp3 lejátszó

Tartalom:

  • A DFPlayer mp3 lejátszó felépítése, gyártó által javasolt felhasználási példák önálló működésre
  • Hangszóró bekötési problémák, soros kapcsolat zajának problémái és megoldásuk
  • Programkönyvtár letöltése, és függvényeinek használata, file név szerinti lejátszás, könyvtár szerkezetek az SD kártyán
  • Rövid hangfile-ok lejátszásának mintapéldája a BUSY kivezetés használata nélkül
  • BUSY kivezetés Arduino-val való összekötésének előnyei, módosított, jobban működő lejátszó program
  • Számok kimondása rövid hang állományok sorrendi lejátszásával. Példaprogram!
  • Kapcsolódó leírás a tökéletesített magyarul beszélő, számokat, dátumokat és időpontokat kimondó modulról

—————————————————————————————

Egy olyan szerkezetre lenne szükségem, ami kimondja a dátumokat, mérési eredményeket stb. és ehhez egy mp3 lejátszó modult használtam. Arra számítottam, hogy ez a kis modul semmilyen meglepetést nem fog okozni, lejátssza a hang fájlokat és kész. Nem ennyire egyszerű a működése, és végül több mint két hetet vacakoltam azzal, hogy kiismerjem a működését. Előre bocsátom, hogy sima zene lejátszásra tökéletes! És persze az általam eltervezett feladatra is alkalmas kicsike kompromisszumokkal. A megismerése közben szerzett tapasztalataimat szeretném most átadni!

A modul igen picike (kb 1.5×1.5cm), elméletileg kaphatja a tápfeszt az Arduino-ról, meghajt egy 3W-os hangszórót (Ez Arduino-ról már nem biztos, hogy menni fog), és 32Gb méretig fogad be mikro SD kártyát. USB pendrive-ot is kezelne, de ez nekem nem kellett, így nem foglalkoztam ezzel a lehetőséggel. A leírások említik, hogy van egy belső 64Mb-os NOR flash is a chip-ben. Azt megtaláltam, hogyan lehetne arról elindítani a lejátszást, de azt, hogy erre a flash tárolóra hogyan lehetne hanganyagot bejuttatni, arra nem találtam semmilyen lehetőséget. Pedig céljaimhoz ez is bőven elegendő lenne. Még nem adtam fel, keresem a megoldást!

Az egyik interneten fellelt cikkben olvastam, hogy 5V-on 4ohm-os hangszóróval az elméleti teljesítmény1,25W, bár az erősítőt 3W-os erősítőnek hirdetik. A cikk írója nem részletezte, hogy ez csatornánként igaz (mert sztereó erősítő) vagy összesen. (Megnyugtatok előre mindenkit, én egy hangfalra kötöttem, és egy hangfalon monóban már „túl” hangos volt!)

A modul fotója:

A lábkiosztás:

Önállóan képes zene lejátszásra néhány nyomógomb segítségével:

Tömegével találhatók a neten zenehallgató kütyük, amiken 4 nyomógombbal lehet minden funkciót elérni, minden bizonnyal ugyanezzel az mp3 lejátszó chip-el épülnek fel, mint ami ebben a modulban is megtalálható.

 Az ADKEY bemenetek segítségével ellenállások és nyomógombok felhasználásával 20 nyomógombot lehet rákötni. Nekem erre nem volt szükségem, így a kapcsolási rajzot csak, mint érdekességet idézem be.

Azonban lássuk végre a lényeget, hogyan lehet ezt a modult Arduino-ról vezérelni?! A sorosporton keresztül (TX és RX bemenetek) lehet vele kommunikálni, és zeneszámokat elindítani. Több kapcsolási rajzot is találtam, elsőként ezt dugdostam össze a kis próbapanelemen:

Azaz mégsem, mert nem volt hangszóróm, és egy ócska fejhallgatóval kezdtem a kísérletezgetést, amit a GND és a DAC_L kimenet közé kötöttem be. Feltételeztem, hogy a DAC_L és a DAC_R kimenetek egy sztereó fejhallgatóhoz (vagyis inkább fülhallgatóhoz) lettek kitalálva, az SPK1 és SPK2 kimenetek pedig egy 3W-os monó hangkimenetet valósítanak meg. Valószínűleg mindkét dologban tévedtem. A fejhallgatóm kb. 240 ohm-os hangszórókkal működik, és ez az ellenállás a DAC_L kimenetnek valószínűleg nem volt ideális, mert nagyon kicsi volt a hangerő. Alig halottam valamit. Valószínűleg ez egy hangkimenet, amivel az erősítőhöz lehet kapcsolni a lejátszót. Ezért aztán átraktam a hangszóró kimenetre a fejhallgatót. Először a 0 és 30 közötti hangerőt 1-re állítottam, de alig szólalt meg. Végül kiderült, hogy fülre rakva a fejhallgatót kb.15-ös hangerő már kellemes és jól hallható. A 30-as hangerővel már a fejhallgató átment hangszóró üzemmódba, kényelmesen hallgathattam vele a zenét, úgy hogy letettem az asztalra.

Pár hónappal később kiderült anyukámról, hogy szürkehályog van a szemén, ezért fokozatosan megvakul. Valószínűleg a műtét segíteni fog, de akkor sem fog már jól látni, ezért egy beszélő óra építésébe kezdtem. Mivel minden építőkockám meg volt hozzá, gyorsan el is készült (az idő kimondására mp3 lejátszóval itt a megoldás). Rákapcsoltam egy igazi 8 ohm-os hangfalra a kimenetet a fenti ábra szerint, és meg sem szólalt. Sorba raktam vele egy 47ohm-os ellenállást, és recsegve kiesésekkel de felismerhetetlenül megszólalt a hang. Így elkezdtem a leírásokat bújni, hogy kiderítsem mi a baj. Gyorsan megtaláltam a problémát. ROSSZ A FENTI ÁBRA! A GND és az SPK1 illetve SPK2 közé kell bekötni egy-egy hangszórót. Tehát ez erősítő sztereó! A fejhallgatóval azért működött a két hangcsatorna összegzett jele, mert nagy volt az ellenállása, így kicsi a terhelés. Nem ismerem a beépített erősítő lelki világát, de ezzel függhet össze. Nekem csak egy hangszóróm volt, de ez jól működött, mert a hanganyagom monó, vagy jó csatornán szólalt meg (lásd később a hanganyag forrását). Tehát nem a fenti ábra szerint kell használni, hanem így:

Már a fejhallgatón is jól hallatszott az a jelenség, ami az első komoly problémát okozta.

Az első elképzelés szerint a sorosporton beállítok egy műsorszámot, ami nálam nem zene, hanem egy felolvasott szöveg, és folyamatos lekérdezésekkel igyekszem megállapítani, mikor fejezi be a lejátszást. Ez egyébként működik, később lesz mintapélda, de hatalmas probléma van vele. A lejátszás közben folyamatos zaj hallatszik. A kapcsolási rajzon (az elsőn, és a másodikon is) szerepel egy 1Kohm-os ellenállás az Arduino és a lejátszó RX bemenete között. Ha ide nem teszek ellenállást, a zaj hangosabb mint a zene. Ha 1K ellenállást teszek, akkor már a zaj halkabb, de még mindig jól hallható, kifejezetten zavaró. Egyes leírásokban 10K ellenállást láttam, kipróbáltam azt is. 10K-val már teljesen megszűnt a kommunikáció. 4,7K ellenállással még működött, de még mindig elég erős volt a zaj. Végül ez maradt, mint optimális ellenállás érték. Elkezdtem kísérletezgetni, hogy mit lehet csinálni. Ekkor még a DAC_L kimenetet használtam, és átkötöttem a fejhallgatót az SPK1 és SPK2 kimenetekre. Ha feltettem a fejhallgatót és beállítottam egy kicsi hangerőt, akkor jól halottam a zajt. Ha hangszórónak használtam a fejhallgatómat a maximális 30-as hangerőnél már nem is hallatszott a zaj. Ebből arra következtetek, hogy a zaj valahol a végerősítő fokozatban keletkezik, és konstans kimeneti zajt okoz. Ha felemelem a hangerőt, akkor a műsoranyag elnyomja a zajt. Ki is próbáltam, tettem egy soros ellenállást a fejhallgató és a SPK1 kimenet közé. Épp 1Kohm akadt a kezembe. Felvettem a hangerőt 30-ra és füleltem. Bár a zene halk volt a fejhallgatóban, de zajmentes.
Egyik cikkben azt olvastam, hogy a zaj azért keletkezik, mert az Arduino-ról táplálom a lejátszót. Meg tudom erősíteni, hogy ez nem igaz. Külön tápot csináltam a lejátszónak, és csak a GND-t kötöttem össze, és továbbra is zajos maradt. Igaz, hogy kapcsolóüzemű táppal próbálkoztam, de úgy gondoltam több időt már nem érdemel a probléma. Amúgy is hangszóróval fogom használni, és nem hifi zene lejátszás lesz a feladata.

És most újra utólag szúrok közbe egy megjegyzést. Miközben a fentebb említett hangszóró bekötési problémával foglalkoztam, megláttam egy képet az interneten:

Ugye milyen érdekes?! Ezen a hangszóró bekötés az általam hibásnak vélt, de a cikk írója szerint működik. Sőt, videókat is bejátszott a működő berendezésről, és tényleg szép hangosan szólt. Mindegy, nem a hangszóró bekötés itt a lényeg. Azt írja a cikk írója, hogy ez a lejátszó nem tolerálja a bemenetén az 5V feszültséget, ezért zajos a lejátszás. Sajnos a beszélő óra akkor már készen volt, és be is kötöttem a feszültségosztót, de az eredményt nem tudom egyértelműen megerősíteni, mert a vezérlést másként oldottam meg, így nálam már eleve nem volt zaj, de erről később! Beszúrás vége!

Jöhet végre a lejátszó vezérlése! A DFRobotDFPlayerMini programkönyvtárát használtam, amit az Arduino IDE könyvtár kezelőjében így lehet megtalálni:

Igen sok leírást elolvastam, de egyetlenegy sem írta le pontosan és érthetően, hogyan is működik a lejátszandó fájl kiválasztása. Igyekszem most ezért összeszedetten leírni a rendelkezésre álló három, azaz négy lehetőséget:

  1. Fájl kiválasztás az SD kártyára másolás sorrendje alapján. Ennél a módszernél a play(fájlszám) függvényt fogjuk használni, amiben egy int típusú paramétert kell megadni. A lejátszó az állományok nevével nem foglalkozik, pusztán azt nézi, hogy egy állomány hányadiknak lett felmásolva az SD kártyára. Az sem számít, hogy az állományokat milyen könyvtárak alá másolod be. Furcsa módszer, de mint kiderült, ez teszi lehetővé a leggyorsabb kiválasztást. Nem sokat kísérleteztem vele, de valóban bármilyen könyvtárnév alá lehet másolni a hangfájlokat, korrektül megtalálja. Egyébként végső megoldásomban az SD kártya gyökerébe másoltam a hangfájlokat egyenként, és így tényleg jól működött. 62 állományt másoltam fel, mindegyiket ki tudtam választani a play() függvénnyel, a nevük nem számított. Át is lehetett nevezni az SD kártyán.
  2. Fájl kiválasztás az SD kártya MP3 nevű könyvtárából. Ebben az esetben a playMP3Folder(fájlszám) függvényt kell használni. A paraméter itt is integer típusú, azonban a fájl nevét fogja meghatározni. A könyvtárba maximum 9999 db fájl másolható be, és a nevüknek kötelezően egy négyjegyű számmal kell kezdődni.pl. „0002_akármi.mp3” egy tökéletes fájl név. A fájl néveben a számok mögötti tartalom közömbös a lejátszónak.
  3. Fájl kiválasztás számozott könyvtárakból. Maximum 99db könyvtárat használhatunk „01”, „02” stb. névvel, és ezek mindegyikében 999 db állományt helyezhetünk el. Az állományok neve egy három jegyű számmal kell Kezdődjön pl. „002_akármi.mp3” szintén egy valid fájl név. A fájl kiválasztását a playFolder(mappaszám, fájlszám) függvénnyel fogjuk tudni elérni, ahol a mappaszám egy 1-99 közötti integer érték, a fájlszám eddig egy 0-999 közötti integer. A mappaszám a leírásokban 1-től indult, és elfelejtettem kipróbálni, hogy ez sajtóhiba, vagy valóban nincs „00” könyvtár név. Azt hiszem ez nem is lényeges.
  4. Fájl kiválasztás számozott könyvtárakból, könyvtáranként 9999 db állományból. Itt a playLargeFolder(mappaszám, fájlszám) függvényt használjuk. Ugyanaz, mint az előző, csak itt a könyvtárakban 9999 db állomány lehet.

És hogy mi is a különbség a három módszer között? Igen nagy a különbség a működési sebességben. Ha gyorsan akarsz egymás után állományokat lejátszani (nekem erre volt szükségem), akkor a legelső módszer a nyerő. Sajnos még ennél a módszernél is elég tekintélyes 1-2 tized másodperc telik el két állomány lejátszása között, de a többi módszer még lassúbb, érezhetően nagyobbak a szünetek. Megmérni egzaktul nem tudtam, vagyis inkább nem töltöttem vele az időt, de gyors működési igény esetén a fájlokat kézzel, sorrendben kell felmásolni az SD kártya gyökerébe, és a play() függvényt használni, amiben a fájl másolási sorszámára hivatkozunk. Nem kísérleteztem túl sokat, így nem tudom mi lenne, ha fájlokat törölnénk az SD kártyáról? Valahol olvastam, hogy akkor is lejátssza a számokat, hiszen a FAT32-ben a törlés nem a fájl tartalmat törli, csak a fájl táblában töröltre jelöli az állományt, de az attól még az ott marad. Én formázással kezdtem minden másolást. Így jól működött.

Azonban ezzel még nincs vége a különbségeknek. Meg kell ugyanis állapítani, hogy mikor van vége egy állomány lejátszásának. Ehhez a DFRobot programkönyvtárában az első lépés az available() függvény használata. Ezzel kell folyamatosan kérdezgetni. Azonban ennek működése nekem nem volt teljesen egyértelmű, mert sok esetben adja elérhetőnek a lejátszót, nem csak akkor amikor vége a lejátszásnak. PL ha kiveszik az SD kártyát a foglalatból, akkor is true értéket ad vissza. Ezért ha true, akkor még le kell kérdezni az utolsó hibakódot. A példa programban majd látható lesz, hogy korrekt hiba lekérdezések vannak, melyek a readType() és a read() függvényekkel lehet lekérdezni. Szerepel is egy „DFPlayerPlayFinished” konstans a programkönyvtárban, ha a  readType()==DFPlayerPlayFinished vizsgálat eredménye igaz, akkor épp vége egy lejátszásnak. Azt hihetnénk, hogy készen is vagyunk. Kiválasztunk egy állományt, elindítjuk a lejátszását, figyeljük mikor vége, és jöhet a következő állomány lejátszás. Nekem azonban úgy kellett működnie a programnak, hogy lejátszok egy állomány csoportot (10-nél kevesebb hangfájlt egymás után), és hosszabb, esetleg több perces szünet után újra elindítom a lejátszást. Nem órát csináltam, csak a példa kedvéért említem, hogy így kellene működnie egy olyan órának, ami óránként bemondja a pontos időt.  Azonban hosszabb szünet után nem hajlandó az első állományt lejátszani. Azonnal azt mondja, hogy vége a lejátszásnak, és visszaadja az előző fájl csoport utolsó állományának sorszámát a read() függvénnyel. A hibát nem tudtam semmilyen módon kiküszöbölni, csak azzal, hogy reset() parancsot adtam az mp3 lejátszónak a hosszabb szünetet követő első fájl lejátszása előtt. Ez azonban eltart egy ideig, ami lassítja a kimondást, ráadásul a hangszóróban szörnyű hangos pattogó, kattogó hangokat hallat. Megoldásként azt találtam mi, hogy megnézem mit jelez vissza befejezett fájl számnak, és ha ez nem egyezik azzal, amit el akartam indítani, akkor újra elindítom az érintett fájl lejátszását. Így működött is.

Aztán kitaláltam, hogy van férfi és női hangom is, milyen jó lenne, ha paraméterrel dönteném el, hogy melyik szólaljon meg. Váltottam és a felmásolás szerint működő play() függvény helyett átalakítottam a programot a playFolder() függvényre, a „01”-es mappába raktam a férfi hangokat, a „02”-be pedig a női hangokat. Persze rögtön kiderült, hogy az állományok lejátszása közötti szünet megnövekedett, a számok felolvasása zavaróan lelassult, de a program sem működött jól. Ugyanis a read() függvény nem a fájl nevének sorszámát adja vissza ebben az esetben, hanem továbbra is egy fájl sorszámot, ami vélhetőleg a felmásolás sorrendjével van összefüggésben. Így aztán nem lehetett összehasonlítani a lejátszott állomány sorszámát a lejátszás befejezését követően read()-el visszakapott sorszámmal, mert az soha nem egyezett. Vége a jó kis algoritmusomnak. Bár azért a program működik, ha csak egyetlen példány van minden állományból. Íme ennek a kissé hibás algoritmusnak a forrása:

/**************************************************************************************
 * MP3 lejátszóval számok (mértékegységgel) és dátum kimondását megvalósító program.  *
 * A program nem mondja ki a számokat, közvetlenül, de tartalmaz minden kimondáshoz   *
 * szükséges hang file definíciót (hang file-ok külön mellékelve), és tartalmaz egy   *
 * demót ami képes vezérelni a hang file részek lapján a folyamatot.                  *
 * Úgy lett megírva a file lejátszást vezérlő függvény, hogy közben más folyamtok is  *
 * futhatnak a loop()-ban. Egy suo[] nevű tömbben kell megadni a file sorszámokat,    *
 * beállítani egy index nevű változót 0-ra, valamint egy kezd nevű változót 1-re.     *
 * Ennek hatására elindul a file-ok lejátszása a tömb által meghatározott sorrendben. *
 * Amikor egy állomány le lett játszva, a függvény ezt észre veszi az MP3 lejátszó    *
 * folyamatos lekérdezésével, és elindítja a következő file lejátszását. Arra kell    *
 * vigyázni, hogy a loop()-ban ne legyen más nagyon hossz ideig futó programrész.     *
 * azaz a függvény meghívására, különben kihagyhatja egy-egy rész lejátszását.        *
 * A demó a 12,5V számot mondja ki 10 másodpercenként                                 *
 * MP3 lejátszó bekötése:                                                             *
 * Az MP+ lejátszó felűlről nézve (led felül, kártya bedugás alulról) az IC-knél      *
 * megszokott körbejárási sorszámozási iránnyal a következő kivezetésekkel            *
 * rendelkezik a bal oldalon:                                                         *
 *   1 - VCC (5V, 4,2V ajánlott) Arduino-tól kapta a tápfeszt                         *
 *   2 - RX  Arduino 11-es kivezetéshöz kötve egy 1Kohm ellenálláson kersztül         *
 *   3 - TX  Arduino 10-es kivezetéshez kötve                                         *
 *   4 - DAC_R fejhellgató kivezetés, ide kötöttem a fejhellgató egyik kivezetését    *
 *   5 - DAC_L fejhallgató kivezetés (ezt nem használtam)                             *
 *   6 - SPK_1 3W-os hangszóró kimenet (ezt nem használtam)                           *
 *   7 - GND föld pont, Arduino GND-vel összekötve valamint a fejhallgató             *
 *           másik kivezetése                                                         *
 *   8 - SPK_2 3W-os hangszóró kimenet (ezt sem használtam)                           *
 * Jobb oldalon csak a legfelsőt használtam, a busy jelvezetéket, ami 1-el jelzi      *
 * ha szabad az mp3, és éppen nem csinál semmit. Ha ez 0-ról 1-re vált, akkor         *
 * befejeződött egy lejátszás.                                                        *
 *                                                                                    *
 * A leírások az RX bemenet és az Arduino kivezetés közé egy soros ellenállást        *
 * javasolnak. Ellenállás nélkül is működik, de nagyon zajos a lejátszás, behallatszik*
 * a soros port zaja nagyon erősen, szinte elnyomja a szöveget. 1Kohm-al már sokkal   *
 * halkabb a zaj (élvezhető a hang), de még ott van a háttérben. Egyes leírásokban    *
 * 10Kohm-ot írtak, de azzal már nekem nem működött. 4,7K-val még igen, de a zaj      *
 * nem lett jelentősen kevesebb                                                       *
 * Átkötöttem az mp3 lejátszó VCC-jét egy másik tápegységre, ami szintén 5V de ez egy *
 * kapcsoló üzemű táp. A zaj nem változott, nem nőtt és nem csökkent.                 *
 * Megpróbáltam a TX vezetékre is tenni egy soros 1K ellenállást, ez ugyan nem lenne  *
 * logikus, ha csökkenne a zaj, nem is csökkent.                                      *
 * Átkötöttem a fülhallgatómat a 3W-os kimenetre egy 1K soros ellenállással, és így   *
 * már nem tapasztaltam zajt. Tökéletes volt a hang.                                  *
 * Levettem a hangerőt 1-re, és kivettem a soros ellenállást. Kicsit halkabb lett     *
 * így a hangerőt felemeltem 10-re, ez eredményezett hasonló hangerőt. A zaj újra     *
 * megjelent, bár alig hallhatóan                                                     *
 * Ezt követően levettem a fejemről a fejhallgatót és felemeltem a hangerőt 30-ra     *
 * így hangszórónak használtam a fejhallgatót. A zajt nem halottam, de a szöveg       *
 * szépen tisztán hallható lett. Az eredmény kielégítő. A fejhallgatóm kb 40ohm-os.   *
 *                                                                                    *
 * DFRobotDFPlayerMini legfontosabb függvényei:                                       *
 *  myDFPlayer.play(int fájlszám); - bármely könyvtárba másolt bármely fájlokat       *
 *                                    lejátsza de az állományok másolási sorrendjét   *
 *                                    veszi figyelembe!                               *
 *  myDFPlayer.playMp3Folder (int fájlszám) - az mp3 könyvtárban lévő fájlokat játssza*
 *                                    le, és a file első négy karaktere nullákkal     *
 *                                    feltöltött szám kell legyen (max. 10000db)      *
 *                                    pl:0012 a fájl név bármivel folytatódhat        *
 *  myDFPlayer.playFolder (int mappaszám, int fájlszám); - numerikus nevű mappában    *                                      
 *                                    lévő fájlokat játszik le. a mappa neve "01",    *
 *                                    "02" stb., a file első három karaktere nullákkal*
 *                                    feltöltött szám kell legyen (max. 1000db)       *
 *                                    pl:015 a fle név bármivel folytatódhat          *
 *  myDFPlayer.playLargeFolder (int mappaszám, int fájlszám); - ugyanz mint előző     *
 *                                    vak a mappában 9999db file lehet.               *
 **************************************************************************************/

#include "Arduino.h"
#include "SoftwareSerial.h"       //használunk egy szoftveres soros portot, hogy megmaradjon a valódi soros port a fejlesztéshez, hibakereséshez
#include "DFRobotDFPlayerMini.h"  //MP3 lejátszó programkönyvtára

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX   //beállítjuk a szoftveres soros portot
DFRobotDFPlayerMini myDFPlayer;                      //myDFPlayer néven fogunk parancsokat küldeni a lejátszónak

//a szövegek kimondását tartalmazó fájlokat egy SD kártya gyökerébe másoltam
//és mindegyik file neve egy sorszámmal kezdődik három jegyre feltöltve 0-ákkal pl. "016",
//bár a neveknek nincs jelentősége, mert a másolás sorendje dönt, ha a play() függvénnyel
//játsszuk le az állományokat.
const byte egy=1;
const byte ketto=2;
const byte harom=3;
const byte negy=4;
const byte ot=5;
const byte hat=6;
const byte het=7;
const byte nyolc=8;
const byte kilenc=9;
const byte tiz=10;
const byte tizen=11;
const byte husz=12;
const byte huszon=13;
const byte harminc=14;
const byte negyven=15;
const byte otven=16;
const byte hatvan=17;
const byte hetven=18;
const byte nyolcvan=19;
const byte kilencven=20;
const byte szaz=21;
const byte ketszaz=22;
const byte haromszaz=23;
const byte negyszaz=24;
const byte otszaz=25;
const byte hatszaz=26;
const byte hetszaz=27;
const byte nyolcszaz=28;
const byte kielencszaz=29;
const byte hertz=30;
const byte kilohertz=31;
const byte celsiusfok=32;
const byte milibar=33;
const byte ora=34;
const byte perc=35;
const byte masodperc=36;
const byte januar=37;
const byte februar=38;
const byte marcius=39;
const byte aprilis=40;
const byte majus=41;
const byte junius=42;
const byte julius=43;
const byte augusztus=44;
const byte szeptember=45;
const byte oktober=46;
const byte november=47;
const byte december=48;
const byte valto=49;
const byte egyen=50;
const byte ezer=51;
const byte millio=52;
const byte milliard=53;
const byte volt=54;
const byte amper=55;
const byte milivolt=56;
const byte miliamper=57;
const byte ohm=58;
const byte ezred=59;
const byte szazad=60;
const byte tized=61;
const byte egesz=62;

long szunet_tmp=millis();  //10 másodpercenként egyszer indítom el a kimondást, ehhez kellett
byte szo[10];              //Maximum 10 állományt fogunk tudni lejátszani, ha már nincs több lejátszandó, 
                           //akkor a következő tömbelem 0. Ha van 10 lejátszandó, akkor az index érték lesz
                           //10, és innen tudjuk, hogy le kell állítani a lejátszást
byte index=0;              //ez mondja meg, hogy éppen melyik állományt kell lejátszani. Ha értéke 10, akkor
                           //nincs lejátszás illetve már befelyeztük. 10-re állítjuk az utolsó lejátszott állomány esetén is.
                           //A lejátszás indításakor 0-ra kell állítani a kezd nevű változót pedig 1-re.
bool kezd=1;               //egy szöveg kimondásának elindításához 1-re kell állítani. Az első file kimondása után rögtön 0-lesz
                           //így az, hogy vége-e már a kimondásnak, az index változó jelzi 10-el.
unsigned int i=0;          //kíváncsi voltam, hogy egy kimondás alatt kb. hány loop ciklus zajlik le, illetve mennyire terheli le loop-ot
                           //az mp3 lekérdezgetése. Ehhez használom. 
                           //kb. 10 és 20ezer közötti értékeket tapasztaltam, tehát nem konstans ideig tart a loop() végrehajtása 
                           //a 10 másodpercenkénti kimondási ciklusban
                           //meglepő módon, ha kiíratom a soros portra az mp3 lejátszó státusát, akkor 40-60ezer loop() végrehajtás
                           //lesz 10 sec alatt, miközben még "Wrong stack" hibaüzenetet is kapok. Ezzel még foglalkozni kell, hogy mitől van
long lejatszas_ido;        //megmérem a demó szöveg kimondásának idejét is, ehhez használom
                           //lejátszási idő 4,25 sec és 4,28 között van, ha a fileokat az SD gyökérbe másolom és számít a másolási sorrend
                           //lejátszási idő 4,59 sec és 4,61 között van, ha fileokat az MP3 nevű mappába másolom, itt már nem számít a másolási sorrend
bool indul;                //a lejátszás idejének megméréséhez használom
bool vege;                 //a lejátszás idejének megméréséhez használom
int utolso_jatszott;

void setup()
{
  pinMode(3,INPUT);
  
  mySoftwareSerial.begin(9600);               //inicializáljuk a szoftveres sorosportot
  Serial.begin(9600);                         //a hardveres sorosport megmaradt a program eseményeinek nyomon követésére   
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //mp3 lejátszó inicializálása. Ha nem sikerült, akkor 0
    Serial.println("MP3 player hiba!");       //valami hiba volt, nincs jól csatlakoztatva az mp3 lejátszó a 10 és 11-es kimenetekhez, vagy nincs benne sd kártya
  }
  Serial.println("MP3 player OK!");           //mp3 lejátszó kész a működésre
  myDFPlayer.volume(15);                      //Hangerőt maximumra állítjuk (0-30)
  index=0;                                    //az első állomány amit le kell játszani, annak a file sorszáma 0. indexen van a tömbben
  //előkészítünk egy minta szósorozatot. Az mp3 lejátszó felfogja olvasni, hogy: "12,5V"
  szo[0]=tizen;                     //1. állomány sorszáma, amit le kell játszani
  szo[1]=ketto;                     //2. állomány sorszáma, amit le kell játszani
  szo[2]=egesz;                     //3. állomány sorszáma, amit le kell játszani
  szo[3]=ot;                        //4. állomány sorszáma, amit le kell játszani
  szo[4]=tized;                     //5. állomány sorszáma, amit le kell játszani
  szo[5]=volt;                      //6. állomány sorszáma, amit le kell játszani
  szo[6]=0;                         //ez jelzi, hogy nincs több lejátszani való
}




void loop()
{
  if (millis()>szunet_tmp+10000) {   //10 másodpercenként elindítjuk a felolvasást az index=0-val és kezd=1-el
    index=0;                         //nyugalmi állapotban ez 10, 0-val jelezzük, hogy az első állomány felolvasásával indul a folyamat
                                     //minden egyes file lejátszás után növekszik az értéke 1-el
    kezd=1;                          //kezdődik a kimondás a feleolvaso() függvény következő meghívásakor
    szunet_tmp=millis();             //10 másodperc időzítése innen indul
    Serial.print("10 sec alatti loop() szám:");
    Serial.println(i);               //kiírjuk i értékét, hogy lássuk 10 sec alatt hány ciklus zajlott le
    i=0;
  } 
  if (index==0 and indul==0) {lejatszas_ido=millis();indul=1;vege=0;}
  if (index==10 and vege==0) {    Serial.print("Lejátszási idő:");Serial.println(millis()-lejatszas_ido);indul=0;vege=1;}
  i++;
  felolvaso(1);                      //minden ciklusban meghívjuk a felolvasó programot. Vigyázni kell, hogy 
                                     //5-10msec-enként meghívjuk ezta függvényt, mert különben kihagyhat szavakat
}




void felolvaso(bool kiiras) {
  if (index<10) {                                         //csak akkor kell bármit is csinálni, ha index kissebb mint 10, mert akkor épp felolvasás közben vagyunk
    if (kezd==1) {                                        //ha kezd=1, akkor elkezdődik az első részlet lejátszása, ettől a ponttól már figyelhetjük, hogy vége-e a lejátszásnak
      kezd=0;                                             //nem akarjuk többet lejátszani az első részletet
      myDFPlayer.play(szo[index]);                        //elindítjuk az első részlet lejátszását
    }
    //mp3_elerheto=myDFPlayer.available();
    if (myDFPlayer.available()) {                         //éppen elérhetővé vált az mp3 lejátszó, ha ez igaz (míg 0 addig csak várakozunk)
      if (kiiras==1) {printDetail(myDFPlayer.readType(),myDFPlayer.read());} //kiírjuk az mp3 lejátszó státusát, ha a bemenő paraméter 1.
      if (myDFPlayer.readType()==DFPlayerPlayFinished) {  //ellenőrizzük, hogy vége-e a lejátszásnak
        if (myDFPlayer.read()==szo[index]) {              //nem értem miért, de inicializálás után csak az első menetet játszotta le hibátlanul. 
                                                          //Ha újraindítok egy lejátszást, akkor az első részletet nem játssza le, hanem az utoljára 
                                                          //elindított lejátszás utolsó részletének számát adja vissza, mint ha azt játszotta volna le
                                                          //pedig semmit nem csinál. Ilyenkor újra kell indítani az első részlet lejátszását, és ekkor már jól működik
                                                          //az újrajátszáshoz ebben az esetben nem növelem az index értékét.
          index++;                                        //most rendben volt az elindított és lejátszott részlet, így lehet növelni az index értékét
        }
        if (szo[index]==0) {                              //ha az index értékhez tartozó tömbelelem 0, akkor azt jelenti, hogy vége a lejátszható részleteknek
          index=10;                                       //index=10 jelzi, hogy éppen nincs lejátszani való
        }
        else {myDFPlayer.play(szo[index]);}               //elindítjuk a következő részlet lejátszását
      }
    }
  }
}

//Ez a függvény egy kódminta az mp3 lejátszó állapotának lekérdezéséhez. Jelenleg nem használom, de hasznos
//lehet, ezért hagytam a forrásban. Meghívni a következő képpen kell:
//elősször myDFPlayer.available() értékét levizsgálni, és ha 1, akkor
// printDetail(myDFPlayer.readType(),myDFPlayer.read())
void printDetail(uint8_t type, int value){
  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
}

Alaposan felkommenteztem, talán a magyarázatok hosszabbak is mint maga a program.

Nekikeseredve olvasgattam tovább a neten. Az egyik cikkben valaki épp arra keresett megoldást, hogy a sorosporton keresztül tudjon számokat lejátszani a befejezés figyelésével, és ehhez ne kelljen használnia (figyelnie) a BUSY kivezetést. Hoppá, ezt eddig észre sem vettem. Nekem nem gond az a harmadik kivezetés, így gyors átépítés következett erre:

Mint említettem a 10K ellenállással nekem nem működöt a kommunikáció, itt került be helyette 4.7K. Ezen az ábrán az alkotó a fizikai sorosportra kapcsolta a lejátszót és azt használta. Ebben az esetben a setup() részben kicsit másként kell a lejátszót paraméterezni, de a működés ugyanaz marad. Csak hát ekkor nem lehet a fizikai sorosportot használni a hibaüzenetek kiírogatására, így nekem ez a megoldás nem tetszett. További különbség volt a saját megoldásomban, hogy véletlenszerűen a „BUSY” kivezetést az Arduino 3. kivezetésére dugtam rá és nem a 8.-ra. Viszont az ábra jól mutatja a lényeget! Véletlenül vettem észre, hogy a soros port TX vezetékére (ábrán az Arduino 0 kivezetése) nincs is szükség. Nem olvasok semmit a lejátszóból, így minek. A fentebb már említett beszélő órában már be sem kötöttem ezt az összeköttetést!

Egyébként a megoldás majdnem elsőre tökéletesen működött. Az állomány lejátszása közben a BUSY kivezetés végig 0 jelszinten tartózkodik (0 az aktív), és amikor vége a lejátszásnak, akkor felemelkedik 1-re. Azonban ez a jelszint váltás némi tranzienst is tartalmaz. Pontosan nem tudom hogyan működik, de amikor elindítom a lejátszást, akkor egy-két alkalommal lemegy 0-ra és visszajön 1-re. Feltehetőleg ilyenkor még nem a lejátszással foglalkozik, hanem kikeresi az SD kártyán a számot stb. és ez is „foglaltságot” okoz. Ezt a tranzienst úgy védtem ki, hogy a lejátszás elindítása után 100msec-ig nem kérdezem le a BUSY állapotát, csak utána kezdem nézni. Így természetesen 100msec-nél rövidebb hanganyag lejátszása után nem lenne tökéletes a program, mert nem venné észre azonnal, ha vége a lejátszásnak. De ez nem gond, minden hanganyagom hosszabb!

Azonnal megszűnt a soros kommunikáció zavaró hangja, mert hogy nincs soros kommunikáció, csak a lejátszás indításakor. A program is sokkal egyszerűbb lett. Nincs gond a hosszabb szünetek után történő fájl lejátszás indítással sem. Így elhárult az akadály a férfi és női hangok választható lejátszása elől is, de a hanganyagok közötti szünet továbbra is megnő, ha mappákban névvel kerestetjük meg a fájlokat. Így végül mégis maradtam a fapados megoldásnál, a férfi vagy női hangok között csak a fájlok cseréjével lehet választani. Csak egyiken fog beszélni a kütyü, és ha nem tetszik, ki kell venni az SD kártyát és rámásolni a másikat:

Forrás:

/**************************************************************************************
 * MP3 lejátszóval számok (mértékegységgel) és dátum kimondását megvalósító program.  *
 * A program nem mondja ki a számokat, közvetlenül, de tartalmaz minden kimondáshoz   *
 * szükséges hang file definíciót (hang file-ok külön mellékelve), és tartalmaz egy   *
 * demót ami képes vezérelni a hang file részek lapján a folyamatot.                  *
 * Úgy lett megírva a file lejátszást vezérlő függvény, hogy közben más folyamtok is  *
 * futhatnak a loop()-ban. Egy suo[] nevű tömbben kell megadni a file sorszámokat,    *
 * beállítani egy index nevű változót 0-ra, valamint egy kezd nevű változót 1-re.     *
 * Ennek hatására elindul a file-ok lejátszása a tömb által meghatározott sorrendben. *
 * Amikor egy állomány le lett játszva, a függvény ezt észre veszi az MP3 lejátszó    *
 * folyamatos lekérdezésével, és elindítja a következő file lejátszását. Arra kell    *
 * vigyázni, hogy a loop()-ban ne legyen más nagyon hossz ideig futó programrész.     *
 * azaz a függvény meghívására, különben kihagyhatja egy-egy rész lejátszását.        *
 * A demó a 12,5V számot mondja ki 10 másodpercenként                                 *
 * MP3 lejátszó bekötése:                                                             *
 * Az MP+ lejátszó felűlről nézve (led felül, kártya bedugás alulról) az IC-knél      *
 * megszokott körbejárási sorszámozási iránnyal a következő kivezetésekkel            *
 * rendelkezik a bal oldalon:                                                         *
 *   1 - VCC (5V, 4,2V ajánlott) Arduino-tól kapta a tápfeszt                         *
 *   2 - RX  Arduino 11-es kivezetéshöz kötve egy 1Kohm ellenálláson kersztül         *
 *   3 - TX  Arduino 10-es kivezetéshez kötve                                         *
 *   4 - DAC_R fejhellgató kivezetés, ide kötöttem a fejhellgató egyik kivezetését    *
 *   5 - DAC_L fejhallgató kivezetés (ezt nem használtam)                             *
 *   6 - SPK_1 3W-os hangszóró kimenet (ezt nem használtam)                           *
 *   7 - GND föld pont, Arduino GND-vel összekötve valamint a fejhallgató             *
 *           másik kivezetése                                                         *
 *   8 - SPK_2 3W-os hangszóró kimenet (ezt sem használtam)                           *
 * Jobb oldalon csak a legfelsőt használtam, a busy jelvezetéket, ami 1-el jelzi      *
 * ha szabad az mp3, és éppen nem csinál semmit. Ha ez 0-ról 1-re vált, akkor         *
 * befejeződött egy lejátszás.                                                        *
 *                                                                                    *
 * A leírások az RX bemenet és az Arduino kivezetés közé egy soros ellenállást        *
 * javasolnak. Ellenállás nélkül is működik, de nagyon zajos a lejátszás, behallatszik*
 * a soros port zaja nagyon erősen, szinte elnyomja a szöveget. 1Kohm-al már sokkal   *
 * halkabb a zaj (élvezhető a hang), de még ott van a háttérben. Egyes leírásokban    *
 * 10Kohm-ot írtak, de azzal már nekem nem működött. 4,7K-val még igen, de a zaj      *
 * nem lett jelentősen kevesebb                                                       *
 * Átkötöttem az mp3 lejátszó VCC-jét egy másik tápegységre, ami szintén 5V de ez egy *
 * kapcsoló üzemű táp. A zaj nem változott, nem nőtt és nem csökkent.                 *
 * Megpróbáltam a TX vezetékre is tenni egy soros 1K ellenállást, ez ugyan nem lenne  *
 * logikus, ha csökkenne a zaj, nem is csökkent.                                      *
 * Átkötöttem a fülhallgatómat a 3W-os kimenetre egy 1K soros ellenállással, és így   *
 * már nem tapasztaltam zajt. Tökéletes volt a hang.                                  *
 * Levettem a hangerőt 1-re, és kivettem a soros ellenállást. Kicsit halkabb lett     *
 * így a hangerőt felemeltem 10-re, ez eredményezett hasonló hangerőt. A zaj újra     *
 * megjelent, bár alig hallhatóan                                                     *
 * Ezt követően levettem a fejemről a fejhallgatót és felemeltem a hangerőt 30-ra     *
 * így hangszórónak használtam a fejhallgatót. A zajt nem halottam, de a szöveg       *
 * szépen tisztán hallható lett. Az eredmény kielégítő. A fejhallgatóm kb 40ohm-os.   *
 *                                                                                    *
 * DFRobotDFPlayerMini legfontosabb függvényei:                                       *
 *  myDFPlayer.play(int fájlszám); - bármely könyvtárba másolt bármely fájlokat       *
 *                                    lejátsza de az állományok másolási sorrendjét   *
 *                                    veszi figyelembe!                               *
 *  myDFPlayer.playMp3Folder (int fájlszám) - az mp3 könyvtárban lévő fájlokat játssza*
 *                                    le, és a file első négy karaktere nullákkal     *
 *                                    feltöltött szám kell legyen (max. 10000db)      *
 *                                    pl:0012 a fájl név bármivel folytatódhat        *
 *  myDFPlayer.playFolder (int mappaszám, int fájlszám); - numerikus nevű mappában    *                                      
 *                                    lévő fájlokat játszik le. a mappa neve "01",    *
 *                                    "02" stb., a file első három karaktere nullákkal*
 *                                    feltöltött szám kell legyen (max. 1000db)       *
 *                                    pl:015 a fle név bármivel folytatódhat          *
 *  myDFPlayer.playLargeFolder (int mappaszám, int fájlszám); - ugyanz mint előző     *
 *                                    vak a mappában 9999db file lehet.               *
 **************************************************************************************/

#include "Arduino.h"
#include "SoftwareSerial.h"       //használunk egy szoftveres soros portot, hogy megmaradjon a valódi soros port a fejlesztéshez, hibakereséshez
#include "DFRobotDFPlayerMini.h"  //MP3 lejátszó programkönyvtára

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX   //beállítjuk a szoftveres soros portot
DFRobotDFPlayerMini myDFPlayer;                      //myDFPlayer néven fogunk hivatkozni erre az mp3 lejátszó példányra

//a szövegek kimondását tartalmazó fájlokat egy SD kártya gyökerébe másoltam
//és mindegyik file neve egy sorszámmal kezdődik három jegyre feltöltve 0-ákkal pl. "016",
//bár a neveknek nincs jelentősége, mert a másolás sorendje dönt, ha a play() függvénnyel
//játsszuk le az állományokat.
const byte egy=1;
const byte ketto=2;
const byte harom=3;
const byte negy=4;
const byte ot=5;
const byte hat=6;
const byte het=7;
const byte nyolc=8;
const byte kilenc=9;
const byte tiz=10;
const byte tizen=11;
const byte husz=12;
const byte huszon=13;
const byte harminc=14;
const byte negyven=15;
const byte otven=16;
const byte hatvan=17;
const byte hetven=18;
const byte nyolcvan=19;
const byte kilencven=20;
const byte szaz=21;
const byte ketszaz=22;
const byte haromszaz=23;
const byte negyszaz=24;
const byte otszaz=25;
const byte hatszaz=26;
const byte hetszaz=27;
const byte nyolcszaz=28;
const byte kielencszaz=29;
const byte hertz=30;
const byte kilohertz=31;
const byte celsiusfok=32;
const byte milibar=33;
const byte ora=34;
const byte perc=35;
const byte masodperc=36;
const byte januar=37;
const byte februar=38;
const byte marcius=39;
const byte aprilis=40;
const byte majus=41;
const byte junius=42;
const byte julius=43;
const byte augusztus=44;
const byte szeptember=45;
const byte oktober=46;
const byte november=47;
const byte december=48;
const byte valto=49;
const byte egyen=50;
const byte ezer=51;
const byte millio=52;
const byte milliard=53;
const byte volt=54;
const byte amper=55;
const byte milivolt=56;
const byte miliamper=57;
const byte ohm=58;
const byte ezred=59;
const byte szazad=60;
const byte tized=61;
const byte egesz=62;

long szunet_tmp=millis();  //10 másodpercenként egyszer indítom el a kimondást, ehhez kellett
byte szo[10];              //Maximum 10 állományt fogunk tudni lejátszani, ha már nincs több lejátszandó, 
                           //akkor a következő tömbelem 0. Ha van 10 lejátszandó, akkor az index érték lesz
                           //10, és innen tudjuk, hogy le kell állítani a lejátszást
byte index=0;              //ez mondja meg, hogy éppen melyik állományt kell lejátszani. Ha értéke 10, akkor
                           //nincs lejátszás illetve már befelyeztük. 10-re állítjuk az utolsó lejátszott állomány esetén is.
                           //A lejátszás indításakor 0-ra kell állítani a kezd nevű változót pedig 1-re.
long lejatszas_ido;        //megmérem a demó szöveg kimondásának idejét is, ehhez használom
long varakozas=millis();   //amikor elindítom a lejátszást, a lejátszón a busy jelvezeték nem vált azonnal 1-re, illetve
                           //rövid ideig még változik is. Ezért várok egy kis időt, amíg figyelni kezdem. Ehhez kell!

void setup()
{
  pinMode(3,INPUT);
  
  mySoftwareSerial.begin(9600);               //inicializáljuk a szoftveres sorosportot
  Serial.begin(9600);                         //a hardveres sorosport megmaradt a program eseményeinek nyomon követésére   
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //mp3 lejátszó inicializálása. Ha nem sikerült, akkor 0
    Serial.println("MP3 player hiba!");       //valami hiba volt, nincs jól csatlakoztatva az mp3 lejátszó a 10 és 11-es kimenetekhez, vagy nincs benne sd kártya
  }
  Serial.println("MP3 player OK!");           //mp3 lejátszó kész a működésre
  myDFPlayer.volume(15);                      //Hangerőt beállítjuk állítjuk (0-30)
  index=0;                                    //az első állomány amit le kell játszani, annak a file sorszáma 0. indexen van a tömbben
  //előkészítünk egy minta szósorozatot. Az mp3 lejátszó azt fogja felfogja olvasni, hogy: "12,5V"
  szo[0]=tizen;                     //1. állomány sorszáma, amit le kell játszani
  szo[1]=ketto;                     //2. állomány sorszáma, amit le kell játszani
  szo[2]=egesz;                     //3. állomány sorszáma, amit le kell játszani
  szo[3]=ot;                        //4. állomány sorszáma, amit le kell játszani
  szo[4]=tized;                     //5. állomány sorszáma, amit le kell játszani
  szo[5]=volt;                      //6. állomány sorszáma, amit le kell játszani
  szo[6]=0;                         //ez jelzi, hogy nincs több lejátszani való
}




void loop()
{
  if (millis()>szunet_tmp+10000) {   //10 másodpercenként elindítjuk a felolvasást az index=0-val 
    index=0;                         //nyugalmi állapotban ez 10, 0-val jelezzük, hogy az első állomány felolvasásával indul a folyamat
    szunet_tmp=millis();             //10 másodperc időzítése innen indul
    lejatszas_ido=millis();          //lejátszási idő méréshez használtam, de ez nem pontos, mert az utolsó részletet nem méri bele
  } 
  if (digitalRead(3)==1 and index<10 and millis()>varakozas+100) {   //éppen szabad az mp3 lejátszó, lehet neki parancsot küldeni, ha van mit lejátszani és
                                                                     //eltelt legalább 100msec az utolsó indítás óta, mert a busy jelnek be kell állni 0-ra
                                                                     //a lejátszás indítása után, hogy figyelhessem mikor fejezte be a lejátszást (1-re vált)
    varakozas=millis();
    myDFPlayer.play(szo[index]);                      //elindítjuk a soron következő rész lejátszását
    index++;
    if (szo[index]==0) {                              //ha az index értékhez tartozó tömbelem 0, akkor azt jelenti, hogy vége a lejátszható részleteknek
      index=10;                                       //index=10 jelzi, hogy éppen nincs lejátszani való
      Serial.print("Lejátszási idő:");Serial.println(millis()-lejatszas_ido);
    }
  }                     
                                     
}

A forrásban már nem volt szükség az mp3 lejátszó hiba állapotait megvalósító függvényre, mert nincs is benne hibakezelés. Feltételezzük, hogy mindig működik a kütyü, és miért ne működne.

Talán érdemes még pár szóval megemlíteni, hogyan jutottam hozzá a lejátszani kívánt hanganyaghoz. Ugyebár a feladat az volt, hogy számokat olvassak fel a kütyüvel. Röptében kell hát összeszerkeszteni az egyenként felvett kimondott számokat, és egyéb szavakat pl. „volt”, „amper”, „január” stb. Első felindulásban arra gondoltam, hogy magam diktálom be a szavakat a laptopom mikrofonjába, vagy a telefonomba. Aztán átgondoltam, hogy ez nem jó ötlet, nem biztos, hogy saját hangomat szeretném hallani valamilyen szerkezetből. Persze ez csak akkor jelenthetne kényelmetlenséget, ha mégiscsak használom valami értelmesre az elképzelést és megvalósul. A második gondolat feleségem hangja volt, de nem jutottunk el a megvalósításig, mert a véletlen hozzásegített egy teljesen más módszerhez! Épp a Google fordítóját használtam, amikor megláttam a pici kis hangszóró ikont. És igen, az első hanganyagomat a Google fordító olvasta fel. Ettől kezdve már tudatosan kerestem más megoldást is. Kiderült, hogy a Word is tud felolvasni, sőt ez még profibb, mert beállítható a felolvasás sebessége.  A Google női hang, a Word férfi. A Word azért néha hibázik, az amper és a február szavakat nem tudta felismerhetően kimondani, angol akcentussal valami más hangzott el. Így némi betű duplázással és változtatással lehetett csak valami hasonló szót kicsikarni belőle, de így is elfogadható. A következő feladat a szavak felolvastatása és egy hangszerkesztővel az egyes szavak kivágása és külön fájlokba történő vágása volt. Ezzel igen sokat dolgoztam. A következő szavakat másoltam fájlokba:

hercz, kilohercz, celsius fok, millibár, óra, perc, másodperc, váltó, egyen, volt, amper, millivolt, milliamper, ohm,
január, február, március, április, május, június, július, augusztus, szeptember, október, november, december,
egy, kettő, három, négy, öt, hat, hét, nyolc, kilenc,
tizen, huszon, tiz, húsz, harminc, negyven, ötven, hatvan, hetven, nyolcvan, kilencven,
száz, kétszáz , háromszáz, négyszáz, ötszáz, hatszáz, hétszáz, nyolcszáz, kilencszáz,
ezer, millió, milliárd, egész, tized, század, ezred,

A női hang sebessége (Google felolvasó) nem volt beállítható, illetve nem találtam, meg, hogy hol lehetne beállítani, ezért kicsit vontatott a példa programban a felolvasás. A demó programban szereplő „12.5V” („tizen-kettő-egész-öt-tized-volt”) kimondása kb. 4.3 másodperc. A férfi hangot kicsit gyorsabbra állítottam (2.5 másodperc), ezzel meg az a baj hogy egyes szavaknál nagyon hadarós lett. Lehetne még ezen segíteni, de több munkát egyenlőre nem fektettem bele. A női hang bár lassú, de nem annyira zavaró, hogy a hangokat nem tudja teljesen „egybe” olvasni az mp3 lejátszó a szavak közötti kényszerű rövid szünet miatt. A férfihang (Word) esetében ez sokkal zavaróbb, kicsit „ugatós” lett az összhatás.

Azt állítom (remélem), hogy ezekkel a szavakkal mindenféle mennyiséget, időt, dátumot ki lehet majd mondatni az mp3 lejátszóval. A példa programokban már ezeket a hang állományokat használtam. Itt lehet letölteni ez elkészített fájlokat A zip állományt csak ki kell bontani, fájl neve alapján sorba rendezni, és egyenként (62db) felmásolni az SD kártyára a fájl nevek sorrendjében. Ennek a zip állománynak a létrehozásával többet dolgoztam, mint minden mással együtt, ezért ha valaki értelmes feladatra fel tudja használni, licence díjként küldjön egy nagy tábla Milka csokit!

Szolgálati közlemény: A forráskódok között található egy anyag, amiben egy alaposabban átgondolt szó gyűjteményt lehet letölteni. Olvasd el a cikket, és használd az ott feltöltött hanganyagot. Idővel majd ezen a cikken is átvezetem, de most nincs időm rá!

Most következik annak az algoritmusnak az elkészítése, ami bemenő paraméterként megkap egy számot a mértékegységgel vagy dátumot vagy időpontot, és azt felolvassa az mp3 lejátszó. Már dolgozom rajta, idővel meg fog az is jelenni a forráskódok menüpontban!

Mennyire volt hasznos amit olvastál? Értékelés után szövegesen is leírhatod megjegyzéseidet és véleményedet!

Kattints egy csillagra az értékeléshez!

Szövegesen is leírhatod véleményedet! Ha kérdésed van, ne felejtsd el megadni az email címedet!