quarta-feira, janeiro 16, 2019

Sensor de Temperatura (e Umidade) HDC1080 (ou compatível)

Tantos sensores e tão pouco tempo... Acho que este vai ser o último sensor de temperatura que vou examinar por algum tempo. Eu comprei a plaquinha na China, mas tem também em lojas brasileiras e no Mercado Livre. O verso da placa lista nada menos que cinco possíveis componentes, que imagino serem compatíveis. Usei como base para este post o datasheet do HDC1080, que você pode baixar do site da Texas Instruments.



O HDC1080 é um sensor de umidade e temperatura bastante preciso (precisão de 0,2C na temperatura) com interface I2C (com endereço fixo, portanto não dá para ter mais de um sensor no mesmo barramento I2C). Embora o datasheet fale que pode operar a 5V, a placa indica 3.3V.

O primeiro teste foi ligando ao Arduino. Por simplificação, liguei direto SCL e SDA (veja aqui como ligar da forma correta). Bem, a própria Texas faz isso....

As ligações ficam assim:
    HDC1080  Arduino UNO
    GND      GND
    3.3V     3.3V
    SDA      SDA (A4)
    SCL      SCL (A5)


O código abaixo se limita a fazer o dump de alguns registradores, disparar uma leitura de temperatura e umidade, aguardar a sua execução e ler o resultado bruto:
  1. //  
  2. // Teste do sensor de temperatura e humidade HDC1080  
  3. //  
  4.   
  5. #include <Wire.h>  
  6.   
  7. // Endereço I2C do sensor  
  8. #define SENSOR_ADDR  0x40  
  9.   
  10. // Registradores do sensor  
  11. #define HDC1080_TEMP  0x00  
  12. #define HDC1080_UMID  0x01  
  13. #define HDC1080_CONF  0x02  
  14. #define HDC1080_ID0   0xFB  
  15. #define HDC1080_ID1   0xFC  
  16. #define HDC1080_ID2   0xFD  
  17. #define HDC1080_MFG   0xFE  
  18. #define HDC1080_DEV   0xFF  
  19.   
  20. // Rotinas locais  
  21. static void read_tempumid(uint16_t *pTemp, uint16_t *pUmid);  
  22. static uint16_t read_reg(uint8_t reg);  
  23. static void write_reg(uint8_t reg, uint16_t val);  
  24.   
  25. // Iniciação  
  26. void setup() {  
  27.   Serial.begin (9600);  
  28.   Wire.begin();  
  29.   
  30.   // Espera terminar o reset  
  31.   while (read_reg(HDC1080_CONF) & 0x8000) {  
  32.     delay (100);  
  33.   }  
  34.   
  35.   // Mostra informações do chip  
  36.   Serial.print("Fabricante: ");  
  37.   Serial.println(read_reg(HDC1080_MFG), HEX);  
  38.   Serial.print("    Modelo: ");  
  39.   Serial.println(read_reg(HDC1080_DEV), HEX);  
  40.   
  41.   // Garante a configuração desejada  
  42.   write_reg(HDC1080_CONF, 0x1000);  
  43. }  
  44.   
  45. // Laco principal  
  46. void loop() {  
  47.   uint16_t temp, umid;  
  48.   
  49.   // Faz a leitura  
  50.   read_tempumid (&temp, &umid);  
  51.     
  52.   // Mostra resultado bruto  
  53.   Serial.println();  
  54.   Serial.println(temp);  
  55.   Serial.println(umid);  
  56.   
  57.   // Dá um tempo  
  58.   delay(10000);  
  59. }  
  60.   
  61. // Dispara uma leitura de temperatura e umidade e  
  62. // pega o resultado.  
  63. static void read_tempumid(uint16_t *pTemp, uint16_t *pUmid) {  
  64.     
  65.   // Esta escrita dispara a leitura  
  66.   Wire.beginTransmission(SENSOR_ADDR);  
  67.   Wire.write (HDC1080_TEMP);  
  68.   Wire.endTransmission();  
  69.   
  70.   // Aguarda fazer a leitura  
  71.   delay(50);  
  72.   
  73.   // Lê o resultado  
  74.   if (Wire.requestFrom(SENSOR_ADDR, 4) == 4) {  
  75.     *pTemp = Wire.read() << 8;  
  76.     *pTemp |= Wire.read();  
  77.     *pUmid = Wire.read() << 8;  
  78.     *pUmid |= Wire.read();  
  79.   } else {  
  80.     // algo deu errado  
  81.     *pTemp = *pUmid = 0;  
  82.   }  
  83. }  
  84.   
  85. // Lê um registrador  
  86. // Não usar para ler temperatura e umidade!  
  87. static uint16_t read_reg(uint8_t reg) {  
  88.   uint16_t val;  
  89.     
  90.   Wire.beginTransmission(SENSOR_ADDR);  
  91.   Wire.write (reg);  
  92.   Wire.endTransmission();  
  93.   
  94.   if (Wire.requestFrom(SENSOR_ADDR, 2) == 2) {  
  95.     val = Wire.read() << 8;  
  96.     val |= Wire.read();  
  97.   } else {  
  98.     val = 0;  // algo deu errado  
  99.   }  
  100.   return val;  
  101. }  
  102.   
  103. // Escreve em um registrador  
  104. static void write_reg(uint8_t reg, uint16_t val) {  
  105.   Wire.beginTransmission(SENSOR_ADDR);  
  106.   Wire.write (reg);  
  107.   Wire.write (val >> 8);  
  108.   Wire.write (val & 0xFF);  
  109.   Wire.endTransmission();  
  110.     
  111. }  
Algumas observações:
  • Os registradores do HDC1080 são de 16 bits, com o byte mais significativo sendo transferido primeiro.
  • Os valores lidos dos registradores de fabricante e modelo correspondem ao HDC1080
  • Estou usando o modo onde são feitas as leituras consecutivas de temperatura e umidade. Quando é selecionado o registrador de temperatura ou umidade, as leituras são disparadas. Em seguida é necessário aguardar o fim da leitura e depois ler os quatro bytes de resposta.
  • Por este motivo, não dá certo tentar ler normalmente os registradores de temperatura e umidade.
A conversão do valor do registrador na temperatura é simples:
  1. // Calcula e mostra a temperatura em celsius  
  2.   uint32_t aux;  
  3.   aux = temp * 1650L;  
  4.   aux = (aux >> 16) - 400L;  
  5.   temp = (uint16_t) aux;  
  6.   Serial.print(temp/10);  
  7.   Serial.print(",");  
  8.   Serial.println(temp%10);  
  9.   
  10.   // Calcula e mostra a umidade em %  
  11.   aux = umid * 100L;  
  12.   aux = aux >> 16;  
  13.   umid = (uint16_t) aux;  
  14.   Serial.println(umid);  
Cabe destacar que eu preferi evitar o uso de ponto flutuante e fiz as contas com inteiros. A temperatura é calculada com uma casa decimal e a umidade só a parte inteira. Não me preocupei com arredondamento, pois as precisões são de 0,2C e 2%.

O uso deste sensor com o Raspberry Pi fica para o próximo post.

Nenhum comentário: