Авторизация
Зарегистрироваться

Учим разговаривать DIY с помощью MP3 модуля


Когда мы мастерим различные полезности для дома, используя Ардуино, мы мало задумываемся, как получать информацию от этого устройства. Если ее немного, то обходимся чащe всего светодиодами. Но если информации выводить нужно больше, то конечно, это будет видео в том или ином виде — разнообразные индикаторы и дисплейчики, коих в продаже великое множество. Ибо это просто и это привычно. Да, зрение у нас основной орган чувств, но иногда звук гораздо более удобный, а зачастую и единственный способ донести до нас информацию. Примерами могут служить будильник, сигналка на авто или, увы, слабовидящие люди. Но в своих поделках дальше использования пищалки мы звуком не пользовались, поскольку не было удобного инструмента для этого. Теперь это в прошлом.


В этом обзоре мы научим разговаривать (и даже немного шутить) часы и другие приборы и напишем аудиосинтезатор, с помощью которого Ардуино сможет произносить любые числа из натурального ряда голосом.

Для начала о цене вопроса. Не слишком ли она окажется высока для заявленных возможностей? И вот тут нас ожидает первый и весьма приятный сюрприз. Чуть больше доллара MP3 модуль плюс чуть меньше бакса micro SD карточка на 64 mb (я брал на ebay по 99 центов), без которой модуль бесполезен. Недорого, правда? Да, для вывода звука, конечно, понадобится еще динамик, но поскольку никаких выдающихся характеристик от него не требуется, мы его покупать не станем, а вытащим, к примеру, из какого-нибудь старого системника или радиоприемника. А зато в качестве бонуса мы получим возможность выбросить из проекта пищалку, если она там была — с ее ролью прекрасно справится сам MP3 модуль.
Познакомимся с железом:
Модуль представляет собой вполне себе самостоятельный девайс, который можно использовать и без Ардуино. Для этого достаточно подключить к нему несколько кнопок (или даже резистивную клаву), динамик или внешний усилитель, вставить micro SD карточку с музоном и все, можно слушать любимые композиции. Но это совсем неинтересно. Гораздо интересней управлять им программно, чем мы сегодня и займемся. Ниже расписаны все его контакты, но нам для работы с Ардуино понадобятся только первые семь.

Вывод Описание
1. VCC Питание «+»
2. GND Питание «−»
3. RX UART приём
4. TX UART передача
5. SPK1 Громкоговоритель «+»
6. SPK2 Громкоговоритель «−»
7. BUSY Индикатор состояния («0» — простой, «1» — проигрывание)
8. DAC_R Выход на наушник или усилитель (канал «R»)
9. DAC_L Выход на наушник или усилитель (канал «L»)
10. IO1 Вход управления: короткое нажатие — «назад», длинное — уменьшить громкость
11. IO2 Вход управления: короткое нажатие — «вперёд», длинное — увеличить громкость
12. ADKEY1 Порт для подключения резистивной клавиатуры, вход 1
13. ADKEY2 Порт для подключения резистивной клавиатуры, вход 2
14. USB+ USB порт, вывод «+»
15. USB− USB порт, вывод «−»

Что нам следует знать о железке? Плеер может проигрывать как mp3 файлы с битрейтом до 320kbps, так и wav. На его борту присутствует встроенный усилитель, к которому, согласно даташита, можно подключить динамик и выжать до 3W. Качество звука не ахти, но для экспериментов пойдет. Лучше использовать все-таки внешний стерео усилитель, задействовав выводы DAC_R и DAC_L. Для питания требуется напряжение в диапазоне 3.2 — 5V. В плеере присутствует простенький эквалайзер на 5 профилей: NORMAL, POP, ROCK, JAZZ, CLASSIC и BASS. Общаться наш плеер с Ардуино будет через последовательный интерфейс с скоростью 9600bps. В принципе, используя команды из даташита, можно управлять плеером напрямую через UART, но мы будем использовать библиотеку mp3TF, где управление реализовано нагляднее и удобнее. Для обратной связи будем использовать пин BUSY, чтобы знать о состоянии плеера (режим воспроизведения или ожидания). Один интересный момент касается реализации связи по UART. Хотя, в даташите указано прямое соединение TX-RX, RX-TX, народ рекомендует включить в эти цепи по резистору 1-2 кОм. Без них, якобы, появляются искажения, идет нагрев плеера и у кого-то даже плеер вышел из строя. Поверим и включим эти резисторы.

О железе плеера пока все, можно приступать к сборке. В качестве Ардуино я буду использовать Uno, но подойдет любая модель. Поскольку плеер с динамиком 0.5W потребляет прилично для возможностей USB, с которого и пойдет у нас питание, на высокой громкости довольно существенно просаживается напряжение, из-за чего плеер вырубается. Поэтому я к цепи питания добавил конденсатор на 4700 mkF. После такой модификации плеер стабильно работает на любой громкости.

Теперь что касается программной части. Как я уже упоминал выше, я буду использовать библиотеку mp3TF, а не более распространенную DFPlayer-Mini-mp3, так как эта библиотека, предоставляя бОльшие возможности, генерит более компактный код. Но самое главное, в ее составе есть функции, позволяющие воспроизводить файлы из нужной папки! Присутствуют также стандартные функции управления громкостью, навигацией, эквалайзером и несколько экзотических, которые мы применим для модернизации Тетриса.
Немного об организации файлов на micro SD карте при использовании функции playFolder2 из этой библиотеки. Файлы могут располагаться в папках с двузначным номером. Допустимо использовать не более 15 папок, в каждой из которых до 3000 файлов. Файлы при этом сортируются по имени в алфавитном порядке. Номер трека указывается в соответствии с этой сортировкой. Чтобы не путаться, перед именем файла будем ставить четырехзначный номер, типа 0015file.mp3 или просто 0015.mp3.

Чтобы изучение возможностей плеера было нескучным, соберем на макетной плате несколько полезных устройств из того что у меня оказалось под рукой.
Поскольку были найдены модуль реального времени DS1307 и дисплейчик на TM1637, то соберем говорящие часы. Активатором голосового вывода времени будет сенсорный датчик.
Подготовка micro SD карточки. Отформатируем ее в FAT16 или FAT32 и наговорим в микрофон все возможные часы и минуты. Получится 84 файла — 24 часа и 60 минут.
Скачаем и установим библиотеки DS1307RTC.h и TimeLib.h для работы с часами, TM1637Display.h для работы с дисплеем и SoftwareSerial.h для организации виртуального последовательного порта. Можно, конечно, пользоваться и встроенным портом, но так мы получим более гибкую конструкцию с одинаковыми номерами пинов для подключения всех моделей Ардуино. Собираем схему. Теперь нам нужно установить время в наших часах. Поскольку мы собираем часы только для демонстрации возможностей плеера, то не будем писать код для установки и корректировки даты/времени, а воспользуемся примером из состава библиотеки DS1307RTC.h с названием SetTime. Этот скетч просто заливает в RTC дату/время своей компиляции, он выполнит инициализацию модуля DS1307 и больше нам не потребуется. Теперь зальем в папку с именем 02 на флешку наши голосовые файлы, набросаем небольшой скетч для наших часов и запустим его.
Говорящие часы
Таблица соединений:
Сенсор сигнал — Pin 10
Mp3 модуль RX — Pin 8
Mp3 модуль TX — Pin 7
Mp3 модуль Busy — Pin 9
TM1637 CLK — Pin 2
TM1637 DIO — Pin 3
DS1307 Sda — Pin 4
DS1307 Scl — Pin 5
Питание везде 5V. Папка 02 на micro SD обязательна.

// Klop 2017 Говорящие часы
#include <TimeLib.h>
#include <DS1307RTC.h>
#include <TM1637Display.h>
#include <SoftwareSerial.h>
#include <mp3TF.h>
#define BusyState 9 // пин BUSY плеера
#define touch 10    // пин сенсора
// TM1637 пины
#define CLK 2
#define DIO 3
TM1637Display display(CLK, DIO);
byte cyfra[]={63,6,91,79,102,109,125,7,127,111};
byte data[] = {0,0,0,0}, prikol, pm;
bool fldv;
tmElements_t tm;
unsigned long interval=0;
mp3TF mp3tf = mp3TF ();
//------------------------------------------------------------
void setup()
{ display.setBrightness(10);
  SoftwareSerial mySerial(8, 7); // RX, TX 
  mySerial.begin (9600);
  mp3tf.init (&mySerial);
  delay(200);
  mp3tf.volumeSet(20);
  delay(200);
  pinMode(BusyState,INPUT);
  pinMode(touch,INPUT);
}
//------------------------------------------------------------
void ozv(int myfile)
{   mp3tf.playFolder2(2,myfile);
    delay(300);
    while(!digitalRead(BusyState));
}
//------------------------------------------------------------
void golos()
{ ozv(tm.Hour+61);
  ozv(tm.Minute+1);
}
//------------------------------------------------------------
void mydelay(long md)
{unsigned long starttime=millis();  
  while (millis()-starttime<md)
    if (digitalRead(touch)) golos();
}
//------------------------------------------------------------
void hh()
{ getdt();
  if (fldv) data[1]= data[1]|0x80;
  display.setSegments(data);
}  
//------------------------------------------------------------
void getdt()
{  if (RTC.read(tm)) 
      {if (tm.Hour<10) data[0]=0; 
          else data[0]=cyfra[tm.Hour/10];
       data[1]=cyfra[tm.Hour%10];
       data[2]=cyfra[tm.Minute/10];
       data[3]=cyfra[tm.Minute%10];
      } else data[0]=8; 
}
//------------------------------------------------------------
void loop()
{
  hh();
  mydelay(500);
  fldv=!fldv;
}


Мы увидим на дисплее текущее время и моргающее двоеточие-секунды. А теперь прикоснемся к сенсору и вот оно! Часы сообщают нам время голосом. Такие часы я видел когда-то очень давно и мне очень хотелось тогда их иметь, но, увы, возможностей не было. Теперь, не особо напрягаясь, любой может собрать их за несколько минут. Но мы пойдем еще дальше и дадим часам сварливый характер. Пусть наши часы начнут ворчать, если к сенсору прикасаться слишком часто.
Для этого добавим несколько файлов с соответствующей озвучкой и несколько строк кода. Обновленный скетч будет выглядеть так:
Говорящие часы - ворчуны )
Таблица соединений:
Сенсор сигнал — Pin 10
Mp3 модуль RX — Pin 8 (через резистор 2к)
Mp3 модуль TX — Pin 7 (через резистор 2к)
Mp3 модуль Busy — Pin 9
TM1637 CLK — Pin 2
TM1637 DIO — Pin 3
DS1307 Sda — Pin 4
DS1307 Scl — Pin 5
Питание везде 5V. Папка 02 на micro SD обязательна.

// Klop 2017 Говорящие часы - ворчуны )
#include <TimeLib.h>
#include <DS1307RTC.h>
#include <TM1637Display.h>
#include <SoftwareSerial.h>
#include <mp3TF.h>
#define BusyState 9 // пин BUSY плеера
#define touch 10    // пин сенсора
// TM1637 пины
#define CLK 2
#define DIO 3
TM1637Display display(CLK, DIO);
byte cyfra[]={63,6,91,79,102,109,125,7,127,111};
byte data[] = {0,0,0,0}, prikol, pm;
bool fldv;
tmElements_t tm;
unsigned long interval=0;
mp3TF mp3tf = mp3TF ();
//------------------------------------------------------------
void setup()
{ display.setBrightness(10);
  SoftwareSerial mySerial(8, 7); // RX, TX 
  mySerial.begin (9600);
  mp3tf.init (&mySerial);
  delay(200);
  mp3tf.volumeSet(20);
  delay(200);
  pinMode(BusyState,INPUT);
  pinMode(touch,INPUT);
}
//------------------------------------------------------------
void ozv(int myfile)
{   mp3tf.playFolder2(2,myfile);
    delay(300);
    while(!digitalRead(BusyState));
}
//------------------------------------------------------------
void golos()
{ unsigned long i;      // начало кода ворчалок
  i=millis()-interval;   
  interval=millis();  
  if (i<5000 && pm==tm.Minute) 
     {prikol++;
      if (prikol==1) ozv(85); else 
      if (prikol==2) ozv(86); else
      if (prikol==3) ozv(87); 
      delay(200);                
     } else prikol=0;            
if (prikol==0) pm=tm.Minute;
if (prikol<3)               // конец кода ворчалок            
 {ozv(tm.Hour+61);
  ozv(tm.Minute+1);
 }
}
//------------------------------------------------------------
void mydelay(long md)
{unsigned long starttime=millis();  
  while (millis()-starttime<md)
    if (digitalRead(touch)) golos();
}
//------------------------------------------------------------
void hh()
{ getdt();
  if (fldv) data[1]= data[1]|0x80;
  display.setSegments(data);
}  
//------------------------------------------------------------
void getdt()
{  if (RTC.read(tm)) 
      {if (tm.Hour<10) data[0]=0; 
          else data[0]=cyfra[tm.Hour/10];
       data[1]=cyfra[tm.Hour%10];
       data[2]=cyfra[tm.Minute/10];
       data[3]=cyfra[tm.Minute%10];
      } else data[0]=8; 
}
//------------------------------------------------------------
void loop()
{
  hh();
  mydelay(500);
  fldv=!fldv;
}


А вот как они работают.

Теперь, если касаться сенсора чаще, чем раз в 5 сек, часы начинают раздражаться, а после 3-го раза вообще обижаются и перестают сообщать время. Но, конечно, ненадолго ). После 5 секунд настроение у них снова восстанавливается. Характеры можно придумать разные, все ограничивается только нашей фантазией. Собрав подобные часы в корпусе (мыльница?), мы получим отличный подарок для близких. И даже весьма полезный для слабовидящих. А может кому то понравится возможность узнавать ночью время, не открывая глаз, а просто коснувшись корпуса часов рядом. Себе-то я точно соберу, как только приедет микрофон (чтобы в зависимости от шумности вокруг, регулировалась громкость).

Собирая часы, мы использовали полный набор файлов с часами и минутами, где в каждом файле присутствует число и его размерность: “Два часа”, “Двадцать одна минута”, “Восемнадцать часов” и т.д. Нам не пришлось заниматься лексическим разбором: “одна минутА”, но “две минутЫ” или “пять минуТ”. Мы упростили себе жизнь, соединяя только 2 файла – количество часов и количество минут. А комбинаций всех возможных часов и минут получилось всего 84, это немного и нас это устроило. Но мы можем озвучить не только часы, но и показания любых других приборов, значения которых могут превышать тысячи и более. В этом случае все возможные комбинации не надиктуешь. Значит нужно написать универсальный голосовой синтезатор чисел. Этим и займемся.

Как мы произносим число? Есть базовые лексические единицы и сборные. Например, числа “один”, “пятнадцать”, “семьдесят”, “сто” являются базовыми, а число “сто двадцать пять” синтезируется из 3-х базовых единиц. В интервале от 0 до 19 числа все базовые, поэтому надиктуем их в 20 файлов. Далее идут десятки от 20 до 90, их также запишем в 8 файлов. За ними 9 файлов с произношением сотен. Дальше начинаются тысячи. Тут уже новый лексический нюанс. “ОДНА тысячА”, “ДВЕ тысячИ” и “пять тысяЧ”. Почти все в тысячах будет соответствовать и для более высоких размерностей, кроме слов “ОДНА” и “ДВЕ”. Для всех остальных размерностей это будут слова “ОДИН” и “ДВА”. Надиктуем эти варианты произношения для тысяч в 2 файла и добавим их в нашу папку. А затем по три варианта произношения для каждой последующей размерности: «миллион», “миллиона”, “миллионов” и т.д.

Все файлы надиктованы, идея понятна, осталось воплотить её в скетч. Но мы-же программисты, ёпт
Скетч голосового синтезатора чисел
Таблица соединений:
Mp3 модуль RX — Pin 8 (через резистор 2к)
Mp3 модуль TX — Pin 7 (через резистор 2к)
Mp3 модуль Busy — Pin 9
Питание везде 5V. Папка 01 на micro SD обязательна.

//Klop 2017 говорилка чисел
#include <SoftwareSerial.h>
#include <mp3TF.h>
#define BusyState 9 // пин BUSY плеера
#define c19 19  
#define c100 29  
#define c1000 38   
#define odna 76
#define dve 77
bool fl;
mp3TF mp3tf = mp3TF ();
char ccc[3];  
byte troyka [3];

//------------------------------------------------------------
void setup()
{ SoftwareSerial mySerial(8, 7); // RX, TX 
  mySerial.begin (9600);
  mp3tf.init (&mySerial);
  delay(200);
  pinMode(BusyState,INPUT);
  mp3tf.volumeSet(22);
  delay(200);
}
//------------------------------------------------------------
void ozv(int myfile)
{   mp3tf.playFolder2(1,myfile);
    delay(200);
    while(!digitalRead(BusyState));
}
//------------------------------------------------------------
void voicedig(char cc[])
{ int a,b,c,d,jj,sme,dp;
  a=strlen(cc);
  if (atoi(cc)==0) ozv(1); else
 { 
  for (byte i=0;i<3;i++) ccc[i]=0;
  b=a%3;c=a/3;jj=0;
  for (byte i=0;i<c+1;i++)
    {strncpy(ccc,cc+jj,b);
     d=atoi(ccc); a=d;
     for (byte i=0;i<3;i++)
       { troyka[2-i]=a%10; 
         a=a/10;
       }  
    if (d>0)
     { dp=troyka[2];
       if (c-i==1)
        if (troyka[2]==1) dp=odna;
          else if(troyka[2]==2) dp=dve;
       if (troyka[0]>0) ozv(c100+troyka[0]-1);
       if (troyka[1]>1) ozv(c19+troyka[1]);
          else if (troyka[1]==1) 
                  {ozv(troyka[1]*10+troyka[2]+1);
                   goto m1; 
                  }
       if (troyka[2]>0) ozv(dp+1);
       m1: a=d%100;
        if (a>19) a=d%10;
        if (a==1) sme=0; else
        if (a>1 && a<5) sme=1; else sme=2;
       if (c-i>0) ozv(c1000+(c-i-1)*3+sme);
      };
      jj=jj+b;b=3;
      delay(100); 
    }
 }
}
//------------------------------------------------------------

void loop()
{
  voicedig("91352412028529003471097014534460011762920");
 while(true);
}


Вот такая небольшая функция voicedig() способна лексически верно произнести любое натуральное число до 42-х разрядов. А вы сможете? Тогда вперед! )))
Видео работы голосового синтезатора:


Если кому-то этого недостаточно, можно надиктовать еще размерностей, но мне их названия неизвестны. (Не проблема обучить систему произношению дробей и еще многому чему, но для демонстрации возможностей сабжа вполне, думаю, приведенного примера будет достаточно.)

Теперь давайте применим нашу функцию для реальных измерений. Для этого добавим на макетку датчик освещенности BH1750. Значит, нам понадобятся еще 3 файла со словами “люкс”, “люкса”, “люксов”. Закинем эти файлы в новую папку и напишем скетч для опроса датчика. Немножко похулиганим и добавим в инициализацию прибора прибора приветствие ).
Скетч говорящего датчика освещенности
Таблица соединений:
Сенсор сигнал — Pin 10
Mp3 модуль RX — Pin 8 (через резистор 2к)
Mp3 модуль TX — Pin 7 (через резистор 2к)
Mp3 модуль Busy — Pin 9
TM1637 CLK — Pin 2
TM1637 DIO — Pin 3
BH1750 Sda — Pin 4
BH1750 Scl — Pin 5
Питание везде 5V. Папки 01, 03 и 04 на micro SD обязательны.

// Klop 2017 говорящий люксметр
#include <Wire.h>
#include <BH1750.h>
#include <TM1637Display.h>
#include <SoftwareSerial.h>
#include <mp3TF.h>
#define BusyState 9 // пин BUSY плеера
#define touch 10    // пин сенсора
#define c19 19  
#define c100 29  
#define c1000 38   
#define odna 76
#define dve 77
#define f1 1 // папка с числами
#define f4 4 // папка с приветствием
// TM1637 пины
#define CLK 2
#define DIO 3
#define f3 3 // папка с файлами люксов
TM1637Display display(CLK, DIO);
byte cyfra[]={63,6,91,79,102,109,125,7,127,111};
byte data[] = {0,0,0,0}, prikol, pm;
mp3TF mp3tf = mp3TF ();
char str[100]; 
int lp=0; 
uint16_t lux;
BH1750 lightMeter;
char ccc[3];  byte troyka [3];
//------------------------------------------------------------
void setup()
{ Serial.begin(9600);
  lightMeter.begin();
  display.setBrightness(10);
  SoftwareSerial mySerial(8, 7); // RX, TX 
  mySerial.begin (9600);
  mp3tf.init (&mySerial);
  delay(200);
  mp3tf.volumeSet(20);
  delay(200);
  pinMode(BusyState,INPUT);
  pinMode(touch,INPUT);
  ozv(f4,1);
}
//------------------------------------------------------------
void ozv(int papka, int myfile)
{   mp3tf.playFolder2(papka,myfile);
    delay(300);
    while(!digitalRead(BusyState));
}
//------------------------------------------------------------
void voicedig(char cc[])
{ int a,b,c,d,jj,sme,dp;
  a=strlen(cc);
  for (byte i=0;i<3;i++) ccc[i]=0;
  b=a%3;c=a/3;jj=0;
  for (byte i=0;i<c+1;i++)
    {strncpy(ccc,cc+jj,b);
     d=atoi(ccc); a=d;
     for (byte i=0;i<3;i++)
       { troyka[2-i]=a%10; 
         a=a/10;
       }  
    if (d>0)
     { dp=troyka[2];
       if (c-i==1)
        if (troyka[2]==1) dp=odna;
          else if(troyka[2]==2) dp=dve;
       if (troyka[0]>0) ozv(f1,c100+troyka[0]-1);
       if (troyka[1]>1) ozv(f1,c19+troyka[1]);
          else if (troyka[1]==1) 
                  {ozv(f1,troyka[1]*10+troyka[2]+1);
                   goto m1;
                  }
       if (troyka[2]>0) ozv(f1,dp+1);
       m1: a=d%100;
        if (a>19) a=d%10;
        if (a==1) sme=0; else
        if (a>0 && a<5) sme=1; else sme=2;
       if (c-i>0) ozv(f1,c1000+(c-i-1)*3+sme);
      }
      jj=jj+b;b=3;
      delay(100); 
    }
}
//------------------------------------------------------------
void mydelay(long md)
{unsigned long starttime=millis();  
  while (millis()-starttime<md)
    if (digitalRead(touch) && lux>0) 
       {sprintf(str, "%u", lux );
        voicedig(str);
        byte a=lux%100;
        if (a>19) a=lux%10;
        if (a==1) ozv(f3,1); else
        if (a>0 && a<5) ozv(f3,2); else
        ozv(f3,3);
       }
}
//------------------------------------------------------------
void hh()
{ getdt();
  display.setSegments(data);
}  
//------------------------------------------------------------
void getdt()
{ int a=lux;
  for (byte i=0;i<4;i++)     
    { data[3-i]=cyfra[a%10];
      a=a/10;  
    }
}
//------------------------------------------------------------
void loop()
{ lux = lightMeter.readLightLevel();
  hh();
  mydelay(2000);
}


Видео работы говорящего люксметра:


Заменим люксметр на дальномер, поправим немного код и получим говорящий дальномер.
Скетч говорящего дальномера
Таблица соединений:
Сенсор сигнал — Pin 10
Mp3 модуль RX — Pin 8 (через резистор 2к)
Mp3 модуль TX — Pin 7 (через резистор 2к)
Mp3 модуль Busy — Pin 9
TM1637 CLK — Pin 2
TM1637 DIO — Pin 3
HC-SR04 trigPin — Pin 11
HC-SR04 echoPin — Pin 12
Питание везде 5V. Папка 05 на micro SD обязательна.

// Klop 2017
#include <TM1637Display.h>
#include <SoftwareSerial.h>
#include <mp3TF.h>
#define BusyState 9 // пин BUSY плеера
#define touch 10    // пин сенсора
#define c19 19  
#define c100 29  
#define c1000 38   
#define odna 76
#define dve 77
#define f1 1 // папка с числами
#define f5 5 // папка с милиметрами
#define trigPin 11 // пины
#define echoPin 12 // дальномера

// TM1637 пины
#define CLK 2
#define DIO 3
TM1637Display display(CLK, DIO);
byte cyfra[]={63,6,91,79,102,109,125,7,127,111};
byte data[] = {0,0,0,0}, prikol, pm;
mp3TF mp3tf = mp3TF ();
char str[100]; 
int lp=0; 
char ccc[3];  byte troyka [3];
int mm;
//------------------------------------------------------------
void setup()
{ Serial.begin(9600);
  display.setBrightness(10);
  SoftwareSerial mySerial(8, 7); // RX, TX 
  mySerial.begin (9600);
  mp3tf.init (&mySerial);
  delay(200);
  mp3tf.volumeSet(20);
  delay(200);
  pinMode(BusyState,INPUT);
  pinMode(touch,INPUT);
  pinMode(trigPin, OUTPUT); 
  pinMode(echoPin, INPUT); 
}
//------------------------------------------------------------
void ozv(int papka, int myfile)
{   mp3tf.playFolder2(papka,myfile);
    delay(300);
    while(!digitalRead(BusyState));
}
//------------------------------------------------------------
void voicedig(char cc[])
{ int a,b,c,d,jj,sme,dp;
  a=strlen(cc);
  for (byte i=0;i<3;i++) ccc[i]=0;
  b=a%3;c=a/3;jj=0;
  for (byte i=0;i<c+1;i++)
    {strncpy(ccc,cc+jj,b);
     d=atoi(ccc); a=d;
     for (byte i=0;i<3;i++)
       { troyka[2-i]=a%10; 
         a=a/10;
       }  
    if (d>0)
     { dp=troyka[2];
       if (c-i==1)
        if (troyka[2]==1) dp=odna;
          else if(troyka[2]==2) dp=dve;
       if (troyka[0]>0) ozv(f1,c100+troyka[0]-1);
       if (troyka[1]>1) ozv(f1,c19+troyka[1]);
          else if (troyka[1]==1) 
                  {ozv(f1,troyka[1]*10+troyka[2]+1);
                  goto m1;
                  }
       if (troyka[2]>0) ozv(f1,dp+1);
       m1: a=d%100;
        if (a>19) a=d%10;
        if (a==1) sme=0; else
        if (a>0 && a<5) sme=1; else sme=2;
       if (c-i>0) ozv(f1,c1000+(c-i-1)*3+sme);
      }
      jj=jj+b;b=3;
      delay(100); 
    }
}
//------------------------------------------------------------
void mydelay(long md)
{unsigned long starttime=millis();  
  while (millis()-starttime<md)
    if (digitalRead(touch) && mm>0) 
       {sprintf(str, "%u", mm );
        voicedig(str);
        byte a=mm%100;
        if (a>19) a=mm%10;
        if (a==1) ozv(f5,1); else
        if (a>0 && a<5) ozv(f5,2); else
        ozv(f5,3);
       }
}
//------------------------------------------------------------
void hh()
{ getdt();
  display.setSegments(data);
}  
//------------------------------------------------------------
void getdt()
{ int a=mm;
  for (byte i=0;i<4;i++)     
    { data[3-i]=cyfra[a%10];
      a=a/10;  
    }
}
//------------------------------------------------------------
void loop()
{ int duration;
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(trigPin, HIGH); 
  delayMicroseconds(10); 
  digitalWrite(trigPin, LOW); 
  duration = pulseIn(echoPin, HIGH); 
  mm = duration / 5.8;
  hh();
  mydelay(2000);
}


Видео работы говорящего дальномера:


Конечно, данные датчики используют нашу функцию лишь на малую долю. Но ее возможностей хватит на любой прибор с запасом.
Напоследок мы модернизируем игру Тетрис из этого обзора. Отключим уже ненужную пьезопищалку и поставим сабж. Запишем фоновый трек, звук проваливания линии и озвучим установление нового рекорда. Применим из вышеозвученной библиотеки крайне интересные функции: repeatCurrent(bool start) (Проигрывать по кругу текущий трек) и setInterCut(uint16_t track)(ставит текущий проигрываемый трек на паузу и проигрывает заданный).
Тетрис с озвучкой
Таблица соединений:
Serial clock out (SCLK) — pin 3
Serial data out (DIN) — pin 4
Data/Command select (D/C) — pin 5
LCD chip select (CS) — pin 7
LCD reset (RST) — pin 7
Mp3 модуль RX — Pin 10 (через резистор 2к)
Mp3 модуль TX — Pin 11 (через резистор 2к)
Mp3 модуль Busy — Pin 12
Питание везде 5V. Папки 06 и ADVERT на micro SD обязательны.

//// © Klop 2017
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <IRremote.h>
#include <EEPROM2.h>
#include <SoftwareSerial.h>
#include <mp3TF.h>
#define BusyState 12 // пин BUSY плеера
#define rk 4 // ширина квадратика
#define rz 5 // ширина места
#define smeX 1
#define smeY 1
#define MaxX 10 // стакан кол-во мест по гориз
#define speaker 9

#define RECV_PIN 8 // нога на IRDA приемник

// pin 3 - Serial clock out (SCLK)
// pin 4 - Serial data out (DIN)
// pin 5 - Data/Command select (D/C)
// pin 6 - LCD chip select (CS)
// pin 7 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 6, 7);
IRrecv irrecv(RECV_PIN);
decode_results results;
byte mstacan[MaxX][30];
byte Lst,SmeH, center, NumNext;
byte MaxY; // стакан кол-во мест по вертик
int dxx, dyy, FigX, FigY, Victory, myspeed,tempspeed;
unsigned long  ok, levo, pravo, vniz, myrecord;
unsigned long flfirst=12345; // метка первого запуска
mp3TF mp3tf = mp3TF ();

byte fig[][4][4]=
   {
    {{0,0,0,0},
     {0,0,0,0},
     {0,0,0,0},
     {0,0,0,0}},

    {{0,1,0,0},
     {0,1,0,0},
     {0,1,0,0},
     {0,1,0,0}},

    {{0,0,0,0},
     {0,1,1,0},
     {0,1,1,0},
     {0,0,0,0}},

    {{0,1,0,0},
     {0,1,1,0},
     {0,0,1,0},
     {0,0,0,0}},

    {{0,1,0,0},
     {0,1,0,0},
     {0,1,1,0},
     {0,0,0,0}},

    {{0,1,0,0},
     {0,1,1,0},
     {0,1,0,0},
     {0,0,0,0}},

    {{0,0,1,0},
     {0,1,1,0},
     {0,1,0,0},
     {0,0,0,0}},

    {{0,0,1,0},
     {0,0,1,0},
     {0,1,1,0},
     {0,0,0,0}},

    {{0,0,0,0}, //8
     {0,0,0,0},
     {0,0,0,0},
     {0,0,0,0}}
   }; 
//==============================================
void mybeep() // звук
{   mp3tf.setInterCut(2);
    delay(800);
}
//==============================================
void figmove(byte a, byte b)
{ 
  for (byte i=0;i<4;i++)
    for (byte j=0;j<4;j++)
      fig[a][i][j]=fig[b][i][j];
}     
//==============================================
void figinit(byte a)
{ 
  for (byte i=0;i<4;i++)
    for (byte j=0;j<4;j++)
     {
     fig[0][i][j]=fig[NumNext][i][j];

     if (fig[a][j][i]==1) // покажем след фигуру
        display.fillRect(i*rz+60, 20+(j)*rz, rk , rk, BLACK); 
        else  display.fillRect(i*rz+60, 20+(j)*rz, rk , rk, WHITE);
     }
  display.display();
  NumNext=a; 
  tempspeed=myspeed-(Victory/30)*50; // через каждые 30 линий увеличим скорость падения;
  dxx=0;
   for (byte i=0;i<MaxX;i++)
       if (mstacan[i][3]==2) {mp3tf.stop();
                              delay(200);
                              newgame();}

}
//==============================================
void viewstacan()
{
  display.drawLine(0,0,0,display.height()-1, BLACK);
  display.drawLine(0,display.height()-1,Lst, display.height()-1, BLACK);
  display.drawLine(Lst,display.height()-1,Lst,0, BLACK);

  for (byte j=4;j<MaxY;j++)
   for (byte i=0;i<MaxX;i++)
     if (mstacan[i][j]>0) 
        display.fillRect(i*rz+1, SmeH+(j-4)*rz, rk , rk, BLACK); 
         else  display.fillRect(i*rz+1, SmeH+(j-4)*rz, rk , rk, WHITE);
         
  ds(Victory,1);                                  
  display.display();
}
//================================================
void ds(int aa, int b)
{
     display.fillRect(55, 10, 29, 10, WHITE);
     display.setCursor(55,b*10);
     display.println(aa);
}
//================================================
bool iffig(int dx, int dy)
{int i,j;
 bool flag=true; bool pov=false;
 
   for (i=0;i<MaxX;i++)
     for (j=0;j<MaxY;j++)
          if (mstacan[i][j]==1)
          mstacan[i][j]=0;  // убрали временно фигуру

    if (dx==2) //  поворот
      { dx=0; pov=true;
        figmove(8,0); 
        for (i=0;i<4;i++)
          for (j=0;j<4;j++)
          { fig[0][i][j]=fig[8][3-j][i];
            if (fig[0][j][i]==1)
             { if (i+FigX+dx<0)  dx=1;     // пробуем отодвинуть от стенки слева на 1
               if (i+FigX+dx>MaxX-1) dx=-1;// пробуем отодвинуть от стенки справа на 1
             }
          }
      }
      
 for (i=0;i<4;i++)
  for (j=0;j<4;j++)
      if (fig[0][j][i]==1)
        if (i+FigX+dx<0  || i+FigX+dx>MaxX-1 || FigY+j+dy>MaxY-1 || mstacan[i+FigX+dx][FigY+j+dy]>0) 
           {flag=false; break;} // проверили на новые координаты
     
 if (flag)
  {FigX=FigX+dx; FigY=FigY+dy;byte k=0;
   for (i=0;i<4;i++) 
     for (j=0;j<4;j++)
      if (fig[0][j][i]==1)
          {mstacan[i+FigX][j+FigY]=1;
           dxx=0;
          }
  } // переместили фигуру на новые координаты
   else
  { if (pov)  figmove(0,8);
    for (i=0;i<4;i++)    // восстановили фигуру
     for (j=0;j<4;j++)
       if (fig[0][j][i]==1)
       mstacan[i+FigX][j+FigY]=1;
  }
 return(flag);     
}
//================================================
void clearstacan()
{
 for (byte i=0;i<MaxX;i++)
  for (byte j=0;j<MaxY;j++)
    mstacan[i][j]=0;
}
//================================================
unsigned long getbutton(char s[])
{unsigned long tt;
  display.fillRect(5, 30, 40, 10, WHITE);
  display.setCursor(5,30);
  display.print(s);
  display.display();
  while (true)
   if (irrecv.decode(&results)) // ловим код кнопки пульта 
     { tt=results.value;
       delay(400); 
       irrecv.resume();
       break;
     }
  return(tt);   
}
//================================================
void newgame()
{ unsigned long tb;
  dxx=0;  dyy=1;
  display.setCursor(0,0);
  clearstacan();  
  NumNext=random(7)+1;
  figinit(random(7)+1);
  center=MaxX/2-2;
  FigX=center;FigY=0;
  display.setCursor(52,0);
  display.println("Линий");
  viewstacan();
  display.setCursor(5,0);
  display.print("Рекорд");
  display.setCursor(5,10);
  display.print(myrecord);
  display.display();
  if (Victory>myrecord) 
     { myrecord=Victory; 
       EEPROM_write(16, myrecord);
       mp3tf.playFolder2(6,4); 
       delay(200);
       while(!digitalRead(BusyState));
     }
  display.setCursor(5,20);
  delay(2000);irrecv.resume();
  display.println("Нажмите");
  tb=getbutton("  OK");
  if (tb!=ok)
    { ok=tb;
      levo=getbutton("Влево");
      pravo=getbutton("Вправо");
      vniz=getbutton("Вниз");
      EEPROM_write(0, ok);
      EEPROM_write(4, levo);
      EEPROM_write(8, pravo);
      EEPROM_write(12, vniz);
    }
                         
  display.fillRect(5, 0, (MaxX-1)*rz, 40, WHITE);
  myspeed=800; tempspeed=myspeed;
  Victory=0;
 mp3tf.playFolder2(6,3);
} 
//================================================
void setup() 
{ unsigned long tr; word gg=0;
     
  SoftwareSerial mySerial(10, 11); // RX, TX 
  mySerial.begin (9600);
  mp3tf.init (&mySerial);
  delay(200);
  pinMode(BusyState,INPUT);
  mp3tf.volumeSet(22);
  delay(200);
   mp3tf.setEQ(MP3_EQ_BASS );
  
  randomSeed(analogRead(0));
  irrecv.enableIRIn();     // Старт ресивера IRDA
  display.begin();
  display.setContrast(55);
  display.setTextSize(1);
  display.setTextColor(BLACK); // установка цвета текста
  display.clearDisplay();
  Lst=rz*MaxX; // ширина стакана в пикселях
  MaxY=display.height()/rz+4; // Высота стакана в кубиках
  SmeH=display.height()%rz; // смещение сверху в пикселях для отображения
  random(7);

  EEPROM_read(0, ok);
  EEPROM_read(4, levo);
  EEPROM_read(8, pravo);
  EEPROM_read(12, vniz);
  EEPROM_read(20, tr);
  if (tr==flfirst) EEPROM_read(16, myrecord);
     else { myrecord=0; 
            EEPROM_write(16, myrecord);
            EEPROM_write(20, flfirst);
          }    
  newgame();
}
//================================================
void dvoiki()
{
 for (byte i=0;i<MaxX;i++)
  for (byte j=0;j<MaxY;j++)
    if (mstacan[i][j]==1)
        mstacan[i][j]=2;
}
//================================================
void mydelay(int md)
{
 unsigned long starttime=millis();  
 while (millis()-starttime<md) 
   {
   if (irrecv.decode(&results)) // ловим код кнопки пульта 
      {
       if (results.value==levo) dxx=-1; else
       if (results.value==pravo) dxx=1; else 
       if (results.value==ok) dxx=2; else
       if (results.value==vniz) {tempspeed=100; md=0;} 
       if (dxx!=0) {iffig(dxx,0);  viewstacan(); }
       delay(40); // убираем дребезг  
       irrecv.resume();
       mp3tf.repeatCurrent(false);
      }
   }
}
//================================================
bool iffs() // есть ли полные строки?
{bool res=false;
 for (byte j=0;j<MaxY;j++)
 { bool fl=true;
   for (byte i=0;i<MaxX;i++)
    if (mstacan[i][MaxY-1-j]==0) fl=false;
  if (fl) 
    {Victory++; 
    if (myspeed<0) myspeed=0;
    res=true; mybeep(); 
    for (byte k=0;k<MaxX;k++) 
     for (byte n=j;n<MaxY-2;n++) 
        mstacan[k][MaxY-n-1]=mstacan[k][MaxY-n-2];
     viewstacan();
    } 
 }
 return(res);
}
//================================================
void loop()
{   if (!iffig(dxx,dyy)) 
       if (!iffig(0,dyy))
          { dvoiki();
            while (iffs()) ;
            figinit(random(7)+1);
            FigX=center;FigY=0;
          }
   viewstacan();
   mydelay(tempspeed);
}


Посмотреть, что вышло можно ниже. Прошу прощение за качество записи, особенно звука. Снимал чем было, но главное, я думаю, оценить можно. Кстати, из видео можно услышать звук проваливания линий. Кто первый догадается откуда он, сразу плюс в карму! ))



Все скетчи, описанные выше, работают с тем набором файлом, под который заточены. Скачать этот набор можно здесь. Разумеется, я не диктор, потому рекомендую тем, кто захочет повторить эти эксперименты, попросить человека с хорошей дикцией надиктовать эти файлы. Главное — соблюдать последовательность.

Итак, мы увидели, что звук может не только заменять дисплеи, но и, дополняя их, заметно разнообразить выдачу информации. Здесь все будет зависеть только от нашей фантазии… и умения немного программировать.

Выводы:
Из минусов я, пожалуй, отмечу только ограничения на имена файлов и папок, поскольку нужно знать не столько имя файла, сколько его место в таблице FAT. Из-за этого, бывало, надиктуешь полсотни файлов с именами 0001-0050, а один в середине пропустишь. И потом приходится вручную переименовывать кучу файлов, чтобы вставить забытый. Поэтому я написал себе программку на Delphi для вставки и удаления файлов в папке, так, что теперь это для меня не проблема, но производителю все-таки нужно подумать над этим.

Плеер обладает огромным потенциалом и, при своей низкой цене и творческом подходе способен стать отличным помощником программиста микроконтроллеров.
Вердикт: Must have!
Планирую купить +142 Добавить в избранное +115 +231
свернуть развернуть
Комментарии (71)
RSS
+
avatar
+4
Кин-Дза-Дза.
А провал линии — «Money» «Pink Floyd»
+
avatar
  • klop
  • 01 апреля 2017, 19:45
+1
Фоновая музыка из этого фильма. Но при уничтожении линий кусочек композиции одних из самых известных музыкантов мира.
+
avatar
  • klop
  • 01 апреля 2017, 19:50
+1
А провал линии — «Money» «Pink Floyd»
Бинго! Плюс в карму!
+
avatar
  • rexen
  • 01 апреля 2017, 19:48
+1
потом приходится вручную переименовывать кучу файлов
Зачем вручную?
У вас же компьютер!
Программ-переименовщиков предостаточно. Например, лёгонький ReNamer в полтора мегабайта. Да любой другой — стоит загуглить. А уж тупо пронумеровать по порядку — это даже батник наваять может начинающий програмер.
Мне периодически пригождаются.
+
avatar
  • YurkaM
  • 01 апреля 2017, 20:03
0
В мануалах на сей модуль присутствует такой текст:
UART Port
Standard Serial; TTL Level; Baud rate adjustable(default baud rate is 9600)
Однако нужной команды найти не удалось ни в мануале, ни в Гугле…
Кто-нить смог изменить битрейт UARTa в этом модуле?
+
avatar
  • ArturrK
  • 01 апреля 2017, 20:16
0
AT — команды в терминале?
+
avatar
  • YurkaM
  • 01 апреля 2017, 20:30
0
Да не, у этой приблуды свой формат, команда из 10 (можно из 8) байт. Строки или символы оно не понимай…
+
avatar
  • Arm100
  • 01 апреля 2017, 20:13
+2
Как круто… мне не осилить (((
С меня говорящий Вам +
+
avatar
  • SERG27
  • 01 апреля 2017, 20:39
+1
динамик с микрофоном надо брать из растоптанного огрызка №7, иначе не кошерно. :)
+
avatar
0
Где-то такой модуль завалялся. Теперь я знаю чем заняться в отпуске )))
+
avatar
+2
О, надиктованные числа можно спереть у Навител ) Там много голосов разных.
+
avatar
  • Delanet
  • 01 апреля 2017, 23:00
0
Тема «Вождь» забавная: Ленин, Лукашенко, Жириновский.
+
avatar
  • klop
  • 02 апреля 2017, 18:15
0
Сомневаюсь, что «додециллион», «люкс» и т.п. в навителе есть ))
+
avatar
0
Сомневаюсь, что додециллион нужен среднестатическому юзеру :)
+
avatar
  • klop
  • 02 апреля 2017, 18:32
0
Это конечно. Но размерности могут и понадобиться. Метры, градусы, граммы…
+
avatar
0
Ну их немного, можно и надиктовать )
+
avatar
  • klop
  • 02 апреля 2017, 20:18
0
Под Аленку или Жириновского? :)
+
avatar
0
На сколько хватит таланта ))
+
avatar
  • sir0ta
  • 01 апреля 2017, 20:54
+10
надиктуешь полсотни файлов с именами 0001-0050, а один в середине пропустишь. И потом приходится вручную переименовывать кучу файлов, чтобы вставить забытый. Поэтому я написал себе программку на Delphi для вставки и удаления файлов в папке, так, что теперь это для меня не проблема, но производителю все-таки нужно подумать над этим
Total Commander. Выделяем файлы которые надо переименовать толпой Ctrl+M и дальше как душе угодно и в лес и под дрова. Там и перенумерация есть и диапозон можно выбрать и т.д. и т.п.
+
avatar
  • qwer791
  • 01 апреля 2017, 20:54
0
Супер!
Плюсанул и пошел заказывать.

P.s по вашей ссылке товар уже не доступен.
+
avatar
  • pulp
  • 02 апреля 2017, 06:03
0
На али полно таких. Я за 1.18 купил вчера. Ищите по словам MP3 player arduino
+
avatar
0
wifi-iot.com/p/wiki/155/

просто оставлю.
+
avatar
  • Dayner
  • 01 апреля 2017, 21:09
0
Судя по китайскому датащиту, модуль ещё как внешний USB DAC работать умеет. Только мне не удалось этого добиться. Может я не всё понял?
+
avatar
0
usb dac или таки картридер?
+
avatar
  • Dayner
  • 01 апреля 2017, 23:42
0

Как USB DAC. У меня заработал как картридер.
+
avatar
0
Как его переключить в режим звуковой карты?
+
avatar
  • dSave
  • 02 апреля 2017, 00:07
+2
Замечательные у Вас обзоры, а идеи еще лучше! Спасибо огромное! )))
+
avatar
+1
С большим удовольствием прочитал обзор: грамотно, доступно, интересно. Спасибо!
+
avatar
-2
«Кожаные ублюдки!»
+
avatar
-11
+
avatar
+3
Ну так проходим мимо, в чем проблема? Мне, как и многим здесь это интересно.
+
avatar
-5
+
avatar
  • Faster
  • 02 апреля 2017, 16:15
0
Блин уже в виде модуля сделали :) я се сам травил платку
+
avatar
  • marat
  • 02 апреля 2017, 17:22
0
О, у меня такой же ножичек. Enlan
Можно не диктовать числа, а использовать программный синтезатор на ПК, скормив ему текстовый файл. Очень легко и быстро это было проделано на Mac. Даже голос можно выбрать. Уверен что таких программ полно.
+
avatar
  • marat
  • 02 апреля 2017, 17:23
0
А что за дисплей семисегментный у вас? И сенсорная кнопка?
+
avatar
  • klop
  • 02 апреля 2017, 18:14
0
Дисплей, кнопка. По поводу синтезатора на Маке. Число додециллион нужно написать цифрами или текстом, чтобы услышать произношение?
+
avatar
  • marat
  • 02 апреля 2017, 18:23
0
Текстом. Я делал не сам, только наблюдал. Могу уточнить в ближайшее время.
+
avatar
  • balavur
  • 09 апреля 2017, 11:38
0
Speech2Go плюс голосовой движок Ivona Вам в помощь. А послушать можно здесь speech2go.online/
+
avatar
  • uriy
  • 02 апреля 2017, 18:32
0
Спасибо! — очень полезно и креативно. Сам не так давно занялся Ардуино, хотя раньше программировал на «С». Очень важным считаю применить это на практике — придумать что то полезное и нужное, а не собрал-включил-разобрал. Сделал «автоматический рвспылитель аэрозоля» — типа аэрвик только с табло 1620(обратный отсчёт), звуком и температурой и влажностью. И ещё управление вытяжкой в ванну. Больше пока ни чего не придумал. Жду тележки и датчики для роботов, поиграюсь с этим.
+
avatar
  • magic12
  • 02 апреля 2017, 22:34
+1
Отличный обзор и поучительный. Спасибо
+
avatar
0
Есть у меня такие, несколько заказывал, хотел я с них типа музыкальной шкатулки собрать. Но вот возникла проблема, Звук очень тихий, даже на макс. громкости, надо прям прислушаться чтобы понять, что там играет. Правда в наличии были только пьезики и пищалка из ардуиновского набора, но и они должны звучать гораздо громче.
+
avatar
  • klop
  • 03 апреля 2017, 08:31
0
Думаю, дело в большом сопротивлении пищалки. Подсоедините динамик.
+
avatar
  • udavst
  • 04 апреля 2017, 13:05
+1
Работают 2 таких модуля, один в радиобазе (она собирает по nrf24 все датчики по дому — газ, протечка воды, температура, влажность, и говорит, если что-то не так), вторая в дверном звонке. Жалко только флэшку в этот плеер запихивать. Хотя я вот у китайцев по дешёвке взял 3 шт на 128МБ, как раз подходят. Но это я к чему, как я понял, у плеера есть встроенная память, в даташите что-то упоминалось, правда полгода назад смотрел, не припомню сейчас, вот её завести не удалось, только флэшка, либо музыка с неё либо картридер, никак иначе. Обидно, найти бы как её юзать. К стати в последней разработке использовал на esp12, а там, сами знаете, с выводами туго, в итоге подключил её только на TX, те вообще одним проводом управляется, обратно ничего в порт не читаю, занятость тоже не смотрю, в итоге 2 сэкономленных вывода. (очень удобно, что посылка с контрольной суммой, те случайно не заиграет, тк с TX еспхи у меня и на комп идёт инфа, и на последовательный дисплей и на эту вот говорилку, 3 устройсва на одном пине, никто никому не мешает, только в терминал немного муки сыпется, н это мелочи.
+
avatar
  • ambuddy
  • 09 апреля 2017, 12:06
+1
Поскольку имею дело с графикой, в частности спрайтовой анимацией, именование файлов со счетчиком — постоянная задача. Для этих целей нашел себе в помощники программку BatchRename Pro. У нее масса возможностей по именованию файлов по разным правилам, которые можно добавлять одно за другим.
+
avatar
+1
Обзор понравился, сохранил на диск :)
total commander умеет переименовывать + ещё 1000 фукнкий
+
avatar
  • hanvist
  • 10 апреля 2017, 11:50
+1
Очень интересный обзор! Большое спасибо автору! для получения голосовых подтверждений я покупал готовые модули с 9 кнопками, типа:
https://aliexpress.com/item/item/voice-playback-module-MP3-voice-prompts-voice-broadcast-device/32493850856.html
и просто ставил параллельно для каждой кнопки специальное реле 24В (9 штук) и оно замыкало контакты звуковой платы. Конечно, такой способ довольно затратный.
+
avatar
+1
Интересная тема, спасибо за обзор!
+
avatar
  • svp
  • 18 апреля 2017, 14:05
0
Хочу на базе этого модуля, WIFI и RFID модулей сделать детский плеер для сказок и радиоспектаклей. Плейлисты редактировать через-веб-интерфейс, на отдельные сказки и каталоги можно назначать RFID-метки, также метками должна ставиться пауза, и регулироваться громкость.
+
avatar
0
мдя…
Хотелось бы пойти дальше.
Привинтить как то с распознанием голоса и команд, типа:

Приходишь с улицы — зажигается свет и на фоне легкой музыки мягкий голос:
— Приветствую (имя), какие будут пожелания?
-Кузя люстра ярко
-Кузя погода?
-Кузя музыка тихо
-Кузя закажи пицу :))))
+
avatar
+1
Без проблем. Raspberry Pi/ Orange Pi + микрофон + библиотека для отсылки голосовых данных в Amazon Alexa, Google Voice. В ответ получаете текст, текст парсите, достаете управляющие слова (предложения) и производите необходимые действия.
Не уверен, что получится по-русски, но на английском примеров полно в сети.
Должно получится как-то так: «Kuzya, one bottle of vodka and talk to me now».
+
avatar
0
Да уж, чем не повод выучить английский. :)
+
avatar
0
А бывает что-то простое и готовое?
Типа, небольшая коробочка\брелок (со спичечную) с батарейкой, динамиком и кнопкой.
Жмёшь кнопку — играет закинутый файл, пусть в районе 30 секунд.
Типа продвинутый блок от музыкальной открытки или говорящей куклы.
+
avatar
0
Товарищи! Так что на счёт spi? Это встроенная флэш память? Как на неё что-то залить?
+
avatar
0
Синтезатор у меня не заработал, пока не поменял RX и TX местами. Читает цифры, но не так как в видео. Шпарит цифры подряд, иногда говорит сексилионы, тысячи итп. Наверное, при публикации скетч не совсем правильно напечатан.
+
avatar
  • klop
  • 20 августа 2017, 21:05
0
Пришлите видео работы вашей схемы в личку, разберемся. Скетч переносился со среды ардуино копипастом, так, что ошибка исключена.
+
avatar
0
Спасибо! Разобрался, все работает!
+
avatar
  • vkozloff
  • 05 сентября 2018, 16:55
0
Нашел вот такой модуль https://aliexpress.com/item/item/JQ6500-Voice-Sound-Module-USB-Replace-One-to-5-Way-MP3-Voice-Standard-New/32811747396.html
2 мегабайта памяти на борту, для озвучки большинства проектов должно хватить
+
avatar
  • aidar_i
  • 29 сентября 2018, 00:12
0
Обнаружил, что синтезатор не читает число ноль. Хотел сделать термометр. Без него никак.
+
avatar
  • aidar_i
  • 29 сентября 2018, 00:40
0
Обнаружил, что синтезатор не читает число ноль. Хотел сделать термометр. Без него никак.

Подправил, добавил строку else ozv(f1,1);:

void voicedig(char cc[])
{ int a,b,c,d,jj,sme,dp;
a=strlen(cc);
for (byte i=0;i<3;i++) ccc[i]=0;
b=a%3;c=a/3;jj=0;
for (byte i=0;i<c+1;i++)
{strncpy(ccc,cc+jj,b);
d=atoi(ccc); a=d;
for (byte i=0;i<3;i++)
{ troyka[2-i]=a%10;
a=a/10;
}
if (d>0)
{ dp=troyka[2];
if (c-i==1)
if (troyka[2]==1) dp=odna;
else if(troyka[2]==2) dp=dve;
if (troyka[0]>0) ozv(f1,c100+troyka[0]-1);
if (troyka[1]>1) ozv(f1,c19+troyka[1]);
else if (troyka[1]==1)
{ozv(f1,troyka[1]*10+troyka[2]+1);
goto m1;
}
if (troyka[2]>=0) ozv(f1,dp+1);
m1: a=d%100;
if (a>19) a=d%10;
if (a==1) sme=0; else
if (a>1 && a<5) sme=1; else sme=2;
if (c-i>0) ozv(f1, c1000+(c-i-1)*3+sme);
}
else ozv(f1,1);
jj=jj+b;b=3;
delay(100);
}
+
avatar
  • klop
  • 03 октября 2018, 12:54
0
Ok! Спасибо.
+
avatar
  • SAAH
  • 16 ноября 2018, 16:14
0
Помогите, пожалуйста. Не могу подключить библиотеку mp3TF, пишет что не найдена, хотя в списке библиотек я её вижу. Что делать? Верёвку и мыло уже купил.
+
avatar
  • SAAH
  • 16 ноября 2018, 16:44
0
Победил. Руками вставил в папку библиотек. С zip архивом отказался работать.
+
avatar
  • xeretium
  • 19 февраля 2019, 10:18
0
Хороший обзор.Можно ли сделать часы с боем Курантов?
+
avatar
  • klop
  • 03 апреля 2019, 12:23
0
C любым звуком. ))
+
avatar
  • shenrok
  • 03 октября 2019, 10:11
0
Спасибо огромное, то что искал.
Но проблема скетч синтезатора чисел выдаёт ошибку на этой строке: else ozv(f1,1); Говорит, что 'f1' was not declared in this scope
Как вылечить?
+
avatar
  • klop
  • 03 октября 2019, 15:02
+1
Поправил код
+
avatar
  • aidar_i
  • 05 января 2021, 19:18
0
Проверяю.
+
avatar
  • ramilkin
  • 17 февраля 2021, 18:02
0
Прошу Вас помочь интегрировать этот скетч под nodemcu. Отказывается работать, на UNO работает.
+
avatar
  • klop
  • 04 мая 2021, 22:25
0
Прошу Вас помочь интегрировать этот скетч под nodemcu. Отказывается работать, на UNO работает.
Прошу прощения, отписан на комменты. Только увидел. Ну, я даже не знаю, что такое nodemcu.
+
avatar
0
Может ли модуль проигрывать сразу после подачи питания? Или как это организовать?
+
avatar
  • klop
  • 02 июля 2021, 21:51
0
Может ли модуль проигрывать сразу после подачи питания? Или как это организовать?
Конечно. После подачи питания у Arduino отрабатывает секция void setup(). Делай вызов оттуда на проигрывание и все.

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.