Dudas con el compilador XC8

Hola, estoy aprendiendo a programar en C con el compilador XC8 de Microchip ya que programo desde Mac. Tengo dudas en cuanto a la sintaxis ya que según que tutorial o ejemplo sigo... declaran/definen unos comandos u otros y eso me marea mucho.

Uso: MPLAB IDE X, COMPILADOR XC8, LENGUAGE C.

DUDAS:

#include <delays.h> // No lo he usado pero algunos lo ponen.

#include <pic16f84a.h> // Yo uso este Pic.

#include <stdio.h> // El MPLAB IDE X lo crea automáticamente

#include <stdlib.h> // El MPLAB IDE X lo crea automáticamente

#include <xc.h> // Librerías del compilador XC8 creo.

#include <pic.h> // No lo he usado pero algunos lo ponen.

Me podéis explicar la necesidad de poner estos includes?? Según donde miro lo ponen o no (Siempre hablando del XC8). Hay algún orden a tener en cuenta?

__CONFIG (FOSC_XT & WDTE_OFF & CP_OFF & PWRTE_OFF);

o

#pragma config FOSC=XT, WDTE=ON, PWRTE=OFF, CP=OFF

Lo mismo... según que programas/tutoriales usan __CONFIG o #pragma, en que casos o con que criterio se usa uno u otro y con __CONFIG cual es la sintaxis correcta de los Bits de configuración? Para el 16F84A según el datasheet sólo hay estos 4 bits, así que entiendo que no hay nada más que configurar ahí, cierto? Importa el orden de configuración de los Bits? el MPLAB me indica error en la sintaxis usando __CONFIG.

while (1)

el "1" que significa? Loop infinito? y cuando ponen "TRUE"?. He de decir que aún no me he leído el comando while aunque se de que va.

__delay_ms_

Porque el editor del MPLAB me lo subraya en rojo??? aún asi compila bien y se programa el chip, funcionando OK (encender y apagar un led).

return;

Hay que ponerlo? según donde miro no lo ponen.

Finalmente me gustaría que me dijérais que compiladores son mejor en su versión Free; los de Microchip o los de Hi-Tech?

Os adjunto una captura de mi primer programa en base al cual tengo las dudas (encender y apagar un led), el programa funciona OK en el pic. Os agradecería enormemente que comentárais el programa: que me falta... que me sobra... que es recomendable... cuestiones a tener en cuenta... Si hay formas más correctas... si hablo con propiedad en los comentarios... etc.

]


Si no se ve la imagen haced botón derecho ver imagen.
Gracias por la atención, Saludos!!
 
Última edición:
En general tu programa esta bastante bien, algunas aclaraciones: Las primeras tres lineas no son necesarias y el orden no es importante.
PHP:
#include <pic16f86a.h>
#include <stdio.h>
#include <stdlib.h>
Lo unico que debes incluir para este proyecto es:
PHP:
#include <xc.h>
Esta libreria hace que MPLABX y CX8 carguen automaticamente las definiciones del microcontrolador que se usa en el proyecto por lo que incluir el archivo "pic16f86a.h" no es necesario.

Cada libreria tiene un uso especifico y en este caso "stdio.h" y "stdlib.h" no se requieren. Tampoco la instruccion "return" porque no existe sistema operativo. La linea:
PHP:
#define _XTAL_FREQ 4000000
sirve unicamente cuando se usan los macros __delay(_ms) o __delay_us() y sirve para informar al compilador la frecuencia con la que el sistema va a trabajar. Esto hace que se genere las funciones de retraso correctamente.

Si quieres eliminar ese subrayado rojo (que es un error en el IDE que segun Microchip va a ser reparado en las proximas versiones de MPLABX) incluye esta linea al inicio de tu codigo:
PHP:
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
Los bits de configuracion estan bien y se deben hacer con instrucciones #pragma y no con instrucciones _include ya que estas ultimas no tendran soporte en el futuro y estan unicamente validadas por compatibilidad.

Si quieres modificar solo un bit de un puerto puedes usar:
PHP:
PORTBbits.RB1 = 0b1;
aunque hay que tener cuidado con instrucciones "read-modify-write" cuando se accede bits individualmente.

El bucle infinito tambien puede ser implementado de otras maneras pero la mas comun es while(1){}. En donde "1" es como dices TRUE.

En resumen tu programa hola mundo quedaria algo asi:
PHP:
#include <xc.h>

#define _XTAL_FREQ 4000000
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

#pragma config FOSC = XT, WDTE = ON, PWRTE = OFF, CP = OFF

void main(void){
	PORTB = 0;
	TRISB = 0;

	while(1){
		PORTBbits.RB1 = 0b1;
		__delay_ms(500);
		PORTBbits.RB1 = 0b0;
		__delay_ms(500);
	}
}


Saludos
 
Muchísimas gracias carferper, me has sido de enorme ayuda!!

Te comento que he reeditado mi post completando los "#include", por algún motivo al hacer copy paste no se copiaron bien y tenía algo de prisa, sorry por la incidencia.

Si he entendido bien...

Entonces #include <xc.h> es la librería que contiene todo lo necesario sin tener necesidad de incluir ninguna más? por eso tampoco hace falta incluir delays.h ni pic.h? Esta última intuyo que sería para incluir todos los pics pero no es necesario al poner la xc.h o es por estar configurado el microcontrolador previamente en el MPLAB?

Podrías explicarme que hace esta línea que me sugieres? Para tratar de entenderlo:

Código:
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

Lo de tener cuidado con lo de configurar los bits individualmente es por el riesgo a equivocación? Siempre me ha parecido más visual definirlo en binario, pero agradezco el consejo ;)


Vuelvo a agradecerte la ayuda puesto que aunque parezca una tontería... ver tanta ambigüedad en los diferentes tutoriales y programas... me ha truncado todos los intentos hasta la fecha para aprender a programar. Ahora ya no.

Saludos cordiales! ;)
 
Entonces #include <xc.h> es la librería que contiene todo lo necesario sin tener necesidad de incluir ninguna más? por eso tampoco hace falta incluir delays.h ni pic.h? Esta última intuyo que sería para incluir todos los pics pero no es necesario al poner la xc.h o es por estar configurado el microcontrolador previamente en el MPLAB?

Correcto, "xc.h" hace que automaticamente se incluyan las librerias que son necesarias para utilizar las definiciones de cada micro, el cual se especifica previamente cuando se inicia un proyecto.

#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

Basicamente esta linea es un macro que define la funcion __delay_ms(x), donde x es una variable de tipo unsigned long. Cada vez que esta definicion aparece en el codigo, xc8 la reemplaza por la funcion _delay(...), que a su vez genera las instrucciones "asm" necesarias para generar el retraso de tiempo especificado por x.

Hay muchas mas consideraciones acerca de macros y librerias, pero creo que esto es suficiente para empezar.

Lo de tener cuidado con lo de configurar los bits individualmente es por el riesgo a equivocación? Siempre me ha parecido más visual definirlo en binario, pero agradezco el consejo

A lo que me referia es a que es mas facil leer el codigo cuando se usa PORTBbits.RB1 = 0, pero no necesariamente mas conveniente. Al final todo depende del estilo del programador.

Saludos
 
Hola, estoy con problemas con los puertos, despues de doloers de cabeza llegue a la conclucion de que:
Código:
GPIObits.GPO = 0b1;
pone el 1 en GP0 pero puso a cero todos los bits del registro GPIO.
Si pones varios
Código:
GPIObits.GPO = 0b1; 
GPIObits.GP1 = 0b1;
el ultimo queda.
Lo solucione cargando directamente el registro
Código:
GPIO = 0b00000001;

Les a pasado soy nuevo con este compilador ya le estoy agarrando la mano. Pero esto me hace renegar.

Les dejo codigo adjunto uso XMPLAB y xc8.
Saludos
 

Adjuntos

  • TestPWM.rar
    109.1 KB · Visitas: 89
Hola, estoy con problemas con los puertos, despues de doloers de cabeza llegue a la conclucion de que:
Código:
GPIObits.GPO = 0b1;
pone el 1 en GP0 pero puso a cero todos los bits del registro GPIO.
Si pones varios
Código:
GPIObits.GPO = 0b1; 
GPIObits.GP1 = 0b1;
el ultimo queda.
Lo solucione cargando directamente el registro
Código:
GPIO = 0b00000001;
Les a pasado soy nuevo con este compilador ya le estoy agarrando la mano. Pero esto me hace renegar.

Les dejo codigo adjunto uso XMPLAB y xc8.
Saludos

No comprendo muy bien ese 0b1, normalmente funciona colocando solamente GPIObits.GPO = 1; . Pruebalo
 
Hola, estoy con problemas con los puertos, despues de doloers de cabeza llegue a la conclucion de que:
Código:
GPIObits.GPO = 0b1;
pone el 1 en GP0 pero puso a cero todos los bits del registro GPIO.
Si pones varios
Código:
GPIObits.GPO = 0b1; 
GPIObits.GP1 = 0b1;
el ultimo queda.
Lo solucione cargando directamente el registro
Código:
GPIO = 0b00000001;

Efectivamente este es un problema que existe con algunos microcontroladores, se llama "read-modify-write". Lo que ocurre es que cuando tratamos de enviar un dato al puerto del micro, este primero lee el valor presente en cada pin del puerto (el valor fisico no el que esta en los "latches"), luego lo modifica de acuerdo al codigo y finalmente lo escribe en los "latches" de salida. Es decir, los valores modificados requieren cierto tiempo para estar fisicamente presentes en los pines del puerto.

En tu ejemplo, cuando escribes:
Código:
GPIObits.GPO = 0b1; 
GPIObits.GP1 = 0b1;
la segunda instruccion se ejecuta cuando GP0 todavia tiene un cero logico en su pin (aunque su respectivo "latch" ya este con un uno logico"). Es decir el micro toma el valor erroneo de GP0, modifica GP1 y envia estos valores al puerto.

Para solucionar este problema existen varios metodos, cada uno con sus pros y sus contras. De manera muy simplificada, estos se reducen a:

1) reducir la carga en el pin de tal manera que la transicion de los datos desde los latches a los pines sea lo mas rapida posible.

2) utilizar registros sombra o "shadow registers", los cuales son manipulados convenientemenete a nivel de bits y luego se copia su contenido al puerto.

3) uso de retrasos de tiempo despues de este tipo de instrucciones para permitir que el nivel logico deseado alcance el pin.

Finalmente, algunos compiladores poseen instrucciones especales que basicamente incluyen en su paso a ensamblador instrucciones tipo "nop" que retrasan la ejecucion de la siquiente instruccion.

Con respecto al uso de "0b0" o "0b1" en lugar de "0" o "1", es una practica comun que indica explicitamente que se trata de valores en binario.

Saludos
 
Gracias carferper, primero voy a probarlos con una demora, me gusta mas la idea de los registros sombra a probar..

Saludos

Efectivamente este es un problema que existe con algunos microcontroladores, se llama "read-modify-write". Lo que ocurre es que cuando tratamos de enviar un dato al puerto del micro, este primero lee el valor presente en cada pin del puerto (el valor fisico no el que esta en los "latches"), luego lo modifica de acuerdo al codigo y finalmente lo escribe en los "latches" de salida. Es decir, los valores modificados requieren cierto tiempo para estar fisicamente presentes en los pines del puerto.

En tu ejemplo, cuando escribes:
Código:
GPIObits.GPO = 0b1; 
GPIObits.GP1 = 0b1;
la segunda instruccion se ejecuta cuando GP0 todavia tiene un cero logico en su pin (aunque su respectivo "latch" ya este con un uno logico"). Es decir el micro toma el valor erroneo de GP0, modifica GP1 y envia estos valores al puerto.

Para solucionar este problema existen varios metodos, cada uno con sus pros y sus contras. De manera muy simplificada, estos se reducen a:

1) reducir la carga en el pin de tal manera que la transicion de los datos desde los latches a los pines sea lo mas rapida posible.

2) utilizar registros sombra o "shadow registers", los cuales son manipulados convenientemenete a nivel de bits y luego se copia su contenido al puerto.

3) uso de retrasos de tiempo despues de este tipo de instrucciones para permitir que el nivel logico deseado alcance el pin.

Finalmente, algunos compiladores poseen instrucciones especales que basicamente incluyen en su paso a ensamblador instrucciones tipo "nop" que retrasan la ejecucion de la siquiente instruccion.

Con respecto al uso de "0b0" o "0b1" en lugar de "0" o "1", es una practica comun que indica explicitamente que se trata de valores en binario.

Saludos
 
hola expertos!

queria preguntarles como habilitar la funcion de AUTO COMPLETAR en el MPLB XC8 , porque vi en varios video tutoriales que la usan y es muy practica por ejemplo cuando usamos esto:

PORTBbits. y al poner el punto ya te salen todas las opciones , y lo mismo para el resto de los registros

yo tengo la version 1.51 y no encuentro como habilitar esto, gracias :)
 
hola expertos!

queria preguntarles como habilitar la funcion de AUTO COMPLETAR en el MPLB XC8 , porque vi en varios video tutoriales que la usan y es muy practica por ejemplo cuando usamos esto:

PORTBbits. y al poner el punto ya te salen todas las opciones , y lo mismo para el resto de los registros

yo tengo la version 1.51 y no encuentro como habilitar esto, gracias :)

En Options > Editor > Code Completion, activa para todos los lenguajes las opciones que quieras. Para forzar mientraz escribes se usa Ctrl + Espaciador. No funciona entonces reinstala el programa o actualiza Java.
Saludos
 
bueno gracias, acabo de probar esas 2 opciones pero sigue sin funcionar, ya estoy descargando la version mas actual 1.95 a ver si funciona bien,en un rato aviso como me fue ! :)

una consulta para la instalacion del 1.95,,,,se puede instalar sobre el que ya esta instalado ? (1.51) y se actualiza automaticamente ? o tengo que desinstalar primero el 1.51 ? gracias de nuevo :)
 
bueno ya instalada la version 1.95 funciona OK ! gracias



me aprovecho de su generosidad para consultarles otra duda que tengo

en algunos programas eh visto que para generar una demora utilizan solo: __delay_ms(valor);
que es muy entendible y no necesita mucha explicacion,solo reemplazando valor por un numero tenemos la cantidad de milisegundos que querramos

pero en otros programas a demas del anterior tambien usan por ejemplo:

Delay10TCYx(10); //no se cuanto tiempo es, como se cuenta el tiempo aca ??
y Delay1KTCYx(20); //serian 15ms pero no se porque, como se cuenta el tiempo en esta otra??

y para usar estas ultimas encima hay que incluir la libreria #include <delays.h>

mis preguntas entonces son 2: porque usan la segunda forma si es mas complicada? tendrá alguna ventaja ?, y segundo .....como se calculan los tiempos en la segunda forma? gracias :)
 
Última edición:
Hola.
El Delay10TCYx(10), Delay1KTCYx(20) y otros parecidos los he visto más para el compilador C18, esas funciones cuentan ciclos de instrucción, no tiempo en s o ms; por lo que es necesario hacer el cálculo de tiempo manualmente sabiendo la freq. del oscilador.

Por ejemplo, se tiene un oscilador a 4Mhz, el ciclo de instrucción dura 1us (microsegundo) y sabiendo que Delay1KTCYx() multiplica por 1000 entonces para lograr 1ms se escribe Delay1KTCYx(1) que es 1us x 1000 veces = 1ms. Y bueno, en cierto modo hay mayor presición pero generalmente no es necesario y es más facil usando __delay_ms().

Es posible que los ejemplos que encuentras que dicen ser para el XC8 son en realidad para el C18, claro son similares pero dudo que compilen.
 
Hola como estan espero q bien.

A ver si alguien me da una mano quería saber si Dentro de las librerías de XC8 c Compiler hay una librería que me facilite trabajar con displeys de 7 segmentos y como implementarla. Ó donde bajar una.

Muchas gracias, Este Foro es excelente
Saludos un abrazo
 
A ver si alguien me da una mano quería saber si Dentro de las librerías de XC8 c Compiler hay una librería que me facilite trabajar con displeys de 7 segmentos y como implementarla. Ó donde bajar una.
Hola.
XC8 no inluye tal libreria, pero no es dificil... se necesita un contador usado como puntero a un array donde hay una serie de valores que van a ser enviados al puerto donde se encuentra el display... algo asi:

Código:
unsigned char cnt;
unsigned char dis[10] = {0b00000001, 0b00000011, 0b00000111, 0b00001111, 0b00011111,
                        0b10000000, 0b11000000, 0b11100000, 0b11110000, 0b11111000};

void main(void){
    PORTB = 0;
    TRISB = 1;

    while(1){
        for(cnt=0 ; cnt<10 ; cnt++){
            PORTB = dis[cnt];
            // Delay, mantiene el dígito durante un tiempo
        }
    }
}

Es solo un ejemplo y es para un display... necesitas acomodar los valores de acuerdo al tipo de display que tengas (ánodo compun o catodo común), si es para más ya necesitas de un técnica llamada multiplexado...
Estos temas los encuentras en el foro... también en otros lenguajes pero el método practicamente es igual.
Saludos
 
Muy buenas gente!
Estoy ahora mismo trabajando en crear una librería en Keypad, y estoy intentando que funcione pero no lo hace correctamente y es que estoy teniendo problemas con el return, me explico
Esta es la parte final de la librería de mi keypad:
Código:
  if(key == 6)
    {
        LED = 1;
    }


    return key;
El if sobra, es simplemente que lo estoy usando ahora para asegurarme que la key tiene un valor, al meterlo en proteus vemos que el led se enciende, por lo que sabemos que key está teniendo el valor 6, pero cuando lo recibo desde el main:

Código:
/*
 * File:   Main.c
 * Author: Manuel
 *
 * Created on 14 de mayo de 2014, 13:13
 */


#include <xc.h>
#include <stddef.h>

#include "Keypad.h"
#include "lcd_hd44780.h"

// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = ON         // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)


int variable;
void main(void) {

  Keypad_Init();
  LCDInit(LS_NONE);
  LCDClear();



  while(1){


   variable = Keypad_Check();
 LCDGotoXY(5,0);
   if (variable == 0)
   {
       LCDClear();
       //LCDWriteInt(78,2);
       LCDWriteString("0");
       //LCDWriteInt(variable,3);
   }   else if(variable == 1)
   {
       LCDClear();
       LCDWriteString("1");
   }   else if(variable == 2)
   {
       LCDClear();
       LCDWriteString("2");
   }   else if(variable == 3)
   {
       LCDClear();
       LCDWriteString("3");
   }   else if(variable == 4)
   {
       LCDClear();
       LCDWriteString("4");
   }   else if(variable == 5)
   {
       LCDClear();
       LCDWriteString("5");
   }   else if(variable == 6)
   {
       LCDClear();
       LCDWriteString("6");
   }   else if(variable == 7)
   {
       LCDClear();
       LCDWriteString("7");
   }   else if(variable == 8)
   {
       LCDClear();
       LCDWriteString("8");
   }   else if(variable == 9)
   {
       LCDClear();
       LCDWriteString("9");
   }   else if(variable == 10)
   {
       LCDClear();
       LCDWriteString("10");
   }   else if(variable == 11)
   {
       LCDClear();
       LCDWriteString("11");
   }
  }
 

}
Imprime un valor completamente distinto.
¿Por qué se está corrompiendo el valor si es de entero a entero?

PD: El que haga tanto else if y no lo imprima directamente en la lcd como una variable es porque no tengo aun implementada en la librería lcd para imprimir un caracter no String.


Muchas gracias.

Un saludo!.
 
Tengo algo similar pero con [ unsigned char ] como tipo de retorno... igual que la variable... prueba especificando el int como unsigned... puede que el asunto del signo sea el detalle.
No creo que tengas más de 255 teclas jeje...
Saludos.
 
Cuando definiste la función, ¿qué tipo de variables devolvía?

Otras cosas:

- No tiene mucho sentido usar una variable global para luego obtener su valor mediante la devolución de una función. Sería bueno que esa variable sea local.

- Te recomiendo usar el comando switch, para no tener que hacer poner tantos if, a la larga el código se entiende mucho más.
 
Atrás
Arriba