Fab Academy 2018 - Thierry Dassé
/*
* e-bin firmware
* Thierry Dassé - Fabacademy 2018
* cc-by-nc-sa
*/
#include "TinyWireM.h" // I2C library for ATtiny 25/45/85 24/44/84
#include "LiquidCrystal_attiny.h" // LCD display library for ATtiny 25/45/85 24/44/84
LiquidCrystal_I2C lcd(0x3F,16,2); // set the LCD address to 0x30 for my LCD display
#define encoderPinA 9 ///encoder pins
#define encoderPinB 10
#define pushPin 8
#define potNumber 5 // number of potentiometer
typedef struct param { //potentiometer parameters
unsigned int pin; //pin number
unsigned int zero; //value when bin is empty
unsigned int one; //value when bin contains 500g
int level; //current level
} potParam;
unsigned short encoder = 0b000111; // encoder 6 bits state
potParam potentiometer[potNumber] = {{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{5,0,0,0}}; //potentiometers pins number
unsigned long date;
bool lcdOn;
int val;
char strval[8];
int menu = 0;
int weight;
void printAt(char *s,int col,int row) {
// print a string at col and row position
int i = 0;
while (s[i] != 0) {
lcd.setCursor(col+i,row);
lcd.print(s[i]);
i++;
}
}
void print_weight() {
// print total weight of all bins on lcd display first line
int w = 0;
for (int i=0;i<potNumber;i++) {
w += map(potentiometer[i].level,potentiometer[i].zero,potentiometer[i].one,0,500);
}
if (w) {
itoa(w,strval,10);
printAt(strval,5,0);
} else {
printAt("e-bin",5,0);
}
}
void print_bin(int i) {
// print bin weight on lcd display second line
printAt("bin",1,1);
itoa(i+1,strval,10);
printAt(strval,5,1);
printAt(":",7,1);
itoa(map(potentiometer[i].level,potentiometer[i].zero,potentiometer[i].one,0,500),strval,10);
printAt(strval,9,1);
}
void setup() {
// setup function, executed one time at the begining
pinMode(encoderPinA, INPUT_PULLUP); //encoder pins are in input mode using pull up resistor
pinMode(encoderPinB, INPUT_PULLUP);
pinMode(pushPin, INPUT_PULLUP);
date = millis();
delay(1000); // wait lcd display ready before sending commands
TinyWireM.begin();
lcd.init();
lcd.backlight();
printAt("e-bin",6,0);
delay(1000);
lcd.clear();
lcdOn = true;
}
void loop() {
// main infinite loop
unsigned short readPin = (unsigned short) digitalRead(encoderPinA); //read encoder pins
encoder = (encoder & 0b110111) | (readPin << 3); //write encoderA state in the fourth digit
readPin = (unsigned short) digitalRead(encoderPinB);
encoder = (encoder & 0b101111) | (readPin << 4); //write encoderB state in the fifth digit
readPin = (unsigned short) digitalRead(pushPin);
encoder = (encoder & 0b011111) | (readPin << 5); //write push state in the sixth digit
if (encoder == 0b110111) { //turn clockwise
date = millis();
if (lcdOn) {
menu = (menu + 1 ) % (1 + potNumber);
lcd.clear();
if (menu) {
if (potentiometer[menu-1].zero != potentiometer[menu-1].one) {
print_bin(menu-1);
} else {
printAt("bin",5,0);
itoa(menu,strval,10);
printAt(strval,9,0);
printAt("click to setup",1,1);
}
} else {
print_weight();
}
}
} else if (encoder == 0b101111) { //turn counterclockwise
date = millis();
if (lcdOn) {
menu = (menu - 1 ) % (1 + potNumber);
lcd.clear();
if (menu) {
if (potentiometer[menu-1].zero != potentiometer[menu-1].one) {
print_bin(menu-1);
} else {
printAt("bin",5,0);
itoa(menu,strval,10);
printAt(strval,9,0);
printAt("click to setup",1,1);
}
} else {
print_weight();
}
}
} else if (encoder == 0b011111) { //push on encoder
date = millis();
if (lcdOn && menu) {
lcd.clear();
printAt("bin",5,0);
itoa(menu,strval,10);
printAt(strval,9,0);
printAt("click when empty",0,1);
do {
encoder = (encoder >> 3) | 0b011000;
readPin = (unsigned short) digitalRead(pushPin);
encoder = (encoder & 0b011111) | (readPin << 5);
} while (encoder != 0b011111);
potentiometer[menu-1].zero = analogRead(potentiometer[menu-1].pin);
printAt("click with 500g",0,1);
do {
encoder = (encoder >> 3) | 0b011000;
readPin = (unsigned short) digitalRead(pushPin);
encoder = (encoder & 0b011111) | (readPin << 5);
} while (encoder != 0b011111);
potentiometer[menu-1].one = analogRead(potentiometer[menu-1].pin);
lcd.clear();
if (potentiometer[menu-1].zero != potentiometer[menu-1].one) {
printAt("done",0,1);
} else {
printAt("failed",0,1);
}
}
}
encoder = encoder >> 3; // write encoder current values to encoder previous values
bool change = false;
for (int i= 0;i<potNumber;i++) {
if (potentiometer[i].zero != potentiometer[i].one) {
val = analogRead(potentiometer[i].pin);
if (abs(val-potentiometer[i].level) > 2) {
potentiometer[i].level = val;
change = true;
if (!lcdOn) {
lcdOn = true;
lcd.setBacklight(255);
}
lcd.clear();
print_bin(i);
date = millis();
}
}
}
if (change) {
print_weight();
}
if ((millis()-date > 5000) && lcdOn) { //if nothing happen during last 5s, turn display off
lcdOn = false;
lcd.setBacklight(0);
} else if ((millis()-date < 5000) && !lcdOn) {
lcdOn = true;
lcd.setBacklight(255);
}
}