This content originally appeared on DEV Community and was authored by Jorge Martin
This is the blog of the P3-SETR, where I have created a Vending Machine Controller using an Arduino Kit.
Schematic
Here I show you the schematic of the circuit.
Components
Component Name | Amount |
---|---|
Arduino Uno board | x1 |
Protoboard | x1 |
LEDs | x2 |
Button | x1 |
DHT11 sensor | x1 |
Ultrasonic sensor | x1 |
Joystick | x1 |
LCD | x1 |
330Ω resistance | x3 |
2kΩ resistance | x1 |
Requirements
- One of the LEDs must be connected to a digital input (pin 1 to pin 13) in order to be able to modify the LED intensity using pulse-width modulation (PWM).
- The button must be connected in the pin 2 or 3, those pins are associated to the interruptions.
- The joystick have 2 potentiometer (X and Y) that generate analogic signals so the pins related to the X and Y axis of the joystick must being connected to an analogic input.
- The button of the joystick must be connected to a digital input in order to be able to declare the button as a pull-up input.
Coding
Libraries
During this proyect we need to use multiple libraries.
- This library is related to the implementation and management of threads.
#include <Thread.h>
#include <ThreadController.h>
#include <StaticThreadController.h>
- This library is used to control the LCD.
#include <LiquidCrystal.h>
- This library is necessary to interact with the DHT sensor.
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
- This library is used to set and control timers.
#include "TimerOne.h"
- This library is used to set and control the watchdog.
#include <avr/wdt.h>
Threads
To make this project i used 5 differents thread associated to periodic tasks.
- Show distance in real time.
// Creation of threads
Thread show_distanceThread = Thread();
void setup(){
Serial.begin(9600);
// show_distance Thread config
show_distanceThread.enabled = true;
show_distanceThread.setInterval(200);
show_distanceThread.onRun(callback_measure_distance);
}
void callback_measure_distance(){
// Send a 10us pulse
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Calculate the distance in cm
t = pulseIn(echoPin, HIGH);
d = t/59;
// Print on the LCD the actual disntance
lcd.clear();
lcd.print(d);
lcd.print(" cm");
}
- Show how much time has passed since the program started.
// Creation of threads
Thread clockThread = Thread();
void setup(){
Serial.begin(9600);
// clock Thread config
clockThread.enabled = true;
clockThread.setInterval(200);
clockThread.onRun(callback_clock);
}
void callback_clock(){
initial_time = millis();
lcd.clear();
lcd.print(initial_time);
}
- Check if someone is near the machine (< 1m).
// Creation of threads
Thread check_distanceThread = Thread();
void setup(){
Serial.begin(9600);
// check_distance Thread config
check_distanceThread.enabled = true;
check_distanceThread.setInterval(2500);
check_distanceThread.onRun(callback_check_distance);
}
void callback_check_distance() {
// Send a 10us pulse
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Calculate the distance in cm
t = pulseIn(echoPin, HIGH);
d = t/59;
lcd.clear();
// If someone is < 1m from the sensor, distance = true
if (d < 100){
distance = true;
}
else{
distance = false;
show_temp = true;
}
return distance, show_temp;
}
Controller
For the next 2 threads we will need a controller, because one of the threads will show the temperature and the other will show the humidity, they must update themselves, but they must be executed interleaved.
- Show temperature thread.
// Creation of threads
Thread measure_tempThread = Thread();
void setup(){
Serial.begin(9600);
// measure_temp Thread config
measure_tempThread.enabled = true;
measure_tempThread.setInterval(1000);
measure_tempThread.onRun(callback_measure_temp);
}
void callback_measure_temp() {
// Lógica para medir la temperatura aquí
temperature = dht.readTemperature();
lcd.clear();
lcd.print("T: ");
lcd.print(temperature);
lcd.print("C");
delay(1000);
}
- Show humidity thread.
// Creation of threads
Thread measure_humThread = Thread();
void setup(){
Serial.begin(9600);
// measure_hum Thread config
measure_humThread.enabled = true;
measure_humThread.setInterval(1000);
measure_humThread.onRun(callback_measure_hum);
}
void callback_measure_hum() {
// Lógica para medir la humedad aquí
humidity = dht.readHumidity();
lcd.clear();
lcd.print("H: ");
lcd.print(humidity);
lcd.print("%");
}
- Controller for the two threads.
// Creation of the controller
ThreadController controller = ThreadController();
void setup(){
Serial.begin(9600);
// adding measure_temp Thread and measure_hum Thread to the controller
controller.add(&measure_tempThread);
controller.add(&measure_humThread);
}
void admin_temp(){
while (analogRead(pinX) > 400){
controller.run();
}
}
Interruption
I used interruptions to be able to enter the admin mode and reset while serving a coffee.
I used 2 types of interruptions:
- Hardware interruption.
void setup() {
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(BUTTON), button_pressed, CHANGE);
}
- Software interruption.
void setup() {
Serial.begin(9600);
Timer1.initialize(1000000);
Timer1.attachInterrupt(callback_count);
}
- Both interruptions:
void button_pressed() {
// Enable interruptions
interrupts();
// Enable the watchdog (8sec)
wdt_enable(WDTO_8S);
// If the button is not pressed
if (digitalRead(BUTTON) == HIGH) {
wdt_disable();
// Stops the timer
Timer1.stop();
// Depending on the time and where were you before entering the interruption does a thing or an other
if (pressed_time >= 2 && pressed_time <= 3) {
// Reset pressed_time
pressed_time = 0;
Serial.println("Botón pulsado entre 2 y 3 segundos");
if (check_serve == true){
check_serve = false;
menu();
}
}
else if (pressed_time >= 5) {
// Reset pressed_time
pressed_time = 0;
Serial.println("Botón pulsado más de 5 segundos");
if (check_admin == false){
admin();
}
else if (check_admin == true){
analogWrite(LED2, 0);
digitalWrite(LED1, LOW);
menu();
}
}
// Reset pressed_time
pressed_time = 0;
}
else {
// Enable interruptions
interrupts();
// Enable watchdog(8s)
wdt_enable(WDTO_8S);
// Start the timer
Timer1.start();
}
}
void callback_count() {
// Disable interruptions
noInterrupts();
pressed_time++;
Serial.println(pressed_time);
}
Variables
To modify variables that are inside interruptions, we need to declare them as volatile.
volatile bool check_admin = false;
volatile int pressed_time;
volatile bool check_serve = false;
TimerOne
We need to use TimerOne library because the Timer0 of the Arduino board doesn´t work while it´s inside an interruption, so, to count how many seconds have you been pressing the button we need it.
Watchdog
This program has a watchdog in the interruptions, in case something has blocked or is not responding to the behavior wanted, the watchdog resets the system after 8 seconds.
void setup() {
Serial.begin(9600);
// Disable the watchdog
wdt_disable();
}
void button_pressed() {
// Enable the watchdog (8sec)
wdt_enable(WDTO_8S);
}
Functionality
- Client mode. (In case the video doesn´t play try this link: https://youtu.be/roYreZuSSTw)
- Admin mode. (In case the video doesn´t play try this link: https://youtu.be/-UY6RScsZmc)
This content originally appeared on DEV Community and was authored by Jorge Martin
Jorge Martin | Sciencx (2024-09-11T12:13:36+00:00) Vending Machine Controller. Retrieved from https://www.scien.cx/2024/09/11/vending-machine-controller/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.