ничего страшного, опросит дважды или трижды. Для этого и нужен антидребезг и, кстати, лучше это делать вообще без прерываний - будет проще и надежнее. Антидребезг на прерываниях - тот еще гемор
спорить не буду. скажу только что судя по словам ТС, что у него кнопки "подторможивают" - он их опрашивает не раз в 50мс и даже не в 150. а скорее раз в полсекунды
Учение это свет но к сожалению то, что авторам кажется элементарным и не требует объяснения, вызывает вопросы у учеников, а ответить на них помогают форумы и люди готовые тратить на это всё время. Я честно почти месяц читал уроки, но без практики это не остаётся в голове. до того как к Вам обратиться я пробовал несколько библиотек, но как видите я тут. Прошу у вас помощи. В книгах пишут, что не все пины поддерживают прерывание, Значит нужно использовать прерывание по таймеру. Кнопка опрашивается по факту If(digitalRead(48) != HIGH) Выполнять действие:
этот кусок кода ничего не значит. Если хотите, чтобы вам посоветовали конкретно по программе - выкладывайте код целиком. Нужно видеть. что именно занимает у вас 150мс между опросами кнопки
Будет стыдно, но я постараюсь выложить как можно скорее. Код (C++): #include <gfxfont.h> #include <UTFTGLUE.h> #include <DHT.h> #include <iarduino_RTC.h> #include <Adafruit_GFX.h> #include <FreeDefaultFonts.h> #include <Fonts/FreeMono12pt7b.h> #include <MCUFRIEND_kbv.h> MCUFRIEND_kbv tft(A3, A2, A1, A0, A4);//int CS=A3, RS=A2, WR=A1, RD=A0, RST=A4; iarduino_RTC time(RTC_DS1302, 47, 29, 39); DHT dht(44, DHT22); //Инициация датчика температуры и влажности #define BLACK 0x0000 #define NAVY 0x000F #define DARKGREEN 0x03E0 #define DARKCYAN 0x03EF #define MAROON 0x7800 #define PURPLE 0x780F #define OLIVE 0x7BE0 #define LIGHTGREY 0xC618 #define DARKGREY 0x7BEF #define BLUE 0x001F #define GREEN 0x07E0 #define CYAN 0x07FF #define RED 0xF800 #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define WHITE 0xFFFF #define ORANGE 0xFD20 #define GREENYELLOW 0xAFE5 #define PINK 0xF81F #define GREY 0x8410 void setup() { Serial.begin (9600); time.begin(); //инициализация часов dht.begin();// инициализация датчика влажности и температуры uint16_t ID = tft.readID();// получение информации о дисплее tft.begin(ID);// инициализация дисплея pinMode(52, INPUT_PULLUP);//up pinMode(53, INPUT_PULLUP);//dw pinMode(48, INPUT_PULLUP);//mid pinMode(46, INPUT_PULLUP);//rst pinMode(49, INPUT_PULLUP);//set pinMode(50, INPUT_PULLUP);//left tft.setRotation(1); // повернуть экран tft.fillScreen(GREY); // заливка экрана tft.setTextColor(0xFFFF, GREY); // белый цвет шрифта/серая заливка tft.setTextSize(1); //размер шрифта 1-5 //tft.setFont(&FreeMono12pt7b); } static int levmenu; static unsigned long timer;// переменная для задержки отображения времени struct Menu //структура хранения данных меню { String myname; String paragraph[5]; int index; }; int menu(String myname, String paragraph[], int index, int levmenu)//функция отображения меню { const int poscur[] = {40, 80, 120, 160, 180};//координаты пунктов меню if (levmenu < 0) levmenu = index - 1; if (levmenu > index - 1) levmenu = 0; if (digitalRead(52) != HIGH) levmenu ++; if (digitalRead(53) != HIGH) levmenu --; tft.setTextSize(3); tft.setTextColor(0xFFFF, 0x0000); tft.setCursor(0, 0); tft.print(myname); for (int i = 0; i < index; i++) { tft.setCursor (0, poscur[i]); if (i != levmenu) tft.print(paragraph[i]); } tft.setTextColor(WHITE, BLUE); tft.setCursor(0, poscur[levmenu]); tft.print(paragraph[levmenu]); return levmenu; } void temphum(int x, int y)// выводит на экран температуру и влажность { // float h = dht.readHumidity(); //Измеряем влажность // float t = dht.readTemperature(); //Измеряем температуру tft.setCursor(x,y); tft.setTextSize(3); if(dht.readTemperature() > 28) tft.setTextColor(RED,GREY); else if(dht.readTemperature() < 24) tft.setTextColor(BLUE,GREY); else tft.setTextColor(GREEN, GREY); tft.print(dht.readTemperature()); tft.println("C"); tft.setTextColor(WHITE, GREY); tft.print(dht.readHumidity()); tft.print("%"); tft.setCursor(0, 0); } void loop () { static int realmenu;// переменная для навигации по страницам меню Menu mainmenu; mainmenu.myname = "MENU"; mainmenu.paragraph[0] = "Profil"; mainmenu.paragraph[1] = "Seting"; mainmenu.paragraph[2] = "Back"; mainmenu.index = 3; Menu profilmenu; profilmenu.myname = "PROFIL MENU"; profilmenu.paragraph[0] = "Select"; profilmenu.paragraph[1] = "Edit"; profilmenu.paragraph[2] = "Back"; profilmenu.index = 3; Menu setingmenu; setingmenu.myname = "SETING MENU"; setingmenu.paragraph[0] = "Clock"; setingmenu.paragraph[1] = "Calibration sensors"; setingmenu.paragraph[2] = "Back"; setingmenu.index = 3; if (realmenu == 0) // код отображения времени на главном экране { tft.setTextSize(2); tft.setTextColor(0xFFFF, 0x0000); tft.setCursor(120, 140); if (millis() - timer > 1000) { tft.setTextColor(0xFFFF, 0x0000); tft.print(time.gettime("H:i:s")); temphum(0, 0); timer = millis(); } if (digitalRead(48) != HIGH) { tft.fillScreen(GREY); tft.setTextColor(WHITE, GREY); realmenu = 1; } } if (realmenu == 1) { levmenu = menu(mainmenu.myname, mainmenu.paragraph, mainmenu.index, levmenu); if (digitalRead(48) != HIGH) { tft.fillScreen(0x0000); // обновление экрана заливкой switch (levmenu) { case 0: realmenu = 2; levmenu = 0; break; case 1: realmenu = 3; levmenu = 0; break; case 2: realmenu = 0; tft.fillScreen(0x0000); // обновление экрана заливкой levmenu = 0; break; } } } if (realmenu == 2) //2 - меню профиля { levmenu = menu(profilmenu.myname, profilmenu.paragraph, profilmenu.index, levmenu); if (digitalRead(48) != HIGH) { tft.fillScreen(0x0000); // обновление экрана заливкой switch (levmenu) { case 0: realmenu = 11; levmenu = 0; break; case 1: realmenu = 12; levmenu = 0; break; case 2: realmenu = 1; levmenu = 0; break; } } } if (realmenu == 3)// 3 - меню настроек системы { levmenu = menu(setingmenu.myname, setingmenu.paragraph, setingmenu.index, levmenu); if (digitalRead(48) != HIGH) { tft.fillScreen(0x0000); // обновление экрана заливкой switch (levmenu) { case 0: realmenu = 21; levmenu = 0; break; case 1: realmenu = 22; levmenu = 0; break; case 2: realmenu = 1; levmenu = 0; break; } } } if (realmenu == 21)// настройки часов { static int setclock;//переменная определения типа настраиваемого времени часы, минуты, секунды tft.setCursor(200, 0); tft.print(levmenu); tft.setCursor(0, 0); tft.print("TIME SETUP"); tft.setCursor(60, 150); tft.print(time.gettime("H:i:s")); if (digitalRead(52) != HIGH) levmenu ++; if (digitalRead(53) != HIGH) levmenu --; switch (setclock) { case 0: levmenu = time.Hours; time.blinktime(3); if(digitalRead(52) != HIGH) levmenu ++; if(digitalRead(53) != HIGH) levmenu --; if(levmenu > 60) levmenu = 0; if(levmenu < 0) levmenu = 60; if (digitalRead(48) != HIGH) setclock = 1; time.settime(-1, -1, levmenu); break; case 1: time.blinktime(2); levmenu = time.minutes; if(digitalRead(52) != HIGH) levmenu ++; if(digitalRead(53) != HIGH) levmenu --; if(levmenu > 60) levmenu = 0; if(levmenu < 0) levmenu = 60; if(digitalRead(48) != HIGH) setclock = 2; time.settime(-1, levmenu); break; case 2: time.blinktime(1); levmenu = time.seconds; if(digitalRead(52) != HIGH) levmenu ++; if(digitalRead(53) != HIGH) levmenu --; if(levmenu > 60) levmenu = 0; if(levmenu < 0) levmenu = 60; time.settime(levmenu); if(digitalRead(48) != HIGH) { setclock = 0; realmenu = 1; time.blinktime(0); levmenu = 0; tft.fillScreen(0x0000); // обновление экрана заливкой } break; } } }
главный принцип при работы с ТФТ-экраном на ардуино - обновлять как можно меньшую часть изображения, перерисовывать только то. что реально изменилось. Это связано с тем, что реально ардуина экран 320Х200 по быстродействию едва тянет и например заполнение экрана каким-то цветом занимает очень заметное время. Теперь смотрим в ваш код - вы делаете fillScreen() по нескольку раз подряд, выводите на экран информацию и сразу ее чистите, так что юзер не успевает ничего понять. Вот например: Код (C++): if (digitalRead(48) != HIGH) { tft.fillScreen(GREY); tft.setTextColor(WHITE, GREY); realmenu = 1; } } if (realmenu == 1) { levmenu = menu(mainmenu.myname, mainmenu.paragraph, mainmenu.index, levmenu); if (digitalRead(48) != HIGH) { tft.fillScreen(0x0000); // обновление экрана заливкой что мы видим. вы проверяете кнопку на пине 48, если она нажата, вы первым делом заливаете весь экран серым цветом. Потом вы приравниваете realmenu = 1;. Сразу после этого программа попадает в условие if (realmenu == 1) и выполняетеся конструирование меню, на экран выводятся какие-то строчки и тд.... Потом идет снова проверка кнопки 48 - и скорее всего она снова нажата, потому что мы ее только что проверяли. И что мы видим - вы снова чистите экран заливкой... ЗАЧЕМ? - зачем чистить экран два раза подряд? и зачем между двумя чистками вы рисовали на нем меню?? Чтобы сразу его стереть? И такая, с позволения сказать. кривая логика у вас по всей программе... Есть и другие очевидные косяки. например с описанием переиенных. Зачем вы в начале процедуры loop() каждый раз заново создаете строчки меню? - они же не меняются, так вынесите их в глобальные переменные и создайте один раз.
Что хочу сказать, если не обновлять экран перед сменой пунктов меню то, текст из одних пунктов накладывается на текст из других пунктов, экран 480x320 tft там логика такая, что процессор экрана обновляет только измененные пиксели, в данном случае у нас один цвет фона по всей программе обновляется только те участки которое это требует, и еще самое важное, что это только пилотный образец и цвета пока экспериментальные для пробы пера, а как быть с кнопкой, как раз чтение кнопки сейчас не совсем комфортное, но позволяет свободно перемещаться по меню, пунктов меню и его глубины будет много. Есть какие то пожелания которые могут помочь с кнопками?
Во-первых, надо обновлять экран только под обновляемыми пунктами меню. Во-вторых, обновлять экран, рисовать на нем меняю и тут же стирать снова - это дурость несусветная. с чего вы это взяли? - он все подряд обновляет сорри за грубость, но вы русский язык плохо понимаете? - я вам уже три раза сказал. в чем у вас беда с кнопками... У вас очень медленный кривой код, который надо убыстрить примерно на порядок. Вы или делаете что вам говорят - разбираетесь с меню, убираете многократные перерисовки - или если не хотите - разбирайтесь тогда сами.
Код (C++): #include <gfxfont.h> #include <UTFTGLUE.h> #include <DHT.h> #include <iarduino_RTC.h> #include <Adafruit_GFX.h> #include <FreeDefaultFonts.h> #include <Fonts/FreeMono12pt7b.h> #include <MCUFRIEND_kbv.h> MCUFRIEND_kbv tft(A3, A2, A1, A0, A4);//int CS=A3, RS=A2, WR=A1, RD=A0, RST=A4; iarduino_RTC time(RTC_DS1302, 47, 29, 39); DHT dht(44, DHT22); //Инициация датчика #define BLACK 0x0000 #define NAVY 0x000F #define DARKGREEN 0x03E0 #define DARKCYAN 0x03EF #define MAROON 0x7800 #define PURPLE 0x780F #define OLIVE 0x7BE0 #define LIGHTGREY 0xC618 #define DARKGREY 0x7BEF #define BLUE 0x001F #define GREEN 0x07E0 #define CYAN 0x07FF #define RED 0xF800 #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define WHITE 0xFFFF #define ORANGE 0xFD20 #define GREENYELLOW 0xAFE5 #define PINK 0xF81F #define GREY 0x8410 void setup() { Serial.begin (9600);// инициализация монитора порта time.begin(); dht.begin(); uint16_t ID = tft.readID();// получение информации о дисплее tft.begin(ID);// инициализация дисплея pinMode(52, INPUT_PULLUP);//up pinMode(53, INPUT_PULLUP);//dw pinMode(48, INPUT_PULLUP);//mid pinMode(46, INPUT_PULLUP);//rst pinMode(49, INPUT_PULLUP);//set pinMode(50, INPUT_PULLUP);//left tft.setRotation(1); // повернуть экран tft.fillScreen(GREY); // заливка экрана tft.setTextColor(0xFFFF, GREY); // белый цвет шрифта/сераязаливка tft.setTextSize(1); //размер шрифта 1-5 //tft.setFont(&FreeMono12pt7b); } static int levmenu; static unsigned long timer;// переменная для задержки отображения времени struct Menu //структура хранения данных меню { String myname; String paragraph[5]; int index; }; int menu(String myname, String paragraph[], int index, int levmenu)//функция отображения меню { const int poscur[] = {40, 80, 120, 160, 180};//координаты пунктов меню if (levmenu < 0) levmenu = index - 1; if (levmenu > index - 1) levmenu = 0; if (digitalRead(52) != HIGH) levmenu ++; if (digitalRead(53) != HIGH) levmenu --; tft.setTextSize(3); tft.setCursor(0, 0); tft.setTextColor(BLACK,GREY); tft.print(myname); for (int i = 0; i < index; i++) { tft.setCursor (0, poscur[i]); if (i != levmenu) tft.print(paragraph[i]); } tft.setTextColor(WHITE, BLACK); tft.setCursor(0, poscur[levmenu]); tft.print(paragraph[levmenu]); return levmenu; } void temphum(int x, int y)// выводит на экран температуру и влажность { // float h = dht.readHumidity(); //Измеряем влажность // float t = dht.readTemperature(); //Измеряем температуру tft.setCursor(x,y); tft.setTextSize(3); if(dht.readTemperature() > 28) tft.setTextColor(RED,GREY); else if(dht.readTemperature() < 24) tft.setTextColor(BLUE,GREY); else tft.setTextColor(GREEN, GREY); tft.print(dht.readTemperature()); tft.println("C"); tft.setTextColor(WHITE, GREY); tft.print(dht.readHumidity()); tft.print("%"); tft.setCursor(0, 0); } void loop () { static int realmenu;// переменная для навигации по страницам меню Menu mainmenu; mainmenu.myname = "MENU"; mainmenu.paragraph[0] = "Profil"; mainmenu.paragraph[1] = "Seting"; mainmenu.paragraph[2] = "Back"; mainmenu.index = 3; Menu profilmenu; profilmenu.myname = "PROFIL MENU"; profilmenu.paragraph[0] = "Select"; profilmenu.paragraph[1] = "Edit"; profilmenu.paragraph[2] = "Back"; profilmenu.index = 3; Menu setingmenu; setingmenu.myname = "SETING MENU"; setingmenu.paragraph[0] = "Clock"; setingmenu.paragraph[1] = "Calibration sensors"; setingmenu.paragraph[2] = "Back"; setingmenu.index = 3; if (realmenu == 0) // код отображения времени на главном экране { tft.setTextSize(2); tft.setTextColor(0xFFFF, GREY); tft.setCursor(120, 140); if (millis() - timer > 1000) { tft.setTextColor(0xFFFF, GREY); tft.print(time.gettime("H:i:s")); temphum(0, 0); timer = millis(); } if (digitalRead(48) != HIGH) { tft.fillScreen(GREY); tft.setTextColor(WHITE, GREY); realmenu = 1; } } if (realmenu == 1) { levmenu = menu(mainmenu.myname, mainmenu.paragraph, mainmenu.index, levmenu); if (digitalRead(48) != HIGH) { tft.fillScreen(GREY); // обновление экрана заливкой switch (levmenu) { case 0: realmenu = 2; levmenu = 0; break; case 1: realmenu = 3; levmenu = 0; break; case 2: realmenu = 0; levmenu = 0; break; } } } if (realmenu == 2) //2 - меню профиля { levmenu = menu(profilmenu.myname, profilmenu.paragraph, profilmenu.index, levmenu); if (digitalRead(48) != HIGH) { tft.fillScreen(GREY); // обновление экрана заливкой switch (levmenu) { case 0: realmenu = 11; levmenu = 0; break; case 1: realmenu = 12; levmenu = 0; break; case 2: realmenu = 1; levmenu = 0; break; } } } if (realmenu == 3)// 3 - меню настроек системы { levmenu = menu(setingmenu.myname, setingmenu.paragraph, setingmenu.index, levmenu); if (digitalRead(48) != HIGH) { tft.fillScreen(GREY); // обновление экрана заливкой switch (levmenu) { case 0: realmenu = 21; levmenu = 0; break; case 1: realmenu = 22; levmenu = 0; break; case 2: realmenu = 1; levmenu = 0; break; } } } if (realmenu == 21)// настройки часов { static int setclock;//переменная определения типа настраиваемого времени часы, минуты, секунды tft.setCursor(200, 0); tft.print(levmenu); tft.setCursor(0, 0); tft.print("TIME SETUP"); tft.setCursor(60, 150); tft.print(time.gettime("H:i:s")); if (digitalRead(52) != HIGH) levmenu ++; if (digitalRead(53) != HIGH) levmenu --; switch (setclock) { case 0: levmenu = time.Hours; time.blinktime(3); if(digitalRead(52) != HIGH) levmenu ++; if(digitalRead(53) != HIGH) levmenu --; if(levmenu > 60) levmenu = 0; if(levmenu < 0) levmenu = 60; if (digitalRead(48) != HIGH) setclock = 1; time.settime(-1, -1, levmenu); break; case 1: time.blinktime(2); levmenu = time.minutes; if(digitalRead(52) != HIGH) levmenu ++; if(digitalRead(53) != HIGH) levmenu --; if(levmenu > 60) levmenu = 0; if(levmenu < 0) levmenu = 60; if(digitalRead(48) != HIGH) setclock = 2; time.settime(-1, levmenu); break; case 2: time.blinktime(1); levmenu = time.seconds; if(digitalRead(52) != HIGH) levmenu ++; if(digitalRead(53) != HIGH) levmenu --; if(levmenu > 60) levmenu = 0; if(levmenu < 0) levmenu = 60; time.settime(levmenu); if(digitalRead(48) != HIGH) { setclock = 0; realmenu = 1; time.blinktime(0); levmenu = 0; tft.fillScreen(GREY); // обновление экрана заливкой } break; } } } исправил несколько перерисовок, и разобрался с цветами что бы не было проблем. с пониманием. коа. допустим можно ускорить эту часть кода но это все лишь 10% от задумки все равно скорость будет падать, а значит ловить нажатия "онлайн" не вариант. тут видно как визуально впроисходит навигация
учитесь правильно писать код. Не пишите его "линейно", когда все программа выполняется последовательно. Разбивайте работу на маленькие кусочки, после каждой части возвращайтесь в основную програму и проверяйте кнопки и делайте другие неотложные дела. Вот например у вас в коде вы проходите через все пункты меню. Это логически неверно. Сменилось меню - сначалай выйдите в корень программы, проверьте кнопки. потом войдите в другое. И так каждый раз. Почитайте что-нибудь про конечные автоматы. все сложные программы пишутся только так.
основной код программы еще не написан, но ведь если меню не активно то и функция не будет запущена, и код пройдет мимо, а если какое либо из меню активно то код идет только ней. А с кнопками я так и не приблизился к ответу, неужели если бы я умел красиво писать то просил бы у вас помощи (в лучшем случае то помогал бы сам), сейчас я знаю, что буду делать, это расширять функцию меню, перенося в нее условия отображения из петли, затем, перенесу установку часов в функцию, и заменю большую часть алгоритма на switch. А дальше мозг не позволяет понять ваши советы.
Последнее время больше внимания уделяю правильным, красивым и оптимальным решениям. Раньше старался быстро написать, как получается, сейчас хочется найти оптимальное решение. Поэтому выкладывал здесь обработку дребезга на вертикальных счетчиках.Это бест из обработки дребезга. Протащтился от оптимальности. По меню - это структуры с диапазонами, и указателями на функции обработки. Это тоже бест! Работают без ошибок годами. Не получается сделать ошибку. Я в 1990-ых написал утилиту, которая позволяла в интерактиве, создать пользовательское меню с подменю под нашу операционную систему, под которую писала софт на Си и Асме вся контора. То есть, ты в графическом режиме создаешь меню. Мышь, и контекстные меню. Главное - расположение на экране. Выбор подложки, теней, стилей меню - все было Генерится текст программы на Си, который потом компилируется и идеально соответствует данным программы из MS-DOS. Потом в структуры в забиваются функции обработки. Вдохновила утилита makemenu из примеров Паскаля.
не пытался разобраться в коде, поэтому может тупость напишу - мне кажется лучше сделать отдельную функцию обновления экрана, в которой нужный текст будет прописываться в нужное место, и главное - только тогда, когда это надо, о чем сигнал передавать через флаг, который будет взводиться когда произошли изменения требующие перерисовки то есть функция стоит в одном месте в цикле и ждет когда взведется флаг, тогда принимает нужный текст и координаты и рисует на экран.
Послушайте, я с удовольствием приму все ваши пожелания, так как понимаю, что мои знания хуже чем чьи либо на форуме, но давайте не будем отходить от темы, я уже осознал что код кривой и знал об этом мне было стыдно его выкладывать, но суть темы мы так и не затронули, точно знаю, что нельзя пользоваться аппаратными прерываниями, значит остается пользоваться прерываниями по таймеру соответственно нужно создать такое количество переменных которое соответствует количеству кнопок, для создания тримера, либо создать еще одно временное прерывание что бы избавиться от дребезга? Какая из библиотек имеет такие функии, и поможет мне?
вы знаете, меня на этом форуме просили не кидаться на новичков. но вы меня выводите из себя. До вас так и не дошло, что все эти рассуждаения о меню и конечных автоматах - это и есть СУТЬ ТЕМЫ?? ведь все это нужно именно для того, чтобы ваши кнопки заработали! Последний раз обьясняю - вам нужно переписать код так, чтобы исполнения основного цикла занимало от 5 до 20 мс. И я уверен, что это ТОЧНО ВОЗМОЖНО, каким бы сложным у вас не был код. И тогда никакие прерывания для кнопок не понадобятся. А на прерывания не надейтесь. Со своими почти нулнвыми знаниями вы просто не понимаете, что они вашу проблему не решают. В прерываниях вы максимум что можете сделать - это поймать сам факт нажатия кнопки. А отрабатывать реакцию на кнопку все равно нужно в основной программе - а значит так или иначе ускорять основной цикл все до тех же 20мс все равно придется, с прерываниями или без них. Вообще, судя по коду и вопросам, вам бы надо еще с полгода поделать простенькие проекты, этот вы начали рано, вам его сейчас не потянуть.
та, которую сам напишешь. Я с кнопками вот так делал: Код (C++): void Get_Button(void) { Switch.Press_up = (~Switch_up_reg & (1 << Switch_up)); Switch.Press_down = (~Switch_down_reg & (1 << Switch_down)); switch (Switch.Key) { case Button_off: if (Switch.Press_up) { Switch.Key = Button_up; Timer0_Start(); } if (Switch.Press_down) { Switch.Key = Button_down; Timer0_Start(); } break; case Button_up: if (!Switch.Press_up) { Switch.Key = Button_Pause_up; Timer0_Clear(); } break; case Button_Pause_up: if (Switch.Press_up) { Switch.Key = Button2_up; Timer0_Clear(); } break; case Button2_up: if (!Switch.Press_up) { Switch.Key = Button_Double_up; Timer0_Stop(); } break; case Button_Long_up: if (!Switch.Press_up) { Switch.Key = Button_off; } break; case Button_down: if (!Switch.Press_down) { Switch.Key = Button_Pause_down; Timer0_Clear(); } break; case Button_Pause_down: if (Switch.Press_down) { Switch.Key = Button2_down; Timer0_Clear(); } break; case Button2_down: if (!Switch.Press_down) { Switch.Key = Button_Double_down; Timer0_Stop(); } break; case Button_Long_down: if (!Switch.Press_down) { Switch.Key = Button_off; } break; } } А саму функцию Get_Button() вызываю 50 раз в секунду и в структуре Switch у меня всегда лежат актуальные данные о состоянии кнопок.
Один мой знакомый только получил права и купил не дорогую машину. У него не горела одна фара. Он обратился в сервис с помощью, а ему там ответили, что у него медленная машина и в добавок ко всему еще и не красивая, и если он хочет что бы заработала фара, то поменяй ее или чини сам.
один мой знакомый буквально вчера написал на другом форуме про такие вопросы: "У меня сломана нога, но пока я лежу в кровати. она не болит. Прошу. не советуйте мне, как лечить ногу, посоветуйте, как пробежать марафон"