/* Humidity/Temperature sensor si7021@atmega328p-pu chip running at 1 MGz powered by the two AA batteries * Emulates Oregon V2.1 protocol to send the data * The voltage regulator ams1117-adj, supplies constant 1.24 volts to battPIN pin when is powered up through the powerPIN * The higher the value read on battPIN the lower the battery. * arduine reads 380 at 3.3 volts on battery, and 569 at 2.22 volts on the battery */ #include #include #include #include #include #include const byte transPIN = 1; // Pin for the radio transmitter const byte battPIN = 3; // A3, Pin to read battery level const byte ledPIN = 4; // The test led pid const uint16_t low_battery = 2100; // The limit for low battery (2.1 mV) //------------ digitalWrite using direct port manipulation, attuny85 has portB only ----------------------- class directPort { public: directPort() { } void sendOne(void); void sendZero(void); void selectPin(byte pin) { set_mask = 0; if (pin <= 7) { set_mask = 1 << pin; clr_mask = ~set_mask; } } protected: byte set_mask; byte clr_mask; public: const unsigned long TIME = 512; const unsigned long TWOTIME = TIME*2; }; void directPort::sendOne(void) { PORTB &= clr_mask; // digitalWrite(tx_pin, LOW); delayMicroseconds(TIME); PORTB |= set_mask; // digitalWrite(tx_pin, HIGH); delayMicroseconds(TWOTIME); PORTB &= clr_mask; // digitalWrite(tx_pin, LOW); delayMicroseconds(TIME); } void directPort::sendZero(void) { PORTB |= set_mask; // digitalWrite(tx_pin, HIGH); delayMicroseconds(TIME); PORTB &= clr_mask; // digitalWrite(tx_pin, LOW); delayMicroseconds(TWOTIME); PORTB |= set_mask; // digitalWrite(tx_pin, HIGH); delayMicroseconds(TIME); } //----------------------------------- Send the temp & humidity using oregon v2.1 protocol ------------- class OregonSensor { public: OregonSensor(byte txPin, byte channel, byte sensorID, bool Humidity = false) { tx_pin = txPin; if (tx_pin <= 7) { // PORTD dpB.selectPin(tx_pin); } existsHumidity = Humidity; int type = 0xEA4C; // by default emulate TNHN132N if (existsHumidity) type = 0x1A2D; // emulate THGR2228N buffer[0] = type >> 8; buffer[1] = type & 0xFF; buffer[2] = channel; buffer[3] = sensorID; } void init(void); void sendTempHumidity(int temp, byte humm, bool battery); private: inline void sendOne(void) { dpB.sendOne(); } inline void sendZero(void) { dpB.sendZero(); } void sendData(const byte *data, byte size); // Send data buffer void sendPreamble(void); // Send preamble void sendPostamble(void); // Send postamble void sendOregon(void); // Send preamble, data, postamble void sendSync(void); int sum(byte count); // Count the buffer summ void calculateAndSetChecksum(void); bool existsHumidity; // Weither THGR2228N (send Humidity) byte buffer[9]; byte tx_pin; directPort dpB; const unsigned long TIME = 512; const unsigned long TWOTIME = TIME*2; }; void OregonSensor::init(void) { pinMode(tx_pin, OUTPUT); digitalWrite(tx_pin, LOW); } void OregonSensor::sendData(const byte *data, byte size) { for(byte i = 0; i < size; ++i) { byte m = 1; byte d = data[i]; (d & m)? sendOne(): sendZero(); m <<= 1; (d & m)? sendOne(): sendZero(); m <<= 1; (d & m)? sendOne(): sendZero(); m <<= 1; (d & m)? sendOne(): sendZero(); m <<= 1; (d & m)? sendOne(): sendZero(); m <<= 1; (d & m)? sendOne(): sendZero(); m <<= 1; (d & m)? sendOne(): sendZero(); m <<= 1; (d & m)? sendOne(): sendZero(); } } void OregonSensor::sendOregon(void) { sendPreamble(); byte size = 8; if (existsHumidity) size = 9; sendData(buffer, size); sendPostamble(); digitalWrite(tx_pin, LOW); } void OregonSensor::sendPreamble(void) { byte PREAMBLE[] = {0xFF,0xFF}; sendData(PREAMBLE, 2); } void OregonSensor::sendPostamble(void) { sendZero(); sendZero(); sendZero(); sendZero(); if (!existsHumidity) return; // TNHN132N sendZero(); sendZero(); sendZero(); sendZero(); } void OregonSensor::sendSync(void) { byte data = 0xA; (data & 1)? sendOne(): sendZero(); data >>= 1; (data & 1)? sendOne(): sendZero(); data >>= 1; (data & 1)? sendOne(): sendZero(); data >>= 1; (data & 1)? sendOne(): sendZero(); } int OregonSensor::sum(byte count) { int s = 0; for(byte i = 0; i < count; i++) { s += (buffer[i]&0xF0) >> 4; s += (buffer[i]&0xF); } if(int(count) != count) s += (buffer[count]&0xF0) >> 4; return s; } void OregonSensor::calculateAndSetChecksum(void) { if (!existsHumidity) { int s = ((sum(6) + (buffer[6]&0xF) - 0xa) & 0xff); buffer[6] |= (s&0x0F) << 4; buffer[7] = (s&0xF0) >> 4; } else { buffer[8] = ((sum(8) - 0xa) & 0xFF); } } void OregonSensor::sendTempHumidity(int temp, byte humm, bool battery) { // temperature centegrees * 10 if(!battery) buffer[4] = 0x0C; else buffer[4] = 0x00; if(temp < 0) { buffer[6] = 0x08; temp *= -1; } else { buffer[6] = 0x00; } byte d3 = temp % 10; // Set temperature decimal part buffer[4] |= d3 << 4; temp /= 10; byte d1 = temp / 10; // 1st decimal digit of the temperature byte d2 = temp % 10; // 2nd deciaml digit of the temperature buffer[5] = d1 << 4; buffer[5] |= d2; if (existsHumidity) { // THGR2228N buffer[7] = humm / 10; buffer[6] |= (humm % 10) << 4; } calculateAndSetChecksum(); sendOregon(); // The v2.1 protocol send the message two times delayMicroseconds(TWOTIME*8); sendOregon(); } //================================ End of the class definitions ================================================== SI7021 sensor; OregonSensor os(transPIN, 0x20, 0xAA, true); void enterSleep(void) { ADCSRA &= ~(1<= low_battery); } ++check_battery; if (check_battery > 100) check_battery = 0; int temperature = sensor.getCelsiusHundredths(); if (temperature > 0) temperature += 5; else temperature -= 5; temperature /= 10; byte humidity = sensor.getHumidityPercent(); digitalWrite(ledPIN, HIGH); // turn-on the led during the data transmition os.sendTempHumidity(temperature, humidity, batteryOK); digitalWrite(ledPIN, LOW); } enterSleep(); // power-save mode for 8 seconds } } ISR(WDT_vect) { if (f_wdt == 0) f_wdt = 1; }