Los temporizadores son ampliamente usados en electrónica para controlar el tiempo que un sistema puede funcionar. Ellos son usados en panaderías, restaurantes, en hornos microondas y en muchos tipos de industrias. En este articulo aprenderemos como construir un temporizador descendente con Arduino Uno.

 

Los temporizadores son construidos en base a los periféricos timer que vienen dentro de los microcontroladores. Vea la Figura 1. Los periféricos timer son circuitos digitales contadores que cuentan los pulsos de reloj (clock) del microcontrolador.

 


 

 

Estos contadores son programados para que, en una determinada cantidad de pulsos de reloj, ejecuten una interrupción. Así podemos implementar por ejemplo un timer para que a cada milisegundo genere una interrupción. Con esto se pueden construir un base de tiempo para contar milisegundos.

 

EJEMPLO BASICO PARA TEMPORIZADOR.

Un método muy usado en Arduino para generar temporizaciones es la función delay(), la cual recibe como parámetro la cantidad de milisegundos que se quiere temporizar. El siguiente es un ejemplo básico de temporización usando esta función:

 

int LED_OUTPUT = 13;

int TIME_TO_DEC = 22;

 

const int display_1_Pinout[7] = { 2, 3, 4, 5, 6, 7, 8 };

const int display_2_Pinout[7] = { 9, 10, 11, 12, A0, A1, A2 };

 

const byte anodeDisplay[10] =

{

0b1000000, //0

0b1111001, //1

0b0100100, //2

0b0110000, //3

0b0011001, //4

0b0010010, //5

0b0000010, //6

0b1111000, //7

0b0000000, //8

0b0010000, //9

};

 

***************************************************************
**************************************************************/
void setup()

{

pinMode(LED_OUTPUT, OUTPUT);

 

for(int i = 0; i < 7; i++)

{

pinMode(display_1_Pinout[i], OUTPUT);

pinMode(display_2_Pinout[i], OUTPUT);

}

}

 

***************************************************************
**************************************************************/
void Display_2_Write(int number)

{

 

byte numberBit = anodeDisplay[number];

 

for (int i = 0; i < 7; i++)

{

int bit = bitRead(numberBit, i);

digitalWrite(display_2_Pinout[i], bit);

}

}

 

***************************************************************
**************************************************************/
void Display_1_Write(int number)

{

 

byte numberBit = anodeDisplay[number];

 

for (int i = 0; i < 7; i++)

{

int bit = bitRead(numberBit, i);

digitalWrite(display_1_Pinout[i], bit);

}

}

 

***************************************************************
**************************************************************/
void Display_Show(int number)

{

int units = number % 10;

int tens = number / 10;

 

Display_1_Write(units);

Display_2_Write(tens);

}

 

***************************************************************
**************************************************************/
void loop()

{

digitalWrite(LED_OUTPUT, HIGH);

 

for(int cnt=TIME_TO_DEC; cnt>=1; cnt--)

{

Display_Show(cnt);

delay(1000);

}

 

Display_1_Write(0);

digitalWrite(LED_OUTPUT, LOW);

 

while(1);

}

 

 

El circuito para probar el anterior programa puede ser visto en la Figura 2.

 


 

 

 

Es usado el LED de la tarjeta Arduino para comprobar la temporización. Este LED está conectado a la salida digital número 13 de la tarjeta Arduino Uno. Esta temporización se ejecuta cada vez que se conecta la tarjeta Arduino a la fuente de tensión. Note que al final del programa hay un bucle o loop while(1) infinito formado por la instrucción while(1). La función delay() cuando se ejecuta, no permite que el microcontrolador pueda ejecutar alguna otra instrucción, por eso en programas de temporización donde se requiera más complejidad es usada la función:

millis();

Esta función lo que hace es retornar el número de milisegundos desde que la tarjeta de Arduino comenzó a ejecutar el programa, es decir desde que se conectó el circuito a la fuente de alimentación. Un detalle a tener en cuenta con la función millis() es que el valor retornado es un unsigned long . Este es un tipo de dato que se almacena en 4 bytes, es decir 32 bits y su rango va desde 0 hasta 4,294,967,295. Es necesario tener cuidado al hacer cálculos matemáticos, pues es necesario que las variables usadas en esos cálculos sean también unsigned long para evitar errores. Un error muy común es usar variables de tipoint, unsigned int y long . Los tipos de variable int y unsigned int en Arduino Uno son de 16 bits. El tipo long es de 32 bits, pero son números que pueden almacenar valores negativos pues su rango va desde -2,147,483,648 hasta 2,147,483,647.

En este articulo implementaremos un temporizador con 2 dígitos. También visualizaremos este proyecto desde el punto de vista de la UML, que es un lenguaje para gestionar proyectos y cada vez más se usa en el mundo de los microcontroladores.

 

UML.

UML o Lenguaje Unificado de Modelado, es una manera de visualizar un proyecto a través de gráficos o imágenes. El logotipo que representa este lenguaje puede ser observado en la Figura 3.

 


 

 

 

Los gráficos más utilizados en el área de microcontroladores son:

El diagrama de Casos de Uso.

El diagrama de Estado.

El diagrama de Clases.

A medida que vayamos avanzando en este artículo, iremos describiendo la utilidad de cada diagrama para verlo de una manera práctica.

 

EL DIAGRAMA DE CASOS DE USO.

Describe de manera genérica las funciones que un usuario puede realizar en el sistema. Para el caso del temporizador, necesitamos un caso de uso para el Start y un otro caso de uso para el Stop . Observe la Figura 4.

 


 

 

 

EL DIAGRAMA DE ESTADOS.

Los diagramas de estado representan los posibles estados en los que se encuentra un sistema en un determinado momento. Para el caso del temporizador tenemos 3 estados:

enum STATES {

  Begining,

  Decreasing,

  Ending

};

 

Los eventos son usados para pasar o transitar de un estado a otro. Para el caso del temporizador tenemos 3 eventos:

 

enum EVENTS {

  START,

  STOP_SETPOINT,

  TICK

};

 

La Figura 5 muestra el diagrama de estados para el temporizador.

 


 

 

 

El punto negro en el estado Begining, indica que cuando el programa comienza a ejecutarse, el temporizador se inicializa en ese estado. A este tipo de diagrama también se le referencia como: Maquina de Estados .

 

DIAGRAMA DE CLASES.

Los diagramas de clases nos permiten visualizar las variables y funciones usadas en un proyecto. Para el caso del temporizador la Figura 6 muestra el diagrama de clases. Como algunos proyectos no son totalmente escritos en lenguaje C++, sino que son una mezcla de lenguaje C y lenguaje C++, es necesario adaptar los conceptos del diagrama de clases para estos 2 lenguajes. La Figura 6 es una muestra de esta adaptación.

 


 

 

 

PROGRAMA PARA EL TEMPORIZADOR DESCENDENTE CON ARDUINO UNO.

El siguiente programa es un temporizador descendente en segundos. El valor que determina la temporización (set point), es declarado en la línea de programa:

int SET_POINT = 37;

Esta línea indica al programa para temporizar por 37 segundos. Cambiando este valor se puede temporizar hasta un rango de 99 segundos. La Figura 7 muestra el circuito electrónico para probar el temporizador.

 


| Haga click en la imagen para ampliar |

 

El circuito pose dos pulsadores para controlar el temporizador. El código es el siguiente:

 

 

int LED_OUTPUT = A5;

int SET_POINT = 37;

 

enum EVENTS {

START,

STOP_SETPOINT,

TICK

};

 

enum STATES {

Begining,

Decreasing,

Ending

};

 

int stateTimer = Begining;

int miliSecond_Time = 0;

int timer = 0;

 

const int display_1_Pinout[7] = { 2, 3, 4, 5, 6, 7, 8 };

const int display_2_Pinout[7] = { 9, 10, 11, 12, A0, A1, A2 };

 

const byte anodeDisplay[10] =

{

0b1000000, //0

0b1111001, //1

0b0100100, //2

0b0110000, //3

0b0011001, //4

0b0010010, //5

0b0000010, //6

0b1111000, //7

0b0000000, //8

0b0010000, //9

};

 

class Button

{ private:

int pin;

int level;

int lastLevel;

unsigned long lastDebounceTime = 0;

unsigned long debounceDelay = 50;

 

public:

Button( int _pin)

{

pin = _pin;

pinMode(pin, INPUT_PULLUP);

level = digitalRead(pin);

lastLevel = !level;

}

 

bool getLevel()

{

int currentLevel = digitalRead(pin);

 

if (currentLevel != lastLevel)

{

lastDebounceTime = millis();

}

 

if ((millis() - lastDebounceTime) > debounceDelay)

{

level = currentLevel;

}

 

lastLevel = currentLevel;

 

return level;

}

 

} ;

 

Button start_Button(A3);

Button stopSetpoint_Button(A4);

 

***************************************************************
**************************************************************/
void setup()

{

pinMode(LED_OUTPUT, OUTPUT);

 

for(int i = 0; i < 7; i++)

{

pinMode(display_1_Pinout[i], OUTPUT);

pinMode(display_2_Pinout[i], OUTPUT);

}

 

miliSecond_Time = millis();

Stop();

}

 

***************************************************************
**************************************************************/
void Display_2_Write(int number)

{

 

byte numberBit = anodeDisplay[number];

 

for (int i = 0; i < 7; i++)

{

int bit = bitRead(numberBit, i);

digitalWrite(display_2_Pinout[i], bit);

}

}

 

***************************************************************
**************************************************************/
void Display_1_Write(int number)

{

 

byte numberBit = anodeDisplay[number];

 

for (int i = 0; i < 7; i++)

{

int bit = bitRead(numberBit, i);

digitalWrite(display_1_Pinout[i], bit);

}

}

 

***************************************************************
**************************************************************/
void Display_Show(int number)

{

int units = number % 10;

int tens = number / 10;

 

Display_1_Write(units);

Display_2_Write(tens);

}

 

***************************************************************
**************************************************************/
void Rele_Off()

{

digitalWrite(LED_OUTPUT, HIGH);

}

 

***************************************************************
**************************************************************/
void Rele_On()

{

digitalWrite(LED_OUTPUT, LOW);

}

 

***************************************************************
**************************************************************/
void Stop()

{

Rele_Off();

timer = SET_POINT;

Display_Show(timer);

stateTimer = Begining;

}

 

***************************************************************
**************************************************************/
void Decrement()

{

timer--;

if( timer == 0 )

{

stateTimer = Ending;

Rele_Off();

}

 

Display_Show(timer);

}

 

***************************************************************
**************************************************************/
void Start()

{

miliSecond_Time = millis();

Rele_On();

stateTimer = Decreasing;

}

 

***************************************************************
**************************************************************/
void SM(EVENTS e)

{

switch( stateTimer )

{

case Begining:

switch( e )

{

case START:

Start();

break;

}

break;

 

case Decreasing :

switch( e )

{

case STOP_SETPOINT:

Stop();

break;

 

case TICK:

Decrement();

break;

}

break;

 

case Ending :

switch( e )

{

case STOP_SETPOINT:

Stop();

break;

}

break;

}

}

 

***************************************************************
**************************************************************/
void loop()

{

int current_Time = millis();

 

if ((current_Time - miliSecond_Time) >= 1000)

{

miliSecond_Time = current_Time;

SM(TICK);

}

 

if ( start_Button.getLevel() == LOW)

  {

    SM(START);

  }

 

if ( stopSetpoint_Button.getLevel() == LOW)

  {

    SM(STOP_SETPOINT);

  }

}

 

En la función loop() se escanean los pulsadores para ver si fueron presionados y también se verifica el tiempo del temporizador para ver si ya transcurrió un segundo y enviar el evento TICK, a la función SM(), que es la encarga de procesar la Maquina de Estados . La función SM(), se encarga de verificar en qué estado se encuentra el temporizador y enviar el evento a ese estado. Cada estado procesa el evento de acuerdo con la lógica de funcionamiento del temporizador.

Cuando el temporizador está en el estado Begining, es verificado si fue enviado el evento START . Si así es, entonces se hace una transición para el estado Decreasing. Cuando el temporizador está en el estado Decreasing, se verifican 2 eventos. El evento STOP, para o detine el temporizador y hace la transición para el estado Begining . El evento TICK, decrementa la variable timer, y verifica si aún no ha llegado a cero. Si así, el estado no cambia y se mantiene en el estado Begining . Pero si la variable llego a cero, entonces hace una transición para el estado Ending y es apagado el LED. El estado Ending, verifica si el evento STOP fue recibido, si así, se hace una transición para el estado Begining . La salida usada para el LED puede ser usada para controlar un rele y así permitir manejar componentes electrónicos o eléctricos que tengan un mayor consumo. Vea la Figura 8.

 


 

 

 

LA CLASE BUTTON.

La clase Button es usada para representar y manejar pulsadores o botones en este proyecto. Cuando es presionado un pulsador, es almacenado el tiempo o momento en que sucedió y si este tiempo es superior a 70 milisegundos entonces se genera un evento. El código que implementa la clase Button es el siguiente:

 

class Button

{ private:

int pin;

int level;

int lastLevel;

unsigned long lastDebounceTime = 0;

unsigned long debounceDelay = 50;

 

public:

Button( int _pin)

{

pin = _pin;

pinMode(pin, INPUT_PULLUP);

level = digitalRead(pin);

lastLevel = !level;

}

 

bool getLevel()
  {
   int currentLevel = digitalRead(pin);

   if (currentLevel != lastLevel)
      {
         lastDebounceTime = millis();
      }

   if ((millis() - lastDebounceTime) > debounceDelay)
      {
        level = currentLevel;
      }

   lastLevel = currentLevel;
   return level;
}

 

} ;

 

Las clases implementadas en C++, son formadas por variables y funciones que se declaran dentro de texto como el siguiente:

 

class Xxxxxx

{

};

 

Las Xxxxxx representa el nombre de la clase y este debe hacer referencia a la utilidad que presta esa clase. Como implementamos una clase para manejar los pulsadores, por ese motivo se le dio el nombre de Button . La Figura 9 muestra en más detalle las variables y funciones de la clase Button .

 


 

 

 

Buscador de Datasheets



N° de Componente