Partage d'instance SoftwareSerial

Bonjour,

J'attaque mon premier gros projet sur Arduino, je souhaite réaliser une connexion RS485 avec une climatisation de la marque LG.

J'ai donc en premier tout mis mon code dans un seul et même fichier CPP pour gérer mes 5 unités de clim. La gestion de ces 5 unités passe par une même connexion RS485 relié physiquement a une passerelle LG.

La communication se passe bien mais j'ai voulu aller plus loin en créant une classe "LgapController" et de l'instancier 5 fois.

J'ai bien réussi a créer ma première classe avec son fichier H et son CPP.

La ou je rencontre une difficulté c'est pour l'initialisation de ma connexion RS485 avec SoftwareSerial.h. Je n'arrive pas a partagerla meme connexion RS485 entre mes 5 instances de ma classe MonSplitLG.

Auriez vous des pistes ou un tuto sympa ?

#include <LgapController.h>

byte defaultUnit01[] = {0x00,  0x00,  0x00,  0x00,  0x00}; 
byte defaultUnit02[] = {0x00,  0x00,  0x00,  0x00,  0x00}; 
byte defaultUnit03[] = {0x00,  0x00,  0x00,  0x00,  0x00}; 
byte defaultUnit04[] = {0x00,  0x00,  0x00,  0x00,  0x00}; 
byte defaultUnit05[] = {0x00,  0x00,  0x00,  0x00,  0x00};

LgapController verandaGroudCLIMATE(0, 1, defaultUnit01);
LgapController livingRoomCLIMATE(0, 2, defaultUnit02);
LgapController kitchenCLIMATE(0, 3, defaultUnit03);
LgapController verandaFirstCLIMATE(0, 4, defaultUnit04);
LgapController ductCLIMATE(0, 5, defaultUnit05);

void setup()  {
  Serial.begin(115200);
  
  Serial.println("************************************************");
  Serial.println("Project      :  Arduino_ESP32_LG-PI485-Controller");                 
  Serial.println("Author       :  JULLIEN Cédric");
  Serial.println("Date         :  01/10/2022");
  Serial.println("Email        :  cedric.jullien@gmail.com");
  Serial.println("************************************************"); 

  delay(1000);

  Serial.println("------------  Init HVAC Units  ------------"); 
  verandaFirstCLIMATE.initUnit();
  verandaGroudCLIMATE.initUnit();
  ductCLIMATE.initUnit();
  kitchenCLIMATE.initUnit();
  livingRoomCLIMATE.initUnit();
  Serial.println("-------------------------------------------"); 
}

void loop() {
  verandaGroudCLIMATE.process();
  delay(5000);
  livingRoomCLIMATE.process();
  delay(5000);
  kitchenCLIMATE.process();
  delay(5000);
  verandaFirstCLIMATE.process();
  delay(5000);
  ductCLIMATE.process();  
  delay(5000);
}
#ifndef LgapController_h
#define LgapController_h

#include <Arduino.h>
#include <SoftwareSerial.h>

#define RXPin 16  // Serial Receive pin
#define TXPin 17  // Serial Transmit pin
#define SERIAL_COMMUNICATION_CONTROL_PIN 4 	// Transmission set pin
#define LGAP_TX_PIN_VALUE HIGH
#define LGAP_RX_PIN_VALUE LOW

class LgapController {
	public:
		LgapController(byte groupId, byte unitId, byte * defaultData);
		void initUnit();
		void process();
		byte getGroupId();
		byte getUnitId();

	private:
		byte * encodePi485Data(byte groupId, byte unitId, byte EXE, byte power, byte mode, byte desiredTemp, byte fanSpeed, byte autoSwing, byte plasma, byte lock);
		void decodePi485Data(byte * datas);

		void setGroupId(byte groupId);
		void setUnitId(byte unitId);
		void setPower(byte power);
		void setMode(byte mode);
		void setFanSpeed(byte fanSpeed);
		void setAutoSwing(byte autoSwing);
		void setPlasma(byte plasma);
		void setLock(byte lock);
		void setDesiredTemp(byte desiredTemp);
		void setRoomTemp(byte roomTemp);

		byte getPower();
		byte getMode();
		byte getFanSpeed();
		byte getAutoSwing();
		byte getPlasma();
		byte getLock();
		byte getDesiredTemp();
		byte getRoomTemp();

		byte _groupId;
		byte _unitId;
		byte * _unitData;	
};
#endif
#include "Arduino.h"
#include "LgapController.h"

// [00] // Group ID (4bits), Unit ID (4bits)
// [01] // Unused (1bits), Power (1bits), Mode (3bits), Fan speed (3bits) //12 = X 0 010 010
// [02] // Unused (5bits), Auto swing (1bits), Plasma (1bits), Lock (1bits) 
// [03] // desiredTemp
// [04] // roomTemp 
// byte defautUnitData[] = {0x00,  0x00,  0x00,  0x00,  0x00}; 

// TX0 start byte
// TX1 init byte
// TX2 init byte
// TX3 groupId (4bit) & UnitId (4bit)
// TX4 "000" & Plasma (1bit) & "0" & Lock (1bit) & EXE (1bit) & Power ON/OFF (1bit)
// TX5 "0" & Fan speed (3bit) & Auto Swing (1bit) & Mode (3bit)
// TX6 "000" & Desired temperature (5bit)
// TX7 Check Sum = (TX1 + ... + TX6) XOR 0x55
byte defaultPI485Data[] = {0x80, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00}; 

LgapController::LgapController(byte groupId, byte unitId, byte * defaultData) {
    _groupId = groupId;
    _unitId = unitId;
    _unitData = defaultData;
}

void LgapController::initUnit() {
    Serial.print("#LGAP Class# Set group and unit ID: ");
    Serial.print(_groupId);  
    Serial.println(_unitId);  
    setGroupId(_groupId);
    setUnitId(_unitId);

    Serial.print("#LGAP Class# ID: ");
    Serial.print(getGroupId()); 
    Serial.println(getUnitId()); 
}

void LgapController::setGroupId(byte groupId) { _unitData[0] = (groupId << 4) + (_unitData[0] & 0x0F); }
void LgapController::setUnitId(byte unitId) { _unitData[0] = (_unitData[0] & 0xF0) + unitId; }
void LgapController::setPower(byte power) { bitWrite(_unitData[1], 7, power); }
void LgapController::setMode(byte mode) { _unitData[1] &= (mode << 3) + 0x07; }
void LgapController::setFanSpeed(byte fanSpeed) { _unitData[1] &= fanSpeed + 0xF8; }
void LgapController::setAutoSwing(byte autoSwing) { bitWrite(_unitData[2], 2, autoSwing); }
void LgapController::setPlasma(byte plasma) { bitWrite(_unitData[2], 1, plasma); }
void LgapController::setLock(byte lock) { bitWrite(_unitData[2], 0, lock); }
void LgapController::setDesiredTemp(byte desiredTemp) { _unitData[2] = desiredTemp & 0x0F; }
void LgapController::setRoomTemp(byte roomTemp) { _unitData[3] = roomTemp & 0xFF; }

byte LgapController::getGroupId() { return (_unitData[0] & 0xF0) >> 4; }
byte LgapController::getUnitId() { return _unitData[0] & 0x0F; }
byte LgapController::getPower() { return bitRead(_unitData[1], 6); }
byte LgapController::getMode() { return (_unitData[1] & 0x38) >> 3; }
byte LgapController::getFanSpeed() { return _unitData[1] & 0x07; }
byte LgapController::getAutoSwing() { return bitRead(_unitData[2], 2); }
byte LgapController::getPlasma() { return bitRead(_unitData[2], 1); }
byte LgapController::getLock() { return bitRead(_unitData[2], 0); }
byte LgapController::getDesiredTemp() { return _unitData[3] & 0x0F;  }
byte LgapController::getRoomTemp() { return _unitData[4] & 0xFF; }

// Generate RS485 data for PI485
byte * LgapController::encodePi485Data(byte groupId, byte unitId, byte EXE, byte power, byte mode, byte desiredTemp, byte fanSpeed, byte autoSwing, byte plasma, byte lock) {
    uint16_t checkSum = 0x00;

    for (int i = 0; i < 8; i++) {
        if (i == 3) { defaultPI485Data[i] = (groupId << 4) + unitId; }
        if (i == 4) { defaultPI485Data[i] = plasma * 0x10 + lock * 0x04 + EXE * 0x02 + power; }
        if (i == 5) { defaultPI485Data[i] = fanSpeed * 0x10 + autoSwing * 0x08 + mode; }
        if (i == 6) { defaultPI485Data[i] = desiredTemp & 0x1F; }
        if (i == 7) { defaultPI485Data[i] = checkSum ^ 0x55; } else { checkSum = checkSum + defaultPI485Data[i]; }
    }
    return defaultPI485Data;
}

// Convert RS485 received data from PI485
void LgapController::decodePi485Data(byte * datas) {
  uint16_t checkSum = 0x00;
  for (int i = 0; i < 15; i++) {
    checkSum = checkSum + datas[i];
  }
  checkSum = checkSum & 0xFF;
  checkSum = checkSum ^ 0x55;

  bool validDatas = (checkSum == datas[15]);

  if (validDatas) {
    byte groupId = (datas[4] & 0xF0) >> 4;
    Serial.print(" group ID: ");Serial.print(groupId);    
    byte unitId = datas[4] & 0x0F;
    Serial.print(" Unit ID: ");Serial.print(unitId);

    byte power = bitRead(datas[1], 0);
    Serial.print(" Power: ");Serial.print(power);
    // setPower(power);

    byte mode = datas[6] & 0x07;
    Serial.print(" Mode: ");Serial.print(mode);    
    // setMode(mode);

    byte fanSpeed = datas[6] & 0x70 >> 4;
    Serial.print(" Fan speed: ");Serial.print(fanSpeed);  
    // setFanSpeed(fanSpeed);  

    byte autoSwing = bitRead(datas[6], 3);
    Serial.print(" Auto swing: ");Serial.print(autoSwing);  
    // setAutoSwing(autoSwing);

    byte plasma = bitRead(datas[7], 5);
    Serial.print(" Plasma: ");Serial.print(plasma);    
    // setPlasma(plasma);

    byte lock = bitRead(datas[1], 2);
    Serial.print(" Lock: ");Serial.print(lock);
    // setLock(lock);

    // Temperatures
    byte desiredTemp = datas[7] & 0x1F;
    Serial.print(" Desired temp: ");Serial.print(desiredTemp);
    // setDesiredTemp(desiredTemp);   

    byte roomTemp = datas[8];
    Serial.print(" Room temp: ");Serial.print(roomTemp);
    // setRoomTemp(roomTemp);  

    Serial.println("");

  } else {
    Serial.println("Wrong reception");
  }
}

void LgapController::process() {
    byte dataReceived[160];
    byte dataIndex = 0;

    // Convert unit data from parameters
    byte groupId       = getGroupId();     // Group ID
    byte unitId        = getUnitId();      // Unit ID
    byte power         = getPower();       // 1 power ON - 0 power OFF
    byte mode          = getMode();        // 0 Cooling - 1 Dry - 2 Fan - 3 Auto (Monitoring) - 4 Heat
    byte fanSpeed      = getFanSpeed();    // 1 Low - 2 Middle - 3 Hight - 4 Auto (Optional) - 5 Very low (Optional) - 6 Very high (Optional)
    byte autoSwing     = getAutoSwing();   // 1 Auto swing ON - 0 Auto Swing OFF
    byte plasma        = getPlasma();      // 1 plasma ON - 0 plasma OFF
    byte lock          = getLock();        // 1 Lock - 0 Unlock
    byte desiredTemp   = getDesiredTemp(); // Temperature table
    byte roomTemp      = getRoomTemp();    // Temperature table

    Serial.print("Send data to PI485:");
    Serial.print(" UNIT ID:");Serial.print(groupId);Serial.print(unitId);
    Serial.print(" Power:");Serial.print(power);
    Serial.print(" Mode:");Serial.print(mode);
    Serial.print(" Fan speed:");Serial.print(fanSpeed);
    Serial.print(" Plasma:");Serial.print(plasma);
    Serial.println("");

    int EXE = 0;  
    for (int i = 1; i <= 4; i++) {
        digitalWrite(SERIAL_COMMUNICATION_CONTROL_PIN, LGAP_TX_PIN_VALUE); // Init transmit

        if (i <= 3) { 
            EXE = 1; 
        } else { 
            EXE = 0; 
        } // Set to 1 for 3times then set to 0

        byte * msg = encodePi485Data(groupId, unitId, EXE, power, mode, desiredTemp, fanSpeed, autoSwing, plasma, lock);
        for (int i = 0; i < 8; i++) {
            Serial.print(msg[i], HEX);
            if (i < 7){ Serial.print(", "); } else if (i == 7) { Serial.println(""); }
            LGAPSerial.write(msg[i]);
        } 

        delayMicroseconds(2200);

        // if (EXE == 0) {
          Serial.print("Receive data from PI485:");
          digitalWrite(SERIAL_COMMUNICATION_CONTROL_PIN, LGAP_RX_PIN_VALUE); // Init receive
            
          while(LGAPSerial.available() > 0) {
            byte b = LGAPSerial.read();
            dataReceived[dataIndex++] = b;
          }

          if (dataIndex == 16) {
            decodePi485Data(dataReceived);
            dataIndex = 0;
          } else {
            Serial.print("ERROR dataIndex: ");Serial.println(dataIndex);
          }
        // }
        delay(100);
    }    
}

J'ai posté mon code ce sera plus simple d'expliquer :wink:

Dans ma classe j'ai une méthode process() qui doit partager la connexion série entre toutes les instances de ma classe.

J'ai vu des post ou l'on parle de définir ma ressource SoftwareSerial dans un pointeur mais j'y arrive pas.

Merci d'avance pour votre aide.

Salut.
Je pense que tu veux parler de l'objet LGAPSerial, dont je ne vois pas de déclaration nulle part dans ton code.
Tu pourrais ajouter un membre du type SoftwareSerial nommé LGAPSerial à la classe et un argument du type SoftwareSerial au constructeur, et celui-ci stockerait la valeur dans le membre LGAPSerial.

// Au niveau de la classe :
	private:
          // ...
          SoftwareSerial LGAPSerial;

// Au niveau du contructeur :
        public:
		LgapController(SoftwareSerial& serial, byte groupId, byte unitId, byte * defaultData);

LgapController::LgapController(SoftwareSerial& serial, byte groupId, byte unitId, byte * defaultData) {
    LGAPSerial = serial;
    _groupId = groupId;
    _unitId = unitId;
    _unitData = defaultData;
}

// Au niveau de la déclaration : 

SoftwareSerial mySerial(RXPin, txPin);
LgapController verandaGroudCLIMATE(mySerial, 0, 1, defaultUnit01);
LgapController livingRoomCLIMATE(mySerial, 0, 2, defaultUnit02);
// etc.

Là je suis passé par une référence SoftwareSerial& serial.
Mais tu pourrais aussi passer par un pointeur SoftwareSerial *serial, mais ensuite il faudrait modifier :

// Au niveau de la classe :
	private:
          // ...
          SoftwareSerial *LGAPSerial;

// Au niveau du contructeur :
        public:
		LgapController(SoftwareSerial *serial, byte groupId, byte unitId, byte * defaultData);

LgapController::LgapController(SoftwareSerial *serial, byte groupId, byte unitId, byte * defaultData) {
    LGAPSerial = serial;
    _groupId = groupId;
    _unitId = unitId;
    _unitData = defaultData;
}

// Au niveau de la déclaration : 

SoftwareSerial mySerial(RXPin, txPin);
LgapController verandaGroudCLIMATE(&mySerial, 0, 1, defaultUnit01);
LgapController livingRoomCLIMATE(&mySerial, 0, 2, defaultUnit02);
// etc.

Ce qui est assez perturbant en C++ est que & sert à désigner une référence, mais aussi l'adresse d'un objet (un pointeur), comme en C.

Autre différence :

Avec une référence :

            byte b = LGAPSerial.read();

Avec un pointeur :

            byte b = LGAPSerial->read();

Un conseil : évite de laisser traîner ton nom, prénom, adresse mail sur un forum.
A moins que ce soit des fakes ?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.