quinta-feira, novembro 05, 2015

Usando o nRF24L01+ com o MSP430: Um Sensor a Bateria - Parte 2

Continuando a nossa prova de conceito, vamos acrescentar o sensor de temperatura.



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).
  1. #define delayMicroseconds(n)  __delay_cycles(n)   // 1MHz = 1uS por ciclo  
  2.   
  3. // Macros para comunicação com o DS18B20  
  4. // Usadas para maior velocidade  
  5. #define setDQ_LOW()  { P1DIR |= DS18B20; P1REN &= ~DS18B20; P1OUT &= ~DS18B20; }  
  6. #define setDQ_HIGH() { P1DIR &= ~DS18B20; P1REN |= DS18B20; P1OUT |= DS18B20;  }  
  7.   
  8. // Leitura da temperatura  
  9. // Retorna temperatura em décimos de grau  
  10. // Considera que temos apenas um sensor conectado  
  11. // e ele está com a configuração padrão  
  12. // Ref: AN162 da Maxim  
  13. static unsigned leTemperatura(void)  
  14. {  
  15.   unsigned valor;  
  16.     
  17.   if (!OW_Reset())  
  18.     return 0;  
  19.   OW_WriteByte (0xCC);  // Skip ROM  
  20.   OW_WriteByte (0x44);  // Start conversion  
  21.   delay(8);             // aguarda fim da conversao  
  22.     
  23.   OW_Reset();  
  24.   OW_WriteByte (0xCC);  // Skip ROM  
  25.   OW_WriteByte (0xBE);  // Read ScratchPAD  
  26.   valor = OW_ReadByte();                 // LSB  
  27.   valor = (OW_ReadByte() << 8) + valor;  // MSB  
  28.   OW_Reset();           // Nao queremos o resto  
  29.   
  30.   valor = (valor * 100) / 16;  
  31.   return (valor+5)/10;  
  32. }  
  33.   
  34. // OneWire reset  
  35. // Retorna true se tem um sensor conectado  
  36. static byte OW_Reset(void)  
  37. {  
  38.   byte resposta;  
  39.     
  40.   setDQ_LOW();  
  41.   delayMicroseconds(500);  // comanda reset  
  42.   setDQ_HIGH();  
  43.   delayMicroseconds(70);      // aguarda sensor responder  
  44.   resposta = P1IN & DS18B20;  // le a resposta  
  45.   delayMicroseconds(500);     // aguarda fim da resposta  
  46.   return resposta == 0;  
  47. }  
  48.   
  49. // OneWire Read Byte  
  50. static byte OW_ReadByte(void)  
  51. {  
  52.   byte i, resp;  
  53.   for (i = 0; i < 8; i++)  
  54.   {  
  55.     // Pulso de 1uS abre janela para resposta  
  56.     setDQ_LOW();  
  57.     setDQ_HIGH();  
  58.     // Dá um tempo para sensor colocar a resposta e a lê  
  59.     delayMicroseconds(8);  
  60.     resp = resp >> 1;  
  61.     if ((P1IN & DS18B20) != 0)  
  62.     {  
  63.       resp = resp | 0x80;  
  64.     }  
  65.     // Aguarda o final da janela  
  66.     delayMicroseconds(50);  
  67.   }  
  68.     
  69.   return resp;  
  70. }  
  71.   
  72. // OneWire Write Byte  
  73. static void OW_WriteByte(byte valor)  
  74. {  
  75.   byte i;  
  76.   for (i = 0; i < 8; i++)  
  77.   {  
  78.     // Low inicia a janela  
  79.     setDQ_LOW();  
  80.     if (valor & 0x01)  
  81.     {  
  82.       // Volta o nivel alto se for "1"  
  83.       setDQ_HIGH();  
  84.       // Manter o bit até o final da janela  
  85.       delayMicroseconds(90);  
  86.     }  
  87.     else  
  88.     {  
  89.       // Manter o bit até o final da janela  
  90.       delayMicroseconds(90);  
  91.       // Voltar ao repouso  
  92.       setDQ_HIGH();  
  93.     }  
  94.     // Passar para o próximo bit  
  95.     valor = valor >> 1;  
  96.   }  
  97. }  

Nenhum comentário: