Laboratorio de Estructuras de Computadores. Lab 07. Se dispone del siguiente programa: 02/99 #include <reg51.h> /* P1.3 Se le da nombre a un bit determinado */ sbit at 0x93 reloj ; /*Forma de definir la rutina de servicio del timer 0, usando banco de registros 2 */ void timer0(void) interrupt 1 using 2 { if (reloj == 0) reloj=1 ; else reloj=0; TH0 = 0xFF; /* set timer period valor real= 0x63C0*/ TL0 = 0xFC; /*para simular se coloca valor bajo */ /* 65536-40000=25536=0x63C0 Cálculo de cuenta regresiva del timer en modo 1*/ } void main(void) { /* setup timer 0 interrupt. Inicialización del timer con interrupciones.*/ TMOD = 0x01; /* select mode 1 */ TR0 = 1; /* start timer 0 */ ET0 = 1; /* enable timer 0 interrupt */ EA = 1; /* global interrupt enable */ TCON = 0x30; /* timer on and force interrupt */ /* program main routine, do forever */ while (1) {;} } 1. Simular, visualizando el timer y la puerta 1. Usar modo animación. 2. Dibujar la forma de onda del reloj, de acuerdo al programa. 3. Escribir programa que genere dos relojes ( P1.3 y P1.4) P1.3: Está en uno durante 50 mseg y en cero 150 mseg. P1.4: De ciclo 50 %, se coloca en uno en el canto de bajada de P1.3 Laboratorio de Estructuras de Computadores I. Segundo Semestre 1999. 1 Solución. 1. Para poder observar la salida del puerto1 o del timer 0 fuimos al menú View-Hardware – y aquí podemos elegir las dos opciones para ver en pantalla. En port1 se pueden observar los niveles de las 8 salidas, variando en este caso sólo la 3, que cambiaba de nivel cada vez que se leía el ‘if’. En el Timer0 se puede apreciar como varía THLO, mostrando su estado, y al producirse un over-flow, se activa TCON en 0x30, con lo cual el programa se va a la interrupción. 2. Para dibujar la forma de onda debemos ir al menú View-Simbols-(aquí seleccionamos P1.3 – add watch, luego vamos a View-Trace, donde elegimos en opciones modo continuo, para poder ver la señal pedida en pantalla. La señal vista en Proview32 es la siguiente: 3.El programa creado en el laboratorio es el siguiente: #include <reg51.h> /*P1.3 Se le da nombre a un bit determinado */ sbit at 0x93 reloj ; sbit at 0x94 reloj1; int j=0; /*Forma de definir la rutina de servicio del timer 0, usando banco de registros 2 */ void timer0(void) interrupt 1 using 2 { if (j == 0) { reloj=1 ; reloj1=0; /*para simular se coloca valor bajo */ /* 65536-40000=25536=0x63C0 Cálculo de cuenta regresiva del timer en modo 1*/ } Laboratorio de Estructuras de Computadores I. Segundo Semestre 1999. 2 if (j == 1) { reloj = 0; reloj1 = 1; } if (j == 2) { reloj = 0; reloj1 = 1; } if (j == 3) { reloj=0; reloj1 = 0; j=-1;} else; TH0 = 0xff; TL0 = 0xe8; j++; } void main(void) { /* setup timer 0 interrupt. Inicialización del timer con interrupciones.*/ TMOD = 0x1; /* select mode 1 */ TR0 = 1; /* start timer 0 */ ET0 = 1; /* enable timer 0 interrupt */ EA = 1; /* global interrupt enable */ TCON = 0x30; /* timer on and force interrupt */ /* program main routine, do forever */ while (1) {;} } La idea principal del programa es dividir la rutina en 4 partes, de modo de setear los niveles de ambos relojes en tiempos discretos, y no dedicarse todo el tiempo a controlar solamente los relojes. Debido a que los tiempos de simulación no permiten trabajar con los valores propuestos en la pauta, decidimos ocupar valores de manera de mantener la relación en los relojes. Laboratorio de Estructuras de Computadores I. Segundo Semestre 1999. 3 Otra solución. Desarrollo experiencia de laboratorio Nº7. Se dispone del siguiente programa: #include <reg51.h> /* P1.3 Se le da nombre a un bit determinado */ sbit at 0x93 reloj ; /*Forma de definir la rutina de servicio del timer 0, usando banco de registros 2 */ void timer0(void) interrupt 1 using 2 ; /* Define una rutina de servicio llamada timer0, está asociada a la interrupción uno que corresponde, en este caso, a una interrupción interna, por hardware, esto es, es el contador quien llama la interrupción. Cuando se inicia la ejecución del programa, de inicializan los registros de control con valores apropiados. TMOD indica que el contador cuenta en modo de 16 bits. TR0 = 1 Timmer Ram 1 indica al contador que cuente ET0 = 1 habilita particularmente a timmer 0 como “generador” de interrupciones. ( ET0 corresponde a un bit del registro IE) EA = 1 habilita a todas aquellas interrupciones que hayan sido previamente validadas con los bits demás de control del registro EA. TCON = 0x30 esta instrucción fuerza la primera interrupción. */ { if (reloj == 0) reloj=1 ; else reloj=0; /* Al iniciar la rutina de servicio, se setea o resetea la variable reloj, que en este caso corresponde al bit 3 de la puerta uno, según la definición que se hace previamente. */ TH0 = 0xFF; /* set timer period valor real= 0x63C0*/ TL0 = 0xFC; /*para simular se coloca valor bajo */ /* En estas dos instrucciones, se inicializa el byte alto y el byte bajo del registro contador, que ya se encuentra preparado para contar en modo de 16 bits, ( TH0 y TL0 son ambos de ocho bits. El registro contiene entonces 0xFFFC que es el inicio del conteo ascendente, el cual se realiza hasta que el contador se rebalsa, sobrepasando el valor 0xFFFF. Si tenemos que el contador cuenta instrucciones ejecutadas (del assembler, no de C), y cada instrucción tiene un tiempo aproximado de ejecución de un microsegundo, al definir estos valores, definimos el tiempo que permanecerá en alto ( 1 ) el bit reloj, y cuanto tiempo permanecerá en bajo. El rebalse ocurre si contador>0xFFFF, luego, nosotros tenemos que el tiempo en alto de la señal reloj esta dado por la diferencia entre el Primer numero no representable en cuatro bits HEX y el valor que se pasa al registro contador, el tiempo está expresado en microsegundos, pues cada incremento de contador tarda un microsegundo Notar que en este caso, el tiempo que esta reloj en uno es igual al tiempo que permanece en cero. Laboratorio de Estructuras de Computadores I. Segundo Semestre 1999. 4 Si se hubiesen considerado los valores indicados en comentarios precedentes, se habría tenido una señal de período igual a 80 milisegundos ( 40 [ms] en alto y 40 [ms] en bajo ).*/ /* 65536-40000=25536=0x63C0 Cálculo de cuenta regresiva del timer en modo 1*/ } void main(void) { /* setup timer 0 interrupt. Inicialización del timer con interrupciones. */ TMOD = 0x01; /* select mode 1 */ TR0 = 1; /* start timer 0 */ ET0 = 1; /* enable timer 0 interrupt */ EA = 1; /* global interrupt enable */ TCON = 0x30; /* timer on and force interrupt */ /* Al pasar por estas líneas, se inicializan los bits necesarios del control de las interrupciones, como se indicó anteriormente, */ /* program main routine, do forever */ while (1) {;} /* Al entrar a while, evalúa la condición uno es igual a uno, y como es siempre verdadera, ejecuta este lazo indefinidamente. Sin embargo, el contador que se encontraba previamente inicializado con el valor indicado anteriormente, se incrementa con cada ciclo de reloj hasta el momento en que se produce el rebalse. En ese momento, se genera la interrupción que invoca a la rutina timmer0, que hace variar al bit reloj entre uno y cero. } 1. Simular, visualizando el timer y la puerta 1. Usar modo animación. Se copia el segmento de texto en el editor del PROVIEW32, se graba como archivo .c, y se ejecuta. Timmer0 y puerta uno se encuentran seleccionando el menú VIEW, hardware. Una vez que se tienen a la vista, nos permite visualizar la evolución de las variables que representan. El modo animación permite la ejecución paso a paso del programa, ya sea dejándolo correr con una velocidad regulable desde el panel o paso a paso mediante la tecla F7. 2. Dibujar la forma de onda del reloj, de acuerdo al programa. Para dibujar la forma de onda, se debe realizar la traza de las variables que nosotros queremos graficar. La traza se ve en el menú VIEW, TRACE, habiendo previamente agregado al watch las variables de interés y seteando las opciones de la traza para visualización continua, que se borre el contenido al reinicializar. La forma de onda se aprecia en la parte inferior de la ventana de la traza, haciendo clic en el casillero en que se indica el nombre de la variable. En este caso, la señal corresponde a una onda cuadrada que tiene la características de periodo y ciclo de trabajo antes mencionados. 3. Escribir programa que genere dos relojes ( P1.3 y P1.4) P1.3: Está en uno durante 50 mseg y en cero 150 mseg. P1.4: De ciclo 50 %, se coloca en uno en el canto de bajada de P1.3 #include <reg51.h> Laboratorio de Estructuras de Computadores I. Segundo Semestre 1999. 5 /* P1.3 Se le da nombre a un bit determinado */ sbit at 0x93 reloj ; /* Bit 0x93, corresponde a la puerta uno, tercer bit.*/ sbit at 0x94 reloj1 ; /* Bit 0x94 corresponde a la puerta uno, cuarto bit.*/ int k=0; /*Se declara una variable auxiliar k, la cual será usada como un contador */ /*en la rutina de interrupción.*/ /*Con la rutina de servicio se pretende generar las señales en los bits correspondientes de la siguiente forma: Primero tenemos que hacer que la rutina de interrupción dure 50 milisegundos, para lo cual modificamos los valores de TH0 y TL0 con el número correspondiente como se explicó en el punto anterior. El cálculo nos queda: 0x10000 – 0xc350 = 0x3cb0 ; en donde 0xc350 = 50000 (para lograr tiempo de 50milisegundos=50000 microsegundos) y 0x3cb0 que es el valor que debemos usar para inicializar el contador( TH0=0x3c , TL0=0xb0 ). Como cada rutina de interrupción dura 50 milisegundos nuestro programa debe lograr la siguiente secuencia en cada bit antes definido: Tiempo en milisegundos 50 100 150 200 250 300 350 400 Valor de k Reloj Reloj1 0 1 2 4 0 1 2 Etc... 0 1 0 0 0 1 0 0 0 1 1 0 0 1 Con el programa que se muestra a continuación se da solución a lo planteado; k es una variable usada para contar y controlar el ciclo de ejecución del programa. Notar que se obtiene la sincronización pedida, es decir, cuando el bit 0x93 tiene un canto de bajada, en el bit 0x94 se tiene un canto de subida .*/ void timer0(void) interrupt 1 using 2 { if (k == 4) k=0; if (k == 0) { reloj=1 ; reloj1=0; k=1; } else { reloj=0; if (k==1) reloj1=1; if (k==3) reloj1=0; Laboratorio de Estructuras de Computadores I. Segundo Semestre 1999. 6 k=k+1; } TH0 = 0x3c; TL0 = 0xb0; } void main(void) { /* setup timer 0 interrupt. Inicialización del timer con interrupciones.*/ TMOD = 0x01; /* select mode 1; Registro 81h: indica Timer 0 como contador de 16 bit*/ TR0 = 1; ET0 = 1; EA = 1; P1=0; TCON = 0x30 while (1) {;} Laboratorio de Estructuras de Computadores I. Segundo Semestre 1999. 7