Помогите с LCD меню
- Войдите на сайт для отправки комментариев
Втр, 22/10/2013 - 23:23
Доброго времени суток, друзья!
Недавно наткнулся на код одного из форумчан, yul-i-an. Так вот, запустил я его, всё класно, но мерцает экран, может кто смог бы подсказать где поставить перерисовку экрана, чтобы она не заставляла его постоянно мерцать.
Буду крайне благодарен, если кто сможет подсказать, как значения, которые выбираются в меню можно писать в EEPROM.
Всем откликнувшимся огромное спасибо!
Далее привожу пример кода, наверное это самое внятное меню, которое я пока встречал.
1 |
//Пример простого меню для Arduino |
002 |
//В меню используется 4 экрана |
003 |
//за номер отображаемого экрана отвечает переменная m |
004 |
//Значения переменных р1,р2 меняются циклически от 0-10 затем опять 0, р3(LED) только 0 или 1 |
005 |
006 |
#include <LiquidCrystal.h> //Библиотека LCD |
007 |
// инициализация LCD |
008 |
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); |
009 |
int m=0; //переменная для экранов меню |
010 |
int p1=0; // переменная для переменной 1 |
011 |
int p2=0; // -//- 2 |
012 |
int p3=0; // -//- 3 |
013 |
014 |
byte nextPin = 6; //кнопка NEXT на 6 входе |
015 |
byte prevPin = 7; //кнопка PREV |
016 |
byte upPin = 9; //увеличение значения (UP) отображаемого параметра |
017 |
byte downPin = 10; //уменьшение значения (DOWN) |
018 |
byte ledPin =13; //Светодиод (исполнительное устройство) |
019 |
020 |
long previousMillis = 0; //счетчик прошедшего времени для AutoMainScreen |
021 |
long interval = 3000; //задержка автовозврата к MainScreen 3сек |
022 |
023 |
void setup() { |
024 |
//Настройка входов |
025 |
pinMode(nextPin, INPUT); |
026 |
pinMode(prevPin, INPUT); |
027 |
pinMode(upPin, INPUT); |
028 |
pinMode(downPin, INPUT); |
029 |
//Настройка выходов |
030 |
pinMode(ledPin, OUTPUT); |
031 |
//Настройка дисплея |
032 |
//Установка количества столбцов и строк дисплея |
033 |
lcd.begin(16, 2); |
034 |
// Вывод приветствия при включении питания если нужно |
035 |
lcd.setCursor(3, 0); |
036 |
lcd.print("DEMO MENU"); |
037 |
delay (300);//Задержка приветствия |
038 |
} |
039 |
040 |
void loop() { |
041 |
unsigned long currentMillis = millis(); |
042 |
//Обработка нажатия кнопки NEXT |
043 |
if (digitalRead(nextPin)== HIGH) |
044 |
{ |
045 |
m++;//увеличиваем переменную уровня меню |
046 |
previousMillis = currentMillis; //если кнопка была нажата сбросить счетчик автовозврата к главному экрану |
047 |
delay (100); |
048 |
//lcd.clear(); |
049 |
if (m>3)//если уровень больше 3 |
050 |
{ |
051 |
m=0;// то вернуться к началу |
052 |
} |
053 |
} |
054 |
//Обработка нажатия кнопки PREV |
055 |
if (digitalRead(prevPin)== HIGH) |
056 |
{ |
057 |
m--; |
058 |
previousMillis = currentMillis; |
059 |
delay (100); |
060 |
//lcd.clear(); |
061 |
if (m<0) |
062 |
{ |
063 |
m=3; |
064 |
} |
065 |
} |
066 |
|
067 |
//Обработка нажатия UP для р1 |
068 |
if (digitalRead(upPin)== HIGH && m==1)//если находимся на экране с переменной р1 |
069 |
{ |
070 |
p1++; //то при нажатии кнопки + увеличиваем переменную р1 на единицу |
071 |
previousMillis = currentMillis; |
072 |
delay (100); |
073 |
//lcd.clear(); |
074 |
if (p1>10) //устанавливаем придел изменения переменной = 10 |
075 |
{ //если больше предела |
076 |
p1=0; //то возвращаем ее к 0 (тут код условия что делать при достижении приделов) |
077 |
} |
078 |
} |
079 |
//UP для р2 |
080 |
if (digitalRead(upPin)== HIGH && m==2) |
081 |
{ |
082 |
p2++; |
083 |
previousMillis = currentMillis; |
084 |
delay (100); |
085 |
//lcd.clear(); |
086 |
if (p2>10) |
087 |
{ |
088 |
p2=0; |
089 |
} |
090 |
} |
091 |
//UP для р3 |
092 |
if (digitalRead(upPin)== HIGH && m==3) |
093 |
{ |
094 |
p3++; |
095 |
previousMillis = currentMillis; |
096 |
delay (100); |
097 |
//lcd.clear(); |
098 |
if (p3>1) |
099 |
{ |
100 |
p3=0; |
101 |
} |
102 |
digitalWrite(ledPin, p3); |
103 |
} |
104 |
//сдесь код для уменьшения значений |
105 |
//аналогичен коду увеличения если нужно |
106 |
|
107 |
//Вывод меню |
108 |
//Описание экранов меню |
109 |
lcd.clear(); |
110 |
if (m==0) //переменная m=0 |
111 |
{ //отображаем |
112 |
lcd.setCursor(3, 0); //******************* |
113 |
lcd.print("Main Screen"); //*Main Screen * |
114 |
lcd.setCursor(0, 1); //*P1=p1 P2=p2 LED=0* |
115 |
lcd.print("P1="); //******************* |
116 |
lcd.print(p1); |
117 |
lcd.print(" P2="); |
118 |
lcd.print(p2); |
119 |
lcd.print(" LED="); |
120 |
lcd.print(p3); |
121 |
} |
122 |
else if (m==1) //переменная m=1 |
123 |
{ //отображаем |
124 |
lcd.setCursor(0, 0); //******************* |
125 |
lcd.print("Parametr-1"); //*Parametr-1 * |
126 |
lcd.setCursor(0, 1); //*P1=p1 * |
127 |
lcd.print("P1 = "); //******************* |
128 |
lcd.print(p1); |
129 |
} |
130 |
else if (m==2) //переменная m=2 |
131 |
{ //отображаем |
132 |
lcd.setCursor(0, 0); //******************* |
133 |
lcd.print("Parametr-2"); //*Parametr-2 * |
134 |
lcd.setCursor(0, 1); //*P2=p2 * |
135 |
lcd.print("P2 = "); //******************* |
136 |
lcd.print(p2); |
137 |
} |
138 |
else if (m==3) //переменная m=3 |
139 |
{ //отображаем |
140 |
lcd.setCursor(0, 0); //******************* |
141 |
lcd.print("LED Control"); //LED Control * |
142 |
lcd.setCursor(0, 1); //LED = p3 * |
143 |
lcd.print("LED = "); //******************* |
144 |
lcd.print(p3); |
145 |
} |
146 |
//Проверка автовозврата |
147 |
if(currentMillis - previousMillis > interval) //Если счетчик |
148 |
{ |
149 |
previousMillis = currentMillis; //достиг интервала |
150 |
m=0; //то отобразить главный экран |
151 |
//lcd.clear(); |
152 |
} |
153 |
//yul-i-an@gmail.com форум allduino.forum2x2.ru |
154 |
} |
//Пример простого меню для Arduino //В меню используется 4 экрана //за номер отображаемого экрана отвечает переменная m //Значения переменных р1,р2 меняются циклически от 0-10 затем опять 0, р3(LED) только 0 или 1 #include <LiquidCrystal.h> //Библиотека LCD // инициализация LCD LiquidCrystal lcd(12, 11, 5, 4, 3, 2); int m=0; //переменная для экранов меню int p1=0; // переменная для переменной 1 int p2=0; // -//- 2 int p3=0; // -//- 3 byte nextPin = 6; //кнопка NEXT на 6 входе byte prevPin = 7; //кнопка PREV byte upPin = 9; //увеличение значения (UP) отображаемого параметра byte downPin = 10; //уменьшение значения (DOWN) byte ledPin =13; //Светодиод (исполнительное устройство) long previousMillis = 0; //счетчик прошедшего времени для AutoMainScreen long interval = 3000; //задержка автовозврата к MainScreen 3сек void setup() { //Настройка входов pinMode(nextPin, INPUT); pinMode(prevPin, INPUT); pinMode(upPin, INPUT); pinMode(downPin, INPUT); //Настройка выходов pinMode(ledPin, OUTPUT); //Настройка дисплея //Установка количества столбцов и строк дисплея lcd.begin(16, 2); // Вывод приветствия при включении питания если нужно lcd.setCursor(3, 0); lcd.print("DEMO MENU"); delay (300);//Задержка приветствия } void loop() { unsigned long currentMillis = millis(); //Обработка нажатия кнопки NEXT if (digitalRead(nextPin)== HIGH) { m++;//увеличиваем переменную уровня меню previousMillis = currentMillis; //если кнопка была нажата сбросить счетчик автовозврата к главному экрану delay (100); //lcd.clear(); if (m>3)//если уровень больше 3 { m=0;// то вернуться к началу } } //Обработка нажатия кнопки PREV if (digitalRead(prevPin)== HIGH) { m--; previousMillis = currentMillis; delay (100); //lcd.clear(); if (m<0) { m=3; } } //Обработка нажатия UP для р1 if (digitalRead(upPin)== HIGH && m==1)//если находимся на экране с переменной р1 { p1++; //то при нажатии кнопки + увеличиваем переменную р1 на единицу previousMillis = currentMillis; delay (100); //lcd.clear(); if (p1>10) //устанавливаем придел изменения переменной = 10 { //если больше предела p1=0; //то возвращаем ее к 0 (тут код условия что делать при достижении приделов) } } //UP для р2 if (digitalRead(upPin)== HIGH && m==2) { p2++; previousMillis = currentMillis; delay (100); //lcd.clear(); if (p2>10) { p2=0; } } //UP для р3 if (digitalRead(upPin)== HIGH && m==3) { p3++; previousMillis = currentMillis; delay (100); //lcd.clear(); if (p3>1) { p3=0; } digitalWrite(ledPin, p3); } //сдесь код для уменьшения значений //аналогичен коду увеличения если нужно //Вывод меню //Описание экранов меню lcd.clear(); if (m==0) //переменная m=0 { //отображаем lcd.setCursor(3, 0); //******************* lcd.print("Main Screen"); //*Main Screen * lcd.setCursor(0, 1); //*P1=p1 P2=p2 LED=0* lcd.print("P1="); //******************* lcd.print(p1); lcd.print(" P2="); lcd.print(p2); lcd.print(" LED="); lcd.print(p3); } else if (m==1) //переменная m=1 { //отображаем lcd.setCursor(0, 0); //******************* lcd.print("Parametr-1"); //*Parametr-1 * lcd.setCursor(0, 1); //*P1=p1 * lcd.print("P1 = "); //******************* lcd.print(p1); } else if (m==2) //переменная m=2 { //отображаем lcd.setCursor(0, 0); //******************* lcd.print("Parametr-2"); //*Parametr-2 * lcd.setCursor(0, 1); //*P2=p2 * lcd.print("P2 = "); //******************* lcd.print(p2); } else if (m==3) //переменная m=3 { //отображаем lcd.setCursor(0, 0); //******************* lcd.print("LED Control"); //LED Control * lcd.setCursor(0, 1); //LED = p3 * lcd.print("LED = "); //******************* lcd.print(p3); } //Проверка автовозврата if(currentMillis - previousMillis > interval) //Если счетчик { previousMillis = currentMillis; //достиг интервала m=0; //то отобразить главный экран //lcd.clear(); } //yul-i-an@gmail.com форум allduino.forum2x2.ru }В первом посте похоже запорол исходный код, вставил криво.
Так вот, запустил я его, всё класно, но мерцает экран, может кто смог бы подсказать где поставить перерисовку экрана, чтобы она не заставляла его постоянно мерцать.
Ясно - всё хорошо, но плохо.
не вникая в суть программы можно сделать вывод, что автор пытался избавиться от мерцания(//lcd.clear();), но не осилил.
по сути:
- lcd.clear() нужно использовать, тогда когда необходимо очистить весь экран.
- применение delay (100) тоже маловразумительно, может и не влияет на мерцания, но тормозит выполнение программы, что не есть правильно.
В том то и вопрос, delay по сути подвешивает весь процесс на какое то время. Из моих догадок - надо каким то образом повесить lcd.clear только там, где у нас происходят нажатие на кнопки, в том числе и при изменении параметров.
Клапауций буду крайне благодарен если поможете асилить новичку сей код.
Код не смотрел, но, есть варианты не чистить экран, а выделить в памяти место под буфер для вывода и обновлять этот буфер, а потом его выводить, тогда и чистить экран не нужно.
А вам доводилось делать меню?
На самом деле я ищу вариант с наименее запутанной структурой и простотой использования. Может есть идеи, примеры?
Не вижу проблем, DI HALT эту тему (отображение информации на лсд экран) разжевал вполне достаточно, чтобы этим вопросом не париться.
Потому я и говорю, пишем информацию в буфер, а потом весь буфер отображаем. Чему тут моргать то?
ну, так и делайте c единственной поправкой - если вам не нужно очищать экран, то не нужно этого делать, если вам кажется, что вам нужно очистить экран, то возможно вам нужно перезаписать экран или перезаписать один или несколько символов.
все записи в экран производить не в общем теле программы, а по условию изменения чего-либо - изменения переменной, нажатия на кнопку, предыдущие состояния переменных и состояний кнопок хранить в оперативке.
можно использовать следующие конструкции - типо подпрограммы:
// для кнопки void BUTTON() { int nb = digitalRead(3); if (nb != b) { b = nb; if (digitalRead(3) == LOW) {что-то делаем при нажатии кнопки - здесь можно стереть экран, если нужно;} if (digitalRead(3) == HIGH) {что-то делаем при отпускании кнопки - здесь можно стереть экран, если нужно;} } }// для переменной, обобщённый вариант. void TEMP() { int nb = (источник переменной, датчик или что ещё); if (nb != b) { b = nb; if (digitalRead(3) == LOW) { } if (digitalRead(3) == HIGH) { } } }Спасибо большое, будем мучать.
А у вас нет примеров ваших меню из проектов?
И что можете сказать про применение EEPROM для хранения данных?
В общем получилось немного оптимизировать код на свой манер. Единственное что не нравится - как реагируют кнопки на нажатие. Иногда может пропустить значение, тоесть как двойное нажатие срабатывает. Насколько помню, это как то лечится с помощью bounce. Но я честно говоря дикий нуб в этом деле, поэтому может кто поможет поправить код. Ещё не получилось прописать кнопку down, чтобы значение можно было уменьшать :( Что ещё хочу - избавиться от delay.
Вот что вышло:
//Пример простого меню для Arduino //В меню используется 4 экрана //за номер отображаемого экрана отвечает переменная m //Значения переменных р1,р2 меняются циклически от 0-10 затем опять 0, р3(LED) только 0 или 1 #include <Wire.h> #include <LCD.h> #include <LiquidCrystal_I2C.h> #define LCD_I2C_ADDR 0x27 // Define I2C Address where the PCF8574A is #define BACKLIGHT 15 //PIN that turn on backlight #define LCD_EN 2 #define LCD_RW 1 #define LCD_RS 0 #define LCD_D4 4 #define LCD_D5 5 #define LCD_D6 6 #define LCD_D7 7 // инициализация LCD LiquidCrystal_I2C lcd(LCD_I2C_ADDR,LCD_EN,LCD_RW,LCD_RS,LCD_D4,LCD_D5,LCD_D6,LCD_D7); int m=0; //переменная для экранов меню int p1=0; // переменная для переменной 1 int p2=0; // -//- 2 int p3=0; // -//- 3 byte nextPin = 34; //кнопка NEXT на 6 входе byte prevPin = 32; //кнопка PREV byte upPin = 30; //увеличение значения (UP) отображаемого параметра byte downPin = 28; //уменьшение значения (DOWN) byte ledPin =13; //Светодиод (исполнительное устройство) long previousMillis = 0; //счетчик прошедшего времени для AutoMainScreen long interval = 5000; //задержка автовозврата к MainScreen 3сек void setup() { //Настройка входов pinMode(nextPin, INPUT); pinMode(prevPin, INPUT); pinMode(upPin, INPUT); pinMode(downPin, INPUT); //Настройка выходов pinMode(ledPin, OUTPUT); //Настройка дисплея //Установка количества столбцов и строк дисплея lcd.begin(20, 4); // Вывод приветствия при включении питания если нужно lcd.setCursor(3, 0); lcd.print("DEMO MENU"); delay (300);//Задержка приветствия } void loop() { unsigned long currentMillis = millis(); //Обработка нажатия кнопки NEXT if (digitalRead(nextPin)== HIGH) { m++;//увеличиваем переменную уровня меню lcd.clear(); previousMillis = currentMillis; //если кнопка была нажата сбросить счетчик автовозврата к главному экрану delay (100); if (digitalRead(nextPin)== LOW) { lcd.clear(); } if (m>3)//если уровень больше 3 { m=0;// то вернуться к началу } } //Обработка нажатия кнопки PREV if (digitalRead(prevPin)== HIGH) { m--; previousMillis = currentMillis; delay (100); if (digitalRead(prevPin)== LOW) { lcd.clear(); } //lcd.clear(); if (m<0) { m=3; } } //Обработка нажатия UP для р1 if (digitalRead(upPin)== HIGH && m==1)//если находимся на экране с переменной р1 { p1++; //то при нажатии кнопки + увеличиваем переменную р1 на единицу previousMillis = currentMillis; delay (100); if (digitalRead(upPin)== LOW) { lcd.clear(); } //lcd.clear(); if (p1>10) //устанавливаем придел изменения переменной = 10 { //если больше предела p1=0; //то возвращаем ее к 0 (тут код условия что делать при достижении приделов) } } //UP для р2 if (digitalRead(upPin)== HIGH && m==2) { p2++; previousMillis = currentMillis; delay (100); if (digitalRead(upPin)== LOW) { lcd.clear(); } //lcd.clear(); if (p2>10) { p2=0; } } //UP для р3 if (digitalRead(upPin)== HIGH && m==3) { p3++; previousMillis = currentMillis; delay (100); if (digitalRead(upPin)== LOW) { lcd.clear(); } if (p3>1) { p3=0; } digitalWrite(ledPin, p3); } //сдесь код для уменьшения значений //аналогичен коду увеличения если нужно //Вывод меню //Описание экранов меню if (m==0) //переменная m=0 { //отображаем lcd.setCursor(3, 0); //******************* lcd.print("Main Screen"); //*Main Screen * lcd.setCursor(0, 1); //*P1=p1 P2=p2 LED=0* lcd.print("P1="); //******************* lcd.print(p1); lcd.print(" P2="); lcd.print(p2); lcd.print(" LED="); lcd.print(p3); } else if (m==1) //переменная m=1 { //отображаем lcd.setCursor(0, 0); //******************* lcd.print("Parametr-1"); //*Parametr-1 * lcd.setCursor(0, 1); //*P1=p1 * lcd.print("P1 = "); //******************* lcd.print(p1); // lcd.clear(); } else if (m==2) //переменная m=2 { //отображаем lcd.setCursor(0, 0); //******************* lcd.print("Parametr-2"); //*Parametr-2 * lcd.setCursor(0, 1); //*P2=p2 * lcd.print("P2 = "); //******************* lcd.print(p2); // lcd.clear(); } else if (m==3) //переменная m=3 { //отображаем lcd.setCursor(0, 0); //******************* lcd.print("LED Control"); //LED Control * lcd.setCursor(0, 1); //LED = p3 * lcd.print("LED = "); //******************* lcd.print(p3); // lcd.clear(); } //Проверка автовозврата if(currentMillis - previousMillis > interval && m !=0) //Если счетчик { previousMillis = currentMillis; //достиг интервала lcd.clear(); m=0; //то отобразить главный экран } }Клапауций
Может могли бы поглядеть мой код, сказать где что поправить. Спасибо заранее!
Клапауций
Может могли бы поглядеть мой код, сказать где что поправить. Спасибо заранее!
я не программист совсем - радиомонтажник
поправить могу посоветовать только аппаратно железную часть и архитектурно программый код (в меру своего понимания концепции меню девайса)
- конденсаторы 0,1 микрофарад на кнопки, что бы избавиться от паразитного дребега некачественных кнопок. двойные нажатия останутся, но не будут настолько непредсказуемыми и раздражающими, можно программно затупить ввод, но тогда будет раздражать невозможность быстрого ввода параметров/переключения меню. но лучше изначально решать эту проблему на этапе построения логической блок-схемы работы всега. к примеру - лучше, что бы некие параметры изменялись при нажатии или, наоборот, при отпускании кнопки.
- меню есть индикация работы девайса (не более), весь основной код должен работать корректно даже, если полностью закомментировать код меню. Тогда всё становится проще - на этапе тестирования кода индицируем на один экран все переменные: служебные переменные меню(номера меню и подменю), переменные программ, переменные, которые поступают на девайс, прочие. Рулите этими переменными с помощью кнопок, вылавливаете тараканов - долго, но просветляет суть своих хотелок. Только затем одеваете всё бохатство в красивые экраны - почему мигает будет понятно.
*сам лично - пока на этапе построения простого меню на двух энкодерах и одной кнопке(выбор экранов производится кручением одного энкодера при нажатой кнопке, манипуляции с переменными в пределах одного экрана производится энкодерами(простой вариант - две переменные, по одной на каждый энкодер, сложный вариант - одним энкодером выбираем переменную, вторым - ея изменяем), запоминание в оперативку изменений производим во время отпускания кнопки(одновременно пишем изменения состояния всего в ееепром). Публиковать код смысла не вижу - пока сам не знаю, чем это всё окончится - не желается, что бы пару неофитов потом мучились со странным.
Спасибо за инфу, будет интересно поглядеть ваш код, когда доведёте до ума.
*сам лично - пока на этапе построения простого меню на двух энкодерах и одной кнопке(выбор экранов производится кручением одного энкодера при нажатой кнопке, манипуляции с переменными в пределах одного экрана производится энкодерами(простой вариант - две переменные, по одной на каждый энкодер, сложный вариант - одним энкодером выбираем переменную, вторым - ея изменяем), запоминание в оперативку изменений производим во время отпускания кнопки(одновременно пишем изменения состояния всего в ееепром). Публиковать код смысла не вижу - пока сам не знаю, чем это всё окончится - не желается, что бы пару неофитов потом мучились со странным.
дружище, ты изобретаеш лисапед, причем очень кривой и страшный :)
возьми готовые решения.. когда крутиш ручку то передвигаешся по меню по кругу, а когда нажал на ручку то выбрал и першел на следующий уровень меню.. и количество кнопок уменьшится и срочки кода усохнут :)
дружище, ты изобретаеш лисапед, причем очень кривой и страшный :)
возьми готовые решения.. когда крутиш ручку то передвигаешся по меню по кругу, а когда нажал на ручку то выбрал и першел на следующий уровень меню.. и количество кнопок уменьшится и срочки кода усохнут :)
готовые решения - это где?, посоветуй топикстартеру - у него мигает халабуда.
*повторю описание своего велосипеда - пока не нашёл отличий от твоего описания невелосипеда:
аппаратно - два энкодера, одна кнопка.
когда кручу энкодер1 при нажатой кнопке, то переключаю экраны по кругу, когда просто кручу энкодер1, то переключаю выбор переменной в пределах одного экрана, энкодером2 меняю значение, выбранной энкодером1 переменной.
куда там ещё код сократить - не знаю: три служебных переменных меню(состояния энкодеров 1,2, состояние кнопки), состояния энкодеров запоминаются в еепром. согласно значениям этих трёх переменных происходит печать в индикатор.
оставь адын энкодер. нафига тебе их два то? и почему не три?
оставь адын энкодер. нафига тебе их два то? и почему не три?
точно - меню для бедных с одной кнопкой.
*я расписал подробно, зачем два энкодера - потому, что можно два, но не принципиально обязательно.
Друзья, а с моим кодом мне больше никто не поможет? Энкодер кстати интересная идея.
Друзья, а с моим кодом мне больше никто не поможет? Энкодер кстати интересная идея.
перепиши сам всё с нуля - будешь хоть понимать, что глючит.
djominov,
Похоже у вас неправильно собрана электрическая схема кнопок.
У меня нет мерцания.
Привет всем,
kisoft
помогите с этой темой, где можно почитать подробнее, можите сбросить
пару ссылок. А то облазил google и нечего не нашел.
" Не вижу проблем, DI HALT эту тему (отображение информации на лсд экран) разжевал вполне достаточно, чтобы этим вопросом не париться.
Потому я и говорю, пишем информацию в буфер, а потом весь буфер от
ображаем. Чему тут моргать то? "
Di halt lcd - в гугле.
Найдете учебный курс, там всё есть
Вот тут по смотори
Кто нибуть с таким экраном разбирался G128064-MH-R1 http://www.rcscomponents.kiev.ua/r46646.html
И что нужно знать о экране чтоб подключить к ардуино?
И что нужно знать о экране чтоб подключить к ардуино?
Нужно знать какой там контролер стоит. Дальше либо искать готовые библиотеки на данный контроллер, либо брать даташит и изучать. По вышеприведенной ссылке указан контроллер дисплея и дан даташит на сам дисплей, где приведена распиновка.
Я добавил изминение в код для своего устройства которое откривает заслонку при определенных условиях температуры и давления, и эти параметры срабатывания можно менять нажатием кнопки UP и DOWN и, то сейчас меня интересует как можно сделать чтоб при дальнейшем включении были предидущие настройки срабатывания ???
"Энергонезависимая память" она же EEPROM
какую функцию использовать если мне нужно увеличить параметр на 10 или 20 едениц одним нажатием так как при такой (P1++) только на еденицу увеличивает?
P1 = P1+10
Благодарю, но лучше создать новую переменную как по мне R1 = p1+10 или если нада больше R1 = p1*10 и подставлять R1 там где нужно изминять параметр, а то код неадекватно работает :)
А потом к новой переменной будем 10 добавлять и так до бесконечности. Р1 в этом случае ведь не изменится.
я разобрался в общем ;)
Теперь вопрос стал разобратся с сохранением настроек и заданых параметров после последнего включения ардуино с использованием EEPROM библиотеки
Раздел "Программирование" в самом низу. Там правда только для однобайтовых переменных. По многобайтовым, форум почитайте.
Моя версия меню, есть переменняе в коде которые надо менять, в данное меню передаются ссылки на эти переменные Левой кнопкой заходим-выходим из меню вверх - них соотверственно + - Правой перебираем айтемы по кругу #include <Bounce.h> #include <LiquidCrystal_I2C.h> #include <Wire.h> LiquidCrystal_I2C lcd(0x27,20,4); #define BUTTON_LEFT 9 #define BUTTON_RIGHT 12 #define BUTTON_UP 10 #define BUTTON_DOWN 11 //переменные которые надо менять int _V1_rastopka = 30; int _V1_rabota = 60; int _V1_zavershenie = 20;int _T_Rastopka = 50;int _T_Zavershenie = 40;int _T_Stop = 30;int _T_Avariya = 90; //текущий пунет меню, флаг отображения меню int curMenu = 0; bool b_ShowmMenu = 0; //кол пунктов меню const int CountMenu = 7; //создание кнопок через класс Bounce Bounce bLeft = Bounce( BUTTON_LEFT, 5 ); Bounce bRight = Bounce( BUTTON_RIGHT, 5 ); Bounce bUp = Bounce( BUTTON_UP, 5 ); Bounce bDown = Bounce( BUTTON_DOWN, 5 ); //массив элементов меню struct MENU_ITEM{ // char name[17]; int *val; }; //инициализация меню //строковое имя, адрес переменной которую надо менять MENU_ITEM mMenu[CountMenu] = { "V1_rastopka 1", &_V1_rastopka, "V1_rabota 2", &_V1_rabota, "V1_zavershen 3", &_V1_zavershenie, "T_Rastopka 4", &_T_Rastopka, "T_Zavershenie 5", &_T_Zavershenie, "T_Stop 6", &_T_Stop, "T_Avariya 7", &_T_Avariya }; //функия выполнения меню void menu(){ // bRight //след пункт меню по кругу if (bRight.update()) if (bRight.read() == HIGH) if (curMenu == CountMenu - 1) curMenu = 0; else curMenu++; // bLeft выход из меню if (bLeft.update()) if (bLeft.read() == HIGH) b_ShowmMenu = 0; // bUp +1 значение if (bUp.update()) if (bUp.read() == HIGH) (*mMenu[curMenu].val)++; // bDown -1 зачение if (bDown.update()) if (bDown.read() == HIGH) (*mMenu[curMenu].val)--; //вывод использую буффур char ch[16]; snprintf(ch, 16, "%d ", *mMenu[curMenu].val); lcd.setCursor(0,0); lcd.print(mMenu[curMenu].name); lcd.setCursor(0,1); lcd.print(ch); } void setup() { lcd.init(); lcd.backlight(); pinMode( BUTTON_LEFT, INPUT ); pinMode( BUTTON_UP, INPUT ); pinMode( BUTTON_DOWN, INPUT ); pinMode( BUTTON_RIGHT, INPUT ); } void loop() { //вывод меню if (b_ShowmMenu) { menu(); }else{ if ( bLeft.update() ) if ( bLeft.read() ) b_ShowmMenu = 1; lcd.clear(); } }вот мой доработанный код. Экран не мерцает. В качестве экрана и кнопок использовал LCD Keypad Shield.
Экран обновляется по взведенному флагу. Если флаг не взведен, то экран не обновляется.
//Пример простого меню для Arduino //В меню используется 4 экрана //за номер отображаемого экрана отвечает переменная m //Значения переменных р1,р2 меняются циклически от 0-10 затем опять 0, р3(LED) только 0 или 1 #include <LiquidCrystal.h> //Библиотека LCD // инициализация LCD LiquidCrystal lcd(8, 9, 4, 5, 6, 7); int m=0; //переменная для экранов меню int p1=0; // переменная для переменной 1 int p2=6; // -//- 2 время возврата к главному экрану от 2 до 9 сек int p3=0; // -//- 3 int f=1; // флаг обновления экрана int k=0; // флаг нажатия кнопки для возврата на главный экран byte ledPin =13; //Светодиод (исполнительное устройство) long previousMillis = 0; //счетчик прошедшего времени для AutoMainScreen long interval = p2*1000; //задержка автовозврата к MainScreen 6 сек void setup() { //Настройка выходов pinMode(ledPin, OUTPUT); //Настройка дисплея //Установка количества столбцов и строк дисплея lcd.begin(16, 2); // Вывод приветствия при включении питания если нужно lcd.setCursor(3, 0); lcd.print("DEMO MENU"); delay (3000);//Задержка приветствия } void loop() { //кнопки int x; x = analogRead (0); long interval = p2*1000; //задержка автовозврата к MainScreen сек unsigned long currentMillis = millis(); //Обработка нажатия кнопки NEXT if (x < 60 && x>0) { m++;//увеличиваем переменную уровня меню previousMillis = currentMillis; //если кнопка была нажата сбросить счетчик автовозврата к главному экрану delay (500); //lcd.clear(); if (m>3)//если уровень больше 3 { m=0;// то вернуться к началу } f=1; k=1; } //Обработка нажатия кнопки PREV if (x < 600 && x>400) { m--; previousMillis = currentMillis; delay (500); //lcd.clear(); if (m<0) { m=3; } f=1; k=1; } //Обработка нажатия UP для р1 if (x < 200 && x >60 && m==1)//если находимся на экране с переменной р1 { p1++; //то при нажатии кнопки + увеличиваем переменную р1 на единицу previousMillis = currentMillis; delay (500); //lcd.clear(); if (p1>10) //устанавливаем придел изменения переменной = 10 { //если больше предела p1=0; //то возвращаем ее к 0 (тут код условия что делать при достижении приделов) } f=1; k=1; } //UP для р2 if (x < 200 && x >60 && m==2) { p2++; previousMillis = currentMillis; delay (500); //lcd.clear(); if (p2>9) { p2=2; } f=1; k=1; } //UP для р3 if (x < 200 && x >60 && m==3) { p3++; previousMillis = currentMillis; delay (500); //lcd.clear(); if (p3>1) { p3=0; } f=1; k=1; digitalWrite(ledPin, p3); } //сдесь код для уменьшения значений //аналогичен коду увеличения если нужно //Вывод меню //Описание экранов меню if (f==1) { lcd.clear(); if (m==0) //переменная m=0 { //отображаем lcd.setCursor(3, 0); //******************* lcd.print("Main Screen"); //*Main Screen * lcd.setCursor(0, 1); //*P1=p1 P2=p2 LED=0* lcd.print("P1="); //******************* lcd.print(p1); lcd.print(" Pau="); lcd.print(p2); lcd.print(" LED="); lcd.print(p3); } else if (m==1) //переменная m=1 { //отображаем lcd.setCursor(0, 0); //******************* lcd.print("Parametr-1"); //*Parametr-1 * lcd.setCursor(0, 1); //*P1=p1 * lcd.print("P1 = "); //******************* lcd.print(p1); } else if (m==2) //переменная m=2 { //отображаем lcd.setCursor(0, 0); //******************* lcd.print("Pause"); //*Parametr-2 * lcd.setCursor(0, 1); //*P2=p2 * lcd.print("Pau = "); //******************* lcd.print(p2); } else if (m==3) //переменная m=3 { //отображаем lcd.setCursor(0, 0); //******************* lcd.print("LED Control"); //LED Control * lcd.setCursor(0, 1); //LED = p3 * lcd.print("LED = "); //******************* lcd.print(p3); } f=0; } //Проверка автовозврата if(currentMillis - previousMillis > interval && k==1) //Если счетчик { previousMillis = currentMillis; //достиг интервала m=0; //то отобразить главный экран //lcd.clear(); f=1; k=0; } }всех приветствую, у меня проблема, решить не могу, в логику не укладывается
для наладки переменных использую монитор порта, в котором выводятся значения переменных. еще стоит дисплей от нокиа 3310, который должен будет остаться в конечном варианте. в мониторе порта переменные выводяться правильные. а на дисплее переменная которая управляет шимом( переменная равна шиму) не корректна до 100, после 100 соответсвует действительности(сравниваю по результатам монитора порта и свечением диода).
//ВВЕРХ-БЕЛЫЙ, ВЛЕВО -КРАСНЫЙ, ВНИЗ-ЗЕЛЕНЫЙ,ВПРАВО-СИНИЙ //+ЯРКОСТЬ-ЯРКОСТЬ, SCRL F ВЫКЛ #include <IRremote.h> // это скачанная библиотека #include <PCD8544.h> static const byte glyph[] = { B00010000, B00110100, B00110000, B00110100, B00010000 }; static PCD8544 lcd; int r=0;// int g=0;// int b=0;// int x=1;//ручной выбор цвета1-7 boolean R=false; // Флаг вывода индикатора boolean G=false; boolean B=false; boolean W=false;// флаг белого boolean X=false;//режим выбора цвета int RECV_PIN = 11; //вход ИК приемника IRrecv irrecv(RECV_PIN); decode_results results; void setup(){ lcd.begin(84, 48); // Add the smiley to position "0" of the ASCII table... lcd.createChar(0, glyph); Serial.begin (9600); Serial.println("Hello"); pinMode(9, OUTPUT); pinMode(10, OUTPUT); pinMode(6, OUTPUT); irrecv.enableIRIn(); } // включить приемник void loop() { static int counter = 0; analogWrite(9,r); analogWrite(10,g); analogWrite(6,b); if (irrecv.decode(&results)) { delay(300); Serial.println("power"); if (results.value == 0xB54A50AF){// если нажали кнопку + if (R == true) {r=r+15;} if (G == true) {g=g+15;} if (B == true) {b=b+15;} if (W == true) {r=r+15; g=g+15; b=b+15;} if (X == true) {x=x+1;} } if (results.value == 0xB54AD02F)// если нажали кнопку - { if (R == true) {r=r-15;} if (G == true) {g=g-15;} if (B == true) {b=b-15;} if (W == true) {r=r-15; g=g-15; b=b-15;} if (X == true) {x=x-1;} } if (results.value == 0xB54A58A7)// R {b=LOW; g=LOW; r=255; R=true; G=false; B=false; W=false; X=false; } if (results.value == 0xB54A1AE5) // G {b=LOW; r=LOW; g=255; R=false; G=true; B=false;W=false; X=false; } if (results.value == 0xF50AE649) //B {r=LOW; g=LOW; b=255; R=false; G=false; B=true; W=false; X=false; } if (results.value == 0xB54A48B7) //W БЕЛЫЙ {b=255; g=255; r=255; R=false; G=false; B=false; W=true; X=false; } if (results.value == 0xB54A30CF) //Х РАДУГА {b=LOW; g=LOW; r=LOW; R=false; G=false; B=false; W=false; X=true; } if (X == true && x==1) {r=255; g=100; b=0; }//красный if (X == true && x==2) {r=255; g=100; b=0; }//оранжевый if (X == true && x==3) {r=255; g=100; b=0; }//желтый if (X == true && x==4) {r=255; g=100; b=0; }//зеленвй if (X == true && x==5) {r=255; g=100; b=0; }//голубой if (X == true && x==6) {r=255; g=100; b=0; }//синий if (X == true && x==7) {r=255; g=100; b=0; }//фиолетовый if (results.value == 0xB54A9867) //ВЫКЛ {b=LOW; g=LOW; r=LOW; } if (r>255) {r=255;} if (r<0) {r=0;} if (g>255) {g=255;} if (g<0) {g=0;} if (b>255) {b=255;} if (b<0) {b=0;} if (x>7) {x=1;} if (x<1) {x=7;} Serial.print("R"); Serial.print(R); Serial.print("G"); Serial.print(G); Serial.print("B"); Serial.print(B); Serial.print("W"); Serial.println(W); Serial.print("R"); Serial.print(r); Serial.print("G"); Serial.print(g); Serial.print("B"); Serial.println(b); Serial.print("X"); Serial.println(x); lcd.setCursor(0, 0); lcd.print("NISSAN"); lcd.setCursor(0, 1); lcd.print(r); lcd.setCursor(0, 2); lcd.print(g); delay(50); // irrecv.resume(); // } }ураааа. эксперементы рулят. дописал по ln и все показания корректны
lcd.println(r);
Почему в выводе на экран перед числом стоит "0"? Как исправить???
код в студию, у меня все четко
что такое кнопка
NEXTДобрый день. Такой к вам имеется вопрос.
На сайте http://winavr.scienceprog.com/example-avr-projects/avr-lcd-menu-routine.html нашел пример меню на LCD дисплее и atmega8. Четырьмя кнопками задается режим работы 3 светодиодов. В архиве кроме файлов проекта есть файл симуляции протеуса. Проверил - работает как надо.
Решил попробывать просимулировать для ардуино - пролема в том что не происходит опроса кнопки, точнее условие по нажатию не срабатывает. Опрос в исходном коде(mega8) идет в теле обработчика прерывания таймера 0 каждые 122 раза в секунду(Гц). Таймер 0 в среде ардуино системный поэтому я сделал аналогично на таймере 2 - 100 раз в секунду. В остальном практически нет изменений.
menu.c (mega8)
Моя аналогия с ошибкой
#include <Wire.h> #include <LiquidCrystal_I2C.h> //------------------------------------------ #include <avr/io.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include <util/delay.h> //------------------------------------------ // Set the LCD address to 0x27 for a 16 chars and 2 line display LiquidCrystal_I2C lcd(0x27, 16, 2); //------------------------------------------ #define UP 0 #define DOWN 3 #define LEFT 1 #define RIGHT 2 #define LED_R 2 #define LED_G 1 #define LED_B 0 //------------------------------------------ typedef void (*FuncPtr)(void); //function pointer FuncPtr FPtr; //Structure describes current menu and submenu state struct Menu_State{ uint8_t menuNo;//1,2,3,4 uint8_t subMenuNo;//1,2,3 }MN; //flag required for exiting from functions loops uint8_t Flag=1; //Menu Strings in flash const uint8_t MN000[] PROGMEM="Menu Demo\0"; //menu 1 const uint8_t MN100[] PROGMEM="<<One Led>>\0"; //menu 1 submenus const uint8_t MN101[] PROGMEM="R ON\0"; const uint8_t MN102[] PROGMEM="G ON\0"; const uint8_t MN103[] PROGMEM="B ON\0"; //menu 2 const uint8_t MN200[] PROGMEM="<<All ON/OFF>>\0"; //Submenus of menu 2 const uint8_t MN201[] PROGMEM="All ON\0"; const uint8_t MN202[] PROGMEM="All OFF\0"; //menu 3 const uint8_t MN300[] PROGMEM="<<Auto scroll>>\0"; //Submenus of menu 3 const uint8_t MN301[] PROGMEM="Left\0"; const uint8_t MN302[] PROGMEM="Right\0"; //menu 4 const uint8_t MN400[] PROGMEM="<<Blink All>>\0"; //submenus of menu 4 const uint8_t MN401[] PROGMEM="Blink Fast\0"; const uint8_t MN402[] PROGMEM="Blink Slow\0"; //more menus and submenus can be added. //Arrays of pointers to menu strings stored in flash const uint8_t *MENU[] ={ MN100, //menu 1 string MN200, //menu 2 string MN300, //menu 3 string MN400 //menu 4 string }; const uint8_t *SUBMENU[] ={ MN101, MN102, MN103, //submenus of menu 1 MN201, MN202, //подменю пунктам меню 2 MN301, MN302, //submenus of menu 3 MN401, MN402 //submenus of menu 4 }; //Menu structure //[0] -Number of level 0 menu items //[1]...[n] number of second level menu items //Eg. MSTR2[1] shows that menu item 1 has 3 submenus const uint8_t MSTR2[] PROGMEM ={ 4, // количество пунктов меню 3, //Number of submenu items of menu item 1 2, //of menu item 2 2, //of menu item 3 2 //of menu item 4 }; //Function prototypes //Timer2 initialization void init_timer2(void); //Initial menu void menu_Init(void); //Inits ports for buttons and LED's void ports_Init(void); //Functions for each menu item void func101(void); void func102(void); void func103(void); void func201(void); void func202(void); void func301(void); void func302(void); void func401(void); void func402(void); //Arrray of function pointers in Flash const FuncPtr FuncPtrTable[] PROGMEM= { func101, func102, func103, //functions for submenus of menu 1 func201, func202, //functions for submenus of menu 2 func301, func302, //functions for submenus of menu 3 func401, func402 //functions for submenus of menu 4 }; //SubMenu and Function table pointer update uint8_t MFIndex(uint8_t, uint8_t); //------------------------------------------ //Timer0 overflow interrupt service routine ISR(TIMER2_COMPA_vect) { //if button UP pressed if (bit_is_clear(PINB, UP)) { if (MN.menuNo<pgm_read_byte(&MSTR2[0])) { MN.menuNo++; MN.subMenuNo=1; } else { MN.menuNo=1; } lcd.clear(); //Display menu item CopyStringtoLCD(MENU[MN.menuNo-1], 0, 0 ); //Display submenu item CopyStringtoLCD(SUBMENU[MFIndex(MN.menuNo, MN.subMenuNo)], 0, 1 ); //Assign function to function pointer FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.menuNo, MN.subMenuNo)]); //set Flag to 0 menas menu have changed Flag=0; //wait for button release loop_until_bit_is_set(PINB, UP); } //if Button DOWN pressed if (bit_is_clear(PINB, DOWN)) { if (MN.menuNo==1) { MN.menuNo=pgm_read_byte(&MSTR2[0]); MN.subMenuNo=1; } else { MN.menuNo--; } lcd.clear(); CopyStringtoLCD(MENU[MN.menuNo-1], 0, 0 ); CopyStringtoLCD(SUBMENU[MFIndex(MN.menuNo, MN.subMenuNo)], 0, 1 ); FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.menuNo, MN.subMenuNo)]); Flag=0; loop_until_bit_is_set(PINB, DOWN); } //If Button RIGHT pressed if (bit_is_clear(PINB, RIGHT)) { if (MN.subMenuNo<pgm_read_byte(&MSTR2[MN.menuNo])) { MN.subMenuNo++; } else { MN.subMenuNo=1; } lcd.clear(); CopyStringtoLCD(MENU[MN.menuNo-1], 0, 0 ); CopyStringtoLCD(SUBMENU[MFIndex(MN.menuNo, MN.subMenuNo)], 0, 1 ); FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.menuNo, MN.subMenuNo)]); Flag=0; loop_until_bit_is_set(PINB, RIGHT); } //If button LEFT pressed if (bit_is_clear(PINB, LEFT)) { if (MN.subMenuNo==1) { MN.subMenuNo=pgm_read_byte(&MSTR2[MN.menuNo]); } else { MN.subMenuNo--; } lcd.clear(); CopyStringtoLCD(MENU[MN.menuNo-1], 0, 0 ); CopyStringtoLCD(SUBMENU[MFIndex(MN.menuNo, MN.subMenuNo)], 0, 1 ); FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.menuNo, MN.subMenuNo)]); Flag=0; loop_until_bit_is_set(PINB, LEFT); } } //------------------------------------------ void setup() { lcd.begin(); // initialize the LCD lcd.backlight(); // Turn on the blacklight and print a message. lcd.home(); //Welcome demo message CopyStringtoLCD(MN000, 0, 0 ); _delay_ms(1000); lcd.clear(); ports_Init(); //Initial menu and initial function menu_Init(); init_timer2(); sei(); } //------------------------------------------ void loop() { while(1) { //set flag to 1 //when button menu changes flag sets to 0 Flag=1; //execute function that is pointed by FPtr FPtr(); } } void init_timer2(void) { //Прерывание происходит каждые 10 мс TCCR2B=0; // таймер2 остановлен TCNT2=0; //счётный регистр обнулён OCR2B=0; TIFR2&=0xff; //отчистить флаги прерываний TCCR2A = (1<<WGM21); // Режим CTC (сброс по совпадению) TCCR2B = (1<<CS20)|(1<<CS21)|(1<<CS22); // CLK/1024 OCR2A = 155; TIMSK2 = (1<<OCIE2A); // Разрешить прерывание по совпадению } //------------------------------------------ void CopyStringtoLCD(const uint8_t *FlashLoc, uint8_t x, uint8_t y) { uint8_t i; lcd.setCursor(x,y); for(i=0;(uint8_t)pgm_read_byte(&FlashLoc[i]);i++) { lcd.write((uint8_t)pgm_read_byte(&FlashLoc[i])); } } //------------------------------------------ void ports_Init() { DDRB&=~(0<<UP|0<<DOWN|0<<LEFT|0<<RIGHT);//as input PORTB|=1<<UP|1<<DOWN|1<<LEFT|1<<RIGHT;//Pullups DDRC |=1<<LED_R|1<<LED_G|1<<LED_B;//Leds OFF PORTC |=1<<LED_R|1<<LED_G|1<<LED_B;//Led pins as output } //------------------------------------------ void menu_Init(void) { MN.menuNo=1; MN.subMenuNo=1; lcd.clear(); CopyStringtoLCD(MENU[(MN.menuNo-1)], 0, 0 ); CopyStringtoLCD(SUBMENU[(MN.subMenuNo-1)], 0, 1 ); FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[0]); } //------------------------------------------ uint8_t MFIndex(uint8_t mn, uint8_t sb) { uint8_t p=0;//points to menu in table of function pointer for(uint8_t i=0; i<(mn-1); i++) { p=p+pgm_read_byte(&MSTR2[i+1]); } p=p+sb-1; return p; } //------------------------------------------ void func101(void) { PORTC&=~(1<<LED_R); PORTC|=1<<LED_G|1<<LED_B;//Led_R ON } void func102(void) { PORTC&=~(1<<LED_G); PORTC|=1<<LED_R|1<<LED_B;//Led_G ON } void func103(void) { PORTC&=~(1<<LED_B); PORTC|=1<<LED_R|1<<LED_G;//Led_B ON } void func201(void) { PORTC&=~(1<<LED_R|1<<LED_G|1<<LED_B);//Leds ON } void func202(void) { PORTC|=1<<LED_R|1<<LED_G|1<<LED_B;//Leds OFF } void func301(void) { while(Flag) { PORTC|=1<<LED_R|1<<LED_G|1<<LED_B;//Leds OFF _delay_ms(1000); PORTC&=~(1<<LED_R); PORTC|=1<<LED_G|1<<LED_B;//Led_R ON _delay_ms(1000); PORTC&=~(1<<LED_G); PORTC|=1<<LED_R|1<<LED_B;//Led_G ON _delay_ms(1000); PORTC&=~(1<<LED_B); PORTC|=1<<LED_R|1<<LED_G;//Led_B ON _delay_ms(1000); } } void func302(void) { while(Flag) { PORTC|=1<<LED_R|1<<LED_G|1<<LED_B;//Leds OFF _delay_ms(1000); PORTC&=~(1<<LED_B); PORTC|=1<<LED_R|1<<LED_G;//Led_B ON _delay_ms(1000); PORTC&=~(1<<LED_G); PORTC|=1<<LED_R|1<<LED_B;//Led_G ON _delay_ms(1000); PORTC&=~(1<<LED_R); PORTC|=1<<LED_G|1<<LED_B;//Led_R ON _delay_ms(1000); } } void func401(void) { while(Flag) { PORTC&=~(1<<LED_R|1<<LED_G|1<<LED_B);//Leds ON _delay_ms(1000); PORTC|=1<<LED_R|1<<LED_G|1<<LED_B;//Leds OFF _delay_ms(1000); } } void func402(void) { while(Flag) { PORTC&=~(1<<LED_R|1<<LED_G|1<<LED_B);//Leds ON _delay_ms(1000); _delay_ms(1000); PORTC|=1<<LED_R|1<<LED_G|1<<LED_B;//Leds OFF _delay_ms(1000); _delay_ms(1000); } }Не совсем понимаю смысл применения макроса loop_until_bit_is_set. Зачем ждать отпускания кнопки?
//if button UP pressed if (bit_is_clear(PINB, UP)) { if (MN.menuNo<pgm_read_byte(&MSTR2[0])) { MN.menuNo++; MN.subMenuNo=1; } else { MN.menuNo=1; } lcd.clear(); //Display menu item CopyStringtoLCD(MENU[MN.menuNo-1], 0, 0 ); //Display submenu item CopyStringtoLCD(SUBMENU[MFIndex(MN.menuNo, MN.subMenuNo)], 0, 1 ); //Assign function to function pointer FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.menuNo, MN.subMenuNo)]); //set Flag to 0 menas menu have changed Flag=0; //wait for button release loop_until_bit_is_set(PINB, UP); }И прошу не делйте мне замечаний по поводу этого, никто не запрещает тут использовать while(1) {}
void loop() { while(1) { //set flag to 1 //when button menu changes flag sets to 0 Flag=1; //execute function that is pointed by FPtr FPtr(); } }Вопрос снят