to get the file

Anuncio
SISTEMAS
DIGITALES II
EJERCICIOS TEMA 2
RESUELTOS
Departamento de Sistemas Electrónicos y de Control
2005-2006
1
2
SISTEMAS DIGITALES II
EJERCICIOS RESUELTOS TEMA 2
EJERCICIO 1
Se dispone de un sistema basado en el 80C552 cuyas primeras posiciones de
memoria contienen las siguientes instrucciones:
Dirección
Instrucción
0000H-0002H
LJMP 4000H
0003H-0005H
LJMP 6000H
000BH-000DH
LJMP 6100H
0013H-0015H
LJMP 6200H
Además, se conoce que el contenido de algunos registros es el que se muestra en la
tabla siguiente:
Registro
Contenido
IEN0
10000111b
IEN1
00000000b
IP0
00000010b
IP1
00000000b
TCON
00000101b
Por ultimo se sabe que como parte del código desarrollado para la aplicación existen
las siguientes rutinas, ubicadas por el “enlazador” en las direcciones que se muestran:
Función
Dirección
void rutina0 (void) interrupt 0
6000H
void rutina1 (void) interrupt 1
6100H
void rutina2 (void) interrupt 2
6200H
Responda a las siguientes preguntas:
a) ¿Qué interrupciones se utilizan en este sistema y cómo están programadas?
b) ¿Qué función da servicio a cada una de las interrupciones utilizadas?
c) Suponga que el microcontrolador, en un momento dado, se
medio de la ejecución de la “rutina0” y se producen las dos
restantes de forma simultánea. ¿Cuál sería la secuencia de
código seguida por el microcontrolador? (indique tan sólo el
3
encuentra en
interrupciones
ejecución del
nombre de la
función, cuando considere que se debe ejecutar el programa principal indíquelo
con “main”)
d) Suponga que el microcontrolador, en un momento dado, se encuentra en
medio de la ejecución de la “rutina0” y se producen las tres interrupciones de
forma simultánea. ¿Cuál sería la secuencia de ejecución del código seguida
por el microcontrolador? (indique tan sólo el nombre de la función, cuando
considere que se debe ejecutar el programa principal indíquelo con “main”)
e) ¿Qué se entiende por tiempo de latencia en una interrupción?
SOLUCIÓN:
a)
Interrupción externa 0, activa por flanco de bajada y en el nivel bajo de prioridad.
Interrupción externa 1, activa por flanco de bajada y en el nivel bajo de prioridad.
Interrupción por desbordamiento del timer 0, en el nivel alto de prioridad.
b)
Externa 0: rutina0 (void)
Externa 1: rutina2 (void)
Timer 0: rutina1 (void)
c)
La secuencia en la ejecución sería la siguiente
se producen las dos interrupciones restantes a la vez
rutina0 → rutina1 → rutina0 (continuación) → main →
→ rutina2 → main
d)
La secuencia en la ejecución sería la siguiente
se producen las tres interrupciones a la vez
rutina0 → rutina1 → rutina0 (continuación) → main →
→ rutina0 (otra vez) → main → rutina2 → main
e)
El tiempo que tarda el microcontrolador desde que se produce la petición de
interrupción hasta que se ejecuta la primera instrucción de la rutina de atención a la
misma. No es un tiempo fijo, al contrario, se trata de un tiempo variable cuyo valor
depende de tres parámetros principalmente:
•
Si se está ejecutando otra interrupción de mayor o igual prioridad, en cuyo caso
habrá de esperar la nueva interrupción a que finalice la ejecución de la rutina
en curso
4
•
•
Siempre tiene que ejecutarse por completo una instrucción antes de proceder
con la secuencia de atención a la interrupción, por lo tanto el retraso dependerá
del tiempo de ejecución de la instrucción en curso.
Si la instrucción en curso es un RETI o una escritura en los registros IE o IP ha
de ejecutarse una instrucción adicional.
Por lo tanto, el tiempo de latencia es desconocido a priori y su valor dependerá de las
circunstancias en las que se produzca la petición.
EJERCICIO 2
Se quiere realizar un reloj de tiempo real con el 8051 programando uno de los timers para
que genere interrupciones periódicamente, con una frecuencia que sea múltiplo de una
centésima de segundo; también habrá que realizar la rutina de atención a la interrupción
de manera que actualice los datos del reloj: las centésimas, los segundos, los minutos y
las horas.
Se utilizará el timer 0 del 8051 para realizar un temporizador con recarga automática, de
manera que dicho timer interrumpa a la CPU con una frecuencia constante. La subrutina
de atención a estas interrupciones se encargará de actualizar las variables que tendrán
en todo momento los datos sobre las centésimas, los segundos, los minutos y las horas.
Indique los valores (en binario) que deben tener los siguientes registros del 8051 para
cumplir con las especificaciones anteriores, explicando brevemente el significado del
contenido de cada uno de ellos:
TMOD=
TCON=
IE=
Sabiendo que el 8051 tiene conectado un reloj de 11.059 Mhz, calcule el número de
cuenta que debería cargarse en TH0 para generar una interrupción cada centésima de
segundo:
TH0=
Si el número calculado sobrepasa la capacidad de TH0 ¿cómo se puede resolver este
problema?
Realice el código en lenguaje C correspondiente al programa principal y a la rutina de
atención a la interrupción del Timer 0. Teniendo en cuenta que:
La rutina de atención a la interrupción del timer 0 debe actualizar
convenientemente las centésimas, los segundos, los minutos y las horas de
nuestro reloj. Cada uno de estos datos se manejará como un contador software
que habrá que incrementar en uno o bien habrá que ponerlo a cero si ha
llegado al final de su cuenta.
5
El programa principal, una vez realizada la inicialización del sistema,
permanecerá en un bucle infinito en el que no deberá realizar ninguna tarea.
SOLUCIÓN:
unsigned short int cuenta_tics=0; /* cuenta las interrupciones del timer 0 */
unsigned short int centesimas=0;
unsigned short int segundos=0;
unsigned short int minutos=59;
unsigned short int horas=23;
/* Rutina de atención a la interrupción del timer 0 Actualiza los registros del reloj con
el valor adecuado */
void tic_tac (void) interrupt 1
{
cuenta_tics++;
//almacena el numero de interrupciones que se producen
if (cuenta_tics>63)
//cuenta_tics = 64 indica que ha pasado una centésima
//de segundo */
{
cuenta_tics=0;
// puesta a cero para iniciar la medida de una nueva
//centésima
centesimas++;
if (centesimas>99)
{
centesimas=0;
segundos++;
if (segundos>59)
{
segundos=0;
minutos++;
if (minutos>59)
{
minutos=0;
horas++;
if (horas>23) horas=0;
}
}
}
}
}
main () {
EA = 0;
TMOD|=0x02;
TMOD&=0xFD;
// prohibimos interrupciones para programar los periféricos
// timer 0 como temporizador sin GATE y en modo 2
TH0=256-144;
// 1 centésima son 9216 tic_tacs del
reloj de 11,059 MHz dividido por 12
9216/64 = 144, se cuentan 64 tic_tacs para medir
una centésima
/* ponemos en marcha el timer 0 */
TR0=1;
6
IE |= 0x02;
EA = 1;
/* habilitamos la interrupción del timer 0 */
/* habilitamos las interrupciones */
while (1);
}
EJERCICIO 3
NOTA: Se supone que la frecuencia del reloj del sistema es de 11MHz
•
Configurar el Timer 0 para que genere una interrupción de alta prioridad cada
8.9 mseg aproximadamente. Indique también las tareas que sería
imprescindible realizar en la rutina de tratamiento de esta interrupción para que
el funcionamiento fuera el correcto.
•
Calcular cual es el máximo periodo que se puede configurar entre
interrupciones periódicas empleando este Timer
•
Realizar la programación del Timer para obtener una interrupción cada 200
useg
•
Calcular la precisión con la que se produce la interrupción anterior (suponiendo
que es la única existente en el sistema)
•
Obtener el rango de periodos en los que se podría generar una interrupción
empleando el modo 2 del Timer 0.
•
Indicar cómo podría generarse una interrupción cada segundo con la máxima
resolución posible.
SOLUCIÓN:
a) Se emplea el Modo 0 ya que para conseguir este periodo se necesita un contador
de 13bits
TMOD & = 0xF0;
IEN0 | = 0x02;
IP0 | = 0x02;
IEN0 | = 0x80;
TCON | = 0x10;
While (1);
//Modo 0, temporizador
//Habilita INTs Timer 0
//Int de alta prioridad
//Habilita INTs
//Habilita T0
En la rutina no hay que hacer nada puesto que el flag se borra solo.
void timer_0 (void) interrupt 1
{
Procesamiento de la interrupción
}
b) Se emplea el Modo 1 ya que este permite un mayor estado de cuenta al tener 16
bits
7
TMOD & = 0xF1;
TMOD | = 0x01;
IEN0 | = 0x02 ;
IP0 | = 0x02;
IEN0 | = 0x80;
TCON | = 0x10;
While (1);
//Modo 1, temporizador
//Habilita INTs Timer 0
//Int de alta prioridad
//Habilita INTs
//Habilita T0
En la rutina no hay que hacer nada puesto que el flag se borra solo.
void timer_0 (void) interrupt 1
{
Procesamiento de la interrupción
}
c) Se emplea el Modo 2 ya que este permite una recarga del contador que facilita la
configuración de un tiempo concreto. Para 200useg son necesarios 183,3 ciclos de
reloj del timer por lo que se aproxima por el entero más próximo 183 (0xB7).
TMOD & = 0xF2;
TMOD | = 0x02;
TH0 = 0x49;
IEN0 | = 0x02 ;
IP0 | = 0x02;
IEN0 | = 0x80;
TCON | = 0x10;
While (1);
//Modo 2, temporizador
//Habilita INTs Timer 0
//Int de alta prioridad
//Habilita INTs
//Habilita T0
El tiempo real entre interrupciones sería 199.69 useg
En la rutina no hay que hacer nada puesto que el flag se borra solo.
void timer_0 (void) interrupt 1
{
Procesamiento de la interrupción
}
d) La precisión viene marcada por el reloj que le llega al contador: 1,09useg
e) Para un valor de cuenta de 1 se obtiene un periodo de 1.09 useg
Para un valor de cuenta de 255 se obtiene un periodo de 279,2 useg
f) La solución pasa por contar interrupciones. La mayor precisión se obtendrá en el
modo 2 que es recargable y permite afinar el periodo.
Si por ejemplo si se cuentan hasta el valor 220 por parte del contador
(TH0=0x23) se necesitarían 4166.66 interrupciones. En este caso el tiempo real
entre interrupciones sería de 1.00008 segundos
8
EJERCICIO 4
NOTA: Se supone que la frecuencia del reloj del sistema es de 11MHz.
a) Programar las comunicaciones asíncronas del 80c552 para enviar de forma
continua el dato 0x55 por la línea de TX a la máxima velocidad posible
empleando 8 bits de datos y dos de stop. El microcontrolador no debe realizar
ninguna otra tarea.
a. Empleando poolling
b. Empleando interrupciones
b) Programar el microcontrolador para enviar y recibir simultáneamente datos por
el puerto serie a la velocidad de 9600 baudios con 8 bits de datos, 1 de parada
y sin paridad. El dato a enviar será siempre el 0xAA;
c) Programar el microcontrolador para enviar lo más rapidamente posible los 10
datos de un array de unsigned char llamado datos empleando velocidad de 200
baudios con 8 bits por dato, paridad par y con 1 bit de stop. Una vez finalizado
el envio la UART debe quedar deshabilitada.
d) Esperar a recibir 10 datos por el puerto serie y almacenarlos en el array
unsigned char datos [10]. Una vez recibidos los 10 datos se inhabilitará toda
Rx. Los datos llegan a 4800 baudios con 8 bits por dato, 1 bit de paridad y 1 bit
de stop. (NOTA la paridad no es necesario analizarla)
SOLUCIÓN:
a) Empleando polling
La máxima velocidad se obtiene con el modo 2 y activando el bit SMOD
Unsigned char dato=0x55;
PCON|=0x80;
S0CON=0x88;
//Se activa el bit SMOD
//Modo 2 con dos bits de stop y 8
//de datos
while (1)
{
S0BUF=dato;
S0CON & =0xFD;
While((S0CON&0x02)==0);
}
Empleando interrupciones
La máxima velocidad se obtiene con el modo 2 y activando el bit SMOD
Unsigned char dato=0x55;
PCON| = 0x80;
S0CON = 0x88;
//Se activa el bit SMOD
//Modo 2 con dos bits de stop y 8
//de datos
//Interrupciones de la UART
//Alta prioridad
//Habilita ints
IEN0 | = 0x10;
IP0 | = 0x10;
IEN0 | =0x80;
9
S0BUF=dato;
While (1);
//envía el primer dato
Void Int_UART (void) interrupt 4
{
if (S0CON&0x02)
{
S0BUF = dato;
S0CON & = 0xFD;
//Int de transmision?
//enviar nuevo dato
//Borrar el flag
}
}
b) Para poder enviar 8 datos + 1 bit de parada es necesario trabajar en modo 1 puesto
que los modos 2 y 3 solo permiten enviar tramas de 9 bits (+ 1 bit de stop)
Para ajustar la velocidad de Tx/Rx es necesario emplear el Timer 1 como
generador de reloj configurado en el modo 2 para posibilitar la recarga.
El valor de recarga se obtendrá de la expresión
BAUD=(2SMOD*fosc)/(32*12*(256-TH1))
Seleccionando SMOD = 1 y despejando queda TH1=250’032.
Como se emplea 250 (0xFA) no se obtienen 9600 baudios sino 9548.
Unsigned char dato_enviar=0x55, dato_recibir;
TCON & = 0xB0;
//Parar el T1
TMOD & = 0x2F;
//Gate=0, CT=0
TMOD | = 0x20;
//Modo 2
TH1=0xFA;
//Ajuste de la velocidad
PCON| = 0x80;
//Se activa el bit SMOD
S0CON = 0x50;
//Modo 1 con 1 bit de stop y 8
//de datos. Se activa REN
IEN0 | = 0x10;
//Interrupciones de la UART
IP0 | = 0x10;
//Alta prioridad
IEN0 | =0x80;
//Habilita ints
TCON | = 0x40;
//Arranca el T1
S0BUF=dato;
//envío del primer dato
While (1);
Void Int_UART (void) interrupt 4
{
if (S0CON&0x02){
S0BUF = dato_enviar;
S0CON & = 0xFD;
}
if (S0CON&0x01) {
dato_recibir=S0BUF;
Tratamiento (dato_recibir)
S0CON & = 0xFE;
}
}
10
//Int de transmision?
//enviar nuevo dato
//Borrar el flag
//Int de recepción?
//se lee el dato
//tratamiento de un dato recibido
//Borrar el flag
c) Para enviar 8+1+1 es necesario trabajar en modo 2 o modo 3. De estos dos el que
permite ajustar la velocidad de salida es el modo 3.
Para calcular el valor de recarga del Timer1 es necesario emplear la expresión
BAUD=(2SMOD*fosc)/(32*12*(256-TH1)).
Si se selecciona SMOD=0 el resultado es TH1=113 (para SMOD=1 no sería
posible)
Unsigned char datos[10];
Unsigned char paridad_par;
TCON & = 0xB0;
TMOD & = 0x2F;
TMOD | = 0x20;
TH1=0x71;
PCON & = 0x7F;
S0CON = 0xC0;
IEN0 | = 0x10;
IP0 | = 0x10;
IEN0 | =0x80;
TCON | = 0x40;
Paridad_par=CalculaParidad(dato[0]);
If (Paridad_par)
S0CON & = 0xF7;
Else
S0CON | = 0x08;
S0BUF=dato[0];
//Parar el T1
//Gate=0, CT=0
//Modo 2
//Ajuste de la velocidad
//Desactiva el bit SMOD
//Modo 3 con 1 bit de stop 1 de
//paridad y 8 de datos.
//Interrupciones de la UART
//Alta prioridad
//Habilita ints
//Arranca el T1
//se pone a 0 la paridad
//se pone a 1 la paridad
//envio del primer dato
While (1);
Void Int_UART (void) interrupt 4
{
static unsigned int cuenta=1;
if (S0CON&0x02){
//Int de transmision?
Paridad_par=CalculaParidad(dato[cuenta++]);
If (Paridad_par)
S0CON & = 0xF7;
//se pone a 0 la paridad
Else
S0CON | = 0x08;
//se pone a 1 la paridad
If (cuenta<10)
S0BUF = dato[cuenta];
//enviar nuevo dato
S0CON & = 0xFD;
//Borrar el flag
}
}
unsigned char CalculaParidad(unsigned char dato)
{
unsigned char paridad=0;
for (i=0;i<8;i++) {
paridad=paridad^((dato>>i)&0x01);
}
11
return paridad;
}
d) Para recibir 8+1+1 es necesario trabajar en modo 2 o modo 3. De estos dos el que
permite ajustar la velocidad de salida es el modo 3.
Para calcular el valor de recarga del Timer1 es necesario emplear la expresión
BAUD=(2SMOD*fosc)/(32*12*(256-TH1)).
Si se selecciona SMOD=0 el resultado es TH1=0xFA
Unsigned char datos[10];
Unsigned char paridad_par;
TCON & = 0xB0;
TMOD & = 0x2F;
TMOD | = 0x20;
TH1=0xFA;
PCON & = 0x7F;
S0CON = 0xD0;
//Parar el T1
//Gate=0, CT=0
//Modo 2
//Se ajusta la velocidad
//Desactiva el bit SMOD
//Modo 3 con 1 bit de stop 1 de
//paridad y 8 de datos y Rx activa.
//Interrupciones de la UART
//Alta prioridad
//Habilita INTs
//Arranca el T1
IEN0 | = 0x10;
IP0 | = 0x10;
IEN0 | =0x80;
TCON | = 0x40;
While (1);
Void Int_UART (void) interrupt 4
{
static unsigned int cuenta=0;
if (S0CON&0x01){
dato[cuenta++]= S0BUF;
If (cuenta==10)
S0CON&=0xEF;
S0CON & = 0xFE;
}
}
12
//Int de recepcion?
//guardar nuevo dato
//Deshabilita Rx
//Borrar el flag
Descargar