Here, try this code (I changed yours a little to just change Serial) with an external adapter connected to RX0, debugging will be much easier
Code: Select all
#include "SPI.h"
#include "Wire.h"
#include "ZUNO_OneWire.h"
#define SPI_CS 8
SPISettings spi_settings = SPISettings(8000000, MSBFIRST, SPI_MODE0);
#define oneWirePin 12
// MAX31820 uses default 12 bit for 0.05 °C resolution, requires > 750ms conversion time
OneWire oneWire(oneWirePin);
uint8_t MAX31820addr[8][4]; //2-d array for 4 MAX31820 ROM addresses
uint16_t RTCaddress = 0xA2; //PCF85263A I2C target write address; read target address is 0xA3
//ZUNO_SETUP_CHANNELS(ZUNO_SENSOR_BINARY())
ZUNO_SETUP_ISR_INT0(ofenSetError);
ZUNO_SETUP_ISR_INT1(RTCseconds);
#define FET1 16
#define FET2 15
#define FET3 14
#define FET4 3
#define INT_RTC 18
#define INT_OFEN 17
#define INT_LFTG 19
#define LED_OFEN 21
#define LED_LFTG 20
#define MY_SERIAL Serial0
//variables
float v_resistorLadder = 4.7; //Spannung der Resistor Ladder Op-Amp
uint8_t ofenDefault = 7; //Standardheizleistung Ofen in kW
uint8_t lueftungDefault = 2; //Standardstufe Lüftung
uint8_t ofenHeizleistung = ofenDefault; //Aktuelle Heizleistung Ofen in kW
uint8_t lueftungStufe = lueftungDefault; //Aktuelle Stufe Lüftung
float tempAussen;
float tempZuluft;
float tempFortluft;
float tempAbluft;
//bypass settings
float tMax = 20; //default 24
float tMin = 13; //default 13
uint8_t incrementLueftung = 0;
uint8_t incrementOfen = 0;
uint8_t retryCounter = 0;
uint8_t deviceCount = 0; //number of discovered OneWire-Devices on the bus
uint16_t borDetectionInterval = 300; //seconds between Brownout-Checks
uint16_t temperaturePollingIntervall = 300;
uint16_t RTCintCounter = 0; //counter variable for periodic (1s) RTC interrupts, reset after 300s
boolean FET1_on = false; //Koppelrelais Ofen
boolean FET2_on = true; //Koppelrelais Lüftung
boolean FET3_on = false;
boolean FET4_on = true;
boolean ofenOn = false;
boolean lueftungOn = true;
boolean ofenError = false; //Störmeldung Ofen D1
boolean lueftungError = false; //Störmeldung Lüftung D2
boolean lueftungBypassOffen = false;
boolean RTCalarm1 = false; //mm:dd:hh:mm:ss
boolean RTCalarm2 = false; //hh:mm and weekday
//void DACpowerState(int channel = 0, char* state = "off"); (SDCC compiler error, optional args werden nicht kompiliert?)
//void lueftungSetState(char* state, int duration = 0);
void RTCseconds() {
RTCintCounter++;
}
void ofenSetError() {
ofenError = true;
digitalWrite(LED_OFEN, LOW);
}
uint8_t newAddr[8];
void setup() {
MY_SERIAL.begin(115200);
SPI.begin();
pinMode(SPI_CS, OUTPUT);
digitalWrite(SPI_CS, HIGH);
delay(1);
Wire.begin();
//Wire.setWireTimeout(3000, true); //abort transmission after 3000 us and reset communication module
zunoExtIntMode(ZUNO_EXT_INT0, RISING);
zunoExtIntMode(ZUNO_EXT_INT1, RISING);
// set up inputs
pinMode(INT_LFTG, INPUT);
pinMode(INT_OFEN, INPUT);
pinMode(INT_RTC, INPUT);
// set up outputs
pinMode(FET1, OUTPUT);
pinMode(FET2, OUTPUT);
pinMode(FET3, OUTPUT);
pinMode(FET4, OUTPUT);
pinMode(LED_LFTG, OUTPUT);
pinMode(LED_OFEN, OUTPUT);
digitalWrite(FET1, LOW);
digitalWrite(FET2, LOW);
digitalWrite(FET3, LOW);
digitalWrite(FET4, LOW);
digitalWrite(LED_LFTG, LOW);
digitalWrite(LED_OFEN, LOW);
delay(1000);
MY_SERIAL.println("Opened serial connection.");
//Set up DAC registers
DACinit();
//Set up RTC registers
RTCinit();
MY_SERIAL.println("Probing OneWire bus...");
oneWire.reset_search();
deviceCount = 0;
while (oneWire.search(newAddr)) {
deviceCount++;
MY_SERIAL.print("New device found:");
for (int i = 0; i < 8; i++) {
MAX31820addr[deviceCount][i] = newAddr[i];
MY_SERIAL.print(newAddr[i], HEX);
MY_SERIAL.print(" ");
}
MY_SERIAL.println();
}
MY_SERIAL.println("No more devices found.");
}
void loop() {
//testing
MY_SERIAL.println("LOOP>>>");
if (incrementOfen > 13) incrementOfen = 0;
if (incrementLueftung > 3) incrementLueftung = 0;
if (RTCintCounter == 20) {
DACsetVoltage(1, ofenCalcVoltage(ofenHeizleistung));
DACsetVoltage(2, lueftungCalcVoltage(ofenHeizleistung));
ofenHeizleistung = incrementOfen;
lueftungStufe = incrementLueftung;
}
//end testing
if (RTCintCounter == 60) {
MY_SERIAL.println("60s elapsed.");
delay(16); //maximum time for periodic interrupt flag clearance is 2* 1/128 = 16 ms
RTCgetFlags();
}
if (RTCintCounter == 300) {
MY_SERIAL.println("300s elapsed.");
RTCintCounter = 0;
MAX31820getAllTemperatures();
DACborDetection();
}
}
void DACinit() {
MY_SERIAL.println("Initializing DAC...");
DACread(0x0A); //clear POR Bit by reading status register
DACwrite(0x0A, 0x03, 0x00); //set gain B9:B8 of 1x for both channels
DACwrite(0x08, 0x00, 0x00); //set VREF to VDD for both channels
DACsetVoltage(1, ofenCalcVoltage(ofenHeizleistung));
DACsetVoltage(2, lueftungCalcVoltage(lueftungStufe));
if (ofenOn) ofenSetState("on");
if (!ofenOn) ofenSetState("off");
if (lueftungOn) lueftungSetState("on");
if (!lueftungOn) lueftungSetState("off");
MY_SERIAL.println("Done initzializing DAC.");
}
void DACborDetection() {
MY_SERIAL.print("Checking for BOR-related memory corruption on DAC...");
word borWord = DACread(0x0A);
boolean borBitSet = bitRead(borWord, 8);
if (borBitSet == true) {
MY_SERIAL.println("FAILED! Reinitizialing DAC.");
DACinit(); //reinitialize DAC with current values
} else {
MY_SERIAL.println("PASS.");
}
}
void DACsetVoltage(int channel = 0, float voltage = 0) { //writes register 0x00 or 0x01 respectively
MY_SERIAL.print("Setting wiper value of ");
if (voltage > 2 * v_resistorLadder) voltage = 2 * v_resistorLadder;
if (voltage < 0) voltage = 0;
byte wiperPosition = (int)(((voltage / 2) / v_resistorLadder) * 256);
MY_SERIAL.print(wiperPosition);
if (channel == 1) {
MY_SERIAL.println(" for oven...");
DACwrite(0x00, 0x00, wiperPosition);
}
if (channel == 2) {
MY_SERIAL.println(" for lueftung...");
DACwrite(0x01, 0x00, wiperPosition);
}
//confirm correct output voltage is set in DAC register
}
void DACpowerState(int channel = 0, char *state = "off") { //writes register 0x09, if channel 0 is used, both channels are switched
if (channel == 0) {
if (!strcmp(state, "on")) {
DACwrite(0x09, 0x00, 0x00);
ofenOn = true;
lueftungOn = true;
}
if (!strcmp(state, "off")) {
DACwrite(0x09, 0x00, 0x03);
ofenOn = false;
lueftungOn = false;
}
} else if (channel == 1) {
if (!strcmp(state, "on")) {
byte cmd = 0x00;
bitWrite(cmd, 1, lueftungOn);
DACwrite(0x09, 0x00, cmd);
ofenOn = true;
}
if (!strcmp(state, "off")) {
byte cmd = 0x01;
bitWrite(cmd, 1, lueftungOn);
DACwrite(0x09, 0x00, cmd);
ofenOn = false;
}
} else if (channel == 2) {
if (!strcmp(state, "on")) {
byte cmd = 0x00;
bitWrite(cmd, 0, ofenOn);
DACwrite(0x09, 0x00, cmd);
lueftungOn = true;
}
if (!strcmp(state, "off")) {
byte cmd = 0x02;
bitWrite(cmd, 0, ofenOn);
DACwrite(0x09, 0x00, cmd);
lueftungOn = false;
}
}
}
void DACwrite(byte writeAddr, byte data2, byte data1) {
if (retryCounter < 3) {
MY_SERIAL.print("Writing ");
MY_SERIAL.print(data2, HEX);
MY_SERIAL.print(data1, HEX);
MY_SERIAL.print(" at DAC address ");
MY_SERIAL.print(writeAddr, HEX);
MY_SERIAL.print(" ...");
byte cmdReturn;
writeAddr = writeAddr << 3;
byte cmdByte = writeAddr; // 00 write 0 error bit, so nothing has to be added
SPI.beginTransaction(&spi_settings);
digitalWrite(SPI_CS, LOW);
delay(1);
SPI.transfer(cmdByte);
cmdReturn = SPI.transfer(data2);
SPI.transfer(data1);
delay(1);
digitalWrite(SPI_CS, HIGH);
SPI.endTransaction();
if (cmdReturn != 0xFF) {
retryCounter++;
MY_SERIAL.println("FAILED! Retrying.");
DACwrite(writeAddr, data2, data1);
} else
retryCounter = 0;
MY_SERIAL.println("Done.");
} else {
MY_SERIAL.println("FAILED 3 times. Abort.");
retryCounter = 0;
}
}
word DACread(byte readAddr) {
if (retryCounter < 3) {
MY_SERIAL.print("Reading 1 byte at DAC address ");
MY_SERIAL.print(readAddr, HEX);
MY_SERIAL.print(" ...");
byte cmdReturn;
readAddr = readAddr << 3;
byte cmdByte = readAddr + 6;
SPI.beginTransaction(&spi_settings);
digitalWrite(SPI_CS, LOW);
delay(1);
SPI.transfer(cmdByte);
cmdReturn = SPI.transfer(0);
word DACreply = SPI.transfer16(0);
delay(1);
digitalWrite(SPI_CS, HIGH);
SPI.endTransaction();
MY_SERIAL.print("DAC returned ");
MY_SERIAL.println(cmdReturn, HEX);
if (cmdReturn != 0xFF) {
retryCounter++;
DACread(readAddr);
} else {
retryCounter = 0;
MY_SERIAL.println("Done.");
return DACreply;
}
} else {
word error = 0;
MY_SERIAL.println("FAILED 3 times. Abort.");
return error;
}
}
float ofenCalcVoltage(uint8_t leistung) { //geforderte Leistung zwischen 3 und 13 kW
MY_SERIAL.print("Calculating analog value for ");
MY_SERIAL.print(leistung);
MY_SERIAL.println("kW thermal power...");
if (leistung < 3) leistung = 3;
if (leistung > 13) leistung = 13;
ofenHeizleistung = leistung; //bad programming (eventuell unterscheiden sich dann Zustand und simulierte Variable, wenn der write-Befehl dreimal scheitert)
float voltage = ((13 - 3) / 10) * (leistung - 3);
MY_SERIAL.print(voltage);
MY_SERIAL.println("V");
return voltage;
}
float voltage[3] = { 3, 6, 9 };
float lueftungCalcVoltage(uint8_t stufe) { //LUT-artig für Lüftungsstufen
MY_SERIAL.print("Calculating analog value for fan level");
MY_SERIAL.print(stufe);
MY_SERIAL.println("...");
if (stufe < 1) lueftungSetState("off");
if (stufe > 3) stufe = 3;
lueftungStufe = stufe; //bad programming (eventuell unterscheiden sich dann Zustand und simulierte Variable, wenn der write-Befehl dreimal scheitert)
MY_SERIAL.print(voltage[stufe - 1]);
MY_SERIAL.println("V");
return voltage[stufe - 1];
}
void ofenSetState(char *state) {
if (!strcmp(state, "on")) {
MY_SERIAL.println("Setting ofen state to on...");
digitalWrite(FET1, HIGH);
FET1_on = true;
DACpowerState(1, "on");
DACsetVoltage(1, ofenCalcVoltage(ofenHeizleistung)); //Ofen schaltet auf letztem bekannten Wert ein
ofenOn = true;
MY_SERIAL.println("Ofen state set to on.");
}
if (!strcmp(state, "off")) {
MY_SERIAL.println("Setting ofen state to off...");
digitalWrite(FET1, LOW);
FET1_on = false;
DACpowerState(1, "off");
ofenOn = false;
MY_SERIAL.println("Ofen state set to off.");
}
}
void lueftungSetState(char *state) { //argument duration missing
if (!strcmp(state, "on")) {
MY_SERIAL.println("Setting lueftung state to on...");
digitalWrite(FET2, HIGH);
FET2_on = true;
DACpowerState(2, "on");
DACsetVoltage(2, lueftungCalcVoltage(lueftungStufe)); //Lueftung schaltet auf letztem bekannten Wert ein
lueftungOn = true;
MY_SERIAL.println("Lueftung state set to on.");
}
if (!strcmp(state, "off")) {
MY_SERIAL.println("Setting lueftung state to off...");
digitalWrite(FET2, LOW);
FET2_on = false;
DACpowerState(2, "off");
lueftungOn = false;
MY_SERIAL.println("Lueftung state set to off.");
}
}
void MAX31820getAllTemperatures() {
MY_SERIAL.println("Getting temperature data from all known MAX31820 sensors...");
oneWire.reset();
oneWire.skip(); //simulataneously start temperature conversion on all devices
oneWire.write(0x44);
delay(1000); //wait 1000 ms, because read time slot allocation is not possible in multi-slaves queries
for (int i = 0; i < deviceCount; i++) {
uint8_t rom[8];
for (int j = 0; i < 8; i++) {
rom[j] = MAX31820addr[i][j];
}
oneWire.reset();
oneWire.select(rom);
oneWire.write(0xBE); //read scratchpad register
byte scratchpad[9]; //9 bit scratchpad
for (int i = 0; i < 9; i++) {
scratchpad[i] = oneWire.read();
}
if (oneWire.crc8(scratchpad, 8) == rom[7]) {
MY_SERIAL.println("CRC match for ROM ");
for (int i = 0; i < 8; i++) {
MY_SERIAL.println(rom[i]);
}
int16_t raw = (scratchpad[1] << 8) | scratchpad[0];
if (bitRead(raw, 15)) {
raw = (raw ^ 0xFFFF) - 0x01; //two's complement for negative numbers
}
float celsius = (float)raw / 0xF; //last nibble 1111b = 15d = 0xF
if (bitRead(raw, 15)) celsius = -celsius;
switch (i) {
case 0:
tempAussen = celsius;
MY_SERIAL.print("tempAussen ");
MY_SERIAL.println(tempAussen);
break;
case 1:
tempZuluft = celsius;
MY_SERIAL.print("tempZuluft ");
MY_SERIAL.println(tempZuluft);
break;
case 2:
tempFortluft = celsius;
MY_SERIAL.print("tempFortluft ");
MY_SERIAL.println(tempFortluft);
break;
case 3:
tempAbluft = celsius;
MY_SERIAL.print("tempAbluft ");
MY_SERIAL.println(tempAbluft);
break;
case 4: break;
}
}
}
MY_SERIAL.println("Done.");
}
void lueftungTemperatureControl() {
float hysterese = 0.7; // Hysterese von 1 K
if ((tempAussen < tempFortluft - 2) && tempFortluft > tMax && tempZuluft > tMin) {
if (abs(tempAussen - tempZuluft) < 1.5) lueftungBypassOffen = true;
} else {
lueftungBypassOffen = false;
}
if (((tempZuluft + hysterese / 2) > tempFortluft) && (lueftungBypassOffen == true)) {
lueftungSetState("off");
}
if (((tempZuluft - hysterese / 2) < tempFortluft) && (lueftungBypassOffen == true)) {
lueftungSetState("on");
}
if ((((tempZuluft - hysterese / 2) - tempFortluft) < -5) && (lueftungBypassOffen = false)) {
lueftungSetState("off");
}
if ((((tempZuluft + hysterese / 2) - tempFortluft) > -5) && (lueftungBypassOffen = false)) {
lueftungSetState("on");
}
}
void checkInputs() {
if (!digitalRead(INT_LFTG)) {
lueftungError = true;
digitalWrite(LED_LFTG, HIGH);
}
}
void RTCinit() {
MY_SERIAL.print("Initializing RTC...");
Wire.beginTransmission(RTCaddress);
Wire.write((uint8_t)0x23); // Start register (timestamp_mode)
Wire.write((uint8_t)0x6); // TSR Register 3 First time switch to batt, TSR Register 2 Last time switch to batt
Wire.write((uint8_t)0x00); // 0x24 Two's complement offset value
Wire.write((uint8_t)0x15); // 0x25 no INV, normal offset correction mode, 24h,low-jitter mode, 6pF load caps
Wire.write((uint8_t)0x00); // 0x26 battery switch enabled, switch at Vth (internal ref)
Wire.write((uint8_t)0x00); // 0x27 Enable periodic interupt pin on INTA
Wire.write((uint8_t)0x47); // 0x28 INTA Clock pulse every 1 minute, RTC Mode, STOP ctl default, no CLK output
Wire.write((uint8_t)0x40); // 0x29 pulsed periodic interrupt
Wire.write((uint8_t)0x00); // 0x2a no INTB, so no interrupts configured
Wire.endTransmission();
MY_SERIAL.println("Done initializing RTC.");
}
void RTCgetFlags() {
MY_SERIAL.print("Getting current RTC flag status...");
Wire.beginTransmission(RTCaddress);
Wire.write((uint8_t)0x02); //stopwatch minutes register contains EMON bit
Wire.endTransmission(false); //RTC accepts I2C restart conditions, so the bus is not released
Wire.requestFrom(RTCaddress, 1);
byte emonRegister = Wire.read();
if (bitRead(emonRegister, 7)) { //read flags if EMON shows that flags are set
Wire.endTransmission(false);
Wire.beginTransmission(RTCaddress);
Wire.write((uint8_t)0x2B);
Wire.endTransmission(false);
Wire.requestFrom(RTCaddress, 1);
byte flags = Wire.read();
Wire.endTransmission();
MY_SERIAL.println("Done");
if (flags != 0x00) {
if (bitRead(flags, 5)) {
RTCalarm1 = true;
MY_SERIAL.println("Alarm1 RTC asserted - not implemented.");
}
if (bitRead(flags, 6)) {
RTCalarm2 = true;
MY_SERIAL.println("Alarm2 RTC asserted - not implemented.");
}
}
} else {
Wire.endTransmission();
MY_SERIAL.println("No flags set.");
}
}
If you change back to Serial, you will see only the beginning after the chip is rebooted and the loop output immediately - the USB driver loses the byte stream when the chip is restarted, but the duplicate data in the loop will be visible. Therefore, if you need to log sensor data while the device is running inside the loop Serial is suitable. Initial initialization is difficult to see through Serial correctly - use Serial0 for such cases together with an external adapter.
Alex.