Ejercicios Dspic
Ejercicios Dspic
Ejercicios Dspic
87
CAPÍTULO 3
3.1 INTRODUCCIÓN
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.
90
3.2.4 IMPLEMENTACIÓN EN HARDWARE
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.
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.
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.
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.
93
Figura 3.3 Circuito para realizar las pruebas del Ejercicio No. 1
INICIO
CONFIGURACIÓN DEL
DISPOSITIVO
CONFIGURACIÓN DEL
PUERTO B Y F
MANTENER EL
WHILE( _PORTF1) NO
ESTADO DE RB1
BUCLE INFINITO SI
CAMBIAR EL ESTADO DE
RB1
FIN DE PROCESO
94
3.3.1.2.2 Elaboración de Código
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>
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.
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;
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
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.
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
102
Figura 3.8 Programación del ejercicio con el Pickit 2
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
104
El MPLAB indica si la programación se realizó correctamente, tal como indica
la figura 3.12.
106
Figura 3.15 Archivo a grabar en el dspic
107
Figura 3.16 Probando el ejercicio en el equipo de entrenamiento Easydspic 4
3.3.2.1 El Oscilador
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.
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.
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
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.
Voltaje de alimentación.
Temperatura de funcionamiento.
110
Figura 3.17 Diagrama de bloques del Sistema Oscilador32
Un Postscaler Programable.
32
www.Microchip.com
111
Un monitor de seguridad ante fallas de reloj (FSCM).
33
www.Microchip.com
34
www.Microchip.com
112
3.3.2.6 Ejercicio No. 2: Encender LEDS con Retardos Programados.
113
Figura 3.19 Circuito para realizar las pruebas del Ejercicio No. 2
114
3.3.2.6.2 Elaboración de Código
/* LIBRERÍAS */
//Incluir la librería del dspic30F4013
#include <p30f4013.h>
//Incluye la librería que contiene la función delay32();
#include <libpic30.h>
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.
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
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
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:
Esta frecuencia será un dato útil para poder comprobar que funcione
correctamente el ejercicio propuesto con ayuda del osciloscopio.
119
3.3.2.6.3 Compilación y Depuración de Código
Una vez aquí se tiene listo ya el archivo .hex para realizar las pruebas y
análisis de los resultados.
120
Figura 3.21 Circuito probado en el entrenador Easydspic4
121
La señal de salida se la muestra en el osciloscopio tal como se indica en la
figura 3.23.
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.
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
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.
Estos niveles son asignados por el usuario, teniendo en cuenta el nivel 1 (nivel
más bajo) y nivel 7 (nivel más alto).
125
3.3.3.2 Tiempo de Proceso de las Interrupciones
37
www.Microchip.com
126
3.3.3.2.2 Retorno de la interrupció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.
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.
128
3.3.3.4 Ejercicio No. 3 Manejo de Interrupciones Externas
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
APAGAR EL PUERTO B EN
RB0
FIN DE PROCESO
130
INT0
LIMPIAR INT0IF
WHILE(1)
BUCLE INFINITO
ENCENDER PUERTO B EN
RB0
APAGAR EL PUERTO B EN
RB0
FIN DE INTERRUPCIÓN
(RETFIE)
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.
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
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;
}
}
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;
}
}
.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
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
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
137
;Inicio de interrupción
INICIAINT0:
;Configuración de interrupción externa INT0
MOV #0x0001, W0
MOV W0, IEC0
RETURN
;EOF
.end
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;
}
}
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;
}
}
140
Figura 3.27 Compilación Ejercicio No. 3
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.
142
Figura 3.30 Mapa del espacio de la memoria de datos39
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.
144
3.3.4.2 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
41
www.Microchip.com
147
3.3.4.2.3 La instrucción de tabla
148
2. Programación serie en circuito ICSP, la misma utiliza una interfaz SPI y
software integral tipo bootloader.
149
3.3.4.3.1 Borrado y escritura de una palabra en la EEPROM
150
1. Leer una línea de la EEPROM de datos y almacenarlos en la RAM
como “imagen”.
151
3.3.4.3.3 Lectura de la EEPROM
3.3.4.4.1 Descripción
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.
Señal de lectura/escritura:
R/W
5 R/W=0 Escritura (Write)
44
http://www.scribd.com/doc/6660774/LCD-2x16
153
3.3.4.5 Ejercicio No. 4 Manejo de la Memoria EEPROM
transf_lcd.h
Donde los pines de control y datos del LCD quedan definidos como se muestra
en la tabla 3.5.
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.
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;
}
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.
156
En la figura 3.35 se muestra el ejemplo funcionando.
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
DECLARACIÓN DE SUBFUNCIONES DE
TRANSFORMACIÓN A ASCII Y DEL LCD
GUARDAR DATOS EN LA EEPROM CON _EEDATO()
WHILE(1)
BUCLE INFINITO
FIN DE PROCESO
158
El contenido de la función está descrita en el espacio de código 3.19.
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;
}
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;
}
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
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);
Comando_LCD(0xC0);
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;
}
165
3.3.4.5.3 Compilación y Depuración de Código
166
Figura 3.37 Circuito del ejercicio 4 armado y probado en el protoboard
167
Además, cada uno de los temporizadores tiene asociado una serie de bits para
realizar el control de las interrupciónes.
3.3.5.1.1.1 Tipo A
168
Figura 3.38 Estructura interna del temporizador tipo A45
3.3.5.1.1.2 Tipo B
45
www.Microchip.com
169
Figura 3.39 Estructura interna del temporizador tipo B46
Los temporizadores Tipo C30 están asociados con los TIMER3 y TIMER5 y
poseen ciertas características las cuales son:
46
www.Microchip.com
170
Figura 3.40 Estructura interna del temporizador Tipo C3047
Temporizador sincrónico.
Contador sincrónico.
Contador asincrónico.
47
www.Microchip.com
171
3.3.5.1.2.1 Modo temporizador 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
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.
TON = 0L
174
3.3.5.1.4 Interrupciones de los temporizadores
175
Figura 3.42 Interrupción por coincidencia de periodos49
3.3.5.1.5.1 Escritura
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.
Figura 3.43 Circuito para realizar las pruebas del ejercicio No. 5
177
3.3.5.2.1 Diagrama de flujo
INICIO
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
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.
178
A continuación se debe configurar la forma de funcionamiento del TIMER, eso
se hace con el espacio de código 3.22.
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;
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();
}
180
Figura 3.44 Compilación Ejercicio 5
182
Figura 3.47 Señal Muestreada
FS ≥ 2 x AB
3.3.6.1.1 El Aliasing
183
Figura 3.48 Representación espectral del Aliasing
Como conclusión para evitar el aliasing se debe elegir una correcta frecuencia
de muestreo.
3.3.6.1.2 Cuantificación
184
Figura 3.49 Señal Cuantificada
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.
Resolución de 10 bits.
dV M ( ADC )
dt 2n tc
En donde:
M: margen de tensión del ADC.
n: número de bits (resolución).
tC: tiempo de conversión.
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>.
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
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
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:
Entonces:
191
Este valor del TAD cumple con el mínimo necesario para el correcto
funcionamiento del conversor AD.
192
3.3.6.3 Ejercicio No. 6 Utilización del ADC
193
3.3.6.3.1 Diagrama de flujo
INICIO
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
RETARDO DE LECTURA
FIN DE PROCESO
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;
}
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.
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) = '.';
}
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.
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';
}
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);
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
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
199
*(puntero_ascii + 3) = '.';
}
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';
}
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);
203
Figura 3.52 Compilación Ejercicio No. 6
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.
205
El módulo UART está compuesto por 3 bloques los cuales son:
Generador de baudios.
Transmisor asincrónico.
Receptor asincrónico.
51
www.Microchip.com
206
Ecuación 3.6 Detalle de la frecuencia en baudios52
52
www.Microchip.com
207
Figura 3.55 Diagrama de bloques del transmisor asincrónico del módulo
UART53
53
www.Microchip.com
208
4. Se habilita la recepción.
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
210
3.3.7.2.1 Diagrama de flujo
INICIO
WHILE(1)
BUCLE INFINITO
FIN DE PROCESO
211
3.3.7.2.2 Elaboración de código
#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
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];
}
}
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;
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;
//Habilitar la uart
OpenUART1(U1MODEvalue, U1STAvalue, baudvalue);
//Entra en el lazo infinito
while(1)
{
215
//Apuntar a la primera posición
TXPtr = &hello[0];
//Esperar hasta que la transmisión se complete
while(BusyUART1());
}
return 0;
}
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;
217
Figura 3.58 Compilación Ejercicio 7
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
219
Figura 3.61 Resultado del Ejercicio 7 mostrado en el hyperterminal del
computador
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
221
INICIO
WHILE(1)
INICIALIZAR LA UART
INICIALIZAR EL ADC
BUCLE INFINITO
LEER EL ADCBUF0 Y TRANSFORMARLO EN ASCII
FIN DE PROCESO
222
De donde la FCY es:
Entonces:
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.
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;
}
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;
}
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)
{
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
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 )
{
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;
}
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.
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]
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]
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