LusoRobótica - Robótica em Português
Electrónica => Protocolos => Tópico iniciado por: TMAsantos em 10 de Julho de 2015, 01:36
-
Boas malta, tenho uma questão que me anda a fazer confusão há algum tempo.
O meu GPS comunica em porta série (UART) com o arduino, por exemplo. Esta comunicação é feita a um baud rate de 38400.
Isto significa que transmito 38400 bits por segundo, logo demoro cerca de 0.026 ms a transmitir 1 bit. Como o NMEA transmite strings e a string do GPGGA tem aproximadamente 64 caracteres ASCII (cada 1 tem 8 bits), demoro cerca de 0.026*8 ms a transmitir 1 carácter e 0.026*8*64 a transmitir todos, o que me dá aproximadamente 13 ms, ignorando o start bit e stop bit.
Estou a fazer a leitura no arduino e a medir o tempo que a leitura demora, utilizando a função "millis()" e obtenho um tempo de aproximadamente 0-2 ms na leitura, o que é muito menos do que estava à espera.
Estou a interpretar mal o protocolo?
Obrigado pela ajuda
PS:
Exemplo de uma strinf GPGGA:
$GPGGA,205526.500,3938.8970,N,00984.5289,W,1,5,1.86,84.6,M,50.7,
-
Não sei ao certo como escolheram implementar no Arduino, mas a leitura provavelmente é feita "em background" para um buffer (array, circular) interno da biblioteca, e quando fazes o read dos bytes esse read só está a ler do buffer. A recepção de 1 byte é feita pelo hardware, e depois é gerada uma interrupção, onde o byte *já recebido* apenas é lido de um registo e guardado no buffer, de onde depois o read lê.
-
Estou a utilizar a biblioteca SoftwareSerial do Arduino.
Utilizo a função read() do objecto. Se calhar está a guardar num buffer interno como dizes, mas há outra questão.
O GPS envia dados com uma frequência de 10Hz. Se eu não respeitar esta frequência na leitura, quando chamo o read(), ele manda-me um caracter que não é o inicio da string, o que me faz achar que ele não os guarda num buffer.
A função millis() pode corromper se no meio de dois millis() tiver um ciclo while a fazer a leitura, sem delays internamente?
-
O buffer tem um limite de tamanho, se não leres dados do buffer a tempo, os que lá estão são sobrepostos por novos bytes a chegar (ou os novos são descartados, não sei como está implementado).
Mete aí o código do teu teste.
-
Estive a ler melhor a documentação e é verdade, tem um buffer de 64 bytes.
O código não é totalmente meu, retirei à uns tempos de um blog, já não me lembro qual. Só fiz umas ligeiras alterações para medir o tempo.
SoftwareSerial GPS(2, 3);
String reads;
int sta;
void setup () {
Serial.begin(38400);
// connect GPS RX-O to pin 2
pinMode (2, INPUT);
// connect GPS TX-I to pin 3
pinMode (3, OUTPUT);
GPS.begin(38400);
// setup NMEA output mode.
GPS.print("$PGCMD,16,1,1,1,1,1*6B\r\n");
sta= millis();
}
void loop() {
char ch = GPS.read();
if (ch != -1){
if(ch == '$'){
Serial.println(millis()-sta);
Serial.println(reads);
sta= millis();
reads= "$";
} else
reads+=ch;
}
Entretanto depois criei uma biblioteca em cpp para compactar o código, mas faz basicamente a mesma coisa.
O importante aqui é só mesmo verificar os 13 ms, que neste caso são entre 0 e 2 ms (devido ao buffer).
-
Humm, a coisa ainda não está bem explicada. Seria interessante saber quanto tempo demora isto a executar:
Serial.println(millis()-sta);
Serial.println(reads);
p.s. "char ch" é arriscar um bocado, ch devia ser int.
-
Ser char ou int não é a mesma coisa? Ele depois converte de int para ASCII por ser char.
As linhas que indicaste demoram entre 2 e 3 ms a executar, acabei de medir.
-
Pois, ainda há por aí qualquer coisa incoerente na explicação do curto tempo de leitura, mas se recebes bem as strings é porque o "erro" está na medição ou na configuração.
Se o GPS te enviasse 0xff provavelmente não, char e int não era a mesma coisa. Noutras plataformas poderias ter ainda outro tipo de problema, porque o char nem sempre é signed por omissão.
-
Fiz esta script rápida, para perceber como é que os dados chegam ao buffer:
int aval = GPS.available();
Serial.println(aval);
if(aval >=63){
reads="-";
for(i=0; i<aval; i++)
reads+= (char)(GPS.read());
Serial.println(reads);
}
delay(1);
O resultado foi o seguinte:
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
59
63
-$GPGGA,210610.100,XXXX.XXXX,N,XXXXX.XXXX,W,1,7,1.68,58.5,M,50.7
Basicamente dá para ver que os dados chegam com uma frequência de 10Hz, como esperado, e enchem logo o buffer (em menos de 2ms). Depois ler é num instante, claro, já está no buffer do Arduino.
Não é estranho ser em menos de 2ms? As contas no meu primeiro post não estão bem feitas?
-
Isto significa que transmito 38400 bits por segundo, logo demoro cerca de 0.026 ms a transmitir 1 bit. Como o NMEA transmite strings e a string do GPGGA tem aproximadamente 64 caracteres ASCII (cada 1 tem 8 bits), demoro cerca de 0.026*8 ms a transmitir 1 carácter e 0.026*8*64 a transmitir todos, o que me dá aproximadamente 13 ms, ignorando o start bit e stop bit.
Na realidade para enviar um byte de 8 bits via série precisas de mais um start e um stop bit, portanto nas tuas contas deviam ser 0.026*10*64=16.66ms
Assim por alto parece-me que estás a o software serial, que depende de interrupts para ler os dados série, e devem maram-te os millis(), que nem sempre são de fiar.