Skocz do zawartości

Własny program dla monitora portu szeregowego Arduino w C++ dla systemu Windows


mangan

Pomocna odpowiedź

Dzień dobry,

Chcę stworzyć własny program dla monitora portu szeregowego Arduino Uno w C++ dla systemu Windows. Arduino zaprogramowałem tak, żeby co 2 s wysyłało literę 'a' oraz żeby wyświetlało dane wprowadzone na komputerze na podpiętym do Arduino wyświetlaczu LED.

Komunikacja działa w przypadku Arduino Ide czy np. programu Realterm. Problem pojawia się w "moim" programie. Komunikacja komputer->Arduino działa (wprowadzone dane wyświetlają się na podpiętym ekranie). Nie działa jednak w drugą stronę. Zamieszczam poniżej kod.

#include <iostream>
#include <Windows.h>

int main() 
{
	HANDLE hSerial;
	DCB dcbSerialParams = { 0 };
	COMMTIMEOUTS timeouts = { 0 };

	// Otwórz port szeregowy 
	hSerial = CreateFile("COM4", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hSerial == INVALID_HANDLE_VALUE) {
		std::cerr << "Nie mozna otworzyc portu szeregowego." << std::endl;
		return 1;
	}

	// Ustaw parametry portu szeregowego
	dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
	if (!GetCommState(hSerial, &dcbSerialParams)) 
	{
		std::cerr << "Blad podczas pobierania stanu portu szeregowego." << std::endl;
		CloseHandle(hSerial);
		return 2;
	}
	dcbSerialParams.BaudRate = CBR_9600;  // Prędkość transmisji
	dcbSerialParams.ByteSize = 8;         // Rozmiar bajtu
	dcbSerialParams.StopBits = ONESTOPBIT; // Bit stopu
	dcbSerialParams.Parity = NOPARITY;     // Brak parzystości

	if (!SetCommState(hSerial, &dcbSerialParams)) 
	{
		std::cerr << "Blad podczas ustawiania parametrow portu szeregowego." << std::endl;
		CloseHandle(hSerial);
		return 3;
	}

	// Ustaw timeouty
	timeouts.ReadIntervalTimeout = 50;
	timeouts.ReadTotalTimeoutConstant = 50;
	timeouts.ReadTotalTimeoutMultiplier = 10;
	timeouts.WriteTotalTimeoutConstant = 50;
	timeouts.WriteTotalTimeoutMultiplier = 10;
	if (!SetCommTimeouts(hSerial, &timeouts)) 
	{
		std::cerr << "Blad podczas ustawiania timeoutow." << std::endl;
		CloseHandle(hSerial);
		return 4;
	}

    // Wyczyść bufor wejściowy i wyjściowy
	PurgeComm(hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR);
  
	// Odczytaj dane z Arduino i wyświetl na ekranie
	char buffer[256];
	DWORD bytesRead;

	while (true) 
	{
		if (ReadFile(hSerial, buffer, sizeof(buffer), &bytesRead, NULL)) 
			std::cout << "  Odebrano dane: " << buffer << std::endl;	


		// Wysyłanie danych do Arduino
		std::string dataToSend = "Hello, Arduino!";
		DWORD bytesWritten;
		if (WriteFile(hSerial, dataToSend.c_str(), dataToSend.size(), &bytesWritten, NULL)) 
			std::cout << "\nWyslano dane do Arduino." << std::endl;	
	}

	// Zamknij port szeregowy
	CloseHandle(hSerial);
	return 0;
}

Działająca komunikacja PC->Arduino sugeruje, że poprawnie ustawiłem parametry portu, szybkość transmisji itp.

Czy ktoś już spotkał się z podobnym problemem? Ma ktoś pomysł jak poprawić ten kod tak by dało się poprawnie odbierać dane z Arduino? Będę wdzięczny za pomoc.

Edytowano przez mangan
Link do komentarza
Share on other sites

(edytowany)

Napisałem jakiś czas temu mały programik, który siorbie dane z COM i zapisuje w postaci pliku. Porównuję z Twoim i tak na szybko rzucają mi się w oczy dwie różnice:

if (!SetCommMask(hComm, EV_RXCHAR | EV_ERR))
{
    printf("SetCommMask failed with error: %ld\n", GetLastError());
    return 0;
}

I potem:

while (continueLoop)
{
    printf("Waiting for COM...\n");
    if (WaitCommEvent(hComm, &dwEvtMask, nullptr)) {
        if (dwEvtMask & EV_ERR) {
            printf("Wait failed with error %ld.\n", GetLastError());
            continueLoop = false;
            ret = -1;
            break;
        }
    }
  
    // (...)
  
    if (!ReadFile(hComm, &filenameLength, 1, &read, nullptr)) {
        printf("Error while reading on mode %d!", mode);
        continueLoop = false;
        ret = -1;
    }
  
    // (...)
}

Wrzucam jeszcze moją inicjalizację COM, może coś dostrzeżesz...

int hComm_init(char* port)
{
    hComm = CreateFileA(port,
        GENERIC_READ,
        0,
        nullptr,
        OPEN_EXISTING,
        0,
        nullptr);

    if (hComm == INVALID_HANDLE_VALUE)
        return -1;

    DCB commStateConfig;

    if (!GetCommState(hComm, &commStateConfig))
        return -2;

    commStateConfig.BaudRate = CBR_115200;
    commStateConfig.ByteSize = 8;
    commStateConfig.fBinary = TRUE;
    commStateConfig.fNull = FALSE;

    if (!SetCommState(hComm, &commStateConfig))
        return -3;

    COMMTIMEOUTS comm_timeouts;

    if (!GetCommTimeouts(hComm, &comm_timeouts))
        return -4;

    comm_timeouts.ReadIntervalTimeout = 0;
    comm_timeouts.ReadTotalTimeoutMultiplier = 0;
    comm_timeouts.ReadTotalTimeoutConstant = 1;
    comm_timeouts.WriteTotalTimeoutMultiplier = 0;
    comm_timeouts.WriteTotalTimeoutConstant = 0;

    if (!SetCommTimeouts(hComm, &comm_timeouts))
        return -5;

    return 0;
}

// (...)

    int portNameSize = 11 + strlen(argv[1]);
    char* portName = new char[portNameSize];
      
    strcpy_s(portName, portNameSize, "\\\\.\\COM");
    strcat_s(portName, portNameSize, argv[1]);

    int err = hComm_init(portName);

Aha i jeszcze:

  • Co to (dokładnie) znaczy, że "nie działa" odbieranie? Co się dzieje?
  • Pamiętaj, żeby nie uruchamiać Twojego programu równolegle z działającymi monitorami portu szeregowego, bo na gwarant nic nie odbierzesz 🙂
Edytowano przez spook
  • Lubię! 1
Link do komentarza
Share on other sites

W między czasie znalazłem źródło problemu - dodanie "dcbSerialParameters.fDtrControl = DTR_CONTROL_ENABLE;" rozwiązało problem.

Program bez tego wysyłał dane jednak ich nie pobierał lub (nie wiem od czego to zależało) wyświetlał emotikonę uśmiechniętej buźki. Po wielu trudach i znojach wyświetlenie tej emotikony wyglądało trochę jakby los miał dziwne poczucie humoru... W każdym razie problem udało się zażegnać. Dzięki za kod do porównania

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.