16CH Binary Input

From KONNEKTING Wiki
Jump to navigation Jump to search
16CH Binary Input
16CH Binary Input Overview.jpg
16CH Binary Input comp.jpg
Developer Matthias F.
Status Version 1.0 finished
Microcontroller/Board
KNX connectivity Mini-BCU


Description

16ch Binary Input (potential-free)

The binary input has 16 inputs available and is used to connect eight conventional push-buttons or floating contacts such as window or relay contacts. There is one status LED for each input. In addition, the input status is sent to the bus. A separate power supply is not necessary


Technical Data:

  • Operating voltage:         KNX Bus voltage <10mA
  • Installation type:             Top Hat Rail mounting
  • Number of Inputs:           16
  • Number of S0-Inputs:      4 (CH13 - CH16)
  • Input polling:                    with 100ms, 300ms or 500ms
  • Typ of Inputs:                   potential-free / floating contacts
  • Max. cable length:           30m tested (more possible)
  • input voltage:                  5V
  • Max. input voltage:          24V (absolute rating, for <1min)
  • Max. input current:          10mA
  • The device makes a contact supply voltage (5V) which is not electrically isolated from the bus voltage!
  • x-Inputs can configure to a "room" ("room"-GA can show if one of the windows is open in the room)


Hardware

What you need

for this device do you need:

  • 1x OKW Housing
  • 1x PCB Kit
  • 1x Mounting Kit (screws, ...)
OKW Housing link OKW-Website:[1]
1x B6503121 RAILTEC B, 4 Module
3x B6607140 Klemmenabdeckung, flach 
1x B6607145 Abdeckung KNX, flach
4x B6607142 Klemmenabdeckung, flach 
(1x) B6603180 Frontplatte, 4 Module (only if you don't use the "LED-Status-PCB" 


PCB Kit:
1) Application PCB
2) Controller PCB
3) LED-Status PCB (for function not necessary, only to show the status of the Inputs)
4) Mini-BCU (KNX-Transceiver)
16CH Binary Input PCBs.jpg


Mounting Kit
1x Micromatch cable
8x Screws 


without housing


Block Diagram

16CH Binary INput Block Diagramm.PNG

Detection Circuit

16CH Binary Input Schematic.png


Software

What you need

  • Arduino IDE ([2])
  • Arduino Lib PCF8575 ([3])
  • Arduino Code for 16CH Binary Input
  • XML-File for 16CH Binary Input
  • KONNEKTING SUITE (link)

Arduino Code

Libs

 #include <KonnektingDevice.h>
 #include "kdevice_KNX_Bineareingang_Multi.h"  -> erzeugte lib aus Konnekting
 #include "Timer.h"
 #include "EEPROM.h"
 #include "S0_Schnittstelle.h"
 #include <RTCZero.h>
 #include <Wire.h>
 #include <PCF8575.h> // Required for PCF8575

Debug Config

Hier hat man Möglichkeiten bestimmte Funktionen zu aktivieren/deaktivieren

 // I2C-MODE (enable for normal mode)
 #define I2COFF // comment this line to disable I2C mode
 // DEBUG-MODE (for normal mode without debugging you must deactivate the function)
 #define KDEBUG // comment this line to disable DEBUG mode
 // Anzeige-Platine (enable if you use the Status LED PCB)
 #define ANZEIGE_Platine

KNX Serial Config

Hier wird das Serial-IF zum KNX-Bus konfiguriert

 #ifdef __AVR_ATmega328P__
 #define KNX_SERIAL Serial // Nano/ProMini etc. use Serial
 #elif ESP8266
 #define KNX_SERIAL Serial // ESP8266 use Serial
 #else
 #define KNX_SERIAL Serial1 // Leonardo/Micro/Zero etc. use Serial1
 #endif

RTC Config

Jeden Tag um 0UHr werden alle Daten ins EEPROM geschrieben

 /* Create an rtc object */
 RTCZero rtc;
 /* Change these values to set the current initial time */
 const byte seconds = 0;
 const byte minutes = 00;
 const byte hours = 00;
 /* Change these values to set the current initial date */
 const byte day = 1;
 const byte month = 1;
 const byte year = 17;


 
 void alarmMatch()
 { 
  digitalWrite(LED_YELLOW, HIGH);
  #ifdef KDEBUG
  Debug.println("SAFE");
  #endif
  rtc.setTime(hours, minutes, seconds);
  rtc.setAlarmTime(23, 59, 00);
  rtc.enableAlarm(rtc.MATCH_HHMMSS);
  run_save=true;
 }

define IO Config

 #define PROG_LED_PIN    A2
 #define PROG_BUTTON_PIN A1
 #define LED_YELLOW      25     
 #define SAVE_PIN        38
 #define MAX_CH          15
 #define S0_1_pin        11    //IO6
 #define S0_2_pin         5    //IO7
 #define S0_3_pin         6    //IO8
 #define S0_4_pin         2    //IO9

Save Parameters

Funktion wird aufgerufen:

- jeden Tag um 0Uhr
- Wenn ein Busspannugsabfall detekiert wird
 void SAVE_State(){
 digitalWrite(LED_YELLOW, HIGH);   // LED indicator 
 writeSAVE(S0_Zaehler,S0_impuls);  // EEPROM write routine to save all values
 }

IRQ S0 Interface

 void irq_S0_1(){
  time_S0_stopp[0] = millis();
  S0_impuls[0]++;
  if(S0_impuls[0]>=zaehler_Impulse[0])
    {S0_Zaehler[0]++;
     S0_impuls[0] = 0;}
  set_S0_LED[0] = true;      
  #ifdef KDEBUG
  Debug.print("S0_1: ");
  Debug.println("%d",S0_impuls[0]);
  #endif   
 }

 void irq_S0_2(){
  time_S0_stopp[1] = millis();
    S0_impuls[1]++;
  if(S0_impuls[1]>=zaehler_Impulse[1])
    {S0_Zaehler[1]++;
     S0_impuls[1] = 0;}
  set_S0_LED[1] = true;   
  #ifdef KDEBUG
  Debug.print("S0_2: "); 
  Debug.println("%d",S0_impuls[1]);
  #endif   
}

 void irq_S0_3(){
  time_S0_stopp[2] = millis();
    S0_impuls[2]++;
  if(S0_impuls[2]>=zaehler_Impulse[2])
    {S0_Zaehler[2]++;
     S0_impuls[2] = 0;}
  set_S0_LED[2] = true;   
  #ifdef KDEBUG
  Debug.print("S0_3: "); 
  Debug.println("%d",S0_impuls[2]); 
  #endif   
 }

 void irq_S0_4(){
  time_S0_stopp[3] = millis();
    S0_impuls[3]++;
  if(S0_impuls[3]>=zaehler_Impulse[3])
    {S0_Zaehler[3]++;
     S0_impuls[3] = 0;}
  set_S0_LED[3] = true;    
    #ifdef KDEBUG
    Debug.print("S0_4: ");
    Debug.println("%d",S0_impuls[3]);  
    #endif
 }


Setup() Routine

 void setup(){

 //****************** Init IO *******************************************************
  pinMode(LED_YELLOW, OUTPUT);
  digitalWrite(LED_YELLOW, HIGH);
  pinMode(S0_1_pin, INPUT);
  pinMode(S0_2_pin, INPUT);
  pinMode(S0_3_pin, INPUT);
  pinMode(S0_4_pin, INPUT);
  Wire.begin(); // join i2c bus (address optional for master)

  
 //****************** Init Debug Interface ********************************************
  #ifdef KDEBUG
      // Start debug serial with 9600 bauds
      DEBUGSERIAL.begin(115200);
  #if defined(__AVR_ATmega32U4__) || defined(__SAMD21G18A__)
      // wait for serial port to connect. Needed for Leonardo/Micro/ProMicro/Zero only
      while (!DEBUGSERIAL)
  #endif
      // make debug serial port known to debug class
      // Means: KONNEKTING will sue the same serial port for console debugging
      Debug.setPrintStream(&DEBUGSERIAL);
      Debug.print(F("KONNEKTING DemoSketch\n"));
  #endif

 //****************** Init Debug KONNEKTING ********************************************  
  Konnekting.setMemoryReadFunc(&readEeprom);
  Konnekting.setMemoryWriteFunc(&writeEeprom);
  Konnekting.setMemoryUpdateFunc(&updateEeprom);    
  
  // Initialize KNX enabled Arduino Board
  Konnekting.init(KNX_SERIAL,
            PROG_BUTTON_PIN,
            PROG_LED_PIN,
            MANUFACTURER_ID,
            DEVICE_ID,
            REVISION);

  
  
 //****************** Read Parameter ***************************************************
  #ifdef KDEBUG
  Debug.println("READ Parameter");  
  #endif
  abfrage_Interval            = (((uint8_t) Konnekting.getUINT8Param(0)+1)*30);  // abfrage_Interval
  sende_Zyklus_Zaehler        = (uint8_t) Konnekting.getUINT8Param(1);           // sende_Zyklus_Zaehler
  zimmerMaskierung_Sendvalue  = (uint8_t) Konnekting.getUINT8Param(2);           // Ob HIGH oder LOW gesendet wird
  invertLED                   = (uint8_t) Konnekting.getUINT8Param(3);           // invertiert LED Anzeige
                              
 
  #ifdef KDEBUG
  Debug.print("Abfrage-Interval: ");  
  Debug.println("%d",abfrage_Interval); 
  Debug.print("Zimmer Maskierung Sendvalue: ");  
  Debug.println("%d",zimmerMaskierung_Sendvalue); 
  Debug.print("Anzahl Messungen: ");  
  Debug.println("%d",filter_count); 
  Debug.print("LED invert: ");  
  Debug.println("%d",invertLED); 
  #endif

 //****************** Set Sendezyklus (S0-Schnittstelle) ********************************
  if(sende_Zyklus_Zaehler == 1) sende_Zyklus =   6000;  // 1min
  if(sende_Zyklus_Zaehler == 2) sende_Zyklus =  60000;  //10min
  if(sende_Zyklus_Zaehler == 3) sende_Zyklus = 180000;  //30min
  if(sende_Zyklus_Zaehler == 4) sende_Zyklus = 360000;  //60min

  #ifdef KDEBUG
  Debug.print("Sende-Zyklus: ");  
  Debug.println("%d",sende_Zyklus); 
  #endif

 //****************** Load Settings *****************************************************  
  //Kanal 1 - 16 Load Settings
  for(int cha=0; cha<16; cha++)
    {
     CH_invert[cha] = (uint8_t) Konnekting.getUINT8Param(cha+5); 
    }
  //S0 1 - 4 Load Settings
  for(int cha=1; cha<5; cha++)
    {
    S0_aktiv[cha] = (uint8_t) Konnekting.getUINT8Param(cha+20); 
    }
  //Zählerimpulse Load Settings
  for(int cha=0; cha<4; cha++)
    {
    zaehler_Impulse[cha] = (uint16_t) Konnekting.getUINT16Param(cha+25);   
    }
  #ifdef KDEBUG
  Debug.println("READ Zaehler");
  Debug.print("S0_1 Zaehler(Imp/kwh): ");
  Debug.println("%d",zaehler_Impulse[0]);
  Debug.print("S0_2 Zaehler(Imp/kwh): ");
  Debug.println("%d",zaehler_Impulse[1]);
  Debug.print("S0_3 Zaehler(Imp/kwh): ");
  Debug.println("%d",zaehler_Impulse[2]);
  Debug.print("S0_4 Zaehler(Imp/kwh): ");
  Debug.println("%d",zaehler_Impulse[3]);
  #endif  

  #ifdef KDEBUG
  Debug.println("READ Zimmermaske");  
  #endif
  //ZimmerMasken Load Settings
  for(int cha=0; cha<5; cha++)
    {
    mask_Zimmer[cha] = (uint16_t) Konnekting.getUINT16Param(cha+29);
    }
  #ifdef KDEBUG
  Debug.print("Zimmer1: ");  
  SerialUSB.println(mask_Zimmer[0], BIN);
  Debug.print("Zimmer2: ");  
  SerialUSB.println(mask_Zimmer[1], BIN);
  Debug.print("Zimmer3: ");  
  SerialUSB.println(mask_Zimmer[2], BIN);
  Debug.print("Zimmer4: ");  
  SerialUSB.println(mask_Zimmer[3], BIN);
  Debug.print("Zimmer5: ");  
  SerialUSB.println(mask_Zimmer[4], BIN);
  #endif    
 
  #ifdef KDEBUG
  Debug.println("READ Zaehlerstaende");  
  #endif
  //Read Zählerstände
  S0_Zaehler[0] = (((uint16_t)readEeprom(1024))<<8 | readEeprom(1025));
  S0_Zaehler[1] = (((uint16_t)readEeprom(1026))<<8 | readEeprom(1027));
  S0_Zaehler[2] = (((uint16_t)readEeprom(1028))<<8 | readEeprom(1029));
  S0_Zaehler[3] = (((uint16_t)readEeprom(1030))<<8 | readEeprom(1031));
  S0_impuls[0]  = (((uint16_t)readEeprom(1032))<<8 | readEeprom(1033));
  S0_impuls[1]  = (((uint16_t)readEeprom(1034))<<8 | readEeprom(1035));
  S0_impuls[2]  = (((uint16_t)readEeprom(1036))<<8 | readEeprom(1037));
  S0_impuls[3]  = (((uint16_t)readEeprom(1038))<<8 | readEeprom(1039));
  attachInterrupt(SAVE_PIN,SAVE_State, FALLING);

  #ifdef KDEBUG
  Debug.println("Aktuelle Zähler_Impulse");
  Debug.print("S0_1 Zaehler(Imp): ");
  Debug.println("%d",S0_impuls[0]);
  Debug.print("S0_2 Zaehler(Imp): ");
  Debug.println("%d",S0_impuls[1]);
  Debug.print("S0_3 Zaehler(Imp): ");
  Debug.println("%d",S0_impuls[2]);
  Debug.print("S0_4 Zaehler(Imp): ");
  Debug.println("%d",S0_impuls[3]);
  #endif   
  
  S0_Zaehler_old[0] = S0_Zaehler[0];
  S0_Zaehler_old[1] = S0_Zaehler[1];
  S0_Zaehler_old[2] = S0_Zaehler[2];
  S0_Zaehler_old[3] = S0_Zaehler[3];

  //Sendet aktuellen Zählerstand
  sendZaehlerStand_2(0,S0_Zaehler);
  sendZaehlerStand_2(1,S0_Zaehler);
  sendZaehlerStand_2(2,S0_Zaehler);
  sendZaehlerStand_2(3,S0_Zaehler);

  
  //S0 Schnittstelle 
  if (S0_aktiv[1] == 1)   
      {attachInterrupt(S0_1_pin,irq_S0_1, FALLING);
       #ifdef KDEBUG
       Debug.println("S0_1 aktiv");  
       #endif 
       }
  else {
        #ifdef KDEBUG 
        Debug.println("S0_1 inaktiv");  
        #endif 
        }
  if (S0_aktiv[2] == 1)   
      {attachInterrupt(S0_2_pin,irq_S0_2, FALLING);
       #ifdef KDEBUG
       Debug.println("S0_2 aktiv");  
       #endif
       }
  else {
        #ifdef KDEBUG 
        Debug.println("S0_2 inaktiv");  
        #endif 
        }     
  if (S0_aktiv[3] == 1)   
      {attachInterrupt(S0_3_pin,irq_S0_3, FALLING);
       #ifdef KDEBUG
       Debug.println("S0_3 aktiv");  
       #endif
       }
   else {
         #ifdef KDEBUG 
         Debug.println("S0_3 inaktiv");  
         #endif 
         }    
   if (S0_aktiv[4] == 1)   
      {attachInterrupt(S0_4_pin,irq_S0_4, FALLING);
       #ifdef KDEBUG
       Debug.println("S0_4 aktiv");  
       #endif
       }
   else {
         #ifdef KDEBUG 
         Debug.println("S0_4 inaktiv");  
         #endif 
         }    

  //****** State Maschine ***********************
  //Init POrt Abfrage
  CHState = SetVCC;
  //Init 5min mom Leistung 
  MomL_State = state_S0;

  
  //****** INIT I2C Expander ********************
  #ifdef KDEBUG
  Debug.println("Expander INIT START");
  #endif
  #ifdef I2COFF
  expander.begin(0x20);
  #endif
  #ifdef KDEBUG
  Debug.println("Expander IO finish");
  #endif
  #ifdef I2COFF
  expander_VCC.begin(0x23);
  #endif
  #ifdef KDEBUG
  Debug.println("Expander VCC finish");
  #endif
  #ifdef ANZEIGE_Platine
  expander_LED.begin(0x24);    
  #endif
  #ifdef KDEBUG
  Debug.println("Expander INIT FINISH");
  #endif
  // Init OUTPUTS LED 
  #ifdef I2COFF
  for(int i=0;i<16;i++)
        {expander.pinMode(i, INPUT_PULLUP);  // WICHTIG: muss "INPUT_PULLUP" sein !!! 
         expander_VCC.pinMode(i, OUTPUT);
         expander_VCC.digitalWrite(i,LOW);
         #ifdef ANZEIGE_Platine
         expander_LED.pinMode(i, OUTPUT);
         expander_LED.digitalWrite(i,LOW);
         #endif 
         } 
  #endif   
    
  // Daten Lesen
  #ifdef I2COFF
  PNS = expander.read();
  #endif

  for(int i=0;i<16;i++)
        {
         //check Open_HIGH & Open_LOW
         if(CH_invert[i]==1) //wenn Open_LOW
           {PNS ^= 1 << i;}
        }   
   maske = (uint16_t) PNS;
   
   // Abfrage Ports
   for(int i=0;i<16;i++)
        {
         // HW-PIN "open" 
         if( (maske & (1 << i)))  
          { ch_old[i] = false; }          
         //HW-PIN "closed"
         else                   
           { ch_old[i] = true; } 
          
        sendStatus(i,ch_old);  
        } 
        
   // CHECK Zimmer maskierung
   for(int cha=0;cha<5;cha++){  
      if((maske & mask_Zimmer[cha]) != 0) 
          {state_Zimmer[cha]= true;}
      else     
          {state_Zimmer[cha]= false;} 
           #ifdef KDEBUG
           Debug.println("%d",state_Zimmer[cha]);  
           #endif
     // if(state_Zimmer[cha] != state_Zimmer_old[cha])
          send_Zimmer_Status(cha,state_Zimmer);
          state_Zimmer_old[cha]=state_Zimmer[cha];
      }
      
  //****************** Init RTC *******************************************************  
  rtc.begin();
  rtc.setTime(hours, minutes, seconds);
  rtc.setDate(day, month, year);

  rtc.setAlarmTime(23, 59, 00);
  rtc.enableAlarm(rtc.MATCH_HHMMSS);
  rtc.attachInterrupt(alarmMatch);    
  
  
  //****************** Init Timer *******************************************************  
  setTimer();
  setTimer_ms(10);
      
  #ifdef KDEBUG
  Debug.println("FINISH Setup");  
  #endif
  digitalWrite(LED_YELLOW, LOW);
 }

Loop()

 void loop(){ 
  //digitalWrite(LED_YELLOW, LOW);
  Knx.task();
  if (Konnekting.isReadyForApplication()) {
    // Sendet bei Zählerstand-Änderung
    if(sende_Zyklus_Zaehler == 0){
      if(S0_aktiv[1]== 1) sendZaehlerStand(0,S0_Zaehler,S0_Zaehler_old);
      if(S0_aktiv[2]== 1) sendZaehlerStand(1,S0_Zaehler,S0_Zaehler_old);
      if(S0_aktiv[3]== 1) sendZaehlerStand(2,S0_Zaehler,S0_Zaehler_old);
      if(S0_aktiv[4]== 1) sendZaehlerStand(3,S0_Zaehler,S0_Zaehler_old);
      }
    else if(sendZaehler_Cycle==true){
      sendZaehler_Cycle = false;
      if(S0_aktiv[1]== 1) sendZaehlerStand(0,S0_Zaehler,!S0_Zaehler);
      if(S0_aktiv[2]== 1) sendZaehlerStand(1,S0_Zaehler,!S0_Zaehler);
      if(S0_aktiv[3]== 1) sendZaehlerStand(2,S0_Zaehler,!S0_Zaehler);
      if(S0_aktiv[4]== 1) sendZaehlerStand(3,S0_Zaehler,!S0_Zaehler);
      } 

     

    // Zyklisches Abfragen
    if(isDelay==true)
    {    
     if(inputCH<16)
          {
            switch(CHState)
            {
              case SetVCC:
                expander_VCC.digitalWrite(inputCH,LOW);
                CHState = ReadIO;
                
              break;
              case ReadIO:
                #ifdef I2COFF
                PNS = expander.read();
                #endif
                CHState = IsInvert;
              break;
              case IsInvert:
                if(CH_invert[inputCH]==1) //wenn Open_LOW
                   {PNS ^= 1 << inputCH;}
                if(CH_invert[inputCH+1]==1) //wenn Open_LOW
                   {PNS ^= 1 << inputCH+1;}   
                CHState = MaskIO;
              break;
              case MaskIO:
                  
                 if( (PNS & (1 << inputCH)))  {ch[inputCH] = 0;} 
                 else                         {ch[inputCH] = 1;} 
                 
                 if( (PNS & (1 << inputCH+1))){ch[inputCH+1] = 0;} 
                 else                         {ch[inputCH+1] = 1;}
                                    
              CHState = IsChange_CH_ONE;
              break;
              case IsChange_CH_ONE:
              isChange(inputCH,ch,ch_old); 
              CHState = IsChange_CH_TWO;  
              break;
              case IsChange_CH_TWO:
              isChange(inputCH+1,ch,ch_old); 
              CHState = UnsetVCC;
              break;
              case UnsetVCC:
                Knx.task();
                if( (S0_aktiv[4]==1 && inputCH==14) || (S0_aktiv[3]==1 && inputCH-1==13) || (S0_aktiv[2]==1 && inputCH==12) || (S0_aktiv[1]==1 && inputCH-1==11) )
                   {
                    ;
                   }
                else
                    {
                   //expander_VCC.digitalWrite(inputCH,HIGH);
                    ;
                    }
              CHState = MaskRoom;
              break;
              case MaskRoom:
                if(ch[inputCH] == true)    {maske |= (1<<inputCH);}
                else                        {maske &= ~(1<<inputCH);}
                if(ch[inputCH+1] == true)    {maske |= (1<<inputCH+1);}
                else                        {maske &= ~(1<<inputCH+1);}
                CHState = Finish;
              break;
              case Finish:
                inputCH=inputCH+2;
                if(inputCH==16)
                  {
                    inputCH = 17;
                    isDelay = false;   
                  }
                CHState = SetVCC;   
              break;   
            }//Ende Switch
           }//Ende Abfrage Ports
                                  
        // CHECK Zimmer maskierung
        for(int cha=0;cha<5;cha++)
             {  
               maske2 = maske & mask_Zimmer[cha];
               if( maske2 !=  mask_Zimmer[cha]) 
                      {state_Zimmer[cha]= true;}
               else     
                      {state_Zimmer[cha]= false;} 
               if(state_Zimmer[cha] != state_Zimmer_old[cha])
                      {state_Zimmer_old[cha]=state_Zimmer[cha];
                       send_Zimmer_Status(cha,state_Zimmer);}
              }
        
      }//ENDE ISDELAY

  //***************************************************************************************************        
  // S0_1 LED Blinken  
    if(set_S0_LED[0] == true)
      { 
        set_S0_LED_time[0] = time_count;
        S0_LED_ON[0] = true;
        set_S0_LED[0] = false;
        #ifdef ANZEIGE_Platine
        expander_LED.digitalWrite(MAX_CH-12,LOW);
        #endif  
        // Berechnung mom Leistung
        watt_S0[0] = 3600.0/ ((time_S0_stopp[0]-time_S0_start[0])/(zaehler_Impulse[0]*1.0));
         #ifdef KDEBUG
         Debug.print("W0: ");
         Debug.println("%f", watt_S0[0]);  
         #endif
        time_S0_start[0] = time_S0_stopp[0]; 
      }
    if(S0_LED_ON[0] == true && (time_count > set_S0_LED_time[0]+30))
      {
        S0_LED_ON[0] = false;
        #ifdef ANZEIGE_Platine
        expander_LED.digitalWrite(MAX_CH-12,HIGH);
        #endif
      }  
        
    // S0_2 LED Blinken  
    if(set_S0_LED[1] == true)
      { 
        set_S0_LED_time[1] = time_count;
        S0_LED_ON[1] = true;
        set_S0_LED[1] = false;
        #ifdef ANZEIGE_Platine
        expander_LED.digitalWrite(MAX_CH-13,LOW);
        #endif  
        // Berechnung mom Leistung
        watt_S0[1] = 3600.0/ ((time_S0_stopp[1]-time_S0_start[1])/(zaehler_Impulse[1]*1.0));
         #ifdef KDEBUG
         Debug.print("W1: ");
         Debug.println("%f", watt_S0[1]);  
         #endif
        time_S0_start[1] = time_S0_stopp[1]; 
      }
    if(S0_LED_ON[1] == true && (time_count > set_S0_LED_time[1]+30))
      {
        S0_LED_ON[1] = false;
        #ifdef ANZEIGE_Platine
        expander_LED.digitalWrite(MAX_CH-13,HIGH);
        #endif
      }  
      
    // S0_3 LED Blinken  
    if(set_S0_LED[2] == true)
      { 
        set_S0_LED_time[2] = time_count;
        S0_LED_ON[2] = true;
        set_S0_LED[2] = false;
        #ifdef ANZEIGE_Platine
        expander_LED.digitalWrite(MAX_CH-14,LOW);
        #endif  
        // Berechnung mom Leistung
        watt_S0[2] = 3600.0/ ((time_S0_stopp[2]-time_S0_start[2])/(zaehler_Impulse[2]*1.0));
         #ifdef KDEBUG
         Debug.print("W2: ");
         Debug.println("%f", watt_S0[2]);  
         #endif
        time_S0_start[2] = time_S0_stopp[2]; 
      }
    if(S0_LED_ON[2] == true && (time_count > set_S0_LED_time[2]+30))
      {
        S0_LED_ON[2] = false;
        #ifdef ANZEIGE_Platine
        expander_LED.digitalWrite(MAX_CH-14,HIGH);
        #endif
      }  

    // S0_4 LED Blinken  
    if(set_S0_LED[3] == true)
      { 
        set_S0_LED_time[3] = time_count;
        S0_LED_ON[3] = true;
        set_S0_LED[3] = false;
        #ifdef ANZEIGE_Platine
        expander_LED.digitalWrite(MAX_CH-15,LOW);
        #endif  
        // Berechnung mom Leistung
        watt_S0[3] = 3600.0/ ((time_S0_stopp[3]-time_S0_start[3])/(zaehler_Impulse[3]*1.0));
         #ifdef KDEBUG
         Debug.print("W3: ");
         Debug.println("%f", watt_S0[3]);  
         #endif
        time_S0_start[3] = time_S0_stopp[3]; 
      }
    if(S0_LED_ON[3] == true && (time_count > set_S0_LED_time[3]+30))
      {
        S0_LED_ON[3] = false;
        #ifdef ANZEIGE_Platine
        expander_LED.digitalWrite(MAX_CH-15,HIGH);
        #endif
      }

  //***************************************************************************************************      
  //Momentane Verlustleistung senden     

  if(is_5min == true)
    {
     switch(MomL_State)
       {
        case state_S0:
        if(S0_aktiv[1]==1)
        {
          if(millis()-time_S0_start[0]>60000)   
                {
                 if(millis()-time_S0_start[0]>240000)       // kein Impuls nach 4min
                    {
                     watt_S0[0] = 0;
                     Knx.write(33,watt_S0[0]);
                    }
                  else if(millis()-time_S0_start[0]>180000)  // kein Impuls nach 3min
                    {
                      if(watt_S0[0]>(3600.0 / (180000/zaehler_Impulse[0])))
                          {watt_S0[0] = 3600.0 / (180000/zaehler_Impulse[0]);}
                      Knx.write(33,watt_S0[0]);
                    }
                  else if(millis()-time_S0_start[0]>120000)  // kein Impuls nach 2min
                    {
                      if(watt_S0[0]>(3600.0 / (120000/zaehler_Impulse[0])))
                          {watt_S0[0] = 3600.0 / (120000/zaehler_Impulse[0]);}
                      Knx.write(33,watt_S0[0]); 
                    }          
                  else 
                    {
                      if(watt_S0[0]>(3600.0 / (60000/zaehler_Impulse[0])))
                          {watt_S0[0] = 3600.0 / (60000/zaehler_Impulse[0]);}
                      Knx.write(33,watt_S0[0]);  
                    }         
                 } 
          else
                   Knx.write(33,watt_S0[0]);     
        }           
        MomL_State = state_S1;       
        break;
        
        case state_S1:
        if(S0_aktiv[2]==1)
        {
          if(millis()-time_S0_start[1]>60000)
                {
                 if(millis()-time_S0_start[1]>240000)       // kein Impuls nach 4min
                    {
                     watt_S0[1] = 0;
                     Knx.write(36,watt_S0[1]);
                    }
                  else if(millis()-time_S0_start[1]>180000)  // kein Impuls nach 3min
                    {
                      if(watt_S0[1]>(3600.0 / (180000/zaehler_Impulse[1])))
                          {watt_S0[1] = 3600.0 / (180000/zaehler_Impulse[1]);}
                      Knx.write(36,watt_S0[1]);
                    }
                  else if(millis()-time_S0_start[1]>120000)  // kein Impuls nach 2min
                    {
                      if(watt_S0[1]>(3600.0 / (120000/zaehler_Impulse[1])))
                          {watt_S0[1] = 3600.0 / (120000/zaehler_Impulse[1]);}
                      Knx.write(36,watt_S0[1]); 
                    }          
                  else 
                    {
                      if(watt_S0[1]>(3600.0 / (60000/zaehler_Impulse[1])))
                          {watt_S0[1] = 3600.0 / (60000/zaehler_Impulse[1]);}
                      Knx.write(36,watt_S0[1]);  
                    }         
                 }
          else
              Knx.write(36,watt_S0[1]); 
        }            
        MomL_State = state_S2;       
        break;
        case state_S2:
        if(S0_aktiv[3]==1)
        {
          if(millis()-time_S0_start[2]>60000)
                {
                 if(millis()-time_S0_start[2]>240000)       // kein Impuls nach 4min
                    {
                     watt_S0[3] = 0;
                     Knx.write(39,watt_S0[2]);
                    }
                  else if(millis()-time_S0_start[2]>180000)  // kein Impuls nach 3min
                    {
                      if(watt_S0[2]>(3600.0 / (180000/zaehler_Impulse[2])))
                          {watt_S0[2] = 3600.0 / (180000/zaehler_Impulse[2]);}
                      Knx.write(39,watt_S0[2]);
                    }
                  else if(millis()-time_S0_start[2]>120000)  // kein Impuls nach 2min
                    {
                      if(watt_S0[2]>(3600.0 / (120000/zaehler_Impulse[2])))
                          {watt_S0[2] = 3600.0 / (120000/zaehler_Impulse[2]);}
                      Knx.write(39,watt_S0[2]); 
                    }          
                  else 
                    {
                      if(watt_S0[2]>(3600.0 / (60000/zaehler_Impulse[2])))
                          {watt_S0[2] = 3600.0 / (60000/zaehler_Impulse[2]);}
                      Knx.write(39,watt_S0[2]);  
                    }         
                 }
          else
              Knx.write(39,watt_S0[2]); 
        }            
        MomL_State = state_S3;       
        break;
        case state_S3:
        if(S0_aktiv[4]==1)
        {
            if(millis()-time_S0_start[3]>60000)
                {
                 if(millis()-time_S0_start[3]>240000)       // kein Impuls nach 4min
                    {
                     watt_S0[3] = 0;
                     Knx.write(42,watt_S0[3]);
                    }
                  else if(millis()-time_S0_start[3]>180000)  // kein Impuls nach 3min
                    {
                      if(watt_S0[3]>(3600.0 / (180000/zaehler_Impulse[3])))
                        {watt_S0[3] = 3600.0 / (180000/zaehler_Impulse[3]);}//20W
                      Knx.write(42,watt_S0[3]);
                    }
                  else if(millis()-time_S0_start[3]>120000)  // kein Impuls nach 2min
                    {
                      if(watt_S0[3]>(3600.0 / (120000/zaehler_Impulse[3])))
                        {watt_S0[3] = 3600.0 / (120000/zaehler_Impulse[3]);} //30W
                      Knx.write(42,watt_S0[3]); 
                    }          
                  else 
                    {
                      if(watt_S0[3]>(3600.0 / (60000/zaehler_Impulse[3])))
                        {watt_S0[3] = 3600.0 / (60000/zaehler_Impulse[3]);}  //60W
                      Knx.write(42,watt_S0[3]);  
                    }         
                 }
            else
                Knx.write(42,watt_S0[3]); 
        }              
        MomL_State = state_S0; 
        is_5min = false;      
        break;
      }//Switch 
    }//5min

  //***************************************************************************************************
  // Wenn neue Zälerstände über Suite gespeichert werden
    if(run_save == true)
      {
        run_save = false;
        #ifdef KDEBUG
        Debug.println("Set Zaehlerstand");
        #endif  
        sendZaehlerStand_2(0,S0_Zaehler);
        sendZaehlerStand_2(1,S0_Zaehler);
        sendZaehlerStand_2(2,S0_Zaehler);
        sendZaehlerStand_2(3,S0_Zaehler);
        writeSAVE(S0_Zaehler,S0_impuls);
        digitalWrite(LED_YELLOW, LOW);
      }
  }//ENDE KONNEKTING APPLIKATION RUNING
 }

XML-File

User Documentation

How you upload the Arduino Code

1.Step: install Arduino IDE

Getting Started can you find here: [4]

2.Step: download Arduino Libs

Download link ([5]) -> KONNEKTING Lib

Download link ([6]) -> PCF8575 I2C IO Expander

click on both links on the green Button (Clone or Download) -> Download ZIP

3.Step: add both Arduino Libs\

Installing Additional Arduino Libraries (HowTo [7])

add here the .ZIP files

4.Step:open Arduino IDE

open the Arduino Code and connect the KNX device over USB with your PC

4.Step:set the Arduino Board

click in the Arduino IDE -> Tools -> set the Board to "Arduino/Genduino Zero (Native USB Port)"

5.Step:set the USB Port

click in the Arduino IDE -> Tools -> set the Port to the Port with the name "Arduino/Genduino Zero (Native USB Port)"

5.Step:Upload the Code to the KNX-Device

click the green arrow to upload the code.

--> Finish

SW Documentation

Set "Zählerstände" over Suite

Über die Suite kann man die Zählerstände im EEPROM überschreiben.

Sperrobjekte

Room classification

Die Raumerkennung funktioniert als 16Bit Wert und jedes Bit ist ein Input. Möchte man also alle 16 Inputs zusammen als "Zimmer" definieren, dann wäre das:
b1111111111111111 = 65535
oder frei, Inputs wären hier: 1,5,6,10,14,15
b1000110001000110 = 35910
Die Dezimalwerte kann man in die Suite eingeben, beim parameterisieren werden diese Werte ins EEPROM geschrieben. Bei jedem Start werden die Daten ins RAM geladen und decodiert.
Aktuell können so 5 "Zimmer" definiert werden
16CH Binary Input Suite ZimmerErkennung.PNG

HW Documentation

Circuit diagram

One VCC Output-Pin shares two Input-Channels. Because of that always two Channels will monitoring together.

S0 interface Up to four Inputs can configure to an S0-interface. possible CH are Ch13 - Ch16 note: If you configure only one Ch to an S0-Interface on an VCC-Output pair, then the output of the other CH can not be switched off, because the VCC-Output voltage supply always both Channels.


16Ch Input
12Ch Input + 4Ch S0-Interface

Developer Documentation

State Machine

START -> Loop over all Channels (activation Outputs x + y -> readout inputs x + y -> update Status LED -> deactivation Outputs x + y)

Build It

Links