Хорошо объяснюсь по порядку. Изначально пишу на основе уже существующего кода. Код меня много в чем не устраивает особенно тем что построен на куче case для прокрутке меню и десятке использований millis для кнопок когда можно для этого использовать библиотеку. Один подпункт меню у меня будет аналогично сделанному на casах: каждое нажатие кнопки обновляет информацию на экране так что ДОПУСТИМ обновляется строка "STEPS" и соответственно ей переменная profileSteps, следующее нажатие "RAMP: " и double rampRateStep[9]; и т д
Перечислю их
// заданы в виде массива
double rampRateStep[9];
int temperatureStep[9];
int dwellTimerStep[9];
//
int pwr_TOP, pwr_BOTTOM;
int profileSteps;
int Setpoint2;
double kp1, kd1, ki1; // возможно int
double kp2, kd2, ki2; // возможно int
Переменные имеют разный тип поэтому удобно их обработать через структуру
Тестовый код
// TEST
#include <avr/pgmspace.h>
char buf[8];
struct station {
double rampRateStep[9];
int temperatureStep[9];
int dwellTimerStep[9];
int pwr_TOP, pwr_BOTTOM;
int profileSteps;
int Setpoint2;
double kp1, kd1, ki1; // возможно int
double kp2, kd2, ki2; // возможно int
};
const char string_0[] PROGMEM = "STEPS ";
const char string_1[] PROGMEM = "B.HEAT";
const char string_2[] PROGMEM = "T.HEAT";
const char string_3[] PROGMEM = "B.PWR ";
const char string_4[] PROGMEM = "T.PWR ";
const char string_5[] PROGMEM = "RAMP: ";
const char string_6[] PROGMEM = "TARGET ";
const char string_7[] PROGMEM = "DWELL ";
const char *const text[] PROGMEM = { string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7 };
void setup () {
Serial.begin(9600);
} // void setup()
void loop() {
while (!Serial.available());
byte s = Serial.read()-'0'; // Жмем кнопки 0 - 5.
function(s);
} // void loop()
void function (const uint8_t n) {
station reflow;
strcpy_P(buf, (char*)pgm_read_word(&(text[n])));
Serial.print(buf);
//Serial.print(reflow.Setpoint2);
}
Моя идея решения простая: создается функция и в нужном месте вызывается и достаточно. Но решена проблема только со строками. Переменные имеют разный тип и некоторые заданы в виде массива, я это показал. А значит и возника идея в нумерации элементов структуры чтобы затем этот номер и передавать функции чтобы затем по номеру вернуть искомую переменную и ее вывести. Плодить if не хочу
ЕвгенийП пишет:
Я правда не понимаю, что Вам нужно. Все нормальные люди в такой ситуации пишут пачку ифов. Если Вы хотите работать как с массивом, Вам нужно менть организацию данных. Если Вы хотите спрятать печать и писать её в одном месте, Вам надо что структура сама себя печатала через интерфейст Printable. Чего Вам надо то?
Плодить if не хочу. Возможно вы хотели сказать что можно в одном месте печатать струтуру, расскажите подробнее. Да вызов функции необязателен мне просто нужно будет по нажатию печатать элемент затем по следующему уже другой элемент то есть печатать элементы структуры в порядке очереди. Очередь задается нажатием
ЕвгенийП, в этой ветке упоминалось что возможно добавить такую функциональность в класс LCD. Подскажите каким образом, на основе вашего же кода? Заранее спасибо
struct SSensorValue : public Printable {
unsigned long timeStamp; // Время съёма показаний (мс от запуска МК)
float temperture; // температура в градусах С
float humidity; // влажность в %
float pressure; // давление в мм.рт.ст.
size_t printTo(Print& p) const { // в качестве p нам передадут, например, Serial
size_t res = p.print("SENSOR VALUE: Time:");
res += p.print(timeStamp);
res += p.print("ms; T:");
res += p.print(temperture);
res += p.print("C; H:");
res += p.print(humidity);
res += p.print("%; P:");
res += p.print(pressure);
return res + p.println("mm");
}
};
void setup() {
Serial.begin(115200);
Serial.println("Fun begins!");
//
// Объявляем структуру и заполняем какими-то значениями
//
SSensorValue sv;
sv.timeStamp = millis();
sv.temperture = 36.6;
sv.humidity = 93.2;
sv.pressure = 755;
//
// Печатаем структуру
//
Serial.print(sv);
}
void loop() {}
Да это возможно. Дальше уже через if буду выводить как мне нужно. Нужно было раньше найти ваши этюды, помогло
Возник неприятная проблема: если метод вызывается в функции setup() все работает. Как только переношу его в loop() отказывается что либо выводить. Направьте
PS Евгений чтобы у вас потом вопросов не возникало добавлю. К вашему коду претензий не имею но вы в примере:
ЕвгенийП пишет:
Давайте это напишем:
struct SSensorValue : public Printable {
unsigned long timeStamp; // Время съёма показаний (мс от запуска МК)
float temperture; // температура в градусах С
float humidity; // влажность в %
float pressure; // давление в мм.рт.ст.
size_t printTo(Print& p) const { // в качестве p нам передадут, например, Serial
size_t res = p.print("SENSOR VALUE: Time:");
res += p.print(timeStamp);
res += p.print("ms; T:");
res += p.print(temperture);
res += p.print("C; H:");
res += p.print(humidity);
res += p.print("%; P:");
res += p.print(pressure);
return res + p.println("mm");
}
};
void setup() {
Serial.begin(115200);
Serial.println("Fun begins!");
//
// Объявляем структуру и заполняем какими-то значениями
//
SSensorValue sv;
sv.timeStamp = millis();
sv.temperture = 36.6;
sv.humidity = 93.2;
sv.pressure = 755;
//
// Печатаем структуру
//
Serial.print(sv);
}
void loop() {}
Вот так! Обратите внимание: в строке 1 мы указали, что наша структура поддерживает интерфейс Printable, а в строках 7-17 мы реализовали необходимый для этого интерфейса метод printTo. Теперь, мы можем просто писать Serial.print(sv) (строка 34) и система поймёт, чтов этот момент надо просто вызвать наш метод, а он всё. что нужно, напечатает. Причём напечатает не тупо в Serial, а именно в тот поток, для которого он был вызван.
Если Вы запустите этот скетч, то он спокойно скомпилируется и в сериале Вы увидите:
Fun begins!
SENSOR VALUE: Time:0ms; T:36.60C; H:93.20%; P:755.00mm
Организовали метод SSensorValue, для вывода показаний с датчика и сделали вывод в setup(). Да но в моем случае меню логичнее сделать это в loop() поскольку показания постоянно обновляются (нужно часто настраивать). Если перенести это в функцию вызваемую из loop() не работает, не пойму почему
В Вышем коде я не вижу вызова этого метода (всё закоментировано, а то, что заскомментировано - то написано неправильно).
Вот у Вас же есть строки 69-76.
Вставьте такие же в loop (для начала в точности такие же) и больше ничего. Убедитесь, что работает. Потом попробуйте что Вам надо. Если не получится, то покажите код. Но именно неработающий код, а не кучу комментариев.
А от так, строки у тебя будут лежать в PROGMEM, а массив нет. Ну, для конкретно этого массива, думаю, 10 байт (число строк * размер указателя) в ОЗУ не жалко, но, если нада больше строк, то его тоже можно во флэш запхать. Только читать потом придёца специальным образом.
А от так, строки у тебя будут лежать в PROGMEM, а массив нет. Ну, для конкретно этого массива, думаю, 10 байт (число строк * размер указателя) в ОЗУ не жалко, но, если нада больше строк, то его тоже можно во флэш запхать. Только читать потом придёца специальным образом.
да, строк будет много, поэтому с прогмем и хочу заморочиться. Тот пример, что ты написал, в принципе у меня уже работает, (только и массив в прогмем). Но суть вопроса с твоим примером также остается - Помимо самих строк, нужно забивать вручную массив .
Уважаемые Гуру, если не затруднит, посмотрите правильно ли я запихал строки в прогмем по примеру № 3 Садмана (а также вывод их на печать). И ещё, строка прагма оптимизатора действительно нужна? что делает этот оптимизатор?
первая часть кода, это правка к опубликованному коду, для старых версий ардуино, который будет выдавать ошибку вторая часть кода, наработка как использовать массив указателей в SRAM, что значительно быстрее и удобнее... третья часть кода, немного измененный вариант
все три варианта проверены ... а с массивами - давно уже рабочие... и данные примеры писались, естественно, быстро, на коленке, по памяти
если есть что сказать - говорите, народ обсудит, сообществу пригодиться, если это будет умная мымсль
for (int j = 0; j < 4; j++)
{
for (int i = 0; i < 5; i++)
{
Print_PROGMEM((char*)pgm_read_word(&(Lang_Str[j][i])), 0, 130);
lcd.Fill_Screen(BLACK);
delay( 500 );
}
}
При установке констант - оптимизатор выкидывает ВСЕ не используемые строки и массив ! Остаётся только одна строка и у неё есть конкретный адрес - вот он и передаётся ...
Хорошо объяснюсь по порядку. Изначально пишу на основе уже существующего кода. Код меня много в чем не устраивает особенно тем что построен на куче case для прокрутке меню и десятке использований millis для кнопок когда можно для этого использовать библиотеку. Один подпункт меню у меня будет аналогично сделанному на casах: каждое нажатие кнопки обновляет информацию на экране так что ДОПУСТИМ обновляется строка "STEPS" и соответственно ей переменная profileSteps, следующее нажатие "RAMP: " и double rampRateStep[9]; и т д
Перечислю их
Переменные имеют разный тип поэтому удобно их обработать через структуру
Тестовый код
// TEST #include <avr/pgmspace.h> char buf[8]; struct station { double rampRateStep[9]; int temperatureStep[9]; int dwellTimerStep[9]; int pwr_TOP, pwr_BOTTOM; int profileSteps; int Setpoint2; double kp1, kd1, ki1; // возможно int double kp2, kd2, ki2; // возможно int }; const char string_0[] PROGMEM = "STEPS "; const char string_1[] PROGMEM = "B.HEAT"; const char string_2[] PROGMEM = "T.HEAT"; const char string_3[] PROGMEM = "B.PWR "; const char string_4[] PROGMEM = "T.PWR "; const char string_5[] PROGMEM = "RAMP: "; const char string_6[] PROGMEM = "TARGET "; const char string_7[] PROGMEM = "DWELL "; const char *const text[] PROGMEM = { string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7 }; void setup () { Serial.begin(9600); } // void setup() void loop() { while (!Serial.available()); byte s = Serial.read()-'0'; // Жмем кнопки 0 - 5. function(s); } // void loop() void function (const uint8_t n) { station reflow; strcpy_P(buf, (char*)pgm_read_word(&(text[n]))); Serial.print(buf); //Serial.print(reflow.Setpoint2); }Моя идея решения простая: создается функция и в нужном месте вызывается и достаточно. Но решена проблема только со строками. Переменные имеют разный тип и некоторые заданы в виде массива, я это показал. А значит и возника идея в нумерации элементов структуры чтобы затем этот номер и передавать функции чтобы затем по номеру вернуть искомую переменную и ее вывести. Плодить if не хочу
Я правда не понимаю, что Вам нужно. Все нормальные люди в такой ситуации пишут пачку ифов. Если Вы хотите работать как с массивом, Вам нужно менть организацию данных. Если Вы хотите спрятать печать и писать её в одном месте, Вам надо что структура сама себя печатала через интерфейст Printable. Чего Вам надо то?
Плодить if не хочу. Возможно вы хотели сказать что можно в одном месте печатать струтуру, расскажите подробнее. Да вызов функции необязателен мне просто нужно будет по нажатию печатать элемент затем по следующему уже другой элемент то есть печатать элементы структуры в порядке очереди. Очередь задается нажатием
Прежде всего поймите что строки в меню разные по типу https://habr.com/post/257607/
Главным догматом менюОС является «Все есть файл». Да будет так.
У каждого файла есть тип, название, родительская папка, прочие параметры
Евгений нашел ваши Этюды для начинающих: интерфейс Printable
Буду разбираться http://arduino.ru/forum/programmirovanie/etyudy-dlya-nachinayushchikh-interfeis-printable
ЕвгенийП, в этой ветке упоминалось что возможно добавить такую функциональность в класс LCD. Подскажите каким образом, на основе вашего же кода? Заранее спасибо
struct SSensorValue : public Printable { unsigned long timeStamp; // Время съёма показаний (мс от запуска МК) float temperture; // температура в градусах С float humidity; // влажность в % float pressure; // давление в мм.рт.ст. size_t printTo(Print& p) const { // в качестве p нам передадут, например, Serial size_t res = p.print("SENSOR VALUE: Time:"); res += p.print(timeStamp); res += p.print("ms; T:"); res += p.print(temperture); res += p.print("C; H:"); res += p.print(humidity); res += p.print("%; P:"); res += p.print(pressure); return res + p.println("mm"); } }; void setup() { Serial.begin(115200); Serial.println("Fun begins!"); // // Объявляем структуру и заполняем какими-то значениями // SSensorValue sv; sv.timeStamp = millis(); sv.temperture = 36.6; sv.humidity = 93.2; sv.pressure = 755; // // Печатаем структуру // Serial.print(sv); } void loop() {}Да это возможно. Дальше уже через if буду выводить как мне нужно. Нужно было раньше найти ваши этюды, помогло
// TEST #include <avr/pgmspace.h> #include <Wire.h> // библиотека для управления устройствами по I2C #include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 2004 LiquidCrystal_I2C lcd(0x27, 16, 2); // присваиваем имя lcd для дисплея 20х4 char buf[6]; struct SSensorValue : public Printable { float rampRateStep[9]; int temperatureStep[9]; int dwellTimerStep[9]; int profileSteps; int pwr_BOTTOM; int pwr_TOP; int Setpoint2; float kp1; float kd1; float ki1; // возможно int float kp2; float kd2; float ki2; // возможно int; size_t printTo(Print& p) const { size_t res = p.print("Steps:"); //res += p.println(timeStamp); //res += p.print("ms; T:"); //res += p.print(temperture); //res += p.print("C; H:"); res += p.print(profileSteps); //res += p.print("%; P:"); //res += p.print(pressure); return res; } }; /*enum state_t : byte {REFLOW_STATE_IDLE, REFLOW_STATE_MENU_STEPS, REFLOW_STATE_MENU_BOTTOM_HEAT, REFLOW_STATE_MENU_BOTTOM_PWR, REFLOW_STATE_MENU_STEP_RAMP, REFLOW_STATE_MENU_STEP_TARGET, REFLOW_STATE_MENU_TOP_PWR, REFLOW_STATE_MENU_STEP_DWELL, REFLOW_STATE_STEP_RAMP, REFLOW_STATE_STEP, REFLOW_STATE_STEP_DWELL, REFLOW_STATE_COMPLETE, REFLOW_STATE_ERROR, REFLOW_STATE_MENU_RESET};*/ const char string_0[] PROGMEM = "IDLE "; const char string_1[] PROGMEM = "STEPS"; const char string_2[] PROGMEM = "HEAT "; const char string_3[] PROGMEM = "PWR "; const char string_4[] PROGMEM = "RAMP "; const char string_5[] PROGMEM = "RESET"; const char *const text[] PROGMEM = { string_0, string_1, string_2, string_3, string_4, string_5 }; void setup () { Serial.begin(9600); lcd.begin(); lcd.backlight(); // включение подсветки дисплея SSensorValue sv; sv.Setpoint2 = 100; sv.profileSteps = 9; sv.kp1 = 36.6; sv.kd1 = 93.2; sv.ki1 = 55.1; Serial.print(sv); lcd.setCursor(0, 0); lcd.print(sv); } // void setup() void loop() { while (!Serial.available()); byte s = Serial.read()-'0'; // Жмем кнопки 0 - 5. function(s); } // void loop() void function (const uint8_t n) { strcpy_P(buf, (char*)pgm_read_word(&(text[n]))); Serial.print(buf); }Возник неприятная проблема: если метод вызывается в функции setup() все работает. Как только переношу его в loop() отказывается что либо выводить. Направьте
// TEST #include <avr/pgmspace.h> #include <Wire.h> // библиотека для управления устройствами по I2C #include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 2004 LiquidCrystal_I2C lcd(0x27, 16, 2); // присваиваем имя lcd для дисплея 20х4 char buf[6]; struct reflowStation : public Printable { float rampRateStep[9]; int temperatureStep[9]; int dwellTimerStep[9]; int profileSteps; int pwr_BOTTOM; int pwr_TOP; int Setpoint2; float kp1; float kd1; float ki1; // возможно int float kp2; float kd2; float ki2; // возможно int; size_t printTo(Print& p) const { size_t res = p.print("Steps:"); //res += p.println(timeStamp); //res += p.print("ms; T:"); //res += p.print(temperture); //res += p.print("C; H:"); res += p.print(profileSteps); //res += p.print("%; P:"); //res += p.print(pressure); return res; } }; /*enum state_t : byte {REFLOW_STATE_IDLE, REFLOW_STATE_MENU_STEPS, REFLOW_STATE_MENU_BOTTOM_HEAT, REFLOW_STATE_MENU_BOTTOM_PWR, REFLOW_STATE_MENU_STEP_RAMP, REFLOW_STATE_MENU_STEP_TARGET, REFLOW_STATE_MENU_TOP_PWR, REFLOW_STATE_MENU_STEP_DWELL, REFLOW_STATE_STEP_RAMP, REFLOW_STATE_STEP, REFLOW_STATE_STEP_DWELL, REFLOW_STATE_COMPLETE, REFLOW_STATE_ERROR, REFLOW_STATE_MENU_RESET};*/ const char string_0[] PROGMEM = "IDLE "; const char string_1[] PROGMEM = "STEPS"; const char string_2[] PROGMEM = "HEAT "; const char string_3[] PROGMEM = "PWR "; const char string_4[] PROGMEM = "RAMP "; const char string_5[] PROGMEM = "RESET"; const char *const text[] PROGMEM = { string_0, string_1, string_2, string_3, string_4, string_5 }; void setup () { Serial.begin(9600); lcd.begin(); lcd.backlight(); // включение подсветки дисплея // прекрасно работает reflowStation pr; pr.Setpoint2 = 100; pr.profileSteps = 9; pr.kp1 = 36.6; pr.kd1 = 93.2; pr.ki1 = 55.1; Serial.print(pr); lcd.setCursor(0, 0); lcd.print(pr); } // void setup() void loop() { while (!Serial.available()); byte s = Serial.read()-'0'; // Жмем кнопки 0 - 5. function(s); } // void loop() void function (const uint8_t n) { strcpy_P(buf, (char*)pgm_read_word(&(text[n]))); Serial.print(buf); // не работает /*reflowStation pr; pr.Setpoint2 = 100; pr.profileSteps = 9; pr.kp1 = 36.6; pr.kd1 = 93.2; pr.ki1 = 55.1; Serial.print(pr); lcd.setCursor(0, 0); lcd.print(pr); */ }Ошибок нет, но и монитор пуст
void function (const uint8_t n) { strcpy_P(buf, (char*)pgm_read_word(&(text[n]))); Serial.print(buf); // не работает /*reflowStation pr; pr.Setpoint2 = 100; pr.profileSteps = 9; pr.kp1 = 36.6; pr.kd1 = 93.2; pr.ki1 = 55.1; Serial.print(pr); lcd.setCursor(0, 0); lcd.print(pr); */ }PS Евгений чтобы у вас потом вопросов не возникало добавлю. К вашему коду претензий не имею но вы в примере:
Давайте это напишем:
struct SSensorValue : public Printable { unsigned long timeStamp; // Время съёма показаний (мс от запуска МК) float temperture; // температура в градусах С float humidity; // влажность в % float pressure; // давление в мм.рт.ст. size_t printTo(Print& p) const { // в качестве p нам передадут, например, Serial size_t res = p.print("SENSOR VALUE: Time:"); res += p.print(timeStamp); res += p.print("ms; T:"); res += p.print(temperture); res += p.print("C; H:"); res += p.print(humidity); res += p.print("%; P:"); res += p.print(pressure); return res + p.println("mm"); } }; void setup() { Serial.begin(115200); Serial.println("Fun begins!"); // // Объявляем структуру и заполняем какими-то значениями // SSensorValue sv; sv.timeStamp = millis(); sv.temperture = 36.6; sv.humidity = 93.2; sv.pressure = 755; // // Печатаем структуру // Serial.print(sv); } void loop() {}Вот так! Обратите внимание: в строке 1 мы указали, что наша структура поддерживает интерфейс Printable, а в строках 7-17 мы реализовали необходимый для этого интерфейса метод printTo. Теперь, мы можем просто писать Serial.print(sv) (строка 34) и система поймёт, чтов этот момент надо просто вызвать наш метод, а он всё. что нужно, напечатает. Причём напечатает не тупо в Serial, а именно в тот поток, для которого он был вызван.
Если Вы запустите этот скетч, то он спокойно скомпилируется и в сериале Вы увидите:
Организовали метод SSensorValue, для вывода показаний с датчика и сделали вывод в setup(). Да но в моем случае меню логичнее сделать это в loop() поскольку показания постоянно обновляются (нужно часто настраивать). Если перенести это в функцию вызваемую из loop() не работает, не пойму почему
Какая разница методу откуда его вызывают?
В Вышем коде я не вижу вызова этого метода (всё закоментировано, а то, что заскомментировано - то написано неправильно).
Вот у Вас же есть строки 69-76.
Вставьте такие же в loop (для начала в точности такие же) и больше ничего. Убедитесь, что работает. Потом попробуйте что Вам надо. Если не получится, то покажите код. Но именно неработающий код, а не кучу комментариев.
Рабочий
// TEST #include <avr/pgmspace.h> #include <Wire.h> // библиотека для управления устройствами по I2C #include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 2004 LiquidCrystal_I2C lcd(0x27, 16, 2); // присваиваем имя lcd для дисплея 20х4 char buf[6]; struct reflowStation : public Printable { float rampRateStep[9]; int temperatureStep[9]; int dwellTimerStep[9]; int profileSteps; int pwr_BOTTOM; int pwr_TOP; int Setpoint2; float kp1; float kd1; float ki1; // возможно int float kp2; float kd2; float ki2; // возможно int; size_t printTo(Print& p) const { size_t res = p.print("Steps:"); //res += p.println(timeStamp); //res += p.print("ms; T:"); //res += p.print(temperture); //res += p.print("C; H:"); res += p.print(profileSteps); //res += p.print("%; P:"); //res += p.print(pressure); return res; } }; const char string_0[] PROGMEM = "IDLE "; const char string_1[] PROGMEM = "STEPS"; const char string_2[] PROGMEM = "HEAT "; const char string_3[] PROGMEM = "PWR "; const char string_4[] PROGMEM = "RAMP "; const char string_5[] PROGMEM = "RESET"; const char *const text[] PROGMEM = { string_0, string_1, string_2, string_3, string_4, string_5 }; void setup () { Serial.begin(9600); lcd.begin(); lcd.backlight(); // включение подсветки дисплея reflowStation pr; pr.Setpoint2 = 100; pr.profileSteps = 9; pr.kp1 = 36.6; pr.kd1 = 93.2; pr.ki1 = 55.1; Serial.print(pr); lcd.setCursor(0, 0); lcd.print(pr); } // void setup() void loop() { while (!Serial.available()); byte s = Serial.read()-'0'; // Жмем кнопки 0 - 5. function(s); } // void loop() void function (const uint8_t n) { strcpy_P(buf, (char*)pgm_read_word(&(text[n]))); Serial.print(buf); }Нерабочий
// TEST #include <avr/pgmspace.h> #include <Wire.h> // библиотека для управления устройствами по I2C #include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 2004 LiquidCrystal_I2C lcd(0x27, 16, 2); // присваиваем имя lcd для дисплея 20х4 char buf[6]; struct reflowStation : public Printable { float rampRateStep[9]; int temperatureStep[9]; int dwellTimerStep[9]; int profileSteps; int pwr_BOTTOM; int pwr_TOP; int Setpoint2; float kp1; float kd1; float ki1; // возможно int float kp2; float kd2; float ki2; // возможно int; size_t printTo(Print& p) const { size_t res = p.print("Steps:"); //res += p.println(timeStamp); //res += p.print("ms; T:"); //res += p.print(temperture); //res += p.print("C; H:"); res += p.print(profileSteps); //res += p.print("%; P:"); //res += p.print(pressure); return res; } }; const char string_0[] PROGMEM = "IDLE "; const char string_1[] PROGMEM = "STEPS"; const char string_2[] PROGMEM = "HEAT "; const char string_3[] PROGMEM = "PWR "; const char string_4[] PROGMEM = "RAMP "; const char string_5[] PROGMEM = "RESET"; const char *const text[] PROGMEM = { string_0, string_1, string_2, string_3, string_4, string_5 }; void setup () { Serial.begin(9600); lcd.begin(); lcd.backlight(); // включение подсветки дисплея } // void setup() void loop() { while (!Serial.available()); byte s = Serial.read()-'0'; // Жмем кнопки 0 - 5. function(s); reflowStation pr; pr.Setpoint2 = 100; pr.profileSteps = 9; pr.kp1 = 36.6; pr.kd1 = 93.2; pr.ki1 = 55.1; Serial.print(pr); lcd.setCursor(0, 0); lcd.print(pr); } // void loop() void function (const uint8_t n) { strcpy_P(buf, (char*)pgm_read_word(&(text[n]))); Serial.print(buf); }Их единственное отличие
В первом случае на экран выводится надпись "Steps:9", во втором экран пустой
Какая разница методу откуда его вызывают?
Согласен с вами, но не могу найти ошибку
В первом случае на экран выводится надпись "Steps:9", во втором экран пустой
вангую - причина в строке 56.
Кстати Всех с наступающим праздником :) Мирного неба над головой
Приехал домой, кое что убрал в нерабочем коде, заработал. Задумаюсь... может и правда - причина в строке 56 (проверка буфера)
Сериал соединение мне только для отладки нужно было, его убрал. Спасибо всем
// TEST #include <avr/pgmspace.h> #include <Wire.h> // библиотека для управления устройствами по I2C #include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 2004 #include "Cl_do_btn_long.h" // подключаем библиотеку для опроса кнопок LiquidCrystal_I2C lcd(0x27, 16, 2); // присваиваем имя lcd для дисплея 20х4 #define BTN_NEXT 11 // кнопка uint8_t i = 0; char buf[6]; Cl_do_btn_long Btn_next(BTN_NEXT); void press_next() { /*обработчик короткого*/ if (i < 5) i++; //увеличивает счетчик кнопки на 1 else i = 0; //если счетчик достиг предела положений то его надо обнулить. } void longPress_next() { /*обработчик длинного*/ } struct reflowStation : public Printable { float rampRateStep[9]; int temperatureStep[9]; int dwellTimerStep[9]; int profileSteps; int pwr_BOTTOM; int pwr_TOP; int Setpoint2; float kp1; float kd1; float ki1; // возможно int float kp2; float kd2; float ki2; // возможно int; size_t printTo(Print& p) const { size_t res; if (i == 0) res = p.print(profileSteps); else if (i == 1) res = p.print(pwr_BOTTOM); else if (i == 2) res = p.print(pwr_TOP); else if (i == 3) res = p.print(kp1); else if (i == 4) res = p.print(kd1); else res = p.print(ki1); //res += p.print(kp2); return res; } }; const char string_0[] PROGMEM = "IDLE "; const char string_1[] PROGMEM = "STEPS"; const char string_2[] PROGMEM = "HEAT "; const char string_3[] PROGMEM = "PWR "; const char string_4[] PROGMEM = "RAMP "; const char string_5[] PROGMEM = "RESET"; const char *const text[] PROGMEM = { string_0, string_1, string_2, string_3, string_4, string_5 }; void setup () { lcd.begin(); lcd.backlight(); // включение подсветки дисплея DDRB = 0x00; // назначить пины кнопок на вход PORTB = 0b00111111; // подключить внутренние подтягивающие pull-up резисторы } // void setup() void loop() { Btn_next.run(&press_next, &longPress_next); reflowStation pr; pr.Setpoint2 = 100; pr.profileSteps = 9; pr.kp1 = 36.6; pr.kd1 = 93.2; pr.ki1 = 55.1; pr.kp2 = 14.3; pr.kd2 = 78.5; pr.ki2 = 99.4; pr.pwr_BOTTOM = 33.8; pr.pwr_TOP = 46.7; lcd.setCursor(0, 1); lcd.print(pr); function(i); } // void loop() void function (const uint8_t n) { strcpy_P(buf, (char*)pgm_read_word(&(text[n]))); lcd.setCursor(0, 0); lcd.print(buf); }Ну, и слава Богу.
Кстати, поупражняйтесь. Два часа потратил! Правда, большую часть на писание текста :)
напишу сюда. Взял стандартный пример прогмем. Все работает
#include <avr/pgmspace.h> #define BUF_LENGTH 50 char buf[BUF_LENGTH]; const char stringMES_0[] PROGMEM = "NULL_C"; const char stringMES_1[] PROGMEM = "COMMAND"; const char stringMES_2[] PROGMEM = "REPORT"; const char stringMES_3[] PROGMEM = "REQUEST"; const char* const string_tableMES[] PROGMEM = { stringMES_0, stringMES_1, stringMES_2, stringMES_3, }; void PRiNT(byte addr) { strcpy_P(buf, (char*)pgm_read_word(&(string_tableMES[addr]))); Serial.println (buf); } void setup() { Serial.begin (115200); PRiNT(1); } void loop() {}но в моем скетче нужно будет часто изменять число строк и сами строки. Можно ли сделать попроще, чтобы каждый раз этот массив
const char* const string_tableMES[] PROGMEM = { stringMES_0, stringMES_1, stringMES_2, stringMES_3, };не заполнять вручную?
Может как-то так:
#include <avr/pgmspace.h> #define BUF_LENGTH 50 const char stringMES[][BUF_LENGTH] PROGMEM = { "VATA", "SHLYAPA", "KAKA" }; const char* const string_tableMES[sizeof(stringMES)/BUF_LENGTH] PROGMEM = { stringMES[0], stringMES[1], stringMES[2] }; char buf[BUF_LENGTH]; void PRiNT (int addr) { strcpy_P(buf, (char*)pgm_read_word(&(string_tableMES[addr]))); Serial.println (buf); } void setup() { Serial.begin (115200); PRiNT (0); } void loop() {}только как бы заставить автоматически заполнять массив string_tableMES в зависимости от количества строк в массиве stringMES ?
у тебя в этом случае
const char stringMES[][BUF_LENGTH] PROGMEM = { "VATA", "SHLYAPA", "KAKA" };в PROGMEM попадают не сами строки, а указатели на них, а сами строки по-брежнему валяюца в ОЗУ. Думаю, это не то, что ты хотел.
и от это
string_tableMES[sizeof(stringMES)/BUF_LENGTH];мня неуловимо смущает. Мошт, я, правда не протрезвел еще.Если ты мне, как тупому, обьяснишь, что ты _на самом деле_ хочешь получить - мошт и получица помочь.А от так, строки у тебя будут лежать в PROGMEM, а массив нет. Ну, для конкретно этого массива, думаю, 10 байт (число строк * размер указателя) в ОЗУ не жалко, но, если нада больше строк, то его тоже можно во флэш запхать. Только читать потом придёца специальным образом.
const char str_1[] PROGMEM = "String 1"; const char str_2[] PROGMEM = "String 2"; const char str_3[] PROGMEM = "String 3"; const char str_4[] PROGMEM = "String 4"; const char str_5[] PROGMEM = "String 5"; const char *PMemStrings[] = { str_1, str_2, str_3, str_4, str_5 }; const uint8_t Strings_Count = sizeof(PMemStrings) / sizeof(PMemStrings[0]); void setup() { Serial.begin(115200); delay(250); Serial << "Count = " << Strings_Count << eoln; for (uint8_t i = 0; i < Strings_Count; i++) Serial << PFlashString(PMemStrings[i]) << eoln; }Если есть желание поиграться с PROGMEM, то вот вам задачка
/**/ void html( const char * title, ... ) { va_list ap; const char * message; va_start( ap, title ); Serial.println(title); message = va_arg( ap, const char * ); while (message) { Serial.println(message); message = va_arg( ap, const char *); } va_end( ap ); } void setup() { Serial.begin(9600); html( "1", //PSTR("1") "2", //PSTR("2") 0 //<-- конец ); } void loop() { }да, строк будет много, поэтому с прогмем и хочу заморочиться. Тот пример, что ты написал, в принципе у меня уже работает, (только и массив в прогмем). Но суть вопроса с твоим примером также остается - Помимо самих строк, нужно забивать вручную массив .
string_tableMES[sizeof(stringMES)/BUF_LENGTH];мня неуловимо смущает. Мошт, я, правда не протрезвел еще.Если ты мне, как тупому, обьяснишь, что ты _на самом деле_ хочешь получить - мошт и получица помочь.все строки будут одинаковой длины, поэтому чтобы, забивая массив, ничего не забыть (в противном случае компилятор должен ругнуться), сделал так
string_tableMES[sizeof(stringMES)/BUF_LENGTH]; а не такstring_tableMES[]все строки будут одинаковой длины,
http://arduino.ru/forum/programmirovanie/progmem-tricks#comment-439006 -> №3
пасиб, посмотрю
/**/ void html_P( const char * title, ... ) { va_list ap; const char * message; va_start( ap, title ); Serial.println((const __FlashStringHelper *)title); message = va_arg( ap, const char * ); while (message) { Serial.println((const __FlashStringHelper *)message); message = va_arg( ap, const char *); } va_end( ap ); } void setup() { Serial.begin(9600); html_P( PSTR("<html>"), PSTR("<head>"), PSTR("<title>"), PSTR("С чего начинается страница"), PSTR("</title>"), PSTR("</head>"), PSTR("<body>"), PSTR("Каждая HTML-страница начинается с тега <html> "), PSTR("</body>"), PSTR("</html>"), 0 //<-- конец ); } void loop() { }Ответ на задачу #65
const char* const string_tableMES[] PROGMEM = { stringMES_0, stringMES_1, stringMES_2, stringMES_3, };не заполнять вручную?
#pragma GCC optimize ("O0") #define BUF_SIZE 13 enum devices_enum { Rosetka, Lampa, Shtora, Boiler, DEVICE_QUANTITY }; const char PROGMEM devices[][BUF_SIZE]= { "Rosetka", "Lampa", "Shtora", "Boiler" }; void PrinT (byte addr) { char buf[BUF_SIZE]; if (addr<DEVICE_QUANTITY) {strcpy_P(buf, devices[addr]);} else {Serial.print (F("Неизвестное устройство ")); return;} Serial.print(buf); } void setup() { Serial.begin (9600); PrinT (Lampa); } void loop() {}прагму выкинь, она отключает оптимизацию
ок, понятно зачем эта строка.
ну и безопаснее будет вместо
char buf[BUF_SIZE]; if (addr<DEVICE_QUANTITY) {strcpy_P(buf, devices[addr]);}написать
char buf[BUF_SIZE+1]; memset(buf, 0x00, BUF_SIZE+1); if (addr<DEVICE_QUANTITY) {strcpy_P(buf, devices[addr]);}добрый день
по поводу поста #23
на старых версиях мандарины (младше 1.6.х) будет выдаваться ошибка
invalid conversion from 'uint16_t {aka unsigned int}' to 'const char*' [-fpermissive]соотв. строки надо изменить на
И давно у нас char стал размера 16 бит, как нужно функции pgm_read_word?
Sunjob, помоему вы ерунду предложили
> помоему вы ерунду предложили
во первых, Вы пропустили либо пробел, либо тире, во вторых, да, я обычно так и делаю, предлагаю всякую ерунду :о)
можно немного упростить (разыменовывать обычным обращением к элементу массива)
#include <avr/pgmspace.h> const char eep_str0 [] PROGMEM = "EEP String 0"; // string to 'PROGMEM' :o) const char eep_str1 [] PROGMEM = "EEP String 1"; const char eep_str2 [] PROGMEM = "EEP String 2"; const char eep_str3 [] PROGMEM = "EEP String 3"; const char eep_str4 [] PROGMEM = "EEP String 4"; const char eep_str5 [] PROGMEM = "EEP String 5"; const char eep_str6 [] PROGMEM = "EEP String 6"; const char eep_str7 [] PROGMEM = "EEP String 7"; const char eep_str8 [] PROGMEM = "EEP String 8"; const char eep_str9 [] PROGMEM = "EEP String 9"; const char ram_str [] = "RAM String"; void* mass_eep_str[] = { (void*) eep_str0,(void*) eep_str4, (void*) eep_str8 }; // mass to RAM //////////////////////////////////////////////////////////////////////////////// void setup() //////////////////////////////////////////////////////////////////////////////// { char buff[30]; Serial.begin(115200); Serial.println("### Test AVR PROGMEM string :"); strcpy_P(buff, (const char*) mass_eep_str[0]); Serial.println(buff); // w.o. clear buff ... strcpy_P(buff, (const char*) mass_eep_str[1]); Serial.println(buff); strcpy_P(buff, (const char*) mass_eep_str[2]); Serial.println(buff); } //////////////////////////////////////////////////////////////////////////////// void loop () //////////////////////////////////////////////////////////////////////////////// { ; } ////////////////////////////////////////////////////////////////////////////////-->
т.о. можно создавать "разношерстные" массивы/списки строк, находящиеся в EEPROM, и перебирать их обычным способом
удачи :о)
p.s. к стати, можно и по "другому упаковать"
const char* mass_eep_str[] = { (const char*) eep_str0,(const char*) eep_str4, (const char*) eep_str8 }; strcpy_P(buff, mass_eep_str[0]); Serial.println(buff);ver. Arduino-1.5.8
p.s.
по поводу EEP_xxx: писалось быстро, на коленке, переделкой старого кода, поэтому все так "как есть"... :o)
могу ошибаться, правьте :о)
Можешь, и ашыбаешьса.
отлично, банкуй, ушастый... рассказывай, примеры на коленке накоцаны, возможно, что-то ступил, вот вы сейчас все и поправите :о)
Нет. Не поправлю. Думай.
я сюда зашел не для "запроса вашей помочи"...
первая часть кода, это правка к опубликованному коду, для старых версий ардуино, который будет выдавать ошибку
вторая часть кода, наработка как использовать массив указателей в SRAM, что значительно быстрее и удобнее...
третья часть кода, немного измененный вариант
все три варианта проверены ... а с массивами - давно уже рабочие... и данные примеры писались, естественно, быстро, на коленке, по памяти
если есть что сказать - говорите, народ обсудит, сообществу пригодиться, если это будет умная мымсль
но иногда, лучше, молчать...
Ну да, типично...
"ребята, три дня искал как кнопку прочитать, в гугле ничего похожего нет... выкладываю код, может кому пригодицца..."
Все приветствую, прошу помочь разобраться.. Есть рабочая программа
const char Lang_ln0[] PROGMEM = "Select MODE"; const char Lang_ln1[] PROGMEM = "Select RU"; const char Lang_ln2[] PROGMEM = "Select EN"; const char Lang_ln3[] PROGMEM = "Select СH"; const char Lang_ln4[] PROGMEM = "CONFIRM MAIN"; const char Lang_ru0[] PROGMEM = "ВЫБОР"; const char Lang_ru1[] PROGMEM = "НАСТРОЙКИ"; const char Lang_ru2[] PROGMEM = "РАБОТА"; const char Lang_ru3[] PROGMEM = "ВЫХОД"; const char Lang_ru4[] PROGMEM = "ПОДТВЕРЖДЕНИЕ"; const char Lang_en0[] PROGMEM = "SELECT"; const char Lang_en1[] PROGMEM = "SETUP"; const char Lang_en2[] PROGMEM = "WORKING IN SYS"; const char Lang_en3[] PROGMEM = "EXIT 01"; const char Lang_en4[] PROGMEM = "CONFIRM 01"; const char Lang_ch0[] PROGMEM = "MODE"; const char Lang_ch1[] PROGMEM = "SYSTEM"; const char Lang_ch2[] PROGMEM = "WORKING IN SYS"; const char Lang_ch3[] PROGMEM = "EXIT 02"; const char Lang_ch4[] PROGMEM = "CONFIRM 02"; const char* const Lang_Str[][5] PROGMEM = { {Lang_ln0, Lang_ln1, Lang_ln2, Lang_ln3, Lang_ln4}, {Lang_ru0, Lang_ru1, Lang_ru2, Lang_ru3, Lang_ru4}, {Lang_en0, Lang_en1, Lang_en2, Lang_en3, Lang_en4}, {Lang_ch0, Lang_ch1, Lang_ch2, Lang_ch3, Lang_ch4}, }; void setup() { lcd.Init_LCD(); //initialize lcd } void loop() { for (int j = 0; j < 4; j++) { for (int i = 0; i < 5; i++) { char buffer [strlen_P(Lang_Str[j][i]) + 1]; strcpy_P(buffer, (char*)pgm_read_word(&(Lang_Str[j][i]))); lcd.Print_String(buffer, CENTER, 230); // вывод на экран lcd.Fill_Screen(BLACK); delay( 500 ); } }Дальше создаю функцию Print_PROGMEM
void Print_PROGMEM(const char* const Lang_Str_1, int Pos_x, int Pos_y) { char buffer [strlen_P(Lang_Str_1) + 1]; strcpy_P(buffer, Lang_Str_1); lcd.Print_String(buffer, Pos_x, Pos_y); }вставляю в loop
for (int j = 0; j < 4; j++) { for (int i = 0; i < 5; i++) { Print_PROGMEM(Lang_Str[j][i], 0, 130); lcd.Fill_Screen(BLACK); delay( 500 ); } }после этого программа выводит абракадабру, если задаю переменные константами j = 1 и i = 1 без цикла, все работает. Что не так, плиз ???
Массив же в PROGMEM !!!for (int j = 0; j < 4; j++) { for (int i = 0; i < 5; i++) { Print_PROGMEM((char*)pgm_read_word(&(Lang_Str[j][i])), 0, 130); lcd.Fill_Screen(BLACK); delay( 500 ); } }При установке констант - оптимизатор выкидывает ВСЕ не используемые строки и массив ! Остаётся только одна строка и у неё есть конкретный адрес - вот он и передаётся ...
Спасибо, разобрался