Advertisement
Guest User

Untitled

a guest
Jul 18th, 2022
48
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.14 KB | None | 0 0
  1. #include "SPI.h"
  2. #include "Wire.h"
  3. #include "ZUNO_OneWire.h"
  4.  
  5. #define SPI_CS 8
  6. SPISettings spi_settings = SPISettings(8000000, MSBFIRST, SPI_MODE0);
  7.  
  8. #define oneWirePin 12
  9. // MAX31820 uses default 12 bit for 0.05 °C resolution, requires > 750ms conversion time
  10.  
  11. OneWire oneWire(oneWirePin);
  12. uint8_t MAX31820addr[8][4];  //2-d array  for 4 MAX31820 ROM addresses
  13. uint16_t RTCaddress = 0xA2;  //PCF85263A I2C target write address; read target address is 0xA3
  14.                              //ZUNO_SETUP_CHANNELS(ZUNO_SENSOR_BINARY())
  15.  
  16.  
  17. ZUNO_SETUP_ISR_INT0(ofenSetError);
  18. ZUNO_SETUP_ISR_INT1(RTCseconds);
  19.  
  20. #define FET1 16
  21. #define FET2 15
  22. #define FET3 14
  23. #define FET4 3
  24.  
  25. #define INT_RTC 18
  26. #define INT_OFEN 17
  27. #define INT_LFTG 19
  28.  
  29. #define LED_OFEN 21
  30. #define LED_LFTG 20
  31.  
  32.  
  33. //variables
  34. float v_resistorLadder = 4.7;  //Spannung der Resistor Ladder Op-Amp
  35.  
  36. uint8_t ofenDefault = 7;                  //Standardheizleistung Ofen in kW
  37. uint8_t lueftungDefault = 2;              //Standardstufe Lüftung
  38. uint8_t ofenHeizleistung = ofenDefault;   //Aktuelle Heizleistung Ofen in kW
  39. uint8_t lueftungStufe = lueftungDefault;  //Aktuelle Stufe Lüftung
  40.  
  41. float tempAussen;
  42. float tempZuluft;
  43. float tempFortluft;
  44. float tempAbluft;
  45.  
  46. //bypass settings
  47. float tMax = 20;  //default 24
  48. float tMin = 13;  //default 13
  49.  
  50. uint8_t incrementLueftung = 0;
  51. uint8_t incrementOfen = 0;
  52.  
  53. uint8_t retryCounter = 0;
  54. uint8_t deviceCount = 0;              //number of discovered OneWire-Devices on the bus
  55. uint16_t borDetectionInterval = 300;  //seconds between Brownout-Checks
  56. uint16_t temperaturePollingIntervall = 300;
  57. uint16_t RTCintCounter = 0;  //counter variable for periodic (1s) RTC interrupts, reset after 300s
  58.  
  59. boolean FET1_on = false;  //Koppelrelais Ofen
  60. boolean FET2_on = true;   //Koppelrelais Lüftung
  61. boolean FET3_on = false;
  62. boolean FET4_on = true;
  63.  
  64. boolean ofenOn = false;
  65. boolean lueftungOn = true;
  66. boolean ofenError = false;      //Störmeldung Ofen D1
  67. boolean lueftungError = false;  //Störmeldung Lüftung D2
  68. boolean lueftungBypassOffen = false;
  69.  
  70. boolean RTCalarm1 = false;  //mm:dd:hh:mm:ss
  71. boolean RTCalarm2 = false;  //hh:mm and weekday
  72.  
  73. //void DACpowerState(int channel = 0, char* state = "off"); (SDCC compiler error, optional args werden nicht kompiliert?)
  74. //void lueftungSetState(char* state, int duration = 0);
  75.  
  76. void RTCseconds() {
  77.   RTCintCounter++;
  78. }
  79.  
  80. void ofenSetError() {
  81.   ofenError = true;
  82.   digitalWrite(LED_OFEN, LOW);
  83. }
  84.  
  85. void setup() {
  86.   Serial.begin(115200);
  87.   SPI.begin();
  88.   pinMode(SPI_CS, OUTPUT);
  89.   digitalWrite(SPI_CS, HIGH);
  90.   delay(1);
  91.   Wire.begin();
  92.   //Wire.setWireTimeout(3000, true);  //abort transmission after 3000 us and reset communication module
  93.  
  94.   zunoExtIntMode(ZUNO_EXT_INT0, RISING);
  95.   zunoExtIntMode(ZUNO_EXT_INT1, RISING);
  96.  
  97.   // set up inputs
  98.   pinMode(INT_LFTG, INPUT);
  99.   pinMode(INT_OFEN, INPUT);
  100.   pinMode(INT_RTC, INPUT);
  101.   // set up outputs
  102.   pinMode(FET1, OUTPUT);
  103.   pinMode(FET2, OUTPUT);
  104.   pinMode(FET3, OUTPUT);
  105.   pinMode(FET4, OUTPUT);
  106.   pinMode(LED_LFTG, OUTPUT);
  107.   pinMode(LED_OFEN, OUTPUT);
  108.   digitalWrite(FET1, LOW);
  109.   digitalWrite(FET2, LOW);
  110.   digitalWrite(FET3, LOW);
  111.   digitalWrite(FET4, LOW);
  112.   digitalWrite(LED_LFTG, LOW);
  113.   digitalWrite(LED_OFEN, LOW);
  114.  
  115.   delay(100);
  116.   Serial.println("Opened serial connection.");
  117.   //Set up DAC registers
  118.   DACinit();
  119.  
  120.   //Set up RTC registers
  121.   RTCinit();
  122.  
  123.   Serial.println("Probing OneWire bus...");
  124.   oneWire.reset_search();
  125.   deviceCount = 0;
  126.   uint8_t newAddr[8];
  127.   while (oneWire.search(newAddr)) {
  128.     deviceCount++;
  129.     Serial.print("New device found:");
  130.  
  131.     for (int i = 0; i < 8; i++) {
  132.       MAX31820addr[deviceCount][i] = newAddr[i];
  133.       Serial.print(newAddr[i], HEX);
  134.       Serial.print(" ");
  135.     }
  136.     Serial.println();
  137.   }
  138.   Serial.println("No more devices found.");
  139. }
  140.  
  141. void loop() {
  142.   //testing
  143.  
  144.   if (incrementOfen > 13) incrementOfen = 0;
  145.   if (incrementLueftung > 3) incrementLueftung = 0;
  146.   if (RTCintCounter == 20) {
  147.     DACsetVoltage(1, ofenCalcVoltage(ofenHeizleistung));
  148.     DACsetVoltage(2, lueftungCalcVoltage(ofenHeizleistung));
  149.     ofenHeizleistung = incrementOfen;
  150.     lueftungStufe = incrementLueftung;
  151.   }
  152.  
  153.  
  154.   //end testing
  155.   if (RTCintCounter == 60) {
  156.     Serial.println("60s elapsed.");
  157.     delay(16);  //maximum time for periodic interrupt flag clearance is 2* 1/128 = 16 ms
  158.     RTCgetFlags();
  159.   }
  160.  
  161.   if (RTCintCounter == 300) {
  162.     Serial.println("300s elapsed.");
  163.     RTCintCounter = 0;
  164.     MAX31820getAllTemperatures();
  165.     DACborDetection();
  166.   }
  167. }
  168.  
  169. void DACinit() {
  170.   Serial.println("Initializing DAC...");
  171.   DACread(0x0A);               //clear POR Bit by reading status register
  172.   DACwrite(0x0A, 0x03, 0x00);  //set gain B9:B8 of 1x for both channels
  173.   DACwrite(0x08, 0x00, 0x00);  //set VREF to VDD for both channels
  174.   DACsetVoltage(1, ofenCalcVoltage(ofenHeizleistung));
  175.   DACsetVoltage(2, lueftungCalcVoltage(lueftungStufe));
  176.   if (ofenOn) ofenSetState("on");
  177.   if (!ofenOn) ofenSetState("off");
  178.   if (lueftungOn) lueftungSetState("on");
  179.   if (!lueftungOn) lueftungSetState("off");
  180.   Serial.println("Done initzializing DAC.");
  181. }
  182. void DACborDetection() {
  183.   Serial.print("Checking for BOR-related memory corruption on DAC...");
  184.   word borWord = DACread(0x0A);
  185.   boolean borBitSet = bitRead(borWord, 8);
  186.  
  187.   if (borBitSet == true) {
  188.     Serial.println("FAILED! Reinitizialing DAC.");
  189.     DACinit();  //reinitialize DAC with current values
  190.   } else {
  191.     Serial.println("PASS.");
  192.   }
  193. }
  194. void DACsetVoltage(int channel = 0, float voltage = 0) {  //writes register 0x00 or 0x01 respectively
  195.   Serial.print("Setting wiper value of ");
  196.   if (voltage > 2 * v_resistorLadder) voltage = 2 * v_resistorLadder;
  197.   if (voltage < 0) voltage = 0;
  198.  
  199.   byte wiperPosition = (int)(((voltage / 2) / v_resistorLadder) * 256);
  200.   Serial.print(wiperPosition);
  201.  
  202.   if (channel == 1) {
  203.     Serial.println(" for oven...");
  204.     DACwrite(0x00, 0x00, wiperPosition);
  205.   }
  206.   if (channel == 2) {
  207.     Serial.println(" for lueftung...");
  208.     DACwrite(0x01, 0x00, wiperPosition);
  209.   }
  210.  
  211.  
  212.  
  213.   //confirm correct output voltage is set in DAC register
  214. }
  215.  
  216. void DACpowerState(int channel = 0, char *state = "off") {  //writes register 0x09, if channel 0 is used, both channels are switched
  217.   if (channel == 0) {
  218.     if (!strcmp(state, "on")) {
  219.       DACwrite(0x09, 0x00, 0x00);
  220.       ofenOn = true;
  221.       lueftungOn = true;
  222.     }
  223.     if (!strcmp(state, "off")) {
  224.       DACwrite(0x09, 0x00, 0x03);
  225.       ofenOn = false;
  226.       lueftungOn = false;
  227.     }
  228.   } else if (channel == 1) {
  229.     if (!strcmp(state, "on")) {
  230.       byte cmd = 0x00;
  231.       bitWrite(cmd, 1, lueftungOn);
  232.       DACwrite(0x09, 0x00, cmd);
  233.       ofenOn = true;
  234.     }
  235.     if (!strcmp(state, "off")) {
  236.       byte cmd = 0x01;
  237.       bitWrite(cmd, 1, lueftungOn);
  238.       DACwrite(0x09, 0x00, cmd);
  239.       ofenOn = false;
  240.     }
  241.   } else if (channel == 2) {
  242.     if (!strcmp(state, "on")) {
  243.       byte cmd = 0x00;
  244.       bitWrite(cmd, 0, ofenOn);
  245.       DACwrite(0x09, 0x00, cmd);
  246.       lueftungOn = true;
  247.     }
  248.     if (!strcmp(state, "off")) {
  249.       byte cmd = 0x02;
  250.       bitWrite(cmd, 0, ofenOn);
  251.       DACwrite(0x09, 0x00, cmd);
  252.       lueftungOn = false;
  253.     }
  254.   }
  255. }
  256.  
  257. void DACwrite(byte writeAddr, byte data2, byte data1) {
  258.   if (retryCounter < 3) {
  259.     Serial.print("Writing ");
  260.     Serial.print(data2, HEX);
  261.     Serial.print(data1, HEX);
  262.     Serial.print(" at DAC address ");
  263.     Serial.print(writeAddr, HEX);
  264.     Serial.print(" ...");
  265.     byte cmdReturn;
  266.     writeAddr = writeAddr << 3;
  267.     byte cmdByte = writeAddr;  // 00 write 0 error bit, so nothing has to be added
  268.     SPI.beginTransaction(&spi_settings);
  269.     digitalWrite(SPI_CS, LOW);
  270.     delay(1);
  271.     SPI.transfer(cmdByte);
  272.     cmdReturn = SPI.transfer(data2);
  273.     SPI.transfer(data1);
  274.     delay(1);
  275.     digitalWrite(SPI_CS, HIGH);
  276.     SPI.endTransaction();
  277.     if (cmdReturn != 0xFF) {
  278.       retryCounter++;
  279.       Serial.println("FAILED! Retrying.");
  280.       DACwrite(writeAddr, data2, data1);
  281.     } else
  282.       retryCounter = 0;
  283.     Serial.println("Done.");
  284.   } else {
  285.     Serial.println("FAILED 3 times. Abort.");
  286.     retryCounter = 0;
  287.   }
  288. }
  289.  
  290. word DACread(byte readAddr) {
  291.   if (retryCounter < 3) {
  292.     Serial.print("Reading 1 byte at DAC address ");
  293.     Serial.print(readAddr, HEX);
  294.     Serial.print(" ...");
  295.     byte cmdReturn;
  296.     readAddr = readAddr << 3;
  297.     byte cmdByte = readAddr + 6;
  298.     SPI.beginTransaction(&spi_settings);
  299.     digitalWrite(SPI_CS, LOW);
  300.     delay(1);
  301.     SPI.transfer(cmdByte);
  302.     cmdReturn = SPI.transfer(0);
  303.     word DACreply = SPI.transfer16(0);
  304.     delay(1);
  305.     digitalWrite(SPI_CS, HIGH);
  306.     SPI.endTransaction();
  307.     Serial.print("DAC returned ");
  308.     Serial.println(cmdReturn, HEX);
  309.     if (cmdReturn != 0xFF) {
  310.       retryCounter++;
  311.       DACread(readAddr);
  312.     } else {
  313.       retryCounter = 0;
  314.       Serial.println("Done.");
  315.       return DACreply;
  316.     }
  317.   } else {
  318.     word error = 0;
  319.     Serial.println("FAILED 3 times. Abort.");
  320.     return error;
  321.   }
  322. }
  323.  
  324. float ofenCalcVoltage(uint8_t leistung) {  //geforderte Leistung zwischen 3 und 13 kW
  325.   Serial.print("Calculating analog value for ");
  326.   Serial.print(leistung);
  327.   Serial.println("kW thermal power...");
  328.   if (leistung < 3) leistung = 3;
  329.   if (leistung > 13) leistung = 13;
  330.   ofenHeizleistung = leistung;  //bad programming (eventuell unterscheiden sich dann Zustand und simulierte Variable, wenn der write-Befehl dreimal scheitert)
  331.   float voltage = ((13 - 3) / 10) * (leistung - 3);
  332.   Serial.print(voltage);
  333.   Serial.println("V");
  334.   return voltage;
  335. }
  336.  
  337. float lueftungCalcVoltage(uint8_t stufe) {  //LUT-artig für Lüftungsstufen
  338.   Serial.print("Calculating analog value for fan level");
  339.   Serial.print(stufe);
  340.   Serial.println("...");
  341.   if (stufe < 1) lueftungSetState("off");
  342.   if (stufe > 3) stufe = 3;
  343.   lueftungStufe = stufe;  //bad programming (eventuell unterscheiden sich dann Zustand und simulierte Variable, wenn der write-Befehl dreimal scheitert)
  344.   float voltage[3] = { 3, 6, 9 };
  345.   Serial.print(voltage[stufe - 1]);
  346.   Serial.println("V");
  347.   return voltage[stufe - 1];
  348. }
  349.  
  350. void ofenSetState(char *state) {
  351.   if (!strcmp(state, "on")) {
  352.     Serial.println("Setting ofen state to on...");
  353.     digitalWrite(FET1, HIGH);
  354.     FET1_on = true;
  355.     DACpowerState(1, "on");
  356.     DACsetVoltage(1, ofenCalcVoltage(ofenHeizleistung));  //Ofen schaltet auf letztem bekannten Wert ein
  357.     ofenOn = true;
  358.     Serial.println("Ofen state set to on.");
  359.   }
  360.   if (!strcmp(state, "off")) {
  361.     Serial.println("Setting ofen state to off...");
  362.     digitalWrite(FET1, LOW);
  363.     FET1_on = false;
  364.     DACpowerState(1, "off");
  365.     ofenOn = false;
  366.     Serial.println("Ofen state set to off.");
  367.   }
  368. }
  369. void lueftungSetState(char *state) {  //argument duration missing
  370.   if (!strcmp(state, "on")) {
  371.     Serial.println("Setting lueftung state to on...");
  372.     digitalWrite(FET2, HIGH);
  373.     FET2_on = true;
  374.     DACpowerState(2, "on");
  375.     DACsetVoltage(2, lueftungCalcVoltage(lueftungStufe));  //Lueftung schaltet auf letztem bekannten Wert ein
  376.     lueftungOn = true;
  377.     Serial.println("Lueftung state set to on.");
  378.   }
  379.   if (!strcmp(state, "off")) {
  380.     Serial.println("Setting lueftung state to off...");
  381.     digitalWrite(FET2, LOW);
  382.     FET2_on = false;
  383.     DACpowerState(2, "off");
  384.     lueftungOn = false;
  385.     Serial.println("Lueftung state set to off.");
  386.   }
  387. }
  388.  
  389. void MAX31820getAllTemperatures() {
  390.   Serial.println("Getting temperature data from all known MAX31820 sensors...");
  391.   oneWire.reset();
  392.   oneWire.skip();  //simulataneously start temperature conversion on all devices
  393.   oneWire.write(0x44);
  394.   delay(1000);  //wait 1000 ms, because read time slot allocation is not possible in multi-slaves queries
  395.  
  396.   for (int i = 0; i < deviceCount; i++) {
  397.     uint8_t rom[8];
  398.     for (int j = 0; i < 8; i++) {
  399.       rom[j] = MAX31820addr[i][j];
  400.     }
  401.     oneWire.reset();
  402.     oneWire.select(rom);
  403.     oneWire.write(0xBE);  //read scratchpad register
  404.     byte scratchpad[9];   //9 bit scratchpad
  405.     for (int i = 0; i < 9; i++) {
  406.       scratchpad[i] = oneWire.read();
  407.     }
  408.     if (oneWire.crc8(scratchpad, 8) == rom[7]) {
  409.       Serial.println("CRC match for ROM ");
  410.       for (int i = 0; i < 8; i++) {
  411.         Serial.println(rom[i]);
  412.       }
  413.       int16_t raw = (scratchpad[1] << 8) | scratchpad[0];
  414.       if (bitRead(raw, 15)) {
  415.         raw = (raw ^ 0xFFFF) - 0x01;  //two's complement for negative numbers
  416.       }
  417.  
  418.       float celsius = (float)raw / 0xF;  //last nibble 1111b = 15d = 0xF
  419.       if (bitRead(raw, 15)) celsius = -celsius;
  420.  
  421.       switch (i) {
  422.         case 0:
  423.           tempAussen = celsius;
  424.           Serial.print("tempAussen ");
  425.           Serial.println(tempAussen);
  426.           break;
  427.         case 1:
  428.           tempZuluft = celsius;
  429.           Serial.print("tempZuluft ");
  430.           Serial.println(tempZuluft);
  431.           break;
  432.         case 2:
  433.           tempFortluft = celsius;
  434.           Serial.print("tempFortluft ");
  435.           Serial.println(tempFortluft);
  436.           break;
  437.         case 3:
  438.           tempAbluft = celsius;
  439.           Serial.print("tempAbluft ");
  440.           Serial.println(tempAbluft);
  441.           break;
  442.         case 4: break;
  443.       }
  444.     }
  445.   }
  446.   Serial.println("Done.");
  447. }
  448.  
  449. void lueftungTemperatureControl() {
  450.   float hysterese = 0.7;  // Hysterese von 1 K
  451.   if ((tempAussen < tempFortluft - 2) && tempFortluft > tMax && tempZuluft > tMin) {
  452.     if (abs(tempAussen - tempZuluft) < 1.5) lueftungBypassOffen = true;
  453.   } else {
  454.     lueftungBypassOffen = false;
  455.   }
  456.  
  457.   if (((tempZuluft + hysterese / 2) > tempFortluft) && (lueftungBypassOffen == true)) {
  458.     lueftungSetState("off");
  459.   }
  460.   if (((tempZuluft - hysterese / 2) < tempFortluft) && (lueftungBypassOffen == true)) {
  461.     lueftungSetState("on");
  462.   }
  463.  
  464.   if ((((tempZuluft - hysterese / 2) - tempFortluft) < -5) && (lueftungBypassOffen = false)) {
  465.     lueftungSetState("off");
  466.   }
  467.   if ((((tempZuluft + hysterese / 2) - tempFortluft) > -5) && (lueftungBypassOffen = false)) {
  468.     lueftungSetState("on");
  469.   }
  470. }
  471.  
  472. void checkInputs() {
  473.   if (!digitalRead(INT_LFTG)) {
  474.     lueftungError = true;
  475.     digitalWrite(LED_LFTG, HIGH);
  476.   }
  477. }
  478. void RTCinit() {
  479.   Serial.print("Initializing RTC...");
  480.   Wire.beginTransmission(RTCaddress);
  481.   Wire.write((uint8_t)0x23);  // Start register (timestamp_mode)
  482.   Wire.write((uint8_t)0x6);   // TSR Register 3 First time switch to batt, TSR Register 2 Last time switch to batt
  483.   Wire.write((uint8_t)0x00);  // 0x24 Two's complement offset value
  484.   Wire.write((uint8_t)0x15);  // 0x25 no INV, normal offset correction mode, 24h,low-jitter mode, 6pF load caps
  485.   Wire.write((uint8_t)0x00);  // 0x26 battery switch enabled, switch at Vth (internal ref)
  486.   Wire.write((uint8_t)0x00);  // 0x27 Enable periodic interupt pin on INTA
  487.   Wire.write((uint8_t)0x47);  // 0x28 INTA Clock pulse every 1 minute, RTC Mode, STOP ctl default, no CLK output
  488.   Wire.write((uint8_t)0x40);  // 0x29 pulsed periodic interrupt
  489.   Wire.write((uint8_t)0x00);  // 0x2a no INTB, so no interrupts configured
  490.   Wire.endTransmission();
  491.   Serial.println("Done initializing RTC.");
  492. }
  493.  
  494. void RTCgetFlags() {
  495.   Serial.print("Getting current RTC flag status...");
  496.   Wire.beginTransmission(RTCaddress);
  497.   Wire.write((uint8_t)0x02);    //stopwatch minutes register contains EMON bit
  498.   Wire.endTransmission(false);  //RTC accepts I2C restart conditions, so the bus is not released
  499.   Wire.requestFrom(RTCaddress, 1);
  500.   byte emonRegister = Wire.read();
  501.   if (bitRead(emonRegister, 7)) {  //read flags if EMON shows that flags are set
  502.     Wire.endTransmission(false);
  503.     Wire.beginTransmission(RTCaddress);
  504.     Wire.write((uint8_t)0x2B);
  505.     Wire.endTransmission(false);
  506.     Wire.requestFrom(RTCaddress, 1);
  507.     byte flags = Wire.read();
  508.     Wire.endTransmission();
  509.     Serial.println("Done");
  510.     if (flags != 0x00) {
  511.       if (bitRead(flags, 5)) {
  512.         RTCalarm1 = true;
  513.         Serial.println("Alarm1 RTC asserted - not implemented.");
  514.       }
  515.       if (bitRead(flags, 6)) {
  516.         RTCalarm2 = true;
  517.         Serial.println("Alarm2 RTC asserted - not implemented.");
  518.       }
  519.     }
  520.   } else {
  521.     Wire.endTransmission();
  522.     Serial.println("No flags set.");
  523.   }
  524. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement