Está en la página 1de 173

SISTEMAS ELECTRNICOS DIGITALES

Autores:
Fernndez Martnez Cesreo
Snchez Miralles lvaro

Sistemas Electrnicos Digitales.

Captulo 1

Filosofa del libro _______________________________________________ 5

Captulo 2

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

Cuestiones de comprensin _________________________________________________ 33

Ejercicios propuestos ______________________________________________________ 33

Prctica 1: Introduccin al Siemens C167 _____________________________________ 40

Captulo 4

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

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 ________________________________________

4
5

61
62
62
63
63
63

Cuestiones de comprensin _________________________________________________ 65


Ejercicios propuestos ______________________________________________________ 66
5.1 PWM sencillo (30 min) ____________________________________________________________ 66

Prctica 4: timers _________________________________________________________ 68

Captulo 6
1
2

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

Instrucciones para realizar operaciones lgicas ________________________________ 77


5.1 AND __________________________________________________________________________
5.2 OR ____________________________________________________________________________
5.3 XOR___________________________________________________________________________
5.4 CPL ___________________________________________________________________________

77
78
78
79

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

Directivas de ensamblador _________________________________________________ 88

11

Cuestiones de comprensin _________________________________________________ 90

12

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

13

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) ____________________________________________________________

14

100
101
102
103
104

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_________________________________________________________

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

115
116
116
116
118
119
119
119

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

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

Cuestiones de comprensin ________________________________________________ 141

10

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

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

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

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

Dato

0000
0001

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

0x1010

Los 16 bits del cdigo de instruccin indican:

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

12
1

7
NA

Rs2

Rs1

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

15

12 11
2

0x2010

8 7
Rs

0
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

0080
0082

0007
0003

Instruccin
Instruccin
Instruccin
Instruccin

Dato
Dato

A0

FFFF

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.
Execute

Fetch

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

Lenguaje C

Cdigos de alto nivel


ASCII

Interpretacin 0's y 1's


Ensamblador

Interpretacin 0's y 1's


Nmeros con y sin signo

PROGRAMAS FPGA

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.

Bus del sistema

CPU
(ALU, Registros
y Control)

Memoria

Entrada/Salida

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.

CPU

Memoria
FF FFFF

Registros

00 0001
00 0000

00 FE00

R7

R15

PC

R6

R14

PSW

R5

R13

SP

R4

R12

R3

R11

R2

R10

R1

R9

R0

R8

(SFRs)

(GPRs)

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

Direccin de
memoria

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

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

Operandos

Comentarios (opcional)

En lnea
500
502
504
506
508
50C
50E
510

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

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

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

next:

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;

otro:

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

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)

FFFF

C000

256
Segmentos
de 64 kB

16 Mb

Pgina 2
8000

Pgina 1
(RAM ext)
4000

S1 64Kb
01 0000
00 0000

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


FF00

SFRs
SFRs

FE00

Acceso bit a bit


FD00

GPRs
FC00

RAM
STACK

F600

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

MOV
MOV

DPP0, #0x29
R0, 0x3000

Pgina seleccionada

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

MOV
MOV

DPP2, #0x29
R0, 0xB000

10 11 0000 0000 0000


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
...

CP,#0FC00 H
a, R0

Dato
... ...

FC08

4400

R4

FC06

FF00

R3

FC04

FC04

R2

FC02

A050

R1

FC00

1034

R0

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


= 0xFC04.

...

...
MOV
MOV
...

CP,#0FC04 H
a, R0

Direccin

Dato

R4

...

...

R3

FC08

4400

R2

FC06

FF00

R1

FC04

FC04

R0

FC02

A050

FC00

1034

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

r1
rl0
00

rh1
00

rl1
01

PASO 1

r0
MOV R0, #2

rh0

r1
rl0

rh1

rl1

PASO 2

r0
MOV R0, 0x202

rh0

r1
rl0

rh1

rl1

PASO 3

r0
MOV R1, R0

rh0

r1
rl0

rh1

rl1

PASO 4

r0
MOV 0x200, R1

rh0

r1
rl0

rh1

rl1

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

35

Sistemas Electrnicos Digitales.

PASO 5

MOV R2, #0x4433


MOV 0x202, R2

r0
rh0

r1
rl0

rh1

rl1

PASO 6

r0
MOVB rl0, #4

rh0

r1
rl0

rh1

rl1

PASO 7

r0
MOVB rh1, [r0]

rh0

r1
rl0

rh1

rl1

PASO 8

r0
MOV r1, [r0+]

rh0

r1
rl0

rh1

rl1

PASO 9

r0
MOVB rl1, [r0+]

rh0

r1
rl0

rh1

rl1

PASO 10

r0
ADD r1, r0

rh0

r1
rl0

rh1

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

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

00
00
00
00
00
00

FC 00
FC 01
FC 02
FC 03
FC 04
FC 05

Instruccin
R 1,#3
R 0,#1
R 0, R 1
0x202, R 0

E scribir aqu la solucin final


C elda 8 bits

D ireccin d e

C eld a 8 b its

m em o ria 24

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
..

m ov
m ov
m ov
m ov

(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

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

(H ex)

FC 00
FC 01
FC 02
FC 03
FC 04
FC 05

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

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

Registros
CSP =
CP = FC02
IP =

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

13 12

---

T1R

---

11
T1M

10

8
T1I

---

T0R

5
---

3
T0M

0
T0I

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

T0IR T0IE

2 1
ILVL

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

rebose o final de
cuenta

T0REL

Pre-escalado
clk

T0I

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

= ~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.

= complemento a 1 de P2.
T01CON | 0x40,

#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

section code at 0H
proc NEAR
jmp main
endp
ends

DAT
DC

section data at 200H


db 13

DAT

ends

SM
main

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

8 bits sin signo

16 sin extender
signo

16 bits extendiendo signo

0xFF

-1

255

255 (0x00FF)

-1 (0xFFFF)

0x80

-128

128

128 (0x0080)

-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.

Rx 16 bits
MOV
SHL

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

Con 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 ) ]

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
....

R0,R1
cc_ugt,next

;si R0 > R1

next:
Figura 38: Ejemplo de salto condicional

Una condicin completa se muestra en la Figura 39.

else:

MOV
R0,a
CMP
R0,b
JMPR
cc_ne,else
; condicin if
..
JMPR
cc_uc,endif
; condicin 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:

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

endif:

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:

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

next:
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


FF00

SFRs
SFRs

FE00

Acceso bit a bit


FD00

GPRs
FC00

RAM
STACK

F600

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

bit, dir

; si bit = 1 entonces salta a dir

JNB

bit, dir

; si bit = 0 entonces salta a dir

JB
....

C,next

;si C = 1 salta next

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

bit1, bit2

; bit1 <- bit1 and bit2

BOR

bit1, bit2

; bit1 <- bit1 or bit2

BXOR

bit1, bit2

; bit1 <- bit1 xor 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.

Seccin de datos D100


en direccin 0x200

Procedimiento ej1

maxdata

$nonsegmented
equ
0x10 ; constante

D100
j
h
D100

section data at 200H


dsw
10 ; int j[10];
dw
1 ; int h =1;
ends

ej
ej1

section
proc
MOV
MOV
MOV
CMP
JMPR
MOV
ADD
ADD
JMPR
NOP
endp
ends
end

otro:

Seccin de cdigo ej
en direccin 0x300
next:
ej1
ej

code at 300H
NEAR
R0,#0
R1,#1
R2,#j
R0,#maxdata
cc_sge,next
[R2],R0
R0,R1
R2,#2
cc_uc,otro

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

R0, #0xFC

;R0 = __________

Movbs

R0, #0xFC

;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

R0, #0

;PSW = ___________

add

R0, #0x6500

;PSW = ___________

add

R0, #0x6500

;PSW = ___________

add

R0, #0x6500

;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

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


MOV
MOV
DIV
MOV
MOV

R3 = ____________

R2 = ____________

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

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.

300
304
306

....
MOV
CALLR
MOV
....

R0, #0x54
400
R1, #0x32

400
402
406
408

PUSH
MOV
POP
RET

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

section code at 0H
proc NEAR
jmp main
endp
ends

DAT
origen
dest

section data at 200H


dsb 16
dsb 16

DAT

ends

SM
main

section code at 300H


proc NEAR
.

copia:

fin:

ret

main
SM

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

section code at 0H
proc NEAR
jmp main
endp
ends

DAT
result
dato

section data at 200H


dsb 1
dsb 1

DAT

ends

SM
main

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

section code at 300H

main

proc NEAR

bucle:

ini_for:

next_for:

fin_for:

if_1:

MOV

DP2, #0xFF

MOV

R0, P2

AND

R0, #0xFF00

SHR

R0, #8

MOV

R4, #0

MOVB

RL4, [R0]

; dato de la direccin de memoria

MOV

R1, #0

; contador de for

MOV

R2, #1

; mscara

MOV

R3, #0

; contador de nmero de bits a 0

CMP

R1, #8

JMPR

cc_ugt, fin_for

MOV

R0, R4

AND

R0, R2

JMPR

cc_ne, next_for

MOV

R5, R1 ; almacena la posicin del bit a 0

ADD

R3, #1

ADD

R1, #1

SHL

R2, #1

JMPR

cc_uc, ini_for

CMP

R3, #0

JMPR

cc_ne, if_1

MOV

P2, #0xEF

JMPR

cc_uc, bucle

CMP

R3, #1

JMPR

cc_ne, if_n

; enciende LED P2.4

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.

ANALOGICO

ADCH

ADDAT

Convertidor AD

ADCIR

P5.0 (canal 0)

5V
0V

MUX

P5.15 (canal 15)

5V
0V

Figura 50:Esquema del convertidor AD

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:

ADBSY ADST

6
---

ADM

0
ADCH

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.

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

CANAL

9
---

RESULTADO

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.

averiguar si un determinado nmero es mltiplo de otro; por ejemplo el nmero


es mltiplo de 33 porque 4580169%33 da cero.

4580169

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

= 1

yb

= 14

es TRUE

Si a

= 0

yb

= 32

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

yb = 0
yb = 0

= 32

es FALSE
es TRUE

Ya que a y b son cero


Ya que a es distinto de cero

Tabla 2: Ejemplo de OR lgico

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

c = ! b

Si b = 14
Si b = 0

es FALSE
c es TRUE

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

yb = 1
0yb = 1

= 0, d = 0
= 10, d =

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.

a
a
a
a

=
=
=
=

P2;
P2;
P2;
P2;

a
a
a
a

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

//
//
//
//

Cuanto
Cuanto
Cuanto
Cuanto

vale
vale
vale
vale

en
en
en
en

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

equ

D100
Iniciado
SinIni
D100

section data at 200H


dw
1,5,8,4,3
dsw
5
ends

ej
ej1

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

ini:

fin:
ej1
ej

;contador

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

i
c

pti

ptc

Valor 8 bits

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

section data at 200H


dsw
1
dsw
1
ends

ej
ej1

section
proc
MOV
MOV
MOV
MOV
MOV
endp
ends

ej1
ej

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

main() {
int i1,i2;
int *pi;
i1 = 5;
pi = &i1;
i2 = *pi;

// i2?

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

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+]

i = *pti++

MOV R1, [-R2]

i = *--pti

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

133

Sistemas Electrnicos Digitales.

MAX

equ

D100
VWord
VByte
D100

section data at 200H


dsw
5
dsb
5
ends

ej
ej1

section
proc
MOV
MOV
MOV
MOV
MOV
CMP
JMPR
MOVB
ADD
ADD
ADD
JMPR
NOP
endp
ends

suma:

fin:
ej1
ej

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

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]

i = *(pti+5); // en caso de int

MOVB RL1, [R0+#5]

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

equ

D100
i
j
k
D100

section data at 200H


dsb
1
dsw
1
dw
1
ends

ej
ej1

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

fin:
ej1
ej

-1

;1

;2
;3
;4

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

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();

void Efecto2000(int *pa);

main ()
{
double *pd=NULL;
pd=pdActualiza();
printf("2 %f\n",pd[0]);
return 0;
}

main(){
int i=74;

double *pdActualiza()
{
double md[3]={1.2,-2.3,-1.4};
double *pd=md;
printf("1 %f\n",pd[0]);
return pd;
}

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 ;

// 1 ms

anterior = actual;
if (contador == 0) {
contador = -1;
if (actual)
dato[ciclo++] = temp >> 12; //recogida de dato
}
if(ciclo == 3) {
ciclo = 0;

// Operaciones

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;

// funcin de filtrado genrica

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;
}
}

// 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

xxIR xxIE

2 1
ILVL

GLVL

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

15

12
ILVL

11
IEN

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