Created
March 9, 2014 20:23
-
-
Save renepenner/9454043 to your computer and use it in GitHub Desktop.
Arduino Sketch for my Smart Home Controller
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Wire.h> // modify speed to 400kHz | |
#include <OneWire.h> | |
#include <SerialCommand.h> | |
#define ONEWIRECOUNT 4 | |
OneWire oneWirePorts[ONEWIRECOUNT] = {8,9,10,11}; | |
// Pattern for & bit Operation to get a 6 Bit Time info | |
const long TIM_PATTERN = 0x0000000000000000000000000000003F; | |
// Indicates a MPX Pin has chanced | |
volatile uint8_t interrupt_state = LOW; | |
uint8_t input_adrs[4] = {0x10, 0x11, 0x12, 0x13}; // MPX address for inputs | |
uint16_t input_state[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; // MPX state for inputs | |
uint8_t output_adrs[5] = {0x20, 0x21, 0x22, 0x23, 0x24}; // MPX address for inputs | |
uint16_t output_state[5] = {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}; // MPX state for output | |
/** | |
* Bit 0-2 => MXP | |
* Bit 3-6 => PIN | |
* Bit 7-9 => button Level | |
* Bit 10-15 => timeout timer | |
*/ | |
uint16_t buttons[] = { | |
0x0000, 0x0200, 0x0400, 0x0600, 0x0800, 0x0A00, 0x0C00, 0x0E00, | |
0x1000, 0x1200, 0x1400, 0x1600, 0x1800, 0x1A00, 0x1C00, 0x1E00, | |
0x2000, 0x2200, 0x2400, 0x2600, 0x2A00, 0x2800, 0x2C00, 0x2E00, | |
0x3000, 0x3200, 0x3400, 0x3600, 0x3800, 0x3A00, 0x3C00, 0x3E00, | |
0x4000, 0x4200, 0x4400, 0x4600, 0x4800, 0x4A00, 0x4C00, 0x4E00, | |
0x5000, 0x5200, 0x5400, 0x5600, 0x5800, 0x5A00, 0x5C00, 0x5E00, | |
0x6000, 0x6200, 0x6400, 0x6600, 0x6800, 0x6A00, 0x6C00, 0x6E00, | |
0x7000, 0x7200, 0x7400, 0x7600, 0x7800, 0x7A00, 0x7C00, 0x7E00 | |
}; | |
/** | |
* Bit 0-2 => MPX IN | |
* Bit 3-6 => PIN IN | |
* Bit 7-9 => MPX OUT | |
* Bit 10-13 => PIN OUT | |
* Bit 14-17 => Funktions | |
* Bit 18 => Type (0 = light | 1 = raffstore) | |
* Bit 19 => run state (timmer is running) | |
* Bit 20-23 => timmer id (is from timmer array) | |
* Bit 24-32 => timeout (1024 Resolution => approx. 1 second) | |
*/ | |
unsigned long button_config[] = { | |
0x00004000 // IN MPX 0 | IN PIN 0 | Out MPX 0 | OUT PIN 0 | FNC 0 (light) | |
}; | |
uint8_t input_mpx_size; | |
uint8_t output_mpx_size; | |
uint8_t buttons_size; | |
uint8_t button_config_size; | |
uint8_t bounce_state = LOW; | |
long last_interrupt = 0; | |
long debounceDelay = 20; | |
SerialCommand sCmd; | |
void setup(void) | |
{ | |
Wire.begin(); // set arduino to i2c master | |
Serial.begin(115200); // default 9600 | highspeed: 115200 | |
init_mpx(); | |
input_mpx_size = sizeof(input_adrs) / sizeof(uint8_t); | |
output_mpx_size = sizeof(output_adrs) / sizeof(uint8_t); | |
buttons_size = sizeof(buttons) / sizeof(uint16_t); | |
button_config_size = sizeof(button_config) / sizeof(unsigned long); | |
pinMode(2, INPUT); // set interrupt pin to input | |
digitalWrite(2, HIGH); // set pull up resistor to interrupt pin | |
attachInterrupt(0, interrupt_handler, HIGH); // add interrupt on pin 2 is HIGH ( changes in inputs of max7311 set pin 2 to HIGH ) | |
// Serial Commands: | |
sCmd.addDefaultHandler(err); | |
Serial.println("READY"); | |
/* | |
uint8_t in_mpx = (uint8_t) (button_config[0] >> 29); | |
uint8_t in_pin = (uint8_t) (button_config[0] >> 25 & 0x0000000F); | |
uint8_t out_mpx = (uint8_t) (button_config[0] >> 22 & 0x00000007); | |
uint8_t out_pin = (uint8_t) (button_config[0] >> 18 & 0x0000000F); | |
uint8_t fnc = (uint8_t) (button_config[0] >> 14 & 0x0000000F); | |
uint8_t type = (uint8_t) (button_config[0] >> 13 & 0x00000001); | |
uint8_t runstate = (uint8_t) (button_config[0] >> 12 & 0x00000001); | |
uint8_t time_id = (uint8_t) (button_config[0] >> 9 & 0x0000000F); | |
uint8_t timeout = (uint8_t) (button_config[0] & 0x000001FF); | |
*/ | |
} | |
void init_mpx() | |
{ | |
// configure inputs | |
for(uint8_t i=0;i<input_mpx_size;i++) | |
{ | |
// set CONFIG register to Input | |
Wire.beginTransmission(input_adrs[i]); | |
Wire.write(0x06); // select Register CONFIG | |
Wire.write(0xFF); // set PIN 0-7 to INPUT | |
Wire.write(0xFF); // set PIN 8-15 to INPUT | |
Wire.endTransmission(); | |
// Change Register to read Inputs | |
Wire.beginTransmission(input_adrs[i]); | |
Wire.write(0x00); // set Register to Input for next reads | |
Wire.endTransmission(); | |
} | |
// configure outputs | |
for(uint8_t i=0;i<output_mpx_size;i++) | |
{ | |
// set CONFIG register to Output | |
Wire.beginTransmission(output_adrs[i]); | |
Wire.write(0x06); // select Register CONFIG | |
Wire.write(0x00); // set PIN 0-7 to OUTPUT | |
Wire.write(0x00); // set PIN 8-15 to OUTPUT | |
Wire.endTransmission(); | |
// Set all Outputs to Off | |
Wire.beginTransmission(output_adrs[i]); | |
Wire.write(0x02); // set Register to Output for next write | |
Wire.write(0x00); // set PIN 0-7 to OFF | |
Wire.write(0x00); // set PIN 8-15 to OFF | |
Wire.endTransmission(); | |
} | |
} | |
void loop(void) | |
{ | |
refresh_input_state(); | |
tick_button_state(); | |
sCmd.readSerial(); // check for incomming commands | |
} | |
void interrupt_handler() | |
{ | |
detachInterrupt(0); | |
interrupt_state = HIGH; | |
} | |
void refresh_input_state() | |
{ | |
if(interrupt_state == HIGH){ | |
//Serial.println("interrupt"); | |
last_interrupt = millis(); | |
interrupt_state = LOW; | |
bounce_state = HIGH; | |
} | |
if(bounce_state == HIGH && (last_interrupt + 25) < millis()){ // wait bounce delay time after interrupt | |
//Serial.println("Check Inputs"); | |
for(uint8_t i=0;i<input_mpx_size;i++){ // read all multiplexer | |
Wire.requestFrom((uint8_t)input_adrs[i],(uint8_t) 2); | |
byte low_byte = Wire.read(); | |
byte high_byte = Wire.read(); | |
word new_state = high_byte << 8 | low_byte; | |
if(input_state[i] != new_state){ | |
//Serial.print("NEW STATE ON "); | |
//Serial.println(i, DEC); | |
input_state[i] = new_state; | |
break; // interrupt found ... no need to check more | |
} | |
} | |
bounce_state = LOW; | |
attachInterrupt(0, interrupt_handler, HIGH); | |
} | |
} | |
void tick_button_state() | |
{ | |
uint8_t NOW = millis() >> 5 & TIM_PATTERN; | |
for(uint8_t i=0;i<buttons_size;i++) | |
{ | |
uint8_t MPX = (uint8_t) (buttons[i] >> 13); // first 3 Bit | |
uint8_t PIN = (uint8_t) (buttons[i] >> 9 & 0x000F); // next 4 Bit | |
uint8_t LEV = (uint8_t) (buttons[i] >> 6 & 0x0007); // next 3 Bit | |
uint8_t TIM = (uint8_t) (buttons[i] & 0x003F); // last 6 Bit | |
uint8_t IDX = MPX*16+PIN; | |
// calc distance between NOW and TIM | |
uint8_t DIFF = 0; | |
if(TIM > NOW){ | |
DIFF = 63-NOW+TIM; | |
}else{ | |
DIFF = NOW-TIM; | |
} | |
// Level 0 | |
if(LEV == 0) | |
{ | |
if(bitRead(input_state[MPX], PIN) == 0){ // BTN-DOWN detected | |
buttons[i] &= 0xFE00; // reset LEV and TIM | |
buttons[i] |= ( 1 << 6 | NOW ); // set new LEV (1) and new TIM (NOW) | |
} | |
} | |
// Level 1 | |
else if(LEV == 1) | |
{ | |
if(DIFF > 19) // timeout 640ms or bigger (20 * 32=>640) | |
{ | |
buttons[i] &= 0xFE3F; // reset LEV | |
buttons[i] |= ( 0x0004 << 6 ); // set LEV (4) | |
btn_press(IDX); // call press action | |
} | |
else if(bitRead(input_state[MPX], PIN) == 1) // BTN-UP detected | |
{ | |
buttons[i] &= 0xFE00; // reset LEV and TIM | |
buttons[i] |=( 2 << 6 | NOW ); // set LEV (2) and new TIM (NOW) | |
} | |
} | |
// Level 2 | |
else if(LEV == 2) | |
{ | |
if(DIFF > 6) // timeout 192ms or bigger(7 * 32=>224) | |
{ | |
buttons[i] &= 0xFE3F; // reset LEV => automatic set LEV to 0 | |
btn_click(IDX); // call click action | |
} | |
else if(bitRead(input_state[MPX], PIN) == 0) // BTN-DOWN detected | |
{ | |
buttons[i] &= 0xFE3F; // reset LEV | |
buttons[i] |=( 3 << 6 ); // set LEV (3) | |
} | |
} | |
// Level 3 | |
else if(LEV == 3 && bitRead(input_state[MPX], PIN) == 1) | |
{ | |
buttons[i] &= 0xFE3F; // reset LEV => automatic set LEV to 0 | |
btn_doubleclick(IDX); | |
} | |
// Level 4 | |
else if(LEV == 4 && bitRead(input_state[MPX], PIN) == 1) | |
{ | |
buttons[i] &= 0xFE3F; // reset LEV => automatic set LEV to 0 | |
btn_release(IDX); | |
} | |
} | |
} | |
void btn_click(uint8_t IDX) | |
{ | |
Serial.print("click "); | |
Serial.println(IDX); | |
doAction(1,IDX); | |
} | |
void btn_doubleclick(uint8_t IDX) | |
{ | |
Serial.print("doubleclick "); | |
Serial.println(IDX); | |
doAction(2, IDX); | |
} | |
void btn_press(uint8_t IDX) | |
{ | |
Serial.print("press "); | |
Serial.println(IDX); | |
doAction(4,IDX); | |
} | |
void btn_release(uint8_t IDX) | |
{ | |
Serial.print("release "); | |
Serial.println(IDX); | |
doAction(8,IDX); | |
} | |
void doAction(uint8_t fnc_call, uint8_t INX) | |
{ | |
// run through all configs | |
for(int i=0; i<button_config_size; i++) | |
{ | |
uint8_t adrs = (uint8_t) (button_config[0] >> 25 & 0x0000007F); | |
// check called input index matches config input index (index => MPX + PIN) | |
if(INX == adrs) | |
{ | |
uint8_t fnc = (uint8_t) (button_config[0] >> 14 & 0x0000000F); | |
// check called function ist in config | |
if(fnc & fnc_call != 0) | |
{ | |
uint8_t type = (uint8_t) (button_config[0] >> 13 & 0x00000001); | |
uint8_t out_mpx = (uint8_t) (button_config[0] >> 22 & 0x00000007); | |
uint8_t out_pin = (uint8_t) (button_config[0] >> 18 & 0x0000000F); | |
// check config is for light or raffstore | |
if(type == 0){ | |
// light | |
switch(fnc_call) { | |
case 1: | |
// click | |
toogleOutputPin(out_mpx, out_pin); | |
break; | |
case 2: | |
// doubleclick | |
break; | |
case 4: | |
// press | |
break; | |
case 8: | |
// release | |
break; | |
} | |
}else{ | |
// raffstore | |
switch(fnc_call) { | |
case 1: | |
// click | |
break; | |
case 2: | |
// doubleclick | |
break; | |
case 4: | |
// press | |
break; | |
case 8: | |
// release | |
break; | |
} | |
} | |
} | |
} | |
} | |
} | |
void toogleOutputPin(uint8_t mpx, uint8_t pin) | |
{ | |
output_state[mpx] ^= 1 << pin; // flip output bit | |
uint8_t low_byte = highByte(output_state[mpx]); | |
uint8_t high_byte = lowByte(output_state[mpx]); | |
Serial.println(low_byte, HEX); | |
Serial.println(high_byte, HEX); | |
Wire.beginTransmission(output_adrs[mpx]); | |
Wire.write(0x02); // set Register to Input for next reads | |
Wire.write(high_byte); // set PIN 0-7 to OFF | |
Wire.write(low_byte); // set PIN 8-15 to OFF | |
Wire.endTransmission(); | |
} | |
void err() | |
{ | |
Serial.println(F("err")); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment