Обратный отсчет по нажатию кнопки
- Войдите на сайт для отправки комментариев
Пнд, 07/11/2016 - 11:16
Добрый день!
Только начинаю изучать Arduino и прошу Вас дать советы по написанию кода.
Программа состоит из двух частей:
1) Необходимо подсчитать количество нажатий на кнопку от 0 до 9 и вывести на 7-сегментный индикатор, использую сдвиговый регистр для экономии выходов (такой пример есть разобранный и по нему вроде все понятно, код приведен ниже)
2) Другая кнопка должна запускать обратный отсчет с количества нажатий до нуля и на каждой секунде издавать короткий сигнал, а при окончании долгий сигнал и должен загореться светодиод.
Подскажите, пожалуйста, какой цикл лучше использовать при обратном отсчете for или do..while?
И как написать код, чтобы сдвиговый регистр отсчитывал строго до нуля и не уходил в облать отрицательных чисел?
Заранее спасибо.
Если подобное ранее обсуждалось, то прошу дать ссылку.
#define DATA_PIN 13 // пин данных (англ. data)
#define LATCH_PIN 12 // пин строба (англ. latch)
#define CLOCK_PIN 11 // пин такта (англ. clock)
#define BUTTON_PIN 10
int clicks = 0;
boolean buttonWasUp = true;
byte segments[10] = {
0b01111101, 0b00100100, 0b01111010, 0b01110110, 0b00100111,
0b01010111, 0b01011111, 0b01100100, 0b01111111, 0b01110111
};
void setup()
{
pinMode(DATA_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
}
void loop()
{
// считаем клики кнопки, как уже делали это раньше
if (buttonWasUp && !digitalRead(BUTTON_PIN)) {
delay(10);
if (!digitalRead(BUTTON_PIN))
clicks = (clicks + 1) % 10;
}
buttonWasUp = digitalRead(BUTTON_PIN);
// для записи в 74HC595 нужно притянуть пин строба к земле
digitalWrite(LATCH_PIN, LOW);
// задвигаем (англ. shift out) байт-маску бит за битом,
// начиная с младшего (англ. Least Significant Bit first)
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, segments[clicks]);
// чтобы переданный байт отразился на выходах Qx, нужно
// подать на пин строба высокий сигнал
digitalWrite(LATCH_PIN, HIGH);
}
Любой, какой Вам больше нравится.
Никак. Сдвиговый регистр не умеет ничего отсчитывать, это не его функция. Отсчитывать будете сами. Просто сравнивайте с нулём и если достигнут, дальше не уменьшайте.
Весьма оригинально!
Вы используете программную реализацию последовательного интерфейса, который в данном контроллере реализован также аппаратно. Обычно программную реализацию используют тогда, когда пины, к которым привязана аппаратная реализация заняты и их невозможно совободить.
Вы же повесили программную реализацию на те же пину, на которых живёт аппаратная. Зачем?
Добрый вечер!
Учел все замечания, написал код, компилирование проходит успешно, но после загрузки не работает, если не трудно, подскажите в чем дело, вероятнее всего ошибка в коде обратного отсчета, так как подсчет количества нажатий работал успешно.
При обратно отсчете необходимо чтобы программа останавливалась и загорался светодиод.
Заранее спасибо!
int led = 8; //светодиод, загорающийся при окончании обратного отсчета //Пин подключен к ST_CP входу 74HC595 int LATCH_PIN = 12; //Пин подключен к SH_CP входу 74HC595 int CLOCK_PIN = 11; //Пин подключен к DS входу 74HC595 int DATA_PIN = 13; #define BUTTON_PIN 10 //кнопка, с которой происходит подсчет нажатий #define BUTTON_REV 9 // кнопка запуска обратного отсчета int clicks = 0; //число нажатий boolean BUTT_PIN = true; //начальное состояние кнопки boolean BUTT_REV = true; unsigned long TimerINTERVAL; // Для интервала / паузы, обратного отсчета таймера, без delay. byte massiv[10] = { 0b01111101, 0b00100100, 0b01111010, 0b01110110, 0b00100111, 0b01010111, 0b01011111, 0b01100100, 0b01111111, 0b01110111 }; //числа от 0 до 9 void setup() { //устанавливаем режим OUTPUT для линий, //которые требуются для работы с регистром pinMode(LATCH_PIN, OUTPUT); pinMode(CLOCK_PIN, OUTPUT); pinMode(DATA_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT); pinMode(BUTTON_REV, INPUT); pinMode(led, OUTPUT); } // Код основной программы void loop() { // считаем клики кнопки if (BUTT_PIN>0) { delay(10); if (!digitalRead(BUTTON_PIN)) clicks = (clicks + 1) % 10; } // запись в 74HC595 притянуть пин строба к земле digitalWrite(LATCH_PIN, LOW); // задвигаем (англ. shift out) байт-маску бит за битом, // начиная с младшего (англ. Least Significant Bit first) shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, massiv[clicks]); // чтобы переданный байт отразился на выходах Qx, нужно // подать на пин строба высокий сигнал digitalWrite(LATCH_PIN, HIGH); //обратный отсчет по нажатию кнопки BUTTON_REV if (BUTT_REV>0) { delay(10); // Обратный перебор массива, начиная с номера элемента равного числу нажатий for (clicks = 0; 0 <= 9; clicks++); if (TimerINTERVAL == 0)TimerINTERVAL = millis(); // пауза для шага вниз таймера, можно увеличивать / уменьшать. if(millis()-TimerINTERVAL > 3000) // если прошло 3000 = 3 секунды. //при достижении 0 должен загореться светодиод if (clicks == 0) { digitalWrite(led, HIGH);} } //вывод цифр при обратном отсчете на индикатор digitalWrite(LATCH_PIN, LOW); // задвигаем (англ. shift out) байт-маску бит за битом, // начиная с младшего (англ. Least Significant Bit first) shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, massiv[clicks]); // чтобы переданный байт отразился на выходах Qx, нужно // подать на пин строба высокий сигнал digitalWrite(LATCH_PIN, HIGH); }dbv1991,
Вас не смущает тот факт, что переменные BUTT_PIN и BUTT_REV никогда не меняются? Как Вы их сделали true в строка 15 и 16, так они таковыми и остаются пожизненно. Но при этом Вы старательно сравниваете их с 0 в строках 48 и 67. Зачем?
Я уж не говорю, что переменную типа boolean не стоит сравнивать на >0, т.к. она может быть >0, а может и <0 но всё равно она при этом true.
И ещё, на "языке наших партнёров" существительное butt имеет много значений, но одно из наиболее распространённых - "задница". За что Вы эти переменные так?
// все пины лучше сразу через define #define led 8 //светодиод, загорающийся при окончании обратного отсчета #define BUTTON_PIN 10 //кнопка, с которой происходит подсчет нажатий #define BUTTON_REV 9 // кнопка запуска обратного отсчета int clicks = 0; //число нажатий boolean BUTT_PIN=false; //нельзя в программе задать состояние кнопки, оно у нас физическое. сделаем из этих переменных флаги как и было задумано // начальное состояние кнопки boolean BUTT_REV=false; // //unsigned long TimerINTERVAL; // Для интервала / паузы, обратного отсчета таймера, без delay.ПОРВЕМ ШАБЛОН И СДЕЛАЕМ ДЕЛАЙ! void setup() { Serial.begin(9600);// я убрал сдвиговый регистр и сделал через сириал, так как по регистру вопросов не было pinMode(BUTTON_PIN, OUTPUT); pinMode(BUTTON_REV, OUTPUT); digitalWrite(BUTTON_PIN,1); digitalWrite(BUTTON_REV,1); pinMode(led, OUTPUT); Serial.println("SET THE TIMER BY BOTTON +"); } // весь луп сделаем из ifов void loop() { // if (BUTT_PIN>0) BUTT_PIN ВСЕГДА БУДЕТ БОЛЬШЕ НУЛЯ! МЫ ЖЕ ЕГО ТРУ ПРОПИСАЛИ! // { // delay(10);// што это было? дребезг? if (!digitalRead(BUTTON_PIN)&&!BUTT_PIN) { Serial.print("INCREASE TIMER = "); digitalWrite(led,0);// гасим диод, типо в цикле работает вся это бойда clicks++; Serial.print(clicks); Serial.println(" SEC"); BUTT_PIN=true;// Поднять флаг! } if (digitalRead(BUTTON_PIN)&&BUTT_PIN) BUTT_PIN=false;// СПУСТИТЬ ФЛАГ! if (!digitalRead(BUTTON_REV)&&!BUTT_REV&&clicks==0) { Serial.println("NOT THIS BUTTON IDIOT!!!"); BUTT_REV=true; } if(!digitalRead(BUTTON_REV)&&!BUTT_REV) { Serial.println("AHTUNG!!!COUNTDOWN IS STARTED!!!"); for (; clicks >= 0; clicks--)// устал комментить, вот тут вот так... { delay(1000); Serial.println(clicks); } digitalWrite(led,1); Serial.println("BOOOOOM!"); clicks=0; } if(digitalRead(BUTTON_REV)&&BUTT_REV)BUTT_REV=false; }Я честно пытался сделать кнопки как у Вас, но ничего не получилось, сделал по своему. Убрать сериал и добавить 7 сегментный экран (у меня опять же в эмуляторе не получилось его сделать) решил не тратить время и сделать через сериал.
От души благодарен! Теперь стала понятна структура скетча!
Но по условию задачи все равно надо выводить на 7-сегментный индикатор с помощью регистра сдвига и чтобы нажатие на кнопку считало от 0 до 9 только. Сейчас попробую адаптировать под свою задачу!
Еще раз огромное спасибо!
Добрый день!
Прошу Вашей помощи в модернизации программы, она должна выполнять следущее:
//Светодиоды #define LED_0 8 //светодиод, загорающийся при окончании обратного отсчета #define LED_1 7 //светодиод - ошибка на 1-ом датчике Холла #define LED_2 6 //светодиод - ошибка на 2-ом датчике Холла //Датчики Холла //define SensorPIN_1 A0 // 1-ый датчик Холла //define SensorPIN_1 A1 // 2-ой датчик Холла int SensorPIN_1; int SensorPIN_2; boolean flag1=false; //флаг ошибки на 1-ом Холле boolean flag2=false; //флаг ошибки на 2-ом Холле //Кнопки #define BUTTON_PIN 10 //кнопка, с которой происходит подсчет нажатий #define BUTTON_REV 9 // кнопка запуска обратного отсчета int clicks = 0; //число нажатий boolean BUTT_PIN=false; // начальное состояние кнопки BUTT_PIN boolean BUTT_REV=false; // начальное состояние кнопки BUTT_REV //для кнопки обратного отсчета boolean button_state=false; uint32_t ms_button=0; uint32_t ms=millis(); //Сдвиговый регистр #define DATA_PIN 13 // пин данных #define LATCH_PIN 12 // пин строба #define CLOCK_PIN 11 // пин такта //Индикатор byte massiv[10] = { 0b01111101, 0b00100100, 0b01111010, 0b01110110, 0b00100111, 0b01010111, 0b01011111, 0b01100100, 0b01111111, 0b01110111 }; void setup() { //Используем серийный порт Serial.begin(9600); //Светодиоды pinMode(LED_0, OUTPUT); pinMode(LED_1, OUTPUT); pinMode(LED_2, OUTPUT); //Холл pinMode(SensorPIN_1, INPUT); pinMode(SensorPIN_2, INPUT); //Кнопки pinMode(BUTTON_PIN, OUTPUT); pinMode(BUTTON_REV, OUTPUT); digitalWrite(BUTTON_PIN,1); digitalWrite(BUTTON_REV,1); //Сдвиговый регистр pinMode(DATA_PIN, OUTPUT); pinMode(CLOCK_PIN, OUTPUT); pinMode(LATCH_PIN, OUTPUT); } void loop() //подсчет количества нажатий на кнопку BUTTON_PIN { if (!digitalRead(BUTTON_PIN)&&!BUTT_PIN) { Serial.print("INCREASE TIMER = "); digitalWrite(LED_1,0);// погасить диод при отсутствии нажатий clicks = (clicks + 1) % 10; Serial.print(clicks); Serial.println(" SEC"); //Вывод на индикатор через сдвиговый регистр digitalWrite(LATCH_PIN, LOW); shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, massiv[clicks]); digitalWrite(LATCH_PIN, HIGH); BUTT_PIN=true;// Поднять флаг! } if (digitalRead(BUTTON_PIN)&&BUTT_PIN) BUTT_PIN=false;// СПУСТИТЬ ФЛАГ! // Обратный отчсет if (!digitalRead(BUTTON_REV)&&!BUTT_REV&&clicks==0) //как праывильно записать код для тумблера? Можно так? //фиксируем нажатие кнопки if(digitalRead(BUTTON_REV)==LOW&&!button_state&&(ms-ms_button)>50) { BUTT_REV=true; ms_button=ms; } //фиксируем отпускание кнопки if(digitalRead(BUTTON_REV)==HIGH&&!button_state&&(ms-ms_button)>50) { BUTT_REV=false; ms_button=ms; } //проверка условий для датчиков Холла //первый датчик flag1 = digitalRead(A0); if (flag1 == LOW){ digitalWrite(7, HIGH); // нет сигнала-загорается LED_1 } else { digitalWrite(7, LOW); } //второй датчик { flag2 = digitalRead(A1); if (flag2 == LOW){ digitalWrite(8, HIGH); // нет сигнала-загорается LED_2 } else { digitalWrite(8, LOW); } //есть сигналы-начинается обратный отсчет { Serial.println("KNOPKA OBRATNOGO OTSCHETA"); } if(!digitalRead(BUTTON_REV)&&!BUTT_REV) { Serial.println("AHTUNG!!!COUNTDOWN IS STARTED!!!"); for (; clicks >= 0; clicks--) { delay(1000); Serial.println(clicks); digitalWrite(LATCH_PIN, LOW); shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, massiv[clicks]); digitalWrite(LATCH_PIN, HIGH); } } //загорается светодиод при окончании обратного отсчета digitalWrite(LED_0,1); Serial.println("BOOOOOM!"); clicks=0; } if(digitalRead(BUTTON_REV)&&BUTT_REV)BUTT_REV=false; }Добрый день!
Прошу Вашей помощи в модернизации программы, она должна выполнять следущее:
Судя по скетчу в Вас каша в голове. Вы не определили пины Холов через #define, хотя попытка была, только решетку забыли добавить. потом решили их через int сделать, что не несть хорошо. лучше все же черед Дефайн. Так как в при их инициализации через int вы их ни к чему не приравняли поскольку трудно приравнять аналоговые порты к int овой переменной вы сдались, а какие они у Вас значения получили хз. потом.... Работа с тумблером от работы с кнопкой ничем не отличается, работа с датчиком холла от работы с кнопкой особо ничем не отличается. Используйте функции которые опрашивают состояния устройств и ставят флаги когда состояние меняется.
про миллис. вы его используете неправильно, вот вы переменную ms создали, приравняли ее в начале к millis(); это значит что она будет равна millis(); только там где вы ее приравняли, то есть в начале программы, потом она не меняется. Мой совет-уберите ms и пропишите в лупе вместо нее millis()
Моя программа была рабочей и делала то что было нужно. Ваша же уже то что нужно не делает. мне сейчас не хочется сидеть и искать где Вы ошиблись. Попробуйте решать поэтапно, выводите переменные в сириал где это нужно для отладки. Возмите рабочее (мое) решение и постипенно добавляейте элементы, так чтобы оно работало как надо на каждом этапе добавления. Сначала добавьте millis() вместо delay (), потом добавьте датчик Холла с диодом, потом второй... не нужно все городить в кучу а потом искать где ошибся.