LusoRobótica - Robótica em Português

Sistemas específicos => Arduino / AVR => Tópico iniciado por: bdesigns em 21 de Junho de 2010, 00:02

Título: Delay OneWire Thermo
Enviado por: bdesigns em 21 de Junho de 2010, 00:02
Boas Noites  ;D
Ando aqui numas brincadeiras utilizando o 74HC164 (serial In, Parallel Out), e 3 displays de 7-segmentos, todos ligados ao mesmo 74HC164  e depois comuto entre eles.
O código está bastante funcional quanto a essa parte, já testei a contar eventos, ou até mesmo a fazer percorrer os números de 0 a 999 e vice versa.
Hoje lembrei-me de brincar com o ds18s20, e adicionar ao projecto já existente, pois bem, o mesmo parece que cria quase um atraso de 1 segundo para obter a temperatura e depois realizar a conversão.
Alguém sabe de alguma maneira de reduzir isso?


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;
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);
}

void loop()
{
  sensors.requestTemperatures(); // Send the command to get temperatures
  a=sensors.getTempCByIndex(0);
  for(i=0;i<100;i++){  //para ver o tempo
    rot(a);
  }
}



void rot (int a){
  c=a;

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

byte caso(byte test){
  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 no que dará, ficara o valor antigo ?
  digitalWrite(set3, LOW);
}


Até ver está assim, ainda ando a testar, mas se alguem souber como reduzir o atraso do ds18s20 força.

Nota: Ainda não optimizei o codigo  ??? deve ter uma ou duas variáveis a mais ;) ou consumo desnecessário de sram, (char vs int).

Dicas são bem vindas :D
Título: Re: Delay OneWire Thermo
Enviado por: FET_Destroyer em 21 de Junho de 2010, 02:42
Boas
O protocolo 1-wire é feito por tempo, não sei as temporizações mas é do género, X us equivale a um comando, Y us equivale a outro, é provável que demore algum tempo para comunicar mas 1 segundo se calhar também é de mais.
Tenta ver o protocolo 1-wire.
Título: Re: Delay OneWire Thermo
Enviado por: Sérgio_Sena em 21 de Junho de 2010, 10:15
Se fores ver as especificações do chip termómetro, vais ver que a linha de dados tem que estar a 1, sem limitação de corrente, durante no mínimo 750ms. Este é o tempo que demora a aquisição e conversão.

Devido a ser um chip de baixo consumo, e q está pendurado numa linha onde só tem duas ligações: dados e massa, é natural que isto assim seja.
Tem a ver com o protocolo criado.

No entanto, depois deste tempo, obter o valor convertido é bastante rápido, é o tempo de envio de ROM e leitura dos dois bytes.

Título: Re: Delay OneWire Thermo
Enviado por: bdesigns em 21 de Junho de 2010, 16:42
Sim, eu percebo que existe esse atraso, afinal está lá mesmo expecificado na pagina inicial do pdf,
O problema é mais de hardware do que outra coisa, é que eu estou somente a utilizar um IC SiPo para 3 displays de 7 segmentos, ora quando para de percorrer a escolha de cada um deles, fica nenhum acesso, ou a ficarem todas ficam todos com o mesmo digito (ex:026->666);

A minha questão é se alguem tem algum truqe para manter a saida a correr a função seg(...)...
Por basicamente é isso que me tá a limitar agora a implementação ???
será que um do{....}while("qualquer coisa"); funcionaria..(a ideia era não parar o ciclo).

alguem tem ideias?

Senão tenho de me virar para sensores analogicos e a probabilidade de ruido.
Título: Re: Delay OneWire Thermo
Enviado por: FET_Destroyer em 21 de Junho de 2010, 16:53
Não estou a ver as duas coisas a funcionar ao mesmo tempo. Segundo o que está no datasheet o tempo máximo de conversão é de 750ms, mas são 750ms em que o processador fica preso nessa função de receber dados. Em arduino não sei se existem interrupções mas penso que não. Logo se ele fica preso nessa função a função de correr os 7segmentos não está activa logo vão lá aparecer coisas esquisitas ou nem sequer aparecer nada. Ele mostra-se sempre o mesmo digito, pois como fica preso na função de 1-wire não te vai fazer o varrimento dos leds. tenta por a ler o ds1820 de 2s em 2s, assim so te acontece isso de 2s em 2s.
Título: Re: Delay OneWire Thermo
Enviado por: Sérgio_Sena em 21 de Junho de 2010, 17:08
Estão confusos vocês, e por má interpretação do datasheet.

Os 750ms são necessários para que o chip consiga fazer aquisição/conversão. APENAS isto. O micro não tem que prestar atenção ao que o chip faz. A única coisa que tem que fazer, é esperar o tempo mínimo. Até pode esperar 5seg... é indiferente.

E claro, depois do micro comunicar a ordem ao chip, põem o pino 1Wire a 1, e vão à vida.
Não vão ficar presos enqt o chip converte.
Afinal... ambos trabalham sózinhos, ou não? :)


Podem usar um temporizador por hardware, que gera uma interrupção, para vos dizer que acabou o tempo mínimo necessário.
Findo esse tempo, chamam a função de leitura do chip, e já está.

Se contarem o tempo que o micro está preso por causa do chip, é muito muito pouco. A comunicação é rápida mesmo assim. É um chip muito simples e fiavel. Aguenta-se bem em barramento com muitos juntos.
Título: Re: Delay OneWire Thermo
Enviado por: bdesigns em 21 de Junho de 2010, 19:18
Já percebi ;) Obrigado asena  ;D
a questão é que mesmo trabalhando com o millis(); fico com um pausa quase imperceptivel e outra grande.
Código: [Seleccione]
unsigned long currentMillis = millis();
  if(b==0){ 
    sensors.requestTemperatures();
    b=1;
    } /// Send the command to get temperatures //0.75s para obter
  }
 if(b==1){
   if(currentMillis- pretime > time){
    pretime = currentMillis;
    a=sensors.getTempCByIndex(0); //*enquanto não obter bloqueia.
    b=0;
  }
****
 
Inicialmente :
time=1000;
pretime=0;
b=0;
Acho que 1 segundo entre o pedido e a leitura chega?

mas mesmo assim :S pisca


...Tive a fazer um pouco de debug utilizando o led para me dizer que acção estava a demorar +, é o sensors.requestTemperatures();  hmm então a minha linha de pensamento não esta correcta.
Título: Re: Delay OneWire Thermo
Enviado por: Sérgio_Sena em 21 de Junho de 2010, 19:46
1seg é mais que sificiente.

Não esquecer de deixar o pino 1-wire no estado lógico 1, para fornecer a corrente necessária ao sensor.
Título: Re: Delay OneWire Thermo
Enviado por: FET_Destroyer em 21 de Junho de 2010, 20:35
Pois. Eu não conheço o protocolo 1-wire, tenho só uma ideia de como funciona e pela minha rapida passagem pelo datasshet pensei que ele demorasse 750ms a fazer a aquisição depois de ser mandado o pedido de dados, mas pelos vistos não.
Título: Re: Delay OneWire Thermo
Enviado por: Sérgio_Sena em 21 de Junho de 2010, 21:07
Sim, tens razão, demora minimo de 750ms na aquisição/conversão.
Título: Re: Delay OneWire Thermo
Enviado por: FET_Destroyer em 21 de Junho de 2010, 21:12
Sim, mas não da maneira que eu estava a pensar. Pensei que depois de ele ter recebido o pedido de dados, é que ia converter.
Título: Re: Delay OneWire Thermo
Enviado por: Sérgio_Sena em 21 de Junho de 2010, 21:25
Envias ::

# ROM
# ordem de conversão
-espera
# ROM
# pedido de dados

Isto porque podes emitir um broadcast, e todos os sensores fazem a aquisição ao mesmo tempo.
Depois do tempo passado, vais um-a-um pedir a informação.

Título: Re: Delay OneWire Thermo
Enviado por: bdesigns em 21 de Junho de 2010, 23:22
Ok, após andar aqui nas voltas (troquei para modo normal para ver se acelarava um pouco o processo), continuo com o mesmo problema.

Guardei o registo do endereço para obter só dados apartir deste, o problema persiste.
O problema situa-se no sensors.requestTemperatures(); por maior que aumente o tempo até este correr o tempo persiste.

Tive analizar a libraria  Dallas Temperature...
e aqui se encontra o porque do atraso, o codigo base que estava a utilizar (que obti no arduino playground)

Código: [Seleccione]
void DallasTemperature::requestTemperatures(void)
{
  _wire->reset();
  _wire->skip();
  _wire->write(STARTCONVO, parasite);

  switch (conversionDelay)
  {
    case TEMP_9_BIT:
      delay(94);
      break;
    case TEMP_10_BIT:
      delay(188);
      break;
    case TEMP_11_BIT:
      delay(375);
      break;
    case TEMP_12_BIT:
    default:
      delay(750);
      break;
  }
}

Então estou a tentar de outra maneira, mas sinceramente sinto-me perdi-do, como aínda não percebo muito bem os protocolos e a formato de comunicação do one wire, encontrei um codigo semelhante para teste do sensor, que me da todos os dados do sensor, agora o meu problema é obter e processar a temperatura :S
Código: [Seleccione]
{
  if(b==0){ 
    ds.reset();
    ds.select(addr);
    ds.write(0x44,1);         // start conversion, with parasite power on at the end
    b=1;
    } /// Send the command to get temperatures //0.75s para obter
 
 if(b==1){
   if(currentMillis- pretime > time){
    pretime = currentMillis;
    present = ds.reset();
    ds.select(addr);   
    ds.write(0xBE);         // Read Scratchpad

    for ( i = 0; i < 9; i++){ // we need 9 bytes
      data[i] = ds.read();
    }
   
//
// Parte da conversão que falta
//
  a=...; //a temperatura
   }
 }
   b=0;
   rot(a);
}

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..


Mais uma vez agradeço ajuda ;)
Título: Re: Delay OneWire Thermo
Enviado por: Sérgio_Sena em 21 de Junho de 2010, 23:44
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.
Título: Re: Delay OneWire Thermo
Enviado por: Njay em 21 de Junho de 2010, 23:53
O teu problema é facilimo de resolver. Só tens que partir o método requestTemperatures(void) em 2, mandar fora a 2ª parte,

Código: [Seleccione]
void DallasTemperature::requestTemperatures(void)
{
  _wire->reset();
  _wire->skip();
  _wire->write(STARTCONVO, parasite);
}

e ficares responsável por garantir que, depois de invocar este método, aguentas pelo menos o tempo necessário (ver o switch do método original) para a conversão terminar. Durante este tempo podes mostrar números no display, fazer contas, contar carneiros, o que quer que seja.

Aconselho-te ler com atenção este artigo aqui (http://troniquices.wordpress.com/2010/05/24/arduino-a-fazer-varias-coisas-ao-mesmo-tempo/) e começares a pensar e a estruturar os teus programas desta forma. Não é preciso ir mexer em interrupções.
Título: Re: Delay OneWire Thermo
Enviado por: senso 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.
Título: Re: Delay OneWire Thermo
Enviado por: bdesigns 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 ;)
Título: Re: Delay OneWire Thermo
Enviado por: senso 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.
Título: Re: Delay OneWire Thermo
Enviado por: bdesigns 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.
Título: Re: Delay OneWire Thermo
Enviado por: Sérgio_Sena em 22 de Junho de 2010, 22:10
Põe fotos para o pessoal ver! :)
Título: Re: Delay OneWire Thermo
Enviado por: bdesigns 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)

(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fi77.photobucket.com%2Falbums%2Fj64%2Fcumps%2FElectronics%2F1SiPo_bb.png&hash=a37dd2eff3f7b522a7fd9c74e28a826574fb05e0)

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.

 ::)


Título: Re: Delay OneWire Thermo
Enviado por: Njay 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.

Título: Re: Delay OneWire Thermo
Enviado por: bdesigns 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)
Título: Re: Delay OneWire Thermo
Enviado por: senso em 23 de Junho de 2010, 01:18
Sim, podes usar hexadecimal, binário ou até mesmo decimal, para o compilador é tudo o mesmo.
Título: Re: Delay OneWire Thermo
Enviado por: Njay 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.
Título: Re: Delay OneWire Thermo
Enviado por: bdesigns 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.

(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fi77.photobucket.com%2Falbums%2Fj64%2Fcumps%2FElectronics%2FDSCF9778.jpg&hash=67fc9457586aa8f75a7fafa4497d3a0d89c82fad)

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

(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fi77.photobucket.com%2Falbums%2Fj64%2Fcumps%2FElectronics%2FDSCF9779.jpg&hash=fbc8277b9b3d4408dd7d0807290cb54f6c3a38db)
Título: Re: Delay OneWire Thermo
Enviado por: Njay 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).