11-17-15, 07:15 AM | #11 | |
Supreme EcoRenovator
|
Quote:
I used a "freebie" power board out of a donated portable dehumidifier for a relay shield equivalent. The board also has a regulated 5VDC power supply built into it that feeds the Uno board through the USB plug. The board in its old home The board connected to the Uno with LCD keypad shield Please take note that this rig functions as a non-standard heat pump thermostat as wired. The yellow and green wires are compressor and reversing valve call, the red is the 24VAC feed to run contactors and controls inside the unit. Defrost control is handled by an ICM 315 board inside the unit. That's what I had in it before the GP controller was made. However, these power boards are pretty much the same in every window AC or portable dehumidifier out there that has a digital readout and pushbutton control. These boards have enough relays on them that are matched to the demands of the patient unit, so all that wiring and such is already tested and proven by the OEM. To morph a unit into a heat pump, one of the fan relays could easily be rewired to control a reversing valve solenoid. For a water-source unit, a HX pump or two could run straight off a relay or two. |
|
11-17-15, 10:34 AM | #12 | |
FNG
Join Date: Jul 2015
Location: Washington
Posts: 71
Thanks: 8
Thanked 19 Times in 13 Posts
|
Quote:
I'm mentally breaking down that board: Transformer to bring down the mains voltage... four discrete diodes are the rectifier... Perhaps the TO-220 package to the upper left is the LM7805 with a few filter caps surrounding it for 5v power. I imagine that little DIP 16 sized IC in the upper right quadrant of the first picture is some kind of gate array or buffer to interface the relays with TTL signals... or perhaps some other low complexity IC? The white header at the top is the control interface. ...and some kind of piezoelectric alarm/horn in there too? I would presume the large black square relay is the compressor. The 3 blue relays are fan motors, etc. Good stuff. |
|
The Following User Says Thank You to TechShop For This Useful Post: | jeff5may (11-17-15) |
11-17-15, 03:29 PM | #13 | |
Supreme EcoRenovator
|
Quote:
Another power board mentioned is the Amana p/n 30132033. This one has no mains transformer, but has extra high-current relays (original purpose:strip heaters) and thermistors on board that connect to the same type of pin headers. This board originally went in hotel PTAC units and still sells for around $20. Last edited by jeff5may; 11-20-15 at 06:17 AM.. Reason: part number added |
|
01-03-16, 02:17 PM | #14 |
Apprentice EcoRenovator
Join Date: May 2011
Location: Tortosa, Spain
Posts: 221
Thanks: 2
Thanked 81 Times in 46 Posts
|
Code for heatpump controller
Ok, here we go.. This is my code for my heat pump controller. First an explanation of the structure.
There are 9 individual modules (.ino files) that make up the controller. Each one attempts to encapsulate functionality of a particular part of the controller. As the complexity of the controller and the necessity to run various peripheral parts increased it became evident that a real time operating system would be needed, many of the modules run functions specifically related to the peripherals leaving the 'main' program (thread) to control the state of the machine. Enough waffle.. The code for the RTOS was found here: https://github.com/greiman/NilRTOS-Arduino Other code libraries are either part of the Arduino code or are easily found searching on Google. Some code is modified from samples and extended to meet my needs. The code is commented so hopefully makes sense. I'll split it into individual posts as it's a bit much all in one... Note: Some defines/code may not be used as it was there in development and I haven't removed it yet.. 1. Main header file HeatpumpController.h #pragma once #ifndef HPCONTROLLER_H #define HPCONTROLLER_H int defTemp; //Temperature to run a defrost cycle int defTime; //Time to run defrost cycle int defUpperTemp; //If evap reaches this temperature abandon the defrost cycle int maxWaterTemp; //Maximum circuit water temperature int desiredRoomTemp; //Desired room temperature int hysterisis; //Hysterisis setting int defStep; //Defrost step int deltaOn; //Temp to turn on pump int deltaOff; //Temp to turn off pump bool operatingState; //System operating state - true=on, false=off bool machineRunningState = FALSE; //State of machine - true=on, false=off int operatingMode; //System operating mode char systemState[20]; //System state string bool readAnalog = FALSE; //Flag to indicate an analogue conversion is taking place. Needed for rtos so 2 analogue reads don't clash bool rtosStarted = FALSE; //Flag the RTOS has started (needed for change from delay to nilDelay...) unsigned long lastDefrost = 0; unsigned long timeBetweenDefrost; //Time between defrost cycles unsigned long defrostRunTime; unsigned long defrostStartDelay; unsigned long defrostStartTime; bool defrostFlag = FALSE; //Flag to say if we are in a defrost cycle (and to start a defrost cycle) float lastTempEvaporator; float lastTempCompressor; float tempCompressor; float tempEvaporator; float humidity; float dht11Temperature; float dewPointTemp; #define ON 0 #define OFF 1 #define COOL 0 #define HEAT 1 //Analogue sensors int ntcSensor[4]; #define flowTemp ntcSensor[0] #define returnTemp ntcSensor[1] #define ambientTemp ntcSensor[2] #define s4 ntcSensor[3] //Heat pump control pins (Digital outputs) #define FANLOW 2 #define FANHIGH 3 #define COMPRESSOR 4 #define DHT11PIN 5 #define DS18B20 7 #define PUMP 8 #define VALVE 9 //Status of individual relays. Set all on so startup sets the pin outputs correctly bool compStat = ON; bool fanLow = ON; bool fanHigh = ON; bool valve = ON; bool pump = ON; //Non volatile memory storage //#define STARTDELAY 0 //Startup delay time //#define MAX_TEMP 1 // //#define MIN_TEMP 2 //#define HEATCOOL 3 #define DEFROSTTIME 4 //Defrost time #define DEFROSTTEMP 5 //Defrost start temperature #define DEFROSTMAXTEMP 6 //Temperature to stop defrost (overrides time for defrost cycle) #define MAXCOMPTEMP 7 //Maximum compressor temperature #define LASTSYSTEMSTATE 8 //Last state - on or off #define LASTSYSTEMMODE 9 //Last operating mode (heat/cool) #define DESIREDROOMTEMP 10 //Temperature for room #define MAXWATERTEMP 11 //Maximum water temperature #define HYSTERISIS 12 //Hysterisis setting #define TIMEBETWEENDEFROST 13 //Time between defrost cycles #define LASTCOMPRUN 14 //Time last compressor run - note 4 bytes! #define NEXTFREE 18 /* System constants */ #define DEFROSTTEMP 2 #define DEFROST_OFFSET 10 #define COMPSTARTDELAY 180000 //Minimum delay time between compressor starts (for power fail/reset etc) /* LCD Pages */ #define LCD_PAGE0 0 //General status #define LCD_PAGE1 1 //Defrost settings #define LCD_PAGE2 2 #define LCD_PAGE3 3 #define LCD_PAGE4 4 #define LCD_PAGES 4 int lcd_page = LCD_PAGE0; //Starting LCD page #include <Time.h> tmElements_t tm; void writeTime(tmElements_t tmw); void readTime(); void saveSystemState(char *state); //Stuff for debug output via serial port void SerialPrint2(char *format, ...); #ifdef DEBUG #define DEBUG_PRINT(x) Serial.print (x) #define DEBUG_PRINTST(x,...) SerialPrint2 (x,__VA_ARGS__) #define DEBUG_PRINTLN(x) Serial.println (x) #else #define DEBUG_PRINT(x) #define DEBUG_PRINTST(x,...) #define DEBUG_PRINTLN(x) #endif //Thread definitions for NilRTOS NIL_THREAD(threadEthernet, arg); NIL_THREAD(threadReadNTC, arg); NIL_THREAD(threadReadDHT11, arg); NIL_THREAD(threadReadSensors, arg); NIL_THREAD(threadReadBAC1000, arg); NIL_THREAD(threadDisplayOLED, arg); NIL_THREAD(threadSetBACTime, arg); //System strings const char sOn[] = "On"; const char sOff[] = "Off"; const char sTrue[] = "True"; const char sFalse[] = "False"; #endif |
01-03-16, 02:19 PM | #15 |
Apprentice EcoRenovator
Join Date: May 2011
Location: Tortosa, Spain
Posts: 221
Thanks: 2
Thanked 81 Times in 46 Posts
|
2. Main code file HeatpumpController.ino
/* ROCA heat pump pins: 1 - Live 2 - Neutral (Common) 3 - Earth 4 - Valve 5 - 6 - Fan HIGH 7 - Fan LOW 8 - Sensors: #1 - pipe sensor (bottom of evaporator) #5 - Environment */ #define DEBUG #include <DallasTemperature.h> #include <NilRTOS.h> #include <Arduino.h> #include <avr/wdt.h> #include <NilSerial.h> #include <NilAnalog.h> #include <Wire.h> #include "HeatpumpController.h" #include "BAC1000.h" // Macro to redefine Serial as NilSerial to save RAM. // Remove definition to use standard Arduino Serial. #define Serial NilSerial #define analogRead(pin) nilAnalogRead(pin) //#define delay(ms) nilThdSleep(ms) void setup(void) { byte data[1]; //Disable watchdog while setting up everything wdt_disable(); // Open serial communications Serial.begin(115200); setupEthernet(); // start the Ethernet connection and the server: readTime(); //Get the time from the DS1307 setupRS485(); //Setup RS485 (BAC1000) EEPROM_read_byte(DEFROSTTEMP, data); //Temperature to run defrost cycle defTemp = data[0] - DEFROST_OFFSET; if (defTemp > 10) { defTemp = 2; EEPROM_write_byte(DEFROSTTEMP, defTemp + DEFROST_OFFSET); } EEPROM_read_byte(DEFROSTTIME, data); //Defrost cycle time (minutes) defTime = data[0]; if (defTime > 10) { defTime = 2; EEPROM_write_byte(DEFROSTTIME, defTime); } EEPROM_read_byte(DEFROSTMAXTEMP, data); //Defrost Maximum temperature (temperature to stop defrost, overrides timer) defUpperTemp = data[0]; if (defUpperTemp > 20) { defUpperTemp = 10; EEPROM_write_byte(DEFROSTMAXTEMP, defUpperTemp); } EEPROM_read_byte(TIMEBETWEENDEFROST, data); //Minimum time between defrost cycles timeBetweenDefrost = data[0]; if ((timeBetweenDefrost > 60) || (timeBetweenDefrost < 15)) { timeBetweenDefrost = 30; EEPROM_write_byte(TIMEBETWEENDEFROST, timeBetweenDefrost); } EEPROM_read_byte(DESIREDROOMTEMP, data); //Desired room temperature desiredRoomTemp = data[0]; if ((desiredRoomTemp > 35) || (desiredRoomTemp < 10)) { desiredRoomTemp = 21; EEPROM_write_byte(DESIREDROOMTEMP, desiredRoomTemp); } EEPROM_read_byte(MAXWATERTEMP, data); //Max water temperature maxWaterTemp = data[0]; if ((maxWaterTemp > 35) || (maxWaterTemp < 10)) { maxWaterTemp = 21; EEPROM_write_byte(MAXWATERTEMP, maxWaterTemp); } EEPROM_read_byte(HYSTERISIS, data); //Hysterisis hysterisis = data[0]; if ((hysterisis > 15) || (hysterisis < 2)) { hysterisis = 5; EEPROM_write_byte(HYSTERISIS, hysterisis); } EEPROM_read_byte(LASTSYSTEMSTATE, data); //Last system state (on/off) operatingState = data[0]; //If the system was on then start the circulating pump before waiting for everything else if (operatingState == TRUE) { setRelay(PUMP, ON); } sendBAC1000Command(POWERONOFF, 0, 1, (operatingState << 4), 0, 0, 0); EEPROM_read_byte(LASTSYSTEMMODE, data); //Last system operating mode (heat/cool) operatingMode = data[0]; if (operatingMode > 1) { operatingMode = 1; EEPROM_write_byte(LASTSYSTEMMODE, operatingMode); } DEBUG_PRINTLN(F("STARTUP - STARTUP - STARTUP")); debugStateOutput(); DEBUG_PRINTLN(F("END STARTUP - END STARTUP")); //For testing defrost //defrostUpperTemperature = 40; //defrostFlag = TRUE; //Set BAC1000 time and then read its settings so we can synchronise operations sendBAC1000Command(SETTIME, 0, 1, tm.Second, tm.Minute, tm.Hour, 1); do { delay(2000); sendBAC1000Command(READALL, 0, 1, 0, 0, 0, 0); } while (BACRead == FALSE); //Set outputs to off before enabling pinMode so relays don't turn on at startup setRelay(PUMP, OFF); setRelay(VALVE, OFF); setRelay(FANLOW, OFF); setRelay(FANHIGH, OFF); setRelay(COMPRESSOR, OFF); pinMode(PUMP, OUTPUT); // sets the digital pin as output pinMode(VALVE, OUTPUT); // sets the digital pin as output pinMode(FANLOW, OUTPUT); // sets the digital pin as output pinMode(FANHIGH, OUTPUT); // sets the digital pin as output pinMode(COMPRESSOR, OUTPUT); // sets the digital pin as output wdt_enable(WDTO_8S); //Start watchdog timer - watchdog reset is in oled code as no delays nilSysBegin(); // Start Nil RTOS. rtosStarted = TRUE; //Flag the RTOS has started (needed for change from delay to nilDelay...) } void loop(void) { //int keyValue = 0; //keyValue = readKeys(); //if (keyValue == 1) { // lcd_page = lcd_page++ >= LCD_PAGES ? 0 : lcd_page; //Cycle the lcd page count //} } //Main running loop NIL_THREAD(threadMain, arg) { unsigned long lastCompressorRun; char buf[10]; while (TRUE) { debugStateOutput(); //See if the machine is on or off if ((operatingMode == HEAT)&&(operatingState == TRUE)) { //Operational modes for heating DEBUG_PRINTLN(F("Mode:HEAT, operatingState:ON")); if ((defrostFlag == FALSE)&&((flowTemp >= maxWaterTemp)||(bacRoomTemp >= desiredRoomTemp))) { //If we have achieved the target temperature then turn everything but the circulating pump off saveSystemState("Circulate"); setRelay(PUMP, ON); setRelay(VALVE, OFF); setRelay(FANLOW, OFF); setRelay(FANHIGH, OFF); setRelay(COMPRESSOR, OFF); machineRunningState = FALSE; } //Machine startup else if ((flowTemp <= maxWaterTemp - hysterisis)&&(machineRunningState == FALSE)){ //See if the compressor ran recently if so delay startup lastCompressorRun = EEPROM_readlong(LASTCOMPRUN); //DEBUG_PRINTST("Last run=%lu\n", lastCompressorRun); unsigned long currentTimeMs = makeTimeMilli(tm); //DEBUG_PRINTST("Current=%lu\n", currentTimeMs); setRelay(PUMP, ON); if ((lastCompressorRun + COMPSTARTDELAY) < currentTimeMs) { saveSystemState("Startup"); setRelay(FANLOW, ON); setRelay(FANHIGH, ON); setRelay(VALVE, ON); nilThdSleepSeconds(5); setRelay(COMPRESSOR, ON); machineRunningState = TRUE; } else { saveSystemState("Wait for startup"); } } //Check to see if we need to do a defrost. else if (tempEvaporator == defTemp) { if(millis() - lastDefrost >= timeBetweenDefrost) defrostFlag = TRUE; } else if (machineRunningState == TRUE) { saveSystemState("Running"); } } //Else if it is running turn everything off else if(operatingState == FALSE) { saveSystemState("Off"); setRelay(FANLOW, OFF); setRelay(FANHIGH, OFF); setRelay(COMPRESSOR, OFF); setRelay(VALVE, OFF); setRelay(PUMP, OFF); defrostFlag = FALSE; machineRunningState = FALSE; } //If the compressor is running save the current time for startup delay if (compStat == ON) { EEPROM_writelong(LASTCOMPRUN, makeTimeMilli(tm)); } // Sleep for 5S. nilThdSleepSeconds(5); } } //Debug out system status void debugStateOutput(void) { DEBUG_PRINTST("Operating mode=%s\n", mode[operatingMode]); DEBUG_PRINTST("operatingState=%s\n", operatingState == TRUE ? sTrue : sFalse); DEBUG_PRINTST("machineRunningState=%s\n", machineRunningState == TRUE ? sTrue : sFalse); DEBUG_PRINTST("flowTemp=%d\n", flowTemp); DEBUG_PRINTST("maxWaterTemp=%d\n", maxWaterTemp); DEBUG_PRINTST("bacRoomTemp=%d\n", bacRoomTemp); DEBUG_PRINTST("desiredRoomTemp=%d\n", desiredRoomTemp); } //Save string for system state and output the state on debugger void saveSystemState(char *state) { sprintf(systemState, state); DEBUG_PRINTLN(systemState); } // Turn on/off relays and preserve state flag void setRelay(int relay, bool state) { switch (relay) { case COMPRESSOR: if (compStat != state) { digitalWrite(COMPRESSOR, state); compStat = state; } break; case FANLOW: if (fanLow != state) { digitalWrite(FANLOW, state); fanLow = state; } break; case FANHIGH: if (fanHigh != state) { digitalWrite(FANHIGH, state); fanHigh = state; } break; case VALVE: if (valve != state) { digitalWrite(VALVE, state); valve = state; } break; case PUMP: //DEBUG_PRINTST("Pump = %d, set = %d\n", pump, state); if (pump != state) { digitalWrite(PUMP, state); pump = state; } break; } } //Thread to control derfost cycle NIL_THREAD(threadDefrost, arg) { while (TRUE) { const char defStepS[] = "Defrost step"; if (defrostFlag == TRUE) { sprintf(systemState, "%s 1", defStepS); DEBUG_PRINTLN(systemState); defStep = 1; defrostStartTime = millis(); setRelay(FANLOW, OFF); setRelay(FANHIGH, OFF); setRelay(COMPRESSOR, OFF); nilThdSleepSeconds(10); defStep = 2; sprintf(systemState, "%s 2", defStepS); setRelay(VALVE, OFF); nilThdSleepSeconds(10); defStep = 3; sprintf(systemState, "%s 3", defStepS); setRelay(COMPRESSOR, ON); while (defrostFlag == TRUE) { if (tempEvaporator >= defUpperTemp) defrostFlag = FALSE; //Cancel defrost if we have reached the programmed upper temperature defrostRunTime = millis() - defrostStartTime; if(defrostRunTime >= (defTime * 60000)) defrostFlag = FALSE; //Cancel defrost if we have reached the timeout for the defrost cycle nilThdSleepMilliseconds(500); } defStep = 4; sprintf(systemState, "%s 4", defStepS); setRelay(COMPRESSOR, OFF); nilThdSleepSeconds(10); defStep = 5; sprintf(systemState, "%s 5", defStepS); setRelay(FANHIGH, ON); nilThdSleepSeconds(5); defStep = 6; sprintf(systemState, "%s 6", defStepS); setRelay(VALVE, ON); nilThdSleepSeconds(10); setRelay(COMPRESSOR, ON); defStep = 0; defrostFlag = FALSE; lastDefrost = millis(); //Save the last defrost end time } // Sleep for 30S. nilThdSleepSeconds(30); } } |
01-03-16, 02:20 PM | #16 |
Apprentice EcoRenovator
Join Date: May 2011
Location: Tortosa, Spain
Posts: 221
Thanks: 2
Thanked 81 Times in 46 Posts
|
Last part of HeatpumpController.ino
// Declare stacks for threads
NIL_WORKING_AREA(waThreadMain, 1024); NIL_WORKING_AREA(waThreadEth, 1024); NIL_WORKING_AREA(waThreadDS18B20, 128); NIL_WORKING_AREA(waThreadBAC, 256); NIL_WORKING_AREA(waThreadDHT11, 128); NIL_WORKING_AREA(waThreadOLED, 128); NIL_WORKING_AREA(waThreadDefrost, 32); NIL_WORKING_AREA(waThreadNTC, 64);//128 NIL_WORKING_AREA(waThreadSetBACTime, 256); /* * Threads static table, one entry per thread. A thread's priority is determined by its position in the table with highest priority first. * These threads start with a null argument. A thread's name may also be null to save RAM since the name is currently not used. */ NIL_THREADS_TABLE_BEGIN() NIL_THREADS_TABLE_ENTRY("", threadEthernet, NULL, waThreadEth, sizeof(waThreadEth)) NIL_THREADS_TABLE_ENTRY("", threadMain, NULL, waThreadMain, sizeof(waThreadMain)) NIL_THREADS_TABLE_ENTRY("", threadDisplayOLED, NULL, waThreadOLED, sizeof(waThreadOLED)) NIL_THREADS_TABLE_ENTRY("", threadReadBAC1000, NULL, waThreadBAC, sizeof(waThreadBAC)) NIL_THREADS_TABLE_ENTRY("", threadReadSensors, NULL, waThreadDS18B20, sizeof(waThreadDS18B20)) NIL_THREADS_TABLE_ENTRY("", threadReadDHT11, NULL, waThreadDHT11, sizeof(waThreadDHT11)) NIL_THREADS_TABLE_ENTRY("", threadDefrost, NULL, waThreadDefrost, sizeof(waThreadDefrost)) NIL_THREADS_TABLE_ENTRY("", threadReadNTC, NULL, waThreadNTC, sizeof(waThreadNTC)) NIL_THREADS_TABLE_ENTRY("", threadSetBACTime, NULL, waThreadSetBACTime, sizeof(waThreadSetBACTime)) NIL_THREADS_TABLE_END() //Format and output string to serial debug port void SerialPrint2(char *format, ...) { char buff[128]; va_list args; va_start(args, format); vsnprintf(buff, sizeof(buff), format, args); va_end(args); buff[sizeof(buff) / sizeof(buff[0]) - 1] = '\0'; Serial.print(buff); } |
01-03-16, 02:21 PM | #17 |
Apprentice EcoRenovator
Join Date: May 2011
Location: Tortosa, Spain
Posts: 221
Thanks: 2
Thanked 81 Times in 46 Posts
|
3. 24C34EEPROM.ino
#define AT24C32_I2C_ADDRESS 0x50 // the I2C address of Tiny RTC AT24C32 EEPROM void EEPROM_write_byte(unsigned int uiAddress, byte bData) { int iCount = 0; do { Wire.beginTransmission(AT24C32_I2C_ADDRESS); Wire.write((byte)(uiAddress >> 8)); // MSB Wire.write((byte)uiAddress); // LSB Wire.write(bData); } while (Wire.endTransmission() != 0 && ++iCount<10); } void EEPROM_read_byte(unsigned int uiAddress, byte *pbData) { int iCount = 0; do { Wire.beginTransmission(AT24C32_I2C_ADDRESS); Wire.write((byte)(uiAddress >> 8)); // MSB Wire.write((byte)uiAddress); // LSB } while (Wire.endTransmission() != 0 && ++iCount<10); Wire.requestFrom(AT24C32_I2C_ADDRESS, 1); *pbData = Wire.read(); } ////////////////////////////////////////////////////////////////////////////////////// // read long from EEPROM, give starting address unsigned long EEPROM_readlong(int address) { byte data[1]; unsigned long dword = 0; EEPROM_read_byte(address, data); dword = data[0]; dword = dword << 8; EEPROM_read_byte(address+1, data); dword = dword + data[0]; dword = dword << 8; EEPROM_read_byte(address+2, data); dword = dword + data[0]; dword = dword << 8; EEPROM_read_byte(address+3, data); dword = dword + data[0]; return dword; } void EEPROM_writelong(int address, unsigned long dword) { byte data; data = dword & 0xff; EEPROM_write_byte(address + 3, data); dword = dword >> 8; data = dword & 0xff; delay(100); EEPROM_write_byte(address + 2, data); dword = dword >> 8; data = dword & 0xff; delay(100); EEPROM_write_byte(address + 1, data); dword = dword >> 8; data = dword & 0xff; delay(100); EEPROM_write_byte(address, data); } |
01-03-16, 02:22 PM | #18 |
Apprentice EcoRenovator
Join Date: May 2011
Location: Tortosa, Spain
Posts: 221
Thanks: 2
Thanked 81 Times in 46 Posts
|
4. BAC1000.h - header file for BAC1000 thermometer
#pragma once #ifndef _BAC1000_h #define _BAC1000_h //RS485 settings #define RS485TxControl 10 //RS485 Direction control #define RS485Transmit HIGH #define RS485Receive LOW #define RS485Serial Serial1 //Commands #define READALL 0xa0 //Read all data from thermostat #define TRANSMITALL 0xa1 //Send all data to thermostat #define POWERONOFF 0xa2 //Power on/off #define FANSPEED 0x03 //Control fan speed relays #define MODESETTING 0xa4 //Mode setting #define KEYLOCK 0xa5 //Lock/unlock keypad #define TEMPSETTING 0xa6 //Set desired temperature #define TEMPCALIB 0xa7 //Temperature calibration #define SETTIME 0xa8 //Set thermostat clock #define AUTOMANUAL 0xa9 //Manual/auto programmable #define DATAACK 0x50 //Command accepted ok //Masks for status #define UNITONOFF 0x10 //Unit on - 1, off - 0 #define HEATCOOL 0x60 //Operation mode - 00 - Cooling, 01 - Heating, 10 - Ventilation #define FANS 0x03 //Fan speed - 00 - Auto, 01 - High, 10 - Medium, 11 - Low #define POWERON 0x10 //Power unit on, power off with 00 int bacRoomTemp; int bacSetTemp; bool powerStateBAC; int operatingModeBAC; const char* mode[] = { "Cool", "Heat", "Ventilate" }; bool BACRead = FALSE; bool waitRead = FALSE; bool sendBAC1000Command(int bacCmd, int idl, int idh, int data1, int data2, int data3, int data4); #endif |
01-03-16, 02:23 PM | #19 |
Apprentice EcoRenovator
Join Date: May 2011
Location: Tortosa, Spain
Posts: 221
Thanks: 2
Thanked 81 Times in 46 Posts
|
5. BAC1000.ino
#include <Wire.h> //For BAC1000 thermometer #include "BAC1000.h" NIL_THREAD(threadReadBAC1000, arg) { while (TRUE) { { sendBAC1000Command(READALL, 0, 1, 0, 0, 0, 0); // Sleep for 30 seconds. nilThdSleepSeconds(30); } } } //Reset BAC time every hour NIL_THREAD(threadSetBACTime, arg) { while (TRUE) { { DEBUG_PRINTLN("Set BAC Time"); sendBAC1000Command(SETTIME, 0, 1, tm.Second, tm.Minute, tm.Hour, 1); // Sleep for 1 hour nilThdSleepSeconds(3600); } } } void setupRS485(void) { //Setup for RS485 pinMode(RS485TxControl, OUTPUT); digitalWrite(RS485TxControl, RS485Receive); // Init Transceiver RS485Serial.begin(2540); // set the data rate } //Send command to BAC1000. Retry 5 times // Command, Device ID low, ID high, Data(4) bool sendBAC1000Command(int bacCmd, int idl, int idh, int data1, int data2, int data3, int data4) { int retryCount = 0; bool result; //Wait for current read to end before trying to read again do{ if (rtosStarted == TRUE) nilThdSleepSeconds(2); else delay(2000); }while (waitRead == TRUE); waitRead = TRUE; for (retryCount = 0; retryCount < 2; retryCount++) { result = sendBAC1000Cmd(bacCmd, idl, idh, data1, data2, data3, data4); if (result == FALSE) { DEBUG_PRINTLN("BAC command fail"); if (rtosStarted == TRUE) nilThdSleepSeconds(5); else delay(5000); } else { DEBUG_PRINTLN("BAC read ok"); break; } } waitRead = FALSE; return result; } bool sendBAC1000Cmd(int bacCmd, int idl, int idh, int data1, int data2, int data3, int data4) { int byteReceived; int byteSend; int i = 0; char checksum; char frameRX[8]; char frameTX[7] = { bacCmd, idl, idh, data1, data2, data3, data4 }; //char frame[7] = { 0xA8, 0, 1, 0, 0x0, 9, 1 }; DEBUG_PRINTLN("Send BAC command frame"); digitalWrite(RS485TxControl, RS485Transmit); // Enable RS485 Transmit for (int i = 0; i < 7; i++) { RS485Serial.write(frameTX[i]); // Send bytes to thermostat } RS485Serial.write(bac1000Checksum(frameTX)); // Send byte to Remote RS485Serial.flush(); //Wait for end of send before disabling RS485 digitalWrite(RS485TxControl, RS485Receive); // Disable RS485 Transmit while (RS485Serial.available()) //Look for data { byteReceived = RS485Serial.read(); // Read received byte frameRX[i] = byteReceived; i++; //Serial.print(byteReceived); // Show on Serial Monitor //Serial.print(" "); } if (frameRX[0] == DATAACK) { //Data received ok switch (bacCmd) { case READALL: char buf[20]; char checksum1; checksum = frameRX[7]; frameRX[7] = '\0'; checksum1 = bac1000Checksum(frameRX); if (checksum1 != checksum) { //sprintf(buf, " Frame=%x %x %x %x %x %x %x %x", frameRX[0], frameRX[1], frameRX[2], frameRX[3], frameRX[4], frameRX[5], frameRX[6], frameRX[7]); //Serial.println(buf); //sprintf(buf, " o=%x n=%x", checksum, checksum1); DEBUG_PRINTLN("BAC CS Failure"); //Serial.println(buf); return FALSE; } bacRoomTemp = frameRX[6]; bacSetTemp = frameRX[5] / 2; desiredRoomTemp = bacSetTemp; //Read and update BAC power state if necessary powerStateBAC = frameRX[3] & UNITONOFF; if(operatingState != powerStateBAC){ operatingState = powerStateBAC; EEPROM_write_byte(LASTSYSTEMSTATE, operatingState); } //Read and update operating mode if necessary operatingModeBAC = (frameRX[3] & HEATCOOL) >> 5; if (operatingMode != operatingModeBAC) { operatingMode = operatingModeBAC; EEPROM_write_byte(LASTSYSTEMMODE, operatingMode); } BACRead = TRUE; //Flag the BAC has been successfully read //char buf[20]; //sprintf(buf, "Room temp: %d", frameRX[6]); //Serial.println(buf); //sprintf(buf, "Set temp: %d", frameRX[5] / 2); //Serial.println(buf); //sprintf(buf, "Thermometer power: %s", powerStateBAC == 0 ? "Off" : "On"); //Serial.println(buf); //sprintf(buf, "Mode: %s", mode[operatingModeBAC]); //Serial.println(buf); break; } return TRUE; } else { return FALSE; } } //CheckSum = (COMMAND + ID0 + ID1 + Data0 + Data1 + Data2 + Data3) & 0xFF ^ 0xA5; unsigned char bac1000Checksum(char *ptr) { unsigned char chk = 0; for (int i = 0; i < 7; i++) { chk += ptr[i]; } chk = chk & 0xff; chk = chk ^ 0xa5; return chk; } |
01-03-16, 02:24 PM | #20 |
Apprentice EcoRenovator
Join Date: May 2011
Location: Tortosa, Spain
Posts: 221
Thanks: 2
Thanked 81 Times in 46 Posts
|
6. DHT11.ino
#include <dht.h> #include <math.h> dht DHT11; NIL_THREAD(threadReadDHT11, arg) { while (TRUE) { int chk = DHT11.read11(DHT11PIN); //Serial.print("Read sensor: "); switch (chk) { case DHTLIB_OK: humidity = (float)DHT11.humidity; dht11Temperature = (float)DHT11.temperature; dewPointTemp = dewPoint(DHT11.temperature, DHT11.humidity); break; case DHTLIB_ERROR_CHECKSUM: Serial.println("DHT11 Checksum error"); break; case DHTLIB_ERROR_TIMEOUT: Serial.println("DHT11 Time out error"); break; default: Serial.println("DHT11 Unknown error"); break; } //Serial.print("Humidity (%): "); //Serial.println(humidity, 2); //Serial.print("Temperature (°C): "); //Serial.println(dht11Temperature, 2); //Serial.print("Dew Point (°C): "); //Serial.println(dewPointTemp); // Sleep for 10 seconds. nilThdSleepSeconds(10); } } // dewPoint function NOAA // reference (1) : Algorithms - Schlatter and Baker // reference (2) : About the Weather Station // double dewPoint(double celsius, double humidity) { // (1) Saturation Vapor Pressure = ESGG(T) double RATIO = 373.15 / (273.15 + celsius); double RHS = -7.90298 * (RATIO - 1); RHS += 5.02808 * log10(RATIO); RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1 / RATIO))) - 1); RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1); RHS += log10(1013.246); // factor -3 is to adjust units - Vapor Pressure SVP * humidity double VP = pow(10, RHS - 3) * humidity; // (2) DEWPOINT = F(Vapor Pressure) double T = log(VP / 0.61078); // temp var return (241.88 * T) / (17.558 - T); } |
|
|