Fab Academy 2018 - Thierry Dassé

Bin project

Rules

Firmware

/*
 * 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);
  }
}