Класс-процессы и Программа Blink Bottom

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Это просто демонстрация еще одного инструмента(приема). Вообщем светодиод на выв 13 мигает, а выв 2 включают 0/ выключают 1 это мигание. Все организовано с помощью класс-процессов. Что означет, что можно одновременно организовать 6 таких пар. Причем мигать светодиоды могут с разной частотой.

https://yadi.sk/d/pXeze5_XtkRbP

код на яндекс диске.

// Класс-процесс Вспышка
class qw_blink {
  public:
    qw_blink(int pin);// конструктор с таймингом по умолчанию
    qw_blink(int pin,unsigned long span);// конструктор c установкой тайминга
    void on(); // включить мигание
    void off();// прекратить мигание    
    void go(); // драйвер blink
  private:
    unsigned long span;// интервал гашения или включения
    unsigned long future;// время сменить состояние гашения или включения    
    int            pin;// номер вывода
    boolean      state;// состояние светодиода
    boolean      blinks;// 0 - нет мигания/ 1- мигание    
};
qw_blink::qw_blink(int pin){ // конструктор с таймингом по умолчанию
    // общая часть  
  this->span = 500;// тайминг 0.5 сек
  future       = span+millis();
  // индивидуальная часть  
  this->pin  =  pin;
  pinMode(pin, OUTPUT);
  blinks    = 1; // миганиe включить
  state      = 0;
  digitalWrite(pin, state);
}
qw_blink::qw_blink(int pin,unsigned long span){ // конструктор c установкой тайминга
    // общая часть  
  this->span = span/2;
  future       = span+millis();
   // индивидуальная часть  
  this->pin  =  pin;
  pinMode(pin, OUTPUT);
  blinks    = 1; // миганиe включить
  state      = 0;
  digitalWrite(pin, state);
}
void qw_blink::on(){ // включить мигание
  blinks = 1;
}
void qw_blink::off(){// прекратить мигание
  blinks = 0; 
}
void qw_blink::go(){
    // общая часть 
  if (millis() < future) return;
  future       = span+millis();
   // индивидуальная часть  
  if (blinks == 0) state = 0;
   else  state  = ! state ;
  digitalWrite(pin, state);
}
// Класс-процесс "мигалка-кнопка"
// (вывод)-(кнопка)-(земля) 
// подтягивающий резистор подключен программно
//  1 -не нажата / 0 - нажата
class qw_blink_bottom {
  public:
    qw_blink_bottom(int pin,qw_blink * BLINK);// конструктор qw_blink_bottom с таймингом по умолчанию 
    qw_blink_bottom(unsigned long span,int pin,qw_blink * BLINK);// конструктор qw_blink_bottom
    void go();// драйвер qw_blink_bottom
    qw_blink * BLINK; // ссылка на нужного представителя qw_blink
  private:
    unsigned long span;// интервал сообщения
    unsigned long future;// время следующего сообщения 
    int pin; // нога для подключения аналог кнопок 
    boolean state;// состояние кнопки 1 -не нажата / 0 - нажата    
};
qw_blink_bottom::qw_blink_bottom(int pin,qw_blink * BLINK){ // конструктор qw_blink_bottom
  // общая часть  
  this->span = 5;// тайминг 5 миллисек
  future = span+millis();
  // индивидуальная часть 
  this->pin = pin;
  pinMode(pin, INPUT);
  state = digitalRead(pin);
  this->BLINK = BLINK;
}
qw_blink_bottom::qw_blink_bottom(unsigned long span,int pin,qw_blink * BLINK){ // конструктор qw_blink_bottom
  // общая часть  
  this->span = span;
  future = span+millis();
  // индивидуальная часть 
  this->pin = pin;
  pinMode(pin, INPUT);
  digitalWrite (pin, HIGH); // включить подтягивающий резистор
  state = digitalRead(pin);
  this->BLINK = BLINK;  
}
void qw_blink_bottom::go(){ // драйвер qw_blink_bottom
  // общая часть 
  if (millis() < future) return;
  future       = span+millis(); 
   // индивидуальная часть
  state = digitalRead(pin);
  if  (state == 0) BLINK->on();
            else BLINK->off();
}
// ===== Программа =======
 // объявить класс объекты
qw_blink VD1(13); // класс-процесс мигание светодиода на выв. 13
qw_blink_bottom SB1(2, & VD1); // класс-процесс включение (выключение) мигания светодиода на выв. 2

void setup() {
}
void loop() {
 // подключить драйвера
VD1.go();
SB1.go();
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну а это пример Мультивибратора , частота мигания светодиода задается потенциометром на выв А0.

Разумеется на одной Ардуине можно собрать до 6 независимых мультивибраторов.По числу аналоговых входов.

http://yadi.sk/d/mS_0LnSJtkh97

// Программа Мультивибратор . Частота мигания задается потенциометром
// Класс-процесс Вспышка
class qw_blink2 {
  public:
    // общая часть  
    qw_blink2(int BlinkPin,int FreacPin);// конструктор 
    void go(); // драйвер blink2
  // индивидуальная часть  
  private:
    // общая часть  
    unsigned long span;// интервал гашения или включения
    unsigned long future;// время сменить состояние гашения или включения    
  // индивидуальная часть  
    int          BlinkPin;// номер вывода светодиода
    int          FreacPin;// номер вывода регулятора частоты   
    boolean      state;// состояние светодиода   
};
qw_blink2::qw_blink2(int BlinkPin,int FreacPin){ // конструктор 
    // общая часть  
  this->FreacPin  =  FreacPin;
  pinMode(FreacPin, OUTPUT);
  span = 1+analogRead(FreacPin)*2 ;// шаг мигания 1+(0..1023)*2 
  future       = span+millis();
   // индивидуальная часть  
  this->BlinkPin  =  BlinkPin;
  pinMode(BlinkPin, OUTPUT);
  state      = 0;
  digitalWrite(BlinkPin, state);
}
void qw_blink2::go(){
    // общая часть 
  if (millis() < future) return;
  span = 1+analogRead(FreacPin)*2 ;// шаг мигания 1+(0..1023)*2
  future       = span+millis();
   // индивидуальная часть  
  state  = ! state ;
  digitalWrite(BlinkPin, state);
}
// ===== Программа =======
 // объявить класс объекты
qw_blink2 VD1(13,A0); // класс-процесс мигание светодиода на выв. 13 c регулятором частоты на выв А0

void setup() {
}
void loop() {
 // подключить драйвера
VD1.go();
}

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Светодиод на 110 строк, с возможностью адресации 65536 пинов, но без защиты от переполнения - это круто!

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
Еврейская пара ложится спать. Муж спрашивает:
- Сара, а ты дверь закрыла?
- Конечно же, Абрмчик.
- На большой замок?
- Да, на большой закрыла.
- А на мальнький замок тоже закрыла?
- Обязательно, Абрамчик.
- И на шпингалет тоже закрыла?
- Конечно закрыла.
- На большой?
- На большой.
- И на маленький?
- И на маленький.
- А на цепочку не забыла закрыть?
- Конечно же не забыла.
- На большую?
- На большую.
- И на мальнькую?
- И на маленькую.
- А на швабру закрыла?
- Ой, Абрамчик, на швабру забыла.
- Ну вот, заходи кто хочет, бери кому что надо!

Ссылка здесь http://www.anekdot.ru/id/-10050884/

 Это я к тому. Что если горе программист залезет в исходник, то все защиты уйдут по боку. А вот утяжелять код ради защиты, так я деньги на кодинге не зарабатываю.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

andriano пишет:

Светодиод на 110 строк, с возможностью адресации 65536 пинов, но без защиты от переполнения - это круто!

У меня есть имхо по этому поводу: просто сейчас у ТС такой период: классовая горячка. Когда хочется всё и вся сделать классами, библиотеками, универсальными решениями. Это одновременно и хорошо, и плохо. Хорошо - потому что обучает мыслить архитектурно. Плохо - потому что обучает мыслить архитектурно там, где этого - не надо.

Как показывает опыт - это проходит, всему своё время.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:

 с помощью класс-процессов.

«Не следует привлекать новые сущности без крайней на то необходимости» (Уильям Оккам)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Точно. Вот только моя задача это не мигать светодиодом. А отработать технологию создания драйверов. Разумеется для себя.  Вот я привел здесь 2 программы. Сколько вам времени понадобится, что бы совместить 2 разнородные программы. А вот эти программы я совместил за 5 минут. Загрузите и посмотрите. 

// Класс-процесс Вспышка
class qw_blink {
  public:
    qw_blink(int pin);// конструктор с таймингом по умолчанию
    qw_blink(int pin,unsigned long span);// конструктор c установкой тайминга
    void on(); // включить мигание
    void off();// прекратить мигание    
    void go(); // драйвер blink
  private:
    unsigned long span;// интервал гашения или включения
    unsigned long future;// время сменить состояние гашения или включения    
    int            pin;// номер вывода
    boolean      state;// состояние светодиода
    boolean      blinks;// 0 - нет мигания/ 1- мигание    
};
qw_blink::qw_blink(int pin){ // конструктор с таймингом по умолчанию
    // общая часть  
  this->span = 500;// тайминг 0.5 сек
  future       = span+millis();
  // индивидуальная часть  
  this->pin  =  pin;
  pinMode(pin, OUTPUT);
  blinks    = 1; // миганиe включить
  state      = 0;
  digitalWrite(pin, state);
}
qw_blink::qw_blink(int pin,unsigned long span){ // конструктор c установкой тайминга
    // общая часть  
  this->span = span/2;
  future       = span+millis();
   // индивидуальная часть  
  this->pin  =  pin;
  pinMode(pin, OUTPUT);
  blinks    = 1; // миганиe включить
  state      = 0;
  digitalWrite(pin, state);
}
void qw_blink::on(){ // включить мигание
  blinks = 1;
}
void qw_blink::off(){// прекратить мигание
  blinks = 0; 
}
void qw_blink::go(){
    // общая часть 
  if (millis() < future) return;
  future       = span+millis();
   // индивидуальная часть  
  if (blinks == 0) state = 0;
   else  state  = ! state ;
  digitalWrite(pin, state);
}
// Класс-процесс "мигалка-кнопка"
// (вывод)-(кнопка)-(земля) 
// подтягивающий резистор подключен программно
//  1 -не нажата / 0 - нажата
class qw_blink_bottom {
  public:
    qw_blink_bottom(int pin,qw_blink * BLINK);// конструктор qw_blink_bottom с таймингом по умолчанию 
    qw_blink_bottom(unsigned long span,int pin,qw_blink * BLINK);// конструктор qw_blink_bottom
    void go();// драйвер qw_blink_bottom
    qw_blink * BLINK; // ссылка на нужного представителя qw_blink
  private:
    unsigned long span;// интервал сообщения
    unsigned long future;// время следующего сообщения 
    int pin; // нога для подключения аналог кнопок 
    boolean state;// состояние кнопки 1 -не нажата / 0 - нажата    
};
qw_blink_bottom::qw_blink_bottom(int pin,qw_blink * BLINK){ // конструктор qw_blink_bottom
  // общая часть  
  this->span = 5;// тайминг 5 миллисек
  future = span+millis();
  // индивидуальная часть 
  this->pin = pin;
  pinMode(pin, INPUT);
  state = digitalRead(pin);
  this->BLINK = BLINK;
}
qw_blink_bottom::qw_blink_bottom(unsigned long span,int pin,qw_blink * BLINK){ // конструктор qw_blink_bottom
  // общая часть  
  this->span = span;
  future = span+millis();
  // индивидуальная часть 
  this->pin = pin;
  pinMode(pin, INPUT);
  digitalWrite (pin, HIGH); // включить подтягивающий резистор
  state = digitalRead(pin);
  this->BLINK = BLINK;  
}
void qw_blink_bottom::go(){ // драйвер qw_blink_bottom
  // общая часть 
  if (millis() < future) return;
  future       = span+millis(); 
   // индивидуальная часть
  state = digitalRead(pin);
  if  (state == 0) BLINK->on();
            else BLINK->off();
}

// Программа Мультивибратор . Частота мигания задается потенциометром
// Класс-процесс Вспышка
class qw_blink2 {
  public:
    // общая часть  
    qw_blink2(int BlinkPin,int FreacPin);// конструктор 
    void go(); // драйвер blink2
  // индивидуальная часть  
  private:
    // общая часть  
    unsigned long span;// интервал гашения или включения
    unsigned long future;// время сменить состояние гашения или включения    
  // индивидуальная часть  
    int          BlinkPin;// номер вывода светодиода
    int          FreacPin;// номер вывода регулятора частоты   
    boolean      state;// состояние светодиода   
};
qw_blink2::qw_blink2(int BlinkPin,int FreacPin){ // конструктор 
    // общая часть  
  this->FreacPin  =  FreacPin;
  pinMode(FreacPin, OUTPUT);
  span = 1+analogRead(FreacPin)*2 ;// шаг мигания 1+(0..1023)*2 
  future       = span+millis();
   // индивидуальная часть  
  this->BlinkPin  =  BlinkPin;
  pinMode(BlinkPin, OUTPUT);
  state      = 0;
  digitalWrite(BlinkPin, state);
}
void qw_blink2::go(){
    // общая часть 
  if (millis() < future) return;
  span = 1+analogRead(FreacPin)*2 ;// шаг мигания 1+(0..1023)*2
  future       = span+millis();
   // индивидуальная часть  
  state  = ! state ;
  digitalWrite(BlinkPin, state);
}
// ===== Программа =======
 // объявить класс объекты
qw_blink2 VD1(13,A0); // класс-процесс мигание светодиода на выв. 13 c регулятором частоты на выв А0
qw_blink VD2(12); // класс-процесс мигание светодиода на выв. 13
qw_blink_bottom SB1(2, & VD2); // класс-процесс включение (выключение) мигания светодиода на выв. 2

void setup() {
}
void loop() {
 // подключить драйвера
VD1.go();
VD2.go();
SB1.go();
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

ЕвгенийП пишет:

«Не следует привлекать новые сущности без крайней на то необходимости» (Уильям Оккам)

А что делать. Если в классах помимо переменных и методов появились ПРОЦЕССЫ. Тут приходится приводить новые понятия. Другое дело что это понятие уже занято.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:

А что делать. Если ...

Что делать? Изучить предмет и пользоваться общепринятой терминологией. Если, конечно, хотите, чтобы Вас понимали.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

ЕвгенийП пишет:

Что делать? Изучить предмет и пользоваться общепринятой терминологией. Если, конечно, хотите, чтобы Вас понимали.

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

a5021
Offline
Зарегистрирован: 07.07.2013

Перефразировка из В. И. Ленина: "Учиться настоящему делу военным образом!"

Logik
Offline
Зарегистрирован: 05.08.2014

И чего прицепились к ТС. Код он выложил очень даже неплохой. По крайней мере не хуже чем 90% осталього кода начинающих.

 И его .go() это именно процес, я усебя их так и называю Process(). А то что нет хендла и креатпроцесса - ну так не винда ж. А по сути это именно процесс, т.к. важен не один вызов .go() а непрерывная последовательность вызовов.

Драйвером этот класс я бы не стал называть. 

В целом подход верный, ООП попустит и совсем хороше будит.

По коду.

Два конструктора не нужно достаточно так qw_blink(int pin,unsigned long span=500); 

Если решили играть с ООП - почему два класса есть, а иерархии нет. Нужен родитель, наследование...

Про millis(). Ну так, как у вас, её используют большинство. Но учитывая что Вы в начале большого пути и правильно смотрите на вещи - мой совет. Делайте так.

long int LoopTime;

void Loop()
{
  LoopTime=millis();
  go();
......

}

И так в каждом проекте. А в либах экстерном цепляйте LoopTime и не используете millis(). Это кривовато архитектурно, но зато очень хороше по размеру кода, скорости, мерзопакостным плавающим  бага и в отладке. Кроме того для времени до минуты long int не нужен, хватит и int - мелочь, но  экономит. 

 

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

У меня не совсем класс. Я больше стороник считать что у меня ПРОЦЕСС  получился.

Если бы Си поддерживал это , то код был таким.

process name_process (timing){ // timing это время в миллисекундах через которое это дествие вызывается
  // здесь код cамого процесса
}


// или в классе
class qw_class{
  public:

  private:
process name_process2 (timing) ; // процесс пристроеный в класс

}

 qw_class OBJECT; // при создании объекта автоматом получается и процесс объекта

Так что никакого наследования в принципе быть не может.  А то что я 2 процесса сделал, так это 1 ) отработка взаимодествий двух изначально независимых процессов 2) просто так решение было проще 1 процесс мигает светодиодом. А 2-й опрашивает вывод и в случае если кнопка нажата, отключает светодиод, но процесс идет.   Замечание у процессов даже тайминги могут не совпадать. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:

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

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

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

qwone пишет:

У меня не совсем класс. Я больше стороник считать что у меня ПРОЦЕСС  получился.

Если бы Си поддерживал это , то код был таким.

process name_process (timing){ // timing это время в миллисекундах через которое это дествие вызывается
  // здесь код cамого процесса
}

Ну раз уж мы юзаем ключевое слово class - то это уже С++, а не С, это, что называется, раз. Два - в С++ требуемое вами решается стотыщью разных способов. Лично я, если подумать - сходу выбрал бы шаблонную реализацию, немножко секса, зато потом красота.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Тот же секс только в профиль. Я не показываю стотыщь способов решать проблему. Я объясняю как решить этим способом. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:

Я объясняю как решить этим способом. 

Спасибо. Будем знать.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вот это класика такого подхода. Мигать 12 светодиодами, каждый мигает со своей частотой

http://yadi.sk/d/HdcfkT5Otm884

// ---класс вспышка---
class qw_blink {
  public:
    // общая часть
    qw_blink(int pin,unsigned long span);
    void go();// драйвер blink
  private:
    // общая часть
    unsigned long span;// интервал гашения или включения
    unsigned long future;// время сменить состояние гашения или включения    
     // индивидуальная часть 
    int            pin;// номер вывода
    boolean      state;// состояние светодиода
};
qw_blink::qw_blink(int pin,unsigned long span){
  // общая часть
  this->span = span/2;
  future       = span+millis();
  // индивидуальная часть 
  this->pin  =  pin;
  pinMode(pin, OUTPUT);
  state      = 0;
  digitalWrite(pin, state);
}
void qw_blink::go(){
  // общая часть  
  if (millis() < future) return;
  future       = span+millis();
   // индивидуальная часть 
  state  = ! state ;
  digitalWrite(pin, state);
}

// ====== Программа ======  
qw_blink VD1(13,1200); // светодиод нв 13 мигает 1.2 сек
qw_blink VD2(12,1100); // светодиод нв 12 мигает 1.1 сек
qw_blink VD3(11,1000); // светодиод нв 11 мигает 1.0 сек
qw_blink VD4(10, 900); // светодиод нв 10 мигает 0.9 сек
qw_blink VD5(9,  800); // светодиод нв 9 мигает 0.8 сек
qw_blink VD6(8,  700); // светодиод нв 8 мигает 0.7 сек
qw_blink VD7(7,  600); // светодиод нв 7 мигает 0.6 сек
qw_blink VD8(6,  500); // светодиод нв 6 мигает 0.5 сек
qw_blink VD9(5,  400); // светодиод нв 5 мигает 0.4 сек
qw_blink VD10(4, 300); // светодиод нв 4 мигает 0.3 сек
qw_blink VD11(3, 200); // светодиод нв 3 мигает 0.2 сек
qw_blink VD12(2, 100); // светодиод нв 2 мигает 0.1 сек

void setup() {
}

void loop() {
VD1.go();  
VD2.go();
VD3.go();  
VD4.go();
VD5.go();  
VD6.go();
VD7.go();  
VD8.go();
VD9.go();  
VD10.go();
VD11.go();  
VD12.go();
}

 

spa-sam
Offline
Зарегистрирован: 14.12.2012

Давно хотел высказаться. Заранее прошу прощение у автора топика за отступление от темы!

Регулярно просматриваю форум... ЕвгенийП (и такие же товарищи как Он, Светилы этого форума и вобще просто молодцы по жизни))) ), я вижу, Вы походу неплохо разбиратесь "во всем этом нелёгком деле", но... Я вот понимаю, когда Вы гнобите народ, который не хочет разбираться и просит помочь в вовпросе, котором им самим приложить хоть какое-то усилие лень ( это я про "новичков" на форуме). Но, когда Вы начинаете носатить более менее толковых и имеющих желание разобраться, поделиться какими-то навыками, порой пускай даже поначалу быдлокодом ( это не относится к автору этой статьи!), то это уже перебор. Форум создан чтобы помогать друг другу, а не отбивать желание и мотивацию учиться! У Вас же всё наоборот. Лучше дайте людям направление правильное ( что почитать, где посмотреть, просто сами разжуйте, если есть желание). Почему у "буржуев" народ относится иначе?! Сколько читаю англоязычные форумы такого не вижу. У нас же всё иначе...

P.S. Сам являюсь быдлокодером, копипастером и т .д., но с большим желание разбираться и изучать начиная с осонов, чем постоянно и занимаюсь. Разводить срач не хочу, поэтому просто оставлю это тут и не более того. (т.е. ответа не жду и сам того желаю))...просто для размышления )

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

spa-sam,

наверное, я в чём-то неправ, раз Вы так это поняли. Но, видит Бог, я вовсе не хотел как-то принижать ТС, просто попросил его пользоваться общепринятой терминологией и не придумывать свою. Ладно, постараюсь быть повнимательнее в выборе выражений.

a5021
Offline
Зарегистрирован: 07.07.2013

qwone пишет:
Вот это класика такого подхода. Мигать 12 светодиодами, каждый мигает со своей частотой

И чем оно лучше привычной классики?

uint8_t pinNo[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
static bool state[sizeof(pinNo)];
uint32_t span[] = {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200};
uint32_t future[sizeof(pinNo)];

void setup() {
  uint32_t t = millis();
  for (int i = 0; i < sizeof(pinNo); i++) {
    span[i] /= 2;
    future[i] = span[i] + t;
    pinMode(pinNo[i], OUTPUT);
    digitalWrite(pinNo[i], 0);
  }
}

void loop() {
  uint32_t t = millis();
  for (int i = 0; i < sizeof(pinNo); i++) {
    if (t < future[i]) continue;
    future[i] = span[i] + t;
    state[i] = !state[i];
    digitalWrite(pinNo[i], state[i]);
  }
}

На данный момент я вижу, что "новая" классика проигрывает "старой" по объему исходного кода, объему результирующего исполняемого кода, аппетитам к ОЗУ и скоростью выполнения. Собственно, по всем важным параметрам и проигрывает. И где тут плюсы нового подхода?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

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

Повторюсь. Это просто еще один подход. Для кого-то хорош, для кого-то плох.

ПС: Совмещаются к сожалению только программы написаные этим подходом. Со старыми такой фокус не пройдет.

Ваша 1270-129

Моя старая 1478-141

поменял типы переменых на uint32_t и uint8_t

Стало 1446-129 

// ---класс вспышка---
class qw_blink {
  public:
    // общая часть
    qw_blink(uint8_t pin,uint32_t span);
    void go();// драйвер blink
  private:
    // общая часть
    uint32_t span;// интервал гашения или включения
    uint32_t future;// время сменить состояние гашения или включения    
     // индивидуальная часть 
    uint8_t        pin;// номер вывода
    boolean      state;// состояние светодиода
};
qw_blink::qw_blink(uint8_t pin,uint32_t span){
  // общая часть
  this->span = span/2;
  future       = span+millis();
  // индивидуальная часть 
  this->pin  =  pin;
  pinMode(pin, OUTPUT);
  state      = 0;
  digitalWrite(pin, state);
}
void qw_blink::go(){
  // общая часть  
  if (millis() < future) return;
  future       = span+millis();
   // индивидуальная часть 
  state  = ! state ;
  digitalWrite(pin, state);
}

// ====== Программа ======  
qw_blink VD1(13,1200); // светодиод нв 13 мигает 1.2 сек
qw_blink VD2(12,1100); // светодиод нв 12 мигает 1.1 сек
qw_blink VD3(11,1000); // светодиод нв 11 мигает 1.0 сек
qw_blink VD4(10, 900); // светодиод нв 10 мигает 0.9 сек
qw_blink VD5(9,  800); // светодиод нв 9 мигает 0.8 сек
qw_blink VD6(8,  700); // светодиод нв 8 мигает 0.7 сек
qw_blink VD7(7,  600); // светодиод нв 7 мигает 0.6 сек
qw_blink VD8(6,  500); // светодиод нв 6 мигает 0.5 сек
qw_blink VD9(5,  400); // светодиод нв 5 мигает 0.4 сек
qw_blink VD10(4, 300); // светодиод нв 4 мигает 0.3 сек
qw_blink VD11(3, 200); // светодиод нв 3 мигает 0.2 сек
qw_blink VD12(2, 100); // светодиод нв 2 мигает 0.1 сек

void setup() {
}

void loop() {
VD1.go();  
VD2.go();
VD3.go();  
VD4.go();
VD5.go();  
VD6.go();
VD7.go();  
VD8.go();
VD9.go();  
VD10.go();
VD11.go();  
VD12.go();
}

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

qwone пишет:

поменял типы переменых на uint32_t и uint8_t

Стало 1446-129 

Подход имеет право на существование, безусловно. Насчёт быстродействия: тут я согласен с a5021 - надо над этим ещё поработать. Например, не вижу смысла каждый раз дёргать millis во всех экземплярах класса - зачем такой оверхед? Достаточно в метод go передавать дельту между последним вызовом millis и текущим, эту дельту вычислять в loop. Тогда, при наличии 10 экземпляров класса - millis будет дёргаться только 1 раз, а не 10, согласитесь, это сильно лучше в плане эффективности?

То же самое касается и digitalWrite - жирно, очень жирно каждый раз её вызывать, если периодичность вызова довольно высокая. Тут уж - либо напрямую работа с портами напрямую, либо, если не хочется уходить от удобной привязки номеров пинов к портам - digitalPinToBitMask сотоварищи в конструкторе класса.

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

Что касается архитектуры: вот смотрю я на 12 экземпляров класса, и так и просится паттерн "visitor", чтобы не писать в loop простыню из вызовов VD9.go(); и т.п. Впрочем, это тоже - дело вкуса.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

1. Длинные портянки из почти одинаковых операторов как в setup, так и в loop выглядят, прямо скажем, отталкивающе.

2. Если уж делать класс, то следовало бы дать ему возможность самостоятельно управлять вызовом методов go. Т.е. мы в setup (или в любом другом месте программы) сообщаем управляющему классу, какие классы мы хотим включить в циклическую обработку, и уже он сам все это обеспечивает. Аналогично должен быть метод для исключения вызовов объектов из цикла. И пусть в loop все это выглядит вызовом единтственного управляющего объекта, а внутри он сам уже отслеживает, какие объекты ему нужно вызывать, а какие - нет.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Я согласен. Но вот какое дело? Если писать программу, то кодом в котором уверен. Конечно есть в мире конструкции, которые работают, но при этом их не знаешь.  Ну да ,учится учится учится. Но что бы не быть Попугаем , висящим на форуме , и тролящим других. Надо писать код самому, даже с учетом того минимума , в котором уверен.  Про  "visitor" я ничего не знаю.

a5021
Offline
Зарегистрирован: 07.07.2013

qwone пишет:
В невозможности работать параллельно нескольким программам.   Вы видели я вверху сделал две программы, а потом в третей их совместил.

Если я вынесу содержимое setup() и loop() в отдельные функции, а заодно напишу еще кучку подобных функций с иным наполенением, то точно так же смогу вызывать.

setup() {
  setup1();
  setup2();
  ..
  setup22();
}

loop() {
  func1();
  func2();
  ..
  func22();
}

а то и вовсе:

void (*setupf[])(void) = {setup1, setup2, ... setup33, setup34};

void setup() {
  for (int i = 0; i < sizeof(setupf); i++) (*setupf[i])();
}

void (*func[])(void) = {func1, func2, ... func43, func44};
int i = 0;

void loop() {
  (*func[i++])();
  if (i == sizeof(func)) i = 0;
}

И чем это будет отличаться от вашего "совместил" ? Я уж не Бог весть, какой программист, но "много текста" это как раз при вашем подходе. И, что еще хуже, там к этому добавиться еще и много исполняемого кода.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

qwone пишет:

Про  "visitor" я ничего не знаю.

https://www.google.ru/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#newwindow=1&q=%D0%BF%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD+%D0%BF%D0%BE%D1%81%D0%B5%D1%82%D0%B8%D1%82%D0%B5%D0%BB%D1%8C

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

Вот ещё, кстати, применительно к реализации разных поведенческих моделей: https://www.google.ru/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#newwindow=1&q=%D0%BF%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD+%D0%BF%D0%BE%D0%B4%D0%BF%D0%B8%D1%81%D1%87%D0%B8%D0%BA

Logik
Offline
Зарегистрирован: 05.08.2014

qwone пишет:

У меня не совсем класс. Я больше стороник считать что у меня ПРОЦЕСС  получился.

Не льстите себе :). Это класс, что  вы сами явно декларировали. Где в коде указано что это процесс? Нигде. Предсавление о том что одна из функций класса используется как процесс не заявлено, следовать это принято на прикладном уровне на основе навания функция и её описания. А для компилятора это ф-ия член класса и усьо.

qwone пишет:

Если бы Си поддерживал это , то код был таким.

Ну если бы у бабы были яйки, то Вы знаете.. А так - см. выше. 

Кстати  на каком языке этот пример?

qwone пишет:

Так что никакого наследования в принципе быть не может. 

Хммм... Тут или ктото когото не понял или Вам с ООП еще игратся надо. Откройте обявление ваших 2-х классов и найдите совпадения. Вот то что совпало - в предок. И окажется что go именно в нем. Виртуальная. Тогда и код аналогичный приведенному  в 2-м примере  http://arduino.ru/forum/programmirovanie/klass-protsessy-i-programma-blink-bottom#comment-209760 напишется легко и непренужденно, но в ООП.  

Однако имеет ли смысл делать как в 2-м примере http://arduino.ru/forum/programmirovanie/klass-protsessy-i-programma-blink-bottom#comment-209760 . Иногда да, но как правило нет. Обычная ситуация не 12 мигающих светодиодов, а некоторое количество зависимых друг от друга разнородных процессов. Например процессы опроса датчика, протокола обмена, обновления данных на экране, мигания иконки на экране. Причем обновление данных на экране активизируется после успешного опроса датчика а мигание иконки - при наличии обмена по протоколу в течении 5 секунд. И это логика самого верхнего уровня, очевидное её место - прямо в лупе, где она непосредственно решает какие из функций процессов активны, а какие нет. Конечно это тоже можно засунуть в класс, завернуть в функции возвращающие активность и т.д. А зачем? Это самая прога и есть, ей самое место в лупе.

ПС. Очень полезно когда функция процесса возвращает его статус (типа "жду", "завершить процес сейчас нельзя", "отправлен ответ", "возникла критическая ошибка" и т.д.) и принимает команду - "работай", "завершись сейчас", "пауза", "уходим в слип" и т.д. Тогда и логика управления активностью процессов выглядит просто и естественно.

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Logic. Наследование это конечно хорошо. Но у меня наследование нормально не получилось.

class qw_basic { // базовый класс
  public:  
    qw_basic(uint32_t span);
    void go();
    uint32_t span;// интервал гашения или включения
    uint32_t future;// время сменить состояние гашения или включения    
};
qw_basic::qw_basic(uint32_t span){
  this->span = span/2;
  future       = span+millis();
}
void qw_basic::go(){
  if (millis() < future) return;
  future       = span+millis();
   Serial.println("basic");
}
class qw_a_son : public qw_basic 
{
  public:
    qw_a_son(uint32_t span);
    void go();
  private:
};
qw_a_son::qw_a_son(uint32_t span):qw_basic(span)
{

}
void qw_a_son::go()
{
  if (millis() < future) return;
  future       = span+millis();
  Serial.println("son");
}






qw_a_son BASIC(1000);
//qw_basic BASIC(1000);
void setup() {
  Serial.begin(9600);

}

void loop() {
BASIC.go();
}

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015
class qw_basic { // базовый класс
  public:  
    qw_basic(uint32_t span);
    void go();
protected:
   virtual void logic() = 0;
    uint32_t span;// интервал гашения или включения
    uint32_t future;// время сменить состояние гашения или включения    
};
qw_basic::qw_basic(uint32_t span){
  this->span = span/2;
  future       = span+millis();
}
void qw_basic::go(){
  if (millis() < future) return;
  future       = span+millis();
   Serial.println("basic");
  logic();
}
class qw_a_son : public qw_basic 
{
  public:
    qw_a_son(uint32_t span);

protected:
    void logic();
  private:
};
qw_a_son::qw_a_son(uint32_t span):qw_basic(span)
{

}
void qw_a_son::logic()
{
  Serial.println("son");
}






qw_a_son BASIC(1000);
//qw_basic BASIC(1000);
void setup() {
  Serial.begin(9600);

}

void loop() {
BASIC.go();
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Про protected: понятно. Но в классе qw_a_son метод go() должен наследаваться целиком + еще модефикация и имя go() должно сохранится.

Хотя для разового наследования virtual void logic() может подойти

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

qwone пишет:

Про protected: понятно. Но в классе qw_a_son метод go() должен наследаваться целиком + еще модефикация и имя go() должно сохранится.

class qw_basic { // базовый класс
  public:  
    qw_basic(uint32_t span);
    virtual void go();
    uint32_t span;// интервал гашения или включения
    uint32_t future;// время сменить состояние гашения или включения    
};
qw_basic::qw_basic(uint32_t span){
  this->span = span/2;
  future       = span+millis();
}
void qw_basic::go(){
  if (millis() < future) return;
  future       = span+millis();
   Serial.println("basic");
}
class qw_a_son : public qw_basic 
{
  public:
    qw_a_son(uint32_t span);
    void go();
  private:
};
qw_a_son::qw_a_son(uint32_t span):qw_basic(span)
{

}
void qw_a_son::go()
{
  qw_basic::go();
  Serial.println("son");
}






qw_a_son BASIC(1000);
//qw_basic BASIC(1000);
void setup() {
  Serial.begin(9600);

}

void loop() {
BASIC.go();
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Похоже void go(); надо перестать быть void 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

qwone пишет:

Похоже void go(); надо перестать быть void 

Это уже детали реализации ;)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Причесал. Правда еще одна приятная неожиданость получилась

class qw_basic {             // базовый класс
  public:  
    qw_basic(uint32_t span);
    virtual uint8_t go();
protected:    
    uint32_t span;         // интервал гашения или включения
    uint32_t future;     // время сменить состояние гашения или включения    
};
qw_basic::qw_basic(uint32_t span){
    this->span = span ;
    future = span +  millis();
}
uint8_t qw_basic::go() {           // конструктор qw_basic
    if (millis() < future) return 1;
    future  = span + millis();
    Serial.println("basic");
    return 0;
}
class qw_a_son : public qw_basic  { //  класс наследника
  public:
    qw_a_son(uint32_t span);
    uint8_t go();
  private:
};
qw_a_son::qw_a_son(uint32_t span):qw_basic(span) { // конструктор qw_a_son

}
uint8_t qw_a_son::go(){ // драйвер qw_a_son
  if ( qw_basic::go() ) return 1;  
  Serial.println("son");
  return 0;
}

qw_a_son BASIC(1000);
void setup() {
  Serial.begin(9600);
}

void loop() {
 if ( ! BASIC.go() ) {
 Serial.println("loop()"); // тоже работает раз в 0.1 сек
 };
}

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

qwone пишет:

Причесал. Правда еще одна приятная неожиданость получилась

А теперь смотрите, пути дальнейшего улучшения: что делать, если надо динамически поменять интервал, например? Я в следующем посте напишу один из примеров реализации, раз уж мы тут разминаемся ;)

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

class Delta
{
  public:
    Delta()
    {
      dt_last = millis();
    }
    
    void update()
    {
      unsigned long cur = millis();
      this->dt = cur - this->dt_last;
      this->dt_last = cur;
    }
    
    bool check(unsigned long interval) const
    {
      return (this->dt >= interval);
    }
    
  private:
    unsigned long dt_last, dt;
};

class IntervalStrategy
{
  public:
    IntervalStrategy(unsigned long intrval)
    {
      set(intrval);
    }
    
    void set(unsigned long intrval)
    {
      this->interval = intrval;
    }
    
    bool go(const Delta& d)
    {
      if(!d.check(this->interval))
        return false;
        
      return do_work();
    }
    
  protected:
    unsigned long interval;
    virtual bool do_work() = 0;
};

class MyBlink : public IntervalStrategy
{
  public:
    MyBlink(unsigned long intrval) : IntervalStrategy(intrval) {}
  protected:

  bool do_work()
  {
      // тут специфичная работа

     return true;
  }
  
};

Delta dt;

MyBlink is1(100);
MyBlink is2(500);
MyBlink is3(1000);


void setup()
{
}

void loop()
{
  dt.update();
  
  is1.go(dt);
  
  if(is2.go(dt))
    is2.set(250);
    
  is3.go(dt);
}
qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Так посмотреть код 

 // базовый класс   - согласовывает работу программы
class qw_basic {            
  public:  
    qw_basic(uint32_t span);
    virtual uint8_t go();
protected:    
    uint32_t span;         // интервал гашения или включения
    uint32_t future;     // время сменить состояние гашения или включения    
};
qw_basic::qw_basic(uint32_t span){
    this->span = span ;
    future = span +  millis();
}
uint8_t qw_basic::go() {           // конструктор qw_basic
    if (millis() < future) return 1;
    future  = span + millis();
    return 0;
}
// ====== Программа ======
qw_basic Time_per_1sec(1000);
qw_basic Time_per_100msec(100);

// Cоздание матрицы переменных
 uint8_t BASE_Format[10] =   {     2,     2,     2,     2,     2,     3,     3,     3,     3,     3};
 char *  BASE_Title[ ] = {"  A1","  A2","  A3","  A4","  A5","pin2","pin3","pin4","pin5","pin6"};
 uint8_t BASE_Value[ ]  =    { 50   , 50   , 50   , 50   , 50   , 0    , 0    , 0    , 0    , 0    };
 uint8_t N;
 char * BOOLEAN[] = {"OFF"," ON"};

void setup() {
 Serial.begin(9600);
 
 pinMode(A1, OUTPUT); // потенциометр на А1
 pinMode(A2, OUTPUT); // потенциометр на А2
 pinMode(A3, OUTPUT); // потенциометр на А3
 pinMode(A4, OUTPUT); // потенциометр на А4
 pinMode(A5, OUTPUT); // потенциометр на А5
   // подключение реле
 pinMode(2, OUTPUT);
 pinMode(3, OUTPUT);
 pinMode(4, OUTPUT);
 pinMode(5, OUTPUT);
 pinMode(6, OUTPUT);
 N =0;
}

void loop() {
 if ( ! Time_per_1sec.go()) {
  Serial.print  ( N );
  Serial.print  (" > " );  
  Serial.print  ( BASE_Format[N] );
  Serial.print  (" : " );
  Serial.print  ( BASE_Title[N]); 
  Serial.print  (" = " );
  
  if (BASE_Format[N] == 3) {Serial.println( BOOLEAN[BASE_Value[N]] );}
                      else Serial.println( BASE_Value[N] );
  N++;
  if (N>9) N = 0;
  };
  if ( ! Time_per_100msec.go()) {
  BASE_Value[0 ] = analogRead(A1);
  BASE_Value[1 ] = analogRead(A2);
  BASE_Value[2 ] = analogRead(A3);
  BASE_Value[3 ] = analogRead(A4);
  BASE_Value[4 ] = analogRead(A5);
  if (BASE_Value[0 ] > 500){BASE_Value[5 ] =1;digitalWrite(2, 1);}
                      else {BASE_Value[5 ] =0;digitalWrite(2, 0);};   
  if (BASE_Value[1 ] > 500){BASE_Value[6 ] =1;digitalWrite(3, 1);}
                      else {BASE_Value[6 ] =0;digitalWrite(3, 0);};      
  if (BASE_Value[2 ] > 500){BASE_Value[7 ] =1;digitalWrite(4, 1);}
                      else {BASE_Value[7 ] =0;digitalWrite(4, 0);};
  if (BASE_Value[3 ] > 500){BASE_Value[8 ] =1;digitalWrite(5, 1);}
                      else {BASE_Value[8 ] =0;digitalWrite(5, 0);};       
  if (BASE_Value[4 ] > 500){BASE_Value[9 ] =1;digitalWrite(6, 1);}
                      else {BASE_Value[9 ] =0;digitalWrite(6, 0);};       
      };  
}

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Можно и так :) Кстати, в приведённом мной коде - недоработка серьёзная, прошу воспринимать как говноподелку :)

Logik
Offline
Зарегистрирован: 05.08.2014

И шо это за ужас я увидел среди ночи?! Совсем распустились? Как циклами пользоватся забыли?! Сейчазже строки 62-76 в цикл засунуть! Пока другие спят и не видят! ;)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

 А это и есть цикл. Только цикл ИСПОЛНЯТЬ РАЗ 100 мсек.

Ну не зачем дергать датчики чаще, как чаще давать команды на исполнение. 

(анекдот) В программиском центре. Начальник центра своему заму.
- Что то программисты совсем перестали работать.
- Та нет же вот сидят за компьютерами.
- Не слышу стука клавиш. А раз часто не стучат клавишами, то значит совсем не работают.

А то что по строчке выдает на экран, так чаще и не надо. Это заготовка для Меню. LCD 1602 все за раз не поместится.

Logik
Offline
Зарегистрирован: 05.08.2014

 

qwone пишет:

 А это и есть цикл. Только цикл ИСПОЛНЯТЬ РАЗ 100 мсек.

У как все запущенно.. Какие операторы цикла в С Вы знаете (кроме if конечно))))

 


 // базовый класс   - согласовывает работу программы
class qw_basic {            
  public:  
    qw_basic(uint32_t span);
    virtual uint8_t go();
protected:    
    uint32_t span;         // интервал гашения или включения
    uint32_t future;     // время сменить состояние гашения или включения    
};
qw_basic::qw_basic(uint32_t span){
    this->span = span ;
    future = span +  millis();
}
uint8_t qw_basic::go() {           // конструктор qw_basic
    if (millis() < future) return 1;
    future  = span + millis();
    return 0;
}
// ====== Программа ======
qw_basic Time_per_1sec(1000);
qw_basic Time_per_100msec(100);

// Cоздание матрицы переменных
 uint8_t BASE_Format[10] =   {     2,     2,     2,     2,     2,     3,     3,     3,     3,     3};
 char *  BASE_Title[ ] = {"  A1","  A2","  A3","  A4","  A5","pin2","pin3","pin4","pin5","pin6"};
 uint8_t BASE_Value[ ]  =    { 50   , 50   , 50   , 50   , 50   , 0    , 0    , 0    , 0    , 0    };
 uint8_t N;
 char * BOOLEAN[] = {"OFF"," ON"};

void setup() {
 Serial.begin(9600);
 
 pinMode(A1, OUTPUT); // потенциометр на А1
 pinMode(A2, OUTPUT); // потенциометр на А2
 pinMode(A3, OUTPUT); // потенциометр на А3
 pinMode(A4, OUTPUT); // потенциометр на А4
 pinMode(A5, OUTPUT); // потенциометр на А5
   // подключение реле
 pinMode(2, OUTPUT);
 pinMode(3, OUTPUT);
 pinMode(4, OUTPUT);
 pinMode(5, OUTPUT);
 pinMode(6, OUTPUT);
 N =0;
}

void loop() {
 if ( ! Time_per_1sec.go()) {
  Serial.print  ( N );
  Serial.print  (" > " );  
  Serial.print  ( BASE_Format[N] );
  Serial.print  (" : " );
  Serial.print  ( BASE_Title[N]); 
  Serial.print  (" = " );
  
  if (BASE_Format[N] == 3) {Serial.println( BOOLEAN[BASE_Value[N]] );}
                      else Serial.println( BASE_Value[N] );
  N++;
  if (N>9) N = 0;
  };
  if ( ! Time_per_100msec.go()) {
    for(byte a=0, p=A1;a<5;a++,p++)
    {
       BASE_Value[a] = analogRead(p);
       if (BASE_Value[a] > 500){BASE_Value[a+5 ] =1;digitalWrite(a+2, 1);}
                      else {BASE_Value[a+5 ] =0;digitalWrite(a+2, 0);};      
    }
  };  
}

 Инкремент адресов пинов сделан лихо. Так можна далеко не везде и всегда. По хорошему пины в массивы и выбирать через итератор цикла. BASE_Value если больше нигде не нужен - изкоренить.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Logik Вы когда нибудь клеммы видели. http://www.ru.all.biz/img/ru/catalog/1357495.jpeg  Бесполезная вещь вроде.:) Ведь можно завести напрямую к устройcтву. А ведь народ извращается лепит везде. Вот такая штука и здесь. Только я не придумал как лучше ее реализовать. Вот приходится единую BASE делать из трех BASE_Format[] ,BASE_Title[ ], BASE_Value[ ].

Logik
Offline
Зарегистрирован: 05.08.2014

Клемник видел, с его бесполезностью не согласен категоричо ;), т.к. приходилось открывать шкафы релейки и там их стоко... и без них никак. 

Мой ответ несколько запоздалый. Знаете, море, пляж, винчик не способствуют висению на форуме, пока чаек покормиш, девок попоиш - уже и утро, снова пора на пляж... ))) Сегодня пасмурно.

По сути - Вам нужна структура и инициализированный массив этих структур, чтото типа

struct Base
{
uint8_t Format;
char* Title;
uint8_t Value;
};
Base BASE[]= {
{2, "  A1", 50},
{2, "  A2", 50},
{2, "  A3", 50},

};
.....
Serial.println(BASE[2].Title);

Можете заметить что структура очень похожа на класс. Злые языки поговаривают, что вообще нет разницы между ними и компилятор воспринимает class так же как struct. И классы в С++ это мировой заговор "сионистов" ))