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

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

ЕвгенийП пишет:
Про это ТС говорили ещё месяц назад, но, похоже, здесь принципиальное неприятие :)
Если нужна пакетная обработка, то лучше setup и loop сделать статическим методом. А городить с абстракными и виртуальными. Так это надо сначало написать новую среду разработки программ на Винде , и потом эта среда будет уже программировать абстрактные классы. 

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

Вот и я ж про тоже :)))

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

Да qwone, то архитектура не того гарварда, то винду дописывать, то статически лучше но потом. Пишите проще "гранаты не той системы", мы поймем ;)

Бабы в таких случаях говорят "проще дать чем обяснить чего нет". Вижу проще самому написать, чем обяснить почему.

Код. Проверен. Смотрим сириал и наслаждаемся. Саму музыку в Cl_music и  кнопку в Cl_Btn сами прицепите. У меня они не припаяны.

class Arduiner
{
public:
 virtual void setup()=0;
 virtual void loop()=0; 
};

 class Cl_Btn : public Arduiner
{
 void setup() { Serial.println("Cl_Btn.setup"); }
 void loop() {  Serial.println("Cl_Btn.loop");  }
};

unsigned long mill;//переменая для millis()

 class Cl_delay : public Arduiner
{
 unsigned long int OldMs;
 unsigned long int Per;
 int cnt;
 
protected:
 void setup() 
 { 
   Serial.println("Cl_delay.setup");
   Per=0 ;
   cnt=0;
 }
private: 
 void loop() 
 {
   Serial.println("Cl_delay.loop");
   if(mill-OldMs>Per)
   {
    OldMs=mill;
    Per=Timer(cnt++); 
   }
 }
public:
 virtual unsigned long int Timer(int step)=0;
};


class Cl_music : public Cl_delay
{
 void setup() { 
 Serial.println("Cl_music.setup");
 Cl_delay::setup();
 }
 unsigned long int Timer(int step)
 {
  Serial.println("***Cl_music.tone");  
  return 200; //сколько мсек до следующего вызова этой функции
 }
};

class Cl_blim : public Cl_delay
{
  int t;
 unsigned long int Timer(int step)
 {
  Serial.println("***Cl_blim.tone");
  digitalWrite(13, step&1);  
  return t; 
 }
public:
 Cl_blim(int p){t=p;}; 
};

Cl_Btn Btn;
Cl_music music;
Cl_blim blim(300);

Arduiner* Obj[]={&Btn, &music, &blim};

#define ALL_OBJ(a) for(byte i=0;i<sizeof(Obj)/sizeof(Obj[0]);i++){Obj[i]->a;};

void setup()
{
  Serial.begin(9600);
  ALL_OBJ(setup());
}

void loop()
{
  mill = millis();
  ALL_OBJ(loop());
  delay(50);
 
}

ПС. Такая работа с классами - вобщем все что нужно знать ардуинщику о ООП. Для джуниора умение писать такое - необходимый минимум для допуска к собеседованию по С++.

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

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

/**/
unsigned long mill;//переменая для millis()
//----------------------------------------
//виртуальный класс
class Cl_Virt {
  public:
    virtual void setup() = 0;
    virtual void loop() = 0;
};
//------Cl_delay----------------------------------
// класс пока не понятно для чего
class Cl_delay : public Cl_Virt {
    unsigned long int OldMs;
    unsigned long int Per;
    int cnt;
  protected:
    void setup() {
      Serial.println("Cl_delay.setup");
      Per = 0 ;
      cnt = 0;
    }
  private:
    void loop()   {
      Serial.println("Cl_delay.loop");
      if (mill - OldMs > Per)      {
        OldMs = mill;
        Per = Timer(cnt++);
      }
    }
  public:
    virtual unsigned long int Timer(int step) = 0;
};
//------Cl_Btn----------------------------------
// класс кнопка (пока формально)
class Cl_Btn : public Cl_Virt {
    void setup() {
      Serial.println("Cl_Btn.setup");
    }
    void loop() {
      Serial.println("Cl_Btn.loop");
    }
};
//-----Cl_music---------------------------------
// класс музыка
class Cl_music : public Cl_delay {
    void setup() {
      Serial.println("Cl_music.setup");
      Cl_delay::setup();
    }
    unsigned long int Timer(int step)    {
      Serial.println("***Cl_music.tone");
      return 200; //сколько мсек до следующего вызова этой функции
    }
};
//------Cl_blink--------------------------------------
// класс блинк - мигает светодиод на 13 ноге
class Cl_blink : public Cl_delay {
    int t;
    unsigned long int Timer(int step)    {
      Serial.println("***Cl_blink.tone");
      digitalWrite(13, step & 1);
      return t;
    }
  public:
    Cl_blink(int p) {
      t = p;
    }
};
//---------Компановка----------------------------------------
Cl_Btn Btn;
Cl_music music;
Cl_blink blim(300);
// подключение объектов класса к пакетной обработке
Cl_Virt* Obj[] = {&Btn, &music, &blim};
#define ALL_OBJ(a) for(byte i=0;i<sizeof(Obj)/sizeof(Obj[0]);i++){Obj[i]->a;};
//--------main-------------------------------
void setup() {
  Serial.begin(9600);
  ALL_OBJ(setup());
}
void loop() {
  mill = millis();
  ALL_OBJ(loop());
  delay(50);
}
/*Скетч использует 2360 байт (7%) памяти устройства. Всего доступно 32256 байт.
  Глобальные переменные используют 354 байт (17%) динамической памяти, оставляя 1694 байт для локальных переменных. Максимум: 2048 байт.
*/

 

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

Да на здорове! :) Только в либу не спешите запихивать, весь шарм пропадет.

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

Есть такой модуль на MAX7219.Ну и я написал скетч. Сыроватый, но уже работает. Осталось закинуть знакогенератор на все знаки . Можно русские или латинские. Разумеется те что можно отобразить и использовать в проектах. Вот код

/**/
// ------Cl_print------------------
class Cl_print {
  protected:
  public:
    virtual write(char obj) = 0;
    void print(char *obj) {
      int len = strlen(obj);
      for (int i; i < len; ++i) write(obj[i]);
    }
    void print(int value, unsigned char base = 10) {
      char buf[18];
      itoa(value, buf, base);
      int len = strlen(buf);
      for (int i; i < len; ++i) write(buf[i]);
    }
    void print(unsigned int value, unsigned char base = 10) {
      char buf[17];
      itoa(value, buf, base);
      int len = strlen(buf);
      for (int i; i < len; ++i) write(buf[i]);
    }
    void print(long value, unsigned char base = 10) {
      char buf[34];
      ultoa(value, buf, base);
      int len = strlen(buf);
      for (int i; i < len; ++i) write(buf[i]);
    }
    void print(unsigned long value, unsigned char base = 10) {
      char buf[33];
      ultoa(value, buf, base);
      int len = strlen(buf);
      for (int i; i < len; ++i) write(buf[i]);
    }
    void print(float value, unsigned char decimalPlaces = 2) {
      char buf[33];
      dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
      int len = strlen(buf);
      for (int i; i < len; ++i) write(buf[i]);
    }
    void print(double value, unsigned char decimalPlaces = 2) {
      char buf[33];
      dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
      int len = strlen(buf);
      for (int i; i < len; ++i) write(buf[i]);
    }
};
//------Cl_canvas------------------
// класс полотно
class Cl_canvas: public Cl_print {
  protected:
    char *buff;
    unsigned int len;
    unsigned int pos;
  public:
    Cl_canvas(unsigned int len_ = 10): len(len_) {
      buff = new char[len + 1];
      clear();
    }
    ~Cl_canvas() {
      delete[]  buff;
    }
    //**
    virtual write(char obj) {
      if (obj == 0) return;
      if (pos < len) {
        buff[pos] = obj;
        ++pos;
      }
    }
    char read(unsigned int pos_) {
      if (0 <= pos_ && pos_ < len) return buff[pos_];
      else return ' ';
    }
    unsigned int readLen() {
      return len;
    }
    void setPos(unsigned int pos_) {
      if (0 <= pos_ && pos_ < len) pos = pos_;
      else pos = len;
    }
    void clear() {
      for (byte i = 0; i < len; ++i) buff[i] = ' ';
      buff[len] = 0;
      pos = 0;
    }
    void viev() {
      Serial.println(buff);
    }
};
//-------Cl_Max7219_8x7seg------------------------------------------
// класс Cl_Max7219_8x7seg 8 семисегментных индикаторов на Max7219
#define DECODEMODE_ADDR  9
#define BRIGHTNESS_ADDR  10
#define SCANLIMIT_ADDR   11
#define SHUTDOWN_ADDR    12
#define DISPLAYTEST_ADDR 15
/*функция     toSing
  описание    конвертировать с ANSI2 в знак
  ввод        ansi: код в ANSI2
  вывод       знак
*/
// знакогенератор
const char Font[] PROGMEM = {
  0x00, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, //
  0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, //
  0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, //01234567
  0x7F, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //89abcdef
};
char toSing(byte ansi) {
  if (0x20 <= ansi && ansi <= 0x3F)
    return pgm_read_byte_near(Font + ansi - 0x20);
  return 0x20;
}
class Cl_Max7219_8x7seg {
    const byte dinPin;
    const byte csPin;
    const byte clkPin;
  public:
    Cl_canvas canvas;
    /*функция     Cl_Max7219_8x7seg
      описание    создать объект
      ввод        _dinPin:пин данных
                  _dinPin:пин CS
                  _dinPin:пин CLK
      вывод       нет
    */
    Cl_Max7219_8x7seg(byte _dinPin, byte _csPin, byte _clkPin)
      : dinPin(_dinPin), csPin (_csPin), clkPin (_clkPin), canvas(8) {
      pinMode(dinPin, OUTPUT);
      pinMode(csPin, OUTPUT);
      pinMode(clkPin, OUTPUT);
      digitalWrite(csPin, HIGH);
    }
    /*функция     setup
      описание    инициализация экрана
      ввод        нет
      вывод       нет
    */
    void setup() {
      setBright(10);
      transfer(DISPLAYTEST_ADDR, 0);
      transfer(SCANLIMIT_ADDR, 7);
      transfer(DECODEMODE_ADDR, 0);
      //clear();
      show();
    }
    /*функция     setBright
      описание    установить яркость экрана
      ввод        bright:яркость 0-15
      вывод       нет
    */
    void setBright(byte bright) {
      transfer(BRIGHTNESS_ADDR, bright & 0x0F);
    }
    /*функция     show
      описание    вывести буфер на экран
      ввод        нет
      вывод       нет
    */
    void show() {
      off();
      for (byte i = 0; i < 8; ++i) {
        char aaa = canvas.read(i);
        transfer(8 - i, toSing(aaa));
      }
      on();
    }
    /*функция     transfer
      описание    отправить команду
      ввод        com: команда
                  data: данные
      вывод       нет
    */
    void transfer(byte com, byte data) {
      digitalWrite(csPin, LOW);
      for (byte i = 0; i < 8; ++i)  {
        digitalWrite(dinPin, !!(com & (0x80 >> i)));
        digitalWrite(clkPin, HIGH);
        digitalWrite(clkPin, LOW);
      }
      for (byte i = 0; i < 8; ++i)  {
        digitalWrite(dinPin, !!(data & (0x80 >> i)));
        digitalWrite(clkPin, HIGH);
        digitalWrite(clkPin, LOW);
      }
      digitalWrite(csPin, HIGH);
    }
    /*функция     on
      описание    включить дисплей
      ввод        нет
      вывод       нет
    */
    void on() {
      transfer(SHUTDOWN_ADDR, 0x01);
    }
    /*функция     off
      описание    выключить дисплей
      ввод        нет
      вывод       нет
    */
    void off() {
      transfer(SHUTDOWN_ADDR, 0x00);
    }
};
//------------------------
Cl_Max7219_8x7seg ld(/*DIN*/2,/*CS*/ 3,/*CLK*/4);
//------------------------
int main() {
  init();
  //setup()
  Serial.begin(9600);
  ld.setup();
  ld.canvas.setPos(2);// курсор в позицию 2
  ld.canvas.print(33.8);// напечатать число 33.8
  ld.canvas.viev();//отправить вид в Serial
  ld.show();//отправить вид на дисплей
  for (;;) {
    //loop()
  }
  return 0;
}
/*Скетч использует 4646 байт (14%) памяти устройства. Всего доступно 32256 байт.
  Глобальные переменные используют 213 байт (10%) динамической памяти, оставляя 1835 байт для локальных переменных. Максимум: 2048 байт.
*/

 

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

Вот еще один своеобразный скетч. Отправка пакета-команды от управляющего компонента к исполнительному через систему стека внутри МК

/**/
unsigned long mill;
//------st_Package---------------------------
// пакет команды
enum enCommand { LedON = 1, LedOFF, LedBlink};
typedef struct st_Package {
  enCommand command;
  unsigned long data;
} Pack ;
Pack PackageLedON() { // создать пакет-команду вкл светодиод
  Pack ret = {LedON, 0};
  return ret;
}
Pack PackageLedOFF() { // создать пакет-команду выкл светодиод
  Pack ret = {LedOFF, 0};
  return ret;
}
Pack PackageLedBlink(unsigned long data) { // создать пакет команду мигать светодиодом
  Pack ret = {LedBlink, data};
  return ret;
};
//------Cl_Stack----------------
//класс стек (вместо радио-эфира)
template <class T>struct st_Sheath {
  struct st_Sheath *next;
  T data;
};
template <class T>class Cl_Stack {
  protected:
    struct st_Sheath<T>  *start;
  public:
    Cl_Stack(): start(NULL) {}
    bool push(T & data) { // отправить в "эфир" пакет-команду
      struct st_Sheath<T>  *newData = new struct st_Sheath<T>;
      if (newData == NULL) return 0;
      newData->data = data;
      newData->next = start;
      start = newData;
      return 1;
    }
    bool pop(T & data) { // получить из "эфира" пакет-команду
      if (start == NULL) return 0;
      struct st_Sheath<T> *newData = start;
      start = start->next;
      data = newData->data;
      delete newData;
      return 1;
    }
};
//-------Cl_decoder--------------------------
// класс декодер // переводит пакет-команду в нужные действия
class Cl_decoder {
  protected:
    Cl_Stack<Pack> *Stack;
    void (*Do1)(), (*Do2)();
    void (*Do3)(unsigned long);
  public:
    Cl_decoder(Cl_Stack<Pack> *Stack_, void (*Do1_)(), void (*Do2_)(), void (*Do3_)(unsigned long))
      : Stack(Stack_), Do1(Do1_), Do2 (Do2_), Do3(Do3_) {}
    void setup() {}
    void loop() {
      Pack Package;
      if (!Stack->pop(Package)) return;
      if (Package.command == 1)(*Do1)();
      if (Package.command == 2)(*Do2)();
      if (Package.command == 3)(*Do3)(Package.data);
      Serial.println();
      Serial.print(Package.command);
      Serial.print("  ");
      Serial.print(Package.data);
    }
};
//------Cl_Led----------------------
// класс светодиод
class Cl_Led {
  protected:
    const byte pin;
    bool led;
    bool statBlink;
    unsigned long past, time;
  public:
    Cl_Led(byte pin_): pin(pin_) {}
    void setup() {
      pinMode(pin, OUTPUT);
      OFF();
    }
    void loop() {
      if (statBlink && mill - past >= time) {
        past = mill;
        digitalWrite(pin, led = !led);
      }
    }
    void ON() {
      digitalWrite(pin, led = HIGH);
      statBlink = 0;
    }
    void OFF() {
      digitalWrite(pin, led = LOW);
      statBlink = 0;
    }
    void blink(unsigned long time_ = 200) {
      statBlink = 1;
      time = time_;
      past = mill;
      digitalWrite(pin, led = !led);
    }
};
//------Cl_Btn----------------------
// класс кнопка
class Cl_Btn {
  protected:
    const byte pin;
    void (*Do)();
    bool bounce = 0;
    bool btn = 1, oldBtn;
    unsigned long past;
  public:
    Cl_Btn(byte pin_, void (*Do_)()): pin(pin_), Do(Do_) {}
    void setup() {
      pinMode(pin, INPUT_PULLUP);
    }
    void loop() {
      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) (*Do)();
      }
    }
};
//-------Компоновка---------------
Pack PackageIn = {LedON, 100}, PackageOut;
Cl_Stack<Pack> Stack;
Cl_Led Led(/*пин*/13);
void DoDecoder1();
void DoDecoder2();
void DoDecoder3(unsigned long);
Cl_decoder Decoder(/*стек приема*/&Stack,/*обраб1*/DoDecoder1,/*обраб2*/DoDecoder2,/*обраб3*/DoDecoder3);
void DoDecoder1() { // действия по 1-й пакет-команде
  Led.ON();
}
void DoDecoder2() { // действия по 2-й пакет-команде
  Led.OFF();
}
void DoDecoder3(unsigned long time) { // действия по 3-й пакет-команде
  Led.blink(time);
}
void DoBtn1() {
  Pack Package = PackageLedON(); // создать по 1-ю пакет-команду
  Stack.push(Package);     // отправить в "эфир"
}
void DoBtn2() {
  Pack Package = PackageLedOFF(); // создать по 2-ю пакет-команду
  Stack.push(Package);      // отправить в "эфир"
}
void DoBtn3() {
  Pack Package = PackageLedBlink(/*частота мигания*/100); // создать по 3-ю пакет-команду
  Stack.push(Package);      // отправить в "эфир"
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/DoBtn1);
Cl_Btn Btn2(/*пин*/3,/*обработчик*/DoBtn2);
Cl_Btn Btn3(/*пин*/4,/*обработчик*/DoBtn3);
//-------main()---------------
int main() {
  init();
  //setup()
  Serial.begin(9600);
  Decoder.setup();
  Led.setup();
  Btn1.setup();
  Btn2.setup();
  Btn3.setup();
  for (;;) {
    //loop()
    mill = millis();
    Decoder.loop();
    Led.loop();
    Btn1.loop();
    Btn2.loop();
    Btn3.loop();
  }
  return 0;
}
/*Скетч использует 3722 байт (11%) памяти устройства. Всего доступно 32256 байт.
  Глобальные переменные используют 253 байт (12%) динамической памяти, оставляя 1795 байт для локальных переменных. Максимум: 2048 байт.
*/

 

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

Вот еще один скетч. Попытался найти замену pinMode, digitalRead,digitalWrite   внутри класса на почти тоже самое, но чуть тоньше.

//**/
unsigned long mill;
typedef void (*handler)() ;
//------Cl_Led----------------------
// класс светодиод
class Cl_Led {
  protected:
    uint8_t bit ;
    uint8_t port;
    bool led;
    bool statBlink;
    unsigned long past, time;
    inline void init() {
      uint8_t SREG_ = SREG;
      cli();
      *portModeRegister(port) |= bit;
      SREG = SREG_;
    }
    void write(bool stat) {
      uint8_t SREG_ = SREG;
      cli();
      if (stat)*portOutputRegister(port) |= bit;// out =1
      else *portOutputRegister(port) &= ~bit; // out =0
      SREG = SREG_;
    }
  public:
    Cl_Led(byte pin) {
      bit = digitalPinToBitMask(pin);
      port = digitalPinToPort(pin);
    }
    void setup() {
      init();
      OFF();
    }
    void loop() {
      if (statBlink && mill - past >= time) {
        past = mill;
        write(led = !led);
      }
    }
    void ON() {
      write(led = 1);
      statBlink = 0;
    }
    void OFF() {
      write(led = 0);
      statBlink = 0;
    }
    void blink(unsigned long time_ = 200) {
      statBlink = 1;
      time = time_;
      past = mill;
      write(led = !led);
    }
};
//------Cl_Btn----------------------
// класс кнопка
class Cl_Btn {
  protected:
    uint8_t bit ;
    uint8_t port;
    handler Do;
    bool bounce = 0;
    bool btn = 1, oldBtn;
    unsigned long past;
    void init() {
      uint8_t SREG_ = SREG;
      cli();
      *portModeRegister(port) &= ~bit;
      *portOutputRegister(port) |= bit; //INPUT_PULLUP
      SREG = SREG_;
    }
    bool read() {
      return !!(*portInputRegister(port) & bit);
    }
  public:
    Cl_Btn(byte pin, handler Do_):  Do(Do_) {
      bit = digitalPinToBitMask(pin);
      port = digitalPinToPort(pin);
    }
    void setup() {
      init();
    }
    void loop() {
      bool newBtn = read();
      if (!bounce && newBtn != btn) {
        bounce = 1;
        past = mill;
      }
      if (bounce && mill - past >= 10) {
        bounce = 0 ;
        oldBtn = btn;
        btn = newBtn;
        if (!btn && oldBtn) Do();
      }
    }
};
//-----компоновка----------------------
Cl_Led Led(/*пин*/13);
void DoBtn1() {
  Led.ON();
  Serial.println("DoBtn1");
}
void DoBtn2() {
  Led.OFF();
  Serial.println("DoBtn2");
}
void DoBtn3() {
  Led.blink();
  Serial.println("DoBtn3");
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/DoBtn1);
Cl_Btn Btn2(/*пин*/3,/*обработчик*/DoBtn2);
Cl_Btn Btn3(/*пин*/4,/*обработчик*/DoBtn3);
//-----main-----------------------
int main() {
  init();
  // setup()
  Serial.begin(9600);
  Led.setup();
  Btn1.setup();
  Btn2.setup();
  Btn3.setup();
  for (;;) {
    // loop()
    mill = millis();
    Led.loop();
    Btn1.loop();
    Btn2.loop();
    Btn3.loop();
  }
  return 0;
}
/*Скетч использует 2366 байт (7%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 255 байт (12%) динамической памяти, оставляя 1793 байт для локальных переменных. Максимум: 2048 байт.
*/

 

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

Еще пара вариантов замены pinMode, digitalRead,digitalWrite .

/**/
//-------Cl_outPin-------------------------
// класс вывод ноги
class Cl_outPin {
  protected:
    uint8_t bit ;
    uint8_t port;
    void init() {
      uint8_t SREG_ = SREG;
      cli();
      *(volatile uint8_t *)(pgm_read_word(port_to_mode_PGM + port)) |= bit;
      SREG = SREG_;
    }
    void write(bool stat) {
      uint8_t SREG_ = SREG;
      cli();
      if (stat) *(volatile uint8_t *)(pgm_read_word( port_to_output_PGM + port)) |=  bit; // out =1
      else      *(volatile uint8_t *)(pgm_read_word( port_to_output_PGM + port)) &= ~bit; // out =0
      SREG = SREG_;
    }
  public:
    Cl_outPin(byte pin) {
      bit  = pgm_read_byte(digital_pin_to_bit_mask_PGM + pin);
      port = pgm_read_byte(digital_pin_to_port_PGM     + pin);
    }
    void setup() {
      init();
    }
    void ON() {
      write(1);
    }
    void OFF() {
      write(0);
    }
};
//---Компоновка-----------------------------
Cl_outPin outPin(/*пин*/13);
//---main-----------------------------
int main() {
  init();
  //setup()
  outPin.setup();
  for (;;) {
    //loop()
    outPin.ON();
    delay(300);
    outPin.OFF();
    delay(300);
  }
  return 0;
}
/*Скетч использует 850 байт (2%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 11 байт (0%) динамической памяти, оставляя 2037 байт для локальных переменных. Максимум: 2048 байт.
*/
/**/
//-------Cl_inPin-------------------------
// класс вывод ноги
class Cl_inPin {
  protected:
    uint8_t bit ;
    uint8_t port;
    void init() {
      uint8_t SREG_ = SREG;
      cli();
      *(volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + port)) &= ~bit;
      *(volatile uint8_t *)( pgm_read_word( port_to_output_PGM + port)) &= ~bit;  //INPUT
      //*(volatile uint8_t *)( pgm_read_word( port_to_output_PGM + port)) |= bit; //INPUT_PULLUP
      SREG = SREG_;
    }
  public:
    Cl_inPin(byte pin) {
      bit  = pgm_read_byte( digital_pin_to_bit_mask_PGM + pin );
      port = pgm_read_byte( digital_pin_to_port_PGM + pin ) ;
    }
    void setup() {
      init();
    }
    bool read() {
      return !!(*(volatile uint8_t *)( pgm_read_word( port_to_input_PGM + port)) & bit);
    }
};
//---Компоновка-----------------------------
Cl_inPin inPin(/*пин*/2);
//---main-----------------------------
int main() {
  init();
  //setup()
  Serial.begin(9600);
  inPin.setup();
  for (;;) {
    //loop()
    delay(300);
    Serial.println(inPin.read());
  }
  return 0;
}
/*Скетч использует 1956 байт (6%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 188 байт (9%) динамической памяти, оставляя 1860 байт для локальных переменных. Максимум: 2048 байт.
*/

 

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

Есть такая таблица под UNO и Nano

/*
  Таблица
    пин   порт  бит    порт на ввод      порт  на вывод    вывод1           вывод0            ввода значения
    0      PD ; 1<<0 ; DDRD &= ~(1<<0) ; DDRD |= (1<<0) ; PORTD |=(1<<0) ; PORTD &= ~(1<<0) ; !!(PIND& (1<<0))
    1      PD ; 1<<1 ; DDRD &= ~(1<<1) ; DDRD |= (1<<1) ; PORTD |=(1<<1) ; PORTD &= ~(1<<1) ; !!(PIND& (1<<1))
    2      PD ; 1<<2 ; DDRD &= ~(1<<2) ; DDRD |= (1<<2) ; PORTD |=(1<<2) ; PORTD &= ~(1<<2) ; !!(PIND& (1<<2))
    3      PD ; 1<<3 ; DDRD &= ~(1<<3) ; DDRD |= (1<<3) ; PORTD |=(1<<3) ; PORTD &= ~(1<<3) ; !!(PIND& (1<<3))
    4      PD ; 1<<4 ; DDRD &= ~(1<<4) ; DDRD |= (1<<4) ; PORTD |=(1<<4) ; PORTD &= ~(1<<4) ; !!(PIND& (1<<4))
    5      PD ; 1<<5 ; DDRD &= ~(1<<5) ; DDRD |= (1<<5) ; PORTD |=(1<<5) ; PORTD &= ~(1<<5) ; !!(PIND& (1<<5))
    6      PD ; 1<<6 ; DDRD &= ~(1<<6) ; DDRD |= (1<<6) ; PORTD |=(1<<6) ; PORTD &= ~(1<<6) ; !!(PIND& (1<<6))
    7      PD ; 1<<7 ; DDRD &= ~(1<<7) ; DDRD |= (1<<7) ; PORTD |=(1<<7) ; PORTD &= ~(1<<7) ; !!(PIND& (1<<7))
    8      PB ; 1<<0 ; DDRB &= ~(1<<0) ; DDRB |= (1<<0) ; PORTB |=(1<<0) ; PORTB &= ~(1<<0) ; !!(PINB& (1<<0))
    9      PB ; 1<<1 ; DDRB &= ~(1<<1) ; DDRB |= (1<<1) ; PORTB |=(1<<1) ; PORTB &= ~(1<<1) ; !!(PINB& (1<<1))
    10     PB ; 1<<2 ; DDRB &= ~(1<<2) ; DDRB |= (1<<2) ; PORTB |=(1<<2) ; PORTB &= ~(1<<2) ; !!(PINB& (1<<2))
    11     PB ; 1<<3 ; DDRB &= ~(1<<3) ; DDRB |= (1<<3) ; PORTB |=(1<<3) ; PORTB &= ~(1<<3) ; !!(PINB& (1<<3))
    12     PB ; 1<<4 ; DDRB &= ~(1<<4) ; DDRB |= (1<<4) ; PORTB |=(1<<4) ; PORTB &= ~(1<<4) ; !!(PINB& (1<<4))
    13     PB ; 1<<5 ; DDRB &= ~(1<<5) ; DDRB |= (1<<5) ; PORTB |=(1<<5) ; PORTB &= ~(1<<5) ; !!(PINB& (1<<5))
    (14)A0 PC ; 1<<0 ; DDRC &= ~(1<<0) ; DDRC |= (1<<0) ; PORTC |=(1<<0) ; PORTC &= ~(1<<0) ; !!(PINC& (1<<0))
    (15)A1 PC ; 1<<1 ; DDRC &= ~(1<<1) ; DDRC |= (1<<1) ; PORTC |=(1<<1) ; PORTC &= ~(1<<1) ; !!(PINC& (1<<1))
    (16)A2 PC ; 1<<2 ; DDRC &= ~(1<<2) ; DDRC |= (1<<2) ; PORTC |=(1<<2) ; PORTC &= ~(1<<2) ; !!(PINC& (1<<2))
    (17)A3 PC ; 1<<3 ; DDRC &= ~(1<<3) ; DDRC |= (1<<3) ; PORTC |=(1<<3) ; PORTC &= ~(1<<3) ; !!(PINC& (1<<3))
    (18)A4 PC ; 1<<4 ; DDRC &= ~(1<<4) ; DDRC |= (1<<4) ; PORTC |=(1<<4) ; PORTC &= ~(1<<4) ; !!(PINC& (1<<4))
    (19)A5 PC ; 1<<5 ; DDRC &= ~(1<<5) ; DDRC |= (1<<5) ; PORTC |=(1<<5) ; PORTC &= ~(1<<5) ; !!(PINC& (1<<5))
    (20)A6 PC ; 1<<6 ; DDRC &= ~(1<<6) ; DDRC |= (1<<6) ; PORTC |=(1<<6) ; PORTC &= ~(1<<6) ; !!(PINC& (1<<6))
    (21)A7 PC ; 1<<7 ; DDRC &= ~(1<<7) ; DDRC |= (1<<7) ; PORTC |=(1<<7) ; PORTC &= ~(1<<7) ; !!(PINC& (1<<7))
*/

Ну и на основе ее скетч Blink

/*blink*/
void setup() {
  DDRB |= (1 << 5) ;
}
void loop() {
  PORTB |= (1 << 5) ;
  delay(1000);
  PORTB &= ~(1 << 5) ;
  delay(1000);
}

 

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

А классы где? Нещитова!

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

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

А классы где? Нещитова!

 А дальше я постараюсь показать написание классов без классов.

/**/
//----------------------------------
namespace Led {
const byte pin = 13;
bool led;
unsigned long past = 0;
void init() {
  pinMode(pin, OUTPUT);
  digitalWrite(pin, led = 0);
}
void loop() {
  if (millis() - past >= 500) {
    past = millis();
    digitalWrite(pin, led = !led);
  }
}
}//namespace Led
//----Компоновка------------------------------
//----main------------------------------
void setup() {
  Led::init();
}
void loop() {
  Led::loop();
}
/*Скетч использует 842 байт (2%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 14 байт (0%) динамической памяти, оставляя 2034 байт для локальных переменных. Максимум: 2048 байт.
*/

 

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

qwone пишет:
А дальше я постараюсь показать написание классов без классов.

Даааа, а ведь всё начиналось поди с безобидного безалкогольного пива :)

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

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

/*namespace_Led*/
unsigned long mill;
//----------------------------------
// светодиод на пине 13 (PORTB D5)
namespace Led {
void init();
void loop();
void ON();
void OFF();
void blink(unsigned int time_);
void write(bool stat);

bool led, statBlink = 0;
unsigned long time, past = 0;

void init() {
  uint8_t SREG_ = SREG;
  cli();
  DDRB |= (1 << 5) ; //<--при измении выводa поставить нужное
  SREG = SREG_;
  OFF();
}
void loop() {
  if (statBlink && mill - past >= time) {
    past = mill;
    write(led = !led);
  }
}
void ON() {
  write(led = 1);
  statBlink = 0;
}
void OFF() {
  write(led = 0);
  statBlink = 0;
}
void blink(unsigned int time_=500) {
  time = time_;
  statBlink = 1;
}
void write(bool stat) {
  uint8_t SREG_ = SREG;
  cli();
  if (stat) PORTB |= 1 << 5; //<-- при измении выводa поставить нужное
  else      PORTB &= ~(1 << 5);//<--при измении выводa поставить нужное
  SREG = SREG_;
}
}//namespace Led
//----Компоновка------------------------------
//----main------------------------------
int main() {
  init();
  Led::init();
  Led::blink(500);
  for (;;) {
    mill = millis();
    Led::loop();
  }
  return 0;
}
/*Скетч использует 626 байт (2%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 23 байт (1%) динамической памяти, оставляя 2025 байт для локальных переменных. Максимум: 2048 байт.
*/

Это код для кнопки

/*namespace_Btn*/
unsigned long mill;
typedef void (*handler)() ;
//----------------------------------
// кнопка на пине 2 (PORTD D2) программная подтяжка
namespace Btn {
void init();
void loop();
bool read();

handler Do;
bool bounce = 0, btn = 1, oldBtn;
unsigned long past;

void init() {
  uint8_t SREG_ = SREG;
  cli();
  // порт на ввод
  DDRD &= ~(1 << 2) ; //<--при измении выводa поставить нужное
  // программная подтяжка
  PORTD |= (1 << 2) ; //<--при измении выводa поставить нужное
  SREG = SREG_;
  btn = read();
}
void loop() {
  bool newBtn = read();
  if (!bounce && newBtn != btn) {
    bounce = 1;
    past = mill;
  }
  if (bounce && mill - past >= 10) {
    bounce = 0 ;
    oldBtn = btn;
    btn = newBtn;
    if (!btn && oldBtn) Do();
  }
}
bool read() {
  return !!(PIND & (1 << 2)); //<--при измении выводa поставить нужное
}
}//namespace Btn
//----Компоновка------------------------------
void DoBtn() {
  Serial.println("DoBtn");
}
//----main------------------------------
int main() {
  init();
  // setup()
  Serial.begin(9600);
  Btn::init();
  Btn::Do = DoBtn;
  for (;;) {
    // loop()
    mill = millis();
    Btn::loop();
  }
  return 0;
}
/*Скетч использует 1602 байт (5%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 204 байт (9%) динамической памяти, оставляя 1844 байт для локальных переменных. Максимум: 2048 байт.
*/

А это взаимодействие 1светодиода и 3-х кнопок

/*namespace_Led_3Btn*/
unsigned long mill;
typedef void (*handler)() ;
//----------------------------------
// светодиод на пине 13 (PORTB D5)
namespace Led {
void init();
void loop();
void ON();
void OFF();
void blink(unsigned int time_ = 500);
void write(bool stat);

bool led, statBlink = 0;
unsigned long time, past = 0;

void init() {
  uint8_t SREG_ = SREG;
  cli();
  DDRB |= (1 << 5) ; //<--при измении выводa поставить нужное
  SREG = SREG_;
  OFF();
}
void loop() {
  if (statBlink && mill - past >= time) {
    past = mill;
    write(led = !led);
  }
}
void ON() {
  write(led = 1);
  statBlink = 0;
}
void OFF() {
  write(led = 0);
  statBlink = 0;
}
void blink(unsigned int time_) {
  time = time_;
  statBlink = 1;
}
void write(bool stat) {
  uint8_t SREG_ = SREG;
  cli();
  if (stat) PORTB |= 1 << 5; //<-- при измении выводa поставить нужное
  else      PORTB &= ~(1 << 5);//<--при измении выводa поставить нужное
  SREG = SREG_;
}
}//namespace Led
//----------------------------------
// кнопка на пине 2 (PORTD D2) программная подтяжка
namespace Btn1 {
void init();
void loop();
bool read();

handler Do;
bool bounce = 0, btn = 1, oldBtn;
unsigned long past;

void init() {
  uint8_t SREG_ = SREG;
  cli();
  // порт на ввод
  DDRD &= ~(1 << 2) ; //<--при измении выводa поставить нужное
  // программная подтяжка
  PORTD |= (1 << 2) ; //<--при измении выводa поставить нужное
  SREG = SREG_;
  btn = read();
}
void loop() {
  bool newBtn = read();
  if (!bounce && newBtn != btn) {
    bounce = 1;
    past = mill;
  }
  if (bounce && mill - past >= 10) {
    bounce = 0 ;
    oldBtn = btn;
    btn = newBtn;
    if (!btn && oldBtn) Do();
  }
}
bool read() {
  return !!(PIND & (1 << 2)); //<--при измении выводa поставить нужное
}
}//namespace Btn1
//----------------------------------
// кнопка на пине 3 (PORTD D3) программная подтяжка
namespace Btn2 {
void init();
void loop();
bool read();

handler Do;
bool bounce = 0, btn = 1, oldBtn;
unsigned long past;

void init() {
  uint8_t SREG_ = SREG;
  cli();
  // порт на ввод
  DDRD &= ~(1 << 3) ; //<--при измении выводa поставить нужное
  // программная подтяжка
  PORTD |= (1 << 3) ; //<--при измении выводa поставить нужное
  SREG = SREG_;
  btn = read();
}
void loop() {
  bool newBtn = read();
  if (!bounce && newBtn != btn) {
    bounce = 1;
    past = mill;
  }
  if (bounce && mill - past >= 10) {
    bounce = 0 ;
    oldBtn = btn;
    btn = newBtn;
    if (!btn && oldBtn) Do();
  }
}
bool read() {
  return !!(PIND & (1 << 3)); //<--при измении выводa поставить нужное
}
}//namespace Btn2
//----------------------------------
// кнопка на пине 4 (PORTD D4) программная подтяжка
namespace Btn3 {
void init();
void loop();
bool read();

handler Do;
bool bounce = 0, btn = 1, oldBtn;
unsigned long past;

void init() {
  uint8_t SREG_ = SREG;
  cli();
  // порт на ввод
  DDRD &= ~(1 << 4) ; //<--при измении выводa поставить нужное
  // программная подтяжка
  PORTD |= (1 << 4) ; //<--при измении выводa поставить нужное
  SREG = SREG_;
  btn = read();
}
void loop() {
  bool newBtn = read();
  if (!bounce && newBtn != btn) {
    bounce = 1;
    past = mill;
  }
  if (bounce && mill - past >= 10) {
    bounce = 0 ;
    oldBtn = btn;
    btn = newBtn;
    if (!btn && oldBtn) Do();
  }
}
bool read() {
  return !!(PIND & (1 << 4)); //<--при измении выводa поставить нужное
}
}//namespace Btn3
//----Компоновка------------------------------
void DoBtn1() {
  Serial.println("DoBtn1");
  Led::ON();
}
void DoBtn2() {
  Serial.println("DoBtn2");
  Led::OFF();
}
void DoBtn3() {
  Serial.println("DoBtn3");
  Led::blink(200);
}
//----main------------------------------
int main() {
  init();
  // setup()
  Led::init();
  Serial.begin(9600);
  Btn1::init();
  Btn1::Do = DoBtn1;
  Btn2::init();
  Btn2::Do = DoBtn2;
  Btn3::init();
  Btn3::Do = DoBtn3;
  for (;;) {
    // loop()
    mill = millis();
    Led::loop();
    Btn1::loop();
    Btn2::loop();
    Btn3::loop();
  }
  return 0;
}
/*Скетч использует 2262 байт (7%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 248 байт (12%) динамической памяти, оставляя 1800 байт для локальных переменных. Максимум: 2048 байт.
*/

ПС: Разумеется можно немного сохранить размеры убрав отключение и включение прерываний, если у вас они не используются

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

Давно не писал в своей теме. Сейчас сделаю новый наброс. Все конечно знают blink через delay(), и разумеется blink через millis() не все. Есть еще другие варианты blink-ов. Вот я вам предлагаю ознакомится c BLINK через Менеджер задач на Ардуине. Неплохая фишка, но код не все поймут. И да он работает, проверял.

unsigned long mill; // переменная под millis()
//-----Cl_Manager---------------------------
// класс менеджер задач
struct task_t {
  void (*Do)();
  unsigned long past;
  unsigned long time;
  struct task_t *next;
};
class Cl_Manager {
  protected:
    struct task_t (*start) = NULL;
  public:
    void run() {
      for (struct task_t (**iii) = &start; (*iii) != NULL; ) {
        if (mill - (**iii).past >= (**iii).time) {
          struct task_t (*_new) = (*iii);
          (*iii) = (**iii).next;
          (*_new).Do();
          delete _new;
        }
        else iii = &((**iii).next);
      }
    }
    void Task(void (*Do)(), unsigned long time) {
      struct task_t (*_new) = new struct task_t;
      (*_new).Do = Do;
      (*_new).past = mill;
      (*_new).time = time;
      (*_new).next = start;
      start = _new;
    }
};
Cl_Manager Manager;
//---Компоновка-----------------------
const byte ledPin =/*пин светодиода*/13;
bool led = 0;
unsigned long time_1s = 1000;
void blinkInit() {
  pinMode(ledPin, OUTPUT);
  blinkRun();
}
void blinkRun() {
  Manager.Task(&blinkRun, time_1s);
  digitalWrite(ledPin, led = !led);
}

//---main-----------------------------
void setup() {
  blinkInit();

}

void loop() {
  mill = millis();
  Manager.run();
}
/*Скетч использует 1588 байт (5%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 26 байт (1%) динамической памяти, оставляя 2022 байт для локальных переменных. Максимум: 2048 байт.
*/

ПС:Через Менеджер можно запустить несколько независимых задач.

unsigned long mill; // переменная под millis()
//-----Cl_Manager---------------------------
// класс менеджер задач
struct task_t {
  void (*Do)();
  unsigned long past;
  unsigned int time;
  struct task_t *next;
};
class Cl_Manager {
  protected:
    struct task_t (*start) = NULL;
  public:
    void run() {
      for (struct task_t (**iii) = &start; (*iii) != NULL; ) {
        if (mill - (**iii).past >= (**iii).time) {
          struct task_t (*_new) = (*iii);
          (*iii) = (**iii).next;
          (*_new).Do();
          delete _new;
        }
        else iii = &((**iii).next);
      }
    }
    void Task(unsigned int time, void (*Do)()) {
      struct task_t (*_new) = new struct task_t;
      (*_new).Do = Do;
      (*_new).past = mill;
      (*_new).time = time;
      (*_new).next = start;
      start = _new;
    }
};
Cl_Manager Manager;
//---Компоновка-----------------------
//--led
const byte ledPin =/*пин светодиода*/13;
bool led = 0;
void blinkInit() {
  pinMode(ledPin, OUTPUT);
  blinkRun();
}
void blinkRun() {
  Manager.Task(/*через 0.3 сек*/ 300,/*сделать это*/&blinkRun);
  digitalWrite(ledPin, led = !led);
}
// --serial
void serialRun() {
  Manager.Task(/*через 0.5 сек*/ 500,/*сделать это*/&serialRun);
  Serial.println("!!!");
}

//---main-----------------------------
void setup() {
  Serial.begin(9600);
  blinkInit();
  serialRun();
}

void loop() {
  mill = millis();
  Manager.run();
}
/*Скетч использует 2610 байт (8%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 207 байт (10%) динамической памяти, оставляя 1841 байт для локальных переменных. Максимум: 2048 байт.
*/

 

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017
61   mill = millis();
62   Manager.run();

у тебя менеджер не берёт системное время самостоятельно и приходится в лупе его постоянно кормить свежим временем - это так задумано или почему?

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

Конечно так задумано. Но вы можете делать как угодно. Вот еще вариант программы с менеджером. В принципе на нем можно писать своеобразные программы. Вот 5 функций в цикле.

unsigned long mill; // переменная под millis()
//-----Cl_Manager---------------------------
// класс менеджер задач
struct task_t {
  void (*Do)();
  unsigned long past;
  unsigned int time;
  struct task_t *next;
};
class Cl_Manager {
  protected:
    struct task_t (*start) = NULL;
  public:
    void run() {
      for (struct task_t (**iii) = &start; (*iii) != NULL; ) {
        if (mill - (**iii).past >= (**iii).time) {
          struct task_t (*_new) = (*iii);
          (*iii) = (**iii).next;
          (*_new).Do();
          delete _new;
        }
        else iii = &((**iii).next);
      }
    }
    void Task(unsigned int time, void (*Do)()) {
      struct task_t (*_new) = new struct task_t;
      (*_new).Do = Do;
      (*_new).past = mill;
      (*_new).time = time;
      (*_new).next = start;
      start = _new;
    }
};
Cl_Manager Manager;
//---Компоновка-----------------------
// --serial
void serial_1() {
  Manager.Task(/*через 0.5 сек*/ 500,/*сделать это*/&serial_2);
  Serial.println("1-one");
}
void serial_2() {
  Manager.Task(/*через 0.5 сек*/ 500,/*сделать это*/&serial_3);
  Serial.println("2-two");
}
void serial_3() {
  Manager.Task(/*через 0.5 сек*/ 500,/*сделать это*/&serial_4);
  Serial.println("3-three");
}
void serial_4() {
  Manager.Task(/*через 0.5 сек*/ 500,/*сделать это*/&serial_5);
  Serial.println("4-four");
}
void serial_5() {
  Manager.Task(/*через 0.5 сек*/ 500,/*сделать это*/&serial_1);
  Serial.println("5-five");
}
//---main-----------------------------
void setup() {
  Serial.begin(9600);
  serial_1();
}

void loop() {
  mill = millis();
  Manager.run();
}
/*Скетч использует 2400 байт (7%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 236 байт (11%) динамической памяти, оставляя 1812 байт для локальных переменных. Максимум: 2048 байт.
*/

 

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

.del

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

del

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Квон застрял в пещерном веке, где баб и врагов нужно бить дубиной по голове. 

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

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

Для тех кому мешает "программировать в Адруине digtalWrite"/

Это обычный blink

/**/
const byte blinkPin =/**/13;
void setup() {
  pinMode(blinkPin, OUTPUT);

}
void loop() {
  digitalWrite(blinkPin, 1);
  delay(1000);
  digitalWrite(blinkPin, 0);
  delay(1000);
}
/*Скетч использует 928 байт (3%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт.
*/

1 модификация

/*blink*/
void setup() {
  DDRB |= (1 << 5) ;
}
void loop() {
  PORTB |= (1 << 5) ;
  delay(1000);
  PORTB &= ~(1 << 5) ;
  delay(1000);
}
/*Скетч использует 644 байт (2%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт.
*/

2 модификация

/*blink*/
//----------------------------
struct pin_t {
  volatile uint8_t *reg;
  volatile uint8_t *adr;
  byte bit;/*поз бита*/
};
//----------------------------
struct pin_t blinkPin={
  &DDRB, &PORTB, 5 // пин 13
};
//----------------------------
void setup() {
  *(blinkPin.reg) |= (1 << blinkPin.bit) ;
}
void loop() {
  *(blinkPin.adr) |= (1 << blinkPin.bit) ;
  delay(1000);
  *(blinkPin.adr) &= ~(1 << blinkPin.bit) ;
  delay(1000);
}
/*Скетч использует 644 байт (2%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт.
*/

3 модификация

/*blink*/
//----------------------------
#define pinRead(pin, bit) ((*(pin) >> (bit)) & 0x01)
#define pinSet(pin, bit) (*(pin) |= (1UL << (bit)))
#define pinClear(pin, bit) (*(pin) &= ~(1UL << (bit)))


struct pin_t {
  volatile uint8_t *reg;
  volatile uint8_t *adr;
  byte bit;/*поз бита*/
};
//----------------------------
struct pin_t blinkPin = {
  &DDRB, &PORTB, 5 // пин 13
};
//----------------------------
void setup() {
  pinSet(blinkPin.reg, blinkPin.bit); //*(blinkPin.reg) |= (1 << blinkPin.bit) ;
}
void loop() {
  pinSet(blinkPin.adr, blinkPin.bit); //*(blinkPin.adr) |= (1 << blinkPin.bit) ;
  delay(1000);
  pinClear(blinkPin.adr, blinkPin.bit); //*(blinkPin.adr) &= ~(1 << blinkPin.bit) ;
  delay(1000);
}
/*Скетч использует 644 байт (2%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт.
*/

4 модификация

/*blink*/
//----------------------------
#define pinOut(pin)   (*((pin).reg) |=  (1UL << ((pin).bit)))
#define pinIn(pin)    (*((pin).reg) &= ~(1UL << ((pin).bit)))
#define pinReg(pin,stat) (stat ? pinOut(pin) : pinIn(pin))

#define pinSet(pin)     (*((pin).adr) |=  (1UL << ((pin).bit)))
#define pinClear(pin)   (*((pin).adr) &= ~(1UL << ((pin).bit)))
#define pinWrite(pin, stat) (stat ? pinSet(pin) : pinClear(pin))

struct pin_t {
  volatile uint8_t *reg;
  volatile uint8_t *adr;
  byte bit;/*поз бита*/
};
//----------------------------
struct pin_t blinkPin = {
  &DDRB, &PORTB, 5 // пин 13
};
//----------------------------
void setup() {
  pinOut(blinkPin);
}
void loop() {
  pinSet(blinkPin);
  delay(1000);
  pinClear(blinkPin);
  delay(1000);
}
/*Скетч использует 644 байт (2%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт.
*/

Размер получаемых скетчей одинаков. И в PROGMEM укладывать пока не буду :)

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Думаю, что справидливости ради нужно отметить, что digitalWrite - это больше, чем запись в порт. Это, также, защита от записи куда попало, как попало (операция атомарна), отключение PWM. 

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Думаю, что справидливости ради нужно отметить, что digitalWrite - это больше, чем запись в порт. Это, также, защита от записи куда попало, как попало (операция атомарна), отключение PWM. 

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

А что такое "модефикация"? Модификация, сделанная по последней моде? :))))))))))))

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

Вот программа без  digtalWrite

//**/
//----------------------------
#define pinOut(pin)   (*((pin).reg) |=  (1UL << ((pin).bit)))
#define pinIn(pin)    (*((pin).reg) &= ~(1UL << ((pin).bit)))

#define pinSet(pin)     (*((pin).out) |=  (1UL << ((pin).bit)))
#define pinClear(pin)   (*((pin).out) &= ~(1UL << ((pin).bit)))
#define pinWrite(pin, stat) (stat ? pinSet(pin) : pinClear(pin))
#define pinRead(pin)  (((*((pin).in) >> (pin).bit)) & 1UL)

struct pin_t {
  volatile uint8_t *reg;
  volatile uint8_t *out;
  volatile uint8_t *in;
  byte bit;/*поз бита*/
};
//-----------------------------------------
unsigned long mill;
typedef void (*handler)() ;
//------Cl_Led----------------------
// класс светодиод
class Cl_Led {
  protected:
    struct pin_t pin;
    bool led;
    bool statBlink;
    unsigned long past, time;
  public:
    Cl_Led(struct pin_t pin_): pin(pin_) {}
    void setup() {
      pinOut(pin);
      OFF();
    }
    void loop() {
      if (statBlink && mill - past >= time) {
        past = mill;
        led = !led;
        pinWrite(pin, led);
      }
    }
    void ON() {
      led = HIGH;
      pinSet(pin);
      statBlink = 0;
    }
    void OFF() {
      led = LOW;
      pinClear(pin);
      statBlink = 0;
    }
    void blink(unsigned long time_ = 200) {
      statBlink = 1;
      time = time_;
      past = mill;
      led = !led;
      pinWrite(pin, led);
    }
};
//------Cl_Btn----------------------
// класс кнопка
class Cl_Btn {
  protected:
    struct pin_t pin;
    handler Do;
    bool bounce = 0;
    bool btn = 1, oldBtn;
    unsigned long past;
  public:
    Cl_Btn(struct pin_t pin_, handler Do_): pin(pin_), Do(Do_) {}
    void setup() {
      pinIn(pin);
      pinSet(pin);
    }
    void loop() {
      bool newBtn = pinRead(pin);
      if (!bounce && newBtn != btn) {
        bounce = 1;
        past = mill;
      }
      if (bounce && mill - past >= 10) {
        bounce = 0 ;
        oldBtn = btn;
        btn = newBtn;
        if (!btn && oldBtn) Do();
      }
    }
};
//-----компоновка----------------------
const struct pin_t ledPin = {&DDRB, &PORTB, &PINB, 5 }; // пин 13
Cl_Led Led(/*пин*/ledPin);
void DoBtn1() {
  Led.ON();
  Serial.println("DoBtn1");
}
void DoBtn2() {
  Led.OFF();
  Serial.println("DoBtn2");
}
void DoBtn3() {
  Led.blink();
  Serial.println("DoBtn3");
}
const struct pin_t btn1Pin = {&DDRD, &PORTD, &PIND, 2 };// пин 2
const struct pin_t btn2Pin = {&DDRD, &PORTD, &PIND, 3 };// пин 3
const struct pin_t btn3Pin = {&DDRD, &PORTD, &PIND, 4 };// пин 4
Cl_Btn Btn1(/*пин*/btn1Pin,/*обработчик*/DoBtn1);
Cl_Btn Btn2(/*пин*/btn2Pin,/*обработчик*/DoBtn2);
Cl_Btn Btn3(/*пин*/btn3Pin,/*обработчик*/DoBtn3);
//-----main-----------------------
int main() {
  init();
  // setup()
  Serial.begin(9600);
  Led.setup();
  Btn1.setup();
  Btn2.setup();
  Btn3.setup();
  for (;;) {
    // loop()
    mill = millis();
    Led.loop();
    Btn1.loop();
    Btn2.loop();
    Btn3.loop();
  }
  return 0;
}
/*Скетч использует 2558 байт (8%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 303 байт (14%) динамической памяти, оставляя 1745 байт для локальных переменных. Максимум: 2048 байт.
*/

и с  digtalWrite такая же


//**/
unsigned long mill;
typedef void (*handler)() ;
//------Cl_Led----------------------
// класс светодиод
class Cl_Led {
  protected:
    const byte pin;
    bool led;
    bool statBlink;
    unsigned long past, time;
  public:
    Cl_Led(byte pin_): pin(pin_) {}
    void setup() {
      pinMode(pin, OUTPUT);
      OFF();
    }
    void loop() {
      if (statBlink && mill - past >= time) {
        past = mill;
        digitalWrite(pin, led = !led);
      }
    }
    void ON() {
      digitalWrite(pin, led = HIGH);
      statBlink = 0;
    }
    void OFF() {
      digitalWrite(pin, led = LOW);
      statBlink = 0;
    }
    void blink(unsigned long time_ = 200) {
      statBlink = 1;
      time = time_;
      past = mill;
      digitalWrite(pin, led = !led);
    }
};
//------Cl_Btn----------------------
// класс кнопка
class Cl_Btn {
  protected:
    const byte pin;
    handler Do;
    bool bounce = 0;
    bool btn = 1, oldBtn;
    unsigned long past;
  public:
    Cl_Btn(byte pin_, handler Do_): pin(pin_), Do(Do_) {}
    void setup() {
      pinMode(pin, INPUT_PULLUP);
    }
    void loop() {
      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) Do();
      }
    }
};
//-----компоновка----------------------
Cl_Led Led(/*пин*/13);
void DoBtn1() {
  Led.ON();
  Serial.println("DoBtn1");
}
void DoBtn2() {
  Led.OFF();
  Serial.println("DoBtn2");
}
void DoBtn3() {
  Led.blink();
  Serial.println("DoBtn3");
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/DoBtn1);
Cl_Btn Btn2(/*пин*/3,/*обработчик*/DoBtn2);
Cl_Btn Btn3(/*пин*/4,/*обработчик*/DoBtn3);
//-----main-----------------------
int main() {
  init();
  // setup()
  Serial.begin(9600);
  Led.setup();
  Btn1.setup();
  Btn2.setup();
  Btn3.setup();
  for (;;) {
    // loop()
    mill = millis();
    Led.loop();
    Btn1.loop();
    Btn2.loop();
    Btn3.loop();
  }
  return 0;
}
/*Скетч использует 2488 байт (7%) памяти устройства. Всего доступно 32256 байт.
  Глобальные переменные используют 251 байт (12%) динамической памяти, оставляя 1797 байт для локальных переменных. Максимум: 2048 байт.
*/

 

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

Расжевая методичка как писать программы с классами под Ардуину. Там предложена программа написания конвейера для предметов #25

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

Помимо инкапсуляции, у классов есть ещё несколько замечательных фишек, типа наследования (вкл. можественное), полиморфизма, виртуализации и т.п.

Вы же пользуетесь только инкапсуляцией, начисто игнорируя всё остальное. Это довело Вас уже до такой ручки, что в #164 Вы умудрились обыкновенные пространства имён обозвать "классозаменителями".

Что-то в этом подходе не так, не находите?

 

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

У обычного кухоного ножа есть куча колющих и режущих родственников. Но все равно на кухне используется кухоный нож. А как было бы прекрасно если бы кухарь чистил бы картошку , к примеру, шашкой или фламбергом.  Замечательное  зрелище со стороны, но почему то чистят ножиком. Это я к тому , что нах*ра это в простых скетчах.

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

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Да ладно... кто-то еще чистит картошку ножом? Я только в лесу так делаю. А для дома есть овощечистка.

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

sadman41 пишет:
Да ладно... кто-то еще чистит картошку ножом? Я только в лесу так делаю. А для дома есть овощечистка.
А теперь представьте себе, что вы чистите картошку овощечисткой, и уже мечтаете о жареной картошки , а вам говорят что овощечистка отстой, так как овощечистка это простой наследник кухоного ножа, а еще множественное наследование , полиморфизма, виртуализации и т.п для кухонных ножей от канадской компании которые мы продадим со скидкой.

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

qwone пишет:
нах*ра это в простых скетчах

Что "это"? Ваша инкапсуляция? Или пространства имён, которые Вы обозвали "классозаменителями"? :)

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Ну, я не знаю, что у вас там в голове творится, но овощечистка, как мне кажется - как раз и есть морфированный наследник ножа ))

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

sadman41 пишет:

морфированный наследник ножа ))

class VPleer : public Knife {
    int powerVoltage;
    int powerCurrent;
....
};

:)

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

sadman41 пишет:

Ну, я не знаю, что у вас там в голове творится, но овощечистка, как мне кажется - как раз и есть морфированный наследник ножа ))

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

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

qwone пишет:
А вот ЕвгенийП, требует от меня

Я требую???? Господь с Вами, где, когда и при каких обстоятельствах я что-то от Вас требовал?

Я лишь спросил "не находите ли Вы это странным". Могли бы ответить "нет, не нахожу" и всего делов. Нет же, надо выдумать какое-то требование и яростно от него отбиваться :)))))

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

а у мня вот, на все случаи жызни есть 

class TSensor
{
 protected:
	 byte			fpin;
	 int			flastvalue;
	 long			flasttime;
	 EnumSensorType		fsensortype;
	 EnumSensorState	fstate;

	 virtual int		 internalRead();
	 virtual EnumSensorState getState(int value);

 public:
	 PEventFunc OnChangeValue;
	 PEventFunc OnChangeState;

	 TSensor(byte pin);
	 TSensor(byte pin, bool pullup);

	 PFlashString ClassName() const;
	 PFlashString StateString() const;

	 virtual int Read();

	 inline EnumSensorType	getSensorType()	const	{ return fsensortype; }

	 inline EnumSensorState GetState(void)	const	{ return fstate; }
	 inline int GetValue(void)		const 	{ return flastvalue; }
};

и всё остальные даччики от него наследуюца. 

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

Строки 14-15 я бы делал не так, а через виртуальные функции. Расходы практичски не увеличиваются, выгод много.

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

Нее.. виртуальные здесь не годятся ;) Я пробовал в #153 для qwone, показать как юзать наследование с абстрактным классом. Вышло так -

qwone пишет:

Но честно сильно горомоздко. 

 
)))
 
 
Действительно, лишние буквы в коде ))))
 
Хороше DetSimen понял прелесть наследования, для любительского форума - прогресс небывалый, а Вы еще виртуальные методы хотите... Это громоздко ;) Ясно ж написано - классы для чайников!
qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вот, вот. Если бы для новичков на форуме, было нормой использовать классы и программировать по методичке, то да это было к месту. А так даже мои простые скетчи, в в глазах большинства как "божественное откровение". Так что такая схема програмировать это противовес "честного Си на Ардуине".  Наверно к этому и пришли разработчики ПO на Ардуине, потому что заказчик платит деньги, на которые они и живут. 

ПС: Я разумеется был бы не против если бы кто-то разрабатывал более прогрессивные библиотеки под Ардуино.

ППС: Считайте коды здесь просто маленькой ступенькой для новичков, которые пытаюся освоить Си++ в Ардуино.

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

Все привыкли к такой записи b=func(a); Но иногда возможно обратное func(a)=b; Для тех кто не верит вот код

//-----------------------
int &func(int &val) {
  return val;
}
//----main()-----------------
void setup() {
  Serial.begin(9600);
  int a = 5;
  func(a) = 10;//<-- обратите на эту запись
  Serial.println(a);
  // выведено 10
  int b = 1;
  func(b) = 75;//<-- обратите на эту запись
  Serial.println(b);
  // выведено 75
}

void loop() {
}
/*Скетч использует 1762 байт (5%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 186 байт (9%) динамической памяти, оставляя 1862 байт для локальных переменных. Максимум: 2048 байт.*/

 

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

О сколько нам открытий чудных... Уже и до ссылок докопали ;)

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

Logik пишет:
О сколько нам открытий чудных... Уже и до ссылок докопали ;)
Просто это основа примения функции возвращающих ссылки. А дальше все это модификации и импровизации.  Но лучше начинать с такого простого варианта, а не более сложных фунций. Так становится проще понять механизм.

ПС: функции возвращающие ссылки это просто переменные. И обратно. Обычные переменные это функции возвращающие ссылки, но просто встроены во внутрь среды. 

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

qwone пишет:

Для тех кто не верит вот код

Верить или не верить можно в Бога, а ссылки ... при чём тут вера?

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

Действительно, нету ссылкам веры. Верую только в истиные указатели.

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

Вот еще интересный код. Попытка управлять Ардуиной как консолью. Хотя пока про управление говорить не стоит

/**/
const char *versia = "1.00";
unsigned long mill;
//----------------------------------
class Cl_Console {
  protected:
    unsigned int pos;
    char buffer[30];
    unsigned int argc;
    char *argv[10];
    bool fbs;
  public:
    /*конструктор*/
    Cl_Console() {}
    /*иницирование*/
    void init() {
      Serial.begin(9600);
      clear();
    }
    /*очиcтить*/
    void clear() {
      pos = 0;
      buffer[pos] = 0;
      argc = 0;
      argv[argc] = &buffer[pos];
      fbs = true;
    }
    /*показать*/
    void view() {
      for (int i = 0; i <= argc; ++i) {
        Serial.println(argv[i]);
      }
    }
    /*проанализировать*/
    void analysis() {
      if (!strcmp(argv[0], "ver")) {
        Serial.print("versia:");
        Serial.println(versia);
      }
    }
    /*работа*/
    void run() {
      if (Serial.available() > 0) {
        char value = Serial.read();
        switch (value) {
          case ' ':
            if (fbs == false) {
              fbs = true;
              buffer[pos++] = 0;
              buffer[pos] = 0;
              argc++;
              argv[argc] = &buffer[pos];
            }
            break;
          case '\n':
            //view();
            analysis();
            clear();
            break;
          default:
            fbs = false;
            buffer[pos++] = value;
            buffer[pos] = 0;
        }
      }
    }
};
//----------------------------------
Cl_Console Console;
//----------------------------------
void setup() {
  Console.init();
}
void loop() {
  mill = millis();
  Console.run();
}
/*Скетч использует 1790 байт (5%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 261 байт (12%) динамической памяти, оставляя 1787 байт для локальных переменных. Максимум: 2048 байт.
*/

 

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

А чего в нем интересного? Разве что работа с char *argv[10]; элегантная. Но на односвязном списке еще лучше былобы, и без ограничения на кол-во аргументов. И еще массив указателей вполне заменяем на массив индекса символа в строке. Просто для экономии.  А так обычный код.

ПС. Я и сам не люблю проверять индексы на выход за пределы массива ;)  , но в приложении принимающем в массив данные извне это очень нужно!

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

ну вот это 

47             if (fbs == false) {
48               fbs = true;

дааа, прямо "элегантный код" ...

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

Было бы ещё элегантнее, если бы в 48-ой строке false было. Я тут такое не раз встречал.

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

Читать разучились? Цитирую по буквам "работа с char *argv[10]; элегантная". Причем тут if (fbs == false) ? Кстати оно тоже без криминала. Или кто тут про превосходство if (!fbs) потрындеть захотел.

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

так отрабатываю "новые механизмы"

/**/
//--------------------------------
typedef struct u {
  byte pin;
} U, *pU;
class Cl_device {
  protected:
  public:
    /*иницирование*/
    void init(pU &unit) {
      pinMode(unit->pin, OUTPUT);
    }
    /*включить*/
    void ON(pU &unit) {
      digitalWrite(unit->pin, HIGH);
    }
    /*выключить*/
    void OFF(pU &unit) {
      digitalWrite(unit->pin, LOW);
    }
};
Cl_device device;
//-------------------------
pU Led1 = new U;//<-coздадим объект Led1
pU Led2 = new U;//<-coздадим объект Led2
//------main()-----------
void setup() {
  Led1->pin = /*пин*/13;
  Led2->pin = /*пин*/12;
  device.init(Led1);
  device.init(Led2);
}
void loop() {
  device.ON(Led1);
  device.ON(Led2);
  delay(500);
  device.OFF(Led1);
  device.OFF(Led2);
  delay(500);
}
/*Скетч использует 1726 байт (5%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 23 байт (1%) динамической памяти, оставляя 2025 байт для локальных переменных. Максимум: 2048 байт.
*/