Создание пользовательского класса

Smith2007
Offline
Зарегистрирован: 30.10.2017

Спасибо. Значит я не верно истолковал строчку в h файле

extern ProtocolBus4 Bus4;

Но если определять экземпляр класса в основном скетче - то зачем эта строка в хидере?

 

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

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

extern вообще делается для того, чтобы знать, что такая вещь где-то есть.

Smith2007
Offline
Зарегистрирован: 30.10.2017

Спасибо, Евгений.

Скомпилилось все врено.

Есть еще одна задача, которую пытаюсь решить но пока с трудом....

При создании экземпляра класса, мне нужно передать имя функции, которую должел вызвать экземпляр класса Bus4.

В функцию нужно передать ссылку на заполненную структуру

Пример

MyClass Bus( 33, func<с параметрами>)

33 - это просто uint, а func - это имя функции, которая описана в скетче как

void func(ссылка на структуру экземпляра Bus) {
    f1 = <Элемент структуры экземпляра Bus>
}

 

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

Ну, передавать классу ссылку на функцию - само по себе идея плохая. Классы и ссылки на функции - это разные технологии программирования.

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

Smith2007
Offline
Зарегистрирован: 30.10.2017

Передача имени функции (без параметров)

#include <Bus4.h>

ProtocolBus4 Bus4(0x33333333, exec);

void setup() {
     Serial.begin(115200);
 }

void loop() {
  Bus4.Recv();
}

void exec() {
  Serial.println("Ok");
}

 

Bus4.h

// *********************************************************************
//	Bus4.h - library for Arduino - Version 0.2
//	
//	Original library 		(0.2) by Igor Kuznetsov
//
//        Протокол обмена
//	sendBuf[7], recvBuf[7] 
//	<Адрес><Команда><Регистр><D3><D2><D1><D0><CRC>
//        Адрес - Адрес устройства кому предназначен пакет. Если FF - всем
//	Команда-0xff - Передача ID устройства (ID в поле данных)
//		0x01 - Чтение uint8_t   D0
//		0x02 - Чтение uint16_t  D1, D0
//		0x03 - Чтение uint32_t  D3, D2, D1, D0
//		0x11 - Запись байта D0
//		0x12 - Запись uint8_t   D0
//		0x13 - Запись uint16_t  D1, D0
//		0x14 - Запись uint32_t  D3, D2, D1, D0
//                0xFA - Чтение переменных из EEPROM
//                0xFB - Запись переменных в EEPROM
//	Регистр - 00..FF - Адрес регистра
//	D0..D3 - данные
//	CRC - контрольная сумма
//
// =====================================================================
#ifndef Bus4_h
  #define Bus4_h

  #if defined(ARDUINO) && ARDUINO >= 100
    #include <Arduino.h>
  #else
    #include <WProgram.h>
  #endif

  // *******************************************************************
   
  //Command code
  #define CMD_READL	1
  #define CMD_READ8	2
  #define CMD_READ16	3
  #define CMD_READ32	4
  #define CMD_WRITEL	5
  #define CMD_WRITE8	6
  #define CMD_WRITE16	7
  #define CMD_WRITE32	8
  
  // Структура буфера приема
  struct xBuf_t {   // Структура буфера
    uint8_t adr;
    uint8_t cmd;
    uint8_t reg;
    uint8_t b3;
    uint8_t b2;
    uint8_t b1;
    uint8_t b0;
  };
  
  
  class ProtocolBus4 {
     public:
       // Кноструктор
       ProtocolBus4(uint32_t SIGN, void (*f)() );
       void Recv(void);			// Процедура приема. 
       
       // передача данных
       void sendLine(uint8_t adr, uint8_t reg, uint8_t value);	// 
       void sendLine(uint8_t adr, uint8_t reg, uint16_t value);	// 
       void sendLine(uint8_t adr, uint8_t reg, uint32_t value);	// 
       void (*func)();

     private:
       uint32_t _SIGN; // = 0x33333333;  // Сигнатура начала пакета
       uint8_t _count;   // Счетчик байт данных (принимаем 4 байта данных)
       uint8_t _inChr;   // принятый байт
       uint32_t _sign;   // регистр сигнатуры с линии. Данные полученные с линии.
       uint8_t _crc;     // Подсчет CRC (XOR) с линии. Сигнатура не считается.
       uint8_t _mode;    // Режим. 
                        // 0 - ожидание сигнатуры, 1 - ожидание адреса, 
                        // 2 - ожидание команды, 3 - ожидание регистра, 
                        // 4 - ожидание данных, 5 - проверка crc Если crc верно - буфер готов
       
       xBuf_t xBuf;     // Буфер данных с линии
       uint8_t *p_b0;   // Указатель на xBuf.b0
       
       uint32_t _tStart; // = 0;  
       uint32_t _millisec; // = 0;
       uint32_t _timeOut; // = 10000;  // В реальной системе тайм аут следует снизить. Например 50 мс.
       
       // Следующие переменные для замера времени выполнения основного цикла, мкс
       //uint32_t t1;
       //uint32_t t2;
       
       uint8_t sendBuf[8]; // Буфер для отправки
       void sendPacket(void);
  };
#endif

Bus4.cpp

#include <Bus4.h>
//
//        Протокол обмена
//	sendBuf[7], recvBuf[7] 
//	<Адрес><Команда><Регистр><D3><D2><D1><D0><CRC>
//        Адрес - Адрес устройства кому предназначен пакет. Если FF - всем
//	Команда-0xff - Передача ID устройства (ID в поле данных)
//		0x01 - Чтение uint8_t   D0
//		0x02 - Чтение uint16_t  D1, D0
//		0x03 - Чтение uint32_t  D3, D2, D1, D0
//		0x11 - Запись байта D0
//		0x12 - Запись uint8_t   D0
//		0x13 - Запись uint16_t  D1, D0
//		0x14 - Запись uint32_t  D3, D2, D1, D0
//                0xFA - Чтение переменных из EEPROM
//                0xFB - Запись переменных в EEPROM
//	Регистр - 00..FF - Адрес регистра
//	D0..D3 - данные
//	CRC - контрольная сумма
//
//********************************************************************


void (*func)();

// Конструктор
ProtocolBus4::ProtocolBus4(uint32_t SIGN, void (*f)()  )  {
  _SIGN = SIGN;
  func = f;
}

void ProtocolBus4::Recv() {
// Обработка тайм-аута. Если на линии ничего нет более чем TIME_OUT - сбрасываем режим
  _millisec = millis();
  if ( (_millisec - _tStart) > _timeOut) {
    _mode = 0;    // Сброс режима
    _sign = 0;    // Сброс регистра сигнатуры
  }
  
  uint8_t n = Serial.available();
  // Если буфер приема не пустой
  if ( n > 0) {
    _tStart = _millisec;              // Время отсчета тайм-аута
    //t1 = micros();                  // Для отладки. Вычисление времени работы цикла
    _inChr = Serial.read();
    //Serial.print(" inChr = ");
    //Serial.println(inChr, HEX);
    //Serial.print(" n = ");
    //Serial.println(n);
    //Serial.print(" mode = ");
    //Serial.println(mode);

    switch ( _mode ) {
      // Режим 0. Проверка на сигнатуру
      case 0:                       
        _sign |= _inChr;              // Принятый с линии байт помещаем в младший байт 4-х байтовой переменной
        //Serial.print(" sign = ");
        //Serial.println(sign, HEX);
        if (_sign == _SIGN) {         // Если сигнатура с линии совпала с заданной
          _sign = 0;                 // Обнуляем сигнатуру для следующего пакета
          //Serial.println("SIGN - OK");
          _mode = 1;                 // Переходим на ввод адреса
          _crc = 0;                  // Очистили подсчет crc
          _count = 0;                // Обнулили счетчик байт данных. (4 байта)
        }
        else {
          _sign = _sign << 8;
          //Serial.println("SIGN - Filed");          
        }
        break;

      // Ввод адреса устройства  
      case 1:        
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        xBuf.adr = _inChr;           // записали адрес в буфер
        _mode = 2;                   // Переходим на ввод команды
        //Serial.print(" xBuf.adr = ");
        //Serial.println(xBuf.adr, HEX);
        break;

      // Ввод команды  
      case 2:         
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        xBuf.cmd = _inChr;           // Записали команду в буфер
        _mode = 3;                   // Переходим на ввод регистра
        //Serial.print(" xBuf.cmd = ");
        //Serial.println(xBuf.cmd, HEX);
        break;

      // Ввод регистра  
      case 3:         
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        xBuf.reg = _inChr;           // Записали регистр в буфер
        _mode = 4;                   // Переходим на ввод команды
        p_b0 = &xBuf.b0;              // Получаем адрес xBuf.b0
        //Serial.print(" xBuf.reg = ");
        //Serial.println(xBuf.reg, HEX);
        break;

      // Ввод данных 4 байта  
      case 4:         
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        *(p_b0 - _count) = _inChr;    // Записываем байт по адресу xBuf.b0 скорректированному на номер байта
        _count++;                    // Переходим к следующему байту данных
        if (_count == 4) {           // Если 4 байта приняты (от 0 до 3)
          _mode = 5;                 // Переходим на ввод crc
          //Serial.print("b3 = ");
          //Serial.println(xBuf.b3, HEX);
          //Serial.print("b2 = ");
          //Serial.println(xBuf.b2, HEX);
          //Serial.print("b1 = ");
          //Serial.println(xBuf.b1, HEX);
          //Serial.print("b0 = ");
          //Serial.println(xBuf.b0, HEX);
        }
        //Serial.print("count = ");
        //Serial.println(count, HEX);
        break;

      // Ввод crc  
      case 5:         
        if (_crc == _inChr) {         // Сравниваем подсчитанную crc с указанной в inChr
          _mode = 0;                 // Сбрасываем режим
          //Serial.println(" crc - OK!");
          //Serial.println("OK");     // Успешное чтение пакета
                                    // Тут может быть вызов процедуры установки значений
                                    // или просто взведение флага готовности
                                    // или копирование буфера в выходные переменные
//          (*func)();
        }
        else {                      // Контрольная сумма не совпала
          _mode = 0;                 // Сброс режима
          //Serial.println(" crc - FALSE!");
          //Serial.println("Err");
//          (*func)();
        };
        break;
    } // switch ( mode )
    //Serial.print("crc = ");
    //Serial.println(crc, HEX);
    // Для отладки. Подсчте времени выполнения цикла.
    // Без отладочных вызовов Serial.print колеблется от 12 до 40 мкс
    // С отладочными Serial.print - время увеличивается до 800 мкс
    //t2 = micros();
    //Serial.print("  T = ");
    //Serial.println(t2-t1);
  } // if ( n > 0)
}   // Recv()



// **************************************************
//             ПЕРЕДАЧА
//
// Передача байта
void ProtocolBus4::sendLine(uint8_t adr, uint8_t reg, uint8_t value) {
   sendBuf[0] = adr;
   sendBuf[1] = CMD_WRITE8;
   sendBuf[2] = reg;
   sendBuf[3] = 0;
   sendBuf[4] = 0;
   sendBuf[5] = 0;
   sendBuf[6] = value;
   sendBuf[7] = adr ^ CMD_WRITE8 ^ reg ^ sendBuf[3] ^ sendBuf[4] ^ sendBuf[5] ^ sendBuf[6];
   sendPacket();
}

// Передача uint16_t
void ProtocolBus4::sendLine(uint8_t adr, uint8_t reg, uint16_t value) {
   sendBuf[0] = adr;
   sendBuf[1] = CMD_WRITE8;
   sendBuf[2] = reg;
   sendBuf[3] = 0;
   sendBuf[4] = 0;
   sendBuf[5] = (value & 0xff00) >> 8;
   sendBuf[6] = value & 0x00ff;
   sendBuf[7] = adr ^ CMD_WRITE8 ^ reg ^ sendBuf[3] ^ sendBuf[4] ^ sendBuf[5] ^ sendBuf[6];
   sendPacket();
}

// Передача uint32_t
void ProtocolBus4::sendLine(uint8_t adr, uint8_t reg, uint32_t value) {
   sendBuf[0] = adr;
   sendBuf[1] = CMD_WRITE32;
   sendBuf[2] = reg;
   sendBuf[3] = (value & 0xff000000) >> 24;
   sendBuf[4] = (value & 0x00ff0000) >> 16;                                                 
   sendBuf[5] = (value & 0x0000ff00) >> 8;                                                  
   sendBuf[6] =  value & 0x000000ff;
   sendBuf[7] = adr ^ CMD_WRITE8 ^ reg ^ sendBuf[3] ^ sendBuf[4] ^ sendBuf[5] ^ sendBuf[6];
   sendPacket();
}

void ProtocolBus4::sendPacket() {
  Serial.write((uint8_t*)(&_SIGN),4);
  for (int i=0; i < 8; i++) {
     Serial.write(sendBuf[i]);
  }
}

Ошибки компиляции

Arduino: 1.8.5 (Windows 7), Плата:"Arduino Leonardo"

sign:10: error: 'exec' was not declared in this scope

 ProtocolBus4 Bus4(0x33333333, exec);

                               ^

exit status 1
'exec' was not declared in this scope

Этот отчёт будет иметь больше информации с
включенной опцией Файл -> Настройки ->
"Показать подробный вывод во время компиляции"

 

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

прототип нужен

void exec(void);

ProtocolBus4 Bus4(0x33333333, exec);

 

 

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

Для начала перенесите строки 13-15 выше строки 3. А там посмотрим

Smith2007
Offline
Зарегистрирован: 30.10.2017

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

Для начала перенесите строки 13-15 выше строки 3. А там посмотрим

#include <Bus4.h>

void exec() {
  Serial.println("Ok");
}

ProtocolBus4 Bus4(0x33333333, exec);

void setup() {
     Serial.begin(115200);
}

void loop() {
  Bus4.Recv();
}

Ошибка

Arduino: 1.8.5 (Windows 7), Плата:"Arduino Leonardo"

C:\Program Files (x86)\Arduino\libraries\Bus4\Bus4.cpp:41:20: error: expected unqualified-id before '(' token

 void ProtocolBus4::(*func)();

                    ^

exit status 1
Ошибка компиляции для платы Arduino Leonardo.

 

Добавил в Bus4.cpp 

void ProtocolBus4::(*func)();

#include <Bus4.h>

//*********************************************************************
//        Протокол обмена
//	sendBuf[7], recvBuf[7] 
//	<Адрес><Команда><Регистр><D3><D2><D1><D0><CRC>
//        Адрес - Адрес устройства кому предназначен пакет. Если FF - всем
//	Команда-0xff - Передача ID устройства (ID в поле данных)
//		0x01 - Чтение uint8_t   D0
//		0x02 - Чтение uint16_t  D1, D0
//		0x03 - Чтение uint32_t  D3, D2, D1, D0
//		0x11 - Запись байта D0
//		0x12 - Запись uint8_t   D0
//		0x13 - Запись uint16_t  D1, D0
//		0x14 - Запись uint32_t  D3, D2, D1, D0
//                0xFA - Чтение переменных из EEPROM
//                0xFB - Запись переменных в EEPROM
//	Регистр - 00..FF - Адрес регистра
//	D0..D3 - данные
//	CRC - контрольная сумма
//
//********************************************************************



// Конструктор
ProtocolBus4::ProtocolBus4(uint32_t SIGN, void (*f)()  )  {
  _SIGN = SIGN;
  _crc = 0;
  _mode = 0;    
  _tStart = 0; 
  _millisec = 0;
  _timeOut = 10000;
  func = f;
}

void ProtocolBus4::(*func)();


void ProtocolBus4::Recv() {
// Обработка тайм-аута. Если на линии ничего нет более чем TIME_OUT - сбрасываем режим
  _millisec = millis();
  if ( (_millisec - _tStart) > _timeOut) {
    _mode = 0;    // Сброс режима
    _sign = 0;    // Сброс регистра сигнатуры
  }
  
  uint8_t n = Serial.available();
  // Если буфер приема не пустой
  if ( n > 0) {
    _tStart = _millisec;              // Время отсчета тайм-аута
    //t1 = micros();                  // Для отладки. Вычисление времени работы цикла
    _inChr = Serial.read();
    //Serial.print(" inChr = ");
    //Serial.println(inChr, HEX);
    //Serial.print(" n = ");
    //Serial.println(n);
    //Serial.print(" mode = ");
    //Serial.println(mode);

    switch ( _mode ) {
      // Режим 0. Проверка на сигнатуру
      case 0:                       
        _sign |= _inChr;              // Принятый с линии байт помещаем в младший байт 4-х байтовой переменной
        //Serial.print(" sign = ");
        //Serial.println(sign, HEX);
        if (_sign == _SIGN) {         // Если сигнатура с линии совпала с заданной
          _sign = 0;                 // Обнуляем сигнатуру для следующего пакета
          //Serial.println("SIGN - OK");
          _mode = 1;                 // Переходим на ввод адреса
          _crc = 0;                  // Очистили подсчет crc
          _count = 0;                // Обнулили счетчик байт данных. (4 байта)
        }
        else {
          _sign = _sign << 8;
          //Serial.println("SIGN - Filed");          
        }
        break;

      // Ввод адреса устройства  
      case 1:        
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        xBuf.adr = _inChr;           // записали адрес в буфер
        _mode = 2;                   // Переходим на ввод команды
        //Serial.print(" xBuf.adr = ");
        //Serial.println(xBuf.adr, HEX);
        break;

      // Ввод команды  
      case 2:         
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        xBuf.cmd = _inChr;           // Записали команду в буфер
        _mode = 3;                   // Переходим на ввод регистра
        //Serial.print(" xBuf.cmd = ");
        //Serial.println(xBuf.cmd, HEX);
        break;

      // Ввод регистра  
      case 3:         
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        xBuf.reg = _inChr;           // Записали регистр в буфер
        _mode = 4;                   // Переходим на ввод команды
        p_b0 = &xBuf.b0;              // Получаем адрес xBuf.b0
        //Serial.print(" xBuf.reg = ");
        //Serial.println(xBuf.reg, HEX);
        break;

      // Ввод данных 4 байта  
      case 4:         
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        *(p_b0 - _count) = _inChr;    // Записываем байт по адресу xBuf.b0 скорректированному на номер байта
        _count++;                    // Переходим к следующему байту данных
        if (_count == 4) {           // Если 4 байта приняты (от 0 до 3)
          _mode = 5;                 // Переходим на ввод crc
          //Serial.print("b3 = ");
          //Serial.println(xBuf.b3, HEX);
          //Serial.print("b2 = ");
          //Serial.println(xBuf.b2, HEX);
          //Serial.print("b1 = ");
          //Serial.println(xBuf.b1, HEX);
          //Serial.print("b0 = ");
          //Serial.println(xBuf.b0, HEX);
        }
        //Serial.print("count = ");
        //Serial.println(count, HEX);
        break;

      // Ввод crc  
      case 5:         
        if (_crc == _inChr) {         // Сравниваем подсчитанную crc с указанной в inChr
          _mode = 0;                 // Сбрасываем режим
          //Serial.println(" crc - OK!");
          //Serial.println("OK");     // Успешное чтение пакета
                                    // Тут может быть вызов процедуры установки значений
                                    // или просто взведение флага готовности
                                    // или копирование буфера в выходные переменные
          (*func)();
        }
        else {                      // Контрольная сумма не совпала
          _mode = 0;                 // Сброс режима
          //Serial.println(" crc - FALSE!");
          //Serial.println("Err");
          (*func)();
        };
        break;
    } // switch ( mode )
    //Serial.print("crc = ");
    //Serial.println(crc, HEX);
    // Для отладки. Подсчте времени выполнения цикла.
    // Без отладочных вызовов Serial.print колеблется от 12 до 40 мкс
    // С отладочными Serial.print - время увеличивается до 800 мкс
    //t2 = micros();
    //Serial.print("  T = ");
    //Serial.println(t2-t1);
  } // if ( n > 0)
}   // Recv()



// **************************************************
//             ПЕРЕДАЧА
//
// Передача байта
void ProtocolBus4::sendLine(uint8_t adr, uint8_t reg, uint8_t value) {
   sendBuf[0] = adr;
   sendBuf[1] = CMD_WRITE8;
   sendBuf[2] = reg;
   sendBuf[3] = 0;
   sendBuf[4] = 0;
   sendBuf[5] = 0;
   sendBuf[6] = value;
   sendBuf[7] = adr ^ CMD_WRITE8 ^ reg ^ sendBuf[3] ^ sendBuf[4] ^ sendBuf[5] ^ sendBuf[6];
   sendPacket();
}

// Передача uint16_t
void ProtocolBus4::sendLine(uint8_t adr, uint8_t reg, uint16_t value) {
   sendBuf[0] = adr;
   sendBuf[1] = CMD_WRITE8;
   sendBuf[2] = reg;
   sendBuf[3] = 0;
   sendBuf[4] = 0;
   sendBuf[5] = (value & 0xff00) >> 8;
   sendBuf[6] = value & 0x00ff;
   sendBuf[7] = adr ^ CMD_WRITE8 ^ reg ^ sendBuf[3] ^ sendBuf[4] ^ sendBuf[5] ^ sendBuf[6];
   sendPacket();
}

// Передача uint32_t
void ProtocolBus4::sendLine(uint8_t adr, uint8_t reg, uint32_t value) {
   sendBuf[0] = adr;
   sendBuf[1] = CMD_WRITE32;
   sendBuf[2] = reg;
   sendBuf[3] = (value & 0xff000000) >> 24;
   sendBuf[4] = (value & 0x00ff0000) >> 16;                                                 
   sendBuf[5] = (value & 0x0000ff00) >> 8;                                                  
   sendBuf[6] =  value & 0x000000ff;
   sendBuf[7] = adr ^ CMD_WRITE8 ^ reg ^ sendBuf[3] ^ sendBuf[4] ^ sendBuf[5] ^ sendBuf[6];
   sendPacket();
}

void ProtocolBus4::sendPacket() {
  Serial.write((uint8_t*)(&_SIGN),4);
  for (int i=0; i < 8; i++) {
     Serial.write(sendBuf[i]);
  }
}

 

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

а это 

void ProtocolBus4::(*func)();

что должно означать?

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

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

ПС: так что скорее сейчас идет просто отработка кода.

Smith2007
Offline
Зарегистрирован: 30.10.2017

qwone пишет:

...И да что бы можно было добавлять в систему новые устройства, а в канал новые функции под новые варианты пакетов. 

ПС: так что скорее сейчас идет просто отработка кода.

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

 

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

Упрощеная схема такая.

const char *packet1 = "Packet1";
void DoPacket1() {
};
const char *packet2 = "Packet2";
void DoPacket2() {
};

Cl_channel channel;
void setup() {
  channel.init();
  channel.Add(/*пришел пакет такой*/packet1,/*выполнить это*/&DoPacket1);
  channel.Add(/*пришел пакет такой*/packet2,/*выполнить это*/&DoPacket2);
}

void loop() {
  channel.run();

}

 

Smith2007
Offline
Зарегистрирован: 30.10.2017

qwone пишет:

Упрощеная схема такая.

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

Smith2007
Offline
Зарегистрирован: 30.10.2017

Похоже, что в конструкторе нельзя в качестве параметра указывать ссылку на функцию.

Убрал этот параметр из конструткора и завел отдельную процедуру.

Все скомпилилось без ошибок и сразу заработало.

#include <Bus4.h>

ProtocolBus4 Bus4(0x33333333);

void setup() {
     Serial.begin(115200);
     Bus4.init(exec);
}

void loop() {
  Bus4.Recv();
}

void exec() {
  Serial.println("Ok");
}
// *********************************************************************
//        Протокол обмена
//	sendBuf[7], recvBuf[7] 
//	<Адрес><Команда><Регистр><D3><D2><D1><D0><CRC>
//        Адрес - Адрес устройства кому предназначен пакет. Если FF - всем
//	Команда-0xff - Передача ID устройства (ID в поле данных)
//		0x01 - Чтение uint8_t   D0
//		0x02 - Чтение uint16_t  D1, D0
//		0x03 - Чтение uint32_t  D3, D2, D1, D0
//		0x11 - Запись байта D0
//		0x12 - Запись uint8_t   D0
//		0x13 - Запись uint16_t  D1, D0
//		0x14 - Запись uint32_t  D3, D2, D1, D0
//                0xFA - Чтение переменных из EEPROM
//                0xFB - Запись переменных в EEPROM
//	Регистр - 00..FF - Адрес регистра
//	D0..D3 - данные
//	CRC - контрольная сумма
//
// =====================================================================
#ifndef Bus4_h
  #define Bus4_h

  #if defined(ARDUINO) && ARDUINO >= 100
    #include <Arduino.h>
  #else
    #include <WProgram.h>
  #endif

  // *******************************************************************
   
  //Command code
  #define CMD_READL	1
  #define CMD_READ8	2
  #define CMD_READ16	3
  #define CMD_READ32	4
  #define CMD_WRITEL	5
  #define CMD_WRITE8	6
  #define CMD_WRITE16	7
  #define CMD_WRITE32	8
  
  // Структура буфера приема
  struct xBuf_t {   // Структура буфера
    uint8_t adr;
    uint8_t cmd;
    uint8_t reg;
    uint8_t b3;
    uint8_t b2;
    uint8_t b1;
    uint8_t b0;
  };
  
  
  class ProtocolBus4 {
     public:
       // Кноструктор
       ProtocolBus4(uint32_t SIGN);
       void init(void (*f)() );
       void Recv(void);			// Процедура приема. 
       
       // передача данных
       void sendLine(uint8_t adr, uint8_t reg, uint8_t value);	// 
       void sendLine(uint8_t adr, uint8_t reg, uint16_t value);	// 
       void sendLine(uint8_t adr, uint8_t reg, uint32_t value);	// 
       void (*func)();

     private:
       uint32_t _SIGN; // = 0x33333333;  // Сигнатура начала пакета
       uint8_t _count;   // Счетчик байт данных (принимаем 4 байта данных)
       uint8_t _inChr;   // принятый байт
       uint32_t _sign;   // регистр сигнатуры с линии. Данные полученные с линии.
       uint8_t _crc;     // Подсчет CRC (XOR) с линии. Сигнатура не считается.
       uint8_t _mode;    // Режим. 
                        // 0 - ожидание сигнатуры, 1 - ожидание адреса, 
                        // 2 - ожидание команды, 3 - ожидание регистра, 
                        // 4 - ожидание данных, 5 - проверка crc Если crc верно - буфер готов
       
       xBuf_t xBuf;     // Буфер данных с линии
       uint8_t *p_b0;   // Указатель на xBuf.b0
       
       uint32_t _tStart; // = 0;  
       uint32_t _millisec; // = 0;
       uint32_t _timeOut; // = 10000;  // В реальной системе тайм аут следует снизить. Например 50 мс.
       
       // Следующие переменные для замера времени выполнения основного цикла, мкс
       //uint32_t t1;
       //uint32_t t2;
       
       uint8_t sendBuf[8]; // Буфер для отправки
       void sendPacket(void);
  };
#endif
#include <Bus4.h>

//*********************************************************************
//        Протокол обмена
//	sendBuf[7], recvBuf[7] 
//	<Адрес><Команда><Регистр><D3><D2><D1><D0><CRC>
//        Адрес - Адрес устройства кому предназначен пакет. Если FF - всем
//	Команда-0xff - Передача ID устройства (ID в поле данных)
//		0x01 - Чтение uint8_t   D0
//		0x02 - Чтение uint16_t  D1, D0
//		0x03 - Чтение uint32_t  D3, D2, D1, D0
//		0x11 - Запись байта D0
//		0x12 - Запись uint8_t   D0
//		0x13 - Запись uint16_t  D1, D0
//		0x14 - Запись uint32_t  D3, D2, D1, D0
//                0xFA - Чтение переменных из EEPROM
//                0xFB - Запись переменных в EEPROM
//	Регистр - 00..FF - Адрес регистра
//	D0..D3 - данные
//	CRC - контрольная сумма
//
//********************************************************************



// Конструктор
ProtocolBus4::ProtocolBus4(uint32_t SIGN)  {
  _SIGN = SIGN;
  _crc = 0;
  _mode = 0;    
  _tStart = 0; 
  _millisec = 0;
  _timeOut = 10000;
//  func = f;
}

void ProtocolBus4::init(void (*f)()  )  {
  func = f;
}

void (*func)();


void ProtocolBus4::Recv() {
// Обработка тайм-аута. Если на линии ничего нет более чем TIME_OUT - сбрасываем режим
  _millisec = millis();
  if ( (_millisec - _tStart) > _timeOut) {
    _mode = 0;    // Сброс режима
    _sign = 0;    // Сброс регистра сигнатуры
  }
  
  uint8_t n = Serial.available();
  // Если буфер приема не пустой
  if ( n > 0) {
    _tStart = _millisec;              // Время отсчета тайм-аута
    //t1 = micros();                  // Для отладки. Вычисление времени работы цикла
    _inChr = Serial.read();
    //Serial.print(" inChr = ");
    //Serial.println(inChr, HEX);
    //Serial.print(" n = ");
    //Serial.println(n);
    //Serial.print(" mode = ");
    //Serial.println(mode);

    switch ( _mode ) {
      // Режим 0. Проверка на сигнатуру
      case 0:                       
        _sign |= _inChr;              // Принятый с линии байт помещаем в младший байт 4-х байтовой переменной
        //Serial.print(" sign = ");
        //Serial.println(sign, HEX);
        if (_sign == _SIGN) {         // Если сигнатура с линии совпала с заданной
          _sign = 0;                 // Обнуляем сигнатуру для следующего пакета
          //Serial.println("SIGN - OK");
          _mode = 1;                 // Переходим на ввод адреса
          _crc = 0;                  // Очистили подсчет crc
          _count = 0;                // Обнулили счетчик байт данных. (4 байта)
        }
        else {
          _sign = _sign << 8;
          //Serial.println("SIGN - Filed");          
        }
        break;

      // Ввод адреса устройства  
      case 1:        
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        xBuf.adr = _inChr;           // записали адрес в буфер
        _mode = 2;                   // Переходим на ввод команды
        //Serial.print(" xBuf.adr = ");
        //Serial.println(xBuf.adr, HEX);
        break;

      // Ввод команды  
      case 2:         
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        xBuf.cmd = _inChr;           // Записали команду в буфер
        _mode = 3;                   // Переходим на ввод регистра
        //Serial.print(" xBuf.cmd = ");
        //Serial.println(xBuf.cmd, HEX);
        break;

      // Ввод регистра  
      case 3:         
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        xBuf.reg = _inChr;           // Записали регистр в буфер
        _mode = 4;                   // Переходим на ввод команды
        p_b0 = &xBuf.b0;              // Получаем адрес xBuf.b0
        //Serial.print(" xBuf.reg = ");
        //Serial.println(xBuf.reg, HEX);
        break;

      // Ввод данных 4 байта  
      case 4:         
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        *(p_b0 - _count) = _inChr;    // Записываем байт по адресу xBuf.b0 скорректированному на номер байта
        _count++;                    // Переходим к следующему байту данных
        if (_count == 4) {           // Если 4 байта приняты (от 0 до 3)
          _mode = 5;                 // Переходим на ввод crc
          //Serial.print("b3 = ");
          //Serial.println(xBuf.b3, HEX);
          //Serial.print("b2 = ");
          //Serial.println(xBuf.b2, HEX);
          //Serial.print("b1 = ");
          //Serial.println(xBuf.b1, HEX);
          //Serial.print("b0 = ");
          //Serial.println(xBuf.b0, HEX);
        }
        //Serial.print("count = ");
        //Serial.println(count, HEX);
        break;

      // Ввод crc  
      case 5:         
        if (_crc == _inChr) {         // Сравниваем подсчитанную crc с указанной в inChr
          _mode = 0;                 // Сбрасываем режим
          //Serial.println(" crc - OK!");
          //Serial.println("OK");     // Успешное чтение пакета
                                    // Тут может быть вызов процедуры установки значений
                                    // или просто взведение флага готовности
                                    // или копирование буфера в выходные переменные
          (*func)();
        }
        else {                      // Контрольная сумма не совпала
          _mode = 0;                 // Сброс режима
          //Serial.println(" crc - FALSE!");
          //Serial.println("Err");
          (*func)();
        };
        break;
    } // switch ( mode )
    //Serial.print("crc = ");
    //Serial.println(crc, HEX);
    // Для отладки. Подсчте времени выполнения цикла.
    // Без отладочных вызовов Serial.print колеблется от 12 до 40 мкс
    // С отладочными Serial.print - время увеличивается до 800 мкс
    //t2 = micros();
    //Serial.print("  T = ");
    //Serial.println(t2-t1);
  } // if ( n > 0)
}   // Recv()



// **************************************************
//             ПЕРЕДАЧА
//
// Передача байта
void ProtocolBus4::sendLine(uint8_t adr, uint8_t reg, uint8_t value) {
   sendBuf[0] = adr;
   sendBuf[1] = CMD_WRITE8;
   sendBuf[2] = reg;
   sendBuf[3] = 0;
   sendBuf[4] = 0;
   sendBuf[5] = 0;
   sendBuf[6] = value;
   sendBuf[7] = adr ^ CMD_WRITE8 ^ reg ^ sendBuf[3] ^ sendBuf[4] ^ sendBuf[5] ^ sendBuf[6];
   sendPacket();
}

// Передача uint16_t
void ProtocolBus4::sendLine(uint8_t adr, uint8_t reg, uint16_t value) {
   sendBuf[0] = adr;
   sendBuf[1] = CMD_WRITE8;
   sendBuf[2] = reg;
   sendBuf[3] = 0;
   sendBuf[4] = 0;
   sendBuf[5] = (value & 0xff00) >> 8;
   sendBuf[6] = value & 0x00ff;
   sendBuf[7] = adr ^ CMD_WRITE8 ^ reg ^ sendBuf[3] ^ sendBuf[4] ^ sendBuf[5] ^ sendBuf[6];
   sendPacket();
}

// Передача uint32_t
void ProtocolBus4::sendLine(uint8_t adr, uint8_t reg, uint32_t value) {
   sendBuf[0] = adr;
   sendBuf[1] = CMD_WRITE32;
   sendBuf[2] = reg;
   sendBuf[3] = (value & 0xff000000) >> 24;
   sendBuf[4] = (value & 0x00ff0000) >> 16;                                                 
   sendBuf[5] = (value & 0x0000ff00) >> 8;                                                  
   sendBuf[6] =  value & 0x000000ff;
   sendBuf[7] = adr ^ CMD_WRITE8 ^ reg ^ sendBuf[3] ^ sendBuf[4] ^ sendBuf[5] ^ sendBuf[6];
   sendPacket();
}

void ProtocolBus4::sendPacket() {
  Serial.write((uint8_t*)(&_SIGN),4);
  for (int i=0; i < 8; i++) {
     Serial.write(sendBuf[i]);
  }
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
unsigned long mill;
//---------------------
// класс канал
struct packet_t {
  byte adr;
  byte commamd;
  int param1;
}

//-----------компoновка--------------------------
Cl_Led Led(/*пин*/13);// <-устройство с адр 5

packet_t packet1 = {/*адрес*/5,/*команда*/1,/*параметр*/0};//<-  параметр param1 не важен
void DoPacket1() {
  Led.ON();
};
packet_t packet2 = {/*адрес*/5,/*команда*/2,/*параметр*/0};//<-   параметр param1 не важен
void DoPacket2() {
  Led.OFF();
};
packet_t packet2 = {/*адрес*/5,/*команда*/3,/*параметр*/0};//<-   параметр param1 передает частоту мигания
void DoPacket3(int var) {
  Led.blink(var);
};
Cl_channel channel(/*параметры установки канала*/);
void setup() {
  Led.init();
  channel.init();
  channel.Add(/*пришел пакет такой*/packet1,/*выполнить это*/&DoPacket1);
  channel.Add(/*пришел пакет такой*/packet2,/*выполнить это*/&DoPacket2);
  channel.Add(/*пришел пакет такой*/packet3,/*выполнить это*/&DoPacket3);
}

void loop() {
  mill = millis();
  Led.run();
  channel.run();
}
/**/

 

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

Smith2007 пишет:

Похоже, что в конструкторе нельзя в качестве параметра указывать ссылку на функцию.

Почему? #4

Smith2007
Offline
Зарегистрирован: 30.10.2017

В таком случае отпадает необходимость в явном описании конструктора. Я думал все начальные параметры в нем устанавливать. А раз имеются ограничения, то конструктор можно опустить (не указывать явно), а всю инициализацию провести в процедуре init.

Теперь осталось разобраться как передавать параметры в

exec(параметры);

Smith2007
Offline
Зарегистрирован: 30.10.2017

qwone пишет:

Smith2007 пишет:

Похоже, что в конструкторе нельзя в качестве параметра указывать ссылку на функцию.

Почему? #4

Хм..... Почему же появляется ошибка при компиляции?

Покажите фрагмент .cpp

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

Smith2007 пишет:
Покажите фрагмент .cpp
(Удивление) Здесь все для нормальной работы

/* Пример 2.0
  Кнопка пин 1 <-> Ардуино пин 2
         пин 2 <-> Ардуино GND
         принцип кода : нажатие на кнопку отсылает в Serial что кнопку нажали
*/
//---------------классы---------
//класс кнопка подключ на землю с программной подтяжкой
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (* Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // конструктор класса
    Cl_Btn( byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {}
    // метод setup()
    void setup() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // метод loop()
    void loop() {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do();
      }
    }
};
//--------------компоновка------------
void Do_Btn1() {
  Serial.println("Btn1 press");
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/&Do_Btn1);
//------------main()--------------
void setup() {
  Serial.begin(9600);
  Btn1.setup();
}
void loop() {
  Btn1.loop();
}

 

Smith2007
Offline
Зарегистрирован: 30.10.2017

Не могу понять вот эту строку. Что такое ":"  ?

    Cl_Btn( byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {}

В конструктор передаете 2 значения byte _pin и ссылку на функцию (* _Do)()

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

Прочитайте про конструкторы https://msdn.microsoft.com/ru-ru/library/s16xw1a8.aspx#default_constructors

А если надо писать ответ мастеру по посылке код станет таким 

/**/
unsigned long mill;
//---------------------
// класс канал
// структура пакета-команды
struct packet_t {
  unsigned int ind;// уникальный индификатор пакета
  byte adr;        // адресс устройства получателя
  byte commamd;    // команда устройству получателю
  int param1;      // параметр команды
}
// структура пакета-ответа
struct packetOut_t {
  unsigned int ind;// уникальный индификатор пакета
  byte adr;        // адресс устройства получателя
  byte stat;       // 0 - OК / 1 - ошибка
}
//-----------компoновка--------------------------
Cl_channel channel(/*параметры установки канала*/);

Cl_Led Led(/*пин*/13);// <-устройство с адр 5

packet_t packet1 = {/*индетуфикатор*/0,/*адрес*/5,/*команда*/1,/*параметр*/0};//<-  параметр param1 не важен
void DoPacket1(/**/ind) {
  Led.ON();
  packetOut_t packet(/*индетуфикатор*/ind,/*адрес*/0);//<- отправить ответ OK мастеру
  channel.tansferOut(packet);
};
packet_t packet2 = {/*индетификатор*/0,/*адрес*/5,/*команда*/2,/*параметр*/0};//<-   параметр param1 не важен
void DoPacket2(/*индетификатор*/ind) {
  Led.OFF();
  packetOut_t packet(/*индетификатор*/ind,/*адрес*/0);//<- отправить ответ OK мастеру
  channel.tansferOut(packet);
};
packet_t packet2 = {/*индетефикатор*/0,/*адрес*/5,/*команда*/3,/*параметр*/0};//<-   параметр param1 передает частоту мигания
void DoPacket3(int var,/*индетификатор*/ind) {
  Led.blink(var);
  packetOut_t packet(/*индетификатор*/ind,/*адрес*/0);//<- отправить ответ OK мастеру
  channel.tansferOut(packet);
};

void setup() {
  Led.init();
  channel.init();
  channel.Add(/*пришел пакет такой*/packet1,/*выполнить это*/&DoPacket1);
  channel.Add(/*пришел пакет такой*/packet2,/*выполнить это*/&DoPacket2);
  channel.Add(/*пришел пакет такой*/packet3,/*выполнить это*/&DoPacket3);
}

void loop() {
  mill = millis();
  Led.run();
  channel.run();
}
/**/

 

Smith2007
Offline
Зарегистрирован: 30.10.2017

Остатки мозга вскипели :)

/* Этот конструктор выдает ошибку компиляции
ProtocolBus4::ProtocolBus4(uint32_t SIGN, void (* f)() )  {
  _SIGN = SIGN;
  _crc = 0;
  _mode = 0;    
  _tStart = 0; 
  _millisec = 0;
  _timeOut = 10000;
  func = f;
}
*/

удаляю описание конструктора и завожу функцию init - работает
void ProtocolBus4::init(uint32_t SIGN, void (* f)() )  {
  _SIGN = SIGN;
  _crc = 0;
  _mode = 0;    
  _tStart = 0; 
  _millisec = 0;
  _timeOut = 10000;
  func = f;
}

Соответственно в h файле так же поправки вношу. Особенность объявления конструктора с передачей имени функции не смог понять :(

Может быть проблема в разнице компилятора или версии arduino IDE?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
ProtocolBus4::ProtocolBus4(uint32_t SIGN, void (* f)() )
: _SIGN(SIGN),_crc(0),_mode(0),_tStart(0),_millisec(0),_timeOut(10000),func(f){}

 

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

Smith2007 пишет:

 void ProtocolBus4::(*func)();

Раньше такого боеда не было. Зачем Вы это добавили

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

Я это спрашивал в #109. Нет ответа

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

Smith2007 пишет:

Может быть проблема в разнице компилятора или версии arduino IDE?

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

Хотите нормально нормально работать - прекратите это

Smith2007
Offline
Зарегистрирован: 30.10.2017

qwone пишет:

ProtocolBus4::ProtocolBus4(uint32_t SIGN, void (* f)() )
: _SIGN(SIGN),_crc(0),_mode(0),_tStart(0),_millisec(0),_timeOut(10000),func(f){}

 

Перебрал все варианты :(

Ошибки при компиляции

Оставил только один параметр - передача функции

header

  class Channel {
     public:
       // Кноструктор
       Channel( (* f)() ) : func(f) {} ;
//       void init(uint32_t SIGN, void (* f)() );
       void (* func)();
       void run(void);			// Процедура приема. 

cpp

Channel::Channel(void (* f)() ) {
//  _SIGN = SIGN;
//  _crc = 0;
//  _mode = 0;    
//  _tStart = 0; 
//  _millisec = 0;
//  _timeOut = 10000;
//  func = f;
}

Подскажите пожалуйста, где я туплю?


Arduino: 1.8.5 (Windows 7), Плата:"Arduino Leonardo"

In file included from D:\Project\Arduino\sign\sign.ino:1:0:

C:\Program Files (x86)\Arduino\libraries\Bus4/Bus4.h:72:25: error: function definition does not declare parameters

        Channel( (* f)() ) : func(f) {} ;

                         ^

sign:3: error: 'exec' was not declared in this scope

 Channel Bus4(exec);

              ^

exit status 1
'exec' was not declared in this scope

 

Smith2007
Offline
Зарегистрирован: 30.10.2017

DetSimen пишет:

а это 

void ProtocolBus4::(*func)();

что должно означать?

Это была опечатка. 

Smith2007
Offline
Зарегистрирован: 30.10.2017

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

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

Хотите нормально нормально работать - прекратите это

Смотрю примеры, пробую. Но не доходит как правильно записать конструктор. 

Это вообще в ступор ввело :)

ProtocolBus4::ProtocolBus4(uint32_t SIGN, void (* f)() )
: _SIGN(SIGN),_crc(0),_mode(0),_tStart(0),_millisec(0),_timeOut(10000),func(f){}

_crc - это же не функция, а переменная и другие...

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

Сравните вашу строку Channel( (* f)() ) : func(f) {} ;

и правильную  Channel(void (* f)() ) : func(f) {} ;

ПС:

/**/
unsigned long mill; // переменная под millis()
//--------------------------------
class Cl_Channel {
  protected:
    void (* func)();
  public:
    /*констуктор*/
    Cl_Channel(void (* f)() ) : func(f) {} ;
    /*инициализация */
    void init() {};
    /*работа*/
    void run() {};    // Процедура приема.
};
//---Компоновка-----------------------------
void DoChannel() {};
Cl_Channel Channel(/**/&DoChannel);

//---main-----------------------------
void setup() {
  Channel.init();
}

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

Пройдитесь по мой теме. Там вроде понятно , но лучше в личную своими пальцами эти скетчи пройти. Мускулы C++ подкачать.

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

Smith2007 пишет:
Это вообще в ступор ввело :)

А это

/**/
class Cl_AAA {
    int val;
  public:
    Cl_AAA(int val_): val(val_) {}
};
class Cl_BBB {
    int val;
    Cl_AAA AAA;
  public:
    Cl_BBB(int val_, int val2_): val(val_), AAA(val2_) {} //AAA(val2_) <---обратите на это
};
//------------------------
Cl_BBB Cl_BBB(1, 2);
//----main----------------------
void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}
/* использует 502 байт (1%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 13 байт (0%) динамической памяти, оставляя 2035 байт для локальных переменных. Максимум: 2048 байт.
*/

Причем весь мой код это полный примитивизм в Си++

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

У Вас проблема не в конструкторе, а в том, что Вы не везде неверно записываете тип "указатель на функцию".

До тех пор, пока Вы не привыкли, определяёте этот тип с помощью typedef и не таскайте за собой этот громоздкий синтаксис, а просто пишите одним словом.

Вот смотрите, вот вся Ваша задача

// Определение типа - указатель на функцияю void f(void)
// название типа - SuperFunction
typedef void (* SuperFunction)(void); 

// Класс, конструтор которого принимает SuperFunction
class Kaka {
	SuperFunction m_fPtr; // Сввойство для хранения SuperFunction
	int m_k;
public:
	Kaka(int n, SuperFunction f) {
		m_k = n;
		m_fPtr = f; // Присваивание свойству
	}
	void doSomething(void) {
		m_fPtr(); // Вызов по сохранённому указателю
	}
};

void exec(void) {}

Kaka instance(3, exec); // Сохздание экземпляра

И всего делов-то!

Создаётся экземпляр. указатель передаётся конструктору - всё как у людей.

------------------

Но ещё раз провторюсь, если Вам пришлось классу передавать указательна функцию, значит класс плохо спроектирован.

Smith2007
Offline
Зарегистрирован: 30.10.2017

Невнимательность

Channel(void (* f)() ) : func(f) {} ;

Скетч

#include <Bus4.h>

Channel Bus4(exec);

void setup() {
     Serial.begin(115200);
     //Bus4.init(0x33333333, exec);
}

void loop() {
  Bus4.run();
}

void exec() {
  Serial.print("Cmd = OK");
}
#ifndef Bus4_h
  #define Bus4_h

  #if defined(ARDUINO) && ARDUINO >= 100
    #include <Arduino.h>
  #else
    #include <WProgram.h>
  #endif

  // *******************************************************************
   
  //Command code
  #define CMD_READL	1
  #define CMD_READ8	2
  #define CMD_READ16	3
  #define CMD_READ32	4
  #define CMD_WRITEL	5
  #define CMD_WRITE8	6
  #define CMD_WRITE16	7
  #define CMD_WRITE32	8
  
  // Структура буфера приема
  struct packetIn_t {   // Структура принятого пакета
    uint8_t adr;
    uint8_t cmd;
    uint8_t reg;
    uint8_t b0;
    uint8_t b1;
    uint8_t b2;
    uint8_t b3;
  };

  struct packetOut_t {   // Структура передаваемого пакета
    uint8_t adr;
    uint8_t cmd;
    uint8_t reg;
    uint8_t b0;
    uint8_t b1;
    uint8_t b2;
    uint8_t b3;
    uint8_t crc;
  };
  
  
  class Channel {
     public:
       // Кноструктор
       Channel(void (* f)() ) : func(f) {} ;
//       void init(uint32_t SIGN, void (* f)() );
       void (* func)();
       void run(void);			// Процедура приема. 
       packetIn_t  packetIn;      // Принятый пакет с линии
       packetOut_t packetOut;     // Пакет для отправки
       // передача данных
       void sendLine(uint8_t adr, uint8_t reg, uint8_t value);	// 
       void sendLine(uint8_t adr, uint8_t reg, uint16_t value);	// 
       void sendLine(uint8_t adr, uint8_t reg, uint32_t value);	// 
       void sendLine(void);

     private:
       uint32_t _SIGN;            // = 0x33333333;  // Сигнатура начала пакета
       uint8_t _count;            // Счетчик байт данных (принимаем 4 байта данных)
       uint8_t _inChr;            // принятый байт
       uint32_t _sign;            // регистр сигнатуры с линии. Данные полученные с линии.
       uint8_t _crc;              // Подсчет CRC (XOR) с линии. Сигнатура не считается.
       uint8_t _mode;             // Режим. 
                                  // 0 - ожидание сигнатуры, 1 - ожидание адреса, 
                                  // 2 - ожидание команды, 3 - ожидание регистра, 
                                  // 4 - ожидание данных, 5 - проверка crc Если crc верно - буфер готов
       uint8_t *ptrX;             // Указатель
       
       uint32_t _tStart;          // = 0;  
       uint32_t _millisec;        // = 0;
       uint32_t _timeOut;         // = 10000;  // В реальной системе тайм аут следует снизить. Например 50 мс.
       
       // Следующие переменные для замера времени выполнения основного цикла, мкс
       //uint32_t t1;
       //uint32_t t2;
       void sendPacket(void);
  };
#endif

cpp

#include <Bus4.h>

// Конструктор

Channel::Channel(void (* f)() ) { }

/*
void Channel::init(uint32_t SIGN, void (* f)() )  {
  _SIGN = SIGN;
  _crc = 0;
  _mode = 0;    
  _tStart = 0; 
  _millisec = 0;
  _timeOut = 10000;
  func = f;
}
*/
void (* func)();


void Channel::run() {
// Обработка тайм-аута. Если на линии ничего нет более чем TIME_OUT - сбрасываем режим
  _millisec = millis();
  if ( (_millisec - _tStart) > _timeOut) {
    _mode = 0;    // Сброс режима
    _sign = 0;    // Сброс регистра сигнатуры
  }
  
  uint8_t n = Serial.available();
  // Если буфер приема не пустой
  if ( n > 0) {
    _tStart = _millisec;              // Время отсчета тайм-аута
    //t1 = micros();                  // Для отладки. Вычисление времени работы цикла
    _inChr = Serial.read();
    //Serial.print(" inChr = ");
    //Serial.println(inChr, HEX);
    //Serial.print(" n = ");
    //Serial.println(n);
    //Serial.print(" mode = ");
    //Serial.println(mode);

    switch ( _mode ) {
      // Режим 0. Проверка на сигнатуру
      case 0:                       
        _sign |= _inChr;              // Принятый с линии байт помещаем в младший байт 4-х байтовой переменной
        //Serial.print(" sign = ");
        //Serial.println(sign, HEX);
        if (_sign == _SIGN) {         // Если сигнатура с линии совпала с заданной
          _sign = 0;                 // Обнуляем сигнатуру для следующего пакета
          //Serial.println("SIGN - OK");
          _mode = 1;                 // Переходим на ввод адреса
          _crc = 0;                  // Очистили подсчет crc
          _count = 0;                // Обнулили счетчик байт данных. (4 байта)
        }
        else {
          _sign = _sign << 8;
          //Serial.println("SIGN - Filed");          
        }
        break;

      // Ввод адреса устройства  
      case 1:        
        _crc ^= _inChr;              // Считаем контрольную сумму XOR
        packetIn.adr = _inChr;      // записали адрес в буфер
        _mode = 2;                   // Переходим на ввод команды
        //Serial.print(" xBuf.adr = ");
        //Serial.println(xBuf.adr, HEX);
        break;

      // Ввод команды  
      case 2:         
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        packetIn.cmd = _inChr;       // Записали команду в буфер
        _mode = 3;                    // Переходим на ввод регистра
        //Serial.print(" xBuf.cmd = ");
        //Serial.println(xBuf.cmd, HEX);
        break;

      // Ввод регистра  
      case 3:         
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        packetIn.reg = _inChr;       // Записали регистр в буфер
        _mode = 4;                    // Переходим на ввод команды
        ptrX = &packetIn.b0;         // Получаем адрес xBuf.b0
        //Serial.print(" xBuf.reg = ");
        //Serial.println(xBuf.reg, HEX);
        break;

      // Ввод данных 4 байта  
      case 4:         
        _crc ^= _inChr;               // Считаем контрольную сумму XOR
        *(ptrX + _count) = _inChr;    // Записываем байт по адресу xBuf.b0 скорректированному на номер байта
        _count++;                     // Переходим к следующему байту данных
        if (_count == 4) {            // Если 4 байта приняты (от 0 до 3)
          _mode = 5;                  // Переходим на ввод crc
          //Serial.print("b3 = ");
          //Serial.println(xBuf.b3, HEX);
          //Serial.print("b2 = ");
          //Serial.println(xBuf.b2, HEX);
          //Serial.print("b1 = ");
          //Serial.println(xBuf.b1, HEX);
          //Serial.print("b0 = ");
          //Serial.println(xBuf.b0, HEX);
        }
        //Serial.print("count = ");
        //Serial.println(count, HEX);
        break;

      // Ввод crc  
      case 5:         
        if (_crc == _inChr) {         // Сравниваем подсчитанную crc с указанной в inChr
          _mode = 0;                 // Сбрасываем режим
          //Serial.println(" crc - OK!");
          //Serial.println("OK");     // Успешное чтение пакета
                                    // Тут может быть вызов процедуры установки значений
                                    // или просто взведение флага готовности
                                    // или копирование буфера в выходные переменные
          (*func)();
        }
        else {                      // Контрольная сумма не совпала
          _mode = 0;                 // Сброс режима
          //Serial.println(" crc - FALSE!");
          //Serial.println("Err");
          (*func)();
        };
        break;
    } // switch ( mode )
    //Serial.print("crc = ");
    //Serial.println(crc, HEX);
    // Для отладки. Подсчте времени выполнения цикла.
    // Без отладочных вызовов Serial.print колеблется от 12 до 40 мкс
    // С отладочными Serial.print - время увеличивается до 800 мкс
    //t2 = micros();
    //Serial.print("  T = ");
    //Serial.println(t2-t1);
  } // if ( n > 0)
}   // Recv()



// **************************************************
//             ПЕРЕДАЧА
//
// Передача байта
void Channel::sendLine(uint8_t adr, uint8_t reg, uint8_t value) {
   packetOut.adr = adr;
   packetOut.cmd = CMD_WRITE8;
   packetOut.reg = reg;
   packetOut.b0 = value;
   packetOut.b1 = 0;
   packetOut.b2 = 0;
   packetOut.b3 = 0;
   packetOut.crc = adr ^ CMD_WRITE8 ^ reg ^ packetOut.b0 ^ packetOut.b1 ^ packetOut.b2 ^ packetOut.b3;
   sendPacket();
}

// Передача uint16_t
void Channel::sendLine(uint8_t adr, uint8_t reg, uint16_t value) {
   packetOut.adr = adr;
   packetOut.cmd = CMD_WRITE8;
   packetOut.reg = reg;
   packetOut.b0 = value & 0x00ff;
   packetOut.b1 = (value & 0xff00) >> 8;
   packetOut.b2 = 0;
   packetOut.b3 = 0;
   packetOut.crc = adr ^ CMD_WRITE8 ^ reg ^ packetOut.b0 ^ packetOut.b1 ^ packetOut.b2 ^ packetOut.b3;
   sendPacket();
}

// Передача uint32_t
void Channel::sendLine(uint8_t adr, uint8_t reg, uint32_t value) {
   packetOut.adr = adr;
   packetOut.cmd = CMD_WRITE8;
   packetOut.reg = reg;
   packetOut.b0 = value & 0x000000ff;
   packetOut.b1 = (value & 0x0000ff00) >> 8;
   packetOut.b2 = (value & 0x00ff0000) >> 16;
   packetOut.b3 = (value & 0xff000000) >> 24;
   packetOut.crc = adr ^ CMD_WRITE8 ^ reg ^ packetOut.b0 ^ packetOut.b1 ^ packetOut.b2 ^ packetOut.b3;
   sendPacket();
}

void Channel::sendLine() {
   sendPacket();
}

void Channel::sendPacket() {
  Serial.write((uint8_t*)(&_SIGN),4);
  Serial.write((uint8_t *)(&packetOut), 8);
}

Ошибка компиляции

Arduino: 1.8.5 (Windows 7), Плата:"Arduino Leonardo"

sign:3: error: 'exec' was not declared in this scope

 Channel Bus4(exec);

              ^

exit status 1
'exec' was not declared in this scope

 

Smith2007
Offline
Зарегистрирован: 30.10.2017

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

У Вас проблема не в конструкторе, а в том, что Вы не везде неверно записываете тип "указатель на функцию".

До тех пор, пока Вы не привыкли, определяёте этот тип с помощью typedef и не таскайте за собой этот громоздкий синтаксис, а просто пишите одним словом.

Вот смотрите, вот вся Ваша задача

// Определение типа - указатель на функцияю void f(void)
// название типа - SuperFunction
typedef void (* SuperFunction)(void); 

// Класс, конструтор которого принимает SuperFunction
class Kaka {
	SuperFunction m_fPtr; // Сввойство для хранения SuperFunction
	int m_k;
public:
	Kaka(int n, SuperFunction f) {
		m_k = n;
		m_fPtr = f; // Присваивание свойству
	}
	void doSomething(void) {
		m_fPtr(); // Вызов по сохранённому указателю
	}
};

void exec(void) {}

Kaka instance(3, exec); // Сохздание экземпляра

И всего делов-то!

Создаётся экземпляр. указатель передаётся конструктору - всё как у людей.

------------------

Но ещё раз провторюсь, если Вам пришлось классу передавать указательна функцию, значит класс плохо спроектирован.

Вот теперь мне стал понятен код. Спасибо.

Буду пробовать

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

Разбирайтесь

Smith2007
Offline
Зарегистрирован: 30.10.2017

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

Разбирайтесь

Я описал почти в точности Ваш пример

Но ошибка компиляции не исчезла. 

Я описал это .h файле. Это верно?

#ifndef Bus4_h
  #define Bus4_h

  #if defined(ARDUINO) && ARDUINO >= 100
    #include <Arduino.h>
  #else
    #include <WProgram.h>
  #endif
   
  //Command code
  #define CMD_READL	1
  #define CMD_READ8	2
  #define CMD_READ16	3
  #define CMD_READ32	4
  #define CMD_WRITEL	5
  #define CMD_WRITE8	6
  #define CMD_WRITE16	7
  #define CMD_WRITE32	8
  
  // Структура буфера приема
  struct packetIn_t {   // Структура принятого пакета
    uint8_t adr;
    uint8_t cmd;
    uint8_t reg;
    uint8_t b0;
    uint8_t b1;
    uint8_t b2;
    uint8_t b3;
  };

  struct packetOut_t {   // Структура передаваемого пакета
    uint8_t adr;
    uint8_t cmd;
    uint8_t reg;
    uint8_t b0;
    uint8_t b1;
    uint8_t b2;
    uint8_t b3;
    uint8_t crc;
  };


  // Определение типа - указатель на функцияю void f(void)
  // название типа - SuperFunction
  typedef void (* SuperFunction)(void);

  // Класс, конструтор которого принимает SuperFunction
  class Channel {
       SuperFunction m_fPtr; // Сввойство для хранения SuperFunction
     public:
       // Кноструктор
       Channel(SuperFunction f) {
          m_fPtr = f;
       } 
	void doSomething(void) {
		m_fPtr(); // Вызов по сохранённому указателю
	}
//       void init(uint32_t SIGN, void (* f)() );
//       void (* func)();
       void run(void);			// Процедура приема. 
       packetIn_t  packetIn;      // Принятый пакет с линии
       packetOut_t packetOut;     // Пакет для отправки
       // передача данных
       void sendLine(uint8_t adr, uint8_t reg, uint8_t value);	// 
       void sendLine(uint8_t adr, uint8_t reg, uint16_t value);	// 
       void sendLine(uint8_t adr, uint8_t reg, uint32_t value);	// 
       void sendLine(void);

     private:
       uint32_t _SIGN;            // = 0x33333333;  // Сигнатура начала пакета
       uint8_t _count;            // Счетчик байт данных (принимаем 4 байта данных)
       uint8_t _inChr;            // принятый байт
       uint32_t _sign;            // регистр сигнатуры с линии. Данные полученные с линии.
       uint8_t _crc;              // Подсчет CRC (XOR) с линии. Сигнатура не считается.
       uint8_t _mode;             // Режим. 
                                  // 0 - ожидание сигнатуры, 1 - ожидание адреса, 
                                  // 2 - ожидание команды, 3 - ожидание регистра, 
                                  // 4 - ожидание данных, 5 - проверка crc Если crc верно - буфер готов
       uint8_t *ptrX;             // Указатель
       
       uint32_t _tStart;          // = 0;  
       uint32_t _millisec;        // = 0;
       uint32_t _timeOut;         // = 10000;  // В реальной системе тайм аут следует снизить. Например 50 мс.
       
       // Следующие переменные для замера времени выполнения основного цикла, мкс
       //uint32_t t1;
       //uint32_t t2;
       void sendPacket(void);
  }; // Channel class
#endif

В cpp оставил


// Конструктор

Channel::Channel(SuperFunction f) { }

Скетч

#include <Bus4.h>

void exec() {
  Serial.print("Cmd = OK");
}

Channel Bus4(exec);

void setup() {
     Serial.begin(115200);
     //Bus4.init(0x33333333, exec);
}

void loop() {
  Bus4.run();
}

Ошибка

Arduino: 1.8.5 (Windows 7), Плата:"Arduino Leonardo"

C:\Program Files (x86)\Arduino\libraries\Bus4\Bus4.cpp:32:1: error: redefinition of 'Channel::Channel(SuperFunction)'

 Channel::Channel(SuperFunction f) { }

 ^

In file included from C:\Program Files (x86)\Arduino\libraries\Bus4\Bus4.cpp:1:0:

C:\Program Files (x86)\Arduino\libraries\Bus4/Bus4.h:78:8: note: 'Channel::Channel(SuperFunction)' previously defined here

        Channel(SuperFunction f) {

        ^

exit status 1
Ошибка компиляции для платы Arduino Leonardo.

Мой опыт в программировании на Си чуть больше недели :(

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

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

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

Например:

void cat(void) {
	Serial.begin(115200);
	Serial.println("Op-pa! I am working!");
}

void setup(void) {
	// Объявление указателя "по образцу". 
	// Компилятор сам разберётся что там за cat и какой у неё тип
	auto f = cat;	
	//
	f(); // Выоз функции по указателю
}

void loop(void) {}

Можете запустить, всё работает.

Smith2007
Offline
Зарегистрирован: 30.10.2017

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

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

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

Например:

void cat(void) {
	Serial.begin(115200);
	Serial.println("Op-pa! I am working!");
}

void setup(void) {
	// Объявление указателя "по образцу". 
	// Компилятор сам разберётся что там за cat и какой у неё тип
	auto f = cat;	
	//
	f(); // Выоз функции по указателю
}

void loop(void) {}

Можете запустить, всё работает.

 

Компилируется без ошибок. Но в терминале пусто. Я обратил внимание, что Serial.print выводит информацию только в loop()

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

Вы прочитали что Вам написал компилятор?

Он написал, что конструктор Channel::Channel(SuperFunction f) определён дважды.

Зачем Вы сначала определили его в h файле (строки 52-54), а птом ещё и в .cpp файле?

Определяйте в одном месте. Хотите - целиком в .h, но тогда в cpp он вообще не нужен. Хотите в cpp - пожалуйста, тода в h вместо строк 52-52 напишите только заголовок

Channel(SuperFunction f);

а в .сpp файле первой строкой конструктора вставьте 

m_fPtr = f;

а дальше - что Вам надо. Т.е. там в cpp будет

Channel::Channel(SuperFunction f) {
   m_fPtr = f;
   // ..... la-la-la
}

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

Smith2007 пишет:

Компилируется без ошибок. Но в терминале пусто. 

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

Smith2007 пишет:

Я обратил внимание, что Serial.print выводит информацию только в loop()

Сейчас Вы сказали бред. Больше так не говорите - будут смеяться и троллить. Он выводит независимо от того где его вызывают. Как говорилось с старом анекдоте: "У нас тут всё по-простому, где поймают, там и прут".

 

Smith2007
Offline
Зарегистрирован: 30.10.2017

Вот так работает.

Видимо встроенный терминал не успевает включиться

void cat(void) {
  Serial.println("Op-pa! I am working!");
}

void setup(void) {
  Serial.begin(9600);
  delay(2000);
  // Объявление указателя "по образцу". 
  // Компилятор сам разберётся что там за cat и какой у неё тип
  auto f = cat; 
  //
  f(); // Выоз функции по указателю
}

void loop(void) {}

 

Smith2007
Offline
Зарегистрирован: 30.10.2017

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

Вы прочитали что Вам написал компилятор?

Он написал, что конструктор Channel::Channel(SuperFunction f) определён дважды.

Зачем Вы сначала определили его в h файле (строки 52-54), а птом ещё и в .cpp файле?

Определяйте в одном месте. Хотите - целиком в .h, но тогда в cpp он вообще не нужен. Хотите в cpp - пожалуйста, тода в h вместо строк 52-52 напишите только заголовок

Channel(SuperFunction f);

а в .сpp файле первой строкой конструктора вставьте 

m_fPtr = f;

а дальше - что Вам надо. Т.е. там в cpp будет

Channel::Channel(SuperFunction f) {
   m_fPtr = f;
   // ..... la-la-la
}

Скомпилилось без ошибок.

Теперь там где мне необходимо вызвать exec (указатель на нее ссылается) я просто пишу m_fPtr(); ?

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

Если внутри класса, то да. Если через экземпляр, то instancename.m_fPtr()

Smith2007
Offline
Зарегистрирован: 30.10.2017

С этим вроде более понятно стало. Нужно еще несколько примеров сделать для закрепления материала. Можно ли в такую функцию m_fPtr() (она же exec)

передавать параметры? Например ссылку на структуру или массив? И как это будет указываться в конструкторе?

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

Ну, в такую - нет, Вы же при описании титпа её без параметров описали. Опишите с параметрами - будет можно.

(в примере с auto - можно всё)

Smith2007
Offline
Зарегистрирован: 30.10.2017
#include <Bus4.h>
#define SIGN 0x33333333
#define TIME_OUT 5000
void exec(uint8_t i1);
Channel Bus4(SIGN, TIME_OUT, exec);
void exec(uint8_t i1) {
  Serial.print("exec cmd = ");
  Serial.println(Bus4.packetIn.cmd, HEX);
  Serial.print("i1 = ");
  Serial.println(i1, HEX);
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  Bus4.run();
}

Заменил в хидере тип указателя 

  typedef void (* func)(uint8_t i);

В классе сделал вызов

fPtr(_inChr);

Все получилось! Значение передается.

 

Smith2007
Offline
Зарегистрирован: 30.10.2017

Вопрос (не совсем по классам)

Есть переменная

uint16_t var16;

Как она располагается в памяти? Т.е. где расположен младший байт, а гле старший? 

В струтуре сейчас имею 

  struct packetIn_t {   // Структура принятого пакета
    uint8_t adr;
    uint8_t cmd;
    uint8_t reg;
    uint8_t b0;
    uint8_t b1;
    uint8_t b2;
    uint8_t b3;
  };

Если мне нужно записать значение в переменную var16, то я хотел бы обратиться к элементам данных струтуры как uint16_t :

var16 = (uint16_t *)(&Bus4.packetIn.b0);

 

Но компилятор выдает предупреждение

D:\Project\Arduino\sign\sign.ino: In function 'void parsing()':

D:\Project\Arduino\sign\sign.ino:32:15: warning: invalid conversion from 'uint16_t* {aka unsigned int*}' to 'uint16_t {aka unsigned int}' [-fpermissive]

         var16 = (uint16_t *)(&Bus4.packetIn.b0);

 

При этом код загружается и выполняется. Но явно не то число получаю.

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

Есть такой код

hernya
void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}

Вот сообщение об ошибке

sketch_dec03g:1: error: 'hernya' does not name a type

 hernya

 ^

exit status 1
'hernya' does not name a type

И вот в строке 5 есть значек   ^   .вот это и есть стрелочка указывающая на ошибку.

sketch_dec03g:1  - цифра в :1 это строка где есть ошибка

Может вы хотели так     var16 = (uint16_t)(Bus4.packetIn.b0);

Smith2007
Offline
Зарегистрирован: 30.10.2017

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

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

Smith2007 пишет:
Значение передается.
А куда ему деваться?