Помогите с созданием таймера обратного отсчета
- Войдите на сайт для отправки комментариев
Вс, 03/11/2013 - 18:32
Здравствуйте, уважаемые форумчане.
Помогите, пожалуйста, со скечтем. Возможно, есть какие- то похожие решения с минимальной переделкой. К сожалению, с программированием и ардуино, в частности, дружу не очень сильно. Аппаратную часть реализую, а вот с программной туго) Нужен таймер с таким функционалом:
Два 7-и сегментных индикатора, одна кнопка. Отсчет только 60 секунд без возможности выбора. Логика работы такая: при нажатии на кнопку начинается предварительный отсчет в 5 секунд со звуковой индикацией, затем, по его истечении, основной в 60 секунд с отображением на индикаторах, после начала предварительного и до конца основного отсчета кнопка должна быть "заблокирована", т.е. никак не влиять идущий отсчет. Так же, в начале и в момент окончания основного отсчета, на какой- либо пин должен посылаться высокий уровень на 200-300мс для управления внешним устройством. После окончания отсчета - звуковой сигнал и блокировка кнопки на 15 секунд. Затем устройство готово к следующему циклу работы. Точность большая не нужна, +/- 1-2 секунды вполне нормально.
В брейн ринг играете, так и скажи.
Проблем как таковых с программированием нет. Но как мы можем тебе помочь,если не известно, что ты там куда напоял? Саму программу писать быстро (30 мин) но ее еще надо отладить. Фальшстарт, плохой контакт в кнопках.... Думаю, что день на отладку положить надо...
Блокировка это никаая не проблема, скорее наоборот сложность. В 90% случаев происходит программный опрос клавиатуры. т.е. Не опросил, не знаешь что там на кнопке происходит. Почему индикаторы 7 сегментные? Мне кажется что это сильно устарело...
Вот рабочий код. Индикаторов у меня нету, поэтому в коде надо заменить заглушки (конкретно будет зависеть от интерфейса индикаторов и его библиотеки).
Параметры лучше в константы вынести, но оно мне лень :)
const int buttonPin = 26; // назначаем пин D26 для кнопки const int ledPin = 13; // назначаем пин D13 для сигнального светодиода const int buzzerPin = 46; // назначаем PWM-пин D46 для пищалки, кроме 3 и 11!!! const int highLevelPin = 30; // назначаем пин D30 для дублирущего светодиода // const int displayPin = 6; // назначаем пины для семисегментого индикатора boolean buttonState = false; // логическая переменная для состояния кнопки void setup() { // инициализация пинов pinMode(buttonPin, INPUT); digitalWrite(buttonPin, HIGH); //включаем внутренний подтягивающий резистор на 20К, чтобы не закоротить пины при нажатии кнопки без обвязки pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); // гасим светодиод pinMode(buzzerPin, OUTPUT); // digitalWrite(buzzerPin, LOW); // затыкаем пищалку pinMode(highLevelPin, OUTPUT); digitalWrite(highLevelPin, LOW); // обнуляем выход на устройство // pinMode(displayPin, OUTPUT); // display.init(); // сюда подставить команду инициализации дисплея // display.show("--"); Serial.begin(9600); // вывод отладочной информации Serial.println("Ready..."); } void loop() { buttonState = !digitalRead(buttonPin); // читаем состояние кнопки и инвертируем его, т.к. у нас включен подтягивающий резистор // Serial.println(buttonState); if (buttonState == true) { // дeйствия при нажатии кнопки Serial.println("Button pressed!"); preStart(); // выполняем условия предстарта sendSignal(); // подаем сигнал на устройство mainStart(); // выполняем условия старта sendSignal(); // подаем сигнал на устройство finish(); // выполняем условия финиша Serial.println("THE END"); } else { // действия, если кнопка не нажата // digitalWrite(ledPin, LOW); } } void preStart() { Serial.println("Prestart..."); // display.show(" "); // очищаем дисплей for (int i = 5; i > 0; i--) { Serial.println(i); // выводим в порт показания отсчета // display.show(i); // выводим на дисплей показания отсчета digitalWrite(ledPin, HIGH); // мигаем светодиодом tone(buzzerPin, 2000, 200); // пищим 200 мс с частотой 2000 Гц delay(800); // ждем еще 0,8 сек digitalWrite(ledPin, LOW); } noTone(buzzerPin); // затыкаем пищалку Serial.println("Done."); } void mainStart() { Serial.println("Main Start!"); digitalWrite(ledPin, HIGH); // включаем светодиод for (int i = 0; i <= 59; i++) { Serial.println(i); // выводим в порт показания отсчета // display.show(i); // выводим на дисплей показания отсчета delay(1000); // ждем 1 сек } digitalWrite(ledPin, LOW);// гасим светодиод Serial.println("Done."); } void finish() { Serial.println("Finish..."); tone(buzzerPin, 2000, 1000); // пищим сигнал об окончании noTone(buzzerPin); // затыкаем пищалку Serial.println("Wait 15 seconds..."); delay(15000); // ничего не делаем 15 сек for (int i = 0; i <= 4; i++) // пищим финальный аккорд { tone(buzzerPin, 3000, 100); delay(200); } noTone(buzzerPin); // затыкаем пищалку // display.show("--"); // закончили задачу, выводим режим готовности к следующему этапу buttonState = false; // устанавливаем исходное состояние кнопки Serial.println("Done."); } void sendSignal() { Serial.println("Send HI to device"); digitalWrite(highLevelPin, HIGH); // подаем высокий уровень на устройство delay(250); // ждем 250 мсек digitalWrite(highLevelPin, LOW); Serial.println("Send LOW to device"); }Думаю, на дребезг кнопки можно не обращать внимания, ибо она после старта все равно блокируется на 75 сек.
А мелькающие индикаторы создают видимость действия и динамику (хотя вместо их можно сделать и световой столб на LED-лентах) ;)
achest, спасибо за ответ.
Нет, это не брейн-ринг) Для брейн- ринга где-то встречал готовый проект. Устройство нужно для подключения к контактам кнопки авто-регистратора для записи минутных видеороликов при нажатии на кнопку. Паять ничего не паял. На макетке сдвоенный 7-и сегментый индикатор с общими катодами. Ардуино Mega1280. Аноды спараллелены посимвольно. На катодах резисторы на 220 Ом или около того. Пробовал нескольо готовых проектов типа кухонного таймера только так и не смог додумать как изменить на нужный мне функционал. 7-и сегментные индикаторы нагляднее да и достать проще нужного цвета и размера.
Tomasina, большое спасибо за помощь.
Завтра обязательно попробую Ваш варант. Сейчас, к сожалению, нет возможности. Индикатор обычный светодиодный 7-и сегментный сдвоенный в общим катодом. Вроде такого http://www.chipdip.ru/product/bl-d56a-21upg/ Т.е. им ни спец. интерфейс ни библиотеки не нужны. Только 7пинов ардуины для управления анодами и 2 пина для катодов.
пример работы с индикатором: http://lucky-byte.livejournal.com/9748.html
Опробовал. работает почти как нужно. Осталось немного "допилить") Думаю, как прицепить индикаторы.
Немного подправил код, вот что получилось.
const int buttonPin = 26; // назначаем пин D26 для кнопки const int ledPin = 10; // назначаем пин D13 для сигнального светодиода const int buzzerPin = 46; // назначаем PWM-пин D46 для пищалки, кроме 3 и 11!!! const int highLevelPin = 30; // назначаем пин D30 для дублирущего светодиода // const int displayPin = 6; // назначаем пины для семисегментого индикатора boolean buttonState = false; // логическая переменная для состояния кнопки void setup() { // инициализация пинов pinMode(buttonPin, INPUT); digitalWrite(buttonPin, HIGH); //включаем внутренний подтягивающий резистор на 20К, чтобы не закоротить пины при нажатии кнопки без обвязки pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); // гасим светодиод pinMode(buzzerPin, OUTPUT); // digitalWrite(buzzerPin, LOW); // затыкаем пищалку pinMode(highLevelPin, OUTPUT); digitalWrite(highLevelPin, LOW); // обнуляем выход на устройство // pinMode(displayPin, OUTPUT); // display.init(); // сюда подставить команду инициализации дисплея // display.show("--"); Serial.begin(9600); // вывод отладочной информации Serial.println("Ready..."); } void loop() { buttonState = !digitalRead(buttonPin); // читаем состояние кнопки и инвертируем его, т.к. у нас включен подтягивающий резистор // Serial.println(buttonState); if (buttonState == true) { // дeйствия при нажатии кнопки Serial.println("Button pressed!"); preStart(); // выполняем условия предстарта sendSignal(); // подаем сигнал на устройство mainStart(); // выполняем условия старта sendSignal(); // подаем сигнал на устройство finish(); // выполняем условия финиша Serial.println("THE END"); } else { // действия, если кнопка не нажата // digitalWrite(ledPin, LOW); } } void preStart() { Serial.println("Prestart..."); // display.show(" "); // очищаем дисплей for (int i = 4; i > 0; i--) { digitalWrite(ledPin, HIGH); // мигаем светодиодом Serial.println(i); // выводим в порт показания отсчета // display.show(i); // выводим на дисплей показания отсчета tone(buzzerPin, 2000, 200); // пищим 200 мс с частотой 2000 Гц delay(900); // ждем еще 0,8 сек digitalWrite(ledPin, LOW); } tone(buzzerPin, 1000, 200); //низкий тон delay(900); // ждем еще 0,8 сек noTone(buzzerPin); // затыкаем пищалку Serial.println("Done."); } void mainStart() { Serial.println("Main Start!"); digitalWrite(ledPin, HIGH); // включаем светодиод for (int i = 10; i >= 0; i--) { Serial.println(i); // выводим в порт показания отсчета // display.show(i); // выводим на дисплей показания отсчета delay(1000); // ждем 1 сек } digitalWrite(ledPin, LOW);// гасим светодиод Serial.println("Done."); } void finish() { Serial.println("Finish..."); for (int i = 0; i <= 4; i++) // пищим финальный аккорд { tone(buzzerPin, 3000, 100); delay(200); } noTone(buzzerPin); // затыкаем пищалку Serial.println("Wait 15 seconds..."); delay(5000); // ничего не делаем 15 сек // display.show("--"); // закончили задачу, выводим режим готовности к следующему этапу buttonState = false; // устанавливаем исходное состояние кнопки Serial.println("Done."); } void sendSignal() { Serial.println("Send HI to device"); digitalWrite(highLevelPin, HIGH); // подаем высокий уровень на устройство delay(250); // ждем 250 мсек digitalWrite(highLevelPin, LOW); Serial.println("Send LOW to device"); }Временные промежутки для теста выставил пока поменьше. В блоке void preStart() почему то должен мигать светодиод ledPin но он горит постоянно.
проверь, что светодиод подключен к пину D10.
200+900, это уже больше секунды получается, за цикл preStart набежит 0,5 секунды, не учтенных в ТЗ :)
Да, знаю что больше выходит, просто слишком быстро как то получается) Мне не критично +/- 1 секунда. Светодиод точно на 10 порту. Пробовал разные порты. Почему то не мигает.
Сделал так, замигало:
void preStart() { Serial.println("Prestart..."); // display.show(" "); // очищаем дисплей for (int i = 4; i > 0; i--) { digitalWrite(ledPin, HIGH); // мигаем светодиодом Serial.println(i); // выводим в порт показания отсчета // display.show(i); // выводим на дисплей показания отсчета tone(buzzerPin, 2000, 200); // пищим 200 мс с частотой 2000 Гц delay(450); // ждем еще 0,8 сек digitalWrite(ledPin, LOW); delay(450); } digitalWrite(ledPin, HIGH); tone(buzzerPin, 1000, 200); //низкий тон delay(450); // ждем еще 0,8 сек digitalWrite(ledPin, LOW); delay(450); noTone(buzzerPin); // затыкаем пищалку Serial.println("Done."); }вожможно, светодиод дохлый или подключен в обратной плоярности. Ибо на моей плате он моргает :)
Светодиод рабочий. Пробовал несколько разных, пробовал другой пин. Пробовал в обратной полярности- вообще не горит)
Понял, почему не мигает светодиод. Странно, что у вас работает. Получается, что в цикле он включается затем, через 900мс он выключается и сразу включается. Т.е. не горит он долю секунды.
Проблема теперь в том, как прицепить индикатор. Т.к. таймер реализован через deleay(), то хз как делать динамическую индикацию. Завтра, если найду в продаже, буду пробовать через сдвиговые регистры 74HC595 как тут http://greenoakst.blogspot.ru/2012/01/arduino-7-spi.html
Вот что наваял. Проблема тепереь в том, что единицы секунд отображаются нормально а десятки вспыхивают очень быстро в начале отсчета. Как сделать нормальное отображение десятков?
const int buttonPin = 26; // назначаем пин D26 для кнопки const int ledPin = 42; // назначаем пин D13 для сигнального светодиода const int buzzerPin = 46; // назначаем PWM-пин D46 для пищалки, кроме 3 и 11!!! const int highLevelPin = 30; // назначаем пин D30 для дублирущего светодиода // const int displayPin = 6; // назначаем пины для семисегментого индикатора boolean buttonState = false; // логическая переменная для состояния кнопки #include <SPI.h> enum { reg = 53 }; void setup() { SPI.begin(); pinMode(reg, OUTPUT); // инициализация пинов pinMode(buttonPin, INPUT); digitalWrite(buttonPin, HIGH); //включаем внутренний подтягивающий резистор на 20К, чтобы не закоротить пины при нажатии кнопки без обвязки pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); // гасим светодиод pinMode(buzzerPin, OUTPUT); // digitalWrite(buzzerPin, LOW); // затыкаем пищалку pinMode(highLevelPin, OUTPUT); digitalWrite(highLevelPin, LOW); // обнуляем выход на устройство // pinMode(displayPin, OUTPUT); // display.init(); // сюда подставить команду инициализации дисплея // display.show("--"); Serial.begin(9600); // вывод отладочной информации Serial.println("Ready..."); } int hundreds=0, tens=0, ones=0; int delayTime=7; static uint8_t digit[11] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF}; static uint8_t pos[3]= {0xE7,0xEB,0xF3}; void loop() { buttonState = !digitalRead(buttonPin); // читаем состояние кнопки и инвертируем его, т.к. у нас включен подтягивающий резистор // Serial.println(buttonState); if (buttonState == true) { // дeйствия при нажатии кнопки Serial.println("Button pressed!"); preStart(); // выполняем условия предстарта sendSignal(); // подаем сигнал на устройство mainStart(); // выполняем условия старта sendSignal(); // подаем сигнал на устройство finish(); // выполняем условия финиша Serial.println("THE END"); } else { // действия, если кнопка не нажата // digitalWrite(ledPin, LOW); } } void preStart() { Serial.println("Prestart..."); // display.show(" "); // очищаем дисплей for (int i = 4; i > 0; i--) { digitalWrite(ledPin, HIGH); // мигаем светодиодом Serial.println(i); // выводим в порт показания отсчета // display.show(i); // выводим на дисплей показания отсчета tone(buzzerPin, 2000, 200); // пищим 200 мс с частотой 2000 Гц delay(450); // ждем еще 0,8 сек digitalWrite(ledPin, LOW); delay(450); } digitalWrite(ledPin, HIGH); tone(buzzerPin, 1000, 200); //низкий тон delay(450); // ждем еще 0,8 сек digitalWrite(ledPin, LOW); delay(450); noTone(buzzerPin); // затыкаем пищалку Serial.println("Done."); } void mainStart() { Serial.println("Main Start!"); for (int i = 60; i >= 0; i--) { hundreds=i/100; tens=(i-hundreds*100)/10; ones=i-hundreds*100-tens*10; digitalWrite(reg, LOW); SPI.transfer(digit[tens]); SPI.transfer(pos[1]); digitalWrite(reg, HIGH); delay(delayTime); digitalWrite(reg, LOW); SPI.transfer(digit[ones]); SPI.transfer(pos[2]); digitalWrite(reg, HIGH); delay(delayTime); digitalWrite(ledPin, HIGH); // мигаем светодиодом Serial.println("SEC"); // выводим в порт показания отсчета Serial.println(i); // display.show(i); // выводим на дисплей показания отсчета delay(1000); // ждем 1 сек digitalWrite(ledPin, LOW); } Serial.println("Done."); } void finish() { Serial.println("Finish..."); for (int i = 0; i <= 4; i++) // пищим финальный аккорд { tone(buzzerPin, 3000, 100); delay(200); } noTone(buzzerPin); // затыкаем пищалку Serial.println("Wait 15 seconds..."); delay(5000); // ничего не делаем 15 сек // display.show("--"); // закончили задачу, выводим режим готовности к следующему этапу buttonState = false; // устанавливаем исходное состояние кнопки Serial.println("Done."); } void sendSignal() { Serial.println("Send HI to device"); digitalWrite(highLevelPin, HIGH); // подаем высокий уровень на устройство delay(250); // ждем 250 мсек digitalWrite(highLevelPin, LOW); Serial.println("Send LOW to device"); }В итоге, заставил этого Франкенштейна работать. Отказался от динамической индикации, подключил к двум 74HC595 катоды от каждого разряда, общие аноды повесил на +. Через SPI посылаю байт с десятками и байт с единицами. Мягко говоря, не самый элегантный код вышел, но оно работает, так как нужно)
Если reg=53 для обоих регистров, т. е. из первого с выхода Q7' (вывод 8) идет провод на DS второго (вывод 14), тогда понятно почему промигивает старшая цифра. Некоторое время на ней находится информация с младшей цифры, потом продвигается дальше (в этот момент становится нормально). Нужно завести 2 переменных reg, и каждую цифру посылать отдельно. Иначе (соединение регистров в цепь и один общий вывод защёлки) визуально воспринимается как промигивание во время изменения цифр. У меня была такая хрень когда делал трёхзначный индикатор из рассыпухи (некогда было ждать с Китая TM1637).
Решается так:
- вход данных (MOSI, вывод 14) второго регистра (того что для единиц) отцепить с переноса первого, соединить на 14 первого регистра, т. е. параллельно.
- вход защёлки второго регистра отцепить от первого, завести на отдельный провод, допустим 52 или что там рядом с 53.
Как выводить:
где:
MSG_TENS - десятки, MSG_ONES - единицы; 52 - вывод защёлки десяток (первый регистр), 53 - вывод защёлки единиц (второй регистр).
Это ничего не меняет. Для динамической индикации мне нужно было быстро переключать аноды для вывода десятков и единиц. Т.е. фактически в один момент времени горит либо десяток либо единица. Но, в силу инерции человеческого зрения и высокой скорости переключения, картинка воспринимается без миганий. Проблема в том, что в счетчике используется delay(), из-за которого быстрого переключения не получить. В итоге, сделал так:
Отказался от динамической индикации, соединил со 2-м сдвиговым регистром 2-е катоды сегментов. По SPI сначала посылается байт десятка потом байт единицы. Т.к. регистр 8-и битовый, 2-й байт проходит через него дальше, 1-й остается. Может быть, до меня дойдет, как все сделать без delay()-ев. А пока, пусть будет такой велосипед)
del