В цикле while не работает i++
- Войдите на сайт для отправки комментариев
Пнд, 19/05/2014 - 11:24
По какой-то причине 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);
}
}
Не понял, что я сделал с форматированием текста, и кнопки редактирования нет.
По какой-то причине while работает бесконечно, а i c самого начала равно 3, на дисплее всегда выводится 3, в чем может быть ошибка и как исправить?Текст не весь. Есть следующие темные моменты:
1. Как объявлен массив free_id? Переменная i где объявлена? Рядом с free_id? Памяти точно хватает?
2. Судя по косвенным данным getFingerprintDez пишет во free_id массив, так? Может писать, например, в free_id[-1]
3. Какая Ардуина? Скетч большой?
Спасибо, вот полный код. 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); }Попробуйте объявить массив free_id[255] как 256 байтный - free_id[256]. Я сильно не вникал в программу, но увидел что индекс массива у вас может достигать значения 255. Видимо компилятор разместил переменную i сразу после этого массива, естественно она у вас затирается.
Спасибо, но к сожалению не помогло(
Вообще не могу представитть в чем проблема, при попытке сделать через for - i становится 2 и не изменяется, если использовать метку и условие с goto, то тоже ничего не работает.
Ещё в коде выше два раза int i=0;, но это ни на что не повлияло.
да работает ваш код. вставляйте задержку побольше и смотрите.
кстати, в конце while наверное что-то делайте в программе. обнулите i или в вечный цикл что-ли.
вот. и так до 14.
Да уж, красиво жить не запретишь, чтобы хранить единичку (1 бит) используется int.
Массив объявляется как
т.е. 255 * 2 байт, чтобы хранить 255 бит информации. Хватило бы и 8 байт, но это совсем другая история, там свои заморочки. Вообще то хоть и Мега2560, но памяти тоже не особо 8К всего, на этот массив free_id скушали килобайт. На стм32 я бы не парился, а здесь это уже звоночек. В любом случае мои предположение не подтвердились, переменная i и free_id расположены несколько в разных местах, потому наезда не будет. Опасное место строки 300-302, теоретически, если весь массив в 1, то зациклится, потому что freeFinger однобайтовая переменная. А если нажать на кнопку 256 раз, то вылезет за границы точно. Может нереально, но в жизни всякое бывает.
Да в 136 строке всё таки выкиньте int i, а то как обезьяна с гранатой. Во всяком случае лучше так не делать.
_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Хотя бы так, будет вдвое короче: uint8_t free_id[255]
Теперь такая штука, у Вас uint8_t ppp, а FingertypeDez возвращает int, Вы уже сделайте одинаково, иначе будет плохо, тем более если возвращает -1, то как оно его в байт затолкает, я не знаю. В любом случае это неправильно в беззнаковую переменную заносить отрицательное значение, надеясь на авось. Скорей всего в этом и проблема.
Я бы для начала сделал int ppp и проверял его на >= 0 И <255, это если в лоб, а вообще надо сразу корректно делать и типы не смешивать.
При -1 в uint вернётся 255, возможно так и было задумано
А я в этом не уверен, но проверить не на чем. Вы проверяли? То, что так и задумано - не вопрос, просто тут перекос на все 200%. Я уже объяснял, почему это неправильно.
Да и проверять незачем, нужно просто сделать правильно.
Нет, конкретно это переполнение я не проверял, но переполнение переменной или знака это известный приём. Ниже я задавал вопрос по преполнению, сам бы хотел знать является ли такая процедура для ардуино нормальной
Спасибо огромное, действительно, из-за переполнения ppp - остальная часть инта записывалась в чужую память, не додумался до этого. Раньше собирался сделать одинаковые типы, но в итоге забыл. Благодарю!!! Очень выручили!
Хочу увидеть это собственными глазами, вечером посмотрю в отладчике. А вообще это достаточно странное поведение компилятора. Ок, надеюсь это была реальная ошибка ;)