Ejercicios Dspic

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 147

CAPÍTULO 3

EJERCICIOS BÁSICOS UTILIZANDO


DSPICS

87
CAPÍTULO 3

3.1 INTRODUCCIÓN

En este capítulo se revisará los procedimientos básicos de uso y configuración


de los diferentes módulos de los dspics.

A continuación se presenta una serie de ejercicios que forman parte de una


recopilación de proyectos y experiencias de miembros de blogs y foros de
Internet.

Cabe recalcar que las fuentes de información para la programación en dspics


es mínima, debido a que se trata de una tecnología nueva donde Microchip ha
incursionado como pionera, el simple hecho de producir un microcontrolador
de carácter híbrido la hace sumamente atractiva para usarla en un sinúmero
de aplicaciones como el procesamiento de señales, manejo de sensores,
audio, etc.

En la actualidad hay muy pocas personas que han incursionado en el manejo


de los dspics como lo que son, microcontroladores que procesan señales.

En realidad lo que se tiene a la mano en cuanto a información del manejo de


los dspics como controladores digitales de señal, es apenas lo que se tiene en
foros dedicados a los microcontroladores, datasheets, y lo más destácable el
libro Microcontroladores Avanzados. Sin embargo todos estos tienen las
mismas características y limitantes, en muy pocos de los casos se trata con
aplicaciones o ejercicios que muestren la forma de programación desde cero, y
se debe dedicar muchísimo tiempo a entender cientos de hojas de manuales y
datasheets para poder entender su manejo, o a su vez se tienen bosquejos de
programación con ejercicios básicos que no funcionan.

En forma global en este proyecto se tiene a la mano un manual donde se


detalla de forma específica lo que se debe y lo que no se debe hacer para
88
poder implementar aplicaciones en dspics orientadas al procesamiento de
señales, yendo poco a poco de ejercicios básicos hasta ejercicios avanzados
entendiendo lo estructural y medular en cada uno de estos.

Se presentarán ejemplos prácticos del uso y manejo de los dspic y además, de


manera muy resumida, se verá el manejo de herramientas útiles en el
desarrollo de aplicaciones, ya que para un estudio a profundidad de los dspic
están disponibles los manuales en los respectivos sitios web.

3.2 CONSIDERACIONES PREVIAS DE PROGRAMACIÓN

Debido a la extensión y a la variedad de aplicaciones, los ejercicios aquí


mostrados son solamente una breve muestra de la potencialidad de los dspics.
Sin embargo se debe tener en claro que el objetivo de estos ejercicios es
impulsar el desarrollo de aplicaciones que permitan luego explotar totalmente
la potencialidad de los dspics. Por tanto no se presentan aplicaciones
enfocadas a un fin práctico más bien se intenta exponer las capacidades y
virtudes así como también lás limitaciones de estos microcontroladores.

Todas las prácticas han sido implementadas en hardware. Por practicidad se


usan equipos de entrenamiento en algunos casos, aunque su uso no es
obligatorio en el desarrollo de aplicaciones con dspics. Se puede hacer uso de
un protoboard común y un grabador de dspics, y cualquier aplicación se vuelve
realizable, sin ningún problema.

Los lenguajes de programación usados se basan en el compilador MPLAB


C30, este compilador admite trabajar en conjunto con el lenguaje ensamblador
y lenguaje C30.

En el caso de usar C30 como lenguaje de programación de los


microcontroladores se debe tener en claro que se puede trabajar libremente
con las subrutinas utilizadas en C30, comparadores, condicionales, etc. Esto a
su vez facilita de sobremanera la creación de programas y de aplicaciones ya
que su forma de programación es mucho más simple y más rápida de elaborar.

89
Para explicar en forma metódica la programación de los diferentes módulos de
los dspics se hará uso del siguiente proceso:

 Diagrama de Flujo

 Elaboración de Código

 Compilación y Depuración

 Implementación en Hardware.

3.2.1 DIAGRAMA DE FLUJO

En el diagrama de flujo se representan los pasos principales que deben darse


para la configuración de los diferentes módulos del dspic.

3.2.2 ELABORACIÓN DE CÓDIGO

En la elaboración del código se incluyen las diferentes funciones y líneas de


código que configuran el dspic.

3.2.3 COMPILACIÓN Y DEPURACIÓN

En este paso se efectúa una prueba virtual de la efectividad del código


elaborado.

Se trabaja en el MPLAB IDE con el compilador MPLAB C30, en lenguaje


ensamblador y en lenguaje C30, la compilación se efectúa como paso previo a
la prueba en hardware.

Aquí se pueden efectuar depuraciones de código y optimización del mismo.

90
3.2.4 IMPLEMENTACIÓN EN HARDWARE

En la etapa de pruebas se cargará el archivo compilado, .hex en el dspic, y se


realizarán pruebas de funcionamiento de los ejercicios propuestos en
hardware.

Dependiendo del ejercicio se lo probará en un protoboard común o en un


entrenador, sin que esto signifique restricciones a la forma de probar uno u
otro ejercicio. Cabe recalcar que una de las virtudes más poderosas de los
dspics es que funcionan como un microcontrolador común, es decir sin ningún
tipo de restricciones a que se realice pruebas en un protoboard.

3.3 EJERCICIOS BÁSICOS DE MANEJO DE DSPICS


En este trabajo se realizan los siguientes ejericios básicos:

 Encender un LED.
 Encender LEDS con Retardos Programados.
 Manejo de Interrupciones Externas.
 Manejos de la Memoria EEPROM.
 Utilización Básica de los TIMERs.
 Utilización del ADC.
 Utilización del Módulo UART y el Hyperterminal del Computador.
 Utilización del Módulo UART, ADC y MATLAB.

3.3.1 MANEJO DE PUERTOS DE ENTRADA Y SALIDA

En la familia dspic30fxxxx se dispone de pines de entrada y salida como en el


más común de los microcontroladores.

El propósito general de los puertos de E/S es permitir al microcontrolador


controlar y comunicarse con los dispositivos externos.

91
En la figura 3.1 se muestra un diagrama de bloques de la estructura interna de
un pin de un puerto de entrada y salida del dspic30fxxxx.

Figura 3.1 Estructura interna de un pin de E/S30

3.3.1.1 Registros de Control de los Puertos de Entrada y Salida

Todos los puertos de entrada y salida tienen asociados tres registros para el
control de la operación de dichos puertos, la letra x denota el puerto E/S
particular.

 TRISx: Registro que determina si los pines de los puertos son entradas
o salidas.

 PORTx: Registro que contiene el valor de los pines de entrada de los


puertos.

 LATx: Registro latch que almacena el valor que tienen los pines de
salida del puerto.

30
www.Microchip.com

92
3.3.1.2 Ejercicio No. 1: Encender un LED.

Se empieza el manejo de los puertos de los dspics desde el ejercicio más


básico, es decir encendiendo un LED en el pin de un puerto de un dspic. Como
complemento a este ejercicio se le añadirá el leer el estádo lógico de un pin
adicional del dspic para encender otro LED conectado en otro pin.

Para realizar este ejercicio se escogió el dspic30F4013 cuyo diagrama de


pines se muestra en la figura 3.2.

Figura 3.2 Distribución de pines resumida del dspic30F4013

Para la programación de este ejercicio se escogieron el puerto B, y el pin RB0,


como pin de señalización, RB1 como pin indicador del estádo lógico de RF1;
en la figura 3.3 se muestra el diagrama del circuito a implementarse.

93
Figura 3.3 Circuito para realizar las pruebas del Ejercicio No. 1

3.3.1.2.1 Diagrama de Flujo

Para facilitar la programación de este ejercicio se sigue el flujograma 3.1.

INICIO

CONFIGURACIÓN DEL
DISPOSITIVO

CONFIGURACIÓN DEL
PUERTO B Y F

 ENCIENDER PIN RBO


 APAGAR PIN RB1

MANTENER EL
WHILE( _PORTF1) NO
ESTADO DE RB1

BUCLE INFINITO SI

CAMBIAR EL ESTADO DE
RB1

FIN DE PROCESO

Flujograma 3.1 Flujograma del Ejercicio No. 1

94
3.3.1.2.2 Elaboración de Código

El código será escrito en lenguaje C30 como también en ensamblador


teniendo así dos posibilidades de programación.

Para empezar con la programación es necesario estructurar el encabezado de


las librerías, y la configuración del dispositivo. Estos son los dos primeros
procesos especificados en el Flujograma 3.1.

El encabezado de las librerías contiene todo lo referente a los archivos


necesarios, macros y funciones para realizar el proceso de compilación del
archivo .hex.

El espacio de código 3.1 muestra la forma de invocar la librería del dspic para
el lenguaje C30 a usar en el presente ejercicio, así como el espacio de código
3.2 muestra la forma de invocar las librerías a utilizarse cuando se trabaja en
lenguaje ensamblador.

/* Librerías
//Incluir la librería del dspic30F4013
#include <p30f4013.h>

Espacio de Código 3.1 Librerías de encabezado para lenguaje C30

;Incluye la librería del dspic con sus macros escritas en lenguaje


Ensamblador
.include "p30f4013.inc"

Espacio de Código 3.2 Librerías de encabezado para lenguaje ensamblador

En general cuando se llama a la librería de un dspic se sigue como regla la


notación de p30fxxxx.h donde xxxx es el modelo de dspic a utilizarse ya sea
en lenguaje ensamblador o en lenguaje C30; nótese la diferencia entre el
lenguaje C30 y el lenguaje ensamblador en cuanto a los comentarios y líneas
de código.
95
La configuración inicial del funcionamiento del dspic para lenguaje C30 está
detallada en el espacio de código 3.3, así como para el lenguaje ensamblador
se detalla en el espacio de código 3.4.

//******* CONFIGURACIÓN DEL DISPOSITIVO *********//


//Configuración del Registro del Oscilador
//CSW_FSCM_OFF Oscilador a prueba de errores
//FRC Oscilador interno RC corriendo a 8 MHz
_FOSC(CSW_FSCM_OFF & FRC);
//Configuración del Temporizador WATCHDOG
//WDT_OFF Deshabilita el temporizador
_FWDT(WDT_OFF);
//Configuración del Registro de Protección de Voltaje
//Brown-out reset deshabilitado
//PBOR reset deshabilitado
//MCLR reset habilitado
_FBORPOR(PBOR_OFF & MCLR_EN);
//Configuración del Registro de Protección de Memoria de
//Programa
//Deshabilitada la protección de código de memoria de
//programa
_FGS(CODE_PROT_OFF);

Espacio de Código 3.3 Configuración del dispositivo para lenguaje C30

; Configuración del dispositivo


;La descripción de las siguientes líneas de código son similares
;en ensamblador a las escritas en el espacio de código 3.3
;por esa razón se omite las descripciones de éstas
config __FOSC, CSW_FSCM_OFF & FRC
config __FWDT, WDT_OFF
config __FBORPOR, PBOR_OFF & MCLR_EN
config __FGS, CODE_PROT_OFF

Espacio de Código 3.4 Configuración del dispositivo para lenguaje


ensamblador

96
Una vez configurado el dispositivo en cuanto a las librerías necesarias y a la
inicialización, se añade las líneas del espacio de código 3.5 en lenguaje C30 y
del espacio de código 3.6 para lenguaje ensamblador del programa que
ejecutará lo solicitado en este ejercicio.

//******************* PROGRAMA PRINCIPAL **********************//


//Función principal
int main (void)
{
//Deshabilita la conversión, analógico/digital, para trabajar
//solo en modo digital
ADPCFG=0xFFFF;
//Apaga los conversores analógico/digitales, para ahorrar
//energía
_ADON=0;
//Se configura RB0 salida
TRISBbits.TRISB0=0;
//Se obtiene los mismos resultados con;
//_TRISB=0;
// Lazo infinito repetición
while(1)
{
//Se escribe un 1 lógico en RB0, se obtiene el mismo
//resultado con _LATB0=1;
LATBbits.LATB0=1;
//Compara el estádo lógico del RF1 con 1 si es así
//ejecuta sino es así salta
if(PORTFbits.RF1) // Se obtiene el mismo resultado con _RF1
{

//Escribe un 1 lógico en el pin RB1


LATBbits.LATB1=1;
//Se obtiene el mismo resultado con _LATB0=1;
}
}

Espacio de Código 3.5 Programa principal en lenguaje C30

97
;Declaración de variables y subprocesos
;Subrutinas para el manejo de nombres simbólicos de registros
.global __reset
.global _main ;Programa principal
.global _fin
.global _escribe
.section .text
;Programa principal
_main:
;Almacenamiento de valores de inicialización en W0,W1,W2,W3,W5
;Mover 0x0000 a W0
mov #0x0000,W0;
;Mover 0x0001 a W1
mov #0x0001,W1;
;Mover 0x0000 a W2
mov #0x0000,W2;
;Mover 0xFFFF a W3
mov #0xFFFF,W3;
;Mover 0x0000 a W5
mov #0x0000,W5;
;Configuración el puerto B como salida
;Mover W0 al registro TRISB
mov W0,TRISB;
;Configuración el puerto F como entrada
mov W3,TRISF;
;Encendido el puerto RB0
;Limpiar el contenido del puerto B
clr PORTB
;Poner un 1 lógico en RBO
bset PORTB,#RB0;
;Lectura del estádo lógico de RF0
mov PORTF,W4;
;Compara W4 con W5, si es cero, salta; si no, va a escribe
cpseq W4,W5;
;Llama a la subrutina escribe
call _escribe;

Espacio de Código 3.6 Programa principal en lenguaje Ensamblador

98
;Llama a la subrutina fin
call _fin;
_escribe:
;Escritura en RB1
bset PORTB,#RB1;
;Bucle lazo repetitivo principal
bra _main
_fin:
;Bucle lazo repetitivo principal
bra _main
;EOF , final de proceso
.end

Espacio de Código 3.6 Programa principal en lenguaje Ensamblador


(continuación)

En este ejercicio podemos notar la diferencia entre el número de líneas


necesarias para la programación en el lenguaje C30 así como en el lenguaje
ensamblador, aunque el compilador C30 soluciona está diferencia mediante
macros de optimización de código, debido a está diferencia la utilización del
lenguaje C30 es la más recomendada; pese a esto y por motivos didácticos,
gracias al mejor seguimiento de los procesos entre registros, se utilizarán los
dos tipos de lenguajes en algunos de los ejercicios. Sin embargo el fin es
poder escribir en lenguaje C30 aplicaciones de PDS de alto nivel y optimizado
en tamaño de memoria.

3.3.1.2.3 Compilación y Depuración de Código

Una vez disponible el código, ya sea en ensamblador o en C30, que cumple


con los requerimientos del ejercicio se procede a realizar la compilación y
depuración en el MPLAB IDE, usando el compilador MPLAB C30. Se debe
tener listo un proyecto de trabajo, este proceso se lo resume, ya que se explicó
a detalle en el capítulo 2.

Primeramente se crea una carpeta donde residirá el proyecto a estructurar, tal


como se muestra en la figura 3.4.
99
Figura 3.4 Creación de la carpeta Encender un LED

Luego se crea el archivo principal.c, mismo que tiene el contenido del espacio
de código 3.1,3.3 y 3.5 en forma concatenada, y se lo guarda en la carpeta del
proyecto como se muestra en la figura 3.5.

Figura 3.5 Creación del archivo principal.c en el MPLAB IDE

100
Luego se debe crear un proyecto que contenga los archivos necesarios para la
compilación, en este caso se crea el proyecto LED.mcp que se muestra en la
figura 3.6, con el árbol listo, es decir con las librerías y el archivo principal.c
añadido. En caso de haber usado el código de lenguaje ensamblador se debe
añadir el archivo p30f4013.inc en lugar del p30f4013.h.

Figura 3.6 Árbol del proyecto LED.mcp con el proyecto estructurado y listo
para la compilación

Una vez listo esto, se procede a realizar la compilación del proyecto, una forma
fácil de hacerlo es con la tecla rápida F10, en el proceso de compilación se
reportarán posibles errores en la elaboración del código, teniendo como
respuestá la ventana de la figura 3.7.

101
Figura 3.7 Compilación del proyecto del Ejercicio No. 1

3.3.1.2.4 Implementación en Hardware

Para está etapa se manejan dos opciones, el usar un protoboard común o un


entrenador; dado que se tienen dos opciones de programación (C30 y
ensamblador), el ejercicio funciona de la misma forma con cualquiera de los
dos. Primeramente se usará un protoboard común para probar el ejercicio
propuesto.

Para grabar el microcontrolador con el archivo .hex que se obtuvo en el


proceso de compilación, se tienen varias opciones como son: el Pickit2,
MPLAB ICD2 y dspicFlash.

Una vez implementado el circuito propuesto en un protoboard común se


procede a grabarlo usando las herramientas mencionadas, primeramente con
el Pickit 2.

La conexión entre el programador y el dspic se muestra en la figura 3.8.

102
Figura 3.8 Programación del ejercicio con el Pickit 2

En la figura 3.9 se muestra que la grabación se realizó correctamente.

Figura 3.9 Indicador de programación exitosa

103
La figura 3.10 muestra la programación del ejercicio con el MPLAB ICD2 desde
el entorno de programación MPLAB IDE.

Figura 3.10 Programación del dspic con el MPLAB ICD2 desde el MPLAB IDE

La conexión de la configuración se realiza como se muestra en la figura 3.11.

Figura 3.11 Conexiones para la programación con el MPLAB ICD2

104
El MPLAB indica si la programación se realizó correctamente, tal como indica
la figura 3.12.

Figura 3.12 Indicador de programación exitosa

Los resultados del ejercicio completo probado en un protoboard usando como


grabadores el Pickit 2 y el MPLAB ICD2 se los muestra en la figura 3.13.

Figura 3.13 Ejercicio 1 armado en el protoboard


105
En la figura 3.13 se resume los resultados de utilizar el MPLAB ICD2 y el Pickit
2 como grabadores, debido a lo básico del ejercicio.

Para la programación con el equipo de entrenamiento solamente es necesario


colocar el dspic en el sócalo para el mismo y correr el dspicFlash.

La figura 3.14 muestra la pantalla de entrada del software utilizado para la


grabación de microcontrolador (dspicFlash).

Figura 3.14 Grabador de dspics, propiedad de Mikroelektronika

Como se ve en la figura anterior se trata de una pantalla con botones de


manejo muy intuitivo en todas sus opciones. Al hacer click en el botón LOAD
HEX se presentará un cuadro de diálogo donde se hará referencia a que se
indique la ruta de nuestro archivo .hex a grabar, como se muestra en la figura
3.15.

106
Figura 3.15 Archivo a grabar en el dspic

En este caso ya se tiene en pantalla el archivo .hex a grabar, se lo escoge y


se da click en abrir, una vez hecho esto se volverá a la pantalla de inicio del
grabador de dspics. Ahí solo basta hacer un click en Write y el programa
empezará a correr solo, una vez que se indica que el programa ha sido
grabado, se cierra el grabador de dspics, esto para asegurarnos que la
comunicación USB se rompa por precaución, e inmediatamente se puede
proceder a probar nuestro programa.

En la figura 3.16 se muestra la conexión con el equipo de entrenamiento para


grabar el dspic.

107
Figura 3.16 Probando el ejercicio en el equipo de entrenamiento Easydspic 4

3.3.2 MANEJO DEL OSCILADOR INTERNO.

3.3.2.1 El Oscilador

Tiene como función proporcionar la señal de reloj principal y todas las


auxiliares utilizadas por el dispositivo. El sistema oscilador dispone de 3
osciladores primarios, un secundario, 2 internos y un externo. Como también
se dispone de un circuito PLL para multiplicar la frecuencia interna.

3.3.2.2 Osciladores Primarios

Los osciladores primarios general la señal de reloj, son conocidos como: XTL,
XT y HS.

El oscilador XLT está diseñado para trabajar con cristal de cuarzo o resonador
cerámico para un rango de frecuencias comprendido entre 200 KHz y 4 MHz.

108
El oscilador XT también trabaja con cristal o resonador en un rango de
frecuencias comprendido entre 4MHz y 10 MHz.

El oscilador HS trabaja solamente con cristal y cubre un rango de frecuencias


que va desde los 10 MHz hasta 25 MHz.

Todos los osciladores emplean los pines OSC1 y OSC2; en la tabla 3.1 se
muestran los 13 modos de funcionamiento de los osciladores primarios.

Tabla 3.1 Modos de funcionamiento de los osciladores31

3.3.2.3 Oscilador Secundario

Este oscilador está diseñado para trabajar a baja potencia y está basado en un
resonador de cristal o cerámico de 32 KHz, emplea los pines SOSC1 y
SOSC2. Este oscilador también puede controlar el Timer 1 en aplicaciones de
tiempo real.

31
www.Microchip.com

109
3.3.2.4 Osciladores Internos

Existen dos osciladores internos el oscilador FRC y el oscilador LPRC en los


cuales la frecuencia de oscilación depende de la temperatura y del voltaje con
el que trabaje el dispositivo.

3.3.2.4.1 Oscilador FRC (RC Rápido)

El mismo trabaja a 8 MHz, este oscilador está diseñado para trabajar a


frecuencias altas, sin la necesidad de conectar un cristal de cuarzo.

3.3.2.4.2 Oscilador LPRC (RC de baja potencia)

Este oscilador trabaja a 512 KHz. Trabaja como fuente de reloj para el
temporizador PWRT, el Watchdog y los circuitos de monitorización de reloj.

3.3.2.5 Oscilador Externo

El oscilador externo que poseen los dspics es el EXTRC que trabaja a


frecuencias de hasta 4 MHz, el mismo necesita de una resistencia y un
condensador conectados al pin OSC1, en el cual también se puede conectar
una señal de reloj externa (modo EC).

La frecuencia del oscilador RC varía en función a:

 Voltaje de alimentación.

 Valor de la resistencia externa.

 Valor del capacitor externo.

 Temperatura de funcionamiento.

En la figura 3.17 se muestra el diagrama de bloques del sistema de oscilación


que poseen los dspics.

110
Figura 3.17 Diagrama de bloques del Sistema Oscilador32

El sistema oscilador dispone de las siguientes funcionalidades:

 Varias opciones de oscilador internas y externas.

 Un circuito PLL para multiplicar las frecuencias de funcionamiento.

 Selección entre varias fuentes de reloj.

 Un Postscaler Programable.

32
www.Microchip.com

111
 Un monitor de seguridad ante fallas de reloj (FSCM).

 Un registro de control de opciones de reloj (OSCON).

 Bits de configuración no volátiles para la selección del oscilador


principal.

3.3.2.5.1 Cálculo de FCY

La frecuencia FCY es utilizada para calcular el tiempo del ciclo de máquina, la


misma se deriva de la frecuencia de oscilación F OSC tal como se muestra en la
figura 3.18.

Figura 3.18 Diagrama de tiempos de la frecuencia de oscilación33

El valor de la frecuencia de oscilación viene dado por la ecuación 3.1.

Ecuación 3.1 Relación entre el número de instrucciones por segundo y la


frecuencia del oscilador34

El valor de la FOSC se calcula según el modo de oscilación con el que se


necesita trabajar.

33
www.Microchip.com
34
www.Microchip.com

112
3.3.2.6 Ejercicio No. 2: Encender LEDS con Retardos Programados.

Para este ejercicio se seguirá trabajando con el dspic30F4011, como también


se hará uso de la librería libpic30.h en el caso de lenguaje C30 donde se tiene
una instrucción que permite producir retardos con simples instrucciones nop.
Esta instrucción se presenta como se detalla en el espacio de código 3.7.

void __delay32(unsigned long cycles);

Espacio de Código 3.7 Estructura de la función delay32()

Esta instrucción recibe como argumento solamente el número de ciclos de


máquina que se requiere que cuente y lo que hace es reemplazar ese número
de ciclos de máquina por instrucciones nop (no operation), es decir genera un
retardo de un número específico de ciclos de reloj, para el funcionamiento de
está instrucción es necesaria incluir la librería libpic30.h, en la misma que se
encuentra el archivo __delay32.c.

Por facilidad se tomará el código anterior y le haremos una pequeña


modificación para hacer que el LED se prenda y apague cada cierto tiempo,
se escogerá un número de instrucciones nop adecuado para poder ver el
parpadeo del diodo LED, en este caso será de 500000 para escribirlo como
argumento de la función __delay32(), cabe recalcar que está función permite
contar solamente hasta un número de 4294967296 instrucciones nop o ciclos
de máquina, esto viene de 232 = 4 294 967 296 ciclos de máquina.

En este ejercicio se realiza una simple generación de parpadeos controlados


en un LED, estos parpadeos se producirán gracias a los retardos producidos
por la función delay32() para el lenguaje C30, la misma que está reemplazada
por una subrutina de retardo en el caso del lenguaje ensamblador; el circuito a
implementar se muestra en la figura 3.19.

113
Figura 3.19 Circuito para realizar las pruebas del Ejercicio No. 2

3.3.2.6.1 Diagrama de flujo

Para empezar con la programación de este ejercicio se ejecutarán las


diferentes etapas descritas en el diagrama de flujo 3.2.

Flujograma 3.2 Diagrama de flujo del segundo ejercicio.

114
3.3.2.6.2 Elaboración de Código

La elaboración de código en este ejercicio es similar al ejercicio anterior,


bastan ciertos cambios para generar los retardos que a su vez provocan el
parpadeo del LED.

En el espacio de código 3.8 se especifica las líneas de encabezado para


lenguaje C30 que deben utilizarse para este ejercicio, como también en el
espacio de código 3.9 se especifica el encabezado para el lenguaje
ensamblador.

Debido a que en el lenguaje ensamblador no contamos con la instrucción


__delay32, ésta es simulada en base a repeticiones y decrementos de
registros, por lo cual no se añade la librería libpic30.h.

/* LIBRERÍAS */
//Incluir la librería del dspic30F4013
#include <p30f4013.h>
//Incluye la librería que contiene la función delay32();
#include <libpic30.h>

Espacio de Código 3.8 Librerías de encabezado para lenguaje C30

;Incluye la librería del dspic con sus macros escritas en lenguaje


;ensamblador
.include "p30f4013.inc"
;Los retardos se hacen manualmente, por está razón no se incluye
;una librería adicional

Espacio de Código 3.9 Librerías de encabezado para lenguaje ensamblador

La configuración del dispositivo se conserva del ejercicio anterior, es decir hay


que incluir las líneas del espacio de código 3.3 para lenguaje C30 y en el
espacio de de código 3.4 para lenguaje ensamblador.

115
Para el programa principal se añaden pequeñas modificaciones en las líneas
del programa principal del ejercicio anterior tanto en C30 como en
ensamblador tal como se muestran en los espacios de código 3.10 y 3.11 para
C30 y ensamblador respectivamente.

//************* PROGRAMA PRINCIPAL ********************//


int main (void)
{
//Deshabilita la conversión analógico/digital, para trabajar
//solo en modo digital
ADPCFG=0xFFFF;
//Apaga los conversores analógico/digitales, para ahorrar
//energía
_ADON=0;
//Configura RB0 como salida
TRISBbits.TRISB0=0;
//Lazo infinito
while(1)
{
//Se escribe un 0 lógico en RB0, Se obtiene el mismo
//resultado con _LATB0=0;
LATBbits.LATB0=0;
// Retardo de 50000 ciclos de máquina
__delay32(50000);
//Se escribe un 1 lógico en RB0, se obtiene el mismo
//resultado con _LATB0=1;
LATBbits.LATB0=1;
// Retardo de 50000 ciclos de máquina
__delay32(50000);
//Se escribe un 0 lógico en RB0, se obtiene el mismo
//resultado con _LATB0=0;
LATBbits.LATB0=0;
}
}

Espacio de Código 3.10 Programa principal del ejercicio propuesto para


lenguaje C30

116
;Declaración de variables y subprocesos
.global __reset
.global _main
.global _delay
.global _delay1
.section .text
;Programa principal
_main:
;Almacenamiento de valores de inicialización en W0,W1,W2,W3
mov #0x0000,W0;
mov #0x0001,W1;
mov #0x0000,W2;
;Repeticiones x1000 para la creación de los retardos
;0x0032h = 52d
mov #0x0032,W3;
;Configuración el puerto B como salida
mov W0,TRISB;
;Encendido del puerto RB0
mov W1,LATB;
;Subrutina de Retardo en alto
_delay:
dec W3,W4
mov W4,W3
;Repetición mil veces
repeat #0x03E8
nop
CP0 W4
bra NZ,_delay ;Bucle en alto
;Recarga del número de repeticiones x1000
mov #0x0032,W3;
;Apagado RB0
mov W2,LATB;
;Subrutina de Retardo en bajo
_delay1:
dec W3,W4

Espacio de Código 3.11 Programa principal del ejercicio propuesto para


lenguaje ensamblador

117
mov w4,w3
;Repetición mil veces
repeat #0x3E8
nop
CP0 W4
bra NZ,_delay1 ;Bucle principal
;Bucle lazo repetitivo principal
bra _main
;EOF
.end

Espacio de Código 3.11 Programa principal del ejercicio propuesto para


lenguaje ensamblador (continuación)

Como método de comprobación se va a calcular la frecuencia de la señal de


salida en función del retardo producido.

Se tiene que la frecuencia de oscilación con el FRC es:

De la ecuación 3.1 se tiene que la frecuencia de trabajo F CY es:

Ya que no se está trabajando con ningún multiplicador de frecuencia (PLL), la


FCY es:

De la ecuación 3.1 se tiene:

118
De donde el retardo total R es igual al tiempo que dura un ciclo de máquina por
el número total de ciclos de máquina que se dio de argumento en la función
__delay32() la cual se tiene con la fórmula:

Para poder visualizar la frecuencia de encendido y apagado del LED se va a


calcular la frecuencia de oscilación, misma que viene dada por:

De donde la frecuencia f de oscilación viene dada por la fórmula:

Esta frecuencia será un dato útil para poder comprobar que funcione
correctamente el ejercicio propuesto con ayuda del osciloscopio.

En el caso que se necesite un retardo de 1 segundo es necesario el cálculo del


número de ciclos de máquina necesarios para su utilización en la función
__delay32().

Para esto se toma en cuenta que:

Entonces el número de ciclos de máquina en función del tiempo se calcula:

Con lo que se tiene para el caso de 1 segundo:

119
3.3.2.6.3 Compilación y Depuración de Código

Para realizar la compilación y depuración del código, realizamos el


procedimiento realizado en el ejercicio anterior, obteniendo como resultado la
ventana de la figura 3.20.

Figura 3.20 Compilación del Ejercicio No. 2.

Una vez aquí se tiene listo ya el archivo .hex para realizar las pruebas y
análisis de los resultados.

3.3.2.6.4 Implementación en Hardware

Para realizar la prueba de este ejercicio se utilizará el entrenador Easydspic4


así como el circuito armado en el protoboard; de igual manera como en el
ejercicio anterior este ejercicio funciona igual con cualquiera de los lenguajes
de programación C30 o ensamblador.

Como se vio anteriormente se debe grabar el archivo .hex en el dspic, luego de


aquello conectamos el osciloscopio en el pin RB0 para obtener la señal de
salida como se muestra en la figura 3.21.

120
Figura 3.21 Circuito probado en el entrenador Easydspic4

En la figura 3.22 se muestra el circuito armado en el protoboard del ejercicio.

Figura 3.22 Ejercicio 2 armado en protoboard

121
La señal de salida se la muestra en el osciloscopio tal como se indica en la
figura 3.23.

Figura 3.23 Señal de salida en el osciloscopio

3.3.3 MANEJO DE INTERRUPCIONES

Las interrupciónes y excepciones son acciones que provocan la desviación del


flujo de control de la CPU, por lo cual abandona el programa principal y pasa a
ejecutar la rutina que atiende la causa que originó la interrupción.

Las interrupciónes son provocadas generalmente por acontecimientos


externos. Las excepciones son desviaciones del flujo de control provocadas
automáticamente como consecuencia de algún tipo de anomalía en la CPU.

La familia de los dspic30F cuenta con una Tabla de Vectores de Interrupción


llamada IVT.

La tabla IVT tiene 62 entradas distintas, ya que está tabla tiene un vector de
interrupción por cada uno de los tipos de interrupciónes.

122
Además cuenta con una Tabla Alternativa de Vectores de Interrupción AIVT,
similar a la IVT.

La familia de los dspic se caracteriza porque el control de las interrupciónes es


manejado mediante prioridad de las mismas.

La tabla 3.2 muestra la tabla de interrupciónes y excepciones IVT.

Tabla 3.2 Características de los 8 primeros vectores de interrupción35

35
www.Microchip.com

123
Tabla 3.3 Características de vectores de interrupción36

36
www.Microchip.com

124
3.3.3.1 Niveles de Prioridad

3.3.3.1.1 Prioridades de la CPU

La prioridad en las interrupciónes y excepciones están definidas en 16 niveles


de prioridad del nivel 0 al 15. Por esto para que una excepción o interrupción
que se presenta sea atendida debe tener una prioridad mayor a la del CPU.

La CPU por defecto tiene la prioridad igual a 0, la más baja de todos. Este nivel
puede ser modificado de forma manual escribiendo los bits IPL.

Los 16 niveles de prioridad están divididos en dos grupos:

 Del 0 al 7, Interrupciones externas (periféricos). La CPU toma uno de


estos niveles.

 Del 8 al 15, Excepciones internas, no mascarables, las mismas que se


atienden en el momento que se producen.

3.3.3.1.2 Prioridad de las interrupciónes

Estos niveles son asignados por el usuario, teniendo en cuenta el nivel 1 (nivel
más bajo) y nivel 7 (nivel más alto).

Teniendo en cuenta también el orden de prioridad natural el cual está definido


en la IVT.

La prioridad natural de las interrupciónes tiene como misión ayudar a la CPU a


escoger qué interrupción escoger en el caso de que 2 interrupciónes tengan
niveles de prioridad iguales, en este caso se escogerá la que posea el nivel de
prioridad natural más alto. La prioridad natural está dada por el orden de
colocación de la interrupción en la tabla de vectores de interrupción; mientras
el número de vector sea menor, la interrupción tiene una mayor prioridad.

125
3.3.3.2 Tiempo de Proceso de las Interrupciones

3.3.3.2.1 Latencia de una interrupción

La latencia de la interrupción es de 4 ciclos de instrucción, y el proceso es el


siguiente:

1.° ciclo: Se activa la bandera de estádo.

2.° ciclo: En buffers temporales se guarda el contenido del PC y de SRL


los mismos que serán recuperados después.

3.° ciclo: Se carga el PC con el valor correspondiente a la interrupción que


se va a atender el mismo que se obtiene de la tabla de vectores de
interrupciónes.

4.° ciclo: Se carga el PC con el valor de la rutina que atenderá la


interrupción.

En la figura 3.24 se detalla la secuencia que tiene una interrupción externa.

Figura 3.24 Secuencia correspondiente a una interrupción externa37

37
www.Microchip.com

126
3.3.3.2.2 Retorno de la interrupción

Para realizar el retorno de una interrupción es necesaria la instrucción RETFIE,


además se necesitan 3 ciclos de instrucción:

1.° ciclo: En la pila se cargan los 8 bits más significativos del PC y todos
los bits del SRL.

2.° ciclo: En la pila se cargan los 16 bits menos significativos del PC.

3.° ciclo: Buscar la dirección de la instrucción.

En la figura 3.25 se detalla la secuencia para el retorno de una interrupción.

Figura 3.25 Secuencia correspondiente al retorno de una interrupción38

3.3.3.3 Ejecución de una Interrupción

3.3.3.3.1 Modo de funcionamiento

En el momento que se dé una interrupción y/o excepción, la CPU guardará de


forma automática los registros indispensables para el funcionamiento (PC y el
byte menos significativo del registro SRL) y se accederá a la IVT. En donde se
leerá la dirección almacenada para cargarla en el PC y ejecutarse la ISR. De la

38
www.Microchip.com

127
misma manera el SRL será modificado con los valores nuevos de prioridad, los
cuales serán leídos del registro IPCx correspondiente.

Antes de realizar la interrupción deben guardarse los registros que serán


modificados durante la ISR, como también los valores de los registros de
trabajo W, lo cual se programará con la ayuda de PUSH y sus variantes. Luego
de realizado el proceso se podrá ejecutar el código correspondiente a la ISR.
La CPU ejecuta las instrucciones de la interrupción de la misma forma como lo
hace con el programa principal, para terminar la interrupción es necesario
ejecutar la instrucción RETFIE.

Al ejecutar dicha instrucción se carga el PC y el registro SR con los valores


almacenados en los buffers para continuar con el programa desde el mismo
punto en el cual se interrumpió, de la misma manera también se deben cargar
los registros de trabajo W con los valores guardados, la instrucción POP es
utilizada para realizar lo antes mencionado, y para finalizar la interrupción es
necesario desactivar la bandera correspondiente a la interrupción.

128
3.3.3.4 Ejercicio No. 3 Manejo de Interrupciones Externas

Se propone encender el LED en RB0 con un retardo de 50000 ciclos de


máquina para hacerlo parpadear y mediante el uso de una interrupción externa
INT0, pin 17 (INT0), se desea cambiar al LED a un retardo de 500 ciclos de
máquina.

Tal como se muestra en el cicuito de la figura 3.26.

Figura 3.26 Circuito para realizar las pruebas del Ejercicio No. 3

129
3.3.3.4.1 Diagrama de flujo

INICIO

CONFIGURACIÓN DEL
DISPOSITIVO

DECLARACIÓN DE LAS
INTERRUPCIONES INT0

 CONFIGURACIÓN EN
MODO DIGITAL
 CONFIGURACIONES DEL
PUERTO B

 HABILITAR EN INT0
(INT0EP)
 LIMPIAR LA BANDERA
DE INT0 (INT0IF)
 HABILITAR INT0 (INT0IE)

WHILE(1)

BUCLE INFINITO
ENCENDER PUERTO B EN
RB0

RETARDO 500 CICLOS DE


MAQUINA

APAGAR EL PUERTO B EN
RB0

FIN DE PROCESO

Flujograma 3.3 Diagrama de flujo del programa principal

130
INT0

LIMPIAR INT0IF

WHILE(1)

BUCLE INFINITO
ENCENDER PUERTO B EN
RB0

RETARDO 500 CICLOS DE


MAQUINA

APAGAR EL PUERTO B EN
RB0

FIN DE INTERRUPCIÓN
(RETFIE)

Flujograma 3.4 Diagrama de flujo de la interrupción

3.3.3.4.2 Elaboración de Código

Para el manejo de las interrupciónes externas, se adjuntará al código del


ejercicio anterior ciertas funciones que permiten la manipulación de las
interrupciónes externas de un dspic.

En el caso del uso de lenguaje C30 la función de interrupción es:

void __attribute__((__interrupt__)) _INT0Interrupt(void);

La cual tiene que estár declarada en la cabecera del programa.

131
El contenido de la función está descrita en el espacio de código 3.12 para
lenguaje C30 y el espacio de código 3.13 para el lenguaje ensamblador.

void _ISR __attribute__((interrupt, no_auto_psv)) _INT0Interrupt(void)


{
//Limpia la bandera de la interrupción externa 0
IFS0bits.INT0IF=0;
//Código a ejecutar cuando se llame a la interrupción
//en ciclo repetitive while(1)
while (1)
{
LATBbits.LATB0=0;
// Retardo de 500 ciclos de máquina
__delay32(500);
LATBbits.LATB0=1;
// Retardo de 500 ciclos de máquina
__delay32(500);
}
}

Espacio de Código 3.12 Contenido de la función de interrupción en lenguaje


C30

;Subrutina interrupción INT0


__INT0Interrupt:
;Borrado de la bandera de la INT0
BCLR IFS0,#0
bucle1:
CLRWDT
;Repeticiones x1000
mov #0x0001,W3;
bset PORTB,#RB0
;Subrutina de Retardo en alto
_delay2:

Espacio de Código 3.13 Contenido de la función de interrupción en lenguaje


ensamblador

132
dec W3,W4
mov w4,w3
;Repetición mil veces
repeat #0x03E8
nop
CP0 W4
bra NZ,_delay2 ;Bucle en alto
;Recarga del número de repeticionesx1000
mov #0x0001,W3;
;Apagado RB0
bclr PORTB,#RB0
;Subrutina de Retardo en bajo
_delay3:
dec W3,W4
mov w4,w3
;Repetición mil veces
repeat #0x3E8
nop
CP0 W4
bra NZ,_delay3
;Bucle principal
GOTO bucle1
;Final de Interrupción y retorno
RETFIE

Espacio de Código 3.13 Contenido de la función de interrupción en lenguaje


ensamblador (continuación)

En el caso de la utilización del lenguaje ensamblador es necesario el uso de


una subrutina para hacer funcionar la interrupción.

Para este caso se incluye el programa completo para tener en cuenta cómo se
ha de estructurar la llamada a subfunciones en caso de lenguaje C30 y
subrutinas en caso de ensamblador.

133
/* LIBRERÍAS */
//Incluir la librería del dspic30F4011
#include <p30f4011.h>
//Librería de la subfunción delay32()
#include <libpic30.h>
//******* CONFIGURACIÓN DEL DISPOSITIVO *********//
_FOSC(CSW_FSCM_OFF & FRC);
_FWDT(WDT_OFF);
_FBORPOR(PBOR_OFF & MCLR_EN);
_FGS(CODE_PROT_OFF);
//Declaración de la subfunción interrupción 0
void _ISR __attribute__((__interrupt__)) _INT0Interrupt(void);
//*************** PROGRAMA PRINCIPAL ********************//
int main (void)
{
ADPCFG=0xFFFF;
_ADON=0;
TRISBbits.TRISB0=0;
//Habilita la INT0
INTCON2bits.INT0EP=1;
//Limpia la bandera de la INT0
IFS0bits.INT0IF=0;
//Habilita la INT0
IEC0bits.INT0IE=1;
//Lazo infinito while
while(1)
{
LATBbits.LATB0=0;
// Retardo de 50000 ciclos de máquina
__delay32(50000);
LATBbits.LATB0=1;
// Retardo de 50000 ciclos de máquina
__delay32(50000);
LATBbits.LATB0=0;
}
}

Espacio de Código 3.14 Programa principal utilizando lenguaje C30

134
void _ISR __attribute__((interrupt, no_auto_psv)) _INT0Interrupt(void)
{
IFS0bits.INT0IF=0;
while (1)
{
LATBbits.LATB0=0;
// Retardo de 500 ciclos de máquina
__delay32(500);
LATBbits.LATB0=1;
// Retardo de 500 ciclos de máquina
__delay32(500);
LATBbits.LATB0=0;
}
}

Espacio de Código 3.14 Programa principal utilizando lenguaje C30


(continuación)

.include "p30f4011.inc"
;Configuración del dispositivo
config __FOSC, CSW_FSCM_OFF & FRC
config __FWDT, WDT_OFF
config __FBORPOR, PBOR_OFF & MCLR_EN
config __FGS, CODE_PROT_OFF
;
;Declaración de variables globales
.global __reset
.global __INT0Interrupt
.section .text
;
;Subrutina interrupción INT0
__INT0Interrupt:
;Borrado de la bandera de la INT0
BCLR IFS0,#0

Espacio de Código 3.15 Programa principal utilizando lenguaje ensamblador

135
bucle1:
CLRWDT
;Repeticiones x1000
mov #0x0001,W3;
bset PORTB,#RB0
;Subrutina de Retardo en alto
_delay2:
dec W3,W4
mov W4,W3
;Repetición mil veces
repeat #0x03E8
nop
CP0 W4
bra NZ,_delay2 ;Bucle en alto
;Recarga del número de repeticionesx1000
mov #0x0001,W3;
;Apagado RB0
bclr PORTB,#RB0
;Subrutina de Retardo en bajo
_delay3:
dec W3,W4
mov W4,W3
;Repetición mil veces
repeat #0x3E8
nop
CP0 W4
bra NZ,_delay3
;Bucle principal
GOTO bucle1
;Final de Interrupción y retorno
RETFIE
;Programa principal
.global _main
_main:
;Carga de valores de inicialización

Espacio de Código 3.15 Programa principal utilizando lenguaje ensamblador


(continuación)

136
mov #0xFFFF,W6;
;Apagado de los adcs
mov W6,_ADPCFG;
;Configuración del puerto B como salida
mov #0x0000,W0;
mov W0,TRISB;
CALL INICIAINT0
bucle:
CLRWDT
;Repeticiones x1000
mov #0x0031,W3;
bset PORTB,#RB0
;Subrutina de Retardo en alto
_delay:
dec W3,W4
mov w4,w3
;Repeticiones mil veces
repeat #0x03E8
nop
CP0 W4
bra NZ,_delay ;Bucle en alto
;Recarga del número de repeticiones x1000
mov #0x0031,W3;
;Apagado RB0
bclr PORTB,#RB0
;Subrutina de Retardo en bajo
_delay1:
dec W3,W4
mov w4,w3
;Repeticiones mil veces
repeat #0x3E8
nop
CP0 W4
bra NZ,_delay1 ;Bucle principal
GOTO bucle

Espacio de Código 3.15 Programa principal utilizando lenguaje ensamblador


(continuación)

137
;Inicio de interrupción
INICIAINT0:
;Configuración de interrupción externa INT0
MOV #0x0001, W0
MOV W0, IEC0
RETURN
;EOF
.end

Espacio de Código 3.15 Programa principal utilizando lenguaje ensamblador


(continuación)

Para objeto práctico en el entendimiento de la utilización de los distintos


lenguajes de programación como son C30 y ensamblador, este ejercicio está
realizado también como se muestra en el espacio de código 3.16, en el cual se
mezclan los dos lenguajes de programación obteniendo resultados similares;
dada la virtud adicional con la que cuenta el compilador MPLAB C30.

//*************** PROGRAMA PRINCIPAL ********************//


int main (void)
{
ADPCFG=0xFFFF;
_ADON=0;
//Configura RB0,RB3 como salida, y RF1 como entrada.
TRISBbits.TRISB0=0;
//Habilita la INT0
INTCON2bits.INT0EP=1;
//Resetea la bandera de la Interrupción 0
IFS0bits.INT0IF=0;
//Habilita la INT0
IEC0bits.INT0IE=1;
//Lazo infinito

Espacio de Código 3.16 Programa Principal utilizan los lenguajes C30 y


ensamblador

138
while(1)
{
LATBbits.LATB0=0;
// Retardo de 50000 ciclos de máquina
//Instrucciones en ensamblador, una de las virtudes del
//compilador C30
asm("_delay1:");
asm("mov #0x0032,W3;");
asm("mov w4,w3;");
asm("repeat #0x03E8");
asm("nop");
asm("CP0 W4");
asm("bra NZ,_delay1;");

LATBbits.LATB0=1;
// Retardo de 500 ciclos de máquina
//Instrucciones en ensamblador, una de las virtudes del
//compilador C30
asm("_delay2:");
asm("mov #0x0032,W3;");
asm("mov w4,w3;");
asm("repeat #0x03E8");
asm("nop");
asm("CP0 W4");
asm("bra NZ,_delay2;");
LATBbits.LATB0=0;
}
}

void _ISR __attribute__((interrupt, no_auto_psv)) _INT0Interrupt(void)


{
IFS0bits.INT0IF=0;
while (1)
{
LATBbits.LATB0=0;
// Retardo de 500 ciclos de máquina

Espacio de Código 3.16 Programa Principal utilizan los lenguajes C30 y


ensamblador (continuación)

139
//Instrucciones en ensamblador, una de las virtudes del
//compilador C30
asm("_delay3:");
asm("mov #0x0005,W3;");
asm("mov w4,w3;");
asm("repeat #0x03E8");
asm("nop");
asm("CP0 W4");
asm("bra NZ,_delay3;");
LATBbits.LATB0=1;
// Retardo de 50000 ciclos de máquina
//Instrucciones en ensamblador, una de las virtudes del
//compilador C30
asm("_delay4:");
asm("mov #0x0005,W3;");
asm("mov w4,w3;");
asm("repeat #0x03E8");
asm("nop");
asm("CP0 W4");
asm("bra NZ,_delay4;");
LATBbits.LATB0=0;
}
}

Espacio de Código 3.16 Programa Principal utilizando los lenguajes C30 y


ensamblador (continuación)

3.3.3.4.3 Compilación y Depuración de Código

Para realizar la compilación y depuración del código, realizamos el


procedimiento utilizado en los ejercicios anteriores y se obtiene como resultado
la ventana de la figura 3.27.

140
Figura 3.27 Compilación Ejercicio No. 3

3.3.3.4.4 Implementación en Hardware

Las señales de salida se presentan en las figuras 3.28 y 3.29, las mismas
muestran trenes de pulsos de 18 Hz y 18 KHz con un retardos de 50000 ciclos
de máquina y de 500 ciclos de máquina luego de la interrupción,
respectivamente.

Figura 3.28 Señal de salida con retardo de 50000 ciclos de máquina


141
Figura 3.29 Señal de salida con retardo de 500 ciclos de máquina luego de la
interrupción

3.3.4 MANEJO DE MEMORIAS

3.3.4.1 Memoria de Datos

La memoria de datos está dividida en dos espacios de memoria denominados


X y Y. Para el manejo de la memoria de datos se utilizan 2 tipos de
instrucciones de las cuales las instrucciones DSP pueden acceder
independientemente a los espacios X y Y, mientras que las instrucciones MCU
acceden solamente a un espacio de datos líneal de 64 KB o 32 KB. Para
realizar el acceso a la memoria se utilizan Unidades de Generación de
Direcciones (AGU) como también buses de datos independientes; en la figura
3.30 se muestra un mapa de la memoria de datos.

142
Figura 3.30 Mapa del espacio de la memoria de datos39

Las direcciones del espacio de memoria que se encuentren en el espacio de


RAM no implementada, son utilizadas para almacenar los registros de control y
registros de función específica (SFR), los mismos que gobiernan el
comportamiento del dspic.

Para realizar la escritura de los datos en la memoria de datos, los dos espacios
X y Y son accedidos como si se tratase de un solo espacio líneal de datos.
Para las operaciones de lectura los espacios son accedidos
independientemente por las instrucciones DSP y como un solo espacio líneal
de datos por las instrucciones MCU.

39
www.Microchip.com

143
Al realizar la lectura de datos por las instrucciones DSP, se utilizan los
registros W10 y W11 para realizar la lectura del espacio de memoria Y,
mientras que los registros W8 y W9 se encargan de la lectura del espacio de
memoria X, siendo está la razón para que las instrucciones DSP pueden leer
dos datos a la vez.

Para las operaciones de escritura y lectura de la memoria, las instrucciones


MCU utilizan como punteros cualquier registro W.

3.3.4.1.1 Unidades de generación de direcciones (AGU)

Las familias de los dspic disponen de dos unidades de generación de


direcciones AGU X y AGU Y, las cuales generan direcciones efectivas (EA)
que abarcan el rango de 64 KB de la memoria de datos.

3.3.4.1.2 Descripción de registros de control

Los siguientes registros son utilizados para el direccionamiento modular y el de


inversión del acarreo:
 MODCON: Registro de control del direccionamiento modular.

 XMODSRT: registro de la dirección modular de inicio AGUX.

 XMODEND: Registro de la dirección modular de fin AGUX.

 YMODSRT: Registro de la dirección modular de inicio AGUY.

 YMODEND: Registro de la dirección modular de fin AGUY.

 XBREV: registro de control de direccionamiento por inversión del


acarreo AGUX.

144
3.3.4.2 Memoria de Programa

El espacio máximo que puede tener la memoria de programa es de 4M


posiciones de 24 bits cada una.

El mapa de la memoria de programa está dividido en dos espacios:

1. El espacio del programa de usuario. Contiene el vector RESET, la tabla


de los vectores de interrupción, la memoria de programa y la memoria
EEPROM de datos.

2. El espacio de configuración. Contiene los bits de configuración no


volátiles que seleccionan el comportamiento de los diversos recursos y
las posiciones ID del dispositivo.

Como también existen tres métodos de acceso al espacio de memoria de


programa:

1. A través del contador de programa PC de 23 bits.

2. Mediante las instrucciones de lectura y escritura de Tabla (TBLRD y


TBLWT).

3. Mapeando un segmento de 32 Kbytes de la memoria de programa en el


espacio de direcciones de la memoria de datos.

En la figura 3.31 se muestra el mapa de la memoria de programa.

145
Figura 3.31 Mapa del espacio de memoria de programa 40

40
www.Microchip.com

146
3.3.4.2.1 El contador de programa

El contador de programa dispone de 23 bits y se incrementa de 2 en 2


manteniendo a cero el bit menos significativo y sumando una unidad a los
otros 22 restántes, lo cual se muestra en la figura 3.32.

Figura 3.32 Ejemplo de ejecución de una Instrucción41

El bit menos significativo del PC es utilizado para seleccionar el octeto cuando


se accede a la memoria de programa desde el espacio de datos utilizando la
visibilidad del espacio de programa o las instrucciones de tabla.

3.3.4.2.2 Acceso a datos desde la memoria de programa

Mediante la utilización de las instrucciones especiales de tabla y el mapeo de


páginas de 32 Kbytes es como se puede transferir datos entre la memoria de
programa y la memoria de datos.

Mediante la tabla TBLRDL y TBLWTL se permite la lectura y escritura de la


palabra menos significativa de cualquier dirección del espacio de programa sin
pasar por el espacio de datos.

41
www.Microchip.com

147
3.3.4.2.3 La instrucción de tabla

El conjunto de instrucciones de tabla permite mover datos de tamaño byte y


palabra desde el espacio de memoria de programa a la memoria de datos.
Existen 4 instrucciones de tabla:

1. TBLRDL: Lectura de la palabra baja de la tabla.

2. TBLWTL: escritura de la palabra baja de la tabla.

3. TBLRDH: lectura de la palabra alta de la tabla.

4. TBLWTH: escritura de la palabra alta de la tabla.

Mediante el uso de las instrucciones de tabla la memoria de programa se


comporta como un espacio en el cual cada posición ocupa 2 palabras de 16
bits.
Los 8 bits más significativos de la dirección no son válidos y se leen como 0s.
Cada posición del espacio de programa de 24 bits ocupa 2 palabras de 16 bits,
en donde sobra el byte más significativo.

3.3.4.2.4 Escritura de la memoria de programa

La familia de los dspic30F dispone de una memoria FLASH la misma que es


utilizada para contener los programas con código ejecutable del usuario.

Existen 2 métodos para escribir o grabar dicha memoria:

1. La auto programación en tiempo de ejecución (RTPS), Lo mismo se


consigue con las instrucciones TBLRD y TBLWT y los registros de
control NVM (NVMCON, NVMADR, NVMADRU y NVMKEY). Con RTPS
el usuario puede borrar en la memoria de programa 32 instrucciones al
mismo tiempo además puede escribir en la memoria de datos del
programa 4 instrucciones al mismo tiempo.

148
2. Programación serie en circuito ICSP, la misma utiliza una interfaz SPI y
software integral tipo bootloader.

3.3.4.3 Grabación de la Memoria EEPROM

En el espacio de memoria de programa se encuentra mapeada la memoria


EEPROM la misma que está organizada en palabras de 16 bits pudiendo así
alcanzar un tamaño de 2K palabras.

Para la operación de grabado en la memoria EEPROM es necesario la


utilización de las instrucciones de tabla con excepción de TBLWTH y TBLRDH
dado que las posiciones de la EEPROM son de 16 bits.

Las operaciones que pueden realizarse en la memoria EEPROM son:

 Borrar una palabra.

 Borrar una línea (16 palabras).

 Escribir una palabra.

 Escribir una línea.

El programa de usuario es el responsable de esperar a que la operación de


escritura/borrado se complete. Para realizar esto, el fin de está operación se
puede detectar mediante 3 métodos:

1. Leer el bit WR mediante software. El bit se encontrará en cero cuando la


operación sea completada.

2. Leer el bit NVMF mediante software. El bit será puesto a 1L cuando la


operación se complete.

3. Habilitar las interrupciónes NVM. La CPU recibirá una interrupción


cuando la operación se complete.

149
3.3.4.3.1 Borrado y escritura de una palabra en la EEPROM

Para realizar el borrado de una palabra en la memoria EEPROM se debe


realizar los siguientes pasos:

1. Cargar la dirección de la palabra a borrar en los registros TBLPAG y


NVMADR.

2. Configurar el registro NVMCON para borrar una palabra de la EEPROM.

3. Borrar el bit de estádo NVMIF y habilitar la interrupción NVM.

4. Escribir la secuencia de desbloqueo en el registro NVMKEY.

5. Poner a 1 el bit WR. Inicia el ciclo de borrado.

Y para realizar la operación de escritura de una palabra en la memoria


EEPROM son necesarios los siguientes pasos:

1. Carga el registro TBLPAG.

2. Cargar la palabra de datos en el registro escritura de la EEPROM.

3. Configurar el registro NVMCON para escribir una palabra en el


EEPROM.

4. Borrar el bit de estádo NVMIF y habilitar la interrupción NVM.

5. Escribir la secuencia de desbloqueo en el registro NVMKEY.

6. Activar el bit WR. Inicia el ciclo de escritura.

7. Detectar el fin de ciclo de escritura.

3.3.4.3.2 Borrado y escritura de una línea en la EEPROM

Para realizar el borrado de una línea en la memoria EEPROM se debe realizar


los siguientes pasos:

150
1. Leer una línea de la EEPROM de datos y almacenarlos en la RAM
como “imagen”.

2. Actualizar la imagen de datos con el nuevo dato.

3. Cargar los registros TBLPAG y NVMADR.

4. Configurar el registro NVMCON para borrar la línea de la EEPROM.

5. Borrar el bit estádo NVMIF y habilitar la interrupción NVM.

6. Escribir la secuencia de seguridad de NVMKEY.

7. Poner a 1 el bit WR. Inicia el ciclo de borrado.

8. Obtener el bit WR o el de espera para la interrupción NVM.

Y para realizar la operación de escritura de una línea en la memoria EEPROM


son necesarios los siguientes pasos:

1. Escribir la línea (16 palabras) de datos en los registros de escritura de la


EEPROM.

2. Cargar el registro TBLPAG.

3. Configurar el registro NVMCON para escribir una palabra en el


EEPROM.

4. Borrar el bit de estádo NVMIF y habilitar la interrupción NVM.

5. Escribir la secuencia de desbloqueo en el registro NVMKEY.

6. Activar el bit WR. Inicia el ciclo de programación.

7. Obtener el bit WR o el de espera para la interrupción NVM.

151
3.3.4.3.3 Lectura de la EEPROM

Para realizar la lectura de la memoria EEPROM se utiliza la instrucción


TBLDR, la misma que permite leer una palabra de la EEPROM.

3.3.4.4 LCD 2 x 16 Tipo Hitachi42

3.3.4.4.1 Descripción

El LCD (Liquid Crystal Display) es un dispositivo microcontrolado de


visualización grafica para la presentación de caracteres, símbolos o incluso
dibujos, este tipo dispone de 2 filas de 16 caracteres cada una y cada carácter
dispone de una matriz de 5x7 puntos (pixels). Este dispositivo está gobernado
internamente por un microcontrolador Hitachi 44780 y regula todos los
parámetros de presentación; el LCD se muestra en la figura .

Figura 3.33 Display LCD 2x16 tipo Hitachi43

3.3.4.4.2 Características principales

 Pantalla de caracteres ASCII, además de los caracteres kanji y griegos.


 Desplazamiento de los caracteres hacia la izquierda o la derecha.
 Proporciona la dirección de la posición absoluta o relativa del caracter.
 Memoria de 40 caracteres por línea de pantalla.

42
http://www.scribd.com/doc/6660774/LCD-2x16
43
www.HVWTech.com

152
 Movimiento del cursor y cambio de su aspecto.
 Permite que el usuario pueda programar 8 caracteres.
 Conexión a un procesador usando un interfaz de 4 u 8 bits.

3.3.4.4.3 Descripción de pines

No. Pin Símbolo Descripción

1 Vss Tierra de alimentación GND

2 Vdd Alimentación de +5V

3 Vo Contraste del cristal líquido. ( 0 a +5V )

Selección del registro de control/registro de datos:

4 RS RS=0 Selección registro de control

RS=1 Selección registro de datos

Señal de lectura/escritura:
R/W
5 R/W=0 Escritura (Write)

R/W=1 Lectura (Read)

Habilitación del módulo:


E
6 E=0 Módulo desconectado

E=1 Módulo conectado

7 -14 D0-D7 Bus de datos bidireccional.

Tabla 3.4 Descripción de pines del LCD 2 x 1644

44
http://www.scribd.com/doc/6660774/LCD-2x16

153
3.3.4.5 Ejercicio No. 4 Manejo de la Memoria EEPROM

En primera instancia como información adicional a este ejercicio se hará un


ejemplo del manejo básico de un LCD usando un dspic.

El manejo del LCD con el dspic se centra en estáblecer la comunicación entre


el microprocesador Hitachi 44780 o compatibles, este microprocesador se
encarga de la escritura en pantalla del LCD.

Para la comunicación con el LCD se ha desarrollado la siguiente librería:

transf_lcd.h

Donde los pines de control y datos del LCD quedan definidos como se muestra
en la tabla 3.5.

Pin LCD Pin dspic


RD7 RE3
R/W RE4
RS RE5
E RE8
D0 RE0
D1 RE1
D2 RE2
D3 RE3

Tabla 3.5 Pines de control y datos del LCD

Al utilizar está librería se debe tener cuidado de conectar correctamente los


pines según la asignación de la tabla 3.5 o a su vez acceder al código de la
librería y reasignar los pines de control y datos del LCD para que no se
produzcan errores.

154
Las funciones disponibles en la librería transf_lcd.h se describen a
continuación en el espacio de código 3.17, además se incluye su forma de
utilización y argumentos.

//Subfunción Inicializar el LCD


void Prender_LCD(void)
//Escribir una cadena en modo nible
void Escribir_cadena_LCD(char *dato)
//Escribir un comando directamente en microprocesador del LCD
Comando_LCD(unsigned int);

Espacio de Código 3.17 Funciones disponibles en la librería transf_lcd.h

Como un ejemplo básico de la forma de utilización de está librería se incluye el


siguiente espacio de código donde únicamente se escribe un mensaje en el
LCD, esto haciendo uso de las funciones descritas en el espacio de código
3.18.
//LIBRERÍAS
#include <p30f4011.h>
#include "LCDbitbang4lib.h"
//INICIALIZACIÓN DEL DISPOSITIVO
_FOSC(CSW_FSCM_OFF & FRC);
_FWDT(WDT_OFF);
_FBORPOR(PBOR_OFF & MCLR_EN);
_FGS(CODE_PROT_OFF)
//PROGRAMA PRINCIPAL
int main(void)
{
//variables auxiliares
char *comando = "Voltaje: ADC:";
char *mensaje = "[V]";
// INICIALIZACIÓN DEL LCD
Prender_LCD();
// ESCRIBE buf1 string AL LCD

Espacio de Código 3.18 Ejemplo básico del manejo de la librería transf_lcd.h


y el LCD con un dspic.

155
Escribir_cadena_LCD(comando);
//Nueva línea
Comando_LCD(0x40);
while(1)
{
//Envía un comando directo al LCD
Comando_LCD(0xC0);
//Escribir mensaje en el LCD
Escribir_cadena_LCD(mensaje);
Idle();
}
return 0;
}

Espacio de Código 3.18 Ejemplo básico del manejo de la librería transf_lcd.h


y el LCD con un dspic (continuación)

Para probar el código del espacio de código anterior basta con crear un
proyecto y añadir las librerías del dspic a usar y la librería del manejo del LCD,
compilarlo y grabarlo para poder visualizar el mensaje “LCD funcionando” en el
LCD, el circuito de conexión del LCD con el dspic se muestra en la figura 3.34.

Figura 3.34 Conexión del dspic con el LCD

156
En la figura 3.35 se muestra el ejemplo funcionando.

Figura 3.35 Ejemplo del manejo de LCD en funcionamiento

El ejemplo del manejo del LCD sirve como introducción para el siguiente
ejercicio donde se quiere guardar 15 números en las primeras 15 localidades
de la memoria EEPROM, los cuales serán leídos y mostrados en un LCD con
un retardo de 1 segundo entre cada número, el circuito se muestra en la figura
3.34; el mismo utilizado en el ejemplo de la utilización del LCD.

157
3.3.4.5.1 Diagrama de flujo

INICIO

CONFIGURACIÓN DEL DISPOSITIVO

 CONFIGURACIÓN EN MODO ANALÓGICO RB0


 DESCARTAR PUERTO E (USADO PARA EL LCD)

 DECLARACIÓN DE SUBFUNCIONES DE
TRANSFORMACIÓN A ASCII Y DEL LCD
 GUARDAR DATOS EN LA EEPROM CON _EEDATO()

 DECLARACION DE VARIABLES A USAR TIPO CHAR


 PRENDER LCD

WHILE(1)

BUCLE INFINITO

GUARDAR LOS i-ÉSIMO DATO EN eeprom_dato DE


LAS LOCALIDADES DEL PUNTERO
*eeprom_puntero

REPETIR 16 VECES TRANSFORMAR A ASCII Y ESCRIBIR EN EL LCD

ESCRIBIR MENSAJE EN EL LCD

ESCRIBIR MENSAJE EN EL LCD

FIN DE PROCESO

Flujograma 3.5 Diagrama de flujo del programa principal

3.3.4.5.2 Elaboración de Código

Para el manejo de la memoria EEPROM, se utiliza la instrucción EEDATA la


misma que permite guardar los datos que se quieran guardar en orden en los
espacios de memoria, la instrucción es utilizada de la siguiente manera:

Int _EEDATA(16) datos_eeprom[] =


{0,1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xD,0xE,0xF};

158
El contenido de la función está descrita en el espacio de código 3.19.

//Libreria del dspic a usar


#include <p30f4011.h>
//Libreria de cabecera para usar las subfunciones de
//LibreriaLCD30f.c y escribir en el LCD
#include "transf_lcd.h"
//Pines de control del LCD
#define RD7 LATEbits.LATE3
#define RW LATEbits.LATE4
#define RS LATEbits.LATE5
#define E LATEbits.LATE8
#define ENCENDIDO 1
#define APAGADO 0
//Subfunción que escribe en el LCD en modo nibble
void LCD30f4write(char dato, char control)
{
if (control == 0)
RS = 0;
else
RS = 1;
char byte_alto, byte_bajo;
//Escoger nibble alto
byte_bajo = dato & 0x0F;
byte_bajo = (0x0F & byte_bajo);
//Escoger nibble bajo
byte_alto= dato >> 4;
byte_alto = (0x0F & byte_alto);
//Escribir en el LCD
RW =0;
//Escritura lista?
E=0;
//Limpiar Puerto E
PORTE &=0xF0;
//Esperar por un nuevo dato
TMR1 = 0;

Espacio de Código 3.19 Contenido de la librería transf_lcd.h

159
while(TMR1 < 2);
//Cargar el dato en el Puerto B
PORTE |= byte_alto;
//dato enviado?
E = 1;
while(TMR1 < 20);
E=0;
//Limpiar puerto E
PORTE &=0xF0;
//Repetir el proceso para el nibble bajo
TMR1 = 0;
while (TMR1 < 2);
PORTE |= byte_bajo;
E = 1;
while(TMR1 < 20);
E=0;
PORTE &= 0xF0;
LATE &= 0xF0;
}

//Subfunción para leer en modo nibble


char LCD30f4read(char control)
{
char byte_alto, byte_bajo, dato;
if (control == 0)
RS = 0;
else
RS = 1;
//Leer
RW = 1;
E=0;
PORTE &= 0xf0;
LATE &= 0xf0;
TRISE = 0x0F;
TMR1 = 0;

Espacio de Código 3.19 Contenido de la librería transf_lcd.h (continuación)

160
while(TMR1 < 2);
E = 1;
while(TMR1 < 20);
byte_alto = PORTE;
byte_alto &= 0x0F;
E = 0;
TMR1 = 0;
while(TMR1 < 2);
E = 1;
while(TMR1 < 20);
byte_bajo = PORTE;
byte_bajo &= 0x0F;
E = 0;
dato = byte_alto << 4;
dato |= byte_bajo;
TRISE = 0x00;
PORTE &= 0xf0;
LATE &= 0xf0;
RW = 0;
return dato;
}

//Subfunción Inicializar el LCD


void Prender_LCD(void)
{
TRISE &=0xFEC0 ;
T1CON = 0x8030;
TMR1 = 0;
while(TMR1 < 4000);
RS = 0 ;
RW = 0;
E=0;
TMR1 = 0;
while (TMR1 < 2);
PORTE |= 0x0003;
E = 1;

Espacio de Código 3.19 Contenido de la librería transf_lcd.h (continuación)


161
while(TMR1 < 470);
E=0;
PORTE = 0;
TMR1 = 0;
while(TMR1 < 2);
PORTE |= 0x0003;
E = 1;
while(TMR1 < 20);
E=0;
PORTE = 0;
TMR1 = 0;
while(TMR1 < 2);
PORTE |=0x0002;
E = 1;
while(TMR1 < 20);
E=0;
PORTE = 0;
//Configura el LCD en modo nibble para optimizar el uso de
//pines, 0X28
LCD30f4write(0x28,RS) ;
//Limpiar el LCD
LCD30f4write(0x01,RS) ;
TMR1 = 0;
//Apagar parpadeos
LCD30f4write(0x0C,RS) ;
LCD30f4write(0x06,RS) ;
}
//Escribir una cadena en modo nibble
void Escribir_cadena_LCD(char *dato)
{
while(*dato)
LCD30f4write(*dato++,1);
}

Espacio de Código 3.19 Contenido de la librería transf_lcd.h (continuación)

162
Como se describió anteriormente, debido al menor nivel de complejidad y
optimización del código de programa, la resolución del ejercicio 4 se utilizará
solamente el lenguaje C30. En el espacio de código 3.20 se puede apreciar la
solución de este ejercicio.

/* LIBRERÍAS */
#include <p30f4011.h>
#include "transf_lcd.h"
#include <libpic30.h>
//Inicialización del Dispositivo
_FOSC(CSW_FSCM_OFF & FRC);
_FWDT(WDT_OFF);
_FBORPOR(PBOR_OFF & MCLR_EN);
_FGS(CODE_PROT_OFF);
//Datos a Guardar en la Memoria Eeprom
int _EEDATO(16) datos_eeprom[] =
{0,1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xD,0xE,0xF};
//Declaración de variables globales
unsigned int eeprom_datos[16];
unsigned int *eeprom_puntero;
//DECLARACIÓN DE LA SUBFUNCIÓN DE TRANSFORMACIÓN BINARIO-BCD
void transformacion_ASCII(int datos, char* puntero_ascii);
//FUNCIÓN PARA TRANSFORMAR DE BINARIO A BCD
void transformacion_ASCII(int datos, char* puntero_ascii)
{
int aux,i;
aux = datos/10;
//Conversión de DECENAS
*(puntero_ascii + 1) = datos - aux*10;
datos = datos - *(puntero_ascii + 1);
aux = datos/100;
//Conversión de UNIDADES

Espacio de Código 3.20 Programa principal del ejercicio 4

163
*(puntero_ascii + 0) = (datos - aux*100)/10; // 1/tenth
datos = datos - *(puntero_ascii + 0);
for( i=0;i<=1;i++)
//Conversión a formato ASCII
*(puntero_ascii + i) += 0x30;
}
//PROGRAMA PRINCIPAL
int main(void)
{
//Declaración de variables auxiliares
int i,aux1;
//Puntero orden
char *comando = "Cuenta (0-15):";
//Puntero mensaje
char *mensaje = " <-DO IT!-> ";
//Puntero datos de cuenta
char cuenta[7];
// INICIALIZACIÓN DEL LCD
Prender_LCD();
// ESCRIBE buf1 string AL LCD

Escribir_cadena_LCD(comando);

//Avanzar a la segunda línea


Comando_LCD(0x40);
while(1)
{
//Lazo for para sacar los 16 datos de la EEPROM
for(i=0;i<16;i++)

Comando_LCD(0xC0);

Espacio de Código 3.20 Programa principal del ejercicio 4 (continuación)

164
//Vector de datos en la EEPROM
eeprom_datos[i] = *eeprom_puntero+i;
//Variable auxiliary para no hacer
//transferencia directa, y evitar un
//crash de memoria

aux1=eeprom_datos[i];
//Transformar a ascii aux1
transformacion_ASCII(aux1, cuenta);
//Escribir en el LCD

Escribir_cadena_LCD(cuenta);
//Avanzar 2 lugares
Comando_LCD(0xC2);
//Escribir el mensaje en el LCD
Escribir_cadena_LCD(mensaje);
Comando_LCD(0xCE);
//Escribir cuenta en los dos últimos
//lugares
Escribir_cadena_LCD(cuenta);
//Retardo de 20000000 ciclos
__delay32(2000000);
}
}
return 0;
}

Espacio de Código 3.20 Programa principal del ejercicio 4 (continuación)

165
3.3.4.5.3 Compilación y Depuración de Código

Para realizar la compilación y depuración del código, se realiza el


procedimiento utilizado en los ejercicios anteriores y se obtiene como resultado
la ventana de la figura 3.36.

Figura 3.36 Compilación Ejercicio No. 4

3.3.4.5.4 Implementación en Hardware

El circuito tiene como resultado un contador de 15 números que se muestran


en el LCD tal como se muestra en la figura 3.37 en la cual se muestra el
circuito armado en el protoboard.

166
Figura 3.37 Circuito del ejercicio 4 armado y probado en el protoboard

3.3.5 MANEJO DE TEMPORIZADORES

Los microcontroladores de la familia dspic30F disponen de temporizadores de


16 bits, los cuales según sus características pueden combinarse para tener
temporizadores de 32 bits, una de las utilidades que tienen los temporizadores,
además de controlar el tiempo autónomamente, es proporcionar una base de
tiempo para otros periféricos como por ejemplo el periférico de Captura o el
periférico Comparador/PWM.

Cada uno de los temporizadores de 16 bits dispone de registros susceptibles a


lectura y escritura los cuales son:

 TMRx.- Registro contador del temporizador.

 PRx.- Registro de periodos asociado al temporizador.

 TxCON.- Registro de control asociado al temporizador.

167
Además, cada uno de los temporizadores tiene asociado una serie de bits para
realizar el control de las interrupciónes.

 TxIE.- Bit de control de la interrupción de Timer.

 TxIF.- Bit de estádo del señalizador de desbordamiento.

 TxIP<2:0>.- Bits para determinar el nivel de prioridad de la interrupción.

3.3.5.1.1 Tipos de Temporizadores.

Los temporizadores de los microcontroladores de la familia dspic30F se


clasifican en tres clases A, B y C30.

3.3.5.1.1.1 Tipo A

Este tipo de temporizadores están asociados al TIMER1, tiene ciertas


características especiales como:

 El temporizador puede ser utilizado en modo oscilador LP (Low Power)


u oscilador secundario de 32KHz para aplicaciones de reloj en tiempo
real (RTC).

 La temporización también puede funcionar de forma asincrónica a


través de una señal de reloj externa.

En la figura 3.38 se muestra un temporizador tipo A, en el cual se utiliza un


multiplexor para la elección del modo de funcionamiento del temporizador y
también para la elección de las distintas fuentes de reloj. Cuenta también con
otro multiplexor el cual controla la sincronización con el exterior, siempre y
cuando una fuente de reloj externa haya sido configurada previamente.

168
Figura 3.38 Estructura interna del temporizador tipo A45

3.3.5.1.1.2 Tipo B

Los temporizadores Tipo B están asociados con los TIMER2 y TIMER4,


poseen ciertas características las cuales son:

 Los temporizadores tipo B pueden concadenarse con los


temporizadores tipo C30 para formar temporizadores de 32 bits. El
registro TxCON del temporizador tipo B contiene el bit de control T32, el
mismo que cuando tiene el valor de 1 permite el funcionamiento del
temporizador de 32 bits.

 La sincronización del reloj se realiza después de atravesar la lógica del


divisor de frecuencia. (PRESCALER)

La estructura interna de este tipo de temporizadores es similar a la del


temporizador tipo A, la diferencia está en que no cuenta con la sincronización
con el reloj externo ni el oscilador LP, lo cual se observa en la figura 3.39.

45
www.Microchip.com

169
Figura 3.39 Estructura interna del temporizador tipo B46

3.3.5.1.1.3 Tipo C30

Los temporizadores Tipo C30 están asociados con los TIMER3 y TIMER5 y
poseen ciertas características las cuales son:

 Los temporizadores tipo C30 pueden concadenarse con los


temporizadores tipo B para formar temporizadores de 32 bits.

 Generalmente en los dispositivos un temporizador tipo C30 tiene la


capacidad de disparo en una conversión A/D.

La estructura interna del temporizador tipo C30 se muestra en la figura 3.40.

46
www.Microchip.com

170
Figura 3.40 Estructura interna del temporizador Tipo C3047

3.3.5.1.2 Modos de Funcionamiento

Los temporizadores pueden trabajar en cuatro distintos modos de


funcionamiento:

 Temporizador sincrónico.

 Contador sincrónico.

 Contador asincrónico.

 Contador de disparo por acumulación de tiempo.

El modo de funcionamiento en el cual trabaje el temporizador será


determinado por los bits de control TCS, TSYNC y TGATE.

47
www.Microchip.com

171
3.3.5.1.2.1 Modo temporizador sincrónico

En este modo pueden funcionar los tres tipos de temporizadores mencionados


anteriormente los cuales son: Tipo A, Tipo B y Tipo C30. En este modo los
temporizadores utilizan para su funcionamiento el reloj interno del
microcontrolador el cual es de Fosc/4, el mismo que cuando el divisor de
frecuencias tiene la selección de 1:1 incrementa su cuenta en una unidad por
ciclo de instrucción.
Para realizar la selección de este modo de funcionamiento del temporizador es
necesario que el bit TCS tenga el valor de 0L, dado el caso que un
temporizador Tipo A active el modo sincrónico de funcionamiento no será
necesario la realización de alguna operación adicional ya que el bit TSYNC es
ignorado.

3.3.5.1.2.2 Modo contador sincrónico

Los tres tipos de temporizadores pueden funcionar en este modo, para poner
en funcionamiento al temporizador en este modo es necesario que el bit TCS
tenga el valor de 1L ya que en este modo el temporizador trabaja con el reloj
externo y los incrementos del temporizador estárán dados por los pulsos en el
pin TxCK.
Los temporizadores Tipo A también deben tener en el bit TSYNC el valor de 1L
para realizar la sincronización con la señal de reloj externa.
Cuando el temporizador está trabajando en este modo no funcionara cuando el
microcontrolador entre en el modo de reposo (SLEEP), esto se da porque los
circuitos de sincronización se desconectan cuando el microcontrolador entra
en este modo.

172
3.3.5.1.2.3 Modo contador asincrónico

Solamente los temporizadores Tipo A pueden trabajar en este modo, la señal


de reloj utilizada en este modo es una señal externa y es necesario que el bit
TSYNC sea igual a 0L, dado que no realiza sincronismo con el reloj interno del
dispositivo lo que indicaría que el conteo se realiza en forma asincrónica
respecto al reloj interno.

Las ventajas que presenta el contador asincrónico están en que el


temporizador puede seguir su funcionamiento cuando el dispositivo se
encuentra en reposo y puede generar una interrupción que saque al mismo de
dicho estádo. Cabe aclarar que si el temporizador trabaja en dicho estádo se
podrían dar resultados inesperados.

3.3.5.1.2.4 Modo de contador por disparo por acumulación de tiempo

El conteo del temporizador en este modo de funcionamiento está dado en


función de la duración de los pulsos en el pin TxCK y utiliza la señal de reloj
interna, el diagrama de tiempos del funcionamiento del temporizador se
muestra en la figura 3.42.

Figura 3.41 Diagrama de tiempos del modo de contador por disparo por
acumulación de tiempo48

48
www.Microchip.com

173
El proceso empieza con un flanco positivo en el pin TxCK y el contador se
incrementara mientras el estádo de este pin sea alto, cuando el estádo cambie
a bajo se detendrá el conteo, este cambio de estádo pondrá un 1L en la
bandera de interrupción TxIF, el valor de la bandera TxFI deberá ser puestá a
cero por el usuario mediante software.

Para que se ponga en funcionamiento el temporizador en este modo el bit


TGATE debe estár activo, el bit TCS debe ser igual a 0L y el bit TON estár
habilitado.

3.3.5.1.3 Divisor de frecuencia (PRESCALER)

Para realizar la configuración del divisor de frecuencia se utilizan los bits de


control TCKPS <1:0> del registro TxCON mediante la tabla 3.6.

TCKPS <1:0> PRESCALER


00 1:1
01 1:8
10 1:64
11 1:256

Tabla 3.6 Valores de rangos del divisor de frecuencia

El divisor de frecuencia se borrará cuando se realice alguna de las siguientes


acciones:

 Escritura en el registro (TMRx)

 TON = 0L

 RESET del dispositivo.

174
3.3.5.1.4 Interrupciones de los temporizadores

Los temporizadores de 16 bits pueden generar una interrupción cuando hay un


flanco descendente en la señal externa o cuando se produce la coincidencia
de periodos, esto depende del modo en el que el temporizador esté
funcionando.

Para que se pueda generar la interrupción se debe habilitar el bit de control


TxIE como también iniciar con un valor diferente de cero los bits que controlan
la prioridad de la interrupción TXIP<2:0>.

En el momento que se produce una interrupción el bit TxIF toma el valor de 1L


y ésta se da cuando se produce una de las siguientes condiciones:

 Existe una coincidencia entre el contador TMRx y el registro de periodos


PRx, cuando el temporizador no está funcionando en el modo de
disparo por acumulación de tiempo.

 Cuando se detecta un flanco descendente en la señal de entrada,


cuando el temporizador trabaja en el modo de disparo por acumulación
de tiempo.

Para poner el valor de 0L en el bit TxIF se debe hacer mediante software, y


cuando el registro PRx se carga con el valor de 0x0000 y el temporizador está
activado no se genera ninguna interrupción, lo cual se muestra en la figura
3.42.

175
Figura 3.42 Interrupción por coincidencia de periodos49

3.3.5.1.5 Escritura y Lectura en Temporizadores

3.3.5.1.5.1 Escritura

El temporizador como el registro de periodos PRx pueden ser escritos mientras


esté funcionando el temporizador, y pueden ser escritos con tamaño de byte o
palabra; para esto se debe tener en cuenta los siguientes puntos:

 Cuando el temporizador está incrementándose y se escribe en el byte


bajo del temporizador, el byte alto no es afectado, en el caso que se
escriba el valor 0xFF el siguiente incremento genera un acarreo en el
byte alto y se escribe el valor 0x00 en el byte bajo del temporizador.

 Cuando el temporizador está incrementándose y se escribe en el byte


alto del temporizador, el byte bajo no es afectado, en el caso que en el
momento de realizar la escritura el byte bajo tenga el valor de 0xFF en
el siguiente incremento se realizará un incremento en el valor del byte
alto.

Se enmascara el incremento del temporizador durante el ciclo de instrucción


en el que se realiza la escritura para que la misma pueda realizarse.

49
www.Microchip.com

176
3.3.5.1.5.2 Lectura

Para realizar la lectura del registro del temporizador debe realizarse con
tamaño palabra, si se intenta realizar la lectura de un byte no tendrá ningún
efecto y se tendrá un valor de cero. De la misma manera que en el caso de la
escritura, la lectura puede realizarse mientras el temporizador se encuentre
funcionando.

El temporizador sigue incrementando su cuenta en el mismo ciclo de


instrucción en el que se realice la lectura de los 16 bits del temporizador.

3.3.5.2 Ejercicio No. 5 Utilización Básica de los TIMERs

Lo que se propone es realizar un generador de onda cuadrada de 0 a 5 V, con


una frecuencia de 10 KHz. Para esto se utilizará el pin RB0 del dspic 30F4011,
mismo que se lo hará parpadear cada cierto número de ciclos de máquina
haciendo uso de la interrupción interna del TIMER.

En la figura 3.43 se muestra lo propuesto en el presente ejercicio.

Figura 3.43 Circuito para realizar las pruebas del ejercicio No. 5

177
3.3.5.2.1 Diagrama de flujo

INICIO

CONFIGURACIÓN DEL DISPOSITIVO

 DECLARACIÓN DE LA SUBSUNCIÓN INTERRUPCIÓN

 CONFIGURACIÓN EN MODO DIGITAL DE RB0, COMO


SALIDA DE DATOS.

 CONFIGURAR Modo operación TIMER1 (T1CON,


TMR1=0;
 GUARDAR el número de ciclos en PR1
 CONFIGURAR LAS INTERRUPCIONES DEL TIMER1
(IFS0bits.T1IF, IEC0bits.T1IE, T1CONbits.TON)
 ARRANCAR EL TIMER 1

WHILE(1)

BUCLE INFINITO
 EMPEZAR RBO EN O LÓGICO

CUENTA EL TEMPORIZADOR 1
SALTA AL SERVICIO DE INTERRUPCIÓN 1 Y CAMBIA EL
ESTADO DE RB0.
LIMPIAR LA BANDERA DE INTERRUPCIÓN Y SALIR

FIN DE PROCESO

Flujograma 3.6 Diagrama de flujo del programa principal

3.3.5.2.2 Elaboración de código

El programa tiene como función generar una interrupción cada cierto número
de ciclos de máquina, esto se verá reflejado en el pin RB0 del dspic 30F4011.

En primera instancia se debe configurar servicio en la interrupción del TIMER


1, esto se muestra en el espacio de código 3.21.

void _ISR _T1Interrupt()


{
// Borra Interrupt Flag
IFS0bits.T1IF=0;
// Cambia bit 0 de puerto B
_LATB0= ! _LATB0;
}

Espacio de Código 3.21 Servicio de Interrupción del TIMER 1

178
A continuación se debe configurar la forma de funcionamiento del TIMER, eso
se hace con el espacio de código 3.22.

// Modo operación TIMER1


T1CON=0x0000;
// Modo operación TIMER1: reloj interno, escala 1:1,
// Empieza cuenta en 0
TMR1=0;
// Cuenta 500 ciclos
PR1=500;
// Interrupciones TIMER1
// Borra Interrupt Flag
IFS0bits.T1IF=0;
// Habilita Interrupción
IEC0bits.T1IE=1;
// Arranca TIMER1
T1CONbits.TON=1;
// Permanece estádo IDLE, vuelve si se sale

Espacio de Código 3.22 Configuración del TIMER 1

Una vez hecho esto, solamente falta estructurar la configuración del dspic,
añadir las librerías del dspic a usar y compilar el proyecto. El espacio de
código 3.23 muestra el cogido del ejercicio listo para ser compilado.

#include <p30f4011.h>
_FOSC(CSW_FSCM_OFF & XT_PLL4 )
_FWDT( WDT_OFF)
_FBORPOR(PBOR_OFF & BORV_27 & PWRT_16 & MCLR_EN);
_FGS(CODE_PROT_OFF)
void _ISR _T1Interrupt()
{
// Borra Interrupt Flag
IFS0bits.T1IF=0;
// Cambia bit 0 de puerto B
_LATB0= ! _LATB0;

Espacio de Código 3.23 Programa principal del Ejercicio 5

179
}
main()
{
// Modo operación PORTB
// Puerto B, bit 0 es entrada
// Bit 0 puerto B = 0
TRISBbits.TRISB0=0;
_LATB0=0;
// Modo operación TIMER1
T1CON=0x0000;
// Modo operación TIMER1: reloj interno, escala 1:1,
// Empieza cuenta en 0
TMR1=0;
// Cuenta 500 ciclos
PR1=500;
// Interrupciones TIMER1
// Borra Interrupt Flag
IFS0bits.T1IF=0;
// Habilita Interrupción
IEC0bits.T1IE=1;
// Arranca TIMER1
T1CONbits.TON=1;
// Permanece estádo IDLE, vuelve si se sale
while (1)
Idle();
}

Espacio de Código 3.23 Programa principal del Ejercicio 5 (continuación)

3.3.5.2.3 Compilación y Depuración de Código

Para la realización de la compilación y depuración del código, se realiza el


procedimiento utilizado en los ejercicios anteriores y se tiene como resultado la
ventana de la figura 3.44.

180
Figura 3.44 Compilación Ejercicio 5

3.3.5.2.4 Implementación en Hardware

El ejercicio fue implementado en el equipo de entrenamiento Easydspic4, en


donde se puede observar el parpadeo del LED así como también se conecta
al osciloscopio para obtener la señal de salida tal como se muestra en la figura
3.45.

Figura 3.45 Circuito del Ejercicio 5 probado en el equipo de entrenamiento


Easydspic4
181
En la figura 3.46 se tiene de forma más clara la señal obtenida en el
osciloscopio.

Figura 3.46 Señal obtenida en el osciloscopio del ejercicio 5

3.3.6 MANEJO DE LOS CONVERSORES A/D

3.3.6.1 Muestreo y Reconstrucción de Señales

El proceso de muestreo consiste en tomar muestras de la señal cada cierto


tiempo, esto se hace de manera periódica cada T S o también según la
frecuencia de muestreo F S = 1/TS.

En la figura 3.47 se muestra la señal de entrada y la señal muestreada.

182
Figura 3.47 Señal Muestreada

Para el teorema de muestreo se optará por el teorema de Nyquist, en el cual


se indica que el ancho de banda de la señal de entrada debe ser limitado y
que la frecuencia de muestreo F S tiene que ser mayor o igual al doble del
ancho de banda.

FS ≥ 2 x AB

Ecuación 3.2 Teorema de Nyquist

3.3.6.1.1 El Aliasing

Cuando no se respeta el teorema de Nyquist se produce un efecto llamado


aliasing el cual se produce por la mala elección de la frecuencia de muestreo
provocando así la mezcla de los espectros.

En la figura 3.48, se muestra el espectro de una señal que tiene aliasing.

183
Figura 3.48 Representación espectral del Aliasing

Al reconstruir una señal con aliasing en está aparecen componentes no


deseadas, provocando una distorsión con respecto a la señal original.

Como conclusión para evitar el aliasing se debe elegir una correcta frecuencia
de muestreo.

3.3.6.1.2 Cuantificación

Después de realizada la discretización en el eje del tiempo mediante el


muestreo, es necesaria la discretización en el eje de amplitud, esto se logra
mediante la cuantificación. En la figura 3.49 se muestra la cuantificación de
una señal variando el número de bits utilizados para la misma.

184
Figura 3.49 Señal Cuantificada

Para reducir los errores en la cuantificación se utiliza la cuantificación no líneal,


con lo que se mejora la calidad de la señal y se reduce el número de bits
utilizados para la misma. Para esto se tiene la Ley A y la Ley µ las mismas que
plantean 2 formas de cuantificar la señal.

Es evidente que en la digitalización de la señal existe una pérdida de


información, dado que las aplicaciones que se utilizarán son de PDS es
necesario la utilización de una señal digital con mayor fidelidad para lo cual se
debe utilizar:

 Mayor frecuencia de muestreo.

 Mayor número de bits, lo que da mayor resolución.

3.3.6.2 Conversor A/D

La familia de los dspic30F dispone de un conversor de 10 bits de resolución y


de alta velocidad, y otro de 12 bits de alta resolución.

La conversión de las señales analógicas a digitales es realizada en tres


etapas:

185
1. Muestreo: el mismo consiste en obtener una señal discreta en el tiempo
y en amplitud a partir de una señal continua de entrada.

2. Cuantificación: esto consiste en representar la amplitud de las muestras


mediante un número finito de valores distintos. Si el convertidor es de n
bits, habrá 2n posibles valores.

3. Codificación: es la representación del valor asignado a la señal en la


etapa de cuantificación mediante los niveles de tensión 1 y 0L.

El convertidor analógico digital de 10 bits del dspic30F tiene las siguientes


características:

 Resolución de 10 bits.

 Tiempo de muestreo de 154 ns.

 Conversión por aproximaciones sucesivas.

 Velocidad de conversión de hasta 500 ksps a 5 V y 100 ksps a 2,7 V.

 Hasta 16 pines de entradas analógicas.

 Pines de entrada destinados a soportar el voltaje de referencia externo.

 Cuatro amplificadores unipolares diferenciales de muestreo y retención.

 Muestreo de hasta 4 pines de entrada analógica de manera simultánea.

 Modo automático de exploración de canal.

 Fuente seleccionable del disparador de la conversión.

 Buffer para almacenar el resultado de la conversión de 16 palabras.

 Modos de selección para rellenar el buffer.

 Cuatro opciones de alíneamiento del resultado.

 Funciona mientras la CPU se encuentre en los modos Sleep e Idle.


186
 La tensión analógica de referencia puede ser seleccionada por software.

 Alimentación única comprendida entre 2,7 y 5,5 V.

Es necesario el empleo de multiplexores para conectar el conversor analógico


digital con las distintas señales adquiridas, el multiplexor debe ser más rápido
y debe funcionar en sincronismo con el ADC, conectando las señales de
entrada antes de comenzar cada lectura y desconectando las señales un poco
antes de conectar el siguiente canal para evitar efectos cruzados entre los
distintos canales.

El tiempo de conversión (tC) está asociado a la conversión de un valor


analógico a digital. La velocidad máxima de cambio de amplitud de la señal de
entrada se detalla en la ecuación 3.3.

dV M ( ADC )

dt 2n tc

Ecuación 3.3 Velocidad de conversión con respecto a la resolución y al


número de bits

En donde:
M: margen de tensión del ADC.
n: número de bits (resolución).
tC: tiempo de conversión.

Para evitar la fluctuación de la entrada durante el periodo de conversión, antes


del ADC es necesario el uso de un amplificador de muestreo y retención
(Sample & Hold o S&H), el mismo que retiene las muestras de la señal
analógica de entrada durante el tiempo de conversión y se muestra en la figura
3.50.

Mediante la utilización de un S&H no es necesario que la conversión sea muy


rápida y el S&H tiene los siguientes elementos:
187
 Condensador (CH ), el mismo mantiene la muestra adquirida durante el
tiempo de retención.

 Interruptor (I), este permanece cerrado mientras se realiza la retención y


se abre en el momento de retención.

 Red de adaptación de impedancias (A1 y A2), el amplificador A1


funciona como un separador de impedancia de entrada alta. El mismo
ofrece una gran estábilidad cuando se conecta a una carga capacitiva
con una corriente de salida alta para realizar la carga del condensador
CH en un tiempo pequeño. Y el amplificador A2 es un separador con
una corriente de polarización muy pequeña evitando así que se
descargue el capacitor.

Figura 3.50 Estructura de un S&H50

3.3.6.2.1 Configuración del módulo analógico digital

Los pasos necesarios para la conversión analógica digital son:

 Seleccionar los pines como entradas analógicas con los pines ADPCFG
<15:0>.

50
www.Microchip.com

188
 Seleccionar la fuente del voltaje de referencia para realizar la
conversión con los bits ADCON2 <15:13>.
 Seleccionar el reloj de conversión con los bits ADCON3 <5:0>.
 Determinar el número de canales de muestreo a utilizar mediante los
bits ADCON2 <9:8> y ADPCFG <15:0>.
 Determinar el tipo de muestreo ADCON1 <3> y ADCSSL <15:0>.
 Asignar las entradas a los canales de muestreo mediante los bits
ADCHS <15:0>.
 Seleccionar la secuencia de muestreo con los bits ADCON1 <7:0>.
 Seleccionar la representación del resultado de la conversión en el buffer
de resultado con los bits ADCON1 <9:8>.
 Determinar el número de conversiónes que deben darse para que se
genere una interrupción mediante los bits ADCON2 <5:9>.
 Encender el módulo analógico digital, ADCON1 <15>.

3.3.6.2.2 Selección de la fuente del voltaje de referencia

El voltaje de referencia que el módulo utiliza es seleccionado con los bits


VCFG <2:0>.

Los voltajes de referencia alto y bajo pueden ser los voltajes de polarización
del dspic así como también voltajes ingresados en los pines V REF+ y VREF-. para
utilizar estos pines estos tienen que estár configurados como entradas
analógicas, al igual de cumplir con valores que no lleguen a dañar al dspic.

189
3.3.6.2.3 Selección del reloj de conversión

El conversor AD tiene un límite de velocidad de conversión de datos. Para


realizar el cálculo de la velocidad de conversión es necesario el valor de un
periodo de reloj (TAD), dado que el tiempo de conversión es igual a 12T AD por
cada dato.

La selección del periodo de la señal de reloj se da mediante software con los


bits de control ADCON3 <5:0>.

La ecuación 3.4 relaciona el valor del T AD con los bits de control ADCS como
también del reloj del ciclo de instrucciones T CY

Ecuación 3.4 Cálculo del periodo de reloj

Los parámetros necesarios para que el coversor AD funcione correctamente


son:

 Determinar la secuencia de muestreo y retención apropiada.


 Se debe tener un mínimo TAD = 84 ns para el muestreo.
 Se debe configurar correctamente los servicios de interrupción para
extraer los datos de los buffers del ADC.

Bajo estos parámetros se va a calcular los diferentes valores que se le debe


dar a los registros del conversor AD para configurar una frecuencia de
muestreo.

190
Para comprender de mejor manera el cálculo del periodo de muestreo se
plantea el siguiente ejemplo: Se tiene una señal de 1 kHz a ser muestreada en
el pin AN0, según el teorema de muestreo se necesita una frecuencia de
muestreo mínima de 2 kHz.

Para empezar se toma como referencia la ecuación 3.4, dado esto se define la
frecuencia de oscilación del dspic, para este ejemplo se trabaja con la
frecuencia del oscilador interno FRC.

Entonces se tiene:

De donde la FCY es:

A su vez el TCY es:

Asumiendo un valor de 0 en ADCS entonces se tiene que:

Entonces:

191
Este valor del TAD cumple con el mínimo necesario para el correcto
funcionamiento del conversor AD.

Teniendo en cuenta el valor de TCY y tomando FS = 2 KHz se tiene:

Este es el número de ciclos de máquina que se demorará el dspic en tomar


cada muestra de la señal de entrada, el mismo que será guardado en el
registro PR.

Se debe recalcar que existen diferentes métodos de temporización del ADC,


mediante temporizadores, retardos simples, etc. Sin embargo este método de
cálculo del periodo de muestreo es válido para todos, ya que lo que se
necesita saber es el número de ciclos a contar antes de tomar una muestra.

192
3.3.6.3 Ejercicio No. 6 Utilización del ADC

Se requiere elaborar un voltímetro mediante la utilización del conversor ADC,


los temporizadores, además la utilización del LCD para visualizar el voltaje a
medir, para este ejercicio se plantea tomar muestras de una señal variable en
la entrada en el pin RB0 del dspic.

Como se trata de una señal continua no se detalla el cálculo del periodo de


muestreo, el circuito a implementar se presenta en la figura 3.51.

Figura 3.51 Circuito propuesto para probar el ejercicio 6

193
3.3.6.3.1 Diagrama de flujo

INICIO

CONFIGURACIÓN DEL DISPOSITIVO

 CONFIGURACIÓN EN MODO ANALÓGICO RB0


 DESCARTAR PUERTO E (USADO PARA EL LCD)

 DECLARACIÓN DE SUBFUNCIONES DE
TRANSFORMACION A ASCII Y DEL LCD
 GUARDAR DATOS EN LA EEPROM CON _EEDATO()
 DECLARACIÓN DE LA INTERRUPCIÓN DEL ADC CON
T3 PRENDER LCD: Hace referencia a la función
de Inicialización del LCD

AVANZAR UNA LÍNEA: Escribir 0X40


directamente en el LCD con
Comando_LCD(0x40)
 DECLARACIÓN DE VARIABLES A USAR TIPO CHAR
 PRENDER LCD INICIALIZAR EL ADC: Hace referencia a los
 ESCRIBIR COMANDO VOLTAJE Y ADC siguientes pasos:
 AVANZAR UNA LÍNEA  Configurar el T3
 INICIALIZAR ADC  Configurar el Registro SSRC
 Configurar el Registro ASAM
 Configurar el Registro CHSA
 Configurar la interrupción del ADC
 Encender el T3
WHILE(1)

 TOMAR EL VOLTAJE DE LA INTERRUPCIÓN ADC


 CALCULAR PASO A VOLTIOS
 TRANSFORMAR A ASCII EL VALOR EN VOLTIOS
BUCLE INFINITO
 AVANZAR SEGUNDA LINEA PRIMER CARACTER
 ESCRIBIR VALOR EN VOLTIOS

RETARDO DE LECTURA

TRANSFORMA EL VALOR DEL ADC A ASCII

AVANZAR 8 POSICIONES Y ESCRIBIR EL VALOR DEL ADC


EN ASCII

FIN DE PROCESO

Flujograma 3.7 Diagrama de flujo del programa principal

3.3.6.3.2 Elaboración de código

El voltaje a ser medido será obtenido de un potenciómetro, el cual está


conectado al ADC, el mismo que debe ser inicializado mediante la función que
se detalla en el espacio de código 3.24.

194
//Inicialización del ADC
void init_ADC( void )
{
//Configuración del Timer
//Preescalado 1:8
T3CONbits.TCKPS=1;
//Poner a cero el contador
TMR3=0;
//Periodo de muestreo
PR3=921;
//Inicia la conversión con T3
ADCON1bits.SSRC=2;
//Inicia el muestreo al finalizar la conversión
ADCON1bits.ASAM=1;
//Muestreo en el canal 0
ADCHSbits.CH0SA=0;
//Borra la bandera de la interrupción en el ADC
IFS0bits.ADIF=0;
//Habilita la interrupción del ADC
IEC0bits.ADIE=1;
//Inicia la conversión
ADCON1bits.ADON=1;
//Inicia el conteo poniendo el T3 en marcha
T3CONbits.TON=1;
}

Espacio de Código 3.24 Función de inicialización del ADC

El valor que se almacena en el buffer del ADC (ADCBUF0) es procesado


mediante la ecuación 3.4 la misma que indica el valor del voltaje.

Ecuación 3.5 Valor del voltaje en voltios

195
Una vez hecha está ecuación es necesaria la utilización de una función de
transformación a ASCII para la visualización del voltaje con decimales en el
LCD, está función se detalla en el espacio de código 3.25.

void transformacion_ASCII(int datos, char* puntero_ascii)


{
int temp,i;
*(puntero_ascii + 0) = '='; //add positive sign

temp = datos/10;
//Miles
*(puntero_ascii + 5) = datos - temp*10;
datos = datos - *(puntero_ascii + 5);
temp = datos/100;
//Centenas
*(puntero_ascii + 4) = (datos - temp*100)/10;
datos = datos - *(puntero_ascii + 4);
temp = datos/1000;
//Decenas
*(puntero_ascii + 2) = (datos - temp*1000)/100;
datos = datos - *(puntero_ascii + 2);
//Unidades
temp = datos/10000;
*(puntero_ascii + 1) = (datos - temp*10000)/1000;
datos = datos - *(puntero_ascii + 1);

for( i=1;i<=5;i++)
//Convertir a ASCII
*(puntero_ascii + i) += 0x30;
//Termino el espacio de escritura
*(puntero_ascii + 6) = '\0';
//Punto decimal
*(puntero_ascii + 3) = '.';
}

Espacio de Código 3.25 Función de transformación a un valor ASCII

196
Y para la visualización del valor del ADCBUF en el LCD, es necesaria la
utilización de una función de transformación ADC la cual está detallada en el
espacio de código 3.26.

void transformacion_adc(int datos, char* puntero_ascii)


{
int temp,i;
*(puntero_ascii + 0) = '=';

temp = datos/10;
//Miles
*(puntero_ascii + 4) = datos - temp*10;
datos = datos - *(puntero_ascii + 4);

temp = datos/100;
//Centenas
*(puntero_ascii + 3) = (datos - temp*100)/10;
datos = datos - *(puntero_ascii + 3);

temp = datos/1000;
//Decenas
*(puntero_ascii + 2) = (datos - temp*1000)/100;
datos = datos - *(puntero_ascii + 2);
temp = datos/10000;
//Unidades
*(puntero_ascii + 1) = (datos - temp*10000)/1000;
datos = datos - *(puntero_ascii + 1);

for( i=1;i<=4;i++)
//Transforma a ASCII
*(puntero_ascii + i) += 0x30;
//Evita excesos en la línea
*(puntero_ascii + 5) = '\0';
}

Espacio de Código 3.26 Función de transformación a formato ADC

197
La solución total del ejercicio 6 se detalla en el espacio de código 3.27.

//LIBRERÍAS
#include <p30f4011.h>
#include "transf_lcd.h"
#include <libpic30.h>
#include "math.h"
#include "dsp.h"
//INICIALIZACIÓN DEL DISPOSITIVO
//Configuración del Registro del Oscilador
//CSW_FSCM_OFF Oscilador a prueba de errores
//FRC Oscilador interno RC corriendo a 8 MHz
_FOSC(CSW_FSCM_OFF & FRC);
//Configuración del Temporizador WATCHDOG
//WDT_OFF Deshabilita el temporizador
_FWDT(WDT_OFF);
//Configuración del Registro de Protección de Voltaje
//Brown-out reset desabilitado
//PBOR reset desahabilitado
//MCLR reset habilitado
_FBORPOR(PBOR_OFF & MCLR_EN);
//Configuración del Registro de Protección de Memoria de Programa
//Deshabilitada la protección de código de memoria de programa
_FGS(CODE_PROT_OFF)
//DECLARACIÓN DE LA SUBFUNCIÓN DE TRANSFORMACIÓN BINARIO-BCD
void transformacion_ASCII(int datos, char* puntero_ascii);
//Inicialización del ADC
void init_ADC( void );
//Declaración de la subrutina Interrupción
void _ISR _ADCInterrupt(void);
//Transformación de formato hex a bcd
void transformacion_adc(int datos, char* puntero_ascii);

Espacio de Código 3.27 Programa principal del ejercicio 6

198
//Variables usadas el el programa
// paso_a_voltios = lectura_adc en voltios
long paso_a_voltios;
//lectura_adc = lectura del ADC0
unsigned lectura_adc;
//FUNCIÓN PARA TRANSFORMAR DE BINARIO A BCD

void transformacion_ASCII(int datos, char* puntero_ascii)


{
int temp,i;
*(puntero_ascii + 0) = '='; //add positive sign

temp = datos/10;
//Miles
*(puntero_ascii + 5) = datos - temp*10;
datos = datos - *(puntero_ascii + 5);
temp = datos/100;
//Centenas
*(puntero_ascii + 4) = (datos - temp*100)/10;
datos = datos - *(puntero_ascii + 4);
temp = datos/1000;
//Decenas
*(puntero_ascii + 2) = (datos - temp*1000)/100;
datos = datos - *(puntero_ascii + 2);
//Unidades
temp = datos/10000;
*(puntero_ascii + 1) = (datos - temp*10000)/1000;
datos = datos - *(puntero_ascii + 1);

for( i=1;i<=5;i++)
//Convertir a ASCII
*(puntero_ascii + i) += 0x30;
//Termino el espacio de escritura
*(puntero_ascii + 6) = '\0';
//Punto decimal

Espacio de Código 3.27 Programa principal del ejercicio 6 (continuación)

199
*(puntero_ascii + 3) = '.';
}

//FUNCIÓN PARA TRANSFORMAR DE BINARIO A BCD EL VALOR DEL ADC


void transformacion_adc(int datos, char* puntero_ascii)
{
int temp,i;
*(puntero_ascii + 0) = '=';

temp = datos/10;
//Miles
*(puntero_ascii + 4) = datos - temp*10;
datos = datos - *(puntero_ascii + 4);

temp = datos/100;
//Centenas
*(puntero_ascii + 3) = (datos - temp*100)/10;
datos = datos - *(puntero_ascii + 3);

temp = datos/1000;
//Decenas
*(puntero_ascii + 2) = (datos - temp*1000)/100;
datos = datos - *(puntero_ascii + 2);

temp = datos/10000;
//Unidades
*(puntero_ascii + 1) = (datos - temp*10000)/1000;
datos = datos - *(puntero_ascii + 1);

for( i=1;i<=4;i++)
//Transforma a ASCII
*(puntero_ascii + i) += 0x30;
//Evita excesos en la línea
*(puntero_ascii + 5) = '\0';
}

Espacio de Código 3.27 Programa principal del ejercicio 6 (continuación)


200
//Inicialización del ADC
void init_ADC( void )
{
//Configuración del Timer
//Preescalado 1:8
T3CONbits.TCKPS=1;
//Poner a cero el contador
TMR3=0;
//Periodo de muestreo
PR3=921;
//Inicia la conversión con T3
ADCON1bits.SSRC=2;
//Inicia el muestreo al finalizar la conversión
ADCON1bits.ASAM=1;
//Muestreo en el canal 0
ADCHSbits.CH0SA=0;
//Borra la bandera de la interrupción en el ADC
IFS0bits.ADIF=0;
//Habilita la interrupción del ADC
IEC0bits.ADIE=1;
//Inicia la conversión
ADCON1bits.ADON=1;
//Inicia el conteo poniendo el T3 en marcha
T3CONbits.TON=1;
}

//Interrupción del ADC


void _ISR _ADCInterrupt(void)
{
//Borra la bandera de la interrupción del adc
IFS0bits.ADIF=0;
//Guarda la lectura del adc en lectura_adc
lectura_adc=ADCBUF0;

Espacio de Código 3.27 Programa principal del ejercicio 6 (continuación)

201
}

//PROGRAMA PRINCIPAL
int main(void)
{
//variables auxiliares
int aux1;
char *comando = "Voltaje: ADC:";
char *mensaje = "[V]";
char cuenta[7];
// INICIALIZACIÓN DEL LCD
Prender_LCD();
// ESCRIBE buf1 string AL LCD
Escribir_cadena_LCD(comando);
//Nueva línea
Comando_LCD(0x40);
//Inicializar el ADC
init_ADC();
while(1)
{
//Convierte la lectura del ADC0 a
voltios
//VOLTIOS=(5/1023)*ADCBUF0*ESCALA_LCD
//ESCALA_LCD=100
paso_a_voltios
=(lectura_adc*0.0048875855327468230694037145650049*100); //
//Toma la parte entera de la variable
paso_a_voltios en aux1
aux1=(int)(paso_a_voltios);
//Envía un comando directo al LCD
Comando_LCD(0xC0);
//Transforma el valor de aux1 en ASCII
transformacion_ASCII(aux1, cuenta);
//Escribir cuenta en el LCD
Escribir_cadena_LCD(cuenta);

Espacio de Código 3.27 Programa principal del ejercicio 6 (continuación)


202
//Retardo de Lectura
__delay32(900000);
//Escribir comando directo al LCD
Comando_LCD(0xC6);
//Escribir mensaje en el LCD
Escribir_cadena_LCD(mensaje);
//Retardo de Lectura
__delay32(900000);
//Avanza 8 lugares en el LCD
Comando_LCD(0xCA);
//Transforma la lectura del ADC para ser
mostrada
transformacion_adc(lectura_adc, cuenta);
//Escribe la lectura del ADC en bcd
Escribir_cadena_LCD(cuenta);
//Retardo de lectura
__delay32(900000);
Idle();
}
return 0;
}

Espacio de Código 3.27 Programa principal del ejercicio 6 (continuación)

3.3.6.3.3 Compilación y Depuración de Código

Para la realización de la compilación y depuración del código, se realiza el


procedimiento utilizado en los ejercicios anteriores y se tiene como resultado la
ventana de la figura 3.52.

203
Figura 3.52 Compilación Ejercicio No. 6

3.3.6.3.4 Implementación en Hardware

Como resultado final se obtiene un voltímetro el cual muestra en el LCD el


valor del voltaje medido así como el valor de ADCBUF0, como se muestra en
la figura 3.53.

Figura 3.53 Circuito del ejercicio 6 armado en el Protoboard


204
3.3.7 MANEJO DEL MÓDULO UART

3.3.7.1 Módulo UART

La familia de los dspic30F disponen de un módulo de comunicaciones serial


asincrónica conocido como UART (Receptor y Transmisor Universal
Asincrónico); es un sistema de comunicación full-dúplex asincrónico.

Las principales características de la UART son:

 Funcionamiento full-duplex con datos de 8 o 9 bits.


 Posibilidad de trabajar con paridad, impar o sin paridad.
 Uno o dos bits de STOP.
 Tiene un generador de baudios con un prescaler de 16 bits, el cual tiene
la función de generar la frecuencia de trabajo del módulo.
 Buffer de transmisión con capacidad de 4 caracteres.
 Buffer de recepción con capacidad de 4 caracteres.
 Posibilidad de empleo de interrupciónes indicando el fin de la
transmisión o recepción
 Pines específicos para transmitir o recibir (TX y RX).

El envío de información se lo realiza de tal forma que los datos son enviados
independientemente, normalmente de 8 o 9 bits además de un bit de inicio
START y uno de parada STOP.

Los registros de control y estádo del módulo UART son:

 USTA.- Registro de control del módulo UART.

 URREG.- Registro de recepción del módulo UART.

 UTREG.- Registros de transmisión del módulo UART.

205
El módulo UART está compuesto por 3 bloques los cuales son:

 Generador de baudios.

 Transmisor asincrónico.

 Receptor asincrónico.

El diagrama de bloques del módulo UART se muestra en la figura 3.54.

Figura 3.54 Diagrama de bloques del módulo UART 51

3.3.7.1.1 Generador de Baudios

En el protocolo asincrónico RS-232 la transferencia de información debe tomar


un valor de frecuencia en baudios normalizada como: 330, 600, 1200, 2400,
4800, 9600, 19200, 38400, etc. Debido a esto el módulo UART dispone de un
generador de baudios controlado por el valor del registro UBRG; la frecuencia
en baudios se detalla en la ecuación 3.6.

51
www.Microchip.com

206
Ecuación 3.6 Detalle de la frecuencia en baudios52

3.3.7.1.2 Transmisor Asincrónico

El dato que se va a transmitir es almacenado en el registro UTREG, a


continuación se traslada al registro de desplazamiento UTSR, de donde se van
sacando los bits secuencialmente, antes de los bits existe el bit de START y un
bit STOP al final de los mismos.

En la figura 3.55 se muestra el diagrama de bloques del transmisor asincrónico


de la UART.

La secuencia para implementar una transmisión UART es:

1. Cuando se desea trabajar con interrupción se debe poner el valor 1 en


UTISEL, así como también habilitar las interrupciónes en general.

2. Se carga el valor adecuado en el registro UBRG el cual es utilizado para


generar la frecuencia de trabajo deseada.

3. Para permitir la transmisión se debe poner el valor de 1 en el bit UTEN.

4. Poner el valor a transmitir en el registro UTREG.

52
www.Microchip.com

207
Figura 3.55 Diagrama de bloques del transmisor asincrónico del módulo
UART53

3.3.7.1.3 Receptor Asincrónico

Los bits se reciben en serie bit a bit y van introduciéndose secuencialmente en


el registro de desplazamiento URSR, esto funciona a una frecuencia de 16
bits/seg más rápida que la frecuencia de trabajo, en la figura 3.56 se muestra
un diagrama de bloques de recepción del módulo UART.

La secuencia a seguir en el modo interrupción es:

1. Se carga el registro UBRG con el valor para que trabaje a la frecuencia


deseada.

2. Se pone un valor de 1L en el bit URISEL si se desea que se genere una


interrupción con el bit de STOP.

3. Poner un 1L al bit ADDEN para detectar la dirección.

53
www.Microchip.com

208
4. Se habilita la recepción.

5. Luego de la recepción se producirá una interrupción si están


habilitadas.

6. Se realiza la lectura de los bits PERR y FERR para revisar si se ha


producido algún error.

7. Determinar si el dispositivo ha sido direccionado.

8. Si el dispositivo está direccionado se pone 0L en el bit ADDEN para


permitir la recepción de UART.

Figura 3.56 Diagrama de bloques del receptor asincrónico del módulo UART54

54
www.Microchip.com

209
3.3.7.2 Ejercicio No. 7 Utilización del Módulo UART y el Hyperterminal del
Computador

Enviar un mensaje desde el dspic hacia el hyperterminal del computador y


mostralo en la pantalla a una velocidad de 9600 baudios, teniendo en cuenta el
diagrama de la figura 57.

FUENTE DE SEÑAL ANALÓGICA


PC
ENTRENADOR
EASYDSPIC
WORKS

Figura 3.57 Modo de conexión para las pruebas del Ejercicio 7

210
3.3.7.2.1 Diagrama de flujo

INICIO

CONFIGURACIÓN DEL DISPOSITIVO

 DEFINICIÓN DE MACROS Y CÁLCULO DE


VELOCIDAD DE TRANSMISIÓN
CONFIGURAR LOS SIGUIENTES REGISTROS
CON LOS VALORES ADECUADOS

U1MODE, U1STA, U1BRG,U1STAbits.UTXEN

PARA LA CONFIGURACIÓN MEDIANTE


 CONFIGURACIÓN DE LA UART, EN MODO LIBRERÍAS HACER USO DE:
TRANSMISIÓN A LA VELOCIDAD FIJADA Y BAJO LAS
SIGUIENTES CARACTERÍSTICAS. ConfigIntUART1();
 Configuración básica de la uart CloseUART1();
OpenUART1();
 9600 baudios
BusyUART1();
 8 bits de datos
 sin paridad
 1 bit de parada
 sin control de flujo

WHILE(1)

 TRANSMITIR EL PRIMER DATO ASCCI APUNTADO POR


EL PUNTERO EN EL VECTOR DE DATOS

BUCLE INFINITO

INCREMENTAR UNA POSICIÓN EN EL PUNTERO

TRANSMITIR EL ÚLTIMO DATO ASCCI APUNTADO POR EL


PUNTERO EN EL VECTOR DE DATOS

AVANZAR 8 POSICIONES Y ESCRIBIR EL VALOR DEL ADC


EN ASCII

FIN DE PROCESO

Flujograma 3.8 Diagrama de Flujo Ejercicio 7

211
3.3.7.2.2 Elaboración de código

Al despejar el valor del registro UBRG de la ecuación 3.5 obtenemos la


ecuación 3.7.

Ecuación 3.7 Cálculo del valor del registro UBRG

Teniendo en cuenta que se quiere una frecuencia igual a 9600 baudios,


podemos calcular el valor del registro UBRG, con lo que se realiza la
configuración del módulo UART.

Para este ejercicio se manejan dos métodos de programación los cuales


implican la utilización de los registros como se muestra en el espacio de código
3.28, como también la utilización de librerías como se muestra en el espacio
de código 3.29, obteniendo iguales resultados.

#include "p30F4011.h"
#include <libpic30.h>
//Inicialización del dispositivo
_FOSC(CSW_FSCM_OFF & XT_PLL8)
_FWDT(WDT_OFF)
_FBORPOR(PBOR_ON & BORV_27 & MCLR_DIS )
_FGS(CODE_PROT_OFF)
//Definición de constantes a usar
#define PLL 8
#define BAUD 9600
#define FCY 10000000*PLL/4
#define VELOCIDAD ((FCY/16)/BAUD) - 1;
//Definición de variables globales

Espacio de Código 3.28 Programa principal utilizando Registros

212
//Vector de datos
//enter
const unsigned char hello[] = {"\r\rEsta es una prueba de
transmicion\r\nDSPIC -----> UART\r\r\r"};
//Puntero de transmisión
unsigned char *TXPtr;
//Programa principal
int main(void)
{
// Configuración básica de la uart
// 9600 baudios
// 8 bits de datos
// sin paridad
// 1 bit de parada
// sin control de flujo
U1MODE = 0x8000;
U1STA = 0x0000;
//Velocidad de transmisión
U1BRG = VELOCIDAD;
//Apunta al primer carácter de la cadena
TXPtr = &hello[0];
//Inicializa la transmisión
U1STAbits.UTXEN = 1;
//Entra en el lazo infinito
chile (1)
{
//Transmite solo caracteres ascii validos
while (*TXPtr)
//Si el buffer no está vacío, transmitir
if (!U1STAbits.UTXBF)
//Transmitir la cadena
U1TXREG = *TXPtr++;
//Apuntar a la primera posición
TXPtr = &hello[0];
}
}

Espacio de Código 3.28 Programa principal utilizando Registros


(continuación)

213
//Librerías a usar
//Añadir el archivo ...coff.a y ...elf.a del dspic al árbol del
proyecto
#include "p30F4011.h"
#include <libpic30.h>
#include<uart.h>
//Inicialización del dispositivo
_FOSC(CSW_FSCM_OFF & XT_PLL8)//FRC_PLL8)
_FWDT(WDT_OFF)
_FBORPOR(PBOR_ON & BORV_27 & MCLR_DIS )
_FGS(CODE_PROT_OFF)
//Definición de constantes a usar
#define FCY 10000000*PLL/4
#define PLL 8
#define BAUD 9600
#define CÁLCULO ((FCY/16)/BAUD) - 1;
//Corrección de la librería
#define UART_RX_TX 0xFBE7
//Programa principal
int main(void)
{
//Definición de variables
//Vector de datos
const unsigned char hello[] = {"\r\rEsta es una prueba de
transmicion\r\nDSPIC -----> UART\r\r\r\n"};
//Puntero de transmisión
unsigned char *TXPtr;
//Velocidad de transmisión
unsigned int baudvalue;
//Constante de configuración
//puede ser una variable cualesquiera
unsigned int U1MODEvalue;
//Constante de configuracion
//puede ser una variable cualesquiera
unsigned int U1STAvalue;

Espacio de Código 3.29 Programa principal utilizando Librerías

214
CloseUART1();
//Apagar el módulo UART
//Configuración de la UART
ConfigIntUART1(UART_RX_INT_EN & UART_RX_INT_PR6 &
UART_TX_INT_DIS & UART_TX_INT_PR2);
//Velocidad de transmisión

baudvalue = CÁLCULO;

// 8 bits de datos, sin paridad, 1 bit de parada, sin control de


flujo

U1MODEvalue = UART_EN & UART_IDLE_CON & UART_RX_TX &


UART_DIS_WAKE & UART_EN_LOOPBACK &
UART_EN_ABAUD & UART_NO_PAR_8BIT &
UART_1STOPBIT;
U1STAvalue = UART_INT_TX_BUF_EMPTY &
UART_TX_PIN_NORMAL &
UART_TX_ENABLE & UART_INT_RX_3_4_FUL &
UART_ADR_DETECT_DIS &
UART_RX_OVERRUN_CLEAR;

//Habilitar la uart
OpenUART1(U1MODEvalue, U1STAvalue, baudvalue);
//Entra en el lazo infinito
while(1)
{

//Transmite solo caracteres ascii válidos


while (*TXPtr)
//Si el buffer no está vacío, transmitir
if (!U1STAbits.UTXBF)
//Transmitir la cadena
U1TXREG = *TXPtr++;

Espacio de Código 3.29 Programa principal utilizando Librerías (continuación)

215
//Apuntar a la primera posición
TXPtr = &hello[0];
//Esperar hasta que la transmisión se complete
while(BusyUART1());
}
return 0;
}

Espacio de Código 3.29 Programa principal utilizando Librerías (continuación)

Para realizar la reconstrucción de la señal utilizando el MATLAB es necesaria


la programación de un script, el mismo que está detallado en el espacio de
código 3.30.

%Script de adquisición de datos en matlab


%Adquisición
%Variables globales
global s;
global i;
%Abrir el puerto serial
%Se usa el COM1 el puerto que maneja cualquier pc de escritorio
%Si se cambia a una laptop se debe actualizar el Com que se usa
s=serial ('com1');
s.BaudRate=19200;
s.Timeout=1;
%Permitir el paso de 5 caracteres, luego vaciar el buffer
s.InputBufferSize=5;
%Abrir el puerto
fopen(s);
%Tomar 50 muestras, por defecto cada 100 ms
for i=1:50
if (i==1)

Espacio de Código 3.30 Código del Script en MATLAB

216
fprintf(s,'an00')
end
while(~(s.BytesAvailable))
end
%Leer el puerto COM1
q=fgetl(s);
%Convierte el i-ésimo dato a número de tipo double la cadena leída
en el puerto COM1
w(i)=(str2double(q));
end
%Base de tiempos
t=0:0.02/50:0.0196;
%Normalización del vector de datos
w_nor=(w./1024)*5;
%Imprimir en pantalla la señal interpolada mediante plot
plot(t,w_nor,'.-')
grid
title('Señal Senoidal de 50[Hz]')
xlabel('Tiempo [s]')
ylabel('Voltaje [V]')
%Cerrar el puerto
fclose(s);
delete(s);
clear s;

Espacio de Código 3.30 Código del Script en MATLAB (continuación)

3.3.7.2.3 Compilación y Depuración de Código

Tanto la compilación como la depuración del código se la realiza tal como se


ha venido realizando en los ejercicios anteriores, en lo cual se tiene como
resultado la ventana de la figura 3.58.

217
Figura 3.58 Compilación Ejercicio 7

3.3.7.2.4 Implementación en Hardware

Las pruebas de los resultados de este ejercicio, tanto del código que maneja
registros como del código implementado con el manejo de librerías, se las
realizaron en primera instancia con el simulador del MPLAB obteniendo como
resultado la ventana de la figura 3.59 y posteriormente se realizaron las
pruebas en el equipo de entrenamiento Easydspic 4 y el hyperterminal del
computador tal como se muestra en la figura 3.60, obteniendo como resultado
lo indicado en la figura 3.61.

218
Figura 3.59 Resultado de la Simulación del Ejercicio 7 en el MPLAB

Figura 3.60 Conexión del equipo de entrenamiento Easydspic 4 y el


hyperterminal del computador

219
Figura 3.61 Resultado del Ejercicio 7 mostrado en el hyperterminal del
computador

3.3.7.3 Ejercicio No. 8 Utilización del Módulo UART, ADC y MATLAB

Se propone un ejercicio que muestree una señal de 50 Hz en el pin RB0 con el


módulo ADC, enviarlos al módulo UART para luego reconstruir la señal de
entrada en el MATLAB, el diagrama del ejercicio se muestra en la figura 3.62.

FUENTE DE SEÑAL ANALOGICA


SCRIPT EN
PC MATLAB
ENTRENADOR
EASYDSPIC
WORKS

Figura 3.62 Modo de conexión para las pruebas en el MATLAB del ejercicio 8

220
3.3.7.3.1 Diagrama de flujo

En la elaboración de la solución de este ejercicio se trabaja en etapas, ya que


requiere la integración de todo lo visto anteriormente, a pesar de centrarse
solamente en el manejo del dspic, desde aquí se empezará a tomar ciertos
conceptos básicos del procesamiento digital de señales.

Primeramente se trabajará en la elaboración del programa que convertirá a


analógica una señal conectada en el RB0, está señal se muestreara mediante
el ADC del dspic, este valor se convertirá a código ASCII mediante una
subrutina de programación, luego se enviará por medio de la UART del dspic a
la PC.

Luego se probará una correcta recepción en la PC, primero mediante el


hyperterminal, luego se ejecutará un pequeño script en MATLAB para
transformar el valor del ADC que nos estrega la UART en valores
normalizados, es decir se realizará el paso a voltios, para finalmente visualizar
la señal con la ayuda de MATLAB.

221
INICIO

CONFIGURACIÓN DEL DISPOSITIVO

 CONFIGURACIÓN DE LA UART, EN MODO


TRANSMISIÓN A LA VELOCIDAD FIJADA Y BAJO LAS
SIGUIENTES CARACTERÍSTICAS.
 Configuración básica de la uart
 9600 baudios
 8 bits de datos
 sin paridad
 1 bit de parada
 sin control de flujo

 CONFIGURACIÓN DEL ADC

WHILE(1)

 INICIALIZAR LA UART
 INICIALIZAR EL ADC

BUCLE INFINITO
LEER EL ADCBUF0 Y TRANSFORMARLO EN ASCII

TRANSMITIR LA TRANSMORACION DEL ADCBUF0 POR LA


UART

INICIAR EL MUESTREO NUEVAMENTE

FIN DE PROCESO

Flujograma 3.9 Diagrama de Flujo del Ejercicio 8

3.3.7.3.2 Elaboración de Código

Para este ejercicio es necesario conocer el periodo de muestreo de la señal en


ciclos de máquina, este proceso de cálculo se expresa a continuación:

Se trabajará con la FRC como frecuencia de oscilación del dspic:

222
De donde la FCY es:

A su vez el TCY es:

Con el valor de TCY en segundos se puede ya estimar un valor adecuado para


TAD y ADCS:

Asumiendo ADCS = 0 entonces se tiene que:

Entonces:

Ahora en base al TCY se puede ya el número de ciclos necesarios para el


periodo de muestreo de la señal.
Sea Fs = 100Hz se tiene:

Con este valor se configurará la temporización del periodo de muestreo.

223
Para la programación del dspic, se integrarán los conceptos revisados
anteriormente, además de ciertos registros nuevos en la configuración de la
UART y el ADC.

La subfunción detallada en el espacio de código 3.31 se encarga de la


configuración e inicialización del módulo de la UART del dspic.

void Inicializar_UART(void)
{
//Velocidad de transmisión
U1BRG = VELOCIDAD;
//Deshabilitar opción de loopback
U1MODEbits.LPBACK = 0;
U1STAbits.UTXBRK = 0;
//Continuar la operación en modo IDLE
U1MODEbits.USIDL = 0;
//8 bits de datos, sin paridad
U1MODEbits.PDSEL = 0b00;
//1 bit de parada
U1MODEbits.STSEL = 0;
//Usar los pines de transmisión en modo normal
U1MODEbits.ALTIO = 0;
//Habilitar la UART
U1MODEbits.UARTEN = 1;
//Habilitar la transmisión
U1STAbits.UTXEN = 1;
}

Espacio de Código 3.31 Subfunción de inicialización del módulo UART

En la configuración de la UART hay que tener en cuenta que la subfunción que


transforma el valor del ADC en valores ASCII es sumamente eficiente e
importante, está función se detalla en el espacio de código 3.32.

224
void cambio_ascii(int valor)
{
//Variables Usadas
//La conversión se realiza por divisiones sucesivas
//Se extrae correspondientemente el dígito de miles
//decenas, centenas, y unidades, las mismas
//serán transmitidas posteriormente por la UART
int b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0;
b=valor/10000; c=valor%10000; dec_mil=b+48;
d=c/1000; e=c%1000; miles=d+48; f=e/100;
g=e%100; centena=f+48; h=g/10; i=g%10;
decena=h+48; unidad=i+48;
}

Espacio de Código 3.32 Subfunción de cambio de valores de ADC a ASCII

Así como las subfunciones anteriormente descritas, la función de inicialización


del módulo ADC juega un papel importante en la resolución del ejercicio, y ésta
se encuentra detallada en el espacio de código 3.33.

void init_ADC( void )


{
//Configura todos los pines del puerto B C30 como digitales solo RB0
como analógico. Ahí se conectará la señal de entrada
ADPCFG = 0xFFFE;
ADCON1 = 0x00E0;
ADCHS = 0x0000;
ADCSSL = 0;
ADCON3 = 0x1F3F;
ADCON2 = 0;
ADCON1bits.ADON = 1;
ADCON1bits.SAMP = 1;
}

Espacio de Código 3.33 Subfunción de inicialización del módulo ADC

225
El programa principal para la resolución del ejercicio 8 se detalla en el espacio
de código 3.34.

//LIBRERÍAS
#include "p30F4011.h"
#include <libpic30.h>
#include <adc10.h>
#include <uart.h>
//INICIALIZACIÓN DEL DISPOSITIVO
_FOSC(CSW_FSCM_OFF & FRC_PLL8)
_FWDT(WDT_OFF)
_FBORPOR(PBOR_ON & BORV_27 & MCLR_DIS )
_FGS(CODE_PROT_OFF)
//Definición de constantes a utilizar
#define PLL 8
#define BAUD 19200
#define FCY 7370000*PLL/4
#define VELOCIDAD ((FCY/16)/BAUD) - 1;
//Declaración de las subfunciones usadas
//Configuración de la UART
void Inicializar_UART(void);
void init_ADC( void );
void cambio_ascii(int valor);
//Declaración de las variables usadas
unsigned int count,dato1,dato2,var;
int dec_mil=0,miles=0,centena=0,decena=0,unidad=0
//PROGRAMA PRINCIPAL
int main(void)
{
//Encender el módulo UART
Inicializar_UART();
//Lazo infinito
while(1)
{

Espacio de Código 3.34 Programa Principal del Ejercicio 8

226
//Encender el módulo ADC
init_ADC();
//Esperar a que la configuración termine
while (!ADCON1bits.DONE);
//Cambia a Ascii el valor del ADC
cambio_ascii(ADCBUF0);
//Enviar por la UART el dígito miles
U1TXREG=miles;
//Esperar a que termine la transmisión
while(U1STAbits.TRMT==0);
//Enviar por la UART el dígito centenas
U1TXREG=centena;
//Esperar a que la transmisión termine
while(U1STAbits.TRMT==0);
//Enviar por la UART el dígito decenas
U1TXREG=decena;
while(U1STAbits.TRMT==0);
//Enviar por la UART el dígito miles
U1TXREG=unidad;
while(U1STAbits.TRMT==0);
//Enviar por la UART una coma para separar la próxima cantidad
U1TXREG = 0x2C;
while (U1STAbits.TRMT == 0){}
//Iniciar el muestreo
ADCON1bits.SAMP = 1;
//Retardo de conversión
//Simula la regulación de fs
//Cálculo para f = 50 [Hz]
__delay32(18425);
}
}
//Inicialización de la UART
void Inicializar_UART(void)
{
//Velocidad de transmisión

Espacio de Código 3.34 Programa Principal del Ejercicio 8 (continuación)

227
U1BRG = VELOCIDAD;
//Deshabilitar opción de loopback
U1MODEbits.LPBACK = 0;
U1STAbits.UTXBRK = 0;
//Continuar la operación en modo IDLE
U1MODEbits.USIDL = 0;
//8 bits de datos, sin paridad
U1MODEbits.PDSEL = 0b00;
//1 bit de parada
U1MODEbits.STSEL = 0;
//Usar los pines de transmisión en modo normal
U1MODEbits.ALTIO = 0;
//Habilitar la UART
U1MODEbits.UARTEN = 1;
//Habilitar la transmisión
U1STAbits.UTXEN = 1;
}
//Cambio a ASCII
void cambio_ascii(int valor)
{
//Variables Usadas
//La conversión se realiza por divisiones sucesivas
//Se extrae correspondientemente el dígito de miles
//decenas, centenas, y unidades, las mismas
//serán transmitidas posteriormente por la UART
Into b=0, c=0, d=0, e=0, f=0, g=0, h=0, i=0;
b=valor/10000; c=valor%10000; decimal=b+48;
d=c/1000; e=c%1000; miles=d+48; f=e/100;
g=e%100; centena=f+48; h=g/10; i=g%10;
Decena=h+48; unidad=i+48;
}
//INICIALIZACIÓN DEL ADC
void init_ADC( void )
{

Espacio de Código 3.34 Programa Principal del Ejercicio 8 (continuación)

228
//Configura todos los pines del puerto B C30 como digitales
//solo RB0 como analógico
//Ahí se conectará la señal de entrada
ADPCFG = 0xFFFE;
ADCON1 = 0x00E0;
ADCHS = 0x0000;
ADCSSL = 0;
ADCON3 = 0x1F3F;
ADCON2 = 0;
ADCON1bits.ADON = 1;
ADCON1bits.SAMP = 1;
}

Espacio de Código 3.34 Programa Principal del Ejercicio 8 (continuación)

3.3.7.3.3 Compilación y Depuración de código

Para la realización de la compilación y depuración del código, se realiza el


procedimiento utilizado en los ejercicios anteriores y se tiene como resultado la
ventana de la figura 3.63.

Figura 3.63 Compilación Ejercicio No. 8

229
3.3.7.3.4 Implementación en Hardware

Para realizar las pruebas del ejercicio, en primera instancia se realiza el envío
de los datos obtenidos por el módulo ADC, estos datos pueden ser
visualizados en el hyperterminal del computador tal como se muestra en la
figura 3.64.

Figura 3.64 Datos recibidos por el hyperterminal enviados desde el módulo


ADC

Para reconstruir la señal en el MATLAB primero tenemos que llamar al script


que contiene el código para realizar dicha operación, tal como se muestra en la
figura 3.65.

230
Figura 3.65 Ventana del MATLAB para invocar al script

Luego de invocado el script, éste nos genera una figura la cual contiene la
forma de onda reconstruida con sus niveles de voltaje, como nos indica la
figura 3.66.
Señal Senoidal de 50[Hz]
4

3.5

2.5
Voltaje [s]

1.5

0.5

0
0 0.002 0.004 0.006 0.008 0.01 0.012 0.014 0.016 0.018
Tiempo [s]

Figura 3.66 Forma de onda reconstruida mostrando los niveles de voltaje

231
Luego de tener está onda, solamente queda interpolar los puntos de la onda,
teniendo así una onda más definida y similar a la forma de onda de entrada
capturada en el osciloscopio. Estas formas de onda se las puede observar en
las figuras 3.67 y 3.68 respectivamente.
Señal Senoidal de 50[Hz]
4

3.5

2.5
Voltaje [s]

1.5

0.5

0
0 0.002 0.004 0.006 0.008 0.01 0.012 0.014 0.016 0.018
Tiempo [s]

Figura 3.67 Forma de onda de salida después de la interpolación

Figura 3.68 Señal de entrada capturada en el osciloscopio

232
Teniendo en cuenta los resultados obtenidos en los ejercicios 6, 7 y 8, nace la
pregunta: ¿hasta qué frecuencia puede muestrear el conversor AD del dspic
sin problemas?. Teóricamente se tiene los siguientes límites, de hasta 500
ksps a 5V y 100 ksps a 2.7 V, por lo general se trabajará a 5V es decir el límite
teórico es de 250kHz como máxima frecuencia de muestreo.

233

También podría gustarte