Электронный сейф (не работает)

Тема в разделе "Arduino & Shields", создана пользователем Беспалов Олег, 29 фев 2016.

  1. Здравствуйте, обращаюсь за помощью. Приспичило мне сделать электронный сейф с кнопкой, потенциометром и кучей светодиодов. Как всегда идеально все сделать не получилось.
    Конкретно проблема: сейф закрывается нормально, но открывается любым кодом.
    Поясню еще, код вводим поворачивая потенциометр и выбирая риской число на круговой шкале. Потом нажимаем кнопку, первый символ введен, повторяем для трех символов.
    Код (C++):
    #include <Servo.h>//библиотека сервы
    #define POT_PIN A0 //вход потенциометра
    #define LED_RED 13//входы светодиодов
    #define LED_GREEN 2
    #define LED_BLUE1 3
    #define LED_BLUE2 5
    #define LED_BLUE3 6
    #define KEY 8 //вход кнопки
    Servo myServo;
    void setup()
    {
    pinMode(LED_RED,OUTPUT);//настраиваем пины светодиодов на выход
    pinMode(LED_GREEN,OUTPUT);
    pinMode(LED_BLUE1,OUTPUT);
    pinMode(LED_BLUE2,OUTPUT);
    pinMode(LED_BLUE3,OUTPUT);
    pinMode(POT_PIN,INPUT);//настраиваем пин потенциометра на вход
    myServo.attach(9);//серв на 9 пин
    digitalWrite(LED_RED, HIGH);//включаем все светодиоды при подключении питания
    digitalWrite(LED_GREEN, HIGH);
    digitalWrite(LED_BLUE1, HIGH);
    digitalWrite(LED_BLUE2, HIGH);
    digitalWrite(LED_BLUE3, HIGH);
    delay(50);
    myServo.write(0);//поворачиваем серв(открываем замок)
    delay(25);
    digitalWrite(LED_RED, LOW);//выключаем светодиоды
    digitalWrite(LED_GREEN, LOW);
    digitalWrite(LED_BLUE1, LOW);
    digitalWrite(LED_BLUE2, LOW);
    digitalWrite(LED_BLUE3, LOW);
    delay(50);
    }
    void loop()
    {
      int A;//назначаем переменные для хранения показаний с потенциометра
      int B;
      int C;
      int a;
      int b;
      int c;
     
      int servo=myServo.read();//назначаем переменную принимающую значением угол сервы
      boolean zamok=(servo>90);//переменная если true замок закрыт, если false - открыт
      int rot;//потенциометр
      int i;//переменная с помощью которой определяю какой по счету знак вводится
     
    if(zamok){
      digitalWrite(LED_RED, HIGH);//сейф закрыт
      if(i==0){       //вводится первый знак
         boolean keyUp=digitalRead(KEY);//проверка кнопки
         if(!keyUp){                    //если нажали кнопку
         a=analogRead(POT_PIN)/102;//угол с потенциометра
         digitalWrite(LED_BLUE1, HIGH);//зажигаем первый светодиод
         ++i;//прибавляем i
         delay(500);
         }
       }
       if(i==1){      //вводится второй знак
         boolean keyUp=digitalRead(KEY);//проверка кнопки
         if(!keyUp){                   //если нажали кнопку
         b=analogRead(POT_PIN)/102;//угол с потенциометра
         digitalWrite(LED_BLUE2, HIGH);//зажигаем второй светодиод
         ++i;
         delay(500);
         }
       }
       if(i==2){        //вводится третий знак
         boolean keyUp=digitalRead(KEY);//проверка кнопки
         if(!keyUp){
         c=analogRead(POT_PIN)/102;//угол с потенциометра
         digitalWrite(LED_BLUE3, HIGH);
          delay(500);
          digitalWrite(LED_BLUE1, LOW);//выключаем все светодиоды
          digitalWrite(LED_BLUE2, LOW);
          digitalWrite(LED_BLUE3, LOW);
           i=0;
         }
          boolean Aa=(A==a);//переменные принимающие значение true,
           boolean Bb=(B==b);// если переменные введенные при закрытии и открытии сейфа равны
            boolean Cc=(C==c);
          if(Aa){
            if(Bb){
              if(Cc){
           myServo.write(0);//сейф открывается
           delay(25);
          digitalWrite(LED_RED, LOW); //выключается красный светодиод
              }
            }
         }
     
       }
    }else{
      digitalWrite(LED_GREEN, HIGH);//сейф открыт

       if(i==0){
         boolean keyUp=digitalRead(KEY);//проверка кнопки
         if(!keyUp){
         A=analogRead(POT_PIN)/102;//угол с потенциометра
         digitalWrite(LED_BLUE1, HIGH);
         ++i;
         delay(500);
         }
       }
       if(i==1){
         boolean keyUp=digitalRead(KEY);//проверка кнопки
         if(!keyUp){
         B=analogRead(POT_PIN)/102;//угол с потенциометра
         digitalWrite(LED_BLUE2, HIGH);
         ++i;
         delay(500);
         }
       }
       if(i==2){
         boolean keyUp=digitalRead(KEY);//проверка кнопки
         if(!keyUp){
         C=analogRead(POT_PIN)/102;//угол с потенциометра
         digitalWrite(LED_BLUE3, HIGH);
          myServo.write(170); // странно, но если поставить 180 серва жжужит
          delay(500);
          digitalWrite(LED_BLUE1, LOW);
          digitalWrite(LED_BLUE2, LOW);
          digitalWrite(LED_BLUE3, LOW);
          digitalWrite(LED_GREEN, LOW);
           i=0;
        }
       }
      }
    }

     
     
  2. Tomasina

    Tomasina Сушитель лампочек Модератор

    Код (C++):
    boolean Aa=(A==a);
    а теперь смотрим внимательно:
    Код (C++):

    A = 0; // при первом включении, потом всегда больше нуля
    a = analogRead(POT_PIN)/102; //угол с потенциометра
    A == a; // всегда true, кроме редкого сочетания, когда при первом включении потенциометр стоит в нуле
    Aa = true;
     
    В итоге условие всегда выполняется, поэтому замок честно открывается.
     
    Беспалов Олег нравится это.
  3. А если определение каждой переменной отнести в участок кода где мы назначаем ей значение потенциометра, проблема будет решена?
    Или допустим сразу писать так:
    Код (C++):
    int A=digitalRead(POT_PIN)/102
     
  4. Tomasina

    Tomasina Сушитель лампочек Модератор

    a,b,c - это то, что вводится крутилками?
    A,B,C - это заранее записанный код?

    Тогда для проверки валидности тупо сравнить одно с другим:
    Код (C++):
    if(a==A && b==B && c==C)
    {
    // открыть
    }
    else
    {
    // послать нафиг
    }
     
     
    Беспалов Олег нравится это.
  5. Нееее, тут в чем фишка, в самом начале сейф открыт, мы вводим ABC-закрываем. Потом вводим abc-открываем. То есть сейфу не нужен ни режим програмирования, ни нужно использовать один и тот же код. Круто же?
     
  6. Tomasina

    Tomasina Сушитель лампочек Модератор

    да пофиг, пусть сначала запоминаем код, затем анализируем крутилки.
    Сам код валидации не меняется. А ввод значений с крутилок у тебя уже есть.
     
    Беспалов Олег нравится это.
  7. Попытался перенести определение переменных, не хочет загружать скетч.
     
  8. Tomasina

    Tomasina Сушитель лампочек Модератор

    да все то же, просто вместо
    Код (C++):
    boolean Aa=(A==a);//переменные принимающие значение true,
           boolean Bb=(B==b);// если переменные введенные при закрытии и открытии сейфа равны
            boolean Cc=(C==c);
          if(Aa){
            if(Bb){
              if(Cc)
    вставить
    Код (C++):
    if(a==A && b==B && c==C)
     
    Беспалов Олег нравится это.
  9. Да, так тоже делал (изначально так и хотел), не получается. Суть та же, неважно каким кодом закрываем сейф, открывается всегда одной и той комбинацией.
    Пробовал еще перенести проверку кода в самый конец программы, сейф вообще не закрывается.
     
  10. Tomasina

    Tomasina Сушитель лампочек Модератор

    Код (C++):
    #include <Servo.h>//библиотека сервы
    #define POT_PIN A0 //вход потенциометра
    #define LED_RED 13//входы светодиодов
    #define LED_GREEN 2
    #define KEY 8 //вход кнопки
    const byte LEDblue[3]={3,5,6};
    Servo myServo;

    void setup()
    {
      pinMode(LED_RED,OUTPUT);//настраиваем пины светодиодов на выход
      pinMode(LED_GREEN,OUTPUT);
      for(byte i=0; i<3; i++) pinMode(LEDblue[i],OUTPUT);
      pinMode(POT_PIN,INPUT);//настраиваем пин потенциометра на вход
      myServo.attach(9);//серв на 9 пин
      digitalWrite(LED_RED, HIGH);//включаем все светодиоды при подключении питания
      digitalWrite(LED_GREEN, HIGH);
      for(byte i=0; i<3; i++) digitalWrite(LEDblue[i],HIGH);
      delay(50);
      myServo.write(0);//поворачиваем серв(открываем замок)
      delay(25);
      digitalWrite(LED_RED, LOW);//выключаем светодиоды
      digitalWrite(LED_GREEN, LOW);
      for(byte i=0; i<3; i++) digitalWrite(LEDblue[i],LOW);
      delay(50);
    }

    void loop()
    {
      byte userCode[3];        // вводимый код для открытия замка
      static byte passCode[3]; // запоминаемый код замка
      int servo=myServo.read();// назначаем переменную принимающую значением угол сервы
      boolean zamok=(servo>90);// переменная если true замок закрыт, если false - открыт

      if(zamok)
      {
        digitalWrite(LED_RED, HIGH);//сейф закрыт

        for(byte i=0; i<3; i++) // трижды вводим код
        {
          while(!digitalRead(KEY));// ждем нажатия на кнопку
          userCode[i] = analogRead(POT_PIN)/102;//угол с потенциометра
          digitalWrite(LEDblue[i], HIGH);//зажигаем светодиод
          delay(500);
        }

        byte verifyCode = 0; // переменная для хранения признака корректности кодв
        for(byte i=0; i<3; i++) // сравнение кода с эталоном
        {
          if(userCode[i] == passCode[i]) verifyCode++; // плюсуем единичку если правильный код
        }

        if(verifyCode == 3) // если все три кода совпали с эталоном
        {
          myServo.write(0);//сейф открывается
          delay(25);
          digitalWrite(LED_RED, LOW); //выключается красный светодиод
        }
      }
      else
      {
        digitalWrite(LED_GREEN, HIGH);//сейф открыт

        for(byte i=0; i<3; i++) // трижды вводим код
        {
          while(!digitalRead(KEY));// ждем нажатия на кнопку
          passCode[i] = analogRead(POT_PIN)/102;//угол с потенциометра
          digitalWrite(LEDblue[i], HIGH);//зажигаем светодиод
          delay(500);
        }

        myServo.write(170); // странно, но если поставить 180 серва жжужит
        delay(500);
        for(byte i=0; i<3; i++) digitalWrite(LEDblue[i],LOW);
        digitalWrite(LED_GREEN, LOW);
      }
    }
    хотя по сути это то же самое.
     
    Беспалов Олег нравится это.
  11. Блин, я думал насчет цикла for, но решил, что он будет после первого нажатия повторяться. Ладно.
    Более менее понятно, но не все. Что за static, почему не знаю про него.
    И кстати посоветуйте, чтобы сделать шкалу, можно ли использовать вывод значения потенциометра на компьютер(чтоб разметить шкалу). А то сейчас свой код переделанный проверяю, сейф ведет себя абсолютно рандомно, не так как у вас.
     
  12. Tomasina

    Tomasina Сушитель лампочек Модератор

    я не знаю как он себя ведет, мне даже код вгрузить некуда :)

    for можно заменить на три почти одинаковых блока (отличие только в одном символе), на функционал не влияет.

    static не обнуляет переменную при повторе цикла loop (иначе код сейфа получится "одноразовым" и его пришлось бы вводить каждый раз перед следующим закрытием замка).
     
  13. То есть когда первый раз закрываем сейф вводим код, которым будем пользоваться дальше и при открытии и при закрытии.
    Сейчас если получится на компьютер интернет словить постараюсь проверить ваш код. Пока даже свой код не могу прошить.
     
  14. Limoney

    Limoney Гик

    В твоем варианте лучше использовать енкодер
     
  15. ostrov

    ostrov Гуру

    Немного по теме:

    1. Введенный код хранится в переменных? А если МК ребутнется? Нужно хранить обязательно в EEPROM.
    2. Ввод данных потенциометром ИМХО очень ненадежен, мнение выше про потенциометр правильное.
     
  16. Рад бы, но его нет, а хотелось собрать и проверить как работает.
    Кстати в мышке на колесике же энкодер? Интересно со своей старой мышки смогу поставить?
    Сейчас попытаюсь разобраться с EEPROM может переделаю.
    А почему ввод данных потенциометра ненадежен?
     
  17. Tomasina

    Tomasina Сушитель лампочек Модератор

    1. не всё сразу, это только начало... ;)
    2. В данном скетче потенциометр используется как энкодер и его точность для этих целей более чем достаточная, т.к. у энкодера диапазон 22 щелчка на оборот, а в данном примере диапазон потенциометра - 10 шагов на оборот: analogRead(POT_PIN)/102, что как раз соответствует цифрам 0...9 и идеально подходит под многие ручки для потенциометров.
     
    Последнее редактирование: 29 фев 2016
  18. А скажите пожалуйста, как сделать чтобы код выполнялся пошагово, или такое только в эмуляции бывает.
    И еще думаю подключить сейчас монитор порта чтобы смотреть какие значения потенциометра записываются. Есть смысл?
     
  19. ostrov

    ostrov Гуру

    Я бы все равно сделал небольшой разброс для измерений с потенциометра, мой опыт подсказывает, что значения могут плавать, особенно при смене температуры. То есть просто записать показания в массив а потом сравнивать их новыми измерениями в теории правильно, а на практике могут быть сюрпризы. Вот эту строку я бы немного переделал:
    Код (C++):
    if(userCode[i] == passCode[i]) verifyCode++;
     
    Беспалов Олег нравится это.
  20. Tomasina

    Tomasina Сушитель лампочек Модератор

    нет, отладчика нет.
    В нужной точке временно впиши:
    Код (C++):
    Serial.println("Testpoint #3");
    Serial.print("POT value =");
    Serial.println(value);
    while (Serial.read() != '0'); // необязательно. Продолжаем выполнение только после ввода <0><ENTER>
     
     
    Беспалов Олег нравится это.