Цифровые автоматы в классах по qwone

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

Или так 

typedef int(*pDo)();  //<-- создаем тип указатель на функцию
byte fun(pDo Do) {
  return Do();
}
//-----------------------------------
void setup() {
  Serial.begin(9600);
  Serial.print(
    fun(
      [] { return 5;} //< внутри функции объявляем новую лямда функцию
    )
  );
}
void loop() {
}

 

Ворота
Ворота аватар
Онлайн
Зарегистрирован: 10.01.2016

Это что за поток сознания? О чём этом? То, что ты неоправданно и не к месту используешь довольно сложный и дорогостоящий механизм, это понятно, а вот смысла предыдущего поста не понял.

Ворота
Ворота аватар
Онлайн
Зарегистрирован: 10.01.2016

Слушь, Квон, ты меня убедил! Принимай в свою секту лямбдафилов!

Как опытный человек, зацени мою попытку. Это обычный блинк на 13-ом пине с периодом в одну секунду. но написан не по-лоховски, а продвинуто - с лямбдами.

Вопрос не в работоспособности - работает на uno/nano отлично (компилировал в IDE 1.8.9). Вопрос в том, достаточно ли лямбдануто?. Или можно полямбданутее?

Покритикуй в общем, пожалуйста.

//
// Лямбда-блинк на пине LED_BUILTIN
//

constexpr auto pp = [] {return 500;}; // функция вычисления полупериода блинка

void setup(void) {
	[] {
		[] {
			return pinMode;}() (
				[] {
					return LED_BUILTIN;
				}(),
				[] {
					return OUTPUT;
				}()
		);
		while(1) 
			[] (void (*dw)(uint8_t, uint8_t)) {
				auto b = [] {
					return LED_BUILTIN;
				}();
				dw(
					[&b] {
						return b;
					} (),
					![] {
						return digitalRead;
					}() ([=] {
						return b;
					}())
				);
				[] {
					return delay;
				} () (pp());
			} ([] {
				return digitalWrite;
			}()); 
	} ();
}

void loop(void) {}

 

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Богу лямбд нужно больше лямбд)

sadman41
Offline
Зарегистрирован: 19.10.2016

А богу лямд?

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

Ну, я всё понимаю, но constexpr-то нафига здесь?

Ворота
Ворота аватар
Онлайн
Зарегистрирован: 10.01.2016

Да, шоб был!

Schwarz78
Offline
Зарегистрирован: 19.01.2019

sadman41 пишет:

А богу лямд?

Богу лямд - меньше метастабильности, и больше MTBF.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
"DIYMan, post: 213550, member: 10047" пишет:
Открой для себя рефакторинг - непременный атрибут профессиональной жизни программиста  Когда я слышу "легче переписать" - хочется дать пинка говорящему. Хотя да - у самого возникают иногда такие мысли, в запале, но, как правило - подумавши, понимаешь, что нет - не легче переписать, надо именно рефакторить.
Отсюда

http://forum.amperka.ru/threads/%D0%90%D0%BD%D1%82%D0%B8-%D0%B4%D1%80%D0...

А теперь вопрос? Что такое рефакторить и с чем его едят. Гугл дал ответ такой https://iiba.ru/basic-principles-and-rules-of-refactoring/

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

А лямбданутее можно. Здесь я не вижу лямбд высших порядков, а можно было бы замутить.

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

qwone пишет:
Отсюда
А чё, теперь ответы на посты из амперки надо здесь читать? Это все посты так или только некоторые?

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

С одной стороны понятно. Если в коде много строк, то переписывать все долго, трудно и бесплатно. Лучше переписать часть и даже часть части. С другой стороны здесь на форуме открывается много тем, где надо провести "рефактринг"=поправить чуть чуть код, а то код не работает . Хотя всей душой понимаешь, что ТС его код ( а скорее и не его) надо отправить на **й, потому что переписывать надо все а потом еще учить его почему и зачем это надо.  Вот и выходит что рефакторинг это еще одно модное словечко из лексикона эффективных менеджеров от программирования. :))

ПС: ЕвгенийП Вы что решились чистить эту тему? Я что нарушил какие-то неписаные правила .!!!

Ворота
Ворота аватар
Онлайн
Зарегистрирован: 10.01.2016

qwone пишет:
рефакторинг это еще одно модное словечко из лексикона эффективных менеджеров от программирования. :))

Пральна пух! Так их!

ну, а чё за мои лябды? Не прокомментируешь?

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

qwone пишет:

ПС: ЕвгенийП Вы что решились чистить эту тему?

Я? Господь с Вами! И в мыслях не было. Удивило увидет здесь ответ на вопрос из амперки, вот и спросил. Нельзя? Я что-то нарушил?

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

Эта тема для сброса сюда очередного квонокода, а остальное просто лишнее.
project_AAA.ino

/*project_AAA*/
// Ардуино нано . Среда Arduino 1.8.0
// кнопки на землю и на пины 2,3,4
// реле 8,9,10,11
// lcd 1602_I2c на I2c

#include "menu.h"
#include "device.h"
//---------------------------------------
void setup() {
  device_init();
  menu_init();
}

void loop() {
  device_run();
  menu_run();
}

device.h

/*device.h*/
#ifndef device_h
#define device_h
#include <Arduino.h>
//--------------------------------------
class Cl_Relay {
  protected:
    byte pin;
    unsigned long past;
    bool state;
    void set( bool s) {
      digitalWrite(pin, state = s);
    }
  public:
    Cl_Relay(byte p): pin(p) {}
    void init() {
      pinMode(pin, OUTPUT);
      set(false);
    }
    void ON() {
      set(true);
    }
    void OFF() {
      set(false);
    }
    bool read() {
      return state;
    }
};
template <> inline Cl_lcd1602_i2c & operator << (Cl_lcd1602_i2c &s, Cl_Relay obj) {
  if (obj.read()) s.print(" 0N");
  else s.print("OFF");
  return s;
}
//----------------------------------
const byte Relay_num = 4;
Cl_Relay Relay[Relay_num] = {
  Cl_Relay(/*пин*/8),
  Cl_Relay(/*пин*/9),
  Cl_Relay(/*пин*/10),
  Cl_Relay(/*пин*/11)
};
void device_init() {
  for (int i = 0; i < Relay_num; i++) Relay[i].init();
}
void device_run() {
}
#endif // device.h

lcd1602_I2C.h

/*lcd1602_I2C.h*/
#ifndef lcd1602_I2C_h
#define lcd1602_I2C_h
#include <Arduino.h>
//------------- дисплей-----------------------
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_lightON 0x08
#define LCD_lightOFF 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd1602_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _lightONval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[32];
  public:
    Cl_lcd1602_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // ждем не меньше 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // ждем не меньше 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _lightONval = LCD_lightOFF;
      expanderWrite(_lightONval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
      lightON();
    }
    // подсветку вкл/выкл
    void lightON(void) {
      _lightONval = LCD_lightON;
      expanderWrite(0);
    }
    void lightOFF(void) {
      _lightONval = LCD_lightOFF;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 32; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 16; i++ )out(buffer[i]);
      line(1);
      for (byte i = 16; i < 32; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 16) x = 16;
      else posX = x;
      if (y > 2) x = 2;
      else posY = y;
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      if (l == 0) command(LCD_SETDDRAMADDR | 0x00);
      else command(LCD_SETDDRAMADDR | 0x40);
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    inline size_t write(uint8_t value) {
      if (posX < 16 && posY < 2) {
        buffer[posY * 16 + posX] = value;
        posX++;
      }
      return 1;
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _lightONval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};

typedef Cl_lcd1602_i2c& (*pDo1)(Cl_lcd1602_i2c&);
template <typename T> inline Cl_lcd1602_i2c & operator << (Cl_lcd1602_i2c &s, T n) {
  s.print(n);
  return s;
}
template <> inline Cl_lcd1602_i2c & operator << (Cl_lcd1602_i2c &s, pDo1 Do) {
  Do(s);
  return s;
}
template <> inline Cl_lcd1602_i2c & operator << (Cl_lcd1602_i2c &s, byte n) {
  if (n < 10)s.print("0");
  s.print(n);
  return s;
}
Cl_lcd1602_i2c& clear(Cl_lcd1602_i2c& s) {
  s.clear();
  return s;
}
Cl_lcd1602_i2c& show(Cl_lcd1602_i2c& s) {
  s.show();
  return s;
}
Cl_lcd1602_i2c lcd(0x27);//0x3F
#endif // lcd1602_I2C.h

menu.h

/*menu.h*/
#ifndef menu_h
#define menu_h
#include <Arduino.h>
#include "lcd1602_I2C.h"
#include "device.h"
//-----------  кнопки  ------------------------
typedef void (*pDo)();
class Cl_Btn {
  protected:
    byte pin;
    unsigned long past;
    bool state;
    void set(bool s) {
      past = millis();
      state = s;
      if (s == true)Do();
    }
  public:
    pDo Do = [] {};
    Cl_Btn(byte p): pin(p) {}
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100) {
        switch (state) {
          case false :
            if (!digitalRead(pin)) set(true);
            break;
          case true :
            if (digitalRead(pin)) set(false);
            break;
        }
      }
    }
};
Cl_Btn BtnL(/*пин*/2);// кнопка левая
Cl_Btn BtnR(/*пин*/3);// кнопка правая
Cl_Btn BtnS(/*пин*/4);// кнопка селект
//-----------   меню  ----------------------------------
const byte scr0 = 0;// главный экран
const byte scr1 = 10;// вкл/выкл реле 1
const byte scr2 = 20;// вкл/выкл реле 2
const byte scr3 = 30;// вкл/выкл реле 3
const byte scr4 = 40;// вкл/выкл реле 4
byte scr;
unsigned long menu_past;
void go(byte s) {
  scr = s;
  menu_past = millis();
  lcd << clear;
  switch (s) {
    case scr0: { // главный экран
        lcd << F("1:") << Relay[0] << F(" 2:") << Relay[1];
        lcd.setCursor(0, 1);
        lcd << F("3:") << Relay[2] << F(" 4:") << Relay[3];
        BtnL.Do = [] {};
        BtnR.Do = [] {go(scr1);};
        BtnS.Do = [] {};
      }
      break;
    case scr1: {// вкл/выкл реле 1
        lcd << F("Re1:") << Relay[0];
        BtnL.Do = [] {go(scr0);};
        BtnR.Do = [] {go(scr2);};
        BtnS.Do = [] {
          if (Relay[0].read()) Relay[0].OFF();
          else Relay[0].ON();
          go(scr1);
        };
      }
      break;
    case scr2: {// вкл/выкл реле 2
        lcd << F("Re2:") << Relay[1];
        BtnL.Do = [] {go(scr1);};
        BtnR.Do = [] {go(scr3);};
        BtnS.Do = [] {
          if  (Relay[1].read()) Relay[1].OFF();
          else Relay[1].ON();
          go(scr2);
        };
      }
      break;
    case scr3: {// вкл/выкл реле 3
        lcd << F("Re3:") << Relay[2];
        BtnL.Do = [] {go(scr2);};
        BtnR.Do = [] {go(scr4);};
        BtnS.Do = [] {
          if  (Relay[2].read()) Relay[2].OFF();
          else Relay[2].ON();
          go(scr3);
        };
      }
      break;
    case scr4: {// вкл/выкл реле 4
        lcd << F("Re4:") << Relay[3];
        BtnL.Do = [] {go(scr3);};
        BtnR.Do = [] {};
        BtnS.Do = [] {
          if  (Relay[3].read()) Relay[3].OFF();
          else Relay[3].ON();
          go(scr4);
        };
      }
      break;
  }
  lcd << show;
}
void menu_init() {
  lcd.init();
  BtnL.init();
  BtnR.init();
  BtnS.init();
  go(scr0);
}
void menu_run() {
  BtnL.run();
  BtnR.run();
  BtnS.run();
  if (scr == scr0 && millis() - menu_past >= 500)  go(scr0);
  if (scr != scr0 && millis() - menu_past >= 5000) go(scr0);
}
#endif // menu.h

 

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

Мне вот интересно: переписывание блинка с дилей на миллис - это рефакторинг или нет?

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

andriano пишет:

Мне вот интересно: переписывание блинка с дилей на миллис - это рефакторинг или нет?

Если вам за это заплатят, то скорее всего да. А если на шару то скорее нет. А так музыкальная пауза

/**/
#define ntB0  31
#define ntC1  33
#define ntCS1 35
#define ntD1  37
#define ntDS1 39
#define ntE1  41
#define ntF1  44
#define ntFS1 46
#define ntG1  49
#define ntGS1 52
#define ntA1  55
#define ntAS1 58
#define ntB1  62
#define ntC2  65
#define ntCS2 69
#define ntD2  73
#define ntDS2 78
#define ntE2  82
#define ntF2  87
#define ntFS2 93
#define ntG2  98
#define ntGS2 104
#define ntA2  110
#define ntAS2 117
#define ntB2  123
#define ntC3  131
#define ntCS3 139
#define ntD3  147
#define ntDS3 156
#define ntE3  165
#define ntF3  175
#define ntFS3 185
#define ntG3  196
#define ntGS3 208
#define ntA3  220
#define ntAS3 233
#define ntB3  247
#define ntC4  262 //до -1 октава
#define ntCS4 277 //до# 
#define ntD4  294 //ре
#define ntDS4 311 //ре#
#define ntE4  330 //ми
#define ntF4  349 //фа
#define ntFS4 370 //фа#
#define ntG4  392 //соль
#define ntGS4 415 //соль#
#define ntA4  440 //ля
#define ntAS4 466 //ля#
#define ntB4  494 //си
#define ntC5  523 //до -2 октава
#define ntCS5 554 //до# 
#define ntD5  587 //ре
#define ntDS5 622 //ре#
#define ntE5  659 //ми
#define ntF5  698 //фа
#define ntFS5 740 //фа#
#define ntG5  784 //соль
#define ntGS5 831 //соль#
#define ntA5  880 //ля
#define ntAS5 932 //ля#
#define ntB5  988 //си
#define ntC6  1047
#define ntCS6 1109
#define ntD6  1175
#define ntDS6 1245
#define ntE6  1319
#define ntF6  1397
#define ntFS6 1480
#define ntG6  1568
#define ntGS6 1661
#define ntA6  1760
#define ntAS6 1865
#define ntB6  1976
#define ntC7  2093
#define ntCS7 2217
#define ntD7  2349
#define ntDS7 2489
#define ntE7  2637
#define ntF7  2794
#define ntFS7 2960
#define ntG7  3136
#define ntGS7 3322
#define ntA7  3520
#define ntAS7 3729
#define ntB7  3951
#define ntC8  4186
#define ntCS8 4435
#define ntD8  4699
#define ntDS8 4978
typedef struct {
  int note;
  int time;
} note_t;
const note_t mld[] PROGMEM = {// постой паровоз
  {ntE4, 250}, {ntE4, 750}, {ntA4, 125}, {ntG4, 125},
  {ntF4, 500}, {ntD4, 250}, {ntC4, 250}, {ntB3, 250},
  {ntE4, 500}, {ntD4, 250}, {ntC4, 250}, {ntA3, 500},
  {ntG4, 250}, {ntG4, 375}, {ntC4, 375}, {ntE4, 250},
  {ntG4, 250}, {ntC5, 250}, {ntB4, 250}, {ntA4, 250},
  {ntGS4, 1000}, {0, 1000}, {ntE4, 250}, {ntC5, 500},
  {ntB4, 250}, {ntC5, 250}, {ntB4, 250}, {ntA4, 500},
  {ntE4, 250}, {ntA4, 250}, {ntA4, 250}, {ntG4, 250},
  {ntA4, 250}, {ntG4, 250}, {ntF4, 500}, {ntF4, 250},
  {ntE4, 500}, {ntG4, 250}, {ntF4, 250}, {ntE4, 250},
  {ntD4, 250}, {ntC4, 250}, {ntB3, 250}, {ntA3, 1000},
  {0, 1000}, {ntE4, 250}, {ntC5, 500}, {ntB4, 250},
  {ntC5, 250}, {ntB4, 250}, {ntA4, 500}, {ntE4, 250},
  {ntA4, 250}, {ntA4, 250}, {ntG4, 250}, {ntA4, 250},
  {ntG4, 250}, {ntF4, 500}, {ntF4, 250}, {ntE4, 500},
  {ntG4, 250}, {ntF4, 250}, {ntE4, 250}, {ntD4, 250},
  {ntC4, 250}, {ntB3, 250}, {ntA3, 1000}, {0, 0}
};
const byte st0 = 0;// не играть
const byte st1 = 1;// играть мелодию 1
class Cl_Beep {
  protected:
    byte pin;
    byte state;
    byte i;
    unsigned long past, time;
    void set(byte s) {
      state = s;
      if (s == st0) return;
      past = millis();
      unsigned int note = pgm_read_word(&mld[i].note);
      time = pgm_read_word(&mld[i].time);
      i++;
      if (time == 0) state = st0;
      else tone(pin, note, time * 0.8);
    }
  public:
    Cl_Beep(byte p): pin(p) {}
    void init() {
      set(st0);
    }
    void run() {
      if (millis() - past >= time) set(state);
    }
    void play() {
      i = 0;
      set(st1);
    }
};
Cl_Beep Beep(/*пин*/8);
void setup() {
  Beep.init();
  Beep.play();
}
void loop() {
  Beep.run();
}

 

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

qwone пишет:

 "рефактринг"=поправить чуть чуть код, а то код не работает

Это дебагинг, это не рефакторинг.

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

Слова похожие....

Ворота
Ворота аватар
Онлайн
Зарегистрирован: 10.01.2016

qwone пишет:

Эта тема для сброса сюда очередного квонокода, а остальное просто лишнее.

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

Ладно, буду ещё стараться, мож лучше получится.

Ворота
Ворота аватар
Онлайн
Зарегистрирован: 10.01.2016

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

А лямбданутее можно.

От брейнфакера слышу! 

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

qwone пишет:

Вот и выходит что рефакторинг это еще одно модное словечко из лексикона эффективных менеджеров от программирования. :))

Это не модное словечко, отнюдь. Если ты не ел устриц - то про их вкус навряд ли сможешь что-то сказать.

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

andriano пишет:

Мне вот интересно: переписывание блинка с дилей на миллис - это рефакторинг или нет?

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

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

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

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

Ладно, буду ещё стараться, мож лучше получится.

Снимаю шляпу за такой шикарный пример забивания гвоздей микроскопом!  Я в культурном шоке, смакую каждую строчку ;)

Lotus6202
Lotus6202 аватар
Offline
Зарегистрирован: 12.01.2018

qwone пишет:

С одной стороны понятно. Если в коде много строк, то переписывать все долго, трудно и бесплатно. Лучше переписать часть и даже часть части. С другой стороны здесь на форуме открывается много тем, где надо провести "рефактринг"=поправить чуть чуть код, а то код не работает . Хотя всей душой понимаешь, что ТС его код ( а скорее и не его) надо отправить на **й, потому что переписывать надо все а потом еще учить его почему и зачем это надо.  Вот и выходит что рефакторинг это еще одно модное словечко из лексикона эффективных менеджеров от программирования. :))

ПС: ЕвгенийП Вы что решились чистить эту тему? Я что нарушил какие-то неписаные правила .!!!

ДАкуя Умничаешь

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

andriano пишет:

Мне вот интересно: переписывание блинка с дилей на миллис - это рефакторинг или нет?

qwone пишет:

 Если вам за это заплатят, то скорее всего да. А если на шару то скорее нет. А так музыкальная пауза

DIYMan пишет:

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

Лично я в большей степени согласен с DIYMan.

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

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

sadman41
Offline
Зарегистрирован: 19.10.2016

А если я начал переписывать код, сделал его понятней, убавил багов, но при етом, мать его ети, увеличил на 1кб - это рефакторинг или перевод добра на г....?

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

sadman41 пишет:

А если я начал переписывать код, сделал его понятней, убавил багов, но при етом, мать его ети, увеличил на 1кб - это рефакторинг или перевод добра на г....?

Это пятница :)))))

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

sadman41 пишет:

А если я начал переписывать код, сделал его понятней, убавил багов, но при етом, мать его ети, увеличил на 1кб - это рефакторинг или перевод добра на г....?

Я надеюсь, код не для Ардуино? Тогда мегабайтом больше, мегабайтом меньше, какая разница.

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

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

andriano пишет:

Разумеется, если предыдущий килобайт не был последним.

Предыдущий килобайт - всегда предпоследний, закон-тайга :)))

sadman41
Offline
Зарегистрирован: 19.10.2016

Для ATMega328. Думал, что выцыганю полкило, а вышло так, что слил килобайт. Прям слёзы в глазах стоят третий день.

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

sadman41 пишет:

Прям слёзы в глазах стоят третий день.

Соберись, третий день - ни в какие ворота :)

lean_74
Offline
Зарегистрирован: 22.12.2015

DIYMan пишет:

Соберись, третий день - ни в какие ворота :)

Дим, а почему Ворота, с маленькой буквы? не уважаешь? :)))))

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

lean_74 пишет:

DIYMan пишет:

Соберись, третий день - ни в какие ворота :)

Дим, а почему Ворота, с маленькой буквы? не уважаешь? :)))))

Ля! И точно! Оплошал, блин :))

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

Шаблон метода класса

class Cl_AAA {
  public:
    template<typename T> T & func( T &obj);
  protected:
};
template<typename T> T& Cl_AAA::func( T &obj) {
  return obj;
}
template<> byte& Cl_AAA::func(byte &obj) {
  return obj;
}
Cl_AAA AAA;

void setup() {
  Serial.begin(9600);
  int q = -342, w;
  w = AAA.func(q);
  Serial.println(w);
  byte q1 = 123, w1;
  w1 = AAA.func(q1);
  Serial.println(w1);
}
void loop() {
}

 

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

Это для конкурса самых дибильных методов печати 2-х констант?

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

Подключаем и получаем память дополнительно 4К байт

#include "e24c32.h"
void setup() {
  Serial.begin(9600);
  outpram.init();
  uint16_t addr = 30;
  float a = 13.18, b;
  outpram.write(addr, a); //<- загрузить в e24c32
  outpram.read(addr, b); //<- прочитать в e24c32
  Serial.println(b);
}

void loop() {
}

и файл e24c32.h

/**/
#ifndef e24c32_h
#define e24c32_h
#include <Arduino.h>
#include <Wire.h>

#define EEPROM__PAGE_SIZE         32
#define EEPROM__WR_BUFFER_SIZE    (BUFFER_LENGTH - 2)
#define EEPROM__RD_BUFFER_SIZE    BUFFER_LENGTH

class e24c32 {
  public:
    e24c32(byte adr): adr_i2c(adr) {}
    void init() {
      Wire.begin();
    }
    byte readByte(word address);
    void writeByte(word address, byte data);
    void readBytes(word address, byte length, byte* p_data);
    void writeBytes(word address, byte length, byte* p_data);
    template<typename T> T &read (word address, T &obj);
    template<typename T> T &write(word address, T &obj);
  private:
    byte adr_i2c;
    void writePage  (word address, byte length, byte* p_data);
    void writeBuffer(word address, byte length, byte* p_data);
    void readBuffer (word address, byte length, byte* p_data);
};

byte e24c32::readByte(word address) {
  Wire.beginTransmission(adr_i2c);
  Wire.write(address >> 8);
  Wire.write(address & 0xFF);
  Wire.endTransmission();
  Wire.requestFrom(adr_i2c, (byte)1);
  byte data = 0;
  if (Wire.available()) data = Wire.read();
  return data;
}
void e24c32::writeByte( word address, byte data) {
  Wire.beginTransmission(adr_i2c);
  Wire.write(address >> 8);
  Wire.write(address & 0xFF);
  Wire.write(data);
  Wire.endTransmission();
}

void e24c32::writeBytes(word address, byte length, byte* p_data) {
  // Write first page if not aligned.
  byte notAlignedLength = 0;
  byte pageOffset = address % EEPROM__PAGE_SIZE;
  if (pageOffset > 0) {
    notAlignedLength = EEPROM__PAGE_SIZE - pageOffset;
    if (length < notAlignedLength) notAlignedLength = length;
    writePage(address, notAlignedLength, p_data);
    length -= notAlignedLength;
  }
  if (length > 0) {
    address += notAlignedLength;
    p_data += notAlignedLength;
    // Write complete and aligned pages.
    byte pageCount = length / EEPROM__PAGE_SIZE;
    for (byte i = 0; i < pageCount; i++) {
      writePage(address, EEPROM__PAGE_SIZE, p_data);
      address += EEPROM__PAGE_SIZE;
      p_data += EEPROM__PAGE_SIZE;
      length -= EEPROM__PAGE_SIZE;
    }
    if (length > 0)
      writePage(address, length, p_data); // Write remaining uncomplete page.
  }
}
void e24c32::readBytes (word address, byte length, byte* p_data) {
  byte bufferCount = length / EEPROM__RD_BUFFER_SIZE;
  for (byte i = 0; i < bufferCount; i++) {
    word offset = i * EEPROM__RD_BUFFER_SIZE;
    readBuffer(address + offset, EEPROM__RD_BUFFER_SIZE, p_data + offset);
  }
  byte remainingBytes = length % EEPROM__RD_BUFFER_SIZE;
  word offset = length - remainingBytes;
  readBuffer(address + offset, remainingBytes, p_data + offset);
}
void e24c32::writePage(word address, byte length, byte* p_data) {
  // Write complete buffers.
  byte bufferCount = length / EEPROM__WR_BUFFER_SIZE;
  for (byte i = 0; i < bufferCount; i++) {
    byte offset = i * EEPROM__WR_BUFFER_SIZE;
    writeBuffer(address + offset, EEPROM__WR_BUFFER_SIZE, p_data + offset);
  }
  // Write remaining bytes.
  byte remainingBytes = length % EEPROM__WR_BUFFER_SIZE;
  byte offset = length - remainingBytes;
  writeBuffer(address + offset, remainingBytes, p_data + offset);
}
template<typename T> T& e24c32::read(word address, T &obj) {
  readBytes(address, sizeof(T), (byte*)&obj);
  return obj;
}
template<> byte & e24c32::read (word address, byte &obj) {
  return obj = readByte(address);
}
template<typename T> T & e24c32::write (word address, T &obj) {
  writeBytes(address, sizeof(T),(byte*)&obj);
  return obj;
}
template<> byte & e24c32::write(word address, byte &obj) {
  writeByte(address, obj);
  return obj;
}
void e24c32::writeBuffer (word address, byte length, byte* p_data) {
  Wire.beginTransmission(adr_i2c);
  Wire.write(address >> 8);
  Wire.write(address & 0xFF);
  for (byte i = 0; i < length; i++) Wire.write(p_data[i]);
  Wire.endTransmission();
  // Write cycle time (tWR). See EEPROM memory datasheet for more details.
  delay(10);
}

void e24c32::readBuffer (word address, byte length, byte* p_data) {
  Wire.beginTransmission(adr_i2c);
  Wire.write(address >> 8);
  Wire.write(address & 0xFF);
  Wire.endTransmission();
  Wire.requestFrom(adr_i2c, length);
  for (byte i = 0; i < length; i++)
    if (Wire.available())
      p_data[i] = Wire.read();
}

static e24c32 outpram(/* адр i2c*/0x57);
#endif // e24c32_h

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

qwone пишет:

Шаблон метода класса

class Cl_AAA {
  public:
    template<typename T> T & func( T &obj);
  protected:
};
template<typename T> T& Cl_AAA::func( T &obj) {
  return obj;
}
template<> byte& Cl_AAA::func(byte &obj) {
  return obj;
}
Cl_AAA AAA;

void setup() {
  Serial.begin(9600);
  int q = -342, w;
  w = AAA.func(q);
  Serial.println(w);
  byte q1 = 123, w1;
  w1 = AAA.func(q1);
  Serial.println(w1);
}
void loop() {
}

 

не пойму в чём цимес?

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

ua6em пишет:
не пойму в чём цимес?
Как только разберетесь в цимесе использования шаблонов, такого глупого вопроса не будет. И да здесь тусуется куча народа программирующего через шаблоны, чего меня спрашивать. http://microsin.net/programming/pc/an-idiots-guide-to-cpp-templates-part1.html

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

А для чего строки №№ 9-11? (скетч из #135)

qwone пишет:

template<> byte& Cl_AAA::func(byte &obj) {
  return obj;
}

Разве для byte не сработает основной шаблон, который в строках №№6-8 ?

Может я чего не заметил, но мне кажется. что строки №№ 9-11 можно удалить и ничего не изменится. Я чего-то недопонял?

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

ЕвгенийП пишет:
Может я чего не заметил, но мне кажется. что строки №№ 9-11 можно удалить и ничего не изменится. Я чего-то недопонял?
Да именно НЕ допоняли и именно НЕ заметили.

ЕвгенийП пишет:
Этот текст НЕ является универсальной библиотекой, НЕ поддерживается и НЕ сопровожадется. Это домашняя вещь для домашнего использования. Я просто увидел, что она как-то расползлась и даже появилась у нас в одном из проектов в соответсвующем разделе. Потому и решил выложить изменения, о чём уже жалею.

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

 #8  Так я тоже сделаю исключение. 1- код сырой и больше нужен для отработки механизмов работы 2- если не сделаешь как получилось , не поймешь что можно лучше 3- у той микросхемы есть большой прикол - работаем побайтно или по странично (32 байта). Если делаем постранично , то нужна задержка 0,01 секунда 4-  мне было интересно совместить шаблон и часные случаи. 
ПС: учитель это не тот кто учит, а у того кого вы учитесь. Код здесь это просто личная записная книжка выложенная для публичного просмотра. Если кому интересно учится на моем коде я не возражаю. Но меня учить не надо. Я прекрасно вижу свои ошибки. А если не увижу сейчас , то увижу потом,для чего я и открыл эту тему.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

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

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

qwone пишет:
меня учить не надо
И в мыслях не было. Я лишь спросил то, чего не понял и совершенно не понимаю Вашей агрессии в ответ.

Если это личная записаня книжка, то почему она на публичном ресурсе? А если публичная, то может Вам как-то поадекватнее реагировать на вопросы, которые Вам задают? Впрочем, это, конечно, не моё дело.

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

ЕвгенийП пишет:
Если это личная записаня книжка, то почему она на публичном ресурсе? А если публичная, то может Вам как-то поадекватнее реагировать на вопросы, которые Вам задают? Впрочем, это, конечно, не моё дело.
Ответов не будет. Так как только этим и придется заниматься, а потом еще "в говне" окажешься. Я же все же питаюсь научиться программировать серьезные программы , а так же пройти всю цепочку развития программирования самостоятельно.

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

Пух, не забывай, что буфер у Wire 32 байта, и когда ты страницу хочешь записать, адрес ячейки куда писать займет в буфере 2 байта, и записать потом ты можешь еще 30, а 2 последних в ROM не попадут. 

Код твой я не читал, я просто спрашиваю, знаешь ли ты абэтом

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

Похоже и wire придется переписывать. А тестировать надо многоватенько. 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Воспользуйтесь этим драйвером I2C, тут буфер внешний. Сколько надо - столько и заявите и даже статически:

/**
 * Работа с TWI (I2C, 2-Wire) интерфейсом через аппаратные прерывания.
 *
 * ! Аппаратно не бывает одновременно режима Master-RX и Slave-RX - поэтому тут используется ОДИН буфер.
 * ! Нет никаких "проверок", настройка глобалов - обязательна до каждого запуска автомата:
 * Master-Transmitter: twiMT_Ptr, twiMT_Count                  -- откуда и сколько байт свистеть;
 * Master-Receiver:    twiRX_Ptr, twiRX_Count, twiMasterReader -- куда и сколько принять и (опц.)что потом сделать;
 * Slave-Receiver:     twiRX_Ptr, twiRX_Count, twiSlaveReader  -- куда и сколько принять и (обяз.)что сделать;
 * Slave-Transmitter:  twiST_Ptr, twiST_Count, twiSlaveWriter  -- откуда и сколько отдать и (обяз.)что потом сделать;
 *
 * Особенности и отличия от типовых разработок (собрано многое вместе):
 * 1. Возможность одновременной работы как в режиме Master так и в режиме Slave;
 * 2. Внешняя буферизация данных при необходимости. Размер памяти определяется вашей программой, а не тут;
 * 3. Возможность ведения статистики - управляется константами компиляции;
 * 4. Произвольная настройка скорости работы интерфейса от 490гц до 1Мгц с авто вычислением прескалера и регистра скорости
 * 5. Возможность уменьшенной комплиции, если не требуются все режимы сразу.
 *
 * Константы компиляции #define:
 * #define TWI_ON   1 // если не определено, то обработчик прерывания I2C останется, но практически ПУСТОЙ!
 * Перед включением этого файла надо определить TWI_ON значениями:
 *
 * #define TWI_ON 1  // Master-Transmitter only: компилировать как режим Мастера-передатчика    ,ISR(TWI)=190 байт
 * #define TWI_ON 2  // Master-Receiver only:    компилировать как режим Мастер-приемник        ,ISR(TWI)=224 байт
 * #define TWI_ON 4  // Slave-Receiver only:     компилировать как режим Ожидающий получатель   ,ISR(TWI)=202 байт
 * #define TWI_ON 8  // Slave-Transmitter only:  компилировать как режим Отправитель по запросу ,ISR(TWI)=188 байт
 *
 * @TODO: #define TWI_ON 16 // + Logging: Включить в компиляцию логирование работы интерфейса.
 *
 * !!! Допускается компиляция нескольких режимов одновременно:
 * #define TWI_ON (1+2+4+8) // Включить в компиляцию ВСЕ режимы. ,ISR(TWI)=424 байт.
 *
 * @author Arhat109-20160402. arhat109@mail.ru
 * @license:
 *   1. This is a free software for any using and distributing without any warranties.
 *   2. You should keep author tag with any changes. May be with adding.
 *   Это свободное ПО для любого использования без каких-либо гарантий и претензий.
 *   Требуется сохранять тег @author при любых изменениях. Можете дописать свой.
 */
#ifndef _ARHAT_TWI_H_
#define _ARHAT_TWI_H_ 1

#include "arhat.h"

// If not defined - use as Master Transmitter only!
// Если нет ничего, то только управляющий мастер!
#ifndef TWI_ON
#  define TWI_ON TWI_MASTER_TX
#endif // TWI_ON

// ------------ All states TWI status register AND twiState: ------------- //
// Misc
#define TWI_ERROR                  0x00 // Misc: illegal start or stop condition
#define TWI_NO_INFO                0xF8 // Misc: no state information available

// I am Master
#define TWI_START                  0x08 // start condition transmitted
#define TWI_REP_START              0x10 // repeated start condition transmitted
#define TWI_MTR_ARB_LOST           0x38 // arbitration lost in SLA+W or data

// Master Transmitter
#define TWI_MT_SLA_ACK             0x18 // address: SLA+W transmitted, ACK received
#define TWI_MT_SLA_NACK            0x20 // address: SLA+W transmitted, NACK received
#define TWI_MT_DATA_ACK            0x28 // data: transmitted, ACK received
#define TWI_MT_DATA_NACK           0x30 // data: transmitted, NACK received

// Master Receiver
#define TWI_MR_SLA_ACK             0x40 // address: SLA+R transmitted, ACK received
#define TWI_MR_SLA_NACK            0x48 // address: SLA+R transmitted, NACK received
#define TWI_MR_DATA_ACK            0x50 // data: received, ACK returned
#define TWI_MR_DATA_NACK           0x58 // data: received, NACK returned

// I am Slave
// Slave Receiver
#define TWI_SR_SLA_ACK             0x60 // address: SLA+W received, ACK returned
#define TWI_SR_ARB_LOST_SLA_ACK    0x68 // arbitration lost in SLA+RW, SLA+W received, ACK returned
#define TWI_SR_GCALL_ACK           0x70 // general call received, ACK returned
#define TWI_SR_ARB_LOST_GCALL_ACK  0x78 // arbitration lost in SLA+RW, general call received, ACK returned
#define TWI_SR_DATA_ACK            0x80 // data: received, ACK returned
#define TWI_SR_DATA_NACK           0x88 // data: received, NACK returned
#define TWI_SR_GCALL_DATA_ACK      0x90 // general call data received, ACK returned
#define TWI_SR_GCALL_DATA_NACK     0x98 // general call data received, NACK returned
#define TWI_SR_STOP                0xA0 // stop or repeated start condition received while selected

// Slave Transmitter
#define TWI_ST_SLA_ACK             0xA8 // address: SLA+R received, ACK returned
#define TWI_ST_ARB_LOST_SLA_ACK    0xB0 // arbitration lost in SLA+RW, SLA+R received, ACK returned
#define TWI_ST_DATA_ACK            0xB8 // data: transmitted, ACK received
#define TWI_ST_DATA_NACK           0xC0 // data: transmitted, NACK received
#define TWI_ST_LAST_DATA           0xC8 // last data byte transmitted, ACK received

// ------------ Macros for TWI ------------- //

#define TWI_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3)) // Two LSB are prescaler bits
#define TWI_STATUS      (TWSR & TWI_STATUS_MASK)                            // Get status from TWSR

#define TWI_READ    1                   // for SLA+R address
#define TWI_WRITE   0                   // SLA+W address
#define TWI_ACK     1
#define TWI_NACK    0

#define twiOn()       (PRR0 &= ~_BV(7)) // =0: TWI power is On (default on power!)
#define twiOff()      (PRR0 |= _BV(7))  // =1: TWI power is Off

/**
 * Set twi bit rate and prescaler: _twbr:[0..255], _twsr:[0..3]
 * ------------------------------------------------------------
 * _twsr = 3: scl freq. = [   490 .. 111_111] hz
 * _twsr = 2: scl freq. = [ 1_960 .. 333_333] hz
 * _twsr = 1: scl freq. = [ 7_782 .. 666_667] hz
 * _twsr = 0: scl freq. = [30_418 .. 888_889] hz
 * IF _twbr = 0: frequency equal 1 Mhz with any _twsr!
 *
 * @example twiSetRate(72,0) : use 100_000hz standart mode
 * @example twiSetRate(12,0) : use 400_000hz standart mode
 * @example twiSetRate(0,0)  : use 1 Mhz mode
 */
#define twiSetRate(_twbr, _twsr)      \
{                                     \
  _SFR_BYTE(TWSR) = (uint8_t)(_twsr); \
  TWBR = (uint8_t)(_twbr);            \
}
/**
 * Макросы управления автоматом TWI: последняя команда везде - запись в TWCR
 *
 * @param bool ack -- есть ли режимы Slave, надо ли слушать шину?
 *
 * twiStart()      -- включаем, разрешаем, сброс прерывание(запуск КА) и выставляем старт на шину.
 * twiReply()      -- оно же, только без старта
 * twiReleaseBus() -- включаем, сброс прерывание(запуск КА), а вот прерывание разрешаем только если есть Slave
 * twiStop()       -- оно же, только ещё и отправляем "стоп" в шину и ждем исполнения.
 */
#define twiStart(ack)                   (_BV(TWEN)|_BV(TWINT)|_BV(TWIE)|_BV(TWSTA)|((ack)?_BV(TWEA):0))
#define twiReply(ack)                   (_BV(TWEN)|_BV(TWINT)|_BV(TWIE)|((ack)? _BV(TWEA):0))
#define twiReleaseBus(ack)              (_BV(TWEN)|_BV(TWINT)|((ack)? _BV(TWEA)|_BV(TWIE):0))
#define twiSetAddress(address, isGcall) (TWAR  = (uint8_t)(((address) << 1)|((isGcall)&0x01)))
#define twiSetMaskAddress(mask)         (TWAMR = (uint8_t)(mask))
#define twiStop(ack)                    \
{                                       \
  TWCR = _BV(TWSTO)|twiReleaseBus(ack); \
  while(TWCR & _BV(TWSTO));             \
  twiMode |= TWI_READY;                 \
}

#ifdef __cplusplus
    extern "C" {
#endif
// ------------ TWI internal variables ------------- //

enum TwiModes {
     TWI_IS_SLAVE  = 1                                  // have I slave mode too?
    ,TWI_SEND_STOP = 2                                  // is need send stop when Master is ending?
    ,TWI_READY     = 4                                  // previous work is ended
};

volatile uint8_t    twiMode;
volatile uint8_t    twiState;                           // state TWI automat
volatile uint8_t    twiSLARW;                           // address for send to (SLARW)

volatile uint8_t   twiMT_Count;                         // остаток байт для передачи мастеров
volatile uint8_t  * twiMT_Ptr;                          // указатель текущего байта внешнего буфера передачи мастером

volatile uint8_t   twiRX_Count;                         // остаток байт для приема мастером/слейвом
volatile uint8_t  * twiRX_Ptr;                          // указатель текущего байта внешнего буфера приема мастером/слейвом

volatile uint8_t   twiST_Count;                         // остаток байт для передачи слейвом
volatile uint8_t  * twiST_Ptr;                          // указатель текущего байта внешнего буфера передачи слейвом

void    (* twiHookRestart)(void) = 0;          // указатель на функцию перезапуска мастера без освобождения шины (TWI_SEND_STOP)
void    (* twiMasterReader)(void) = 0;         // указатель на функцию "Master принял данные, куда их?"
void    (* twiSlaveReader)(void) = 0;          // указатель на функцию "Slave принял данные, куда их?"
void    (* twiSlaveWriter)(void) = 0;          // указатель на функцию "Slave всё отправил, что дальше?"

/*
#if defined(TWI_ON) && (TWI_ON & TWI_LOG_ON)

typedef struct {
    uint16_t   starts,restarts,stops,losts,noslarw,mtx,mrx,srx,grx,stx;
} TwiStat;
#define ptrTwiStat(ptr)  ((TWI_Stat *)(ptr))
static volatile TwiStat    twiStatistic;

#endif // TWI_ON::TWI_LOG_ON
*/
// ------------ TWI functions ------------- //

/**
 * Autocalculate and set twi prescaler and bit rate
 * 1Mhz      .. 30.418khz : TWSR=0!
 * 30.42khz  ..  7.782khz : TWSR=1
 *  7.782khz ..  1.960khz : TWSR=2
 *  1/960khz ..  0.490khz : TWSR=3
 */
void twiSpeed(uint32_t freq)
{
    uint16_t bitRate = (F_CPU / freq) - 16;
    uint8_t  bitMul  = 0;

    while( (bitRate > 511) && (bitMul < 3) ){
        bitRate /= 4; bitRate += 1; bitMul++;
    }
    bitRate /= 2;
    if( bitRate > 255 ) return;
    twiSetRate(bitRate, bitMul);
}

/**
 * for Arduino setup() as Master or Slave or Both modes
 * freq:[490 .. 1 000 000], mode:[0,TWI_IS_SLAVE]
 */
void twiSetup(uint32_t freq, uint8_t mode)
{
    pinOut(I2C_SDA, HIGH);                                        // internal pullup is ON.
    pinOut(I2C_SCL, HIGH);
    twiSpeed(freq);                                               // set bitrate and prescaler for frequency
    twiMode = mode;
    TWCR = _BV(TWEN)|_BV(TWIE)|((mode&TWI_IS_SLAVE)?_BV(TWEA):0); // module, acks, and interrupt is ON
}

/**
 * for ISR(TWI): control restart conditions in all modes:
 * ! if only 1 mode -- this is a MACRO with next RETURN into ISR, else - function !
 *
 * 1. Освобождать шину, или надо ещё (напр. прием после передачи)?
 * да: Сеанс завершен. Ждем прямо тут прохождения стопа! Выходим из обработчика тут!
 * нет, рестарт:
 * .. есть Хук? процедура подготовки след. посылки: указатели, размеры, адрес, режим..
 * .. а нет Хука! Типовой режим "чтение после записи"
 * в любом случае отправляем restart
 *
 */
#if ((TWI_ON & 0x0F)!=1) && ((TWI_ON & 0x0F)!=2) && ((TWI_ON & 0x0F)!=4) && ((TWI_ON & 0x0F)!=8)
void twiSendStop(uint8_t _md)
{
    if (_md & TWI_SEND_STOP)
    {
        TWCR = _BV(TWSTO)|twiReleaseBus(_md & TWI_IS_SLAVE);
        while(TWCR & _BV(TWSTO));
        twiMode |= TWI_READY;
    }else{
        if( twiHookRestart ){
            twiHookRestart();
        } else {
            twiSLARW |= TWI_READ;
        }
        TWCR = twiStart(_md & TWI_IS_SLAVE);
    }
}
#else
#define twiSendStop(_md)                                   \
{                                                          \
    TWCR = _BV(TWSTO)|twiReleaseBus((_md) & TWI_IS_SLAVE); \
    while(TWCR & _BV(TWSTO));                              \
    twiMode |= TWI_READY;                                  \
}
#endif

/**
 * ISR for TWI interface: realised master and slave modes
 * ------------------------------------------------------
 */
ISR(TWI_vect)
{
    uint8_t _cr = twiReply(0);
    uint8_t _md = twiMode;
    uint8_t _st = twiState=TWI_STATUS;

#if defined(TWI_ON) && ((TWI_ON & TWI_IS_SLAVE_TX)||(TWI_ON & TWI_IS_SLAVE_RX))
    if( _st >= TWI_SR_SLA_ACK )
    {
#if (TWI_ON & TWI_IS_SLAVE_TX)
        if( (_st == TWI_ST_DATA_NACK) || (_st == TWI_ST_LAST_DATA) )
        {
            // ST: Был последний байт, мастер наелся ..
            // ST: Был наш последний байт: предупреждали мастера twiReply(NACK)
            twiSlaveWriter();                                   // Хук - обязателен! Дальше нечего передавать..
            _md=twiMode;                                        // возможно изменение режимов в хуке!
            twiSendStop(_md); return;
        }else{
            if( (_st == TWI_ST_ARB_LOST_SLA_ACK) || (_st == TWI_ST_SLA_ACK || _st == TWI_ST_DATA_ACK) )
            {
                // ST: Моего мастера заткнули и просят данные ..
                // ST: Мой адрес, начинаем ..
                // ST: Отправлено успешно, продолжаем ..
                TWDR = *twiST_Ptr++;
                _cr = twiReply(--twiST_Count);
            }else{
#endif // TWI_ON::TWI_IS_SLAVE_TX
#if (TWI_ON & TWI_IS_SLAVE_RX)
                if( (_st == TWI_SR_GCALL_DATA_NACK) || (_st == TWI_SR_DATA_NACK) || (_st == TWI_SR_STOP) )
                {
                    if( (_st == TWI_SR_GCALL_DATA_NACK) || (_st == TWI_SR_DATA_NACK) )
                    {
                        // SR: УПС. GCall - туда же.
                        // SR: УПС. Получен байт, мастеру уже был отправлен NACK
                        *twiRX_Ptr = TWDR;
                    }
                    // SR: Обнаружен stop или restart в процессе приема .. это всё?
                    twiSlaveReader();                           // Хук обязателен! это последний, дальше некуда складывать!
                    _md=twiMode;                                // возможно изменение режимов в хуке!
                    twiSendStop(_md); return;
                }else{
                    if( (_st == TWI_SR_GCALL_DATA_ACK) || (_st == TWI_SR_DATA_ACK) )
                    {
                        // SR: пришел байт всем - аналогично
                        // SR: пришел байт, можно ещё принять
                        *(twiRX_Ptr++) = TWDR;
                    }
                    // TWI_SR_ARB_LOST_SLA_ACK   SR: Мастер потерял шину: нет данных ..
                    // TWI_SR_ARB_LOST_GCALL_ACK SR: Вызов всем потерял шину (как это?) --""--
                    // TWI_SR_SLA_ACK            SR: Адрес принят, ещё только ждем данные
                    // TWI_SR_GCALL_ACK          SR: Вызов всем принят оно же
                    _cr = twiReply(--twiRX_Count);              // .. приняли байт и отправляем NACK если осталось 1 место.
                }
#endif // TWI_ON::TWI_IS_SLAVE_RX
#if (TWI_ON & TWI_IS_SLAVE_TX)
            }
        }
#endif // TWI_ON::TWI_IS_SLAVE_TX
    }else{

#endif // TWI_ON::TWI_SLAVE..
#if defined(TWI_ON) && (TWI_ON & TWI_MASTER_TX)
        // Master Transmiter or Reciever modes
        if( (_st == TWI_START) || (_st == TWI_REP_START) )
        {
            // MT,MR:: Прошла отправка стартовой посылки
            // MT,MR:: Прошла отправка повторного старта
            TWDR = twiSLARW;
            _cr = twiReply(_md & TWI_IS_SLAVE);
        }else{
            if( (_st == TWI_MT_SLA_NACK) || (_st == TWI_MT_DATA_NACK) )
            {
                // TWI_MT_DATA_NACK MT:: Упс. data NACK: Получатель не хотит?
                // TWI_MT_SLA_NACK  MT:: Упс. Получатель NACK .. не откликается зараза.
                twiSendStop(_md); return;
            }
            if( (_st == TWI_MT_SLA_ACK)  || (_st == TWI_MT_DATA_ACK) )
            {
                // MT: Адрес получателя отправлен успешно, начинаем
                // MT: Байт данных отправлен, продолжаем
                if( twiMT_Count-- ){
                    TWDR = *twiMT_Ptr++;
                    _cr = twiReply(_md & TWI_IS_SLAVE);
                }else{
                    twiSendStop(_md); return;
                }
            }else{
#endif // TWI_ON::TWI_MASTER_TX
#if defined(TWI_ON) && (TWI_ON & TWI_MASTER_RX)
                if( _st == TWI_MTR_ARB_LOST )
                {
                    // MT,MR: Упс. Мастер потерял шину: освобождаем и ждем/слушаем.
                    _md |= TWI_READY;
                    _cr = twiReleaseBus(_md & TWI_IS_SLAVE);
                }else{
                    if( (_st == TWI_MR_DATA_ACK) || (_st == TWI_MR_SLA_ACK) )
                    {
                        if( _st == TWI_MR_DATA_ACK ){
                            // MR: байт принят, ACK отправлен
                            *(twiRX_Ptr++) = TWDR;
                        }
                        // MR: Отправитель найден, начинаем прием
                        _cr = twiReply( --twiRX_Count );        // .. Можно ещё принять? Или Отправителю - NACK
                    }else{
                        if( _st == TWI_ERROR ) return;
                        if( _st == TWI_MR_DATA_NACK )
                        {
                            // MR: Упс. Получен последний байт дальше принимать некуда.
                            *twiRX_Ptr = TWDR;
                            if( twiMasterReader ) twiMasterReader();
//                            goto TWI_RET_HOOK;
                            _md=twiMode;                        // возможно изменение режимов в хуке!
                        }
                        // All other Master states: stop/restart if need
                        // TWI_MR_SLA_NACK  MR:: Упс. Отправитель NACK .. не откликается зараза.
                        twiSendStop(_md); return;
                    }
                }
#endif // TWI_ON::TWI_MASTER_RX
#if defined(TWI_ON) && (TWI_ON&TWI_MASTER_TX)
            }
        }
#endif // TWI_ON::TWI_MASTER_TX
#if defined(TWI_ON) && ((TWI_ON & TWI_IS_SLAVE_TX)||(TWI_ON & TWI_IS_SLAVE_RX))
    }
#endif // TWI_SLAVE_ON
    twiMode = _md;
    TWCR = _cr;
} //end ISR()

// -------------------------              (PROTECTED)             ------------------------- //
// Внутренние методы интерфейса, могут пригодится для создания внешних уровней работы с I2C //
// ---------------------------------------------------------------------------------------- //

/**
 * INTERNAL:: Простая передача. Запись адреса собеседника и запуск автомата TWI
 *
 * @see twiWrite(), twiRead()
 */
void _twiStartTo(uint8_t address)
{
    twiSLARW = address;                                 // Режим поставляется вместе с адресом!
    twiMode |= TWI_SEND_STOP;                           // только 1 бит! Могли быть иные режимы..
    TWCR = twiStart(twiMode & TWI_IS_SLAVE);
}

/**
 * INTERNAL:: Передача с рестартом. Запись адреса собеседника и запуск автомата TWI
 *
 * @see twiWrite(), twiRead()
 */
void _twiStartRe(uint8_t address)
{
    twiSLARW = address;                                 // Режим поставляется вместе с адресом!
    twiMode &= ~TWI_SEND_STOP;                          // только 1 бит! Могли быть иные режимы..
    TWCR = twiStart(twiMode & TWI_IS_SLAVE);
}

#define _twiWaitReady()             {while(!(TWI_READY & twiMode)); twiMode &= ~TWI_READY;}
#define _twiMT_Buffer(data, length) (twiMT_Ptr=(volatile uint8_t *)(data), twiMT_Count=(volatile uint8_t)(length))
#define _twiRX_Buffer(data, length) (twiRX_Ptr=(volatile uint8_t *)(data), twiRX_Count=(volatile uint8_t)(length))
#define _twiST_Buffer(data, length) (twiST_Ptr=(volatile uint8_t *)(data), twiST_Count=(volatile uint8_t)(length))

// -------------------------                PUBLIC                ------------------------- //
// ---------------------------------------------------------------------------------------- //

/**
 * Master-TX:: Передача length байт по адресу получателя. Только запуск!
 */
void twiWrite(uint8_t address, const uint8_t * data, uint8_t length)
{
    _twiWaitReady();                                    // Ждем завершения предыдущей работы
    _twiMT_Buffer(data, length);
    _twiStartTo( (address<<1) | TWI_WRITE );            // Режим передачи!
}

/**
 * MASTER-RX:: Прием length байт из адреса отправителя. Только запуск!
 */
void twiRead(uint8_t address, uint8_t * data, uint8_t length)
{
    _twiWaitReady();                                    // Ждем завершения предыдущей работы
    _twiRX_Buffer(data, length);
    _twiStartTo( (address<<1) | TWI_READ );             // Режим приема данных!
}

/**
 * Master Read-after-Write:: Чтение данных после отправки команды. Только запуск.
 * !!! Не совместимо с Slave Receive Mode - буфер приема общий !!!
 */
void twiRAW(uint8_t address                             // адрес устройства
, uint8_t* command, uint8_t clength                     // команда и её длина
, uint8_t* data, uint8_t dlength                        // буфер приема данных и его длина
){
    _twiWaitReady();                                    // Ждем завершения предыдущей работы
    _twiMT_Buffer(command, clength);
    _twiRX_Buffer(data, dlength);

    twiHookRestart = 0;                                 // типовой переход на чтение этого же Slave
    twiMode |= TWI_SEND_STOP;                           // рестарт после отправки команды
    twiSLARW = (address<<1 | TWI_WRITE);                // Сначала режим передачи!
    TWCR = twiStart(twiMode & TWI_IS_SLAVE);
}

/**
 * @example: Пример реализации обработчика "SLAVE отправил всё, что дальше?"
 * для случая, когда текущий буфер можно отправлять повторно по следующему запросу
 *
 * !!! Использует доп. глобалы (должны быть определены в вашем скетче):
 *  uint8_t * stBuffer;
 *  uint8_t   stBufferSize;
 *//*
 void twiSlaveRewriter(void)
 {
     _twiST_Buffer(stBuffer, stBufferSize);             // просто перенастраиваем буфер на повторную передачу.
 }
*/
#ifdef __cplusplus
    }
#endif

#endif // _ARHAT_TWI_H_

Где-то был вариант с ведением логов передач и ошибок, если надо, поищу.

Строку 42 - можно удалить и в строках 212,213 заменить макрос pinOut() на digitalWrite() на ноги вашего I2C. Больше нигде этот хидер тут не нужен вроде бы..

Ворота
Ворота аватар
Онлайн
Зарегистрирован: 10.01.2016

"Пропал дом!" :(

sadman41
Offline
Зарегистрирован: 19.10.2016

Похоже, что не только Wire переписывать надо, но и вообще менять всю систему.

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

Именно систему! Да что систему менять - цивилизацию менять надо, планетарно мыслить! И вселенски!

ПС. Два дебила - это сила, а у нас здесь - коллектив!