Аналог беспроводного датчика температуры домашних метеостанций работающих от батарейного питания, используется китайский микроконтроллер LGT8F328P в среде Arduino.
Версия с LGT8F328P и LM75A:
Схема подключения:
![](https://arduinolab.pw/wp-content/uploads/2019/09/Untitled-Sketch_bb2-1024x772.jpg)
- Приемник LR43B подключается к выход D2 Arduino или LGT8F328P.
![](https://arduinolab.pw/wp-content/uploads/2019/09/Untitled-Sketch_bb0-1024x549.png)
- Передатчик SYN115 подключается к выход D10 Arduino или LGT8F328P.
- LM75A подключается к I2C интерфейсу, SDA и SCL микросхемы к A4 и A5 соответственно, входы нужно подтянуть резисторами на 10к к питанию, выходы A0, A1 и A2, (выбор адреса на шине) соединяются с массой.
- Питание подключается на вход 5V микроконтроллера, никакое другое питание в этот момент, подключено быть не должно.
Код:
Пример для приемника, одинаков для всех вариантов передатчиков и должен работать без изменений. Перевод в градусы цельсия взят из примера работы с LM75 (без А), перевод 9 битный, вне зависимо от разрешения передатчика, шаг отображаемой температуры будет 0,5, это исправимо, но пока так.
// receiver.pde // // Simple example of how to use VirtualWire to receive messages // Implements a simplex (one-way) receiver with an Rx-B1 module // // See VirtualWire.h for detailed API docs // Author: Mike McCauley (mikem@airspayce.com) // Copyright (C) 2008 Mike McCauley // $Id: receiver.pde,v 1.3 2009/03/30 00:07:24 mikem Exp $ #include <VirtualWire.h> /// медленный, экономный память способ uint8_t crc8(const uint8_t *addr, uint8_t len) { uint8_t crc = 0; while (len--) { uint8_t inbyte = *addr++; for (uint8_t i = 8; i; i--) { uint8_t mix = (crc ^ inbyte) & 0x01; crc >>= 1; if (mix) crc ^= 0x8C; inbyte >>= 1; } } return crc; } //// This table comes from Dallas sample code where it is freely reusable, //// though Copyright (C) 2000 Dallas Semiconductor Corporation //static const uint8_t PROGMEM dscrc_table[] = { // 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65, // 157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220, // 35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98, // 190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255, // 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7, // 219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154, // 101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36, // 248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185, // 140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205, // 17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80, // 175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238, // 50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115, // 202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139, // 87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22, // 233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168, // 116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53}; //// //// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM //// and the registers. (note: this might better be done without to //// table, it would probably be smaller and certainly fast enough //// compared to all those delayMicrosecond() calls. But I got //// confused, so I use this table from the examples.) //// //uint8_t crc8(const uint8_t *addr, uint8_t len) { // uint8_t crc = 0; // while (len--) { // crc = pgm_read_byte(dscrc_table + (crc ^ *addr++)); // } // return crc; //} void setup() { Serial.begin(9600); // Debugging only Serial.println("setup"); vw_set_rx_pin(2); vw_setup(1024); // Bits per sec vw_rx_start(); // Start the receiver PLL running } void loop() { uint8_t msb, lsb = 0; float Grad; uint8_t buf[VW_MAX_MESSAGE_LEN]; uint8_t buflen = VW_MAX_MESSAGE_LEN; if (vw_get_message(buf, &buflen)) // Non-blocking { digitalWrite(13, true); // Flash a light to show received good message // Message with a good checksum received, dump it. Serial.print("Got: "); for (int i = 0; i < buflen; i++) { Serial.print(buf[i], HEX); Serial.print(" "); } Serial.println(""); digitalWrite(13, false); //// температура msb = buf[1]; lsb = buf[2]; if (msb < 0x80) { Grad = ((msb * 10) + (((lsb & 0x80) >> 7) * 5)); } else { Grad = ((msb * 10) + (((lsb & 0x80) >> 7) * 5)); Grad = (2555.0 - Grad); } Grad = Grad / 10; Serial.print("ID: "); Serial.println( buf[0]); Serial.print("Temp: "); Serial.println(Grad); Serial.print("crc: "); Serial.print (buf[3]); Serial.print(" = "); Serial.println(crc8((uint8_t*)&buf, buflen - 1)); Serial.println(""); } }
#include <Wire.h> #include <PMU.h> #include <VirtualWire.h> #define LM75_ADDRESS 0x48 #define LM75_TEMP_REGISTER 0 #define LM75_CONF_REGISTER 1 #define LM75_CONF_SHUTDOWN 0 #define TXPIN 10 // нога OOK радиомодуля #define LED 13 // светодиод на плате, мигает при передачи #define SETIDPIN 7 // перемычка выбор id uint8_t ID = 0; uint8_t oldmsb = 0; uint8_t Send[4]; // This table comes from Dallas sample code where it is freely reusable, // though Copyright (C) 2000 Dallas Semiconductor Corporation static const uint8_t PROGMEM dscrc_table[] = { 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65, 157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220, 35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98, 190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255, 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7, 219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154, 101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36, 248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185, 140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205, 17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80, 175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238, 50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115, 202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139, 87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22, 233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168, 116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53}; // // Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM // and the registers. (note: this might better be done without to // table, it would probably be smaller and certainly fast enough // compared to all those delayMicrosecond() calls. But I got // confused, so I use this table from the examples.) // uint8_t crc8(const uint8_t *addr, uint8_t len) { uint8_t crc = 0; while (len--) { crc = pgm_read_byte(dscrc_table + (crc ^ *addr++)); } return crc; } void shutDownLM75(boolean val) { /// 1 выкл, 0 вкл Wire.beginTransmission(LM75_ADDRESS); Wire.write(LM75_CONF_REGISTER); Wire.write(val << LM75_CONF_SHUTDOWN); Wire.endTransmission(); } void setup() { Wire.begin(); vw_set_tx_pin(TXPIN); vw_set_ptt_inverted(false); // false! иначе передатчик останется включенным vw_setup(1024); // Bits per sec pinMode(LED, OUTPUT); digitalWrite(LED, LOW); pinMode(SETIDPIN, INPUT_PULLUP); // читаем состояние ноги ID = digitalRead(SETIDPIN); pinMode(SETIDPIN, INPUT); // исключаем подтягивающий резистор } void loop(){ shutDownLM75(0); // включаем термометр PMU.sleep(PM_POFFS0, SLEEP_256MS); // ждем пока он очухается (можно SLEEP_128MS) // читаем регистры LM75 uint8_t msb, lsb = 0; Wire.beginTransmission(LM75_ADDRESS); Wire.write(LM75_TEMP_REGISTER); Wire.endTransmission(LM75_ADDRESS); Wire.requestFrom(LM75_ADDRESS, 2); // while(Wire.available() < 2); /// тут может все поламаться msb = Wire.read(); lsb = Wire.read(); // если температура изменилась if (oldmsb != msb) { // смотрим в старший бит oldmsb = msb; // сохраняем для следующей проверки // заполняем массив Send[0] = ID; Send[1] = msb; Send[2] = lsb; Send[3] = crc8((uint8_t*)&Send, sizeof(Send) - 1); // отправляем digitalWrite(LED, HIGH); vw_send((uint8_t *)Send, sizeof(Send)); vw_wait_tx(); // Wait until the whole message is gone digitalWrite(LED, LOW); shutDownLM75(1); // выключаем градусник // PMU.sleep(PM_POWERDOWN, SLEEP_1S); PMU.sleep(PM_POWERDOWN, SLEEP_32S); // вообще все выключаем на 32 сек } else { /// иначе спим дальше shutDownLM75(1); // выключаем градусник // PMU.sleep(PM_POWERDOWN, SLEEP_1S); PMU.sleep(PM_POWERDOWN, SLEEP_32S); } // if (msb < 0x80) // { // Grad = ((msb * 10) + (((lsb & 0x80) >> 7) * 5)); // } // else // { // Grad = ((msb * 10) + (((lsb & 0x80) >> 7) * 5)); // Grad = (2555.0 - Grad); // } // // Grad = Grad / 10; }
Видео:
Версия датчика с LGT8F328P и TMP100 \ TMP102:
TMP100 \ TMP102 схожие по характеристикам термодатчики с низким энергопотреблением, имеют аналогичные LM75A регистры с температурой и могут его заменить без особых изменений в коде. Датчики TMP100 и TMP102 имеют одинаковые регистры, код передатчика ниже работает с обоими без изменений, описание датчиков на странице тут и тут. TMP102 имеет корпус SOT563 сложный для ручного монтажа, но доступен в виде модуля, у TMP100 более привычный корпус SOT23-6.
////// датчик температуры с OOK радиомодулем и батарейным питанием ///// TMP100 и 8F328P #include <Wire.h> #include <PMU.h> #include <VirtualWire.h> #define TMP100_ADDRESS 0x48 #define TMP100_TEMP_REGISTER 0 #define TMP100_CONF_REGISTER 1 #define TMP100_SETRESOLUTION 10 // 9 - 12 bit #define TXPIN 10 // нога OOK радиомодуля #define LED 13 // светодиод на плате, мигает при передачи #define SETIDPIN 7 // перемычка выбор id uint8_t ID = 0; uint8_t oldmsb = 0; uint8_t Send[4]; // This table comes from Dallas sample code where it is freely reusable, // though Copyright (C) 2000 Dallas Semiconductor Corporation static const uint8_t PROGMEM dscrc_table[] = { 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65, 157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220, 35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98, 190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255, 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7, 219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154, 101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36, 248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185, 140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205, 17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80, 175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238, 50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115, 202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139, 87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22, 233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168, 116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53}; // // Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM // and the registers. (note: this might better be done without to // table, it would probably be smaller and certainly fast enough // compared to all those delayMicrosecond() calls. But I got // confused, so I use this table from the examples.) // uint8_t crc8(const uint8_t *addr, uint8_t len) { uint8_t crc = 0; while (len--) { crc = pgm_read_byte(dscrc_table + (crc ^ *addr++)); } return crc; } void shutDownTMP100(boolean val) { /// 1 выкл, 0 вкл Wire.beginTransmission(TMP100_ADDRESS); Wire.write(TMP100_CONF_REGISTER); Wire.write((TMP100_SETRESOLUTION - 9) << 5 | val); Wire.endTransmission(); } void setup() { // Serial.begin(9600); Wire.begin(); vw_set_tx_pin(TXPIN); vw_set_ptt_inverted(false); // false! иначе передатчик останется включенным vw_setup(1024); // Bits per sec pinMode(LED, OUTPUT); digitalWrite(LED, LOW); pinMode(SETIDPIN, INPUT_PULLUP); // читаем состояние ноги ID = digitalRead(SETIDPIN); pinMode(SETIDPIN, INPUT); // исключаем подтягивающий резистор } void loop(){ shutDownTMP100(0); // включаем термометр PMU.sleep(PM_POFFS0, SLEEP_256MS); // ждем пока он очухается (можно SLEEP_128MS) // читаем регистры uint8_t msb, lsb = 0; Wire.beginTransmission(TMP100_ADDRESS ); Wire.write(TMP100_TEMP_REGISTER); Wire.endTransmission(TMP100_ADDRESS); Wire.requestFrom(TMP100_ADDRESS, 2); // while(Wire.available() < 2); /// тут может все поламаться msb = Wire.read(); lsb = Wire.read(); // если температура изменилась if (oldmsb != msb) { // смотрим в старший бит oldmsb = msb; // сохраняем для следующей проверки // заполняем массив Send[0] = ID; Send[1] = msb; Send[2] = lsb; Send[3] = crc8((uint8_t*)&Send, sizeof(Send) - 1); // отправляем digitalWrite(LED, HIGH); vw_send((uint8_t *)Send, sizeof(Send)); vw_wait_tx(); // Wait until the whole message is gone digitalWrite(LED, LOW); shutDownTMP100(1); // выключаем градусник // PMU.sleep(PM_POWERDOWN, SLEEP_1S); PMU.sleep(PM_POWERDOWN, SLEEP_32S); // вообще все выключаем на 32 сек } else { /// иначе спим дальше shutDownTMP100(1); // выключаем градусник // PMU.sleep(PM_POWERDOWN, SLEEP_1S); PMU.sleep(PM_POWERDOWN, SLEEP_32S); } // float Grad; // int TemperatureSum = ((msb << 8) | lsb) >> 4; // // Serial.println(TemperatureSum*0.0625); // //delay(1000); }