TMR1: Time as a critical variable EN/ES
4 comments
This article is focused on complementing the information provided in the article TMR1 Theoretical basis EN/ES, we will consider some applications where the speed with which a system can act becomes extremely important, we will explain how to configure the TMR1 using C language and finally we are going to create a circuit with two microcontrollers in which through a simulation we will compare the speed of the TMR0 vs TMR1.
Este artículo está enfocado a complementar la información brindada en el artículo TMR1 Theoretical basis EN/ES, consideraremos algunas aplicaciones donde la rápidez con la que puede actuar un sistema se convierte en algo de extrema importancia, explicaremos la forma de configurar el TMR1 usando lenguaje C y finalmente vamos a crear un circuito con dos microcontroladores en el que mediante una simulación compararemos la velocidad del TMR0 vs TMR1.
Some demanding applications |
---|
Time is a particularly interesting variable for me, it is not like temperature or any other whose value oscillates between high and low values, time once you start the measurement only goes in one direction and always increasing in that direction. We can take a portion of this variable, such as 10 minutes, and we would not be able to say if it is a lot or a little, the truth will depend on what we need to do, since it may be a lot or it may not be enough.
The truth is that sometimes we can afford to be 10 minutes late for work, school or an appointment, but there are circumstances in which every second counts, such as a firefighter who wants to enter a burning building to look for survivors, a diver inside of a marine depth and many others of this type.
There are circumstances in which the response is so urgently required that the blink of an eye can be like a turtle traveling on foot from Australia to Germany, and I am not exaggerating, that is where a measurement of time in seconds is no longer comfortable and we move on to the sub units like ms, us, ns and even ps.
Until now the most demanding one that could have in mind is the Large Particle Collider, the particles collide and the results last an extremely short time, so much so that the measuring instruments must be extremely precise.
On the other hand, we can consider an electrical protection system in which the elements against an overload can be damaged if the exposure time is extended and I am referring to times of less than 1 second since the longer the time, the greater the probability that the element is destroyed, that is why a protection system must be fast enough to cut off the power supply before any component is affected.
The transfer of loads in a backup system within an industrial plant can also be considered, the system must be able to alternate between the main source and the backup source without the equipment connected to the power detecting the cut that occurs during the transfer.
I could go on with more examples but we are past the theoretical part, so let's see some practice.
El tiempo es para mí una variable particularmente interesante, no es como la temperatura o cualquier otra cuyo valor oscila entre valores altos y bajos, el tiempo una vez inicias la medición solo va en una dirección y aumentando siempre en esa dirección. Podemos tomar una porción de esta variable como por ejemplo 10 minutos y no sabríamos decir si es mucho o poco, la verdad dependerá de lo que necesitemos hacer ya que puede que sea mucho o puede que no sea suficiente.
La verdad es que a veces podemos permitirnos llegar 10 minutos tarde al trabajo, al colegio o a una cita, pero existen circunstancias en las que cada segundo es importante, como un bombero que quiere ingresar a un edificio en llamas a buscar sobrevivientes, un buzo dentro de una profundidad marina y muchas otras de este tipo.
Existen circunstancias en las que la respuesta se requiere con tanta urgencia que un parpadeo puede resultar como una tortuga viajando a pie desde Australia hasta Alemania, y no exagero, es ahí donde una medición de tiempo en segundos ya no es cómoda y pasamos a las sub unidades como el ms, us, ns y hasta ps.
Hasta ahora la más exigente que pudo tener en mente es el Gran Colisonador de Partículas, las particulas colisionan y los resultados duran un tiempo extremadamente corto, tanto que los instrumentos de medición deben ser extremadamente precisos.
Por otro lado podemos considerar un sistema de protecciones eléctricas en los que los elementos frente a una sobrecarga pueden dañarse si el tiempo de exposición es extendido y estoy refiriendome a tiempos inferiores a 1 segundo ya que a mayor tiempo mayor es la probabilidad de que el elemento se destruya, por eso un sistema de protecciones debe ser tan rápido como para cortar el suministro de energía antes que algún componente se vea afectado.
También se puede considerar la transferencia de cargas en un sistema de respaldo dentro de una planta industrial, el sistema debe ser capaz de alternar entre la fuente principal y la fuente de respaldo sin que los equipos conectados a la energía detecten el corte que ocurre durante la transferencia.
Podría seguir con más ejemplos pero ya pasamos la parte teórica, así que veamos algo de práctica.
Test circuit |
---|
In our practical circuit we are going to use the TMR0 in a PIC16F877A microcontroller to generate a time of 5 seconds, but simultaneously another PIC16F877A microcontroller will be counting the same time (5s) using the TMR1, the first to fulfill its task will activate a signal of output that will be received in the RB0 pin of the other microcontroller, we will configure the interruption by RB0 so that the one that receives the signal stops its counting and shows on the screen how much it has counted, in this way we can notice what difference it has with respect to the one that it reached the 5s.
But after that the account will continue for the second TMR to execute its interruption and it will show how far the one that activated it first has advanced. Each microcontroller will have a 20x4 LCD screen to display the results.
En nuestro circuito práctico vamos a usar el TMR0 en un microcontrolador PIC16F877A para generar un tiempo de 5 segundos, pero de forma simultánea otro microcontrolador PIC16F877A estará contando el mismo tiempo (5s) usando el TMR1, el primero en cumplir su tarea activara una señal de salida que será recibida en el pin RB0 del otro microcontrolador, configuraremos la interrupción por RB0 para que el que reciba la señal detenga su conteo y muestre en pantalla cuanto es lo que ha contado, de esa forma podremos notar que diferencia lleva respecto al que alcanzó los 5s.
Pero luego de eso la cuenta seguirá para que el segundo TMR ejecute su interrupción y se mostará cuanto ha avanzado el que la activo primero. Cada microcontrolador tendra una pantalla LCD20x4 para mostrar los resultados.
Programming |
---|
Since we have already seen articles referring to the TMR0, I will not make much effort to describe the way to control it, however, we can notice that two subroutines have been established apart from the main routine, this is because we will use two interruptions, the one for the TMR0 and the one for RB0 ( EXT), in the first we will do the counting and we will establish that when it occurs it will activate a Bit that causes the interruption by RB0 of the other microcontroller to stop its counting.
The interruption by RB0 occurs only if the other microcontroller reaches its time first, in the interruption by RB0 we print the count of that microcontroller to be able to establish the time difference, to do the 5 seconds we make a time of 10ms and load it 500 times in a variable, to make the 10ms we calculate the load of the TMR0 in 61, the code is presented below.
Cómo ya vimos artículos referentes al TMR0 no haré mucho esfuerzo en describir la forma de controlarlo, sin embargo podremos notar que se han establecido dos subrutinas a parte de la rutina principal, es así porque usaremos dos interrupciones, la del TMR0 y la de RB0 (EXT), en la primera haremos el conteo y estableceremos que al ocurrir activara un Bit que provoque la interrupción por RB0 del otro microcontrolador para detener su conteo.
La interrupción por RB0 ocurre solo si el otro microcontrolador alcanza su tiempo primero, en la interrupción por RB0 imprimimos el conteo que lleva ese microcontrolador para poder establecer la diferencia de tiempo, para hacer los 5 segundos hacemos un tiempo de 10ms y lo cargamos 500 veces en una variable, para hacer los 10ms calculamos la carga del TMR0 en 61, el código se presenta a continuación.
#include <16f877a.h>
#fuses HS,NOWDT,NOPROTECT,NOPUT,NOLVP,BROWNOUT
#use delay(clock=20M)
#use standard_io(D)
#use fast_io(A)
#use fast_io(B)
#define LCD_DB4 PIN_D4
#define LCD_DB5 PIN_D5
#define LCD_DB6 PIN_D6
#define LCD_DB7 PIN_D7
#define LCD_RS PIN_D2
#define LCD_E PIN_D3
#include <LCD_20X4.c>
float t=0;
float timer=0;
long interruption = 0;
#INT_TIMER0
void timer0_interrupcion()
{
interruption++;
if(interruption ==500 )
{
output_low(PIN_D0);
lcd_clear();
lcd_gotoxy(3,1);
printf(lcd_putc,"TMR0 INTERRUPTION");
lcd_gotoxy(2,2);
printf(lcd_putc,"TIME IS CRITICAL");
lcd_gotoxy(2,3);
printf(lcd_putc,"@electronico - HIVE");
lcd_gotoxy(4,4);
printf(lcd_putc,"original content");
delay_ms(10000);
}
set_timer0(61);
}
#INT_EXT
void interruption_RB0()
{
timer = interruption * 10;
lcd_clear();
lcd_gotoxy(3,1);
printf(lcd_putc,"TMR1 INTERRUPTION");
lcd_gotoxy(2,2);
printf(lcd_putc,"TIME IS CRITICAL");
lcd_gotoxy(2,3);
printf(lcd_putc,"TMR0 count is %f ms", timer);
lcd_gotoxy(4,4);
printf(lcd_putc,"TMR0 IS %f ms", t);
delay_ms(10000);
}
void main()
{
lcd_init();
set_tris_A(0b00001111);
set_tris_B(0xFF);
output_high(PIN_D0);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_EXT);
ext_int_edge(L_TO_H);
enable_interrupts(GLOBAL);
set_timer0(61);
lcd_clear();
while(TRUE)
{
lcd_gotoxy(2,1);
timer = interruption * 0.01;
t = get_timer0() * 0.0390625;
printf(lcd_putc,"WELCOME TO MY BLOG");
lcd_gotoxy(2,2);
printf(lcd_putc,"TIME IS CRITICAL");
lcd_gotoxy(2,3);
printf(lcd_putc,"interruptions is %f s", timer);
lcd_gotoxy(4,4);
printf(lcd_putc,"TMR0 is %f ms", t);
}
}
I have already explained some of the things that this code contains in previous articles, but that is not the reason why I am writing it completely, but rather that the program that we are going to load in the microcontroller that the TMR1 will use is very similar and it is necessary explain the configuration of TMR1 so that since they are similar, what you have not understood in the previous code will have an explanation in the one that follows, which is the one that corresponds to TMR1.
In our main configuration lines we enable port D to manage the LCD and in turn we will use pin D0 to generate the pulse that causes the interrupt by RB0 in the second microcontroller, as we will use interrupt by RB0 we enable the PORTB as data input, and we define the variables that we will use.
Algunas cosas de las que contiene este código ya las he explicado en artículos anteriores, pero no es esa la razón por la que lo escribo completo sino que el programa que vamos a cargar en el microcontrolador que usara el TMR1 es muy similar y se hace necesario explicar la configuración de TMR1 así que como son similares lo que no has entendido en el código anterior tendrá explicacion en el que sigue que es el que se corresponde con el TMR1:
En nuestras líneas principales de configuración habilitamos el puerto D para el manejo del LCD y a su vez usaremos el pin D0 para generar el pulso que provoque la interrupción por RB0 en el segundo microcontrolador, como usaremos interrupción por RB0 habilitamos el PORTB como entrada de datos, y definimos las variables que usaremos.
#include <16f877a.h>
#fuses HS,NOWDT,NOPROTECT,NOPUT,NOLVP,BROWNOUT
#use delay(clock=20M)
#use standard_io(D)
#use fast_io(B)
#define LCD_DB4 PIN_D4
#define LCD_DB5 PIN_D5
#define LCD_DB6 PIN_D6
#define LCD_DB7 PIN_D7
#define LCD_RS PIN_D2
#define LCD_E PIN_D3
#include <LCD_20X4.c>
float timer = 0;
float t=0;
int interruption = 0;
Our interruption by TMR1 will be programmed to occur every 100ms, for which we calculate the load of TMR1 in 3036, since there are 100ms we must execute 50 interruptions to reach 5 seconds, that is why a variable will increase in each interruption and it will be monitored with an if conditional so that when the time is reached it produces the RB0 interrupt in the other microcontroller (the one with TMR0) and shows a message on the screen indicating that the count is over.
Nuestra interrupción por TMR1 será programada para que ocurra cada 100ms para lo cual calculamos la carga del TMR1 en 3036, como son 100ms debemos ejecutar 50 interrupciones para lelgar a los 5 segundos, es por eso que una variable se incrementará en cada interrupción y se monitoreará con un condicional if para que al alcanzar el tiempo produzca la interrupción RB0 en el otro microcontrolador (el que cuenta con TMR0) y muestre un mensaje en pantalla indicando que terminó el conteo.
#INT_TIMER1
void timer1_interrupcion()
{
interruption++;
if(interruption == 50)
{
output_low(PIN_D0);
lcd_clear();
lcd_gotoxy(3,1);
printf(lcd_putc,"TMR1 INTERRUPTION");
lcd_gotoxy(2,2);
printf(lcd_putc,"TIME IS CRITICAL");
lcd_gotoxy(2,3);
printf(lcd_putc,"@electronico - HIVE");
lcd_gotoxy(4,4);
printf(lcd_putc,"original content");
delay_ms(10000);
}
enable_interrupts(INT_TIMER1);
set_timer1(3036);
}
Now we enable the RB0 interrupt assuming that the other microcontroller's timer is interrupted by its TMR then this microcontroller will respond with the RB0 interrupt to show where its count was going.
Ahora habilitamos la interrupción por RB0 suponiendo que el temporizador del otro microcontrolador se interrumpa por su TMR entonces este microcontrolador responderá con la interrupción por RB0 para mostrar por donde iba su conteo.
#INT_EXT
void interruption_RB0()
{
lcd_clear();
lcd_gotoxy(3,1);
printf(lcd_putc,"TMR0 INTERRUPTION");
lcd_gotoxy(2,2);
printf(lcd_putc,"TIME IS CRITICAL");
lcd_gotoxy(2,3);
printf(lcd_putc,"TMR1 TIME IS %f s", timer);
lcd_gotoxy(4,4);
printf(lcd_putc,"TMR1 is %f ms", t);
delay_ms(10000);
}
Now comes the main program, in which we will enable the interrupt by RB0 and TMR1, remember that the TMR1 prescaler can only have a maximum value of 8, so we configure it to work with the internal clock with a prescaler of 8 using the line setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); we also activate the interrupt with the line enable_interrupts(INT_TIMER1); and we load the TMR1 for 100ms with the line set_timer1(3036); we also clear the LCD.
Ahora viene el programa principal, en el que habilitaremos la interrupción por RB0 y TMR1, recordemos que el preescaler de TMR1 solo puede tener un valor máximo de 8, así que configuramos para que trabaje con el reloj interno con un preescaler de 8 usando la línea setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); además activamos la interrupción con la línea enable_interrupts(INT_TIMER1); y cargamos el TMR1 para 100ms con la línea set_timer1(3036); además limpiamos la LCD.
void main()
{
lcd_init();
set_tris_B(0xFF);
output_high(PIN_D0);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_EXT);
ext_int_edge(L_TO_H);
enable_interrupts(GLOBAL);
set_timer1(3036);
lcd_clear();
Now we will create a while loop in which we will configure the variables so that they show us on the LCD the count of the timer at all times with respect to 5 seconds and the value of the charge of the TMR expressed in microseconds, in the first case it is enough to multiply 0.1 ( which are the 100ms it takes for the TMR1 interruption to occur) by the interruption variable, which is the one that contains the value of how many times the interruption has occurred.
For the second case we need to express the value of the TMR1 load in ms, but this value is expressed in bits from 0 to 65535, being able to store 65536 values, as the expected maximum is 100ms, the formula to calculate the value contained in ms is to divide 100 /65536 and multiply that value by the one that contains the TMR1 that we can know using the instruction get_timer1(); and we store all that in the variable t that will be displayed on the LCD.
Ahora crearemos un bucle while en el que configuraremos las variables para que nos muestren en el LCD la cuenta del temporizador en todo mento respecto a los 5 segundos y el valor de la carga del TMR expresado en microsegundos, en el primer caso basta multiplicar 0.1 (que son los 100ms que tarda en ocurrir la interrupción del TMR1) por la variable interruption que es la que contiene el valor de cuantas veces ha ocurrido la interrupción.
Para el segundo caso necesitamos expresar el valor de la carga del TMR1 en ms, pero este valor es expresado en bits de 0 a 65535 pudiendo almacenar 65536 valores, como el máximo esperado es 100ms la formula para calcular el valor contenido en ms es dividir 100/65536 y multiplicar ese valor por el que contenga el TMR1 que podemos conocer usando la instrucción get_timer1(); y todo eso lo almacenamos en la variable t que será la mostrada en el LCD.
while(TRUE)
{
lcd_gotoxy(2,1);
timer = interruption * 0.1;
t = get_timer1() * 0.00152587890625;
printf(lcd_putc,"WELCOME TO MY BLOG");
lcd_gotoxy(2,2);
printf(lcd_putc,"TIME IS CRITICAL");
lcd_gotoxy(2,3);
printf(lcd_putc,"interruptions is %f s", timer);
lcd_gotoxy(4,4);
printf(lcd_putc,"TMR1 is %f ms", t);
}
}
Simulation |
---|
When the simulator turns on the circuit, both microcontrollers will start counting, one will use TMR0 and the other the TMR1, the one that reaches 5s first will cause the interruption by RB0 of the one that has not yet arrived, both will show the message indicating that the interruption has occurred and The one that has yet to reach 5s will show the value of its account so that we can establish how much of a difference it presents with respect to the other. After an instant, the counts will continue for the second microcontroller to produce its interrupt and show how far the one that did it first has advanced.
Cuando el simulador encienda el circuito ambos microcontroladores iniciaran el conteo, uno usará el TMR0 y el otro el TMR1, el que llegue primero a 5s provocará la interrupción por RB0 del que aun no ha llegado, ambos mostrarán el mensaje indicando que interrupción ha ocurrido y al que le falte por llegar a los 5s mostrará el valor de su cuenta para que podamos establecer cuando de diferencia presenta respecto al otro. Luego de un instante las cuentas seguiran para que el segundo microcontrolador produzca su interrupción y mostrar cuanto ha avanzado el que lo hizo primero.
Our simulation shows that the TMR0 is 500 ms late with respect to the TMR1, this is a 10% error that many applications cannot afford, even so we should not completely rule out the TMR0 as a counter since it can still be used for applications not so demanding, but apart from that it has another utility that we have not seen yet and that I will consider if it will be the subject of my next article 😉.
I know that these topics that we have dealt with lately require more analysis and knowledge, so I will be very attentive to the comments to read and seek answers to your doubts in case they exist.
Nuestra simulación demuestra que el TMR0 se retrasa 500 ms respecto al TMR1, esto es un error del 10% que muchas aplicaciones no se pueden permitir, aun así no debemos descartar del todo al TMR0 como contador ya que aun puede ser usado para aplicaciones no tan exigentes, pero a parte de eso tiene otra utilidad que aun no hemos visto y que consideraré si será el tema de mi siguiente artículo 😉.
Se que estos temas que hemos tratado ultimamente exigen mayor análisis y conocimientos, por eso estaré muy atento a los comentarios para leer y buscar respuestas a tus dudas en caso de que existan.
Comments