Está en la página 1de 173

SISTEMAS ELECTRNICOS DIGITALES

Autores: Fernndez Martnez Cesreo Snchez Miralles lvaro

Sistemas Electrnicos Digitales.

Captulo 1 Captulo 2
1 2 3

Filosofa del libro _______________________________________________ 5 Arquitectura de un micro _________________________________________ 6

Introduccin ______________________________________________________________ 6 Objetivos y conceptos a entender en este captulo________________________________ 6 Modelo del programador de un micro _________________________________________ 6
3.1 La CPU _________________________________________________________________________ 7 3.2 La memoria ______________________________________________________________________ 7 3.3 Codificacin de las instrucciones _____________________________________________________ 9 3.4 Ciclos de ejecucin de una instruccin ________________________________________________ 10 3.5 Ejemplo de funcionamiento de la ejecucin de un programa _______________________________ 11 3.6 Distintos niveles de abstraccin de un sistema electrnico digital ___________________________ 13 3.7 Organizacin de un micro a nivel de bloques y buses _____________________________________ 15

Cuestiones de comprensin _________________________________________________ 17

Captulo 3
1 2

Arquitectura y Mapa de memoria del C167 _________________________ 18

Objetivos y conceptos a entender en este captulo_______________________________ 18 Arquitectura del C167 _____________________________________________________ 18


2.1 Modelo del programador del C167 ___________________________________________________ 2.2 Ensamblador de C167 _____________________________________________________________ 2.2.1 Resumen de instrucciones en ensamblador _________________________________________ 2.2.2 Modos de direccionamiento_____________________________________________________ 2.2.3 Nmeros con signo y sin signo __________________________________________________ 2.2.4 Ejemplos bsicos de codificacin en ensamblador ___________________________________ 2.3 Mapa de memoria del C167_________________________________________________________ 2.3.1 Los registros de propsito general GPRs___________________________________________ 2.3.2 Principales SFRs de la CPU_____________________________________________________ 19 20 23 24 26 27 27 29 29

3 4 5

Cuestiones de comprensin _________________________________________________ 33 Ejercicios propuestos ______________________________________________________ 33 Prctica 1: Introduccin al Siemens C167 _____________________________________ 40

Captulo 4
1 2 3 4 5

Puertos ______________________________________________________ 48

Objetivos y conceptos a entender en este captulo_______________________________ 48 Puertos paralelo __________________________________________________________ 48 Ejercicios propuestos ______________________________________________________ 52 Prctica 2: entradas y salidas digitales________________________________________ 53 Prctica 3: ensamblar y depurar ____________________________________________ 55

Captulo 5
1 2 3

Perifricos____________________________________________________ 60

Objetivos y conceptos a entender en este captulo_______________________________ 60 Perifricos del C167 _______________________________________________________ 60 El Timer ________________________________________________________________ 61

Sistemas Electrnicos Digitales.

3.1 Registro de control T01CON________________________________________________________ 3.2 Registros de datos ________________________________________________________________ 3.3 Registro de control de interrupciones T0IC_____________________________________________ 3.4 Resumen de funcionamiento ________________________________________________________ 3.5 Ajuste del pre-escalado ____________________________________________________________ 3.6 Ejemplo de programacin: LEDs a ritmo de reloj ________________________________________

61 62 62 63 63 63

4 5 6

Cuestiones de comprensin _________________________________________________ 65 Ejercicios propuestos ______________________________________________________ 66


5.1 PWM sencillo (30 min) ____________________________________________________________ 66

Prctica 4: timers _________________________________________________________ 68

Captulo 6
1 2 3

Ensamblador__________________________________________________ 71

Objetivos y conceptos a entender en este captulo_______________________________ 71 Introduccin _____________________________________________________________ 71


2.1 Codificacin de instrucciones _______________________________________________________ 71

Operaciones de transferencia de datos________________________________________ 72


3.1 MOV y MOVB __________________________________________________________________ 72 3.2 MOVBZ y MOVBS ______________________________________________________________ 73 3.3 PUSH y POP ____________________________________________________________________ 73

Instrucciones para realizar operaciones aritmticas_____________________________ 74


4.1 ADD y ADDB ___________________________________________________________________ 4.2 SUB y SUBB____________________________________________________________________ 4.3 NEG___________________________________________________________________________ 4.4 MUL y MULU __________________________________________________________________ 4.5 DIV y DIVU ____________________________________________________________________ 74 75 75 76 76 77 78 78 79

Instrucciones para realizar operaciones lgicas ________________________________ 77


5.1 AND __________________________________________________________________________ 5.2 OR ____________________________________________________________________________ 5.3 XOR___________________________________________________________________________ 5.4 CPL ___________________________________________________________________________

6 7 8

Instrucciones para realizar desplazamientos de bits_____________________________ 79 Saltos ___________________________________________________________________ 81 Ejemplos de equivalencias de C y ensamblador ________________________________ 83
8.1 Condicin if _____________________________________________________________________ 83 8.2 Bucle for _______________________________________________________________________ 84 8.3 Bucle while _____________________________________________________________________ 84

Instrucciones a nivel de bit _______________________________________________ 85


9.1 Saltos __________________________________________________________________________ 86 9.2 Otras __________________________________________________________________________ 86

10 11 12 13

Directivas de ensamblador _________________________________________________ 88 Cuestiones de comprensin _________________________________________________ 90 Ejemplo de discusin: medida de ancho de pulso, sin/con filtrado de rebotes ________ 96 Ejercicios _______________________________________________________________ 100

Sistemas Electrnicos Digitales.

13.1 Acceso a memoria (15 min)_______________________________________________________ 13.2 Encendido apagado de LED (10 min) _______________________________________________ 13.3 Volcado de memoria (20 min)_____________________________________________________ 13.4 Cuenta de pulsos (30 min) ________________________________________________________ 13.5 Calculadora (40 min) ____________________________________________________________

100 101 102 103 104

14

Ejercicios resueltos _______________________________________________________ 106


14.1 LEDs e interruptores ____________________________________________________________ 106 14.2 Medida de ancho de pulso con rebotes (20 min) _______________________________________ 108 14.3 Medida de ancho de pulso (20 min)_________________________________________________ 110

15

Prctica 5: ejercicios en ensamblador, control de un servo ______________________ 112

Captulo 7
1 2

Drivers. El convertidor AD _____________________________________ 115

Objetivos y conceptos a entender en este captulo______________________________ 115 Concepto de driver _______________________________________________________ 115
2.1 Ejemplos de driver_______________________________________________________________ 2.1.1 Driver sencillo del puerto P2 ___________________________________________________ 2.2 Driver del Timer 0 _______________________________________________________________ 2.3 Driver del convertidor AD_________________________________________________________ 115 116 116 116 118 119 119 119

El convertidor analgico digital (AD)________________________________________ 117


3.1 Registro de control ADCON _______________________________________________________ 3.2 Registro de datos ADDAT ________________________________________________________ 3.3 Registro de control de interrupciones ADCIC__________________________________________ 3.4 Ejemplo de programacin _________________________________________________________

Captulo 8
1 2

Programacin en C para micros _________________________________ 121

Objetivos y conceptos a entender en este captulo______________________________ 121 Tipos de datos para el C167 _______________________________________________ 121
2.1 Nmeros enteros ________________________________________________________________ 121 2.2 Nmeros reales _________________________________________________________________ 123 2.3 Variables lgicas ________________________________________________________________ 123

3 4 5 6 7

Operadores bit a bit ______________________________________________________ 124 Instrucciones de control___________________________________________________ 125 Bucles__________________________________________________________________ 126 Vectores ________________________________________________________________ 127 Punteros _______________________________________________________________ 129
7.1 El operador & ___________________________________________________________________ 130 7.2 El operador * ___________________________________________________________________ 131 7.3 Operaciones con punteros _________________________________________________________ 132

Funciones ______________________________________________________________ 135


8.1 Variables globales y locales _______________________________________________________ 137 8.2 Paso de parmetros por "referencia" _________________________________________________ 137 8.3 Paso de vectores como parmetros __________________________________________________ 138

9 10

Cuestiones de comprensin ________________________________________________ 141 Ejercicios propuestos _____________________________________________________ 145

Sistemas Electrnicos Digitales.

10.1 Timer y puertos (40 min)_________________________________________________________ 145 10.2 Acceso a memoria (40 min)_______________________________________________________ 146

11

Ejercicios resueltos _______________________________________________________ 148


11.1 La calculadora (30 min)__________________________________________________________ 148 11.2 El coche fantstico (20 min) ______________________________________________________ 151 11.3 El autobus (30min) _____________________________________________________________ 153

12

Prctica 6: ejercicios en lenguaje C _________________________________________ 155

Captulo 9
1 2 3 4 5

Interrupciones _______________________________________________ 158

Objetivos y conceptos a entender en este captulo______________________________ 158 Nociones bsicas de interrupciones__________________________________________ 158 Recursos utilizados en una interrupcin _____________________________________ 159 Ejemplos _______________________________________________________________ 160 Prctica 7: interrupciones en C_____________________________________________ 162

Captulo 10
1 2 3 4

Sistemas digitales complejos ____________________________________ 165

Objetivos y conceptos a entender en este captulo______________________________ 165 Sistemas muestreados ____________________________________________________ 165 Fechado ________________________________________________________________ 167 Programacin basada en estados ___________________________________________ 170

Referencias ______________________________________________________________ 172

Sistemas Electrnicos Digitales.

Captulo 1 FILOSOFA DEL LIBRO


El objetivo de este libro es optimizar el aprendizaje del lector, presentndole un material autocontenido que incluye informacin terica, ejemplos, cuestiones de comprensin, ejercicios propuestos y resueltos, problemas propuestos y resueltos, y finalmente las prcticas de laboratorio. Adicionalmente, cada captulo tiene una seccin que informa de los conceptos prioritarios que deben quedar claros en el mismo. La organizacin se ha hecho para conseguir una sincronizacin perfecta entre los contenidos tericos y de laboratorio, de forma que el lector pueda conocer qu es lo que tiene que saber para hacer una prctica. Adems todo el libro sigue un orden que se corresponde con el orden cronolgico de las clases presenciales. Para optimizar el aprovechamiento del libro se recomienda seguir los siguientes pasos: Ir leyendo captulo a captulo, en orden secuencial segn el ritmo de las clases presenciales y del laboratorio. En cada captulo prestar especial atencin a la seccin de "Objetivos y conceptos a entender", de forma que se debe tener claro cuando se considera que se han cumplido esos objetivos. Una vez que se tenga claro el punto anterior se puede proceder a leer las siguientes secciones descriptivas y los ejemplos. El lector puede cerciorarse del entendimiento de los conceptos, haciendo las cuestiones de comprensin que hay en cada captulo. Comprobada la comprensin del captulo, el lector debe hacer los ejercicios que se propongan. Finalmente existen problemas al final de cada captulo que sirven de material complementario para adquirir habilidad y destreza en el planteamiento y solucin de problemas de sistemas digitales. Por ltimo, cabe resear que es importante reflexionar y pararse a pensar sobre los conceptos que aparecen en negrita en el texto, ya que aunque no tienen por qu ser conceptos ms importantes que otros, si es cierto que suelen olvidarse con mayor facilidad y son claves para entender otros conceptos.

Sistemas Electrnicos Digitales.

Captulo 2 ARQUITECTURA DE UN MICRO


1 Introduccin
Para poder utilizar un microcontrolador es necesario conocer su arquitectura; es decir en qu consiste por dentro desde el punto de vista de un programador, enfocndose en conocer cules son sus recursos, como son qu instrucciones y modos de direccionamiento soporta, cules son los registros y su tamao, cmo es el mapa de memoria y cunto tarda una instruccin en ejecutarse. Cosa muy distinta a lo que es la organizacin de un computador, que consiste en conocer las tripas del mismo, el hardware, cuantos mdulos tiene y cmo estn conectados (punto de vista del diseador); nada ms lejos de los objetivos de esta asignatura.

2 Objetivos y conceptos a entender en este captulo


Entender por qu es importante conocer el modelo del programador de un micro. Entender el modelo del programador, conociendo las unidades de las que consta y cmo se comunican entre s. para qu sirve el PC? Entender cmo la CPU ejecuta una instruccin Entender qu almacena fsicamente una memoria y los niveles de abstraccin que permiten interpretar esa informacin.

3 Modelo del programador de un micro


Desde el punto de vista del programador, segn el modelo Von Neumann, un micro se ve como una mquina con los bloques mostrados en la Figura 1: La unidad de control y la unidad aritmtico lgica (ALU) que junto con los registros forman la CPU. La ALU es la encargada de realizar las operaciones aritmticas que requieran cada una de las instrucciones, los registros son celdas de memoria de acceso rpido y la unidad de control reparte trabajo y coordina el resto de bloques. La memoria principal, que es la encargada de almacenar datos, programas y resultados intermedios (ms grande pero ms lenta que el banco de registros). La unidad de entrada y salida de datos (I/O). Elemento imprescindible para que el microcontrolador se pueda comunicar con el exterior, de otra forma sera intil. Gracias a esta unidad se pueden conectar sensores y actuadores al micro, adems de poderse comunicar con otros micros y sistemas digitales.

Sistemas Electrnicos Digitales.

Unidad de Memoria

Unidad de Entrada

Unidad Aritmtica y lgica (ALU)

Unidad de salida

Unidad de Control CPU


Figura 1: Modelo Von Neumann de un microcontrolador

A continuacin se pasa a explicar cada una de estas unidades ms en detalle. 3.1 La CPU La CPU adems de incluir la unidad de control y de la unidad aritmtico lgica, contiene los registros, que es un banco de memoria acceso de acceso rpido para el almacenamiento de datos. Se dice que un micro es de 8 bits si estos registros son de 8 bits, es de 16 bits si estos registros son de 16 bits, etc. De todos los registros que tiene una CPU, desde el punto de vista de un programador interesa conocer los siguientes: Rx o registros de proposito general: registros que se usan como lugar de almacenamiento temporal de un dato. Son bsicos para operaciones en la ALU, ya que sirven como punto de entrada y salida de la misma, sirven de apoyo para transferir informacin entre dos posiciones de memoria, etc. En el C167 estos registros son 15 y se notan por Rx (siendo x un nmero del 0 al 15). PC o program counter: contiene la direccin de la prxima instruccin a ejecutar. En el C167 est registro est formado por dos el IP y el CSP. IR o instruction register: (nico registro que almacena instrucciones en lugar de datos) registro que contiene la instruccin que se est procesando. Este registro no se puede usar por un programador, simplemente es parte del hardware necesario para que la CPU procese instrucciones. SR o state register: contiene el estado del micro despus de haber ejecutado una instruccin. Por ejemplo, contiene informacin de si una operacin ha dado un resultado negativo, si en una suma ha generado un acarreo, etc. En el C167 este registro se denomina PSW. 3.2 La memoria La memoria es la encargada de almacenar las instrucciones a ejecutar o programa y los datos que usa ese programa.

Sistemas Electrnicos Digitales.

Los datos estn almacenados en formato binario en celdas de 8 bits. Por ejemplo el nmero 5 est codificado de la siguiente forma: 0000 0101 5 0x05

Nmeros ms grandes, por ejemplo el 127: 0111 1111 127 0x7F

Para manejar nmeros binarios con comodidad se utiliza la base hexadecimal. Los nmeros binarios agrupados de 4 en 4 bits forman las cifras en hexadecimal. La memoria est organizada en celdas de 8 bits. A cada celda se asigna una direccin de memoria, de forma que el micro puede acceder al dato almacenado en dicha celda indicndole a la memoria (en el bus de direcciones) la direccin de la celda a la que desea acceder, ver Figura 2.

Direccin 0000 0001

Dato 05 7F

FFFF

A0

Figura 2: Organizacin de la memoria

El micro sabe qu direcciones de memoria contienen instrucciones y qu direcciones de memoria contienen datos: Toda direccin de memoria que se acceda a travs del registro PC, el micro interpreta su contenido como una instruccin de programa. Toda direccin de memoria que se acceda de otra manera se considera como que contiene un dato; por ejemplo cuando el micro acceda para coger un dato y guardarlo en un registro de proposito general.

Sistemas Electrnicos Digitales.

3.3 Codificacin de las instrucciones Las instrucciones tambin estn almacenadas en memoria en formato binario. Por ejemplo, la siguiente instruccin: add R1,R0

Significa: Suma el dato almacenado en el registro R0 con el dato almacenado en el registro R1 y deja el resultado en el registro R1. Esta instruccin podra estar codificada de la siguiente forma

0001 0000 0001 0000


Los 16 bits del cdigo de instruccin indican:

0x1010

Los 4 bits ms significativos almacenan el cdigo de la instruccin (0001 para la instruccin ADD) Los 12 bits menos significativos indican cules son los operandos o parmetros de la instruccin. Para el caso de la instruccin anterior, los 4 bits menos significativos codifican el nmero de registro que se usa como sumando primero (0000 significa R0), los 4 siguientes bits codifican el nmero de registro que se usa como sumando segundo (0001 significa R1) y por ltimo los siguientes bits no se usan.

15 1

12 NA

3 Rs1

Rs2

Utilizando esta codificacin el microprocesador en cuestin podra hacer operaciones de suma de: Un mximo de 16 registros de propsito general (dado que slo se utilizan cuatro bits para codificar el nmero de registros. Un mximo de 16 instrucciones (cuatro bits para el cdigo de instruccin). Los micros reales, en particular el C167, tienen ms registros y soportan en amplio conjunto de operaciones aritmtico/lgicas. Otro ejemplo posible de codificacin siguiendo este esquema es el siguiente: move R0,0x10

Sistemas Electrnicos Digitales.

Pone lo que hay en la direccin de memoria 0x10 en el registro R0. La codificacin podra ser:

0002 0000 0001 0000

0x2010

15 2

12 11 Rs

8 7 mem

Los 4 bits ms significativos almacenan el cdigo de la instruccin (0002 para la instruccin MOV Rx, mem) Los 8 bits menos significativos codifican la direccin de la memoria de donde se coge el dato (0x10), los 4 siguientes bits codifican el nmero de registro que se usa como destino (0000 significa R0).

Estos ejemplos de codificacin indican que: El nmero de bits necesarios para codificar una instruccin depende del tamao del microprocesador. Un micro ms grande (con ms registros) necesitar ms bits para codificar una instruccin dada. Las instrucciones en memoria necesitarn por tanto ms o menos celdas de memoria para ser almacenadas.

3.4 Ciclos de ejecucin de una instruccin La CPU es la encargada de ejecutar las instrucciones que estn en la memoria a partir de la posicin de la misma que indique el PC. La ejecucin de una instruccin supone la ejecucin de dos ciclos, ver Figura 3: 1. Ciclo de Fetch: en este ciclo se busca la instruccin que se tiene que ejecutar y se interpreta para saber qu se tiene que ejecutar. Adems incrementa PC para que apunte a la siguiente instruccin. Los pasos de este ciclo son: a. El Contador de Programa (PC) contiene la direccin de la prxima instruccin a ejecutar b. El procesador captura la instruccin de memoria c. La instruccin se carga en el Registro de Instrucciones (IR) d. El PC se incrementa (salvo en las instrucciones de salto, que el PC ser el valor de la direccin de salto). e. Se interpreta la instruccin y se generan las seales de control (decodificacin instruccin) 2. Ciclo de ejecucin: en este ciclo se ejecuta propiamente lo que indica la instruccin. La CPU puede ejecutar diferentes instrucciones: a. Transferencia de procesador a memoria

10

Sistemas Electrnicos Digitales.

b. c. d. e.

Transferencia de procesador a I/O Procesado de datos. La ALU efecta una operacin sobre los datos Instrucciones de control. Alteran la secuencia de programa; p.e. Jump Combinacin de las anteriores

Figura 3: ciclos de ejecucin de una instruccin

3.5 Ejemplo de funcionamiento de la ejecucin de un programa A continuacin se presenta un ejemplo muy importante desde el punto de vista conceptual, que ilustra cmo un micro ejecuta un conjunto de instrucciones, poniendo de manifiesto los conceptos explicados en anteriores secciones. En lenguaje de alto nivel, el ejercicio consiste en sumar los dos nmeros que se encuentran las direcciones de memoria 0x80 y 0x82, para posteriormente guardar el resultado en la direccin 0x84. Algo similar a la instruccin: (0x84) = (0x80) + (0x82) los parntesis indican "lo que hay en la direccin de memoria". En lenguaje simblico cdigo mquina, que es el que entiende el micro, esta operacin requiere de tres instrucciones que se apoyan en los registros de proposito general para realizar la operacin anterior: move R0,0x80 que en cdigo mquina se representa por 2080(H) move R1,0x82 que en cdigo mquina se representa por 2182(H) add R1,R0 que en cdigo mquina se representa por 1010(H) move 0x84,R1 que en cdigo mquina se representa por 3841(H) Si se analiza con detalle la codificacin mquina, cada una de las instrucciones (codificadas en ensamblador, que es el lenguaje ms cercano al cdigo mquina que un programador conoce) consiste de cuatro dgitos, el primero de ellos representa la operacin a realizar segn el tipo de parmetros que usa, y los ltimos tres dgitos representan los operandos de la misma. Es necesario hacer notar que las tres instrucciones son las ms sencillas en las que se puede descomponer el ejemplo, desde el punto de vista de una mquina, ya cada una de ellas slo realiza una accin, o bien una transferencia de informacin o bien una operacin con la ALU.

11

Sistemas Electrnicos Digitales.

Una vez cargado el programa en la posicin 0, la memoria queda como se indica en la

0000 0002 0004 0006

2080 2182 1010 3841

Instruccin Instruccin Instruccin Instruccin

0080 0082

0007 0003

Dato Dato

FFFF

A0

Figura 4: Memoria despus de cargar el programa ejemplo

Una vez que se manda ejecutar el programa, poniendo PC = 0x0000, se empieza a ejecutar la primera instruccin, como se muestra en la Figura 5. En la fase de Fetch se coge la instruccin de la memoria a la que apunta PC y se guarda en IR, quedando IR = 0x2080, para posteriormente incrementar PC para que apunte a la siguiente instruccin. En la fase de Execute se ejecuta la instruccin que hay en IR; es decir, se coge el valor que hay en la direccin de la memoria 0x80 y se pone en R0, quedando R0 = 7. Y as sucesivamente para las tres siguientes instrucciones, como se puede ver en la Figura 6, Figura 7 y Figura 8.
Fetch Execute

0000 0002

2080 2182 1010

0002 2080

PC IR

0080 0082

0007 0003 0000

0007 0000

R0 R1

Figura 5: ejecucin de la instruccin mov R0, 0x80

12

Sistemas Electrnicos Digitales.

0000 0002

2080 2182 1010

0004 2182

PC IR

0080 0082

0007 0003 0000

0007 0003

R0 R1

Figura 6: ejecucin de la instruccin mov R1, 0x82


ALU: R1 <- R0+R1

0004 0006

1010 3841 0000

0006 1010

PC IR

0080 0082 0084

0007 0003 0000

0007 000A 0000

R0 R1 R2

Figura 7: ejecucin de la instruccin add R1,R0

0004 0006

1010 3841 0000

0008 3841

PC IR

0080 0082 0084

0007 0003 000A

0007 000A 0000

R0 R1 R2

Figura 8: ejecucin de la instruccin move 0x84, R1

Es importante entender este ejemplo, para entender cmo ejecuta las instrucciones un micro y por lo tanto comprender mejor los detalles del lenguaje ensamblador para programar un micro. Este lenguaje es el de ms bajo nivel que se puede programar, el cual tiene una correspondencia biunvoca entre cdigo mquina e instruccin de ensamblador. 3.6 Distintos niveles de abstraccin de un sistema electrnico digital Segn al nivel que se trabaje, se puede ver un sistema electrnico de muchas maneras, como se puede ver en la Figura 9. El nivel ms bajo o nivel fsico, se corresponde con la interpretacin elctrica y es comn a todo tipo de sistema electrnico. En este nivel slo hay medidas elctricas de tensin; es el nivel al que se trabaja cuando se usa el osciloscopio y con las leyes de Kirchhoff. El segundo nivel o nivel lgico, se corresponde con la interpretacin lgica de las medidas elctricas del primer nivel. Las medidas de tensin se traducen a ceros y unos, de forma que por ejemplo un nivel de tensin por debajo de 0.7 Voltios se considera un 0 lgico y un valor por encima se considera un 1 lgico. Se pueden realizar operaciones en este nivel usando el lgebra de Bool. A este nivel se sita el cdigo mquina.

13

Sistemas Electrnicos Digitales.

El tercer nivel o nivel de codificacin, se corresponde con la codificacin de esos ceros y unos en palabras que puedan ser entendidas mejor por una persona. Este nivel s que depende del sistema electrnico que se use; es decir, del cdigo que se use, ya que existen cdigos que interpretan los ceros y unos de distinta manera dependiendo para qu se apliquen. Si se quiere realizar un programa para un micro, la codificacin se llama ensamblador. En caso de que se quiera trabajar con nmeros, la codificacin puede ser binaria o hexadecimal, interpretando los nmeros con signo y sin signo. Por ltimo, si lo que se quiere es programar FPGA o EPLD (lgica programable), la codificacin que se usa es VHDL. Estas codificaciones dependen dentro de cada aplicacin del dispositivo que se quiera programar; por ejemplo, existen distintos cdigos ensamblador para diferentes micros. Finalmente el cuarto nivel, o nivel ms alto de abstraccin, consiste en realizar una codificacin ms entendible por una persona, que adems sea independiente del dispositivo que se quiere programar. En caso de que se quieran programar micros, el lenguaje que se usa es C, que independiente del micro que se quiere programar; es decir, slo existe un lenguaje C. En caso de que se quiera trabajar con datos, existen varias codificaciones como son la ASCII, UNICODE, etc, que son iguales para todos sistemas; es decir, slo existe un cdigo ASCII.

PROGRAMAS uC

DATOS Cdigos de alto nivel ASCII Interpretacin 0's y 1's Nmeros con y sin signo

PROGRAMAS FPGA

Lenguaje C

Interpretacin 0's y 1's Ensamblador

Lenguaje VHDL

Nivel lgico 0's y 1's

Nivel fsico Hardware +5V, 0V

ABSTRACCIN
Figura 9: Niveles de abstraccin de un sistema electrnico digital

Existen niveles de abstraccin superiores, pero que no se usan en la programacin de sistemas electrnicos digitales.

14

Sistemas Electrnicos Digitales.

3.7 Organizacin de un micro a nivel de bloques y buses Aunque la organizacin de un micro no es el objetivo de la asignatura, es entender qu es un Sistema Electrnico Digital (SED) es necesario introducir algunos aspectos de organizacin, como es la composicin a nivel de bloques fsicos y la conexin entre bloques mediante buses. En la Figura 10 se muestra el modelo Von Neumann a nivel de bloques y de buses. Un bus no es ms que un conjunto de lneas comn a varios bloques que permite la comunicacin entre ellos. En un SED tpico tenemos tres buses: Bus de direcciones. Bus de datos. Bus de control.

CPU (ALU, Registros y Control)

Memoria

Entrada/Salida

Bus del sistema

Bus de datos Bus de direcciones Bus de control

Figura 10: Modelo Von Neumann a nivel de hardware

Desde la CPU el exterior se ve como direcciones. Cuando se quiere acceder a un dato en la memoria, la CPU pone en el bus de direcciones la direccin de la memoria donde se encuentra el dato y la memoria le da el dato en el bus de datos. El bus de control sirve para organizar la transferencia del dato entre memoria y CPU (o entre I/O y CPU). Por ejemplo, para leer el dato de la posicin 0x82: 0x82 (CPU) Bus dir -> RD (CPU) Bus control -> 0003 (MEM) Bus datos Esto significa: la CPU pone en el bus de direcciones la direccin del dato a leer (0x82), a continuacin activa una lnea del bus de control que indica operacin de lectura (RD: Read), la memoria suministra el dato almacenado en dicha posicin de memoria (3) en el bus de datos. Por ltimo la CPU recoge el dato del bus de datos y lo almacena en un registro de proposito general.

15

Sistemas Electrnicos Digitales.

El ciclo de escritura es similar. En este caso la CPU suministra tanto la direccin como el dato a escribir en memoria (en el bus de direcciones y en el bus de datos respectivamente) y activa la lnea WR (Write) del bus de control. Los microcontroladores tienen perifricos y memoria integrados en el chip de CPU, mientras que los microprocesadores no. Los perifricos sirven para comunicar la CPU con el exterior y para realizar ciertas tareas sin consumir tiempo de CPU del micro; por ejemplo hay perifricos que sirven para controlar motores, otros digitalizan seales analgicas, etc. Al igual que la CPU los perifricos tienen registros que le permiten funcionar. Se dice que un perifrico est mapeado en memoria si la CPU ve a los registros del perifrico como una direccin ms de memoria; es decir, el micro accede a los registros del perifrico de la misma manera que lo hace para acceder a cualquier otra direccin de memoria. El mapa de memoria describe de forma grfica qu hay en cada rango de direcciones: memoria RAM, ROM o Perifricos. Cuando la CPU manda hacer algo a un perifrico se puede quedar a la espera a que ste termine su labor, preguntndole continuamente si ha terminado, o bien puede configurar al perifrico de que le avise y le interrumpa cuando termine. En el primer modo de funcionamiento se dice que la CPU usa polling (es la CPU la que pregunta si ha terminado), mientras que el segundo modo de funcionamiento se dice que la CPU usa interrupciones (es el perifrico el que indica a la CPU que ha terminado, interrumpiendo lo que est haciendo en ese momento). La CPU realiza polling consultado un bit de un registro del perifrico; es decir, de la misma manera que consulta una direccin de memoria. En cambio las interrupciones utilizan lneas especficas de comunicacin entre el perifrico y la CPU, las cuales se encuentran en el bus de control.

16

Sistemas Electrnicos Digitales.

4 Cuestiones de comprensin
A continuacin se enumeran un conjunto de preguntas que ayudan a comprender lo que se ha descrito en el captulo. 0) Qu significa modelo del programador?

1) De qu partes consta un microprocesador segn el modelo del programador?

2) Qu significa que un microprocesador sea de 16 bits?

3) Qu diferencia un microprocesador de un microcontrolador?

4) Qu es el PC? Para qu sirve?

5) De qu diferentes formas se te ocurren que se pueden interpretar los bits que se almacenan en la memoria de un micro?

17

Sistemas Electrnicos Digitales.

Captulo 3 ARQUITECTURA Y MAPA DE MEMORIA DEL C167


1 Objetivos y conceptos a entender en este captulo
Por orden de importancia: Entender cmo se almacenan los datos y los programas, as como la ejecucin de los mismos que permite relacionar ambos. Entender los modos de direccionamiento Entender la arquitectura y, sumamente importante, ver la equivalencia entre el modelo del programador presentado en este captulo y el presentado de forma general en el captulo anterior. Empezar a familiarizarse con el ensamblador y la equivalencia que tiene con el C. Por ello en este captulo se recomienda empezar un esquema, que se seguir completando en sucesivos captulos, con las equivalencias entre el ensamblador y el C. Entender cmo se organiza la memoria del C167 Hacerse con la terminologa "direccionar", "modo de direccionamiento", "puntero", etc.

2 Arquitectura del C167


Es un microcontrolador de 16 bits, lo que implica que la ALU, el bus de datos y los registros son de 16 bits. Es un micro muy robusto, diseado para tareas de control industrial. Es capaz de direccionar (pedir direcciones) 16 Mbytes de memoria, es decir, su bus de direcciones es de 24 bits. Como microcontrolador que es lleva incorporados muchos perifricos integrados en el chip: Controladores de comunicaciones serie: para comunicarse con el exterior en serie; por ejemplo un PC. Puertos paralelo: para comunicarse con el exterior; por ejemplo para conectar LEDs, interruptores, un PC, etc. Temporizadores (timers): para contar eventos, para llevar un computo del tiempo transcurrido, etc. Convertidor analgico/digital (A/D): sirve para pasar una seal del dominio analgico al digital, formato que puede ya procesar el micro. Moduladores PWM: muy usados en electrnica de potencia para controlar motores, etc

18

Sistemas Electrnicos Digitales.

2.1 Modelo del programador del C167 El modelo del programador del C167 se muestra en la Figura 11. Tiene una CPU con registros clasificados en dos tipos: registros de propsito especfico (SFR, tienen una funcin muy concreta) y registros de propsito general (GPR, se pueden usar para cualquier cosa). Los GPR son equivalentes a los registros de proposito general que se presentaron en la arquitectura general de un micro en la seccin 3.1, y se usan como posiciones de memoria de acceso rpido. Como registros de propsito especfico tenemos, entre otros, el PC (contador de programa), el PSW (registro de estado) y el SP (Stack Pointer). Por otro lado, tenemos el modelo de memoria. La memoria est organizada en "celdas" de 1 Byte (8bits). Cada byte tiene una direccin asociada. Las direcciones van desde al 0 hasta la 0xFFFFFF; es decir, se puede direccionar con 24 bits. Para acceder a una celda de memoria se usa su direccin: Para la lectura: la CPU pone la direccin en el bus de direcciones de la cual quiere el dato, mientras indica por el bus de control que la operacin es de lectura. La memoria devuelve el dato almacenado en la celda en el bus de datos; dato = READ (direccin). Para la escritura: la CPU pone el dato en el bus de datos, mientras indica por el bus de control que la operacin es escritura, y la direccin en el bus de direcciones. La memoria escribe en la celda direccionada el dato suministrado por la CPU. WRITE(dato, direccin). La unidad de entrada y salida se controla a travs de sus SFRs. El acceso a estos es similar al acceso a memoria; es decir, los SFRs estn mapeados en memoria.

19

Sistemas Electrnicos Digitales.

Memoria FF FFFF
R7 R6 R5 R4 R3 R2

CPU Registros
R15 R14 R13 R12 R11 R10 R9 R8 PC PSW SP

(SFRs)

00 0001 00 0000

R1 R0

(GPRs)

00 FE00

00 FE02

I/O (SFRs)

00 FE0X

Figura 11: modelo del programador del C167

2.2 Ensamblador de C167 Como se coment en el captulo 2 seccin 3.6, el lenguaje ensamblador es el lenguaje de ms bajo nivel que entienden las personas, ya que cada instruccin ensamblador se corresponde con una instruccin cdigo mquina que entiende el micro, es decir, hay una correspondencia biunvoca entre el ensamblador y el cdigo mquina, entre lo que entienden las personas y lo que entienden las mquinas. El programa sencillo presentado en el captulo anterior para una mquina de propsito general (esta vez en la direccin 0x100, ya que en el C167 no se pueden usar las 0x100 primeras direcciones) (0x104) = (0x100) + (0x102) En lenguaje ensamblador de C167 queda de la siguiente forma:
MOV MOV ADD MOV R0,0x100 R1,0x102 R1,R0 0x104,R0

20

Sistemas Electrnicos Digitales.

El tamao del registro R0 es de 2 bytes (16 bits). Como cada direccin de memoria almacena nicamente 8 bits (1 byte) son necesarios dos bytes (almacenados en direcciones consecutivas) para llenar el registro. Por este motivo se ha situado el primer dato en la posicin 0x100 y el segundo dato dos direcciones ms all (posicin 0x102). (El C167 es un little endian; es decir, almacena el byte menos significativo del dato, parte baja de R0, en la direccin par. El byte ms significativo va a la direccin impar de memoria). A la hora de presentar ejemplos ms complejos usaremos como lenguaje de descripcin en alto nivel el lenguaje C, que se da por conocido (a nivel bsico). El lenguaje en ensamblador se explicar en detalle en el captulo 6. En el captulo 7 se explicar el detalle de las particularidades del lenguaje C en la programacin de micros, y lo que es ms importante la relacin entre el lenguaje C y el ensamblador. Para empezar, se va a presentar el primer cdigo ensamblador equivalente al programa siguiente en C, que no es ms que un bucle para incrementar una variable N veces. Es necesario recordar que en C j += 1 es equivalente a j = j +1.
for (i=1; i <=N; i++) j += 1;

Suponiendo que N=5 y que el dato al que representa j se encuentra en la direccin de memoria 0xfa00, el programa en ensamblador equivalente sera:
Direccin inicial del programa
500 502 504 506 508 50C 50E 510 E0 E0 48 AD 04 08 0D 10 11 05 05 F1 00 FA 01 FA MOV MOV CMP JMPR ADD ADD JMPR R0,#1 R1,#1 R0,#5 cc_sgt,0x510 0xfa00,R1 R0,#1 cc_uc,0x504 ; ; ; ; ; ; ; r0 (i) auxiliar if i>N then goto 512H j += 1 i += 1 salto sin condicin

Direccin de memoria

Codificacin de la instruccin

A simple vista se pueden observar varias cosas del programa: En lenguaje ensamblador ms largo que en C Una lnea de ensamblador se corresponde con una instruccin en cdigo mquina que almacena en una direccin de memoria. Cada instruccin de ensamblador se corresponde con una operacin elemental, donde casi siempre estn involucrados los GPRs

21

Sistemas Electrnicos Digitales.

Las instrucciones se almacenan en memoria en formato binario (1s y 0s), aunque en se hayan mostrado en hexadecimal por simplificar la notacin. Las instrucciones ocupan 2 4 bytes. Por ejemplo la instruccin 0x0801 situada en la direccin 0x50C ocupa 2 bytes, muestras que la instruccin 0x04F100FA situada en la direccin 0x508 ocupa 4 bytes. Las instrucciones se almacenan en posiciones de memoria consecutivas. Se ejecutan de forma secuencial, salvo el los saltos.

De forma concisa cada una de las instrucciones del programa hace lo siguiente, (para ms informacin y detalles del lenguaje ensamblador ir al captulo 6): MOV R0,#1. R0 representa la variable i y se inicializa a 1; i = 1. MOV significa en ingls move, mueve 1 a R0. El # significa que el valor que le acompaa se trata como literal y no como una direccin de memoria donde buscar el dato. R1,#1. R1. R1 es una variable temporal que representa la cantidad a sumar a j, MOV que aunque siempre vale 1 se necesita para poder invocar a la instruccin de suma. CMP R0,#5. Compara si R0 es 5. CMP en ingls compare. JMPR cc_sgt,0x510. Si es mayor que 5 salta a la direccin 0x510. La instruccin JMPR, en ingls jump, salta segn la condicin puesta. En este caso cc_sgt, en ingls signed greater than, est haciendo una comparacin con signo de mayor que. con qu? como se ver ms adelante, cada instruccin en ensamblador deja una huella en la CPU despus de ser ejecutada, en concreto en el registro de estado, y es esa huella como entrada a la comparacin. En este caso la instruccin CMP anterior, dej una huella que indicaba si R0 era mayor, menor o igual que 5, que se usa en JMPR para hacer el salto. Generalmente CMP y JMPR van juntos. 0xfa00,R1. Aade R1 al dato que haya en la direccin de memoria 0xfa00; es ADD decir, j=j+1. Como se coment con anterioridad la instruccin ADD 0xfa00, #1 no existe, de ah que fuera necesario guardar en R1 el 1. Esto significa que no todas las operaciones soportan todo tipo de operandos. Se puede apreciar que no se ha puesto #0xfa00, ya que 0xfa00 no es un literal sino una direccin de memoria donde buscar el dato. R0,#1. Aade 1 a R0; es decir, i = i+1. ADD JMPR cc_uc,0x504. Esta instruccin en un salto sin condicin cc_uc, en ingls unconditional, a la direccin 0x504, precisamente para que el bucle contine. Es necesario hacer notar que a lo largo de la ejecucin del programa el PC contiene la direccin de la siguiente instruccin a ejecutar, para ms detalles ver captulo 2 seccin 3.3. Cada vez que la CPU ejecuta una instruccin, incrementa el PC en dos o cuatro, para que apunte a la direccin de memoria de la siguiente instruccin. En la terminologa de programacin cuando una variable o registro contiene como dato una direccin de memoria, se dice que la variable o el registro es un puntero que apunta a una determinada direccin de memoria.

22

Sistemas Electrnicos Digitales.

Para el C167 existen dos tipos de ensambladores, uno de muy bajo nivel llamado ensamblador de lnea y otro de alto nivel llamado ensamblador de PC. Nada mejor que un ejemplo para entender la diferencia entre ambos, ver Figura 12

Etiquetas (op)
bucle:

En PC
MOV MOV CMP JMPR ADD ADD JMPR R0,#1 R1,#1 R0,#5 cc_sgt,fin 0xfa00H,R1 R0,#1 cc_uc, bucle ; ; ; ; ; ; r0 (i) auxiliar if i>N then goto fin j += 1 i += 1

fin:

Instruccin
500 502 504 506 508 50C 50E 510 MOV MOV CMP JMPR ADD ADD JMPR

Operandos En lnea
R0,#1 R1,#1 R0,#5 cc_sgt,0x510 0xfa00,R1 R0,#1 cc_uc,0x504 ; ; ; ;

Comentarios (opcional)
r0 (i) auxiliar if i>N then goto 512H ; j += 1 ; i += 1 ; salto sin condicin

Figura 12: comparacin entre ensamblador de lnea y de PC

El ensamblador de lnea es lo ms parecido al cdigo mquina ya que cuando se escribe se debe tener muy claro en qu direccin de memoria se encuentra cada instruccin, de forma que cuando se hacen saltos se tiene que poner la direccin de memoria donde se salta. Esto es as porque cuando se escribe ensamblador en lnea se est escribiendo cdigo mquina directamente en la memoria, gracias a un programa que est cargado en la pastilla del micro que se llama monitor y que es capaz de comunicarse una consola del PC y escribir en memoria el cdigo ensamblador que se quiera. En cambio el ensamblador de PC admite lo que se llaman etiquetas, que no son ms que nombres que representan una direccin de memoria, que no se conoce a priori y por lo tanto se usa la etiqueta en su lugar. Esas direcciones de memoria se resuelven o se conocen cuando el programa se termina y se ensambla. El programa que ensambla se llama ensamblador y se ejecuta en un PC, y lo nico que hace es traducir las etiquetas en direcciones de memoria, traducir cada instruccin a cdigo mquina y situar cada instruccin en una direccin de memoria. Como resultado se genera un fichero que se puede cargar en la memoria del micro directamente. 2.2.1 Resumen de instrucciones en ensamblador Se pueden clasificar las instrucciones de ensamblador en diferentes tipos:

23

Sistemas Electrnicos Digitales.

Transferencia de datos. Son instrucciones que sirven para mover los datos de un lugar a otro. La instruccin ms importante es mov. Aritmticas. Son instrucciones que sirven para realizar operaciones aritmticas. Las ms importantes son: add (suma), sub (resta), cmp (comparacin, resta operandos y compara con 0), neg (hace el complemento a dos), mul (multiplica), div (divide). Lgicas. Realizan operaciones lgicas: and (multiplicacin lgica), or (suma lgica), cpl (complemento a 1). Desplazamientos de bits. Desplazan los bits de un registro hacia la derecha o izquierda. shr (shift right -> derecha), shl (shift left -> izquierda). Saltos en la ejecucin. Realiza saltos en la ejecucin segn la condicin. jmpr cc_uc (sin condicin), cc_eq (igual), cc_ne (no igual), cc_ugt (sin signo mayor que), cc_sgt (con signo mayor que), cc_ule (sin signo menor o igual que, ...). Para entender cmo funcionan los saltos ver captulo 6 seccin 7.

Los nmero en ensamblador se suelen usar o bien para literales o para referirse a direcciones de memoria. Por defecto el nmero que se escribe se considera que est en decimal, si se pone un 0x por delante el nmero est en hexadecimal. A continuacin se muestran ejemplos de utilizacin de instrucciones para irse familiarizando con el ensamblador y el C: MOV R0, #0x4433. Esto hace R0 = 0x4433 MOV R1, R0. Es equivalente a R1 = R0, por lo tanto R1 = 0x4433 AND R1, #0xFF00. Es equivalente a R1 = R1 & 0xFF00. Un and lgico bit a bit, quedando R1 = 0x4400. MOV R2, R0. Es equivalente a R2 = R0, por lo tanto R2 = 0x4433. AND R2, #0x00FF. Es equivalente a R2 = R2 & 0x00FF. Un and lgico bit a bit, quedando R2 = 0x0033. SHR R1, #8. Es R1 = R1 >> 8. Un desplazamiento de bits a la derecha, quedando R1 = 0x0044. ADD R1, R2. Es una suma aritmtica R1 = R1 + R2, quedando R1 = 0x0077. CPL R1. Realiza el complemento a 1, en C sera R1 = ~R1, quedando R1 = 0xFF88. XOR R1,#0xFFFF. Realiza un XOR de R1, en C sera R1 = R1 ^0xFFFF. Este ejemplo es interesante ya que un XOR con 0xFFFF es lo mismo que un complemento a 1, justo como el ejemplo anterior. 2.2.2 Modos de direccionamiento El 167 dispone de los siguientes modos de direccionamiento para acceder a los operandos:

24

Sistemas Electrnicos Digitales.

Direccionamiento Inmediato Directo a GPR Directo a SFR o GPR Directo a memoria Indirecto Indirecto con pre-decremento Indirecto con post-incremento Indirecto con desplazamiento

Smbolo #data Rw, Rb reg mem [Rw] [-Rw] [Rw+] [Rw+#data16]

A continuacin se describen diferentes ejemplos de utilizacin con la instruccin MOV:


MOV MOV MOVB MOVB MOV MOV MOV MOV MOV R0,R1 R0,#5 RL0,#0 RH0,#3 R1,0xFA00h R1,[R0] [-R0],R1 [R0+],R1 R1,[R0+#4] ; Directo a registro (R1 -> R0) ; Inmediato (5 -> R0) ; Inmediato al byte bajo (0 -> R0) ; Inmediato al byte alto (3 -> R0) ; Directo desde memoria ; Indirecto ( (R0) -> R1) ; Indirecto con pre-decremento ; Indirecto con post incremento ; Indirecto con desplazamiento

La primera instruccin utiliza direccionamiento directo a registro en ambos operandos. La instruccin carga el contenido del registro R1 en el registro R0, a nivel de word (16 bits). La segunda instruccin utiliza direccionamiento inmediato (smbolo #) en el segundo operando. La instruccin carga el nmero 5 en el byte (8 bits) bajo de R0. La siguiente instruccin carga 0 en el byte alto de R0. La parte baja R0 recibe el nombre de RL0, mientras que la parte alta recibe el nombre de RH0. No olvidar especificar parte alta o baja del registro. De lo contrario el ensamblador da el error 74: "Illegal Operand Type". La instruccin MOV R1,0xFA00h carga el valor almacenado en la posicin de memoria 0xFA00h en R1, utilizando direccionamiento a memoria (16 bits para la direccin). En el direccionamiento largo se utilizan los registros DPP's (Data Page Pointers). Ntese que si en la segunda instruccin olvidramos el smbolo #, en R0 se cargara el contenido de la posicin 5 de memoria, en lugar del nmero 5. La instruccin MOV R1,[R0] carga el contenido de la posicin de memoria apuntada por R0, en R1. El modo de direccionamiento se conoce con el nombre de "indirecto". (Ntense los corchetes en R0 para indicar contenido de la posicin de memoria). Si en R0 tenemos almacenado el valor 0x200, se carga en R1 el contenido de la posicin de memoria 0x200. En el acceso a memoria se utilizan los DPP's. Las dos instrucciones siguientes utilizan variantes del modo de direccionamiento indirecto. Variantes con pre-decremento y con post-incremento. Estas variantes, a parte de obtener el operando, actualizan el valor del puntero (registro de direcciones). En las instrucciones con pre-decremento el puntero se decrementa antes de obtener el operando.

25

Sistemas Electrnicos Digitales.

Luego si en R0 se tiene el valor 0x200, la instruccin MOV [-R0],R1 decrementa en dos unidades (R0 = 0x1FE). A continuacin carga el valor almacenado en R1 (2 bytes) en la posicin de memoria apuntada por R0. En las instrucciones con post-incremento, el puntero se incrementa despus de obtener el operando. Luego si en R0 tiene el valor 0x200, la instruccin MOV [R0+],R1 carga R1 en la posicin de memoria apuntada por R0 (2 bytes), e incrementa (R0 = 0x202) en dos unidades. Las instrucciones con predecremento y con post-incremento actualizan el valor del puntero de acuerdo con el tamao de operando. Es decir, si el operando es a nivel de byte se suma/resta 1. Si es a nivel de word, se suma/resta 2 (dos bytes). (Esta es una forma rudimentaria de manejo automtico de tamaos. Los operadores ++ y - del lenguaje C hacen esto mismo con cualquier tipo de operandos). La ltima instruccin MOV R1,[R0+#4] utiliza un cierto desplazamiento 4. Estos direccionamientos (indirectos con desplazamiento) no actualizan el valor del puntero. El desplazamiento sirve nicamente para obtener la direccin del operando.

2.2.3 Nmeros con signo y sin signo Un nmero negativo es aquel que sumado al mismo positivo da cero. Por ejemplo si se suma en 16 bits el nmero 0xFFFF y 0x0001 da como resultado 0x10000 que en 16 bits es el 0x0000. Esta aritmtica se llama aritmtica en como fija complemento a 2 y permite deducir el negativo de un nmero con la ecuacin:

nmero _ negativo = 2nmero _ de _ bits nmero _ positivo


Por ejemplo, en 16 bits, el negativo de 2 es 0xFFFE en hexadecimal o 65534 en decimal:

0 xFFFE = 216 0 x0002


En definitiva los nmeros que tienen un uno como bit ms significativo son negativos y los que no son positivos. Por lo tanto si se mira en una direccin de memoria del micro y se ve que est almacenado el nmero 0xFFFE, qu significa?. Puede tener muchos significados: Puede representar a una instruccin Puede representar al nmero 65534 Puede representar al nmero -2 Puede representar cualquier tipo de cdificacin que se el usuario quiera

Esto viene a decir, que la interpretacin del contenido de una posicin de memoria depende del programador, la cul se escenifica en el tipo de instrucciones que use para decodificarla. Si pone el PC apuntanto a esa direccin de memoria significa que la est interpretando como una instruccin, si accede a esa direccin de memoria con una instruccin que tiene en cuenta el signo (MUL, DIV, JMPR cc_sgt,...) entonces la est interpretando como un nmero con signo y si accede con una instruccin que no tiene en cuenta el signo (MULU, DIVU, JMPR cc_ugt,...) entonces la est interpretando como un nmero sin signo.

26

Sistemas Electrnicos Digitales.

2.2.4 Ejemplos bsicos de codificacin en ensamblador A continuacin se muestran dos ejemplos de programacin estructurada en C y su equivalencia en ensamblador. 2.2.4.1 Condicin
if (a == b) a = 0;

MOV CMP JMPR MOV MOV next:

R0,a R0,b cc_ne,next R0,#0 a,R0

2.2.4.2 Bucle
i = 0; while (i<10) { a[i] = i; i += 1; }

Es necesario hacer notar que i += 1 es lo mismo que i = i +1;


MOV MOV MOV CMP JMPR MOV ADD ADD JMPR R0,#0 R1,#1 R2,#0fa00h R0,#10 cc_sge,next [R2],R0 R0,R1 R2,#2 cc_uc, otro

otro:

next:

2.3 Mapa de memoria del C167 El mapa de memoria describe de forma grfica qu hay en cada rango de direcciones: memoria RAM, ROM o Perifricos. El mapa de memoria del C167 est dividido en segmentos de 65536 Bytes, cada uno de los cuales se divide a su vez en 4 pginas de 16384

27

Sistemas Electrnicos Digitales.

Bytes. Como la memoria puede llegar a ser de 16MBytes, puede haber 256 segmentos y 256*4=1024 pginas, como se puede ver en la Figura 13. En la tarjeta que se utiliza para las prcticas de laboratorio todos los segmentos menos el primero tienen memoria ROM. El primer segmento tiene RAM (externa, esto es, fuera del chip de la CPU). Una pequea parte del segmento S0 (pgina 3) tiene RAM interna (dentro del chip de la CPU) y los registros, por ello es el segmento ms importante.
FF FFFF

Pgina 3 (RAM Interna) 256 Segmentos de 64 kB

FFFF

C000

Pgina 2
8000

16 Mb

Pgina 1 (RAM ext) S1 64Kb


01 0000 00 0000 4000

S0 64Kb

16 Kb

Pgina 0 (RAM ext)


0000

Figura 13: mapa de memoria del C167

Como se puede ver en la Figura 13, la pgina 0 y 1 del micro son generalmente RAM externa (ciertas versiones del micro tienen ROM interna). La pgina 3 contiene la RAM interna y los registros tal como se muestra en la Figura 14: Desde la direccin 0xF600 hasta la 0xFC00 se encuentra el STACK, que es memoria RAM para almacenamiento temporal. Desde la direccin 0xFC00 hasta la 0xFD00 estn mapeados los GPRs. Como los GPRs son 15 y caben 256 en esa zona de memoria, significa que los GPRs pueden estar mapeados en distintas direcciones de memoria. Para ms informacin sobre el mapeo de los GPRs ver seccin 2.3.2.5. Desde la direccin 0xFD00 hasta la 0xFE00 se encuentra una zona de memoria RAM que se puede acceder a nivel de bit, es decir, se pueden usar como operandos con instrucciones que trabajan a nivel de bit. Desde la direccin 0xFE00 hasta la 0XFFFF se encuentran mapeados los SFRs.

28

Sistemas Electrnicos Digitales.

FFFF

SFRs acceso bit a bit SFRs SFRs


FE00 FF00

Acceso bit a bit


FD00

GPRs RAM STACK


F600 FC00

Figura 14: Organizacin de la pgina 3 del C167

2.3.1 Los registros de propsito general GPRs Los registros de propsito general son 16 y se van de R0 hasta R15. Los 8 primeros registros (R0 a R7) se pueden acceder a nivel de byte (8 bits). En este caso reciben los nombres, por ejemplo para R0, de RL0 y RH0, y se pueden usar con instrucciones que manejan datos a nivel de byte. Solamente los 4 primeros registros (R0 a R3) pueden almacenar direcciones (punteros), para ser usados con modos de direccionamiento indirecto. Para ms informacin sobre modos de direccionamiento ver seccin 2.2.2 de este captulo. Se encuentran ubicados en la zona de la memoria que comprende 0xFC00 a 0xFD00, en concreto donde indique el registro CP. 2.3.2 Principales SFRs de la CPU En las siguientes subsecciones se describen los principales registros de propsito especfico que tiene la CPU. En posteriores captulos se tratarn otros SFRs que permiten gestionar los perifricos del C167. 2.3.2.1 PC (Program Counter) Como la memoria del C167 puede llegar a ser de 16MBytes, significa que podra haber partes de un programa que estuvieran situadas en los ltimos segmentos, lo que implica que el PC debera tener la capacidad de direccionar hasta 16MBytes. Por otro lado, dado que el C167 es un micro de 16 bits, sus registros son de a lo sumo 16 bits. Por lo tanto para poder direccionar hasta 16 MBytes (24 bits) es necesario usar dos registros. Precisamente por esa razn el PC del C167 se desdobla en dos registros: CSP (Code Segment Pointer): registro de 8 bits que almacena el Byte ms alto de PC; lo que es lo mismo que decir que apunta al segmento en uso por PC. IP (Instruction Pointer): registro de 16 bits que almacena los 2 Bytes ms bajos de PC; lo que es lo mismo que decir que apunta a cualquier direccin dentro del segmento seleccionado por CSP.

29

Sistemas Electrnicos Digitales.

Por ejemplo:

Si PC = 01 0000
CSP IP

01

0000

Esto mismo se explica de forma ilustrada en la Figura 15.


8 bits
FF FFFF

CSP indica el segmento en uso de los 255 posibles

Segmentos

S1 64Kb
01 0000 00 0000

S0 64Kb

IP indica la zona del segmento en uso de las 64k posibles

16 bits

Figura 15

2.3.2.2 PSW (Processor Status Word) El registro de estado PSW, se encarga de almacenar el estado en el que ha quedado el micro despus de que se ejecuta una instruccin. Es un registro de 16 bits, del que por ahora slo se vern los flags de estado, que son los siguientes: C (flag de acarreo). Para nmeros sin signo, se sabe si ha existido rebose al efectuar la suma, comprobando el flag de "carry" (flag C) del registro de estado de P. (Este bit tambin sirve para indicar si ha existido acarreo "negativo" (borrow), que se produce cuando el substraendo es mayor que el minuendo en una operacin de resta). V (flag de rebose). Cuando se opera con nmeros con signo se debe comprobar el estado del flag de "overflow" (flag V). Este flag se pone a 1 si al sumar dos nmeros positivos se obtiene uno negativo (bit ms significativo a 1), y viceversa. Al sumar dos nmeros de distinto signo nunca se tiene rebose. N (flag de nmero negativo). Indica que una operacin ha generado un resultado negativo. En 8 bits significa que el bit 7 es 1 y en 16 bits significa que el bit 15 es 1. Z (flag de cero). Indica si una operacin ha obtenido como resultado un cero. 2.3.2.3 SP (Stack pointer)

30

Sistemas Electrnicos Digitales.

Apunta a la zona de Stack, que est comprendida entre la direccin 0xF600 y 0xFC00). El Stack es una zona de la memoria donde el micro guarda de forma temporal informacin que necesita para la ejecucin de un programa; por ejemplo, cuando hay una llamada a una funcin guarda la informacin de la direccin desde donde se llama la funcin para poder posteriormente seguir la ejecucin por donde iba. El funcionamiento del Stack es de tipo LIFO (last in, first out). Inicialmente SP apunta a la direccin 0xFC00 y segn se van almacenando datos en el Stack, el SP va decreciendo. De modo contrario, cuando se van recuperando datos del Stack, el SP va creciendo. Si SP es igual a 0xFC00 quiere decir que el Stack no tiene datos, se dice que est vaco. 2.3.2.4 DPPs (Data Page Pointer Registers) De la misma forma que sucede con el PC, cuando se quiere acceder a una zona de la memoria del micro para coger un dato, es necesario usar 24 bits. Por ejemplo, si se quiere acceder a un dato en la direccin 0x0A7000, es necesario partir la direccin en dos trozos, usando un registro de apoyo de 10 bits denominado DPP0. Existen tambin el DPP1, DPP2 y DPP3, que se pueden usar indistintamente para poder conseguir los 24 bits necesarios. El concepto es similar al usado con el PC, pero en vez de utilizar un registro para seleccionar el segmento y otro para direccionar dentro del segmento, se usa un registro para seleccionar una pgina de la memoria y otro para direccionar dentro de la pgina. Por ello se dice que la memoria del C167 es segmentada para programas y paginada para datos. El registro DPPx se encarga de seleccionar la pgina dentro de la memoria seleccionada para coger el dato. A continuacin se va a resolver el problema de intentar de ejecutar la instruccin siguiente, que es incorrecta:
MOV R0, 0x0A7000 ; INCORRECTA

La solucin pasara por usar, por ejemplo, el DPP0 que almacenar los 10 bits ms altos de la zona que queremos direccionar; en este caso y en binario 00 0010 1001 (DPP0 = 0x29). El resto de la direccin deseada, los 14 bits ms bajos se dejan como estn y se les aade como 2 bits ms altos el nmero de DPP utilizado para resolver la direccin deseada; en este caso el 0.
DPP0 10bits

0000 1010 01 11 0000 0000 0000


Segmento seleccionado Nmero de DPP seleccionado

00 11 0000 0000 0000


Pgina seleccionada

MOV MOV

DPP0, #0x29 R0, 0x3000

31

Sistemas Electrnicos Digitales.

Otra solucin podra haber usado el DPP2, que se muestra a continuacin:


DPP2 10bits

0000 1010 01 11 0000 0000 0000 10 11 0000 0000 0000

MOV MOV

DPP2, #0x29 R0, 0xB000

2.3.2.5 CP (Context Pointer) Como se coment con anterioridad los GPRs se pueden mapear desde la direccin 0xFC00 hasta la 0xFD00. El registro CP indica donde estn mapeados los GPRs en todo momento, ya que almacena la direccin de memoria donde se encuentra R0. El resto de registros se suponen a continuacin. Por defecto el valor de CP es 0xFC00, pero se puede modificar desde un programa. En el ejemplo siguiente se muestra como se modifica CP de forma que R0 se sita en la direccin 0xFC00, haciendo que valga a = 0x1034.
Direccin ... ... MOV MOV ... FC08 CP,#0FC00 H a, R0 FC06 FC04 FC02 FC00 Dato ... ... 4400 FF00 FC04 A050 1034 R4 R3 R2 R1 R0

En el siguiente ejemplo, en cambio R0 se sita en la direccin 0xFC04, haciendo que valga a


= 0xFC04.

... Direccin ... MOV MOV ... ... CP,#0FC04 H a, R0 FC08 FC06 FC04 FC02 FC00 Dato ... 4400 FF00 FC04 A050 1034 R4 R3 R2 R1 R0

32

Sistemas Electrnicos Digitales.

3 Cuestiones de comprensin
Practicando con la memoria del micro 1) Escribir en ensamblador un cdigo que escriba el contenido de la direccin de memoria 0x1F0468 en el registro R1. Usar DPP2.

2) Cuantos bits son necesarios para poder direccionar hasta 8 Mbytes de datos? _____

Practicando con la arquitectura del micro 3) Si el microcontrolador est ejecutando la lnea de cdigo de programa 0x1F0468 Cul es el valor del registro IP y CSP? IP = CSP = 4) Qu hay que hacer para que el registro R1 sea mapeado en la direccin de memoria FC06?

4 Ejercicios propuestos
1) Hacer un programa en ensamblador que intercambie el contenido de la direccin de memoria 0x200 por el de la 0x202.

33

Sistemas Electrnicos Digitales.

2) Hacer un programa en ensamblador que intercambie el contenido de la direccin de memoria 0x200 por el de la 0x201.

3) Hacer un programa en ensamblador que intercambie el contenido de la direccin de memoria indicada en el registro R0, por el contenido de la direccin de memoria indicada en el registro R1.

4) Hacer un programa en ensamblador que busque el valor mximo (a nivel de byte sin signo) de los datos que hay entre la direccin de memoria 0x200 y 0x300, y lo guarde en R1.

5) Dadas las condiciones iniciales de los registros y las instrucciones escritas a continuacin, indicar cmo se modifica la memoria y los registros R0 y R1 en los sucesivos pasos.

34

Sistemas Electrnicos Digitales.

SITUACIN INICIAL DE LA MEMORIA Y REGISTROS

r0 rh0 FF rl0 00 rh1 00

r1 rl1 01

Direccin de Celda 8 bits memoria 24 bits (Hex) (Hex) 00 0200 05 00 0201 00 00 0202 10 00 0203 02 00 0204 11 00 0205 FF 00 0206 A0 Direccin de Celda 8 bits memoria 24 bits (Hex) (Hex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206 Direccin de Celda 8 bits memoria 24 bits (Hex) (Hex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206 Direccin de Celda 8 bits memoria 24 bits (Hex) (Hex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206 Direccin de Celda 8 bits memoria 24 bits (Hex) (Hex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206

PASO 1

r0 MOV R0, #2 rh0 rl0 rh1

r1 rl1

PASO 2

r0 MOV R0, 0x202 rh0 rl0 rh1

r1 rl1

PASO 3

r0 MOV R1, R0 rh0 rl0 rh1

r1 rl1

PASO 4

r0 MOV 0x200, R1 rh0 rl0 rh1

r1 rl1

35

Sistemas Electrnicos Digitales.

PASO 5

MOV R2, #0x4433 MOV 0x202, R2

r0 rh0 rl0 rh1

r1 rl1

Direccin de Celda 8 bits memoria 24 bits (Hex) (Hex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206 Direccin de Celda 8 bits memoria 24 bits (Hex) (Hex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206 Direccin de Celda 8 bits memoria 24 bits (Hex) (Hex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206 Direccin de Celda 8 bits memoria 24 bits (Hex) (Hex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206 Direccin de Celda 8 bits memoria 24 bits (Hex) (Hex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206 Direccin de Celda 8 bits memoria 24 bits (Hex) (Hex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206

PASO 6

r0 MOVB rl0, #4 rh0 rl0 rh1

r1 rl1

PASO 7

r0 MOVB rh1, [r0] rh0 rl0 rh1

r1 rl1

PASO 8

r0 MOV r1, [r0+] rh0 rl0 rh1

r1 rl1

PASO 9

r0 MOVB rl1, [r0+] rh0 rl0 rh1

r1 rl1

PASO 10

r0 ADD r1, r0 rh0 rl0 rh1

r1 rl1

36

Sistemas Electrnicos Digitales.

6) Dada la tabla de cdigos de instrucciones y la situacin inicial de los registros CP, IP, DPP0 y CSP indicar cmo se modifica la memoria cuando se ejecuta el programa de tres instrucciones cargado en memoria. Indicar en la tabla de la derecha cmo queda la memoria despus de la ejecucin de la tercera instruccin del programa.
C digo de instruccin E 0 31 E 0 10 F0 01 F6 F0 02 02 R egistros C S P = 00 C P = FC 00 D P P0 =0 IP = 020A D ireccin de m em oria 24 b its (H ex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206 00 0207 00 0208 00 0209 00 020A 00 020B 00 020C 00 020D 00 020E 00 020F 00 0210 00 0211 00 0212 00 0213 00 0214 .. 00 00 00 00 00 00 FC 00 FC 01 FC 02 FC 03 FC 04 FC 05 (H ex) FF 20 20 10 01 11 03 03 11 10 10 E0 31 E0 02 02 F0 F6 00 00 00 01 02 34 45 65 76 C elda 8 bits Instruccin R 1,#3 R 0,#1 R 0, R 1 0x202, R 0

m ov m ov m ov m ov

E scribir aqu la solucin final D ireccin d e m em o ria 24 bits (H ex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206 00 0207 00 0208 00 0209 00 020A 00 020B 00 020C 00 020D 00 020E 00 020F 00 0210 00 0211 00 0212 00 0213 00 0214 .. 00 00 00 00 00 00 FC 00 FC 01 FC 02 FC 03 FC 04 FC 05 (H ex) C eld a 8 b its

37

Sistemas Electrnicos Digitales.

7) Dado el programa siguiente, rellenar los registros y la memoria indicada justo antes de que el programa ejecute la instruccin de la direccin de memoria 0x514 (final del programa)
Direccin memoria HEX 500 502 504 508 50A 50C 510 512 514 Registros CSP = CP = FC02 IP = Cdigo E0 10 E0 11 F6 F1 00 FA 48 05 AD 05 04 F1 00 FA 08 01 0D FA CC 00 Instruccin mov R0,#1 mov R1,#1 mov 0xfa00,R1 cmp R0,#5 jmpr cc_sgt,0x514 add 0xfa00,R1 add R0,#1 jmpr cc_uc,0x508 nop

38

Sistemas Electrnicos Digitales.

Direccin de Celda 8 bits memoria 24 bits (Hex) (Hex)

39

Sistemas Electrnicos Digitales.

5 Prctica 1: Introduccin al Siemens C167

40

Sistemas Electrnicos Digitales.

41

Sistemas Electrnicos Digitales.

42

Sistemas Electrnicos Digitales.

43

Sistemas Electrnicos Digitales.

44

Sistemas Electrnicos Digitales.

45

Sistemas Electrnicos Digitales.

46

Sistemas Electrnicos Digitales.

47

Sistemas Electrnicos Digitales.

Captulo 4 PUERTOS
1 Objetivos y conceptos a entender en este captulo
El objetivo del captulo es entender y aprender a manejar los puertos paralelo del C167. Este objetivo se consigue cuando se sepa manejar y diferenciar el registro de direcciones (DPx) y de datos de un puerto (Px).

2 Puertos paralelo
El C167 tiene 9 puertos paralelo, con un total de 111 lneas. Cada lnea se corresponde con un pin o patita del chip del micro, que tiene 144 pines en total. Los puertos se nombran Px, de forma que el puerto 0 se llama P0, el puerto 1 se llama P1, etc. Cada puerto consta de un conjunto de lneas, como mximo 16, que salen al exterior o entran del exterior por los pines del micro. Existe una correspondencia biunivoca entre pines y lneas. A continuacin se enumeran los puertos explicando muy someramente su funcin: El P0 tiene 16 lneas y es el bus de datos del micro que tanto se ha hablado a lo largo del captulo 2 y 3. Este bus se conecta a las memorias externas y a los perifricos y se usa para transmitir los datos que contienen los mismos. No se debe olvidar que tiene 16 bits, cada uno corresponde con una lnea, ya que el C167 es de 16 bits. El P1 tiene 16 lneas y representa la parte baja del bus de direcciones. Este bus se conecta a las memorias externas y a los perifricos y se usa para que la CPU indique la direccin de memoria que se quiere acceder para recuperar o escribir un dato. Este bus es de 24 bits y por ello este puerto nicamente representa a los 16 bits ms bajos del mismo. Ser necesario usar el puerto 4 para completar el bus. El P2 tiene 16 lneas y es de propsito general. En el laboratorio, se tienen conectados en la parte baja del puerto, 8 diodos LED, y en la parte alta del puerto, 8 interruptores. Pero es muy importante no olvidar que se podra haber conectado cualquier otra cosa al puerto. El P3 tiene 16 lneas. Parte de las lneas se usan para un puerto serie, que en el caso del laboratorio se usa para comunicarlo con el PC. El resto de las lneas son de propsito general. El P4 tiene 8 lneas que completan la parte alta del bus de direcciones. El P5 tiene 16 lneas que se usan como entradas para el conversor A/D. En cada una de estas entradas se puede conectar una seal analgica, para poder realizar una digitalizacin de la misma. El P6 es de 8 lneas y tiene parte del bus de control. El P7 tiene 8 lneas que son las salidas correspondientes a la unidad de PWM que tiene el micro.

48

Sistemas Electrnicos Digitales.

El P8 tiene 8 lneas que son las entradas correspondientes a la unidad de "Capture Compare del micro.

Cada puerto tiene dos registros que sirven para manejarlo, un registro de control (DPx) y otro de datos (Px). A continuacin se explica cada uno de ellos particularizado para el puerto 2. DP2 tiene 16 bits, uno para cada lnea (pin) del puerto. Se utiliza para indicar si el pin hace de entrada o de salida (el pin no puede hacer de entrada y de salida al mismo tiempo). Con un 0 en DP2 se indica que el pin hace de entrada. Con un 1 el pin hace de salida. Por ejemplo, si en DP2 cargamos 0xFFFF estamos indicando que todos los pines del puerto hacen de salida. Si cargamos 0x0000 indicamos que todos hacen de entrada. Con 0x00FF la mitad de los pines del puerto hacen de entrada y la otra mitad de salida. Una vez configurado el puerto va DP2, ste se maneja a travs de P2. Cuando se lee P2 se lee el estado de los pines del micro. Cuando se escribe en P2 se escribe en los pines del micro. En el sistema usado para las prcticas de laboratorio se han conectado diodos LED en parte baja de P2 (P2.0 a P2.7) e interruptores en la parte alta (P2.8 a P2.15), de la manera que se muestra en la Figura 16.
+ 5V + 5V

P2.8 P2.0

Figura 16: conexin de los LED e interruptores al puerto 2 del C167 de la tarjeta de laboratorio

Con este hardware en DP2 se tiene que escribir 0x00FF. Cuando se lea P2 se estar leyendo el estado de los pines que hacen de entrada (parte alta de P2: interruptores). Cuando se escriba en P2 se actuar sobre los diodos (parte baja de P2).

Ntese que: Cuando se lee P2 la nica informacin de inters es la que viene de las entradas (la informacin de las salidas no tiene inters, se desecha)

49

Sistemas Electrnicos Digitales.

Cuando se escribe P2 slo se acta sobre las salidas (en las entradas tenemos el valor fijado en el exterior va interruptores). DP2 depende nicamente del hardware conectado y por ello slo se configura una vez dentro de los programas. De forma que aquellos pines del micro que tengan conectados actuadores, se configurarn como salidas y los que tengan conectados sensores, se configurarn como entradas.

Por ejemplo: Si el interruptor conectado a P2.8 lo ponemos a 5V (actuando manualmente sobre l) y el resto de interruptores los ponemos a 0V y adems la CPU tiene encendidos todos los LED, entonces al leer P2 obtenemos 0x0100. Si en ese momento alguien mueve el interruptor conectado a P2.9, entonces P2 vale 0x0300, lo que permite a la CPU darse cuenta de lo sucedido simplemente leyendo P2. Si la CPU decide apagar el diodo menos significativo escribir 0x0001 en el puerto. Si a continuacin se lee el puerto, sin cambiar ninguno de los interruptores, se obtendr 0x0301 (obtenemos en valor que hemos escrito previamente).

A continuacin se muestra un programa que suma dos nmeros de 4 bits, uno representado por los 4 interruptores conectados a la parte ms alta de P2 (P2.12 a P2.15) y otro representado por los 4 interruptores conectados desde P2.8 hasta P2.11. El resultado de la suma se muestra por los LEDs. La solucin en C sera:
void main(void) { int temp1,temp2; DP2 = 0x00ff; while (1) { temp1 = P2; temp2 = temp1; /* Mejor que "temp2 = P2 */ temp1 = temp1 & 0x0f00; /* AND bit a bit */ temp1 = temp1 >> 8; /* SHR rotar 8 a la decha*/ temp2 = temp2 & 0xf000; temp2 = temp2 >> 12; P2=~(temp1 + temp2); /* CPL */ } }

En el ejemplo se puede apreciar que la operacin AND en C es &, que la operacin desplazamiento de bits a la derecha SHR en C es >> y que el complemento a 1 CPL en C es ~. El siguiente cdigo presenta la solucin en ensamblador para irse familiarizando con el mismo y as poder compararlo con el lenguaje C.

50

Sistemas Electrnicos Digitales.

bucle:

MOV DP2,#0x00ff MOV R0, P2 MOV R1, R0 AND R0, #0x0F00 SHR R0, #8 AND R1, #0xF000 SHR R1, #12 ADD R1, R0 CPL R1 MOV P2, R1 JMPR CC_UC, bucle

Ntese que el programa maneja DP2 una nica vez en la fase de inicializacin (configuracin del puerto, antes del bucle while). El manejo de puerto se realiza a travs de P2.

51

Sistemas Electrnicos Digitales.

3 Ejercicios propuestos
1) Hacer un programa en ensamblador que encienda el primer LED de la tarjeta del laboratorio (situados en la parte baja del puerto 2).

2) Hacer un programa en ensamblador que indique en los LED (parte baja de P2) la posicin de los interruptores (parte alta de P2) de la tarjeta del laboratorio.

52

Sistemas Electrnicos Digitales.

4 Prctica 2: entradas y salidas digitales

53

Sistemas Electrnicos Digitales.

54

Sistemas Electrnicos Digitales.

5 Prctica 3: ensamblar y depurar

55

Sistemas Electrnicos Digitales.

56

Sistemas Electrnicos Digitales.

57

Sistemas Electrnicos Digitales.

58

Sistemas Electrnicos Digitales.

59

Sistemas Electrnicos Digitales.

Captulo 5 PERIFRICOS
1 Objetivos y conceptos a entender en este captulo
Entender cmo se maneja de forma general cualquier perifrico del micro. Entender para qu sirve, cmo se maneja y configura el Timer. Ser capaz de establecer una correspondencia entre el funcionamiento general de un perifrico y el funcionamiento del Timer.

2 Perifricos del C167


Un perifrico es un dispositivo que tiene todo SED para realizar tareas especficas sin consumir tiempo de CPU. En el C167 los registros de programacin de los perifricos se encuentran mapeados en ciertas direcciones de memoria; es decir, se manejan igual que una posicin cualquiera de memoria, haciendo operaciones de lectura/escritura, ver seccin 3.7. Estas posiciones de memoria se corresponden con los registros de propsito especfico (SFR) que tiene el perifrico. Hay tres tipos de SFRs que permiten programar el perifrico: Los registros de control o de configuracin: permiten configurar el modo de funcionamiento del perifrico. Indican cuando el perifrico debe realizar su tarea y cuando debe parar Start/Stop. La nomenclatura que se usa es xxxCON; es decir, el nombre de los registros de control siempre acaban en CON. Registros de datos: almacenan informacin relevante de los resultados o parmetros necesarios para el funcionamiento del perifrico. Registros de control de interrupcin: este registro informa de cundo el perifrico termina la tarea que desempea. El programa que se ejecuta en la CPU se entera de que el perifrico ha terminado su trabajo haciendo polling (de un bit) de este registro, o va interrupcin, ver seccin 3.7 para un resumen o el captulo 8 para los detalles. La nomenclatura que se usa para el nombre de estos registros es xxxIC (Interrupt Control register). Generalmente los perifricos suelen tener contacto con el exterior y por ello pueden adems utilizar un puerto del micro. El micro tiene muchos perifricos, de los cuales los ms importantes son: Temporizadores (timers): para contar eventos, para llevar un computo del tiempo transcurrido, etc. Convertidor analgico/digital (A/D): sirve para pasar una seal del dominio analgico al digital, formato que puede ya procesar el micro.

60

Sistemas Electrnicos Digitales.

Controladores de comunicaciones serie: para comunicarse con el exterior en serie; por ejemplo un PC. Moduladores PWM: muy usados en electrnica de potencia para controlar motores. En este captulo slo se describir el Timer.

3 El Timer
Es un perifrico que se encarga de contar los pulsos de una seal. La cuenta la almacena en un registro de 16 bits. En un momento dado la CPU le manda empezar a contar y cuando rebosa (llega a 0xFFFF+1), avisa de que ha terminado la cuenta. El C167 tiene muchos Timers, pero todos se usan de forma similar. Esta seccin explica con detalle el funcionamiento del Timer 0, y por similitud queda descrito el funcionamiento del resto de Timers del micro. Los registros de programacin del mismo son: T01CON: es un registro (SFR) de configuracin de 16 bits del Timer 0 y 1 como su nombre indica. La parte baja del registro, primeros 8 bits, configuran el Timer 0 y la parte alta configura el Timer 1. T0: es un registro (SFR) de datos del perifrico de 16 bits que se encarga de llevar la cuenta del nmero de pulsos detectados. El equivalente para el Timer 1 se llama T1. T0REL: es el registro (SFR) de 16 bits que indica el valor con el que se carga T0 una vez que rebosa, sobrepasa su mxima cuenta que es 0xFFFF. Dicho de otro modo, una vez que el Timer 0 a realizado tantas cuentas como para T0 sobrepase 0xFFFF, en vez de pasar a valer T0=0, pasa a valer T0=T0REL. De esta forma aunque el Timer 0 termina su tarea, puede seguir contando. El registro equivalente para el Timer 1 es T1REL. T0IC: es el registro (SFR) de 16 bits tiene un bit (T0IR) que indica cuando el Timer 0 ha rebosado. El resto de bits sirven para configurar su control por interrupcin A continuacin se explica en detalle cada uno de estos registros. 3.1 Registro de control T01CON El registro de T01CON tiene 16 bits y consta de dos partes, una parte baja que configura el Timer 0 y otra parte alta que configura el Timer 1:
15 --14 T1R 13 12 --11 T1M 10 T1I 8 7 --6 T0R 5 --4 3 T0M 2 T0I 0

T0M: es el bit 3 e indica el modo de funcionamiento del Timer. Como se ha comentado el Timer cuenta pulsos, pero no se ha especificado de dnde provienen. Pues bien, el bit de modo indica si los pulsos provienen del reloj interno que usa la CPU o no. En el primer caso se dice que funciona en modo timer ya que el origen es una seal peridica y de frecuencia constante que equivale a un reloj de medida de

61

Sistemas Electrnicos Digitales.

tiempo, y en el segundo se dice que funciona en modo counter, por ejemplo el Timer 0 cuenta los pulsos de la seal que entra por el pin T0IN/P3.0. T0I: es el pre-escalado y lo forman los bits 0-2. El pre-escalado, como su nombre indica, es un cambio de escala en la cuenta. Indica el nmero de pulsos de la seal de reloj que tienen que suceder para que el Timer 0 incremente en 1 su cuenta. De esta forma se logra que el timer cuente ms despacio, ya que el pre-escalado funciona como un divisor de frecuencia, dividiendo por:

2 ( 3+T 0 I )
Por ejemplo, para el caso de que el Timer 0 funcione en modo timer, y la CPU use un reloj de 20 MHz, la salida del pre-escalado es:

20 MHz 2 ( 3+ T 0 I ) T0R es el bit 6 y sirve para arrancar y para el Timer. Cuando la CPU quiere que empiece la tarea, pone este bit a 1, y cuando ha terminado de contar, la CPU puede poner este bit a 0 y deja de contar o bien le deja continuar recargando de forma automtica T0=T0REL.
clk = 20MHz
T0I

3.2 Registros de datos Existen dos registros de datos de 16 bits cada uno: T0: es un SFR que almacena la cuenta del Timer 0 T0REL: es el valor al que se inicializa el registro T0 cuando ste rebosa 3.3 Registro de control de interrupciones T0IC Es un registro de 16 bits que tiene los siguientes bits:
15 8 7 6 5 ILVL 2 1 0 T0IR T0IE GLVL

De todos los bits el nico que interesa por ahora es el T0IR, ya que los dems se vern en ms detalle en el Captulo 8. T0IR: es un bit que indica que el Timer 0 ha terminado su tarea; es decir, en el momento en que el registro T0 pasa de 0xFFFF a 0000. T0IE: habilita el control por interrupciones. ILVL: indica el nivel de la interrupcin (0 a 15. Nivel 15 nivel ms alto) GLVL: grupo del nivel de interrupcin.

62

Sistemas Electrnicos Digitales.

3.4 Resumen de funcionamiento El Timer cuenta hacia arriba desde el valor inicial de T0, hasta 0xFFFF. En el momento que supera este ltimo valor se dice que ha rebosado y entonces T0=T0REL. Posteriormente procede a seguir su cuenta. Es necesario caer en la cuenta que la primera cuenta va desde el valor inicial de T0 a 0xFFFF. Las siguientes cuentas van desde T0REL a 0xFFFF. El rebose queda registrado en el bit T0IR del registro T0IC.

Valor de recarga despus de un rebose Pre-escalado


clk T0I

T0REL

rebose o final de cuenta

T0

T0IR

Almacena la cuenta

3.5 Ajuste del pre-escalado El pre-escalado permite al Timer cambiar de escala el ritmo de la cuenta, de forma que en modo timer puede llegar a contar con nicamente 16 bits durante 3.36s sin rebosar. Como T0I tiene tres bits, significa que existen 8 escalas o velocidades de cuenta. Por ejemplo, en modo timer, con un reloj de CPU de 20 MHz, se puede deducir que: Escala 0 (T0I=0): la velocidad de la cuenta es de 2.5MHz; es decir, incrementa la cuenta cada 400ns. A esta velocidad el tiempo mximo que puede pasar hasta el rebose es 26ms, que se corresponde a una cuenta que va desde 0 hasta 0xFFFF, momento en que rebosa. Por lo tanto, en este ltimo caso el valor inicial de T0 para la primera cuenta debe ser 0 y para las siguientes T0REL = 0. Escala 1 (T0I=1): la velocidad de cuenta es la mitad de rpida, 1.25 MHz; es decir, incrementa la cuenta cada 800ns. A esta velocidad el tiempo mximo de rebose es de 52ms (el doble que el caso anterior). 20MHz Escalas 2-7: el razonamiento es anlogo, aplicando la ecuacin 2+T 0 I . 2 3.6 Ejemplo de programacin: LEDs a ritmo de reloj Antes de leer la explicacin del ejercicio, sera conveniente intentar entenderlo por uno mismo, qu Timer usa?, a qu frecuencia cuenta?, cuanto tiempo tarda en rebosar? qu pasa con el puerto?. Es necesario suponer un sistema como el del laboratorio donde hay LEDs conectados a la parte baja del puerto P2. Por otro lado, la operacin ^ es un XOR; es decir, P2 ^= 0xFFFF, es lo mismo que P2 = P2 ^0xFFFF, que es en ensamblador XOR P2, #0xFFFF, que es

63

Sistemas Electrnicos Digitales.

lo mismo que P2
T01CON | 0x40,

= complemento a 1 de P2.

que es lo mismo que en ensamblador CPL P2, que es lo mismo que P2 De la misma manera T01CON |= 0x40 es lo mismo que T01CON = que es en ensamblador OR T01CON,#0x40.

= ~P2,

#include <reg167.h> main() { T01CON = 0x06; T0REL = PERIOD; T0 = PERIOD; T0IR = 0; T01CON |= 0x40; DP2 = 0x00FF; P2 = 0; // timer a 39 kHz // Qu valores son razonables? // flag rebose = 0 // Start

while (1) { while(!T0IR) ; P2 ^= 0xFFFF; T0IR = 0; } }

// bucle de espera // XOR // flag rebose = 0

El Timer cuenta a una frecuencia de 39kHz y funciona en modo timer. Lo que supone que dependiendo de la inicializacin de T0 y T0REL el Timer puede rebosar desde aproximadamente 25us (cuando PERIOD = 0xFFFF) hasta aproximadamente 1.65s (cuando PERIOD = 0). En un principio los LEDs estn encendidos. Cuando el programa entra en el bucle infinito, se comprueba si el timer rebosa (T0IR == 1) y si es as entonces cambia el estado del puerto P2, apagando los LEDs. Luego el programa vuelve a esperar al siguiente rebose y despus enciende los LEDs. En resumen el programa enciende y apaga los LEDs de forma peridica con un periodo que depende de la inicializacin de PERIOD. Para que el ojo humano perciba el parpadeo de los LED este debe hacerse a una frecuencia inferior a 10Hz, por ejemplo, PERIOD = 0 es razonable.

64

Sistemas Electrnicos Digitales.

4 Cuestiones de comprensin
1) Deducir la frmula que relaciona el tiempo de rebose del timer (t) con el prescalado (T0I) y la cuenta inicial (T0); es decir, t = funcin(T0I,T0).

2) Si el tiempo que tarda en rebosar el timer 0 es 2s, cunto vale T0 y T0I (la cuenta inicial y el preescalado)?. Razona la respuesta

3) Responder a las siguientes preguntas: a. Cul es el mnimo nmero negativo (aproximadamente) que se puede conseguir con 16 bits? ____________________________ b. Cul es el mayor nmero positivo (aproximadamente) que se puede conseguir con 16 bits con signo? _________________________ c. Ves alguna incoherencia entre las respuestas que has dado a los apartados 3.a) y 3.b) con la solucin obtenida en el ejercicio 2? Razona la respuesta.

65

Sistemas Electrnicos Digitales.

5 Ejercicios propuestos
5.1 PWM sencillo (30 min)

Hacer un programa que genere una secuencia de pulsos, por el pin P7.0 del micro, de forma peridica a frecuencia 256kHz. El ancho de cada pulso viene fijada, en milisegundos, por la variable de 8 bits DC.
$nonsegmented S0 ini ini S0 DAT DC section code at 0H proc NEAR jmp main endp ends section data at 200H db 13

DAT SM main

ends section code at 300H proc NEAR

66

Sistemas Electrnicos Digitales.

main SM

endp ends end

67

Sistemas Electrnicos Digitales.

6 Prctica 4: timers

68

Sistemas Electrnicos Digitales.

69

Sistemas Electrnicos Digitales.

70

Sistemas Electrnicos Digitales.

Captulo 6 ENSAMBLADOR
1 Objetivos y conceptos a entender en este captulo
Los objetivos de este captulo son: Darse cuenta de que cada instruccin ensamblador se codifica de una forma en hexadecimal. Entender los nmeros con signo y sin signo, complemento a 2, qu implica el overflow y el carry. Entender cmo funcionan los saltos basndose en los flags del PSW. Cmo se maneja el stack: cuando se usan funciones y con las instrucciones push y pop

2 Introduccin
El objetivo de este captulo es describir las principales instrucciones de ensamblador para el microcontrolador Siemens C167. Las instrucciones de ensamblador se caracterizan por los modos de direccionamiento que soportan, los flags de estado a los que afectan y el tamao de los operandos que usan. Los modos de direccionamiento son la forma que se tiene en ensamblador para acceder a cada uno de los operandos de una instruccin. Se explican en el captulo 2 seccin 2.2.2. Los flags de estado dan informacin cualitativa del resultado despus de ejecutar una instruccin. Se explican en el captulo 2 seccin 2.3.2.2. El 167 maneja operandos de distintos tamaos: Byte: 8 bits Word: 16 bits Bit: 1 bit
2.1 Codificacin de instrucciones La CPU slo entiende de ceros y unos. Por ello en memoria las instrucciones que tiene que ejecutar se encuentran codificadas de forma binaria, cdigo mquina. El programa encargado de traducir del lenguaje ensamblador a cdigo mquina se llama ensamblador. Si se trabaja en alto nivel, el programa encargado de traducir del lenguaje C a cdigo mquina se llama compilador.

71

Sistemas Electrnicos Digitales.

La codificacin interna de una instruccin se realiza en 16 o en 32 bits, de los cuales 8 son de cdigo de operacin o tipo de instruccin, y los dems se usan para codificar los operandos de la instruccin. En la Figura 17 y en la Figura 18 se muestran dos ejemplos de cmo se codifica una instruccin de 16 bits y una de 32 bits respectivamente. En el primer ejemplo la instruccin ocupa 16 bits porque la codificacin de los operandos se puede hacer en 8 bits, 4 bits para indicar el primer GPR (que slo hay 16) y 4 bits para indicar el segundo GPR. En el segundo ejemplo la instruccin ocupa 32 bits porque el primer operando ocupa 8 bits y el segundo 16 bits.

F0
Cdigo de instruccin

x y
Nmero de GPR

Figura 17: Codificacin de la instruccin MOV Rx, Ry

E6
Cdigo de instruccin

reg
Nmero de SFR

dato
Nmero de 16 bits

Figura 18: Codificacin de la instruccin MOV reg, #data

3 Operaciones de transferencia de datos


Todas ellas actualizan nicamente los flags N y Z. Si el resultado es cero se pone a uno el flag Z y si el resultado es negativo se pone a uno el flag N.
3.1 MOV y MOVB La instruccin ms utilizada en transferencia de datos es MOV. Equivale a un = en C. La sintaxis es la siguiente:
MOV MOVB op1,op2 op1,op2 ; op1 = op2 a nivel de Word ; op1 = op2 a nivel de Byte

Transfiere el contenido del operando fuente op2, al operando destino op1. En este ensamblador el operando fuente siempre est a la derecha y el destino a la izquierda. Es la instruccin que permite el mayor nmero de combinacin de modos de direccionamiento en sus operandos. Una regla que vale en un 95% de las veces es suponer que puede con todos los modos de direccionamiento menos MOV mem,mem y MOV mem,#data. Para ms informacin de los modos de direccionamiento consultar seccin 2.2.2 del captulo 3.

72

Sistemas Electrnicos Digitales.

3.2 MOVBZ y MOVBS

Si un dato a nivel de byte se va a utilizar a continuacin como dato a nivel de word, es necesario tener en cuenta si el nmero tiene o no tiene signo. Si el nmero no tiene signo, los 8 bits ms significativos debern ser igual a cero. Si el nmero tiene signo (complemento a dos) los 8 bits ms significativos debern estar a 0 si el bit 7 est a 0, y estarn a 1 si el bit 7 est a uno. A esta operacin se le conoce como extensin de signo. Las instrucciones de que dispone el ensamblador de 167 para este propsito son:
MOVBZ op1, op2

Carga el byte en parte baja, extiende (a los 16 bits) con ceros


MOVBZ MOVBZ
MOVBS

R0,#0xFF ; r0 <- 0x00FF R0,#-1 ; r0 <- 255 no respeta el signo


op1,op2

Carga el byte en la parte baja, extiende (a los 16 bits) con ceros


MOVBS MOVBS R0,#0xFF ; r0 <- 0xFFFF R0,#-1 ; r0 <- -1 respeta el signo

En la tabla siguiente se exponen dos ejemplos:


8 bits con signo 0xFF 0x80 -1 -128 8 bits sin signo 255 128 16 sin extender signo 255 (0x00FF) 128 (0x0080) 16 bits extendiendo signo -1 (0xFFFF) -128 (0xFF80)

3.3 PUSH y POP Otras instrucciones de transferencia de datos son:


PUSH POP reg reg

La operacin PUSH decrementa el Stack Pointer y carga el operando en la posicin de memoria apuntada por el mismo. La operacin POP efecta la operacin inversa. El operando debe ser uno de los GPR's o SFR's.

73

Sistemas Electrnicos Digitales.

Figura 19: Ejemplo de uso de PUSH

Estas instrucciones se suelen usar para guardar los GPRs que se van a usar en una funcin como variables locales, ya que en caso contrario la funcin modificara el contenido de los mismos y no funcionara correctamente el programa que llama a la funcin.

4 Instrucciones para realizar operaciones aritmticas


Los flags se actualizan de acuerdo con el resultado de la operacin: N y Z para negativo y cero, C para el acarreo y V para cambios en el bit de signo.
4.1 ADD y ADDB Sirve para sumar dos nmeros en, guardando el resultado en el primero. La forma estndar de la instruccin ADD es:
ADD op1, op2 ; op1 <- op1 + op2

MOV MOV ADD ADD

R0,#0x0001 0xFA00,R0 R0,#0x0009 0xFA00,R0

Figura 20: Ejemplo de ADD. Finalmente R0 = 0x000A y 0xFA00 = 0x000B

El conjunto de modos de direccionamiento queda bastante restringido con respecto a la instruccin MOV. Los modos que se pueden usar son:
ADD Rx, Ry ADD Rx, [Ry] ; Ry con y = 0..3 ADD Rx, [Ry+] ; Ry con y = 0..3

74

Sistemas Electrnicos Digitales.

ADD Rx, #data ADD reg, #data ADD reg, mem ADD mem, reg

La instruccin ADD admite la variante ADDB para operandos a nivel de byte.


MOV ADDB R0,#0x0001 Rh0,#0x01

Figura 21: Ejemplo de ADDB. Finalmente R0 = 0x0101

4.2 SUB y SUBB La instruccin SUB sirve para restar dos nmeros. Admite las mismas variantes que la instruccin ADD. (En este caso el flag de carry C, recoge el borrow. El borrow est a 1 cuando el minuendo es menor que el substraendo).
SUB op1, op2 ; op1 <- op1 op2

MOV MOV SUB ADD

R0,#0x01FF 0xFA00,R0 R0,#0x0009 0xFA00,R0

Figura 22: Ejemplo de SUB. Finalmente R0 = 0x1F6 y (0xFA00) =0x3F5

A nivel de byte

MOV SUBB

R0,#0x01FF Rh0,#0x01

Figura 23: Ejemplo de SUB. Finalmente R0 = 0xFF

4.3 NEG La instruccin NEG sirve para obtener el complemento a dos de un nmero. Es equivalente a restar el operando op1 de 0 y almacenar el resultado en el mencionado operando (en este caso el flag de C tambin recoge el borrow).
NEG Rx ; Rx <- 0 - Rx

75

Sistemas Electrnicos Digitales.

MOV NEG

R0,#0x01FF R0

Figura 24: Ejemplo de NEG. Finalmente R0 = 0xFE01

A nivel de byte
MOV NEGB R0,#0x01FF Rl0

Figura 25: Ejemplo de NEGB. Finalmente R0 =0x0101

4.4 MUL y MULU Son instrucciones para realizar multiplicaciones de dos nmeros. Admiten dos variantes: con y sin signo.
MUL MULU Rx,Ry Rx,Ry ; [MDH, MDL] <- Rx * Ry

La instruccin MUL admite dos registros como operandos. El resultado viene dado en 32 bits, que se almacena en el registro MD (registro Multiply/Divide de la CPU, almacenando en MDL la parte baja de MD, y en MDH la parte alta de MD). En esta operacin nunca se tiene rebose (C = 0). El flag V se pone a 1 si el resultado no cabe en 16 bits (til si se pretende multiplicar el resultado de este primer producto por algn otro factor.) Los flags Z y N se actualizan de acuerdo con el valor del resultado. La instruccin MULU es la variante para operandos sin signo.
MOV MOV MUL MOV MOV MULU R0,#0xFFFF R1,#0xFFFF R0,R1 R2,MDL R3,MDH R0,R1

Figura 26: Ejemplo de MUL y MULU. Finalmente R2 = 1, R3 = 0, MDL = 0x0001 y MDH = 0xFFFE

4.5 DIV y DIVU La instruccin DIV divide la parte baja del registro MD (MDL: 16 bits) entre el operando Rx (tambin de 16 bits).
DIV DIVU Rx Rx ;MDL <- MDL / Rx MDH <- MDL mod Rx

76

Sistemas Electrnicos Digitales.

El cociente viene dado en 16 bits que se almacenan en la parte baja del registro MD (MDL), el resto queda en la parte alta (MDH). Caso de que el cociente supere los 16 bits significativos, o el cociente sea 0, el bit V se pone a 1. La variante DIVU opera con nmeros sin signo.
MOV MOV MOV DIV MOV MOV MOV MOV DIVU R3,#0xFFFF MDL,R3 R0,#0x0001 R0 R1,MDL R2,MDH R3,#0xFFFF MDL,R3 R0

Figura 27: Ejemplo de DIV y DIVU. Finalmente R1 = 0xFFFF, R2 = 0, MDL = 0xFFFF y MDH = 0

5 Instrucciones para realizar operaciones lgicas


Las operaciones lgicas trabajan bit a bit dentro de un registro. Se suelen usar para aplicar "mscaras", una especie de filtro que permite seleccionar ciertos bits de un registro. Todas ellas actualizan nicamente los flags N y Z. Si el resultado es cero se pone a uno el flag Z y si el resultado es negativo se pone a uno el flag N.
5.1 AND Se utiliza para efectuar el producto lgico de dos operandos, bit a bit. La instruccin AND admite la forma:
AND Rx,op ; Rx <- Rx and op

Admite los mismos modos de direccionamiento que la instruccin ADD. Los flags V y C quedan a 0 y el resto (A, N) se actualizan de acuerdo con el valor del resultado. La variante ANDB opera a nivel de byte.
MOV AND R0,#0x0001 R0,#0x0009

Figura 28: Ejemplo de AND. Finalmente R0 = 1

La instruccin AND sirve como mscara, para seleccionar nicamente ciertos bits de un registro o para borrar bits de forma selectiva.

77

Sistemas Electrnicos Digitales.

AND

R0,#0xFFFD

Figura 29: Se quiere poner el bit 1 del registro R0 a 0. O lo que es lo mismo, se seleccionan el resto de bits del registro R0

5.2 OR Se usa para efectuar la suma lgica de dos operandos, bit a bit. La instruccin OR admite la forma:
OR Rx, op ; Rx <- Rx or op

Admite los mismos modos de direccionamiento que la instruccin ADD. La variante ORB opera a nivel de byte.
MOV OR R0,#0x0001 R0,#0x0009

Figura 30: Ejemplo de OR. Finalmente R0 =9

La instruccin OR sirve como mscara, para seleccionar nicamente ciertos bits de un registro o para poner a uno ciertos bits de forma selectiva.

OR

R0,#0x0002

Figura 31: Se quiere poner el bit 1 del registro R0 a 1. O lo que es lo mismo, se seleccionan el resto de bits del registro R0

La combinacin de AND con OR permite igualar dos bits de dos registros.


AND MOV AND OR R0,#0xFFFD R2,R1 R2,#0x0002 R0,R2 ; ; ; ; se pone a 0 el bit 1 de R0 para no modificar R1 se selecciona el bit 1 de R2 R0.1 = R2.1 = R1.1

Figura 32: Se quiere poner el bit 1 del registro R0 igual que el bit 1 del registro R1.

5.3 XOR Realiza un OR EXCLUSIVO bit a bit de dos operandos. La instruccin XOR admite la forma:
XOR Rx, op ; Rx <- Rx xor op

La variante XORB opera a nivel de byte.

78

Sistemas Electrnicos Digitales.

MOV XOR

R0,#0x0101 R0,#0xFFFF

; R0 <- 0xFEFE

Figura 33: Ejemplo de XOR. Finalmente R0 = 0xFEFE

5.4 CPL Realiza el complemento a 1 de un nmero. La instruccin CPL admite la forma:


CPL Rx ; Rx <- complemento a 1 de Rx

La variante CPLB opera a nivel de byte.


MOV CPL R0,#0x0101 R0

; R0 <- 0xFEFE

Figura 34: Ejemplo de CPL. Finalmente R0 = 0xFEFE

6 Instrucciones para realizar desplazamientos de bits


Las instrucciones de desplazamiento SHL y SHR permiten desplazar los bits de un registro un nmero arbitrario de desplazamientos (a izquierda y derecha respectivamente). La forma genrica de utilizacin es:
SHL SHL Rx,Ry Rx,#num ; Desplaza num veces a la izda los bits de Rx

donde Rx es el operando a desplazar, y Ry da el nmero de desplazamientos. SHL desplaza los bits hacia la izquierda. El bit de Carry se pone a uno si el bit 15 que sale del desplazamiento es 1 (en la ltima iteracin). Las posiciones libres que van quedando a la derecha se rellenan con ceros.

C
MOV SHL

Rx 16 bits
R0,#0x0001 R0,#9

Figura 35: Ejemplo de SHL. Finalmente R0 = 0x0200

79

Sistemas Electrnicos Digitales.

SHR desplaza los bits hacia la derecha. El bit de Carry se pone a uno si el bit 0 que sale del desplazamiento es 1 (en la ltima iteracin). Las posiciones libres que van quedando a la izquierda se rellenan con ceros.

Rx 16 bits

Se puede combinar con las operaciones AND y OR para igualar bits de diferentes registros.
AND MOV AND SHL OR R0,#0xFFFD R2,R1 R2,#0x0001 R2,#1 R0,R2 ; ; ; ; ; se pone a 0 el bit 1 de R0 para no modificar R1 se selecciona el bit 0 de R2 el bit 0 pasa a ser el bit 1 R0.1 = R2.1 = R1.1

Figura 36: Se quiere poner el bit 1 del registro R0 igual que el bit 0 del registro R1.

Las instrucciones de rotacin ROL y ROR permiten rotar los bits de un registro un nmero arbitrario de desplazamientos (a izquierda y derecha respectivamente), de forma que los bits que salen por una lado del registro entran por el otro. La forma genrica de utilizacin es:
ROL ROL Rx,Ry Rx,#num ; Rota num veces a la izda los bits de Rx

donde Rx es el operando a rotar, y Ry da el nmero de desplazamientos. ROL rota los bits hacia la izquierda. El bit de Carry se pone a uno si el bit 15 que sale del desplazamiento es 1 (en la ltima iteracin). Las posiciones libres que van quedando a la derecha se rellenan con el valor del Carry en cada iteracin.

C
MOV ROL

Rx 16 bits

R0,#0x8001 R0,#9

Figura 37: Ejemplo de ROL. Finalmente R0 = 0x0280 si carry 0 y R0 =0x0380 si carry 1.

ROR rota los bits hacia la derecha. El bit de Carry se pone a uno si el bit 0 que sale del desplazamiento es 1 (en la ltima iteracin). Las posiciones libres que van quedando a la izquierda se rellenan con el valor del Carry en cada iteracin.

80

Sistemas Electrnicos Digitales.

Rx 16 bits

7 Saltos
Como se ha mencionado en las secciones anteriores, el "estado" en el que queda el procesador despus de ejecutar una instruccin (de transferencia de datos, aritmtica, lgica o de desplazamiento), queda almacenado en el Registro de Estado, PSW, ver captulo 3 seccin 2.3.2.2. El estado viene definido por los "flags":

N: Negativo. Z: Cero ("Zero"). V: Rebose ("Overflow"). C: Acarreo o "Carry".

La informacin contenida en estos flags es todo lo que se necesita para realizar el control de flujo de programa. Por ejemplo, las siguientes condiciones del lenguaje C:
if (a == b) if (a != b)

se efectan en ensamblador comparando (instruccin CMP, ver apartado siguiente) el valor de la variable b con el valor de la variable a. Si las dos variables son iguales el procesador pone el flag de "Zero" a uno (Z=1). Si son distintas el flag permanece a cero. Los saltos condicionales, JMPR cc, permiten la ejecucin del bloque if o del bloque else, de acuerdo con el resultado de la comparacin. Cuando la condicin es del tipo desigualdad los flags que se deben comprobar (despus de la operacin de comparacin) son el Acarreo (Carry, C) para operandos sin signo, y el Rebose (Overflow, V) para operandos con signo (complemento a dos). Para facilitar la escritura de programas, el ensamblador de 167 dispone de las siguientes equivalencias entre alto nivel y ensamblador (ordenadas con criterio de alto nivel): Comparaciones de igualdad y desigualdad: Alto nivel Ensamblador Flag == cc_EQ (equal) Z != cc_NE (not equal) [Z]

81

Sistemas Electrnicos Digitales.

Comparaciones de desigualdad (estricta y no estricta): Alto Ensamblador nivel > cc_UGT (unsigned greater than) cc_SGT (signed greater than) < cc_ULT (unsigned less than) cc_SLT (signed less than) >= cc_UGE (unsigned greater than or equal) cc_SGE (signed greater than or equal) <= cc_ULE (unsigned less than or equal) cc_SLE (unsigned less than or equal) Sin signo [C] [Z] [Z] [ ( N V ) ([N] [V] ) ] C ( N [V] ) ([N] V ) [C] ( N V ) ([N] [V] ) C Z Z [ ( N [V] ) ([N] V ) ] Con signo

La instruccin CMP es similar a la instruccin SUB: resta el operando destino y del operando fuente y actualiza los flags de acuerdo con el resultado obtenido. Sin embargo, CMP no actualiza el operando destino. La operacin admite las siguientes variantes:
CMP op1,op2

op1 es el operando destino, y op2 es el operando fuente. Esta instruccin es idnea para comparar dos operandos que no se quieren actualizar, antes de un salto con condicin. Admite la variante CMPB.

En la Figura 38 se muestra un ejemplo. Primero, la instruccin CMP actualiza los flags del registro PSW de la misma forma que lo hace la instruccin SUB. Segundo, la instruccin JMPR se encarga de realizar el salto a la lnea next en caso de que R0 sea mayor que R1 (comparacin sin signo, es necesario hacer notar que -1 es mayor que 100 si se compara sin signo ya que el nmero -1 es 65535 sin signo en 16 bits).

82

Sistemas Electrnicos Digitales.

CMP JMPR .... next:

R0,R1 cc_ugt,next

;si R0 > R1

Figura 38: Ejemplo de salto condicional

Una condicin completa se muestra en la Figura 39.


MOV R0,a CMP R0,b JMPR cc_ne,else ; condicin if .. JMPR cc_uc,endif ; condicin else ..

else: endif:

Figura 39: Ejemplo de condicin en ensamblador de C167

8 Ejemplos de equivalencias de C y ensamblador


8.1 Condicin if A continuacin se muestra un ejemplo de condicin en C y ensamblador

if (a == b) ...; else ...;

Figura 40: Condicin en C

83

Sistemas Electrnicos Digitales.

else: endif:

MOV R0,a CMP R0,b JMPR cc_ne,else ; condicin if .. JMPR cc_uc,endif ; condicin else ..

Figura 41: Condicin en ensamblador

8.2 Bucle for A continuacin se muestra un ejemplo de bucle for en C y ensamblador

for (i=START; i <= STOP; i++){ a = STOP - i;

Figura 42: bucle for en C

for:

test: next:

MOV MOV SUB JMPR MOV SUB ADD CMP JMPR

R0,#START R1,#STOP R1,R0 cc_uc,test a,R1 R1,#1 R0,#1 R0,#STOP cc_slt,for

; r0 (i) ; r1 (STOP-START)

; i += 1 ; i <= STOP

Figura 43: bucle for en ensamblador

8.3 Bucle while A continuacin se muestra un ejemplo de bucle while en C y ensamblador

84

Sistemas Electrnicos Digitales.

i = 0; while (i<10) { a[i] = i; i += 1; }


Figura 44: bucle while en C

otro:

MOV MOV MOV CMP JMPR MOV ADD ADD JMPR

R0,#0 ; R0 es i R1,#1 ; es el incremento de i R2,#0xfa00 ;R2 almacena la direccin de memoria de a R0,#10 cc_sge,next [R2],R0 R0,R1 R2,#2 cc_uc,otro

next:

Figura 45: bucle while en ensamblador

9 Instrucciones a nivel de bit


Las instrucciones que operan con bits de forma individual slo se pueden usar contra zonas de memoria preparadas ello, ver Figura 46
FFFF

SFRs acceso bit a bit SFRs SFRs


FE00 FF00

Acceso bit a bit


FD00

GPRs RAM STACK


F600 FC00

85

Sistemas Electrnicos Digitales.

Figura 46: Zonas de memoria que permiten usar instrucciones a nivel de bit

Las zonas de RAM interna accesibles bit a bit son:


De la 00 FD00 a la 00 FDFF zona bit a bit. De la 00 FF00 a la 00 FFFF SFR's accesibles bit a bit.

9.1 Saltos Las instrucciones JB y JNB permiten realizar un salto en funcin del estado en el que se encuentra un bit.
JB JNB bit, dir bit, dir ; si bit = 1 entonces salta a dir ; si bit = 0 entonces salta a dir

JB .... next:

C,next

;si C = 1 salta next

Figura 47: Ejemplo de manejo de JB.

9.2 Otras La instruccin BSET pone a 1 el bit especificado en op1:


BSET op1

Los bits se especifican dando la direccin de la palabra, punto, nmero de bit. Por ejemplo:
BSET 0xFD00.2

pone a 1 el bit 2 de la palabra 0x00FD00. El flag N contiene el estado previo del bit (0 si el bit estaba a 0), y el flag Z es igual a N complementado. La instruccin BCLR sirve para poner un bit a 0. Para mover un bit de un lugar a otro se usa la instruccin
BMOV bit1, bit2 ; bit1 = bit2

Las siguientes instrucciones realizan operaciones lgicas con un slo bit

86

Sistemas Electrnicos Digitales.

BAND BOR BXOR

bit1, bit2

; bit1 <- bit1 and bit2 ; bit1 <- bit1 or bit2 ; bit1 <- bit1 xor bit2

bit1, bit2 bit1, bit2

En la Figura 48 se muestra algunos ejemplos de uso de estas instrucciones.


;activa bit 1 del P2 BSET P2.1 ; BCLR C ; Carry = 0 BMOV V,C ; V=C
Figura 48: Ejemplos de instrucciones "a nivel de bit"

87

Sistemas Electrnicos Digitales.

10 Directivas de ensamblador
Las directivas son unas instrucciones se ponen en el programa y que indican al programa ensamblador cmo debe ensamblar el cdigo. Estas instrucciones se ejecutan en tiempo de ensamblado y no en tiempo de ejecucin como el cdigo ensamblador propiamente dicho. Por eso a veces las directivas de ensamblador se llaman pseudoinstrucciones. En la Figura 49, se muestra un ejemplo con directivas de ensamblador, que se pasan a explicar a continuacin.
$nonsegmented equ 0x10 ; constante section data at 200H dsw 10 ; int j[10]; dw 1 ; int h =1; ends section proc MOV MOV MOV CMP JMPR MOV ADD ADD JMPR NOP endp ends end code at 300H NEAR R0,#0 R1,#1 R2,#j R0,#maxdata cc_sge,next [R2],R0 R0,R1 R2,#2 cc_uc,otro

maxdata

Seccin de datos D100 en direccin 0x200

D100 j h D100 ej ej1

Procedimiento ej1 Seccin de cdigo ej en direccin 0x300

otro:

next: ej1 ej

Final de programa

Figura 49: Directivas de ensamblador

section y ends: delimita las secciones del programa. El programa se puede dividir en dos tipos de secciones, las secciones de datos y de cdigo: o Las secciones de datos sirven para reservar memoria para variables. La nomenclatura es:
nombre section data at xxxH .... nombre ends

donde nombre es una etiqueta que indica el nombre de la seccin y xxxH es la direccin de memoria donde se guarda la primera variable de la seccin. Las demas se guardan a continuacin. Por ejemplo, en la Figura 49, la variable j se

88

Sistemas Electrnicos Digitales.

guarda en la direccin 0x200 y la variable h se guarda en la direccin 0x20A, ya que j ocupa 10 posiciones. o Las secciones de cdigo sirve para reservar memoria para instrucciones de programa. La nomenclatura es:
nombre section code at xxxH .... nombre ends

dsw: reserva espacios de 2 byte de memoria para una variable. Por ejemplo, en la primera lnea de la seccin de datos de la Figura 49, se reserva 20 bytes (10 espacios de 2 bytes) para la variable j; es quivalente a escribir en lenguaje C int j[10]. Existe la variante dsb que reserva espacios de 1 byte de memoria para la variable. dw: reserva espacios de 2 byte de memoria para una variable y los inicializa. Por ejemplo, en la segunda lnea de la seccin de datos de la Figura 49, se reservan dos bytes que se inicializan a 1; es equivalente a escribir en lenguaje C int h. Por ejemplo, el equivalente a int h[]={2,4}; sera dw h 2,4. Tambin existe la variante db que reserva espacios de 1 byte. equ: define una constante; el equivalente en C es #define. Esta directiva se pone fuera de las secciones. En la primera lnea de la Figura 49 se muestra un ejemplo de cmo se define la constante maxdata igual a 10. end: indica final de programa y se pone al final del fichero. proc: cada seccin de cdigo se puede dividir en varios procedimientos con esta directiva. La nomenclatura es:
nombre proc NEAR .... nombre endp

donde nombre es un etiqueta que indica el nombre del procedimiento y endp indica el final del procedimiento. Se puede acceder a un procedimiento de la misma manera que se hace con una lnea de cdigo etiquetada; por ejemplo jmpr nombre.

89

Sistemas Electrnicos Digitales.

11 Cuestiones de comprensin
1) Cmo se codifica el nmero 16 en hexadecimal usando 8 bits?

2) Qu vale R0 despus de ejecutar las instrucciones siguientes?


Movbz Movbs R0, #0xFC R0, #0xFC ;R0 = __________ ;R0 = _________

3) Indicar el valor de PSW despus de ejecutar las siguientes instrucciones (los bits que no se usan se pueden poner a cero):
mov add add add R0, #0 R0, #0x6500 R0, #0x6500 R0, #0x6500 ;PSW = ___________ ;PSW = ___________ ;PSW = ___________ ;PSW = ___________

4) Qu representa la informacin que almacena R0? (responder a,b c) _____


mov mov R0, #300 R1, [R0]

a) Un dato que podra variar b) Una direccin de memoria c) Una constante genrica

5) Qu representa var? (responder a,b c) _____


var MOV equ 0x300 R0,#var

a) Un dato que podra variar b) Una direccin de memoria c) Una constante genrica

90

Sistemas Electrnicos Digitales.

6) Cul es el valor de R0? __________


MOV NEGB R0,#0x01FF RL0

7) Cual es el valor de R2 y R3? R2 = ____________


MOV MOV MUL MOV MOV R0,#0x6FFF R1,#0xFFFF R0,R1 R2,MDL R3,MDH

R3 = ____________

8) Cual es el valor de R1 y R2? R1 = ____________


MOV MOV DIV MOV MOV MDL,#0xFFFF R0,#0x0001 R0 R1,MDL R2,MDH

R2 = ____________

9) Qu instrucciones de ensamblador hay que programar para hacer que el bit 2 (tercer bit) del registro R0 sea igual que el de R1 sin llegar a modificar ni el registro R1 ni el resto de bits del registro R0? (usar mscaras)

91

Sistemas Electrnicos Digitales.

10) Indicar el valor de SP, el de R0 y el valor de la memoria en hexadecimal? La respuesta debe ir en la secuencia de tablas que se encuentran despus del ejemplo y que cada una se corresponde con la ejecucin de cada una de las instrucciones del ejemplo.
.... MOV CALLR MOV .... PUSH MOV POP RET

300 304 306

R0, #0x54 400 R1, #0x32

400 402 406 408

R0 R0, #1 R0

a) Justo despus de ejecutar la instruccin en la direccin de memoria 300

R0 = _____________ SP = _____________

Direccin mem 00 FC04 00 FC03 00 FC02 00 FC01 00 FC00 00 FBFF 00 FBFE 00 FBFD 00 FBFC 00 FBFB 00 FBFA

Dato mem (HEX)

b) Justo despus de ejecutar la instruccin en la direccin de memoria 304

R0 = _____________ SP = _____________

92

Sistemas Electrnicos Digitales.

Direccin mem 00 FC04 00 FC03 00 FC02 00 FC01 00 FC00 00 FBFF 00 FBFE 00 FBFD 00 FBFC 00 FBFB 00 FBFA

Dato mem (HEX)

c) Justo despus de ejecutar la instruccin en la direccin de memoria 400

R0 = _____________ SP = _____________

Direccin mem 00 FC04 00 FC03 00 FC02 00 FC01 00 FC00 00 FBFF 00 FBFE 00 FBFD 00 FBFC 00 FBFB 00 FBFA

Dato mem (HEX)

d) Justo despus de ejecutar la instruccin en la direccin de memoria 402

R0 = _____________ SP = _____________

93

Sistemas Electrnicos Digitales.

Direccin mem 00 FC04 00 FC03 00 FC02 00 FC01 00 FC00 00 FBFF 00 FBFE 00 FBFD 00 FBFC 00 FBFB 00 FBFA

Dato mem (HEX)

e) Justo despus de ejecutar la instruccin en la direccin de memoria 406

R0 = _____________ SP = _____________

Direccin mem 00 FC04 00 FC03 00 FC02 00 FC01 00 FC00 00 FBFF 00 FBFE 00 FBFD 00 FBFC 00 FBFB 00 FBFA

Dato mem (HEX)

f) Justo despus de ejecutar la instruccin en la direccin de memoria 408

R0 = _____________ SP = _____________

94

Sistemas Electrnicos Digitales.

Direccin mem 00 FC04 00 FC03 00 FC02 00 FC01 00 FC00 00 FBFF 00 FBFE 00 FBFD 00 FBFC 00 FBFB 00 FBFA

Dato mem (HEX)

g) Justo despus de ejecutar la instruccin en la direccin de memoria 306

R0 = _____________ SP = _____________

Direccin mem 00 FC04 00 FC03 00 FC02 00 FC01 00 FC00 00 FBFF 00 FBFE 00 FBFD 00 FBFC 00 FBFB 00 FBFA

Dato mem (HEX)

95

Sistemas Electrnicos Digitales.

12 Ejemplo de discusin: medida de ancho de pulso, sin/con filtrado de rebotes


Se quiere medir el ancho de un pulso que entra por un pin del micro. Desarrollar un programa en C que mida el tiempo (en milisegundos) que est en 1 un pin de un puerto del micro (cada vez que el pin vuelve a cero se debe esperar de nuevo a que se ponga a 1 para poder medir el tiempo en el que est a 1). Supuesto un sistema como el del laboratorio, mostrar el resultado del ancho del pulso en los diodos situados en la parte baja del puerto P2. Aportar varias soluciones y discutir las ventajas y desventajas de cada una. Suponiendo que el pulso lo genera un sistema electrnico (entrada por P7.4) se puede suponer que los flancos son limpios, no tienen rebotes. Los rebotes surgen cuando es un sistema mecnico el que provoca los flancos, como por ejemplo un interruptor (entrada por P2.8). En la siguiente figura se ilustra un flanco sin rebotes y con rebotes.

T
Con rebotes

Sin rebotes
Cuando se producen rebotes suelen durar un tiempo mximo T, que se puede determinar de forma experimental. En general, un mismo interruptor puede tener ms rebotes unas veces que otras, pero s que es cierto que se puede siempre encontrar un cota mxima de T. En todas las soluciones que se proponen a continuacin se debe apreciar que se usa un bucle infinito, como toda aplicacin que funciona en un micro. Soluciones ms detalladas que las que se muestran a continuacin en el contexto de un problema real estn en las secciones 14.2 y 14.3. En un principio se va a valorar la solucin ms sencilla, sin rebotes. Consiste en esperar a que la seal se ponga a uno, en ese momento se activa el Timer que se pone a medir tiempo, y justo cuando se detecta que la seal se vuelve a poner a 0 entonces se apaga el Timer y se actualizan los LED:

96

Sistemas Electrnicos Digitales.

DP2 = 0x00FF; DP7 = 0; inicializacion(T0I=7,T0=-20000); while (1){ while (P7.4==0) ; T0R = 1; while (P7.4==1); T0R=0; t=T0/20; P2=t; }

Este ejemplo tiene la pega de que slo puede medir el ancho de pulso de una lnea y sin rebotes. Desde el punto de vista de la programacin la solucin es poco modular, ya que mezcla el uso del Timer con el del puerto. Una solucin ms modular supone usar un sistema muestreado, donde el periodo de muestreo es un milisegundo. Se detecta cuando la seal se pone a uno y desde ese momento se muestrea el pulso cada segundo, incrementando un contador que lleva la cuenta de milisegundos que mide el ancho del pulso. En el momento que se detecta que la seal vuelve a 0, se actualizan los LED. DP2 = 0x00FF; DP7 = 0; while (1){ while (P7.4==0) ; contador = 0; while (P7.4==1){ retraso(1ms); contador++; } P2 = contador; }

97

Sistemas Electrnicos Digitales.

Este ejemplo tiene la pega de que slo puede medir el ancho de pulso de una lnea y sin rebotes. Si se quisiera aumentar la resolucin bastara con llamar a la funcin retraso con un tiempo inferior a 1ms. La siguiente solucin propuesta, aunque slo trata con una sola lnea, sera capaz de soportar tantas como se quisieran simplemente haciendo que las variables anterior, actual, cuenta y contador fueran vectores de tantos elementos como seales se quieren monitorizar. La idea es que el sistema es muestreado siempre y no slo cuando se detecta el flanco, como en el ejemplo anterior, de forma que cada ms se comprueba si hay un flanco en alguna de las seales que se monitoriza, en este ejemplo slo se mira la lnea P7.4. Adems se ha aadido una variable cuenta que indica si en una determinada lnea se ha detectado el pulso y por ello se est midiendo el ancho del mismo en un determinado instante. Por lo dems el primer if se encarga de detectar el flanco de subida de la seal y el segundo if se encarga de detectar el flanco de bajada.
DP2 = 0x00FF; DP7 = 0; anterior = P7.4; while (1){ retraso(1/8ms); actual = P7.4; if ((anterior != actual) && (actual == 1)) { cuenta = 1; } if ((anterior != actual) && (actual == 0)) { cuenta = 0; P2 = contador; contador = 0; } if(cuenta==1) contador++; anterior = actual; }

La nica pega de esta solucin es que no tiene en cuenta los rebotes. A continuacin se muestra una solucin que permite conectar a una determinada lnea una seal con rebotes. El tratamiento de rebotes es el ms simple que se puede hacer, que consiste en que una vez que se detecta un flanco, se espera un tiempo T (tiempo mximo que duran los rebotes) para comprobar si el flanco es de subida o de bajada. Por lo dems es igual que el ejemplo anterior.

98

Sistemas Electrnicos Digitales.

DP2 = 0x00FF; anterior = P2.8; while (1){ retraso(1/8ms); actual = P2.8; if (anterior != actual) retraso(100ms); actual = P2.8; if ((anterior != actual) && (actual == 1)) cuenta = 1; else if ((anterior != actual) && (actual == 0)) { cuenta = 0; P2 = contador; contador = 0; } if(cuenta==1) contador++; anterior = actual; }

La pega de esta solucin es que se est perdiendo un tiempo de 100ms que no permite monitorizar otras lneas y que adems es muy superior a lo que los rebotes pueden requerir. Por ello esta solucin no soporta monitorizar varias seales de forma simultnea. Por ltimo se presenta una solucin sin ninguna pega, que permite detectar el flanco justo cuando se terminan los rebotes con independencia de lo que duren. La clave est en suponer que el tiempo entre cambios de la seal cuando se producen rebotes es inferior a MAX (que en un sistema real vale con que sea del orden de 3 o 4), ya que se comprueba el flanco en el momento en el que no ha habido un cambio en la seal durante ms tiempo que MAX; es decir se ha estabilizado la seal. La variable que comprueba esto es filtrado. Cuando filtrado llega a 0 quiere decir que la seal se ha estabilizado y por lo tanto, es hora de determinar si el flanco es de subida o de bajada.

99

Sistemas Electrnicos Digitales.

DP2 = 0x00FF; DP7 = 0; anterior = P2.8; while (1){ retraso(1/8ms); actual = P2.8; if (anterior != actual) filtrado = MAX; else if (filtrado >0) filtrado--; if (filtrado==0){ filtrado = -1; if (actual==1) { cuenta = 1; } else { cuenta = 0; P2 = contador; contador = 0; } } if(cuenta==1) contador++; anterior = actual; }

13 Ejercicios
13.1 Acceso a memoria (15 min) Dado un sistema digital como la tarjeta que se usa en laboratorio, se pide realizar un programa que tenga las siguientes caractersticas:

Lee un dato de los interruptores conectados a la parte alta del puerto P2. Accede a la posicin de memoria Muestra el contenido de la posicin en los LEDs

100

Sistemas Electrnicos Digitales.

13.2 Encendido apagado de LED (10 min)

Hacer un programa que encienda o apague un LED conectado al pin P2.0 del microcontrolador C167, segn la posicin de un interruptor que se encuentra conectador en el pin P2.1.

101

Sistemas Electrnicos Digitales.

13.3 Volcado de memoria (20 min) Realizar una subrutina en ensamblador que haga una copia de la zona de memoria comprendida entre la direccin 200H y la 20FH hasta la zona de memoria comprendida entre la direccin 210H y 21FH. $nonsegmented S0 ini ini S0 DAT origen dest section code at 0H proc NEAR jmp main endp ends section data at 200H dsb 16 dsb 16

DAT SM main

ends section code at 300H proc NEAR .

copia:

fin: main SM

ret endp ends end

102

Sistemas Electrnicos Digitales.

13.4 Cuenta de pulsos (30 min)

Supuesto un sistema digital como el del laboratorio, se ha conectado al pin P7.4 del micro una seal que consiste en una secuencia de pulsos. Realizar un programa que muestre en los LEDs, conectados a la parte baja del puerto P2, la cuenta del nmero de pulsos que entran por el pin P7.4.

103

Sistemas Electrnicos Digitales.

13.5 Calculadora (40 min)

Escribir un programa en ensamblador de C167 que consiste en una calculadora que opera con datos de 4 bits (sin signo) y devuelve un resultado de 8 bits. El funcionamiento es el siguiente:

En los cuatro bits ms altos de P2 se proporciona el primer dato. Este dato se valida cuando la lnea P2.8 pasa de 0 a 1. A continuacin se introduce el segundo dato (siguiendo el mismo procedimiento que para el primer dato). Por ltimo se introduce la operacin (+: P2.12 = 1, -: P2.13=1). La operacin se valida de la misma forma que los datos. En caso de que no se haya seleccionado una operacin no se calcula el resultado. El proceso anterior se repite indefinidamente, mantenindose en la parte baja de P2 el resultado de la ltima operacin realizada.
$nonsegmented S0 ini ini S0 DAT result dato section code at 0H proc NEAR jmp main endp ends section data at 200H dsb 1 dsb 1

DAT SM main

ends section code at 300H proc NEAR

104

Sistemas Electrnicos Digitales.

main SM

endp ends end

105

Sistemas Electrnicos Digitales.

14 Ejercicios resueltos
14.1 LEDs e interruptores

Dado un sistema digital como la tarjeta que se usa en laboratorio, se pide realizar un programa en ensamblador que tenga las siguientes caractersticas:

Lee un dato de los interruptores conectados a la parte alta del puerto P2. Accede a la direccin de memoria indicada en los interruptores (8 bits ms altos de la direccin todos a 0). Analiza los ocho bits del dato almacenado en dicha direccin. Si hay siete bits a 1 y uno a 0, se indica en los LED ms bajos de P2 la posicin del bit que se encuentra a 0. Si todos los bits se encuentran a 1 se ilumina el LED conectado a P2.4. Si hay ms de un bit a 0 se encienden los cinco LED conectados a las lneas menos significativas de P2.

void main(void) { int dir; unsigned char dato, mask, i, n, pos; DP2 = 0xFF; while (1) { dir = (P2 & 0xFF00) >> 8; dato = *((unsigned char*)dir); for (i = 0, mask=0x01, n=0; i<8; i++, mask<<=1){ if (!(dato & mask)) { pos = i; n++; } } if (n==0) { P2 = ~0x10; } else if (n==1) {

106

Sistemas Electrnicos Digitales.

SM main

section code at 300H proc NEAR MOV DP2, #0xFF R0, P2 R0, #0xFF00 R0, #8 R4, #0 RL4, [R0] R1, #0 R2, #1 R3, #0 R1, #8 cc_ugt, fin_for R0, R4 R0, R2 cc_ne, next_for R5, R1 ; almacena la posicin del bit a 0 R3, #1 R1, #1 R2, #1 cc_uc, ini_for R3, #0 cc_ne, if_1 P2, #0xEF cc_uc, bucle R3, #1 cc_ne, if_n ; enciende LED P2.4 ; dato de la direccin de memoria ; contador de for ; mscara ; contador de nmero de bits a 0

bucle:

MOV AND SHR MOV MOVB MOV MOV MOV

ini_for:

CMP JMPR MOV AND JMPR MOV ADD

next_for:

ADD SHL JMPR

fin_for:

CMP JMPR MOV JMPR

if_1:

CMP JMPR

107

Sistemas Electrnicos Digitales.

14.2 Medida de ancho de pulso con rebotes (20 min)

Escribir un programa que mida el tiempo en segundos que un interruptor est a uno. Supuesto un sistema como el del laboratorio, el programa debe medir el tiempo (en segundos) que est en 1 el pin P2.8 del micro. Cada vez que el pin vuelva a cero se deber esperar de nuevo a que se ponga a 1 para poder medir el tiempo en el que est a 1. Mostrar el resultado del ancho de cada pulso en los diodos situados en la parte baja del puerto P2. Es necesario tener en cuenta los rebotes que producen los interruptores en la seal. NOTA: Los rebotes se podran eliminar con un filtro analgico paso bajo, pero tiene el inconveniente de que usa resistencias y condensadores con valores que dependen mucho de la temperatura. Es mucho ms robusto realizar un filtrado digital con un micro.

void main(void) { int anterior, actual; // estado anterior y actual de la seal int cuenta=0; // indica si hay que contar o no int mseg=0; // ancho del pulso int filtrado = -1; // contador que mide el tiempo en el mismo //estado de la seal cuando se trata de un rebote DP2 = 0xFF; anterior = P2 & 0x100; while (1){ retraso(0,-2500); // espera 1ms actual = P2 & 0x100; if (anterior != actual) filtrado = MAX; else if (filtrado >0) filtrado--; if (filtrado==0){ // si la seal es estable filtrado = -1; if (actual) { cuenta = 1; } else { cuenta = 0; P2 = ~(mseg/1000); mseg = 0; } } if(cuenta) mseg++; anterior = actual; } }

108

Sistemas Electrnicos Digitales.

SM main

bucle:

filtrado:

flanco:

cero:

seguir:

main SM

section code at 300H proc NEAR MOV DP2, #0xFF MOV R0, P2 AND R0, #0x100 MOV R2, #0 MOV R3, #0 MOV R4, #-2500 MOV R5, #0 MOV R6, #-1 MOV R1, R0 call retraso MOV R0, P2 AND R0, #0x100 CMP R0, R1 JMPR cc_eq, filtrado MOV R6, #MAX JMPR cc_uc, flanco CMP R6, #0 JMPR cc_sle, flanco SUB R6, #1 CMP R6, #0 JMPR cc_ne, seguir MOV R6, #-1 CMP R0, #0 JMPR cc_eq, cero MOV R2, #1 JMPR cc_uc, seguir MOV R2, #0 MOV MDL, R3 MOV R3, #1000 DIV R3 MOV R3, MDL CPL R3 MOV P2, R3 MOV R3, #0 CMP R2, #0 JMPR cc_eq, bucle ADD R3, #1 JMPR cc_uc, bucle endp ends end

; almacena el estado actual ; ; ; ; ; ; cuenta mseg cuenta inicial del timer preescalado filtrado anterior = actual

; actual = P2

109

Sistemas Electrnicos Digitales.

14.3 Medida de ancho de pulso (20 min)

Escribir en ensamblador un programa que mida el ancho de los pulsos de una seal digital. Para ello el programa debe medir el tiempo (en milisegundos) que est en 1 el pin P7.4 del micro. Cada vez que el pin vuelva a cero se deber esperar de nuevo a que se ponga a 1 para poder medir el tiempo en el que est a 1. Supuesto un sistema como el del laboratorio, mostrar el resultado del ancho de cada pulso en los diodos situados en la parte baja del puerto P2.

void main(void) { int anterior, actual; // estado anterior y actual de la seal int cuenta=0; // indica si hay que contar o no int contador =0; // ancho del pulso DP2 = 0xFF; DP7 = 0; anterior = P7 & 0x10; while (1){ retraso(0,-2500); // espera 1ms actual = P7 & 0x10; if ((anterior != actual) && actual) { cuenta = 1; } if ((anterior != actual) && !actual) { cuenta = 0; P2 = contador; contador = 0; } if(cuenta) contador++; anterior = actual; } }

110

Sistemas Electrnicos Digitales.

SM main

bucle:

cero:

seguir:

main SM

section code at 300H proc NEAR MOV DP2, #0xFF MOV DP7, #0 MOV R0, P7 AND R0, #0x10 MOV R2, #0 MOV R3, #0 MOV R4, #-2500 MOV R5, #0 MOV R1, R0 call retraso MOV R0, P7 AND R0, #0x10 CMP R0, R1 JMPR cc_eq, seguir CMP R0, #0 JMPR cc_eq, cero MOV R2, #1 JMPR cc_uc, seguir MOV R2, #0 CPL R3 MOV P2, R3 MOV R3, #0 CMP R2, #0 JMPR cc_eq, bucle ADD R3, #1 JMPR cc_uc, bucle endp ends end

; almacena el estado actual ; ; ; ; ; cuenta contador cuenta inicial del timer preescalado anterior = actual

; actual = P2

111

Sistemas Electrnicos Digitales.

15 Prctica 5: ejercicios en ensamblador, control de un servo

112

Sistemas Electrnicos Digitales.

113

Sistemas Electrnicos Digitales.

114

Sistemas Electrnicos Digitales.

Captulo 7 DRIVERS. EL CONVERTIDOR AD


1 Objetivos y conceptos a entender en este captulo

Entender qu es el convertidor AD y su funcionamiento. Entender la similitud en el manejo del conversor AD y el Timer. Se aconseja esquematizar ambos manejos, para una mayor claridad. Entender el concepto de driver

2 Concepto de driver
El driver es un conjunto de funciones que sirven para independizar al usuario de los detalles de manejo de un perifrico, de manera que un posible desarrollador que quiera usar el perifrico lo nico que tiene que hacer es usar el driver y de esa manera usa el perifrico sin tener que conocer los detalles de implementacin y manejo del mismo. Hay dos tipos de funciones dentro de un driver: Funciones de inicializacin: slo se llaman una vez y sirven para inicializar el driver y el perifrico. Funciones de manejo: se llaman tantas veces como se necesiten en la ejecucin de un programa. Estas funciones tienen que estar perfectamente documentadas indicando Qu hace?, Qu parmetros necesita?, Qu devuelve?. Esto es as ya que estas funciones son lo nico que tiene que conocer cualquier desarrollador que quiera usar al perifrico. Los drivers tienen las siguientes ventajas: El desarrollador no tiene que conocerse los detalles de implementacin del perifrico. Si el perifrico cambia su especificacin o versin, slo hace falta cambiar el driver, pero no las aplicaciones que usan el driver. Se puede reutilizar en cualquier aplicacin sin modificarlo.
2.1 Ejemplos de driver Es necesario hacer notar que para un mismo perifrico se pueden hacer varios drivers, que permiten independizar su manejo de los detalles de implementacin del mismo. Por ello, los ejemplos que se muestran a continuacin son una posible versin de drivers. Adems los drivers suelen estar en ficheros distintos del principal, ya que se usan como libreras, gracias a su gran posibilidad de reutilizacin.

115

Sistemas Electrnicos Digitales.

2.1.1 Driver sencillo del puerto P2 Aunque el manejo del puerto P2 es tan simple que no se necesita realizar un driver que ayude a su manejo, se presenta como primer ejemplo ya que ilustra el concepto como tal. El driver consta de dos funciones de manejo y una de inicializacin.
/* inicializacin del puerto dir: direccin de los pines del puerto*/ void ini_P2 (int dir){ DP2 = dir; } /* funcin que devuelve los datos del puerto P2*/ int get_P2(){ return(P2); } /* funcin modifica los datos del puerto P2*/ int set_P2(int datos){ P2 = datos; }

2.2 Driver del Timer 0 Un posible driver para el Timer 0 es la funcin retarso que se explic en ???, para un micro con un reloj de 20MHz.
/** funcin que espera miliseg milisegundos. El mximo tiempo de espera es 26ms*/ void retraso(int miliseg) { T01CON = 0; T0REL = -miliseg*2500; T0 = T0REL; T0IC = T0IC & 0x7f; // borra flag de rebose T01CON = T01CON | 0x40; // arranca timer while (!(T0IC & 0x80)); // bucle de espera de rebose T01CON = T01CON & 0xbf; // para el timer }

Este driver consta de una funcin de manejo y ninguna de inicializacin. Se podra hacer una funcin de inicializacin que indicara el reloj que tiene el micro y parametrizar la funcin de manejo en funcin del reloj.
2.3 Driver del convertidor AD Para ms informacin de qu es un conversor AD y cmo se maneja, leer la seccin 3 de este captulo. El driver que se muestra a continuacin configura al convertidor AD en modo 0.

116

Sistemas Electrnicos Digitales.

/* funcin que devuelve la conversin AD de un canal canal: canal objeto de la conversin (4 bits) devuelve: resultado en 10 bits */ int convad(int canal){ ADCON = canal & 0xF; ADCIR = 0; ADST=1; while(!ADCIR); return(ADDAT&0X03FF); }

Este driver consta de una funcin de manejo y ninguna de inicializacin. Un ejemplo de manejo de este driver se muestra en la seccin 3.4 de este captulo.

3 El convertidor analgico digital (AD)


En esta seccin se va a ver como funciona el convertidor analgico digital, que es un perifrico ms del micro. Para ms informacin sobre perifricos ver captulo 5. El convertidor AD se encarga de transformar una tensin analgica del exterior en una digital de 10 bits: 5V analgicos se corresponden con 0x3FF 0V analgicos se corresponden con 0x000 Para ello usa el puerto P5 del micro. Este puerto tiene 16 bits y se corresponde con 16 pines del micro que se usan como entradas donde se pueden conectar tensiones analgicas de 0 a 5V. Como existen 16 posibles entradas, se dice que el convertidor AD tiene 16 canales. En cada instante slo se puede hacer la conversin de un slo canal, pero ste es configurable por el usuario. El esquema del convertidor se muestra en la Figura 50. El mundo exterior, analgico, se conecta a cada pin del puerto P5. Estos pines llegan a un multiplexor que elige uno de los mismos para realizar la conversin. La eleccin se realiza programando los bits ADCH. Posteriormente se encuentra el convertidor AD que realiza la conversin a digital del canal seleccionado. El resultado de esta conversin lo deja en ADDAT (10 bits), e indica a travs del bit ADCIR que ha terminado de realizar la conversin. De esta manera un programa podra aprovechar la misma para alguna labor.

117

Sistemas Electrnicos Digitales.

ADCH ADCIR ADDAT


ANALOGICO
P5.0 (canal 0)
5V 0V

La tarea del perifrico finaliza cuando termina la conversin Los registros de programacin del mismo son: ADCON: es un registro (SFR) de configuracin de 8 bits. ADDAT: es un registro (SFR) de datos del perifrico de 16 bits que se encarga de almacenar el resultado de la conversin. ADCIC: es el registro (SFR) de 16 bits que indica cuando el convertidor termina su tarea, y sirve para configurar su control por interrupcin o polling. A continuacin se explica en detalle cada uno de estos registros.
3.1 Registro de control ADCON El registro de control consta de 8 bits, como se muestra a continuacin:

ADCH bits 0-3: estos 4 bits permiten seleccionar uno de los 16 canales posibles donde hacer la conversin. ADM bits 4-5: existen cuatro modos de funcionamiento del convertidor. Si ADM vale 0 se realiza una conversin en el canal seleccionado en ADCH. Existen otros modos que no se van a usar en este curso, que permiten hacer conversiones sucesivas en el mismo canal, una conversin secuencial en cada uno de los canales o incluso conversiones sucesivas siguiendo la secuencia de los canales.

Convertidor AD
8

MUX

P5.15 (canal 15)


5V 0V

Figura 50:Esquema del convertidor AD

6 ---

3 ADCH

ADBSY ADST

ADM

118

Sistemas Electrnicos Digitales.

ADST bit 7: es el encargado de controlar el arranque y paro del convertidor. Si se pone comienza la conversin. ADBSY bit 8: bit que indica que el conversor AD est ocupado haciendo una conversin.

3.2 Registro de datos ADDAT El registro de datos ADDAT tiene 16 bits y almacena el resultado en los 10 bits ms bajos y en el canal convertido (al que corresponde el resultado) en los 4 bits ms altos.
15 12 --9
RESULTADO

CANAL

3.3 Registro de control de interrupciones ADCIC Slo merece la pena resaltar que el registro ADCIC tiene un bit ADCIR, que indica que el conversor AD ha terminado su tarea; es decir, que tiene un resultado en ADDAT. Es equivalente al T0IR del Timer 0. 3.4 Ejemplo de programacin A continuacin se describe cmo se programa el convertidor AD. Es importante comparar este programa con el correspondiente del Timer en el captulo 5 seccin 3.6. El objetivo del programa es hacer una conversin en el pin P5.0 del micro y mostrar la parte alta del resultado en los 8 LEDs conectados a la parte baja del puerto P2.
#include <reg167.h> main() { ADCON = 0x00; ADCIR = 0; ADCON |= 0x80; DP2 = 0x00FF; P2 = 0xFFFF; // ADM=0, ADST=0, ADCH=0 // flag final = 0 // Start ADST=1

while (1) { while(!ADCIR) ; P2 = ~(ADDAT >> 2) ADCIR = 0; ADCON |= 0x80; } }

// // // //

bucle de espera coge 8 bits slo flag fin = 0 Start ADST=1

119

Sistemas Electrnicos Digitales.

Es necesario darse cuenta de que este programa sera ms modular y entendible si se usase el driver descrito en la seccin 2.3 de este captulo:
#include <reg167.h> #include ad.h // lugar donde est el driver main() { int resultado; DP2 = 0x00FF; P2 = 0xFFFF; while (1) { resultado = convad(0); P2 = ~(resultado >> 2) } }

// coge 8 bits slo

Como se puede ver es necesario incluir el driver (#include "ad.h"), para decirle al compilador que la funcin convad existe.

120

Sistemas Electrnicos Digitales.

Captulo 8 PROGRAMACIN EN C PARA MICROS


1 Objetivos y conceptos a entender en este captulo
El objetivo de este captulo es resumir los conceptos de programacin en C que se usan en programacin de microprocesadores. Se supone que el lector ha recibido nociones bsicas de programacin en C antes de leer este captulo. Es muy importante prestar atencin y esquematizar la relacin que existe entre el C y el ensamblador segn se va leyendo el captulo.

2 Tipos de datos para el C167


2.1 Nmeros enteros El C167 admite 3 tipos de enteros que se diferencian en el tamao que tienen. Si se habla de tipos de datos con signo: int (16 bits): desde -32768 a 32767 char (8 bits): desde -128 a 127 long (32 bits): desde -231 a 231-1

En caso de que no tengan signo: unsigned int (16 bits): desde 0 a 65535 unsigned char (8 bits): desde 0 a 255 unsigned long (32 bits): desde 0 a 232-1 Aunque la codificacin interna de los nmeros en memoria fsica siempre se hace con ceros y unos, ya que el micro no entiende otra cosa, desde el punto de vista de la programacin se soportan diferentes bases de codificacin para expresar un nmero: En base 16, hexadecimal, por ejemplo: char i = 0xff; equivale al -1 decimal. En base 10, decimal, por ejemplo: char i = -1; La promocin de nmeros enteros es directa cuando se trata de pasar de un nmero de menor tamao a uno de mayor tamao:

121

Sistemas Electrnicos Digitales.

unsigned int i; unsigned char c = 0xff; i = c;

Figura 51: Promocin de 8 bits sin signo a 16 bits. El resultado en i = 0x00FF

int i; char c = 0xff; i = c;

Figura 52: Promocin de 8 bits con signo a 16 bits. El resultado en i=0xFFFF

La promocin de nmeros enteros en ensamblador tiene instrucciones especiales, como lo son MOVBZ (para la Figura 51) y MOVBS (para la Figura 52). Los operadores ms usados con nmero enteros son:

Operador unitarios : cambia de signo al operando. As en: i = -c; el operador toma el valor de la variable c y le cambia el signo. Por tanto si c vale 17, al finalizar la ejecucin de la instruccin, la variable i contendr el valor -17. Operador unitario ++ y --: dado que una de las aplicaciones principales de los nmeros enteros en los programas es la realizacin de contadores, que usualmente se incrementan o decrementan de uno en uno, los diseadores de C vieron aconsejable definir unos operadores para este tipo de operaciones. El operador incremento se representa aadiendo a la variable que se desee incrementar dos smbolos +. La sintaxis es por tanto: NombreVariable++. As por ejemplo la lnea: Contador++; sumara uno a la variable Contador. El operador decremento es idntico al de incremento, sin mas que sustituir los + por -. Siguiendo el ejemplo anterior: Contador-; Le restara uno a la variable Contador. Operadores binarios: +, -, *: suma, resta y multiplicacin respectivamente. Operador binario / (op1/op2): da como resultado la parte entera de dividir op1 entre op2; es decir, el cociente. As por ejemplo 3/2 da como resultado 1, lo que puede parecer malo, pero an hay cosas peores como 1/2, que da como resultado 0, lo cual tiene un gran peligro en expresiones como: resultado = (1/2)*3; Operador binario % (op1%op2): devuelve el resto de la divisin entre op1 y op2. El operador resto se representa mediante el smbolo %. As por ejemplo 4%2 da como resultado 0 y 1%2 da como resultado 1. Una utilidad de este operador es la de

122

Sistemas Electrnicos Digitales.

4580169

averiguar si un determinado nmero es mltiplo de otro; por ejemplo el nmero es mltiplo de 33 porque 4580169%33 da cero.

NOTA: en C se pueden mezclar asignaciones y operaciones entre dos operandos en un slo operador, situando el = entre los dos operandos de una operacin; por ejemplo:
op1 += op2; // es equivalente a op1 = op1 + op2; op1 %= op2; // es equivalente a op1 = op1 % op2;

2.2 Nmeros reales Al igual que con los enteros, el C167 admite 3 tipos de nmero reales dependiendo de la precisin que se requiera: float (16 bits) double (32 bits) long double (64 bits) 2.3 Variables lgicas En C no existen las variables lgicas. Cualquier variable entera se puede usar como variable lgica, de forma que si su valor es 0 entonces equivale a un FALSE y si es distinto de 0 entonces equivale a un TRUE. Por ejemplo:
int i = 5; int suma; while (i) { suma = suma + i; -- i; }
Figura 53: Ejemplo de variable lgica. Sale del bucle cuando i es igual a cero

Los operadores usados con variables lgicas son los siguientes: &&: es un AND lgico. Ojo no trabaja bit a bit (no confundir con &)
c = a && b

Si a Si a

= 1 = 0

yb yb

= 14 = 32

c c

es TRUE es FALSE

Ya que a y b son distintos de cero Ya que a es igual a cero

Tabla 1: Ejemplo de AND lgico

123

Sistemas Electrnicos Digitales.

|| : es un OR lgico. Ojo no trabaja bit a bit (no confundir con | )

c = a || b

Si a Si a

= 0

= 32

yb = 0 yb = 0

c c

es FALSE es TRUE

Ya que a y b son cero Ya que a es distinto de cero

Tabla 2: Ejemplo de OR lgico

c = ! b

! : es un NOT lgico. No confundir con ~.

Si b = 14 Si b = 0

es FALSE c es TRUE
c

Ya que b es distinto de cero Ya que b es igual a cero

Tabla 3: Ejemplo de NOT lgico

Las posibles condiciones lgicas son: ==: comparacin de igualdad. Ojo no es lo mismo que = (asignacin). No debe confundirse el operador de asignacin = con el operador relacional de igualdad == que no modifica el valor de las variables. Es decir, es totalmente distinto escribir i=7, que introduce el valor 7 en la variable i independientemente del valor que tuviese sta, que escribir i==7, que compara el valor de la variable i con la constante 7. != : comparacin de desigualdad >, >= : comparacin mayor que y mayor igual que respectivamente. <, <= : comparacin menor que y menor o igual que respectivamente.

c = (a > b) && (a != d)

Si a Si a

= 0, d = 0 = 10, d =

yb = 1 0yb = 1

es FALSE c es TRUE
c

Ya que a y d son iguales Ya que a y d son distintos y mayor que b

3 Operadores bit a bit


Cuando se programa un micro es muy habitual realizar operaciones a nivel de bit. En C existen los siguientes operandos que trabajan a nivel de bit: & (op1&op2): realiza un AND bit a bit entre el operando op1 y op2. El equivalente en ensamblador es AND op1,op2. | (op1|op2): realiza un OR bit a bit entre el operando op1 y op2. El equivalente en ensamblador es OR op1,op2.

124

Sistemas Electrnicos Digitales.

>> (op1>>op2): desplaza op2 bits de op1 hacia la derecha. El equivalente ensamblador es SHR op1,op2. << (op1<<op2): desplaza op2 bits de op1 hacia la izquierda. El equivalente ensamblador es SHL op1,op2. ^ (op1^op2): realiza un XOR bit a bit entre el operando op1 y op2. El equivalente ensamblador es XOR op1,op2. ~ (~op1): realiza un complemento a uno del operando op1. El equivalente ensamblador es CPL op1.

en en en en

a a a a

= = = =

P2; P2; P2; P2;

a a a a

&= 0x000F; |= 0x000F; >>= 4; <<= 4;

// // // //

Cuanto Cuanto Cuanto Cuanto

vale vale vale vale

a? a? a? a?

Figura 54: Si P2 = 0xFA45, por orden de aparicin a=0x0005, a=0xFA4F, a=0x0FA4 y a=0xA450

4 Instrucciones de control
Es habitual que los programas realicen tareas diferentes en funcin del valor de determinadas variables. La instruccin if permite definir bloques de cdigo que no son de ejecucin obligatoria y por lo tanto son bloques de instrucciones que el programa se puede saltar. Esta decisin depende del valor de una condicin lgica, que a su vez suele depender del valor que adquieran determinadas variables del programa. Tambin es posible definir dos bloques de instrucciones alternativos, de manera que slo se ejecute uno u otro en funcin del resultado de la condicin lgica. Existen dos formatos bsicos para definir instrucciones que se ejecutan de manera condicional. Un bloque que se puede ejecutar o no (if normal), y dos bloques que se ejecutan uno u otro (bloque if-else). El formato en cada caso es el siguiente:

if (condicin) { ... }

if (condicin) { // si se cumple a condicin ... } else { // si no se cumple la condicin ...

125

Sistemas Electrnicos Digitales.

A continuacin se describen situaciones que se deben tener en cuenta cuando se manejan este tipo de condiciones:
if(a == b) { if(a = b) {

Figura 55: Igualdad versus asignacin. En el caso de la igualdad la condicin se cumple si a es igual a b. En el caso de la asignacin la condicin se cumple si b es distinto de 0.

if(a && b) {

if(a & b) {

Figura 56: AND lgico versus AND bit a bit. En el caso del AND lgico la condicin se cumple si a y b son distintos de cero. En el caso del AND bit a bit la condicin puede no cumplirse aunque a y b sean distintos de cero, por ejemplo si a =0xF0F0 y b = 0x0F0F.

5 Bucles
Es habitual que los programas realicen tareas repetitivas o iteraciones (repetir las mismas operaciones pero cambiando ligeramente los datos). Esto no supone ningn problema para el programador novato, que despus de aprender a cortar y pegar puede repetir varias veces el mismo cdigo, pero dentro de un lmite. Se llama bucle de un programa a un conjunto de instrucciones que se repite varias veces. El bucle for queda definido por tres argumentos: sentencia inicial, condicin de salida y sentencia final de bucle. Estos argumentos se escriben separados por punto y coma y no por coma como en las funciones.
for(sentencia inicial ; condicin ; sentencia final ){ ... }

Como puede apreciarse, la variable i controla el nmero de veces que se ejecuta el bucle. Por ello a este tipo de variables se les denomina variables de control. Es muy importante hacer un buen uso del sangrado para facilitar la lectura del programa. La sentencia inicial se ejecuta antes de entrar en el bucle y la condicin siempre se comprueba antes de cada iteracin. Por lo tanto, puede ocurrir que nunca se llegue a entrar en el bucle si desde el principio no se cumple la condicin. Por ejemplo for(i=0; i<-3;

126

Sistemas Electrnicos Digitales.

i++) nunca entra en el bucle. La sentencia final se ejecuta al terminar cada iteracin. Por lo tanto si no se entra en el bucle esta sentencia no se ejecuta nunca.

Si no se conoce a priori el nmero de iteraciones que deseamos realizar en un bucle se debe utilizar el bucle while. Este tipo de bucles repiten una serie de instrucciones mientras una condicin es cierta. La sintaxis es:
while(condicin){ ... }

El funcionamiento del bucle es como sigue: en primer lugar se evala la expresin condicin. Si el resultado es falso no se ejecutar ninguna de las instrucciones del bucle, el cual est delimitado, al igual que en el caso del bucle for por dos llaves ({ y }). Por tanto la ejecucin continuar despus de la llave }. Si por el contrario la condicin es cierta, se ejecutarn todas las instrucciones del bucle. Despus de ejecutar la ltima instruccin del bucle se vuelve a comprobar la condicin y al igual que al principio se terminar el bucle si es falsa o se realizar otra iteracin si es cierta, y as sucesivamente.
do{ ... }while(condicin);

En este caso se ejecutarn las instrucciones y despus se evaluar la condicin. Si es falsa se contina con la instruccin que sigue al bucle y si es cierta se vuelve a repetir el bucle, se evala la condicin y as sucesivamente.

6 Vectores
Un vector es un conjunto de datos del mismo tipo que se almacenan en el ordenador en posiciones de memoria consecutivas y a los cuales se accede mediante un mismo nombre de variable. La caracterstica fundamental es que todos los datos de un vector son del mismo tipo, por ejemplo todos son int o todos son double. La definicin de vectores es parecida a la definicin de variables, salvo que se debe especificar el tamao del vector entre corchetes [ ]. Por ejemplo, para definir un vector llamado vec que pueda almacenar 10 valores tipo double se escribe:
double vec[10];

La manera de acceder a los valores de estas variables es ahora diferente, ya que de todos los elementos que componen el vector es necesario especificar cul queremos modificar. Esta especificacin se realiza indicando entre corchetes el nmero de orden del elemento, teniendo en cuenta que la numeracin de los elementos siempre empieza en cero.
vec[0]=54.23; vec=4.5; /*Primer elemento del vector*/ /* ERROR */

127

Sistemas Electrnicos Digitales.

vec[10]=98.5;

/* ERROR */

La segunda asignacin no es correcta porque vec no es una variable tipo double sino un vector y por lo tanto todas las asignaciones deben indicar el nmero de orden del elemento al que queremos acceder. El vector vec del ejemplo tiene tamao 10 porque fue declarado como double vec[10] esto significa que almacena 10 elementos. Los 10 elementos se numeran desde el 0 hasta el 9 y por lo tanto, el elemento 10 no existe y la tercera asignacin tampoco es vlida. Es importante destacar que el compilador no dara error en el ltimo caso ya que no comprueba los rangos de los vectores. Este tipo de asignacin hace que el valor 98.5 se escriba fuera de la zona de memoria correspondiente al vector vec, y probablemente machaca los valores de otras variables del programa. Hay que prestar especial atencin ya que slo en algunos casos aparece un error de ejecucin (generalmente cuando el ndice del vector es muy grande de forma que se accede a zonas en las que no hay memora) pero en otras ocasiones no aparece ningn mensaje de error y el programa simplemente funciona mal (OJO: es muy difcil de detectar!!). Como se puede sospechar, la mejor manera de trabajar con vectores es utilizando bucles for, para iterar en el mismo y o bien inicializar sus valores o bien obtener sus datos que almacena. Resulta muy til definir los tamaos de vectores y matrices en funcin de parmetros, ya que luego se pueden modificar fcilmente sin tener que revisar todo el programa. Estos parmetros se definen con la instruccin #define (semejante a equ en ensamblador) que es una directiva del preprocesador, al igual que #include. Existen dos maneras de inicializar vectores: en las instrucciones del programa o en la propia definicin:
#define MAX 5 main() { int Iniciado[]={1,5,8,4,3}; int SinIni[MAX]; int i; for (i=0; i<MAX; i++) SinIni[i] = Iniciado[i]; }
Figura 57: Ejemplo de inicializacin en C de un vector en la propia definicin (Iniciado) o por cdigo (SinIni)

128

Sistemas Electrnicos Digitales.

MAX D100 Iniciado SinIni D100 ej ej1

equ

section data at 200H dw 1,5,8,4,3 dsw 5 ends section code at 300H proc NEAR MOV R1,#SinIni MOV R0,#Iniciado MOV R3,#0 ; Inicializa el vector CMP R3,#MAX JMPR cc_uge, fin MOV [R1+],[R0+] ADD R3, #1 JMPR cc_uc, ini NOP endp ends

;contador

ini:

fin: ej1 ej

Figura 58: Ejemplo de inicializacin en ensamblador de un vector en la propia definicin (Iniciado) o por cdigo (SinIni)

7 Punteros
Los punteros son un tipo de variable un poco especial, ya que en lugar de almacenar valores (como las variables de tipo int o de tipo double) los punteros almacenan direcciones de memoria. Utilizando variables normales slo pueden modificarse valores, mientras que utilizando punteros pueden manipularse direcciones de memoria o valores. Los punteros se definen igual que las variables normales, pero con un asterisco (*) delante del nombre de la variable. Por ejemplo:
int a; int *pa;

En este ejemplo la variable a es de tipo entero y puede almacenar valores como 123 o -24, mientras que la variable p es un puntero y almacena direcciones de memoria. Aunque todos

129

Sistemas Electrnicos Digitales.

los punteros almacenan direcciones de memoria, existen varios tipos de puntero dependiendo de la definicin que se haga. Por ejemplo:
int *pti; char *ptc;

Tanto pti como ptc son punteros y almacenan direcciones de memoria, por lo tanto almacenan datos del mismo tipo y ocupan la misma cantidad de memoria, es decir, 24 bits (aunque si se trabaja en el modelo corto de memoria; es decir, slo se trabaja en un segmento, como es el caso del laboratorio el tamao utilizado es 16 bits). La nica diferencia es que el dato almacenado en la direccin de memoria contenida en el puntero pti es un entero, mientras que el dato almacenado en la direccin de memoria contenida en ptc es un char. Se dice por lo tanto que pti apunta a un entero (puntero a entero) mientras que ptc apunta a un char (puntero a char). En la Figura 59 aparece un ejemplo en el que pti apunta a una direccin de memoria (0x200) donde se encuentra almacenado el valor entero 5, y ptc apunta a otra direccin de memoria (0x202) donde se encuentra almacenado el valor 0x10.
Direccin de memoria 24 bits (Hex) 00 0200 00 0201 00 0202 00 0203 00 0204 00 0205 00 0206 00 0207 00 0208 00 0209 00 020A 00 020B Variable en C Valor 8 bits

i c

pti

ptc

05 00 10 02 00 02 00 00 02 02 00 00

Figura 59

En ensamblador se puede trabajar con punteros usando el direccionamiento indirecto. De forma que los cuatro primeros registros de propsito general pueden almacenar direcciones de memoria.
7.1 El operador & El operador & se utiliza para obtener la direccin de memoria de cualquier variable del programa. Si nuestro programa tiene una variable entera que se llama i, entonces podemos obtener la direccin de memoria que el compilador ha preparado para almacenar su valor escribiendo &i.

130

Sistemas Electrnicos Digitales.

int i; int *pti; i=78; pti=&i;

/* /* /* /*

variable entera */ puntero a entero */ inicializo i */ pti apunta a i */

Al aplicar el operador & a la variable i no se obtiene el valor entero almacenado en ella sino la direccin de memoria en donde se encuentra dicho valor. La direccin de la variable i (&i) se almacena en un puntero a entero, porque es una direccin de memoria donde se halla un entero. El compilador dar un aviso si se intenta realizar una asignacin en la que no corresponden los tipos, por ejemplo al asignar &i a un puntero tipo char *, ya que &i devuelve un puntero a int. Este tipo de comprobaciones del compilador evita muchos errores de programacin. Por tanto, hay que estar muy atento a los mensajes del compilador. Asignaciones entre dos punteros tambin son vlidas siempre que los dos punteros sean del mismo tipo. En ensamblador se usa el inmediato # para acceder a la direccin de memoria de un variable, ver Figura 60.
7.2 El operador * El operador unitario *, llamado operador de indireccin, permite acceder al valor por medio del puntero. int i; int *pti; pti=&i; *pti=78; /* /* /* /* variable entera */ puntero a entero */ pti apunta a i */ equivale a hacer i=78; */

La asignacin *pti=78 introduce el valor entero 78 en la posicin de memoria apuntada por el puntero pti. Como previamente se ha almacenado en pti la direccin de memoria de la variable i, la asignacin equivale a dar el valor 78 directamente a la variable i. Es decir, tras la asignacin pti=&i disponemos de dos maneras de manipular los valores enteros almacenados en la variable i: directamente mediante i,o indirectamente mediante el puntero pti. En ensamblador se usan los corchetes [ ] para acceder al valor que apunta el puntero. En la Figura 60 se muestra la equivalencia entre C y ensamblador en el manejo de punteros. Es importante hacer notar que en C es equivalente escribir *(pti+i) a escribir pti[i], por definicin; ya que ambos acceden al elemento que se encuentra desplazado i unidades de la direccin de memoria que representa el puntero pti.

131

Sistemas Electrnicos Digitales.

D100 i1 i2 D100 ej ej1

section data at 200H dsw 1 dsw 1 ends section proc MOV MOV MOV MOV MOV endp ends code at 300H NEAR R0,#5 ; R0 registro auxiliar i1,R0 R1,#i1 ; R1 puntero a i1 R0,[R1] ; equivale a * en C i2,R0

ej1 ej main() {

int i1,i2; int *pi; i1 = 5; pi = &i1; i2 = *pi; }


Figura 60: Equivalencia entre C y ensamblador en el manejo de punteros

// i2?

7.3 Operaciones con punteros Una vez entendido lo que es un puntero veamos las operaciones que pueden realizarse con estas variables tan especiales. En primer lugar ya se ha visto que admiten la operacin de asignacin para hacer que apunten a un lugar coherente con su tipo. Pero tambin admite operaciones de suma y diferencia que deben entenderse como cambios en la direccin a la que apunta el puntero. Es decir, si tenemos un puntero a entero que almacena una determinada direccin de memoria y le sumamos una cantidad, entonces cambiara la direccin de memoria y el puntero quedara apuntando a otro sitio. Es importante diferenciar claramente las dos formas de manipular el puntero: *pti+=8; pti+=8;

La primera lnea suma 8 al entero al que apunta pti y por lo tanto el puntero sigue apuntando al mismo sitio. La segunda lnea incrementa en 8 el puntero, por lo tanto ste pasa a apuntar a otro sitio. El operador ++ se utiliza mucho en programacin de micros y permite hacer que el puntero pase a apuntar al dato que ocupa la siguiente posicin de memoria. La aplicacin fundamental

132

Sistemas Electrnicos Digitales.

de esta operacin es recorrer posiciones de memoria consecutivas. Adems de valer para fisgonear la memoria del microcontrolador, esto se utiliza para recorrer vectores (cuyos datos siempre se almacenan en posiciones de memoria consecutivas). Cada posicin de memoria del micro almacena un byte. Dado que cada tipo de dato ocupa un nmero de bytes diferente (un char s ocupan 1 byte, un int ocupa 2 bytes), los punteros de cualquier tipo siempre apuntan al primer byte de la codificacin de cada dato. Cuando se accede al dato mediante el operador *, el compilador se encarga de acceder a los bytes necesarios a partir de la direccin almacenada en el puntero. En el caso de punteros a char slo se accede al byte almacenado en la direccin de memoria del puntero, mientras que el caso de punteros a int se accede a la posicin de memoria indicada en el puntero y al siguiente byte. Todo este mecanismo ocurre de manera automtica y el programador slo debe preocuparse de definir punteros a char cuando quiere trabajar con valores char o punteros a int cuando quiere trabajar con valores int. Tambin para facilitar las cosas, la operacin de sumar 1 a un puntero hace que su direccin se incremente la cantidad necesaria para pasar a apuntar al siguiente dato del mismo tipo. Es decir slo en el caso de variables que ocupan 1 byte en memoria (variables char) la operacin de incremento aumenta en 1 la direccin de memoria, en los dems casos la aumenta ms. Lo que hay que recordar es que siempre se incrementa un dato completo y no hace falta recordar cunto ocupa cada dato en la memoria. Por ejemplo, si ptc es un puntero a char que vale 0x202, la operacin ptc++ har que pase a valer 0x203. Por otro lado si pti es un puntero a int que vale 0x200, la operacin pti++ har que pase a valer 0x202.

La equivalencia con ensamblador es la siguiente:


MOV R1, [R2+] MOV R1, [-R2] i = *pti++ i = *--pti

En la Figura 61 y Figura 62 se muestra un ejemplo de esta equivalencia.

133

Sistemas Electrnicos Digitales.

MAX D100 VWord VByte D100 ej ej1

equ

section data at 200H dsw 5 dsb 5 ends section proc MOV MOV MOV MOV MOV CMP JMPR MOVB ADD ADD ADD JMPR NOP endp ends code at 300H NEAR R0,#VWord; R0 R1,#VByte; R1 R2,#0 ; R2 R3,#0 ; R3 R4,#0 ; R4 R3,#MAX cc_uge, fin RL4,[R1+] R2, R4 R2, [R0+] R3, #1 cc_uc, suma

puntero puntero es la suma es i var temporal

suma:

fin: ej1 ej

Figura 61: Ejemplo en ensamblador que suma dos vectores de 5 datos

#define MAX 5 main() { int VWord[MAX]; char VByte[MAX]; int *pti; char *ptc; int i; suma; suma = 0; pti = VWord; ptc = VByte; for (i=0; i<MAX; i++){ suma += *pti++; suma += *ptc++; } }
Figura 62: Ejemplo en C de dos vectores que suma 2 vectores de 5 datos

134

Sistemas Electrnicos Digitales.

Si se quiere incrementar un puntero en ms de una unidad, se puede usar un desplazamiento usando el operador +:
int vi[10]; int *pti, i; pti=vi; i = *(pti+5); /* vector de enteros */ /* puntero a entero */ /* pti apunta a vi */ /*coge el dato 5 enteros adelante */

El equivalente en ensamblador es:


MOV R1, [R0+#10] MOVB RL1, [R0+#5] i = *(pti+5); // en caso de int c = *(ptc+5); // en caso de char

8 Funciones
Una tcnica muy empleada en la resolucin de problemas complejos es la conocida como divide y vencers. La manera ms elegante de construir un programa es dividir la tarea a realizar en otras tareas ms simples. Si estas tareas ms simples no son an lo suficientemente sencillas, se vuelven a dividir, procediendo as hasta que cada tarea sea lo suficientemente simple como para resolverse con unas cuantas lneas de cdigo. A esta metodologa de diseo se le conoce como diseo de arriba-abajo (top-down). Otras ventajas de la divisin de un problema en mdulos claramente definidos es que facilita el trabajo en equipo y permite reutilizar mdulos creados con anterioridad si estos se han diseado de una manera generalista. En C este tipo de mdulos se llaman funciones, que consta de unos argumentos de entrada, una salida, y un conjunto de instrucciones que definen su comportamiento. Esto permite aislar la funcin del resto del programa, ya que la funcin puede considerarse como un programa aparte que toma sus argumentos de entrada, realiza una serie de operaciones con ellos y genera una salida; todo ello sin interactuar con el resto del programa. Esta metodologa de diseo presenta numerosas ventajas, entre las que cabe destacar: La complejidad de cada tarea es mucho menor que la de todo el programa, siendo abordable. Se puede repartir el trabajo entre varios programadores, encargndose cada uno de ellos de una o varias funciones de las que se compone el programa. Al ir construyendo el programa por mdulos se pueden ir probando estos mdulos conforme se van terminando, sin necesidad de esperar a que se termine el programa completo. Esto hace que, tanto la prueba de los mdulos, como la correccin de los errores cometidos en ellos, sea mucho ms fcil al tener que abarcar solamente unas cuantas lneas de cdigo, en lugar de las miles que tendr el programa completo. Una vez construido el programa, tambin el uso de funciones permite depurar los problemas que aparezcan ms fcilmente, pues una vez identificada la funcin que falla, slo hay que buscar el fallo dentro de dicha funcin y no por todo el programa. Si se realizan lo suficientemente generales, las tareas se puede reutilizar en otros programas. As por ejemplo, si en un programa es necesario convertir una cadena a

135

Sistemas Electrnicos Digitales.

maysculas y realizamos una funcin que realice dicha tarea, esta funcin se podr usar en otros programas sin ningn cambio. Si por el contrario la tarea de convertir a maysculas se incrusta dentro del programa, su reutilizacin ser muchsimo ms difcil. En resumen la norma bsica es <<Hacer funciones cortas y que hagan una sola cosa!! (fciles de desarrollar y de depurar, reutilizables)>> En C las funciones deben ser declaradas (en los ficheros cabecera *.h) y definidas. La diferencia entre declaracin y definicin consiste en que siempre que se habla de definicin implica que existe una reserva de memoria para aquello que se define. En cambio en un declaracin no. Un ejemplo de definicin de funcin es el cdigo propiamente dicho:

int power(int base, int n) { int i, p; p = 1; for (i=1; i<=n; i++) p = p * base; return p; }
Figura 63: Ejemplo de definicin de funcin en C

En la Figura 63 se puede observar como una funcin tiene unos parmetros que entran en la funcin y se usan como variables locales; es decir, si se modifica su valor en la funcin el programa principal que llam a la funcin no ve afectados sus valores. Adems la funcin puede devolver un valor en la instruccin return. En la Figura 64 se muestra el prototipo o declaracin de la funcin anterior. El prototipo indica al compilador el nmero y tipo de parmetros de entrada a una funcin y el tipo de variable de salida de la misma.
int power(int base, int n);
Figura 64: Ejemplo de declaracin de funcin en C

Un ejemplo de manejo de la definicin y declaracin de funcin se muestra en la Figura 65.

136

Sistemas Electrnicos Digitales.

int power(int base, int n); main () { int i, a, b; a = 2; b =10; i = power(b,a); } int power(int base, int n) { int i, p; p = 1; for (i=1; i<=n; i++) p = p * base; return p; }
Figura 65: Ejemplo de uso de funcin

En el ejemplo se puede apreciar que el valor de las variables de la funcin main a y b no son alterados por la llamada a la funcin power. Esto se debe a que en C SIEMPRE se pasan los parmetros por valor a las funciones; es decir, se hace una copia cada variable y se pasa la propia copia a la funcin. Es necesario declarar la funcin power antes de la definicin de main, para que cuando el compilador empiece a compilar (que lo hace de forma secuencial y de arriba hacia abajo) el cdigo sepa como se ha definido power y compruebe la correcta sintaxis de la misma. En caso contrario el compilador indicar que la funcin no se ha declarado.
8.1 Variables globales y locales Las variables locales son las que slo se pueden acceder dentro de una misma funcin, que se componen por las variables pasadas por parmetro y las definidas en la propia funcin. La vida de una variable local se termina en el momento en el que el programa sale de la funcin. Por otro lado, las variables globales son las que se encuentra fuera de toda funcin y se pueden usar desde cualquier lugar del cdigo. La vida de una variable global se corresponde con el tiempo de ejecucin del programa. El buen estilo de programacin recomienda usar lo menos posible las variables globales ya que se pueden modificar desde cualquier lugar del cdigo y por tanto son muy complicadas de depurar. 8.2 Paso de parmetros por "referencia" Como se ha comentado con anterioridad en C siempre se pasan a las funciones los parmetros por valor. Por otro lado, dado que una funcin slo puede devolver un valor, se restringen mucho las posibilidades de hacer funciones complejas que puedan devolver ms de un valor. Para poder salvar este escollo, existe un truco que permite pasar los parmetros por "referencia" usando punteros. No es un paso por referencia estrictamente hablando, sino que

137

Sistemas Electrnicos Digitales.

es un paso por valor de un puntero, que equivale a un paso por referencia, ya que aunque no se puede cambiar la direccin del puntero (ya que se ha pasado por valor y por lo tanto se pasa una copia), se puede modificar el contenido de la direccin de memoria a la que apunta el puntero con el operador unario * (derreferenciacin). En la Figura 66 se muestra a la izquierda un ejemplo de paso de parmetros por valor, en donde a y b quedan inalterados porque la funcin swap (que pretende cambiar el valor de la variable x por el de la y) est trabajando con una copia de las variables a y b. En cambio en la derecha se muestra un ejemplo en el que se pasa por valor los punteros a las variables a y b, y que aunque se trabaja con las copias de dichos punteros, se puede modificar el valor del contenido de los mismos, resultando en que a y b intercambian su valor despus de la llamada a la funcin swap.
void swap(int x, int y) { int temp; temp = x; x = y; y = temp; } main () { int a=5, b=6; swap(a,b); } void swap(int *px, int *py) { int temp; temp = *px; *px = *py; *py = temp; } main () { int a=5, b=6; swap(&a,&b); }

Figura 66: Ejemplo de paso por valor y paso por "referencia" en C

8.3 Paso de vectores como parmetros Los vectores se pasan SIEMPRE por "referencia"; es decir, cualquier funcin puede modificar el valor de cada componente de un vector. Esto es as ya que para pasar un vector por valor hay que usar su nombre, que no es ms que una constante que indica la direccin de memoria del primer elemento del vector, ver ejemplo en Figura 67.

138

Sistemas Electrnicos Digitales.

#define MAX 5 int max(int* v, int tam); main() { int vector[]={1,5,8,4,3}; int maximo; maximo = max(vector, MAX); } /* funcin que calcula el mximo de un vector */ int max(int* v, int tam){ int maximo=0; i=0; for (i=0; i<tam; i++){ if (v[i] > maximo) maximo = vector[i]; } return (maximo); }
Figura 67: Ejemplo de paso por parmetro de un vector

Por otro lado, si lo que se quiere es devolver como resultado de una funcin un vector es imprescindible hacerlo a travs de un parmetro de la misma o no a travs de la instruccin return. En la Figura 68 se muestra el tpico manejo errneo de un vector, ya que es una variable local que desaparece al terminar la funcin y por lo tanto aunque el programa principal recupere la direccin de memoria devuelta, el vector se encuentra vaco. Por otro lado, en la Figura 69, Figura 70 y Figura 71 se muestran buenas prcticas de programacin, en donde se reserva la memoria para el vector en el lugar que va a ser utilizado.
#define MAX 50 main() { int *pti; pti = get_vector_discreto(1, 4); } /* funcin que devuelve un vector con los valores enteros comprendidos entre min y max*/ int* get_vector_discreto(int min, int max){ int i, vector[MAX]; for (i=min; i<max; i++) vector[i] = i; return (vector); }
Figura 68: Manejo errneo de vuelta de un vector por una funcin

139

Sistemas Electrnicos Digitales.

#define MAX 50 main() { int vector[MAX]; get_vector_discreto(1, 4, vector); } /* funcin que devuelve un vector con los valores enteros comprendidos entre min y max*/ void get_vector_discreto(int min, int max, int* v){ int i; for (i=min; i<max; i++) *(v+i) = i; }
Figura 69: Manejo tipo puntero

#define MAX 50 main() { int vector[MAX]; get_vector_discreto(1, 4, vector); } /* funcin que devuelve un vector con los valores enteros comprendidos entre min y max*/ void get_vector_discreto(int min, int max, int* v){ int i; for (i=min; i<max; i++) v[i] = i; }
Figura 70: Manejo tipo vector

#define MAX 50 main() { int vector[MAX]; get_vector_discreto(1, 4, vector); } /* funcin que devuelve un vector con los valores enteros comprendidos entre min y max*/ void get_vector_discreto(int min, int max, int* v){ int i; for (i=min; i<max; i++) *v++ = i; }
Figura 71: Uso de post-incremento

140

Sistemas Electrnicos Digitales.

9 Cuestiones de comprensin
1) Dada la siguiente definicin de variable
char c;

Seala con un crculo las opciones correctas: a) c es un nmero de 8 bits siempre b) c es un carcter siempre c) c es un nmero sin signo a veces 2) Seala con un crculo los casos en los que b es igual a 1; es decir, en los que se cumple la condicin. CASO A)
int a; b = 0; a = -1; if (a) b = 1;

CASO B)
b = 0; a = 0; if (a = 0) b = 1;

CASO C)
b = 0; a = 0; if (a = 1) b = 1;

CASO D)
b = 0; a = 0; if (a) b = 1;

3) Indica el valor de la variable entera resultado en cada caso


a) resultado = 0x44 && 0x1 b) resultado = 0x44 | 0x1 c) resultado = ~(0x44 >> 2) = ______________ = ______________ = ______________

141

Sistemas Electrnicos Digitales.

4) Traducir a C el siguiente cdigo en ensamblador. Cada lnea de cdigo ensamblador que se debe traducir tiene un comentario a su derecha indicando el nmero de lnea que le representa. Se debe indicar en cada lnea de C la correspondencia con las lneas ensamblador, escribiendo a la derecha de las lneas en C los nmeros de las lneas ensamblador que correspondan. No se puede codificar de forma que una lnea en ensamblador tenga asociadas varias en C; es decir, cada lnea de C tiene al menos una lnea de ensamblador asociada.
MAX D100 i j k D100 ej ej1 equ -1 ;1

section data at 200H dsb 1 dsw 1 dw 1 ends section code at 300H proc NEAR MOV R0,#MAX MOVB i, RL0 MOVBZ R2, i MOV j, R2 MOV R1, k CMP R1, j JMPR cc_ugt, fin MOV R0,#0 MOV j, R0 JMPR cc_uc, fin endp ends

;2 ;3 ;4

;5 ;6 ;7 ;8 ;9 ;10 ;11 ;12 ;13 ;14

fin: ej1 ej

142

Sistemas Electrnicos Digitales.

5) Para cada uno de los programas siguientes: Est correctamente programado? En caso afirmativo Qu saca por pantalla? En caso negativo, razona la respuesta. Debajo de cada programa se ha dibujado un recuadro que representa la pantalla donde se deben escribir los resultados.
double *pdActualiza(); main () { double *pd=NULL; pd=pdActualiza(); printf("2 %f\n",pd[0]); return 0; } double *pdActualiza() { double md[3]={1.2,-2.3,-1.4}; double *pd=md; printf("1 %f\n",pd[0]); return pd; } void Efecto2000(int *pa); main(){ int i=74; Efecto2000(&i); printf("%d",i); } void Efecto2000(int *pa){ *pa=*pa+1900; }

6) Hacer un programa en C que sume los elementos de un vector de 5 elementos a) Usando un bucle for b) Usando un bucle while.

143

Sistemas Electrnicos Digitales.

7) Supuesto un sistema digital como el del laboratorio, explica con tus palabras qu hacen los programas siguientes: La lnea 6 de este programa coge el contenido de lo que hay en la direccin de memoria indicada por el valor de dir y lo guarda en dato.
void main(void) { int dir, dato; DP2 = 0xFF; while (1) { dir = (P2 & 0xFF00)>>8; dato = *((char*)dir); P2 = dato; }

void main(void) { unsigned char dato, mask, i, n; DP2 = 0xFF; while (1) { dato = (unsigned char)((P2 & 0xFF00) >> 8); mask=0x01; n=0; for (i = 0; i<8; i++){ if (!(dato & mask)) n++; mask<<=1; } if (n==0) P2 = 0xFF; else P2 = 0; }

144

Sistemas Electrnicos Digitales.

10 Ejercicios propuestos
10.1 Timer y puertos (40 min) Dado un sistema como la tarjeta del laboratorio, escribir un programa en C que realice las siguientes operaciones:

Lee los interruptores conectados a la parte alta del puerto P2. Extrae el valor de los dos interruptores ms significativos, y los utiliza para definir los bits ms altos del factor de preescalado del timer 0. El bit menos significativo del preescalado del timer queda a 0. El valor inicial de la cuenta y el valor del rebose del timer quedan igualmente a 0. Los 6 interruptores restantes definen dos operandos, de tres bits cada uno de ellos. El programa realiza la suma y el producto de los dos operandos. En los diodos conectados a la parte baja del puerto P2 aparecen ambos resultados, de forma alterna, con sucesivos reboses de timer (con el primer rebose aparece el resultado de la suma, con el segundo rebose aparece el resultado del producto, y as sucesivamente). Es necesario tener en cuenta los rebotes de los interruptores.
#include <reg167.h>

void main(void) {

145

Sistemas Electrnicos Digitales.

10.2 Acceso a memoria (40 min) Dado un sistema digital como la tarjeta que se usa en laboratorio, se pide realizar un programa que tenga las siguientes caractersticas:

Lee un dato de los interruptores conectados a la parte alta del puerto P2. Accede a la direccin de memoria indicada en los interruptores (8 bits ms altos de la direccin todos a 0). Analiza los ocho bits del dato almacenado en dicha direccin. Si hay siete bits a 1 y uno a 0, se indica en los LED ms bajos de P2 la posicin del bit que se encuentra a 0. Si todos los bits se encuentran a 1 se ilumina el LED conectado a P2.4. Si hay ms de un bit a 0 se encienden los cinco LED conectados a las lneas menos significativas de P2.

Es necesario tener en cuenta los rebotes de los interruptores.


#include <reg167.h>

void main(void) {

146

Sistemas Electrnicos Digitales.

147

Sistemas Electrnicos Digitales.

11 Ejercicios resueltos
11.1 La calculadora (30 min) Partiendo de un sistema como el del laboratorio, escribir un programa en C que consiste en una calculadora que opera con datos de 4 bits (sin signo) y devuelve un resultado de 8 bits. El funcionamiento es el siguiente:

En los cuatro bits ms altos de P2 se proporciona el primer dato. Este dato se valida cuando la lnea P2.8 pasa de 0 a 1. A continuacin se introduce el segundo dato (siguiendo el mismo procedimiento que para el primer dato). Por ltimo se introduce la operacin (+: P2.12 = 1, -: P2.13=1 y *: P2.14=1). La operacin se valida de la misma forma que los datos. En caso de que no se haya seleccionado una operacin no se calcula el resultado. El proceso anterior se repite indefinidamente, mantenindose en la parte baja de P2 el resultado de la ltima operacin realizada. La lnea P2.8 llevar un filtrado de rebotes.

148

Sistemas Electrnicos Digitales.

149

Sistemas Electrnicos Digitales.

#include <reg167.h> #define MAX 3 void retraso(int mseg); void main(void){ int contador=-1, ciclo=0, dato[3], result; unsigned int anterior,actual, temp; DP2 = 0x00FF; P2 = ~0; anterior = P2 & 0x0100; while(1) { retraso(1); temp = P2; actual = temp & 0x0100; if (anterior != actual) contador = MAX; else if (contador > 0) contador--; else ; anterior = actual; if (contador == 0) { contador = -1; if (actual) dato[ciclo++] = temp >> 12; //recogida de dato } if(ciclo == 3) { ciclo = 0; // Operaciones

// 1 ms

if(dato[2] & 0x0001) result = dato[0] + dato[1]; else if(dato[2] & 0x0002) result = dato[0] - dato[1]; else if(dato[2] & 0x0004) result = dato[0] * dato[1]; else ; P2 = ~result; } } }

150

Sistemas Electrnicos Digitales.

11.2 El coche fantstico (20 min) Se quiere hacer un sistema de luces rojas similar al del coche fantstico, que consiste de 8 luces que se encienden de una en una de forma consecutiva, de izquierda a derecha y de derecha a izquierda. Para ello se dispone de un microcontrolador C167, de 8 LEDs y de 8 interruptores. Disear un sistema que encienda una luz roja que se vaya moviendo a la derecha y que cuando llegue al final rebote y vuelva hacia la izquierda, y as sucesivamente. Dado que el sistema est diseado para venderse y la velocidad de movimiento de la luz depende del gusto del consumidor, se tiene pensado que se pueda regular dicha velocidad con 8 interruptores.

151

Sistemas Electrnicos Digitales.

#include <reg167.h> void retraso(int prees, int cuenta); void main(void) { int sentido = 0, dato = 0x01; int prees, cuenta, temp; DP2 = 0x00ff; P2 = ~dato; while(1) { temp = P2; prees = temp & 0x0700; prees >>= 8; cuenta = temp & 0xF800; retraso(prees, cuenta); if (!sentido){ P2 = ~(dato <<= 1); if (dato & 0x80) sentido = 1; } else { P2 = ~(dato >>= 1); if (dato & 0x01) sentido = 0; } } }

152

Sistemas Electrnicos Digitales.

11.3 El autobus (30min) Se quiere controlar el nmero de personas que hay en un autobs. Para ello se ha equipado al autobs con dos sensores de contacto (interruptores con rebotes), uno en la puerta de entrada delantera y otro en la puerta de salida trasera, que detectan el paso de pasajeros. El sensor de la puerta delantera se ha conectado al pin P2.8 de un micro C167 y cada vez que pasa una persona produce una transicin de 0 a 1 en el pin. El sensor de la puerta trasera se ha conectado al pin P2.9 y cada vez que pasa una persona produce una transicin de 1 a 0 en el pin. Por otro lado, se han instalado 8 LEDs, conectados a la parte baja del puerto P2, en la cabina del conductor para indicarle el nmero de personas que viajan en el autobs. Si el nmero de viajeros es mayor que 50, aunque una persona intente subir no se le dejar entrar ya que el autobs se considera lleno.

153

Sistemas Electrnicos Digitales.

La solucin propuesta utiliza una funcin filtraP2, que no es ms que una funcin genrica de filtrado de rebotes del puerto P2. Eso significa que se puede usar en cualquier programa que requiera filtrado de rebotes en P2. Se podra decir que es un driver del puerto P2 cuando se le conectan interruptores, ya que el usuario no necesita conocer los detalles del puerto ni de los interruptores y slo se tiene que preocupar del estado de los mismos. Adems es un driver con autoinicializacin ya que detecta cundo se utiliza por primera vez e inicializa las variables que necesita.
#include <reg167.h> #define MAX 3 void retraso(int mseg); int contador[16],inicializado=0; unsigned int anterior[16], estado[16]; int filtraP2(int nlinea) { int actual, temp, mascara, i; if (!inicializado) for (i=0; i<16; i++) { DP2 = 0x00FF; P2 = ~0; contador[i] = 0; anterior[i] = 0; estado[i] = 0; inicializado = 1; } temp = P2; mascara = 1; mascara <<= nlinea; actual = temp & mascara; if (anterior[nlinea] != actual) contador[nlinea] = MAX; else if (contador[nlinea] > 0) contador[nlinea]--; else ; anterior[nlinea] = actual; if (contador[nlinea] == 0) { contador[nlinea] = -1; if (actual) estado[nlinea] = 1; else estado[nlinea] = 0; } return estado[nlinea]; } void main(void){ int personas=0; int anterior8,anterior9,actual8,actual9; anterior8 = 0; anterior9 = 0; while(1) { retraso(1); actual8 = filtraP2(8); if (anterior8 != actual8 && actual8) if (personas < 50) personas++; anterior8 = actual8; actual9 = filtraP2(9); if (anterior9 != actual9 && !actual9) if (personas > 0) personas--; anterior9 = actual9; P2 = ~personas; } } // funcin de filtrado genrica

// flanco de subida

// flanco de bajada

154

Sistemas Electrnicos Digitales.

12 Prctica 6: ejercicios en lenguaje C

155

Sistemas Electrnicos Digitales.

156

Sistemas Electrnicos Digitales.

157

Sistemas Electrnicos Digitales.

Captulo 9 INTERRUPCIONES
1 Objetivos y conceptos a entender en este captulo
En este captulo se debe aprender qu es una interrupcin y el proceso que se sigue para atenderla. Se recomienda adems, que se hagan esquemas que permitan analizar el paralelismo que hay entre el tratamiento de perifricos por polling y por interrupcin.

2 Nociones bsicas de interrupciones


Cuando la CPU pide realizar una tarea a un perifrico, tiene dos posibilidades para determinar cuando termina el perifrico: Estar continuamente preguntando al perifrico si ha terminado, de forma que cuando el perifrico responda que s, ejecute el cdigo que corresponda aprovechando la tarea realizada por el perifrico. Este mtodo se llama polling y es el que se ha estado usando hasta el momento. Decir al perifrico que avise a la CPU de que ha terminado su tarea. En ese momento la CPU deja de hacer lo que estaba haciendo (slo en caso de que lo que est haciendo sea de menor prioridad que la peticin del perifrico) y se pone a ejecutar el cdigo que corresponda aprovechando la tarea realizada por el perifrico. Este mtodo se llama interrupcin y es el que se va a explicar en este captulo. Para que un perifrico funcione en modo interrupcin, es necesario configurarle para ello. Una peticin de interrupcin de un perifrico slo interrumpe a la CPU El proceso detallado que se sigue funcionando en modo interrupcin es el siguiente: 1. La CPU inicializa el perifrico, para funcionar en modo interrupcin y se indica el grado de prioridad de esa interrupcin (prioridad mayor que 0). 2. La CPU se pone a hacer su trabajo normal que tiene la menor prioridad (prioridad 0). 3. Cuando el perifrico termina su tarea, realiza una peticin de interrupcin a la CPU a travs de una lnea del bus de control denominada IRQ (interrupt request). Para saber ms sobre los buses de la CPU ver el captulo 2 seccin 3.7. 4. La CPU termina de ejecutar la instruccin que estaba ejecutando. 5. La CPU guarda el PSW y el PC (CSP+IP) en el Stack de forma temporal. Esto es necesario para saber lo que estaba ejecutando en el momento de la interrupcin (donde apuntaba PC) y para saber cul es el estado de la CPU en ese instante (PSW). 6. La CPU lanza un ciclo de reconocimiento de interrupcin, para determinar los perifricos que han solicitado la misma. De entre todos los posibles (56 en total), elige la interrupcin que tenga mayor prioridad (16 niveles distintos). 7. La CPU lanza la funcin de tratamiento de la interrupcin, que no es otra cosa que el cdigo que se tiene que ejecutar para aprovechar la tarea realizada por el perifrico

158

Sistemas Electrnicos Digitales.

en cuestin. La direccin de comienzo (denominada vector) de cada funcin que atiende interrupciones (56 posibles, una por cada tipo de interrupcin) se encuentra en la tabla de vectores de interrupcin. Por lo tanto la CPU inicializa PC al valor del vector correspondiente. Durante el tratamiento en PSW se pone el nivel de la interrupcin. 8. Una vez terminada la ejecucin de la funcin de tratamiento de interrupcin, la CPU recupera el PC del Stack para seguir ejecutando lo que estaba haciendo antes de la interrupcin y el PSW del Stack para dejar la CPU en el estado que estaba antes de la interrupcin, tanto los flags, como el nivel de interrupcin.

3 Recursos utilizados en una interrupcin


Hay 56 posibles fuentes de interrupcin, por ejemplo el Timer 0, el Timer 1, el convertidor AD,.... Cada fuente de interrupcin tiene: Un vector de interrupcin, que indica la direccin de memoria de la funcin que hay que ejecutar cuando se produzca la interrupcin. Un registro de control de interrupcin, que tiene un nombre xxIC. Por ejemplo el del Timer 0 es T0IC, el del Timer 1 es T1IC y el del convertidor AD es ADCIC. El registro de control de interrupciones consta de: ILVL: 4 bits que indican el nivel de la interrupcin (0 a 15. Nivel 15 nivel ms alto) (Interrupt Level) xxIE: bit de habilitacin de la interrupcin (Interrupt Enable). Este bit indica al perifrico que tiene que funcionar en modo interrupcin. Si vale 0 el perifrico funciona en modo polling. Por ejemplo para el Timer 0 el bit se llama T0IE, para el Timer 1 se llama T1IE. xxIR: bit de peticin de interrupcin (Interrupt Request). Si se pone a 1 el perifrico est solicitando una interrupcin. Es el bit que se ha usado hasta ahora para saber si el perifrico haba terminado su tarea. Por ejemplo para el Timer 0 el bit se llama T0IR, para el Timer 1 se llama T1IR.

xxIC 15

5 ILVL

2 1

xxIR xxIE

GLVL

Por otro lado, el registro PSW juega un papel muy importante en las interrupciones:

15 ILVL

12

11 IEN -

3 Z

2 V

1 C

0 N

159

Sistemas Electrnicos Digitales.

El bit 11, IEN (Global Interrupt Enable), es un bit que permite habilitar o deshabilitar de forma global las interrupciones. La utilidad radica en que si en algn momento se quiere ejecutar un trozo de cdigo al cual no se puede interrumpir (zona crtica), se puede poner a cero este bit, en vez de tener que poner a cero cada uno de los bits xxIE de cada una de las 56 fuentes de interrupcin. Los 4 bits que van del 12 al 15, indican la prioridad del programa en curso. De forma que una interrupcin solamente puede interrumpir a la CPU si el ILVL del registro xxIC de la interrupcin correspondiente, es mayor que el ILVL del PSW. El ILVL del PSW es cero cuando se ejecuta main. Por lo tanto para que un perifrico funcione en modo interrupcin es necesario configurarlo de la siguiente manera: Habilitar la interrupcin, bit xxIE del registro xxIC. Poner la prioridad de la interrupcin, ILVL del registro xxIC. Habilitar de forma global las interrupciones, bit IEN del registro PSW.

4 Ejemplos
A continuacin se muestra un ejemplo que usa el Timer 0 usando interrupciones para llevar a cabo un calendario. El programa principal muestra en los LEDs conectados en la parte baja de P2 los minutos transcurridos o las horas dependiendo de un interruptor conectado al pin P2.15. Es importante darse cuenta de la sintaxis de la funcin de tratamiento de interrupcin. No se la pueden pasar parmetros, ya que NO se puede invocar explicitamente. Es la propia CPU la que hace que se ejecute cuando el Timer rebosa. El nmero 0x20 que aparece en la definicin de la funcin indica el vector de interrupcin que usa para ser invocada por la CPU. La CPU sabe que es la funcin que atiende al Timer 0 NO por llamarse timer0 sino por corresponder al vector de interrupcin 0x20 que es el que atiende las peticiones del Timer 0. Como no se pueden pasar parmetros a la funcin de interrupcin, la comunicacin de la misma con el programa principal se debe hacer usando variables globales. Dado que la funcin de tratamiento de la interrupcin se ejecuta a mayor prioridad que el resto del cdigo, es necesario que sea corta; es decir, est absolutamente prohibido poner algn bucle en la misma. En caso contrario podra suceder que el resto de cdigo no tuviera casi tiempo de CPU para ejecutarse.

160

Sistemas Electrnicos Digitales.

#include <reg167.h> #include <stdio.h> #define PERIOD -2500 int ticks, sec, min, hour; void main(void) { ticks = sec = min = hour = 0; T01CON = 0x00; T0REL = PERIOD; /* set reload value */ T0 = PERIOD; T0IC = 0x44; /* set T0IE and ILVL = 1 */ IEN = 1; /* set global interrupt enable flag */ T0R = 1; /* start timer 0 */ DP2 = 0x00FF; while(1){ if (P2 & 0x8000) P2 = ~min; else P2 = ~hour; } }

void timer0(void) interrupt 0x20 { ticks++; if (ticks == 1000) { ticks = 0; sec++; if (sec == 60) { sec = 0; min++; if (min == 60) { min = 0; hour++; if (hour == 24) hour = 0; } } } }

161

Sistemas Electrnicos Digitales.

5 Prctica 7: interrupciones en C

162

Sistemas Electrnicos Digitales.

163

Sistemas Electrnicos Digitales.

164

Sistemas Electrnicos Digitales.

Captulo 10

SISTEMAS DIGITALES COMPLEJOS

1 Objetivos y conceptos a entender en este captulo


Este captulo nicamente pretende dar metodologas que faciliten resolver sistemas digitales complejos. No son los nicos mtodos que se pueden usar, pero s es cierto que siguen un estilo de programacin y de resolucin de problemas bueno; es decir, buscan una buena mantenibilidad, flexibilidad y escalabilidad del sistema.

2 Sistemas muestreados
Un sistema muestreado se basa en que cada cierto intervalo de tiempo, llamado periodo de muestreo, realiza determinadas tareas sncronas. La ventaja de estos sistemas es que se sabe con bastante precisin en qu momento se ejecutan las tareas, lo que les hace ideales para llevar un control de tiempo o realizar mediciones. Por otro lado, las tareas muestreadas dejan ms tiempo libre de CPU, ya que entre intervalos de muestreo la CPU queda libre. Volviendo al ejemplo del captulo 6 seccin 12, si se quiere medir el ancho de un pulso que entra por lnea P7.4 la solucin de un sistema sin muestrear es la siguiente:

DP2 = 0x00FF; DP7 = 0; inicializacion(T0I=7,T0=-20000); while (1){ while (P7.4==0) ; T0R = 1; while (P7.4==1); T0R=0; t=T0/20; P2=t; }
Esta solucin no es muestreada porque est mirando continuamente de forma asncrona el estado del pin P7.4. Para poder determinar el ancho del pulso tiene que usar un Timer, ya que por la propia ejecucin de lneas de cdigo no sera factible estimar este tiempo. En cambio en un sistema muestreado la solucin se basa en el uso de un reloj que lleva la cuenta del periodo de muestreo, y slo se mira el estado de la lnea una vez en cada intervalo. La ventaja es que el chequeo de la lnea no consume casi CPU y se hace a intervalos

165

Sistemas Electrnicos Digitales.

regulares, lo que supone que contando el nmero de intervalos se puede tener una medida del ancho del pulso.
#include <reg167.h> #include <stdio.h> #define PERIOD -2500 int cuenta=0, anterior, actual, contador; void main(void) { T01CON = 0x00; T0REL = PERIOD; T0 = PERIOD; T0IC = 0x44; IEN = 1; T0R = 1; DP2 = 0x00FF; DP7 = 0; anterior = P7.4; while(1); }

/* set reload value */ /* set T0IE and ILVL = 1 */ /* set global interrupt enable flag */ /* start timer 0 */

void timer0(void) interrupt 0x20 { actual = P7.4; if ((anterior != actual) && (actual == 1)) { cuenta = 1; } if ((anterior != actual) && (actual == 0)) { cuenta = 0; P2 = contador; contador = 0; } if(cuenta==1) contador++; anterior = actual; }

La clave para un buen funcionamiento consiste en estimar correctamente el periodo de muestreo, ya que si es demasiado pequeo, la CPU no queda libre, y si es demasiado grande puede haber problemas de resolucin y sensibilidad. La regla ptima a seguir para calcular el periodo de muestreo es la siguiente: 1. Determinar el periodo de muestreo de todas las tareas que tenga que realizar la CPU. 2. Escoger el mximo comn divisor de todos ellos.

166

Sistemas Electrnicos Digitales.

Por ejemplo, si un sistema tiene que medir el ancho de pulso con una resolucin de 1 milisegundo y adems generar un pulso de 350 microsegundos en algn momento, claramente el periodo de muestreo es el mximo comn divisor de 350 us y 1 ms, que es 50 us.

3 Fechado
Cuando el funcionamiento de un sistema depende del tiempo, que suele ser casi siempre, es necesario llevar un reloj calendario. Aunque se puede hacer de muchas maneras, en esta seccin se pretende dar una metodologa para hacer programas que dependan del tiempo de forma sencilla y simple. Lo primero que es necesario saber es la medida mnima que se quiere poder contabilizar; es decir, la resolucin de la medida de tiempo. En caso de ser un sistema muestreado, esta resolucin coincide con el periodo de muestreo. En segundo lugar, cada medida de tiempo que se quiere tener supone la creacin de un nuevo contador de tiempo. Por ejemplo, si se quiere ejecutar el evento 1 cada segundo y el evento 2 cada 350 milisegundos, para un periodo de muestreo de 1 ms, el cdigo resultante sera:

167

Sistemas Electrnicos Digitales.

#include <reg167.h> #include <stdio.h> #define PERIOD -2500 int mseg_evento1=0, mseg_evento2=0; void main(void) { T01CON = 0x00; T0REL = PERIOD; T0 = PERIOD; T0IC = 0x44; IEN = 1; T0R = 1; while(1){ if (mseg_evento1 mseg_evento1 // programar } if (mseg_evento2 mseg_evento2 // programar } } }

/* set reload value */ /* set T0IE and ILVL = 1 */ /* set global interrupt enable flag */ /* start timer 0 */ == 1000) { = 0; aqu el evento 1 == 350) { = 0; aqu el evento 2

void timer0(void) interrupt 0x20 { mseg_evento1++; mseg_evento2++; }

En caso de trabajar con polling el cdigo sera:

168

Sistemas Electrnicos Digitales.

#include <reg167.h> #include <stdio.h> #define PERIOD -2500 int mseg_evento1=0, mseg_evento2=0; void main(void) { T01CON = 0x00; T0REL = PERIOD; T0 = PERIOD; T0IC = 0x44; IEN = 1; T0R = 1; while(1){ retardo(1); mseg_evento1++; mseg_evento2++; if (mseg_evento1 mseg_evento1 // programar } if (mseg_evento2 mseg_evento2 // programar } } }

/* set reload value */ /* set T0IE and ILVL = 1 */ /* set global interrupt enable flag */ /* start timer 0 */ /* 1 ms*/

== 1000) { = 0; aqu el evento 1 == 350) { = 0; aqu el evento 2

En caso de que la medida de tiempo sea asncrona; es decir, se hiciera a partir de un evento que no se puede predecir cundo sucede, sera el propio evento el que pondra a cero el contador.

169

Sistemas Electrnicos Digitales.

#include <reg167.h> #include <stdio.h> #define PERIOD -2500 int mseg_evento1=0; void main(void) { T01CON = 0x00; T0REL = PERIOD; T0 = PERIOD; T0IC = 0x44; IEN = 1; T0R = 1; while(1){ if ( ) { // si mseg_evento1 } if (mseg_evento1 // programar } } }

/* set reload value */ /* set T0IE and ILVL = 1 */ /* set global interrupt enable flag */ /* start timer 0 */ sucede evento 1 = 0; == 1000) { aqu el evento 2

void timer0(void) interrupt 0x20 { mseg_evento1++; }

4 Programacin basada en estados


Cuando se quiere resolver un problema complejo siempre existe una frase que se debe aplicar "divide y vencers". Pues bien, existen muchas maneras de llevar esto a cabo, la modularizacin en funciones, el diseo top-down (disear primero a alto nivel con grandes bloques y luego ir diseando dentro de cada bloque los detalles), etc. En esta seccin se va a explicar cmo abordar un problema complejo usando estados. Es un diseo top-down con gran modularizacin. Consiste en modelar cada uno de los posibles procesos de un sistema en lo que se llama una mquina de estados. En esta seccin no se pretende exponer una teora rigorosa sobre las mquinas de estados, ya que no es objetivo del libro, sino de dar ideas de cmo se pueden resolver problemas software usando un mtodo que se le puede ocurrir a cualquiera. A cualquier desarrollador se le puede ocurrir que los pasos a seguir para resolver un problema complejo segn un diseo top-down y modular son: 1. Determinar qu procesos independientes existen en el sistema que se quiere desarrollar

170

Sistemas Electrnicos Digitales.

2. Para cada uno de esos procesos, se deben determinar las etapas de las que consta y cul es la inicial. 3. Una vez determinadas las etapas, se deben definir las variables que hacen que el proceso vaya de una etapa a otra. De forma equivalente se puede definir este mtodo segn una metodologa basada en estados: 1. Determinar las mquinas de estado que tiene el sistema 2. Para cada mquina de estado, se deben determinar cuales son los estados de los que consta. 3. Una vez determinados los estados, se deben definir las variables que definen los cambios de estado Desde el punto de vista software este mtodo quedara: 1. Definir una funcin por cada mquina de estados y definir una variable global que permita conocer el estado actual en que se encuentra la mquina. Por ejemplo:
int estado_actual=0; void maquina(){...}

2. Definir una funcin de estado, por cada estado de cada mquina de estados. Estas funciones sern invocadas desde la funcin que controla cada mquina de estados segn el valor de la variable estado_actual.
void maquina(){ if (estado_actual == 0) estado0(); else if (estado_actual == 1) estado1(); }

3. Dentro de cada funcin de estado, se deben programar las condiciones de paso de un estado a otro en funcin de variables.
void estado0(){ if (var > 0) estado_actual = 1 }

Las transiciones de un estado a otro pueden suceder por el paso de tiempo, en ese caso la variable que se usa en la comparacin ser un contador de tiempo asncrono, tal y como se explic en la seccin 3 de este captulo.

171

Sistemas Electrnicos Digitales.

REFERENCIAS
[1] B.W. Kernighan && D.M. Ritchie. The C Programming Language. Prentice Hall. [2] Instruction set manual for the C166 family of Infineon 16-bit Single Chip Microcontrollers. Infineon Technologies AG.

172

También podría gustarte