Nie zmieniają się wszystkie stany za pomocą channelValueChanged

Awatar użytkownika
pzygmunt
Posty: 9613
Rejestracja: wt sty 19, 2016 9:26 am
Lokalizacja: Paczków
Kontaktowanie:

pn cze 10, 2019 2:41 pm

setStatusFuncImp to funkcja która jest wywoływana jak zmienia się stan połączenia z serwerem z wifi.
Jak zmienisz przyciskiem stan przekaźnika to serwer nie zostanie powiadomiony.

Coś źle nadal robisz jak masz takie opóźnienia. Może Cię rozłącza. Musisz sobie to bardziej precyzyjnie zdebugować.
krycha88
Posty: 914
Rejestracja: pt lis 16, 2018 7:25 am

pn cze 10, 2019 2:48 pm

pzygmunt pisze:
pn cze 10, 2019 2:41 pm
setStatusFuncImp to funkcja która jest wywoływana jak zmienia się stan połączenia z serwerem z wifi.
Jak zmienisz przyciskiem stan przekaźnika to serwer nie zostanie powiadomiony.
Dzięki tej funkcji chcę tylko ustawić zapisany stany przekaźnika w apce po nawiązaniu połączenia. Obsługę przekaźników mam zrobioną w SuplaDevice.setDigitalWriteFuncImpl.

Jeszcze raz dziękuje za pomoc :)
vajera
Posty: 179
Rejestracja: śr paź 31, 2018 7:58 am

pn cze 10, 2019 3:23 pm

krystianmen pisze:
pn cze 10, 2019 2:30 pm
w setup() dodałem SuplaDevice.setStatusFuncImpl(&status_func) później:

Kod: Zaznacz cały

void status_func(int status, const char *msg) {
  if ( status == 17 ) {
    Serial.println("wczytano stan przelacznikow");
    SuplaDevice.channelValueChanged(0, read_supla_relay_state(0));
    SuplaDevice.channelValueChanged(1, read_supla_relay_state(1));
    SuplaDevice.channelValueChanged(2, read_supla_relay_state(2));
  }
}
Chyba jest to już lepsze rozwiązanie niż moje pierwotne? Nie wiem jak bym miał do tego wykorzystać impl_arduino_timer.
Właśnie o coś takiego pytałem :D
EDIT: przy okazji to chyba dobre miejsce na sprawdzanie połączenia z serwerem:
if (status == STATUS_DISCONNECTED) {wejdź w tryb pracy samodzielnej - termostat, pompy itp.)
Awatar użytkownika
Herrero
Posty: 26
Rejestracja: śr wrz 25, 2019 7:29 am
Lokalizacja: Wrocław

pt kwie 24, 2020 1:23 pm

Hej,
Czy poradziliście sobie z tym problem. Piszę soft pod sterownik podlewania. Mam esp8266 i podłączoną do tego płytkę z 4 przekaźnikami (po i2c). Muszę to mieć tak napisane, że nigdy nie mogą się naraz włączyć dwa przekaźniki. Napisałem kod, który przełącza przekaźniki ale mam taki sam problem z aktualizacją statusu na serwerze i w aplikacji. Pojawiają się w opóźnieniem 25-30 sekund. Załóżmy, że działa przekaźnik 2 i chcę zmienić na 3. Klikam 3 i zmienia mi się aktywny przekaźnik. Jednocześnie wysyłam update na serwer no i zmuła 30s. Dodam, że jak będę klikał z apki ręcznie włącz wyłącz dany kanał to działa od razu. Tak samo ze strony działa od razu. Problem jest tylko z wysłanie stanu na serwer. Zmodyfikowałem kolejkę z srpc i nic. Zamieszczam też mój kod (nie jest skończony bo zblokowała mnie ta sprawa).

Kod: Zaznacz cały

#define WDT D7
#define SW_1 D6
#define RS_1 D5

#include <srpc.h>
#include <log.h>
#include <eh.h>
#include <proto.h>
#include <IEEE754tools.h>
// We define our own ethernet layer
#define SUPLADEVICE_CPP
#include <SuplaDevice.h>
#include <lck.h>

//#include <WiFiClient.h>
//#include <ESP8266WiFiType.h>
#include <ESP8266WiFi.h>
//#include <ESP8266WiFiScan.h>
//#include <ESP8266WiFiMulti.h>
//#include <WiFiServer.h>
//#include <ESP8266WiFiGeneric.h>
//#include <WiFiClientSecure.h>
//#include <ESP8266WiFiAP.h>
//#include <ESP8266WiFiSTA.h>
//#include <WiFiUdp.h>
#include <ESP8266HTTPClient.h>
#include <TimeLib.h>
#include "PCF8574.h"
#include <LiquidCrystal_PCF8574.h>
#include <Wire.h>

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "Hatak";
char password[] = "##################";
String buff;

//User variable
unsigned long previousMillisRelayAgent = 0, previousMillisDebug = 0, previousMillisLcdAgent = 0, previousMillisErrorAgent = 0;
uint8_t GLOBAL_STATE = 1, sinceRain = 0;
uint8_t buttonBounceBlocker = 0, buttonBounceBlocker2 = 0;
uint8_t currentRelayBoardState = 255;
uint8_t activeSection = 0;
uint16_t workTime = 0; //maksymalny czas pracy sterownika (ciągły czas podlewania)
uint8_t workTimeH = 0, workTimeM = 0, workTimeS = 0;
uint8_t error = 0; //flaga błedów
char line[60]; //zmienna wykorzystywana przy wyswietlaniu danych na lcd i nie tylko
unsigned long relayAgentTimeout = 0;  //zmienna wykorzystywana przez agenta przekaźników
int heartbeat = LOW; //resetowanie zewnętrznego watchdoga

class BUTTON{
  public:
  uint8_t button; //przycisk
  uint8_t state;  //status przyciska
  uint16_t pressTime;
  unsigned long timeTick; //znacznik czasowy

  BUTTON(uint8_t val_button = 0, uint8_t val_state = 0, uint16_t val_pressTime = 0, unsigned long val_timeTick = 0){
    button = val_button;
    state = val_state;
    pressTime = val_pressTime;
    timeTick = val_timeTick; 
  }
  
  uint8_t checkButton();
};

uint8_t BUTTON::checkButton(){
  if(!digitalRead(button)) {  //obsługa przycisku
    if((millis() >= timeTick)) {
      timeTick = millis() + 50;
      pressTime++;
      if (pressTime >= 10) state = 2; //zwraca 2 jak klawisz wcisniety dluzej niz 5000ms (100*50)
    }      
  } 
  else {
    if ((pressTime > 0) && (pressTime < 10)) state = 1; //zwraca 1 jak klawisz wcisniety poniżej niz 5000ms (20*50)
    else state = 0; //zwraca 0 jak klawisz nie wcisniety
    pressTime = 0;
  }  
  return state;
}

PCF8574 relayBoard(0x20);
LiquidCrystal_PCF8574 lcd(0x27);  

BUTTON SW(SW_1, 0, 0, 0);  //przycisk membranowy

WiFiClient client;

void setup()
{
  // Debug console
  Serial.begin(115200);
  pinMode(SW_1, INPUT_PULLUP);
  pinMode(RS_1, INPUT_PULLUP);
  pinMode(WDT, OUTPUT);
  
  relayBoard.begin();
  relayBoard.write(1,HIGH); //realy 1 off
  relayBoard.write(2,HIGH); //realy 2 off
  relayBoard.write(3,HIGH); //realy 3 off
  relayBoard.write(4,HIGH); //realy 4 off
  relayBoard.write(5,HIGH); //realy 5 off
  relayBoard.write(6,HIGH); //realy 6 off
  relayBoard.write(7,HIGH); //realy 7 off
  relayBoard.write(8,HIGH); //realy 8 off
  //currentRelayBoardState = relayBoard.read8(); 
        currentRelayBoardState = 255; 

  lcd.begin(20, 4);       // initialize the lcd
  lcd.setBacklight(255);  //turn on backlight

  WiFi.mode(WIFI_STA); // Force to station mode because if device was switched off while in access point mode it will start up next time in access point mode.

  uint8_t mac[WL_MAC_ADDR_LENGTH];
  WiFi.macAddress(mac);
  char GUID[SUPLA_GUID_SIZE] = {mac[WL_MAC_ADDR_LENGTH - 6], mac[WL_MAC_ADDR_LENGTH - 5], mac[WL_MAC_ADDR_LENGTH - 4], mac[WL_MAC_ADDR_LENGTH - 3],                                
                                mac[WL_MAC_ADDR_LENGTH - 2], mac[WL_MAC_ADDR_LENGTH - 1], mac[WL_MAC_ADDR_LENGTH - 6], mac[WL_MAC_ADDR_LENGTH - 5], 
                                mac[WL_MAC_ADDR_LENGTH - 4], mac[WL_MAC_ADDR_LENGTH - 3], mac[WL_MAC_ADDR_LENGTH - 2], mac[WL_MAC_ADDR_LENGTH - 1]};
          
  SuplaDevice.addRelay(100);         //włacznik główny        
  SuplaDevice.addSensorNO(RS_1);     //czujnik deszczu NC
  SuplaDevice.addRelay(101, false);  //elektrozawór sekcja 1 
  SuplaDevice.addRelay(102, false);  //elektrozawór sekcja 2
  SuplaDevice.addRelay(103, false);  //elektrozawór sekcja 3
  SuplaDevice.addRelay(104, false);  //elektrozawór sekcja 4
  // SuplaDevice.addRelay(105, false);  
  // SuplaDevice.addRelay(106, false); 
  // SuplaDevice.addRelay(107, false);   
  // SuplaDevice.addRelay(108, false);

  SuplaDevice.setDigitalReadFuncImpl(&supla_DigitalRead);    //            ------Send Value to server -------
  SuplaDevice.setDigitalWriteFuncImpl(&supla_DigitalWrite);   //        -------  Read Value from server   -------
  // SuplaDevice.setTimerFuncImpl(&supla_timer);
  // SuplaDevice.setStatusFuncImpl(&status_func);    //   ----------------------------- Status -----------------------------
  SuplaDevice.setName("nawadniarka");

  // // Replace the falowing GUID
  // char GUID[SUPLA_GUID_SIZE] = {0x96,0x4D,0x66,0x3A,0x50,0x89,0xA0,0x64,0x0C,0x73,0x68,0x52,0x23,0xFF,0x99,0x0C};
  // // with GUID that you can retrieve from https://www.supla.org/arduino/get-guid

  // // Ethernet MAC address
  // uint8_t mac[6] = {0x51, 0xef, 0x05, 0xf0, 0x9f, 0x00};

  SuplaDevice.begin(GUID,              // Global Unique Identifier 
                    mac,               // Ethernet MAC address
                    "suplacloud.herrero-net.com",  // SUPLA server address
                    2,                 // Location ID 
                    "XXXX");               // Location Password

  //InfluxDB_save_bootUP(); //save to starbase boot up event
}

void loop()
{    
  if (heartbeat == LOW) heartbeat = HIGH;       //kasowanie zewnętrznego watchdoga
  else heartbeat = LOW;
  digitalWrite(WDT, heartbeat);
  
  SW.checkButton();

  // if (GLOBAL_STATE && (SW.state == 2) && !buttonBounceBlocker2) {
  //   buttonBounceBlocker2 = 5;
  //   GLOBAL_STATE = 0;
  // }
  // else if (!GLOBAL_STATE && (SW.state == 2) && !buttonBounceBlocker2) {
  //   buttonBounceBlocker2 = 5;
  //   GLOBAL_STATE = 1;
  // }  
  
  yield();
  SuplaDevice.iterate();
  if (GLOBAL_STATE && !error) relayAgent();
  else if (!GLOBAL_STATE && !error) {
    activeSection = 0;
    relayAgent();
  }
  lcdAgent();



  unsigned long currentMillisErrorAgent = millis();  //zabezpieczenie przed zbyt długą praca
  if ((currentMillisErrorAgent - previousMillisErrorAgent) >= 1000) {                                 //wykonuj co 1s
    previousMillisErrorAgent = currentMillisErrorAgent;

    if (activeSection && (workTime < 3600)) workTime++;  //zwiekszanie licznik pracy (pojedyncza sekcja nie moze pracowac dłuzej niz 1h)
    else if (activeSection && (workTime == 3600)) {
      workTime++;
      error = 1;
      activeSection = 0;
      relayAgent();
    }
    else workTime = 0;

    //czujnik deszczu
    if(digitalRead(RS_1)){
      sinceRain = 0;
    }
    else sinceRain++;

  }  

}

void lcdAgent(){    //odswiezanie wyswietlacza
  unsigned long currentMillis = millis();
  if ((currentMillis - previousMillisLcdAgent) >= 1000) {                                 //wykonuj co 1s
    previousMillisLcdAgent = currentMillis;

    lcd.home();
    sprintf(line, "%02d.%02d.%04d     %02d:%02d", day(), month(), year(), hour(), minute());
    lcd.print(line);
    lcd.setCursor(0,1);
    sprintf(line, "Sekcja: %1d WT: %02dm%02ds", activeSection, workTime / 60, workTime % 60);
    lcd.print(line);
    lcd.setCursor(0,2);
    if (sinceRain) sprintf(line, "Deszcz -> jest mokro");
    else sprintf(line, "Od opadow:   %03dd%02dg", sinceRain / (24*3600), sinceRain % (24*3600));
    lcd.print(line);
    lcd.setCursor(0,3);
    if (error) sprintf(line, "Tryb: ERROR   % 2ddBm", WiFi.RSSI());
    else if (!client.connected()) sprintf(line, "Tryb: offline % 2ddBm", WiFi.RSSI());
    else if (sinceRain) sprintf(line, "Tryb: pauza   % 2ddBm", WiFi.RSSI());
    else if (GLOBAL_STATE) sprintf(line, "Tryb:  ON     % 2ddBm", WiFi.RSSI());
    else if (!GLOBAL_STATE) sprintf(line, "Tryb: OFF     % 2ddBm", WiFi.RSSI());
    lcd.print(line);
  }
}

void relayAgent (){                                                           //obsługa przekaźników sekcji
  unsigned long currentMillis = millis();
  if ((currentMillis - previousMillisRelayAgent) >= 1000) {                   //wykonuj co 1s
    previousMillisRelayAgent = currentMillis;

    uint8_t newRelayBoardState = 255;                                         //domyślna wartość maski - wszystkie przekaźniki wyłaczone
    if (activeSection) newRelayBoardState = ~(1 << (activeSection - 1));      //zmiana maski - wlaczenie wybranej sekcji (zero na odpowienie miejsce)

    if (currentRelayBoardState == newRelayBoardState) return;                 //jeśli nie ma potrzeby nie zmieniaj stanu - wyjscie z funkcji

    if (currentRelayBoardState == 255) {                                      //zmiana stanu z wyłaczony na wybraną sekcję
      relayBoard.write8(newRelayBoardState);
      //currentRelayBoardState = relayBoard.read8();                            //zapis aktualnego stanu
            currentRelayBoardState = newRelayBoardState;
      Serial.print("OFF -> ");
      Serial.println(currentRelayBoardState, BIN);
      supla_RelayValueChanged();                                              //synchronizacja z serwerem Supli
    }
    else if (currentRelayBoardState != 255) {                                 //zmiana z włączonej sekcji na wyłączony (w kolejnym cyklu właczy się odpowienia sekcja)
      relayBoard.write8(255);
      //currentRelayBoardState = relayBoard.read8();                            //zapis aktualnego stanu
            currentRelayBoardState = 255;
      Serial.print(currentRelayBoardState, BIN); 
      Serial.println(" - > OFF");
      if (newRelayBoardState == 255) supla_RelayValueChanged();               //synchronizacja z serwerem Supli, tylko gdy nie będzie zmiany przekaźnika
    }

  }
}

void supla_RelayValueChanged(){
  //uint8_t currentRelayBoardState = relayBoard.read8();

  SuplaDevice.channelValueChanged(2, !(currentRelayBoardState & 0x01));
  SuplaDevice.channelValueChanged(3, !(currentRelayBoardState & 0x02));
  SuplaDevice.channelValueChanged(4, !(currentRelayBoardState & 0x04));
  SuplaDevice.channelValueChanged(5, !(currentRelayBoardState & 0x08));

  // SuplaDevice.channelValueChanged(7, !(currentRelayBoardState & 0x10));
  // SuplaDevice.channelValueChanged(8, !(currentRelayBoardState & 0x20));
  // SuplaDevice.channelValueChanged(9, !(currentRelayBoardState & 0x40));
  // SuplaDevice.channelValueChanged(10, !(currentRelayBoardState & 0x80));

}

void InfluxDB_save_bootUP(){

  String data;
  data += "ctrl_ogrod,";
  data += "sensor=bootUP"; 
  data += " value=1"; 

  //Serial.println(data);

  HTTPClient http;
  http.begin("http://10.10.10.250:8086/write?db=starbase&precision=s&u=starsystem&p=XXXXX");
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  http.POST(data);
  //http.writeToStream(&data);
  http.end();
}

// void InfluxDB_save_state(){

//   String data;
//   data += "ctrl_ogrod,";
//   data += "sensor=Sx";
//   switch (activeSection) {
//     case 0:
//         data += " value=0";
//       break;
//     case 1:
//         data += " value=1";
//       break;
//     case 2:
//         data += " value=2";    
//       break;
//     case 3:
//         data += " value=3";    
//       break;
//     case 4:
//         data += " value=4";    
//       break;
//   }
 
// //  data += "sensor=S1"; 
// //  if (activeSection == 1)data += " value=1";
// //  else data += " value=0";
// //  data += '\n';  
// //  data += "ctrl_ogrod,";
// //  data += "sensor=S2"; 
// //  if (activeSection == 2) data += " value=1";
// //  else data += " value=0";
// //  data += '\n';  
// //  data += "ctrl_ogrod,";
// //  data += "sensor=S3"; 
// //  if (activeSection == 3) data += " value=1";
// //  else data += " value=0";
// //  data += '\n';  
// //  data += "ctrl_ogrod,";
// //  data += "sensor=S4"; 
// //  if (activeSection == 4) data += " value=1";
// //  else data += " value=0";
//   data += '\n';   
//   data += "ctrl_ogrod,";
//   data += "sensor=autoMode";  
//   if (autoMode == 1) data += " value=1";
//   else data += " value=0"; 
//   data += '\n';   
//   data += "ctrl_ogrod,";
//   data += "sensor=globalState";  
//   if (GLOBAL_STATE == 1) data += " value=1";
//   else data += " value=0";   
//   data += '\n';   
//   data += "ctrl_ogrod,";
//   data += "sensor=rainSensor";  
//   if (digitalRead(RS_1) == 1) data += " value=1";
//   else data += " value=0";     
//   //Serial.println(data);

//   HTTPClient http;
//   http.begin("http://10.10.10.250:8086/write?db=starbase&precision=s&u=starsystem&p=tst12xvn");
//   http.addHeader("Content-Type", "application/x-www-form-urlencoded");
//   http.POST(data);
//   //http.writeToStream(&data);
//   http.end();
// }

//#########################################################################################################
// Supla.org ethernet layer
int supla_arduino_tcp_read(void *buf, int count) {
  _supla_int_t size = client.available();

  if ( size > 0 ) {
      if ( size > count ) size = count;
      return client.read((uint8_t *)buf, size);
  };

  return -1;
};

int supla_arduino_tcp_write(void *buf, int count) {
  return client.write((const uint8_t *)buf, count);
};

bool supla_arduino_svr_connect(const char *server, int port) {
  return client.connect(server, 2015);
}

bool supla_arduino_svr_connected(void) {
  return client.connected();
}

void supla_arduino_svr_disconnect(void) {
  client.stop();
}
    
void supla_arduino_eth_setup(uint8_t mac[6], IPAddress *ip) {

  // Serial.println("WiFi init");
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
  //    Serial.print(".");
}

//Serial.print("\nlocalIP: ");
//Serial.println(WiFi.localIP());
//Serial.print("subnetMask: ");
//Serial.println(WiFi.subnetMask());
//Serial.print("gatewayIP: ");
//Serial.println(WiFi.gatewayIP());
}

SuplaDeviceCallbacks supla_arduino_get_callbacks(void) {
  SuplaDeviceCallbacks cb;
  
  cb.tcp_read = &supla_arduino_tcp_read;
  cb.tcp_write = &supla_arduino_tcp_write;
  cb.eth_setup = &supla_arduino_eth_setup;
  cb.svr_connected = &supla_arduino_svr_connected;
  cb.svr_connect = &supla_arduino_svr_connect;
  cb.svr_disconnect = &supla_arduino_svr_disconnect;
  cb.get_temperature = NULL;
  cb.get_temperature_and_humidity = NULL;
  cb.get_rgbw_value = NULL;
  cb.set_rgbw_value = NULL;
  
  return cb;
}

int supla_DigitalRead(int channelNumber, uint8_t pin) {

  int result = 0;
  if ((pin >= 101) && (pin <=108)) {
    if ((pin == 101) && (activeSection == 1)) result = 1;
    else if ((pin == 102) && (activeSection == 2)) result = 1;
    else if ((pin == 103) && (activeSection == 3)) result = 1;
    else if ((pin == 104) && (activeSection == 4)) result = 1;
    else result = 0;

    Serial.print("Supla Read(");
    Serial.print(pin);
    Serial.print("): ");
    Serial.println(result);
  }
  else if (pin == 100) {
    if (GLOBAL_STATE) result = 1;
    else result = 0;
  }
  else result = digitalRead(pin);

  return result;
}

void supla_DigitalWrite(int channelNumber, uint8_t pin, uint8_t val) {

  Serial.print("Supla Write(");
  Serial.print(channelNumber);
  Serial.print(",");
  Serial.print(pin);
  Serial.print(",");
  Serial.print(val);
  Serial.println(")");
  if ((pin >= 101) && (pin <=108)) {
    if ((pin == 101) && val) activeSection = 1;
    else if ((pin == 102) && val) activeSection = 2;
    else if ((pin == 103) && val) activeSection = 3;
    else if ((pin == 104) && val) activeSection = 4;
    else activeSection = 0;
  }
  else if (pin == 100) {
    if (val) GLOBAL_STATE = 1;
    else GLOBAL_STATE = 0;
  } 
  
  else digitalWrite(pin, val);
}

void status_func(int status, const char *msg) {
  if (status == 17) {
    Serial.println("zapis na serwer Supla");
    //SuplaDevice.channelValueChanged(1, digitalRead(POWER));
  }
}
elmaya
Posty: 1028
Rejestracja: śr cze 27, 2018 5:48 pm
Lokalizacja: Sevilla

pt kwie 24, 2020 2:03 pm

you can't send everything at once.
this does not work:

Kod: Zaznacz cały

void supla_RelayValueChanged(){
  //uint8_t currentRelayBoardState = relayBoard.read8();

  SuplaDevice.channelValueChanged(2, !(currentRelayBoardState & 0x01));
  SuplaDevice.channelValueChanged(3, !(currentRelayBoardState & 0x02));
  SuplaDevice.channelValueChanged(4, !(currentRelayBoardState & 0x04));
  SuplaDevice.channelValueChanged(5, !(currentRelayBoardState & 0x08));

  // SuplaDevice.channelValueChanged(7, !(currentRelayBoardState & 0x10));
  // SuplaDevice.channelValueChanged(8, !(currentRelayBoardState & 0x20));
  // SuplaDevice.channelValueChanged(9, !(currentRelayBoardState & 0x40));
  // SuplaDevice.channelValueChanged(10, !(currentRelayBoardState & 0x80));

}

or you send only those that have changed (with 2 channel simultaneous it worked fine) or in a sequence one channel in each main loop.
Awatar użytkownika
Herrero
Posty: 26
Rejestracja: śr wrz 25, 2019 7:29 am
Lokalizacja: Wrocław

pn maja 11, 2020 10:16 pm

Dziękuję za pomoc. Teraz wysyłam tylko to co jest konieczne i działa. Mam jeszcze jedno pytanie. Jak elegancko ustawić statusy na serwerze hurtem po restarcie. Czy użycie callback jak to proponuje krych88 jest poprawne i eleganckie?
krycha88 pisze:
pn cze 10, 2019 2:30 pm
w setup() dodałem SuplaDevice.setStatusFuncImpl(&status_func) później:

Kod: Zaznacz cały

void status_func(int status, const char *msg) {
  if ( status == 17 ) {
    Serial.println("wczytano stan przelacznikow");
    SuplaDevice.channelValueChanged(0, read_supla_relay_state(0));
    SuplaDevice.channelValueChanged(1, read_supla_relay_state(1));
    SuplaDevice.channelValueChanged(2, read_supla_relay_state(2));
  }
}
Chyba jest to już lepsze rozwiązanie niż moje pierwotne? Nie wiem jak bym miał do tego wykorzystać impl_arduino_timer.
ODPOWIEDZ

Wróć do „Pomoc”