Last active
March 10, 2024 18:48
-
-
Save ashevchuk/e3ff135dc46874e62dc8c3bb966b7da5 to your computer and use it in GitHub Desktop.
Rack chiller cooling system controller firmware
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
#include <MCP41xxx.h> | |
#include <SerialCommands.h> | |
#include <ArduinoUniqueID.h> | |
#include <DS18B20.h> | |
#define WDT | |
//#define MA_SMOOTH | |
//#define EWMA_SMOOTH | |
#define SIMPLE_SMOOTH | |
#define CALIBRATION | |
//#define LCD_BLINK | |
//#define CHECK_DEVICE_ADDR | |
//#define CHECK_DEVICE_ADDR_ARG | |
//#define VIBRATION_SENSOR | |
#define LCD | |
//#define LED // speed-sensitive LED flashing | |
//#define SERIAL_STATUS | |
#define SERIAL_CONTROL | |
enum PIN_CONFIG { | |
#ifdef LED | |
PIN_LED_STATUS = 13, | |
#endif | |
PIN_SENSOR_COMPRESSOR = A0, | |
PIN_SENSOR_CONDENSER = A1, | |
#ifdef SERIAL_CONTROL | |
PIN_PWM_FAN_EVAPORATOR = 10, | |
PIN_PWM_FAN_CONDENSER = 9, | |
//pin (ST_CP) of 74HC595 | |
PIN_SHIFT_REG_LATCH = 8, | |
//pin (SH_CP) of 74HC595 | |
PIN_SHIFT_REG_CLOCK = 7, | |
//pin (DS) of 74HC595 | |
PIN_SHIFT_REG_DATA = 6, | |
#endif | |
PIN_CONDENSATE_LEVEL = 2, | |
PIN_SENSOR_TEMP = 3, | |
PIN_VFD_CS = 4, | |
#ifdef SERIAL_CONTROL | |
PIN_SER_TX_ENABLE_SERIAL0 = 5, | |
#endif | |
}; | |
enum LCD_CHAR_BITMAP { | |
LCD_CHAR_TEMP = 0, | |
LCD_CHAR_HUMIDITY = 1, | |
LCD_CHAR_CLOCK = 2, | |
LCD_CHAR_HEART = 3, | |
LCD_CHAR_DUCK = 4, | |
LCD_CHAR_CHECK = 5, | |
LCD_CHAR_CROSS = 6, | |
LCD_CHAR_FAN = 7, | |
LCD_CHAR_GRAD = 0b11011111, | |
LCD_CHAR_BAR = 0b11111111, | |
LCD_CHAR_DASH = 0b10100101 | |
// LCD_CHAR_DASH = 0b10110000 | |
}; | |
#define CMD_MAX_LENGTH 64 | |
#ifdef EWMA_SMOOTH | |
#include <math.h> | |
#include <Ewma.h> | |
#include <EwmaT.h> | |
#endif | |
#ifdef MA_SMOOTH | |
#include <movingAvg.h> | |
#endif | |
#ifdef WDT | |
#include <avr/wdt.h> | |
#endif | |
#include <Shifty.h> | |
#include <EEPROM.h> | |
#ifdef VIBRATION_SENSOR | |
#include <LSM303.h> | |
LSM303 acceleration_sensor; | |
#endif | |
#ifdef LCD | |
// set the LCD address to 0x27 for a 16 chars and 2 line display | |
#define LCD_ADDRESS 0x27 | |
#include <Wire.h> | |
#include <LiquidCrystal_PCF8574.h> | |
LiquidCrystal_PCF8574 lcd(LCD_ADDRESS); | |
#endif | |
#ifdef SERIAL_CONTROL | |
#define SERIAL_DEFAULT_BAUD_RATE 9600 | |
#if defined(UDR0) | |
#define UART_SRA UCSR0A | |
#define UART_SRB UCSR0B | |
#define UART_SRC UCSR0C | |
#define UART_SRL UBRR0L | |
#define UART_UDR UDR0 | |
#elif defined(UDR) | |
#define UART_SRA UCSRA | |
#define UART_SRB UCSRB | |
#define UART_SRC UCSRC | |
#define UART_SRL UBRRL | |
#define UART_UDR UDR | |
#endif | |
#define SERIAL_TX_FLUSH while (!(UART_SRA & _BV(UDRE0))) { }; while (!(UART_SRA & _BV(TXC0))) { } | |
#define SERIAL_TX_ENABLE digitalWrite(PIN_SER_TX_ENABLE_SERIAL0, HIGH); delayMicroseconds(120) | |
#define SERIAL_TX_DISABLE delayMicroseconds(120); digitalWrite(PIN_SER_TX_ENABLE_SERIAL0, LOW) | |
#define SERIAL_PORT Serial | |
#define PRINT(...) SERIAL_TX_ENABLE; SERIAL_PORT.print(__VA_ARGS__); SERIAL_TX_FLUSH | |
#define PRINTLN(...) SERIAL_TX_ENABLE; SERIAL_PORT.println(__VA_ARGS__); SERIAL_TX_FLUSH | |
char serial_command_buffer_[CMD_MAX_LENGTH]; | |
SerialCommands serial_commands_(&SERIAL_PORT, serial_command_buffer_, sizeof(serial_command_buffer_), (char *)"<", (char *)"\r", (char *)":", PIN_SER_TX_ENABLE_SERIAL0); | |
void cmd_analog_read(SerialCommands* sender); | |
SerialCommand cmd_analog_read_("AREAD", cmd_analog_read); | |
void cmd_digital_read(SerialCommands* sender); | |
SerialCommand cmd_digital_read_("DREAD", cmd_digital_read); | |
void cmd_reg_on(SerialCommands* sender); | |
SerialCommand cmd_reg_on_("REGON", cmd_reg_on); | |
void cmd_reg_off(SerialCommands* sender); | |
SerialCommand cmd_reg_off_("REGOFF", cmd_reg_off); | |
void cmd_fan_pwm(SerialCommands* sender); | |
SerialCommand cmd_fan_pwm_("FAN", cmd_fan_pwm); | |
void cmd_temp(SerialCommands* sender); | |
SerialCommand cmd_temp_("TEMP", cmd_temp); | |
void cmd_ping(SerialCommands* sender); | |
SerialCommand cmd_ping_("PING", cmd_ping); | |
void cmd_mode(SerialCommands* sender); | |
SerialCommand cmd_mode_("MODE", cmd_mode); | |
void cmd_set_state(SerialCommands* sender); | |
SerialCommand cmd_set_state_("SET_STATE", cmd_set_state); | |
void cmd_vfd(SerialCommands* sender); | |
SerialCommand cmd_vfd_("VFD", cmd_vfd); | |
void cmd_uptime(SerialCommands* sender); | |
SerialCommand cmd_uptime_("UPTIME", cmd_uptime); | |
void cmd_reset(SerialCommands* sender); | |
SerialCommand cmd_reset_("RESET", cmd_reset); | |
void cmd_reboot(SerialCommands* sender); | |
SerialCommand cmd_reboot_("REBOOT", cmd_reboot); | |
void cmd_stop(SerialCommands* sender); | |
SerialCommand cmd_stop_("STOP", cmd_stop); | |
void cmd_start(SerialCommands* sender); | |
SerialCommand cmd_start_("START", cmd_start); | |
void cmd_discover(SerialCommands* sender); | |
SerialCommand cmd_discover_("DISCOVER", cmd_discover); | |
#endif | |
float get_compressor_temp(); | |
float get_condenser_temp(); | |
static bool is_running = true; | |
typedef enum state { | |
STATE_INITIAL = 0, | |
STATE_NORMAL = 1, | |
STATE_COOLING = 2, | |
STATE_UNFREEZING = 3, | |
STATE_CONDENSING = 4, | |
STATE_SUSPEND = 5, | |
STATE_RESUME = 6 | |
} state; | |
enum shift_regs { | |
REG_EVAPORATOR_FAN = 1, | |
REG_CONDENSER_FAN = 2, | |
REG_COMPRESSOR = 6, | |
REG_CONDENSATE_PUMP = 4, | |
REG_EVAPORATOR_BLOW_FAN = 5, | |
REG_EVAPORATOR_HEATER = 7 | |
}; | |
typedef enum reset_cause { | |
RESET_UNKNOWN = 0, | |
RESET_WATCH_DOG = 1, | |
RESET_POWER_SUPERVISOR = 2, | |
RESET_EXTERNAL = 3, | |
RESET_ON_POWER = 4 | |
} reset_cause; | |
typedef enum run_mode { | |
RUN_MODE_MASTER = 0, | |
RUN_MODE_SLAVE = 1, | |
} run_mode; | |
#define TRESHOLD_PWM_MIN 15 | |
#define TRESHOLD_PWM_MAX 320 | |
#define PWM_AS_PERCENT(a) (float)(100 - ( (100.0 / (TRESHOLD_PWM_MAX * 1.0)) * (a))) | |
#ifdef CALIBRATION | |
#define TIMER_RESOLUTION 1000 | |
#else | |
#define TIMER_RESOLUTION 1 | |
#endif | |
#define MSECONDS(a) (unsigned long)((a) * 1) | |
#define TIME_RESOLUTION (unsigned long)(MSECONDS(TIMER_RESOLUTION)) | |
#define SECONDS(a) (unsigned long)((a) * (TIME_RESOLUTION)) | |
#define MINUTES(a) (unsigned long)((SECONDS(a)) * 60) | |
#define HOURS(a) (unsigned long)((MINUTES(a)) * 60) | |
#define TIME_AS_SECONDS(a) (unsigned long)((a) / (TIME_RESOLUTION)) | |
#define TIME_AS_MINUTES(a) (unsigned long)((TIME_AS_SECONDS(a)) / 60 ) | |
#define TIME_AS_HOURS(a) (unsigned long)((TIME_AS_MINUTES(a)) / 60 ) | |
#define HOURS_AS_SEC(a) (unsigned long)((a) * 60 * 60) | |
#define MINS_AS_SEC(a) (unsigned long)((a) * 60) | |
#define SEC_AS_HOURS(a) (unsigned long)((a) / 60 / 60) | |
#define MINS_AS_HOURS(a) (unsigned long)((a) / 60) | |
#define SEC_AS_MINS(a) (unsigned long)((a) / 60) | |
#define CURRENT_TIME millis() | |
#define TEMP_ADC_ADJ_CONDENSER -10 | |
#define TEMP_C(a) (float)((a) * 1.0) | |
#define TEMP_ADC_C(a) (float)((1 / (0.001129148 + (0.000234125 + (0.0000000876741 * log(((10240000 / (a)) - 10000)) * log(((10240000 / (a)) - 10000)) )) * log(((10240000 / (a)) - 10000)) )) - 273.15) | |
#define TEMP_ADC_C_ADJ(a,b) (float)((TEMP_ADC_C(a)) + b) | |
#define TEMP_C_AS_F(a) (float)(((a) * 9.0) / 5.0 + 32.0) | |
#define TEMP_PRECISION 9 | |
#define TEMP_FORMAT DEC | |
#define SHIFT_REGS 8 | |
#define TRESHOLD_TEMP_COMPRESSOR_MAX (TEMP_C(85)) | |
#define TRESHOLD_TEMP_COMPRESSOR_MIN (TEMP_C(70)) | |
#define TIME_MAX_COMPRESSOR_RUN (HOURS(12)) | |
#define TIME_MAX_CONDENSATE_PUMP_RUN (MINUTES(1)) | |
#define TIME_CONDENSATE_EVAPORATION (HOURS(4)) | |
#define TIME_UNFREEZE_EVAPORATOR (MINUTES(1)) | |
#define TIME_UNFREEZE_EVAPORATOR_CONDENSING (MINUTES(1)) | |
#define TIME_INTERVAL_STATUS_SERIAL (SECONDS(1)) | |
#define TIME_INTERVAL_STATUS_LCD (SECONDS(1)) | |
#define TIME_INTERVAL_MEASURE_SENSOR (SECONDS(1)) | |
#define TIME_INTERVAL_LCD_BLINK (MSECONDS(750)) | |
#define TIME_INTERVAL_LCD_CHAR (MSECONDS(450)) | |
#define TIME_INTERVAL_PING_TIMEOUT (SECONDS(60)) | |
#define PING_TIMEOUT ((CURRENT_TIME - lastPing) > TIME_INTERVAL_PING_TIMEOUT) | |
#define TIME_MAX_INITIAL_UNFREEZE (HOURS(1)) | |
#define TIME_SECS_PER_MIN 60 | |
#define TIME_SECS_PER_HOUR 3600 | |
#define MAX_INITIAL_UNFREEZ_CYCLES 2 | |
#define SMOOTH_GET_CONDENSER_TEMP_READINGS 64 | |
#define SMOOTH_GET_COMPRESSOR_TEMP_READINGS 64 | |
#ifdef VIBRATION_SENSOR | |
#define SMOOTH_GET_ACCELERATION_READINGS 64 | |
#endif | |
#define PWM_PID(a) (unsigned int)(TRESHOLD_PWM_MAX - constrain(map(TEMP_C_AS_F(a), 50, 100, 0, TRESHOLD_PWM_MAX), TRESHOLD_PWM_MIN, TRESHOLD_PWM_MAX)) | |
#define PWM_INVERT(a) (unsigned int)(TRESHOLD_PWM_MAX - (a)) | |
#define PWM_EVAPORATOR(a) OCR1A = (a) | |
#define PWM_CONDENSER(a) OCR1B = (a) | |
#ifdef VIBRATION_SENSOR | |
#define ACCEL_RANGE_REG_2G 0b0000000 | |
#define ACCEL_RANGE_REG_4G 0b0000100 | |
#define ACCEL_RANGE_REG_8G 0b0001000 | |
#define ACCEL_RANGE_REG_16G 0b0001100 | |
#define ACCEL_RANGE_REG (ACCEL_RANGE_REG_8G) | |
#define ACCEL_BASE 1000 // mG | |
#define ACCEL_RANGE(mG) (((mG) * (ACCEL_BASE) * 2) / 65535) | |
#define ACCEL_RANGE_2G 0.061 | |
#define ACCEL_RANGE_4G ACCEL_RANGE(4) | |
#define ACCEL_RANGE_8G 0.244 | |
#define ACCEL_RANGE_16G ACCEL_RANGE(16) | |
#define ACCEL_VECTOR(x,y,z) sqrt(pow((x),2)+pow((y),2)+pow((z),2)) * (ACCEL_RANGE_8G) / (ACCEL_BASE) | |
#endif | |
#define TURN_OFF(a) SHIFT_REGS_STATE[(a)] = LOW; shift.writeBit((a), LOW) | |
#define TURN_ON(a) SHIFT_REGS_STATE[(a)] = HIGH; shift.writeBit((a), HIGH) | |
#define TURN_OFF_ALL shift.batchWriteBegin(); for (byte thisReg = 0; thisReg < SHIFT_REGS; thisReg++) { SHIFT_REGS_STATE[thisReg] = LOW; shift.writeBit(thisReg, LOW); } shift.batchWriteEnd() | |
#define RESET_REGS shift.batchWriteBegin(); for (byte thisReg = 0; thisReg < SHIFT_REGS; thisReg++) { shift.writeBit(thisReg, SHIFT_REGS_STATE[thisReg]); } shift.batchWriteEnd() | |
#define PRINT_TIME(a) char * time_str = (char*) malloc(20); big_time_from_sec(time_str, (a) * 60); PRINT(time_str); free(time_str) | |
#define PRINT_LCD_TIME(a) if (LCDavail) { char * time_str = (char*) malloc(9); time_from_sec(time_str, (a)); lcd.print(time_str); free(time_str); } | |
#define PRINT_LCD_BIG_TIME(a) if (LCDavail) { char * time_str = (char*) malloc(20); big_time_from_sec(time_str, (a) * 60); lcd.print(time_str); free(time_str); } | |
#define PRINT_LCD_TEXT(a) if (LCDavail) { lcd.print(F(a)); } | |
#define PRINT_LCD_VALUE(...) if (LCDavail) { lcd.print(__VA_ARGS__); } | |
#define PRINT_LCD_STATUS(a,b) if (LCDavail) { lcd.setCursor(0, 3); lcd.write((a)); lcd.print(F(b)); } | |
//#define PRINT_LCD_TIMING(a,b,c) if (LCDavail) { if (((a) > 0) || ((b) > 0)) { lcd.setCursor(0, 2); lcd.write(LCD_CHAR_CLOCK); lcd.setCursor(2, 2); if ((a) > 0) { PRINT_LCD_TIME((a)); } if (((a) > 0) && ((b) > 0)) { lcd.print("/"); } if ((b) > 0) { PRINT_LCD_TIME((b)); } } } | |
#define PRINT_LCD_TIMING(a) if (LCDavail) { if ((a) > 0) { lcd.setCursor(11, 3); lcd.write(LCD_CHAR_CLOCK); PRINT_LCD_TIME((a)); } } | |
#define PRINT_LCD_XY(a, x, y) if (LCDavail) { lcd.setCursor((x), (y)); lcd.print(a); } | |
#define PRINT_LCD_CHAR(a) if (LCDavail) { lcd.write((byte)a); } | |
#define CURSOR_LCD_XY(x,y) if (LCDavail) { lcd.setCursor((x), (y)); } | |
#define CLEAR_LCD if (LCDavail) { lcd.home(); lcd.clear(); lcd.setCursor(0, 0); } | |
#define BL_LCD_ON if (LCDavail) { lcd.setBacklight(255); } | |
#define BL_LCD_OFF if (LCDavail) { lcd.setBacklight(0); } | |
#define LCD_ON if (LCDavail) { lcd.display(); } | |
#define LCD_OFF if (LCDavail) { lcd.noDisplay(); } | |
#define CREATE_LCD_CHAR(a, b) if (LCDavail) { create_lcd_char((a), (b)); } | |
#ifdef LCD_BLINK | |
#define LCD_BL(a) LCDblink = (a) | |
#endif | |
#define STATE get_service_state() | |
#define IS_NEW_STATE(a) ((STATE) != (a)) | |
#define EEPROM_BOOTLOADER_FLAG_OFFSET 0x42 | |
#define EEPROM_BOOTLOADER_MAGIC_VALUE 0x42 | |
#define EEPROM_BOOTLOADER_BORING_VALUE 0xFF | |
#define EEPROM_INIT_MAGIC B1101011 | |
#define EEPROM_ADDR_STATE_INITIAL 0 | |
#define EEPROM_ADDR_STATE_COMPRESSOR sizeof(byte) | |
#define EEPROM_VAL_STATE_COMPRESSOR_T unsigned long | |
extern const __FlashStringHelper* getBuildTime() __attribute__((weak)); | |
const __FlashStringHelper* getBuildTime() | |
{ | |
static const char __BuildTime__[] PROGMEM = "BUILD:" __TIMESTAMP__; | |
return reinterpret_cast<const __FlashStringHelper *> (&__BuildTime__[0]); | |
} | |
#ifdef LCD | |
static bool LCDavail = false; | |
#ifdef LCD_BLINK | |
static bool LCDblink = false; | |
static bool LCDblink_state = false; | |
static unsigned long LCDBlinkMillis = 0; | |
#endif | |
static bool LCDchar_state = false; | |
static unsigned long LCDBcharMillis = 0; | |
#endif | |
#ifdef LED | |
static unsigned long ledMillis = 0; // stores last time LED status was toggled | |
#endif | |
static state runtimeState = STATE_INITIAL; | |
static state prevState = STATE_INITIAL; | |
#ifdef SERIAL_STATUS | |
static unsigned long serialMillis = 0; // stores last time a serial message was sent | |
#endif | |
static unsigned long lcdMillis = 0; | |
static unsigned long measureMillis = 0; | |
static unsigned long CompressorStopTime = 0; | |
static unsigned long CompressorStartTime = 0; | |
static unsigned long UnfreezeStartTime = 0; | |
static unsigned long CondensingStartTime = 0; | |
static unsigned long CondensatePumpStopTime = 0; | |
static unsigned long CondensatePumpStartTime = 0; | |
static byte initialUnfreezeCycles = 0; | |
static byte runMode = RUN_MODE_MASTER; | |
static unsigned long lastPing = 0; | |
unsigned int lastStatusLEDvalue = 0; | |
static byte SHIFT_REGS_STATE[SHIFT_REGS]; | |
Shifty shift; | |
#ifdef MA_SMOOTH | |
movingAvg compressor_sensor_filter(10); | |
movingAvg condenser_sensor_filter(10); | |
movingAvg acceleration_sensor_filter(10); | |
#endif | |
#ifdef EWMA_SMOOTH | |
EwmaT <unsigned int> compressor_sensor_filter(3, 100); | |
EwmaT <unsigned int> condenser_sensor_filter(3, 100); | |
EwmaT <unsigned int> acceleration_sensor_filter(3, 100); | |
#endif | |
#ifdef SIMPLE_SMOOTH | |
static float condenser_readings[SMOOTH_GET_CONDENSER_TEMP_READINGS] = { 0.0 }; // the readings from the analog input | |
static byte condenser_readIndex = 0; // the index of the current reading | |
static float condenser_total = 0.0; // the running total | |
static float condenser_average = 0.0; // the average | |
static float condenser_last = 45.0; // last reading | |
static float compressor_readings[SMOOTH_GET_COMPRESSOR_TEMP_READINGS] = { 0.0 }; // the readings from the analog input | |
static byte compressor_readIndex = 0; // the index of the current reading | |
static float compressor_total = 0.0; // the running total | |
static float compressor_average = 0.0; // the average | |
#ifdef VIBRATION_SENSOR | |
static float acceleration_readings[SMOOTH_GET_ACCELERATION_READINGS] = { 0.0 }; | |
static byte acceleration_readIndex = 0; // the index of the current reading | |
static float acceleration_total = 0.0; // the running total | |
static float acceleration_average = 0.0; // the average | |
#endif | |
#endif | |
DS18B20 temp_sensors(PIN_SENSOR_TEMP); | |
uint8_t thermometer[8] = { 0 }; | |
uint8_t condenserThermometer[8] = { 0x28, 0xff, 0x64, 0x1d, 0xcd, 0xf9, 0x84, 0x66 }; | |
uint8_t compressorThermometer[8] = { 0x28, 0x7f, 0x64, 0x1d, 0xcd, 0xf4, 0xac, 0x0e }; | |
MCP41xxx vfdSpeedPot(PIN_VFD_CS); | |
#ifdef LCD | |
const char c_duck[8] PROGMEM = {0x00, 0x0c, 0x1d, 0x0f, 0x0f, 0x06, 0x00}; | |
const char c_retarrow[8] PROGMEM = {0x01, 0x01, 0x05, 0x09, 0x1f, 0x08, 0x04}; | |
//clock icon | |
const char c_clock[8] PROGMEM = { | |
0b00000, | |
0b01110, | |
0b10101, | |
0b10111, | |
0b10001, | |
0b01110, | |
0b00000, | |
0b00000 | |
}; | |
//clock icon | |
const char c_clock_inv[8] PROGMEM = { | |
0b00000, | |
0b01110, | |
0b10001, | |
0b11101, | |
0b10101, | |
0b01110, | |
0b00000, | |
0b00000 | |
}; | |
//check icon | |
const char c_check[8] PROGMEM = { | |
0b00000, | |
0b10101, | |
0b01110, | |
0b11011, | |
0b01110, | |
0b10101, | |
0b00000, | |
0b00000 | |
}; | |
//check icon | |
const char c_check_inv[8] PROGMEM = { | |
0b00000, | |
0b01010, | |
0b11111, | |
0b01010, | |
0b11111, | |
0b01010, | |
0b00000, | |
0b00000 | |
}; | |
const char c_cross[8] PROGMEM = { | |
0b00000, | |
0b01110, | |
0b10101, | |
0b11011, | |
0b01110, | |
0b01110, | |
0b00000, | |
0b00000 | |
}; | |
const char c_cross_inv[8] PROGMEM = { | |
0b00000, | |
0b01110, | |
0b10101, | |
0b11011, | |
0b01110, | |
0b01010, | |
0b01110, | |
0b00000 | |
}; | |
//cross icon | |
const char c_cross2[8] PROGMEM = { | |
0b00000, | |
0b01110, | |
0b10101, | |
0b11111, | |
0b01110, | |
0b01010, | |
0b00100, | |
0b00000 | |
}; | |
//cross icon | |
const char c_cross_inv2[8] PROGMEM = { | |
0b00000, | |
0b01110, | |
0b10101, | |
0b11111, | |
0b01110, | |
0b01110, | |
0b00000, | |
0b00000 | |
}; | |
//heart icon | |
const char c_heart[8] PROGMEM = { | |
0b00000, | |
0b01010, | |
0b11111, | |
0b11111, | |
0b01110, | |
0b00100, | |
0b00000, | |
0b00000 | |
}; | |
//heart icon | |
const char c_heart_inv[8] PROGMEM = { | |
0b00000, | |
0b01010, | |
0b11111, | |
0b01110, | |
0b01110, | |
0b00100, | |
0b00000, | |
0b00000 | |
}; | |
//compressor icon | |
const char c_compressor[8] PROGMEM = { | |
0b11111, | |
0b10001, | |
0b11111, | |
0b10101, | |
0b00100, | |
0b01010, | |
0b00100, | |
0b00000 | |
}; | |
//compressor icon | |
const char c_compressor_inv[8] PROGMEM = { | |
0b11111, | |
0b11111, | |
0b10101, | |
0b10101, | |
0b00100, | |
0b01010, | |
0b00100, | |
0b00000 | |
}; | |
//fan icon | |
const char c_fan[8] PROGMEM = { | |
B00000, | |
B00000, | |
B10011, | |
B10100, | |
B01110, | |
B00101, | |
B11001, | |
B00000 | |
}; | |
//fan icon | |
const char c_fan_inv[8] PROGMEM = { | |
B00000, | |
B00000, | |
B00010, | |
B10100, | |
B01110, | |
B00101, | |
B01000, | |
B00000 | |
}; | |
//hum icon | |
const char c_hum[8] PROGMEM = { | |
B00100, | |
B00100, | |
B01010, | |
B01010, | |
B10001, | |
B10001, | |
B10001, | |
B01110 | |
}; | |
//hum icon | |
const char c_hum_inv[8] PROGMEM = { | |
B00100, | |
B00100, | |
B01010, | |
B01010, | |
B10011, | |
B10111, | |
B11111, | |
B01110 | |
}; | |
//temp icon | |
const char c_temp_inv[8] PROGMEM = { | |
B00100, | |
B01010, | |
B01010, | |
B01010, | |
B01010, | |
B11111, | |
B11111, | |
B01110 | |
}; | |
//temp icon | |
const char c_temp[8] PROGMEM = { | |
B00100, | |
B01010, | |
B01010, | |
B01110, | |
B01110, | |
B11111, | |
B11111, | |
B01110 | |
}; | |
#endif | |
const char hex[17] PROGMEM = "0123456789ABCDEF"; | |
char* id; | |
char* start_str; | |
bool condensate_avail(void) | |
{ | |
return (bool)(digitalRead(PIN_CONDENSATE_LEVEL) == 0); | |
} | |
void ID() | |
{ | |
#ifdef SERIAL_CONTROL | |
PRINT(">ID:"); | |
PRINT(id); | |
PRINT(F(":")); | |
PRINTLN(getBuildTime()); | |
#endif | |
} | |
void reboot(void) { | |
eeprom_write_byte((uint8_t*)EEPROM_BOOTLOADER_FLAG_OFFSET, EEPROM_BOOTLOADER_MAGIC_VALUE); | |
cli(); | |
TCCR0A = TCCR1A = TCCR2A = 0; // make sure interrupts are off and timers are reset. | |
#ifdef WDT | |
wdt_enable(WDTO_1S); | |
while (1); | |
#endif | |
} | |
void restart_code(void) { | |
#ifdef WDT | |
wdt_enable(WDTO_1S); | |
while (1); | |
#endif | |
} | |
uint16_t crc16_update(uint16_t crc, uint8_t a) | |
{ | |
int i; | |
crc ^= a; | |
for (i = 0; i < 8; ++i) | |
{ | |
if (crc & 1) | |
crc = (crc >> 1) ^ 0xA001; | |
else | |
crc = (crc >> 1); | |
} | |
return crc; | |
} | |
char * uint_with_crc(uint16_t value) { | |
char * int_str = (char*) malloc(8); | |
sprintf(int_str, "%u", value); | |
realloc(int_str, strlen(int_str) + 1); | |
uint16_t crc = 0; | |
char * int_str_p = int_str; | |
// char * int_str_hex = (char*) malloc(strlen(int_str)*2+1); | |
// char * int_str_hex_ = int_str_hex; | |
while (*int_str_p != '\0') { | |
// *int_str_hex_++ = pgm_read_byte( &hex[(((*int_str_p) >> 4) & 0x0F)] ); | |
// *int_str_hex_++ = pgm_read_byte( &hex[((*int_str_p) & 0x0F)] ); | |
crc = crc16_update(crc, (uint8_t) * int_str_p++); | |
} | |
// *int_str_hex_ = '\0'; | |
char * crc_str = (char*) malloc(8); | |
sprintf(crc_str, "%u", crc); | |
realloc(crc_str, strlen(crc_str) + 1); | |
// char * crc_str_p = crc_str; | |
// char * crc_str_hex = (char*) malloc(strlen(crc_str)*2+1); | |
// char * crc_str_hex_ = crc_str_hex; | |
// while(*crc_str_p++ != '\0') { | |
// *crc_str_hex_++ = pgm_read_byte( &hex[(*crc_str_p >> 4) & 0x0F] ); | |
// *crc_str_hex_++ = pgm_read_byte( &hex[*crc_str_p & 0x0F] ); | |
// } | |
// *crc_str_hex_ = '\0'; | |
char * out_str = (char*) malloc(18); | |
// sprintf(out_str, "0x%s:0x%s", int_str_hex, crc_str_hex); | |
sprintf(out_str, "%s:%s", int_str, crc_str); | |
realloc(out_str, strlen(out_str) + 1); | |
free(int_str); | |
// free(int_str_hex); | |
free(crc_str); | |
// free(crc_str_hex); | |
return out_str; | |
} | |
char * str_crc(char * value) { | |
uint16_t crc = 0; | |
char * str_p = value; | |
while (*str_p != '\0') { | |
crc = crc16_update(crc, (uint8_t) * str_p++); | |
} | |
char * crc_str = (char*) malloc(8); | |
sprintf(crc_str, "%u", crc); | |
realloc(crc_str, strlen(crc_str) + 1); | |
return crc_str; | |
} | |
char * float_with_crc(float value) { | |
char * int_str = (char*) malloc(8); | |
dtostrf(value, -5, 1, int_str); | |
char * int_str_p = int_str; | |
while (*int_str_p++ != '\0') { | |
if (*int_str_p == 0x20) { | |
*int_str_p = '\0'; | |
} | |
} | |
realloc(int_str, strlen(int_str) + 1); | |
uint16_t crc = 0; | |
int_str_p = int_str; | |
while (*int_str_p != '\0') { | |
crc = crc16_update(crc, (uint8_t) * int_str_p++); | |
} | |
char * crc_str = (char*) malloc(8); | |
sprintf(crc_str, "%u", crc); | |
realloc(crc_str, strlen(crc_str) + 1); | |
char * out_str = (char*) malloc(20); | |
sprintf(out_str, "%s:%s", int_str, crc_str); | |
realloc(out_str, strlen(out_str) + 1); | |
free(int_str); | |
free(crc_str); | |
return out_str; | |
} | |
#ifdef WDT | |
uint8_t mcusr_mirror __attribute__ ((section (".noinit"))); | |
void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3"))); | |
void get_mcusr(void) { | |
mcusr_mirror = MCUSR; | |
MCUSR = 0; | |
wdt_disable(); | |
} | |
#endif | |
inline void big_time_from_sec(char * buffer, unsigned long seconds) { | |
if (seconds > 0) { | |
unsigned long hours = seconds / TIME_SECS_PER_HOUR; | |
unsigned long minutes = seconds / TIME_SECS_PER_MIN; | |
unsigned long mins_left = minutes % TIME_SECS_PER_MIN; | |
sprintf (buffer, "%02lu:%02lu", hours, mins_left); | |
} else { | |
sprintf (buffer, "00:00"); | |
} | |
} | |
inline void time_from_sec(char * buffer, unsigned long seconds) { | |
if (seconds > 0) { | |
unsigned long hours = seconds / TIME_SECS_PER_HOUR; | |
unsigned long minutes = seconds / TIME_SECS_PER_MIN; | |
unsigned long mins_left = minutes % TIME_SECS_PER_MIN; | |
unsigned long secs_left = seconds % TIME_SECS_PER_MIN; | |
if (hours > 99) { | |
hours = 99; | |
} | |
sprintf (buffer, "%02lu:%02lu:%02lu", hours, mins_left, secs_left); | |
} else { | |
sprintf (buffer, "00:00:00"); | |
} | |
} | |
void setup_eeprom() { | |
byte eeprom_state = 0; | |
//EEPROM.get(EEPROM_ADDR_STATE_INITIAL, eeprom_state); | |
if (eeprom_state == EEPROM_INIT_MAGIC) { | |
//PRINT_LCD_XY(F("ROM: OK"), 12, 3); | |
} else { | |
eeprom_state = EEPROM_INIT_MAGIC; | |
//EEPROM.put(EEPROM_ADDR_STATE_INITIAL, eeprom_state); | |
EEPROM_VAL_STATE_COMPRESSOR_T last_running_time = 0; | |
//EEPROM.put(EEPROM_ADDR_STATE_COMPRESSOR, last_running_time); | |
//PRINT_LCD_XY(F("ROM: INT"), 12, 3); | |
} | |
//delay(5000); | |
} | |
void setVFDspeed(uint16_t value) { | |
vfdSpeedPot.analogWrite(0, value); | |
} | |
EEPROM_VAL_STATE_COMPRESSOR_T get_compressor_runtime() { | |
EEPROM_VAL_STATE_COMPRESSOR_T last_running_time = 0; | |
// EEPROM.get(EEPROM_ADDR_STATE_COMPRESSOR, last_running_time); | |
// PRINT_LCD_XY("R ", 11, 0); | |
// PRINT_LCD_VALUE(last_running_time); | |
return last_running_time; | |
} | |
EEPROM_VAL_STATE_COMPRESSOR_T update_compressor_runtime(EEPROM_VAL_STATE_COMPRESSOR_T running_time) { | |
EEPROM_VAL_STATE_COMPRESSOR_T last_running_time = get_compressor_runtime(); | |
if (running_time > 0) { | |
last_running_time += running_time; | |
#ifndef CALIBRATION | |
//PRINT_LCD_XY("W ", 0, 0); | |
//PRINT_LCD_VALUE(last_running_time); | |
//CURSOR_LCD_XY(0, 1); | |
//PRINT_LCD_BIG_TIME(get_compressor_runtime()); | |
#endif | |
// EEPROM.put(EEPROM_ADDR_STATE_COMPRESSOR, last_running_time); | |
} | |
return last_running_time; | |
} | |
void turn_on_condensate_pump() { | |
TURN_ON(REG_CONDENSATE_PUMP); | |
CondensatePumpStopTime = 0; | |
CondensatePumpStartTime = TIME_AS_SECONDS(CURRENT_TIME); | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("Condensate pump: ON")); | |
#endif | |
} | |
void turn_off_condensate_pump() { | |
TURN_OFF(REG_CONDENSATE_PUMP); | |
CondensatePumpStopTime = TIME_AS_SECONDS(CURRENT_TIME); | |
CondensatePumpStartTime = 0; | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("Condensate pump: OFF")); | |
#endif | |
} | |
void turn_on_compressor() { | |
TURN_ON(REG_COMPRESSOR); | |
CompressorStopTime = 0; | |
CompressorStartTime = TIME_AS_SECONDS(CURRENT_TIME); | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("Compressor: ON")); | |
#endif | |
} | |
void turn_off_compressor() { | |
TURN_OFF(REG_COMPRESSOR); | |
CompressorStopTime = TIME_AS_SECONDS(CURRENT_TIME); | |
if (CompressorStartTime > 0) { | |
update_compressor_runtime(SEC_AS_MINS(TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime)); | |
} | |
CompressorStartTime = 0; | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("Compressor: OFF")); | |
#endif | |
} | |
void turn_on_condenser_fan() { | |
TURN_ON(REG_CONDENSER_FAN); | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("Condenser Fan: ON")); | |
#endif | |
} | |
void turn_off_condenser_fan() { | |
TURN_OFF(REG_CONDENSER_FAN); | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("Condenser Fan: OFF")); | |
#endif | |
} | |
void turn_on_evaporator_fan() { | |
TURN_ON(REG_EVAPORATOR_FAN); | |
TURN_ON(REG_EVAPORATOR_BLOW_FAN); | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("Evaporator Fan: ON")); | |
#endif | |
} | |
void turn_off_evaporator_fan() { | |
TURN_OFF(REG_EVAPORATOR_FAN); | |
TURN_OFF(REG_EVAPORATOR_BLOW_FAN); | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("Evaporator Fan: OFF")); | |
#endif | |
} | |
void turn_on_evaporator_heater() { | |
TURN_ON(REG_EVAPORATOR_HEATER); | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("Evaporator Heater: ON")); | |
#endif | |
} | |
void turn_off_evaporator_heater() { | |
TURN_OFF(REG_EVAPORATOR_HEATER); | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("Evaporator Heater: OFF")); | |
#endif | |
} | |
state set_service_state(state State) { | |
//EEPROM.update(EEPROM_ADDR_STATE_COMPRESSOR, State); | |
if (!IS_NEW_STATE(State)) { | |
return State; | |
} | |
lcd_update_state(State); | |
prevState = runtimeState; | |
runtimeState = State; | |
if ( State == STATE_NORMAL ) { | |
turn_off_evaporator_heater(); | |
turn_on_evaporator_fan(); | |
turn_on_compressor(); | |
turn_on_condenser_fan(); | |
UnfreezeStartTime = 0; | |
CondensingStartTime = 0; | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("State: NORMAL")); | |
#endif | |
#ifdef LCD_BLINK | |
LCD_BL(false); | |
#endif | |
} | |
else if ( State == STATE_COOLING ) { | |
turn_off_condensate_pump(); | |
turn_on_evaporator_fan(); | |
turn_off_compressor(); | |
turn_on_condenser_fan(); | |
UnfreezeStartTime = 0; | |
CondensingStartTime = 0; | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("State: COOLING")); | |
#endif | |
#ifdef LCD_BLINK | |
LCD_BL(true); | |
#endif | |
} | |
else if ( State == STATE_UNFREEZING ) { | |
turn_on_evaporator_heater(); | |
turn_off_condensate_pump(); | |
turn_on_evaporator_fan(); | |
turn_off_compressor(); | |
turn_on_condenser_fan(); | |
UnfreezeStartTime = TIME_AS_SECONDS(CURRENT_TIME); | |
CondensingStartTime = 0; | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("State: UNFREEZING")); | |
#endif | |
#ifdef LCD_BLINK | |
LCD_BL(true); | |
#endif | |
} | |
else if ( State == STATE_CONDENSING ) { | |
turn_on_evaporator_heater(); | |
turn_off_condensate_pump(); | |
turn_off_compressor(); | |
turn_off_evaporator_fan(); | |
turn_on_condenser_fan(); | |
UnfreezeStartTime = 0; | |
CondensingStartTime = TIME_AS_SECONDS(CURRENT_TIME); | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("State: CONDENSING")); | |
#endif | |
#ifdef LCD_BLINK | |
LCD_BL(true); | |
#endif | |
} | |
else if ( State == STATE_SUSPEND ) { | |
turn_off_evaporator_heater(); | |
turn_off_condensate_pump(); | |
//turn_off_compressor(); | |
turn_off_evaporator_fan(); | |
//turn_on_condenser_fan(); | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("State: SUSPEND")); | |
#endif | |
#ifdef LCD_BLINK | |
LCD_BL(true); | |
#endif | |
} | |
else if ( State == STATE_RESUME ) { | |
turn_off_evaporator_heater(); | |
turn_off_condensate_pump(); | |
//turn_off_compressor(); | |
turn_on_evaporator_fan(); | |
//turn_on_condenser_fan(); | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("State: RESUME")); | |
#endif | |
#ifdef LCD_BLINK | |
LCD_BL(false); | |
#endif | |
} | |
return State; | |
} | |
state get_service_state() { | |
//state State; | |
//EEPROM.get(EEPROM_ADDR_STATE_COMPRESSOR, State); | |
return runtimeState; | |
//return State; | |
} | |
state check_service_state(float Temp) { | |
//if ( Temp < 0 ) { | |
//turn_off_compressor(); | |
//return STATE; | |
//} | |
if ( STATE == STATE_INITIAL ) { | |
turn_off_compressor(); | |
turn_on_condenser_fan(); | |
// if ( Temp <= TRESHOLD_TEMP_COMPRESSOR_MIN ) { | |
// return set_service_state(STATE_NORMAL); | |
// } else { | |
return set_service_state(STATE_UNFREEZING); | |
// } | |
} | |
else if ( STATE == STATE_NORMAL ) { | |
//if (CompressorStartTime > 0) { | |
// if (((TIME_AS_SECONDS(CURRENT_TIME) - lastStateSaveTime) / HOURS_AS_SEC(1)) > 0) { | |
// update_compressor_runtime(SEC_AS_MINS(TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime)); | |
// } | |
//} | |
if (initialUnfreezeCycles < MAX_INITIAL_UNFREEZ_CYCLES) { | |
if ( TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime >= TIME_AS_SECONDS(TIME_MAX_INITIAL_UNFREEZE) ) { | |
initialUnfreezeCycles++; | |
turn_off_compressor(); | |
return set_service_state(STATE_UNFREEZING); | |
} | |
} | |
if ( Temp >= TRESHOLD_TEMP_COMPRESSOR_MAX ) { | |
turn_off_compressor(); | |
return set_service_state(STATE_COOLING); | |
} | |
else { | |
if ( TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime >= TIME_AS_SECONDS(TIME_MAX_COMPRESSOR_RUN) ) { | |
turn_off_compressor(); | |
return set_service_state(STATE_UNFREEZING); | |
} | |
else { | |
TURN_ON(REG_CONDENSER_FAN); | |
TURN_ON(REG_COMPRESSOR); | |
TURN_ON(REG_EVAPORATOR_FAN); | |
TURN_ON(REG_EVAPORATOR_BLOW_FAN); | |
if (CondensatePumpStartTime > 0) { | |
if ( TIME_AS_SECONDS(CURRENT_TIME) - CondensatePumpStartTime >= TIME_AS_SECONDS(TIME_MAX_CONDENSATE_PUMP_RUN) ) { | |
turn_off_condensate_pump(); | |
} | |
} else { | |
if (CondensatePumpStopTime > 0) { | |
//if ( TIME_AS_SECONDS(CURRENT_TIME) - CondensatePumpStopTime >= TIME_AS_SECONDS(TIME_CONDENSATE_EVAPORATION) ) { | |
if ( condensate_avail() ) { | |
turn_on_condensate_pump(); | |
} | |
} | |
} | |
} | |
} | |
} | |
else if ( STATE == STATE_COOLING ) { | |
turn_off_compressor(); | |
if ( Temp <= TRESHOLD_TEMP_COMPRESSOR_MIN ) { | |
return set_service_state(STATE_UNFREEZING); | |
} | |
} | |
else if ( STATE == STATE_UNFREEZING ) { | |
turn_off_compressor(); | |
if ( TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime >= TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR) ) { | |
return set_service_state(STATE_CONDENSING); | |
} | |
} | |
else if ( STATE == STATE_CONDENSING ) { | |
turn_off_compressor(); | |
if ( (TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime) >= TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR_CONDENSING) ) { | |
return set_service_state(STATE_NORMAL); | |
} | |
} | |
else if ( STATE == STATE_SUSPEND ) { | |
return set_service_state(STATE_SUSPEND); | |
} | |
else if ( STATE == STATE_RESUME ) { | |
//turn_on_compressor(); | |
//turn_on_condenser_fan(); | |
turn_on_evaporator_fan(); | |
return set_service_state(STATE_NORMAL); | |
} | |
else { | |
turn_off_compressor(); | |
return set_service_state(STATE_INITIAL); | |
} | |
return STATE_INITIAL; | |
} | |
#ifdef LCD | |
void create_lcd_char(int char_code, const char * lcd_char PROGMEM) { | |
int lcd_char_buff[8]; | |
for (byte i = 0; i < 8; i++) lcd_char_buff[i] = pgm_read_byte( &lcd_char[i] ); | |
lcd.createChar(char_code, lcd_char_buff); | |
} | |
#endif | |
#ifdef LCD | |
int setup_lcd() | |
{ | |
Wire.begin(); | |
Wire.beginTransmission(LCD_ADDRESS); | |
lcd.begin(20, 4); | |
int lcd_status = Wire.endTransmission(); | |
LCDavail = (lcd_status == 0); | |
CREATE_LCD_CHAR(LCD_CHAR_TEMP, c_temp); | |
CREATE_LCD_CHAR(LCD_CHAR_HUMIDITY, c_hum); | |
CREATE_LCD_CHAR(LCD_CHAR_CLOCK, c_clock); | |
CREATE_LCD_CHAR(LCD_CHAR_HEART, c_heart); | |
CREATE_LCD_CHAR(LCD_CHAR_DUCK, c_duck); | |
CREATE_LCD_CHAR(LCD_CHAR_CHECK, c_check); | |
CREATE_LCD_CHAR(LCD_CHAR_CROSS, c_cross); | |
CREATE_LCD_CHAR(LCD_CHAR_FAN, c_fan); | |
BL_LCD_ON; | |
CLEAR_LCD; | |
return lcd_status; | |
} | |
#endif | |
void setup_fan_pwm() | |
{ | |
digitalWrite(PIN_PWM_FAN_EVAPORATOR, HIGH); | |
digitalWrite(PIN_PWM_FAN_CONDENSER, HIGH); | |
// PWM output @ 25 kHz, only on pins 9 and 10. | |
// Configure Timer 1 for PWM @ 25 kHz. | |
TCCR1A = 0; // undo the configuration done by... | |
TCCR1B = 0; // ...the Arduino core library | |
TCNT1 = 0; // reset timer | |
TCCR1A = _BV(COM1A1) // non-inverted PWM on ch. A | |
| _BV(COM1B1) // same on ch; B | |
| _BV(WGM11); // mode 10: ph. correct PWM, TOP = ICR1 | |
TCCR1B = _BV(WGM13) // ditto | |
| _BV(CS10); // prescaler = 1 | |
ICR1 = 320; // TOP = 320 | |
// Set the PWM pins as output. Only pins 9 and 10 will work. | |
pinMode(PIN_PWM_FAN_EVAPORATOR, OUTPUT); | |
} | |
void setup_regs() | |
{ | |
digitalWrite(PIN_SHIFT_REG_LATCH, HIGH); | |
digitalWrite(PIN_SHIFT_REG_CLOCK, HIGH); | |
digitalWrite(PIN_SHIFT_REG_DATA, HIGH); | |
shift.setBitCount(SHIFT_REGS); | |
shift.setPins(PIN_SHIFT_REG_DATA, PIN_SHIFT_REG_CLOCK, PIN_SHIFT_REG_LATCH); | |
TURN_OFF_ALL; | |
} | |
#ifdef VIBRATION_SENSOR | |
void init_accelerometer() { | |
acceleration_sensor.init(LSM303::device_DLHC); | |
acceleration_sensor.enableDefault(); | |
acceleration_sensor.writeAccReg(LSM303::CTRL_REG2_A, ACCEL_RANGE_REG); //8G range | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_unrecognized(SerialCommands* sender, const char* cmd) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINT(F("ERROR:UNKNOWN_COMMAND:")); | |
PRINTLN(cmd); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_digital_read(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
char* port_str = sender->Next(); | |
if (port_str == NULL) | |
{ | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("DREAD:ERROR:NO_PORT")); | |
return; | |
} | |
#ifdef CHECK_CRC | |
char* port_crc_str = sender->Next(); | |
if (port_crc_str == NULL) | |
{ | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("AREAD:ERROR:NO_PORT_CRC")); | |
return; | |
} | |
#endif | |
int port = atoi(port_str); | |
int value = -1; | |
switch (port) | |
{ | |
case 2: | |
value = digitalRead(2); | |
break; | |
default: | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("DREAD:ERROR:INVALID_PORT")); | |
return; | |
} | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINT(F("DREAD:")); | |
PRINT(port); | |
PRINT(":"); | |
char * value_str = uint_with_crc(value); | |
PRINTLN(value_str); | |
free(value_str); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_analog_read(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
char* port_str = sender->Next(); | |
if (port_str == NULL) | |
{ | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("ERROR:NO_PORT")); | |
return; | |
} | |
int port = atoi(port_str); | |
int value = -1; | |
switch (port) | |
{ | |
case 0: | |
value = analogRead(A0); | |
break; | |
case 1: | |
value = analogRead(A1); | |
break; | |
case 2: | |
value = analogRead(A2); | |
break; | |
} | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINT(F("ANALOG_READ:")); | |
PRINT(port); | |
PRINT(":"); | |
char * value_str = uint_with_crc(value); | |
PRINTLN(value_str); | |
free(value_str); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_reg_on(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
char* reg_str = sender->Next(); | |
if (reg_str == NULL) | |
{ | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("ERROR:NO_REG")); | |
return; | |
} | |
int reg = atoi(reg_str); | |
TURN_ON(reg); | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINT(F("REG_ON:")); | |
PRINT(reg); | |
PRINT(":"); | |
PRINTLN("1"); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_reg_off(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
char* reg_str = sender->Next(); | |
if (reg_str == NULL) | |
{ | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("ERROR:NO_REG")); | |
return; | |
} | |
int reg = atoi(reg_str); | |
TURN_OFF(reg); | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINT(F("REG_OFF:")); | |
PRINT(reg); | |
PRINT(":"); | |
PRINTLN("0"); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_fan_pwm(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
char* pwm_str = sender->Next(); | |
if (pwm_str == NULL) | |
{ | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("ERROR:NO_PWM")); | |
return; | |
} | |
int pwm = atoi(pwm_str); | |
int fan_pwm = constrain(map(pwm, 0, 100, TRESHOLD_PWM_MIN, TRESHOLD_PWM_MAX), TRESHOLD_PWM_MIN, TRESHOLD_PWM_MAX); | |
PWM_EVAPORATOR(fan_pwm); | |
PWM_CONDENSER(fan_pwm); | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINT(F("FAN_PWM:")); | |
PRINT(pwm); | |
PRINT(":"); | |
PRINTLN(fan_pwm); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_temp(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
while (temp_sensors.selectNext()) | |
{ | |
float tempC = temp_sensors.getTempC(); | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINT(F("TEMP:LIST:")); | |
temp_sensors.getAddress(thermometer); | |
for (uint8_t i = 0; i < 8; i++) | |
{ | |
if (thermometer[i] < 0x10) { PRINT("0"); } | |
PRINT(thermometer[i], HEX); | |
} | |
PRINT(":"); | |
char * value_str = float_with_crc(tempC); | |
PRINTLN(value_str); | |
free(value_str); | |
} | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_stop(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
is_running = false; | |
set_service_state(STATE_COOLING); | |
TURN_OFF_ALL; | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("STOP")); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_start(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
is_running = true; | |
set_service_state(STATE_COOLING); | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("START")); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_ping(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
lastPing = CURRENT_TIME; | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("PONG")); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_uptime(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINT(F("UPTIME:")); | |
PRINT_TIME(get_compressor_runtime()); | |
PRINTLN(); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_mode(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
char* mode_str = sender->Next(); | |
if (mode_str == NULL) | |
{ | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("ERROR:NO_MODE")); | |
return; | |
} | |
runMode = atoi(mode_str); | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINT(F("MODE:")); | |
PRINTLN(runMode); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_set_state(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
char* state_str = sender->Next(); | |
if (state_str == NULL) | |
{ | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("ERROR:NO_STATE")); | |
return; | |
} | |
byte run_state = atoi(state_str); | |
set_service_state((state)run_state); | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINT(F("STATE:")); | |
PRINTLN(run_state); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_vfd(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
char* value_str = sender->Next(); | |
if (value_str == NULL) | |
{ | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("ERROR:NO_VALUE")); | |
return; | |
} | |
uint16_t value = atoi(value_str); | |
setVFDspeed(value); | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINT(F("VFD:")); | |
PRINTLN(value); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_reboot(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
TURN_OFF_ALL; | |
digitalWrite(13, HIGH); | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("REBOOT")); | |
digitalWrite(13, LOW); | |
reboot(); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_reset(SerialCommands* sender) | |
{ | |
#ifdef CHECK_DEVICE_ADDR_ARG | |
char* addr_str = sender->Next(); | |
if (addr_str == NULL || strcmp(id, addr_str) != 0) | |
return; | |
#endif | |
TURN_OFF_ALL; | |
digitalWrite(13, HIGH); | |
PRINT(">"); | |
#ifdef CHECK_DEVICE_ADDR | |
PRINT(id); | |
PRINT(":"); | |
#endif | |
PRINTLN(F("RESET")); | |
digitalWrite(13, LOW); | |
restart_code(); | |
} | |
#endif | |
#ifdef SERIAL_CONTROL | |
void cmd_discover(SerialCommands* sender) | |
{ | |
PRINT(">ID:"); | |
PRINT(id); | |
PRINT(F(":")); | |
PRINTLN(getBuildTime()); | |
} | |
#endif | |
float get_compressor_temp() | |
{ | |
if(temp_sensors.select(compressorThermometer)) { | |
#ifdef MA_SMOOTH | |
//return compressor_sensor_filter.reading(TEMP_ADC_C(analogRead(PIN_SENSOR_COMPRESSOR))); | |
return compressor_sensor_filter.reading(temp_sensors.getTempC()); | |
#endif | |
#ifdef EWMA_SMOOTH | |
//return TEMP_ADC_C(compressor_sensor_filter.filter(analogRead(PIN_SENSOR_COMPRESSOR))); | |
return compressor_sensor_filter.filter(temp_sensors.getTempC()); | |
#endif | |
#ifdef SIMPLE_SMOOTH | |
// subtract the last reading: | |
compressor_total -= compressor_readings[compressor_readIndex]; | |
// read from the sensor: | |
compressor_readings[compressor_readIndex] = temp_sensors.getTempC(); | |
// add the reading to the total: | |
compressor_total += compressor_readings[compressor_readIndex]; | |
// advance to the next position in the array: | |
if (++compressor_readIndex >= SMOOTH_GET_COMPRESSOR_TEMP_READINGS) { | |
compressor_readIndex = 0; | |
} | |
// calculate the average: | |
return (compressor_total / SMOOTH_GET_COMPRESSOR_TEMP_READINGS); | |
#endif | |
} else { | |
return 0.0; | |
} | |
} | |
float get_condenser_temp() { | |
//return 30.0; | |
if (temp_sensors.select(condenserThermometer)) { | |
#ifdef MA_SMOOTH | |
//return condenser_sensor_filter.reading(TEMP_ADC_C_ADJ(analogRead(PIN_SENSOR_CONDENSER), TEMP_ADC_ADJ_CONDENSER)); | |
return condenser_sensor_filter.reading(temp_sensors.getTempC()); | |
#endif | |
#ifdef EWMA_SMOOTH | |
//return TEMP_ADC_C_ADJ(condenser_sensor_filter.filter(analogRead(PIN_SENSOR_CONDENSER)), TEMP_ADC_ADJ_CONDENSER); | |
return condenser_sensor_filter.filter(temp_sensors.getTempC()); | |
#endif | |
#ifdef SIMPLE_SMOOTH | |
// subtract the last reading: | |
condenser_total -= condenser_readings[condenser_readIndex]; | |
// read from the sensor: | |
condenser_readings[condenser_readIndex] = temp_sensors.getTempC(); | |
// add the reading to the total: | |
condenser_total += condenser_readings[condenser_readIndex]; | |
// advance to the next position in the array: | |
if (++condenser_readIndex >= SMOOTH_GET_CONDENSER_TEMP_READINGS) { | |
condenser_readIndex = 0; | |
} | |
// calculate the average: | |
condenser_last = (condenser_total / SMOOTH_GET_CONDENSER_TEMP_READINGS); | |
#endif | |
} | |
return condenser_last; | |
} | |
#ifdef LED | |
void update_status_led(unsigned int fanPower) { | |
// flash the LED corresponding to the sensor value | |
if (CURRENT_TIME - ledMillis >= fanPower) { | |
ledMillis = CURRENT_TIME; // save the last time you toggled the LED | |
byte ledPinStatus = digitalRead(PIN_LED_STATUS); | |
digitalWrite(PIN_LED_STATUS, byte(!ledPinStatus)); // toggle the PIN_LED_STATUS | |
if (bool(ledPinStatus)) { | |
CREATE_LCD_CHAR(LCD_CHAR_FAN, c_fan_inv); | |
} else { | |
CREATE_LCD_CHAR(LCD_CHAR_FAN, c_fan); | |
} | |
} | |
} | |
#endif | |
#ifdef LCD | |
void lcd_update_values(float compressorTemp, float condenserTemp, unsigned int pwmValue) | |
{ | |
CURSOR_LCD_XY(0, 0); | |
// PRINT_LCD_XY("P ", 0, 0); | |
PRINT_LCD_CHAR(LCD_CHAR_TEMP); | |
// PRINT_LCD_TEXT(" "); | |
PRINT_LCD_VALUE(compressorTemp, 1); | |
PRINT_LCD_CHAR(LCD_CHAR_GRAD); | |
PRINT_LCD_TEXT(" "); | |
CURSOR_LCD_XY(7, 0); | |
// PRINT_LCD_XY("C ", 10, 0); | |
PRINT_LCD_CHAR(LCD_CHAR_TEMP); | |
// PRINT_LCD_TEXT(" "); | |
PRINT_LCD_VALUE(condenserTemp, 1); | |
PRINT_LCD_CHAR(LCD_CHAR_GRAD); | |
PRINT_LCD_TEXT(" "); | |
CURSOR_LCD_XY(14, 0); | |
// PRINT_LCD_XY("F ", 0, 1); | |
PRINT_LCD_CHAR(LCD_CHAR_FAN); | |
// PRINT_LCD_TEXT(" "); | |
PRINT_LCD_VALUE(PWM_AS_PERCENT(pwmValue), 1); | |
PRINT_LCD_TEXT(" "); | |
for (byte thisReg = 0; thisReg < SHIFT_REGS; thisReg++) { | |
CURSOR_LCD_XY(((20 - (SHIFT_REGS / 2)) + thisReg) - ((thisReg / (SHIFT_REGS / 2)) * (SHIFT_REGS / 2)), 1 + (thisReg / (SHIFT_REGS / 2))); | |
if (SHIFT_REGS_STATE[thisReg] == LOW) { | |
PRINT_LCD_CHAR(LCD_CHAR_CROSS); | |
} else { | |
PRINT_LCD_CHAR(LCD_CHAR_HEART); | |
} | |
} | |
lcd_bar(0, 1, 16, 100, PWM_AS_PERCENT(pwmValue)); | |
} | |
#endif | |
#ifdef LCD | |
void lcd_bar(byte bar_x, byte bar_y, byte bar_len, unsigned long max_val, unsigned long val) { | |
byte len = bar_len - 2; | |
unsigned long time_cells = val / (max_val / len); | |
byte x = bar_x + 1; | |
PRINT_LCD_XY("[", bar_x, bar_y); | |
PRINT_LCD_XY("]", bar_x + bar_len - 1, bar_y); | |
for (byte i = 0; i < time_cells; i++) { | |
CURSOR_LCD_XY(x + i, bar_y); | |
PRINT_LCD_CHAR(LCD_CHAR_BAR); | |
} | |
for (byte i = time_cells; i < len; i++) { | |
CURSOR_LCD_XY(x + i, bar_y); | |
PRINT_LCD_CHAR(LCD_CHAR_DASH); | |
} | |
} | |
#endif | |
#ifdef LCD | |
void lcd_update_status() | |
{ | |
if (LCDavail) { | |
if (CURRENT_TIME - lcdMillis >= TIME_INTERVAL_STATUS_LCD) { | |
// save the last time you sent a message | |
lcdMillis = CURRENT_TIME; | |
if (runMode == RUN_MODE_MASTER) { | |
if ( STATE == STATE_NORMAL ) { | |
if (initialUnfreezeCycles < MAX_INITIAL_UNFREEZ_CYCLES) { | |
//PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime), (TIME_AS_SECONDS(TIME_MAX_INITIAL_UNFREEZE) - (TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime))); | |
PRINT_LCD_TIMING((TIME_AS_SECONDS(TIME_MAX_INITIAL_UNFREEZE) - (TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime))); | |
lcd_bar(0, 2, 16, (TIME_AS_SECONDS(TIME_MAX_INITIAL_UNFREEZE)), (TIME_AS_SECONDS(TIME_MAX_INITIAL_UNFREEZE) - (TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime))); | |
} else { | |
//PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime), (TIME_AS_SECONDS(TIME_MAX_COMPRESSOR_RUN) - (TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime))); | |
PRINT_LCD_TIMING((TIME_AS_SECONDS(TIME_MAX_COMPRESSOR_RUN) - (TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime))); | |
lcd_bar(0, 2, 16, (TIME_AS_SECONDS(TIME_MAX_COMPRESSOR_RUN)), (TIME_AS_SECONDS(TIME_MAX_COMPRESSOR_RUN) - (TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime))); | |
} | |
} | |
else if ( STATE == STATE_UNFREEZING ) { | |
//PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime), (TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR) - (TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime))); | |
PRINT_LCD_TIMING((TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR) - (TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime))); | |
lcd_bar(0, 2, 16, (TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR)), ((TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR)) - (TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime))); | |
} | |
else if ( STATE == STATE_CONDENSING ) { | |
//PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime), (TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR_CONDENSING) - (TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime))); | |
PRINT_LCD_TIMING((TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR_CONDENSING) - (TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime))); | |
lcd_bar(0, 2, 16, (TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR_CONDENSING)), (TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR_CONDENSING) - (TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime))); | |
} | |
else if ( STATE == STATE_COOLING ) { | |
PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CompressorStopTime)); | |
} | |
else if ( STATE == STATE_INITIAL ) { | |
CURSOR_LCD_XY(0, 3); | |
PRINT_LCD_CHAR(LCD_CHAR_CLOCK); | |
CURSOR_LCD_XY(2, 3); | |
PRINT_LCD_BIG_TIME(get_compressor_runtime()); | |
} | |
else if ( STATE == STATE_SUSPEND ) { | |
CURSOR_LCD_XY(0, 3); | |
PRINT_LCD_CHAR(LCD_CHAR_CLOCK); | |
CURSOR_LCD_XY(2, 3); | |
PRINT_LCD_BIG_TIME(get_compressor_runtime()); | |
} | |
else if ( STATE == STATE_RESUME ) { | |
CURSOR_LCD_XY(0, 3); | |
PRINT_LCD_CHAR(LCD_CHAR_CLOCK); | |
CURSOR_LCD_XY(2, 3); | |
PRINT_LCD_BIG_TIME(get_compressor_runtime()); | |
} | |
else { | |
} | |
} else if (runMode == RUN_MODE_SLAVE) { | |
if ( STATE == STATE_NORMAL ) { | |
PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime)); | |
} | |
else if ( STATE == STATE_UNFREEZING ) { | |
PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime)); | |
} | |
else if ( STATE == STATE_CONDENSING ) { | |
PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime)); | |
} | |
else if ( STATE == STATE_COOLING ) { | |
PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CompressorStopTime)); | |
} | |
else if ( STATE == STATE_INITIAL ) { | |
} | |
else if ( STATE == STATE_SUSPEND ) { | |
} | |
else if ( STATE == STATE_RESUME ) { | |
} | |
else { | |
} | |
} | |
} | |
} | |
} | |
#endif | |
#ifdef LCD | |
void lcd_update_state(state State) | |
{ | |
if (LCDavail) { | |
if (runMode == RUN_MODE_MASTER) { | |
if ( State == STATE_NORMAL ) { | |
PRINT_LCD_STATUS(LCD_CHAR_CHECK, "CHILL "); | |
} | |
else if ( State == STATE_UNFREEZING ) { | |
PRINT_LCD_STATUS(LCD_CHAR_HUMIDITY, "DEFROST "); | |
} | |
else if ( State == STATE_CONDENSING ) { | |
PRINT_LCD_STATUS(LCD_CHAR_HUMIDITY, "CONDENSE"); | |
} | |
else if ( State == STATE_COOLING ) { | |
PRINT_LCD_STATUS(LCD_CHAR_CROSS, "OVERHEAT"); | |
} | |
else if ( State == STATE_INITIAL ) { | |
PRINT_LCD_STATUS(LCD_CHAR_CHECK, "INIT "); | |
} | |
else if ( State == STATE_SUSPEND ) { | |
PRINT_LCD_STATUS(LCD_CHAR_CHECK, "STANDBY "); | |
} | |
else if ( State == STATE_RESUME ) { | |
PRINT_LCD_STATUS(LCD_CHAR_CHECK, "RESUME "); | |
} | |
else { | |
PRINT_LCD_STATUS(LCD_CHAR_CHECK, "CONFIG "); | |
} | |
} else { | |
PRINT_LCD_STATUS(LCD_CHAR_CHECK, "SLAVE "); | |
} | |
} | |
} | |
#endif | |
#ifdef SERIAL_STATUS | |
void serial_send_state(float compressorTemp, float condenserTemp, unsigned int pwmValue) | |
{ | |
if (CURRENT_TIME - serialMillis >= TIME_INTERVAL_STATUS_SERIAL) { | |
// save the last time you sent a message | |
serialMillis = CURRENT_TIME; | |
PRINT(F("Compressor: ")); | |
PRINT(compressorTemp, TEMP_FORMAT); // display Celsius | |
PRINT(F("C Condenser: ")); | |
PRINT(condenserTemp, TEMP_FORMAT); // display Celsius | |
PRINT(F("C Condenser Fan: ")); | |
PRINT(pwmValue, TEMP_FORMAT); | |
// PRINT(" Evaporator Fan: "); | |
// PRINT(pwmValue, TEMP_FORMAT); | |
if ( STATE == STATE_NORMAL ) { | |
unsigned long comressor_start = TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime; | |
unsigned long comressor_stoped = TIME_AS_SECONDS(TIME_MAX_COMPRESSOR_RUN) - comressor_start; | |
PRINT(F(" Compressor runtime: ")); | |
PRINT(comressor_start, TEMP_FORMAT); // display Celsius | |
PRINT(F("s run / ")); | |
PRINT(comressor_stoped, TEMP_FORMAT); // display Celsius | |
PRINT(F("s to stop")); | |
} | |
else if ( STATE == STATE_UNFREEZING ) { | |
unsigned long unfreeze_start = TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime; | |
unsigned long unfreeze_stoped = TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR) - unfreeze_start; | |
PRINT(F(" Unfreeze runtime: ")); | |
PRINT(unfreeze_start, TEMP_FORMAT); // display Celsius | |
PRINT(F("s run / ")); | |
PRINT(unfreeze_stoped, TEMP_FORMAT); // display Celsius | |
PRINT(F("s to stop")); | |
} | |
else if ( STATE == STATE_CONDENSING ) { | |
unsigned long condensing_start = TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime; | |
unsigned long condensing_stoped = TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR_CONDENSING) - condensing_start; | |
PRINT(F(" Condensing runtime: ")); | |
PRINT(condensing_start, TEMP_FORMAT); // display Celsius | |
PRINT(F("s run / ")); | |
PRINT(condensing_stoped, TEMP_FORMAT); // display Celsius | |
PRINT(F("s to stop")); | |
} | |
else if ( STATE == STATE_COOLING ) { | |
PRINT(F(" State: cooling")); | |
} | |
else if ( STATE == STATE_INITIAL ) { | |
PRINT(F(" State: initial")); | |
} | |
else { | |
PRINT(F(" State: unknown")); | |
} | |
PRINTLN(""); | |
} | |
} | |
#endif | |
#ifdef VIBRATION_SENSOR | |
float get_acceleration_velocity() { | |
acceleration_sensor.readAcc(); | |
#ifdef MA_SMOOTH | |
return acceleration_sensor_filter.reading(ACCEL_VECTOR(acceleration_sensor.a.x, acceleration_sensor.a.y, acceleration_sensor.a.z)); | |
#endif | |
#ifdef EWMA_SMOOTH | |
return acceleration_sensor_filter.filter(ACCEL_VECTOR(acceleration_sensor.a.x, acceleration_sensor.a.y, acceleration_sensor.a.z)); | |
#endif | |
#ifdef SIMPLE_SMOOTH | |
// subtract the last reading: | |
acceleration_total -= acceleration_readings[acceleration_readIndex]; | |
// read from the sensor: | |
acceleration_readings[acceleration_readIndex] = ACCEL_VECTOR(acceleration_sensor.a.x, acceleration_sensor.a.y, acceleration_sensor.a.z); | |
// add the reading to the total: | |
acceleration_total += acceleration_readings[acceleration_readIndex]; | |
// advance to the next position in the array: | |
if (++acceleration_readIndex >= SMOOTH_GET_ACCELERATION_READINGS) { | |
acceleration_readIndex = 0; | |
} | |
// calculate the average: | |
return (acceleration_total / SMOOTH_GET_ACCELERATION_READINGS); | |
#endif | |
} | |
#endif | |
#ifdef VIBRATION_SENSOR | |
void measure_vibration() { | |
float acceleration = get_acceleration_velocity(); | |
#ifdef LCD | |
CURSOR_LCD_XY(14, 2); | |
PRINT_LCD_CHAR(LCD_CHAR_DUCK); | |
PRINT_LCD_VALUE(acceleration); | |
#endif | |
} | |
#endif | |
void setup_id() { | |
id = (char*) malloc(sizeof(char) * (UniqueIDsize * 2 + 1)); | |
start_str = (char*) malloc(sizeof(char) * (UniqueIDsize * 2 + 2)); | |
char *id_ = id; | |
char *start_str_ = start_str; | |
for (size_t i = 0; i < UniqueIDsize; i++) | |
{ | |
*id_++ = pgm_read_byte( &hex[(UniqueID[i] >> 4) & 0x0F] ); | |
*id_++ = pgm_read_byte( &hex[UniqueID[i] & 0x0F] ); | |
} | |
*id_ = '\0'; | |
*start_str_ = '\0'; | |
char *id_crc = str_crc(id); | |
free(id); | |
id = id_crc; | |
strcat(start_str, id); | |
strcat(start_str, ":"); | |
realloc(start_str, strlen(start_str) + 1); | |
//serial_commands_.SetStart(start_str); | |
} | |
void setup_vfd() { | |
vfdSpeedPot.begin(); | |
setVFDspeed(0); | |
} | |
void setup() | |
{ | |
#ifdef WDT | |
wdt_disable(); | |
#endif | |
setup_regs(); | |
setup_fan_pwm(); | |
setup_eeprom(); | |
setup_id(); | |
setup_vfd(); | |
pinMode(3, OUTPUT); | |
digitalWrite(3, HIGH); | |
#ifdef LED | |
// declare the PIN_LED_STATUS as an output: | |
pinMode(PIN_LED_STATUS, OUTPUT); | |
#endif | |
pinMode(PIN_CONDENSATE_LEVEL, INPUT); | |
//analogReference(EXTERNAL); | |
#ifdef SERIAL_CONTROL | |
// initialize the serial port | |
pinMode(PIN_SER_TX_ENABLE_SERIAL0, OUTPUT); | |
digitalWrite(PIN_SER_TX_ENABLE_SERIAL0, LOW); | |
SERIAL_PORT.begin(SERIAL_DEFAULT_BAUD_RATE); | |
ID(); | |
serial_commands_.SetDefaultHandler(cmd_unrecognized); | |
serial_commands_.AddCommand(&cmd_analog_read_); | |
serial_commands_.AddCommand(&cmd_digital_read_); | |
serial_commands_.AddCommand(&cmd_reg_on_); | |
serial_commands_.AddCommand(&cmd_reg_off_); | |
serial_commands_.AddCommand(&cmd_fan_pwm_); | |
serial_commands_.AddCommand(&cmd_temp_); | |
serial_commands_.AddCommand(&cmd_ping_); | |
serial_commands_.AddCommand(&cmd_mode_); | |
serial_commands_.AddCommand(&cmd_set_state_); | |
serial_commands_.AddCommand(&cmd_vfd_); | |
serial_commands_.AddCommand(&cmd_uptime_); | |
serial_commands_.AddCommand(&cmd_reset_); | |
serial_commands_.AddCommand(&cmd_reboot_); | |
serial_commands_.AddCommand(&cmd_stop_); | |
serial_commands_.AddCommand(&cmd_start_); | |
serial_commands_.AddCommand(&cmd_discover_); | |
#endif | |
#ifdef LCD | |
if (setup_lcd() == 0) { | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("LCD found.")); | |
#endif | |
} else { | |
#ifdef SERIAL_STATUS | |
PRINTLN(F("LCD not found.")); | |
#endif | |
} // if | |
#endif | |
#ifdef VIBRATION_SENSOR | |
init_accelerometer(); | |
#endif | |
#ifdef WDT | |
//check_last_wdt_cause(); | |
#endif | |
#ifdef LCD | |
PRINT_LCD_XY(F("CALIBRATION..."), 3, 0); | |
PRINT_LCD_XY("R ", 0, 3); | |
PRINT_LCD_CHAR(LCD_CHAR_CLOCK); | |
CURSOR_LCD_XY(4, 3); | |
PRINT_LCD_BIG_TIME(get_compressor_runtime()); | |
#endif | |
if(temp_sensors.select(compressorThermometer)) { | |
temp_sensors.setResolution(TEMP_PRECISION); | |
} | |
if (temp_sensors.select(condenserThermometer)) { | |
temp_sensors.setResolution(TEMP_PRECISION); | |
} | |
#ifdef CALIBRATION | |
float calibration_temp = 0.0; | |
if(temp_sensors.select(compressorThermometer)) { | |
calibration_temp = temp_sensors.getTempC(); | |
} | |
#ifdef SIMPLE_SMOOTH | |
for (int thisReading = 0; thisReading < SMOOTH_GET_COMPRESSOR_TEMP_READINGS; thisReading++) { | |
compressor_readings[thisReading] = compressor_average = calibration_temp;//analogRead(PIN_SENSOR_COMPRESSOR); | |
compressor_total += compressor_average; | |
//delay(10); | |
#ifdef LCD | |
PRINT_LCD_XY("P ", 0, 1); | |
PRINT_LCD_VALUE(TEMP_ADC_C(compressor_average), 1); | |
#endif | |
} | |
calibration_temp = 35.0; | |
if(temp_sensors.select(condenserThermometer)) { | |
calibration_temp = temp_sensors.getTempC(); | |
} | |
for (int thisReading = 0; thisReading < SMOOTH_GET_CONDENSER_TEMP_READINGS; thisReading++) { | |
condenser_readings[thisReading] = condenser_average = calibration_temp;//analogRead(PIN_SENSOR_CONDENSER); | |
condenser_total += condenser_average; | |
//delay(10); | |
#ifdef LCD | |
PRINT_LCD_XY("C ", 0, 2); | |
PRINT_LCD_VALUE(TEMP_ADC_C_ADJ(condenser_average, TEMP_ADC_ADJ_CONDENSER), 1); | |
#endif | |
} | |
#ifdef VIBRATION_SENSOR | |
for (int thisReading = 0; thisReading < SMOOTH_GET_ACCELERATION_READINGS; thisReading++) { | |
acceleration_readings[thisReading] = acceleration_average = get_acceleration_velocity(); | |
acceleration_total += acceleration_average; | |
#ifdef LCD | |
PRINT_LCD_XY("C ", 0, 3); | |
PRINT_LCD_VALUE(acceleration_average, 1); | |
#endif | |
} | |
#endif | |
#endif | |
#endif | |
#ifdef LCD | |
BL_LCD_ON; | |
CLEAR_LCD; | |
#endif | |
#ifdef WDT | |
wdt_enable(WDTO_8S); | |
#endif | |
} | |
void loop() | |
{ | |
#ifdef WDT | |
wdt_reset(); | |
#endif | |
SERIAL_TX_DISABLE; | |
serial_commands_.ReadSerial(); | |
if (is_running) { | |
if ((runMode != RUN_MODE_MASTER) && PING_TIMEOUT) { | |
runMode = RUN_MODE_MASTER; | |
} | |
#ifdef VIBRATION_SENSOR | |
measure_vibration(); | |
#endif | |
if (CURRENT_TIME - measureMillis >= TIME_INTERVAL_MEASURE_SENSOR) { | |
measureMillis = CURRENT_TIME; | |
//temp_sensors.requestTemperatures(); | |
float compressorTemp = get_compressor_temp(); | |
float condenserTemp = get_condenser_temp(); | |
// temp to fan speed | |
unsigned int fanPower = PWM_PID(condenserTemp); | |
// set the fan speed (PWM output at 25 kHz) per the sensor value | |
// this may need to be changed to (320 - sensorValue) or less | |
if (runMode == RUN_MODE_MASTER) { | |
PWM_EVAPORATOR(PWM_INVERT(fanPower)); | |
PWM_CONDENSER(fanPower); | |
check_service_state(compressorTemp); | |
} | |
lastStatusLEDvalue = fanPower; | |
#ifdef LCD | |
#ifdef CALIBRATION | |
lcd_update_values(compressorTemp, condenserTemp, fanPower); | |
#endif | |
#endif | |
#ifdef SERIAL_STATUS | |
serial_send_state(compressorTemp, condenserTemp, fanPower); | |
#endif | |
} | |
#ifdef LED | |
update_status_led(lastStatusLEDvalue); | |
#endif | |
// check_switches(); | |
RESET_REGS; | |
#ifdef LCD | |
if (CURRENT_TIME - LCDBcharMillis >= TIME_INTERVAL_LCD_CHAR) { | |
LCDBcharMillis = CURRENT_TIME; | |
if ((LCDchar_state = (bool)(!LCDchar_state))) { | |
//CREATE_LCD_CHAR(LCD_CHAR_FAN, c_fan_inv); | |
CREATE_LCD_CHAR(LCD_CHAR_HUMIDITY, c_hum_inv); | |
CREATE_LCD_CHAR(LCD_CHAR_HEART, c_heart_inv); | |
CREATE_LCD_CHAR(LCD_CHAR_TEMP, c_temp_inv); | |
CREATE_LCD_CHAR(LCD_CHAR_CROSS, c_cross_inv); | |
CREATE_LCD_CHAR(LCD_CHAR_CHECK, c_check_inv); | |
CREATE_LCD_CHAR(LCD_CHAR_CLOCK, c_clock_inv); | |
} else { | |
//CREATE_LCD_CHAR(LCD_CHAR_FAN, c_fan); | |
CREATE_LCD_CHAR(LCD_CHAR_HUMIDITY, c_hum); | |
CREATE_LCD_CHAR(LCD_CHAR_HEART, c_heart); | |
CREATE_LCD_CHAR(LCD_CHAR_TEMP, c_temp); | |
CREATE_LCD_CHAR(LCD_CHAR_CROSS, c_cross); | |
CREATE_LCD_CHAR(LCD_CHAR_CHECK, c_check); | |
CREATE_LCD_CHAR(LCD_CHAR_CLOCK, c_clock); | |
} | |
} | |
lcd_update_status(); | |
#ifdef LCD_BLINK | |
if (runMode == RUN_MODE_MASTER) { | |
if (LCDavail) { | |
if (CURRENT_TIME - LCDBlinkMillis >= TIME_INTERVAL_LCD_BLINK) { | |
LCDBlinkMillis = CURRENT_TIME; | |
if (LCDblink) { | |
if ((LCDblink_state = (bool)(!LCDblink_state))) { | |
BL_LCD_ON; | |
} else { | |
BL_LCD_OFF; | |
} | |
} else { | |
BL_LCD_ON; | |
} | |
} | |
} | |
} else { | |
if ((bool)(!LCDblink_state)) BL_LCD_ON; | |
} | |
#endif | |
#endif | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment