collapse

* Posts Recentes

Amplificador - Rockboard HA 1 In-Ear por almamater
[Ontem às 19:13]


O que é isto ? por KammutierSpule
[26 de Março de 2024, 19:35]


Bateria - Portátil por almamater
[25 de Março de 2024, 22:14]


Emulador NES em ESP32 por dropes
[13 de Março de 2024, 21:19]


Escolher Osciloscópio por jm_araujo
[06 de Fevereiro de 2024, 23:07]


TP4056 - Dúvida por dropes
[31 de Janeiro de 2024, 14:13]


Leitura de dados por Porta Serie por jm_araujo
[22 de Janeiro de 2024, 14:00]


Distancia Cabo por jm_araujo
[08 de Janeiro de 2024, 16:30]


Meu novo robô por josecarlos
[06 de Janeiro de 2024, 16:46]


Laser Engraver - Alguém tem? por almamater
[16 de Dezembro de 2023, 14:23]

Autor Tópico: Delay OneWire Thermo  (Lida 8205 vezes)

0 Membros e 1 Visitante estão a ver este tópico.

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Delay OneWire Thermo
« Responder #15 em: 21 de Junho de 2010, 23:55 »
O teu problema é que o teu display é actualizado consoante o código e não tens nenhuma base de tempo fixa, se meteres um timer a gerar um interrupt para um refrescamento ai de 25-30Hz e a fazeres a actualização dos displays dentro do interrupt gerado pelo timer não interessava se o sensor demora-se 1ms ou 1h a ler.
Avr fanboy

Offline bdesigns

  • Mini Robot
  • *
  • Mensagens: 38
  • Return 1
Re: Delay OneWire Thermo
« Responder #16 em: 22 de Junho de 2010, 00:20 »
Mais uma vez agradeço ajuda, o que é certo é que se o display tive-se buffer podia "esquecer" este problema, mas neste caso, quero tentar dar-lhe a volta..

O que queres dizer com o display ter buffer? qual o sentido?

Os buffers podem ser criados no micro. O CPU é o micro, o resto são periféricos.
@ Asena:
Ok, posso tar a errar, mas vamos considerar a combinação 3x7 segmentos mais o 1xSiPo (74hc164) como display. Ora se tive-se um SiPo por cada um dos 7segmentos, facilmente tinha o tal dito "buffer", desde que o não envia-se mais dados, o mesmo mantinha o valor antigo, até recepção do novo.
Ora como eu (vá por falta de componentes) decidi fazer a selecção por software do display que ia acender com respectivos dados, não tenho maneira de ter algo que aguente o valor durante as pausas que aquela libraria fazia.

O teu problema é que o teu display é actualizado consoante o código e não tens nenhuma base de tempo fixa, se meteres um timer a gerar um interrupt para um refrescamento ai de 25-30Hz e a fazeres a actualização dos displays dentro do interrupt gerado pelo timer não interessava se o sensor demora-se 1ms ou 1h a ler.
@senso, sim tal era uma maneira, mas se não tou enganado não ia a interrupção tornar mais lenta ainda a leitura? certo é que apesar de ser rapido o ciclo de escrita parao display ainda ia consumir o seu tempo  :-\
Ainda eí de ver isso ;)

O teu problema é facilimo de resolver. Só tens que partir o método requestTemperatures(void) em 2, mandar fora a 2ª parte,
...
@Njay, ve-la que passou-me completamente ao lado, estava tão focado em procurar alternativa simples, que nem me apercebi disso (Exames queimam-me o tiko e o teko).
Amanha a noite já experimento isso  8)

Li o artigo, as vezes é falha minha, por vezes inicialmente atamanco tudo e só depois tento reduzir.
Mas percebi o teu ponto, dividr em funções para melhor percepção do ciclo.

Obrigado pela ajuda :D ;)

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Delay OneWire Thermo
« Responder #17 em: 22 de Junho de 2010, 01:54 »
Tu mandas o sensor fazer uma leitura e ficas á espera dela se bem estou a perceber esse código, tambem já é tarde lol, e enquanto esperas a leitura dá-se uma interrupção, fazer esses 3 shifts outs, e enquanto estás a actualizar o ecrã o tempo que a leitura demora a ser feita está a passar, a interrupção acaba, e finalmente os dados chegaram, ficas parado á espera da interrupção ou fazes outra coisa qualquer até se dar nova interrupção e os displays são novamente actualizados, não te vai roubar tempo, só te vai dar é tempo.
Avr fanboy

Offline bdesigns

  • Mini Robot
  • *
  • Mensagens: 38
  • Return 1
Re: Delay OneWire Thermo
« Responder #18 em: 22 de Junho de 2010, 20:36 »
Pois bem já funciona, está quase excelente, um pequeno delay, quase nulo...
Agora que levei a utilização de um só Sipo ao limite (pessoalmente não acho que para a função tenha mais por onde testar, pelo menos para agora, a ideia do senso ainda ha-de ser testada mais tarde), agora vou tentar com 3 ;)

Codigo(agradeço a ajuda de todos)!
Código: [Seleccione]
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 8 //ds18s20
#define data 2 //data 74hc164
#define clock 3 //clock 74hc164
#define set1 4 //7segment 1 l
#define set2 5 //7segment 2 c
#define set3 6 //7segment3  r4z5i

OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature.

// bit por led
byte zero  = B01111110;
byte one   = B00000110;
byte two   = B11011010;
byte three = B11010110;
byte four  = B10100110;
byte five  = B11110100;
byte six   = B11111100;
byte seven = B01000110;
byte eight = B11111110;
byte nine  = B11110110;
byte space = B00000000;
byte h =     B10101110;
byte e =     B11111000;
byte l =     B00111000;
int a=0;
int b= 0;
int c;
byte digit[3];
//char tempo=0;
byte var;
char i;
unsigned int time=2000; //se quisserem alterar o tempo entre medições deve ser >0.75seg
unsigned long pretime=0;
unsigned long currentMillis;

void setup()
{

  sensors.begin();
  pinMode(clock, OUTPUT); //  clock pin  output
  pinMode(data , OUTPUT); // data pin  output3
  pinMode(set1, OUTPUT);
  pinMode(set2, OUTPUT);
  pinMode(set3, OUTPUT);
  sensors.requestTemperatures();
  intro(); //mostra HELLO em scroll para o delay (1seg)
  a=sensors.getTempCByIndex(0); //primeira leitura valida;
 
}

void loop(){
  termo();
  rot(a);
}

void termo(void){
  currentMillis = millis();
  if(b==0){
    sensors.requestTemperatures();
    b=1;
  } /// Send the command to get temperatures //0.75s para obter o valor, esperamos 2s para reduzir o efeito do pequeno atraso aqui presente

  if(b==1){
    if(currentMillis- pretime > time){
      pretime = currentMillis;
      a=sensors.getTempCByIndex(0); //*enquanto não obter bloqueia, daí o uso do millis();
      b=0;
    }
  }
}

void rot (int a){ //subdivide a centena em partes
  c=a;

  digit[2] = c % 10;           
  digit[1] = (c / 10) % 10; 
  digit[0] = (c/ 100) % 10;
  for(byte d=0;d<3;d++){
    if(d==0){
      if(digit[d]==0){
        digit[d]=space;
      }
    }
    else
      digit[d]=caso(digit[d]);
  }
  seg(digit[0],digit[1],digit[2]);
  //delay(1);
}

byte caso(byte test){ //descodifica os números no respectivo byte do display.
  switch (test){
  case 0:
    return zero;
    break;
  case 1:
    return one;
    break;
  case 2:
    return two;
    break;
  case 3:
    return three;
    break;
  case 4:
    return four;
    break;
  case 5:
    return five;
    break;
  case 6:
    return six;
    break;
  case 7:
    return seven;
    break;
  case 8:
    return eight;
    break;
  case 9:
    return nine;
    break;
  }
}
void seg(byte un,byte dos, byte tres){
  digitalWrite(set1,HIGH);
  digitalWrite(set2, LOW); //Primeiro Segmento
  digitalWrite(set3, LOW);
  shiftOut(data, clock, LSBFIRST, un);
  delay(6);
  digitalWrite(set1,LOW);
  digitalWrite(set2, HIGH); //Segundo segmeto
  digitalWrite(set3, LOW);
  shiftOut(data, clock, LSBFIRST, dos);
  delay(6);
  digitalWrite(set1,LOW);
  digitalWrite(set2, LOW); //terceiro segmento
  digitalWrite(set3, HIGH);
  shiftOut(data, clock, LSBFIRST, tres);
  delay(6);
  digitalWrite(set1,LOW);
  digitalWrite(set2, LOW); //se atrasar nenhum acende, e o inverso daria em valores todos iguais dos segmentos
  digitalWrite(set3, LOW);
}

void intro(){ //Mensagem de arranque, só para encher para o o primeiro delay não parecer tão grande.
  delay(100);
  seg(space, space, h);
  delay(100);
  seg(space,h,e);
  delay(100);
  seg(h,e,l);
  delay(100);
  seg(e,l,l);
  delay(100);
  seg(l,l,zero);
  delay(100);
  seg(l,zero,space);
  delay(100);
  seg(zero,space,space);
  delay(100);
  seg(space,space,space);
  delay(100);
}

Em anexo deixo as livrarias OneWire e DallasTemperature (com a parte que eliminei como comentário // ) em .rar, se alguem quisser experimentar.


modificação: alteração em 2 comentários.
« Última modificação: 23 de Junho de 2010, 01:07 por bdesigns »

Offline Sérgio_Sena

  • Administrator
  • Mini Robot
  • *****
  • Mensagens: 1.649
    • Electronic Gear for Musicians
Re: Delay OneWire Thermo
« Responder #19 em: 22 de Junho de 2010, 22:10 »
Põe fotos para o pessoal ver! :)

Offline bdesigns

  • Mini Robot
  • *
  • Mensagens: 38
  • Return 1
Re: Delay OneWire Thermo
« Responder #20 em: 22 de Junho de 2010, 23:49 »
Tenho andado a brincar com o Fritzing, acho demasiado simples, mas tem a propriedade boa de poder fazer um copy paste da breadboard.

Se alguem usar posso colocar aqui o ficheiro  8)



asena, amanha logo tiro fotos, dpx de ajeitar os fiozinhos todos  :-X

IC's (da esquerda para a direita):
DS18S20;
ULN2003A; (deu-me a preguiça  :-X e como ocupa o mesmo que os transistores  ::) )
74HC164;

3x 7segmentos.
Uso de pins: 6 I/O;

Motivação: Reduzir ao mínimo o numero de pins usados no arduino, para implementação de display de segmentos, apesar do desuso, os mesmos são uma forma pratica de indicação numérica. (nota que: da forma normal o uso de pinos seria 7+3+1 = 11 quase o dobro!

Ideias futuras: Utilização de 3x74HC164 e 1*74LS08 (AND Gate) aos terminais do clock, para escolher que 74HC164 é que recebe o sinal do clock (desde que esteja a low constante não muda o estado independentemente da entrada)! aí permitiria-me evitar a pequena falha da actualização da temperatura.
E manteria o numero de pinos! visto que escusava de fazer mux aos displays.

 ::)



Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Delay OneWire Thermo
« Responder #21 em: 23 de Junho de 2010, 00:30 »
Muito bem! E vejo que já usaste uma técnica de obter um periodo constante (a utilização do millis()). Num segundo artigo vou falar disto, mas para manter um periodo constante entre execuções da loop(), uma vez que com o delay(), embora um pouco mais simples, há um erro de tempo que se vai acumulando.

Tens o loop() a correr a toda a velocidade, uma vez que optaste por não usar uma base de tempo fixa (o delay no fim da função). Não é muito relevante para o exemplo, mas isto faz com que o mega consuma mais energia pois o CPU está sempre a bombar. Além disso, como não tens uma base de tempo certa, não podes facilmente adicionar mais "tarefas" para fazer ao mesmo tempo, a não ser estares sempre a recorrer à leitura do millis() o que implica teres mais variáveis de tamanho grande.

Código: [Seleccione]
// bit por led
byte zero  = B01111110;
byte one   = B00000110;
byte two   = B11011010;
byte three = B11010110;
byte four  = B10100110;
byte five  = B11110100;
...
byte caso(byte test){ //descodifica os números no respectivo byte do display.
  switch (test){
  case 0:
    return zero;
    break;
...

Bastava fazer return dos valores directamente (return B01111110; ...). Ou, melhor, implementar com uma tabela (não é preciso mais nada do que esta função):

Código: [Seleccione]
byte caso (byte test)
{
    static const byte sDigitTable[] = {B01111110, B00000110, ...};
    return sDigitTable[test];
}

Tens 2s de espera pelo resultado da conversão e não 0.75s.


Offline bdesigns

  • Mini Robot
  • *
  • Mensagens: 38
  • Return 1
Re: Delay OneWire Thermo
« Responder #22 em: 23 de Junho de 2010, 01:04 »
Tens o loop() a correr a toda a velocidade, uma vez que optaste por não usar uma base de tempo fixa (o delay no fim da função). Não é muito relevante para o exemplo, mas isto faz com que o mega consuma mais energia pois o CPU está sempre a bombar. Além disso, como não tens uma base de tempo certa, não podes facilmente adicionar mais "tarefas" para fazer ao mesmo tempo, a não ser estares sempre a recorrer à leitura do millis() o que implica teres mais variáveis de tamanho grande.
O meu problema é que estou totalmente dependente de um ciclo sempre a bombar para fazer o mux dos displays, ou isso ou passar para interrupções (que ainda tou meio a nora no arduino).

Citar
Bastava fazer return dos valores directamente (return B01111110; ...). Ou, melhor, implementar com uma tabela (não é preciso mais nada do que esta função):

Código: [Seleccione]
byte caso (byte test)
{
    static const byte sDigitTable[] = {B01111110, B00000110, ...};
    return sDigitTable[test];
}

Ora, cá esta uma optimização, coisa que ainda não tenho grande jeito a fazer,assim reduzo a dimensão do codigo e de ciclos de maquina, uma outra questão não posso passar o valor como hex? A pouco pus-me a pensar nisso ;) ex.: 0x7E ?

Citar
Tens 2s de espera pelo resultado da conversão e não 0.75s.

Sim, e não, tenho que esperar 0.75s, no entanto espero 2segundos, para não estar sempre a actualizar o valor, e para tornar menos perceptível a pequena falha, já vou tentar actualizar o comentário ;)

Muitas das coisas, espero conseguir melhorar quando tentar com 3x74HC164, visto que aí já posso implementar uma base tempo fixa, digamos por exemplo 2 segundos (ou +, tenho uma ideia, por exemplo calcular o incremento por unidade de tempo entre a temperatura actual e a ultima leitura. Depois até a próxima leitura incrementaria esse valor por unidade de tempo (uma tentativa de previsão básica de previsão..), isto traria um possível erro entre leituras)
« Última modificação: 23 de Junho de 2010, 01:09 por bdesigns »

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Delay OneWire Thermo
« Responder #23 em: 23 de Junho de 2010, 01:18 »
Sim, podes usar hexadecimal, binário ou até mesmo decimal, para o compilador é tudo o mesmo.
Avr fanboy

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Delay OneWire Thermo
« Responder #24 em: 23 de Junho de 2010, 01:32 »
Tens o loop() a correr a toda a velocidade, uma vez que optaste por não usar uma base de tempo fixa (o delay no fim da função). Não é muito relevante para o exemplo, mas isto faz com que o mega consuma mais energia pois o CPU está sempre a bombar. Além disso, como não tens uma base de tempo certa, não podes facilmente adicionar mais "tarefas" para fazer ao mesmo tempo, a não ser estares sempre a recorrer à leitura do millis() o que implica teres mais variáveis de tamanho grande.
O meu problema é que estou totalmente dependente de um ciclo sempre a bombar para fazer o mux dos displays, ou isso ou passar para interrupções (que ainda tou meio a nora no arduino).

Tu tens 3 delays de 6ms... são quase 288000 instruções do CPU, que estás a gastar exclusivamente a fazer népia (e muitas vezes por segundo). Podes usar uma base de tempo de 6ms, partir aquela função dos 6ms em 3 mais uma variável de estado e assim mover o único "verdadeiro" delay para o final da loop(), podendo assim facilmente adicionar outras tarefas sem afectar a frequência com que os displays são actualizados. Mas em vez do delay() no final da loop(), podes usar um esquema para manter constante o periodo entre chamadas das tarefas, que é como fizeste com os millis para a espera da conversão de temperatura. Ficaria algo do género

Código: [Seleccione]
void loop (void)
{
    static unsigned long wakeupTime = 0;
    static unsigned long now = 0;

    termo();
    rot(a);

    do {
        now = millis();
    } while (now < wakeupTime);
    wakeupTime = now + 6;   // 6 = 6 ms
}

(Isto tem um problemazinho de 50 em 50 dias, que é o overflow do millis(), pode ser resolvido mas para já, para não complicar e como não deves precisar de ter o programa a correr mais de 50 dias, ficamos assim.)

As tarefas podem agora podem ser re-escritas de forma a usar contadores como no meu artigo.
Nenhuma delas deverá demorar perto de ou mais do que 6ms, pois caso contrário o periodo "constante" perde-se, deixa de ser constante. Em desenvolvimento e em caso de dúvida pode-se colocar um teste antes do ciclo do {} while para se saber se alguma execução da loop() excedeu os 6ms, e acender um LED como aviso (if (millis() >= wakeupTime) { digitalWrite(LED, HIGH); }).

Citar
Ora, cá esta uma optimização, coisa que ainda não tenho grande jeito a fazer,assim reduzo a dimensão do codigo e de ciclos de maquina, uma outra questão não posso passar o valor como hex? A pouco pus-me a pensar nisso ;) ex.: 0x7E ?

Não sei se entendi... mas em C, em qualquer lado onde podes usar números, também podes usar a versão nas várias bases suportadas, binário, hex, octal... 0x7E é perfeitamente válido onde quer que seja aceite um número.

Offline bdesigns

  • Mini Robot
  • *
  • Mensagens: 38
  • Return 1
Re: Delay OneWire Thermo
« Responder #25 em: 23 de Junho de 2010, 23:05 »
@Njay:

Ok, deixa-me ver se percebi ;) peguei no meu método para controlar o display, e desmantelei-o em partes; dpx no loop, faço controlo que parte liga a cada momento, menos funções a cada loop.
Será algo deste género o que estavas a falar?
Código: [Seleccione]
void loop(){


  termo();
  rot(a);
 
  switch (i){
    case 0:
      seg0(digit[0]);
      i++;
      break;
    case 1:
      seg1(digit[1]);
      i++;
      break;
    case 2:
      seg2(digit[2]);
      i=0;
      break;
  }
 do {
        currentMillis = millis();
    } while (currentMillis < wakeupTime);
    wakeupTime = currentMillis + 5; //Nota aumento ou diminuição deste valor altera taxa de refresh dos segmentos, ajustar (4-8)
}

Aparentemente ganhei alguns valiosos ms, o que dava para mais umas quantas funções ;) obrigado pela dica  ;D

Exacto estava a falar se seria o mesmo, binario, hex, ou dec para o compilador do arduino.



Não liguem a desarumação de fios  :-X



Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Delay OneWire Thermo
« Responder #26 em: 24 de Junho de 2010, 08:00 »
Nem mais! Parecendo que não, aqueles 3 delays de 6ms estavam a desperdiçar quase de certeza mais de 40% do CPU. Agora recuperaste esses 40%, e ainda tens um controlo exacto sobre a taxa de refrescamento do display, e uma base de tempo fixa que podes usar noutras brincadeiras a adicionar ao que já tens.

Só por uma questão de organização eu colocaria esse switch da loop() numa função à parte.
Também aconselho a usar variáveis declaradas com static, porque isto mantém o código mais organizado e mais fácil de perceber, pois as variáveis ficam declaradas nos blocos onde são usadas e sabemos logo que não estão a ser usadas em mais lado nehum (ao contrário de uma variável global declarada fora das funções, que pode estar a ser usada em qualquer lado e obriga-nos a percorrer o código todo para ver onde é usada).