Newsgroup: it.comp.lang.c++
Titolo: porta seriale

Sto cercando di comunicare con la porta seriale com con un PIC,
programmandola in Visual studio (va bene sia c + c++).
Il PIC manda 2 byte da 8 bit ognuno ogni millisecondo (ma questo tempo
può anche essere modificato) con baudrate è di 115200 e a me serve
solo leggere questi dati possibilmente ogni ms.
C'è modo per acquisire direttamente dalla seriale un int e non un
char, come invece ho fatto, evitando il cast da char a int? Ho provato
a dichiarare "int out[2]" ma acquisisce dati strani con migliaia di
cifre (cmq questo non è tanto un problema, tanto con il cast
successivo da char a int si risolve).
I problemi che ho riscontrato sono i seguenti:
 * se non metto PurgeComm(h,PURGE_RXCLEAR); il sistema risponde con un
certo ritardo di circa 10 secondi, cioè dopo circa 10 secondi vengono
mostrati a schermo i dati che erano stati mandati sulla seriale dal
PIC 10 secondi prima. Questo immagino sia un problema dovuto al buffer
della porta seriale, per questo ho provato a settare il buffer a 2
byte ma se metto SetupComm(h, 2, 0) o non lo metto non cambia nulla.
* se commento lo Sleep(1), il tempo del ciclo di lettura t_tot alle
volte è pari 0 e alle volte è pari a 15ms. Se invece è presente nel
cilco lo Sleep(), t_tot diventa pari a 15, 16 ms. Se alzo lo
Sleep(10), t_tot resta sempre a 15, 16 ms.... se lo alzo a (100),
t_tot è pari a 108, 109... se lo alzo a (500), t_tot è pari a 500.....
non capisco
* senza lo Sleep alle volte vengono scambiati i 2 byte inviati, cioè
vengono invertiti il primo col secondo, immagino sia un problema di
sincronizzazione.
Qualcuno sa come risolvere?
Vi ringrazio in anticipo.
P.S.: appena qualcuno mi può aiutare gli mando il codice, tanto sono
solo funzioni di inizializzazione.

 * se commento lo Sleep(1), il tempo del ciclo di lettura t_tot alle
Non è che ti sei scordato di riportare il codice? A quale Sleep stai 
facendo riferimento?
E.

   
Per il resto, mi sembrano piu' problemi legati a Windows che al C++ .......
B.

 
massi.passalac...@gmail.com
 ha scritto:

Non volevo metterlo il codice per non appesantire il tutto.
Cmq ci sono novità, ho provato un codice semplice semplice scaricato
da internet e funziona, nel senso che sembra acquisire in realtime (a
schermo i dati vengono aggiornati in realtime se muovo l'encoder). Ora
l'unico problema è che ogni tot cicli il tempo di lettura arriva a
t_tot=15ms, mentre nelle altre acquisizioni è nullo... non capisco il
perchè.
Stavolta allego il nuovo codice:
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
int main(int argc, char* argv[])
{
char buf[2];
DWORD read = 0;
DWORD i;
int byte[2],angle;
double time_i,time_f,t_tot;
// open port for I/O
HANDLE h = CreateFile("COM1",
GENERIC_READ|GENERIC_WRITE,
0,NULL,
OPEN_EXISTING,0,NULL);
if(h == INVALID_HANDLE_VALUE) {
PrintError("E012_Failed to open port");
} else {
// set timeouts
COMMTIMEOUTS cto = { 1, 100, 1000, 0, 0 };
DCB dcb;
if(!SetCommTimeouts(h,&cto))
PrintError("E013_SetCommTimeouts failed");
// set DCB
memset(&dcb,0,sizeof(dcb));
dcb.DCBlength = sizeof(dcb);
dcb.BaudRate = 115200;
dcb.fBinary = 1;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
// dcb.fOutxCtsFlow = 1;
// dcb.fRtsControl = DTR_CONTROL_HANDSHAKE;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.ByteSize = 8;
if(!SetCommState(h,&dcb))
PrintError("E014_SetCommState failed");
while(!kbhit()) {
                //Prendo il clock iniziale del ciclo di lettura
                time_i=clock();
                ReadFile(h,buf,sizeof(buf),&read,NULL); // read is
updated with the number of bytes read
                //Converto i 2 byte nell'angolo di interesse per
l'encoder
                angle=byte[1]*256+byte[0];
                //Prendo il clock finale del ciclo di lettura
                time_f=clock();
                //Vedo quanto ci ha messo il ciclo di lettura
                t_tot=((time_f-time_i)/CLOCKS_PER_SEC)*1000;
                //Stampo a schermo i byte letti dalla porta COM
                for (i=0; i<read; i++)
                                printf("Byte[%i]: %i ", i,(unsigned
char)buf[i]);
                printf("Angolo: %i Tempo: %.2lf BLetti: %i
\n",angle,t_tot, read);
                //fprintf(stream,"%i\n",angle);
                //printf("\n");
                }
CloseHandle(h);
}
system("PAUSE");
return 0;
}

                 t_tot=((time_f-time_i)/CLOCKS_PER_SEC)*1000;
Quanto vale CLOCKS_PER_SEC?
Comunque metterei:
	t_tot = (time_f-time_i)*1000/CLOCKS_PER_SEC;
E.

 sincronizzazione.
Quando leggi dalla seriale, non è detto che i due byte che stai tentando 
di leggere siano già arrivati. Nel tuo caso, evidentemente a volte nel 
momento in cui chiami ReadFile è arrivato solo il primo byte (la 
variabile read vale 1). Dovresti gestire l'accodamento dei byte ricevuti 
e poi elaborare solo quando hai completato i due byte.
Esempio (scritto un pò male, ma è solo per darti un'idea...):
char buf[2];
char data[2];
int nCount = 0;
while(!kbhit())
{
	// legge 1 o 2 byte
	ReadFile(h,buf,sizeof(buf)-nCount,&read,NULL);
	if (read == 1)
	{
		// accodamento
		data[nCount] = buf[0];
		nCount++;
		if (nCount == 2)
		{
			Elabora(data);
			nCount = 0;
		}
	}
	else if (read == 2)
	{
		data[0] = buf[0];
		data[1] = buf[1];
		Elabora(data);
		nCount = 0;
	}
}

                 angle=byte[1]*256+byte[0];
Sleep(1);
time_f=clock();
t_tot=((time_f-time_i)/CLOCKS_PER_SEC)*1000;
mi succede invece, rispetto al caso precedente in cui c'erano 16 zeri
di t_tot e un valore di t_tot a 16, di avere t_tot sempre fisso  a 16
e solo se alzo lo sleep oltre questi 15ms vedo la sua influenza. Ad
esempio se metto Sleep(20) --> t_tot=20ms
Qualcuno mi sa spiegare il perchè?

 Qualcuno mi sa spiegare il perchč?
A parte la precisione della funzione Clock() (vedi sopra),
Sleep(1) non ti ritorna dopo un millisecondo ma dopo almeno un millisecondo.
La funzione Sleep rilascia il controllo al sistema operativo per un 
certo numero di millisecondi, ma poi Windows ti restituisce il controllo 
   appena gli č possibile e quindi non necessariamente subito.

    appena gli è possibile e quindi non necessariamente subito.
Ok capito, ma allora che posso utilizzare per vedere il tempo
effettivo della funzione readfile?

 effettivo della funzione readfile?
Prova con GetTickCount
E.

 E.
GetTickCount dovrebbe essere uguale a Clock.
Prova invece le funzioni timeGetTime, QueryPerformanceCounter e 
QueryPerformanceFrequency.
Vedi la documentazione e gli esempi su MSDN e su Google, se non riesci 
posso postare un esempio appena ho un pò di tempo...