1

Téma: [vyřešeno] RS 485 / stack

Budu posílat data ( modbus) na 485. Zatím jsem ke 485 ve full C našel jen toto:

 void SDS_serial_config(unsigned int busID, unsigned int BaudRateCfg, unsigned int DataSizeCfg, unsigned int StopBitsCfg, unsigned int ParityCfg);
 void SDS_serial_writeCH(unsigned int busID, unsigned char writeChar);
 void SDS_serial_write(unsigned int busID, char *ptr, unsigned int len);
 unsigned int SDS_serial_read(unsigned int busID, char *ptr, unsigned int maxlen);

a z jiného odstavce dedukuji, že 485 je na COM1. Přesto prosím o ukázku zápisu řetězce hex znaků na RS 485 - ať se zbytečně netrápím.

2

Re: [vyřešeno] RS 485 / stack

Myslím že je to z dokumentace jasné - a praktickému vyzkoušení se člověk stejně nikdy nevyhne.

void main(void)
{
   
  char prikaz[8];
  char odpoved[8];

  int i;

  // Inicializace linky 485 = COM1 na 9800bps 8n1
  SDS_serial_config(1, 9600, 8, 1, 0);

  // poslat 8 bajtu ven

  prikaz[0] = 'a';
  prikaz[1] = 'b';
  prikaz[2] = 'c';
  prikaz[3] = 'd';
  prikaz[4] = 'e';
  prikaz[5] = 'f';
  prikaz[6] = 'g';
  prikaz[7] = 'h';
  SDS_serial_write(1, prikaz, 8);

  // pro tento priklad . . .
  wait(1000);

  // precist 8 bajtu ze vstupniho bufferu (pokud tam nejake budou)

  i = SDS_serial_read(1, odpoved, 8); 
  printf("read %d bytes\n", i);

  // obsah pole odpoved[] obsahuje data poskytnuta funkci SDS_serial_read
  
}

Výstup dat je prakticky okamžitý, a po celou dobu výstupu dat je aktivován RS485 master transmit (platí pro COM1).

Příjem dat z COMx funguje tak, že všechna přicházející data se umisťují do vyrovnávacího bufferu (fifo), a čekají tam až si je FULL-C program vyzvedne (SDS_serial_read). Díky tomu nedochází ke ztrátě dat ani při vysokých rychlostech sériové linky. Jen pozor na omezenou velikost tohoto bufferu, pokud se přeplní (tj. FULL-C neodebírá data, ale přitom z venku stále přicházejí), tak jsou tato data navíc zahozeny. Ale to už je jen detail pro úplnost.

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

3

Re: [vyřešeno] RS 485 / stack

Funguje to díky.
Ještě se chci zeptat: moje ( čínské)  modbusové moduly po každém příkazu vysílají automaticky odpověď, kterou nebudu většinou číst. Jakým příkazem vymazat  buffer, aby se mi nepřeplnil a byl připraven přečíst odpověď na dotaz, když nějaký vyšlu.

4

Re: [vyřešeno] RS 485 / stack

Před odesláním příkazu, po kterém bude chtěno přečíst odpověď, stačí celý vstupní buffer přečíst a tím jeho případný obsah zahodit; zbyde tak celý prázdný a tím pádem připravený pro příchozí odpověď.

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

5

Re: [vyřešeno] RS 485 / stack

Po delší době jsem se vrátil ke čtení dat ze RS485, ale program mi vždy zkolabuje.
Vzal jsem tedy z fora program, který měl být funkční jen jsem upravil odesílaná data pro své relé, ale je to  také stejné s každým přečtením se zvyšuje STACK až dojde k přetečení. Zvýšení Stacku při kompilaci jen oddálí pád programu.

Pokud program ještě jede, tak čte správně hodnoty ze sériové linky až do okamžiku jeho zastavení. Co udělat pro to , aby se program po x načtených hodnotách nezastavil?

Když sem program zkopíruji, tak mi nejde příspěvek odeslat.

6

Re: [vyřešeno] RS 485 / stack

Pošlete mi to na sds@an-d.cz .

Zde je zcela fungující příklad pro RS485 pro komunikaci mezi SDS a střídačem SITON :

// následující kód je jen malá část celého programu, ale i tak je to kompletní ukázka čtení dat z RS485 z připojeného zařízení SITON 

// POZOR jedná se o vlastní protokol použitý autorem střídače SITON, ale pro ilustraci je to neméně vhodné
// protokoly typu MODBUS se budou prakticky zpracovávat úplně stejným principem, s přihlédnutím k jiné formě protokolu

// --- SITON

struct SitonPayloadTX
{
  unsigned char nodeID;  // toto jsou data z nodu xx
  unsigned char address;
  unsigned char command;
  unsigned char func;
  signed short data1; // napeti ve Voltech
  signed short data2; // proud ve formatu 865 (8,65A)
  signed short data3; // vykon ve Wattech
  signed short data4; // teplota ve degC
  signed short data5;
  signed short data6;
  signed short data7;
  signed short data8;
  signed int data9;   // vyroba ve Wh
  signed int data10;
  signed int data11;
  signed int data12;
};

// posledni platna prijata zprava
struct SitonPayloadTX siton;
unsigned int siton_stari_zpravy = 0xFFFF; // sekundy

// sem ukladame novou zpravu
unsigned char sitonpay[sizeof(struct SitonPayloadTX) + 8];

//
unsigned char siton_et_hlavicka = 0;
unsigned char siton_et_ptr = 0;
unsigned char siton_et_chk = 0;
unsigned char siton_et_size = 0;

void SITONserialRead(void)
{

 int limit;
 unsigned char rC;

 limit = 80;

 while (1 == SDS_serial_read(1, (void *) &rC, 1))
 {
   if (0 == siton_et_hlavicka)
   {
     if (0x06 == rC) siton_et_hlavicka = 1;
     siton_et_ptr = 0;
     siton_et_chk = 0;
   } else
   if (1 == siton_et_hlavicka)
   {
     if (0x85 == rC) { siton_et_hlavicka = 2; } else { siton_et_hlavicka = 0; }; 
   } else
   if (2 == siton_et_hlavicka)
   {
     siton_et_size = rC;
     if (siton_et_size != sizeof(struct SitonPayloadTX)) // musi odpovidat na obou stranach
     {
       siton_et_hlavicka = 0;
     } else
     {
       siton_et_chk = siton_et_size;
       siton_et_hlavicka = 3;
     }
   } else
   if ((siton_et_hlavicka >= 3)&&(siton_et_hlavicka < 3+siton_et_size))
   {
     // payload
     sitonpay[siton_et_ptr] = rC;
     siton_et_chk ^= rC;
     siton_et_ptr++;
     siton_et_hlavicka++;
   } else
   if (siton_et_hlavicka == 3+siton_et_size)
   {
     // crc
     if (rC == siton_et_chk)
     {
       memcpy((void *)&siton, (void *)sitonpay, sizeof(struct SitonPayloadTX));

       siton_stari_zpravy = 0;

       if (old_siton_data4 != siton.data4)
       {
         old_siton_data4 = siton.data4;
//         print_time();
         printf(" [%u %u %u %u] %uV %u.%02uA %uW %uC %u\n", siton.nodeID, siton.address, siton.command, siton.func, siton.data1, siton.data2/100, siton.data2 % 100, siton.data3, siton.data4, siton.data9);
       }
     }
     siton_et_hlavicka = 0;
   } else
   {
     // unknown state
     siton_et_hlavicka = 0;
   }

   // rs485 rx counter
   if (0 == limit) break;
   limit--;
 }

}

void main(void)
{
 SDS_serial_config(1, 9600, 8, 1, 0);

 memset(&siton, 0, sizeof(struct SitonPayloadTX));

  // pro jednoduchost je zde jen tato nekonečná smyčka
  while (1)
  {
     SITONserialRead();
     // pro každou přijatou zprávu funkce výše provede její výpis do konzole...
  }

}

Funguje to OK pro celou řadu uživatelů...

Přímo pro vzorový program na MODBUS-485 zkuste napsat zdejšímu členovi fóra s uživatelskou zkratkou "J@M".

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

7

Re: [vyřešeno] RS 485 / stack

Tak po dalším bádání jsem úplně z programu zrušil čtení a ponechal jen zápis na RS485 a STACK s každým odeslaným příkazem také roste.
Nechápu to, když na hlavním zařízení  posílám desítky příkazů denně  bez problémů . Zkontroloval jsem FW - moje hlavní zařízení  má FW z  9.7.2020 a na druhém zařízení, kde provádím tyto pokusy mám FW z 3.11.2020 . Vidím že již existuje FW z 12.12.2020, tak jej zkusím nainstalovat, jen nevím jestli to ještě stihnu letos.

8

Re: [vyřešeno] RS 485 / stack

Tak jsem nahrál poslední verzi FW a Stack pořád roste.
Program jen posílá:

    SDS_serial_config(1, 9600, 8, 1, 0);
    while(1){
              SDS_serial_config(1, 9600, 8, 1, 0); 
char pr4[] = {0x05,0x06,0x00,0x01,0x06,0x20,0xDB,0xF6};

  wait(10000);
 SDS_serial_write(1, pr4,8);
 wait(1000);
       

a výskedek je:

out of mem(29)(24)(S)
!!! YOU NEED TO INCREASE STACK SIZE FOR YOUR PROGRAM !!!
out of mem(110)

9

Re: [vyřešeno] RS 485 / stack

Ještě jsem se k tomu nedostal, ale na první pohled - doporučím premístit tento řádek zevnitř smyčky while ven.

krevla napsal:
char pr4[] = {0x05,0x06,0x00,0x01,0x06,0x20,0xDB,0xF6};
Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

10

Re: [vyřešeno] RS 485 / stack

Přesunutí obsahu pole ven ze smyčky pomohlo a stack již neroste. Toto jsem ověřil na tom nejjednoduším programku, zkusím se vrátit zpět ke čtení z RS485

11

Re: [vyřešeno] RS 485 / stack

Tak po předchozí úpravě již funguje vše jak má jak zápis tak i čtení.
Děkuji.

12

Re: [vyřešeno] RS 485 / stack

viz ... http://wiki.merenienergie.cz/index.php/ … and_tricks

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

13

Re: [vyřešeno] RS 485 / stack

Ve FULL-C Statusu je na pátém řádku:
FC watchdog : inactive
Předpokládám, že se nejedná o IP watchdog, který na Smallu ještě nepoužívám, ale nikde se nemůžu dočíst o tomto watchdogu více - jak jej aktivovat.
Po eliminaci problémů se 485 se zařízení drží, ale přesto se mi jednou stalo, že zatuhlo. Připravuji externí watchdog, ale interní by byl lepší .

14

Re: [vyřešeno] RS 485 / stack

zatuhlo? tak to by mne zajímaly podrobnosti

wdg je v zařízení SDS hned na několika úrovních,
- v HW se samostatným RC oscilátorem, kdy hlídá procesor (timeout 1 sec), resetuje procesor při zaseknutí, aktivován vždy
- v HW dohledy nevhodného poklesu napájení (brownout a PF), aktivován vždy
- v SW programový pro systém, aktivován vždy
- v SW programový pro FULL-C program, ale ten je potřeba aktivovat dle uživatelských potřeb

více viz wiki, tam je vše
http://wiki.merenienergie.cz/index.php/FULL-C_general_functions

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

15

Re: [vyřešeno] RS 485 / stack

Pročtu si to, vidím, že je tam dost informací.
Já myslím že důvodem zaseknutí byl nedostatek paměti ( dle výpisu ve FULL-status) , ale nepodařilo se mi to opakovaně vyvolat. Měřím poměrně dlouhý čas ( 2 hodiny) , během kterého je vypnuté topení, když se větrá a v praxi se hraniční hodnoty většinou nedosáhne. Při zaseknutí byl tento čas překročen, ale asi to nebyla příčina, zkoušel jsem to vyvolat a nepodařilo se.

Mám ještě jednu nejasnost v mém jednoduchém testovacím programu na 485, vše funguje zapisuje i čte, stack se nemění, ale vidím, že roste Heap. Posílám na 485 něco každou 1,5 sekundu , tak po pár minutách běhu programu je Heap 8000kB ze 126615kB. Předpokládám, že po vyčerpání paměti program zkolabuje.
Pomůže v tomto případě si alokovat a pak uvolnit paměť?
pokud ano , tka jak to správně udělat? Napadá mne pře každým vložením HEX řetězce alokovat a po odeslání uvolnit , ale netuším .

16

Re: [vyřešeno] RS 485 / stack

pošlete mi ten program, podívám se

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

17

Re: [vyřešeno] RS 485 / stack

Už vím čím to je, jen nerozumím proč.
Program jsem vám ještě neposílal, protože při srovnávání funkční a testovací verze mne napadla ještě tato věc:
ve funkční verzi ( cca2 roky)  mám většinu polí naplněnu takto:
char pr4[8];
  pr4[0] = 0x05;
  pr4[1] = 0x05;
  pr4[2] = 0x00;
  pr4[3] = 0x00;
  pr4[4] = 0xFF;
  pr4[5] = 0x00;
  pr4[6] = 0x8D;
  pr4[7] = 0xBE;
později jsem začal používat tento způsob zápisu do pole:
char pr4[] = {0x05,0x05,0x00,0x00,0xFF,0x00,0x8D,0xBE};
a ten způsobuje , že roste Heap - právě jsem si to ověřil.
Navíc to vysvětluje i proč se mi onehdá zasekla funkční verze. V této verzi je většina polí naplněna prvním způsobem, ale některé z poslední doby již druhým způsobem a ten pomaličku užírá volnou paměť . Taky jsem to teď ověřil stav Heap byl už na 10792kB a po resetu zařízení je 6560kB.
Raději bych používal druhý způsob zápisu, protože program je s ním přehlednější, dnes ovládám cca 7 relé a další mám v plánu a program je pak v textu hodně dlouhý.

18

Re: [vyřešeno] RS 485 / stack

ano, přesně, viz ... http://wiki.merenienergie.cz/index.php/ … and_tricks

Není to totiž deklarováno jako const a proto je to bráno jako kdykoliv měnitelná proměnná (pole) na heapu či na stacku (podle místa deklarace)... a proto to při každém průchodu místem deklarace "sežere" další paměť.
Řešení je více, vhodné je např. to nastavení po jednotlivých prvcích.

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !