top of page

Говорящие на Arduino

 

Arduino — это небольшая плата с собственным процессором и памятью. На плате также есть пара десятков контактов, к которым можно подключать всевозможные компоненты: лампочки, датчики, моторы, чайники, роутеры, магнитные дверные замки и вообще всё, что работает от электричества. В процессор Arduino можно загрузить программу, которая будет управлять всеми этими устройствами по заданному алгоритму. Таким образом, можно создать бесконечное количество гаджетов, сделанных своими руками и по собственной задумке.

В молодости не думаешь о времени, кажется, что оно идёт очень медленно, и хочется ускорить время, в пожилом возрасте появляется желание замедлить время. Французский писатель, лауреат Нобелевской премии Альбер Камю писал «Время идет медленно, когда за ним следишь». Для слежения за временем человек придумал великое разнообразие часов, в том числе и говорящих. Я решил сделать  для себя говорящие с некоторым набором фраз, как мне казалось, нужных для отслеживания времени и приостановления старения:

  • Объявление наступления часа круглосуточно от 8 до 23 

  • Объявление наступления минут от 1 до 30 в режиме утренней зарядки

  • Объявление наступления/окончания академического часа в 45 минут для 6-и занятий в режиме «Акадчас»

  •  Объявление наступления/окончания перерыва в 15 минут для 6-и занятий в режиме «Акадчас»

  • Срабатывание будильника звуком лесной птицы кукушки.

 

Железо

 

Часы выполнены в фанерном корпусе голубого цвета на 6-и семисегментных индикаторах ярко-зелёного цвета (Рис. 1)

 

 

 

 

 

 

 

 

 

 

 

 

 

                                                 Рис.1

Часы в момент съёмки отображают 15 часов, 17 минут, 38 секунд. Слева, напротив 15 часов отображается OLED дисплей с надписью МИНУТЫ -- для корректировки  минут (об этом чуть позже).

Схема реализована на 2-х микроконтроллерах ATMEGA328P(клиент)  и ATMEGA8A(сервер). Сервер формирует код времени и режима, клиент отвечает за отображение информации на  OLED-дисплее и управлением  звуковых сообщений.

Отображение времени  состоит из 3-х пар семисегментных индикаторах ярко-зелёного цвета. 3-х ватный динамик подключён к плееру DFPlayer_Mini_Mp3. Микро-SD на 4 гБ с записанными мелодиями  встроена в плеер.

OLED дисплей по 2-м линиям связи SDA и SQL отображает текущий режим часов.

Используемой сервис

 

При разработке программы клиента использовалась  популярная оболочка Arduino – Environment версии 1.8.5 . Для формирования звука использовался контроллер DFPlayer Mini c библиотекой DFPlayer_Mini_Mp3.h. Для отображения информации в формате чч:мм:сек на индикаторе используется программа написанная на языке С с использованием оболочки CodeVisionAVR версии V2.05.0. Для отображения информации о режимах, времени будильника на OLED-дисплее использовалась библиотека iarduino_OLED_txt.h и шрифт uint8_t MediumFontRus[].

Схемотехника управления индикатором

 

 

 

 

 

 

 

 

 

 

 

 

 

 

                                                     Рис.2

На Рис. 2 изображён индикатор FJ8201DG. Сегменты обозначены как a,b,c,d,e,f,g.Символом zX обозначен 8-й элемент – точка. Символом А обозначены аноды сегментов. Символами 1-18 обозначены номера контактов индикатора.

Для активации сегмента   необходимо подать нулевой потенциал на сегмент и положительный потенциал на анод. Для ограничения тока через диод сегмента вводится сопротивление от 600 Ом до 3к в зависимости от требуемой яркости сегмента. 

На Рис. 3 показана схема управления индикатором состоящая из собственно индикатора и контроллера ATMega8A. Ограничивающие ток сегментов сопротивления в 600 Ом R1-R8 присоединяются к сегментам индикатора с одной стороны, с другой к контактам контроллера 2-6,11,12. Аноды сегментов А1-А6 управляются контактами контроллера 13,14,15,26-28.

 

 

 

 

 

 

 

 

 

                                                          Рис.3

 

 

 

 

 

 

                                                          Рис.3

 

В Табл.1 показано кодировка символов для выбранной конфигурации. Так для активации символа «0» необходимо подать нулевой потенциал на контакты контроллера PD0, PD1, PD2, PD3, PD5, PD6, PD7, а на PD4(выключение сегмента g) подать логическую единицу. Таким образом для активации символа «0» необходимо на указанных контактах контроллера сформировать код 16 в десятичном представлении. При этом не забыть активировать  анод логической единицей.

                                                         Табл.1

Режимы работы часов

Формируются переменным сопротивлением R10 с движка которого аналоговое напряжение 0-5 В подаётся на вход АЦП (DC2). АЦП конвертирует его в цифровой код в диапазоне 0-1023 и присваивает его переменной Regim. Затем разбивается на 19 диапазонов(Фрагмент 1)

                                                    

if(Regim<=50)val=0;

if((Regim>50)  && (Regim<=100))val=1;

if((Regim>100) && (Regim<=150))val=2;

if((Regim>150) && (Regim<=200))val=3;

if((Regim>200) && (Regim<=250))val=4;

if((Regim>250) && (Regim<=300))val=5;

if((Regim>300) && (Regim<=350))val=6;

if((Regim>350) && (Regim<=400))val=7;

if((Regim>400) && (Regim<=450))val=8;

if((Regim>450) && (Regim<=500))val=9;

if((Regim>500) && (Regim<=550))val=10;

if((Regim>550) && (Regim<=600))val=11;

if((Regim>600) && (Regim<=650))val=12;

if((Regim>650) && (Regim<=700))val=13;

if((Regim>700) && (Regim<=750))val=14;

if((Regim>750) && (Regim<=800))val=15;

if((Regim>800) && (Regim<=850))val=16;

if((Regim>850) && (Regim<=900))val=17;

if((Regim>900) && (Regim<=950))val=18;

if((Regim>950) && (Regim<=1023))val=19;

              Фрагмент 1

с присвоением переменной val и далее  передаётся по интерфейсу SPI(сигналы SCK,MISO,MOSI,SS-M) клиенту. Количество режимов ограничено 19-ю,11 рабочих и 8 резервных для будущих модернизаций. В фрагменте 2 приводится расшифровка режимов.

 

Режим 0: МОЛЧАНИЕ - вывод слова МОЛЧАНИЕ на OLED – блокировка вывода звуковых сообщений

Режим 1: вывод слова МИНУТЫ++ на OLED для корректировки минут

Режим 2: вывод слова МИНУТЫ-- на OLED для корректировки минут

 Режим 3: вывод слова ЧАС++ на OLED для корректировки часов

Режим 4: вывод слова ЧАС-- на OLED для корректировки часов

Режим 5: вывод слова БУД.МИН++ на OLED  для корректировки минут будильника

Режим 6: вывод слова БУД.МИН-- на OLED  для корректировки минут будильника

Режим 7: вывод слова БУД. ЧАС ++ на OLED  для корректировки часов будильника

Режим 8: вывод слова БУД. ЧАС -- на OLED  для корректировки часов будильника

Режим 9:вывод слова ЗАРЯДКА  на OLED,запуск программы utro()

Режим 10:вывод слова БУДИЛЬНИК на OLED – звук лесной кукушки при совпадении текущего времени и установленного времени на будильнике

Режим 11:вывод слова на OLED АКАДЕМЧАС

Режим 12:вывод слова на OLED РЕЗЕРВ 1

 Режим 13:вывод слова на OLED РЕЗЕРВ 2

Режим 14:вывод слова на OLED РЕЗЕРВ 3

Режим 15:вывод слова на OLED РЕЗЕРВ 4

Режим 16:вывод слова на OLED РЕЗЕРВ 5

Режим 17:вывод слова на OLED РЕЗЕРВ 6

Режим 18:вывод слова на OLED РЕЗЕРВ 7

Режим 19:вывод слова на OLED РЕЗЕРВ 8

                       Фрагмент 2

 

В режимах 1-19 снимается блокировка по выдаче звуковых сообщений

Генерация СЕРВЕРОМ точного времени

Происходит с использованием сервисной функции прерывания interrupt [TIM1_COMPA] void timer1_compa_isr(void)(См. Лебедев М.Б. CodeVision AVR Пособие для начинающих п.6.2.5 Таймеры).

Полный текст функции прерывания приведён ниже.

 

interrupt [TIM1_COMPA] void timer1_compa_isr(void)

{

  SPI_sek++;

  if(SPI_sek>59)         {SPI_sek=0;SPI_min++;}

  if(SPI_min>59)         {SPI_min=0;SPI_ch++;}

  if(SPI_ch>23)          {SPI_ch=0;}

}

                Фрагмент 3

 

Функция работает по прерыванию от таймера 1 (См.Микроконтроллеры AVR семейства Tiny и Mega фирмы Atmel, глава 13 Таймеры Стр.255). Сервер на ATMega8 тактируется от кварцевого резонатора в 16 мГц(Рис.3). Записывем в  регистры счётчика Т1 значения TCCR1B=0x0D;OCR1AH=0x3D при достижения которых происходит прерывание и далее переменная SPI_sek увеличивается на 1. Далее в функции проверяется ряд условий по которым происходит увеличение/обнуление переменных минут, часов по алгоритму суточного астрономического времени.

Корректировка текущего времени и установка будильника

В режиме 1-8  часы и будильник можно корректировать с точностью до минут с использованием кнопки 2(Рис.3, Фрагмент 4) и сформированной переменной val (Фрагмент 1)

 

switch (val)

   {

    //корректировка времени

    case 1:while (!PINC.1){T1 if(PINC.1) SPI_min++;SPI_sek=0; if(min>59) min=0;} break;

    case 2:while (!PINC.1){T1 if(PINC.1) SPI_min--;SPI_sek=0;}break;

    case 3:while (!PINC.1){T1 if(PINC.1) SPI_ch++;SPI_sek=0;  if(ch>23)  ch=0;}  break;

    case 4:while (!PINC.1){T1 if(PINC.1) SPI_ch--;SPI_sek=0;} break;

   

    //корректировка будильника

    case 5:while (!PINC.1){T1 if(PINC.1) min_b++; if(min>59) min=0;} break;

    case 6:while (!PINC.1){T1 if(PINC.1) min_b--;}break;

    case 7:while (!PINC.1){T1 if(PINC.1) ch_b++;  if(ch>23)  ch=0;}  break;

    case 8:while (!PINC.1){T1 if(PINC.1) ch_b--;} break;

   }         

                         Фрагмент 4

Как явствует из Фрагмента 4 неоходимо на PINC.1 сформировать кратковременный ноль, затем логическую единицу. Далее идёт корректировка параметра. Манипуляции на   PINC.1 выполняет кнопка 2(Рис.3). Т1 – задержка на 5 млС для отстройки дребезга кнопки.

Передача данных КЛИЕНТУ от СЕРВЕРА

Как было показано (Табл.1) массив кодов чисел от 0 до 9 для 7-и сегментного индикатора забивается в массив типа char S[10] ={16,117,9,65,100,66,2,113,0,64}.

Как было указано (Фрагмент 3), при каждом прерывании от таймера в одну секунду происходит не только изменение переменных отвечающих за время, включая переменные для будильника, но и передача этих данных клиенту по интерфейсу SPI. (См.Микроконтроллеры AVR семейства Tiny и Mega фирмы Atmel, глава 17, Последовательный периферийный интерфейс SPI, Стр.347).

 

 

interrupt [TIM1_COMPA] void timer1_compa_isr(void)

{

   SPI_sek++;

  if(SPI_sek>59)         {SPI_sek=0;SPI_min++;}

  if(SPI_min>59)         {SPI_min=0;SPI_ch++;}

  if(SPI_ch>23)          {SPI_ch=0;}

 

 //SPI

  out(SPI_ch);out(SPI_min);out(SPI_sek);

  out(ch_b);out(min_b);

}

                 Фрагмент 5

Для передачи данных используем функцию out, дополнительно используем канал выбора клиента SS_M(Рис.1). На момент передачи байта данных активируется  SS_M=0, далее идёт отправка байта с регистра SPDR встроенного контроллера SPI и ожидание пока не отправиться байт, затем следует дезактивация SS_M=1. Итак до тех пор пока не отправится все 5 байт. Процедура отправки 5-и байт при выбранной частоте SPI 125 кГц составляет порядка 40 мкС. При наступлении следующей секунды, процесс повторяется. 

 

void out(unsigned char t)

{

  PORTB.2=0;                    //устанавливаем SS в ноль, начало передачи

  SPDR=t;                       //отправляем данные

  while(!(SPSR & (1<<SPIF)));   //ожидание пока, следующий не отправиться пакет

  PORTB.2=1;                    //устанавливаем SS в единицу, конец передачи

}

                                 Фрагмент 6

Схема принципиальная

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

                                                           

 

 

                                                                    Рис.4

Кроме выше описанного, показано управление КЛИЕНТом плеером и OLED-дисплеем. Динамик к плееру цепляется через выходы SPK1, SPK2.Потребляемая  мощность динамика не должна превышать 3-х ватт. Управление плеером идёт по сигналу COM от КЛИЕНТа. Файлы звуков типа MP3 загружаются в SD-микро через любой картридер.Я использовал недорогой MODECOM CR-LEVEL3(См.сайт https://lesson.iarduino.ru/page/urok-17-podklyuchenie-mini-mp3-pleera-k-arduino/).   OLED-дисплей упраляется КЛИЕНТом по двум линияь SDA и SQL(См.сайт https://lesson.iarduino.ru/page/urok-8-russkiy-yazyk-na-oled-displee-128x64/).

 

Технология прошивки контроллеров

 

 

 

 

 

 

 

 

 

 

 

 

                                                             Рис.5

Осуществлялась с помощью STK500(Рис. 5, См. сайт https://imrad.com.ua/ru/stk500). При разработке программы для сервера использовалсь оболочка CodeVisionAVR версии V2.05.0 которая при компиляции давала готовую прошивку – hex и сразу может быть загружена в контроллер ATMega8, то для ATMega328 то микроконтроллер требовалсь программировать в Arduino Uno( https://www.filehorse.com/download-arduino/32296/ Рис.6).  

 

 

 

 

 

 

 

 

 

 

 

 

 

                                                              Рис.6

 

Печатные платы

 

 

 

 

 

 

 

 

 

 

 

 

 

 

                                                      Рис.7

На Рис.7 расположены два микроконтроллера ATMega8,ATMega328, плеер DFPlayer Mini.Серым цветом обозначены дорожки обратной стороны, синей лицевой. Контакты для прошивки обозначены внизу платы MISO, MOSI…. Выход плеера на динамик DIN. Выход клиента на OLED-дисплей в правом верхнем углу платы.Перемычки P1 и P2 исключены из схемы(Рис.4). Кнопка KN1 и ACP входят в левом верхнем углу платы. Сигналы упраления анодами и сегментами индикатора занимают верхний край платы А1-А6(аноды),  A, B, C, D…(сегменты).Сама плата в часах расположена горизонтально.

 

 

 

 

 

 

 

 

 

 

 

                                                         Рис.8

На Рис.8 расположены три индикатора FJ8201DG и OLED-дисплей. Сигналы управления и питания занимают нижний край платы. Синие дорожки  - обратная сторона платы, серые лицевая. Плата в часах расположена вертикально. Разрывы в дорожках это места установки SMD-резисторов.

Обе платы вырезались на фрезерном станке СНС3 Луганского завода(Рис.9),

 

                                                            Рис.9

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

Приложение 1. Полный текст программы для сервера

/*****************************************************

Date    : 28.03.2019

Chip type               : ATmega8

Program type            : Application

AVR Core Clock frequency: 16,000000 MHz

Memory model            : Small

External RAM size       : 0

Data Stack size         : 256

*****************************************************/

#include <mega8.h>

#include <spi.h>

#include <delay.h>

#define T delay_ms(1);//время для вывода разряда индикатора

#define T1 delay_ms(5);//задержка для исключения дребезга кнопки

//активация анодов

#define A6 PORTC.4=1;//6-й разряд-десятки часов

#define A5 PORTC.3=1;//5-й  разряд-часы

#define A4 PORTB.1=1;//4-й разряд справа-десятки минут

#define A3 PORTC.5=1;// 3-ый разряд-минуты

#define A2 PORTD.7=1;//2-й разряд-десятки секунд

#define A1 PORTB.0=1;//1-ый-секунды

//Обнуление анодов

#define Clear PORTC.4=0;PORTC.3=0;PORTB.1=0;PORTC.5=0;PORTD.7=0;PORTB.0=0;

 

unsigned char sek,dsek,min,dmin,ch,dch;//индикатор

unsigned char SPI_sek=0,SPI_min=7,SPI_ch=14;//начальная активация времени 

unsigned char ch_b=15,min_b=15;//начальная активация будильника

//массив кодов чисел от 0 до 9 для 7-и сегментного индикатора(16-0,117-1 и т.д.)

char S[10] ={16,117,9,65,100,66,2,113,0,64};//код символа 0-9 (См.Таблицу)

 

int adc_data;   

int Regim;

char val=0;

interrupt [ADC_INT] void adc_isr(void)

{

  adc_data=ADCW;

 

}

 

void out(unsigned char t)

{

  PORTB.2=0;                    //устанавливаем SS в ноль, начало передачи

  SPDR=t;                       //отправляем данные

  while(!(SPSR & (1<<SPIF)));   //ожидание пока, следующий не отправиться пакет

  PORTB.2=1;                    //устанавливаем SS в единицу, конец передачи

}

 

interrupt [TIM1_COMPA] void timer1_compa_isr(void)

{

 

 

  SPI_sek++;

  if(SPI_sek>59)         {SPI_sek=0;SPI_min++;}

  if(SPI_min>59)         {SPI_min=0;SPI_ch++;}

  if(SPI_ch>23)          {SPI_ch=0;}

 

 //SPI

  out(SPI_ch);out(SPI_min);out(SPI_sek);

  out(ch_b);out(min_b);

 

  ADCSRA.ADSC=1; //пуск АЦП

  while(!ADCSRA.ADIF){}

  Regim=adc_data;

  if(Regim<=50)val=0;

  if((Regim>50)  && (Regim<=100))val=1;

  if((Regim>100) && (Regim<=150))val=2;

  if((Regim>150) && (Regim<=200))val=3;

  if((Regim>200) && (Regim<=250))val=4;

  if((Regim>250) && (Regim<=300))val=5;

  if((Regim>300) && (Regim<=350))val=6;

  if((Regim>350) && (Regim<=400))val=7;

  if((Regim>400) && (Regim<=450))val=8;

  if((Regim>450) && (Regim<=500))val=9;

  if((Regim>500) && (Regim<=550))val=10;

  if((Regim>550) && (Regim<=600))val=11;

  if((Regim>600) && (Regim<=650))val=12;

  if((Regim>650) && (Regim<=700))val=13;

  if((Regim>700) && (Regim<=750))val=14;

  if((Regim>750) && (Regim<=800))val=15;

  if((Regim>800) && (Regim<=850))val=16;

  if((Regim>850) && (Regim<=900))val=17;

  if((Regim>900) && (Regim<=950))val=18;

  if((Regim>950) && (Regim<=1023))val=19;

  //SPI

  out(val);

 

  //индикатор

  dch=SPI_ch/10;   ch  = SPI_ch%10;

  dmin=SPI_min/10; min = SPI_min%10;

  dsek=SPI_sek/10; sek = SPI_sek%10;

 

}

 

 

void main(void)

{

  //начальная активация анодов

  DDRC.4=DDRC.3=DDRB.1=DDRC.5=DDRD.7=DDRB.0=1;

  Clear

  //начальная активация сегментов

  DDRD=0xFF;PORTD=0x7F;

  //активация кнопки внутренним сопротивлением

  DDRC.1=0;PORTC.1=1;

  //Перевод анодов А1(PB0) и А4(PB1) в 0,вывод SS-M(PB2) в 0(режим мастера) 

  DDRB=0x07;PORTB=0x00 ; 

  //При SPI не программирование!!! PORTB.3(MOSI) и PORTB.5(SCK) должны быть активны

  DDRB.3=1;DDRB.5=1;

 

// Timer/Counter 1 initialization

// Clock source: System Clock

// Clock value: 15,625 kHz

// Mode: CTC top=OCR1A

// OC1A output: Discon.

// OC1B output: Discon.

// Noise Canceler: Off

// Input Capture on Falling Edge

// Timer1 Overflow Interrupt: Off

// Input Capture Interrupt: Off

// Compare A Match Interrupt: On

// Compare B Match Interrupt: Off

TCCR1B=0x0D;

OCR1AH=0x3D;

//Корректировка счётчика OCR1AL под реальное время часов смартфона

OCR1AL=0x0C;//0x0B,0x0A,0x09

// Timer(s)/Counter(s) Interrupt(s) initialization

TIMSK=0x10;

 

// SPI initialization

// SPI Type: Master

// SPI Clock Rate: 125,000 kHz

// SPI Clock Phase: Cycle Half

// SPI Clock Polarity: Low

// SPI Data Order: MSB First

SPCR=0x57;

PORTB.2=0;

//Настройка АЦП

//Разрешение АЦП|Разрешить прерывание от компаратора|Коэф.дел=128

ADCSRA.ADEN=1;

ADCSRA.ADIE=1;;

ADCSRA.ADPS0=ADCSRA.ADPS1=ADCSRA.ADPS2=1;

//источник опорного напряжения - питание

ADMUX.REFS1=0;

ADMUX.REFS0=1;

//выбор 2-го АЦП

ADMUX.MUX0=0;

ADMUX.MUX1=1;

 

// Global enable interrupts

#asm("sei")

 

while (1)

 {

 

  switch (val)

   {

    //корректировка времени

    case 1:while (!PINC.1){T1 if(PINC.1) SPI_min++;SPI_sek=0; if(min>59) min=0;} break;

    case 2:while (!PINC.1){T1 if(PINC.1) SPI_min--;SPI_sek=0;}break;

    case 3:while (!PINC.1){T1 if(PINC.1) SPI_ch++;SPI_sek=0;  if(ch>23)  ch=0;}  break;

    case 4:while (!PINC.1){T1 if(PINC.1) SPI_ch--;SPI_sek=0;} break;

   

    //корректировка будильника

    case 5:while (!PINC.1){T1 if(PINC.1) min_b++; if(min>59) min=0;} break;

    case 6:while (!PINC.1){T1 if(PINC.1) min_b--;}break;

    case 7:while (!PINC.1){T1 if(PINC.1) ch_b++;  if(ch>23)  ch=0;}  break;

    case 8:while (!PINC.1){T1 if(PINC.1) ch_b--;} break;

   }         

 

   PORTD=S[sek];  A1 T Clear

   PORTD=S[dsek]; A2 T Clear

   PORTD=S[min];  A3 T Clear

   PORTD=S[dmin]; A4 T Clear

   PORTD=S[ch];   A5 T Clear

   PORTD=S[dch];  A6 T Clear 

  

 

 

 

 }

}

Приложение 2. Полный текст программы для клиента

//Раскомментируйте для программной реализации шины I2C:

#define pin_SW_SDA 5// Назначение любого вывода Arduino для работы в качестве линии SDA программной шины I2C.

#define pin_SW_SCL 6

#include <SoftwareSerial.h>

#include <DFPlayer_Mini_Mp3.h>

#include <iarduino_OLED_txt.h>

iarduino_OLED_txt myOLED(0x78);// Объявляем объект myOLED

extern uint8_t MediumFontRus[];//шрифт

#include <SPI.h>

#define F_CPU 16000000UL

byte  Vcc_0 = 2;// Контакт питания LED

byte sek=0,_min=0,ch=0;//приём от мастера текущего времени 

byte Regim;//индикация режима   

unsigned int time_0=0,time_tek=0;//начальный отсчёт и текущее время для ЗАРЯДКИ и ЗАНЯТИЙ

byte ch_b=10,_min_b=10;//будильник часы/минуты

byte prAcadem=0;

byte pr_utro=0;//если >0 - старт гимнастике

 

void setup()

 

{

   pinMode(Vcc_0, OUTPUT);//переключение вывода в режим «выход» для питания LED

   // SPI initialization

   // SPI Type: Slave

   // SPI Clock Rate: 125,000 kHz

   // SPI Clock Phase: Cycle Half

   // SPI Clock Polarity: Low

   // SPI Data Order: MSB First

   SPCR=0x47;//SPI включено SPCR=0x07;SPI выключено

   Serial.begin(9600);

   myOLED.begin(); // Инициируем работу с дисплеем.

   myOLED.setFont(MediumFontRus);                       

   mp3_set_serial (Serial);// Инициируем работу с DFPlayer-mini

   mp3_set_volume (25);

}

 

void loop()

{

    //приём данных от мастера

    ch   =  SPI_SlaveReceive();

    _min = SPI_SlaveReceive();

    sek  = SPI_SlaveReceive();

    ch_b   =  SPI_SlaveReceive();

    _min_b = SPI_SlaveReceive();

    Regim = SPI_SlaveReceive();

   //озвучивание времени в период 8-32 часов

   zwuk_time();

 

   switch (Regim)

   {

    case 0:myOLED.print(F("МОЛЧАНИЕ   "),0,3);break;//вывод слова МОЛЧАНИЕ на OLED

   // case 0:digitalWrite(Vcc_0, LOW);break;//выключение питания LED не работает!!!

    //К О Р Р Е К Т И Р О В К А  В Р Е М Е Н И

    case 1:myOLED.print(F("  МИНУТЫ++ "),0,3);break;//вывод слова МИНУТЫ++ для корректировки времени  на OLED

    case 2:myOLED.print(F("  МИНУТЫ-- "),0,3);break;//вывод слова МИНУТЫ-- для корректировки времени на OLED

    case 3:myOLED.print(F("   ЧАС++   "),0,3);break;//вывод слова ЧАС++ для корректировки времени на OLED

    case 4:myOLED.print(F("   ЧАС--   "),0,3);break;//вывод слова ЧАС-- для корректировки времени на OLED

    //К О Р Р Е К Т И Р О В К А  Б У Д И Л Ь Н И К А

    case 5:myOLED.print(F(" БУД.МИН++ "),0,3);break;//вывод слова БУД.МИН++ для корректировки будильника на OLED

    case 6:myOLED.print(F(" БУД.МИН-- "),0,3);break;//вывод слова БУД.МИН-- для корректировки будильника на OLED

    case 7:myOLED.print(F(" БУД.ЧАС++ "),0,3);break;//вывод слова БУД.ЧАС++ для корректировки будильника на OLED

    case 8:myOLED.print(F(" БУД.ЧАС-- "),0,3);break;//вывод слова БУД.ЧАС-- для корректировки будильника на OLED

    //вывод слова ЗАРЯДКА для на OLED,запуск программы utro()

    case 9:

    {myOLED.print(F("  ЗАРЯДКА  "),0,3); utro();}break;

    //включение БУДИЛЬНИКА

    case 10:

    {myOLED.print(F("БУДИЛЬНИК"),0,3);if((ch==ch_b) & (_min==_min_b) & (!sek)) mp3_play (1);}break;

    //Начало занятий

    case 11:

    {myOLED.print(F(" АКАДЕМЧАС "),0,3);Academ();} break;

    case 12:{ myOLED.print(F ("  РЕЗЕРВ 1 "),0,3);} break;

    case 13:{ myOLED.print(F ("  РЕЗЕРВ 2 "),0,3);} break;

    case 14:{ myOLED.print(F ("  РЕЗЕРВ 3 "),0,3);} break;

    case 15:{ myOLED.print(F ("  РЕЗЕРВ 4 "),0,3);} break;

    case 16:{ myOLED.print(F ("  РЕЗЕРВ 5 "),0,3);} break;

    case 17:{ myOLED.print(F ("  РЕЗЕРВ 6 "),0,3);} break;

    case 18:{ myOLED.print(F ("  РЕЗЕРВ 7 "),0,3);} break;

    case 19:{ myOLED.print(F ("  РЕЗЕРВ 8 "),0,3);} break;

    default:myOLED.print(F("НЕ ВЫБРАНО"),0,3);

  }

 if((Regim>=5) & (Regim<9) || (Regim==10))

 {

  myOLED.print(ch_b,0,6);myOLED.print(":",22,6);

  myOLED.print(_min_b,30,6);

  //очистка строки OLED при переходе двузначных чисел к однозначным

  if((!_min_b) | (_min_b==10) | (!ch_b) | (ch_b==10)) myOLED.print(F("          "),0,6);

  time_0=0;time_tek=0;pr_utro=0;prAcadem=0;

 } 

 else myOLED.print(F("          "),0,6);

}

//----------------------ПО Д П Р О Г Р А М М Ы------------------

 

//-------Приём байта данных от мастера----------

 byte SPI_SlaveReceive()

 { while(!(SPSR & (1<<SPIF)));

  return SPDR;

 }

 

//----------------------озвучивание времени----------------------

void zwuk_time()

{

   if( (Regim!=0) & (!_min) & (!sek) )

  {

   switch(ch)

   {

    case 8:mp3_play(8);break;

    case 9:mp3_play(9);break;

    case 10:mp3_play(10);break;

    case 11:mp3_play(11);break;

    case 12:mp3_play(12);break;

    case 13:mp3_play(13);break;

    case 14:mp3_play(14);break;

    case 15:mp3_play(15);break;

    case 16:mp3_play(16);break;

    case 17:mp3_play(17);break;

    case 18:mp3_play(18);break;

    case 19:mp3_play(19);break;

    case 20:mp3_play(20);break;

    case 21:mp3_play(21);break;

    case 22:mp3_play(22);break;

    case 23:mp3_play(23);break;

   }

  }

}

//-----------------озвучивание времени утренней зарядки-----------------

void utro ()

{

 

 if ( (Regim!=0) & (!pr_utro) & (!sek) )//разовый режим звучания начала зарядки

 {

  time_0=ch*60+_min;

  time_tek=time_0;

  mp3_play(200);

  pr_utro=1;

 }

 time_tek=ch*60+_min;

 if( (Regim!=0) & (time_tek-time_0)!=0 & (!sek) )

 {

  switch (time_tek-time_0)

  {

    case 1:mp3_play(201);break;case 2:mp3_play(202);break;case 3:mp3_play(203);break;case 4:mp3_play(204);break;

    case 5:mp3_play(205);break;case 6:mp3_play(206);break;case 7:mp3_play(207);break;case 8:mp3_play(208);break;

    case 9:mp3_play(209);break;case 10:mp3_play(210);break;case 11:mp3_play(211);break;case 12:mp3_play(212);break;

    case 13:mp3_play(213);break;case 14:mp3_play(214);break;case 15:mp3_play(215);break;case 16:mp3_play(216);break;

    case 17:mp3_play(217);break;case 18:mp3_play(218);break;case 19:mp3_play(219);break;case 20:mp3_play(220);break;

    case 21:mp3_play(221);break;case 22:mp3_play(222);break;case 23:mp3_play(223);break;case 24:mp3_play(224);break;

    case 25:mp3_play(225);break;case 26:mp3_play(226);break;case 27:mp3_play(227);break;case 28:mp3_play(228);break;

    case 29:mp3_play(229);break;

  } 

 }

}

 

//-----------------АКАДЕМЧАС-озвучивание 6-и занятий и перемен-----------------

void Academ()

{

    //разовый режим звучания начала занятий  

   if ( (Regim!=0) & (!prAcadem)  & (!sek) )

   {

    time_0=ch*60+_min;

    time_tek=time_0;

    mp3_play(300);

    prAcadem=1;

   }

   time_tek=ch*60+_min;

   if( (Regim!=0) & (time_tek-time_0)!=0 & (!sek) )

   {

    switch (time_tek-time_0)

    {

 

      case 45: {mp3_play(301);}break;//занятие 1-e закончилось

      case 60: {mp3_play(302);}break;//начало 2-го занятия

      case 105:{mp3_play(301);}break;//занятие 2-e закончилось

      case 120:{mp3_play(302);}break;//начало 3-го занятия

      case 165:{mp3_play(301);}break;//занятие 3-e закончилось

      case 180:{mp3_play(304);}break;//начало 4-го занятия

      case 225:{mp3_play(301);}break;//занятие 4-e закончилось

      case 240:{mp3_play(305);}break;//начало 5-го занятия

      case 285:{mp3_play(301);}break;//занятие 5-e закончилось

      case 300:{mp3_play(306);}break;//начало 6-го занятия

      case 345:{mp3_play(307);}break;//занятие 6-e закончилось

   }

  }

}

Передняя панель.jpg
Индикатор.jpg
Индикатор.jpg
Таблица.jpg
Часы Схема принципиальная.jpg
Технология прошивки.jpg
Arduino Uno.jpg
Печатная плата клиента и сарвера.jpg
Печатная плата индикатора.jpg
СНС3.jpg
bottom of page