Skocz do zawartości

RS-485 po raz kolejny – komunikacja dwukierunkowa


DCH

Pomocna odpowiedź

Już myślałem, że mam ogarnięty temat RS-485. Jednak nie i znów potrzebuję pomocy.

Czy są jakieś zasady / dobre praktyki, które należy stosować do obsługi komunikacji dwukierunkowej w trybie half duplex? Ew. ktoś to robił i może mi pomóc z moją aplikacją (np. jakiś wieczorny calll?)

 

Aktualnie robię w miarę prosty układ obsługujący komunikację RS-485, wykorzystując 2 płytki: UNO R4 i GIGA. Całość ma działać tak:

1.       (działa) Wciskam przycisk podpięty do UNO. UNO wysyła komunikat do GIGA. Kod:

void sendReadMessage(int command) {
char message[BatteryMonitor_Message_Lenght];   
int commandValueParameter = 1; //wg przykładów z instrukcji urządzenia każdy read wysyła wartość = 1.
int checksum = getChecksum(commandValueParameter);

sprintf(message, ":R%02i=%i,%i,%i,\r\n", command, batteryMonitorParameters.deviceAddress, checksum, commandValueParameter);
 
//Active HIGH for Driver Input Enable; Active LOW for Receiver Output Enable.
digitalWrite(receiverOutputEnablePinNumber, HIGH);

 batteryMonitorSerialDevice->print(message);
 batteryMonitorSerialDevice->flush();

delay(WaitTimeAfterSend);

//Active HIGH for Driver Input Enable; Active LOW for Receiver Output Enable.
 digitalWrite(receiverOutputEnablePinNumber, LOW);
}

W klasie instancją której operuję jest definicja zmiennej: Stream* batteryMonitorSerialDevice; a przy inicjowaniu podpinam pod nią Serial1 na którym jest poprawnie wpięty konwerter RS-485.

 

2.       (działa) GIGA odbiera i prasuje komunikat. W zależności od treści otrzymanego i przetworzonego komunikatu ustala odpowiedź do wysyłki. Kod:

void loop() {

	returnMessage = "";

	switch (readMessage())
	{
	case 0: {
		returnMessage = ":r00=1,47,1120,100,101,\r\n";
		break;
	}
	case 50: {
		returnMessage = ":r50=2,215,2056,200,5408,4592,9437,14353,134,0,0,0,162,30682,\r\n";
		break;
	}
	default:
		break;
	}

	if (returnMessage.length() > 0) {
		sendMessage(returnMessage);
	}

	delay(100);
}

int readMessage() {
	String returnMessage_local = "";
	char message[BatteryMonitor_Message_Lenght];
	int startIndex = 0;
	int endIndex = 0;
	bool receivedFullMessage = false;
	bool receivedMessage = false;
	int index = 0;

	while (Serial1.available() > 0)
	{
		message[index] = Serial1.read();
		receivedMessage = true;

		if (message[index] == '\n')
		{
			receivedFullMessage = true;
			break;
		}

		index++;
	}

	if (receivedMessage and receivedFullMessage)
	{
//parsuję wiadomość i szukam interesującego mnie kodu operacji
		for (int i = 0; i <= index; i++)
		{
			if (message[i] == 'R')
			{
				startIndex = i + 1;
			}
			if (message[i] == '=')
			{
				endIndex = i - 1;
				i = index + 1; //leave the loop
			}
		}

		for (int i = startIndex; i <= endIndex; i++)
		{
			returnMessage_local += message[i];
		}

		if (returnMessage_local == "") {
			return -1;
		}
		else {
			return returnMessage_local.toInt(); //kod operacji
		}
	}
	return -1;
}

 

3.       (zaczynają się problemy) GIGA wysyła komunikat po RS-485. Nie mam żadnych oznak niepoprawnego działania. Kod:

void sendMessage(String message) {

	message.toCharArray(messageToSend, BatteryMonitor_Message_Lenght);

	digitalWrite(ReceiverOutputEnablePinNumber, HIGH);

	for (int i = 0; i < message.length(); i++)
	{
		Serial1.write(messageToSend[i]);
	}

	Serial1.flush();
	delay(100);

	digitalWrite(ReceiverOutputEnablePinNumber, LOW);
}

 

4.       (nie działa) UNO czeka na przychodzący komunikat. Jeżeli coś się pojawia to odbiera i wyświetla na serial (USB). Niestety przy kolejnych naciśnięciach przycisku albo nic nie odbiera, albo odbiera śmieci.  Ani razu nie dotarła wiadomość zwrócona przez GIGA.

void loop() {
	
	if (digitalRead(5) == LOW) {  //Jeśli przycisk jest wciśnięty
		readBasicInformation(); 
		SerialDebug_BM_BasicInformation(); //na potrzeby debugowania wyświetla otrzymane informacje na Serial / USB
	}

	delay(150);
  
}
void readBasicInformation() {
	char returnMessage[140];
	String complexField = "";
	char nextCharacter;
	int index = 0;

//funkcja wysyłania z pkt 1 – ta działająca. Na wejściu kod operacji
	sendReadMessage(BatteryMonitor_Functions_ReadBasicInfo);

	//wiadomości są zakończone dwoma znakami: \r\n
	int tmpTimeout = 0;
//czekam na wiadomość. Aby nie zawiesić aplikacji symulacja timeout w oczekiwaniu na komunikat. Kod do refactoringu	
while (batteryMonitorSerialDevice->available() <=0 && tmpTimeout <=30)
	{
		delay(150);
		tmpTimeout++;
	}

//odczyt znak po znaku i wyświetlanie na Serial w celu debugowania
	while (batteryMonitorSerialDevice->available() > 0)
	{
	

//tu dostaję śmieci lub nic nie dostaję….

		returnMessage[index] = batteryMonitorSerialDevice->read();
		Serial.print(returnMessage[index]);

		index++;
			}
	//odczyt wyświetlanie na Serial w celu debugowania

			Serial.print("Return message full: ");
	Serial.println(returnMessage);
}

Co mogę robić źle?

Edytowano przez DCH
  • Lubię! 1
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.