// Definimos todas las variables
const int pulsador_entrada=13, pulsador_salida=35, pulsador_seta=33;
const int pin_ADC=26, pin_DAC=25, led_emergencia=34, led1=25, led_freq1=14, led_pot=27;
const int led_freq2=12, potenciometro=26;
const int motor_A = 23, motor_B = 22, motor_C = 19, motor_D = 18;
volatile int productos=0, i=0, j=0, k=0, n=0, codigo_ADC, codigo_DAC, codigo_led;
volatile int caso=0;
volatile float tiempo[10], tiempo1[10], V_ADC, V_DAC, V_led;
#define Velocidad_MIN 10000;
#define Velocidad_MAX 3000;
volatile unsigned int t_alarma = Velocidad_MIN;
volatile unsigned int t_freq=1e6;
volatile unsigned long cuenta = 0;
volatile unsigned long cuenta1 = 0;
volatile bool seta=true;
// Definimos el funcionamiento del motor
#define NUMSEC 4 // 4 u 8 # lineas de secuencia de movimiento (4 = paso completo)
int tabla_pasos[NUMSEC][4]={ // A B C D
{HIGH,HIGH, LOW, LOW},
{LOW, HIGH, HIGH,LOW},
{LOW, LOW, HIGH,HIGH},
{HIGH,LOW, LOW, HIGH}
};
// Definimos los timers
hw_timer_t * timer=NULL;
hw_timer_t * timer2=NULL;
hw_timer_t * timerseta=NULL;
hw_timer_t * timer4=NULL;
// función que proporciona el movimiento del siguiente paso
void sgte_paso(){
static int idsec=0; // va recorriendo la siguiente tabla
// escribimos los valores nuevos de la tabla en los pines ABCD
digitalWrite(motor_A, tabla_pasos[idsec][0]);
digitalWrite(motor_B, tabla_pasos[idsec][1]);
digitalWrite(motor_C, tabla_pasos[idsec][2]);
digitalWrite(motor_D, tabla_pasos[idsec][3]);
if( (++idsec)==NUMSEC) idsec=0;
return;
}
// función del primer timer en la que metemos la función que hace que se mueva
// el motor
void IRAM_ATTR fintimer()
{
if(seta) // Solo funciona cuando seta=true, es decir, cuando no está el estado
// de emergencia activado
{
//sgte_paso(); // mueve el motor
static int idsec=0; // va recorriendo la siguiente tabla
// escribimos los valores nuevos de la tabla en los pines ABCD
digitalWrite(motor_A, tabla_pasos[idsec][0]);
digitalWrite(motor_B, tabla_pasos[idsec][1]);
digitalWrite(motor_C, tabla_pasos[idsec][2]);
digitalWrite(motor_D, tabla_pasos[idsec][3]);
if( (++idsec)==NUMSEC) idsec=0;
digitalWrite(led_emergencia, LOW);
}
}
// función del segundo timer para iluminar el led en función de la velocidad
// del motor y cambiar la velocidad de este con el potenciómetro
void IRAM_ATTR fintimer2()
{
if(seta)
{
codigo_ADC=analogRead(pin_ADC); // lee el código del voltaje que proporcionamos
// con el potenciómetro
V_led=2.0 + 1.0*codigo_ADC/4095.0;
codigo_led = 255.0 * ( V_led / 3.3);
dacWrite(pin_DAC, codigo_led); // ilumina más o menos el LED
t_alarma=(codigo_ADC/4095)*(-7000)+Velocidad_MIN; // El motor trabaja a 100Hz
// --> 10ms; luego velocidad min=10ms y max=3ms
timerAlarm(timer, t_alarma, true, 0); // Asociamos nuevo t_alarma
}
}
// función para la entrada de productos
void IRAM_ATTR entrada()
{
if(seta)
{
i++;
if(i>99) i=99;
productos=productos+1;
tiempo[i]=millis(); // nos quedamos con el tiempo en el que entra el producto
if(productos>0)
{
t_freq=1e6/(productos); // cambiamos el tiempo de repetición
// de la función fintimer4 en función del número de productos en la línea
timerWrite(timer4,0);
timerAlarm(timer4, t_freq, true, 0);
}
}
}
// función para la salida de productos
void IRAM_ATTR salida()
{
if(seta)
{
j++;
if(j>99) j=99;
tiempo1[j]=millis(); // nos quedamos con el tiempo en el que queremos sacar
// el producto
if(productos>0) // solo funciona si hay productos en la línea
{
k=j-n;
if(k<0) k=0;
if(tiempo1[j]-tiempo[k]<5000) // si el producto lleva menos de 5 segundos
// en la línea, sigue todo igual
{
n++;
productos=productos;
}
if(tiempo1[j]-tiempo[k]>=5000) // si el producto lleva 5 segundos o más en
// la línea, sale de ella
{
productos=productos-1;
}
}else{
j=0;
n=-i;
}
if(productos>0)
{
t_freq=1e6/(productos); // cambiamos el tiempo de repetición
// de la función fintimer4 en función del número de productos en la línea
timerAlarm(timer4, t_freq, true, 0);
}
}
}
// función de emergencia cuando pulsamos la seta de emergencia
void IRAM_ATTR emergencia()
{
seta=false; // no hace ninguna función por lo que el motor no gira, los
// pulsadores de entrada y salida de productos quedan inhabilitados, el led
// del potenciómetro no ilumina y los leds no parpadean
digitalWrite(led_emergencia, HIGH); // se enciende el led de emergencia
productos=0; // se retiran todos los productos
}
// función para que vuelva a funcionar todo tras mantener la seta de emergencia
// presionada durante al menos 3 segundos
void IRAM_ATTR fintimer3()
{
if(digitalRead(pulsador_seta)==HIGH) // lee que el pin esté en HIGH
{
seta=false; // sigue sin funcionar nada
cuenta++; // aumenta la variable cuenta mientras el pulsador esté pulsado
if(cuenta>=3e3) // cuando la variable supera el valor de 30.000 quiere decir
// que han pasado 3 segundos y entonces vuelve a funcionar todo
{
seta=true;
}
}else{
cuenta=0; // si se deja de pulsar el pulsador la variable vuelve a 0
}
}
// función para el parpadeo de los leds en función de la cantidad de productos
void IRAM_ATTR fintimer4()
{
if(productos>0) // parpadean si hay algún producto en la línea
{
if(caso>4) // hay 4 casos: led1=HIGH, led1=LOW, led2=HIGH y led2=LOW
{
caso=1; // cuando supera 4, vuelve a 1
}else{
caso++;
}
switch(caso) // se va metiendo en los diferentes casos segun varía "caso"
{
case 1:
digitalWrite(led_freq1, HIGH);
digitalWrite(led_freq2, LOW);
break;
case 2:
digitalWrite(led_freq1, LOW);
digitalWrite(led_freq2, LOW);
break;
case 3:
digitalWrite(led_freq1, LOW);
digitalWrite(led_freq2, HIGH);
break;
case 4:
digitalWrite(led_freq1, LOW);
digitalWrite(led_freq2, LOW);
break;
}
}else{ // si no hay productos, los dos leds no parpadean
digitalWrite(led_freq1, LOW);
digitalWrite(led_freq2, LOW);
}
}
void setup()
{ // definimos los diferentes pines como salidas o entradas
pinMode(pulsador_entrada, INPUT);
pinMode(pulsador_salida, INPUT);
pinMode(pulsador_seta, INPUT);
pinMode(led_emergencia, OUTPUT);
pinMode(led1, OUTPUT);
pinMode(led_freq1, OUTPUT);
pinMode(led_freq2, OUTPUT);
pinMode(led_pot, OUTPUT);
pinMode(potenciometro, INPUT);
// pines de salida del motor
pinMode(motor_A, OUTPUT);
pinMode(motor_B, OUTPUT);
pinMode(motor_C, OUTPUT);
pinMode(motor_D, OUTPUT);
digitalWrite(led1, HIGH); // led que representa que el sistema funciona
// definición de los diferentes timers
timer=timerBegin(1e6);
timerAttachInterrupt(timer, &fintimer);
timerAlarm(timer, t_alarma, true, 0);
timer2=timerBegin(1e6);
timerAttachInterrupt(timer2, &fintimer2);
timerAlarm(timer2, 1000, true, 0);
timerseta=timerBegin(1e6);
timerAttachInterrupt(timerseta, &fintimer3);
timerAlarm(timerseta, 1000, true, 0);
timer4=timerBegin(1e6);
timerAttachInterrupt(timer4, &fintimer4);
timerAlarm(timer4, t_freq, true, 0);
// asiganción de las diferentes interrupciones
attachInterrupt(digitalPinToInterrupt(pulsador_entrada), entrada, RISING);
attachInterrupt(digitalPinToInterrupt(pulsador_salida), salida, RISING);
attachInterrupt(digitalPinToInterrupt(pulsador_seta), emergencia, RISING);
//set the resolution to 12 bits (0-4096)
analogReadResolution(12);
// voltage full-range 150mV - 3100 mV
analogSetAttenuation(ADC_11db); // ADC_0db, ADC_2_5db, ADC_6db, ADC_11db
// DAC channel 1 is attached to GPIO25, DAC channel 2 is attached to GPIO26
// acepta valores de 0 a 255 -> Vout = 0 a 3.3v
Serial.begin(115200);
}
void loop()
{
if(seta)
{
Serial.println("La línea está en funcionamiento");
}else{
Serial.println("La línea está en estado de emergencia");
}
Serial.printf("productos en la línea = %i\n", productos);
delay(1000);
}