Классы Ардуино по qwone для чайников.

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

А вот скетч

/**/
unsigned long mill;
typedef void (*pDo)();
//------Cl_Display----------------------
// класс регулярный вывод на дисплей
class Cl_Display {
  protected:
    pDo Do;//обработчик
    bool refreshON = 1; //сигнал обновить
  public:
    /*конструктор*/
    Cl_Display(pDo D): Do(D) {}
    /*инициализация-вставить в setup()*/
    void init() {
    }
    /*работа-вставить в loop()*/
    void run() {
      if (refreshON) {
        refreshON = 0;
        Do();
      }
    }
    void refresh() {
      refreshON = 1;
    }
    /*записать новый обработчик*/
    void write( pDo D) {
      Do = D;
    }
};
//------Cl_Btn----------------------
class Cl_Btn {                      /* класс кнопка*/
  protected:
    const byte pin;
    pDo Do;//обработчик
    bool bounce = 0;
    bool btn = 1, oldBtn;
    unsigned long past;
  public:
    /*конструктор*/
    Cl_Btn(byte p, pDo D): pin(p), Do(D) {}
    /*инициализация-вставить в setup()*/
    void init() {
      pinMode(pin, INPUT_PULLUP);
    }
    /*работа-вставить в loop()*/
    void run() {
      bool newBtn = digitalRead(pin);
      if (!bounce && newBtn != btn) {
        bounce = 1;
        past = mill;
      }
      if (bounce && mill - past >= 10) {
        bounce = 0 ;
        oldBtn = btn;
        btn = newBtn;
        past = mill;
        if (!btn && oldBtn) Do();
      }
    }
    /*записать новый обработчик*/
    void write( pDo D) {
      Do = D;
    }
};
//------Cl_BtnR----------------------
class Cl_BtnR : public Cl_Btn {      /* класс кнопка с повтором при удерж кнопки*/
  protected:
  public:
    /*конструктор*/
    Cl_BtnR(byte p, pDo D): Cl_Btn(p, D) {}
    /*работа-вставить в loop()*/
    void run() {
      bool newBtn = digitalRead(pin);
      if (!bounce && newBtn != btn) {
        bounce = 1;
        past = mill;
      }
      if (bounce && mill - past >= 10) {
        bounce = 0 ;
        oldBtn = btn;
        btn = newBtn;
        past = mill;
        if (!btn && oldBtn) Do();
      }
      if (!newBtn && !btn && mill - past >= 150) {
        past = mill;
        Do();
      }
    }
};
//-----Компоненты Меню-------------------------
void ExitMenu() {};
int Value1, Value2, Value3, Value4, Value5, Value6, Value7, Value8, Value9;
byte screen ; byte line ; bool fEdit;
void initMenu( byte screen);/*предварительное объявление*/
//-----sItemMenu----------------
enum {
  ROOT,
  HOLDER,
  CONFIGINT
};
struct sItemMenu {
  byte type;
  byte num;
};
const sItemMenu dbItemMenu[] PROGMEM = {
  /*type,num*/
  {ROOT, 0},     /*#0 ROOT[0]    1-3*/
  {HOLDER, 0},   /*#1 HOLDER[0]  4-6*/
  {HOLDER, 1},   /*#2 HOLDER[1]  7-9 */
  {CONFIGINT, 0},/*#3 var 1  CONFGINT[0]*/

  {HOLDER, 2},     /* #4 HOLDER[2]  10-12   */
  {CONFIGINT, 1},  /* #5 var 2  CONFGINT[1] */
  {CONFIGINT, 2},  /* #6 var 3  CONFGINT[2] */

  {CONFIGINT, 3},  /* #7 var 4  CONFGINT[3] */
  {CONFIGINT, 4},  /* #8 var 5  CONFGINT[4] */
  {CONFIGINT, 5},  /* #9 var 6  CONFGINT[5] */

  {CONFIGINT, 6},  /* #10 var 7  CONFGINT[6]*/
  {CONFIGINT, 7},  /* #11 var 8  CONFGINT[7]*/
  {CONFIGINT, 8}  /* #12 var 9  CONFGINT[8]*/
};
void pgm_viev(char *name) {/*вывод из PROGMEM*/
  char buffer[15];
  strcpy_P(buffer, name);
  Serial.print(buffer);
}
//------sItemRoot-------------------
struct sItemRoot {
  const byte top;
  const byte bottom;
  const pDo Do;
};
const sItemRoot dbItemRoot[] PROGMEM = {
  {1, 3, ExitMenu} /*ROOT[0]*/
};
byte readTopItemRoot(byte the) { /* <- top[the] */
  return pgm_read_byte(&dbItemRoot[the].top);
}
byte readBottomItemRoot(byte the) { /* <- top[the] */
  return pgm_read_byte(&dbItemRoot[the].bottom);
}
void DoItemRoot(byte the) {  /* Do[the] */
  pDo Do = pgm_read_word(&dbItemRoot[the].Do);
  Do();
}
//------sItemHolder-------------------
struct sItemHolder {
  const byte father;
  const byte top;
  const byte bottom;
  const char *name;
};
const char txtItemHolder0[] PROGMEM = "R0 HOLDER 1";
const char txtItemHolder1[] PROGMEM = "R0 HOLDER 2";
const char txtItemHolder2[] PROGMEM = "H0 HOLDER 3";
const sItemHolder dbItemHolder[] PROGMEM = {
  /*father,top,bottom,name*/
  {0,  4,  6, txtItemHolder0}, /*#0 HOLDER[0]*/
  {0,  7,  9, txtItemHolder1}, /*#1 HOLDER[1]*/
  {1, 10, 12, txtItemHolder2}  /*#2 HOLDER[2]*/
};
byte readFatherItemHolder(byte the) { /* <- father[the] */
  return pgm_read_byte(&dbItemHolder[the].father);
}
byte readTopItemHolder(byte the) { /* <- top[the] */
  return pgm_read_byte(&dbItemHolder[the].top);
}
byte readBottomItemHolder(byte the) { /* <- top[the] */
  return pgm_read_byte(&dbItemHolder[the].bottom);
}
char * readItemHolderName(byte the) { /* <- name[the] */
  return (char *)pgm_read_byte(&dbItemHolder[the].name);
}
//-------sItemConfigInt----------------
struct sItemConfigInt {
  int * pointer;
  byte addr;
  int   maxValue;
  int   minValue;
  int   setValue;
  const char *name;
};
const byte numItemConfigInt = 9; /*кол-во элементов ConfigInt */
const char txtItemConfigInt0[] PROGMEM = "R0 var 1=";
const char txtItemConfigInt1[] PROGMEM = "H0 var 2=";
const char txtItemConfigInt2[] PROGMEM = "H0 var 3=";
const char txtItemConfigInt3[] PROGMEM = "H1 var 4=";
const char txtItemConfigInt4[] PROGMEM = "H1 var 5=";
const char txtItemConfigInt5[] PROGMEM = "H1 var 6=";
const char txtItemConfigInt6[] PROGMEM = "H2 var 7=";
const char txtItemConfigInt7[] PROGMEM = "H2 var 8=";
const char txtItemConfigInt8[] PROGMEM = "H2 var 9=";
const sItemConfigInt dbItemConfigInt[] PROGMEM = {
  /*pointer,addr,max,min,set,name*/
  { &Value1,  0, 100, 10, 10, txtItemConfigInt0}, /*CONFGINT[0]*/
  { &Value2,  2, 100, 10, 20, txtItemConfigInt1}, /*CONFGINT[1]*/
  { &Value3,  4, 100, 10, 30, txtItemConfigInt2}, /*CONFGINT[2]*/
  { &Value4,  6, 100, 10, 40, txtItemConfigInt3}, /*CONFGINT[3]*/
  { &Value5,  8, 100, 10, 50, txtItemConfigInt4}, /*CONFGINT[4]*/
  { &Value6, 10, 100, 10, 60, txtItemConfigInt5}, /*CONFGINT[5]*/
  { &Value7, 12, 100, 10, 70, txtItemConfigInt6}, /*CONFGINT[6]*/
  { &Value8, 14, 100, 10, 80, txtItemConfigInt7}, /*CONFGINT[7]*/
  { &Value9, 16, 100, 10, 90, txtItemConfigInt8}  /*CONFGINT[8]*/
};
int readItemConfigInt(byte the) {    /*<-VAL[the]*  ++ */
  int * pointer = pgm_read_word(&dbItemConfigInt[the].pointer);
  return * pointer;
}
void readItemConfigIntfromPROGMEM(byte the) { /*VAL[the]<-PROGMEM[the] ++ */
  int * pointer = pgm_read_word(&dbItemConfigInt[the].pointer);
  *pointer      = pgm_read_word(&dbItemConfigInt[the].setValue);
}
void plusItemConfigInt(byte the) {/*if (VAL[the]<max[the]) ++VAL[the]*/
  int * pointer = pgm_read_word(&dbItemConfigInt[the].pointer);
  byte maxValue = pgm_read_byte(&dbItemConfigInt[the].maxValue);
  if (* pointer < maxValue) *pointer += 1;
}
void minusItemConfigInt(byte the) {/*if (VAL[the]>min[the]) --VAL[the]*/
  int * pointer = pgm_read_word(&dbItemConfigInt[the].pointer);
  byte minValue = pgm_read_byte(&dbItemConfigInt[the].minValue);
  if (* pointer > minValue ) *pointer -= 1;
}
char * readItemConfigIntName(byte the) { /* <- name[the] */
  return (char *)pgm_read_byte(&dbItemConfigInt[the].name);
}
#include <EEPROM.h>
void readItemConfigIntfromEEPROM(byte the) { /*VAL[the]<-EEPROM[the]*/
  int * pointer = pgm_read_word(&dbItemConfigInt[the].pointer);
  byte addr = pgm_read_byte(&dbItemConfigInt[the].addr);
  EEPROM.get(addr, *pointer);
}
void writeItemConfigIntToEEPROM(byte the) { /*EEPROM[the]<-VAL[the]*/
  int * pointer = pgm_read_word(&dbItemConfigInt[the].pointer);
  byte addr = pgm_read_byte(&dbItemConfigInt[the].addr);
  EEPROM.put(addr, *pointer);
}
void readAllItemConfigIntfromEEPROM() { /*VAL[All]<-EEPROM[All]*/
  for (int i = 0; i < numItemConfigInt; ++i) {
    readItemConfigIntfromEEPROM(i);
  }
}
void AllItemConfigIntPROGMEMtoEEPROM() { /*EEPROM[All]<-PROGMEM[the][All]*/
  for (int i = 0; i < numItemConfigInt; ++i) {
    int ConfigInt = pgm_read_word(&dbItemConfigInt[i].setValue);
    byte addr = pgm_read_byte(&dbItemConfigInt[i].addr);
    EEPROM.put(addr, ConfigInt);
  }
}
//-------------------
void initMenu( byte scr) {
  screen = scr;
  byte type = pgm_read_byte(&dbItemMenu[screen].type);
  byte num  = pgm_read_byte(&dbItemMenu[screen].num);
  if (type == ROOT)   line = pgm_read_byte(&dbItemRoot[num].top);
  if (type == HOLDER) line = pgm_read_byte(&dbItemHolder[num].top);
  fEdit = 0;
}
//-------------------
void VievMenu(byte screen, byte line, byte fEdit) {
  byte type = pgm_read_byte(&dbItemMenu[screen].type);
  byte num  = pgm_read_byte(&dbItemMenu[screen].num);
  if (type == ROOT) {
    byte top    = pgm_read_byte(&dbItemRoot[num].top);
    byte bottom = pgm_read_byte(&dbItemRoot[num].bottom);
    Serial.println();
    for (int i = top; i <= bottom; ++i) {
      Serial.println();
      if (i == line) {
        if (fEdit)Serial.print("*");
        else Serial.print(">");
      }
      else Serial.print(" ");
      byte t = pgm_read_byte(&dbItemMenu[i].type);
      byte n = pgm_read_byte(&dbItemMenu[i].num);
      if (t == CONFIGINT) {
        char * name = readItemConfigIntName(n);
        pgm_viev(name);
        int ItemValue = readItemConfigInt(n);
        Serial.print(ItemValue);
      }
      if (t == HOLDER) {
        char * name = readItemHolderName(n);
        pgm_viev(name);
      }
    }
  }
  if (type == HOLDER) {
    byte top    = pgm_read_byte(&dbItemHolder[num].top);
    byte bottom = pgm_read_byte(&dbItemHolder[num].bottom);
    Serial.println();
    for (int i = top; i <= bottom; ++i) {
      Serial.println();
      if (i == line) {
        if (fEdit)Serial.print("*");
        else Serial.print(">");
      }
      else Serial.print(" ");
      byte t = pgm_read_byte(&dbItemMenu[i].type);
      byte n = pgm_read_byte(&dbItemMenu[i].num);
      if (t == HOLDER) {
        char * name = readItemHolderName(n);
        pgm_viev(name);
      }
      if (t == CONFIGINT) {
        char * name = readItemConfigIntName(n);
        pgm_viev(name);
        int ItemValue = readItemConfigInt(n);
        Serial.print(ItemValue);
      }
    }
  }
}
//-----Компоновка------------------------------
void DoViev() {
  VievMenu(screen, line, fEdit);
}
Cl_Display Display(/*обработчик*/DoViev);
void DoBtn1() {/*-*/
  Display.refresh();
  if (fEdit) { /*реж редактирования*/
    byte t = pgm_read_byte(&dbItemMenu[line].type);
    byte n = pgm_read_byte(&dbItemMenu[line].num);
    if (t == CONFIGINT) {
      minusItemConfigInt(n);
    }
  }
  else {/*реж передвиж*/
    byte type = pgm_read_byte(&dbItemMenu[screen].type);
    byte num = pgm_read_byte(&dbItemMenu[screen].num);
    if (type == ROOT) {
      byte top    = pgm_read_byte(&dbItemRoot[num].top);
      if (line > top ) --line;
    }
    if (type == HOLDER) {
      byte top    = pgm_read_byte(&dbItemHolder[num].top);
      if (line > top ) --line;
      else if (line == top ) {
        screen = pgm_read_byte(&dbItemHolder[num].father);
        byte t = pgm_read_byte(&dbItemMenu[screen].type);
        byte n = pgm_read_byte(&dbItemMenu[screen].num);
        if (t == ROOT) line = pgm_read_byte(&dbItemRoot[n].top);
        else         line = pgm_read_byte(&dbItemHolder[n].top);
      }
    }
  }
}
void DoBtn2() {/*+*/
  Display.refresh();
  if (fEdit) { /*реж редактирования*/
    byte t = pgm_read_byte(&dbItemMenu[line].type);
    byte n = pgm_read_byte(&dbItemMenu[line].num);
    if (t == CONFIGINT) {
      plusItemConfigInt(n);
    }
  }
  else {/*реж передвиж*/
    byte type = pgm_read_byte(&dbItemMenu[screen].type);
    byte num = pgm_read_byte(&dbItemMenu[screen].num);
    if (type == ROOT) {
      byte bottom = pgm_read_byte(&dbItemRoot[num].bottom);
      if (line < bottom ) ++line;
    }
    if (type == HOLDER) {
      byte bottom = pgm_read_byte(&dbItemHolder[num].bottom);
      if (line < bottom ) ++line;
    }
  }
}
void DoBtn3() {/*exe*/
  Display.refresh();
  byte t = pgm_read_byte(&dbItemMenu[line].type);
  byte n = pgm_read_byte(&dbItemMenu[line].num);
  if (fEdit) { /*реж редактирования*/
    if (t == CONFIGINT) {
      writeItemConfigIntToEEPROM(n);
      fEdit = 0;
    }
    return;
  }
  else {     /*реж передвиж*/
    if (t == HOLDER   ) initMenu(line);
    if (t == CONFIGINT) fEdit = 1;
  }
}
Cl_BtnR Btn1(/*пин*/2,/*обработчик*/DoBtn1);/*-*/
Cl_BtnR Btn2(/*пин*/3,/*обработчик*/DoBtn2);/*+*/
Cl_Btn  Btn3(/*пин*/4,/*обработчик*/DoBtn3);/*exe*/
//--main()-------------------
void setup() {
  Serial.begin(9600);
  //AllItemConfigIntPROGMEMtoEEPROM();/*первичная настройка EEPROM из PROGMEM*/
  readAllItemConfigIntfromEEPROM(); /*прочитать из памяти*/
  initMenu(0);/*установить меню в начало*/
  Display.init();
  Btn1.init();
  Btn2.init();
  Btn3.init();
}

void loop() {
  mill = millis();
  Display.run();
  Btn1.run();
  Btn2.run();
  Btn3.run();
}
/*Скетч использует 4380 байт (14%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 250 байт (12%) динамической памяти, оставляя 1798 байт для локальных переменных. Максимум: 2048 байт.
*/

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016
 
ZaabaL пишет:
Необходимо включить насос через 3 минутыпосле того как одна из трех кнопок нажата(удерживается,сухой контакт) и отключить насос через 1 минутуесли ни одна кнопка не нажата.P.S. для теплого пола. 3 минуты задержки нужны для открытия сервопривода на коллекторе и 1 минута на закрытие
/*насос*/
unsigned long mill; // переменная под millis()
//-------кнопки---------------------
const byte Btn1Pin =/*пин*/2;
const byte Btn2Pin =/*пин*/3;
const byte Btn3Pin =/*пин*/4;
//-------насос---------------------
const byte pumpPin =/*пин*/13;
byte state = 0;      /*0 выкл /1 вкл /2 собирается выкл/3 собирается вкл*/
const unsigned long timeON  = 180000;
const unsigned long timeOFF =  60000;
unsigned long pastPump;
void stand(byte s) {      /*установить в состояние*/
  state = s;
  pastPump = mill;
  switch (s) {
    case 0:/*0 выкл*/
      digitalWrite(pumpPin, LOW);
      break;
    case 1:/*1 вкл*/
      digitalWrite(pumpPin, HIGH);
      break;
  }
}
void initPump() { /* инициализация воткнуть в setup*/
  pinMode(Btn1Pin, OUTPUT);
  stand(0);
}
void runPump() { /*воткнуть в loop*/
  if (state == 2 && mill - pastPump >= timeON ) stand(0);
  if (state == 3 && mill - pastPump >= timeOFF) stand(1);
}
void ONtime() { /*вкл с задержкой*/
  if (state == 1)return;
  if (state == 3)return;
  stand(3);
}
void OFFtime() { /*выкл с задержкой*/
  if (state == 0)return;
  if (state == 2)return;
  stand(2);
}
//--------------main--------------
void setup() {
  pinMode(Btn1Pin, INPUT_PULLUP);
  pinMode(Btn2Pin, INPUT_PULLUP);
  pinMode(Btn3Pin, INPUT_PULLUP);
  initPump();
}
void loop() {
  mill = millis();
  bool Btn1 = digitalRead(Btn1Pin);
  bool Btn2 = digitalRead(Btn2Pin);
  bool Btn3 = digitalRead(Btn3Pin);
  if (!Btn1 || !Btn2 || !Btn3) { /*если одна из кнопок нажата*/
    ONtime();          /*то включить насос с задержкой 3 мин*/
  }
  if (Btn1 && Btn2 && Btn3) { /*если все кнопки отжаты */
    OFFtime();        /*то отключить насос с задержкой 1 мин*/
  }
  runPump() ;
}
/*Скетч использует 1384 байт (4%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 18 байт (0%) динамической памяти, оставляя 2030 байт для локальных переменных. Максимум: 2048 байт.
*/

 

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Так скетч Блинкер. Задаете программу и мигает по программе. Нажали кнопку включилось. еще раз нажали выключилось. Можно хоть на мигать различными ногами и по своей программе.

/**/
unsigned long mill;
typedef void (*pDo)() ;// тип -функция обработчик
//------------------------------------
typedef struct { /*формат записи программы*/
  byte maxTick;         // количество миганий
  unsigned long OnTick; // сколько нужно светить
  unsigned long OffTick; // сколько "держать паузу
}  Tick_t;
enum {sStop = 0, sStart, sOnTick, sOffTick, sPause};
class Cl_Blinker {
  protected:
    byte pin;/*нога*/
    Tick_t *prog;
    unsigned long past, interval;
    const unsigned long pause = 1000;/*длительность паузы между сериями*/
    byte iTick, iPeriod, maxTick, maxPeriod;
    byte state;
    void stand(byte s) {
      state = s;
      past = mill;
      switch (state) {
        case sStop:
          digitalWrite(pin, LOW);
          break;
        case sStart:
          iTick = 0;
          iPeriod = 0;
          maxTick = prog[iPeriod].maxTick;
          state = sOnTick;
        case sOnTick:
          interval = prog[iPeriod].OnTick;
          digitalWrite(pin, HIGH);
          break;
        case sOffTick:
          interval = prog[iPeriod].OffTick;
          digitalWrite(pin, LOW);
          break;
        case sPause:
          interval = pause;
          break;
      }
    }
  public:
    Cl_Blinker(byte p, Tick_t *pr, byte s)
      : pin(p), prog(pr), maxPeriod(s) {}
    void init() {
      pinMode(pin, OUTPUT);
      stand(sStop);
    }
    void run() {
      if (state == sOnTick  && mill - past >= interval) stand(sOffTick);
      if (state == sOffTick && mill - past >= interval) {
        iTick++;
        if (iTick >= maxTick) {
          iPeriod++;
          if (iPeriod >= maxPeriod) {
            stand(sPause);
            return;
          }
          else {
            iTick = 0;
            maxTick = prog[iPeriod].maxTick;
            stand(sOnTick);
          }
        }
        else  stand(sOnTick);
      }
      if (state == sPause   && mill - past >= interval) stand(sStart);
    }
    void start() {
      stand(sStart);
    }
    void stop() {
      stand(sStop);
    }
};
//------Cl_Btn----------------------
// класс кнопка
class Cl_Btn {
  protected:
    const byte pin;
    pDo Do1, Do2; //обработчик 1 и 2
    bool bounce = 0;
    bool btn = 1, oldBtn;
    unsigned long past;
    byte stand = 0;
    void tick() {
      if (stand == 0) {
        stand = 1;
        Do1();
      }
      else {
        stand = 0;
        Do2();
      }
    }
  public:
    /*конструктор*/
    Cl_Btn(byte pin_, pDo D1, pDo D2)
      : pin(pin_), Do1(D1), Do2(D2) {}
    /*инициализация-вставить в setup()*/
    void init() {
      pinMode(pin, INPUT_PULLUP);
      tick();
    }
    /*работа-вставить в loop()*/
    void run() {
      bool newBtn = digitalRead(pin);
      if (!bounce && newBtn != btn) {
        bounce = 1;
        past = mill;
      }
      if (bounce && mill - past >= 10) {
        bounce = 0 ;
        oldBtn = btn;
        btn = newBtn;
        if (!btn && oldBtn) tick();
      }
    }
};
//------Компоновка-------------------------------
Tick_t prog[] = {
  /* maxTick OnTick OffTick*/
  {3, 100 , 100}, // 3 коротких
  {3, 500 , 100}, // 3 длиных
  {3, 100 , 100}, // 3 коротких
};
byte step = sizeof(prog) / sizeof(Tick_t); // вычисляем сколько у нас всего "комманд".
Cl_Blinker Blinker(/*пин*/13,/*программа*/prog,/*количество*/step);
void Do1Btn1() {
  Blinker.start();
}
void Do2Btn1() {
  Blinker.stop();
}
Cl_Btn Btn1(/*пин*/2,/*обработчик 1*/Do1Btn1,/*обработчик 2*/Do2Btn1);
//---------Main----------------------------
void setup() {
  Blinker.init();
  Btn1.init();

}

void loop() {
  mill = millis();
  Blinker.run();
  Btn1.run();
}
/*Скетч использует 1910 байт (6%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 74 байт (3%) динамической памяти, оставляя 1974 байт для локальных переменных. Максимум: 2048 байт.
*/

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Светофор через цифровой автомат. Это картинка не подходит для программирования.Попробуем немного изменить.

Вот получился скетч.

/*TrafficLight светофор*/
unsigned long mill; // переменная под millis()
//--------------------------------
enum {sOFF = 0, sRed, sYellow1, sGreen, sYellow2};
class Cl_TrafficLight {
  protected:
    byte Rpin, Ypin, Gpin;
    unsigned long past;
    byte state;
    void stand(byte s) {
      past = mill;
      state = s;
      switch (state) {
        case sOFF:
          digitalWrite(Rpin, LOW);
          digitalWrite(Ypin, LOW);
          digitalWrite(Gpin, LOW);
          break;
        case sRed:
          digitalWrite(Ypin, LOW);
          digitalWrite(Rpin, HIGH);
          break;
        case sYellow1:
          digitalWrite(Rpin, LOW);
          digitalWrite(Ypin, HIGH);
          break;
        case sGreen:
          digitalWrite(Ypin, LOW);
          digitalWrite(Gpin, HIGH);
          break;
        case sYellow2:
          digitalWrite(Gpin, LOW);
          digitalWrite(Ypin, HIGH);
          break;
      }
    }
  public:
    /**/
    Cl_TrafficLight(byte R, byte Y, byte G)
      : Rpin(R), Ypin(Y), Gpin(G) {}
    /**/
    void init() {
      pinMode(Rpin, OUTPUT);
      pinMode(Ypin, OUTPUT);
      pinMode(Gpin, OUTPUT);
      OFF();
    }
    /**/
    void run() {
      if (state == sRed && mill - past >= 3000)stand(sYellow1);
      if (state == sYellow1 && mill - past >= 1000)stand(sGreen);
      if (state == sGreen && mill - past >= 3000)stand(sYellow2);
      if (state == sYellow2 && mill - past >= 1000)stand(sRed);
    }
    /*включить*/
    void ON() {
      stand(sRed);
    }
    /*выключить*/
    void OFF() {
      stand(sOFF);
    }
};

//---Компоновка-----------------------------
Cl_TrafficLight Light(/*пин Красный*/2,/*пин Желтый*/3,/*пин Зеленый*/4);
//---main-----------------------------
void setup() {
  Light.init();
  Light.ON();
}
void loop() {
  mill = millis();
  Light.run();
}
/*Скетч использует 1382 байт (4%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 21 байт (1%) динамической памяти, оставляя 2027 байт для локальных переменных. Максимум: 2048 байт.
*/

 

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

Нипонял, а где мигание зеленого за 3сек до переключения на желтый и где одновременное горение желтого и красного перед переключением на зеленый? 

По коду, void stand(byte s) выполняет 5 действий (причем 2 из них совпадают) в зависимости от параметра, а два из этих действий обернуты в отдельный вызов в стр55-62. Это явно надумано. Делаем просто 4 функции void standOFF()  void standRed(..... и массив указателей на них, заполненный по порядку их включения. И паузы тоже в массив. В результате стр.50-53 приятно ужимаются почти в одну и их кол-во перестает зависить от числа режимов. И тогда любые хотелки типа мигания зеленого легко добавляются причем почти без правки кода, только добавлением в массив указателей на функции и массив пауз. А совсем уж по уму держать один массив структур.

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Logik, здесь используется цифровой автомат. И решается через цифровой автомат. Если начать оптимизировать, то точно сведется к черному ящику и нефиг лезть туда, где и так все работает.

Logik пишет:
Нипонял, а где мигание зеленого за 3сек до переключения на желтый и где одновременное горение желтого и красного перед переключением на зеленый?
  Это все можно организовать дополнительным классом. Просто расписав алгоритм работы и состояния системы. Как и частоту мигания . А так же вывод сколько секунд осталось до переключения.

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

qwone пишет:

Logik, здесь используется цифровой автомат

таниужели! Ого как! )))) Может добавить знак "Осторожно, цифровой автомат!" ;)

qwone пишет:

Если начать оптимизировать, то точно сведется к черному ящику и нефиг лезть туда, где и так все работает.

Я и не предлагал Вам от цифрового автомата отказыватся. Эта штука годная. Но похоже Вам нравится одиночество в этой теме. Продолжайте.

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

/*TrafficLight светофор*/
unsigned long mill; // переменная под millis()
typedef void (*pDo)() ;// тип -функция обработчик
//---------------Cl_Led---------
//класс Cl_Led управление  светодиодом
enum {sLedOFF = 0, sLedON, sLedBlink};
class Cl_Led {
    byte pin;//нога светодиода
    bool led;// уровень на выводе светодиода
    uint32_t time;// полупериод мигания светодиода
    uint32_t past;// время последнего переключения
    byte state;
    void stand(byte s) {
      state = s;
      past = mill;
      switch (state) {
        case sLedOFF:
          digitalWrite(pin, led = HIGH);
          break;
        case sLedON:
          digitalWrite(pin, led = LOW);
          break;
        case sLedBlink:
          digitalWrite(pin, led = !led);
          break;
      }
    }
  public:
    // конструктор класса
    Cl_Led(int p): pin(p) {}
    // метод setup()
    void init() {
      pinMode(pin, OUTPUT);
      stand(sLedOFF);
    }
    void run() {
      if (state == sLedBlink && mill - past >= time)stand(sLedBlink);
    }
    // включить светодиод
    void ON() {
      stand(sLedON);
    }
    // выключить светодиод
    void OFF() {
      stand(sLedOFF);
    }
    // мигать светодиодом
    void blink(uint32_t t = 500) {
      time = t;
      stand(sLedBlink);
    }
};
//--------------------------------
enum {sOFF = 0, sRed, sYellow1, sGreen, sYellow2, sFault};
class Cl_TrafficLight {
  protected:
    Cl_Led LedRed1, LedYellow1, LedGreen1, LedRed2, LedYellow2, LedGreen2;
    unsigned long past;
    byte state;
    void stand(byte s) {
      past = mill;
      state = s;
      switch (state) {
        case sOFF:
          LedRed1.OFF();/*выкл*/
          LedYellow1.OFF();
          LedGreen1.OFF();
          LedRed2.OFF();
          LedYellow2.OFF();
          LedGreen2.OFF();
          break;
        case sRed:  /*крвсный*/
          LedRed1.ON();
          LedGreen2.ON();
          LedYellow1.OFF();
          LedYellow2.OFF();
          break;
        case sYellow1: /*мигает желтый*/
          LedRed1.OFF();
          LedGreen2.OFF();
          LedYellow1.blink(200);
          LedYellow2.blink(200);
          break;
        case sGreen: /*зеленый*/
          LedGreen1.ON();
          LedRed2.ON();
          LedYellow1.OFF();
          LedYellow2.OFF();
          break;
        case sYellow2:/*мигает желтый*/
          LedGreen1.OFF();
          LedRed2.OFF();
          LedYellow1.blink(200);
          LedYellow2.blink(200);
          break;
        case  sFault:/*авария*/
          LedRed1.OFF();
          LedYellow1.ON();
          LedGreen1.OFF();
          LedRed2.OFF();
          LedYellow2.ON();
          LedGreen2.OFF();
          break;
      }
    }
  public:
    /**/
    Cl_TrafficLight(byte R1, byte Y1, byte G1, byte R2, byte Y2, byte G2)
      : LedRed1(R1), LedYellow1(Y1), LedGreen1(G1), LedRed2(R2), LedYellow2(Y2), LedGreen2(G2) {}
    /**/
    void init() {
      LedRed1.init();
      LedYellow1.init();
      LedGreen1.init();
      LedRed2.init();
      LedYellow2.init();
      LedGreen2.init();
      OFF();
    }
    /**/
    void run() {
      LedRed1.run();
      LedYellow1.run();
      LedGreen1.run();
      LedRed2.run();
      LedYellow2.run();
      LedGreen2.run();
      if (state == sRed && mill - past >= 3000)stand(sYellow1);
      if (state == sYellow1 && mill - past >= 1000)stand(sGreen);
      if (state == sGreen && mill - past >= 3000)stand(sYellow2);
      if (state == sYellow2 && mill - past >= 1000)stand(sRed);
    }
    /*запустить*/
    void start() {
      stand(sRed);
    }
    /*остановить*/
    void stop() {
      stand(sFault);
    }
    /*выключить*/
    void OFF() {
      stand(sOFF);
    }
};
//------Cl_Btn----------------------
// класс кнопка
class Cl_Btn {
  protected:
    const byte pin;
    pDo Do1, Do2; //обработчик 1 и 2
    bool bounce = 0;
    bool btn = 1, oldBtn;
    unsigned long past;
    byte stand = 0;
    void tick() {
      if (stand == 0) {
        stand = 1;
        Do1();
      }
      else {
        stand = 0;
        Do2();
      }
    }
  public:
    /*конструктор*/
    Cl_Btn(byte pin_, pDo D1, pDo D2)
      : pin(pin_), Do1(D1), Do2(D2) {}
    /*инициализация-вставить в setup()*/
    void init() {
      pinMode(pin, INPUT_PULLUP);
      tick();
    }
    /*работа-вставить в loop()*/
    void run() {
      bool newBtn = digitalRead(pin);
      if (!bounce && newBtn != btn) {
        bounce = 1;
        past = mill;
      }
      if (bounce && mill - past >= 10) {
        bounce = 0 ;
        oldBtn = btn;
        btn = newBtn;
        if (!btn && oldBtn) tick();
      }
    }
};
//---Компоновка-----------------------------
Cl_TrafficLight Light(/*пин Красный1*/3,/*пин Желтый1*/4,/*пин Зеленый1*/5,/*пин Красный2*/6,/*пин Желтый2*/7,/*пин Зеленый2*/8);
void Do1Btn1() {
  Light.start();
}
void Do2Btn1() {
  Light.stop();
}
Cl_Btn Btn1(/*пин*/2,/*обработчик 1*/Do1Btn1,/*обработчик 2*/Do2Btn1);
//---main-----------------------------
void setup() {
  Light.init();
  Btn1.init();
}
void loop() {
  mill = millis();
  Light.run();
  Btn1.run();
}
/*Скетч использует 2614 байт (8%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 97 байт (4%) динамической памяти, оставляя 1951 байт для локальных переменных. Максимум: 2048 байт.
*/

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Пух, ну вот КАК тебе удается нести херню, вроде бы, с виду  правильными словами?  Я вот когда несу, у меня слова неправильные, а у тебя дар.  Я прям завидую. 

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

)))) 

Это потому что у него нетрадиционное виденье поддерживается крепостью веры.

Зато когда вижу типа такого

      LedRed1.run();
      LedYellow1.run();
      LedGreen1.run();
      LedRed2.run();
      LedYellow2.run();
      LedGreen2.run();
      if (state == sRed && mill - past >= 3000)stand(sYellow1);
      if (state == sYellow1 && mill - past >= 1000)stand(sGreen);
      if (state == sGreen && mill - past >= 3000)stand(sYellow2);
      if (state == sYellow2 && mill - past >= 1000)stand(sRed);

понимаю что в китайском коде некоторые китайцам и фору дать могут.

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016
RizONE
Offline
Зарегистрирован: 22.03.2018

За тему большое спасибо!

Для новичков или подзабывших про программаж на С/С++ очень полезно.

freeman86
Offline
Зарегистрирован: 07.09.2016
Спасибо вам за тему! Очень полезная. Вы советовали книгу вначале темы. И там как мне показалось указано, что нельзя при создании класса присваивать значение переменным в этом классе. Строки 16 и 17. Однако ваш код работает. 


class Cl_Btn {
13
    byte pin; // номер ноги на кнопке
14
    void (* Do)();// указатель на обработчик
15
    bool btn, btn_old;
16
    bool bounce = 0; // антидребезговый флаг
17
    uint32_t past = 0 ;
18
  public:
19
    // конструктор класса
20
    Cl_Btn( byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {}
21
    // метод setup()
22
    void setup() {
23
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
24
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
25
    }
26
    // метод loop()
27
    void loop() {
28
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
29
        bounce = 1;                              // выставить флаг
30
        past = millis();                         // сделать временую засветку
31
      }
32
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
33
        bounce = 0;                                // то снять флаг
34
        btn_old = btn ;
35
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
36
        if (btn_old && ! btn) Do();
37
      }
38
    }
39
};

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

freeman86, а вот здесь вылез факт о котором новички не догадываются. Они считают что Си/Си++ уже не развивается и не меняется. А последняя редакция Си произошла в 2017 году. А книга о Си написана еще до этих изменений.

https://www.youtube.com/watch?v=eSwrisPYrXE

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

freeman86 пишет:

нельзя при создании класса присваивать значение переменным в этом классе. Строки 16 и 17.

Без крайней нужды этого лучше не делать. А если делать, то точно знать что именно Вы делаете. Там очень много тонкостей, и очень многое может пойти не так. Инициализация в конструкторе - значительно проще и надёжнее.

freeman86
Offline
Зарегистрирован: 07.09.2016

Еще вопросы по дальнейшему коду, если не возражаете. Я все сам переписываю и загружаю в плату ) 

http://arduino.ru/forum/programmirovanie/klassy-arduino-po-qwone-dlya-ch...

вот тут по ссылке бит инверсии. Не понимаю, в чем преимущество такого варианты перед led = !led? И как понимать синтаксис led ^ inv, в таблице я оператор ^ не нашел, только ^=. 

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Шаблоны для тех кто не знал, а потом случилось несчастье забыл. Код отсюда #10

Класс

/**/
//-------------------------------
class Cl_Stack {
  protected:
    byte *ptr;
    byte size;
    int top;
  public:
    Cl_Stack(int s = 10);
    ~Cl_Stack();
    bool push(byte num);
    bool pop(byte & num);
};
Cl_Stack::Cl_Stack(int s) {
  size = s > 0 ? s : 10;  // инициализировать размер стека
  ptr = new byte[size]; // выделить память под стек
  top = -1; // значение -1 говорит о том, что стек пуст
}
Cl_Stack::~Cl_Stack() {
  delete [] ptr;
}
bool Cl_Stack::push(byte num) {
  if (top > size) return 0;
  top++;
  ptr[top] = num;
  return 1;
}
bool Cl_Stack::pop(byte & num) {
  if (top < 0) return 0;
  num = ptr[top];
  top--;
  return 1;
}
//-------------------------------
const byte len = 5;
Cl_Stack Stack(len);
byte num;
//-------------------------------
void setup() {
  Serial.begin(9600);
  for (int i = 0; i < len; i++) {
    Stack.push(i);
  }
  for (int i = 0; i < len; i++) {
    Stack.pop(num);
    Serial.print(" ");
    Serial.print(num);
  }
  Serial.println();
}
void loop() {
}
/*Скетч использует 2392 байт (7%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 204 байт (9%) динамической памяти, оставляя 1844 байт для локальных переменных. Максимум: 2048 байт.
*/

И через шаблон

/**/
//-------------------------------
template <typename T> class Cl_Stack {
  protected:
    T *ptr;
    byte size;
    int top;
  public:
    Cl_Stack(int s = 10);
    ~Cl_Stack();
    bool push(T num);
    bool pop(T & num);
};
template <typename T> Cl_Stack<T>::Cl_Stack(int s) {
  size = s > 0 ? s : 10;  // инициализировать размер стека
  ptr = new T[size]; // выделить память под стек
  top = -1; // значение -1 говорит о том, что стек пуст
}
template <typename T> Cl_Stack<T>::~Cl_Stack() {
  delete[] ptr;
}
template <typename T> bool Cl_Stack<T>::push(T num) {
  if (top > size) return 0;
  top++;
  ptr[top] = num;
  return 1;
}
template <typename T> bool Cl_Stack<T>::pop(T & num) {
  if (top < 0) return 0;
  num = ptr[top];
  top--;
  return 1;
}
//-------------------------------
const byte len = 5;
Cl_Stack<byte> Stack(len);
byte num;
//-------------------------------
void setup() {
  Serial.begin(9600);
  for (int i = 0; i < len; i++) {
    Stack.push(i);
  }
 for (int i = 0; i < len; i++) {
    Stack.pop(num);
    Serial.print(" ");
    Serial.print(num);
  }
  Serial.println();
}
void loop() {
}
/*Скетч использует 2392 байт (7%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 204 байт (9%) динамической памяти, оставляя 1844 байт для локальных переменных. Максимум: 2048 байт.
*/

 

freeman86
Offline
Зарегистрирован: 07.09.2016

А на мой вопрос по поводу бита инверсии и led ^ inv ответите? )

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

freeman86,Возьмем таблицу операторов в Си. https://msdn.microsoft.com/ru-ru/library/126fe14k.aspx  ^ ​Побитовое исключающее ИЛИ led здесь bool-  то есть два значения. Это по синтасису. 

Теперь по программе. Есть реле (светодиоды и т д) . Некоторые срабатывают при HIGH, другие по LOW. Можно написать для них два класса. Но можно написать универсальный, где ввести в консруктор дополнитнльную переменную inv. Если inv - LOW , то это срабатывание при HIGH. И обратно. То есть использование оператора ^ упрощает и сокращает код. И в конце концов делает "универсальный класс".

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

qwone пишет:

Шаблоны для тех кто не знал, а потом случилось несчастье забыл. Код отсюда #10

И через шаблон

/**/
//-------------------------------
template <typename T> class Cl_Stack {
  protected:
    T *ptr;
    byte size;
    int top;
  public:
    Cl_Stack(int s = 10);
    ~Cl_Stack();
    bool push(T num);
    bool pop(T & num);
};
template <typename T> Cl_Stack<T>::Cl_Stack(int s) {
  size = s > 0 ? s : 10;  // инициализировать размер стека
  ptr = new T[size]; // выделить память под стек
  top = -1; // значение -1 говорит о том, что стек пуст
}
template <typename T> Cl_Stack<T>::~Cl_Stack() {
  delete[] ptr;
}
template <typename T> bool Cl_Stack<T>::push(T num) {
  if (top > size) return 0;
  top++;
  ptr[top] = num;
  return 1;
}
template <typename T> bool Cl_Stack<T>::pop(T & num) {
  if (top < 0) return 0;
  num = ptr[top];
  top--;
  return 1;
}
//-------------------------------
const byte len = 5;
Cl_Stack<byte> Stack(len);
byte num;
//-------------------------------
void setup() {
  Serial.begin(9600);
  for (int i = 0; i < len; i++) {
    Stack.push(i);
  }
 for (int i = 0; i < len; i++) {
    Stack.pop(num);
    Serial.print(" ");
    Serial.print(num);
  }
  Serial.println();
}
void loop() {
}
/*Скетч использует 2392 байт (7%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 204 байт (9%) динамической памяти, оставляя 1844 байт для локальных переменных. Максимум: 2048 байт.
*/

Квон, тебе не надоело с напыщенностью усталого ментора постить код с детскими ошибками?

Лови пример для твоего класса с шаблоном:

void setup() {
	Cl_Stack<long> Stack1(2);
	Serial.begin(57600);
	
	String pushRes = "PUSH RESULT: ";
	
	for (int i = 0; i < 3; i++) {
		const int val = i + 100;
		pushRes += "push(";
		pushRes += val;
		pushRes += ")-";
		pushRes += Stack1.push(val) ? "succ" : "fail";
		pushRes += "; ";
	}
	Serial.println(pushRes);
}
void loop() {}
//
// Результат
// SH RESULT: push(100)-succ; push(101)-succ; push(102)-succ; 

А теперь объясни мне. Все пуши завершились успешно, так какая же зараза стырила первые две буквы выводной строки? Куда они делись?

И это кстати, не единственная ошибка в этом коротеньком куске говнокода. Вторая, правда, не детская, а скорее идеологическая. Показать?

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

Ворота пишет:

для твоего класса с шаблоном:

А код без шаблонов что, лучше? Те же самые детские ошибки. Но ТС не очень адекватно реагирует на сообщения об ошибках, так что я уж давно помалкиваю.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Чёт квон не спешит ошибки править. Решил кинуть своих читателей, которые надеются найти у него решение своих проблем :(((