/*
* hose display for Maker Faire Hannover 2016
* Version 1.0
* Copyright (C) 2016 Hartmut Wendt www.hwhardsoft.de
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <AFMotor.h>
#include <font5x7.h>
#define DEBOUNCE 10 // button debouncer, how many ms to debounce, 5+ ms is usually plenty
// here is where we define the buttons that we'll use. button "1" is the first, button "6" is the 6th, etc
byte buttons[] = {14, 15, 17, 18, 19}; // the analog 0-5 pins are also known as 14-19
// This handy macro lets us determine how big the array up above is, by checking the size
#define NUMBUTTONS sizeof(buttons)
// we will track if a button is just pressed, just released, or 'currently pressed'
byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS];
byte previous_keystate[NUMBUTTONS], current_keystate[NUMBUTTONS];
unsigned char pump_air_cnt;
unsigned char pump_liquid_cnt;
unsigned char last_pixel;
unsigned char display_row[8];
const unsigned char test_pattern[] = {
0xC0, 0xC0, 0x00,
0x40, 0x3C, 0x02,
0x40, 0x3C, 0x02,
0x40, 0x3C, 0x02,
0x40, 0x3C, 0x02,
0x40, 0x3C, 0x02,
0x40, 0x3C, 0x02,
};
const unsigned char Maker_pattern[] = {
0xC0, 0xC0, 0xC0,
0x89, 0x92, 0xEE,
0xDA, 0x54, 0x89,
0xAB, 0xD8, 0xCE,
0x8A, 0x54, 0x89,
0x8A, 0x52, 0xE9,
};
const unsigned char Faire_pattern[] = {
0xC0, 0xC0, 0xC0,
0x73, 0x3B, 0x9C,
0x44, 0x92, 0x50,
0x77, 0x93, 0x9C,
0x44, 0x92, 0x50,
0x44, 0xBA, 0x5C,
};
// program modes
enum {
PM_stop, // program mode stop
PM_pump_air, // program mode pump air runs endless
PM_pump_liquid, // program mode pump liquid runs endless
PM_demo, // program mode full automatic demo
PM_demo2, // program mode full automatic demo
PM_test, // shows test pattern
PM_wait, // wait 1 min in demo
PM_wait2, // wait 1 min in demo
};
// set pin numbers:
#define buttonStop 0
#define buttonDemo 1
#define buttonPumpAir 4
#define buttonPumpLiquid 3
#define buttonTest 2
#define pixel_liquid 0
#define pixel_air 1
#define RIGHT 0
#define LEFT 1
#define space_picture_start 10
//#define space_picture_loop 30
//#define space_picture_end 62
#define space_picture_loop 7
#define space_picture_end 13
#define pump_speed 80 //80
#define pump_steps 200
#define pump_delay 100 //100
AF_Stepper pump_liquid(pump_steps, 2);
AF_Stepper pump_air(pump_steps, 1);
unsigned char PMode = PM_stop;
unsigned int wait_cnt;
/*
void draw_pixel_air() {
if (pump_air_cnt < 2) {
pump_air.step(66, BACKWARD, SINGLE);
pump_air_cnt++;
} else {
pump_air.step(68, BACKWARD,SINGLE);
pump_air_cnt = 0;
}
pump_air.release();
delay(5);
}
void draw_pixel_liquid() {
if (pump_liquid_cnt < 2) {
pump_liquid.step(66, BACKWARD, SINGLE);
pump_liquid_cnt++;
} else {
pump_liquid.step(68, BACKWARD, SINGLE);
pump_liquid_cnt = 0;
}
pump_liquid.release();
delay(5);
}
*/
void draw_pixel_air() {
pump_air.step(200, FORWARD, DOUBLE);
pump_air.release();
//delay(5);
}
void draw_pixel_liquid() {
pump_liquid.step(200, FORWARD, DOUBLE);
pump_liquid.release();
//delay(5);
}
void copy_line(unsigned char ucline, const unsigned char *pattern) {
unsigned char uc1;
for (uc1 = 0; uc1 < 3; uc1++) {
display_row[uc1] = pattern[(ucline * 3) + uc1];
}
}
void draw_line(unsigned ucdirection) {
unsigned char uc1, uc2;
if (ucdirection == LEFT) {
for (uc1 = 0; uc1 < 3; uc1++)
for (uc2 = 0; uc2 < 8; uc2++) {
if ((display_row[uc1] << uc2) & 0x80) {
if (last_pixel != pixel_liquid) delay(pump_delay);
draw_pixel_liquid();
last_pixel = pixel_liquid;
} else {
if (last_pixel != pixel_air) delay(pump_delay);
draw_pixel_air();
last_pixel = pixel_air;
}
}
} else {
for (uc1 = 3; uc1 > 0; uc1--)
for (uc2 = 0; uc2 < 8; uc2++) {
if ((display_row[uc1 - 1] >> uc2) & 0x01) {
if (last_pixel != pixel_liquid) delay(pump_delay);
draw_pixel_liquid();
last_pixel = pixel_liquid;
} else {
if (last_pixel != pixel_air) delay(pump_delay);
draw_pixel_air();
last_pixel = pixel_air;
}
}
}
}
void draw_empty_space(unsigned char ucSpace) {
unsigned char uc1;
for (uc1 = 0; uc1 < ucSpace; uc1++) draw_pixel_air();
}
void draw_picture(const unsigned char *pattern) {
//draw_empty_space(space_picture_start);
copy_line(0, pattern);
draw_line(RIGHT);
draw_empty_space(space_picture_loop);
copy_line(1, pattern);
draw_line(LEFT);
draw_empty_space(space_picture_loop);
copy_line(2, pattern);
draw_line(RIGHT);
draw_empty_space(space_picture_loop);
copy_line(3, pattern);
draw_line(LEFT);
draw_empty_space(space_picture_loop);
copy_line(4, pattern);
draw_line(RIGHT);
draw_empty_space(space_picture_loop);
copy_line(5, pattern);
draw_line(LEFT);
draw_empty_space(space_picture_end);
}
void check_switches()
{
static byte previousstate[NUMBUTTONS];
static byte currentstate[NUMBUTTONS];
static long lasttime;
byte index;
if (millis() < lasttime) {
lasttime = millis(); // we wrapped around, lets just try again
}
if ((lasttime + DEBOUNCE) > millis()) {
return; // not enough time has passed to debounce
}
// ok we have waited DEBOUNCE milliseconds, lets reset the timer
lasttime = millis();
for (index = 0; index < NUMBUTTONS; index++) {
justpressed[index] = 0; // when we start, we clear out the "just" indicators
justreleased[index] = 0;
currentstate[index] = digitalRead(buttons[index]); // read the button
if (currentstate[index] == previousstate[index]) {
if ((pressed[index] == HIGH) && (currentstate[index] == HIGH)) {
// just pressed
justpressed[index] = 1;
}
else if ((pressed[index] == LOW) && (currentstate[index] == LOW)) {
// just released
justreleased[index] = 1;
}
pressed[index] = !currentstate[index]; // remember, digital HIGH means NOT pressed
}
//Serial.println(pressed[index], DEC);
previousstate[index] = currentstate[index]; // keep a running tally of the buttons
}
}
byte thisSwitch_justPressed() {
byte thisSwitch = 255;
check_switches(); //check the switches & get the current state
for (byte i = 0; i < NUMBUTTONS; i++) {
current_keystate[i] = justpressed[i];
if (current_keystate[i] != previous_keystate[i]) {
if (current_keystate[i]) thisSwitch = i;
}
previous_keystate[i] = current_keystate[i];
}
return thisSwitch;
}
void setup() {
byte i;
Serial.begin(9600); // set up Serial library at 9600 bps
Serial.println("bit.flow!");
// set input pins for keys
pump_liquid.setSpeed(pump_speed); // 100 rpm
pump_air.setSpeed(pump_speed); // 100 rpm
pump_liquid.release();
pump_air.release();
pump_air_cnt = 0;
pump_liquid_cnt = 0;
// Make input on switch pins
for (i = 0; i < NUMBUTTONS; i++) {
pinMode(buttons[i], INPUT);
}
}
void loop() {
byte thisSwitch = thisSwitch_justPressed();
switch (thisSwitch)
{
case buttonStop:
Serial.println("switch Stop just pressed");
PMode = PM_stop;
break;
case buttonDemo:
Serial.println("switch demo just pressed");
PMode = PM_demo;
break;
case buttonTest:
Serial.println("switch test pattern just pressed");
PMode = PM_test;
break;
case buttonPumpLiquid:
Serial.println("switch pump liquid just pressed");
PMode = PM_pump_liquid;
break;
case buttonPumpAir:
Serial.println("switch pump air just pressed");
PMode = PM_pump_air;
break;
}
switch (PMode) {
case PM_stop:
pump_air.release();
pump_liquid.release();
break;
case PM_pump_air:
draw_pixel_air();
break;
case PM_pump_liquid:
draw_pixel_liquid();
break;
case PM_test:
draw_picture(test_pattern);
PMode = PM_stop;
break;
case PM_demo:
draw_picture(Maker_pattern);
wait_cnt = 0;
PMode = PM_wait;
break;
case PM_demo2:
draw_picture(Faire_pattern);
wait_cnt = 0;
PMode = PM_wait2;
break;
case PM_wait:
delay(10);
wait_cnt++;
if (wait_cnt > 6000) PMode = PM_demo2;
break;
case PM_wait2:
delay(10);
wait_cnt++;
if (wait_cnt > 6000) PMode = PM_demo;
break;
}
}