C++, объединить 2 переменных с байтами в одну

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Добрый день господа! Не силен в С++ сразу говорю, сильно не ругайте... Есть 2 переменные типа int8_t. Например HL=32 и LO=16, как в третью переменную этого же типа получить результат RZ=3216 ???

Какая операция соединит значения этих двух переменных? Пробовал RZ=HL&LO, не помогло... rz=word(hl,lo) тож фигню какую-то выдает ))) Чую что есть что-то простое )))

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

RZ= HL*100+LO

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

аха , только RZ нужно объявить как int ? или повыше ?

а что будет при , например ,  HL=255 и LO=255 ?

если HL < 99 и LO < 99 - то всё будет хорошо ?
так ?

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

SU-27-16, если исходник -байт, значит самое большое число будет 255*100+255=25755, что вписывается в дефолтовый int :)

Хотя для трёх цифр алгоритм усложнять нужно... :))

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Вот косяк на практике получается ))) в HI = 12 LO=34  RZ получился = 60 (3Ch) )))

 

Как это посчиталось так? ))

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Имеет ли значение - система исчисления???

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

dimax пишет:

SU-27-16, если исходник -байт, значит самое большое число будет 255*100+255=25755, что вписывается в дефолтовый int :)

Хотя для трёх цифр алгоритм усложнять нужно... :))

Тут и для трех усложнить не помешало бы:

"Объединяем" 1 и 2. Получаем 102. А нужно 12. Как быть?

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

это понятно...
но ТС , видимо , хочет рулить HL = сотни в десятичном , а LO = десятки в десятичном....
вот и хотел сказать , что HL>=100 или LO>=100 приведут к неадкватному значению....

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

uint8_t au8Buffer[MAX_BUFFER];

int8_t MyGetAdr=au8Buffer[ ADD_HI ]*100+au8Buffer[ ADD_LO ];
int8_t MyGetAdrL=au8Buffer[ ADD_LO ];
int8_t MyGetAdrH=au8Buffer[ ADD_HI ];
int8_t MyGetCoil=au8Buffer[ NB_HI ]*100+au8Buffer[ NB_LO ];
int8_t MyGetCoilL=au8Buffer[ NB_LO ];
int8_t MyGetCoilH=au8Buffer[ NB_HI ];

полный расклад )

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

ТС , поясни - что в байтах сидит !
...от этого и будет пересчёт :)

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Dr_grizzly, а ничего что int8_t только до 127 считает умеет? :)

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

HL=32 и LO=16, как в третью переменную этого же типа получить результат RZ=3216 ???
это частный случай....
по вышепредложенному получится именно 3216
HL=255 и LO=255, как в третью переменную этого же типа получить результат RZ=................. ???
получится = 255*100+255 = 25755
оно тибе надо такое ?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

uint8_t au8Buffer  -  сидит hex значение, к примеру - 03041234

enum MESSAGE {
  ID                             = 0, //!< ID field
  FUNC, //!< Function code position
  ADD_HI, //!< Address high byte
  ADD_LO, //!< Address low byte
  NB_HI, //!< Number of coils or registers high byte
  NB_LO, //!< Number of coils or registers low byte
  BYTE_CNT  //!< byte counter
};

uint16_t u16RegAdd=1234;

au8Buffer[ ADD_HI ] = highByte(u16RegAdd );

au8Buffer[ ADD_LO ] = lowByte(u16RegAdd );

в коде еще такая функция встречается:

 

uint16_t u16StartCoil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );

  - результат правда не знаю..

 

 

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

dimax пишет:

Dr_grizzly, а ничего что int8_t только до 127 считает умеет? :)

Какой тип тогда нам подойдет? ))  int16_t ? или uint16_t ? ))

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Dr_grizzly, не знаю что у вас за функция, но байты складывают иначе,  int x =  Hi_byte<<8 | Lo_byte;

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012
Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Мне еще рано писать такие штуки ))) я только учусь, но задача стоит и приходится раскапывать чужую библиотеку с ModBus протоколом... поэтому нуждаюсь в помоще зала ))

Может стоит сюда вывалить код всей библиотеки? )))

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

Dr_grizzly пишет:

dimax пишет:

Dr_grizzly, а ничего что int8_t только до 127 считает умеет? :)

Какой тип тогда нам подойдет? ))  int16_t ? или uint16_t ? ))

определи - что в HL и в LO сидит.... потом уже решать можно будет....

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

Dr_grizzly пишет:

Мне еще рано писать такие штуки ))) я только учусь, но задача стоит и приходится раскапывать чужую библиотеку с ModBus протоколом... поэтому нуждаюсь в помоще зала ))

Может стоит сюда вывалить код всей библиотеки? )))

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

есть HL и LO - что из них надо поиметь ?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Привожу весь код библиотечки:

Мои добавленные строки 156 - 163  и 665 - 672...

#include <inttypes.h>
#include "Arduino.h"	
#include "Print.h"

/**
 * @struct modbus_t 
 * @brief 
 * Master query structure:
 * This includes all the necessary fields to make the Master generate a Modbus query.
 * A Master may keep several of these structures and send them cyclically or
 * use them according to program needs.
 */
typedef struct {
  uint8_t u8id;          /*!< Slave address between 1 and 247. 0 means broadcast */
  uint8_t u8fct;         /*!< Function code: 1, 2, 3, 4, 5, 6, 15 or 16 */
  uint16_t u16RegAdd;    /*!< Address of the first register to access at slave/s */
  uint16_t u16CoilsNo;   /*!< Number of coils or registers to access */
  uint16_t *au16reg;     /*!< Pointer to memory image in master */
} 
modbus_t;

enum { 
  RESPONSE_SIZE = 6, 
  EXCEPTION_SIZE = 3, 
  CHECKSUM_SIZE = 2
};

/**
 * @enum MESSAGE
 * @brief
 * Indexes to telegram frame positions
 */
enum MESSAGE {
  ID                             = 0, //!< ID field
  FUNC, //!< Function code position
  ADD_HI, //!< Address high byte
  ADD_LO, //!< Address low byte
  NB_HI, //!< Number of coils or registers high byte
  NB_LO, //!< Number of coils or registers low byte
  BYTE_CNT  //!< byte counter
};

/**
 * @enum MB_FC
 * @brief
 * Modbus function codes summary. 
 * These are the implement function codes either for Master or for Slave.
 *
 * @see also fctsupported
 * @see also modbus_t
 */
enum MB_FC {
  MB_FC_NONE                     = 0,   /*!< null operator */
  MB_FC_READ_COILS               = 1,	/*!< FCT=1 -> read coils or digital outputs */
  MB_FC_READ_DISCRETE_INPUT      = 2,	/*!< FCT=2 -> read digital inputs */
  MB_FC_READ_REGISTERS           = 3,	/*!< FCT=3 -> read registers or analog outputs */
  MB_FC_READ_INPUT_REGISTER      = 4,	/*!< FCT=4 -> read analog inputs */
  MB_FC_WRITE_COIL               = 5,	/*!< FCT=5 -> write single coil or output */
  MB_FC_WRITE_REGISTER           = 6,	/*!< FCT=6 -> write single register */
  MB_FC_WRITE_MULTIPLE_COILS     = 15,	/*!< FCT=15 -> write multiple coils or outputs */
  MB_FC_WRITE_MULTIPLE_REGISTERS = 16	/*!< FCT=16 -> write multiple registers */
};

enum COM_STATES {
  COM_IDLE                     = 0,
  COM_WAITING                  = 1

};

enum ERR_LIST {
  ERR_NOT_MASTER                = -1,
  ERR_POLLING                   = -2,
  ERR_BUFF_OVERFLOW             = -3,
  ERR_BAD_CRC                   = -4,
  ERR_EXCEPTION                 = -5
};

enum { 
  NO_REPLY = 255, 		
  EXC_FUNC_CODE = 1,
  EXC_ADDR_RANGE = 2, 		
  EXC_REGS_QUANT = 3,  
  EXC_EXECUTE = 4 
};

const unsigned char fctsupported[] = { 
  MB_FC_READ_COILS,
  MB_FC_READ_DISCRETE_INPUT,
  MB_FC_READ_REGISTERS, 
  MB_FC_READ_INPUT_REGISTER,
  MB_FC_WRITE_COIL,
  MB_FC_WRITE_REGISTER, 
  MB_FC_WRITE_MULTIPLE_COILS,
  MB_FC_WRITE_MULTIPLE_REGISTERS
};

#define T35  5
#define  MAX_BUFFER  64	//!< maximum size for the communication buffer in bytes

/**
 * @class Modbus 
 * @brief
 * Arduino class library for communicating with Modbus devices over
 * USB/RS232/485 (via RTU protocol).
 */
class Modbus {
private:
  HardwareSerial *port; //!< Pointer to Serial class object
  uint8_t u8id; //!< 0=master, 1..247=slave number
  uint8_t u8serno; //!< serial port: 0-Serial, 1..3-Serial1..Serial3
  uint8_t u8txenpin; //!< flow control pin: 0=USB or RS-232 mode, >0=RS-485 mode
  uint8_t u8state;
  uint8_t u8lastError;
  uint8_t au8Buffer[MAX_BUFFER];
  uint8_t u8BufferSize;
  uint8_t u8lastRec;
  uint16_t *au16regs;
  uint16_t u16InCnt, u16OutCnt, u16errCnt;
  uint16_t u16timeOut;
  uint32_t u32time, u32timeOut;
  uint8_t u8regsize;

  void init(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin);
  void sendTxBuffer(); 
  int8_t getRxBuffer(); 
  uint16_t calcCRC(uint8_t u8length);
  uint8_t validateAnswer();
  uint8_t validateRequest(); 
  void get_FC1(); 
  void get_FC3(); 
  int8_t process_FC1( uint16_t *regs, uint8_t u8size ); 
  int8_t process_FC3( uint16_t *regs, uint8_t u8size ); 
  int8_t process_FC5( uint16_t *regs, uint8_t u8size ); 
  int8_t process_FC6( uint16_t *regs, uint8_t u8size ); 
  int8_t process_FC15( uint16_t *regs, uint8_t u8size ); 
  int8_t process_FC16( uint16_t *regs, uint8_t u8size ); 
  void buildException( uint8_t u8exception ); // build exception message

public:
  Modbus(); 
  Modbus(uint8_t u8id, uint8_t u8serno); 
  Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin);
  void begin(long u32speed);
  void begin();
  void setTimeOut( uint16_t u16timeout); //!<write communication watch-dog timer
  uint16_t getTimeOut(); //!<get communication watch-dog timer value
  boolean getTimeOutState(); //!<get communication watch-dog timer state
  int8_t query( modbus_t telegram ); //!<only for master
  int8_t poll(); //!<cyclic poll for master
  int8_t poll( uint16_t *regs, uint8_t u8size ); //!<cyclic poll for slave
  uint16_t getInCnt(); //!<number of incoming messages
  uint16_t getOutCnt(); //!<number of outcoming messages
  uint16_t getErrCnt(); //!<error counter
  uint8_t getID(); //!<get slave ID between 1 and 247
  uint8_t getState();
  int8_t MyGetID;
  int8_t MyGetFunc;
  int8_t MyGetAdr;
  int8_t MyGetAdrL;
  int8_t MyGetAdrH;
  int8_t MyGetCoil;
  int8_t MyGetCoilL;
  int8_t MyGetCoilH;
  
  uint8_t getLastError(); //!<get last error message
  void setID( uint8_t u8id ); //!<write new ID for the slave
  void end(); //!<finish any communication and release serial communication port
};

/* _____PUBLIC FUNCTIONS_____________________________________________________ */

/**
 * @brief
 * Default Constructor for Master through Serial
 * 
 * @ingroup setup
 */
Modbus::Modbus() {
  init(0, 0, 0);
}

/**
 * @brief
 * Full constructor for a Master/Slave through USB/RS232C
 * 
 * @param u8id   node address 0=master, 1..247=slave
 * @param u8serno  serial port used 0..3
 * @ingroup setup
 * @overload Modbus::Modbus(uint8_t u8id, uint8_t u8serno)
 * @overload Modbus::Modbus()
 */
Modbus::Modbus(uint8_t u8id, uint8_t u8serno) {
  init(u8id, u8serno, 0);
}

/**
 * @brief
 * Full constructor for a Master/Slave through USB/RS232C/RS485
 * It needs a pin for flow control only for RS485 mode
 * 
 * @param u8id   node address 0=master, 1..247=slave
 * @param u8serno  serial port used 0..3
 * @param u8txenpin pin for txen RS-485 (=0 means USB/RS232C mode)
 * @ingroup setup
 * @overload Modbus::Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin)
 * @overload Modbus::Modbus()
 */
Modbus::Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin) {
  init(u8id, u8serno, u8txenpin);
}

/**
 * @brief
 * Initialize class object.
 * 
 * Sets up the serial port using specified baud rate.
 * Call once class has been instantiated, typically within setup().
 * 
 * @see http://arduino.cc/en/Serial/Begin#.Uy4CJ6aKlHY
 * @param speed   baud rate, in standard increments (300..115200)
 * @param config  data frame settings (data length, parity and stop bits)
 * @ingroup setup
 */
void Modbus::begin(long u32speed) {

  switch( u8serno ) {
#if defined(UBRR1H)
  case 1:
    port = &Serial1;
    break;
#endif

#if defined(UBRR2H)
  case 2:
    port = &Serial2;
    break;
#endif

#if defined(UBRR3H)
  case 3:
    port = &Serial3;
    break;
#endif
  case 0:
  default:
    port = &Serial;
    break;
  }

  // port->begin(u32speed, u8config);
  port->begin(u32speed);
  if (u8txenpin > 1) { // pin 0 & pin 1 are reserved for RX/TX
    // return RS485 transceiver to transmit mode
    pinMode(u8txenpin, OUTPUT);
    digitalWrite(u8txenpin, LOW);
  }

  port->flush();
  u8lastRec = u8BufferSize = 0;
  u16InCnt = u16OutCnt = u16errCnt = 0;
}

/**
 * @brief
 * Initialize default class object.
 * 
 * Sets up the serial port using 19200 baud.
 * Call once class has been instantiated, typically within setup().
 * 
 * @overload Modbus::begin(uint16_t u16BaudRate)
 * @ingroup setup
 */
void Modbus::begin() {
  begin(19200);
}

/**
 * @brief
 * Method to write a new slave ID address
 *
 * @param 	u8id	new slave address between 1 and 247
 * @ingroup setup
 */
void Modbus::setID( uint8_t u8id) {
  if (( u8id != 0) && (u8id <= 247)) {
    this->u8id = u8id;
  }
}

/**
 * @brief
 * Method to read current slave ID address
 *
 * @return u8id	current slave address between 1 and 247
 * @ingroup setup
 */
uint8_t Modbus::getID() {
  return this->u8id;
}

/**
 * @brief
 * Initialize time-out parameter
 * 
 * Call once class has been instantiated, typically within setup().
 * The time-out timer is reset each time that there is a successful communication
 * between Master and Slave. It works for both.
 * 
 * @param time-out value (ms)
 * @ingroup setup
 */
void Modbus::setTimeOut( uint16_t u16timeOut) {
  this->u16timeOut = u16timeOut;
}

/**
 * @brief
 * Return communication Watchdog state.
 * It could be usefull to reset outputs if the watchdog is fired.
 *
 * @return TRUE if millis() > u32timeOut
 * @ingroup loop
 */
boolean Modbus::getTimeOutState() {
  return (millis() > u32timeOut);
}

/**
 * @brief
 * Get input messages counter value
 * This can be useful to diagnose communication
 * 
 * @return input messages counter
 * @ingroup buffer
 */
uint16_t Modbus::getInCnt() { 
  return u16InCnt; 
}

/**
 * @brief
 * Get transmitted messages counter value
 * This can be useful to diagnose communication
 * 
 * @return transmitted messages counter
 * @ingroup buffer
 */
uint16_t Modbus::getOutCnt() { 
  return u16OutCnt; 
}

/**
 * @brief
 * Get errors counter value
 * This can be useful to diagnose communication
 * 
 * @return errors counter
 * @ingroup buffer
 */
uint16_t Modbus::getErrCnt() { 
  return u16errCnt; 
}

/**
 * Get modbus master state
 * 
 * @return = 0 IDLE, = 1 WAITING FOR ANSWER
 * @ingroup buffer
 */
uint8_t Modbus::getState() {
  return u8state;
}

/**
 * Get the last error in the protocol processor
 * 
 * @returnreturn   NO_REPLY = 255      Time-out
 * @return   EXC_FUNC_CODE = 1   Function code not available
 * @return   EXC_ADDR_RANGE = 2  Address beyond available space for Modbus registers 
 * @return   EXC_REGS_QUANT = 3  Coils or registers number beyond the available space
 * @ingroup buffer
 */
uint8_t Modbus::getLastError() {
  return u8lastError;
}

/**
 * @brief
 * *** Only Modbus Master ***
 * Generate a query to an slave with a modbus_t telegram structure
 * The Master must be in COM_IDLE mode. After it, its state would be COM_WAITING.
 * This method has to be called only in loop() section.
 * 
 * @see modbus_t 
 * @param modbus_t  modbus telegram structure (id, fct, ...)
 * @ingroup loop
 * @todo finish function 15
 */
int8_t Modbus::query( modbus_t telegram ) {
  uint8_t u8regsno, u8bytesno;
  if (u8id!=0) return -2;
  if (u8state != COM_IDLE) return -1;

  if ((telegram.u8id==0) || (telegram.u8id>247)) return -3;

  au16regs = telegram.au16reg;

  // telegram header
  au8Buffer[ ID ]         = telegram.u8id;
  au8Buffer[ FUNC ]       = telegram.u8fct;
  au8Buffer[ ADD_HI ]     = highByte(telegram.u16RegAdd );
  au8Buffer[ ADD_LO ]     = lowByte( telegram.u16RegAdd );

  switch( telegram.u8fct ) {
  case MB_FC_READ_COILS:
  case MB_FC_READ_DISCRETE_INPUT:
  case MB_FC_READ_REGISTERS:
  case MB_FC_READ_INPUT_REGISTER:
    au8Buffer[ NB_HI ]      = highByte(telegram.u16CoilsNo );
    au8Buffer[ NB_LO ]      = lowByte( telegram.u16CoilsNo );
    u8BufferSize = 6;
    break;
  case MB_FC_WRITE_COIL:
    au8Buffer[ NB_HI ]      = ((au16regs[0] > 0) ? 0xff : 0);
    au8Buffer[ NB_LO ]      = 0;
    u8BufferSize = 6;    
    break;
  case MB_FC_WRITE_REGISTER:
    au8Buffer[ NB_HI ]      = highByte(au16regs[0]);
    au8Buffer[ NB_LO ]      = lowByte(au16regs[0]);
    u8BufferSize = 6;    
    break;
  case MB_FC_WRITE_MULTIPLE_COILS: // TODO: implement "sending coils"
    u8regsno = telegram.u16CoilsNo / 16;
    u8bytesno = u8regsno * 2;
    if ((telegram.u16CoilsNo % 16) != 0) {
      u8bytesno++;
      u8regsno++;
    }

    au8Buffer[ NB_HI ]      = highByte(telegram.u16CoilsNo );
    au8Buffer[ NB_LO ]      = lowByte( telegram.u16CoilsNo );
    au8Buffer[ NB_LO+1 ]    = u8bytesno;
    u8BufferSize = 7;

    u8regsno = u8bytesno = 0; // now auxiliary registers
    for (uint16_t i = 0; i < telegram.u16CoilsNo; i++) {


    }
    break;

  case MB_FC_WRITE_MULTIPLE_REGISTERS:
    au8Buffer[ NB_HI ]      = highByte(telegram.u16CoilsNo );
    au8Buffer[ NB_LO ]      = lowByte( telegram.u16CoilsNo );
    au8Buffer[ NB_LO+1 ]    = (uint8_t) ( telegram.u16CoilsNo * 2 );
    u8BufferSize = 7;    

    for (uint16_t i=0; i< telegram.u16CoilsNo; i++) {
      au8Buffer[ u8BufferSize ] = highByte( au16regs[ i ] );
      u8BufferSize++;
      au8Buffer[ u8BufferSize ] = lowByte( au16regs[ i ] );
      u8BufferSize++;
    }
    break;
  }

  sendTxBuffer();
  u8state = COM_WAITING;
  return 0;
}

/**
 * @brief *** Only for Modbus Master ***
 * This method checks if there is any incoming answer if pending.
 * If there is no answer, it would change Master state to COM_IDLE.
 * This method must be called only at loop section.
 * Avoid any delay() function.
 *
 * Any incoming data would be redirected to au16regs pointer,
 * as defined in its modbus_t query telegram.
 * 
 * @params	nothing
 * @return errors counter
 * @ingroup loop
 */
int8_t Modbus::poll() {
  // check if there is any incoming frame
  uint8_t u8current = port->available();  

  if (millis() > u32timeOut) {
    u8state = COM_IDLE;
    u8lastError = NO_REPLY;
    u16errCnt++;
    return 0;
  }

  if (u8current == 0) return 0;

  // check T35 after frame end or still no frame end
  if (u8current != u8lastRec) {
    u8lastRec = u8current;
    u32time = millis() + T35;
    return 0;
  }
  if (millis() < u32time) return 0;

  // transfer Serial buffer frame to auBuffer
  u8lastRec = 0;
  int8_t i8state = getRxBuffer();
  if (i8state < 7) {
    u8state = COM_IDLE;
    u16errCnt++;
    return i8state;
  }

  // validate message: id, CRC, FCT, exception
  uint8_t u8exception = validateAnswer(); 
  if (u8exception != 0) {
    u8state = COM_IDLE;
    return u8exception;
  }

  // process answer
  switch( au8Buffer[ FUNC ] ) {
  case MB_FC_READ_COILS:
  case MB_FC_READ_DISCRETE_INPUT:
    // call get_FC1 to transfer the incoming message to au16regs buffer
    get_FC1( );
    break;
  case MB_FC_READ_INPUT_REGISTER:
  case MB_FC_READ_REGISTERS :
    // call get_FC3 to transfer the incoming message to au16regs buffer
    get_FC3( );
    break;
  case MB_FC_WRITE_COIL:
  case MB_FC_WRITE_REGISTER :
  case MB_FC_WRITE_MULTIPLE_COILS:
  case MB_FC_WRITE_MULTIPLE_REGISTERS :
    // nothing to do
    break;
  default:
    break;
  }  
  u8state = COM_IDLE;
  return u8BufferSize;
}


/**
 * @brief
 * *** Only for Modbus Slave ***
 * This method checks if there is any incoming query
 * Afterwards, it would shoot a validation routine plus a register query
 * Avoid any delay() function !!!!
 * After a successful frame between the Master and the Slave, the time-out timer is reset.
 * 
 * @param *regs  register table for communication exchange
 * @param u8size  size of the register table
 * @return 0 if no query, 1..4 if communication error, >4 if correct query processed
 * @ingroup loop
 */
int8_t Modbus::poll( uint16_t *regs, uint8_t u8size ) {

  au16regs = regs;
  u8regsize = u8size;

  // check if there is any incoming frame
  uint8_t u8current = port->available();  
  if (u8current == 0) return 0;

  // check T35 after frame end or still no frame end
  if (u8current != u8lastRec) {
    u8lastRec = u8current;
    u32time = millis() + T35;
    return 0;
  }
  if (millis() < u32time) return 0;

  u8lastRec = 0;
  int8_t i8state = getRxBuffer();
  u8lastError = i8state;
  if (i8state < 7) return i8state;  

  // check slave id
  if (au8Buffer[ ID ] != u8id) return 0;

  // validate message: CRC, FCT, address and size
  uint8_t u8exception = validateRequest();
  if (u8exception > 0) {
    if (u8exception != NO_REPLY) {
      buildException( u8exception );
      sendTxBuffer(); 
    }
    u8lastError = u8exception;
    return u8exception;
  }

  u32timeOut = millis() + long(u16timeOut);
  u8lastError = 0;
  
  // process message
  switch( au8Buffer[ FUNC ] ) {
  case MB_FC_READ_COILS:
  case MB_FC_READ_DISCRETE_INPUT:
    return process_FC1( regs, u8size );
    break;
  case MB_FC_READ_INPUT_REGISTER:
  case MB_FC_READ_REGISTERS :
    return process_FC3( regs, u8size );
    break;
  case MB_FC_WRITE_COIL:
    return process_FC5( regs, u8size );
    break;
  case MB_FC_WRITE_REGISTER :
    return process_FC6( regs, u8size );
    break;
  case MB_FC_WRITE_MULTIPLE_COILS:
    return process_FC15( regs, u8size );
    break;
  case MB_FC_WRITE_MULTIPLE_REGISTERS :
    return process_FC16( regs, u8size );
    break;
  default:
    break;
  }
  return i8state;
}

/* _____PRIVATE FUNCTIONS_____________________________________________________ */

void Modbus::init(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin) {
  this->u8id = u8id;
  this->u8serno = (u8serno > 3) ? 0 : u8serno;
  this->u8txenpin = u8txenpin;
  this->u16timeOut = 1000;
}

/**
 * @brief
 * This method moves Serial buffer data to the Modbus au8Buffer.
 *
 * @return buffer size if OK, ERR_BUFF_OVERFLOW if u8BufferSize >= MAX_BUFFER
 * @ingroup buffer
 */
int8_t Modbus::getRxBuffer() {
  boolean bBuffOverflow = false;

  if (u8txenpin > 1) digitalWrite( u8txenpin, LOW );

  u8BufferSize = 0;
  while ( port->available() ) {
    au8Buffer[ u8BufferSize ] = port->read();
    u8BufferSize ++;

    if (u8BufferSize >= MAX_BUFFER) bBuffOverflow = true;
  }
  u16InCnt++;

  if (bBuffOverflow) {
    u16errCnt++;
    return ERR_BUFF_OVERFLOW;
  }
  
  MyGetFunc=au8Buffer[ FUNC ];
  MyGetID=au8Buffer[ ID ];
  MyGetAdr=au8Buffer[ ADD_HI ]*100+au8Buffer[ ADD_LO ];
  MyGetAdrL=au8Buffer[ ADD_LO ];
  MyGetAdrH=au8Buffer[ ADD_HI ];
  MyGetCoil=au8Buffer[ NB_HI ]*100+au8Buffer[ NB_LO ];
  MyGetCoilL=au8Buffer[ NB_LO ];
  MyGetCoilH=au8Buffer[ NB_HI ];
  
  
  return u8BufferSize;
}

/**
 * @brief
 * This method transmits au8Buffer to Serial line.
 * Only if u8txenpin != 0, there is a flow handling in order to keep
 * the RS485 transceiver in output state as long as the message is being sent.
 * This is done with UCSRxA register.
 * The CRC is appended to the buffer before starting to send it.
 *
 * @param nothing
 * @return nothing
 * @ingroup buffer
 */
void Modbus::sendTxBuffer() {
  uint8_t i = 0;

  // append CRC to message
  uint16_t u16crc = calcCRC( u8BufferSize );
  au8Buffer[ u8BufferSize ] = u16crc >> 8;
  u8BufferSize++;
  au8Buffer[ u8BufferSize ] = u16crc & 0x00ff;
  u8BufferSize++;

  // set RS485 transceiver to transmit mode
  if (u8txenpin > 1) {
    switch( u8serno ) {
#if defined(UBRR1H)
    case 1:
      UCSR1A=UCSR1A |(1 << TXC1);
      break;
#endif

#if defined(UBRR2H)
    case 2:
      UCSR2A=UCSR2A |(1 << TXC2);
      break;
#endif

#if defined(UBRR3H)
    case 3:
      UCSR3A=UCSR3A |(1 << TXC3);
      break;
#endif
    case 0:
    default:
      UCSR0A=UCSR0A |(1 << TXC0);
      break;
    }
    digitalWrite( u8txenpin, HIGH );
  }

  // transfer buffer to serial line
  port->write( au8Buffer, u8BufferSize );

  // keep RS485 transceiver in transmit mode as long as sending
  if (u8txenpin > 1) {
    switch( u8serno ) {
#if defined(UBRR1H)
    case 1:
      while (!(UCSR1A & (1 << TXC1)));
      break;
#endif

#if defined(UBRR2H)
    case 2:
      while (!(UCSR2A & (1 << TXC2)));
      break;
#endif

#if defined(UBRR3H)
    case 3:
      while (!(UCSR3A & (1 << TXC3)));
      break;
#endif
    case 0:
    default:
      while (!(UCSR0A & (1 << TXC0)));
      break;
    }

    // return RS485 transceiver to receive mode
    digitalWrite( u8txenpin, LOW );
  }
  port->flush();
  u8BufferSize = 0;

  // set time-out for master
  u32timeOut = millis() + (unsigned long) u16timeOut;

  // increase message counter
  u16OutCnt++;
}

/**
 * @brief
 * This method calculates CRC
 *
 * @return uint16_t calculated CRC value for the message
 * @ingroup buffer
 */
uint16_t Modbus::calcCRC(uint8_t u8length) {
  unsigned int temp, temp2, flag;
  temp = 0xFFFF;
  for (unsigned char i = 0; i < u8length; i++) {
    temp = temp ^ au8Buffer[i];
    for (unsigned char j = 1; j <= 8; j++) {
      flag = temp & 0x0001;
      temp >>=1;
      if (flag)
        temp ^= 0xA001;
    }
  }
  // Reverse byte order. 
  temp2 = temp >> 8;
  temp = (temp << 8) | temp2;
  temp &= 0xFFFF; 
  // the returned value is already swapped
  // crcLo byte is first & crcHi byte is last
  return temp; 
}

/**
 * @brief
 * This method validates slave incoming messages
 *
 * @return 0 if OK, EXCEPTION if anything fails
 * @ingroup buffer
 */
uint8_t Modbus::validateRequest() {
  // check message crc vs calculated crc
    
  uint16_t u16MsgCRC = 
    ((au8Buffer[u8BufferSize - 2] << 8) 
    | au8Buffer[u8BufferSize - 1]); // combine the crc Low & High bytes
  if ( calcCRC( u8BufferSize-2 ) != u16MsgCRC ) {
    u16errCnt ++;
    return NO_REPLY;
  }

 
  
  // check fct code
  boolean isSupported = false;
  for (uint8_t i = 0; i< sizeof( fctsupported ); i++) {
    if (fctsupported[i] == au8Buffer[FUNC]) {
      isSupported = 1;
      break;
    }
  }
  if (!isSupported) {
    u16errCnt ++;
    return EXC_FUNC_CODE;
  }

  // check start address & nb range
  uint16_t u16regs = 0;
  uint8_t u8regs;
  
  switch ( au8Buffer[ FUNC ] ) {
  case MB_FC_READ_COILS:
  case MB_FC_READ_DISCRETE_INPUT:
  case MB_FC_WRITE_MULTIPLE_COILS:
    u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]) / 16;
    u16regs += word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ]) /16;
    u8regs = (uint8_t) u16regs;
    if (u8regs > u8regsize) return EXC_ADDR_RANGE;
    break;
  case MB_FC_WRITE_COIL:
    u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]) / 16;
    u8regs = (uint8_t) u16regs;
    if (u8regs > u8regsize) return EXC_ADDR_RANGE;
    break;  
  case MB_FC_WRITE_REGISTER :
    u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
    u8regs = (uint8_t) u16regs;
    if (u8regs > u8regsize) return EXC_ADDR_RANGE;
    break;
  case MB_FC_READ_REGISTERS :
  case MB_FC_READ_INPUT_REGISTER :
  case MB_FC_WRITE_MULTIPLE_REGISTERS :
    u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
    u16regs += word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ]);
    u8regs = (uint8_t) u16regs;
    if (u8regs > u8regsize) return EXC_ADDR_RANGE;    
    break;
  }
  return 0; // OK, no exception code thrown
}

/**
 * @brief
 * This method validates master incoming messages
 *
 * @return 0 if OK, EXCEPTION if anything fails
 * @ingroup buffer
 */
uint8_t Modbus::validateAnswer() {
  // check message crc vs calculated crc
  uint16_t u16MsgCRC = 
    ((au8Buffer[u8BufferSize - 2] << 8) 
    | au8Buffer[u8BufferSize - 1]); // combine the crc Low & High bytes
  if ( calcCRC( u8BufferSize-2 ) != u16MsgCRC ) {
    u16errCnt ++;
    return NO_REPLY;
  }

  // check exception
  if ((au8Buffer[ FUNC ] & 0x80) != 0) {
    u16errCnt ++;
    return ERR_EXCEPTION;
  }

  // check fct code
  boolean isSupported = false;
  for (uint8_t i = 0; i< sizeof( fctsupported ); i++) {
    if (fctsupported[i] == au8Buffer[FUNC]) {
      isSupported = 1;
      break;
    }
  }
  if (!isSupported) {
    u16errCnt ++;
    return EXC_FUNC_CODE;
  }

  return 0; // OK, no exception code thrown
}

/**
 * @brief
 * This method builds an exception message
 *
 * @ingroup buffer
 */
void Modbus::buildException( uint8_t u8exception ) {
  uint8_t u8func = au8Buffer[ FUNC ];  // get the original FUNC code

  au8Buffer[ ID ]      = u8id;
  au8Buffer[ FUNC ]    = u8func + 0x80;
  au8Buffer[ 2 ]       = u8exception;
  u8BufferSize         = EXCEPTION_SIZE;
}

/**
 * This method processes functions 1 & 2 (for master)
 * This method puts the slave answer into master data buffer 
 *
 * @ingroup register
 * TODO: finish its implementation
 */
void Modbus::get_FC1() {
  uint8_t u8byte, i;
  u8byte = 0;

  //  for (i=0; i< au8Buffer[ 2 ] /2; i++) {
  //    au16regs[ i ] = word( 
  //    au8Buffer[ u8byte ],
  //    au8Buffer[ u8byte +1 ]);
  //    u8byte += 2;
  //  }
}

/**
 * This method processes functions 3 & 4 (for master)
 * This method puts the slave answer into master data buffer 
 *
 * @ingroup register
 */
void Modbus::get_FC3() {
  uint8_t u8byte, i;
  u8byte = 3;

  for (i=0; i< au8Buffer[ 2 ] /2; i++) {
    au16regs[ i ] = word( 
    au8Buffer[ u8byte ],
    au8Buffer[ u8byte +1 ]);
    u8byte += 2;
  }
}

/**
 * @brief
 * This method processes functions 1 & 2
 * This method reads a bit array and transfers it to the master
 *
 * @return u8BufferSize Response to master length
 * @ingroup discrete
 */
int8_t Modbus::process_FC1( uint16_t *regs, uint8_t u8size ) {
  uint8_t u8currentRegister, u8currentBit, u8bytesno, u8bitsno;
  uint8_t u8CopyBufferSize;
  uint16_t u16currentCoil, u16coil;

  // get the first and last coil from the message
  uint16_t u16StartCoil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
  uint16_t u16Coilno = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ] );

  // put the number of bytes in the outcoming message
  u8bytesno = (uint8_t) (u16Coilno / 8);
  if (u16Coilno % 8 != 0) u8bytesno ++;
  au8Buffer[ ADD_HI ]  = u8bytesno;
  u8BufferSize         = ADD_LO;

  // read each coil from the register map and put its value inside the outcoming message
  u8bitsno = 0;

  for (u16currentCoil = 0; u16currentCoil < u16Coilno; u16currentCoil++) {
    u16coil = u16StartCoil + u16currentCoil;
    u8currentRegister = (uint8_t) (u16coil / 16);
    u8currentBit = (uint8_t) (u16coil % 16);

    bitWrite(
    au8Buffer[ u8BufferSize ],
    u8bitsno,
    bitRead( regs[ u8currentRegister ], u8currentBit ) );
    u8bitsno ++;

    if (u8bitsno > 7) {
      u8bitsno = 0;
      u8BufferSize++;
    }
  }

  // send outcoming message
  if (u16Coilno % 8 != 0) u8BufferSize ++;
  u8CopyBufferSize = u8BufferSize +2;
  sendTxBuffer();
  return u8CopyBufferSize;
}

/**
 * @brief
 * This method processes functions 3 & 4
 * This method reads a word array and transfers it to the master
 *
 * @return u8BufferSize Response to master length
 * @ingroup register
 */
int8_t Modbus::process_FC3( uint16_t *regs, uint8_t u8size ) {

  uint8_t u8StartAdd = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
  uint8_t u8regsno = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ] );
  uint8_t u8CopyBufferSize;
  uint8_t i;

  au8Buffer[ 2 ]       = u8regsno * 2;
  u8BufferSize         = 3;

  for (i = u8StartAdd; i < u8StartAdd + u8regsno; i++) {
    au8Buffer[ u8BufferSize ] = highByte(regs[i]);
    u8BufferSize++;
    au8Buffer[ u8BufferSize ] = lowByte(regs[i]);
    u8BufferSize++;
  }
  u8CopyBufferSize = u8BufferSize +2;
  sendTxBuffer();

  return u8CopyBufferSize;
}

/**
 * @brief
 * This method processes function 5
 * This method writes a value assigned by the master to a single bit
 *
 * @return u8BufferSize Response to master length
 * @ingroup discrete
 */
int8_t Modbus::process_FC5( uint16_t *regs, uint8_t u8size ) {
  uint8_t u8currentRegister, u8currentBit;
  uint8_t u8CopyBufferSize;
  uint16_t u16coil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );

  // point to the register and its bit
  u8currentRegister = (uint8_t) (u16coil / 16);
  u8currentBit = (uint8_t) (u16coil % 16);

  // write to coil
  bitWrite(
  regs[ u8currentRegister ],
  u8currentBit,
  au8Buffer[ NB_HI ] == 0xff );


  // send answer to master
  u8BufferSize = 6;
  u8CopyBufferSize = u8BufferSize +2;
  sendTxBuffer();

  return u8CopyBufferSize;
}

/**
 * @brief
 * This method processes function 6
 * This method writes a value assigned by the master to a single word
 *
 * @return u8BufferSize Response to master length
 * @ingroup register
 */
int8_t Modbus::process_FC6( uint16_t *regs, uint8_t u8size ) {

  uint8_t u8add = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
  uint8_t u8CopyBufferSize;
  uint16_t u16val = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ] );

  regs[ u8add ] = u16val;

  // keep the same header
  u8BufferSize         = RESPONSE_SIZE;

  u8CopyBufferSize = u8BufferSize +2;
  sendTxBuffer();

  return u8CopyBufferSize;
}

/**
 * @brief
 * This method processes function 15
 * This method writes a bit array assigned by the master
 *
 * @return u8BufferSize Response to master length
 * @ingroup discrete
 */
int8_t Modbus::process_FC15( uint16_t *regs, uint8_t u8size ) {
  uint8_t u8currentRegister, u8currentBit, u8frameByte, u8bitsno;
  uint8_t u8CopyBufferSize;
  uint16_t u16currentCoil, u16coil;
  boolean bTemp;

  // get the first and last coil from the message
  uint16_t u16StartCoil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
  uint16_t u16Coilno = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ] );


  // read each coil from the register map and put its value inside the outcoming message
  u8bitsno = 0;
  u8frameByte = 7;
  for (u16currentCoil = 0; u16currentCoil < u16Coilno; u16currentCoil++) {

    u16coil = u16StartCoil + u16currentCoil;
    u8currentRegister = (uint8_t) (u16coil / 16);
    u8currentBit = (uint8_t) (u16coil % 16);

    bTemp = bitRead(
    au8Buffer[ u8frameByte ],
    u8bitsno );

    bitWrite(
    regs[ u8currentRegister ],
    u8currentBit,
    bTemp );

    u8bitsno ++;

    if (u8bitsno > 7) {
      u8bitsno = 0;
      u8frameByte++;
    }
  }

  // send outcoming message
  // it's just a copy of the incomping frame until 6th byte
  u8BufferSize         = 6;
  u8CopyBufferSize = u8BufferSize +2;
  sendTxBuffer();
  return u8CopyBufferSize;
}

/**
 * @brief
 * This method processes function 16
 * This method writes a word array assigned by the master
 *
 * @return u8BufferSize Response to master length
 * @ingroup register
 */
int8_t Modbus::process_FC16( uint16_t *regs, uint8_t u8size ) {
  uint8_t u8func = au8Buffer[ FUNC ];  // get the original FUNC code
  uint8_t u8StartAdd = au8Buffer[ ADD_HI ] << 8 | au8Buffer[ ADD_LO ];
  uint8_t u8regsno = au8Buffer[ NB_HI ] << 8 | au8Buffer[ NB_LO ];
  uint8_t u8CopyBufferSize;
  uint8_t i;
  uint16_t temp;

  // build header
  au8Buffer[ NB_HI ]   = 0;
  au8Buffer[ NB_LO ]   = u8regsno;
  u8BufferSize         = RESPONSE_SIZE;

  // write registers
  for (i = 0; i < u8regsno; i++) {
    temp = word(
    au8Buffer[ (BYTE_CNT + 1) + i * 2 ],
    au8Buffer[ (BYTE_CNT + 2) + i * 2 ]);

    regs[ u8StartAdd + i ] = temp;
  }
  u8CopyBufferSize = u8BufferSize +2;
  sendTxBuffer();

  return u8CopyBufferSize;
}

Простите за галочку )))

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

Dr_grizzly  , "галочка" - свернуть код !
весь код - не нужен , обычно....

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Дело в том, что когда я не понимаю что ходит по переменным я использую Debugger и StepByStep  отслеживаю все изменения... У ардуино я не нашел такой возможности  )) поэтому мне проще вам показать то с чем я голову ломаю, может быстро определите наметанным глазом что там может быть...

Кста. Исправил переменную int8_t на int16_t - если был результат 3С то стал 073С )))

 

По сути там пакет modbus в HEX виде.... Я пытаюсь разложить опредленные данные по переменным, чтобы потом формировать свои пакеты.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

вопрос был про HL и LO -> преобразование....
этот вопрос закрыт ?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

SU-27-16 пишет:

HL=32 и LO=16, как в третью переменную этого же типа получить результат RZ=3216 ???
это частный случай....
по вышепредложенному получится именно 3216
HL=255 и LO=255, как в третью переменную этого же типа получить результат RZ=................. ???
получится = 255*100+255 = 25755
оно тибе надо такое ?

Как я понял, что данная процедура не уместна если значение байта =255 и второго 255... Но ведь в модбас возможно такое, что адрес состоит из FFFFh  тогда старший и младший байт не получить таким способом... Есть еще варианты?))

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Dr_grizzly, я ж вам написал в #14 как складывать..

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

dimax пишет:

Dr_grizzly, я ж вам написал в #14 как складывать..

Простите, не понял просто что там за комманда )) ща воткнул в свой код и все получилось!!! УРААА!!)) СПААСИБО!

 

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Dr_grizzly пишет:

Простите, не понял просто что там за комманда

Там битовый сдвиг влево (<<) и побитовое "или" ( | ).

https://ru.wikipedia.org/wiki/Битовые_операции

http://www.c-cpp.ru/books/bitovye-operatory

Туцик
Туцик аватар
Offline
Зарегистрирован: 31.03.2020
uint8_t Hi = 2;
uint8_t Lo = 20;

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

uint16_t Index = Hi << 8 | Lo;      
Serial.print("Index =");          
Serial.println(Index);

}
void loop() {


}

У меня почему то не работает, откуда то 532 получается. Хотя вроде раньше работало.

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

2*256 + 20  ==  532, хоть ты тресни

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

а вот если напишешь

Hi = 0x02;

Lo = 0x20;

тогда, 544

Туцик
Туцик аватар
Offline
Зарегистрирован: 31.03.2020

Симен, а как в таком случае 220 получить? переводить в String складывать потом в uint16_t ? Тока так?

Green
Offline
Зарегистрирован: 01.10.2015

512 + 32, даже в уме складываю. Пока.

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

Туцик пишет:

Симен, а как в таком случае 220 получить? 

в каком счислении?

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

Green пишет:

512 + 32, даже в уме складываю. Пока.

у него не HEX

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

Туцик пишет:

Симен, а как в таком случае 220 получить? переводить в String складывать потом в uint16_t ? Тока так?

как дед скажет, ты наркоман что-ле?

uint8_t Hi = 0;
uint8_t Lo = 220;

 

Туцик
Туцик аватар
Offline
Зарегистрирован: 31.03.2020

Да так же в десятичном. Можно и в hex. Если через String, то там вроде можно String a = (Index, HEX); но все как то мудрено. Из байтов лепить строку, потом в число.

b707
Offline
Зарегистрирован: 26.05.2017

Туцик пишет:

Симен, а как в таком случае 220 получить?

0x220 ? - так вы его и получаете - 0х220 = 544

Туцик
Туцик аватар
Offline
Зарегистрирован: 31.03.2020

b707 пишет:

Туцик пишет:

Симен, а как в таком случае 220 получить?

0x220 ? - так вы его и получаете - 0х220 = 544

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

b707
Offline
Зарегистрирован: 26.05.2017

Туцик пишет:

Симен, а как в таком случае 220 получить?

правда наркоман

uint8_t Hi = 0x02;
uint8_t Lo = 0x20;

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

uint16_t Index = Hi << 8 | Lo;      
Serial.print("Index =");     
Serial.print(" 0x");
Serial.println(Index, HEX);

}
void loop() {


}

 

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

Туцик пишет:

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

Нет

b707
Offline
Зарегистрирован: 26.05.2017

Туцик пишет:

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

пипец ты темный... байты всегда байты и как ты их не представляй - имеет значение только их ЗНАЧЕНИЕ, а не представляение

0х220 и 544 это одно и тоже

И эти два выражения абсолютно эквивалентны

(0х02 << 8) | 0x20

(2 << 8) | 32

Туцик
Туцик аватар
Offline
Зарегистрирован: 31.03.2020

[/quote]

правда наркоман

[/quote]

 

Вы о ком? Hi =2, а не 0x02, и Lo = 20, a не 0x20. Мне нужно просто склеить два десятичных числа в одно.

b707
Offline
Зарегистрирован: 26.05.2017

Туцик пишет:

Вы о ком? Hi =2, а не 0x02, и Lo = 20, a не 0x20. Мне нужно просто склеить два десятичных числа в одно.

что это за операция - "склеить" ?

причем тут тогда битовые сдвиги, вы в своем уме?

 

точно наркоман

 

если вам надо "склеить" 220 из отдельных цифр - то их должно быть три - '2' '2' и '0'. Не бывает такой цифры - 20

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

Правда, наркоман.   Клей   2*100+20.

На тебя извели целую рощу стоеросового дерева.  Брось ютубчики смотреть, начни читать, а то совсем оскотинишьса. 

Туцик
Туцик аватар
Offline
Зарегистрирован: 31.03.2020

DetSimen пишет:

Правда, наркоман.   Клей   2*100+20.

На тебя извели целую рощу стоеросового дерева.  Брось ютубчики смотреть, начни читать, а то совсем оскотинишьса. 

Не годится этот вариант. Если hi = 1, а lo = 0.

b707
Offline
Зарегистрирован: 26.05.2017

я пас.... с такой тупостью давно не сталкивался.

Обьясни, что те надо, чудо!

Только не спрашивай как "склеить" - напиши где у тебя такая задача возникла. Наверняка какую-то дурость делаешь, типа обнуления миллис

b707
Offline
Зарегистрирован: 26.05.2017

Туцик пишет:

Мне надо склеить два байта 2 и 220, и получить одно целое число 220.

новая задача, не имеющая ничего общего с предыдущими.

Раз у тебя младший байт УЖЕ 220 - просто отбрось старший и все.

 

 

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

я - пас. 

Green
Offline
Зарегистрирован: 01.10.2015

В школе учился? 2 х 100 + 20

b707
Offline
Зарегистрирован: 26.05.2017

Туцик

Мы услышим рассказ, нахера это надо?

Абсолютно точно это так называемая "проблемаXY". Это когда человеку надо Х, но он уверен что это делается через Y, поэтому он идет и задает вопрос о Y. Через два дня дискуссий выясняется, что никого Y и не требовалось

 

https://xyproblem.info/

 

 

 

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

да мне понятно чЁ ему надо

uint8_t Hi = 2;
uint8_t Lo = 20;

ему надо получить 

rez = 220;

вот он через стринг и трахается, но вопрос правильный - НАХУЯ?