Posílání více "položek" komunikací pomocí STRUCT

Wiring, C++, C, Java, ...
Pravidla fóra
Toto subfórum slouží k řešení obecných otázek kolem programování (konstrukce, knihovny, alokace paměti, ...)
Uživatelský avatar
pavel1tu
Příspěvky: 2054
Registrován: 26 říj 2017, 08:28
Reputation: 0
Bydliště: Trutnov
Kontaktovat uživatele:

Posílání více "položek" komunikací pomocí STRUCT

Příspěvek od pavel1tu » 25 led 2020, 20:51

Asi to většina lidí zná, ale hodím to sem - třeba to někdo kdo se v tom plácá jako já využije.
Úvodní omáčka - klidně odstavec přeskočte ;)
Jak v alarmu, meteostanici, řízení domu potřebuji posílat vícero informací - na druhé straně je roztřídit. Zatím jsem to dle příkladů řešil nějakým "tříděním" v přijímací stanici/centrální jednotce. Problém to nikdy nebyl, až do stavby meteostanic. Už jich funguje 8, a na přenos dat od čidel každý chtěl něco jiného (RFM69xx, HC12 a podobné, nRF24, cokoliv co funguje jako séroivá linka). Na meteostanici držím jeden kod a druhy přenosu mám ve funkcích, tudíž to na přijímací straně pěkně kyne.

Pak jsem objevil náhodou metodu pomocí STRUCT ...

Co to řeší:
- posílání více hodnot/informací po komunikaci najednou, v jednom balíku.
- automatické jednoduché "roztřídění" na jednotlivé informace na straně příjmu.

Na vysílací i přijímací straně MUSÍ být stejně vytvořená struktura dat. Třeba takto:

Kód: Vybrat vše

// kod neřeší knihovny, proměnné - jen nastińuje princip

                                // struktura pro odesilani z ext.cidla musi byt identicka 
                                // jako struktura pro prijem z tohoto cidla
                                     // jednotlivé proměnné jsou ještě jednou nadefinovány mimo strukturu pro vyčítání z čidel 
                                     // - z historických důvodů, budu to rušit a data ukládat do packet.xxxx hned po vyčtení
typedef struct {        // struktura paketu pro odeslání
  uint32_t sensorId;  // ID senzoru
  float T;                  // teplota
  int H;                    // vlhkost
  int P;                    // tlak
  int W;                   // rychlost větru
  int G;                   // maximalni rychlost vetru za tento den
  int B;                   // smer vetru
  int R;                   // srazky - kumulativne za cely den
  int RR;                 // srazky -prumer za hodinu
  int S;                   // svit slunce - W/m2
  int UV;                // UV index
  int SS;                 // svit slunce za den - minut
  int CC;                // oblacnost
} dataPacket;
Data pak odešleme jako balík najednou (příklad pro nRF24, ale funguje mi to všude kde jsem to testoval)

Kód: Vybrat vše

//--------------------------------------------------------------------------------- 
//                     Odeslani dat na zakladnu - nRF24
//---------------------------------------------------------------------------------
   void OdeslatData(){
    
    dataPacket packet;
         
    packet.sensorId = sensorId;   // načtení čerstvých dat co vyčetly senzory - každý senzor je samostatná funkce
    packet.T = T;                        // jen nastiňuji potřebu vložit data, klidně hne dpo vyčtení z čidla, zde z proměnné
    packet.P = P;
    packet.W = W;
    packet.G = G;
    packet.B = B;
    packet.R = R;
    packet.RR = RR;
    packet.S = S;
    packet.UV = UV;
    packet.SS = SS;
    packet.CC = CC;

    radio.write(&packet, sizeof(dataPacket));     //odeslani
    delay(10*sizeof(dataPacket));                       //zatim netusim kolik minimalne postacuje
    
   }
Přijmeme podobně a hned roztřídíme, příklad jen pro výpis na seriovou linku, ale lze uložit do proměnné, nebo hned s daty pracovat.

Kód: Vybrat vše

  if (radio.available()) {
    radio.read(&packet, sizeof(dataPacket));
    delay(10*sizeof(dataPacket));  // asi není potřeba

        Serial.print("Prijato ID= ");
        Serial.println(packet.sensorId);
        Serial.print("Teplota T= ");
        Serial.println(packet.T);
        Serial.print("Tlaka P= ");
        Serial.println(packet.P); 
        Serial.print("Vlhkost H= ");
        Serial.println(packet.H); 
        
        // a tak dale
Mne nadchla jednoduchost - nikde jsem na to nenarazil, ani zde na foru.
jediné co netuším je max. delka "paketu" a spolehlivost při větším objemu dat.
UNO, NANO, Mikro, PRO mini, DUE, ESP32S2, RPi PICO
Pavel1TU
"Správně napsaný kod lze číst jako knihu"

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: Posílání více "položek" komunikací pomocí STRUCT

Příspěvek od ondraN » 26 led 2020, 09:00

K tomu mám jedinou poznámku. Překlad kódu na obou stranách musí být proveden stejným překladačem a nejlépe na stejných platformách. Interní formát struktury řeší překladač a pokud bych podobný přenos udělal třeba mezi kódem přeloženým ve Visual Studiu na PC a arduinem, tak to nedopadne dobře.

Uživatelský avatar
pavel1tu
Příspěvky: 2054
Registrován: 26 říj 2017, 08:28
Reputation: 0
Bydliště: Trutnov
Kontaktovat uživatele:

Re: Posílání více "položek" komunikací pomocí STRUCT

Příspěvek od pavel1tu » 26 led 2020, 16:55

ondraN píše:
26 led 2020, 09:00
K tomu mám jedinou poznámku. Překlad kódu na obou stranách musí být proveden stejným překladačem a nejlépe na stejných platformách. Interní formát struktury řeší překladač a pokud bych podobný přenos udělal třeba mezi kódem přeloženým ve Visual Studiu na PC a arduinem, tak to nedopadne dobře.
Díky, toto jsem si neuvědomil a je to málo pravděpodobné, většinou to stavíme, programujeme i nahráváme jako celek a na jedné platformě.

Takže kamarád co má na centrálce SAM32 má smůlu ? Dobře mu tak ... takle vybočovat z řady.
UNO, NANO, Mikro, PRO mini, DUE, ESP32S2, RPi PICO
Pavel1TU
"Správně napsaný kod lze číst jako knihu"

KamilV
Příspěvky: 479
Registrován: 03 dub 2018, 15:27
Reputation: 0
Bydliště: Olomouc

Re: Posílání více "položek" komunikací pomocí STRUCT

Příspěvek od KamilV » 26 led 2020, 19:18

V té struktuře figuruje int a float, chce to porovnat, jak se int a float ukládá v paměti na SAM32, pokud stejně jako v Arduinu (int 2 B, float 4 B) tak by to mohlo být v pohodě.

Jistotou pak samozřejmě bude formát, který právě eliminuje rozdílnost platforem, tedy např. XML, JSON apod.

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: Posílání více "položek" komunikací pomocí STRUCT

Příspěvek od ondraN » 26 led 2020, 19:24

pavel1tu píše:
26 led 2020, 16:55
ondraN píše:
26 led 2020, 09:00
K tomu mám jedinou poznámku. Překlad kódu na obou stranách musí být proveden stejným překladačem a nejlépe na stejných platformách. Interní formát struktury řeší překladač a pokud bych podobný přenos udělal třeba mezi kódem přeloženým ve Visual Studiu na PC a arduinem, tak to nedopadne dobře.
Díky, toto jsem si neuvědomil a je to málo pravděpodobné, většinou to stavíme, programujeme i nahráváme jako celek a na jedné platformě.

Takže kamarád co má na centrálce SAM32 má smůlu ? Dobře mu tak ... takle vybočovat z řady.
To záleží na tom, jak jeho překladač uspořádá tu strukturu. U jednočipáků je to docela kompatibilní, pokud mají použité typy stejný rozsah (pak bývá i stejná interpretace). Pořadí prvků nechává překladač bezezměn. Nejhorší je to ale mezi jednočipákem a PC, kde má třeba float 8byte a více, int 4byte a překladač si navíc dělá různé zarovnání paměti, aby třeba všechny prvky začínaly na sudé nebo liché adrese paměti.

KamilV
Příspěvky: 479
Registrován: 03 dub 2018, 15:27
Reputation: 0
Bydliště: Olomouc

Re: Posílání více "položek" komunikací pomocí STRUCT

Příspěvek od KamilV » 26 led 2020, 21:53

Máš nějaký zdroj o tom zarovnávání v paměti? Rád bych si početl, to jsem ani netušil, že by tak někdo dělal. Měl jsem za to, že to každý setřásá, aby se prostředky šetřily. Tudíž bych čekal, že když budou sedět velikosti typů, bude sedět i struktura. Což by teď tedy neodpovídalo...

Uživatelský avatar
gilhad
Příspěvky: 778
Registrován: 07 bře 2018, 11:22
Reputation: 0

Re: Posílání více "položek" komunikací pomocí STRUCT

Příspěvek od gilhad » 26 led 2020, 22:30

Neco jde nastavit prepinaci prekladace, ale obecne si to nemuze dovolit "jen tak" preskladat, nebo setrast, protoze ty struktury casto odpovidaji nejakym protokolum, nebo nejakemu HW/registrum a podobnym vecem, nemluve teda o ukladani a prenosech struktur.

Zaroven se dost casto ty struktury vyplnuji tak, aby byly polozky na zarovnanych adresach (pokud teda programator nerozhodne jinak), protoze se to tak rychleji nacita a zpracovava (a kdybys vedel, co vsechno se kvuli urychleni dela v ruznych procesorech, tak by ti hruzou vstavaly vlasy na kilometry daleko :lol: )

Na vlastni nebezpeci muzes hledat treba "struct allignment" "zarovnani pameti" a jina riskantni slovni spojeni :twisted:

martinius96
Příspěvky: 579
Registrován: 01 srp 2017, 19:29
Reputation: 0
Bydliště: Poprad
Kontaktovat uživatele:

Re: Posílání více "položek" komunikací pomocí STRUCT

Příspěvek od martinius96 » 03 úno 2020, 16:13

Fakt super nápad použiť struct :-)
Chcel som to pôvodne odtestovať s knižnicou VirtualWire, ale tam sa dáta posielajú ako uint8_t, nevedel som to vhodne sformátovať, pretypovať mi to nešlo, skúšal som teda pod nRF24L01 s knižnicou RF24, fungovalo na prvý krát bez problému. Pridávam aj testovaný program. Vysielač vysiela vždy. Prijímač vysiela vysielaču odpoveď po prijatí dát.

Vysielač posiela hodnotu 100, prijímač hodnotu 101. Je potrebný ten delay po odosielaní? Funguje mi to i bez neho, možno by to robilo problém pri viacerých položkách štruktúry. V cykle while na prijímači sa to v pohode načíta, rovnako tak i na vysielači pri odpovedi prijímača. Premýšľam len nad tým, ako porovnať položku T pri prijatí a odosielaní, nakoľko sa zapisuje totožne: packet.T. Ako správne porovnávať vysielanú a prijímanú položku takejto štruktúry? Nemôžem porovnať packet.T a packet.T... Rozumiem tomu dobre, že (na vysielači) packet.T má hodnotu 100 a po prijatí 101 z prijímača ako odpoveď prepíše v tejto existujúcej štruktúre tú hodnotu?

Chcel by som to použiť v projekte ktorý som v minulosti vytvoril (aby to vyzeralo viac profesionálne :-) ), kde overujem, či bolo na vysielači a prijímači stlačené rovnaké tlačidlo (či je odosielaná a prijatá hodnota totožná) - napríklad po stlačení tlačidla RED TEAM vysiela vysielač hodnotu 1 stále dookola.
Obrázek
Ak sa RED TEAM tlačidlo stlačí aj na prijímači, ten odošle tiež hodnotu 1, následne to treba porovnať a ukončiť prenos, zapnúť buzzer atď. Je možné to vyriešiť aj inak ako dvomi štruktúrami? (Vysielacia, prijímacia)...

Program vysielač:

Kód: Vybrat vše

// nRF24L01 vysielac 
//Autor: Martin Chlebovec (martinius96)
//Web: https://arduino.php5.sk

#include <SPI.h>
#include "RF24.h"
#define CE 4
#define CS 3
RF24 nRF(CE, CS);

typedef struct {
  int T;
} dataPacket;

byte adresaPrijimac[] = "prijimac00";
byte adresaVysilac[] = "vysilac00";
void setup() {
  Serial.begin(9600);
  nRF.begin();
  nRF.setDataRate( RF24_250KBPS );
  nRF.setPALevel(RF24_PA_LOW);
  nRF.openWritingPipe(adresaVysilac);
  nRF.openReadingPipe(1, adresaPrijimac);
  nRF.startListening();
}

void loop() {
  dataPacket packet;
  packet.T = 100;
  nRF.stopListening();
  nRF.write(&packet, sizeof(dataPacket));
  nRF.startListening();
  while (nRF.available()) {
    nRF.read(&packet, sizeof(dataPacket));
    Serial.print("Hodnota ");
    Serial.println(packet.T);
  }
  delay(50);
}
Program prijímač:

Kód: Vybrat vše

// nRF24L01 prijimac
//Autor: Martin Chlebovec (martinius96)
//Web: https://arduino.php5.sk

#include <SPI.h>
#include "RF24.h"
#define CE 4
#define CS 3
RF24 nRF(CE, CS);

typedef struct {
  int T;
} dataPacket;

byte adresaPrijimac[] = "prijimac00";
byte adresaVysilac[] = "vysilac00";
void setup() {
  Serial.begin(9600);
  nRF.begin();
  nRF.setDataRate( RF24_250KBPS );
  nRF.setPALevel(RF24_PA_LOW);
  nRF.openWritingPipe(adresaPrijimac);
  nRF.openReadingPipe(1, adresaVysilac);
  nRF.startListening();
}

void loop() {
  dataPacket packet;
  if ( nRF.available()) {
    while (nRF.available()) {
      nRF.read(&packet, sizeof(dataPacket));
      Serial.print("Hodnota ");
      Serial.println(packet.T);
    }
    nRF.stopListening();
    packet.T = 101;
    nRF.write(&packet, sizeof(dataPacket));
    nRF.startListening();
  }
}

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: Posílání více "položek" komunikací pomocí STRUCT

Příspěvek od ondraN » 03 úno 2020, 21:05

Ten zápis pomocí typedef je půvocní C způsob. V C++ funguje také, kvůli kompatibilitě. Ale C++ nabízí jednodušší a přirozenější syntaxi. Obě jsou samozřejmě ve výsledku totožné.

Kód: Vybrat vše

//deklarace struktury v C++
struct jmenotypu {
	byte A; //clen struktury se zapisuje typ jmeno strednik, typ muze byt jednoduchy, pole nebo jina struktura
	float B[5];
	// nasleduje libovolny pocet clenu strukrury
};		//ukonceni deklarace struktury, ten strednik je tam nutny!!

Cenda608
Příspěvky: 16
Registrován: 21 úno 2018, 11:16
Reputation: 0

Re: Posílání více "položek" komunikací pomocí STRUCT

Příspěvek od Cenda608 » 22 črc 2020, 12:57

Potřeboval bych poradit ohledně této funkce v mém projektu s moduly LoRa radio node v2.0 čip SX1278
Popis verze 1.0 s čipem SX1276 anglicky https://www.disk91.com/2019/technology/ ... e-arduino/
Knihovny a příklady https://github.com/IOT-MCU/LoRa-Radio-Node-v2.0

Jedná se o hlídání garáže vzdálené asi 500 metrů v lehké zástavbě, signál dobrý, momentálně posílám jen hodnotu 0/1 protože jsem schopný to zpracovat , ale chtěl bych to rozšířit o více položek a tady jsem narazil na problém na straně přijímače - s mými znaslostmi nevím jak přijmout paket více položek pro další zpracování.
část kódu z příkladů, vysílač:

Kód: Vybrat vše

char radiopacket[20] = "Hello World #      ";
  itoa(packetnum++, radiopacket+13, 10);
  Serial.print("Sending "); Serial.println(radiopacket);
  radiopacket[19] = 0;
  
  Serial.println("Sending..."); delay(10);
  rf95.send((uint8_t *)radiopacket, 20);
přijímač:

Kód: Vybrat vše

if (rf95.available())
  {
    // Should be a message for us now   
    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    
    if (rf95.recv(buf, &len))
    {
      digitalWrite(LED, HIGH);
      RH_RF95::printBuffer("Received: ", buf, len);
      Serial.print("Got: ");
      Serial.println((char*)buf);
pokud použiji struct:

Kód: Vybrat vše

typedef struct {        // struktura paketu pro odeslání
  int stav;                  // stav
  int kod;                    // stav kodovany
} radiopacket;
tak na straně vysílače to je snad v pořádku:

Kód: Vybrat vše

radiopacket packet;
    packet.kod = digitalRead(TLAC);


    Serial.print("Sending "); Serial.println(packet.stav);
    rf95.send((uint8_t *)&packet, sizeof(radiopacket));
    rf95.waitPacketSent();
nejsem schopný dát dohromady přijímací čast:

Kód: Vybrat vše

if (rf95.available());
  {
    // Should be a message for us now   
    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(radiopacket);
    
    if (rf95.recv(buf, &len))
    {
      RH_RF95::printBuffer("Received: ", buf, len);
Tady prostě nevím jak z toho dostat packet pro další zpracování. V příkladech se vše posílá na sériový port a to nepotřebuji. Snad jsem to napsal srozumitelně.

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 14 hostů