Conversão A/D e transmissão Serial com Arduino DUE

Olá pessoal, estou usando esse código, mas ele está causando uma descontinuidade no fim da aquisição de 1000 pontos. Tenho certeza que essa descontinuidade é causada pelo tempo de transferência serial.

Como eu posso corrigir isso, para obter uma transmissão contínua sem perda de pontos ao final de cada aquisição de 1000 pontos?

Segue o código em anexo.

Att.

Exibições: 671

Anexos

Responder esta

Respostas a este tópico

Boa noite Sr. T,

O sr. conseguiu compilar sem erros este sketch?

Além deste problema de não compilar, estive analisando o seu sketch e não entendi a lógica.

O Sr. lê 1000 vezes a entrada analógica Port A0  e guarda sempre na mesma variável,

em seguida imprime 1000 vezes esta variável.

Não entendi o sentido lógico para esta sequencia.

poderia me explicar melhor para que tente ajuda-lo na sua dificuldade?

RV

Olá amigo. Para compilar o programa, o arduino DUE precisa estar conectado no computador. Eu só consigo compilar assim.

Dentro do loop, o primeiro FOR vai armazenando ponto a ponto até encher o buffer values com 1000 pontos.

Em seguida entra o segondo laço FOR que transfere todo o buffer values para a serial para visualização no plotter serial.

Ou seja ele carrega o buffer e descarrega via serial. Só que durante o tempo de descarregamento gera um atraso que me faz perder as amostras. Queria corrigir isso, para que eu leia todo meu sinal de forma contínua.

Obrigado pela ajuda e desculpe a demora.

Boa tarde Sr. T.

1.  " Para compilar o programa, o arduino DUE precisa estar conectado no computador.

       Eu só consigo compilar assim."

        Se você estiver usando a IDE do arduino, eu digo : afirmação errônea.

        Para "somente" compilar usando a IDE do arduino, basta selecionar o arduino correto,

        e depois clicar em  no local indicado pela seta vermelha, ou selecionar a opção no losango

        vermelho indicado no menu  pulldown ou clicar Crtl + RFigura abaixo

2. Quando perguntei  " O sr. conseguiu compilar sem erros este sketch?  " e em seguida

    afirmei "  Além deste problema de não compilar, ", foi  porque ao compilar seu  código

    apareceram vários erros,  iniciando por este.

    "  ADC_ARDUINO_DUE:14:11: error: incompatible types in assignment of

       'RoReg {aka volatile long unsigned int}' to 'long unsigned int [1000]'

       values=(ADC->ADC_CDR[7]); // adds the value to the buffer   "

  

     Sabe porque destes erros:

     É que você definiu a variável  values como sendo uma matriz (array) de 1000 células,

    "  unsigned long values[1000];  "

     mas ao usa-la nas linhas 14 e 19, não informou qual célula deveria seu usada.

     o correto na linha 14 seria :  values[i]=(ADC->ADC_CDR[7]);

     e  na 19 seria:   Serial.println(values[i]);

     Desta forma o código compila corretamente.

Espero ter sido mais claro agora.

RV

Olá amigo, deixei em anexo o programa corrigido. Este está compilando direitinho. Compilei e gravei.

Anexos

olá Thiago.

      Como o RV  disse,  esse código que vc anexou no seu post inicial,  irá compilar com erros, e a causa disso é a incompatibilidade de tipos ("no matching") entre o Vetor de 1000 valores tipo "unsigned long", e o "value" usado dentro dos dois statements "for" na sua função "loop".  Isto é bem simples de resolver,  e basta que nas linhas dentro dos "for" onde está escrito apenas "value",  vc mude para "value[i]".  Na realidade, acho que seu código "original" já está assim com o índice "i" para acesso aos elementos do Vetor "value",  e provavelmente no código que vc simplificou para postagem aqui, acabou esquecendo de colocar o índice "i" para o acesso aos elementos do Vetor.

      Sobre a questão de compilar apenas com o Due conectado, isto é estranho, pois aqui comigo seu código (depois de corrigido com o acréscimo do "i"), compila sem necessitar que o Due esteja conectado via USB.  Então pergunto:  qual dos dois botões da IDE do Arduino  vc está usando para compilar?  É o botão que eu marquei na cor verde claro na figura a seguir, ou o botão que marquei na cor  rosa ?

(clique na figura para "zoom")

       E caso queira descobrir alguns truques sobre configurar sua IDE de forma mais adequada ao uso para desenvolvimento, aconselho ver um documento que preparei a algum tempo sobre isto:  "config_IDE_Arduino_00.pdf"

      Já sobre a sobre a Aquisição e "printagem" dos valores, aparentemente vc está com alguns conceitos equivocados, ou não conhece estes conceitos. Veja:  são dois processos:  Aquisição dos valores, e "printagem" destes valores via Serial.  Cada um deles processa em momento diferente, e cada um deles também leva um tempo total diferente para ser executado.

      Para que seja possível "casar" estes dois tempos de execução, é preciso saber qual a natureza do sinal que vc está aquisitando no A0 do Due. Ou seja:  que tipo de sinal é este?  É um sinal de áudio? Ou seria um sinal da variação da temperatura  de alguma coisa?  Em síntese:  qual a faixa de frequência deste sinal ?

      Depois de saber a natureza do sinal que está sendo aquisitado, então é possível determinar a técnica mais adequada para sua aquisição e "printagem" dos valores aquisitados daquele sinal.

      Mas veja a contra-partida que coloquei na sugestão do Vitor Augusto, pois ela contém informações técnicas importantes sobre seu Sistema.

      Abrçs,

      Elcids

Olá. Coloca um delay dentro do "for" que descarrega na serial.

Esse parece ser o problema clássico de fluxo quando o transmissor e o receptor têm velocidades diferentes.

Por curiosidade, o protocolo TCP/IP implementa controle de fluxo por uma "janela deslizante": https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Flow_co...

olá Vitor.

      Colocar um delay  como na sua sugestão, só irá piorar a questão da perda de samples, que causa descontinuidade no sinal observado pelo Thiago no Serial Plotter do Arduino.

      A questão aqui é qual é a natureza do sinal que ele está aquisitando. Ou seja, qual a frequência do sinal  que ele está aquisitando via ADC do Due. A amplitude ele já deve ter tratado adequadamente, uma vez que ele já vê o sinal na Serial Plotter da IDE do Arduino. Mas nada sabemos sobre a frequência do sinal.

      Conhecendo a frequência do sinal é possível determinar a técnica mais adequada para a aquisição e posterior visualização do sinal aquisitado.  E claro, aí entra a Frequência de Nyquist,  e conhecendo a mesma  é possível determinar qual a menor Taxa de Amostragem para a aquisição, mantendo a qualidade desejada para a reprodução digital do sinal.

      Veja: o loop de aquisição do Thiago funciona a "todo vapor", na máxima velocidade que o Due  permite (Hardware e Firmware). O ADC do Due tem uma taxa de conversão máxima de 1MHz, ou seja, resulta em 1 Mega sample por segundo. Considerando que o Due utiliza um ARM, e que o Compilador C++  tenha gerado um código com "boa" performance,  é quase certo que o loop de conversão  gastará para ser executado um tempo igual a 1000 / 1MHz = 1 ms , ou seja, 1 mili-segundo.  E isto seria "adequado" para um sinal de no máximo 500kHz  e com um Processamento de Sinal também adequado (aplicando técnicas para a reconstituição do sinal).  Caso nenhum Processamento de Sinal seja aplicado, como é o caso do Thiago, então temos que reduzir drasticamente a faixa de frequência do sinal, tipo 10 a 20 vezes menor que a Frequência de Nyquist, para que seja algo apresentável na tela do Serial Plotter.

      Mas aqui entra o outro problema:  cada "println" no loop de "printagem" dos 1000 valores aquisitados,  enviará em média, 6 caracteres ASCII para a serial. Desses 6 caracteres, 4 são considerando valores convertidos da ordem de 4 dígitos decimais, ou seja, entre 1000 e 4095 (o ADC do Due tem 12 bits). Não se pode aqui considerar nessa estimativa, valores inferiores a 1000 (que resultariam em 3, 2, ou 1 caracter ASCII para o valor do sample), pois são apenas 1/4 da faixa total, e assim representam 25% da probabilidade (e portanto errôneo considerar isso numa estimativa "grosseira", que é o caso que estou fazendo).  Os outros 2 caracteres ASCII, são o "CR" e o "LF" resultantes do "println".

      Logo, para cada "println", em média teremos 6 caracteres ASCII  sendo enviados pela Serial. Como a taxa da Serial está em 115200, e cada caractere ocupa 10 bits (1 start bit, 8 data, 1 stop bit),  o tempo total necessário para o envio de cada valor  via Serial, será igual a 6 * 10 / 115200 = 0.00052 segundos, ou 0.52 ms (aproximadamente meio mili-segundo). Então aparentemente, multiplicando esse tempo por 1000, teremos o total gasto para enviar todas as 1000 amostras = 0.52 segundos (cerca de meio segundo).

      Infelizmente, a coisa é um pouco pior. Vou explicar porquê. Quando vc "manda" enviar um byte via Serial, o firmware do Due verifica se o TX da UART (Hardware) está livre, e caso esteja, o byte é transferido direto para o Registro do TX da UART. Mas se o TX já está ocupado transmitindo, então o firmware coloca o byte no Queue do TX da Serial, e este byte será automaticamente transmitido  quando o TX ficar livre. Ocorre que o Queue do TX da Serial do Due, tem capacidade para 128 bytes, ou seja, 128 caracteres. Uma vez que um byte tenha sido enviado ao TX da UART, esse byte demorará 87us (87 micro-segundos = resultado de 10 / 115200) para ser enviado. Obviamente que todo o loop de envio não demorará mais que esse tempo (lembrando que é um ARM), então certamente o Queue de 128 bytes ficará entupido após algum tempo (perfeitamente calculável, analisando as iterações iniciais), e quando isso ocorre,  o firmware do Due empaca (há um teste no código da Serial que causa isso intencionalmente), e então fica aguardando que o Queue fique pelo menos um byte livre. Mas claro, assim que essa "vaga" fica livre no Queue, ele já entope de novo com o próximo byte que estava esperando para entrar neste Queue do TX.

      Em suma: após uma quantidade de caracteres um pouco maior que 128, o Queue do TX da Serial  ficará permanentemente entupido no loop de envio, no código do Thiago. E aí a função "println" trava pelo tempo de envio de todos os demais caracteres que restam para serem enviados. Lembrando que cada valor "impresso" via "println", irá gerar em média 6 caracteres, resultando um total de 6 mil caracteres para serem enviados.  Então os cerca de um pouco mais de 128 bytes necessários para o entupimento do Queue do TX da Serial, e a consequente "lerdeza" na execução do loop onde está o "println",  é uma parcela pequena se comparada aos 6 mil caracteres que serão enviados. Ou seja, um grande problema para a descontinuidade da aquisição de samples, se a frequência do sinal aquisitado for tal que o entupimento do Queue cause uma descaracterização do sinal visto no Serial Plotter.

      Claro, sempre é possível usar técnicas de contorno. Mas é preciso saber qual a natureza do sinal aquisitado, especificamente sua faixa de frequência.

      Abrçs,

      Elcids

Elcids, o problema é como o RV falou: só um erro de código. Se tivesse tudo certo e perdesse pacote seria talvez controle de fluxo.

O delay que eu propus iria evitar overflow do buffer, e seria uma solução dependendo do problema. O que você falou de Nyquist seria outro tipo de problema a ser resolvido que não tem a ver com o problema que eu estava tratanto. Outro ponto a pensar é que eu não reduzi a taxa de amostragem, eu propus reduzir a taxa de transferência. No código anexo, a amostragem é feita num loop anterior a transferência.

Ok então.

      Se vc pensa desta forma.

      No entanto, acho que vc pulou a parte onde descrevi que quando o Queue do TX da Serial  fica cheio,  o "println" da Serial não descarta caracteres a serem transmitidos. Ele detecta que o Queue encheu e então aguarda que este fique pelo menos um byte "livre" para então colocar no Queue. E como toda a aquisição está no Vetor de 1000 amostras, nenhum sample deixará de ser enviado. Logo, o problema não é a perda de samples já aquisitados. O problema é a perda de novos samples que representam a continuidade do sinal sendo aquisitado.

      Sobre a função que faz isso no Due, vc pode conferir na figura a seguir, e ver por seus próprios olhos (marquei com uma seta rosa):

(clique na figura para "zoom")

      Abrçs,

      Elcids

Vc está falando do transmissor, poderia ser perda no receptor do outro lado da serial. Eu ainda estava investigando o problema. Por isso eu acho que eu penso certo desta forma.

Esse meu raciocínio foi motivado pela certeza do Thiago: "Tenho certeza que essa descontinuidade é causada pelo tempo de transferência serial.". Só que não era problema na temporização de transferência.

Ok.

      Então continue pensando assim se vc acha que deve.

      Mas veja que no post inicial do Thiago, ele confirma que todas as 1000 amostras são "printadas" corretamente, e que a descontinuidade é depois disso. Ou seja, exatamente como eu descrevi.

      Inicialmente, eu também achei que o problema pudesse ser um overflow do Buffer (ou Queue circular) da  Serial.  Mas ao analisar com cuidado e ver o código fonte específico para o Due (analisei quase toda a LIB relacionada), ficou claro que a coisa era outra.

       Ah, e se não há perda no "lado do TX" no Due, não haverá perda na recepeção no Serial Plotter (e ali é um x86). E ali no lado do PC, nem é uma Serial física, é uma USB onde a taxa de comunicação é muito mais alta, ainda que passe por Drivers e Interfaces até chegar ao Serial Ploter (e no caminho, Queues de 64k aliviam também).

      Abrçs,

      Elcids

Obrigado pela ajuda amigos, amanha irei montar meu set de testes e irei tirar foto dos sinais. Vou organizar melhor meu código e postarei. Li seu artigo sobre a IDE Elcids, muito bacana. Irá ajudar muito na organização. Obrigado pela aula excelente sobre transmissão. Sempre procurei informações sobre isso e nunca achei, vc explicou de forma simples, clara e prática. Irei continuar até resolver tudo. Em breve Tirarei fotos das minhas curvas de aquisição e a frequência da senóide. Obrigado a todos!

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço