#include "TM1637.h"
#define DHTPIN 4
TM1637 TM;
float temperature;
float tempMin; // Minimum temperature, adjustable, default 22
float tempMax; // Maximum temperature, adjustable, default 28
int minDuty = 255 * 0.25; // 25% duty cycle = 255 * 0.25
int maxDuty = 255 * 0.99; // 99% duty cycle = 255 * 0.99
//================================================
// PWM fan
// call function on setup() for initial set of timer and PIN
void setupPWM() {
// Set up Timer 2 for PWM on pin 11.
DDRB |= (1<<3); // set pin 11 as output
TCCR2A = _BV(COM2A1) | _BV(COM2A0) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(CS22); // prescaler of 64
OCR2A = 0;
}
// set PWM of the led to simulate fan behavior
void setupPWM(int duty) {
// Set up Timer 2 for PWM on pin 11.
DDRB |= (1<<3); // set pin 11 as output
TCCR2A = _BV(COM2A1) | _BV(COM2A0) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(CS22); // prescaler of 64
// OCR2A = 0;
OCR2A = duty; // Set duty cycle
}
// shutdown the led to simulate fan behavior
void stopPWM() {
// Set pin 11 as input and clear PORTB3 to ensure that the pin is completely turned off
DDRB &= ~(1 << 3); // Set pin 11 as input
PORTB &= ~(1 << 3); // Clear PORTB3 bit
}
// power up the led to max to simulate fan behavior
void powerUpP11() {
// Disconnect OC2A (pin 11) from Timer 2 and set it HIGH
TCCR2A &= ~(_BV(COM2A1) | _BV(COM2A0));
PORTB |= _BV(PORTB3); // PORTB3 corresponds to digital pin 11
}
//=====================================================
// --- DTH22
byte RH_high, RH_low, temp_high, temp_low, checksum;
int tempM;
void DHT22_data()
{
// start signal
DDRD |= (1 << DHTPIN); // set data pin for o/p
PORTD &= ~(1 << DHTPIN); // first send low pulse
delayMicroseconds(1000); // for 1ms
PORTD |= (1 << DHTPIN); // then send high pulse
delayMicroseconds(40); // for 40us
//-------------------------------------------------------------------
//response signal
DDRD &= ~(1 << DHTPIN); // set data pin for i/p
while (PIND & (1 << DHTPIN)); // wait for DHT22 low pulse
while (!(PIND & (1 << DHTPIN))); // wait for DHT22 high pulse
while (PIND & (1 << DHTPIN)); // wait for DHT22 low pulse
//-------------------------------------------------------------------
// read sensor data (byte level)
RH_high = read_DHT22_byte(); // read high byte humidity
RH_low = read_DHT22_byte(); // read low byte humidity
// I don't need the humidity, but for stability I have to read them too
temp_high = read_DHT22_byte(); // read high byte temp
temp_low = read_DHT22_byte(); // read low byte temp
checksum = read_DHT22_byte(); // read checksum
//-------------------------------------------------------------------
tempM = (temp_high << 8) | temp_low; // get 16-bit value of tempM using a bitwise op
}
float getTemperature()
{
float tempDHT = float(tempM)/10.0;
if (tempDHT < 0) {
return 0.0;
}
return tempDHT;
}
byte read_DHT22_byte()
{
byte dataByte;
for (byte i = 0; i < 8; i++)
{
while (!(PIND & (1 << DHTPIN))); // detect data bit (high pulse)
delayMicroseconds(50);
//--------------------------------------------------------------------
if (PIND & (1 << DHTPIN)) dataByte = (dataByte << 1) | (0x01);
else dataByte = (dataByte << 1); // store 1 or 0 in dataByte
//--------------------------------------------------------------------
while (PIND & (1 << DHTPIN)); // wait for DHT22 low pulse
}
return dataByte;
}
//=====================================================
//ISR and buttons logic
const int LONG_PRESS_DURATION = 2000; // 2 seconds
const int INACTIVITY_DURATION = 5000; // 5 seconds
volatile unsigned long pressedTime = 0;
enum Mode {NORMAL, SET_TMIN, SET_TMAX}; // set mode
volatile Mode currentMode = NORMAL;
ISR(INT0_vect) { // interrupt pin 2
buttonISR_Right();
}
void buttonISR_Right() {
int buttonState = PIND & (1 << PIND2); // Read button state directly from register
if (buttonState == 0) { // Button is pressed
pressedTime = millis();
} else { // Button is released
unsigned long pressDuration = millis() - pressedTime;
if (pressDuration > LONG_PRESS_DURATION) {
Serial.println("Long press detected - RIGHT");
currentMode = SET_TMAX;
}
}
}
ISR(INT1_vect) { // interrupt pin 3
buttonISR_Left();
}
void buttonISR_Left() {
int buttonState = PIND & (1 << PIND3); // Read button state directly from register
if (buttonState == 0) { // Button is pressed
pressedTime = millis();
} else { // Button is released
unsigned long pressDuration = millis() - pressedTime;
if (pressDuration > LONG_PRESS_DURATION) {
Serial.println("Long press detected - LEFT");
currentMode = SET_TMIN;
}
}
}
unsigned long btnInactiveTimer;
unsigned long currentMillis;
void setTempMax() {
EIMSK &= ~(1 << INT0); // Disable interrupt on digital pin 2
EIMSK &= ~(1 << INT1); // Disable interrupt on digital pin 3
Serial.println("Loop started");
float tempSet = tempMax;
int buttonState_R_Prev = 1;
int buttonState_L_Prev = 1;
btnInactiveTimer = millis();
do {
TM.displayFloat(tempSet, 2);
int buttonState_R = PIND & (1 << PIND2); // Read button right state
int buttonState_L = PIND & (1 << PIND3); // Read button left state
if (buttonState_R == 0 && buttonState_R_Prev != 0) { // Increments temp
btnInactiveTimer = millis();
if (tempSet < 90.0) {
tempSet = tempSet + 0.5;
}
}
if (buttonState_L == 0 && buttonState_L_Prev != 0) { // Decrements temp
btnInactiveTimer = millis();
if (tempSet > (tempMin + 1.0)) {
tempSet = tempSet - 0.5;
}
}
buttonState_R_Prev = buttonState_R;
buttonState_L_Prev = buttonState_L;
} while (millis() - btnInactiveTimer < INACTIVITY_DURATION);
tempMax = tempSet;
currentMode = NORMAL;
EIMSK |= (1 << INT0); // Enable interrupt on digital pin 2
EIMSK |= (1 << INT1); // Enable interrupt on digital pin 3
}
void setTempMin() {
EIMSK &= ~(1 << INT0); // Disable interrupt on digital pin 2
EIMSK &= ~(1 << INT1); // Disable interrupt on digital pin 3
Serial.println("Loop started");
float tempSet = tempMin;
int buttonState_R_Prev = 1;
int buttonState_L_Prev = 1;
btnInactiveTimer = millis();
do {
TM.displayFloat(tempSet, 2);
int buttonState_R = PIND & (1 << PIND2); // Read button right state
int buttonState_L = PIND & (1 << PIND3); // Read button left state
if (buttonState_R == 0 && buttonState_R_Prev != 0) { // Increments temp
btnInactiveTimer = millis();
if (tempSet < (tempMax - 1.0)) {
tempSet = tempSet + 0.5;
}
}
if (buttonState_L == 0 && buttonState_L_Prev != 0) { // Decrements temp
btnInactiveTimer = millis();
if (tempSet > 0) {
tempSet = tempSet - 0.5;
}
}
buttonState_R_Prev = buttonState_R;
buttonState_L_Prev = buttonState_L;
} while (millis() - btnInactiveTimer < INACTIVITY_DURATION);
tempMin = tempSet;
currentMode = NORMAL;
EIMSK |= (1 << INT0); // Enable interrupt on digital pin 2
EIMSK |= (1 << INT1); // Enable interrupt on digital pin 3
}
//=== start program ===
void setup()
{
Serial.begin(9600);
//set default values
temperature = 0;
tempMin = 22;
tempMax = 28;
TM.begin(7, 8, 4); // clockpin, datapin, #digits
TM.setBrightness(0x0f);
setupPWM();
DDRD &= ~((1 << DDD2) | (1 << DDD3)); // set pin 2 and 3 as input
EICRA |= (1 << ISC00) | (1 << ISC10); // Set interrupt on pin 2 and 3
EIMSK |= (1 << INT0) | (1 << INT1); // Enable external interrupt
}
void loop() {
cli(); // Disable interrupt to avoid disruption
DHT22_data(); // read data from DHT22
temperature = getTemperature(); // save the result into global variable
TM.displayFloat(temperature, 2); // show float with fixed point (2)
if (temperature < tempMin) {
stopPWM();
} else if (temperature > tempMax) {
powerUpP11();
} else {
int duty = map(temperature, tempMin, tempMax, minDuty, maxDuty);
duty = constrain(duty, minDuty, maxDuty); // Ensure duty cycle stays within bounds
setupPWM(duty);
//debugging
Serial.print(" Duty Cycle: ");
Serial.println(duty);
}
sei(); // Enable the interrupts again, this way millis() function works again
//debugging
delay(100); //DA TOGLIEREEEE
Serial.print("Temperature: ");
Serial.println(temperature);
switch(currentMode) { // check for interrupt flag
case NORMAL:
break;
case SET_TMAX:
setTempMax();
break;
case SET_TMIN:
setTempMin();
break;
}
Serial.println("Start loop again");
}