Skip to content

Instantly share code, notes, and snippets.

@renepenner
Created March 9, 2014 20:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save renepenner/9454043 to your computer and use it in GitHub Desktop.
Save renepenner/9454043 to your computer and use it in GitHub Desktop.
Arduino Sketch for my Smart Home Controller
#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