Escolar Documentos
Profissional Documentos
Cultura Documentos
Vamos a fijar como frecuencia de trabajo los 48 MHz mximos que soporta el microcontrolador, para ello vamos a utilizar como fuente un cristal externo de 12 MHz. Para lograr los 48MHz es necesario habilitar el PLL, esto lo hacemos mediante los bits FOSC3:FOSC0. Para un cristal de 12 MHz se debe colocar 111x = HS oscillator, PLL enabled (HSPLL) y revisando la documentacin que provee XC8 (doc/pic18_chipinfo.html) se debe colocar FOSC=HSPLL_HS. Si observamos la figura anterior, al habilitar el PLL la frecuencia de entrada del mismo debe ser 4 MHz, y para ello se provee de un divisor de frecuencia controlado por PLLDIV, en este caso los 12 MHz los dividimos por 3, por lo tanto debemos hacer PLLDIV=3. La frecuencia de salida del PLL es de 96 MHz, los cuales sirven de fuente de clock para el mdulo USB y tambin para el microcontrolador. Pero
para el microcontrolador los 96 MHz los podemos dividir en 2, 3, 4 o 6! O sea, podemos obtener gran variedad de frecuencias. Como nos establecimos como meta obtener 48 MHz debemos hacer CPUDIV=OSC1_PLL2. En resumen en los bit de configuraciones establecemos: #pragma config FOSC=HSPLL_HS, PLLDIV=3, CPUDIV=OSC1_PLL2 Estas configuraciones seran las principales para establecer el reloj de nuestro microcontrolador pero existen dos fusibles de configuracin que otorgan otras opciones de trabajo. Tenemos IESO, que permite cambiar la fuente de clock cuando el microcontrolador est en funcionamiento y FCMEN que en caso de fallar la fuente de reloj principal realiza el cambio a la fuente de reloj interna INTRC. Dentro del datasheet hay secciones donde podemos encontrar ms detalles para el uso de estos modos, aqu solo los estableceremos como OFF: #pragma config IESO=OFF, FCMEN=OFF Como comentamos anteriormente existen otros fusibles de configuracin que dependen del microcontrolador utilizado, aqu vamos a establecerlos de la siguiente manera, los detalles los podemos encontrar en la seccin Special Feactures of the CPU/Configuration Bits. #pragma config PWRT=OFF, BOR=OFF, BORV=3, VREGEN=OFF, WDT=OFF #pragma config MCLRE=ON, XINST=OFF Hay varios ms, pero si no se configuran quedan como vienen por defecto. En MPLAB X podemos ver la configuracin en Windows/PIC Memory Views/Configuration Bit. Como primer ejemplo vamos hacer titilar un led, este ejemplo es el Hola Mundo en los microcontroladores. Para ello vamos a necesitar una funcin que cree una demora y para ello XC8 dispone de __delay_us() y __delay_ms(), para integrarlas debemos llamar a xc.h pero adems previamente definir el valor de _XTAL_FREQ. A tener en cuenta, tanto __delay_ms como __delay_us utilizan la funcin _delay(), y esta solo soporta hasta 197120 ciclos, o sea que para 48 MHz la mxima demora posible es 16.42 ms. Para el control del led debemos establecer el pin a utilizar como salida y luego escribir en el pin el valor que queramos establecer (0 o 1 lgico), para ello tenemos los registros TRIS y los registros LAT. En caso de necesitar leer el valor que tiene un pin se utilizan los registros PORT. Esto es una mejora introducida a partir de la familia PIC18, debido a que en familias anteriores para hacer operaciones sucesivas en puertos se necesitaba agregar un nop entre ellas. Si por ejemplo queremos controlar nuestro led mediante el pin B0 debemos trabajar con TRISB y LATB, XC8 para facilitarnos el desarrollo tiene definido el bit 0 de TRISB como TRISB0 o como tambin es compatible con C18 se puede acceder mediante TRISBbits.TRISB0. Los mismo para el bit 0 de LATB, LATB0 o LATBbits.LATB0. Esto lo podemos ver en el archivo cabecera pic18F4450.h que se encuentra en xc8\v1.00\include. Entonces el cdigo ejemplo seria de la siguiente forma:
/* * File: main.c * Author: Suky */ #define _XTAL_FREQ 48000000 #include <xc.h> #pragma config FOSC=HSPLL_HS, PLLDIV=3, CPUDIV=OSC1_PLL2 #pragma config IESO=OFF, FCMEN=OFF #pragma config PWRT=OFF, BOR=OFF, BORV=3, VREGEN=OFF, WDT=OFF #pragma config MCLRE=ON, XINST=OFF void main(void) { TRISB0=0; // Lo establecemos como salida while(TRUE){ // _delay(x) 197120 cycles max LATB0=0; // Apagamos led __delay_ms(10); LATB0=1; // Encendemos led __delay_ms(10); } } Nota: Tener en cuenta que la demora generada es solo de 10ms, en simulacin se podr visualizar el titilar del led pero en una implementacin real no, pronto lo mejoraremos Pero hagamos uso de los macros!!! El ejemplo quedara as: /* * File: main.c * Author: Suky */ #define _XTAL_FREQ 48000000 #include <xc.h> #pragma config FOSC=HSPLL_HS, PLLDIV=3, CPUDIV=OSC1_PLL2 #pragma config IESO=OFF, FCMEN=OFF #pragma config PWRT=OFF, BOR=OFF, BORV=3, VREGEN=OFF, WDT=OFF #pragma config MCLRE=ON, XINST=OFF #define PIN_DIR_LED TRISB0 #define PIN_LED LATB0
#define OUTPUT 0 #define INPUT 1 #define ON 1 #define OFF 0 void main(void) { PIN_DIR_LED=OUTPUT; while(TRUE){ // _delay(x) 197120 cycles max PIN_LED=OFF; __delay_ms(10); PIN_LED=ON; __delay_ms(10); } } Se dan cuenta que si quiero cambiar de pin para controlar el Led se hace mucho ms sencillo? Y eso que solo es un ejemplo muy sencillo! En este ejemplo solo implementamos la funcin principal (void main(void)) que debe estar si o si en nuestro proyecto, pues el compilador tiene una funcin que es llamada al ocurrir un reset (vector 000) la cual inicializa el puntero de la pila (Stack en ingles), las variables inicializadas, etc. y luego llama a la funcin main(). Esta funcin puede contener el cdigo para inicializar el hardware de la forma que nosotros queramos, o llamar a funciones adicionales que hagan esta tarea y luego generalmente tiene el bucle infinito. Este bucle debe estar si o si, sino al terminar de ejecutar las instrucciones el microcontrolador se resetea. Dentro del bucle tendremos lo que queremos que el microcontrolador ejecute peridicamente hasta ser reseteado. En C un bucle infinito se puede hacer de varias formas, aqu usamos la sentencia while: while(Condicion){Sentencias} Esta sentencia o estructura de control de C permite ejecutar las sentencias que contiene de forma cclica mientras la condicin sea verdadera. Tener en cuenta que primero se pregunta si la condicin es cierta y luego ejecuta las sentencias. Como la condicin en nuestro caso es TRUE (1), se ejecuta de forma infinita. Esto representado en un diagrama de flujo sera la siguiente:
Otra forma de implementarlo es usando la sentencia do-while: do{Sentencias}while(Condicion); En este caso las sentencias se ejecutan primero y luego se pregunta la condicin, por lo que las sentencias se ejecutan mnimo una vez. El hardware mnimo para poder implementar el ejemplo seria el siguiente: