/**
@file project1.ino
display
sda pin 20
scl pin 21
buzzer
pin 10
motor
pin 9
debugging pullup switch
pin 53
**/
#include <avr/io.h>
#include <util/delay.h>
#include "I2C_Display.h"
#include "HX711.h"
// define const
#define PRODUCT_1_CYCLE_SEC 40
#define PRODUCT_2_CYCLE_SEC 100
#define PRODUCT_1_DEBUG_CYCLE_SEC 4
#define PRODUCT_2_DEBUG_CYCLE_SEC 10
#define false 0x0
#define true 0x1
#define bool unsigned char
#define CALIBRATE 650000
LiquidCrystal_I2C lcd(0x27, 16, 2);
HX711 scale;
volatile bool PRODUCT_1_MEASUREMENT = false;
volatile bool PRODUCT_2_MEASUREMENT = false;
volatile int PRODUCT_1_TIMER_CYCLE = PRODUCT_1_CYCLE_SEC;
volatile int PRODUCT_2_TIMER_CYCLE = PRODUCT_2_CYCLE_SEC;
volatile int product_1_timer_count = 0;
volatile int product_2_timer_count = 0;
volatile int custom_timer = false;
volatile int timeout_count = 0;
volatile long weight = 0;
// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = 2;
const int LOADCELL_SCK_PIN = 3;
/// Setup 1 sec periodic timer and callback
// Using Timer1
void setup_timer() {
// enable global timer
cli();
// enable required timer interupt
TIMSK1 |= (1 << TOIE1);
//set mode of the timer
TCCR1A &= (~(1 << WGM10)) & (~(1 << WGM11));
TCCR1B &= (~(1 << WGM12)) & (~(1 << WGM13));
// set prescaler for the timer
TCCR1B |= (1 << CS12) | (1 << CS10);
TCCR1B &= (~(1 << CS11)); //1024
// preload timer. 15625 count for a sec
TCNT1 = 49911;
sei();
}
/// setup callback
ISR(TIMER1_OVF_vect) {
timer_callback();
TCNT1 = 49911;
}
// using Timer2
// channel A pin 10 for buzzer
// and channel B pin 9 for motor
void setup_pwm_for_buzzer_and_motor() {
// pin 9,PH6,B
// pin 10,PB4,A
DDRH |= (1 << DDH6);
DDRB |= (1 << DDB4);
TCCR2A |= (1 << COM2A1) | (1 << COM2B1) | (1 << WGM21) | (1 << WGM20);
TCCR2B = (1 << CS22);
OCR2A = 0;
OCR2B = 0;
}
// void loop() {
// for( int i = 0; i < 500; i++){
// OCR2A = i;
// // OCR2B = i;
// delay(30);
// }
// OCR2A = 0;
// // OCR2B = 0;
// delay(500);
// }
// can be play custom tone
void product_1_tone() {
Serial.println("product 1 tone start");
// 5 sec
OCR2A = 200;
timeout_count = 5;
while (timeout_count > 0) {
display_state();
}
OCR2A = 0;
Serial.println("product 1 tone end");
}
// can be play custom tone
void product_2_tone() {
Serial.println("product 2 tone start");
// 5 sec
OCR2A = 100;
timeout_count = 5;
while (timeout_count > 0) {
display_state();
}
OCR2A = 0;
Serial.println("product 2 tone end");
}
int weight_product(int min, int max) {
// on success it will return true
Serial.println("weight product");
if (scale.is_ready()) {
weight = scale.read();
Serial.print("HX711 reading: ");
Serial.println(weight);
} else {
Serial.println("HX711 not found.");
}
// display weight
display_state();
if (weight >= min && (max == -1 || weight <= max)) {
Serial.println("weight product return true");
return true;
}
Serial.println("weight product return false");
return false;
}
// start pwm output for motor
void start_motor() {
Serial.println("start motor");
OCR2B = 255;
}
// stop pwm output for motor
void stop_motor() {
Serial.println("stop motor");
OCR2B = 0;
}
// product 1 measurement logics
void product_1_mesurement() {
Serial.println("product 1 measurement start");
// enable custom timer and disable main timer
custom_timer = true;
// play tone, blocking function. function retuns after 5 sec
product_1_tone();
// set 5 sec timeout
timeout_count = 5;
// clear weight mask
bool weight_mask = false;
// check until weight provided or timeout
while (weight_mask == false && timeout_count > 0) {
weight_mask = weight_product(500, -1);
}
// on activate
if (weight_mask == true) {
// start motor pwm
start_motor();
// timeout for 100 sec
timeout_count = 100;
weight_mask = false;
// wait until measure weight + 20 or 100 sec timeout
while (weight_mask == false && timeout_count > 0) {
weight_mask = weight_product(weight + 20, -1);
}
// stop motor
stop_motor();
}
// enable default timer
custom_timer = false;
Serial.println("product 1 measurement end");
}
void product_2_mesurement() {
Serial.println("product 2 measurement start");
// enable custom timer and disable main timer
custom_timer = true;
// play tone, blocking function. function retuns after 5 sec
product_2_tone();
// set 5 sec timeout
timeout_count = 5;
// clear weight mask
int weight_mask = false;
// check until weight provided or timeout
while (weight_mask == false && timeout_count > 0) {
weight_mask = weight_product(100, 500);
}
// on activate
if (weight_mask == true) {
// start motor pwm
start_motor();
// timeout for 100 sec
timeout_count = 100;
weight_mask = false;
// wait until measure weight + 10 or 100 sec timeout
while (weight_mask == false && timeout_count > 0) {
weight_mask = weight_product(weight + 10, -1);
}
// stop motor
stop_motor();
}
// enable default timer
custom_timer = false;
Serial.println("product two measuremnt stop");
}
// for displaying
bool product_1 = true;
void display_state() {
Serial.println("display state");
// clear display
// lcd.clear();
// first row, show weight
lcd.setCursor(0, 0);
String str = String(weight) + String(" g");
Serial.println(str);
lcd.printstr(str.c_str());
if (PRODUCT_1_MEASUREMENT == true || PRODUCT_2_MEASUREMENT == true) {
lcd.setCursor(0, 1);
if (product_1 == true) {
lcd.printstr(String("Product 1 weight").c_str());
} else {
lcd.printstr(String("Product 2 weight").c_str());
}
return;
}
// calculate time in hours minutes and seconds
int hour = product_1_timer_count / 3600;
int minutes = (product_1_timer_count - (hour * 3600)) / 60;
int seconds = product_1_timer_count - ((hour * 3600) + (minutes * 60));
// second row
lcd.setCursor(0, 1);
// show timer
str = String(hour) + String(":") + String(minutes) + String(":") + String(seconds) + String(" ");
Serial.println(str);
lcd.printstr(str.c_str());
// calculate time in hours minutes and seconds
hour = product_2_timer_count / 3600;
minutes = (product_2_timer_count - (hour * 3600)) / 60;
seconds = product_2_timer_count - ((hour * 3600) + (minutes * 60));
// second row
lcd.setCursor(8, 1);
// show timer
str = String(hour) + String(":") + String(minutes) + String(":") + String(seconds) + String(" ");
Serial.println(str);
lcd.printstr(str.c_str());
}
// pin change interrupt setup on pin D53
void setup_interrupt() {
// enable pin change inerrupt 0
PCICR |= (1 << PCIE0);
// enable interrupt on pin
PCMSK0 |= (1 << PCINT0);
// set as input pin
DDRB &= ~(1 << DDB0);
}
/// on pin D53, pin change interrupt handler ISR
ISR(PCINT0_vect) {
read_debug_state();
}
void read_debug_state() {
// read pullup switch state and update
PRODUCT_1_TIMER_CYCLE = (PINB & (1 << DDB0)) ? PRODUCT_1_DEBUG_CYCLE_SEC : PRODUCT_1_CYCLE_SEC;
PRODUCT_2_TIMER_CYCLE = (PINB & (1 << DDB0)) ? PRODUCT_2_DEBUG_CYCLE_SEC : PRODUCT_2_CYCLE_SEC;
Serial.print("Debug State ");
Serial.print(PRODUCT_1_TIMER_CYCLE);
Serial.print(" ");
Serial.println(PRODUCT_2_TIMER_CYCLE);
}
// setup everything
void setup() {
Serial.begin(9600);
// initial timer
setup_timer();
// pwm for buzzer and motor
setup_pwm_for_buzzer_and_motor();
// // init display
lcd.begin();
// turn on display backlight
lcd.backlight();
display_state();
// // set input pullup for time delay from 4 hours to 5 seconds, pin 53
// // D53
setup_interrupt();
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
scale.set_scale(CALIBRATE); // this value is obtained by calibrating the scale with known weights;
scale.tare();
read_debug_state();
Serial.println("Setup finished");
}
// infine loop
void loop() {
// Serial.println(OCR1A);
// Serial.println("loop");
display_state();
if (PRODUCT_1_MEASUREMENT == true) {
Serial.println("loop product 1 measurement");
product_1 = true;
product_1_mesurement();
PRODUCT_1_MEASUREMENT = false;
}
if (PRODUCT_2_MEASUREMENT == true) {
Serial.println("loop product 2 measurement");
product_1 = false;
product_2_mesurement();
PRODUCT_2_MEASUREMENT = false;
}
}
// 1 sec periodic callback
void timer_callback() {
Serial.print("timer call back ");
Serial.print(product_1_timer_count);
Serial.print(" ");
Serial.println(product_2_timer_count);
// if custom timer is enabled then ignore others
if (custom_timer == true) {
timeout_count--;
Serial.println("custom timer");
return;
} else if (PRODUCT_1_MEASUREMENT == false && PRODUCT_2_MEASUREMENT == false) {
// product 1
product_1_timer_count++;
if (product_1_timer_count >= PRODUCT_1_TIMER_CYCLE) {
// on overflow, set flag for measurement of product 1
// Serial.println("product 1 mask");
PRODUCT_1_MEASUREMENT = true;
// reset the timer
product_1_timer_count = 0;
}
// product 2
product_2_timer_count++;
if (product_2_timer_count >= PRODUCT_2_TIMER_CYCLE) {
// on overflow, set flag for measurement of product 1
// Serial.println("product 2 mask");
PRODUCT_2_MEASUREMENT = true;
// reset the timer
product_2_timer_count = 0;
}
}
}