Hardware
A ligação do DS18B20 é trivial: terra, alimentação (3.3V) e o sinal de dados (DQ, conectado a P1.1 na Launchpad).
Software
Aqui as coisas ficam mais "interessantes" (leia-se complicadas). O protocolo usado pelo sensor (OneWire) possui alguns tempos críticos da ordem de microsegundos. Para complicar, o MSP430 está rodando a 1MHz, portanto cada ciclo consome 1 microsegundo.
O compilador da IAR possui uma pseudo função __delay_cycles que gera código que consome "com precisão" um certo número de ciclos. Entretanto, operações comuns (como a chamada de rotina) consome vários ciclos (e portanto microsegundos). As primeiras tentativas não deram certo. Uma observação com osciloscópio mostrou grandes divergências. Infelizmente, o meu osciloscópio é um pouco limitado para este tipo de análise. O resultado final foi obtido pelo ajuste empírico dos tempos. Talvez eu tente revisar isto depois usando um Bus Pirate.
Abaixo as rotinas de comunicação com o sensor. O projeto completo pode ser baixado dos arquivos do blog (arquivo MSP_NRF24_2.zip).
#define delayMicroseconds(n) __delay_cycles(n) // 1MHz = 1uS por ciclo // Macros para comunicação com o DS18B20 // Usadas para maior velocidade #define setDQ_LOW() { P1DIR |= DS18B20; P1REN &= ~DS18B20; P1OUT &= ~DS18B20; } #define setDQ_HIGH() { P1DIR &= ~DS18B20; P1REN |= DS18B20; P1OUT |= DS18B20; } // Leitura da temperatura // Retorna temperatura em décimos de grau // Considera que temos apenas um sensor conectado // e ele está com a configuração padrão // Ref: AN162 da Maxim static unsigned leTemperatura(void) { unsigned valor; if (!OW_Reset()) return 0; OW_WriteByte (0xCC); // Skip ROM OW_WriteByte (0x44); // Start conversion delay(8); // aguarda fim da conversao OW_Reset(); OW_WriteByte (0xCC); // Skip ROM OW_WriteByte (0xBE); // Read ScratchPAD valor = OW_ReadByte(); // LSB valor = (OW_ReadByte() << 8) + valor; // MSB OW_Reset(); // Nao queremos o resto valor = (valor * 100) / 16; return (valor+5)/10; } // OneWire reset // Retorna true se tem um sensor conectado static byte OW_Reset(void) { byte resposta; setDQ_LOW(); delayMicroseconds(500); // comanda reset setDQ_HIGH(); delayMicroseconds(70); // aguarda sensor responder resposta = P1IN & DS18B20; // le a resposta delayMicroseconds(500); // aguarda fim da resposta return resposta == 0; } // OneWire Read Byte static byte OW_ReadByte(void) { byte i, resp; for (i = 0; i < 8; i++) { // Pulso de 1uS abre janela para resposta setDQ_LOW(); setDQ_HIGH(); // Dá um tempo para sensor colocar a resposta e a lê delayMicroseconds(8); resp = resp >> 1; if ((P1IN & DS18B20) != 0) { resp = resp | 0x80; } // Aguarda o final da janela delayMicroseconds(50); } return resp; } // OneWire Write Byte static void OW_WriteByte(byte valor) { byte i; for (i = 0; i < 8; i++) { // Low inicia a janela setDQ_LOW(); if (valor & 0x01) { // Volta o nivel alto se for "1" setDQ_HIGH(); // Manter o bit até o final da janela delayMicroseconds(90); } else { // Manter o bit até o final da janela delayMicroseconds(90); // Voltar ao repouso setDQ_HIGH(); } // Passar para o próximo bit valor = valor >> 1; } }
Nenhum comentário:
Postar um comentário