Tutorial MPLAB C18 Desde 0.

(1/5) > >>

Suky:

MPLAB C18.

Versión en pdf


Entorno de programación MPLAB IDE.
Ensamblador, enlazador, gestión de proyectos, depurador y simulador. La interfaz gráfica del usuario MPLAB IDE sirve como un único entorno para escribir, compilar y depurar código para aplicaciones embebidas. Permite manejar la mayoría de los detalles del compilador, ensamblador y enlazador, quedando la tarea de escribir y depurar la aplicación como foco principal del programador (usuario)Gratuito, se puede descargar de www.microchip.com
Compilador MPLAB C18
MPLAB C18 es un compilador cruzado que se corre en un PC y produce código que puede ser ejecutado por la familia de microcontroladores de Microchip PIC18XXXX. Al igual que un ensamblador, el compilador traduce las declaraciones humanas en unos y ceros para ser ejecutados por el microcontrolador.Sigue la norma ANSI C, salvo en particularidades de los microcontroladoresLibrerías para comunicaciones SPI, I2C, UART, USART, generación PWM, cadena de caracteres y funciones matemáticas de coma flotante Maneja números reales de 32 bits (float y double)Versión demo de 60 días, descargable de www.microchip.com

Indice
InstalaciónCreación de un proyecto1º Ejemplo. Control de un led mediante un pulsador. (Definición de operadores, estructuras, y control de bits de registros)2º Ejemplo. Led titilando (Definición de Variables, librería de Demoras)3º Ejemplo. Led secuenciales.4º Ejemplo. Control Display 7 Segmentos (Definición de Arreglos de variables)5º Ejemplo. Control de Varios Display de 7 Segmentos por multiplexión (Declaración y definicion de funciones)6º Ejemplo. Control LCD7º Ejemplo. Conversión analógica/digital.Manejo de interrupciones.8º Ejemplo. Comunicación Serial RS232Modificación de una librería, Cambiando el puerto de Control de LCDControl de Teclado Matricial, Interrupción por RB4-RB7Creación de una librería, DS1302Reloj/Calendario con DS1302 y LCD, Interrupción por desbordamiento Timer0Comunicación I2C, primer ejemplo Lectura/escritura AleatoriasComunicación I2C, segundo ejemplo Lectura/Escritura secuencialesManejo de punteros. Punteros y Arreglos. Punteros y FuncionesFlex_lcd más utilización de printf
[#] Por aquí pueden encontrar un gran aporte de Jukinch, otorgando ejemplos probados de C18 implementados en la Multiboard Pic Trainer 2.   :gracias:





Suky:
Instalación

Se debe bajar directamente desde Microchip, hay disponible una versión gratuita para estudiantes que es un demo de 60 días. También para poder descargarlo es necesario registrarse.
Una vez descargado ejecutar el instalador MPLAB-C18-Evaluation-v3_30 versión actualmente disponible.
Para a instalación seguimos los siguientes pasos:



















Suky:
Creación de un nuevo proyecto.

Project -> New
Nos aparecerá una pantalla donde le indicamos el nombre de nuestro proyecto y la carpeta donde será guardado.


Pasamos a configurar el dispositivo con el cual trabajaremos: Configure->Select Device


Seleccionamos el compilador: Project->Select Lenguaje Toolsuite y nos aseguramos que todas las direcciones son correctas.


Configuramos los subdirectorios de trabajo: Project->Build options -> Project
Seleccionamos ubicación de ficheros de declaraciones, bibliotecas y script de enlazado.
Show directories for:
Include Search PathLibrary Search PathLinker-Script Search Path


Nota: Según la versión también se debe agregar al proyecto el archivo (PIC18F utilizado).lkr ubicado en MCC18/lkr, sino produce error de compilación.


Luego vamos a New File y lo guardamos en nuestra carpeta eligiendo extensión .c agregándolo a nuestro proyecto.  ;)



Con todo esto configurado ya podemos empezar a desarrollar nuestro código.  :rolleyes2:

Suky:
Introducción al C18:

La idea es ir adquiriendo conceptos a medida que los utilicemos en el desarrollo de los ejemplos, de esta manera lo que se presenta teóricamente lo asociamos inmediatamente con la práctica. Aunque claro está que el lenguaje es muy amplio y no se pueden hacer ejemplos de cada concepto.

En el desarrollo de este tutorial se utilizará el microcontrolador PIC18F2550, y como en todo proyecto siempre se debe tener a mano el datasheet de los dispositivos utilizados, para la correcta interpretación y aplicación de las configuraciones realizadas.

Creando el código:

Lo que se presenta aquí es la estructura general de un archivo fuente de C, en donde como primera medida se incluyen  las librerías, colección de rutinas, que se van a utilizar en el proyecto. Tenemos las librerías estándar de Ansi C que incluye rutinas para manejo de cadenas de texto y operaciones con datos comunes como funciones matemáticas, librerías especificas del microcontrolador a utilizar (p18Fxxxx.h) la cual tiene estructuras de  los registros del microcontrolador para control de sus bits, librerías para control de periféricos del microcontrolador (UART, I2C, SPI, ect) y las librerías propias creadas por el usuario dedicadas al control de un dispositivo externo o una tarea en común.
La librería que siempre incluiremos en el archivo principal será la del PIC  a usar:
Código: (c)

#include <p18F2550.h>

Luego viene la configuración de los fuses del microcontrolador. Ósea configuración de oscilador, watch-dog, Brown-out reset, power-on reset, protección del código, etc. Esto depende del microcontrolador que se utilice:
La sintaxis seria: #pragma config Nombre del fuse=estado.
Para esto es muy útil la ayuda que trae C18, recomiendo mirarla:
C:\MCC18\doc\ hlpPIC18ConfigSet

Definición de variables globales, son las que se utilizaran en el programa principal y funciones del proyecto.
Código: (c)

int variableA, variableB
Ahora viene el código de nuestro programa:
Código: (c)

main{

}

El proceso de compilación

El texto fuente es compilado en bloques de código de programa y datos que luego son enlazados (linked) con otros bloques de código y datos, y colocados en las regiones de memoria del microcontrolador PIC18XXXX seleccionado. Este proceso se llama generación (build) y se suele llevar a cabo muchas veces en el desarrollo de programas en el proceso de probado y depurado. También tenemos la posibilidad de utilizar make que solo compila los archivos fuentes que han sido modificados desde la última vez agilizando el proceso.

Flujo de la generación del hex

En la siguiente imagen se tiene un ejemplo de los pasos que lleva un determinado proyecto, donde tenemos 2 archivos fuentes en c (*.c), 1 archivo en assembler (*.asm) y un archivo precompilado (*.o).


Los archivos fuentes *.c son compilados por MPLAB C y el archivo *.asm es ensamblado por MPASM generando los archivos intermedios llamados archivos objetos. Estos archivos junto al *.lkr del microcontrolador son tomados por el enlazador para generar el *.hex que será utilizado para la grabación en la memoria de programa del microcontrolador. Cabe la posibilidad de agrupar archivos objetos para crear bibliotecas (*.lib)
El archivo *lkr contiene información de la estructura y capacidades del microcontrolador con el cual se está trabajando, sirve como plantilla para el enlazador para organizar el código de programa y datos generados en el proceso de compilación.

Ahora ya tenemos una idea general de como es la estructura de un programa desarrollado en C y cual es el proceso que sigue en la generación del *.hex necesario para embeber a nuestro microcontrolador. Seguiremos con el estudio de las directivas utilizadas en C para el desarrollo de programas simples y más adelante encararemos el tema de las librerias, su modificación, creación, ect.


Primer ejemplo, control de leds con un pulsador.
Para este sencillo ejemplo vamos a necesitar definir operadores y estructuras de control:

Operadores:
Aquí definiremos todos los operadores utilizados por C18.-
Operadores de Comparación:
Estos operadores se encargan de comparar dos condiciones de una expresión:


Operadores aritméticos:
Se utilizan para realizar cálculos matemáticos:


Operadores lógicos:
Son los encargados de producir resultados lógicos del tipo TRUE o FALSE


Operadores bitwise:
Son para modificar los bits de una variable:


Jukinch, usuario del foro y amigo ha realizado la siguiente contribución para mayor entendimiento de los operados bitwise:

El operador AND "&" compara dos bits; si los dos son 1 el resultado es 1, en otro caso el resultado será 0.
Ejemplo:

        c1 = 0x45      --> 01000101
        c2 = 0x71      --> 01110001
        ---------------------------
        c1 & c2 = 0x41 --> 01000001
-----------------------------------------------------------------------------------------------------------------------------
El operador OR  "|" compara dos bits; si cualquiera de los dos bits es 1, entonces el resultado es 1; en otro caso será 0. Ejemplo:

        i1 = 0x47      --> 01000111
        i2 = 0x53      --> 01010011
        ---------------------------
        i1 | i2 = 0x57 --> 01010111

-----------------------------------------------------------------------------------------------------------------------------
El operador exclusivo (XOR) "^", da por resultado uno cuando los dos operandos tienen distinto valor.

Cuando los dos operandos son distintos da 1.-
ej: 1 y 0    =1
    0 y 1    =1

Cuando los dos operandos son iguales da 0.-
    0 y 0    =0
    1 y 1    =0

 Ejemplo:
        i1 = 0x47      --> 01000111
        i2 = 0x53      --> 01010011
        ---------------------------
        i1 ^ i2 = 0x14 --> 00010100
-----------------------------------------------------------------------------------------------------------------------------
El operador de complemento a 1 "~" cambia cada dígito del operando por su opuesto:

Si el bit es 1 se cambia por 0 y viceversa

        c = 0x45  --> 01000101
        ----------------------
        ~c = 0xBA --> 10111010

-----------------------------------------------------------------------------------------------------------------------------
Los operadores de desplazamiento a nivel de bit "<<" y ">>" Desplazan a la izquierda o a la derecha un número especificado de bits.
En un desplazamiento a la izquierda los bits que sobran por el lado izquierdo se descartan y se rellenan los nuevos espacios con ceros. De manera análoga pasa con los desplazamientos a la derecha. Veamos un ejemplo:

    c = 0x1C    00011100

c << 1    c = 0x38    00111000
c >> 2    c = 0x07    00000111

Como en binario se trabaja en base dos cada posición de desplazamiento implica dividir o multiplicar por 2

>> divide por 2.

<< multiplica por 2

   c = 0x1C    00011100

c << 1    c = 0x38    00111000 multiplica por 2
c >> 2    c = 0x07    00000111 divide 2 veces por 2 (divide por 4)

-----------------------------------------------------------------------------------------------------------------------------
Ejemplos de precedencia de los operandos:

puerto &= ~(1<<6) primero se desplaza un 1 hacia la izquierda 6 posiciones y luego el operando ~ lo convierte en cero. Es resultado se combina mediante el operando & con el contenido del byte del puerto. Aplicándose así una máscara que pone en cero el bit 6 dejando pasar los demás bits. De esta manera se logra un equivalente en assembler de bitclr en la posición del bit 6.

#define bit_set(bit,puerto) (puerto |= 1<<bit)
#define bit_clr(bit,puerto) (puerto &= ~(1<<bit))

// ejemplo en código
bit_set(0,PORTB); // pone a 1 el bit 0 del puerto B.
bit_clr(0,PORTB); // pone a 0 el bit 0 del puerto B.
-----------------------------------------------------------------------------------------------------------------------------
Código binario en complemento a dos:

En este sistema, los números positivos se representan reservando el bit más significativo (que debe ser cero) para el signo. Para los números negativos, se utiliza un sistema distinto, denominado complemento a dos, en el que se cambian los bits que serían 0 por 1 y viceversa, y al resultado se le suma uno.
Este sistema sigue reservando el bit más significativo para el signo, que sigue siendo 1 en los negativos. Por ejemplo, la representación de 33 y -33 sería:

    +33    0010 0001
         se invierte todo
    -33    1101 1110
         se le suma 1
         + 0000 0001
          resultado
           1101 1111   numero -33 en complemento a dos

El hardware necesario para implementar operaciones aritméticas con números representados de este modo es mucho más sencillo que el del complemento a uno, por lo que es el sistema más ampliamente utilizado.
-----------------------------------------------------------------------------------------------------------------------------
Muchísimas gracias! Y esto queda abierto a que si tienen ejemplos que ayudan a entender otros operadores, o estructuras de control, etc., estamos abierto a sus recomendaciones  ;)

Estructuras:

Estructura if:
Esta estructura se utiliza para ejecutar instrucciones en forma condicional, de acuerdo con la evaluación de la expresión. Seria si una condición es dada entonces acción.
Código: (c)

if(condicion){
//Accion
}

Estructura if-else
En este caso se agrega la instrucción else. Ahora se evalúa una condición original, si es verdadera, se ejecuta y sino no lo es, se ejecuta el bloque debajo de else.
Código: (c)

if(condicion){
//Acción
else{
//Accion
}
}

Estructura while
Ejecuta un conjunto de instrucciones mientras una condición sea verdadera. La principal característica de esta estructura es que, antes de comenzar el bucle, verifica la condición, por lo que es posible que el bucle no llegue a ejecutarse.
Código: (c)

while(condicion){
// Sentencias
}

Estructura do-while
Es parecida a un while solo que la condición se evalúa al final, por lo que el bucle se ejecutara por lo menos una vez.
Código: (c)

do {
// Sentencias
} while (condicion);

Estructura For:
Esta estructura se usa para ejecutar un bloque de código cierto número de veces. Posee un valor de inicio, un valor final y un valor de incremento.
 Código: (c)

for(valor inicial; valor final; valor de incremento ){
//Sentencias
}

Mas adelante explicaremos la estructura  switch.


Accediendo a los bits de un registro:

Para acceder individualmente a los bits de un registro se escribe la siguiente sentencia:
Registrobits.bit
Ejemplo:
Código: (c)

PORTBbits.RB0


Objetivo:Encender 4 leds del puerto B mientras se mantenga accionado el pulsador.

Hardware


Código:
Código: (c)

#include <p18f2550.h>

#pragma config FOSC = XT_XT,FCMEN = OFF,IESO = OFF, CPUDIV = OSC1_PLL2
#pragma config PWRT = ON,BOR = OFF,BORV = 0
#pragma config WDT = OFF,WDTPS = 32768
#pragma config MCLRE = ON,LPT1OSC = OFF,PBADEN = OFF,CCP2MX = OFF
#pragma config STVREN = OFF,LVP = OFF,XINST = OFF,DEBUG = OFF
#pragma config CP0 = ON,CP1 = ON,CP2 = ON
#pragma config CPB = ON,CPD = ON
#pragma config WRT0 = ON,WRT1 = ON,WRT2 = ON
#pragma config WRTB = ON,WRTC = ON,WRTD = ON
#pragma config EBTR0 = ON,EBTR1 = ON,EBTR2 = ON
#pragma config EBTRB = ON


void main(void){
ADCON1=0x0F;//Todos entrada/salida digitales.-
TRISA=0xFF; //Todos como entrada.-
TRISB=0X00; //Todos como salida.-

PORTB=0x00; //Leds apagados.-
while(1){
        if(PORTAbits.RA0==1){ // testeamos RB0.
                LATB=0x00; // Si esta en 1 Apagamos leds
        }
        else{
                LATB=0x0F; // Si esta en 0 Encendemos leds.
        }
}
}

Suky:
Variables
Una variable es la asignación de un nombre a un espacio determinado en la memoria, en donde el espacio dependerá del tipo de variable. C18 define los siguientes tipos:


Según donde estén declaradas, las variables pueden ser globales (declaradas fuera de todo procedimiento o función) o locales (declaradas dentro de un procedimiento o función). Las primeras serán accesibles desde todo el código fuente y las segundas sólo en la función donde estén definidas.

Modificadores de las variables:
Mplab C18 utiliza los modificadores establecidos por ANSI:

Auto: las variables declaradas fuera de las funciones son globales y las declaradas en la función son locales. Si no se inicializan toman un valor indefinido.
Static: variables locales a una función, y sirven para retener el valor de la variable en llamadas sucesivas a dicha función. El espacio de memoria es reservado únicamente para dicha función.
Extern: La variable declarada pertenece a otro módulo, por lo que no es necesario reservar memoria para ella.
Const: El contenido de la variable es fijo.
Volatile: el contenido de la variable puede cambiar. En interrupciones se debe utilizar este tipo de datos. En la siguiente página pueden encontrar una explicación muy acertada de sus uso. (Información otorgado por Jukinch)
Register: La variable declarada debe guardarse en un registro del microcontrolador.
Overlay: Se aplica a variables locales, hace un almacenamiento estático y las inicializa en cada llamada.
Ram: La variable se sitúa en la memoria de datos.
Rom: la variable se sitúa en la memoria del programa. Por lo general se usa para cadena de caracteres contantes.

Especificación de banco de memoria de datos:
Far: La variable puede ir en cualquier banco.
Near: la variable tiene que estar en el banco de acceso.
Para las variables guardadas en la memoria de programa el acceso no es tan inmediato, sino que se realiza mediante las operaciones Table Reads o Table Writes, los cuales mueven los datos entre el espacio de memoria RAM y de Programa. Cuando se trabaja una variable NEAR solo se necesita 16-bits para su direccionamiento, en cambio para una variable FAR (Que puede estar en cualquier banco) se necesitan 24-bits para su direcionamiento. Esto último se podrá observas más claro cuando se trate punteros.

Demoras:

Para utilizar demoras en nuestro código debemos incluir la librería delays.h. En ella tenemos 4 funciones:
Delay10TCYx(i)      -> 10.Tcy.i
Delay100TCYx(i)   -> 100.Tcy.i
Delay1KTCYx(i)      -> 1000.Tcy.i
Delay10KTCYx(i)   -> 10000.Tcy.i

Donde i puede tomar valores entre 0 y 255.


Ejemplo: Leds titilando.

Objetivo: Hacer titilar 10 veces los leds del puerto B al accionar el pulsador.

Hardware: Idem anterior.

Código:
Código: (c)

#include <p18f2550.h>
#include <delays.h>

#pragma config FOSC = XT_XT,FCMEN = OFF,IESO = OFF, CPUDIV = OSC1_PLL2
#pragma config PWRT = ON,BOR = OFF,BORV = 0
#pragma config WDT = OFF,WDTPS = 32768
#pragma config MCLRE = ON,LPT1OSC = OFF,PBADEN = OFF,CCP2MX = OFF
#pragma config STVREN = OFF,LVP = OFF,XINST = OFF,DEBUG = OFF
#pragma config CP0 = ON,CP1 = ON,CP2 = ON
#pragma config CPB = ON,CPD = ON
#pragma config WRT0 = ON,WRT1 = ON,WRT2 = ON
#pragma config WRTB = ON,WRTC = ON,WRTD = ON
#pragma config EBTR0 = ON,EBTR1 = ON,EBTR2 = ON
#pragma config EBTRB = ON

unsigned char i; //Para contar 0 titilaciones.-

void main(void){
ADCON1=0x0F;//Todos entrada/salida digitales.-
TRISA=0xFF; //Todos como entrada.-
TRISB=0X00; //Todos como salida.-

LATB=0x00; //Leds apagados.-
while(1){
        if(PORTAbits.RA0==1){
                LATB=0x00;
        }
        else{
                for(i=1;i<=10;++i){//Titila 10 veces
                        LATB=0x0F;
                        Delay10KTCYx(30);//Demora 300ms
                        LATB=0x00;
                        Delay10KTCYx(30);//Demora 300ms
                }
        }
}
}




Navegación

[0] Índice de Mensajes

[#] Página Siguiente