Skip to content

Instantly share code, notes, and snippets.

@micw
Last active November 24, 2018 08:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save micw/8211f64559aae52ef0e888e350e52c26 to your computer and use it in GitHub Desktop.
Save micw/8211f64559aae52ef0e888e350e52c26 to your computer and use it in GitHub Desktop.
/**
* D0 - output ok
* D5 - output ok
* D6 - output ok
* D7 - output ok
*
* D3 - output ok
* D4 - output ok, internal LED is inverse
*
* D3 - pullup input ok, bootet nicht wenn LOW
* D4 - pullup input ok, bootet nicht wenn LOW
*
* D3 - pullup input ok, bootet nicht wenn LOW
* D4 - pullup input ok, bootet nicht wenn LOW
*
* D1 - pullup input ok
* D2 - pullup input ok
*/
int i=0;
typedef void (*BusActionFunction) ();
struct BusAction {
char input_type;
byte input_id;
byte state;
BusActionFunction callback;
};
class Bus {
public:
Bus(unsigned int max_actions) :
max_actions(max_actions),
actions(new BusAction[max_actions]) {
}
void send(char input_type, byte input_id, byte state) {
// this->debug(input_type, input_id, state);
for (int i=0;i<this->action_num;i++) {
BusAction& action=this->actions[i];
if (action.input_type!=input_type) continue;
if (action.input_id!=input_id) continue;
if (action.state!=state) continue;
action.callback();
}
}
void debug(char input_type, byte input_id, byte state) {
if (input_type=='b') { // a button
Serial.print("BUTTON ");
Serial.print(input_id);
Serial.print(": ");
if (state==1) {
Serial.println("klicked");
} else if (state==0) {
Serial.println("released");
} else if (state==255) {
Serial.println("pressed");
}
} else {
Serial.print("INPUT ");
Serial.print(input_type);
Serial.print(input_id);
Serial.print(": ");
Serial.println(state);
}
}
void on(char input_type, byte input_id, byte state, BusActionFunction bus_action_function) {
if (this->action_num>this->max_actions) {
Serial.println("Too much actions in bus!!");
return;
}
this->actions[this->action_num++]={input_type,input_id,state,bus_action_function};
}
private:
unsigned int max_actions;
unsigned int action_num;
BusAction* actions;
};
class Button {
public:
static const char TYPE='b';
static const int ACTION_KLICK=1;
static const int ACTION_HOLD=255;
static const int ACTION_RELEASE=0;
Button(unsigned int pin, Bus* bus, byte button_id) :
pin(pin),
bus(bus),
button_id(button_id) {
pinMode(pin,INPUT_PULLUP);
this->state=!digitalRead(pin);
this->state_since=millis();
this->debounce_state=this->state;
this->holding=0;
}
void loop() {
boolean new_state=!digitalRead(pin);
if (new_state!=this->state) {
// debounce: a state change must be pressent for at least 50ms
if (new_state!=this->debounce_state) {
this->debounce_state=new_state;
this->debounce_state_since=millis();
} else if (millis()-this->debounce_state_since>this->debounce_delay_ms) {
this->state=debounce_state;
this->state_since=millis();
}
}
if (this->state) { // button pressed
if (holding==0) {
this->holding=1;
} else if ((this->holding==1) && (millis()-this->state_since>this->holding_delay_ms)) {
this->holding=2;
// state has changed
this->bus->send(TYPE,this->button_id,ACTION_HOLD);
}
} else if (this->holding>0) { // button released
if (this->holding==1) { // klick
this->bus->send(TYPE,this->button_id,ACTION_KLICK);
} else { // holding ended
this->bus->send(TYPE,this->button_id,ACTION_RELEASE);
}
this->holding=0;
}
}
private:
unsigned int pin; // pin of this button
Bus* bus;
byte button_id;
boolean state; // current state (0 or 1)
unsigned long state_since; // state since when - required for klick/hold logic
byte holding; // 0 if button is not pressed, 1 if button is pressed less than hold_time, 2 if it's pressed longer than hold time
const unsigned long holding_delay_ms=500; // if pressed longer than this, it's holding, otherwise klicked
boolean debounce_state; // for debounce
unsigned long debounce_state_since; // for debounce
const unsigned long debounce_delay_ms=50;
};
class DimmableLed {
public:
DimmableLed(unsigned int pin):
pin(pin),
pwm_value(1023) {
pinMode(pin,OUTPUT);
update();
}
void loop() {
if (dimming) {
if (millis()-last_dim<3) return; // dim every 3 ms -> 1 dim cycle ~ 3s
last_dim=millis();
pwm_value+=dim_direction;
if (pwm_value<1) { // switch to dim_up
dim_direction=1;
pwm_value=1;
} else if (pwm_value>1300) { // max 1300 -> remain ~0.5s at 100%
dim_direction=-1;
pwm_value=1300;
}
update();
}
}
void toggle() {
on_off=!on_off;
update();
}
void dim_start() {
dimming=true;
if (!on_off) { // off -> dim up
dim_direction=1;
pwm_value=0;
on_off=true;
} else { // continue dim in other direction
dim_direction=-dim_direction;
if (pwm_value<1) pwm_value=1;
else if (pwm_value>1023) pwm_value=1023;
}
}
void dim_stop() {
dimming=false;
}
private:
unsigned int pin;
int pwm_value;
boolean on_off;
unsigned long last_dim=0;
short dim_direction=1;
boolean dimming;
void update() {
Serial.print(dim_direction);
Serial.print(" ");
Serial.println(pwm_value);
if (on_off && pwm_value>0) {
int v=pwm_value;
if (v<0) v=0;
else if (v>1023) v=1023;
analogWrite(pin,(int)pow(1023, v/1023.0));
} else {
digitalWrite(pin,0);
}
}
};
Bus bus(10);
Button b1=Button(D1,&bus,1);
DimmableLed led1(D4);
void setup() {
/*
pinMode(D1,INPUT_PULLUP);
pinMode(D2,INPUT_PULLUP);
*/
Serial.begin(115200);
bus.on(Button::TYPE,1,Button::ACTION_KLICK,[]() { led1.toggle(); });
bus.on(Button::TYPE,1,Button::ACTION_HOLD,[]() { led1.dim_start(); });
bus.on(Button::TYPE,1,Button::ACTION_RELEASE,[]() { led1.dim_stop(); });
}
void loop() {
b1.loop();
led1.loop();
/*
Serial.print(digitalRead(D1));
Serial.print(" ");
Serial.println(digitalRead(D2));
digitalWrite(D4,++i%10>5);
delay(100);
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment