Está en la página 1de 157

Apuntes de Microcontroladores O22 Ricardo Álvarez González

APUNTES DE LA ASIGNATURA
MICROCONTROLADORES
Introducción ........................................................................................................................................ 4
Conceptos básicos ............................................................................................................................... 5
Arquitectura de von Neumann ....................................................................................................... 6
Arquitectura Harvard ...................................................................................................................... 8
NÚMEROS EN BINARIO, HEXADECIMAL Y DECIMAL ..................................................................... 13
Ejercicio 1 ...................................................................................................................................... 14
Ejercicio 2 ...................................................................................................................................... 14
Microcontroladores....................................................................................................................... 15
PROCESADORES DIGITALES DE SEÑALES: DSP .............................................................................. 18
MICROCONTROLADORES PIC 18F4550 ............................................................................................. 18
ORGANIZACIÓN DE LA MEMORIA ................................................................................................. 19
Organización de la memoria de programa.................................................................................... 19
Stack .............................................................................................................................................. 21
Reinicializaciones (resets) por stack lleno, o por desbordamiento por defecto del stack. ......... 21
PCL, PCLATH Y PCLATU .................................................................................................................. 21
CICLO DE INSTRUCCIÓN. ............................................................................................................... 22
FLUJO DE INSTRUCCIÓN Y SEGMENTACIÓN. ................................................................................ 22
INSTRUCCIONES EN MEMORIA DE PROGRAMA. .......................................................................... 23
ORGANIZACIÓN DE LA MEMORIA DE DATOS................................................................................ 23
REGISTROS DE FUNCIÓN ESPECIAL ............................................................................................... 26
BANCO DE ACCESO ........................................................................................................................ 26
REGISTROS DE SELECCIÓN DE BANCOS ......................................................................................... 27
REGISTRO DE ESTADO (STATUS). .................................................................................................. 27
Registro STATUS ............................................................................................................................ 28
Registro RCON ............................................................................................................................... 28
REGISTRO RCON ............................................................................................................................ 28
CONFIGURACIÓN DEL OSCILADOR ................................................................................................ 29
RESUMEN DEL CONJUNTO DE INSTRUCCIONES............................................................................ 30

1
Apuntes de Microcontroladores O22 Ricardo Álvarez González

PROGRAMACIÓN EN LENGUAJE ENSAMBLADOR ............................................................................. 33


PANORAMA GENERAL DE MPASM ................................................................................................ 33
Directivas del lenguaje .................................................................................................................. 34
Ejemplo de instrucciones: ................................................................................................................. 34
Configuración de puertos de entrada-salida..................................................................................... 35
Estructura de los programas en lenguaje ensamblador ................................................................... 36
Ejemplo: Controlando ocho leds ................................................................................................... 37
¿Cuánto DURA LA RUTINA RETARDO? .......................................................................................... 40
Segunda versión del programa de rotación de luces .................................................................... 41
Ejemplo: Control de un exhibidor de siete segmentos de ánodo común conectado al PORTD. .. 43
Ejemplo: Control de un exhibidor de siete segmentos ................................................................. 44
Ejercicio E2.1 ................................................................................................................................. 44
Ejercicio E2.2 ................................................................................................................................. 45
Ejercicio E2.3 ................................................................................................................................. 48
Ejercicio E2.4 ................................................................................................................................. 48
Ejemplo: Contador ascendente-descendente ............................................................................... 48
Ejercicio E3.1 ................................................................................................................................. 51
Interrupciones ............................................................................................................................... 51
Ejemplo: usando la interrupción externa 0, INT0 ............................................................................. 52
Timers ............................................................................................................................................ 55
Temporizador/Contador 0 ............................................................................................................ 57
Ejemplo usando el timer 0 ............................................................................................................ 61
Ejercicios E4.1 ............................................................................................................................ 62
Ejercicios E4.2 ............................................................................................................................ 63
INTERRUPCIÓN EXTERNA 1 ........................................................................................................... 66
Ejemplo: Contador ascendente descendente, usando el timer 0 y la interrupción externa INT1 67
Ejemplo 6: Manejando tablas por el método del “goto calculado” .............................................. 70
Ejemplo: tablas de búsqueda en memoria de programa usando instrucciones de lectura de tabla
....................................................................................................................................................... 73
Ejemplo: Manejando dos displays de siete segmentos ................................................................ 77
Ejemplo: Usando un teclado Matricial .......................................................................................... 82
Ejemplo: Usando el timer 2 ............................................................................................................... 90

2
Apuntes de Microcontroladores O22 Ricardo Álvarez González

DIRECCIONAMIENTO INDIRECTO .................................................................................................. 95


MÓDULOS CAPTURA, COMPARACIÓN Y PWM ................................................................................. 97
Modo Captura ............................................................................................................................... 98
Modo Comparación....................................................................................................................... 99
Aplicaciones del modo comparación .......................................................................................... 100
Registros de control de los módulos CCP .................................................................................... 100
Modo PWM ................................................................................................................................. 102
Ciclo de trabajo (Duty Cycle) ....................................................................................................... 102
Fórmulas para el periodo y el ciclo de trabajo ............................................................................ 104
Aplicaciones del modo PWM ...................................................................................................... 104
Programa de ejemplo de PWM ....................................................................................................... 104
Ejemplo: Mostrando un letrero en cuatro displays de 7 segmentos .............................................. 109
Ejemplo en ensamblador del ADC ................................................................................................... 115
Ejemplo del USART .......................................................................................................................... 121
PROGRAMACIÓN EN LENGUAJE DE ALTO NIVEL............................................................................. 128
Ejemplos de programas con el compilador CCS .......................................................................... 129
Ejemplo: Controlando LEDs en alto nivel .................................................................................... 130
Ejemplo: Usar un LCD alfanumérico............................................................................................ 134
Ejemplo usando el ADC: .............................................................................................................. 136
Ejemplo: Usando un teclado matricial en CCS ................................................................................ 139
Introducción al internet de las cosas (IoT) ...................................................................................... 140
Ejemplo: Parpadeo de un LED con la NodeMCU......................................................................... 144
Ejemplo: creando un servidor con el ESP8266............................................................................ 146
Ejemplo usando la plataforma para IoT: ThingSpeak ................................................................. 151
Bibliografía: ..................................................................................................................................... 157

3
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Introducción
Se presenta a continuación unas notas que tienen por objetivo facilitar al lector en el uso de
microcontroladores PIC 18F4550,(su contenido es compatible con el curso “Microcontroladores”)
mediante una serie de ejemplos prácticos que le permiten iniciarse en el uso de los mismos, y
también aprender a escribir sus propios programas, tomando como base estos ejemplos,
complementándolos a sus necesidades específicas añadiéndole su toque personal.

La información teórica se tomó de las hojas de datos del fabricante, pero no se pretende ser un
reemplazo de ellas, por lo que siempre se sugiere acudir a las mismas, de tal manera que se
sugiere al lector consultar dicha literatura para abundar sobre el tema que considere que se trata
aquí de una manera muy escueta.

La última sección corresponde a una introducción al internet de las cosas (IoT), mediante el uso de
la tarjeta de desarrollo NodeMCU.

Se agradece la elaboración de algunas de las figuras a Cesar Hugo Pimentel Romero.

Primavera 2022

4
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Conceptos básicos
Nuestra cómoda vida moderna lo es gracias a la gran cantidad de artículos y artefactos con los que
interactuamos diariamente ¡sin ni siquiera darnos cuenta!, muchos de estos artefactos son
electrónicos, y recientemente están basados en las computadoras digitales.

En la historia de las computadoras, los primeros prototipos fueron mecánicos, debido al momento
tecnológico histórico en el que aparecieron. Cuando aparecen los primeros componentes
electrónicos, de manera natural se utilizaron para realizar los primeros prototipos de las
computadoras electrónicas

Microprocesador. Es un circuito integrado que tiene una alta capacidad de procesamiento de


información, usado típicamente como el CPU de una computadora digital. Está compuesto
básicamente por un camino de datos (la conexión de un ALU con sus registros) y una unidad de
control.

Los microprocesadores pueden clasificarse como CISC y RISC

En la siguiente tabla se muestra el significado de estos acrónimos

Procesadores RISC. Procesadores CISC.-


R: Reduced C: Complex
I: instruction I: Instruction
S: Set S: Set
C: Computer C: Computer

Tabla 1.1 Microprocesadores CISC y RISC

Si una máquina RISC requiere 4 ó 5 instrucciones para hacer lo que una máquina CISC hace en una
instrucción, pero si las instrucciones RISC son diez veces más rápidas, RISC gana.

Otro concepto muy importante, es el de Sistema mínimo, el cual consiste en agregarle a un


microprocesador, los elementos indispensables necesarios para que pueda ejecutar una tarea
específica

Computadora: Es un sistema digital de alta capacidad de procesamiento de información, recibe


datos de entrada, genera resultados a alta velocidad y con gran exactitud, mediante la ejecución
de programas.

5
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 1 Bloques básicos que forman una computadora digital

Arquitectura de von Neumann


Arquitectura Von Neumann: Una parte del “Mapa” de memoria está reservado para contener las
instruccionesy otra corresponde a datos, esto implica que deben usarse los mismos buses para
buscar las instrucciones en la memoria y para tener acceso a los datos.

6
Apuntes de Microcontroladores O22 Ricardo Álvarez González

par

Ilustración 2Arquitectura Von Neumann

7
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 3 Ejemplo de Mapa de memoria, de un sistema mínimo basado en arquitectura Von Neumann

Como se muestra en la figura 3, el espacio de memoria se divide en dos partes: la primera esta
reservada para instrucciones, esta se conoce como la parte baja del mapa de memoria, ya que
inician en el valor más bajo del bus de direcciones, es decir, cuando todos los bits del bus de
direcciones son cero. La sección de datos del mapa de ejemplo termina cuando los bits del bus de
direcciones son uno, y se conoce como parte alta.

Arquitectura Harvard
Aquí existen dos espacios de memoria independientes para las instrucciones y los datos, por lo
que los mapas de memoria de programa y de memoria de datos son ajenos. Se puede accesar
concurrentemente a instrucciones y a datos.

Es mucho más rápida, va de la mano con RISC.

8
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 4Arquitectura Harvard

9
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 5 Ejemplos de mapas de memoria en la arquitectura Harvard

Los componentes de una computadora estan conectados mediante buses:

Bus de direcciones: Cuando el procesador “lee instrucciones de” ó “escribe datos a” la memoria a
la que desea accesar. Cada dispositivo de E/S como un monitor, teclado o disco duro también
tienen una dirección de memoria.

Los datos son transferidos vía el bus de datos, cuando el CPU busca datos de la memoria primero
se leen las direcciones del bus de direcciones, después el microprocesador genera la señal de
lectura, y accede a las instrucciones mediante el bus de datos.

El bus de control, consisteenun conjunto de señales dedicadas a realizar operaciones tales como
lectura (RD), escritura (WR), especificar si una lectura o escritura se refiere a un dispositivo de
memoria, o a un dispositivo de salida (M/IO), la señal de reset etc.

10
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 6 Computadora de tres buses

Un sistema puede tener una jerarquía de buses:


Puede usar bus de direcciones, de datos y de control para accesar a la memoria y a un controlador
de E/S. El controlador de E/S, en cambio, podría accesar a todos los dispositivos de E/S usando un
segundo bus llamado: Bus local ó Bus de E/S. La perspectiva práctica describe al bus PCI, un bus
local usado comunmente en computadoras personales

11
Apuntes de Microcontroladores O22 Ricardo Álvarez González

U3
29 5
A1 D0
30 4
A2 D1
31 3
A3 D2
32 2
A4 D3
33 1
A5 D4
34 64
A6 D5
35 62
A7 D7
36 63
A8 D6
37 61
A9 D8
39 60
A11 D9
38 58
A10 D11
40 59
A12 D10
41 57
A13 D12
42 56
A14 D13
43 55
A15 D14
44 54
A16 D15
45
A17
46 6
A18 AS
47 7
A19 UDS
48 8
A20 LDS
51 9
A22 R/W
50
A21
52 11
A23 BG
13
BR
12
BGACK
10
DTACK
19 22
VMA BERR
21
VPA
28
FC0
20 27
E FC1
15 26
CLK FC2
25
IPL0
17 24
HALT IPL1
18 23
RESET IPL2
68000
Ilustración 7 Pines del microprocesador 68000

12
Apuntes de Microcontroladores O22 Ricardo Álvarez González

NÚMEROS EN BINARIO, HEXADECIMAL Y DECIMAL


Antes de entrar de lleno a la revisión de los conceptos arquitectónicos fundamentales de los
sistemas mínimos, es importante recordar los equivalentes en binario y decimal de los números
hexadecimales, ya que la notación hexadecimal es abreviada, debido a que cada uno de sus
números representan 4 bits, es más cómodo y menos susceptible de error escribir un número que
cuatro:

decimal Binario Hexadecimal


0 0000 0
1 0001 1
2 0010 2
3 0011 3
4 0100 4
5 0101 5
6 0110 6
7 0111 7
8 1000 8
9 1001 9
10 1010 A
11 1011 B
12 1100 C
13 1101 D
14 1110 E
15 1111 F
Tabla 1: Equivalentes binarios y decimales de los números hexadecimales

Es altamente recomendable, que el lector memorice estos equivalentes en binario de los números
hexadecimales, ya que finalmente cualquier microprocesador y microcontrolador solamente
procesa números binarios, pero para las personas que escribirán un programa en lenguaje
ensamblador, es más cómodo usar la notación abreviada del hexadecimal. Cualquier número
binario puede convertirse rápidamente al hexadecimal agrupando los bits de cuatro en cuatro,
iniciando por el bit menos significativo (LSB), por ejemplo:

El número de 8 bits 0011 1001, se convierte rápidamente al hexadecimal reemplazando sus dos
grupos de 4 bits, por su equivalente en hexadecimal: 39, como veremos posteriormente, por
compatibilidad con el lenguaje ensamblador de los PICs, podemos anteponer 0x al número para
especificar que se trata de un hexadecimal: 0x39, incluso esta notación nos sirve a nosotros
también para no confundirlo con el treinta y nueve decimal.

Otro ejemplo:

11001100010, formando grupos de cuatro bits, iniciando por el LSB tenemos:

110 0110 0010 que es equivalente al hexadecimal 0x662,

13
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Nótese que el último grupo solo fue de 3 bits, pero podemos agregarle un cero a la izquierda sin
alterar su valor, para completar los cuatro bits, teníamos 110, agregándole el cero: 0110
corresponde al hexadecimal 6. Se pueden agregar los ceros necesarios a la izquierda
(correspondiente al número hexadecimal más significativo), para formar grupos de cuatro bits y
reemplazarlo por su equivalente hexadecimal fácilmente.

Ejercicio 1
Convierta los números binarios a hexadecimal, sustituyendo directamente los grupos de 4 bits
por su equivalente en hexadecimal

a. 110011001010101
b. 110001101010011
c. 101010101110110
d. 110101101001111
e. 100101111101011

Ejercicio 2
Convierta los números hexadecimales a binario, sustituyendo directamente cada dígito decimal
por su equivalente binario
a. 9896
b. A7F2
c. 73B1
d. D53A
e. B3F5

14
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Microcontroladores
 Un microcontrolador es una computadora completa de capacidades limitadas orientada a
efectuar tareas de control, la cual se encuentra encapsulada en un solo circuito integrado.
 Es un sistema mínimo encapsulado en un solo circuito integrado, el cual contiene
memorias de: programa, datos, datos no volátiles (en algunos casos), puertos de
entrada/salida, temporizadores/contadores, temporizador vigía, oscilador, unidades de
comunicación serial, convertidores analógico digitales etc.

Existe una amplia variedad de fabricantes de microcontroladores, entre los cuales podemos
mencionar algunos de ellos:

 INTEL, el cual es considerado como el padre de los microcontroladores, con la familia MCS
8048, posteriormente comercializó a la popular familia MCS 8051, ambas de 8 bits, tiene
también poderosas familias de microcontroladores de 16 bits, por ejemplo: MCS96,
algunos elementos de esta familia tienen convertidores A/D integrados y otros tienen
controladores de motores.

 Freescale antes MOTOROLA, con sus familias de microcontroladores 68HC05, 68HC07, se


usaron bastante en las computadoras de los automóviles.

 NATIONAL con sus microcontroladores COP 8.

 ZILOG contribuye con sus dispositivos Z84 y Z86

 TEXAS INSTRUMENTS tiene su familia de microcontroladores de 8 bits TMS370, a la cual


pertenecen dispositivos con una variedad de periféricos y prestaciones, en encapsulados
desde 28 hasta 68 pines.

 ATMEL inicialmente contribuyó con microcontroladores que eran “clones” de otros


fabricantes, especialmente de Intel, pero bajo tecnología Flash, uno de sus elementos
característicos es el 89C51, el cual es un clon del Intel 87C51. Actualmente contribuye de
manera muy importante con sus microcontroladores AVR. Las tarjetas de desarrollo
“Arduino” están elaboradas microcontroldadores AVR.

 MICROCHIP, con su amplia gama de familias de microcontroladores de 8, 16 y 32 bits,


presentan desde microcontroladores en encapsulados de 6 pines, 33 instrucciones y stack
de dos niveles (familia 10F), dispositivos de 8 pines con un conjunto de 33 instrucciones
(familia 16c5x), familias de 35 instrucciones con chips con una variedad de características y
consecuentemente, diversos números de pines (familias 16xxx), familias poderosas de 77

15
Apuntes de Microcontroladores O22 Ricardo Álvarez González

instrucciones, con un tamaño de palabra de instrucción de 16 bits (familias: 17xxx,


18xxx)varios de estos microcontroladores disponen también de interfaz USB., también
ofrece sus familias de Controladores digitales de señales: los dsPICs, los cuales son chips
poderosos de 16 bits que incluyen instrucciones para procesamiento de señales mediante
su máquina DSP, debido al auge que han tenido estos procesadores, el fabricante también
ofrece estos chips, pero sin la máquina DSP (para aplicaciones que no usan las
instrucciones DSP), obteniendo así la familia PIC24XXX; para realizar aplicaciones
inalámbricas: los rfPICs hasta llegar a los poderosos microcontroladores de 32 bits, con la
familia PIC32.

Cada uno de los fabricantes antes mencionados proveen típicamente de las especificaciones de
sus chips (data sheets), notas de aplicación, herramientas de desarrollo etc. Algunos fabricantes
venden esta información, otros la proporcionan libremente en sus sitios de internet.

16
Apuntes de Microcontroladores O22 Ricardo Álvarez González

U1
19 39
XTAL1 P0.0/AD0
38
P0.1/AD1
37
P0.2/AD2
18 36
XTAL2 P0.3/AD3
35
P0.4/AD4
34
P0.5/AD5
33
P0.6/AD6
9 32
RST P0.7/AD7
21
P2.0/A8
22
P2.1/A9
23
P2.2/A10
29 24
PSEN P2.3/A11
30 25
ALE P2.4/A12
31 26
EA P2.5/A13
27
P2.6/A14
28
P2.7/A15
1 10
P1.0 P3.0/RXD
2 11
P1.1 P3.1/TXD
3 12
P1.2 P3.2/INT0
4 13
P1.3 P3.3/INT1
5 14
P1.4 P3.4/T0
6 15
P1.5 P3.5/T1
7 16
P1.6 P3.6/WR
8 17
P1.7 P3.7/RD
80C31

Ilustración 8 Esquema de pines del microcontrolador 8031

17
Apuntes de Microcontroladores O22 Ricardo Álvarez González

PROCESADORES DIGITALES DE SEÑALES: DSP


Los DSPs son micropocesadores diseñados específicamente para realizar, como su nombre lo dice,
el procesamiento de señales digitales, tienen recursos de hardware específicos para poder
desarrollar su tarea, como los multiplicadores-acumuladores, conocidos comúnmente como
MACs.

Ilustración 9: Diagrama de bloques de un DSP de Texas Instruments

MICROCONTROLADORES PIC 18F4550


Ahora iniciaremos revisando algunas generalidades de estos microcontroladores:

18
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 10: Diagrama de pines

Como se puede apreciar en la figura anterior, cada patita o también llamado “pin”, tiene varias
funciones asociadas, una de ellas es llamada su función principal y las otras funciones alternas, el
reto para el lector es escribir programas en donde seleccione el funcionamiento que se necesita,
en una aplicación específica.

ORGANIZACIÓN DE LA MEMORIA
Estos dispositivos cuentan con tres bloques de memoria:
 Memoria de programa (instrucciones)
 Memoria RAM de datos
 Memoria EEPROM de datos

La memoria de datos y de programa usan buses independientes, lo cual permite acceso


concurrente a esos bloques, debido a la arquitectura Harvard.

Organización de la memoria de programa.


Un contador de programa de 21 bits es capaz de direccionar un espacio de memoria de programa
de 2 Mbyte (MB). Accediendo a una localidad que este entre la memoria implementada
físicamente y la dirección 2 MB causará una lectura de ceros (una instrucción NOP).

19
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Los PIC 18F4550 tienen 32 Kbyte (KB) de memoria Flash (32768 bytes), esto implica que pueden
almacenar hasta 16384 (16K) palabras de instrucción simple, con lo que deducimos que cada
instrucción simple es de dos bytes, es decir de 16 bits.

El vector de reset es la dirección 0000h y existen dos vectores de interrupción:el de alta prioridad
tiene la dirección 0008h y el de baja prioridad la 0018h.

La figura siguiente muestra el mapa de memoria de programa para los dispositivos PIC 18FX550

Ilustración 11Mapa de memoria de programa

20
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Stack
La pila (stack) permite cualquier combinación de hasta 31 llamadas y reconocimientos de
interrupción. El contador del programa (PC) es metido(pushed) al stack, cuando se ejecuta una
instrucción CALL o RCALL o cuando una interrupción es reconocida. El PC es recuperado (pulled)
del stack, en cualquiera de las instrucciones siguientes: RETURN, RETLW o RETFIE.
El stack funciona como una RAM de 31 palabras de 21 bits cada una y un apuntador del stack
(STKPTR) de 5 bits.

La parte alta del stack es de lectura y escritura. Existen tres registros: TOSU, TOSH y TOSL, que
mantienen el contenido de la localidad apuntada por el registro STKPTR, esto permite a los
usuarios implementar un stack por software si es que fuera necesario.

El registro STKPTR contiene el valor del apuntador del stack y los bits de estado STKFUL (stack
lleno) y STKUNF (subflujo del stack). El registro 4-1 muestra el registro STKPTR. El apuntador del
stack se incrementa cuando se introducen valores en la pila, y se decrementa cuando se extraen
valores de ella.

Reinicializaciones (resets) por stack lleno, o por desbordamiento por


defecto del stack.
Estos resets son habilitados por la programación del bit STVREN. Cuando este bit es deshabilitado,
la condición de full o de underflow pondrá los bits STKFUL o STKUNF, respectivamente, pero no
causará una reinicialización del dispositivo, si el bit STVREN es puesto, además de ponerse los bits
antes mencionados en caso de que se llene el stack o se produzca un subflujo, causará que se
reinicie (reset) el procesador. Los bits STKFUL y STKUNF deben de limpiarse por software o
mediante un reset por apagado del dispositivo (POR).

PCL, PCLATH Y PCLATU


El contador de programa (PC) especifica la dirección en la que se buscará la instrucción (fetch)
para su ejecución. El PC es de 21 bits de ancho. El byte mas bajo es llamado el registro PCL, este
registro es de lectura y escritura. El byte alto es el registro PCH, este registro contiene los bits
PC<15:8> y no se puede leer o escribir directamente; se pueden hacer actualizaciones al registro
PCH se pueden efectuar mediante el registro PCLATH. El byte superior es llamado PCU, este
registro contiene los bits PC<20:16> y no se puede leer o escribir directamente, se pueden hacer
correcciones al registro PCU mediante el registro PCLATU.

El PC direcciona bytes en la memoria de programa. Para prevenir que el PC este desalineado con
las palabras de instrucción, el LSB del PCL esta fijo al valor de “0”. El PC incrementa por dos las
direcciones de instrucciones secuenciales en la memoria de programa.

21
Apuntes de Microcontroladores O22 Ricardo Álvarez González

CICLO DE INSTRUCCIÓN.
La entrada de reloj (mediante OSC1) es dividida internamente por cuatro, para generar cuatro
señales de reloj en cuadratura, no traslapados, llamados Q1, Q2 Q3 y Q4. Internamente el PC es
incrementado cada Q1, la instrucción es buscada (fetch) de la memoria de programa y capturada
en el registro de instrucción en Q4. La instrucción es decodificada y ejecutada durante el siguiente
Q1 hasta Q4. Las señales de reloj y la ejecución del flujo de instrucciones se muestran en la
siguiente figura:

Ilustración 12 División del ciclo de reloj

FLUJO DE INSTRUCCIÓN Y SEGMENTACIÓN.


Un ciclo de instrucción consiste de cuatro ciclos Q: Q1, Q2, Q3 y Q4, la búsqueda de la instrucción
y la decodificación son segmentadas (pipelined) de tal manera que la búsqueda toma un ciclo de
instrucción, mientras que la decodificación y la ejecución toman otro ciclo de instrucción. Sin
embargo, debido a la segmentación, cada instrucción se ejecuta efectivamente en un solo ciclo. Si
una instrucción causa que el contador de programa cambie (goto, por ejemplo), entonces se
necesitan dos ciclos para completar la instrucción.

Ilustración 13 Ejemplo de ejecución de instrucciones

22
Apuntes de Microcontroladores O22 Ricardo Álvarez González

INSTRUCCIONES EN MEMORIA DE PROGRAMA.


La memoria de programa es direccionada en bytes. Las instrucciones son almacenadas como dos o
cuatro bytes en memoria de programa. El byte menos significativo de una palabra de instrucción,
siempre es almacenado en una localidad de memoria de programa en una localidad par (LSB=0).

ORGANIZACIÓN DE LA MEMORIA DE DATOS


La memoria de datos es implementada como RAM estática. Cada registro en la memoria de datos
tiene una dirección de 12 bits, permitiendo hasta 4096 bytes de memoria de datos. En la figura 9
se muestra la organización de la memoria de datos para los PIC18FXX2.

El mapa de memoria de datos está dividido en 16 bancos que contienen 256 bytes cada uno. Los
cuatro bits menos significativos del registro de selección de bancos (BSR<3:0> seleccionan cual
banco será elegido, los cuatro bits más significativos del BSR no son implementados.

Ilustración 14 Almacenamiento de instrucciones en memoria de programa

La memoria de datos contiene registros de función especial (SFR) y registros de propósito general
(GPR). Los SFRs son usados para control y estado del controlador y funciones periféricas, mientras
que los GPRs son usados para abastecimiento de datos y para guardar resultados de operaciones
de la aplicación del usuario.

Los SFRs inician en la última localidad del banco 15 (0xfff) y se extienden hacia abajo. Cualquier
espacio disponible más allá de los SFRs en el banco, podrían implementarse como GPRs. Los GPRs

23
Apuntes de Microcontroladores O22 Ricardo Álvarez González

inician en la primera localidad del banco 0 y crecen hacia arriba. Cualquier lectura a una localidad
no implementada se leerá como ceros.

24
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 15 Mapa de memoria de datos

25
Apuntes de Microcontroladores O22 Ricardo Álvarez González

La memoria de datos puede accederse directa o indirectamente. El direccionamiento directo


podría requerir el uso del registro BSR. El direccionamiento indirecto requiere el uso de un registro
de selección de archivo (FSR) y un operando de archivo indirecto (INDFn). Cada FSR mantiene una
dirección de 12 bits que puede usarse para acceder a cualquier localidad en la memoria de datos,
sin necesidad de cambiarse de banco.

Para asegurarse que los registros comúnmente usados (SFRs y GPRs seleccionados) puedan
accederse en un solo ciclo, sin importar el valor del registro BSR, se ha implementado un banco de
acceso. Un segmento del banco 0 y un segmento del banco 15 comprenden el acceso a la RAM.

REGISTROS DE FUNCIÓN ESPECIAL


Los registros de función especial (SFRs) son registros usados por el CPU y módulos periféricos para
controlar la operación deseada del dispositivo. Estos registros se implementan como RAM
estática.
Los SFRs pueden clasificarse en dos conjuntos:
 SFRs asociados con el dispositivo genérico o núcleo (core).
 SFRs asociados con las funciones periféricas.

BANCO DE ACCESO
El banco de acceso es una mejora arquitectónica la cual es muy útil para la optimización de código
de un compilador de C. Las técnicas usadas por un compilador de C pueden ser útiles para
programas escritos en ensamblador.

La región de la memoria de datos puede utilizarse para:

 Almacenamiento de cálculo intermedio de valores.


 Variables locales de subrutinas.
 Almacenamiento/ conmutación rápida de variables.
 Variables comunes.
 Evaluación/ control rápido de SFRs (sin recurrir a los bancos).

El banco de acceso está compuesto de los 160 bytes superiores en el banco 15 (SFRs) y los 96
bytes inferiores en el banco 0. Esas dos secciones serán referidas como el acceso a la RAM alta y el
acceso a la RAM baja, respectivamente.
Un bit en la palabra de instrucción, especifica si la operación ocurre en el banco especificado por el
registro BSR o en el banco de acceso. Este bit es denotado por el bit “a” (por bit de acceso).

Cuando a=0, implica que se permanece en el banco de acceso y la última dirección en el acceso a
la RAM baja es seguida por la primera dirección en el acceso a la RAM alta. El acceso a la RAM alta

26
Apuntes de Microcontroladores O22 Ricardo Álvarez González

mapea los registros de función especial (SFRs), de tal manera que esos registros pueden accederse
sin ningún otro apoyo de software. Esto es útil para verificar las banderas de estado y para
modificar los bits de control.

REGISTROS DE SELECCIÓN DE BANCOS


La necesidad de un espacio grande de memoria de propósito general, origina un esquema de
bancos de memoria RAM. La memoria de datos está seccionada en dieciséis bancos. Cuando se
usa direccionamiento directo, el registrode selección debanco (BSR) debe configurarse para el
banco deseado.

BSR<3:0> mantiene los 4 bits superiores de la dirección de 12 bits de la RAM. Los bits BSR<7:4>
siempre se leerán como “0”s , y su escritura a ellos no tendrá efecto.

La instrucción MOVLB se proporciona en el conjunto de instrucciones, para asistir en la selección


de los bancos.

Si el banco seleccionado actualmente no está implementado, cualquier lectura será de “0”s, y


todas las escrituras serán ignoradas. Los bits del registro de estado (STATUS) serán puestos/
limpiados correctamente, de acuerdo a la instrucción ejecutada.
Cada banco se extiende hasta FF (256 bytes). Toda la memoria de datos es implementada como
RAM estática.

Una instrucción MOVFF ignora el BSR, debido a que las direcciones están incrustadas en la palabra
de instrucción.

REGISTRO DE ESTADO (STATUS).


El registro de estado (le llamaremos simplemente status en lo sucesivo), contiene el estado
aritmético del ALU. El registro STATUS puede ser el destino para cualquier instrucción, como
sucede con cualquier otro registro. Si el registro STATUS es el destino de una instrucción que
afecta a la bandera de cero (Z), al acarreo en el cuarto bit (DC), al acarreo (C), al bit de sobre flujo
(OV) o la bandera de signo negativo (N), entonces la escritura a esos cinco bits es deshabilitada.
Esos bits son puestos o limpiados de acuerdo a la lógica del dispositivo. Por lo tanto, el resultado
de una instrucción con el registro STATUS como destino puede ser diferente del esperado. Se
recomienda entonces, que solamente las instrucciones BCF, BSF, SAWPF, MOVFF Y MOVF sean
usadas para alterar el registro de estado, debido a que esas instrucciones no afectan a los bits de
bandera del registro status: Z, C, DC, OV ó N.

27
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Registro STATUS
bit 7 bIt6 bIt5 bIt4 bIt3 bIt2 bIt1 bit0
U-0 U-0 U-0 R/W-x R/W-x R/W-x R/W-x R/W-x
- - - N OV Z DC C

Ilustración 16 Registro de estado del procesador

Registro RCON
bit 7 bIt6 bIt5 bIt4 bIt3 bIt2 bIt1 bit0
R/W-0 U-0 U-0 R/W-1 R/W-1 R/W-1 R/W-0 R/W-0
IPEN - - /RI /T0 /PD /POR /BOR
Bit 7: IPEN: Bit de habilitación de prioridad de interrupción

1=Habilita niveles de prioridad en las interrupciones

0= Deshabilita niveles de prioridad en las interrupciones (modo compatibilidad con


16cXXX)

Bit 6:5 No implementado, léase como cero

Bit4: /RI Bit de bandera de instrucción de reset

REGISTRO RCON
El registro de control de reset (RCON) contiene los bits de bandera que permiten diferenciar entre
las fuentes de reset del dispositivo. Estas banderas incluyen a los bits TO, PD, POR, BOR y RI. Este
registro es de lectura y escritura.

28
Apuntes de Microcontroladores O22 Ricardo Álvarez González

CONFIGURACIÓN DEL OSCILADOR


LosPIC18F2455/2550/4455/4550cuentan con una amplia variedad de opciones para el oscilador,
además,debido a la existencia del módulo USB que requiere una señal de reloj estable, se necesita
contar con un módulo de reloj independiente para el, que sea compatible con las velocidades de
baja y alta velocidad requeridas por el estandar USB.

Para cumplr con éstos requerimientos, esta familia tiene una nueva ramificación del reloj, para
proporcionar una señal de 48 MHz, para que opere el módulo USB a máxima velocidad. Debido a
que esta es derivada a partir de la fuente primaria de oscilación, existe una gran cantidad de
preescalers y postscaler para generar una amplia variedad de frecuencias de oscilación.

Estos chips pueden funcionar en doce distintas configuraciones del oscilador.

Para saber mas:

Consulte en las hojas de datos del fabricante, las opciones del oscilador.

29
Apuntes de Microcontroladores O22 Ricardo Álvarez González

RESUMEN DEL CONJUNTO DE INSTRUCCIONES


Con la finalidad de iniciar con algunos ejemplos de aplicación, se presentarán ahora el conjunto de
instrucciones de la familia PIC18FXXX.

La mayoría de las instrucciones son ocupan una sola palabra de memoria (16 bits), pero hay tres
instrucciones que requieren dos localidades de la memoria de programa.

Cada palabra de instrucción es de 16 bits dividida en un código de operación (opcode), lo cual


especifica el tipo de instrucción y uno o más operandos, lo cual especifica la operación de la
instrucción.

El conjunto de instrucciones es altamente ortogonal y está agrupado en cuatro categorías básicas:

 Operaciones orientadas a bytes.


 Operaciones orientadas a bits.
 Operaciones con literales.
 Operaciones de control.

El conjunto de instrucciones de los PIC18FXXX está resumido en la tabla 26-2.

La mayoría de las instrucciones orientadas a bytes tienen tres operandos:

1. El registro de archivo (representado por “f”).


2. El destino del resultado (representado por “d”).
3. La memoria accedida (representada por “a”).

El operando de registro de archivo “f” indica cual registro de archivo será usado por la instrucción.

El operando de destino “d” indica en donde se colocará el resultado de la operación:

 Si d=0, el resultado es colocado en el registro de trabajo (WREG).


 Si d=1, el resultado es colocado en el registro f especificado por la instrucción.

Todas las instrucciones orientadas a bits tienen tres operandos:

1. El registro de archivo (representado por “f”).


2. El bit en el registro de archivo (representado por “b”).
3. La memoria accedida (representada por “a”).

El operando de bit “b”, selecciona el número del bit afectado por la operación, mientras el de
registro de archivo “f” representa el número del archivo en el cual está localizado el bit.

30
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Las instrucciones de literal pueden usar algunos de los siguientes operandos:

 Un valor de literal que será cargado en un registro de archivo, especificado por “k”.
 El registro deseado en el cual se cargará el valor de la literal (representado por “f”).
 Ningún operando requerido (representado por “-”).

Las instrucciones de control pueden usar algunos de los siguientes operandos:

 Una dirección de memoria de programa (especificado por “n”).


 El modo de las instrucciones Call o Return (especificado por “s”).
 El modo de instrucciones para lectura y escritura de la tabla (especificado por “m”).
 Ningún operando requerido (representado por “-”).

31
Apuntes de Microcontroladores O22 Ricardo Álvarez González

32
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Todas las instrucciones de una sola palabra son ejecutadas en un solo ciclo, a menos que una
prueba condicional sea verdadera, o que el contador de programa haya cambiado como resultado
de la instrucción. En esos casos, la instrucción toma dos ciclos de instrucción, con el ciclo de
instrucción adicional ejecutado como un NOP.

Una vez que se ha presentado superficialmente el repertorio de instrucciones de los PIC18FXXX,


para mostrar algunos programas de ejemplo, solo nos hace falta revisar algunas directivas del
ensamblador MPASM, que son imprescindibles para escribir programas.

PROGRAMACIÓN EN LENGUAJE ENSAMBLADOR


Los ejemplos que se muestran en estas notas en lenguaje ensamblador, están escritos para
ejecutarse con el ensamblador MPASM, que viene incluido en el MPLAB IDE versión 8.92 (y
versiones anteriores). Si se desea usar el MPLABX, deberán de cambiarse algunas de las directivas
de los ejemplos mostrados, de lo contrario generarán errores de sintaxis; así como también tomar
en cuenta la ubicación de las variables en memoria, ya que MPLABX genera siempre código
relocalizable.

PANORAMA GENERAL DE MPASM


MPASM es una aplicación basada en el sistema operativo DOS o en WINDOWS, que suministra una
plataforma para desarrollar código en lenguaje ensamblador para las familias de
microcontroladores PIC de 12-bit, 14-bit, 16-bit, y 16-bit incrementadas de Microchip,
manteniendo una compatibilidad directa con el ambiente de desarrollo integrado (IDE) MPLAB.

33
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Directivas del lenguaje


Las directivas son comandos que aparecen en el código fuente, pero no son traducidas
directamente en código de operación. Son usadas para controlar el ensamblador: su entrada,
salida y localización de datos. Muchas de las directivas de ensamblador tienen nombres y formatos
alternos. Esos podrían existir para proporcionar compatibilidad con ensambladores previos de
Microchip y para ser compatible con prácticas individuales de programación.

Existen cinco tipos básicos de directivas proporcionadas por MPASM:

a. Directivas de control. Permiten secciones de código condicionalmente ensamblado.


b. Directivas de datos. Controlan la localización de variables en memoria y proporcionan una
manera para referirse a los datos simbólicamente mediante nombres significativos.
c. Directivas de listado. Controlan el formato del archivo de listado (*.lst) generado por
MPASM. Permitiendo la especificación de títulos, paginación y otros controles del listado.
d. Macro directivas. Controlan la localización de datos y la ejecución mediante definiciones
de macros.
e. Directivas de archivo Objeto. Se usan solamente cuando se crea un archivo objeto.

Ejemplo de instrucciones:

34
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Configuración de puertos de entrada-salida


Ahora estamos listos para escribir nuestro primer programa. Se trata de un ejemplo muy simple,
en el cual se han colocado leds en cada uno de los pines del PUERTO D, lo que queremos hacer es
encender secuencialmente cada uno de ellos, para lo cual debemos de declarar dicho puerto como
salida, lo cual conseguimos escribiendo la palabra adecuada de configuración en su registro de
dirección de datos TRISD, tomando en cuenta que al escribir un 1 en un bit del registro TRISD,
configurará su bit de puerto asociado como entrada, en el caso de escribir un cero se configurará
su bit de puerto respectivo como salida. Esto se muestra en las figuras siguientes, debido a que
esto se cumple para cualquier bit del puerto D, (y en verdad para cualquier puerto de los
microcontroladores PIC), se han representado como los bits de puerto m y n, en donde pueden
tener valores entre 0 y 7, ya que PORTD es de 8 bits

TRISDm 0
PORTDm Out, Salida

TRISDn 1
PORTDn In, entrada

Nótese que esto es mas facil de recordar si escribimos los nombres en ingles: 1 In entrada, 0 Out
salida

TRISD7 TRISD6 TRISD5 TRISD4 TRISD3 TRISD2 TRISD1 TRISD0


0 0 0 0 0 0 0 0

PORTD7 PORTD6 PORTD5 PORTD4 PORTD3 PORTD2 PORTD1 PORTD0


Salida Salida Salida Salida Salida Salida Salida Salida

Con instrucciones:

Clrf TRISD ;todos los bits de PORTD son salida

Otro ejemplo:

TRISD7 TRISD6 TRISD5 TRISD4 TRISD3 TRISD2 TRISD1 TRISD0


1 0 1 0 1 1 0 0
PORTD7 PORTD6 PORTD5 PORTD4 PORTD3 PORTD2 PORTD1 PORTD0
entrada salida entrada salida entrada entrada salida salida
Con las instrucciones:

Movlw 0XAC

35
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Movwf TRISD
Configuramos el puerto d como ya lo mencionamos: RD7,RD5,RD3 y RD2 como entradas y el resto
de los pines del PORTD como salidas.

Estructura de los programas en lenguaje ensamblador


Se deben de respetar las secciones de un programa en ensamblador, para hacerlo eficiente, legible
y evitar problemas como desbordamiento del stack, también llamado volcado de pila.

Cuando sucede este error, se genera un reset, el programa no hace su ciclo completo debido al
volcado de pila, incluso los simuladores advierten cuando esto ocurre:

36
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 17 Error de volcado de pila en el simulador Issis Proteus

Ilustración 18 Error de volcado de pila, mostrado en el simulador de MPLAB

Ejemplo: Controlando ocho leds


;******************************************************************************

LISTP=18F4550 ;directiva para efinir el procesador


#include<P18F4550.INC> ;definiciones de variables especificas del procesador

37
Apuntes de Microcontroladores O22 Ricardo Álvarez González

;******************************************************************************
;Bits de configuración
CONFIGFOSC=INTOSC_XT;Oscilador INT usado por el uC , XT usado por el USB
CONFIGBOR=OFF ;BROWNOUT RESET DESHABILITADO
CONFIGPWRT=ON ;PWR UP Timer habilitado
CONFIGWDT=OFF ;Temporizador vigia apagado
CONFIGMCLRE=OFF ;Reset apagado
CONFIGPBADEN=OFF
CONFIGLVP=OFF
;******************************************************************************
;Definiciones de variables
cont equ0
;******************************************************************************
;Reset vector
ORG 0x0000
;Inicio del programa principal
bcf OSCCON,IRCF2,0;Oscilador interno a 31 kHz
movlw0x0F
movwfADCON1,0;Puertos Digitales
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
bsf PORTD,0,0 ;enciende LED conectado en RD0
correirlcf PORTD,F,0
call retardo
bra correi
;******************************************************************************
retardomovlw 0xff
movwf cont,0
nada nop
decfsz cont,1,0
bra nada
return
END

Programa: Rotación de luces

En la figura siguiente se muestra una pantalla del ambiente de desarrollo integrado MPLAB. En la
ventana en donde pregunta si se desea que el proyecto genere codigo absoluto o relocalizable,
debemos seleccionar absoluto, por ahora.

38
Apuntes de Microcontroladores O22 Ricardo Álvarez González

En la figura siguiente se muestra una foto con la conexión de los leds:

Para alambrar la práctica en una tablilla de prototipos (proto board), presentamos el diagrama de
pines:

39
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Diagrama de pines del microcontrolador 18F4550

¿Cuánto DURA LA RUTINA RETARDO?


Para estimar su duración, debemos contar la cantidad de ciclos de máquina que consume la rutina.

Instrucciones de la rutina retardo Ciclos de máquina (Tcy)

retardo movlw d’255’ 1


movwf cont,0 1
nada nop 1
nop 1
nop 1
decfsz cont,1,0 1
bra nada 2
return 2

La duración de la rutina es:

2+(1+1+1+1+2)256+2+1-2=3+256*6=1539
ciclos de máquina

¿Cuánto tiempo corresponde a un ciclo de máquina?

Un pic trabaja a Fosc/4

40
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Fosc=31 kHz entonces Fosc/4=31 kHz/4=7.75 kHz, pero el tiempo, es decir el periodo es 1/(7.75
x103)=1/7750=0.12903 ms=129.03 µ s=Tcy

Entonces la duración de la rutina es 1539(129.03 µs)=198577.17µs=198.57717 ms =0.19857717 s

Hemos estimado el tiempo de duración de la rutina retardo, ahora podemos comprobarlo


mediante el simulador Proteus:

Ilustración 19 Medición con el osciloscopio virtual, la duración de la rutina retardo

Como podemos observar en la figura, la base de tiempo del osciloscopio es de 50 ms y vemos que
el pulso en alto de la señal abarca aproximadamente 4 cuadros, por lo que equivale a un tiempo
de 4(50 ms)=200 ms, lo que es muy cercano con el tiempo que estimamos teóricamente de 198.6
ms.

Segunda versión del programa de rotación de luces


;******************************************************************************

LIST P=18F4550 ;directiva para definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
CONFIG FOSC = INTOSC_XT ;Oscilador INT usado por el uC , XT usado por el USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF

41
Apuntes de Microcontroladores O22 Ricardo Álvarez González

;******************************************************************************
;Definiciones de variables
CBLOCK0x000 ;ejemplo de definición de variables en RAM de acceso
cont
ciclo
ENDC ;fin del bloque de constantes
;******************************************************************************
;Reset vector
ORG 0x0000
;Inicio del programa principal
bcf OSCCON,IRCF2,0 ;oscilador interno 31 kHz
movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
bsf PORTD,0,0 ;enciende LED conectado en RD0
correi rlcf PORTD,F,0
call repite ;llama a una rutina más larga, aprox. 5 s
bra correi
;******************************************************************************
retardo movlw 0xFF ;Dura un tiempo aproximado de 198 ms
movwf cont,0
nada nop
nop
nop
decfsz cont,1,0
bra nada
return
;******************************************************************************
repite movlw d'50' ;llama 50 veces a la rutina retardo= 10 segundos
movwf ciclo ;50(198.6 ms)=9.93 s
llama call retardo
decfsz ciclo,F,0
bra llama
return
END
Programa: Segunda Versión de rotación de luces

En la segunda versión del programa de rotación de luces, se usa una manera alterna para
asignarles nombre a los registros en la memoria RAM, es mediante la directiva CBLOCK, la cual
inicia en cero, después se enlistan el nombre de los registros y les asignará direcciones
consecutivas, terminando con la directiva ENDC, también podríamos declararlos con la directiva
EQU, como en el ejemplo anterior, pero esta es más elegante.

El tiempo en el que durará encendido cada led, será aproximadamente, veinticinco veces más
largo que en el ejemplo 1, esto se logra con la subrutina repitela cual llama a la rutina retardo
veinticinco veces. Nótese como el número de veces se especifica directamente en decimal, para lo

42
Apuntes de Microcontroladores O22 Ricardo Álvarez González

cual es necesario encerrar el número entre apóstrofes y debe ir precedido por una d de “decimal”,
esto está expresado en la instrucción:

movlw d'25' ;llama 25 veces a la rutina retardo

Con esta rutina repite se puede modificar el número de veces que se llamará a la rutina retardo

Ejemplo: Control de un exhibidor de siete segmentos de ánodo común


conectado al PORTD.
Ahora estamos listos para controlar un exhibidor de siete segmentos. Como ya sabemos existen
básicamente dos tipos de displays de siete segmentos, de acuerdo a como se muestra en la
siguiente figura:

20 Displays de siete segmentos

Si ya se entendió el funcionamiento del ejemplo 1, en donde encendemos un led, ahora en este


ejemplo podemos encender ocho leds, dispuestos en un exhibidor de siete segmentos, también
llamado por su nombre en inglésdisplay; se mostrarán los dígitos del 0 al 9, la duración de
exhibición de cada uno de ellos está determinada por la rutina repite del ejemplo anterior.

43
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ejemplo: Control de un exhibidor de siete segmentos


Se muestra en la tabla siguiente, la asignación de los pines del puerto D para la conexión de los
segmentos del display:

RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0


Pto. g f E d c b a
Dec.
cero 1 1 0 0 0 0 0 0 C0
uno 1 1 1 1 1 0 0 1 F9
Tabla E2

Los códigos de siete segmentos para el display de ánodo común, (considerando en


este caso que enciende cada segmento con cero) son los siguientes:

Hexadecimal Binario Digito

C0 1100 0000 0
F9 1111 1001 1
A4 1010 0100 2
B0 1011 0000 3
99 1001 1001 4
92 1001 0010 5
82 1000 0010 6
B8 1011 1000 7
80 1000 0000 8
98 1001 1000 9

Ejercicio E2.1
Usando el mismo orden de los bits mostrado en la tabla E2, genere los códigos de siete segmentos
para los dígitos hexadecimales faltantes, para un exhibidor de siete segmentos de ánodo común

44
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ejercicio E2.2
Genere los códigos de siete segmentos, usando el mismo orden de los bits mostrado en la tabla
E2para los dígitos hexadecimales, para un exhibidor de siete segmentos de cátodo común

;******************************************************************************

LIST P=18F4550 ;directiva para definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
CONFIG FOSC = INTOSC_XT ;Oscilador INT usado por el uC , XT usado por el USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
CBLOCK0x000 ;ejemplo de definición de variables en RAM de acceso
cont
ciclo
ENDC ;fin del bloque de constantes
;******************************************************************************
;Reset vector
ORG 0x0000
;Inicio del programa principal
bcf OSCCON,IRCF2,0 ;Oscilador interno a 31 kHz

movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
cero movlw 0xC0 ;código del cero
movwf PORTD,0
call repite
movlw 0xF9 ;código del uno
movwf PORTD,0
call repite
movlw 0xA4 ;código del dos
movwf PORTD,0
call repite
movlw 0xB0 ;código del tres
movwf PORTD,0

45
Apuntes de Microcontroladores O22 Ricardo Álvarez González

call repite
movlw 0x99 ;código del cuatro
movwf PORTD,0
call repite
movlw 0x92 ;código del cinco
movwf PORTD,0
call repite
movlw 0x82 ;código del seis
movwf PORTD,0
call repite
movlw 0xB8 ;código del siete
movwf PORTD,0
call repite
movlw 0x80 ;código del ocho
movwf PORTD,0
call repite
movlw 0x98 ;código del nueve
movwf PORTD,0
call repite
bra cero
;******************************************************************************
retardo movlw 0xff ;dura aproximadamente 199 ms
movwf cont,0
nada nop
nop
nop
decfsz cont,1,0
bra nada
return
;******************************************************************************
repite movlw d'10' ;llama 10 veces a la rutina retardo
movwf ciclo ;equivale aproximadamente a 2 s
llama call retardo
decfsz ciclo,F,0
bra llama
return
END

Programa E2: Control de un display de siete segmentos

Como podemos apreciar en el código anterior, el control del display es muy simple, consiste
solamente en enviar cada código por el puerto d y llamar a la rutina repite para que permanezca
encendido el tiempo que dure la misma, esto se logra con las instrucciones:

Cero movlw 0xC0 ;código del cero


movwf PORTD,0
call repite

46
Apuntes de Microcontroladores O22 Ricardo Álvarez González

De tal manera que estas tres instrucciones se repiten diez veces, empezando por el código del cero
y terminando con el del nueve, después de esto se regresa el programa nuevamente al código del
cero, con la instrucción de salto incondicional:

bra cero

Se muestra en la siguiente figura el diagrama de la simulación en ISIS Proteus:

21 Ventana de simulación en ISIS

Podemos medir el tiempo, usando el cronómetro del simulador Issis, observamos que todo el
recorrido del programa de 0 a 9, dura un tiempo de 20.2 s, el error de 0.2 s se puede atribuir al
momento de la captura de la pantalla

47
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ejercicio E2.3
Vimos que el ejemplo anterior, consistía en una repetición de diez veces del mismo bloque de
instrucciones. Reescriba el código del ejemplo 2, disminuyendo el número de instrucciones,
usando subrutinas

Ejercicio E2.4
Extienda el programa del ejemplo 2, para mostrar los dígitos hexadecimales del 0,1,2,…,F,0…

Ejemplo: Contador ascendente-descendente


Hasta ahora, hemos realizado ejemplos usando únicamente puertos de salida, por lo cual, el
siguiente ejemplo usará un puerto de entrada RB0, de acuerdo a como se explica en la siguiente
tabla:

RB0 Conteo
1 Ascendente
0 descendente

;******************************************************************************

LIST P=18F4550 ;directiva para definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
CONFIG FOSC = INTOSC_XT ;Oscilador INT usado por el uC , XT usado por el USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado

48
Apuntes de Microcontroladores O22 Ricardo Álvarez González

CONFIG MCLRE=OFF ;Reset apagado


CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
CBLOCK 0x000 ;ejemplo de definición de variables en RAM de acceso
cont
ciclo
ENDC ;fin del bloque de constantes
;******************************************************************************
;Reset vector
ORG 0x0000
;Inicio del programa principal
bcf OSCCON,IRCF2,0
bsf OSCCON,IRCF0,0 ;Oscilador interno a125 kHz
movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
cero movlw 0xC0 ;código del cero
movwf PORTD,0
call repite
btfss PORTB,0,0 ;verifica dirección de conteo
bra nueve
uno movlw 0xF9 ;código del uno
movwf PORTD,0
call repite
btfss PORTB,0,0
bra cero
dos movlw 0xA4 ;código del dos
movwf PORTD,0
call repite
btfss PORTB,0,0
bra uno
tres movlw 0xB0 ;código del tres
movwf PORTD,0
call repite
btfss PORTB,0,0
bra dos
cuatro movlw 0x99 ;código del cuatro
movwf PORTD,0
call repite
btfss PORTB,0,0
bra tres
cinco movlw 0x92 ;código del cinco
movwf PORTD,0
call repite
btfss PORTB,0,0
bra cuatro
seis movlw 0x82 ;código del seis
movwf PORTD,0
call repite
btfss PORTB,0,0

49
Apuntes de Microcontroladores O22 Ricardo Álvarez González

bra cinco
siete movlw 0xB8 ;código del siete
movwf PORTD,0
call repite
btfss PORTB,0,0
bra seis
ocho movlw 0x80 ;código del ocho
movwf PORTD,0
call repite
btfss PORTB,0,0
bra siete
nueve movlw 0x98 ;código del nueve
movwf PORTD,0
call repite
btfss PORTB,0,0
bra ocho
bra cero
;******************************************************************************
retardo movlw 0xff
movwf cont,0
nada nop
decfsz cont,1,0
bra nada
return
;******************************************************************************
repite movlw d'1' ;llama 1 vez a la rutina retardo
movwf ciclo
nada2 nop
call retardo
decfsz ciclo,1,0
bra nada2
return
END
Programa E3: Contador ascendente descendente

En este programa, no es necesario declarar el pin RB0, ya que después de un reset, los puertos del
microcontrolador están declarados como entrada.Una vez que se ha mostrado un digito en el
display, el tiempo determinado por la rutina “repite”, se verifica el nivel en el puerto B, con la
instrucción:

btfss PORTB,0,0

si el nivel de RB0 es alto, la instrucción brincará la instrucción:


bra cero
y mandará a escribir en el puerto D el código de siete segmentos del uno, de lo contrario se
ramificará para mostrar el código de siete segmentos del cero. El programa está formado por la
repetición de las instrucciones mostradas a continuación:

uno movlw 0xF9 ;código del uno


movwf PORTD,0
call repite

50
Apuntes de Microcontroladores O22 Ricardo Álvarez González

btfss PORTB,0,0
bra cero
Se observa en el programa E3 la secuencia completa, notando que si el nivel en RB0 es alto, el
conteo será ascendente, de lo contrario será descendente.

Ejercicio E3.1
Agregue al programa 3 las instrucciones necesarias para exhibir los dígitos hexadecimales de la A
a la F

Interrupciones
Una interrupción consiste en que el procesador suspende temporalmente la tarea que está
ejecutando para atender a algún periférico, mediante la ejecución de una rutina de servicio de
interrupción, una vez que se concluye esta, el procesador continua con la tarea que estaba
ejecutando antes de haber sido interrumpido. Esta familia de microcontroladores tiene múltiples
fuentes de interrupción. A diferencia de una subrutina ordinaria que termina con una instrucción
return, las rutinas de servicio de interrupción deben concluir con la instrucción retfieque
significa “retorno de interrupción habilitada” (return from interrupt enable). Al momento de la
suspensión de una tarea, la dirección de la siguiente instrucción que debería ejecutar, se guarda
en el stack, y se carga el contador de programa con el vector de interrupción. Para los PICS18
existen dos vectores de interrupción:

0x0008 vector de interrupción de alta prioridad

0x0018 vector de interrupción de baja prioridad

Cada fuente de interrupción tiene tres bits para controlar su funcionamiento:

1. El bit de habilitación
2. El bit de bandera
3. El bit de prioridad de interrupción

Existen diez registros para el control de interrupciones:

RCON Registro de control de reset, tiene el bit de habilitación de prioridad de


interrupción: IPEN

INTCON Registro de control de interrupciones


INTCON2 Registro de control de interrupciones

INTCON3 Registro de control de interrupciones

PIR1, PIR2 Registros de solicitud (request) de interrupciones Periféricas, contiene los bits de
bandera de las interrupciones periféricas
PIE1, PIE2 Registros de habilitación (enable) de interrupciones Periféricas, contiene los bits
de habilitación de las interrupciones periféricas
IPR1, IPR2 Registros de prioridad de interrupción

51
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Para saber más, se recomienda revisar en las hojas de datos del fabricante DS39632C:
 Registros INTCON
 Registros PIR
 Registros PIE
 Registros IPR
 Registros RCON

Ejemplo: usando la interrupción externa 0, INT0


Para migrar nuestro ejemplo del conteo ascendente/descendente en el display de siete
segmentos, usando la interrupción externa INT0, necesitamos configurar el registro INTCON:

INTCON
R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-x
GIE/GIEH PEIE/GIEL TMR0IE INT0IE RBIE TMR0IF INT0IF RBIF
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
1 0 0 1 0 0 0 0
Observamos que con el valor 0x90 activamos la interrupción externa 0, denominada INT0. Para
cargar este valor en el registro, usaríamos las instrucciones:

Movlw 0x90

Movwf INTCON

La versión del contador ascendente descendente usando la interrupción externa INT0 es:

;******************************************************************************

LIST P=18F4550 ;directiva para Definir el procesador


#include <P18F4550.INC> ; definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
;CONFIG FOSC = INTOSC_XT ;Oscilador interno para el uC, XT para USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF

52
Apuntes de Microcontroladores O22 Ricardo Álvarez González

;******************************************************************************
;Definiciones de variables
cblock 0x0
cont
ciclo
flags
endc

;******************************************************************************
;Reset vector
ORG 0x0000
bra inicio
org 0x08 ;vector de interrupción de alta prioridad
bra RSI
;Inicio del programa principal
inicio bcf OSCCON,IRCF2,0 ; 000, Oscilador interno a 31 kHz
movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0x90
movwf INTCON,0 ;Configuramos la interrupción externa INT0
cero movlw b'11000000' ;código del cero
movwf PORTD,0
call repite
btfss flags,1,0 ;verifica dirección de conteo
bra nueve
uno movlw 0xF9 ;código del uno
movwf PORTD,0
call repite
btfss flags,1,0 ;verifica dirección de conteo
bra cero
dos movlw 0xA4 ;código del dos
movwf PORTD,0
call repite
btfss flags,1,0 ;verifica dirección de conteo
bra uno
tres movlw 0xB0 ;código del tres
movwf PORTD,0
call repite
btfss flags,1,0 ;verifica dirección de conteo
bra dos
cuatro movlw 0x99 ;código del cuatro
movwf PORTD,0
call repite
btfss flags,1,0 ;verifica dirección de conteo
bra tres
cinco movlw 0x92 ;código del cinco

53
Apuntes de Microcontroladores O22 Ricardo Álvarez González

movwf PORTD,0
call repite
btfss flags,1,0 ;verifica dirección de conteo
bra cuatro
seis movlw 0x82 ;código del seis
movwf PORTD,0
call repite
btfss flags,1,0 ;verifica dirección de conteo
bra cinco
siete movlw 0xB8 ;código del siete
movwf PORTD,0
call repite
btfss flags,1,0 ;verifica dirección de conteo
bra seis
ocho movlw 0x80 ;código del ocho
movwf PORTD,0
call repite
btfss flags,1,0 ;verifica dirección de conteo
bra siete
nueve movlw 0x98 ;código del nueve
movwf PORTD,0
call repite
btfss flags,1,0 ;verifica dirección de conteo
bra ocho
bra cero
;******************************************************************************
retardo movlw 0xff ;esta rutina tarda 128 ms en ejecutarse
movwf cont,0
nada nop
decfsz cont,F,0
bra nada
return
;******************************************************************************
repite movlw d'10' ;esta rutina tarda aprox. 1280 ms en ejecutarse
movwf ciclo,0
llama call retardo
decfsz ciclo,1,0
bra llama
return
;********************************************************************************
RSI bcf INTCON,INT0IF ;apago bit de bandera
btg flags,1 ;bit monitor de interrupción externa
retfie
END

54
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 22 Diagrama del contador ascendente y descendente usando la interrupción externa

Observamos que se introdujo un registro denominado “flags” que nos servirá para monitorear la
activación de la interrupción externa, mediante el bit 1, de tal manera que si este bit es 1, el
conteo será ascendente, de lo contrario será descendente, entonces ahora en el programa
principal se verificará el estado lógico de este bit, en vez del puerto de entrada:

seis movlw 0x82 ;código del seis


movwf PORTD,0
call repite
btfss flags,1,0 ;verifica dirección de conteo
bra cinco
siete movlw 0xB8 ;código del siete

En la versión previa del programa, se verificaba el nivel lógico del puerto:

seis movlw 0x82 ;código del seis


movwf PORTD,0
call repite
btfss PORTB,0,0
bra cinco
siete movlw 0xB8 ;código del siete

Timers
Los timersdenominados temporizadores en español, son dispositivos que nos proporcionan
intervalos regulares de tiempo. Prácticamente cualquier fabricante de microcontroladores incluye
por lo menos un timer en sus dispositivos, pueden programarse para un intervalo de tiempo, y una
vez que se cumple, interrumpen al procesador para avisarle que ha transcurrido el tiempo
programado.

Pero existen muchas maneras de generar intervalos de tiempo. En la antigüedad existieron unos
dispositivos denominados clepsidras, que eran unos tipos de relojes que funcionaban a base de
agua.

55
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Algo similar podemos hacer con la cubeta que se llena con una llave de agua, como la que se
muestra en la figura 5, supongamos que colocamos una cubeta vacia, abrimos la llave y cuando se
llena, han transcurrido 10 segundos, para que no se riegue el agua cerramos la llave justo cuando
empieza a desbordarse el agua. Sabiendo que la cubeta se desbordará en 10 segundos, podemos
lograr que este sistema nos indique cuando ha transcurrido un tiempo menor, por ejemplo, si
quisiéramos que nos indique el tiempo de tres segundos, bastaría con depositar en la cubeta, un
valor de precarga de 7/10 de su capacidad, de tal manera que cuando se desborde, habrán
transcurrido los tres segundos.

23 Con la llave de agua abierta la cubeta se llena en 10 segundos

Para obtener intervalos de tiempo mayores con este mismo sistema, podríamos disminuir el
chorro de agua, cerrando un poco la llave, de tal manera que supongamos que con este ajuste de
la llave, al colocar la cubeta vacía, tarda ahora 10 minutos en llenarse.

56
Apuntes de Microcontroladores O22 Ricardo Álvarez González

24 Con el chorro de agua pequeño, la cubeta se llena en 10 minutos

¿Cuál será el valor de precarga necesario para que este sistema nos indique que ha transcurrido
un tiempo de 6 minutos? Seria depositar en la cubeta 4/10 de su capacidad. Si se ha entendido el
funcionamiento de este sistema, se entenderá fácilmente el funcionamiento típico de los timers.

La familia a la que pertenece el PIC18F4550 incluye los timers:

Timer Número de bits


Temporizador/contador 0 8 ó 16
Temporizador/contador 1 16
Timer2 8
Temporizador/contador 3 16

Temporizador/Contador 0
Este periférico puede funcionar como timer, teniendo como base de tiempo, el ciclo interno de
ejecución de instrucciones Fosc/4, pero también puede funcionar como contador, contando los
impulsos que le llegan por el pin RA4 en su función alterna T0CKI (Timer 0 Clock Input).

Este periférico puede funcionar en dos modalidades: 8 y 16 bits

En la figura siguiente, se muestra el diagrama de bloques del timer 0 en modo de 8 bits. Como se
puede observar, existen multiplexores para seleccionar mediante sus bits de selección (los cuales

57
Apuntes de Microcontroladores O22 Ricardo Álvarez González

son bits de control del timer) su funcionamiento, esto se logra con el bit TOCS (Timer 0 Clock
Select) de tal manera que:

TOCS Configuración
0 Selecciona como señal de sincronía el ciclo interno de instrucción Fosc/4 es decir,
funciona como timer
1 Selecciona comoseñal de sincronía los flancos provenientes del pin RA4/T0CK1,
funcionando entonces como contador externo
El bit TOSE (Timer 0 Select Edge) selecciona el flanco con el que se incrementará el registro TMR0L

TOSE Flanco activo para incrementar TMR0L


0 Ascendente
1 Descendente

25 Diagrama de bloques del Timer contador 0 en modo de 8 bits

Como podemos observar en la figura se puede seleccionar un predivisor (prescaler) programable,


la selección de este predivisor se selecciona con el bit PSA

PSA Prescaler
0 Asignado
1 No asignado

El pre divisor sirve para incrementar la capacidad del timer, si no está asignado, el timer se
incrementará cada vez que reciba un flanco, ó con cada ciclo de instrucción, según se halla
programado como contador o temporizador, respectivamente. Este divisor se puede programar
con los bits T0PS (Timer 0 Preescaler Select) de acuerdo a como lo indica la siguiente tabla:

T0PS2 T0PS1 T0PS0 Valor del


Prescaler
0 0 0 2
0 0 1 4
0 1 0 8
0 1 1 16
1 0 0 32

58
Apuntes de Microcontroladores O22 Ricardo Álvarez González

1 0 1 64
1 1 0 128
1 1 1 256

Estos bits de configuración que hemos descrito, están en el registro de control del timer0, llamado
T0CON:

R/W-1 R/W-1 R/W-1 R/W-1 R/W-1 R/W-1 R/W-1 R/W-1


TMR0ON T08BIT TOCS TOSE PSA T0PS2 T0PS1 T0PS0
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

Como podemos ver en la tabla anterior, el renglón superior indica el valor de los bits después de
un reset, R/W indica que los bits son de lectura/escritura, el renglón inferior indica el número de
bit.

Ya explicamos el funcionamiento de cada bit, solamente faltaron los bits 7 y 6, los cuales tienen la
función:

TMR0ON Función
0 Timer 0 Apagado
1 Timer 0 Encendido

T08BIT Función
0 Timer/Contador 0 de 16 bits
1 Timer/Contador 0 de 8 bits

En la siguiente figura se muestra el diagrama de bloques del temporizador/ contador 0, en


modalidad de 16 bits. Como podemos apreciar en la figura, la diferencia es que se tienen dos
registros de 8 bits, TMR0L y TMR0H, para formar un temporizador/ contador de 16 bits.

59
Apuntes de Microcontroladores O22 Ricardo Álvarez González

26 Diagrama de bloques del temporizador/contador 0 en modo 16 bits

Ahora, recordando nuestro sistema de la cubeta, mostrado en las figuras 5 y 6, podemos hacer
una analogía entre él y el timer:

 El prescaler viene siendo la llave, ya que con ella se regula el chorro de agua, y
consecuentemente el tiempo en que tardará en desparramarse
 El registro del timer, es equivalente a la capacidad del recipiente, por ejemplo para el
modo de 16 bits, ya no hablaríamos de una cubeta, sino tal vez de un tonel
 La cantidad de agua que se deposita previamente en la cubeta, para generar intervalos de
tiempo más pequeños, funciona exactamente de la misma manera que el valor de
precarga del timer
 La interrupción se genera al desbordarse el timer, de la misma manera que nosotros
tenemos que suspender lo que hacemos, cuando escuchamos que se empieza a
desparramar el agua, y corremos a cerrar la llave de agua.

Para los PICS, podemos usar una expresión para calcular el valor de precarga necesario:

Temporización=4.Tosc.valor_prescaler.valor_del_timer (1)

En donde Tosc es el valor del periodo del oscilador principal del microcontrolador

De tal manera que:

Valor_del_timer=Temporización/(4.Tosc.valor_prescaler) (2)

Debemos de tomar en cuenta, que este valor obtenido en la expresión 2, tenemos que restarlo del
máximo valor del timer (de la misma manera que restábamos la cantidad de agua de la capacidad
total de la cubeta).

De tal manera que:

Valor_precarga=máximacapacidad del timer-valor_del_timer (3)

60
Apuntes de Microcontroladores O22 Ricardo Álvarez González

O equivalentemente:

Valor_precarga=máximo valor del timer-Temporización/(4.Tosc.valor_prescaler) (4)


El máximo valor para un timer de 8 bits es 0xFF +1, ya que se desborda al iniciar nuevamente en
cero, en decimal este valor es 256.

Valor_precarga=256-Temporización/(4.Tosc.valor_prescaler) (5)

Para un timer de 16 bits el máximo valor al que puede llegar es 0xFFFF y se desborda en 0xFFFF+1,
es decir 65536 en decimal.

Valor_precarga=65536-Temporización/(4.Tosc.valor_prescaler) (6)

Para saber más, se recomienda revisar en las hojas de datos del fabricante DS39632C:
 Módulo timer 0
 Módulo timer 1
 Módulo timer 2
 Módulo timer 3

Ejemplo usando el timer 0


Ahora estamos listos para nuestro siguiente ejemplo, usando el timer 0. Se quiere generar un
tiempo de 500 ms, considerando que el oscilador principal funciona a una frecuencia de 4 MHz y
un prescaler de 64, sustituyendo estos valores en la ecuación 3 tenemos:

Valor_del_timer=Temporización/(4.Tosc.valor_prescaler)

Valor_del_timer=500 ms/(4*0.25 µs*64)

=500 ms/64µs

=7812.5

Debido a que solo podemos usar valores enteros, el valor del timer es 7812, y notamos también
que debemos de usar el timer de 16 bits, pero recordemos que este valor tenemos que restarlo
del valor máximo. Por lo que:

Valor_precarga=65536-7812=57724

61
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Este valor tenemos que cargarlo en los registros TMR0H y TMR0L, por lo que debemos de
convertir el valor a hexadecimal, que es 0xE17C. Esto se hará con las instrucciones:

movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz, preescaler 64

Ejercicios E4.1
a. Considerando un pre divisor de 32 y una frecuencia del oscilador principal de 1 MHz,
calcule el valor necesario de precarga del timer 0, para generar un intervalo de tiempo de
100 ms.
b. Use el timer 0, para generar una frecuencia de 440 Hz, proponga los valores necesarios
del oscilador principal, así como del pre divisor

Ahora debemos configurar los registros necesarios para activar el timer:

T0CON
R/W-1 R/W-1 R/W-1 R/W-1 R/W-1 R/W-1 R/W-1 R/W-1
TMR0ON T08BIT TOCS TOSE PSA T0PS2 T0PS1 T0PS0
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
1 0 0 1 0 1 0 1

62
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Este valor binario 1001 0101 equivale a 0x95, que debemos cargar en el registro T0CON

El valor de precarga 0xE17C se cargará en los registros del timer, por lo tanto 0xE1 debe cargarse
en TMR0H y 0x7C en TMR0L

Para el funcionamiento óptimo del timer debemos configurar su interrupción, esto se hace en el
registro INTCON, habilitando los bits:

 GIE/GIEH=1, bit de habitación global de interrupciones


 TMR0IE=1, bit de habilitación de interrupción del timer 0

INTCON
R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-x
GIE/GIEH PEIE/GIEL TMR0IE INT0IE RBIE TMR0IF INT0IF RBIF
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
1 0 1 0 0 0 0 0

Por lo que el valor de configuración para INTCON es 1010 0000, 0xA0

Ejercicios E4.2
Escriba el valor necesario para el registro T0CON para los requerimientos de los ejercicios E4.1

El programa siguiente, es la versión mejorada del contador ascendente, descendente, aquí la


duración de cada número exhibido es de exactamente 500 ms. La rutina repite ahora es más
eficiente y controlada por el timer 0. Nótese que ahora se configuró el oscilador interno del µc a 4
MHz, de acuerdo a los cálculos realizados. Los cambios con respecto al programa anterior están en
rojo.

;******************************************************************************

LIST P=18F4550 ;directiva para definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
CONFIG FOSC = INTOSC_XT ;Oscilador INT usado por el uC , XT usado por el USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
CBLOCK 0x000 ;ejemplo de definición de variables en RAM de acceso

63
Apuntes de Microcontroladores O22 Ricardo Álvarez González

flags ;definimos la dirección 0 como registro de banderas


ENDC ;fin del bloque de constantes
;******************************************************************************
ORG 0x0000 ; vector de reset
bra inicio
org 0x08 ;vector de interrupción
bra RST0 ;ramifica servicio interrupción T0
org 0x0020
inicio bsf OSCCON,IRCF2,0;Inicio del programa principal
bsf OSCCON,IRCF1,0
bcf OSCCON,IRCF0,0;Oscilador interno a 4 MHz
movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0x95
movwf T0CON,0 ;timer 16 bits prescalerX64
movlw 0XA0
movwf INTCON,0 ;interrupción TMR0 habilitada
movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
cero movlw 0xC0 ;código del cero
movwf PORTD,0
call espera
btfss PORTB,0,0
bra nueve
uno movlw 0xF9 ;código del uno
movwf PORTD,0
call espera
btfss PORTB,0,0
bra cero
dos movlw 0xA4 ;código del dos
movwf PORTD,0
call espera
btfss PORTB,0,0
bra uno
tres movlw 0xB0 ;código del tres
movwf PORTD,0
call espera
btfss PORTB,0,0
bra dos
cuatro movlw 0x99 ;código del cuatro
movwf PORTD,0
call espera
btfss PORTB,0,0
bra tres
cinco movlw 0x92 ;código del cinco
movwf PORTD,0
call espera
btfss PORTB,0,0
bra cuatro

64
Apuntes de Microcontroladores O22 Ricardo Álvarez González

seis movlw 0x82 ;código del seis


movwf PORTD,0
call espera
btfss PORTB,0,0
bra cinco
siete movlw 0xB8 ;código del siete
movwf PORTD,0
call espera
btfss PORTB,0,0
bra seis
ocho movlw 0x80 ;código del ocho
movwf PORTD,0
call espera
btfss PORTB,0,0
bra siete
nueve movlw 0x98 ;código del nueve
movwf PORTD,0
call espera
btfss PORTB,0,0
bra ocho
bra cero
;******************************************************************************
espera btfss flags,0,0
bra espera
bcf flags,0,0
return
;******************************************************************************
RST0 bcf INTCON,TMR0IF,0 ;apagamos bandera timer0
movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
bsf flags,0,0
retfie
END

Programa: Usando el timer 0 para encender cada dígito del display durante exactamente 500 ms

65
Apuntes de Microcontroladores O22 Ricardo Álvarez González

27 Diagrama de simulación en ISIS del Programa 4

INTERRUPCIÓN EXTERNA 1
Ya revisamos en el ejemplo anterior cómo funciona la interrupción del temporizador 0. Ahora
veremos cómo funciona la interrupción externa INT1. Recordemos que para lograr que el contador
fuera ascendente o descendente, dependía del valor del nivel lógico presente en el puerto de
entrada RB0:

RB0 Conteo
1 Ascendente
0 descendente

Nuestra nueva versión de este programa, hará uso de la interrupción externa INT1, la cual está
asociada al puerto de entrada RB1, colocaremos en este pin un botón pulsador y en vez de
detectar un nivel lógico en este pin, se detectará un flanco ascendente generado por el
accionamiento de este botón, que interrumpirá al procesador y en su rutina de servicio de
interrupción modificaremos el valor de una bandera de propósito general, para cambiar el sentido
del contador.

Para activar la interrupción INT1, debemos:

 poner el bit INT1IE del registro INTCON3:


 limpiar el bit INT1IP, ya que le asignaremos un nivel de prioridad bajo a esta interrupción

INTCON3
R/W-1 R/W-1 U-0 R/W-0 R/W-0 U-0 R/W-0 R/W-x
INT2IP INT1IP - INT2IE INT1IE - INT2IF INT1IF
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
1 0 0 0 1 0 0 0

66
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Según la tabla anterior, el valor para el registro INTCON3 sera: 1000 1000 es decir 0x88

En este programa ejemplificaremos el uso de prioridades de interrupción, por lo que el timer 0, lo


dejaremos en alta prioridad y la interrupción externa en baja, pero debemos de activar el bit de
habilitación de prioridades de interrupción IPEN (Interrupt Priority ENable), que está ubicado en el
registro de control de reset RCON:

RCON
R/W-0 R/W-1 U-0 R/W-1 R-1 R-1 R/W-0 R/W-0
IPEN SBOREN - /RI /T0 /PD /POR /BOR
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
Para activar este bit lo haremos con la instrucción:

bsf RCON,IPEN,0 ;habilitamos prioridades de interrupción

En el ejemplo anterior, solamente teníamos una interrupción activa: la del timer 0, que funcionaba
en alta prioridad, ya que no habíamos activado las prioridades de interrupción; esta interrupción
cuando se generaba, respondía en el vector 0x08. Ahora se adicionan prioridades de interrupción
e INT1, le asignamos baja prioridad, por lo que responderá en el vector de baja prioridad de
interrupción 0x 18.

Para saber más, se recomienda revisar en las hojas de datos del fabricante, DS39632C:
 Interrupciones en los pines INTn

En el siguiente programa se muestran en rojo las instrucciones correspondientes a la activación de


la interrupción INT1, así como también las instrucciones que se modificaron como consecuencia
de este cambio

Ejemplo: Contador ascendente descendente, usando el timer 0 y la


interrupción externa INT1
;******************************************************************************

LIST P=18F4550 ;directiva para definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
CONFIG FOSC = INTOSC_XT ;Oscilador INT usado por el uC , XT usado por el USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigía apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
CBLOCK 0x000 ;ejemplo de definición de variables en RAM de acceso
flags ;banderas

67
Apuntes de Microcontroladores O22 Ricardo Álvarez González

ENDC ;fin del bloque de constantes


;******************************************************************************
;Reset vector
ORG 0x0000
bra inicio
org 0x08 ;vector de alta prioridad
bra RST0 ;ramifica servicio interrupcion T0
org 0x18 ;vector de baja prioridad
bra RSINT1
org 0x0020

;Inicio del programa principal


inicio bsf OSCCON,IRCF2,0
bsf OSCCON,IRCF1,0
bcf OSCCON,IRCF0,0 ;Oscilador interno a 4 MHz
movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0x95
movwf T0CON,0 ;timer 16 bits prescalerX64
movlw 0XE0
movwf INTCON,0 ;interrupciones TMR0,prioridad habilitada
bsf RCON,IPEN,0 ;habilitamos prioridades de interrupción
movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
movlw 0x88
movwf INTCON3,0 ;habilitamos int1 en baja prioridad
cero movlw 0xC0 ;código del cero
movwf PORTD,0
call repite
btfss flags,1,0
bra nueve
uno movlw 0xF9 ;código del uno
movwf PORTD,0
call repite
btfss flags,1,0
bra cero
dos movlw 0xA4 ;código del dos
movwf PORTD,0
call repite
btfss flags,1,0
bra uno
tres movlw 0xB0 ;código del tres
movwf PORTD,0
call repite
btfss flags,1,0
bra dos
cuatro movlw 0x99 ;código del cuatro
movwf PORTD,0
call repite

68
Apuntes de Microcontroladores O22 Ricardo Álvarez González

btfss flags,1,0
bra tres
cinco movlw 0x92 ;código del cinco
movwf PORTD,0
call repite
btfss flags,1,0
bra cuatro
seis movlw 0x82 ;código del seis
movwf PORTD,0
call repite
btfss flags,1,0
bra cinco
siete movlw 0xB8 ;código del siete
movwf PORTD,0
call repite
btfss flags,1,0
bra seis
ocho movlw 0x80 ;código del ocho
movwf PORTD,0
call repite
btfss flags,1,0
bra siete
nueve movlw 0x98 ;código del nueve
movwf PORTD,0
call repite
btfss flags,1,0
bra ocho
bra cero
;******************************************************************************
repite btfss flags,0,0
bra repite
bcf flags,0,0
return
;******************************************************************************
RST0 bcf INTCON,TMR0IF,0 ;apagamos bandera timer0
movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
bsf flags,0,0
retfie
;********************************************************************
RSINT1 bcf INTCON3,INT1IF,0 ;Limpiamos bandera de interrupción
btg flags,1,0 ;bit monitor de interrupción
retfie
END

Programa: Contador ascendente descendente con interrupciones del timer e INT1

69
Apuntes de Microcontroladores O22 Ricardo Álvarez González

28 Diagrama de simulación del contador con interrupción externa

Como hemos visto, en el programa anterior, mandamos a exhibir los códigos de manera directa,
uno por uno, con la consecuencia de que el programa tiene una secuencia repetitiva de
instrucciones, pero ¿qué pasaría si quisiéramos usar dos displays y exhibir un conteo hasta el 99?
¡No sería conveniente repetir una secuencia de instrucciones 100 veces!, por lo cual tenemos que
usar otro método más eficiente para enviar los códigos de siete segmentos al PORTD, que
veremos en la siguiente sección.

Ejemplo 6: Manejando tablas por el método del “goto calculado”


Para crear tablas de búsqueda en memoria de programa con los microcontroladores PIC18, existen
dos métodos:

1. Goto calculado
2. Instrucciones específicas de lectura de tabla

En este ejemplo, veremos el primer método. Para crear un goto calculado, es necesario primero
cargar el valor de desplazamiento en el registro w y sumar un valor de desplazamiento (offset) al
contador de programa, seguida de un grupo de instrucciones retlw nn, como se muestra a
continuación:

movf desplazamiento,W
call tabla
.
.
tabla addwf PCL
retlw nn
retlw nn
.
.
retlw nn

El valor del desplazamiento indica el número de bytes que debe avanzar el contador de programa
y debe ser un múltiplo de dos. Este método recibe el nombre de goto calculado, porque igual que

70
Apuntes de Microcontroladores O22 Ricardo Álvarez González

una instrucción goto, realiza una ramificación, o equivalentemente un salto; pero se logra
sumando un valor al contador de programa.

Debido a que únicamente se suma el desplazamiento al PCL, debe tenerse cuidado de que el grupo
de instrucciones retlw nn, no cruce una página de 256 bytes, ya que el PCL es de 8 bits, y cundo
cambie de FF a 00, no generará un acarreo hacia el registro PCH, ocasionando un salto fuera del
grupo de instrucciones retlw nn, afectando la secuencia del programa, que percibiremos como
un funcionamiento errático del mismo.

Veamos la nueva versión del contador ascendente-descendente del 0 al 9:

;******************************************************************************

LIST P=18F4550 ;directiva para definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
CONFIG FOSC = INTOSC_XT ;Oscilador INT usado por el uC , XT usado por el USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
CBLOCK 0x000 ;ejemplo de definición de variables en RAM de acceso
flags ;banderas
índice
ENDC ;fin del bloque de constantes
;******************************************************************************
ORG 0x0000;vector de reset
bra inicio
org 0x08 ;vector de alta prioridad
bra RST0 ;ramifica servicio interrupción T0
org 0x18 ;vector de baja prioridad
bra RSINT
org 0x0020
inicio bsf OSCCON,IRCF2,0
bsf OSCCON,IRCF1,0
bcf OSCCON,IRCF0,0 ;Oscilador interno a 4 MHz
movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0x95
movwf T0CON,0 ;timer 16 bits prescalerX64
movlw 0XE0
movwf INTCON,0 ;interrupciones TMR0,prioridad habilitada
bsf RCON,IPEN,0 ;habilitamos prioridades de interrupción

71
Apuntes de Microcontroladores O22 Ricardo Álvarez González

movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
movlw 0x88
movwf INTCON3,0 ;habilitamos int1 en baja prioridad
limpia clrf indice,0 ;inicia en cero
next call tabla
movwf PORTD,0 ;exhibe el número
call repite
tst btfss flags,1,0 ;¿ascendente o descendente?
bra decre
incf indice,F,0 ;conteo ascendente
movf indice,W,0
xorlw 0x0a;verifica límite superior de tabla
btfss STATUS,Z,0
bra next
bra limpia
decre decf indice,F,0 ;conteo descendente
movf indice,W,0
xorlw 0xFF;verifica límite inferior de tabla, FF=-1
btfsc STATUS,Z,0
bra inid
llama call tabla
movwf PORTD,0 ;exhibe el número
call repite
bra tst
inid movlw 0x09 ;reinicia en nueve
movwf indice,0
bra llama
;******************************************************************************
repite btfss flags,0,0
bra repite
bcf flags,0,0
return
;******************************************************************************
RST0 bcf INTCON,TMR0IF,0 ;apagamos bandera timer0
movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
bsf flags,0,0
retfie
;********************************************************************
RSINT bcf INTCON3,INT1IF,0 ;Limpiamos bandera de interrupción
btg flags,1,0 ;bit monitor de interrupción
retfie
;********************************************************************
tabla rlcf indice,W,0 ;multiplica índice por 2
addwf PCL,F,0 ;ajusta el PCL de acuerdo al valor del índice
retlw 0xC0 ;código del cero
retlw 0xf9 ;código del uno
retlw 0xA4 ;código del dos

72
Apuntes de Microcontroladores O22 Ricardo Álvarez González

retlw 0xb0 ;código del tres


retlw 0x99 ;código del cuatro
retlw 0x92 ;código del cinco
retlw 0x82 ;código del seis
retlw 0xb8 ;código del siete
retlw 0x80 ;código del ocho
retlw 0x98 ;código del nueve
end

Programa: contador ascendente-descendente del 0 al 9, usando tablas con goto calculado

Como podemos ver en el programa 6, la rutina tabla implementa el método de goto calculado,
vemos que en comparación con el programa 5, esta versión es más compacta. Las modificaciones
de este programa aparecen en rojo. Cada uno de los códigos de siete segmentos forma parte de
una instrucción retlw, de tal manera que cuando se produce el retorno de subrutina, el registro W
contiene este código; por lo tanto, usando este método se puede almacenar un dato de un byte
por cada palabra de instrucción, que como recordamos, es de dos bytes.

Ejemplo: tablas de búsqueda en memoria de programa usando instrucciones


de lectura de tabla
Ahora veremos el segundo método, que ya habíamos mencionado. Para tener un alcance
suficiente, en los PIC18 que tengan mayor capacidad de memoria de programa,tenemos un
apuntador de tabla de 24 bits, llamado TBLPTR (TaBLe PoinTeR)que está distribuido en tres
registros de 8 bits:

 TBLPTRL
 TBLPTRH
 TBLPTRU

Apuntador de tabla parte Apuntador de tabla parte alta Apuntador de tabla parte baja
superior
TBLPTRU TBLPTRH TBLPTRL

También existe un registro llamado TABLAT (TABle LATch), para almacenar el dato leído,
correspondiente a la dirección especificada por TBLPTR.

73
Apuntes de Microcontroladores O22 Ricardo Álvarez González

En la figura se muestra una operación de lectura de tabla TBLRD *, existen cuatro instrucciones de
lectura de TABLA:

TBLRD * Lectura de tabla


TBLRD *+ Lectura de tabla con pos incremento del apuntador
TBLRD +* Lectura de tabla con pre incremento del apuntador
TBLRD *- Lectura de tabla con pos decremento del apuntador

También existen las instrucciones equivalentes para la escritura en memoria de tabla

74
Apuntes de Microcontroladores O22 Ricardo Álvarez González

TBLWT * Escritura de tabla


TBLWT *+ Escritura de tabla con pos incremento del apuntador
TBLWT +* Escritura de tabla con pre incremento del apuntador
TBLWT *- Escritura de tabla con pos decremento del apuntador

Presentamos ahora nuestro contador ascendente del 0 al 9, usando instrucciones de lectura de


tabla

;******************************************************************************

LIST P=18F4550 ;directiva para definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
CONFIG FOSC = INTOSC_XT;Oscilador INT usado por el uC , XT usado por el USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
CBLOCK 0x000 ;ejemplo de definición de variables en RAM de acceso
flags ;banderas
ENDC ;fin del bloque de constantes
;******************************************************************************
;Reset vector
ORG 0x0000
bra inicio
org 0x08 ;vector de alta prioridad
bra RST0 ;ramifica servicio interrupción T0
org 0x18 ;vector de baja prioridad
bra RSINT
org 0x0020
;Inicio del programa principal
inicio bsf OSCCON,IRCF2,0
bsf OSCCON,IRCF1,0
bcf OSCCON,IRCF0,0 ;Oscilador interno a 4 MHz
movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0x95
movwf T0CON,0 ;timer 16 bits prescalerX64
movlw 0XE0
movwf INTCON,0 ;interrupciones TMR0,prioridad habilitada
bsf RCON,IPEN,0 ;habilitamos prioridades de interrupcion
movlw 0xE1
movwf TMR0H,0

75
Apuntes de Microcontroladores O22 Ricardo Álvarez González

movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
movlw 0x88
movwf INTCON3,0 ;habilitamos int1 en baja prioridad
clrf TBLPTRU,0
movlw 0x03
movwf TBLPTRH,0
limpia clrf TBLPTRL,0 ;tblptr=0x000300
lee tblrd *+ ;lee tabla eincrementa apuntador
movff TABLAT,PORTD
call repite
movlw 0x0a
cpfseq TBLPTRL
bra lee
bra limpia
;*****************************************************************************
repite btfss flags,0,0
bra repite
bcf flags,0,0
return
;******************************************************************************
RST0 bcf INTCON,TMR0IF,0 ;apagamos bandera timer0
movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
bsf flags,0,0
retfie
;********************************************************************
RSINT bcf INTCON3,INT1IF,0 ;Limpiamos bandera de interrupción
btg flags,1,0 ;bit monitor de interrupción
retfie
;********************************************************************
org 0x300 ;DB directiva que Define Byte
DB 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xB8,0x80,0x98
END

Programa: usando instrucciones de lectura de tabla

Nuevamente en el programa anterior, se muestran en rojo, las instrucciones usadas para la


lectura de tablas. Iniciamos el apuntador de tabla, TBLPTR con la dirección 0x300, nótese que esto
lo hacemos al configurar los tres registros correspondientes al apuntador. También usamos una
nueva directiva: DB, la cual sirve para definir un byte a partir de la dirección especificada por la
directiva ORG que la antecede, en nuestro caso, indica la dirección 0x300, a partir de esta
dirección definimos nuestros códigos de siete segmentos. Usando esta técnica, optimizamos el uso
de la memoria, ya que almacenamos cada código usando un solo byte. Este programa hace
exactamente lo que el anterior, pero usando las instrucciones de lectura de tabla, pero en el
siguiente programa, veremos cómo usar instrucciones de lectura de tabla, para hacer un contador
de 0 al 99.

76
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ejemplo: Manejando dos displays de siete segmentos


Al tener dos displays, podemos incrementar el conteo hasta el 99, para esto usamos transistores
como interruptores, para encender un solo display a la vez, ya que los segmentos están
conectados en paralelo, es decir, el segmento a esta conectado con el a, el b con el b, y así
sucesivamente, pero solo encenderá el display cuyo transistor está encendido, esta técnica se
conoce como multiplexión, al encender y apagar los transistores a una frecuencia suficientemente
alta (en el órden de los 10 KHz), apreciamos los dos displays como si siempre estuvieran
encendidos.

;******************************************************************************

LIST P=18F4550 ;directiva para definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
CONFIG FOSC = INTOSC_XT ;Oscilador INT usado por el uC , XT usado por el USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigía apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
CBLOCK 0x000 ;ejemplo de definición de variables en RAM de acceso
flags ;banderas
iun ;índice de unidades
cuni ;código de 7 segmentos de unidades
idec ;índice de decenas
cdec ;código de 7 segmentos de decenas
cont
ENDC ;fin del bloque de constantes
;******************************************************************************
;Reset vector
ORG 0x0000
bra inicio
org 0x08 ;vector de alta prioridad
bra RST0 ;ramifica servicio interrupción T0
org 0x18 ;vector de baja prioridad
bra RSINT
org 0x0020
inicio bsf OSCCON,IRCF2,0
bsf OSCCON,IRCF1,0
bcf OSCCON,IRCF0,0 ;Oscilador interno a 4 MHz
movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0xfc ;1111 1100
movwf TRISC,0 ;RC0 y RC1 como salidas

77
Apuntes de Microcontroladores O22 Ricardo Álvarez González

clrf PORTC,0
movlw 0x95
movwf T0CON,0 ;timer0 16 bits prescalerX64
movlw 0XE0
movwf INTCON,0 ;interrupciones TMR0,prioridad habilitada
bsf RCON,IPEN,0 ;habilitamos prioridades de interrupción
movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
movlw 0x88
movwf INTCON3,0 ;habilitamos int1 en baja prioridad
clrf TBLPTRL,0
movlw 0x03
movwf TBLPTRH,0
clrf TBLPTRU,0 ;tblptr=0x000300
clrf iun,0
clrf idec,0 ;iniciamos en 0
lee movff iun,TBLPTRL ;ajusta apuntador
tblrd * ;lee la tabla sin modificar apuntador
movff TABLAT,cuni ;cuni tiene código 7 segmentos
movff idec,TBLPTRL;ajusta apuntador
tblrd * ;lee la tabla sin modificar apuntador
movff TABLAT,cdec ;cdec tiene código 7 segmentos
loop movlw 0x01
movwf PORTC,0 ;encendemos display unidades
movff cuni,PORTD
call retardo
movlw 0x02
movwf PORTC,0 ;encendemos display decenas
movff cdec,PORTD
call retardo
btfss flags,0,0
bra loop
bcf flags,0,0
incf iun,F,0
movf iun,W,0
xorlw 0x0a
btfss STATUS,Z,0;verifica límite de tabla
bra lee
clrf iun,0
incf idec,F,0
movf idec,W,0
xorlw 0x0a
btfss STATUS,Z,0
bra lee
clrf idec,0
goto lee
;******************************************************************************
retardo setf cont,0
nada nop
decfsz cont,F,0
bra nada

78
Apuntes de Microcontroladores O22 Ricardo Álvarez González

return
;******************************************************************************
RST0 bcf INTCON,TMR0IF,0 ;apagamos bandera timer0
movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
bsf flags,0,0
retfie
;********************************************************************
RSINT bcf INTCON3,INT1IF,0 ;Limpiamos bandera de interrupción
btg flags,1,0 ;bit monitor de interrupción
retfie
;********************************************************************
org 0x300 ;DB directiva que Define Byte
DB 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xB8,0x80,0x98
END

Controlando dos exhibidores de 7 segmentos

Como observamos en el código del programa anterior, para controlar dos exhibidores,
necesitamos dos bits de puerto configurados como salida, ya que ellos serán los encargados de
encender y apagar los transistores que manejan los displays. En este programa, no se usa la
instrucción TBLRD *+, ya que tenemos un par de registros en donde se guardan los índices
necesarios para el conteo:

 iun índice de unidades


 idec índice de decenas

El programa mantiene los índices dentro del valor adecuado, iun inicia en cero, y se incrementa
exactamente cada 500 ms, hasta llegar a 9, una vez que iun tiene el valor de 9, en los siguientes
500 ms, iun se regresa a cero, pero a la vez se incrementa idec. Debido a que para encender los
dígitos necesitamos los códigos de 7 segmentos, tenemos también dos registros que los
almacenan

 cuni código de 7 segmentos de unidades


 cdec código de 7 segmentos de decenas

El programa lo que hace es cargar el código de siete segmentos en el PORTD, el tiempo que dura la
rutina retardo, cada 500ms se incrementa iun (y cuando regresa a cero, se incrementa idec) y se
actualiza el código de siete segmentos con las instrucciones:

movff iun,TBLPTRL ;ajusta apuntador con el valor de unidades


tblrd * ;lee la tabla sin modificar apuntador
movff TABLAT,cuni ;cuni tiene código 7 segmentos de unidades
movff idec,TBLPTRL ;ajusta apuntador con el valor de decenas
tblrd * ;lee la tabla sin modificar apuntador
movff TABLAT,cdec ;cdec tiene código 7 segmentos de decenas

79
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 29 Simulación del ejemplo del contador de 00 a 99

Recordemos que en la vida real, al implementar el circuito, debemos colocar un transistor para la
conmutación de los displays, como se muestra en la figura:

80
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 30 Se debe insertar un transistor para poder conmutar un dsiplay

Para controlar cuatro displays con el puerto c:

RC7 RC6 RC5 RC4 RC3 RC2 RC1 RC0 Código


0 0 0 0 0 0 1 0 02

81
Apuntes de Microcontroladores O22 Ricardo Álvarez González

0 0 0 0 0 1 0 0 04
0 1 0 0 0 0 0 0 40
1 0 0 0 0 0 0 0 80

Ilustración 31 Uso de transistores para conmutar 4 displays de ánodo común

Ejemplo: Usando un teclado Matricial


Hasta ahora solamente hemos trabajado básicamente con puertos configurados como salida,
también hemos usado un bit de puerto configurado como entrada, para el contador ascendente
descendente. Usaremos un teclado de 16 teclas, pero con la finalidad de optimizar puertos de
entrada, trabajaremos con el teclado matricial, ya que con el solo necesitaremos un puerto de 8
bits, ya que está organizado en cuatro renglones y cuatro columnas. Esto se observa en la
siguiente figura:

82
Apuntes de Microcontroladores O22 Ricardo Álvarez González

U1
18 1
VUSB RE3/MCLR/VPP
10k 10k 10k 10k 10
RE2/AN7/OESPP
9
RE1/AN6/CK2SPP
8
RE0/AN5/CK1SPP
40 30
RB7/KBI3/PGD RD7/SPP7/P1D
39 29
RB6/KBI2/PGC RD6/SPP6/P1C
38 28
RB5/KBI1/PGM RD5/SPP5/P1B
37 27
RB4/AN11/KBI0/CSSPP RD4/SPP4
36 22
RB3/AN9/CCP2/VPO RD3/SPP3
35 21
RB2/AN8/INT2/VMO RD2/SPP2
34 20
7 8 9 F 33
RB1/AN10/INT1/SCK/SCL RD1/SPP1
19
RB0/AN12/INT0/FLT0/SDI/SDA RD0/SPP0
13
OSC1/CLKI
14 26
4 5 6 E 7
RA6/OSC2/CLKO RC7/RX/DT/SDO
25
RA5/AN4/SS/LVDIN/C2OUT RC6/TX/CK
6 24
RA4/T0CKI/C1OUT/RCV RC5/D+/VP
5 23
RA3/AN3/VREF+ RC4/D-/VM
4 17
RA2/AN2/VREF-/CVREF RC2/CCP1/P1A
3 16
1 2 3 D 2
RA1/AN1 RC1/T1OSI/CCP2/UOE
15
RA0/AN0 RC0/T1OSO/T1CKI
PIC18F4550
0 A B C

Se muestra en las siguientes figuras, el diagrama de flujo para el funcionamiento del teclado

83
Apuntes de Microcontroladores O22 Ricardo Álvarez González

84
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Como se puede observar en loss diagramas de flujo, el barrido de teclado consiste en activar cada
uno de los renglones, esto se hace limpiando solamente uno de los bits que controlan los
renglones, y los otros tres bits restantes poniéndolos a uno. Una vez que se activa un renglón, se
verifica cada una de las columnas para ver si existe un cero, esto nos dice que se pulsó una tecla y
finaliza la rutina colocando en el registro de trabajo su código correspondiente; si en las columnas

85
Apuntes de Microcontroladores O22 Ricardo Álvarez González

existe un nivel alto, es porque no se ha pulsado ninguna tecla, por lo que se desactiva el renglón
correspondiente escribiendo un uno en su bit de puerto y activando el siguiente, escribiendo un
cero en su bit de puerto. En la siguiente figura, mostramos el diagrama del teclado, nótese que se
han omitido las resistencias que se conectan entre cada columna y el voltaje de alimentación, esto
es porque usamos las resistencias de pull up del microcontrolador, estas las activamos con la
instrucción:

U1
18 1
VUSB RE3/MCLR/VPP
10
RE2/AN7/OESPP
9
RE1/AN6/CK2SPP
8
RE0/AN5/CK1SPP
40 30
RB7/KBI3/PGD RD7/SPP7/P1D
39 29
RB6/KBI2/PGC RD6/SPP6/P1C
38 28
RB5/KBI1/PGM RD5/SPP5/P1B
37 27
RB4/AN11/KBI0/CSSPP RD4/SPP4
36 22
RB3/AN9/CCP2/VPO RD3/SPP3
35 21
RB2/AN8/INT2/VMO RD2/SPP2
34 20
7 8 9 F 33
RB1/AN10/INT1/SCK/SCL RD1/SPP1
19
RB0/AN12/INT0/FLT0/SDI/SDA RD0/SPP0
13
OSC1/CLKI
14 26
4 5 6 E 7
RA6/OSC2/CLKO RC7/RX/DT/SDO
25
RA5/AN4/SS/LVDIN/C2OUT RC6/TX/CK
6 24
RA4/T0CKI/C1OUT/RCV RC5/D+/VP
5 23
RA3/AN3/VREF+ RC4/D-/VM
4 17
RA2/AN2/VREF-/CVREF RC2/CCP1/P1A
3 16
1 2 3 D 2
RA1/AN1 RC1/T1OSI/CCP2/UOE
15
RA0/AN0 RC0/T1OSO/T1CKI
PIC18F4550
0 A B C

Se muestra a continuación el programa del teclado. La rutina KBD ejecuta el código


correspondiente al diagrama de flujo anterior, entrega como resultado un código de 4 bits
correspondiente a la tecla pulsada, si por alguna razón ninguna tecla se pulsó, regresa el código FF,
aunque, debido a que activamos la interrupción por cambio de estado en la parte alta del puerto
B, sabemos que si se activó la interrupción, es porque se pulsó una tecla. Incluimos el código nulo,
para que la rutina KBD pueda ejecutarse también sin interrupción, es decir, invocar
periódicamente esta rutina, para que cuando se pulse una tecla, se obtenga su código; este
método es conocido como encuesta (polling). En la rutina de servicio de interrupción RSINT
invocamos la rutina KBD, y si la tecla pulsada es menor que 0xA, entonces usamos este valor para
modificar el dígito de decenas de nuestro contador, si se oprime la tecla C, limpia el contador, es
decir, inicia en 00.

;******************************************************************************

LIST P=18F4550 ;directiva para definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
CONFIG FOSC = INTOSC_XT ;Oscilador INT usado por el uC , XT usado por el USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado

86
Apuntes de Microcontroladores O22 Ricardo Álvarez González

CONFIG WDT = OFF ;Temporizador vigía apagado


CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
CBLOCK 0x000 ;ejemplo de definición de variables en RAM de acceso
flags ;banderas
iun ;índice de unidades
cuni ;código de unidades
idec ;índice de decenas
cdec ;código de decenas
cont
tecla ;registro de código de tecla pulsada
ENDC ;fin del bloque de constantes
;******************************************************************************
;Reset vector
ORG 0x0000
bra inicio
org 0x08 ;vector de alta prioridad
bra RST0 ;ramifica servicio interrupción T0
org 0x18 ;vector de baja prioridad
bra RSINT
org 0x0020
inicio bsf OSCCON,IRCF2,0
bsf OSCCON,IRCF1,0
bcf OSCCON,IRCF0,0 ;Oscilador interno a 4 MHz
movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf PORTB,0
movlw 0xf0
movwf TRISB,0 ;Configurar puerto para teclado
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0xfc
movwf TRISC,0 ;RC0 y RC1 como salidas
clrf PORTC,0
movlw 0x95
movwf T0CON,0 ;timer 16 bits prescalerX64
movlw 0XE8
movwf INTCON,0 ;interrupciones TMR0,RBIE prioridad alta y baja
bsf RCON,IPEN,0 ;habilitamos prioridades de interrupción
movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
movlw 0x04
movwf INTCON2,0 ; intRBI en baja prioridad y activamos R pull up
clrf TBLPTRL,0
movlw 0x03
movwf TBLPTRH,0
clrf TBLPTRU,0 ;tblptr=0x000300
clrf iun,0

87
Apuntes de Microcontroladores O22 Ricardo Álvarez González

clrf idec,0 ;iniciamos en 0


lee movff iun,TBLPTRL
tblrd * ;lee
movff TABLAT,cuni ;cuni tiene codigo 7 segmentos
movff idec,TBLPTRL
tblrd * ;lee
movff TABLAT,cdec ;cdec tiene codigo 7 segmentos
loop movlw 0x01
movwf PORTC,0 ; encendemos display unidades
movff cuni,PORTD
call retardo
movlw 0x02
movwf PORTC,0 ;encendemos display decenas
movff cdec,PORTD
call retardo
btfss flags,0,0
bra loop
bcf flags,0,0
incf iun,F,0
movf iun,W,0
xorlw 0x0a
btfss STATUS,Z,0
bra lee
clrf iun,0
incf idec,F,0
movf idec,W,0
xorlw 0x0a
btfss STATUS,Z,0
bra lee
clrf idec,0
goto lee
;******************************************************************************
retardo setf cont,0
nada nop
decfsz cont,F,0
bra nada
return
;******************************************************************************
RST0 bcf INTCON,TMR0IF,0 ;apagamos bandera timer0
movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
bsf flags,0,0
retfie
;********************************************************************
RSINT call KBD ;Llamamos rutina del teclado
bcf INTCON,RBIF,0 ;LIMPIAMOS BANDERA
movwf tecla,0 ;guardamos tecla pulsada
movlw 0x0a
cpfslt tecla,0;salta si es que se pulsó una tecla entre 0 y 9
bra limpia
movff tecla,idec;carga número de tecla pulsada en decenas

88
Apuntes de Microcontroladores O22 Ricardo Álvarez González

movff idec,TBLPTRL
tblrd * ;lee
movff TABLAT,cdec ;cdec tiene código 7 segmentos
bra exit
limpia movlw 0x0c
cpfseq tecla,0
bra exit
clrf iun,0 ;limpiamos índice de unidades
clrf idec,0 ;limpiamos índice de decenas
movff idec,TBLPTRL
tblrd * ;lee
movff TABLAT,cdec ;cdec tiene código 7 segmentos
movff iun,TBLPTRL
tblrd * ;lee
movff TABLAT,cuni ;cdec tiene código 7 segmentos
exit clrf PORTB,0
retfie
;********************************************************************
KBD movlw 0x0e
movwf PORTB,0 ;activamos primer renglón
btfss PORTB,4,0
retlw 0x00 ;tecla 0
btfss PORTB,5,0
retlw 0x0A ;tecla a
btfss PORTB,6,0
retlw 0x0B ;tecla b
btfss PORTB,7,0
retlw 0x0C ;tecla c
movlw 0x0D
movwf PORTB,0 ;activamos segundo renglón
btfss PORTB,4,0
retlw 0x01 ;tecla 1
btfss PORTB,5,0
retlw 0x02 ;tecla 2
btfss PORTB,6,0
retlw 0x03 ;tecla 3
btfss PORTB,7,0
retlw 0x0D ;tecla d
movlw 0x0B
movwf PORTB,0 ;activamos tercer renglón
btfss PORTB,4,0
retlw 0x04 ;tecla 4
btfss PORTB,5,0
retlw 0x05 ;tecla 5
btfss PORTB,6,0
retlw 0x06 ;tecla 6
btfss PORTB,7,0
retlw 0x0E
movlw 0x07
movwf PORTB,0 ;activamos cuartorenglón
btfss PORTB,4,0
retlw 0x07 ;tecla 7
btfss PORTB,5,0

89
Apuntes de Microcontroladores O22 Ricardo Álvarez González

retlw 0x08 ;tecla 8


btfss PORTB,6,0
retlw 0x09 ;tecla 9
btfss PORTB,7,0
retlw 0x0F ;tecla F
retlw 0xFF ;ninguna tecla pulsada
org 0x300 ;DB directiva que Define Byte
DB 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xB8,0x80,0x98
END

Programa 9, Contador de 0-99, con programación de decenas y borrado con un teclado matricial

Ejercicios 9.1
Modifique la rutina RSINT, para que al pulsar la tecla A, el conteo sea ascendente y al pulsar la
tecla D, el conteo sea descendente.

Ejemplo: Usando el timer 2


En los programas anteriores, usamos nuevamente nuestra rutina básica de retardo, la cual
funciona por el tiempo de ejecución de instrucciones. Pero ahora, modificaremos esta rutina,
usando el timer 2.

Como podemos ver en su diagrama de bloques, el timer 2 tiene las siguientes características
únicas, con respecto a los otros timers existentes en este microcontrolador:

 Solamente puede funcionar como timer


 Cuenta además del pre divisor, con post divisor
 Su funcionamiento no está basado en su desbordamiento, sino que cuenta con un registro
de periodo en donde se coloca su valor de precarga, y mediante un comparador detecta
cuando el timer alcanza y coincide con ese valor

La expresión para calcular el valor en el timer2 seria:

Temporización = 4.Tosc.Prescaler.(PR2+1)

90
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Si tenemos Fosc=4 MHz, entonces Tosc=0.25 µs, preescaler x 16 ¿Cuál será el valor de PR2? Para
un tiempo de 0.1 ms

0.1 ms=4(0.25 µs)16(PR2+1)


0.1 ms= 16 µs(PR2+1)

(PR2+1)=0.1 ms/16µs haciendo operaciones PR2=5.25 aproximando seria PR2=5

El valor para T2CON:

0 0 0 0 0 1 1 1
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

De tal manera que cargando el valor 0x07 en T2CON, tenemos el timer 2 encendido, prescaler
x16 y postscaler x1

En este ejemplo el timer 2 se utiliza para encender cada display por un intervalo de tiempo de 0.1
ms, el timer 0 se usa para que se incremente el conteo cada 500 ms. Hemos usado nuestro
registro de propósito general (GPR) flags, con la función de sus dígitos como sigue:

flags
Tiempo Conteo Tiempo
0.1 ms ascendente 500 ms
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

Hasta ahora solamente hemos usado 3 bits del registro de propósito general flags, por lo que
disponemos de 5 bits para desarrollar nuevas funcionalidades a nuestro ejemplo, nótese que
flags,1 indica si el conteo será ascendente o descendente, pero se deja al lector la adición del
conteo descendente al programa.

;****************************************************************************

LIST P=18F4550 ;directiva para definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
CONFIG FOSC = INTOSC_XT ;Oscilador INT usado por el uC , XT usado por el USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO

91
Apuntes de Microcontroladores O22 Ricardo Álvarez González

CONFIG PWRT = ON ;PWR UP Timer habilitado


CONFIG WDT = OFF ;Temporizador vigía apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
CBLOCK 0x000 ;inicio del bloque de constantes
flags ;banderas
iun ;índice de unidades
cuni ;código de unidades
idec ;índice de decenas
cdec ;código de decenas
cont
tecla
ENDC ;fin del bloque de constantes
;******************************************************************************
; vector de reset
ORG 0x0000
bra inicio
org 0x08 ;vector de alta prioridad
bra RSIHP ;ramifica servicio interrupción T0
org 0x18 ;vector de baja prioridad
bra RSINT
inicio bsf OSCCON,IRCF2,0 ;Inicio del programa principal
bsf OSCCON,IRCF1,0
bcf OSCCON,IRCF0,0 ;Oscilador interno a 4 MHz
movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf LATB,0
movlw 0xF0
movwf TRISB,0 ;Configurar puerto para teclado
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0xf8
movwf TRISC,0 ;RC0, RC1 y RC2 como salidas
clrf PORTC,0
movlw 0x95
movwf T0CON,0 ;timer 16 bits prescalerX64
movlw 0XE8
movwf INTCON,0 ;interrupciones TMR0,RBIE prioridad alta y baja
movlw 0x07
movwf T2CON,0 ;Prescalerx16 y TIMER2 ON, POSTCALER 1
movlw 0x05
movwf PR2,0 ;valor para registro de periodo de .1mS
bsf IPR1,TMR2IP,0 ;timer2 alta prioridad
bsf PIE1,TMR2IE,0 ;habilitamos interrupción
bsf RCON,IPEN,0 ;habilitamos prioridades de interrupción
movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
movlw 0x04

92
Apuntes de Microcontroladores O22 Ricardo Álvarez González

movwf INTCON2,0 ;habilitamos intRBI en baja prioridad y R pull up


clrf TBLPTRL,0
movlw 0x03
movwf TBLPTRH,0
clrf TBLPTRU,0 ;tblptr=0x000300
clrf iun,0
clrf idec,0 ;iniciamos en 0
lee movff iun,TBLPTRL
tblrd * ;lee
movff TABLAT,cuni ;cuni tiene código 7 segmentos
movff idec,TBLPTRL
tblrd * ;lee
movff TABLAT,cdec ;cdec tiene código 7 segmentos
loop clrf PORTB,0
movlw 0x01
movwf PORTC,0 ; encendemos display unidades
movff cuni,PORTD
espera1 btfss flags,2,0
goto espera1
bcf flags,2,0
movlw 0x02
movwf PORTC,0 ;encendemos display decenas
movff cdec,PORTD
espera2 btfss flags,2,0
goto espera2
bcf flags,2,0
btfss flags,0,0
bra loop
bcf flags,0,0
incf iun,F,0
movf iun,W,0
xorlw 0x0a
btfss STATUS,Z,0
bra lee
clrf iun,0
incf idec,F,0
movf idec,W,0
xorlw 0x0a
btfss STATUS,Z,0
bra lee
clrf idec,0
goto lee
;******************************************************************************
RSIHP btfss INTCON,TMR0IF,0
bra RST2
bcf INTCON,TMR0IF,0 ;apagamos bandera timer0
movlw 0xE1
movwf TMR0H,0
movlw 0x7c
movwf TMR0L,0 ;valor de precarga para 500ms a 4MHz
bsf flags,0,0
retfie
RST2 bcf PIR1,TMR2IF,0

93
Apuntes de Microcontroladores O22 Ricardo Álvarez González

bsf flags,2 ;monitor de .1 ms


btg PORTC,2
retfie
;********************************************************************
RSINT call KBD ;Llamamos rutina del teclado
bcf INTCON,RBIF,0 ;LIMPIAMOS BANDERA
movwf tecla,0 ;guardamos tecla pulsada
movlw 0x0a
cpfslt tecla,0
bra opcion
movff tecla,idec
movff idec,TBLPTRL
tblrd * ;lee
movff TABLAT,cdec ;cdec tiene código 7 segmentos
bra exit
opcion movlw 0x0a
cpfseq tecla,0
bra desc
bsf flags,1,0 ;bandera ascendente
bra exit
desc movlw 0x0d
cpfseq tecla,0
bra clr
bcf flags,1,0 ;bandera descendente
bra exit
clr movlw 0x0c
cpfseq tecla,0
bra exit
clrf iun,0 ;limpiamos índice de unidades
clrf idec,0 ;limpiamos índice de decenas
movff idec,TBLPTRL
tblrd * ;lee
movff TABLAT,cdec ;cdec tiene código 7 segmentos
movff iun,TBLPTRL
tblrd * ;lee
movff TABLAT,cuni ;cdec tiene código 7 segmentos
exit clrf PORTB,0
retfie
;********************************************************************
;Regresa el numero de la tecla pulsada: 0 a F, si no se pulsó una
;tecla, regresa FF
KBD movlw 0x0E
movwf PORTB,0 ;activamos primer renglón
btfss PORTB,4,0
retlw 0x00 ;tecla 0
btfss PORTB,5,0
retlw 0x0A ;tecla a
btfss PORTB,6,0
retlw 0x0B ;tecla b
btfss PORTB,7,0
retlw 0x0C ;tecla c
movlw 0x0D
movwf PORTB,0 ;activamos segundo renglón

94
Apuntes de Microcontroladores O22 Ricardo Álvarez González

btfss PORTB,4,0
retlw 0x01 ;tecla 1
btfss PORTB,5,0
retlw 0x02 ;tecla 2
btfss PORTB,6,0
retlw 0x03 ;tecla 3
btfss PORTB,7,0
retlw 0x0D ;tecla d
movlw 0x0B
movwf PORTB,0 ;activamos tercer renglón
btfss PORTB,4,0
retlw 0x04 ;tecla 4
btfss PORTB,5,0
retlw 0x05 ;tecla 5
btfss PORTB,6,0
retlw 0x06 ;tecla 6
btfss PORTB,7,0
retlw 0x0E
movlw 0x07
movwf PORTB,0 ;activamos cuarto renglón
btfss PORTB,4,0
retlw 0x07 ;tecla 7
btfss PORTB,5,0
retlw 0x08 ;tecla 8
btfss PORTB,6,0
retlw 0x09 ;tecla 9
btfss PORTB,7,0
retlw 0x0F ;tecla F
retlw 0xFF ;ninguna tecla pulsada
org 0x300 ;DB es una directiva que Define Byte
;en este caso define los códigos de siete segmentos
DB 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xB8,0x80,0x98
END
Programa 10: Usamos el timer 2, para encender cada digito por 500 ms

Ejercicios 10.1

Modifique el programa 10, calculando el valor de timer 0, para encender cada dígito por un
segundo
Modifique el programa 10, usando el bit de bandera flags,1 para que dependiendo de su valor,
se genere el conteo ascendente o descendente

DIRECCIONAMIENTO INDIRECTO
El direccionamiento indirecto permite tener acceso a una localidad de memoria RAM, sin
proporcionar su dirección fija en la instrucción. Se usan los registros de selección de archivo
FSRs, como apuntadores a las localidades que se leerán o escribirán

;****************************************************************************
LIST P=18F4550 ;directiva para definir el procesador
#include <P18F4550.INC> ;definición de variables especificas del procesador

95
Apuntes de Microcontroladores O22 Ricardo Álvarez González

;****************************************************************************
;Bits de configuración
CONFIG FOSC = INTOSC_XT ;Oscilador interno para uC , XT para el USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;*************************************************************************
ORG 0x0000
bcf OSCCON,IRCF2,0
bsf OSCCON,IRCF0,0 ;Oscilador interno a125 kHz
clrf WREG,0
LFSR FSR0, 100h ;Carga apuntador con dir. inicial banco 1
NEXT addwf POSTINC0 ;INDF+w después incrementa FSR0
incf WREG,0
btfss FSR0H, 1 ;Terminamos con banco 1?
bra NEXT
limp clrf POSTDEC0 ; limpia localidad después incrementa FSR0
movf FSR0L,F,0
btfss STATUS,Z,0
bra limp
aqui bra aqui
;****************************************************************************
END
En verdad el FSR0 está compuesto por dos registros de 8 bits:

FSR0H FSR0L
01 00
Si los vemos en binario:

FSR0H FSR0L
0000 0001 0000 0000 Dirección inicial Banco 1
0000 0001 1111 1111 Dirección final Banco 1
00000010 0000 0000 Dirección inicial Banco 2

Ejercicio: Usando direccionamiento indirecto, llenar todo el banco 2 con alguna frase como:
Hola Mundo, otra frase podría ser: Equipo dos, etc. y observándolo con el simulador de
MPLAB. Entregables: el código fuente en ensamblador y la captura de pantalla del simulador,
en donde se observa el contenido del Banco 2. Se muestra en la figura siguiente, el banco 1,
cargado con la leyenda “Hola Mundo”

96
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 32 Banco 1 cargado con la leyenda “Hola Mundo”

MÓDULOS CAPTURA, COMPARACIÓN Y PWM


Estos son dos módulos, cada uno de ellos puede trabajar en alguno de los tres modos de
operación:

 Captura
 Comparación
 PWM

Para cada modo de funcionamiento, se tiene un pin asociado a cada módulo:

o RC1/CCP2

o RC2/CCP1

RC1 y RC2 deben de configurarse como entrada o salida, según sea el modo de operación
mediante el registro TRISC

Cada módulo tiene dos registros asociados, por ejemplo el módulo CCP1, tiene los registros
CCPR1H y CCPR1L.

En los modos de captura y comparación, estos dos registros de 8 bits, se concatenan para
formar un registro de 16 bits

En el modo PWM, uno de estos registros funciona como maestro y el otro como esclavo

97
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Modo Captura

En este modo, todo inicia en el pin CCP, que en este caso funciona como entrada, puede
detectar flancos, ascendentes o descendentes, si el prescaler esta en 4 (por ejemplo), al
detectarse 4 flancos. El valor de un timer de 16 bits, que puede ser TMR3 o TMR1, se captura
en el par de registros CCPR1H:CCPR1L y se pone la bandera de interrupción CCP1IF. Como se
conoce la base de tiempo asociada al timer correspondiente, se puede conocer exactamente
el tiempo al que se reciben los flancos en el pin CCP1

CCPR1H CCPR1L
3A 24 TMR1H TMR1L
72 5B 3A 24
72 5B
El timer iba en 3A24, después en el siguiente evento se captura el valor 725B ¿Qué tiempo
transcurrió entre los dos eventos? Debemos hacer la resta:725B-3A24=3837, en decimal es

98
Apuntes de Microcontroladores O22 Ricardo Álvarez González

14391, suponiendo que el timer se incrementa cada ms, entonces transcurrió un tiempo de
14391 ms

Aplicaciones del modo captura

Modo Comparación

Este modo funciona de manera contraria al anterior, ya que se realiza una comparación
constante entre el par de registros CCPR1 y un timer de 16 bits (que puede ser el Timer1 o el
timer 3, que finalmente, son hermanos gemelos)

99
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Cuando estos dos valores de 16 bits son iguales (match), se pone la bandera de interrupción
CCP1IF, y ahora el pin asociado debe configurarse como salida, cuando ocurre un match, este
pin se puede poner en 1, en 0, o hacer toggle.

Aplicaciones del modo comparación


Con este modo de operación de los módulos CCP se puede fácilmente controlar eventos
vinculados con el tiempo, incluso, se pueden generar señales, ya que el pin asociado, puede
hacer toggle en cada interrupción y generar fácilmente diversas frecuencias.

Registros de control de los módulos CCP


Como los dos módulos son idénticos, cada uno tiene su registro de control: CCP1CON y CCP2CON,
en las hojas de datos se muestra el registro CCPxCON, en donde x toma los valores de 1 y 2

100
Apuntes de Microcontroladores O22 Ricardo Álvarez González

101
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Modo PWM
• Este modo es muy diferente de los otros dos anteriores:

– Los registros CCPR1H y CCPR1L no funcionan concatenados, CCPR1L funciona


como registro maestro y CCPR1H como esclavo

– Se usa un timer de 8 bits: Timer2

– El pin asociado al módulo CCP se debe declarar como salida

– Este modo no tiene ninguna variante, claro que se puede configurar su periodo y
Ciclo de Trabajo

Ciclo de trabajo (Duty Cycle)


El ciclo de trabajo es el porcentaje del periodo que la señal se encuentra en alto

Con PR2 se establece el periodo de la señal

102
Apuntes de Microcontroladores O22 Ricardo Álvarez González

103
Apuntes de Microcontroladores O22 Ricardo Álvarez González

El ciclo de trabajo se especifica con 10 bits: los 8 MSB se escriben en el CCPR1L y los dos LSB en los
bits 5 y 4 de CCP1CON

El periodo del PWM se escribe en el registro de periodo PR2

Se compara constantemente el valor de 10 bits CCPR1H:CCP1CON<5:4> con el valor de TMR2


concatenado con dos ciclos Q del reloj interno del PIC, cuando son iguales (match) se resetea el
flip flop, bajando la señal en el pin de salida RC2/CCP1

Cuando TMR2=PR2, se pone el pin RC2/CCP1 y se carga el valor de CCPRIL (registro maestro) en
CCPR1H (esclavo) iniciando un nuevo periodo del PWM

Fórmulas para el periodo y el ciclo de trabajo

Es hasta este tema cuando en las hojas de datos, aparece una expresión para calcular el tiempo
generado por un timer, en este caso este tiempo corresponde al periodo de la señal PWM

Como se puede apreciar, esta fórmula es muy similar a la que hemos usado con los otros timers,
claro está que no tenían registro de periodo, pero encontrábamos un valor que se debía de restar
al máximo del timer, para conocer el valor de precarga del timer.

Aplicaciones del modo PWM


• Una señal de modulación de ancho de pulso tiene varias aplicaciones:

– Para variar la potencia suministrada a una carga, por ejemplo a un motor de DC, a
una lámpara resistiva, etc.

– Para controlar y disparar tiristores

– Para establecer el ángulo de funcionamiento de servomotores

– Etc.

Programa de ejemplo de PWM


En este caso se muestra como configurar el módulo PWM, para generar una señal con un ciclo de
trabajo (DC) del 60%, con un periodo de 100 ms, con una frecuencia de 125 KHz del oscilador
principal.

104
Apuntes de Microcontroladores O22 Ricardo Álvarez González

;****************************************************************************
LIST P=18F4550 ;directiva para definir el procesador
#include <P18F4550.INC>;definiciones de variables especificas del procesador
;****************************************************************************
;Bits de configuración
CONFIG FOSC = INTOSC_XT ;Oscilador INT usado por uC , XT para USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;****************************************************************************
;Reset vector
ORG 0x0000
bcf OSCCON,IRCF2,0
bsf OSCCON,IRCF0,0 ;Oscilador interno a125 kHz
movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0x1C ;00011100
movwf CCP1CON ;modo pwm
movlw 0x07
movwf T2CON,0 ;CONFIGURACION PREESCALER timer2 x 16
movlw d'194'
movwf PR2,0 ;PERIODO PWM 100ms
bcf TRISC,2,0 ;PIN ccp1 SALIDA
movlw 0x75
movwf CCPR1L,0 ;CICLO DE TRABAJO AL 60% (60 ms)
nada bra nada
END
Programa 12: generación de una señal PWM con ciclo de trabajo del 60%

Explicando el código por partes:

105
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Como se puede apreciar, cargando el valor 0x1C en CCP1CON, configuramos el modo PWM de
CCP1:

Con el valor 0x07 estamos configurando el timer 2 con un preescaler de 16, de acuerdo con el
registro T2CON.

106
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Con Fosc=125 KHz tenemos que el Tosc= 8µs

De acuerdo con la fórmula para un periodo de 100 ms:

Periodo=(PR2+1)*4*Tosc*Preescaler

99.84ms= (194 +1)*4*8 µs*16 que es muy cercano a 100 ms

Para el ciclo de trabajo de 60%, necesitamos un tiempo de 60 ms

De la fórmula para el DC tenemos que:

Despejando CCPR1L:CCP1CON<5:4>:

CCPR1L:CCP1CON<5:4>=60 ms/(8 µs*16)

CCPR1L:CCP1CON<5:4>=60 ms/128 µs=468.75 aproximándolo a 469, recordemos que es un


valor de 10 bits, por lo que debemos convertirlo a binario: 469=0111010101

El valor de 10 bits debemos acomodarlo en CCPR1L y CCP1CON, como muestra la figura:

107
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Por eso puede observarse en el código del ejemplo que CCPR1L=0x75 y los bits
CCP1CON<5:4>= 01

Como se puede apreciar en el ejemplo, una vez configurado el modo PWM, se estará
generando una señal con DC=60%, ¡sin ni siquiera usar la interrupción!

De tal manera que el procesador puede usarse para cualquier otra actividad, en este ejemplo,
no hace nada más y por eso se manda al ciclo infinito:

nada bra nada

108
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ejemplo: Mostrando un letrero en cuatro displays de 7 segmentos


Aquí veremos cómo podemos exhibir palabras en los displays de 7 segmentos, ajustándonos a
las letras que se pueden mostrar en ellos

RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0


Pto. G f E d c b a
Dec.
H 1 0 0 0 1 0 0 1 89
O 1 1 0 0 0 0 0 0 C0
L 1 1 0 0 0 1 1 1 C7
A 1 0 0 0 1 0 0 0 88
1 1 1 1 1 1 1 1 FF
b 1 0 0 0 0 0 1 1 83
U 1 0 1 0 0 0 0 1 A1
P 1 0 0 0 1 1 0 0 8C
Tabla E2

Para la palabra bUAP: 83,A1,88,8C

Usaremos el PORTD para los códigos de 7 segmentos y el PORTA para multiplexar los displays:

109
Apuntes de Microcontroladores O22 Ricardo Álvarez González

RA7 RA6 RA5 RA4 RA3 RA2 RA1 RA0 Código


0 0 0 0 0 0 0 1 01
0 0 0 0 0 0 1 0 02
0 0 0 0 0 1 0 0 04
0 0 0 0 1 0 0 0 08

110
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Para declarar como salida los pines de RA3 a RA0: Debemos cargar en el registro TRISA: 0xF0

;******************************************************************************

LIST P=18F4550 ;directiva para Definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
;CONFIG FOSC = INTOSC_XT ;Oscilador interno para el uC, XT para USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
cblock 0x0
cont
num
endc

;******************************************************************************
;Reset vector
ORG 0x0000
;Inicio del programa principal
bcf OSCCON,IRCF2,0 ; 001, Oscilador interno a 125 kHz
bsf OSCCON,IRCF0,0

111
Apuntes de Microcontroladores O22 Ricardo Álvarez González

movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0xF0
movwf TRISA ;salidas para multiplexar displays
movlw 0x03
movwf TBLPTRH ;TBLPTR=0X000300
movlw 0x04
movwf num
loop movlw 0x01
movwf PORTA ;enciende primer display
lee tblrd *+
movff TABLAT,PORTD
call retardo
rlcf PORTA,1 ;enciende siguiente display
movf num,W
cpfslt TBLPTRL
bra ini
bra lee
ini clrf TBLPTRL
bra loop
;******************************************************************************
retardo movlw 0x7f ;esta rutina tarda 128 ms en ejecutarse
movwf cont,0
nada nop
decfsz cont,F,0
bra nada
return
;*******************************************************************************
org 0x300
DB 0x89,0xc0,0xc7,0x88,0xff; HOLA
end

112
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ilustración 33 Uso de transistores para conmutar 4 displays de ánodo común

El código fuente sería:

;******************************************************************************

LIST P=18F4550 ;directiva para Definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
;CONFIG FOSC = INTOSC_XT ;Oscilador interno para el uC, XT para USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
cblock 0x0
cont
num
endc

;******************************************************************************
;Reset vector
ORG 0x0000
;Inicio del programa principal
bcf OSCCON,IRCF2,0 ; 001, Oscilador interno a 125 kHz
bsf OSCCON,IRCF0,0
movlw 0x0F

113
Apuntes de Microcontroladores O22 Ricardo Álvarez González

movwf ADCON1,0 ;Puertos Digitales


clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0xF0
movwf TRISA ;salidas para multiplexar displays
movlw 0x1C ;0001 1100
movwf CCP1CON ;modo pwm
movlw 0x07
movwf T2CON,0 ;CONFIGURACION PREESCALER timer2 x 16
movlw d'194'
movwf PR2,0 ;PERIODO PWM 100ms
bcf TRISC,2,0 ;PIN ccp1 SALIDA
movlw 0x75
movwf CCPR1L,0 ;CICLO DE TRABAJO AL 60% (60 ms)
movlw 0x03
movwf TBLPTRH ;TBLPTR=0X000300
movlw 0x04
movwf num
loop movlw 0x01
movwf PORTA ;enciende primer display
lee tblrd *+
movff TABLAT,PORTD
call retardo
rlcf PORTA,1 ;enciende siguiente display
movf num,W
cpfslt TBLPTRL
bra ini
bra lee
ini clrf TBLPTRL
bra loop
;******************************************************************************
Retardo movlw 0x7f ;esta rutina tarda 128 ms en ejecutarse
movwf cont,0
nada nop
decfsz cont,F,0
bra nada
return
;*******************************************************************************
org 0x300
DB 0x89,0xc0,0xc7,0x88,0xff
END

114
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ejemplo en ensamblador del ADC


Se muestra un ejemplo muy básico de como inicializar el convertidor analógico digital. Es muy
simple ya que muestra directamente el valor del resultado de los registros ADRESH y ADRESL en 4
exhibidores de 7 segmentos.

Para la palabra de 10 bits del resultado, se tienen dos opciones de formato:

ADFM U ACQT2 ACQT1 ACQT0 ADCS2 ADCS1 ADCS0


1 0 1 0 0 0 1 0

115
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Seleccionamos justificado a la derecha, con el bit ADFM=1, un tiempo de adquisición de 8 T AD


con la combinación 100 en ACQT2:ACQT0, y seleccionamos como reloj de conversión la
Fosc/32 con la combinación 010 en ADCS2:ADCS0

Sería el valor 0xA2 para ADCON2

Para seleccionar el canal de conversión y encender el módulo ADC:

U U CHS3 CHS2 CHS1 CHS0 GO/DONE ADON


0 0 0 0 0 0 1 1
Sería el valor 0x03 para ADCON0

116
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Como solamente usaremos la entrada analógica AN0, cargamos el valor 0x0E para ADCON1, con lo
cual también estamos seleccionando la fuente del chip, como voltajes de referencia del ADC.

Si usamos el puerto c para encender cada display, necesitamos que RC0:RC2 y RC6 sean salida:

TRISC

7 6 5 4 3 2 1 0
1 0 1 1 1 0 0 0

Para multiplexar los 4 displays, usaremos los bits 0,1,2 y 6. Sería el código B8 para TRISC. Los
valores para multiplexar los displays de 7 segmentos, se muestran en la siguiente tabla:

RC7 RC6 RC5 RC4 RC3 RC2 RC1 RC0 Código


0 0 0 0 0 0 0 1 01
0 0 0 0 0 0 1 0 02
0 0 0 0 0 1 0 0 04
0 1 0 0 0 0 0 0 40

;******************************************************************************

LIST P=18F4550 ;directiva para Definir el procesador

117
Apuntes de Microcontroladores O22 Ricardo Álvarez González

#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
;CONFIG FOSC = INTOSC_XT ;Oscilador interno para el uC, XT para USB
;Quitar el ; inicial del renglón anterior para grabar el chip
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
cblock 0x0
cont
id1 ;índice display 1
id2
id3
id4
cd1 ;código de 7 segmentos display 1
cd2
cd3
cd4
endc
;******************************************************************************
;Reset vector
ORG 0x0000
bra inicio
org 0x8
bra RSI
;Inicio del programa principal
inicio bcf OSCCON,IRCF2,0 ; 001, Oscilador interno a 125 kHz
bsf OSCCON,IRCF0,0
movlw 0x0E
movwf ADCON1,0 ;Puertos Digitales, solo AN0 entrada analógica
movlw 0xA2
movwf ADCON2,0 ;Just der. ADQ. 8 Tad y reloj de conversión fosc/32
bcf PIR1,ADIF ;limpio bandera de interrupción del ADC
bsf PIE1,ADIE ;Activamos interrupción ADC
movlw 0xc0
movwf INTCON ;PONEMOS BITS: GIE yPEIE
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0xB8
movwf TRISC ;RC2:RC0 Y RC6 salidas para multiplexar displays
movlw 0x03
movwf ADCON0 ;canal 0, ADC on, inicio conversión

118
Apuntes de Microcontroladores O22 Ricardo Álvarez González

movlw 0x03
movwf TBLPTRH ;TBLPTR=0X000300
clrf id1
clrf id2
clrf id3
clrf id4 ;iniciamos índices en 0
call inicod ;códigos de 7 segmentos
loop movlw 0x01
movwf PORTC ;encendemos display1
movff cd1,PORTD
call retardo
movlw 0x02
movwf PORTC ;encendemos display2
movff cd2,PORTD
call retardo
movlw 0x04
movwf PORTC ;encendemos display3
movff cd3,PORTD
call retardo
movlw 0x40
movwf PORTC ;encendemos display4
movff cd4,PORTD
call retardo
bra loop
;******************************************************************************
retardo movlw d’64’ ;esta rutina tarda aprox. 32 ms en ejecutarse
movwf cont,0
nada nop
decfsz cont,F,0
bra nada
return
;*******************************************************************************
inicod movff id1,TBLPTRL
tblrd *
movff TABLAT,cd1
movff id2,TBLPTRL
tblrd *
movff TABLAT,cd2
movff id3,TBLPTRL
tblrd *
movff TABLAT,cd3
movff id4,TBLPTRL
tblrd *
movff TABLAT,cd4
return
;*******************************************************************************
RSI movf ADRESL,W
andlw 0x0f ;selecciones los 4 LSB

119
Apuntes de Microcontroladores O22 Ricardo Álvarez González

movwf id1
movf ADRESL,W
andlw 0xf0 ;selecciones los 4 MSB
swapf WREG,1
movwf id2
movf ADRESH,W
andlw 0x0f ;selecciones los 4 LSB
movwf id3
bcf PIR1,ADIF ;limpio bandera de interrupción del ADC
call inicod
bsf ADCON0,1 ;INICIAMOS NUEVA CONVERSIÓN
retfie
;******************************************************************************
org 0x300 ;DB es una directiva que Define Byte
DB
0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xB8,0x80,0x98,0x88,0x83,0xC6,0xA1,0x86,0x8E
END
Recordemos que el valor digital, resultante de la conversión es de 10 bits, por lo tanto su rango
será:

Palabra digital Palabra digital en


en binario hexadecimal
00 0000 0000 000 VALOR
MÍNIMO
11 1111 1111 3FF VALOR
MÁXIMO (Full
scale)

120
Apuntes de Microcontroladores O22 Ricardo Álvarez González

¿Cómo podríamos usar este valor para convertirlo a alguna unidad? Por ejemplo si quisiéramos
ver el valor en voltios, en donde el valor de referencia positivo es 5 V y el de referencia negativo
es 0v? Considerando que tenemos 1024 combinaciones con 10 bits y el voltaje a máxima escala es
de 5v, entonces cada cambio en el valor digital, representa un cambio de 5v/1024=4.88 mv, el
valor de voltaje, correspondiente a un valor digital determinado, seria valor_digital*4.88 mv,
entonces por ejemplo para un valor de 1FF ¿Qué valor de voltaje representa? Haciendo las
operaciones en decimal seria 511*4.88 mv=2493 mv=2.49 v

Ejemplo del USART


En la figura siguiente, se muestran los valores de configuración de los registros del USART, para
modo asíncrono. Utilizaremos dos chips: uno será el transmisor que tendrá activa la entrada
analógica AN0 y la palabra digital la enviará serialmente al chip receptor, el cual tiene la pantalla
de los cuatro displays.

121
Apuntes de Microcontroladores O22 Ricardo Álvarez González

El programa para el transmisor:

;******************************************************************************

LIST P=18F4550 ;directiva para Definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
;CONFIG FOSC = INTOSC_XT ;Oscilador interno para el uC, XT para USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
cblock 0x0
cont
endc
;******************************************************************************
;Reset vector
ORG 0x0000
bra inicio
org 0x8
bra RSI
inicio bsf OSCCON,IRCF2,0 ;Inicio del programa principal
bsf OSCCON,IRCF1,0
bcf OSCCON,IRCF0,0 ;110, Oscilador interno a 4 MHz
movlw 0x0E
movwf ADCON1,0 ;Puertos Digitales, solo AN0 entrada analógica
movlw 0xA2

122
Apuntes de Microcontroladores O22 Ricardo Álvarez González

movwf ADCON2,0 ;Just der. Tiempo adq 8 Tad y reloj de conversión fosc/32
bcf PIR1,ADIF ;limpio bandera de interrupción del ADC
bsf PIE1,ADIE ;Activamos interrupción ADC
movlw 0xc0
movwf INTCON ;GIE y PEIE
movlw 0xF9
movwf TRISA ;RA2 y RA1 salidas
movlw 0x03
movwf ADCON0 ;canal 0, encendemos módulo ADC, inicio conversión
movlw 0x90
movwf RCSTA ;habilitamos puerto serial y receptor
bsf TXSTA,TXEN ;habilitamos el transmisor, modo asíncrono
movlw d'103'
movwf SPBRG ;COMUNICACIÓN A 9600 baudios
bsf TXSTA,BRGH ;Alta velocidad
loop btg PORTA,1 ;led monitor de funcionamiento
call retardo
bra loop
;******************************************************************************
retardo movlw 0xff
movwf cont,0
nada nop
decfsz cont,F,0
bra nada
return
;*******************************************************************************
RSI movff ADRESL,TXREG
wait1 btfss TXSTA,TRMT ;espera a que se vacíe el TSR
bra wait1
btg PORTA,2 ;LED monitor transmisión
movff ADRESH,TXREG
wait2 btfss TXSTA,TRMT;espera a que se vacíe el TSR
bra wait2
bcf PIR1,ADIF ;limpiamos bandera interrupción ADC
btg PORTA,2
bsf ADCON0,1 ;iniciamos nueva conversión
retfie
;******************************************************************************
END

En el MCU receptor, tenemos nuestra pantalla integrada por cuatro displays. Para multiplexar los
displays, usaremos el PORTA:

RA7 RA6 RA5 RA4 RA3 RA2 RA1 RA0


0 0 0 0 1 0X01
0 0 0 1 0 0x02
0 0 1 0 0 0x04
0 1 0 0 0 0X08
El código fuente del MCU receptor se muestra a continuación

123
Apuntes de Microcontroladores O22 Ricardo Álvarez González

;******************************************************************************

LIST P=18F4550 ;directiva para Definir el procesador


#include <P18F4550.INC> ;definiciones de variables especificas del procesador

;******************************************************************************
;Bits de configuración
;CONFIG FOSC = INTOSC_XT ;Oscilador interno para el uC, XT para USB
CONFIG BOR = OFF ;BROWNOUT RESET DESHABILITADO
CONFIG PWRT = ON ;PWR UP Timer habilitado
CONFIG WDT = OFF ;Temporizador vigia apagado
CONFIG MCLRE=OFF ;Reset apagado
CONFIG PBADEN=OFF
CONFIG LVP = OFF
;******************************************************************************
;Definiciones de variables
cblock 0x0
cont
id1
id2
id3
id4
cd1
cd2
cd3
cd4
flags
endc
;******************************************************************************
;Reset vector
ORG 0x0000
bra inicio
org 0x8
bra RSI
;Inicio del programa principal
inicio bsf OSCCON,IRCF2,0
bsf OSCCON,IRCF1,0
bcf OSCCON,IRCF0,0 ; 110, Oscilador interno a 4 MHz
movlw 0x0F
movwf ADCON1,0 ;Puertos Digitales
movlw 0xc0
movwf INTCON ;PONEMOS BITS: global y el de interrupciones periféricas
clrf PORTD,0
clrf TRISD,0 ;Puerto D Configurado como salida
movlw 0xF0
movwf TRISA ;RA3:RA0 salidas para multiplexar displays
movlw 0x90
movwf RCSTA ;HABILITAMOS PUERTO SERIAL Y RECEPTOR

124
Apuntes de Microcontroladores O22 Ricardo Álvarez González

bsf TXSTA,TXEN ;habilitamos el transmisor, modo asíncrono


movlw d'103'
movwf SPBRG ;COMUNICACIÓN A 9600 baudios
bsf TXSTA,BRGH ;Alta velocidad
bsf PIE1,RCIE ;INTERRUPCIÓN DE RECEPCIÓN SERIAL
bcf flags,2 ;valor inicial para leer la parte baja del ADC
movlw 0x03
movwf TBLPTRH ;TBLPTR=0X000300
clrf id1
clrf id2
clrf id3
clrf id4 ;iniciamos índices en 0
call inicod
loop movlw 0x01
movwf PORTA ;encendemos display1
movff cd1,PORTD
call retardo
movlw 0x02
movwf PORTA ;encendemos display2
movff cd2,PORTD
call retardo
movlw 0x04
movwf PORTA ;encendemos display3
movff cd3,PORTD
call retardo
movlw 0x08
movwf PORTA ;encendemos display4
movff cd4,PORTD
call retardo
bra loop
;******************************************************************************
retardo movlw 0xFF
movwf cont,0
nada nop
decfsz cont,F,0
bra nada
return
;*******************************************************************************
inicod movff id1,TBLPTRL
tblrd *
movff TABLAT,cd1
movff id2,TBLPTRL
tblrd *
movff TABLAT,cd2
movff id3,TBLPTRL
tblrd *
movff TABLAT,cd3
movff id4,TBLPTRL

125
Apuntes de Microcontroladores O22 Ricardo Álvarez González

tblrd *
movff TABLAT,cd4
return
;*******************************************************************************
RSI btfsc flags,2
bra alta
movff RCREG,ADRESL
bsf flags,2
bcf PIR1,RCIF
retfie
alta movff RCREG,ADRESH
bcf flags,2
bcf PIR1,RCIF ;apagamos interrupción de recepción
movf ADRESL,W ;inicia procesamiento palabra digital 10 bits
andlw 0x0f ;selecciones los 4 LSB
movwf id1
movf ADRESL,W
andlw 0xf0 ;selecciones los 4 MSB
swapf WREG,1
movwf id2
movf ADRESH,W
andlw 0x0f ;selecciones los 4 LSB
movwf id3
call inicod
retfie
;******************************************************************************
org 0x300 ;DB es una directiva que Define Byte
;en este caso define los códigos de siete segmentos
DB
0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xB8,0x80,0x98,0x88,0x83,0xC6,0xA1,0x86,0x8E
END
En la siguiente figura tenemos la simulación del ejemplo de la comunicación serial:

126
Apuntes de Microcontroladores O22 Ricardo Álvarez González

127
Apuntes de Microcontroladores O22 Ricardo Álvarez González

PROGRAMACIÓN EN LENGUAJE DE ALTO NIVEL


Hasta ahora, todos los programas mostrados se han escrito en lenguaje ensamblador, pero los
microcontroladores también pueden programarse en lenguaje de alto nivel, sin embargo, el
microcontrolador solamente puede ejecutar instrucciones en ensamblador, por lo quese
necesita un programa que traduzca las instrucciones de alto nivel a lenguaje ensamblador,
este trabajo lo realiza el compilador. Existen muchos compiladores de lenguaje de alto nivel
como: C, Pascal, Basic etc.

Al usar un lenguaje de alto nivel para programar un MCU, dependemos del compilador, por lo
que el desempeño del programa está en función de la eficiencia de éste.

VENTAJAS DEL COMPILADOR DE ALTO NIVEL DESVENTAJAS DEL COMPILADOR DE ALTO


NIVEL
Menor tiempo de desarrollo de una aplicación Dependencia del compilador
Uso de subprogramas prefabricados para usar Costo del compilador
algún periférico del MCU (funciones de
biblioteca)
Facilidad para realizar aplicaciones complejas No se tiene un control directo de los recursos
del MCU
No es necesario conocer a fondo la Dependiendo del compilador, un programa
arquitectura del MCU simple puede saturar rápidamente la
memoria de programa
De los compiladores de alto nivel, son muy populares los de lenguaje C, podemos citar
algunos: Mikro C, Pic C, C18, C30. Los dos últimos son de Microchip, para usar la versión
completa, es necesario pagar por la licencia.

128
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Se debe de considerar algunas recomendaciones generales al escribir un código en lenguaje de


alto nivel para un MCU:

 Usar variables del menor “tamaño ” posible


 Usar el lenguaje de alto nivel, para aplicaciones que así lo requieran, debido a su
complejidad que implica un programa en ensamblador que realice la misma función
 Si la aplicación es muy simple, como manejo de leds e interruptores, se recomienda
usar lenguaje ensamblador

Es decir, si la aplicación es relativamente simple, es mejor usar lenguaje ensamblador y usar el


lenguaje de alto nivel solamente para aplicaciones muy complejas o cuando es necesario hacer el
programa rápidamente.

Ejemplos de programas con el compilador CCS


Todas las aplicaciones con microcontroladores, implican un ciclo infinito, como puede observarse
en la figura:

Se muestran unos ejemplos en lenguaje C, usando el compilador CCS

Se debe de crear un proyecto en el compilador CCS:

129
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Una vez creado el proyecto, nos genera una plantilla para escribir nuestro programa:

Como podemos observar en la imagen anterior, se incluye un ciclo infinito en la plantilla.

Ejemplo: Controlando LEDs en alto nivel


#include <leds_c.h>
void main()

130
Apuntes de Microcontroladores O22 Ricardo Álvarez González

{
while(TRUE)
{
output_D(0xf2);
delay_ms(1000);
output_D(0xa5);
delay_ms(1000);
//TODO: User Code
}
}

Al compilar el código se genera su código equivalente en ensamblador, ya que es el único


lenguaje que puede ejecutar el microcontrolador, se muestra en las imágenes siguientes, unas
secciones del código asm generado:

131
Apuntes de Microcontroladores O22 Ricardo Álvarez González

132
Apuntes de Microcontroladores O22 Ricardo Álvarez González

133
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ejemplo: Usar un LCD alfanumérico


#include <LCD.c> //Importante incluir esta librería para activar el LCD
void main()
{
lcd_init(); //D4 RD4, D5 RD5, D6 RD6 D7 RD7, RS RD1, RW RD2, E RD0
lcd_putc("Hola Mundo");
lcd_gotoxy(1,2);
lcd_putc("FCE BUAP");
while(TRUE)
{
output_B(0xf2);
delay_ms(1000);
output_B(0xa5);
delay_ms(1000);
//TODO: User Code
}

134
Apuntes de Microcontroladores O22 Ricardo Álvarez González

135
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ejemplo usando el ADC:


#include <ejemplo1.h>
#include <lcd.c>
int8 valorADC;
void main()
{
OUTPUT_HIGH(PIN_E2);
lcd_init();
delay_us(100);

136
Apuntes de Microcontroladores O22 Ricardo Álvarez González

lcd_putc("Hola Mundo");
WHILE(1)
{
SETUP_ADC(ADC_CLOCK_INTERNAL);
setup_adc_ports(AN0);
set_adc_channel(0);
while(1)
{
delay_ms(500);
valorADC=read_adc();
lcd_gotoxy(1,2);
printf(lcd_putc,"ADC valor= %d", valorADC);
}
}
}

En el ejemplo anterior, solamente se inicializa el ADC y se muestra su valor en la pantalla, sin


hacer ningún procesamiento, observando incluso que se obtienen valores negativos, debido a
la definición de la variable valorADC como int8. La versión mejorada de este programa, en
donde se define la variable valorADC de tipo unsigned int16 y se realizan las operaciones
necesarias con el valorADC para mostrar un valor de voltaje entre 0 y 5v.

#include <ADC_CCS.h>
#include <lcd.c>
unsigned int16 valorADC;
float p;

void main()

137
Apuntes de Microcontroladores O22 Ricardo Álvarez González

{
OUTPUT_HIGH(PIN_E2);
lcd_init();

while(TRUE)
{
//TODO: User Code
SETUP_ADC(ADC_CLOCK_INTERNAL);
setup_adc_ports(AN0);
set_adc_channel(0);
while(TRUE)
{
delay_ms(200);
valorADC=read_adc(); //lectura del ADC
p=5.0*valorADC/1024.0; //conversión a voltaje
printf(lcd_putc,"\fADC valor= %lu", valorADC);
printf(lcd_putc,"\nVoltaje= %01.2fv", p);
}

}
En la figura siguiente, se muestra la simulación de la segunda versión del programa que nos
muestra el valor del ADC y el voltaje:

138
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ejemplo: Usando un teclado matricial en CCS


El siguiente código es para conectar un teclado matricial de 3 x 4 a un PIC18F4550, mostrando el
carácter de la tecla pulsada en una pantalla LCD.

#include <LCD2.h>
#include <LCD.c> //Importante incluir esta librería para activar el LCD
#include <KBD.c> //Función de libreria para un teclado 4 x 3

void main()
{
char tecla;

lcd_init(); //D4 RD4, D5 RD5, D6 RD6 D7 RD7, RS RD1, RW RD2, E RD0


lcd_putc("Quedate en casa");
lcd_gotoxy(1,2);
lcd_putc("COVID19 ");
kbd_init();
port_b_pullups(true);
while(TRUE)
{
tecla=kbd_getc();
if (tecla != 0 )
lcd_putc(tecla);
delay_ms(10);
}
}
}
Revisar la correcta conexión del teclado para que funcione la simulación:

139
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Introducción al internet de las cosas (IoT)


Para esta sección, utilizaremos la tarjeta de desarrollo NodeMCU, que tiene un SoC con un módulo
wifi, que le permite conectarse a una red WIFI y así nos da el poder de realizar sistemas
embebidos con posibilidad de interacción mediante internet.

Ilustración 34 Tarjeta de desarrollo NodeMCU

La NodeMCU podemos configurarla mediante el IDE de arduino, para lo cual es necesario


instalarle la librería de esta tarjeta. Ver el video que está al final del tutorial de la página:

https://programarfacil.com/podcast/nodemcu-tutorial-paso-a-
paso/#NodeMCU_el_kit_de_desarrollo_para_el_IoT

En la siguiente imagen puedes ver una visión general de todos los pines de NodeMCU V2.

140
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Como norma, siempre que haga referencia a este diagrama de pines de NodeMCU, equivaldrá a si
ponemos la placa con el puerto USB hacia abajo como se muestra en la siguiente imagen .

141
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Liga para instalar el archivo json con la librería del esp8266:

http://arduino.esp8266.com/stable/package_esp8266com_index.json

142
Apuntes de Microcontroladores O22 Ricardo Álvarez González

En el menú archivo/preferencias, se debe de pegar estadirección en el gestor de URLs adicionales


de tarjetas:

Posteriormente abrimos el gestor de tarjetas, escribimos esp8266 y le damos click en instalar:

143
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Una vez que ya se instaló la librería aparece el mensaje

Una vez instalada la librería ahora podemos seleccionar la tarjeta, la que funciona bien es la
nodeMCU 0.9ESP12

Ejemplo: Parpadeo de un LED con la NodeMCU


Este ejemplo sirve paraverificar que ya podemos interactuar con la tarjeta de desarrollo mediante
el IDE de Arduino

144
Apuntes de Microcontroladores O22 Ricardo Álvarez González

/*
ESP8266 Blink by Simon Peter
Blink the blue LED on the ESP-01 module
This example code is in the public domain

The blue LED on the ESP-01 module is connected to GPIO1


(which is also the TXD pin; so we cannot use Serial.print() at the same time)

Note that this sketch uses LED_BUILTIN to find the pin with the internal LED
*/

void setup() {
pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output
pinMode(D0, OUTPUT); //declaramos el pin D0 como salida
}

// the loop function runs over and over again forever


void loop() {
digitalWrite(LED_BUILTIN, LOW); // Turn the LED on (Note that LOW is the voltage level
// but actually the LED is on; this is because
// it is active low on the ESP-01)
digitalWrite(D0, HIGH);
delay(2000); // Wait for two seconds
digitalWrite(LED_BUILTIN, HIGH); // Turn the LED off by making the voltage HIGH
digitalWrite(D0, LOW);
delay(2000); // Wait for two seconds (to demonstrate the active low LED)
}

Los mensajes que nos proporciona el IDE de Arduino son:

El Sketch usa 258652 bytes (24%) del espacio de almacenamiento de programa. El máximo es 1044464 bytes.

145
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Las variables Globales usan 26696 bytes (32%) de la memoria dinámica, dejando 55224 bytes para las variables locales.
El máximo es 81920 bytes.

Uploading 262800 bytes from C:\Users\RICARD~1\AppData\Local\Temp\arduino_build_183043/Blink.ino.bin to flash at


0x00000000

................................................................................ [ 31% ]

................................................................................ [ 62% ]

................................................................................ [ 93% ]

................. [ 100% ]

Ejemplo: creando un servidor con el ESP8266


#include <ESP8266WiFi.h>

const char* ssid = "INFINITUMkjh4"; // ;variables para poder acceder a la red


const char* password = "3afcdcb99e"; //en la cual nos vamos a comunicar contraseña y nombre

int ledPin = 16; // GPIO16 pin que vamos a prender y apagar


WiFiServer server(80); //declaramos un servidor en el puerto 80

void setup() {
Serial.begin(115200); //iniciar el puerto serial
delay(10);

pinMode(ledPin, OUTPUT); //configurar el pin como salida


digitalWrite(ledPin, LOW); //lo inicializamos en bajo para que el led este apagado

// Connect to WiFi network


Serial.println();
Serial.println();
Serial.print("Conectando a: "); // avisamos a que red nos conectamos es decir a la red que pusimos al inicio
Serial.println(ssid);

WiFi.begin(ssid, password); //con esto nos conectamos

while (WiFi.status() != WL_CONNECTED) { //se mandan puntos mientras se conecta la red wifi
delay(500);
Serial.print(".");
}
Serial.println(""); //una vez que se conecte saldra del ciclo while
Serial.println("wifi conectado"); //nos mostrara que ya estamos conectados

// Start the server


server.begin(); //iniciamos el servidor
Serial.println("inciando servidor "); //imprime que esta iniciado el servidor

// Print the IP address


Serial.print("usa esta URL para conectarte "); //imprime la URL a la que se tiene que conectar
Serial.print("http://");
Serial.print(WiFi.localIP()); //imprime el IP del dispositivo
Serial.println("/");

void loop() {

146
Apuntes de Microcontroladores O22 Ricardo Álvarez González

// Check if a client has connected


WiFiClient client = server.available(); //creamos un objeto cliente
if (!client) { //aqui se va a meter en ciclo if saliendo solo hasta que se conecte alguien
return;
}

// Wait until the client sends some data


Serial.println("nuevo cliente");
while(!client.available()){ //este ciclo while nos retiene aqui hasta que nosotros hagamos una peticion a la
placa, nuestro servidor
delay(1);
}

// Read the first line of the request


String request = client.readStringUntil('\r'); //declaramos una variable string para guardar los datos que solicita el
cliente
Serial.println(request);
client.flush();

// Match the request

int value = LOW; //creamos una variable para low


if (request.indexOf("/LED=ON") != -1) { //en este ciclo if si el requerimiento del cliente contiene a /led on pondra
la salida en alto
digitalWrite(ledPin, HIGH);
value = HIGH;
}
if (request.indexOf("/LED=OFF") != -1) {
digitalWrite(ledPin, LOW); //en este caso si contiene /LED=0FF" se pondrá en bajo
value = LOW;
}

// Set ledPin according to the request


//digitalWrite(ledPin, value);

// Return the response


client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println(""); // do not forget this one
client.println("<!DOCTYPE HTML>");
client.println("<html>");

client.print("Led conectado al pin esta: ");

if(value == HIGH) {
client.print("On");
} else {
client.print("Off"); //con el código HTML se crean los botones que digan On y OFF en el
navegador
}
client.println("<br><br>");
client.println("<a href=\"/LED=ON\"\"><button>Turn On </button></a>");
client.println("<a href=\"/LED=OFF\"\"><button>Turn Off </button></a><br />"); //nos dira el si el led esta prendido o
apagado
client.println("</html>");

delay(1);
Serial.println("Client disonnected");
Serial.println("");

147
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Después de haber subido el archivo, el IDE de Arduino nos genera la información:

El Sketch usa 275500 bytes (26%) del espacio de almacenamiento de programa. El máximo es 1044464 bytes.

Las variables Globales usan 27888 bytes (34%) de la memoria dinámica, dejando 54032 bytes para las variables locales.
El máximo es 81920 bytes.

148
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Uploading 279648 bytes from C:\Users\RICARD~1\AppData\Local\Temp\arduino_build_723084/IOTFIN.ino.bin to flash


at 0x00000000

................................................................................ [ 29% ]

................................................................................ [ 58% ]

................................................................................ [ 87% ]

.................................. [ 100% ]

149
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Los mensajes mostrados por la terminal serial, del programa Tera Term:

cinectando a: INFINITUMkjh3

...

wifi conectado

inciando servidor

usa esta URL para conectarte http://192.168.1.78/

150
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Ejemplo usando la plataforma para IoT: ThingSpeak


En este ejemplo usaremos la plataforma de IoT mencionada, para leer la temperatura ambiente
mediante un LM35 y graficar su valor. El código del ejemplo es el siguiente:

#include "ThingSpeak.h"

151
Apuntes de Microcontroladores O22 Ricardo Álvarez González

#include <ESP8266WiFi.h>
const int LM35 = A0;
//----------- Enter you Wi-Fi Details---------//
char ssid[] = "INFINITUMkjh4"; //SSID
char pass[] = "3afcdcb99c"; // Password
//-------------------------------------------//

WiFiClient client;

unsigned long myChannelNumber = 1603514; // Channel ID here


const int FieldNumber = 1;
const char * myWriteAPIKey = "1GV3A76D3T6G9VIM"; // Your Write API Key here

void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
ThingSpeak.begin(client);
}
void loop()
{
if (WiFi.status() != WL_CONNECTED)
{
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
while (WiFi.status() != WL_CONNECTED)
{
WiFi.begin(ssid, pass);
Serial.print(".");
delay(5000);
}
Serial.println("\nConnected.");
}
int ADC;
float temp;
ADC = analogRead(LM35); /* Read Temperature */
temp = (ADC * 3); /* Convert adc value to equivalent voltage */
temp = (temp / 10); /* LM35 gives output of 10mv/°C */
Serial.print("Temperature = ");
Serial.print(temp);
Serial.println(" *C");
delay(1000);
ThingSpeak.writeField(myChannelNumber, FieldNumber, temp, myWriteAPIKey);
delay(1000);
}
Debes de registrarte en ThingSpeak mediante tu email y crear un canal

El ID del canal lo obtenemos de thingspeak:

152
Apuntes de Microcontroladores O22 Ricardo Álvarez González

La llave de escritura:

En este ejemplo se esta leyendo la temperatura ambiente y se manda a la nube, observamos la


gráfica:

153
Apuntes de Microcontroladores O22 Ricardo Álvarez González

También podemos observar los datos que nos envía serialmente, podemos usar para esto el
programa TeraTerm o usando la terminal serial de arduino, la cual debemos configurar a 115200
baudios:

ThingSpeak nos permite descargar los datos recolectados por la NodeMCU, en la pestaña Data
import/export:

154
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Nos los genera en un archivo .csv

155
Apuntes de Microcontroladores O22 Ricardo Álvarez González

156
Apuntes de Microcontroladores O22 Ricardo Álvarez González

Bibliografía:
DS39632D Microchip Technology Inc. 2007

Organización de Computadoras, un enfoque estructurado. Andrew S. Tanenbaum. Prentice


Hall. Cuarta Edición, 2000

https://programarfacil.com/podcast/nodemcu-tutorial-paso-a-
paso/#NodeMCU_el_kit_de_desarrollo_para_el_IoT

http://hilite.me/

157

También podría gustarte