-
-
Save Sharangovich/9509c91b43614f820755c956dcdd66ff to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Original Author: Klusjesman | |
Tested with STK500 + ATMega328P | |
GCC-AVR compiler | |
Modified by supersjimmie: | |
Code and libraries made compatible with Arduino and ESP8266 | |
Tested with Arduino IDE v1.6.5 and 1.6.9 | |
For ESP8266 tested with ESP8266 core for Arduino v 2.1.0 and 2.2.0 Stable | |
(See https://github.com/esp8266/Arduino/ ) | |
*/ | |
/* | |
CC11xx pins ESP pins Arduino pins Description | |
1 - VCC VCC VCC 3v3 | |
2 - GND GND GND Ground | |
3 - MOSI 13=D7 Pin 11 Data input to CC11xx | |
4 - SCK 14=D5 Pin 13 Clock pin | |
5 - MISO/GDO1 12=D6 Pin 12 Data output from CC11xx / serial clock from CC11xx | |
6 - GDO2 04=D2 Pin 2? Serial data to CC11xx | |
7 - GDO0 ? Pin ? output as a symbol of receiving or sending data | |
8 - CSN 15=D8 Pin 10 Chip select / (SPI_SS) | |
*/ | |
#include <SPI.h> | |
#include "IthoCC1101.h" | |
#include "IthoPacket.h" | |
#include <HTU21D.h> | |
#include <avr/sleep.h> | |
#include <avr/power.h> | |
#include <avr/wdt.h> | |
#define RF_VCC_PIN 3 | |
#define SENSOR_VCC_PIN 4 | |
#define GREEN_LED_PIN 8 | |
#define AMBER_LED_PIN 9 | |
// Pro Mini version is 3V3 8MHz!!! | |
/* | |
Calculater power consumption during awake period with measurments | |
Devider MHz Uptime(s) mAs | |
clock_div_2 4 0.226 0.4718 | |
clock_div_4 2 0.283 > 0.4213 < | |
clock_div_8 1 0.459 0.52425 | |
clock_div_16 0.5 0.751 0.75805 | |
clock_div_32 0.25 1.355 1.532515 | |
*/ | |
#define CLOCK_DIV 4 // setup works well at divider 16 (0.5MHz). Also on 32 and 64 but Itho lib needs adjustmets to delays. | |
#define CLOCK_DIV_PRESCALE clock_div_4 | |
// #define CLOCK_ADJUSTED_BAUD 300 * CLOCK_DIV // for divider 64 clock 0.125MHz | |
// #define CLOCK_ADJUSTED_BAUD 600 * CLOCK_DIV // for divider 32 clock 0.25MHz | |
// #define CLOCK_ADJUSTED_BAUD 1200 * CLOCK_DIV // for divider 16 clock 0.5MHz | |
// #define CLOCK_ADJUSTED_BAUD 2400 * CLOCK_DIV // for divider 8 clock 1MHz | |
#define CLOCK_ADJUSTED_BAUD 4800 * CLOCK_DIV // for divider 4 clock 2MHz | |
// #define CLOCK_ADJUSTED_BAUD 9600 * CLOCK_DIV // for divider 2 clock 4MHz | |
#define DEFAULT_TARGET_SLEEP_CYCLES 1 | |
#define TIMER_SLEEP_CYCLES 75 // should be around 10 minutes (75 cycles of 8 seconds) | |
// #define TIMER_SLEEP_CYCLES 150 // should be around 10 minutes (150 cycles of 4 seconds) | |
// #define TIMER_SLEEP_CYCLES 300 // should be around 10 minutes (300 cycles of 2 seconds) | |
#define MAX_HUMIDITY 70 | |
#define MAX_VALID_TEMPERATURE 45 | |
#define MIN_VALID_TEMPERATURE 5 | |
#define SHORT_DELAY_MICROSECONDS 3200 / CLOCK_DIV | |
#define LONG_DELAY_MICROSECONDS 360000 / CLOCK_DIV | |
#define RF_DELAY_MICROSECONDS 100000 / CLOCK_DIV | |
IthoCC1101 rf; | |
HTU21D sensor; | |
const uint8_t RFTid[] = {106, 170, 106, 101, 154, 107, 154, 86}; // my ID, magic number | |
volatile uint16_t sleepCycles = 0; // Sleep cycle counter | |
volatile uint16_t targetSleepCycles = DEFAULT_TARGET_SLEEP_CYCLES; // Number of sleep cycles to run, default 1 | |
void setup(void) { | |
// slow clock to divide by N | |
clock_prescale_set(CLOCK_DIV_PRESCALE); // This setup works at divider 16 (1MHz clock) | |
Serial.begin(CLOCK_ADJUSTED_BAUD); | |
Serial.println("Setup start"); | |
digitalWrite(RF_VCC_PIN, LOW); | |
digitalWrite(SENSOR_VCC_PIN, LOW); | |
pinMode(RF_VCC_PIN, OUTPUT); // RF_VCC_PIN powers RF module when necessary | |
pinMode(SENSOR_VCC_PIN, OUTPUT); // SENSOR_VCC_PIN powers temperature and humidity sensor HTU21D when necessary | |
pinMode(GREEN_LED_PIN, OUTPUT); | |
pinMode(AMBER_LED_PIN, OUTPUT); | |
// Register as a new RFT, follow user manual for the Itho fan. | |
// In most cases: power down, wait 15 sec, power on, bind/register RFT within 2 minutes. | |
// | |
// Serial.println("Register command start"); | |
// RFSwitchOn(); | |
// rf.init(); | |
// sendRegister(); | |
// RFSwitchOff(); | |
// Serial.println("Register command sent"); | |
Serial.println("Setup done"); | |
} | |
void RFSwitchOn(void) { | |
Serial.println("RF on"); | |
digitalWrite(RF_VCC_PIN, HIGH); | |
delayMicroseconds(RF_DELAY_MICROSECONDS); | |
rf.init(); | |
Serial.println("RF init done"); | |
} | |
void RFSwitchOff(void) { | |
digitalWrite(RF_VCC_PIN, LOW); | |
Serial.println("RF off"); | |
} | |
void SensorSwitchOn(void) { | |
Serial.println("Sensor on"); | |
digitalWrite(SENSOR_VCC_PIN, HIGH); | |
sensor.begin(); | |
Serial.println("Sensor init done"); | |
} | |
void SensorSwitchOff(void) { | |
digitalWrite(SENSOR_VCC_PIN, LOW); | |
Serial.println("Sensor off"); | |
} | |
void GreenLedBlink(void) { | |
digitalWrite(GREEN_LED_PIN, HIGH); | |
delayMicroseconds(SHORT_DELAY_MICROSECONDS); | |
digitalWrite(GREEN_LED_PIN, LOW); | |
} | |
void ErrorBlink(void) { | |
digitalWrite(AMBER_LED_PIN, HIGH); | |
delayMicroseconds(SHORT_DELAY_MICROSECONDS); | |
digitalWrite(AMBER_LED_PIN, LOW); | |
delayMicroseconds(LONG_DELAY_MICROSECONDS); | |
digitalWrite(AMBER_LED_PIN, HIGH); | |
delayMicroseconds(SHORT_DELAY_MICROSECONDS); | |
digitalWrite(AMBER_LED_PIN, LOW); | |
} | |
void loop(void) { | |
// Serial.println(millis ()); | |
// Serial.println(lastSleep); | |
// Serial.println(WAIT_TIME); | |
// if (millis () - lastSleep <= WAIT_TIME / CLOCK_DIV) | |
// { | |
// lastSleep = millis (); | |
// noInterrupts (); | |
// byte old_ADCSRA = ADCSRA; | |
// // disable ADC | |
// ADCSRA = 0; | |
// // pin change interrupt (example for D0) | |
// PCMSK2 |= bit (PCINT16); // want pin 0 | |
// PCIFR |= bit (PCIF2); // clear any outstanding interrupts | |
// PCICR |= bit (PCIE2); // enable pin change interrupts for D0 to D7 | |
// set_sleep_mode (SLEEP_MODE_PWR_DOWN); | |
// power_adc_disable(); | |
// power_spi_disable(); | |
// power_timer0_disable(); | |
// power_timer1_disable(); | |
// power_timer2_disable(); | |
// power_twi_disable(); | |
// UCSR0B &= ~bit (RXEN0); // disable receiver | |
// UCSR0B &= ~bit (TXEN0); // disable transmitter | |
// sleep_enable(); | |
// digitalWrite (AWAKE_LED, LOW); | |
// interrupts (); | |
// sleep_cpu (); | |
// digitalWrite (AWAKE_LED, HIGH); | |
// sleep_disable(); | |
// power_all_enable(); | |
// ADCSRA = old_ADCSRA; | |
// PCICR &= ~bit (PCIE2); // disable pin change interrupts for D0 to D7 | |
// UCSR0B |= bit (RXEN0); // enable receiver | |
// UCSR0B |= bit (TXEN0); // enable transmitter | |
// } // end of time to sleep | |
SensorSwitchOn(); | |
/* | |
RESOLUTION_RH12_T14 = 0, 12 bit for RH and 14 bit for temperature | |
RESOLUTION_RH8_T12 = 1, 8 bit for RH and 12 bit for temperature | |
RESOLUTION_RH10_T13 = 2, 10 bit for RH and 13 bit for temperature | |
RESOLUTION_RH11_T11 = 3 11 bit for RH and 11 bit for temperature | |
HTU21D_DELAY_T[] = {50, 13, 25, 7}; | |
HTU21D_DELAY_H[] = {16, 3, 5, 8}; | |
*/ | |
sensor.setResolution(RESOLUTION_RH11_T11); // lower resolution for quicker response | |
GreenLedBlink(); | |
if(sensor.measure()) { | |
float temperature = sensor.getTemperature(); | |
float humidity = sensor.getHumidity(); | |
SensorSwitchOff(); | |
// Printing to Serial takes extra 1s at div 32!!! | |
// Serial.print("Temperature (°C): "); | |
Serial.println(temperature); | |
// Serial.print("Humidity (%RH): "); | |
Serial.println(humidity); | |
// Sensor when not ready gives invalid temperature (-46.85 or a value greater than 100) | |
// Only react if the temperature is in the reasonable indoor range. | |
if (humidity > MAX_HUMIDITY && temperature > MIN_VALID_TEMPERATURE && temperature < MAX_VALID_TEMPERATURE) { | |
RFSwitchOn(); | |
sendTimer(); | |
targetSleepCycles = TIMER_SLEEP_CYCLES; | |
RFSwitchOff(); | |
GreenLedBlink(); | |
} else if (temperature < MIN_VALID_TEMPERATURE || temperature > MAX_VALID_TEMPERATURE) { | |
ErrorBlink(); | |
} else { | |
GreenLedBlink(); | |
} | |
} else { | |
ErrorBlink(); | |
} | |
SensorSwitchOff(); | |
// Sleep | |
static byte prevADCSRA = ADCSRA; | |
ADCSRA = 0; | |
set_sleep_mode(SLEEP_MODE_PWR_DOWN); | |
power_adc_disable(); | |
power_spi_disable(); | |
power_timer0_disable(); | |
power_timer1_disable(); | |
power_timer2_disable(); | |
power_twi_disable(); | |
// Without this Serial doesn't work | |
// UCSR0B &= ~bit (RXEN0); // disable receiver | |
// UCSR0B &= ~bit (TXEN0); // disable transmitter | |
sleep_enable(); | |
while (sleepCycles < targetSleepCycles) { // 1 cycle lasts 8 seconds | |
// Turn of Brown Out Detection (low voltage). This is automatically re-enabled upon timer interrupt | |
sleep_bod_disable(); | |
// Ensure we can wake up again by first disabling interrupts (temporarily) so | |
// the wakeISR does not run before we are asleep and then prevent interrupts, | |
// and then defining the ISR (Interrupt Service Routine) to run when poked awake by the timer | |
noInterrupts(); | |
/* Clear the reset flag. */ | |
MCUSR &= ~(1 << WDRF); | |
/* In order to change WDE or the prescaler, we need to | |
* set WDCE (This will allow updates for 4 clock cycles). | |
*/ | |
WDTCSR |= (1 << WDCE) | (1 << WDE); | |
/* set new watchdog timeout prescaler value */ | |
WDTCSR = 1 << WDP0 | 1 << WDP3; // 8.0 seconds | |
// WDTCSR = 1 << WDP3; // 4.0 seconds | |
/* | |
time const Prescaler-Bits | |
WDP0 WDP1 WDP2 WDP3 | |
16 ms WDTO_15MS 0 0 0 0 | |
32 ms WDTO_30MS 1 0 0 0 | |
64 ms WDTO_60MS 0 1 0 0 | |
0,125s WDTO_120MS 1 1 0 0 | |
0,25s WDTO_250MS 0 0 1 0 | |
0,5s WDTO_500MS 1 0 1 0 | |
1,0s WDTO_1S 0 1 1 0 | |
2,0s WDTO_2S 1 1 1 0 | |
4,0s WDTO_4S 0 0 0 1 | |
8,0s WDTO_8S 1 0 0 1 | |
*/ | |
/* Enable the WD interrupt (note no reset). */ | |
WDTCSR |= _BV(WDIE); | |
// Send a message just to show we are about to sleep | |
Serial.print("Sleep cycle "); | |
Serial.print(sleepCycles + 1); | |
Serial.print(" of "); | |
Serial.println(targetSleepCycles); | |
Serial.flush(); | |
// Allow interrupts now | |
interrupts(); | |
blinkInSleep(); | |
// And enter sleep mode as set above | |
sleep_cpu(); | |
} | |
// Prevent sleep mode, so we don't enter it again, except deliberately, by code | |
sleep_disable(); | |
power_all_enable(); | |
// Without this Serial doesn't work | |
// UCSR0B |= bit (RXEN0); // enable receiver | |
// UCSR0B |= bit (TXEN0); // enable transmitter | |
// Re-enable ADC if it was previously running | |
ADCSRA = prevADCSRA; | |
// Wakes up at this point when timer wakes up µC | |
Serial.println("Awake"); | |
// Reset sleep counter | |
sleepCycles = 0; | |
targetSleepCycles = DEFAULT_TARGET_SLEEP_CYCLES; | |
} | |
// When WatchDog timer causes µC to wake it comes here | |
ISR (WDT_vect) { | |
// Turn off watchdog, we don't want it to do anything (like resetting this sketch) | |
wdt_disable(); | |
// Increment the WDT interrupt count | |
sleepCycles++; | |
// Now we continue running the main Loop() just after we went to sleep | |
} | |
void blinkInSleep(void) { | |
power_all_enable(); | |
// Assumed that sleep cycles number is bigger, then the timer is running | |
if (targetSleepCycles > DEFAULT_TARGET_SLEEP_CYCLES) { | |
digitalWrite(AMBER_LED_PIN, HIGH); | |
delayMicroseconds(SHORT_DELAY_MICROSECONDS); | |
digitalWrite(AMBER_LED_PIN, LOW); | |
} | |
power_adc_disable(); | |
power_spi_disable(); | |
power_timer0_disable(); | |
power_timer1_disable(); | |
power_timer2_disable(); | |
power_twi_disable(); | |
} | |
///////////////////////////// | |
///////////////////////////// | |
void sendRegister() { | |
Serial.println("sending join..."); | |
rf.sendCommand(IthoJoin); | |
Serial.println("sending join done."); | |
} | |
void sendStandbySpeed() { | |
Serial.println("sending standby..."); | |
rf.sendCommand(IthoStandby); | |
Serial.println("sending standby done."); | |
} | |
void sendLowSpeed() { | |
Serial.println("sending low..."); | |
rf.sendCommand(IthoLow); | |
Serial.println("sending low done."); | |
} | |
void sendMediumSpeed() { | |
Serial.println("sending medium..."); | |
rf.sendCommand(IthoMedium); | |
Serial.println("sending medium done."); | |
} | |
void sendHighSpeed() { | |
Serial.println("sending high..."); | |
rf.sendCommand(IthoHigh); | |
Serial.println("sending high done."); | |
} | |
void sendFullSpeed() { | |
Serial.println("sending FullSpeed..."); | |
rf.sendCommand(IthoFull); | |
Serial.println("sending FullSpeed done."); | |
} | |
void sendTimer() { | |
Serial.println("sending timer..."); | |
rf.sendCommand(IthoTimer1); | |
Serial.println("sending timer done."); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment