Предыстория. Неделю назад насмотрелся роликов в ютубе, под впечатлением купил ардиуну и еще всякого. Решил попрактиковаться, для начала на часах. программист из меня не очень, но чуть-чуть умею. Имеется Arduino Uno, экран нокиа 5110, пара кнопок, спикер. Как это работает. ардуина считает время. 1-я кнопка переводит в режим установок часов, минут, часов/минут для срабатывания будильника, 2-я кнопка прибавляет в зависимости от режима +1 к минуте или часу. Когда часы/минуты совпадают с часами и минутами установлеными для будильника из пищит пищалка. ну экран все это дело показывает. Проблема в том что пока пищит пищалка, ардуина время, как только доиграла мелодию + 1 сек. Как хочется: хочется чтобы и время считала и пищалка пищала. Как-то наверное нужно распаралелить процессы? Прошу помощи. Возможно ли? Код (Text): #include <Adafruit_GFX.h> #include <Adafruit_PCD8544.h> Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 7, 6); #include "pitches.h" // notes in the melody: int melody[] = { NOTE_G5, NOTE_G5, NOTE_G5, NOTE_DS5, NOTE_AS5, NOTE_G5, NOTE_DS5, NOTE_AS5, NOTE_G5}; // note durations: 4 = quarter note, 8 = eighth note, etc.: int noteDurations[] = { 3, 3, 3, 6, 5, 4, 6, 5, 4}; const int buzzerPin = 11; int s=0; int ledPin = 13; int pinSet = 9; int pinM = 8; int k = 0; boolean lastButton = LOW; boolean currentButton = LOW; boolean lastM; boolean currentButtonMin; boolean ledOn = false; boolean onM = false; unsigned long time=0; byte S=0; byte prS = 0; byte M=0; byte H=0; byte AlarmH=0; byte AlarmM=0; boolean debounce(boolean last, int Pin) { boolean current = digitalRead(Pin); if (last!=current) { delay(5); current =digitalRead(Pin); } return current; } void Alarm () { for (int thisNote = 0; thisNote < 10; thisNote++) { int noteDuration = 1000/noteDurations[thisNote]; tone(11, melody[thisNote],noteDuration); int pauseBetweenNotes = noteDuration * 1.50; delay(pauseBetweenNotes); // stop the tone playing: noTone(11); } } void setup() { pinMode(pinSet, INPUT); pinMode(ledPin, OUTPUT); pinMode(buzzerPin, OUTPUT); Serial.begin(9600); display.begin(); // Очищаем дисплей display.clearDisplay(); display.display(); // Устанавливаем контраст display.setContrast(60); delay(1000); } char vremya (byte H, byte M, byte S) { if (prS < S || prS > S) { display.clearDisplay(); display.display(); display.setCursor(0, 0); // Устанавливаем цвет текста display.setTextColor(BLACK); // Устанавливаем размер текста display.setTextSize(1.8); // Выводим текст if (H < 10) display.write('0'); display.print(H); display.write(':'); if (M < 10) display.write('0'); display.print(M); display.write(':'); if (S < 10) display.write('0'); display.print(S); display.display(); //delay(1000); prS=S; } } void loop() { if ( H==AlarmH && M==AlarmM ) { Alarm(); } currentButton = debounce(lastButton, pinSet); if (lastButton == LOW && currentButton==HIGH) { if ( k==5 ) k=0; k++; if ( k==1 || k==5 ) ledOn=!ledOn; } lastButton = currentButton; digitalWrite(ledPin,ledOn); if (ledOn == HIGH && k == 1) { display.setCursor(0, 20); display.setTextSize(1); display.print("set minit"); display.display(); currentButtonMin = debounce(lastButton,pinM); if ( currentButtonMin == HIGH && lastM == LOW ) { M++; onM=!onM; } digitalWrite(pinM, onM); lastM = currentButtonMin; } if (ledOn == HIGH && k == 2) { display.setCursor(0, 20); display.setTextSize(1); display.print("set hour"); display.display(); currentButtonMin = debounce(lastButton,pinM); if ( currentButtonMin == HIGH && lastM == LOW ) { H++; onM=!onM; } digitalWrite(pinM, onM); lastM = currentButtonMin; } if (ledOn == HIGH && k==3) { display.setCursor(0, 20); display.setTextSize(1); display.println("set alarm hour:"); display.println(AlarmH); display.display(); currentButtonMin = debounce(lastButton,pinM); if (currentButtonMin == HIGH && lastM ==LOW) { AlarmH++; onM=!onM; } digitalWrite(pinM, onM); lastM = currentButtonMin; } if (ledOn == HIGH && k==4) { display.setCursor(0, 20); display.setTextSize(1); display.println("set alarm minit"); display.println(AlarmM); display.display(); currentButtonMin = debounce(lastButton,pinM); if (currentButtonMin == HIGH && lastM ==LOW) { AlarmM++; onM=!onM; } digitalWrite(pinM, onM); lastM = currentButtonMin; } if ( millis()-time>1000) { S++; time=millis(); if ( S > 59 ) { M++; S=0; } if ( M >= 59 ) { H++; M = 0; } if ( H > 23) H=0; } if (k!=3 || k!=4) vremya(H, M, S); }
Процесс вы не распаралелите, это все же простой микроконтроллер а не многоядерный процессор с операционной системой берущей на себя такие заботы. МК способен в один момент времени делать только одну единственную задачу, многозадачность на одноядерных процессорах это лишь иллюзия, там просто ОС очень быстро переключает процессы давая каждому поработать чуть-чуть в итоге складываться ощущение что все процессы работает одновременно. На многоядерных, другое дело там есть возможность распределения заданий по ядрам что делает работу процессов реально одновременной. Но вы можете просто возложить вопрос отсчета времени на модуль реального времени, таким образом пока ваша дуня делает что то, модуль реального времени занимается своим делом ничего не ведая о других тайнах и загадках вселенной Более того модулю реального времени вещь весьма и весьма полезная если вы решили иметь дело со временем.
Вы можете использовать таймер. Функция tone() в Arduino использует второй таймер. Всякие delay() и millis() используют нулевой таймер. Поэтому у вас есть возможность использовать первый таймер так как он свободен (но будет занят если вдруг решите использовать библиотеку для работы с серводвигателями - его там используют для задания хорошего ШИМ т.к. этот таймер 16 битный а те два 8 битные). Почитайте как работают таймера на AVR (в Arduino UNO стоит микроконтроллер ATmega328 и в нем 3 таймера в железе, вам нужен первый). Таймеры они как параллельные процессоры - считают пока ваш код работает. Поэтому можно настроить таймер чтобы он генерировал прерывание например раз в секунду.
Ничего не получается сделать. Почитал, нашел библиотеку TimerOne. В голове не просветлело. Витя выручай, дай еще один толчок.
Даю толчок: чтобы организовать псевдопараллельность, надо обработку внешних событий организовать не в цикле loop(), а через прерывания. http://arduino.cc/en/Reference/AttachInterrupt - вот тут описание простое и пример.
kaoplx: Что бы понять что вам предложили вы должны быть знакомы с прерываниями. Если коротко то выглядит это так. Таймер будет вызывать прерывание каждую секунду(если установить на секунду), к этому событию будет привязана какая то функция, как только возникает прерывание от таймере МК останавливает выполнение той программы которую он выполняет и переходит к выполнению той функции которая была привязана к таймеру. После чего вернется к выполнению того чем был занят до прерывания от таймера. В итоге опять таки распаралеливания нет.. есть просто переключение... Работа с прерываниями уже требует понятия о много поточном программировании, чтобы потом если вдруг вы будите использовать глобальные переменные не начать удивляться почему там не те данные что вы ожидали. Более того, данная схема отсчета времени будет накапливать ошибки, ибо на выполнение вашей функции по плюсованию секунды куда-то атм потребуется время, пусть мизерное но время, в итоге каждую секунду будет накапливаться ошибка. (хотя оно настолько мизерное что ошибка в 1 секунду наверно будет оооооооочень долго накапливаться... но будет)
Во-первых, я совсем другое предложил (прерывания по изменению состояния пинов; в данном случае - из-за нажатия на кнопки). Во-вторых, уж извините, рассуждения про "распараллеливания нет", "накапливать ошибки" и т.п. чуть менее правильны, чем неправильны вовсе.
YVN: На самом деле мое сообщение к вашему отношения не имеет Ибо вы его добавили пока я писал свое, посему мое сообщение относится к более раним сообщениям
Все ребят, получилось. Сделал следующим образом. Использовал библиотеку TimerOne, которая позволяет работать с первым таймером. Используя его завел вторые часы. Когда время будильника совпадает со временем первых часов играет мелодия. Пока играет мелодия первые часы тупят, поэтому сравниваю минуту будильника с минутой по вторым часам. как только они не совпадают первым часам присваиваю значения вторых часов, таким образом синхронизировав их. Спасибо проблема решена. На всякий случай выложу код вдруг кому пригодится))) хотя вряд-ли))) Код (Text): #include <TimerOne.h> #include <Adafruit_GFX.h> #include <Adafruit_PCD8544.h> Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 7, 6); #include "pitches.h" // notes in the melody: int melody[] = { NOTE_G5, NOTE_G5, NOTE_G5, NOTE_DS5, NOTE_AS5, NOTE_G5, NOTE_DS5, NOTE_AS5, NOTE_G5}; // note durations: 4 = quarter note, 8 = eighth note, etc.: int noteDurations[] = { 3, 3, 3, 6, 5, 4, 6, 5, 4}; const int buzzerPin = 11; int s=0; int ledPin = 13; int pinSet = 9; int pinM = 8; int k; boolean lastButton = LOW; boolean currentButton = LOW; boolean lastM; boolean currentButtonMin; boolean ledOn = false; boolean onM = false; unsigned long time=0; byte S=0; byte prS = 0; byte M=0; byte H=0; byte Min=0; byte Hour=0; byte Sek=0; byte AlarmH=0; byte AlarmM=0; //Состояние лампочки boolean debounce(boolean last, int Pin) { boolean current = digitalRead(Pin); if (last!=current) { delay(5); current =digitalRead(Pin); } return current; } //Рингтон Рингтон Рингтон Рингтон Рингтон Рингтон Рингтон Рингтон Рингтон Рингтон Рингтон Рингтон Рингтон void Alarm () { for (int thisNote = 0; thisNote < 10; thisNote++) { int noteDuration = 1000/noteDurations[thisNote]; tone(11, melody[thisNote],noteDuration); int pauseBetweenNotes = noteDuration * 1.50; delay(pauseBetweenNotes); // stop the tone playing: noTone(11); } } // Вторые часы эталонные Вторые часы эталонные Вторые часы эталонные Вторые часы эталонные Вторые часы эталонные void tm2() { Sek++; if(Sek>7) { Sek=0; Min++; if (Min>59) { Hour++; M=0; } if (Hour>23) Hour=0; } } void setup() { pinMode(pinSet, INPUT); pinMode(ledPin, OUTPUT); pinMode(buzzerPin, OUTPUT); Serial.begin(9600); display.begin(); // Очищаем дисплей display.clearDisplay(); display.display(); // Устанавливаем контраст display.setContrast(60); delay(1000); Timer1.initialize(); Timer1.attachInterrupt(tm2); } char vremya (byte H, byte M, byte S) { if (prS < S || prS > S) { display.clearDisplay(); display.display(); display.setCursor(0, 0); // Устанавливаем цвет текста display.setTextColor(BLACK); // Устанавливаем размер текста display.setTextSize(1.8); // Выводим текст if (H < 10) display.write('0'); display.print(H); display.write(':'); if (M < 10) display.write('0'); display.print(M); display.write(':'); if (S < 10) display.write('0'); display.print(S); display.display(); //delay(1000); prS=S; } } void loop() { if ( millis()-time>1000) { S++; time=millis(); if ( S > 7 ) { M++; S=0; } if ( M > 59 ) { H++; M = 0; } if ( H > 23) H=0; } if (k!=3 || k!=4) vremya(H, M, S); currentButton = debounce(lastButton, pinSet); if (lastButton == LOW && currentButton==HIGH) { if ( k==5 ) k=0; k++; if ( k==1 || k==5 ) ledOn=!ledOn; } lastButton = currentButton; digitalWrite(ledPin,ledOn); if (ledOn == HIGH && k == 1) { display.setCursor(0, 20); display.setTextSize(1); display.print("set minit"); display.display(); currentButtonMin = debounce(lastButton,pinM); if ( currentButtonMin == HIGH && lastM == LOW ) { M++; onM=!onM; } digitalWrite(pinM, onM); lastM = currentButtonMin; } if (ledOn == HIGH && k == 2) { display.setCursor(0, 20); display.setTextSize(1); display.print("set hour"); display.display(); currentButtonMin = debounce(lastButton,pinM); if ( currentButtonMin == HIGH && lastM == LOW ) { H++; onM=!onM; } digitalWrite(pinM, onM); lastM = currentButtonMin; } if (ledOn == HIGH && k==3) { display.setCursor(0, 20); display.setTextSize(1); display.println("set alarm hour:"); display.println(AlarmH); display.display(); currentButtonMin = debounce(lastButton,pinM); if (currentButtonMin == HIGH && lastM ==LOW) { AlarmH++; onM=!onM; } digitalWrite(pinM, onM); lastM = currentButtonMin; } if (ledOn == HIGH && k==4) { display.setCursor(0, 20); display.setTextSize(1); display.println("set alarm minit"); display.println(AlarmM); display.display(); currentButtonMin = debounce(lastButton,pinM); if (currentButtonMin == HIGH && lastM ==LOW) { AlarmM++; onM=!onM; } digitalWrite(pinM, onM); lastM = currentButtonMin; } if ( H==AlarmH && M==AlarmM && ledOn==LOW) { do { Alarm(); } while (Min==AlarmM); M++; H=Hour; M=Min; S=Sek; } }
Сначала чтобы "прочувствовать" тренился на лампочке. На всяк случай мож кто-то озаботится подобным.) Код (Text): #include <TimerOne.h> byte S=0; byte M=0; byte H=0; byte Min=0; byte Hour=0; unsigned long time=0; byte Sek; int ledPin=9; void setup() { pinMode(9, OUTPUT); Serial.begin(9600); Timer1.initialize(); Timer1.attachInterrupt(tm2); } void tm2() { Sek++; if(Sek>7) { Sek=0; Min++; if (Min>59) { Hour++; M=0; } if (Hour>23) { Hour=0; } } Serial.print("TM2="); Serial.print(Hour); Serial.print(":"); Serial.print(Min); Serial.print(":"); Serial.println(Sek); } void printer() { Serial.print(H); Serial.print(":"); Serial.print(M); Serial.print(":"); Serial.println(S); } void loop() { if ( millis()-time>1000) { S++; time = millis(); if ( S > 7 ) { M++; S=0; } if ( M > 59 ) { H++; M = 0; } if ( H > 23) H=0; printer(); } if (M==1) { do { digitalWrite(9, !digitalRead(9)); delay(250); } while (1==Min); M++; S=Sek; } }
Почитайте внимательно еще вот эти 2 статьи http://robocraft.ru/blog/985.html http://robocraft.ru/blog/981.html в комментариях еще приложена правильная библиотека http://yadi.sk/d/ulVShcC-3mFTK