C++, объединить 2 переменных с байтами в одну
- Войдите на сайт для отправки комментариев
Пт, 12/02/2016 - 21:54
Добрый день господа! Не силен в С++ сразу говорю, сильно не ругайте... Есть 2 переменные типа int8_t. Например HL=32 и LO=16, как в третью переменную этого же типа получить результат RZ=3216 ???
Какая операция соединит значения этих двух переменных? Пробовал RZ=HL&LO, не помогло... rz=word(hl,lo) тож фигню какую-то выдает ))) Чую что есть что-то простое )))
RZ= HL*100+LO
аха , только RZ нужно объявить как int ? или повыше ?
а что будет при , например , HL=255 и LO=255 ?
если HL < 99 и LO < 99 - то всё будет хорошо ?
так ?
SU-27-16, если исходник -байт, значит самое большое число будет 255*100+255=25755, что вписывается в дефолтовый int :)
Хотя для трёх цифр алгоритм усложнять нужно... :))
Вот косяк на практике получается ))) в HI = 12 LO=34 RZ получился = 60 (3Ch) )))
Как это посчиталось так? ))
Имеет ли значение - система исчисления???
SU-27-16, если исходник -байт, значит самое большое число будет 255*100+255=25755, что вписывается в дефолтовый int :)
Хотя для трёх цифр алгоритм усложнять нужно... :))
Тут и для трех усложнить не помешало бы:
"Объединяем" 1 и 2. Получаем 102. А нужно 12. Как быть?
это понятно...
но ТС , видимо , хочет рулить HL = сотни в десятичном , а LO = десятки в десятичном....
вот и хотел сказать , что HL>=100 или LO>=100 приведут к неадкватному значению....
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 ];
полный расклад )
ТС , поясни - что в байтах сидит !
...от этого и будет пересчёт :)
Dr_grizzly, а ничего что int8_t только до 127 считает умеет? :)
HL=32 и LO=16, как в третью переменную этого же типа получить результат RZ=3216 ???
это частный случай....
по вышепредложенному получится именно 3216
HL=255 и LO=255, как в третью переменную этого же типа получить результат RZ=................. ???
получится = 255*100+255 = 25755
оно тибе надо такое ?
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 );в коде еще такая функция встречается:
- результат правда не знаю..
Dr_grizzly, а ничего что int8_t только до 127 считает умеет? :)
Какой тип тогда нам подойдет? )) int16_t ? или uint16_t ? ))
Dr_grizzly, не знаю что у вас за функция, но байты складывают иначе, int x = Hi_byte<<8 | Lo_byte;
Dr_grizzly , http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukommentarii
Мне еще рано писать такие штуки ))) я только учусь, но задача стоит и приходится раскапывать чужую библиотеку с ModBus протоколом... поэтому нуждаюсь в помоще зала ))
Может стоит сюда вывалить код всей библиотеки? )))
Dr_grizzly, а ничего что int8_t только до 127 считает умеет? :)
Какой тип тогда нам подойдет? )) int16_t ? или uint16_t ? ))
определи - что в HL и в LO сидит.... потом уже решать можно будет....
Мне еще рано писать такие штуки ))) я только учусь, но задача стоит и приходится раскапывать чужую библиотеку с ModBus протоколом... поэтому нуждаюсь в помоще зала ))
Может стоит сюда вывалить код всей библиотеки? )))
вот зал и спрашивает - чего тибе хочется ?
весь код нафиг никому не нужен....
есть HL и LO - что из них надо поиметь ?
Привожу весь код библиотечки:
Мои добавленные строки 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; }Простите за галочку )))
Dr_grizzly , "галочка" - свернуть код !
весь код - не нужен , обычно....
Дело в том, что когда я не понимаю что ходит по переменным я использую Debugger и StepByStep отслеживаю все изменения... У ардуино я не нашел такой возможности )) поэтому мне проще вам показать то с чем я голову ломаю, может быстро определите наметанным глазом что там может быть...
Кста. Исправил переменную int8_t на int16_t - если был результат 3С то стал 073С )))
По сути там пакет modbus в HEX виде.... Я пытаюсь разложить опредленные данные по переменным, чтобы потом формировать свои пакеты.
вопрос был про HL и LO -> преобразование....
этот вопрос закрыт ?
HL=32 и LO=16, как в третью переменную этого же типа получить результат RZ=3216 ???
это частный случай....
по вышепредложенному получится именно 3216
HL=255 и LO=255, как в третью переменную этого же типа получить результат RZ=................. ???
получится = 255*100+255 = 25755
оно тибе надо такое ?
Как я понял, что данная процедура не уместна если значение байта =255 и второго 255... Но ведь в модбас возможно такое, что адрес состоит из FFFFh тогда старший и младший байт не получить таким способом... Есть еще варианты?))
Dr_grizzly, я ж вам написал в #14 как складывать..
Dr_grizzly, я ж вам написал в #14 как складывать..
Простите, не понял просто что там за комманда )) ща воткнул в свой код и все получилось!!! УРААА!!)) СПААСИБО!
Простите, не понял просто что там за комманда
Там битовый сдвиг влево (<<) и побитовое "или" ( | ).
https://ru.wikipedia.org/wiki/Битовые_операции
http://www.c-cpp.ru/books/bitovye-operatory
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 получается. Хотя вроде раньше работало.
2*256 + 20 == 532, хоть ты тресни
а вот если напишешь
Hi = 0x02;
Lo = 0x20;
тогда, 544
Симен, а как в таком случае 220 получить? переводить в String складывать потом в uint16_t ? Тока так?
512 + 32, даже в уме складываю. Пока.
Симен, а как в таком случае 220 получить?
в каком счислении?
512 + 32, даже в уме складываю. Пока.
у него не HEX
Симен, а как в таком случае 220 получить? переводить в String складывать потом в uint16_t ? Тока так?
как дед скажет, ты наркоман что-ле?
Да так же в десятичном. Можно и в hex. Если через String, то там вроде можно String a = (Index, HEX); но все как то мудрено. Из байтов лепить строку, потом в число.
Симен, а как в таком случае 220 получить?
0x220 ? - так вы его и получаете - 0х220 = 544
Симен, а как в таком случае 220 получить?
0x220 ? - так вы его и получаете - 0х220 = 544
Вообще удивительно, если байты представлены в десятичном виде, она мне склеивает как шестнадцатиричные.
Симен, а как в таком случае 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() { }Вообще удивительно, если байты представлены в десятичном виде, она мне склеивает как шестнадцатиричные.
Нет
Вообще удивительно, если байты представлены в десятичном виде, она мне склеивает как шестнадцатиричные.
пипец ты темный... байты всегда байты и как ты их не представляй - имеет значение только их ЗНАЧЕНИЕ, а не представляение
0х220 и 544 это одно и тоже
И эти два выражения абсолютно эквивалентны
(0х02 << 8) | 0x20
(2 << 8) | 32
[/quote]
правда наркоман
[/quote]
Вы о ком? Hi =2, а не 0x02, и Lo = 20, a не 0x20. Мне нужно просто склеить два десятичных числа в одно.
Вы о ком? Hi =2, а не 0x02, и Lo = 20, a не 0x20. Мне нужно просто склеить два десятичных числа в одно.
что это за операция - "склеить" ?
причем тут тогда битовые сдвиги, вы в своем уме?
точно наркоман
если вам надо "склеить" 220 из отдельных цифр - то их должно быть три - '2' '2' и '0'. Не бывает такой цифры - 20
Правда, наркоман. Клей 2*100+20.
На тебя извели целую рощу стоеросового дерева. Брось ютубчики смотреть, начни читать, а то совсем оскотинишьса.
Правда, наркоман. Клей 2*100+20.
На тебя извели целую рощу стоеросового дерева. Брось ютубчики смотреть, начни читать, а то совсем оскотинишьса.
Не годится этот вариант. Если hi = 1, а lo = 0.
я пас.... с такой тупостью давно не сталкивался.
Обьясни, что те надо, чудо!
Только не спрашивай как "склеить" - напиши где у тебя такая задача возникла. Наверняка какую-то дурость делаешь, типа обнуления миллис
Мне надо склеить два байта 2 и 220, и получить одно целое число 220.
новая задача, не имеющая ничего общего с предыдущими.
Раз у тебя младший байт УЖЕ 220 - просто отбрось старший и все.
я - пас.
В школе учился? 2 х 100 + 20
Туцик
Мы услышим рассказ, нахера это надо?
Абсолютно точно это так называемая "проблемаXY". Это когда человеку надо Х, но он уверен что это делается через Y, поэтому он идет и задает вопрос о Y. Через два дня дискуссий выясняется, что никого Y и не требовалось
https://xyproblem.info/
да мне понятно чЁ ему надо
ему надо получить
вот он через стринг и трахается, но вопрос правильный - НАХУЯ?