#1 2018-10-13 20:02:30

Kain
Учасник
Зареєстрований: 2018-10-13
Повідомлень: 6

Не работает антидребезг

Здравствуйте.
Такая проблема, делаю таймер с тремя условиями остановки. По внешнему контакту, по истечению времени и по кнопке.
Кнопку я использую и для пуска, и для остановки, и для сброса таймера. Проблема в том что я не могу нормально реализовать антидребезг, часто проскакивает несколько нажатий. Использую внешнюю подтяжку на 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);                                                  //Зажигаем нужный сегмент
  }
 }

Неактивний

#2 2018-10-13 20:06:15

Kain
Учасник
Зареєстрований: 2018-10-13
Повідомлень: 6

Re: Не работает антидребезг

Я знаю что код - говнище. Это мой первый хоть сколько серьёзный проект. Подскажите по оформлению - нормально ли что 90% кода - это вызов функции "if"?

Неактивний

#3 2018-10-13 20:26:35

Авель
Гість

Re: Не работает антидребезг

Основа кода программы - алгоритм. Если он правильный и нет ошибок программирования то программа работает как ожидалось, и сколько там IF-ов - вопрос второстепенный. Если не работает то до лампочки все оформление!

#4 2018-10-13 21:37:32

Kain
Учасник
Зареєстрований: 2018-10-13
Повідомлень: 6

Re: Не работает антидребезг

Вот схема, если это поможет.
DSC_0345.jpeg

Неактивний

#5 2018-10-13 21:53:26

qwone
Учасник
Зареєстрований: 2016-07-25
Повідомлень: 143

Re: Не работает антидребезг

Вы сами и ответили. Учитесь писать вменяемые программы.

Неактивний

#6 2018-10-13 22:23:51

Kain
Учасник
Зареєстрований: 2018-10-13
Повідомлень: 6

Re: Не работает антидребезг

Может хоть подскажите где ошибка?

Неактивний

#7 2018-10-14 05:58:29

renoshnik
Учасник
Зареєстрований: 2017-04-03
Повідомлень: 1,025

Re: Не работает антидребезг

Какая кнопка ?

Неактивний

#8 2018-10-14 10:27:07

Kain
Учасник
Зареєстрований: 2018-10-13
Повідомлень: 6

Re: Не работает антидребезг

Кнопка подключена к выводу А1.

Неактивний

#9 2018-10-14 17:23:10

renoshnik
Учасник
Зареєстрований: 2017-04-03
Повідомлень: 1,025

Re: Не работает антидребезг

Для начала прицепи конденсатор.

Давй кусок кода где ты еë обрабатываешь, будем смотреть.

Неактивний

#10 2018-10-14 21:27:15

Kain
Учасник
Зареєстрований: 2018-10-13
Повідомлень: 6

Re: Не работает антидребезг

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 в блоке кода отображения чисел на индикаторе то начал проскакивать дребезг.

И куда поцепить конденсатор? Паралельно кнопке?

Неактивний

#11 2018-10-15 05:45:49

renoshnik
Учасник
Зареєстрований: 2017-04-03
Повідомлень: 1,025

Re: Не работает антидребезг

Да, параллельно 0.1 мкФ

Неактивний

#12 2018-10-15 07:08:29

Green
Учасник
Зареєстрований: 2015-11-08
Повідомлень: 593

Re: Не работает антидребезг

Нет, лучше 10 мкф!))) Стыдоба.

Неактивний

#13 2018-10-15 11:27:42

renoshnik
Учасник
Зареєстрований: 2017-04-03
Повідомлень: 1,025

Re: Не работает антидребезг

Green пише:

Нет, лучше 10 мкф!))) Стыдоба.

??? roll

Неактивний

#14 2018-10-15 12:10:12

renoshnik
Учасник
Зареєстрований: 2017-04-03
Повідомлень: 1,025

Неактивний

#15 2018-10-15 14:20:34

Йожэг
Учасник
Зареєстрований: 2015-12-30
Повідомлень: 97

Re: Не работает антидребезг

Титановый велосипед хорош, а у меня тоже есть специальный велосипед для ржавых кнопок:

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); // выдать логическое срабатывание кнопки
      }
    }
  }
}

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму