Skip to content

Instantly share code, notes, and snippets.

@enwi
Created October 1, 2017 17:23
Show Gist options
  • Save enwi/b0e7557168d63f8f8a363cd6201aa850 to your computer and use it in GitHub Desktop.
Save enwi/b0e7557168d63f8f8a363cd6201aa850 to your computer and use it in GitHub Desktop.
Arduino code for the fan control of the modified power inverter: https://youtu.be/2shofvjHGbU
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Function Prototype for wdt_init (place it in init3 section, before main executes to prevent perma-resetting)
void wdt_init(void) __attribute__((naked)) __attribute__((section(".init3")));
void wdt_init(void)
{
MCUSR = 0;
wdt_disable();
return;
}
// All temperatures are calculated by 128 * temperature (degrees C)
const int16_t max_temperature = 7680; // temperature when fans are at max_fan_speed
const int16_t min_temperature = 5504;//4480; // temperature when fans turn on
const int16_t difference_temperature = 384; // min_temperature - difference_temperature when fans turn off (384 = 3 degrees C)
const uint8_t min_fan_speed = 10;
const uint8_t max_fan_speed = 200;
const uint8_t fan_pin = 6;
const uint8_t sensor_pin = 7;
int16_t current_temperature = 0;
uint8_t current_fan_speed = 0;
uint8_t new_fan_speed = 0;
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(sensor_pin);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensor(&oneWire);
DeviceAddress sensor_address;
void initWDT()
{
wdt_reset();
MCUSR &= ~(1<<WDRF); // clear WDRF
WDTCSR |= (1<<WDCE) | (1<<WDE); // enable WDTCSR change
WDTCSR = (1<<WDIE) | (1<<WDP2) | (1<<WDP1); // ~1 sec
}
uint8_t cSREG;
void gotoSleep()
{
cSREG = SREG; // store SREG
cli(); // timed sequences follow
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // use deepest sleep mode
sleep_enable();
MCUCR = (1<<BODS) | (1<<BODSE); // turn off the brown-out detector while sleeping
MCUCR = (1<<BODS); // BODS stays active for 3 cycles, sleep instruction must be executed while it's active
SREG = cSREG; // restore SREG, because we need interrupts now
sleep_cpu(); // go to sleep
sleep_disable(); // wake up here
initWDT(); // initialize WDT for sleep cycle
}
void saveEnergy()
{
uint8_t oldSREG = SREG; // save SREG
cli();
PRR |= 0x8D; // shut off TWI & Timer/Counter1 & SPI & ADC
ADCSRA = 0; // disable the ADC
ADCSRB &= ~(_BV(ACME));
ACSR &= (1<<ACIE); // disable Analog Comparator interrupt to not trigger it in the next command
ACSR |= (1<<ACD); // disable Analog Comparator
DDRD &= ~ 0x7F; // set all pins as input except sensor pin
PORTD |= 0x7F; // turn internal pullup on except sensor pin
DDRB &= ~ 0xFF; // set all pins as input
PORTB |= 0xFF; // turn internal pullup on
DDRC &= ~ 0x3F; // set all pins as input except reset pin
PORTC |= 0x3F; // except reset pin where we do not want to enable pullup
DIDR0 = 0x3F; // disable ADC0D - ADC7D to save more energy, but bits 6 & 7 need to always be 0
DIDR1 = 0x03; // enable AIN0D & AIN1D to disable digital input buffer of pins 6 & 7
SREG = oldSREG; // restore SREG
}
void setup()
{
//initWDT(); // initialize WDT for sleep cycle
saveEnergy(); // use as least energy as possible
Serial.begin(19200); // begin serial with a baudrate of 57600
Serial.println("Inverter fan control");
sensor.begin(); // initialize ds18b20 lib
while( !sensor.getAddress(sensor_address, 0) ) // try to get the address
{
Serial.println("Failed to find sensor. Trying again after 1 second");
gotoSleep();
}
sensor.setResolution(sensor_address, 11); // set ds18b20 resolution to 11 bits
pinMode(fan_pin, OUTPUT); // set fan_pin as output
analogWrite(fan_pin, max_fan_speed);
delay(1000);
analogWrite(fan_pin, 0);
////OCR0A = 0; // set PWM to 0% duty cycle
////TCCR0A |= (1 << COM0A1) | (1 << WGM00); // clear output on compare match & set PWM phase correct mode
//TCCR0B |= (1 << WGM02) | (1 << CS00); // use OCR0A to compare & set prescaler to 1 to get a signal of around 31kHz (31372,549019607843137 Hz)
////TCCR0B |= (1 << WGM02) | (1 << CS01); // use OCR0A to compare & set prescaler to 8 to get a signal of around 4kHz (3921,568627450980392 Hz)
////TCCR0B |= (1 << WGM02) | (1 << CS01) | (1 << CS00); // use OCR0A to compare & set prescaler to 64 to get a signal of around 490 Hz (490,196078431372549 Hz)
////OCR2A = 0;
// set PWM for 50% duty cycle
////TCCR2A |= (1 << COM2A1);
// set none-inverting mode
////TCCR2A |= (1 << WGM21) | (1 << WGM20);
// set fast PWM Mode
////TCCR2B |= (1 << CS21);
}
void loop()
{
Serial.flush();
sensor.requestTemperatures(); // Send the command to get temperatures
//Serial.print("Current temp: ");
current_temperature = sensor.getTemp(sensor_address); // get the current raw temperature
Serial.println(float(current_temperature)/128); // print the temperature after conversion
if( current_temperature > min_temperature ) // if current temperature is bigger than minimal temperature to start the fan
{
new_fan_speed = map(current_temperature, min_temperature - difference_temperature, max_temperature, min_fan_speed, max_fan_speed); // map the current temperature with it's defined max and min to a fan speed
if( current_fan_speed != new_fan_speed ) // only change the fan speed when it changed
{
Serial.println("Turning fan on");
analogWrite(fan_pin, new_fan_speed); // set the PWM register to the current fan speed
current_fan_speed = new_fan_speed; // set the new fan speed as current
}
}
else if( current_temperature < (min_temperature - difference_temperature) && current_fan_speed ) // if tmeperature is smaller than min_temperature - 0.5 degrees
{
Serial.println("Turning fan off");
current_fan_speed = 0; // set current fan speed as 0 to turn it off
analogWrite(fan_pin, current_fan_speed); // set the PWM register to the current fan speed
}
Serial.flush();
//gotoSleep(); // sleep for 1 second to save some energy
delay(1000);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment