Serial.read() inicio condicionado

Viva.

Estou tentando ler dados para preencher umas arrays com dispositivo serial a mandar dados para um mini pro, que posteriormente serão apresentados num lcd..

Até agora consigo receber os dados, preencher as arrays e mostrar-las no lcd.
O meu problema, para qual peco ajuda é no inicio da leitura. Como fazer para receber os dados em sequência, isto é a leitura e preenchimento dos dados para as arrays so ser iniciada quando receber um determinado comando vindo do serial, de forma a que os valores recebido sejam sequenciais, de forma que os dados recebidos sejam colocados na respectiva array.

if (Serial.available()>0)
  {
   
  Serial.readBytesUntil(lf, vr, 20);     
  Serial.readBytesUntil(lf, dt, 20);
  Serial.readBytesUntil(lf, tm, 20);
  Serial.readBytesUntil(lf, wip, 20);
  Serial.readBytesUntil(lf, load, 20);
   
  }

No meu código cada uma das arrays, vr,dt,... estão sendo preenchidas correctamente até receber um LF, 0x\0d, e visualizadas no LCD, a sequência é que varia.. relacionado com time outs, delays do dispositivo serial.
Ja tentei varias formas, serial a espera dum determinado char, delays.. etc, mas até agora sem sucesso.

Agradeço a vossa ajuda.

If seriall.available()>20 ...

Não será isso que pretendes?

bubulindo:
If seriall.available()>20 ...

Não será isso que pretendes?

Viva.

Também tentei, e estou na mesma. A primeira sequência do loop resulta, mas so isso mesmo.
Basicamente o pretendido era receber dados enviados por serial e serem armazenados em arrays .
Tipo:

data1 --> array1
data2 --> array2
data3 --> array3
....

A ideia era ter um marcador de inicio de leitura, fiz algo parecido para ligar/desligar LEDs com :

if (inChar == '\1') {
      digitalWrite(led, HIGH);

Agora neste caso não estou a conseguir a manter a sequência correcta.

Obrigado pela sugestão.

Não te estarás a esquecer de descartar o enter?

Sem saber qual é a string que estás a receber ou o que está a enviar, não há muito por onde te ajudar...

bubulindo:
Não te estarás a esquecer de descartar o enter?

Sem saber qual é a string que estás a receber ou o que está a enviar, não há muito por onde te ajudar...

Viva.

Os dados a serem enviados-recebidos, provem dum sistema linux, o envio é realizado pela seguinte forma:

echo "data1\0x0d" > /dev/tts/1

O conteúdo do data1 são char, ascii sem caracteres especais, tudo alfanumérico 1-0 e a-z,

O \0x0d no final é um marcador de fim de string para a condição do readBytesUntil.

O que nao estou a conseguir é criar uma condição com marcador para definir o inicio da leitura-armazenamento de dados nas arrays.

A tua sugestão deu resultado no 1 primeiro loops, data1 data2 data3 data4 ..., foram correctamente armazenados e mostrados na ordem correcta no lcd. A partir do 2-3 loops, dava uma sequência totalmente diferente, era mostrado no lcd data1 data3 data4 data1 de seguida podia ser data2 data3 data1 data4...

Mais uma vez obrigado pela atenção.

Ou seja, os dados foram bem recebidos, mas são mostrados numa ordem estranha?

Repara que todas estas questões podem ser facilmente respondidas com mais informação, particularmente o código fonte...

Até ao momento temos dois pedacinhos de código bastante pequenos e a tua opinião acerca do que o problema é. Sem mais dados é mesmo impossível ajudar.

data1 tem um tamanho constante? Ou é variável?

O sistema linux está a correr como? Tem threads ou processos a aceder à porta série duma forma não sequencial?

A maneira mais robusta de resolver isto é mesmo através dum protocolo... da mesma maneira uqe mandas um caracter de fim, podes enviar um caracter de inicio que te diz o que a string é...

Algo tipo:

echo "Adata1\0x0d" > /dev/tts/1

bubulindo:
Ou seja, os dados foram bem recebidos, mas são mostrados numa ordem estranha?

Correcto. No 1r loop a ordem esta certa, a seguir, nunca mais.

Repara que todas estas questões podem ser facilmente respondidas com mais informação, particularmente o código fonte...

Até ao momento temos dois pedacinhos de código bastante pequenos e a tua opinião acerca do que o problema é. Sem mais dados é mesmo impossível ajudar.

void loop()
{
  lcd.clear_lcd(WHITE);
  delay (200);
  char wip[20]="                   ";
  char load[20]="                   ";
  char vr[20]="                   ";
  char dt[20]="                   ";
  char tm[20]="                   ";
 
  int st = 03;
  int lf = 10;

// recepcao e armazenamentos de dados via serial

while(Serial.available() > 20)
  {
  Serial.readBytesUntil(lf, vr, 20); 
  Serial.readBytesUntil(lf, dt, 20);
  Serial.readBytesUntil(lf, tm, 20);
  Serial.readBytesUntil(lf, wip, 20);
  Serial.readBytesUntil(lf, load, 20);
  }
  
// visualiza as arrays no lcd

 lcd.str_lcd(vr,1, 1, 1, BLACK, -1);
 lcd.str_lcd(dt,1, 3, 1, BLACK, -1);
 lcd.str_lcd(tm,1, 4, 1, BLACK, -1);
 lcd.str_lcd("WAN ip:",1, 5, 1, BLACK, -1);
 lcd.str_lcd(wip,1, 6, 1, BLACK, -1);
 lcd.str_lcd("Load average:",1, 7, 1, BLACK, -1);
 lcd.str_lcd(load,1, 8, 1, BLACK, -1);
 
 delay (1000);
}

Codigo, extremamente simples.
O restante é irrelevante, acho eu, porque so se aplica a inicialização do LCD e as definições do mesmo.
Nas definições serial, também nada de complicado, so mesmo velocidade: 9600.

data1 tem um tamanho constante? Ou é variável?

Data1, data2, etc, variam de 10 chars ate 19 max.

O sistema linux está a correr como? Tem threads ou processos a aceder à porta série duma forma não sequencial?

È um script basico em bash, que esta no cron e lançado de x em x mns.

 echo -e "$vr\0x0d" > $SR
  echo -e "$D1\0x0d" > $SR
  echo -e "$D2\0x0d" > $SR
  echo -e "$WIP\0x0d" > $SR
  echo -e "$LD\0x0d" > $SR

Também tentei num mesmo echo, também tentei com delay entre cada um,etc.

[/quote]
A maneira mais robusta de resolver isto é mesmo através dum protocolo... da mesma maneira uqe mandas um caracter de fim, podes enviar um caracter de inicio que te diz o que a string é...

Algo tipo:

echo "Adata1\0x0d" > /dev/tts/1[/quote]

Pois, nos LCD 1602, com i2c, mando isso da mesma forma, sem ser por arrays com LF a separar, mas no caso deste lcd so mesmo por string completas e recorrendo a arrays para delimitar os campos. Por isso é que testei com readBytesUntil, com óptimos resultados na aquisição e visualização no LCD, a nao ser o problema de sequência. Vou tentando variações do codigo.

Mais uma vez obrigado.

Qual é essa biblioteca de lcd que estás a usar?

O LCD tem quantas linhas?

bubulindo:
Qual é essa biblioteca de lcd que estás a usar?

O LCD tem quantas linhas?

Viva.

Estou testando um LCD dum siemens M55: 101 x 80 pixels.

A lib: LM15SGFNZ07 library

https://bitbucket.org/mindogas/lm15sgfnz07/overview

A lib, achei a coisa interessante; a cores, nao muito lenta na resposta, da para fazer uns efeitos gráficos, cores. tamanho da letra, etc.. cheguei a testar um 6100 da nokia, achei péssimo os resultados.
Já agora, testei o meu codigo com LiquidCrystal e um 1602, resultado foi o mesmo, nao conseguir definir um inicio de leitura certo com marcador a definir o inicio de leitura.

Obrigado.

Seja como for... mesmo que isto funcionasse, terias na mesma problemas de sincronização porque estás a assumir que ambos estão a fazer a mesma coisa.

Ou seja, que o computador está a mandar precisamente o que o Arduino quer ouvir... o que pode não ser verdade.
Enviando um caracter de inicio de trama e bastante mais simples para o Arduino de fazer o que tem a fazer... e ficarias com um programa mais leve.

char mens[20]; //um array... em vez de 5 ou 6. 
unsigned char tipo = 0; 
if (Serial.available() >20) {
   Serial.readBytesUntil(lf, mens, 20); 
}
switch (mens[0]) {
    case 'A': 
        tipo = 1;
        break;
    case 'B': 
        tipo = 3;
        break;
    case 'C': 
        tipo = 4;
        break;
//.... preenche o resto... 
}

lcd.str_lcd(&mens[1],1, tipo, 1, BLACK, -1);

Outra coisa...
Isto está extremamente errado!!!!

while(Serial.available() > 20) //se estiverem 20 caracteres no buffer.... 
  {
  Serial.readBytesUntil(lf, vr, 20);   //vais ler 20, isto está bem... 
  Serial.readBytesUntil(lf, dt, 20);  // + 20 = 40
  Serial.readBytesUntil(lf, tm, 20);  // + 20 = 60
  Serial.readBytesUntil(lf, wip, 20);  // + 20 = 80
  Serial.readBytesUntil(lf, load, 20);  // + 20 = 100... 
  }

Não pode funcionar. A solução é definires qual a trama que estás a enviar para o Arduino e partires daí.

Assim vai funcionar facilmente. O que pretendes fazer, além de não funcionar vai ocupar-te imenso tempo para conseguires algo que parece funcionar mas que ao minimo problema dá logo borrada.

Viva.

Meu muito obrigado pelo tempo disponibilizado para me ajudar.

Testei o codigo, mas infelizmente continuo a ter os mesmos problemas.
No 1r loop tudo correcto, os dados aparecem na sequência correcta. A partir do 2, fica a coisa descontrolada.
Alias vê-se na 1 foto, o codigo ignora o case B, e ate coloca o B juntamente cos dados no LCD.

Shoots do LCD:

O codigo:

void loop()
{
  //lcd.clear_lcd(WHITE);
  lcd.str_lcd("WAN ip:",1, 5, 1, BLACK, -1);
  lcd.str_lcd("Load average:",1, 7, 1, BLACK, -1);
  int st = 03;
  int lf = 10;
// recepcao e armazenamentos de dados via serial
char mens[19]; //um array... em vez de 5 ou 6.
unsigned char tipo = 0;
if (Serial.available() >20) {
Serial.readBytesUntil(lf, mens, 20);

switch (mens[0]) {
    case 'B':
        tipo = 1;
        break;
    case 'C':
        tipo = 3;
        break;
    case 'D':
        tipo = 4;
        break;
    case 'E':
        tipo = 6;
        break;
    default:
        delay(4000);
        lcd.clear_lcd(WHITE);
       
}

lcd.str_lcd(&mens[1],1, tipo, 1, BLACK, -1);
}
}

Neste teste iniciei em case B, pensando que a hora por ter AM, o A poderia interferir no case.
Adicionei um default para fazer um clear do lcd passado um delay, para tentar perceber o que se passava.

No envio dos dados:

echo -e "B$vr\0x0d" > $SR
  echo -e "C$D1\0x0d" > $SR
  echo -e "D$D2\0x0d" > $SR
  echo -e "E$WIP\0x0d" > $SR

Estou a testar isto tudo num linksys wrt54gs com dd-wrt, sendo linux, é mais pratico para realizar os testes. Fiz dessa forma para implementar com liquidcrystal e uns 1602, não há dificuldades em transpor os scripts de leitura.

Mais uma vez, obrigado.

Existem algumas coisas que sem testar não te sei dizer (por não usar algumas destas funções...)

Tu mandas um LF para identificar o fim da string, mas não sabes o que é que a tua função ReadBytesUntil faz com esse LF. Idealmente devia tirá-lo do buffer e não o colocar no array da mensagem. Mas não sei se faz isso ou não. Este poderá ser um problema.

O outro é o facto dos arrays não estarem terminados... Mais uma vez, não sei se a função readbytesuntil te coloca um '\0' na variável mensagem para que quando leres como string as funções saibam onde parar. Uma solução para isto é garantires que o teu array mens está limpo.

char mens[19]; //um array... em vez de 5 ou 6.
unsigned char tipo = 0;
memset(mens, '\0', 20); //isto inicializa o array com '\0'. Para garantir que tudo está limpo e que ficas com um caracter de termino.

Eu não tenho a última versão do Arduino para experimentar isto... mas pelo que mostras nas imagens parece ser uma sobreposição de memória que está a ocorrer.

Outra coisa que terás de fazer, julgo eu, é limpar o LCD antes de refrescares os dados.

    default:
        delay(4000);
        lcd.clear_lcd(WHITE);
       
}
lcd.str_lcd("                    ",1, tipo, 1, BLACK, -1); //isto deverá "limpar" o LCD para que não haja sobreposição de pixels. 
lcd.str_lcd(&mens[1],1, tipo, 1, BLACK, -1);
}

De momento acho que o problema estará no LCD e não necessariamente na comunicação série. Uma maneira de testares isto é desligares o LCD e em vez de mandares os valores para o LCD, envia para a porta série e vê se aparece o que pretendes sempre que os dados são enviados. Assim tiras a limpo qual é ao certo o problema actual.

o problema tá no “0x0d” troca ele por “\n” que funciona

fabio_h:
o problema tá no "0x0d" troca ele por "\n" que funciona

Viva.

Ja tinha testado, "\n" ou "\0x0a". Tudo na mesma.
Da ajuda que o amigo bubulindo me deu, consegui pelo menos no 1r loop uma sequência correcta.
Ao que testei, desligando os scritps e manualmente lançando o echo , com qualquer dos marcadores; "0x0d" ou como indicaste "\n" ou "\0x0a" quando lanço:

echo "Bdata1\0x0ateste"

No lcd, so é mostrado data1, na linha correcta do LCD

Este LCD ta em vias de ir parar ao lixo. Vou me virar para um nokia 1100, da muito menos problemas e com um codigo de leitura de dados similar ao que utilizo nos 1602.

Muito obrigado aos dois pelas disponibilidade.

Portanto, o protocolo série parece estar a funcionar?

Experimenta com outro lcd então... Talvez até um alfanumérico...

Viva.

bubulindo:
Portanto, o protocolo série parece estar a funcionar?

Parece que sim. Alternando o B-C-D-E o data1 vai ter a linha do LCD desejada.

Experimenta com outro lcd então... Talvez até um alfanumérico...

Pois, tinha achado pinta a estes LCDs, e pelo preço ainda melhor.

Encontrei um post com uma alternativa ao que estava a tentar fazer. Isto é, em vz de enviar sequencialmente os dados, enviar tudo duma vz, separado por ",", e depois retirar da array os dados.

A minha abordagem com a info a ser enviada para o LCD era para a coisa ficar modular do ponto de vista a que uma vz programado o Arduino, nunca mais tivesse que tocar no codigo.
Nos 1602 e no 1100, fiz isso, se quero acrescentar info, é so colocar mais uns echo's no linux ( dados, limpeza de LCD e marcadores ). Com este... ta difícil.

Mais uma vz muito obrigado.