Wysyłanie i odbieranie ramek po RS232

0

Witam

Mam problem z komunikacją po rs232.
Nie potrafię zmusić programu aby wysyłał i odbierał dane z rs.

Program ma za zadanie wysłać zapytanie do urządzenia, pobrać 1 ramkę, wyświetlić wynik i przejść do następnego zapytania.
Generalnie są 3 zapytania.

Zapytanie 1 - status
Zapytanie 2 - waga
Zapytanie 3 - waga_tymczasowa

Zrobiłem już jakąś transmisję ale zdarza się że dane ze statusu trafiają do wagi, wynik wagi jest zafałszowany.
Wydaje mi się że problem polega na buforze. Mam wrażenie że gdy przechodzę do zapytania 2 to przychodzi ramka ze statusu.

Funkcje potrzebne do RS232

int __fastcall Read_Comm(HANDLE hComm,
						 LPDWORD lpNumberOfBytesRead, DWORD Buf_Size)
{
	DWORD nNumberOfBytesToRead;

	ClearCommError(hComm, &Errors ,&Stat);

	if (Stat.cbInQue > 0)
	  {
		if (Stat.cbInQue > Buf_Size)
			nNumberOfBytesToRead = Buf_Size;
		  else
			nNumberOfBytesToRead = Stat.cbInQue;

		ReadFile(hComm, &Buffer_I[0], nNumberOfBytesToRead,
				 lpNumberOfBytesRead, NULL);
	  }
	  else
		*lpNumberOfBytesRead = 0;
	return TRUE;
} 

Zapytanie 1 - Status

 void sprawdzStatus()
	{
		FlushFileBuffers(hComm);
		WriteFile(hComm, status, sizeof status, &RS_ile, 0);
		Read_Comm(hComm, &Number_Bytes_Read, sizeof(Buffer_I));
		Sleep(100);
		if (Buffer_I[0] == 02 && Buffer_I[1] == 03 && Buffer_I[2] == 04 && Buffer_I[3] == 00 && Buffer_I[4] == 00 && Buffer_I[5] == 00 && Buffer_I[6] == 03) {
			 status_wagi = true;
		}
		if (Buffer_I[0] == 02 && Buffer_I[1] == 03 && Buffer_I[2] == 04 && Buffer_I[3] == 00 && Buffer_I[4] == 00 && Buffer_I[5] == 00 && Buffer_I[6] == 01) {
			 status_wagi = false;
		}
		blokada_pomiaru = false;
	}

Zapytanie 2 - Waga

void licznikGlowny()
{
	 FlushFileBuffers(hComm);
	 WriteFile(hComm, wagaGlowna, sizeof wagaGlowna, &RS_ile, 0);
	 Read_Comm(hComm, &Number_Bytes_Read, sizeof(Buffer_I));
	 Sleep(100);
	 wynik2=(Buffer_I[4]*65536)+(Buffer_I[5]*256)+Buffer_I[6];
} 

I teraz w Timer co określony czas wywołuję funkcję.

void __fastcall TForm3::Timer1Timer(TObject *Sender)
{
	zmienna++;
	if(zmienna >= 5) zmienna = 0;

	if (zmienna == 2) {
		 licznikGlowny();
	}
	if (zmienna == 4) {
		 sprawdzStatus();
	}
} 
0
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <cmath>

#include "Unit3.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
#define cbOutQueue 8          //rozmiar bufora danych wyjściowych
#define cbInQueue  8          //rozmiar bufora danych wejściowych
TForm3 *Form3;
    unsigned char    Buffer_O[cbOutQueue]; // bufor danych wyjściowych
	unsigned char    Buffer_I[cbInQueue]; // bufor danych wejściowych
	DWORD   Number_Bytes_Read; // liczba bajtów do czytania
	char statuss;
	static DCB dcb;
	char hex[6] = {0x02,0x03,0x00,0x02,0x00,0x02};
	char status[6] = {0x02,0x03,0x00,0x04,0x00,0x02};
	char wagaGlowna[6] = {0x02,0x03,0x00,0x02,0x00,0x02};
	char stat[8];
	HANDLE hComm;
	char lpBuffor_read[8], lpBuffor_write[8];
	DWORD RS_ile;
	bool abContinue = true;
	int isRead = false;
	bool CommFlag;
	DWORD   fdwEvtMask;    // informacja o aktualnym stanie transmisji
	COMSTAT Stat;             // dodatkowa informacja o zasobach portu
	DWORD   Errors;           // reprezentuje typ ewentualnego błędu
	int liczba0 = 12.5;
	int mod0, mod1, mod2, mod3, mod4, mod5, mod6, mod7, mod8,wynik1;
	unsigned char mo0, mo1, mo2, mo3, mo4, mo5, mo6, mo7, mo8, wynik;
	unsigned char mmo0, mmo1;
	double wynik2;
	char wynikk[6];
	bool status_wagi, blokada_pomiaru, blokada_pomiaruwagi = false;
	int zmienna;

//---------------------------------------------------------------------------

 
0

ściągnij http://www.serial-port-monitor.com/ zainstaluj i zobacz co jest wysyłane do urządzenia

0

Monitor RS pokazuje dane tak trzeba.

Jak mogę sprawdzić czy transmisja się zakończyła.

1

co to wg Ciebie znaczy transmisja się zakończyła.
Jaki to typ wagi? Z doświadczenia mogę powiedzieć, że część urządzeń wymaga znaku końca linii 0D 0A po każdej komendzie co nie zawsze znajduje się w dokumentacji.

0

Generalnie waga odpowiada ładnie gdy wywołuję tylko jedno zapytanie.

Chciałbym tak zrobić żeby po wywołaniu funkcji sprawdzStatus() odebrał dane sprawdził czy jeszcze coś idzie jak nie to wywołaj drugą funkcję licznikGlowny(); i tak w koło.

Wtedy nie powinno być sytuacji że na wysłane zapytanie np sprawdzenie statusu przychodzi odpowiedz na zupełnie inne zapytanie.

0

to z czym masz w końcu problem bo piszesz, że waga odpowiada

0

No waga odpowiada, chciałbym żeby odbieranie danych było tylko w określonym czasie.

Wysyłam ramkę o status-> czekam 5 sekund w tym czasie odbieram dane-> zamykam możliwość odbierania danych->Wysyłam ramkę o wagę-> otwieram możliwość odbierania danych-> czekam 5 sekund w tym czasie odbieram dane->zamykam możliwość odbierania danych-> itd

0

to tak nie działa - po jednej stronie masz komputer i tutaj masz jakieś pole manewru ale po drugiej stronie masz wagę i na nią nie masz wpływu. Nie możesz założyć, że np. po 5 sekundach to jak Ci waga odpowie to będzie za późno. Waga po prostu Ci coś odeśle i ją to nie interesuje co z tą odpowiedzią zrobisz. Nie wiem jaki masz model wagi (nie napisałeś) ale większość z jakimi miałem do czynienia (min. radwag, fawag, rhewa, axis, digi, mettler toledo) odpowiadają w taki sposób, że wiadomo na jaki rozkaz (albo kod rozkazu jest w ramce odpowiedzi albo są po prostu różne ramki). Inna sprawa, że nie zdarzyło mi się żebym musiał czekać dłużej na odpowiedź od wagi niż kilka - kilkanaście milisekund (oczywiście o ile nie było żadnego błędu po drodze)

0

Typ wagi to WMTP

No dobrze ale skąd mogę wiedzieć że dane przyszły już całe, w monitorze portu widzę że przyszło ale czy jest jakaś flaga którą mogę badać.

W tej wadze aby odczytać dane które mnie interesują muszę wysłać 3 różne ramki.
W odpowiedzi dostaje ramki, które są bardzo podobne do siebie, np. ramka odpowiedzi o statusie wygląda tak 02 03 04 00 00 00 01 08 F3, ramka odpowiedzi z wagą wygląda tak 02 03 04 00 00 04 23 8A 2A.

Teraz jak je rozróżniać i interpretować.
Czy rozwiązanie poniżej wystarczy na złapanie całej ramki.

        WriteFile(hComm, status, sizeof status, &RS_ile, 0);
        Read_Comm(hComm, &Number_Bytes_Read, sizeof(Buffer_I)); 
0

jeśli wiesz, że wszystkie ramki zaczynają się na 02 03 04 i mają 9 bajtów to przede wszystkim tak sprawdzaj czy ramka jest cała. Czy da się je odróżnić tego nie wiem bo nie wiem co oznaczają poszczególne bajty. Co do ostatniego pytania to musisz uważać bo jak podłączałem się przez konwerter usb-rs noname to miał tendencję do zwracania na raz tylko 8 bajtów i po resztę trzeba było ponownie robić ReadFile. Ogólnie dobrze by było zwracać lpNumberOfBytesRead

0

Co może być przyczyną sporadycznego odbierania 00 w odpowiedzi?
Czy może być to problem związany z odstępami miedzy zapytaniami?

[02][03][00][02][00][02][65][F8]
[02][03][00][06][00][02][85][F9]
[02][03][00][04][00][02][BB][19]
[00][00][00][00][00][00][00][00]
[02][03][00][06][00][02][85][F9] 
0

jeśli nie jest to system podtrzymywania życia to je po prostu olej - ktoś musiał napisać soft do tego urządzenia i zakładanie, że działa ono idealnie jest głupim założeniem

0

Generalnie testuje to na komputerze, mam 2 konwertery modbus połączone ze sobą.

Obecnie robię tak:

1.Wysyłam zapytanie.
2.Czekam 100 milisekund.
3.Odbieram ramkę.
4.Czekam 1 sekundę.

Czy to może powodować że czasami odbieram 00.

1

Napiszę tak - w pracy mam do czynienia z różnymi konwerterami - RS232-RS485, USB-RS232, USB-RS485, ETH-RS232, ETH-RS485 różnych firm i różnych typów. Jeszcze nie zdarzyło mi się odebrać czegoś, czego urządzenie po drugiej stronie nie wysłało (poza przypadkiem, kiedy konwerter był uszkodzony). Jeśli dostajesz śmieci to pierwszym podejrzanym jest wysyłający. Czy czas ma tu jakiś wpływ? nie wiem - nie znam urządzenia. ModBus to protokół, są dwa typy - ASCII i RTU. W tym drugim ważne są czasy pomiędzy poszczególnymi znakami i ramkami.

1 użytkowników online, w tym zalogowanych: 0, gości: 1