#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "freertos/queue.h"
#include "esp_timer.h"
//Variable para ir contando el pago y el cambio
int coins = 0;
int cambio=0;
QueueHandle_t handlerQueue;
//Macros para los botones
#define INPUT_PIN_1 16
#define INPUT_PIN_5 17
#define INPUT_PIN_10 18
#define INPUT_PIN_20 19
//Macros para los leds
#define LED_PIN_1 21
#define LED_PIN_5 22
#define LED_PIN_10 23
#define LED_PIN_20 25
//Arreglo para optimizar la inicializacion de botones
const int InputBtn[] = {
INPUT_PIN_1,
INPUT_PIN_5,
INPUT_PIN_10,
INPUT_PIN_20
};
//Arreglo para optimizar la inicializacion de leds
const int OutputLed[] = {
LED_PIN_1,
LED_PIN_5,
LED_PIN_10,
LED_PIN_20
};
//Estructura para los posibles estados de la maquina
typedef enum {
En_espera,
Pagando,
Imprimiendo_recibo
} ParkingState;
ParkingState state = En_espera;
int state_old[4]; //Estados viejos
int64_t tm_old[4]; //Tiempos
int64_t tm_btn_old =0; //Variable para tomar el tiempo desde la ultima vez presionado
int64_t tm_btn_now=0; //Variable para saber el tiempo actual
int64_t time_millis(void)
{
return (esp_timer_get_time()/1000); //devuelve millis
}
void init_gpio(void){
//Configuracion de los botones como entrada con pull down interno
for(int i = 0; i<4 ; i++){
gpio_reset_pin(InputBtn[i]);
gpio_set_direction(InputBtn[i], GPIO_MODE_INPUT);
gpio_pulldown_en(InputBtn[i]);
gpio_pullup_dis(InputBtn[i]);
}
//Configuracion de los leds como salida
for(int i=0; i<4; i++){
gpio_reset_pin(OutputLed[i]);
gpio_set_direction(OutputLed[i], GPIO_MODE_OUTPUT);
gpio_set_level(OutputLed[i], 0);
}
}
//Funcion de la interrupcion
static void IRAM_ATTR gpio_interrupt_handler(void *args){
int pinNumber = (int)args;
int i;
for (i = 0; i < 4; i++) {
if (InputBtn[i] == pinNumber){
break;
}
}
int64_t tm_now = time_millis();
if (tm_now - tm_old[i] > 200) {
tm_old[i] = tm_now;
xQueueSendFromISR(handlerQueue, &pinNumber, NULL);
}
}
//funcion para desplegar cambio en los leds
void cambio_Leds(int cambio)
{
while(cambio > 0)
{
if(cambio >= 10){
gpio_set_level(OutputLed[2], 1); //Enciende LEd 10 pesos
vTaskDelay(500 / portTICK_PERIOD_MS);
gpio_set_level(OutputLed[2], 0);
vTaskDelay(500 / portTICK_PERIOD_MS);
cambio -= 10;
printf("Devolviendo moneda de 10 pesos\n");
}else if(cambio >= 5){
cambio -=5;
gpio_set_level(OutputLed[1], 1); //Enciende LEd 5 pesos
vTaskDelay(500 / portTICK_PERIOD_MS);
gpio_set_level(OutputLed[1], 0);
vTaskDelay(500 / portTICK_PERIOD_MS);
printf("Devolviendo moneda de 5 pesos\n");
}else{
cambio -=1;
gpio_set_level(OutputLed[0], 1); //Enciende LEd 1 pesos
vTaskDelay(500 / portTICK_PERIOD_MS);
gpio_set_level(OutputLed[0], 0);
vTaskDelay(500 / portTICK_PERIOD_MS);
printf("Devolviendo moneda de 1 peso\n");
}
}
}
void parking_machine(void *params){
int pinNumber;
while (true) {
switch (state) { //Switch para saber el estado al que debe pasar
case En_espera: //Caso de espera, se pide el dinero
printf("Maquina de cobros de estacionamiento!\n");
printf("Cobro: 15 pesos \n");
if (xQueueReceive(handlerQueue, &pinNumber, portMAX_DELAY)) {
switch (pinNumber){
case INPUT_PIN_1:
coins += 1;
break;
case INPUT_PIN_5:
coins += 5;
break;
case INPUT_PIN_10:
coins += 10;
break;
case INPUT_PIN_20:
coins += 20;
break;
}
printf("Total pagado : %d mxn \n", coins);
state = Pagando; //Si recibe algo en la cola entonces pasa al estado de pagando
}
break;
case Pagando:
if (xQueueReceive(handlerQueue, &pinNumber, 10)) {
if (coins < 15) {
switch (pinNumber){
case INPUT_PIN_1:
coins += 1;
break;
case INPUT_PIN_5:
coins += 5;
break;
case INPUT_PIN_10:
coins += 10;
break;
case INPUT_PIN_20:
coins += 20;
break;
}
printf("Total pagado : %d mxn \n", coins);
}
}
if (coins >= 15) { //Si el pago fue mayor o igual a 15 entonces salda la cuenta y regresa cambio en dado caso
cambio = coins - 15;
printf("Total de cambio: %d mxn\n", cambio);
cambio_Leds(cambio);
state = Imprimiendo_recibo; //Pasa al estado de imprimir el recibo
}
break;
case Imprimiendo_recibo:
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("Feliz viaje, imprimiendo recibo\n");
gpio_set_level(LED_PIN_20, 1);
vTaskDelay(1000 / portTICK_PERIOD_MS);
gpio_set_level(LED_PIN_20, 0);
vTaskDelay(1000 / portTICK_PERIOD_MS);
coins = 0;
cambio = 0;
xQueueReset(handlerQueue);
state = En_espera; // vuelve al inicio
break;
default:
state = En_espera;
break;
}
}
}
void app_main() {
init_gpio();
// Inicializar los tiempos antiguos en 0
for (int i = 0; i < 4; i++) {
tm_old[i] = 0;
}
gpio_set_intr_type(INPUT_PIN_1, GPIO_INTR_POSEDGE);
gpio_set_intr_type(INPUT_PIN_5, GPIO_INTR_POSEDGE);
gpio_set_intr_type(INPUT_PIN_10, GPIO_INTR_POSEDGE);
gpio_set_intr_type(INPUT_PIN_20, GPIO_INTR_POSEDGE);
handlerQueue = xQueueCreate(10, sizeof(int));
xTaskCreate(parking_machine, "parking_machine", 2048 , NULL , 1 , NULL);
gpio_install_isr_service(0);
gpio_isr_handler_add(INPUT_PIN_1, gpio_interrupt_handler, (void *) INPUT_PIN_1);
gpio_isr_handler_add(INPUT_PIN_5, gpio_interrupt_handler, (void *) INPUT_PIN_5);
gpio_isr_handler_add(INPUT_PIN_10, gpio_interrupt_handler, (void *) INPUT_PIN_10);
gpio_isr_handler_add(INPUT_PIN_20, gpio_interrupt_handler, (void *) INPUT_PIN_20);
}