Sto cercando di stabilire una comunicazione seriale tra un’applicazione C++ su Windows e un microcontrollore RP2040 (XIAO RP2040). Ho implementato una funzione ConnectRP
per aprire la porta seriale, configurare i parametri (baud rate, timeout, ecc.), simulare il comportamento del serial monitor attivando/disattivando i segnali DTR/RTS e inviare un segnale di wake-up. Tuttavia, il codice non funziona correttamente a meno che non apra prima un serial monitor (ad esempio, quello integrato in VS Code).
Quando uso il serial monitor:
- L’RP2040 si “sveglia” correttamente.
- La comunicazione avviene senza problemi.
Quando uso il mio codice:
- L’RP2040 non risponde ai comandi successivi.
- Non ricevo alcuna risposta dal dispositivo.
Ho provato diverse soluzioni, come simulare il comportamento del serial monitor (attivando/disattivando DTR/RTS), inviare caratteri di wake-up (\n\n\n
) e aggiungere ritardi, ma il problema persiste.
// Funzione ausiliaria per registrare un errore e chiudere la porta seriale
void CArduMover::LogAndClosePort(const CString& errorMessage) {
if (m_enableLog) {
m_moverLog.WriteError(_T("Connect RP"), errorMessage);
}
if (m_hSerial_rp != INVALID_HANDLE_VALUE) {
CloseHandle(m_hSerial_rp);
m_hSerial_rp = INVALID_HANDLE_VALUE;
}
}
void CArduMover::SimulateSerialMonitor(HANDLE hSerial) {
// Attiva DTR e RTS per 50 ms
EscapeCommFunction(hSerial, SETDTR);
EscapeCommFunction(hSerial, SETRTS);
Sleep(50);
}
int CArduMover::ConnectRP() {
// Recupera la porta seriale associata al dispositivo RP2040
CString comPort_rp = CGetCom::GetPortRP(CGetCom::ComConnectedType_T::RP2040);
int iRet = MVR_ERR_SUCCESS;
// Se non è già connesso, procedi con la connessione
if (!m_connected_rp) {
// Verifica che la porta seriale sia valida (lunghezza > 3 caratteri)
if (comPort_rp.GetLength() > 3) {
// Formatta il nome della porta seriale per Windows
comPort_rp = _T("\\\\.\\") + comPort_rp;
// Apre la porta seriale
m_hSerial_rp = CreateFile(
comPort_rp,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
// Verifica se l'apertura della porta seriale è andata a buon fine
if (m_hSerial_rp == INVALID_HANDLE_VALUE) {
if (m_enableLog) {
m_moverLog.WriteError(_T("Connect RP"), _T("Errore apertura porta seriale"));
}
return MVR_ERR_HARDWAREFAIL;
}
Sleep(1000);
SimulateSerialMonitor(m_hSerial_rp);
Sleep(1000); // Attendi 1 secondo per completare il reset
// Configura i parametri seriali
DCB dcbSerialParams = { 0 };
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (!GetCommState(m_hSerial_rp, &dcbSerialParams)) {
LogAndClosePort(_T("Errore nella lettura dello stato della porta seriale"));
return MVR_ERR_HARDWAREFAIL;
}
dcbSerialParams.BaudRate = CBR_256000;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(m_hSerial_rp, &dcbSerialParams)) {
LogAndClosePort(_T("Errore nella configurazione dei parametri seriali"));
return MVR_ERR_HARDWAREFAIL;
}
// Configura i timeout per la lettura/scrittura
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 5000;
timeouts.WriteTotalTimeoutConstant = 1000;
if (!SetCommTimeouts(m_hSerial_rp, &timeouts)) {
LogAndClosePort(_T("Errore nella configurazione dei timeout"));
return MVR_ERR_HARDWAREFAIL;
}
// Pulisci i buffer prima di inviare il segnale di wake-up
PurgeComm(m_hSerial_rp, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
// Aggiorna lo stato di connessione
m_connected_rp = true;
CleanReadBuffer();
}
else {
if (m_enableLog) {
m_moverLog.WriteError(_T("Connect RP"), _T("Porta seriale non rilevata"));
}
return MVR_ERR_HARDWAREFAIL;
}
}
return iRet;
}