dúvida sobre tempo de execução dentro de uma função

Senhores,

tenho um controle de transferência de cargas (eletrônica a parte) que fornece ao arduino um entrada de status de sincronismo, isso é, se posso realizar a troca de alimentação ou não.
Caso o sincronismo esteja ok a sincronização é direta, mas se não for deve contabilizar um delay para comutação de 16ms. Porem ao executar o código e forçar essa condição tenho me deparado com tempos de 400ms, o que não serve para esse projeto. (linhas do programa 442 a 456)

Alguma ideia de como encurtar esse processamento, me faltou o conhecimento neste ponto.

Obrigado,
Teodoro

Exibições: 647

Responder esta

Respostas a este tópico

Bem organizado o codigo, parabens !

Dei uma lida, vou dar um chute. Veja se ajuda.

Se entendi vc está usando corretamente o mils, o conceito está perfeito.

No entanto o Loop está longo, tem leitura, tratamento e impressão de dados.

Fica dificil para o processador voltar no teste de mils em tempo para o proximo teste.

Algumas rotinas são muito demoradas. A mais demorada de todas é a limpeza do LCD. A segunda mais demorada é a escrita no LCD/posicionamento do cursor. Na sequencia vem a leitura do AD com troca de canal.

O Arduino espera o LCD terminar as operações, o que equivale a um delay, idem para o AD, que pede no manual um delay depois de uma troca de canal para estabilização interna. Para simplificar a vida do programador ele é embutido na função (Assim acredito, nunca fui ver).

Considerar:

- Qual a taxa de atualização do display suficiente para a leitura. Por ex 250ms está otimo em geral, assim só a cada 250ms vc precisa apresentar coisas. Mais rapido que isso ou vc vai reescrever o q estava escrito ou vai ficar "piscando".

- Qual a taxa de mudança de valores. Por ex: Se vc estivesse medindo a tensão de uma bateria, a temperatura de um forno, a temperatura de uma geladeira, ler a cada 1s já está otimo, ela não varia bruscamente. Vc poderia se fosse esse caso chavear menos vezes o canal do AD. Por ex em cada loop ele le apenas 1 AD. Quando fazia isso no 8051 (Sem qualquer biblioteca) usava uma interrupção de tempo e fazia invertido: Ler porta do AD e Chavear o AD. Assim o tempo para acomodação e digitalização acontecia enquanto o processamento principal rolava. Quando interrompia o flag de AD pronto já estava setado. 0 espera.

Enfim, mudaria:

- Criar um flag para informar a condição de "atenção para o delay" deixando algumas funções "menos importantes" em espera. A do display por ex. O serumaninho do outro lado não deve perceber nada. 

Se não resolver: Criar uma interrupção de tempo, vide:

http://playground.arduino.cc/Code/Timer

Nunca fiz com arduino, mas seria algo como usar um timer para disparar a função que precisa ser executada ao fim do delay (setar o pino, por ex). E no programa vc dispararia o timer (que ao final executa).

Essa saída é 100% certa.

Concordo com o Eduardo.

Acho que a solução de usar interrupções é a melhor alternativa.

Sim. Quando você define uma interrupção por tempo ela vai interromper o processamento atual e executá-la, voltando depois ao ponto onde parou.

Veja aqui um exemplo desse tipo de interrupção:

http://labdegaragem.com/profiles/blogs/tutorial-executando-fun-es-e...

No entanto, é preciso escolher o timer correto de modo que não atrapalhe certas librarys.

O timer2, por exemplo, é usado pela biblioteca de servos.

Na verdade, a interrupção vale para o programa inteiro, mesmo que você a defina dentro de uma função.

Conforme disse o Eduardo, você pode usar uma variável flag na função de interrupção, de  modo que teste se as atividades principais foram atendidas. Caso contrário não executar a interrupção.

Teodoro, boa tarde!

Acho que dá para fazer assim:

Quando o sincronismo atendeu e não precisar de delay, dispare o comando noInterrupts(), pois assim as interrupções serão desligadas.

Caso contrário, acione a interrupção pelo tempo que achar suficiente.

Na função da interrupção dispare um noInterrupts novamente

Existe um outro tipo de interrupção que é pelos pinos digitais, que talvez possa te atender também.

Esse tipo de interrupção é executada sempre que o nível em uma porta digital assume determinado valor (LOW ou HIGH).

Será que te atenderia?

https://www.arduino.cc/en/Reference/AttachInterrupt

Oi TO,boa tarde.

Como tenho boa experiência em "manusear" rotinas de interrupt, desde a época que consertava main 

frame, e posteriormente com PIC, me surpreenderam algumas informações que o arduino UNO,

só tinha 2 interrupts externos e 0 Mega 8 interrupts externos

Aí resolvi aprofundar mais e localizei mais 3 interrupts externos para o UNO e o MEGA.

São interrupts de "pin change" , e são agrupados em 3 grupos. Um grupo para os ports de 0 a 7, o outro para os de 8 a 15 e o outro para os de 16 a 24, lembrando que os analog ports do UNO também são ports lógicos.

Estou anexando um code para exemplificar o uso deste grupo de interrupt.

Mas existem vários outros interrupt que podem ser usados no arduino, mas são interrupts internos

Tinmers, ADC, I2C, etc.

Neste link encontrará mais informações sobres os interrupts do arduino.

http://courses.cs.washington.edu/courses/csep567/10wi/lectures/Lect...

Rui

Anexos

Uma dica pra deixar o código mais rápido (e ocupando menos memória também):

Não tem diferença entre os valores HIGH e LOW e true e false, são exatamente a mesma coisa.

então vc pode tranquilamente sustituir códigos como:

if ( digitalRead(i_ESINC) == HIGH) {
SINCRO = true;
}
else {
SINCRO = false;
}

por:
SINCRO = digitalRead(i_ESINC);

Isso já diminui o código e deixa ele um pouco mais rápido. Vi que isso acontece em várias linhas do teu código.

Outro exemplo:
// Sincronismo entre fonte A e B
if (SINCRO) { //true
digitalWrite(o_ESINC_OK, HIGH);
} else {
digitalWrite(o_ESINC_OK, LOW);
}

pode ser trocado por:
digitalWrite(o_ESINC_OK, SINCRO);

Vc também pode usar o resultado de expressões lógicas para escrever em pinos digitais.
Por exemplo, em vez de:

if (VB > VB_H) {
digitalWrite(o_VB_H, HIGH);
}
else {
digitalWrite(o_VB_H, LOW);
}

Pode ser:
digitalWrite(o_VB_H, VB>VB_H);


Outra otimização é evitar atribuições desnecessárias como:

VA = analogRead(i_VA);
VA = map(VA, 0, 1023, 0, 292);

Substitua por:

VA = map(analogRead(i_VA), 0, 1023, 0, 292);

E se isso ainda não for o suficiente, use um timer de hardware para as funções mais críticas e deixa as funções mais lentas fora do timer. Na minha wiki tem uma classe que dá acesso ao timer2 do arduino, é muito fácil de usar, veja a descrição aqui: 

https://fperrotti.wikispaces.com/Classe+Timer2

Se gostar, o download pode ser feito aqui:

https://fperrotti.wikispaces.com/Bibliotecas+para+Arduino

Abraços

Eu não "colei código" na área de texto, eu escrevi um texto que usa algumas linhas de código como exemplo. Não acho que isso tenha prejudicado o forum, a intenção foi ajudar.

By the way, já passou da hora de o Lab de Garagem ter uma ferramenta para incluir código nos posts, eu vejo ferramentas assim em praticamente todos os forums que participo, só aqui que não.

Oi FAP,

sou um usuário igual a você. Nem dequer sou mediador do forum.

O que coloquei foi só um opinião minha.

Realmente colar code na área de texto do tópico de forma nenhuma prejudica o forum, e 

 você tem razão, as vezes temos que colar parte de um code no nosso comentário.

O que muitas vezes acontece é que o code ocupa tanto espaço no tópico, que eu até

desisto de dar minha opiniões ou soluções para o problema.

Mas foi uma boa oportunidade para gerar um diálogo sobre o assunto.

Concordo plenamente com você que este site, pelo número a de amigos que já tem,

deveria disponibilizar ferramentas mais eficientes.

Abraços.

Rui

Tente colocar algo visível, por ex 500ms para testar o codigo. Tem que funcionar ao menos com delay...

16ms não é perceptível a olho nú, vai ver ele "acha" que não está dando delay pq ele leu num manual que esse é o tempo de acionamento de algo ou coisa assim. Quando vc desenergiza um contator/relé demora por inercia, por residuo de magnetização (remanencia), etc. O tempo de acionamento é diferente do tempo de desacionamento (feito por mola, contra feito por ação de solenoide).

Enfim, vai ver tá 16ms mas está pouco.

Só um chute...

Ou com um osciloscópio meça o que de fato o microcontrolador está gerando.

Teodoro, boa tarde!

Na entrada "i_ESINC" está ligado um push button?

Curiosidade: Para medir a corrente, você está usando o ACS712.

E para medir a tensão, como você está fazendo?

Perroti, excelentes dicas, essa eu não conhecia do "digitalWrite(o_ESINC_OK, SINCRO); "

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço