В цикле while не работает i++

dimas6000
Offline
Зарегистрирован: 11.04.2014
По какой-то причине while работает бесконечно, а i c самого начала равно 3, на дисплее всегда выводится 3, а чем может быть ошибка и как исправить? Довольно долго пытаюсь сделать - не работает и все тут./
 int i=0;
     while(i<15)
     {
       uint8_t ppp=255; 
       ppp = getFingerprintIDez(); //считываем с датчика номер под которым запомнен палец в переменнуюо ppp
       i++;
       lcd.setCursor(7, 1);// переводим курсор в 0 столбец 0 строку
       lcd.print(i); 
       digitalWrite(beeper, HIGH); //короткие сигналы дают понять, что мы ждем палец)
       delay(30);
       digitalWrite(beeper, LOW);      
       if (ppp!=255 && free_id[ppp]==1) //если палец валиден - открываем дверь)
       {
         lcd.setCursor(0, 0);// переводим курсор в 0 столбец 0 строку
         lcd.print("  Valid finger  ");
         digitalWrite(door, HIGH);
         delay(5000);
         digitalWrite(door, LOW);
         break;
       }
       else //невалиден сей палец, мигаем светодиодом
       {
         digitalWrite(led, HIGH);
         delay(100);
         digitalWrite(led, LOW);
       }
     }

 

 

dimas6000
Offline
Зарегистрирован: 11.04.2014

Не понял, что я сделал с форматированием текста, и кнопки редактирования нет.
 

По какой-то причине while работает бесконечно, а i c самого начала равно 3, на дисплее всегда 
выводится 3, в чем может быть ошибка и как исправить? 
 

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Текст не весь. Есть следующие темные моменты:

1. Как объявлен массив free_id? Переменная i где объявлена? Рядом с free_id? Памяти точно хватает?

2. Судя по косвенным данным getFingerprintDez пишет во free_id массив, так? Может писать, например, в free_id[-1]

3. Какая Ардуина? Скетч большой?

Если есть подозрения на некорректность работы, то значит одни данные наезжают на другие, либо памяти недостаточно, либо кто то пишет не туда, куда можно.
 
dimas6000
Offline
Зарегистрирован: 11.04.2014

Спасибо, вот полный код. Arduino Mega2560, getFingerprintDez - функция считывания отпечатка пальца, она просто return-ом выдает номер пальца в базе данных, массив free_id в начале работы программы считывается из eeprom.
Код собирался за пару вечеров, и там порой странные комментарии.
И я немного не понял, как free_id может быть связан с i, которая не хочет изменяться. Указателями я не пользовался. 

 

/*
(HIGH) = 5V
(LOW) = gnd (ground) = 0V
(OUTPUT) = делает пин цифровым выходом
(INPUT) = делает пин входом
uint8_t - беззнаковый однобайтовый int
0-254 возможные идентификаторы пальцев, 255 - нет доступа, при этом в массиве под индексом номера пальца должна быть единица!

стоит переписвать подключение датчика к аппаратному серийному порту
разобраться с прерываниями для подключения кнопок и т.п.
правильное подключение кнопки: подтягиваем выход к которому подключена кнопка к земле,  кнопку соединяем с этим выводом и плюсом



*/

/*
Провода датчика и переходника
желтый  - красный
зеленый - зеленый
синий - белый
фиолетовый - черный

*/



#include <EEPROM.h> 
#include <Servo.h> 
#include <LiquidCrystal.h>
#include <Adafruit_Fingerprint.h>
#if ARDUINO >= 100
 #include <SoftwareSerial.h>
#else
 #include <NewSoftSerial.h>
#endif

int ultrasonic(); //прототип определения расстояния (ультрасоник)
int getFingerprintIDez(); //прототип функции считывания нужного отпечатка
void new_finger(); //прототип функции добавленя отпечатка

#define door A2    //сервопривод
#define f_green 10 //in from sensor, green
#define f_white 11 //out from sensor, white
//27,29,31,33,35,37,39,41 - пины матричной клавиатуры
#define led 13     //светодиод для индикации
#define echoPin 3 //ультрасоник 
#define trigPin 4  //ультрасоник 
#define beeper 7   //бипер (пьезопищалка)  на 8
#define button 41   //кнопка для запуска функции добавления отпечатка в базу  

//ересь какая то, хз что, пока не паримся, работает и норм :DDDD
#if ARDUINO >= 100
  SoftwareSerial mySerial(f_green, f_white);
#else
  NewSoftSerial mySerial(f_green, f_white);
#endif
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial); //чё-то куда-то с серийным портом))

Servo myservo;  // объект для управления сервомашинкой
int free_id[255]; //массив для хранения информации занято ли место под палец в базе


LiquidCrystal lcd(42,44,46,48,50,52); 
 /********************************************************** такое подключение если  lcd(2,3,4,5,6,7);  , иначе пины к ардуино инвертируются
 1 - пин дисплея соединяется с пятым, потенциометром и землей
 2 - с потенциометром и плюсом
 3 - со средним пином потенциометра
 4 - 42 пин ардуино
 5 - 1 пин дисплея
 6 - 44 пин ардуино
 7-10 - никуда
 11 - 46 пин ардуино
 12 - 48 пин ардуино
 13 - 50 пин ардуино
 14 - 52 пин ардуино
 15 - плюс подсветки  // используя analogWrite(6, 66); и задав первым символом номер выхода с ШИМ к которому подключаем вместо плюса, а вторым интенсивность подсветки можно регулировать её яркость //попробовать использовать фотодиод для регулировки яркости
 16 - земля подсветки
 ***********************************************************/


void setup()  
{
    pinMode(trigPin, OUTPUT); //для сигналов ультрасонику
    pinMode(echoPin, INPUT); //для информации из ультрасоника 
    pinMode(button, INPUT);
    pinMode(led, OUTPUT);
    pinMode(beeper, OUTPUT); //задаем пин beeper'а как выходной
     pinMode(door, OUTPUT); //задаем пин beeper'а как выходной
     
    lcd.begin(16, 2); //инициализируем lcd 16 столбцов и 2 строки
    lcd.print("Hello world!"); // сразу печатаем первую строку
    digitalWrite(beeper, HIGH); //подаем на него высокий сигнал (издаем писк) 
    delay(1000); // (секунду бипер пищит, мол, включилась плата)
    digitalWrite(beeper, LOW); //снимаем сигнал с бипера (пьезопищалки)
    
    finger.begin(57600);     //как я понял по комментам, серийный порт для датчика отпечатка, как то связан с хедерами и прочим, точно не знаю, но строка нужна!
    
    if (finger.verifyPassword()==0) //если эта функция выдает 0, значит датчик не подключен к плате
    {
      digitalWrite(beeper, HIGH); //подаем на него высокий сигнал (издаем писк) 
    delay(333); // (секунду бипер пищит, мол, включилась плата)
    digitalWrite(beeper, LOW); //снимаем сигнал с бипера (пьезопищалки)
      lcd.setCursor(0, 1);// перводим курсор в 0 столбец первую строку (нумерация с 0)
      lcd.print("No fingerprint!"); //нет сенсора пальца
      lcd.setCursor(0, 0);// перводим курсор в 0 столбец первую строку (нумерация с 0)
      lcd.print(" !Fatal error!");
      while (1); //запускаем бесконечный цикл, датчика не виден платой
    }
    else
    {//если датчик подключен, издаем три очень коротких сигнала
      lcd.setCursor(0, 1);// перводим курсор в 0 столбец первую строку (нумерация с 0)
      lcd.print("Connected sensor"); //придумать сюда норм надписm, типо датчик подключен
      
      digitalWrite(beeper, HIGH);
      delay(76);
      digitalWrite(beeper, LOW);
      delay(50);
      digitalWrite(beeper, HIGH);
      delay(76);
      digitalWrite(beeper, LOW);
      delay(50);
      digitalWrite(beeper, HIGH);
      delay(76);
      digitalWrite(beeper, LOW);
    }
    
    for (int i = 0; i<255; i++)    //цикл для считывания в массив данных из EEPROM, 
      free_id[i]=EEPROM.read(i);   //считывает из EEPROM свободна или занята ячейка под палец (1 - занята, иначе - свободна), есл знята - палец валиден) иначе не валиден, даже если считался датчиком)
    //даем прочитать все нужные тексты и заканчиваем инициализацию всего и вся
    delay(500);
}

void loop()                     
{ 
   int i=0;
   lcd.clear(); //очищаем дисплей
   if (digitalRead(button) == HIGH)   //если нажата кнопка добавления отпечатка в базу
   {
     lcd.setCursor(0, 0);// переводим курсор в 0 столбец 0 строку
     lcd.print("   Add finger   "); //придумать сюда норм надпись, типо датчик подключен
     new_finger();//вызываем функцию добавления нового отпечатка
   }
   if (ultrasonic()<7) //датчик включается если рука близко к ультрасонику (меньше 7 см) или ультрасоник не подключен к плате (тогда дистанция = 0)
   { 
     lcd.setCursor(0, 0);// переводим курсор в 0 столбец 0 строку
     lcd.print("     Finger   "); 
     int i=0;
     while(i<15)
     {
       uint8_t ppp=255; 
       ppp = getFingerprintIDez(); //считываем с датчика номер под которым запомнен палец в переменнуюо ppp
       i++;
       lcd.setCursor(7, 1);// переводим курсор в 0 столбец 0 строку
       lcd.print(i); //придумать сюда норм надпись, типо датчик подключен
       digitalWrite(beeper, HIGH); //короткие сигналы дают понять, что мы ждем палец)
       delay(30);
       digitalWrite(beeper, LOW);      
       if (ppp!=255 && free_id[ppp]==1) //если палец валиден - открываем дверь)
       {
         lcd.setCursor(0, 0);// переводим курсор в 0 столбец 0 строку
         lcd.print("  Valid finger  "); //придумать сюда норм надпись, типо датчик подключен
         digitalWrite(door, HIGH);
         delay(5000);
         digitalWrite(door, LOW);
         break;
       }
       else //невалиден сей палец, мигаем светодиодом
       {
         digitalWrite(led, HIGH);
         delay(100);
         digitalWrite(led, LOW);
       }
     }
   }
\
}


int getFingerprintIDez() {
  
  
  uint8_t p = finger.getImage();
  if (p != FINGERPRINT_OK)  return -1;

  p = finger.image2Tz();
  if (p != FINGERPRINT_OK)  return -1;

  p = finger.fingerFastSearch();
  if (p != FINGERPRINT_OK)  return -1;
  
  return finger.fingerID; 
}

  
uint8_t getFingerprintEnroll(uint8_t id) {
  uint8_t p = -1;
  while (p != FINGERPRINT_OK) {
    p = finger.getImage();
    switch (p) {
    case FINGERPRINT_OK:
     break;
    case FINGERPRINT_NOFINGER:
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      break;
    case FINGERPRINT_IMAGEFAIL:
       break;
    default:
      break;
    }
  }

  p = finger.image2Tz(1);
  switch (p) {
    case FINGERPRINT_OK:
       break;
    case FINGERPRINT_IMAGEMESS:
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      return p;
    case FINGERPRINT_FEATUREFAIL:
      return p;
    case FINGERPRINT_INVALIDIMAGE:
     return p;
    default:
      return p;
  }
  
   delay(2000);
  p = 0;
  while (p != FINGERPRINT_NOFINGER) {
    p = finger.getImage();
  }

  p = -1;
  while (p != FINGERPRINT_OK) {
    p = finger.getImage();
    switch (p) {
    case FINGERPRINT_OK:
      break;
    case FINGERPRINT_NOFINGER:
     break;
    case FINGERPRINT_PACKETRECIEVEERR:
      break;
    case FINGERPRINT_IMAGEFAIL:
      break;
    default:
      break;
    }
  }

  p = finger.image2Tz(2);
  switch (p) {
    case FINGERPRINT_OK:
       break;
    case FINGERPRINT_IMAGEMESS:
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
     return p;
    case FINGERPRINT_FEATUREFAIL:
      return p;
    case FINGERPRINT_INVALIDIMAGE:
      return p;
    default:
      return p;
  }
  
  
  p = finger.createModel();
  if (p == FINGERPRINT_OK) {
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    return p;
  } else if (p == FINGERPRINT_ENROLLMISMATCH) {
    return p;
  } else {
      return p;
  }   
  
  p = finger.storeModel(id);
  if (p == FINGERPRINT_OK) {
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    return p;
  } else if (p == FINGERPRINT_BADLOCATION) {
    return p;
  } else if (p == FINGERPRINT_FLASHERR) {
    return p;
  } else {
    return p;
  }   
}

void new_finger() //поправить метод! плохой алгоритм
{

    //как только увидели нажатие кнопки - запустили цикл, на текущий момент кнопку надо держать, слишком долгий loop()
      uint8_t free_Finger = 1; //0 палец не занимаем пока, там мой)
      
       /*ищем свободную ячейку под новый палец, пока элемент массива равен одному, мы просто увеличиваем индекс элемента массива, как только ячейка не один, значит данная ячейка в флеш-памяти считывателя не занята пальцем и и в неё можно прописать новый*/
      while (free_id[free_Finger]==1) 
        free_Finger++;
      free_id[free_Finger]=1;
      EEPROM.write(free_Finger, 1); //запись в свободную ячейку инфы о ее занятости
        
      digitalWrite(beeper, HIGH); //найдена ячейка под палец
      delay(250);
      digitalWrite(beeper, LOW);
      delay(150);
      digitalWrite(beeper, HIGH);
      delay(250);
      digitalWrite(beeper, LOW);
      delay(150);
      digitalWrite(beeper, HIGH);
      delay(250);
      digitalWrite(beeper, LOW);   
       
      uint8_t k=0; 
      uint8_t ppp=255;
      lcd.setCursor(0, 1);// переводим курсор в 0 столбец 1 строку
      lcd.print("                "); //очистка строки
      lcd.print("Wait true finger");  //ждем правильного пальца, т.е. из базы
newread: //раньше тут что-то странно работало, опасный блок!!! БАГИ!!!
      k++;
      ppp = getFingerprintIDez(); //считываем с датчика номер под которым запомнен палец в переменнуюо ppp
      digitalWrite(beeper, HIGH); //издаем писк очень короткий
      delay(30);
      digitalWrite(beeper, LOW);
      
      //если не считали палец, т.е. ppp осталось 255, или палец был удален (удаляется только из eeprom, в датчик пока перезаписывается) и при этом k<50 (50 попыток с интервалом в 100 мс на считывание валидного отпечатка!) то позвращаемся назад, к считыванию пальца
      if (ppp==255 && k<50) 
      {
        delay(100);
        goto newread;
      }
    
      if (ppp!=255 && free_id[ppp]==1) //если палец есть в базе и валиден (т.е. в еепром он тоже прописан как существующий)
      {
        digitalWrite(beeper, HIGH); //издаем сигнал на 1\3 с
        delay(333);
        digitalWrite(beeper, LOW);
        lcd.setCursor(0, 1);// переводим курсор в 0 столбец 1 строку
        lcd.print("                "); 
        lcd.setCursor(0, 1);// переводим курсор в 0 столбец 1 строку
        lcd.print("Wait new finger"); 
        getFingerprintEnroll(free_Finger); //добавляем новый палец в базу, если здесь лаганет - только перезагрузка платы, и вообще, функция- темный лес, нужно разобраться    
        lcd.setCursor(0, 1);// переводим курсор в 0 столбец 1 строку
        lcd.print("New finger id="); //айди нового пальца, максимум 2 символа сейчас
        lcd.setCursor(14, 1);// переводим курсор в 12 столбец 1 строку
        lcd.print(free_Finger); 
        
        digitalWrite(beeper, HIGH); //палец добавлен, длинный сигнал
        delay(1000);
        digitalWrite(beeper, LOW);
      }
      
}

int ultrasonic()
{
  double duration=0; 
  double distance;
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration/2) / 29.1;
  return (distance);
 }

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Попробуйте объявить массив free_id[255] как 256 байтный - free_id[256]. Я сильно не вникал в программу, но увидел что индекс массива у вас может достигать значения 255. Видимо компилятор разместил переменную i сразу после этого массива, естественно она у вас затирается.

dimas6000
Offline
Зарегистрирован: 11.04.2014

Спасибо, но к сожалению не помогло(
Вообще не могу представитть в чем проблема, при попытке сделать через for - i становится 2 и не изменяется, если использовать метку и условие с goto, то тоже ничего не работает.

Ещё в коде выше два раза int i=0;, но это ни на что не повлияло.
 

__Alexander
Offline
Зарегистрирован: 24.10.2012

да работает ваш код. вставляйте задержку побольше и смотрите.

кстати, в конце while наверное что-то делайте в программе. обнулите i или в вечный цикл что-ли.

вот. и так до 14.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Да уж, красиво жить не запретишь, чтобы хранить единичку (1 бит) используется int.
Массив объявляется как

int free_id[255];

т.е. 255 * 2 байт, чтобы хранить 255 бит информации. Хватило бы и 8 байт, но это совсем другая история, там свои заморочки. Вообще то хоть и Мега2560, но памяти тоже не особо 8К всего, на этот массив free_id скушали килобайт. На стм32 я бы не парился, а здесь это уже звоночек. В любом случае мои предположение не подтвердились, переменная i и free_id расположены несколько в разных местах, потому наезда не будет. Опасное место строки 300-302, теоретически, если весь массив в 1, то зациклится, потому что freeFinger однобайтовая переменная. А если нажать на кнопку 256 раз, то вылезет за границы точно. Может нереально, но в жизни всякое бывает.

Да в 136 строке всё таки выкиньте int i, а то как обезьяна с гранатой. Во всяком случае лучше так не делать.

 

dimas6000
Offline
Зарегистрирован: 11.04.2014

_Alexander, спасибо, у меня почему-то всегда на дисплее только тройка, завтра попробую задержку, но она и сама получается во время работы функций примерно 1,5с. А в чем нарисована схема? freezing?

kisofot, благодарю, из 136 убрал, случайно попало туда, когда менял циклы и пробовал переставлять инициализацию.
Я понимаю, что объявлять int-ом массив не правильно, код вообще надо оптимизировать, сейчас занимаюсь этим, я думаю вообще убрать этот массив и просто считывать значение из eeprom, чтобы не тратить оперативку.
На счет 300-302, там пока всего около 10 ячеек занято, free_id обозначает занятые\свободные ячейки под палец в памяти датчика отпечатка, но их всего около 170. За наводку на ошибку, спасибо)
А как можно free_id объявить, boolean?

Хм. если закомментировать 152ую строку, то цикл начинает работать нормально, вот уж не понимаю, что там происходит, по идее эта функция не должна никак к i относится. При этом если убрать из while i++;, а оставить лишь в начале loop() объявление int i=0;, то тогда на дисплей выводится 0, т.е. i=0, но если в цикле есть i++;, то на дисплее цифра 2.
Ещё попробовал инициализировать i 3, 5, 1, 0, если в while нет i++; то на дисплей выводится именно это число, но если же я пишу i++; то на дисплее именно 2. 

Два варианта строк 151-155:

       i++;
       uint8_t ppp=255; 
       lcd.setCursor(7, 1);//
       lcd.print(i); //
       ppp = getFingerprintIDez();
//если часть кода выглядит так, то на дисплей первый раз выведется 1, а потом всегда 3
....
....
...
        i++;
       uint8_t ppp=255; 
       ppp = getFingerprintIDez();
       lcd.setCursor(7, 1);
       lcd.print(i); 
//а если так, то 2

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Хотя бы так, будет вдвое короче: uint8_t free_id[255]

Теперь такая штука, у Вас uint8_t ppp, а FingertypeDez возвращает int, Вы уже сделайте одинаково, иначе будет плохо, тем более если возвращает -1, то как оно его в байт затолкает, я не знаю. В любом случае это неправильно в беззнаковую переменную заносить отрицательное значение, надеясь на авось. Скорей всего в этом и проблема.

Я бы для начала сделал int ppp и проверял его на >= 0 И <255, это если в лоб, а вообще надо сразу корректно делать и типы не смешивать.

tmr
Offline
Зарегистрирован: 19.05.2014

При -1 в uint вернётся 255, возможно так и было задумано

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

tmr пишет:
При -1 в uint вернётся 255, возможно так и было задумано

А я в этом не уверен, но проверить не на чем. Вы проверяли? То, что так и задумано - не вопрос, просто тут перекос на все 200%. Я уже объяснял, почему это неправильно.

Да и проверять незачем, нужно просто сделать правильно.

 

tmr
Offline
Зарегистрирован: 19.05.2014

Нет, конкретно это переполнение я не проверял, но переполнение переменной или знака это известный приём. Ниже я задавал вопрос по преполнению, сам бы хотел знать является ли такая процедура для ардуино нормальной

dimas6000
Offline
Зарегистрирован: 11.04.2014

Спасибо огромное, действительно, из-за переполнения ppp - остальная часть инта записывалась в чужую память, не додумался до этого. Раньше собирался сделать одинаковые типы, но в итоге забыл. Благодарю!!! Очень выручили!

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Хочу увидеть это собственными глазами, вечером посмотрю в отладчике. А вообще это достаточно странное поведение компилятора. Ок, надеюсь это была реальная ошибка ;)