Ви не увійшли.
Сторінки 1
Здравствуйте.
Такая проблема, делаю таймер с тремя условиями остановки. По внешнему контакту, по истечению времени и по кнопке.
Кнопку я использую и для пуска, и для остановки, и для сброса таймера. Проблема в том что я не могу нормально реализовать антидребезг, часто проскакивает несколько нажатий. Использую внешнюю подтяжку на 5кОм.
Помогите, скажите где ошибка.
Вот скетч
#define secOne 11 //Порт управления младшего розряда индикатора секунд
#define secTwo 10 //Порт управления старшего розряда индикатора секунд
#define minOne 12 //Порт управления молодшим розрядом индикатора минут
#define minTwo 13 //Порт управления старшим розрядом индикатора минут
#define segG 8 //Вывод ручного управления сегментом G
#define segDP 9 //Вивод ручного управления точкой
#define divider A0 //Разделитель разрядов
#define rele A3 //Виход на реле
#define button A1 //Вход для кнопки
#define contact A2 //Вход для контакта
byte numbersArray[]={ //Массив управления портом D для отображения чисел на индикаторе
0x00, //0
0x9C, //1
0x24, //2
0x0C, //3
0x98, //4
0x48, //5
0x40, //6
0x1C, //7
0x00, //8
0x08 //9
};
byte segmentsPos[] = {secOne, secTwo, minOne, minTwo}; //Массив для хранения
//виводов управления сегментами
unsigned long prevTime=0; //Переменная для хранения предыдущего значения millis()
//для подсчета времени
unsigned long debounceTime=0; //Переменная времени для функции антидребезга контактов
unsigned long delaySegments=0; //Переменная для задержки отображения индикаторов
byte timeNumbers[5]; //Массив для хранения чисел для отображения
bool currentState = HIGH; //Нинешнее состояние кнопки
bool prevState = HIGH; //Предыдущее состояние кнопки
bool prevContact=HIGH; //Стабильное состояние контакта
byte flag = 0; //Флаг работы таймера
byte serviceCounter=0; //Переменная для перебора значений отображаемых индикатором
void setup()
{
DDRD=DDRD|B11111100; //Конфигурируем порт D на выход
PORTD=B11111100; //Сегменты не горят
for(byte i=0; i<=3; ++i) //Конфигурируем
{ //порты
pinMode(segmentsPos[i], OUTPUT); //для
digitalWrite(segmentsPos[i], HIGH); //работы
} //с
pinMode(segG, OUTPUT); //сегментами
pinMode(segDP, OUTPUT); //на выход
pinMode(button, INPUT_PULLUP); //Вход для кнопки
pinMode(contact, INPUT_PULLUP); //Вход для контакта
digitalWrite(segG, HIGH); //Сегменты светятся при подаче на них низкого уровня
digitalWrite(segDP, HIGH); //поскольку используються индикаторы с общим анодом
}
void loop()
{
currentState=digitalRead(button); //Считываем состояние кнопки
if (currentState == 0 && prevState == 1 &&(millis()-debounceTime)>50) //Антидребезг
{
prevState=0;
++flag; //Инкрементируем флаг
if (flag>=3) flag=0; //Устраняем перегруженость
prevContact = digitalRead(contact); //Считываем текущее состояние контакта
debounceTime=millis(); //Записываем значение времени для антидребезга
}
else if (currentState == 1 && prevState == 0 &&(millis()-debounceTime)>5) //При отпускании кнопки
{
prevState=1; //меняем предыдущее состояние
}
if (digitalRead(contact)!= prevContact) flag=3; //Остановка таймера по
//изменению состояния
//контакта
if ((millis()-prevTime)>=1000 && flag == 1) //Ожидаем прошествия секунды
{ //после запуска таймера
++timeNumbers[0]; //Инкрементируем значение секунд
prevTime=millis(); //Записываем текущее значение millis()
}
else if(flag == 0) //Сброс таймера по флагу
{
for (byte i=0; i<=4; ++i)
{ //Можно ли записать значения в массив
timeNumbers[i]=0; //без применения цыкла?
}
}
if (timeNumbers[0]==10) //Проверка перегружености
{ //счетчика единиц секунд
timeNumbers[0]=0; //Сборс
++timeNumbers[1]; //Инкрементирование десяток секунд
}
if (timeNumbers[1]==6) //Проверка перегрузки
{ //счетчика десяток секунд
timeNumbers[1]=0; //Сброс
++timeNumbers[2]; //Инкрементируем значение
} //единиц минут
if (timeNumbers[2]==10) //Проверка перегружености
{ //Счетчика единиц минут
timeNumbers[2]=0; //Сброс
++timeNumbers[3]; //Инкрементирование десяток минут
}
if (timeNumbers[3]==2 && timeNumbers[2]==5) flag=4; //Условие остановки таймера по истечению времени
if ((millis() - delaySegments)>=2) //Передача значений подпрограмме по
{ //работе с индикаторами
if(serviceCounter >= 4) serviceCounter=0; //Проверка перегружености счетчика
dispSeg(timeNumbers[serviceCounter], segmentsPos[serviceCounter], 1); //Передача значений подпрограмме
++serviceCounter; //Инкрементирование счетчика
delaySegments=millis();
}
}
void dispSeg(byte num, byte segNum, bool statDP) //Подпрограмма работы с индикатором
{
for(byte i=0; i<=3; ++i) //Гасим индикаторы
{
digitalWrite(segmentsPos[i], HIGH);
}
if (segNum != 4) //Функция if - апендицыт,который остался после попыток управления разделителем сегментов
{
PORTD=numbersArray[num]; //Подаем нужный потенциал на сегменты
if (num == 0 || num == 1 || num == 7) //Ручное управление сегментом G
{
digitalWrite(segG, HIGH);
}
else
{
digitalWrite(segG, LOW);
}
digitalWrite(segDP, statDP); //Управление точкой
digitalWrite(segNum, LOW); //Зажигаем нужный сегмент
}
}
Неактивний
Основа кода программы - алгоритм. Если он правильный и нет ошибок программирования то программа работает как ожидалось, и сколько там IF-ов - вопрос второстепенный. Если не работает то до лампочки все оформление!
currentState=digitalRead(button); //Считываем состояние кнопки
if (currentState == 0 && prevState == 1 &&(millis()-debounceTime)>50) //Антидребезг
{
prevState=0;
++flag; //Инкрементируем флаг
if (flag>=3) flag=0; //Устраняем перегруженость
prevContact = digitalRead(contact); //Считываем текущее состояние контакта
debounceTime=millis(); //Записываем значение времени для антидребезга
}
else if (currentState == 1 && prevState == 0 &&(millis()-debounceTime)>5) //При отпускании кнопки
{
prevState=1; //меняем предыдущее состояние
}
Вот кусок кода, который обрабатывает нажатие кнопки.
С ним у меня проблемы, но я нашел альтернативный код, а именно:
bool reading = digitalRead (button);
if (reading != lastButton) lastDebounce = millis();
if ((millis()-lastDebounce) > debounceDelay)
{
if (reading != buttonState)
{
buttonState = reading;
if (buttonState == LOW)
{
++flag;
if (flag >= 3) flag = 0;
prevContact = digitalRead (contact);
}
}
}
lastButton = reading;
И вот с ним то все работает. Но я не могу понять в чем ошибка первого обработчика и почему он у меня все же работал, но после того как я ушел от использования delay в блоке кода отображения чисел на индикаторе то начал проскакивать дребезг.
И куда поцепить конденсатор? Паралельно кнопке?
Неактивний
Активний
Титановый велосипед хорош, а у меня тоже есть специальный велосипед для ржавых кнопок:
void setup(void) {
buttonSetup(); // настройка кнопки
pinMode(13, OUTPUT); // будем управлять свечением светодиода
digitalWrite(13, HIGH); // изначально он будет включен
}
void loop(void) {
buttonIteration(); // опрос кнопки и вызов обработчика логического события при необходимости
delay(5); // вместо задержки тут может быть что-то более полезное, как то ввод-вывод инфрмации и расчёты
}
/*
* Суперкнопка 14.05.2000 (c) НТУУ "КПИ", ФИВТ, АУТС, ИА71-09
* Хотя ладно... такой же алгоритм наверняка работает в калькуляторах с резиновыми клавишами
* и в других устройствах с ненадёжными контактами.
* Для подстройки скорости срабатывния кнопки изменяйте BUTTON_MAX_LVL и BUTTON_MIN_LVL.
*/
#define BUTTON_PIN 7 // номер ножки для кнопки (второй контакт этой кнопки подключить на землю)
#define BUTTON_MAX_LVL 192 // верхний предел счётчика устранения дребезга, допустимые значения [128..255]
#define BUTTON_MIN_LVL 64 // нижний предел счётчика устранения дребезга, допустимые значения [0..127]
byte buttonData; // внутреннее промежуточное состояние кнопки, которое изменяется от BUTTON_MIN_LVL до BUTTON_MAX_LVL
void buttonSetup() {
buttonData = BUTTON_MAX_LVL; // инициализация верхним значением, если подтянуто к плюсу питания
pinMode(BUTTON_PIN, INPUT_PULLUP); // подтянуть выключенную кнопку к плюсу, обойдёмся без внешних R элементов
}
void buttonEvent(bool isButtonPressed) {
if (isButtonPressed) {
digitalWrite(13, HIGH); // вкл. светодиод
} else {
digitalWrite(13, LOW); // выкл. светодиод
}
}
void buttonIteration() {
if (digitalRead(BUTTON_PIN) == HIGH) { // контакта нет, напряжение подтянулось к плюсу питания
if (buttonData < BUTTON_MAX_LVL) {
if (++buttonData == 128) {
buttonData = BUTTON_MAX_LVL;
buttonEvent(true); // выдать логическое срабатывание кнопки
}
}
} else { // контакт есть, напряжение погашено кнопкой до нуля
if (buttonData > BUTTON_MIN_LVL) {
if (--buttonData == 127) {
buttonData = BUTTON_MIN_LVL;
buttonEvent(false); // выдать логическое срабатывание кнопки
}
}
}
}
Неактивний
Сторінки 1