Protocolo 1-Wire para Displays.

Software e Hardware para uC PIC

Moderadores: andre_luis, 51, guest2003, Renie

Protocolo 1-Wire para Displays.

Mensagempor Pask » 27 Jan 2007 13:50

Olá gente. No livro PIC - PROGRAMAÇÃO EM C do Fábio Pereira (para quem tiver), nas páginas 289 e 290, nosso amigo Fábio, apresenta um código fonte para programar o PIC para leitura de temperatura a partir de um sensor DS18S20 Dallas através de comunicação serial 1-wire e posterior envio desses dados para a uma porta serial de um PC.
Nas últimas linhas desse programa, na pág.290, o autor, evidentemente, apresenta os comandos para acessar a memória de rascunho do DS18S20 e obter a leitura da temperatura do mesmo. Em seguida, ele apresenta uma seqüência de instruções relativas ao comando "printf" para enviar os dados obtidos do sensor à porta serial.
O que eu gostaria é o seguinte: quais modificações eu teria que fazer no código em questão para, ao invés de transmitir o resultado via serial, acionar 2 displays de leds e apresentar somente a temperatura medida diretamente neles? Ou seja, eu não quero enviar serialmente a leitura do sensor. O que eu quero é ler o sensor e indicar a temperatura lida em 2 displays de leds comuns, como se fosse um termômetro digital.
Observem que ele utiliza uma variável ou matriz chamada "buffer [9]" na qual ele armazena os dados provenientes do sensor.
Alguém poderia me dar uma luz neste caso? Obrigado

Pask.
Pask
Word
 
Mensagens: 600
Registrado em: 22 Dez 2006 19:19

Mensagempor MOR_AL » 27 Jan 2007 22:03

Olá Pask

Sei que você não curte muito o assembler, mas aí vai. Acho que é assim:

1 – Vou considerar que as variáveis buffer0 e buffer1 são registros do PIC. Faça as correções necessárias. buffer[0] em C no livro será buffer0 em assembler e buffer[1] em C no livro será buffer1 em assembler.
buffer[0] contém o valor numérico da temperatura multiplicado por 2.
buffer[1] contém o valor do sinal da temperatura. Se buffer[1] = 00000000, a temperatura é positiva. Se buffer[1] = 11111111, a temperatura é negativa.

2 – Vou apresentar o código em assembler.

BCF STATUS,C ; Limpa o bit de “carry”.
RRF buffer0 ; Divide o valor da temperatura por dois. Agora o valor numérico é o valor da temperatura.
BTFSC buffer1 ; Pula se o sinal da temperatura for positivo.
CALL TempNegativa ; Esta sub-rotina coloca o sinal negativo no display.
Aqui deve ser colocado o valor de buffer0 no display.

Exemplo:
Se buffer0 = 0011 0010 (2 + 16 + 32 = 50) e se buffer1 = 0000 0000 (sinal positivo).

RRF buffer0 vai dar buffer0 = 0001 1001 (1 + 8 + 16 = 25)
buffer1 = 0000 0000, vai dar + 25 graus Celsius.

MOR_AL
Avatar do usuário
MOR_AL
Dword
 
Mensagens: 2934
Registrado em: 19 Out 2006 09:38
Localização: Mangaratiba - RJ

Mensagempor Pask » 28 Jan 2007 09:12

Caro MOR_AL, quem disse para você que eu não gosto muito do assembly??? Na verdade, sou fã incondicional desta linguagem e é, justamente, aquela que eu mais conheço e com a qual eu melhor consigo programar! Já sei. Foi porque eu disse que o assembly é a linguagem dos "masoquistas" ?! Mas vou explicar: quando eu disse que o assembly é para quem gosta de sofrer eu estava me referindo a certos detalhes da linguagem. Por exemplo: Na Linguagem C "padrão ANSI-CCS", se eu quiser um atraso de tempo qualquer, eu escrevo "delay_ms(xxx)" e o compilador se encarrega de gerar o código necessário para este atraso de tempo sem nenhum esforço do programador, ok! Em Assembly, para fazer a mesma coisa, eu preciso escrever uma sub-rotina envolvendo algumas linhas de comandos com o timer0 ou outro timer qualquer, decrementar variáveis auxiliares, etc para chegar ao atraso de tempo desejado, ou mesmo usar a interrupção de timer, ou seja, o programador precisa desenvolver todo o código necessário de forma braçal, pois o montador MPASM não faz isto automaticamente! Outro exemplo: em C, quando eu escrevo "input_pin(rb0)", o compilador já direciona este pino do PIC como entrada e altera o TRISB automaticamente sem esforço do programador; em Assembly, para direcionar este pino como entrada, eu tenho que acessar o banco da RAM correto, enviar o byte correto para o work e dele para o TRISB para que o MPASM entenda que o pino RB0 deve ser uma entrada.
Portanto, em Assembly caro MOR_AL, tudo depende muito do esforço do programador e isto é "ótimo" !!! Graças a essa característica mais trabalhosa do assembly, o programador aprende muito mais sobre as "entranhas" do PIC, coisa que já não acontece em C que é uma linguagem mais dinâmica e direta! Eu também aprecio muito a linguagem C, só não a conheço o suficiente para desenvolver programas mais complexos.
Agora, eu quero que você veja, abaixo, um código que eu criei para separar um número binário em código BCD, ou seja, por exemplo, o número "0000 1010" binário que é o número 10 decimal, é separado em unidades e dezenas, ou seja, unidade 1 e dezena 0. E este código pode fazer a mesma coisa com qualquer número binário entre 0 e 99. Se vc quiser ampliá-lo para converter de 0 a 999 também pode e a modificação é simples. O que eu gostaria, é de algo semelhante para o programa do Fábio Pereira, porém, mantendo na linguagem C mesmo, ok. Aguardo seu retorno e lhe desejo um domingo com muita "macarronada" !
-------------------------------------------------------------------------------------
int aux=10;
int unidade;
int dezena;
//-----------------------------------------------------------------------------------
int tabela[]= {0b10111111, // 0
0b10000110, // 1
0b11011011, // 2
0b11001111, // 3
0b11100110, // 4
0b11101101, // 5
0b11111101, // 6
0b10000111, // 7
0b11111111, // 8
0b11100111}; // 9

void ajuste_dec(){ //função para o ajuste decimal
unidade=0;
dezena=0;
while (aux>0){
unidade++;
if(unidade==10){
unidade=0;
dezena++; }
aux--;
}
}

main(){ output_a(0);
output_b(0);
cmcon=7;
option=128;
while (true){
ajuste_dec();
output_low(pin_a0);
output_high(pin_a1);
output_b(tabela[unidade]);
output_low(pin_a1); output_high(pin_a0);
output_b(tabela[dezena]);
}
}
//-------------------------------------------------------------------------
Pask
Word
 
Mensagens: 600
Registrado em: 22 Dez 2006 19:19

Mensagempor MOR_AL » 28 Jan 2007 09:29

Olá Pask.

Estou no mesmo barco que você. Adoro assembler e estou aumentando os meus conhecimentos em C.

Do pouco que entendo de C, notei que você incrementa a variável unidade até chegar a 10, para aí então acrescentar um na variável dezena, não é isso? Porque você não faz o contrário.
Decremente de 10 sua variável que contém o valor em binário e acrescente uma unidade na variável dezena. Faça isso enquanto sua variável der um resultado positivo. Aí você passa este resultado para a variável unidade. Assim você evita muitos loops desnecessários.

Caso eu não tenha entendido seu programa, desconsidere o que eu escervi, ok?

Abaixo segue o exposto sobre conversão binário para bcd.

- Exemplo de número binário contido em um byte (Result = 182).

1 – Este 182 encontra-se no registro Result. Agora vou fazer a conversão binário-BCD.

2 – Retiro quantas centenas puder de Result sem torná-lo negativo. Guardo o número de centenas retiradas no registro Cen, no caso Cen = 1.

3 – Retiro quantas dezenas puder de Result sem torná-lo negativo. Guardo o número de dezenas retiradas no registro Dez, no caso Dez = 8.

4 – Transfiro o que restou no registro Result para o registro Unid, no caso Unid = 2.

5 – Faço a conversão BCD para 7 segmentos e envio aos mostradores das centenas, dezenas e unidades.

Espero ter ajudado.

MOR_AL
Avatar do usuário
MOR_AL
Dword
 
Mensagens: 2934
Registrado em: 19 Out 2006 09:38
Localização: Mangaratiba - RJ

Mensagempor Pask » 28 Jan 2007 09:50

Caro MOR_AL, vc entendeu bem o meu código. Na verdade, do jeito que eu escrevi ele funcionou bem, mas posso experimentar fazer o que vc sugeriu também.
Fico aqui aguardando o seu código para o meu "termômetro digital" em C.
Mais um comentário: observei uma coisa interessante no CI DS18S20, o valor da temperatura que ele fornece precisa ser dividido por 2 para dar o valor correto, não é mesmo? Também não entendi muito bem a TABELA 12.8 da pág.287. Note que esta tabela também consta no datasheet do fabricante. Na segunda linha, menciona-se a parte LSB da temperatura e na terceira linha a parte MSB. O que significam cada um dos "S" na terceira linha da tabela?

Pask.
Pask
Word
 
Mensagens: 600
Registrado em: 22 Dez 2006 19:19

Mensagempor MOR_AL » 28 Jan 2007 11:54

Olá Pask.

Vou te ajudar no que eu posso.

1 - Não possuo o código em C.

2 - O byte LSB possui o formato que inclui um bit para o décimo de grau.
O bit zero possui o peso 2 elevado à potência de -1, ou seja 1/2 = 0,5. Na realidade o valor da temperatura pode ter um ,0 ou ,5 graus.
Como o peso 2 elevado à potência zero (valores 0 e 1) se encontra no bit 1, para ter o valor inteiro em graus será necessário dividir o byte por dois. Isso é conseguido fazendo-se uma rotação à direita do byte, perdendo-se o valor à direita da vírgula (0,0 ou 0,5). Essa rotação tem que ser feita com o bit de carry em zero, caso contrário, após a rotação o bit de carry em 1 acrescenta 127 unidades no byte. Daí a instrução BCF STATUS,C antes de RRF buffer0.

3 - Como lhe apresentei antes, no MSB você encontra o valor do sinal da temperatura. S deve ser "signal" (sinal em inglês).

Se você obtiver as variáveis buffer0 e buffer1, em registros no PIC, siga as minhas instruções que você chega lá.

MOR_AL

PS.: Para o pessoal que domina o C do CCS; transformem estas poucas instruções em assembler para o C pro nosso amigo.
Avatar do usuário
MOR_AL
Dword
 
Mensagens: 2934
Registrado em: 19 Out 2006 09:38
Localização: Mangaratiba - RJ

Mensagempor Pask » 05 Fev 2007 09:45

Caros amigos, consegui fazer o termômetro digital funcionar com os displays de leds. No entanto, só está sendo possível a medição de valores positivos de temperatura. Gostaria de saber como seria possível ajustar o programa para obter as leituras negativas também (abaixo de 0°C) com o DS1820. Estou usando 3 displays: o primeiro, da esquerda é para gerar o sinal (-), o do meio é o das dezenas e o último é o das unidades. Alguém poderia me ajudar com a leitura de valores negativos? Obrigado.

Pask.
Pask
Word
 
Mensagens: 600
Registrado em: 22 Dez 2006 19:19

Mensagempor Fábio Pereira » 05 Fev 2007 11:58

Olá Pask,

Bom, vou tentar elucidar algumas das suas dúvidas:

1- O valor lido não necessita necessariamente ser dividido por dois. O que acontece é que, se você observar a tabela 12.8 verá que o bit 0 do LSB da temperatura vale 2 elevado a -1, ou seja, tem peso 0,5. Dividindo por dois você está simplesmente desprezando a resolução de 0,5 graus do sensor;

2- O S na mesma tabela refere-se, adivinhe ??? Ao sinal :wink: hehehe, apesar de isso não estar explicitamente declarado no texto, pode ser deduzido no parágrafo logo abaixo: "... a temperatura mínima (-55 graus) será lida como 0xFF92."

Até +
Fábio Pereira
embeddedsystems.io
Avatar do usuário
Fábio Pereira
Word
 
Mensagens: 674
Registrado em: 16 Out 2006 09:07
Localização: Kitchener, ON

Mensagempor Pask » 05 Fev 2007 14:48

Caro Fábio Pereira, foi muito bom vc ter se comunicado. O seu livro é muito bom. Em relação à leitura do DS1820, eu já consigo visualizar nos displays de leds o valor positivo da temperatura medida até 0°C. Agora, dê uma olhada no fragmento de rotina abaixo. Nele, eu testo o "buffer[1]" da matriz que armazena o MSB, ou seja, o buffer que armazena os 8 bits "SSSSSSSS". Se eu entendi bem, quando o byte MSB estiver 0000 0000 o valor medido é positivo. Quando o MSB estiver igual a 1111 1111, o valor medido é negativo (veja o datasheet do DS1820). Então, no fragmento de programa abaixo, eu testo o "buffer[1]" da matriz e se for 0 desvio para uma rotina de valores positivos, se for 0xFF desvio para uma rotina de valores negativos. Veja abaixo e me diga se está correto. O que acontece, é que não está funcionando para valores negativos!

ENTÃO, PARA VALORES QUE SEJAM NEGATIVOS:
if(buffer[1]==1){
buffer[0] = ~buffer[0];
temp = (buffer[0]+1)/2; //comp. de 2 do LSB e divisão por 2
i=0; //variável para looping posterior
ajuste_dec(); //faz o ajuste decimal (unidades e dezenas)
-----------------------------------------------------------------------------------
PARA VALORES QUE SEJAM POSITIVOS:

if(buffer[1]==0){
temp = buffer[0]/2; //divide byte LSB por 2
temp = temp-0.25+((buffer[7]-buffer[6])/buffer[7]);
i=0;
ajuste_dec();
----------------------------------------------------------------------------------
Se estiver incorreto, me diga então como fazer o teste para a indicação de valores negativos. Obrigado

Pask.
Pask
Word
 
Mensagens: 600
Registrado em: 22 Dez 2006 19:19

Mensagempor Pask » 06 Fev 2007 11:52

:D Eu gostaria de agradecer a todos que se prontificaram em ajudar-me com a questão da comunicação serial 1-wire para o DS1820 e dizer-lhes, aliviado, que consegui desenvolver o termômetro com os displays e agora ele está funcionando perfeitamente bem. Muito obrigado

Pask.
Pask
Word
 
Mensagens: 600
Registrado em: 22 Dez 2006 19:19


Voltar para PIC

Quem está online

Usuários navegando neste fórum: Bing [Bot] e 1 visitante

x