// VERSION 3 #include #include #include #include #define pinInpT 2 #define pinInpACOK 3 #define pinInpBatLow 4 #define pinInpAux 5 #define pinOutLedBat 6 #define pinOutLedPlc 7 #define pinOutBeep 8 #define pinOutBatCtrl 9 #define pinOutAcCtrl 10 #define pinOutAux 11 #define pinOutLedRun LED_BUILTIN #define VERSION 3 #define REQUEST_LEN 15 #define REQUEST_TIMEOUT 100 #define DEFAULT_TIMEOUT_SERIAL 10 #define DEFAULT_TIMEOUT_BATCTRL 5 #define ADDR_SERIAL_CONNECTED 0 #define ADDR_BAT_CTRL 2 #define ADDR_BEEP_MODE 8 OneWire oneWire(pinInpT); DallasTemperature dallasTemp(&oneWire); int T; boolean outBeep; boolean outBatCtrl; boolean outAcCtrl; boolean outAux; boolean outLedBat; boolean outLedPlc; boolean manual_BatCtrl; int beep_mode; int timeBatCtrl; int cntBatCtrl; int cntLedPlc; long ms; int cnt5000ms; int cnt1000ms; int cnt200ms; boolean serConnected; int timeoutSerialConnected; long serms; int sercnt; uint8_t serbuf[REQUEST_LEN]; boolean plcHasBeenDetected; int lastACOKSentToPlc; void setup() { pinMode(pinInpACOK, INPUT); pinMode(pinInpBatLow, INPUT); pinMode(pinInpAux, INPUT); pinMode(pinOutLedBat, OUTPUT); pinMode(pinOutLedPlc, OUTPUT); pinMode(pinOutBeep, OUTPUT); pinMode(pinOutBatCtrl, OUTPUT); pinMode(pinOutAcCtrl, OUTPUT); pinMode(pinOutAux, OUTPUT); pinMode(pinOutLedRun, OUTPUT); Serial.begin(9600); dallasTemp.begin(); dallasTemp.setWaitForConversion(false); dallasTemp.requestTemperatures(); manual_BatCtrl = false; cnt5000ms = 0; cnt1000ms = 0; cnt200ms = 0; cntLedPlc = 0; cntBatCtrl = 0; plcHasBeenDetected = false; lastACOKSentToPlc = 0; sercnt = 0; serConnected = false; ms = millis(); EEPROM.get(ADDR_SERIAL_CONNECTED, timeoutSerialConnected); EEPROM.get(ADDR_BAT_CTRL, timeBatCtrl); EEPROM.get(ADDR_BEEP_MODE, beep_mode); outAux = 0; digitalWrite(pinOutAux, outAux); validate_vars(); greeting(); } void greeting() { Serial.print("UPS NANO version "); Serial.println(VERSION); Serial.print("SerTimeout = "); Serial.println(timeoutSerialConnected); Serial.print("BatCtrlTimeout = "); Serial.println(timeBatCtrl); } void validate_vars() { if(timeBatCtrl <= 0) timeBatCtrl = 1; if(timeoutSerialConnected <= 0) timeoutSerialConnected = 1; if(beep_mode < 0 || beep_mode > 2) beep_mode = 0; } void loop() { long msdelta = millis() - ms; if( msdelta >= 100 ) { ms += 100; loop100ms(); } else if( msdelta < 0 ) { msdelta += 0x80000000L; if( msdelta >= 100 ) { ms += 100 + 0x80000000L; loop100ms(); } } if( Serial ) { if( Serial.available() == 0 ) { msdelta = millis() - serms; if( msdelta < 0 ) msdelta += 0x80000000L; if( sercnt > 0 && msdelta > REQUEST_TIMEOUT ) { sercnt = 0; serConnected = false; } if( serConnected && (msdelta/1000) >= timeoutSerialConnected ) { serConnected = false; } } else { while( Serial.available() > 0 ) { serbuf[sercnt++] = Serial.read(); if( sercnt == REQUEST_LEN ) { onSerRequest(); sercnt = 0; } } serms = millis(); } } } void loop100ms() { if( cnt5000ms++ >= 50 ) { cnt5000ms = 0; loop5000ms(); } if( cnt1000ms++ >= 10 ) { cnt1000ms = 0; loop1000ms(); } if( cnt200ms++ >= 2 ) { cnt200ms = 0; loop200ms(); } // led plc if( !serConnected ) { if( cntLedPlc++ < 10 ) outLedPlc = cntLedPlc % 2; else if( cntLedPlc >= 30 ) { outLedPlc = false; cntLedPlc = 0; } } else cntLedPlc = 0; digitalWrite(pinOutLedPlc, !outLedPlc); digitalWrite(pinOutLedRun, !outLedPlc); digitalWrite(pinOutLedBat, outLedBat); } void loop200ms() { // led bat if( !digitalRead(pinInpACOK) ) { if( (digitalRead(pinInpBatLow)) == HIGH ) outLedBat = !outLedBat; else outLedBat = HIGH; } else outLedBat = LOW; } void loop1000ms() { if( serConnected ) outLedPlc = !outLedPlc; // bat control if( !manual_BatCtrl ) { outBatCtrl = 1; if( timeBatCtrl > 0 && !serConnected ) { if( !digitalRead(pinInpACOK) ) { if( cntBatCtrl >= timeBatCtrl ) { outBatCtrl = 0; } else cntBatCtrl++; } else cntBatCtrl = 0; } } digitalWrite(pinOutBatCtrl, outBatCtrl); // beep if( !digitalRead(pinInpACOK) ) { if( outBeep = !outBeep ) // second arg: // 1200 - normal tone // 40 - debug tone (very low) if( beep_mode == 0 ) tone(pinOutBeep, 1200, 1000); else if( beep_mode == 1 ) tone(pinOutBeep, 40, 1000); else noTone(pinOutBeep); } // acctrl outAcCtrl = !serConnected && plcHasBeenDetected && (lastACOKSentToPlc == 0); digitalWrite(pinOutAcCtrl, outAcCtrl); // temperature int t = (int)round(dallasTemp.getTempCByIndex(0) * 10); dallasTemp.requestTemperatures(); if( t > -500 && t < 1200 ) T = t; } void loop5000ms() { } void onSerRequest() { serConnected = false; uint32_t cs1 = CRC32::calculate(serbuf, REQUEST_LEN-4); uint32_t cs2 = (((uint32_t)serbuf[REQUEST_LEN-4])<<24) + (((uint32_t)serbuf[REQUEST_LEN-3])<<16) + (((uint32_t)serbuf[REQUEST_LEN-2])<<8) + (uint32_t)serbuf[REQUEST_LEN-1]; if( cs1 != cs2 ) { return; } if( serbuf[0] != VERSION ) { sendErrorVersion(); return; } getSerbufValues(); sendGoodAnswer(); serConnected = true; plcHasBeenDetected = true; } void sendGoodAnswer() { lastACOKSentToPlc = digitalRead(pinInpACOK); serbuf[0] = 0; serbuf[1] = lastACOKSentToPlc + (digitalRead(pinInpBatLow))*2 + (digitalRead(pinInpAux))*4; serbuf[2] = (T >> 8) & 0xFF; serbuf[3] = T & 0xFF; addSerbufCrc(4); Serial.write(serbuf, 8); } void sendErrorVersion() { serbuf[0] = 0xFF; serbuf[1] = VERSION; serbuf[2] = serbuf[3] = 0; addSerbufCrc(4); Serial.write(serbuf, 8); } void addSerbufCrc(int len) { uint32_t cs = CRC32::calculate(serbuf, len); serbuf[len++] = cs >> 24; serbuf[len++] = (cs %= 0x1000000) >> 16; serbuf[len++] = (cs %= 0x10000) >> 8; serbuf[len++] = cs %= 0x100; } void getSerbufValues() { timeBatCtrl = (serbuf[1] << 8) + serbuf[2]; timeoutSerialConnected = (serbuf[3] << 8) + serbuf[4]; if( outAux != serbuf[9] ) { outAux = serbuf[9]; digitalWrite(pinOutAux, outAux); } beep_mode = (serbuf[10] >> 4) & 0xF; validate_vars(); EEPROM.put(ADDR_SERIAL_CONNECTED, timeoutSerialConnected); EEPROM.put(ADDR_BAT_CTRL, timeBatCtrl); EEPROM.put(ADDR_BEEP_MODE, beep_mode); }