# Dudas con el compilador XC8



## nimio (Oct 28, 2012)

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!!


----------



## carferper (Oct 28, 2012)

En general tu programa esta bastante bien, algunas aclaraciones: Las primeras tres lineas no son necesarias y el orden no es importante.

```
#include <pic16f86a.h>
#include <stdio.h>
#include <stdlib.h>
```
Lo unico que debes incluir para este proyecto es:

```
#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:

```
#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:

```
#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:

```
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:

```
#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


----------



## nimio (Oct 28, 2012)

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:


```
#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!


----------



## carferper (Oct 29, 2012)

> 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


----------



## nimio (Oct 29, 2012)

carferper: Gracias Gracias GRACIAS!! te voy a nombrar mi gurú programador!!

Saludos


----------



## Shagui (Ene 19, 2013)

Hola, estoy con problemas con los puertos, despues de doloers de cabeza llegue a la conclucion de que:

```
GPIObits.GPO = 0b1;
```
 pone el 1 en GP0 pero puso a cero todos los bits del registro GPIO. 
Si pones varios 
	
	



```
GPIObits.GPO = 0b1; 
GPIObits.GP1 = 0b1;
```
 el ultimo queda. 
Lo solucione cargando directamente el registro 
	
	



```
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


----------



## Basalto (Ene 20, 2013)

Shagui dijo:


> Hola, estoy con problemas con los puertos, despues de doloers de cabeza llegue a la conclucion de que:
> 
> ```
> GPIObits.GPO = 0b1;
> ...



No comprendo muy bien ese 0b1, normalmente funciona colocando solamente GPIObits.GPO = 1; . Pruebalo


----------



## carferper (Ene 21, 2013)

Shagui dijo:


> Hola, estoy con problemas con los puertos, despues de doloers de cabeza llegue a la conclucion de que:
> 
> ```
> GPIObits.GPO = 0b1;
> ...



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: 
	
	



```
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


----------



## Shagui (Ene 26, 2013)

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

Saludos



carferper dijo:


> 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:
> 
> ...


----------



## ilcapo (Dic 26, 2013)

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


----------



## ByAxel (Dic 26, 2013)

ilcapo dijo:


> 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:
> 
> ...



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


----------



## ilcapo (Dic 26, 2013)

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


----------



## ilcapo (Dic 26, 2013)

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


----------



## ByAxel (Dic 26, 2013)

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.


----------



## ilcapo (Dic 26, 2013)

a usar el __delay_ms  entonces !


----------



## adrianleal (Mar 23, 2014)

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


----------



## ByAxel (Mar 23, 2014)

adrianleal dijo:


> 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:


```
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


----------



## kraw (May 20, 2014)

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:

```
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:


```
/*
 * 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!.


----------



## ByAxel (May 20, 2014)

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.


----------



## cosmefulanito04 (May 20, 2014)

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.


----------



## kraw (May 20, 2014)

cosmefulanito04 dijo:
			
		

> Cuando definiste la función, ¿qué tipo de variables devolvía?
> 
> Otras cosas:
> 
> ...



Cuando definí la función hice que devolviese un entero, la variable key es de tipo entero y la variable que recoge el valor que devuelve la función es también de tipo entero. Probare como se ha dicho de cambiarlo a unsigned int.
Tienes razón, es un poco tontería eso que he hecho de poner la variable global si sólo la quiero para esa función, la pasare a local.
Respecto al comando switch lo suelo utilizar, simplemente he hecho esto para probar que le pasaba a la variable, pero es temporal ya que quiero que lo haga la LCD directamente.

Esta noche en llegar me pongo con el programa y os cuento que tal va saliendo la cosa.

Muchas gracias.
Un saludo!.


----------



## cosmefulanito04 (May 20, 2014)

Por lo que decís, pareciera que hiciste todo bien.

Resumiendo hiciste algo como esto:


```
...

int mi_funcion();

void main()
{
   int variable;
   ...// Inicialización
   while(1)
    {      
      variable=mi_funcion();
      ...//El resto del código
    }
}

int mi_funcion()
{
  int var_ret;
  //... Código
  return var_ret;
}
```


----------



## kraw (May 20, 2014)

cosmefulanito04 dijo:


> Por lo que decís, pareciera que hiciste todo bien.
> 
> Resumiendo hiciste algo como esto:
> 
> ...



Exacto, eso es lo que tenía.
El tema es que lo acabo de modificar todo a unsigned int y me sigue dando problemas, realmente lo que está pasando es lo siguiente:

Desde la librería de Keypad, antes de enviarme el key por return, segun el boton del keypad recibo una key distinta, tal que asi:

    0     4    8
    1     5    9 
    2     6    10 
    3     7    11

Lo cual es lo que quiero, ya que tengo una key distinta para cada botón y desde un array podría tener una letra/numero en funcion de la posicion.

Pero sin embargo, cuando recibo la key en la llamada a la funcion, recibo estas keys cuando pulso los botones respectivos:

  0     0     0
  1     1     1
  2     2     2 
  3     3     3 

La verdad que no tiene sentido que la key tenga un valor antes del return y uno distinto después.
¿Alguna idea de qué podría estar pasando?

Un saludo!.


----------



## cosmefulanito04 (May 20, 2014)

Para mí el problema no lo tenés en ese retorno, sino en el uso de esa librería en conjunto con tu hard.


----------



## kraw (May 20, 2014)

cosmefulanito04 dijo:


> Para mí el problema no lo tenés en ese retorno, sino en el uso de esa librería en conjunto con tu hard.



De ser así, ¿qué provocaría que la variable key adopte distintos valores?



Pongo aquí el método que se encarga de decirme que tecla es la que está pulsada para asegurarnos que no esté ahí el fallo.

```
int Keypad_Check(void)
{
    uint8_t columna;
    int key = 0;


    const unsigned char keypad_array[] =
        {'1','2','3','A',
         '4','5','6','B',
         '7','8','9','C',
         '*','0','#','D','-'};


    if(NUMBER_COLUMNS == 4)
    {
        for (columna = 0b10000000; columna > 0b00000100; columna >>= 1)
    {
        PORTB = ~columna;
        if (PORTBbits.KEYPAD_ROW1 == 0) break; key++;
        if (PORTBbits.KEYPAD_ROW2 == 0) break; key++;
        if (PORTBbits.KEYPAD_ROW3 == 0) break; key++;
        if (PORTBbits.KEYPAD_ROW4 == 0) break; key++;
    }
    }

   if(NUMBER_COLUMNS == 3)
   {

    for (columna = 0b01000000; columna > 0b00001000; columna >>= 1)
    {
        PORTB = ~columna;

        if (PORTBbits.KEYPAD_ROW1 == 0){
            break;
        }
        key++;

        if (PORTBbits.KEYPAD_ROW2 == 0){
            break;
        }
        key++;

        if (PORTBbits.KEYPAD_ROW3 == 0){
            break;
        }
        key++;

        if (PORTBbits.KEYPAD_ROW4 == 0){
            break;
        }
        key++;
        
    }


   }


    //PORTB = 0xFF;
    
    if(key == 11)
    {
        LED = 1;
    }
    else if(key == 1)
    {
        LED = 0;
    }


    return key;

}
```
Lo curioso es que el led se enciende solo cuando pulso la ultima tecla ya que es la tecla 11, pero para apagarlo, debido al fallo que he comentado antes, me sirven las teclas de las posiciones 1, 5 y 9, ya que por alguna extraña razon, si yo digo tecla 5 sería solo la posición 5, pero si digo 1, son las 3.

Un saludo!.


----------



## cosmefulanito04 (May 20, 2014)

Lo que no veo en esa rutina es el antirrebote.

Después habría que analizar si el resto está bien, por ej. el "keypad_array" no lo usas nunca.


----------



## kraw (May 20, 2014)

cosmefulanito04 dijo:


> Lo que no veo en esa rutina es el antirrebote.
> 
> Después habría que analizar si el resto está bien, por ej. el "keypad_array" no lo usas nunca.




Respecto al antirrebote de acuerdo, añadire un pequeño delay cada vez que sepamos que se ha pulsado para evitar posibles problemas.

Respecto a keypad_array es porque iba en un principio a pasar el valor como keypad_array[key], pero no he añadido aun a la libreria lcd la funcion de escribir un solo char, por eso aun no le he dado uso, pero lo he puesto ya para no olvidarlo.


----------



## kraw (May 21, 2014)

Alguna idea de qué puede ser lo que esté sucediendo?


----------



## cosmefulanito04 (May 21, 2014)

Sabes que pasa, es difícil analizar ese código porque no explicás su procedimiento, como tampoco subiste la conexión del hard, en si lo importante es el teclado.

Yo cuando usé teclado matricial lo encaré de otra forma, para que te des una idea:


Antirrebote: para encarar un buen antirrebote lo ideal es una interrupción de timer.
Hard: verificar que el hard esté bien hecho, si los pull-ups están bien, que tenga las protecciones correctas en caso de pulsar dos pulsadores (diodos), que estén conectados al puerto correctamente.
Rutina: una de las mejores formas de encararlo es mediante el uso máquinas de estado en conjunto con el timer.


----------



## kraw (May 22, 2014)

cosmefulanito04 dijo:


> Sabes que pasa, es difícil analizar ese código porque no explicás su procedimiento, como tampoco subiste la conexión del hard, en si lo importante es el teclado.
> 
> Yo cuando usé teclado matricial lo encaré de otra forma, para que te des una idea:
> 
> ...



Tienes razón, voy a explicarlo mejor y más detenido.

Voy a subir primero el código del archivo encargado de manejar las funciones del keypad:


```
#include <xc.h>
#include <stdint.h>
#include <stdio.h>

#include "Keypad.h"


#define KEYPAD_ROWS_PORT     PORT(PORT_ROWS)
#define KEYPAD_ROWS_TRIS     TRIS(PORT_ROWS)

#define KEYPAD_COLUMNS_PORT  PORT(PORT_COLUMNS)
#define KEYPAD_COLUMNS_TRIS  TRIS(PORT_COLUMNS)

#define KEYPAD_ROW1          PORTBIT(PORT_ROWS,KEYPAD_ROW1_POS)
#define KEYPAD_ROW1_TRIS     TRISBIT(PORT_ROWS,KEYPAD_ROW1_POS)

#define KEYPAD_ROW2          PORTBIT(PORT_ROWS,KEYPAD_ROW2_POS)
#define KEYPAD_ROW2_TRIS     TRISBIT(PORT_ROWS,KEYPAD_ROW2_POS)

#define KEYPAD_ROW3          PORTBIT(PORT_ROWS,KEYPAD_ROW3_POS)
#define KEYPAD_ROW3_TRIS     TRISBIT(PORT_ROWS,KEYPAD_ROW3_POS)

#define KEYPAD_ROW4          PORTBIT(PORT_ROWS,KEYPAD_ROW4_POS)
#define KEYPAD_ROW4_TRIS     TRISBIT(PORT_ROWS,KEYPAD_ROW4_POS)

#define KEYPAD_COLUMN1       PORTBIT(PORT_COLUMNS,KEYPAD_COLUMN1_POS)
#define KEYPAD_COLUMN1_TRIS  TRISBIT(PORT_COLUMNS,KEYPAD_COLUMN1_POS)

#define KEYPAD_COLUMN2       PORTBIT(PORT_COLUMNS,KEYPAD_COLUMN2_POS)
#define KEYPAD_COLUMN2_TRIS  TRISBIT(PORT_COLUMNS,KEYPAD_COLUMN2_POS)

#define KEYPAD_COLUMN3       PORTBIT(PORT_COLUMNS,KEYPAD_COLUMN3_POS)
#define KEYPAD_COLUMN3_TRIS  TRISBIT(PORT_COLUMNS,KEYPAD_COLUMN3_POS)

#define KEYPAD_COLUMN4       PORTBIT(PORT_COLUMNS,KEYPAD_COLUMN4_POS)
#define KEYPAD_COLUMN4_TRIS  TRISBIT(PORT_COLUMNS,KEYPAD_COLUMN4_POS)

#define LED    PORTCbits.RC1



void Keypad_Init(void){

    TRISCbits.TRISC1 = 0;
    LED = 0;

    KEYPAD_ROWS_TRIS &=(~(0x0F<<KEYPAD_ROW1_POS)); // Output for the 4 rows
    KEYPAD_ROWS_PORT =(~(0xFF<<KEYPAD_ROW1_POS)); //Cleaning ports

    KEYPAD_COLUMN1_TRIS = 0;


    if (NUMBER_COLUMNS == 4)
    {
        KEYPAD_COLUMN1_TRIS = 0;
        KEYPAD_COLUMN2_TRIS = 0;
        KEYPAD_COLUMN3_TRIS = 0;
        KEYPAD_COLUMN4_TRIS = 0;
    }
    else if (NUMBER_COLUMNS == 3)
    {
        KEYPAD_COLUMN1_TRIS = 0;
        KEYPAD_COLUMN2_TRIS = 0;
        KEYPAD_COLUMN3_TRIS = 0;
    }

}

unsigned int Keypad_Check(void)
{
    uint8_t columna;
    int key = 0;


    const unsigned int keypad_array[] =
        {0,1,2,3,
         4,5,6,7,
         8,9,10,11};


    if(NUMBER_COLUMNS == 4)
    {
        for (columna = 0b10000000; columna > 0b00000100; columna >>= 1)
    {
        PORTB = ~columna;
        if (PORTBbits.KEYPAD_ROW1 == 0) break; key++;
        if (PORTBbits.KEYPAD_ROW2 == 0) break; key++;
        if (PORTBbits.KEYPAD_ROW3 == 0) break; key++;
        if (PORTBbits.KEYPAD_ROW4 == 0) break; key++;
    }
    }

   if(NUMBER_COLUMNS == 3)
   {
       key = 0;

    for (columna = 0b01000000; columna > 0b00001000; columna >>= 1)
    {
        PORTB = ~columna;

        if (PORTBbits.KEYPAD_ROW1 == 0){
            break;
        }
        key++;

        if (PORTBbits.KEYPAD_ROW2 == 0){
            break;
        }
        key++;

        if (PORTBbits.KEYPAD_ROW3 == 0){
            break;
        }
        key++;

        if (PORTBbits.KEYPAD_ROW4 == 0){
            break;
        }
        key++;
        
    }

   }


    PORTB = 0xFF;
    
    if(key == 11)
    {
        LED = 1;
    }
    else if(key == 1)
    {
        LED = 0;
    }


    return keypad_array[key];

}
```
Ahora la función main, la cual llama a la funcion encargada de chequear el keypad:

```
#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)



void main(void) {

  OPTION_REGbits.nRBPU = 0b0;

      
unsigned int variable;

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



  while(1){


   variable = Keypad_Check();

   LCDGotoXY(0,0);
   LCDWriteInt(variable,2);

  }
 

}
```
En cuanto a los rebotes con el timer0 no se como afrontarlo, no estaría bien si utilizo un pequeño delay o hago que el programa espere hasta que el usuario suelte la tecla?

En cuanto a las maquinas de estado de acuerdo, procuraré programar de una forma limpia y más estructurada para poder entender mejor el código.

Un saludo!.


----------



## cosmefulanito04 (May 22, 2014)

Sigue faltando el hard, más que nada la conexión del teclado, así medio que estoy adivinando .

El uso del delay no es la mejor solución, pero se puede implementar, el tema es que hay que hacerlo con cuidado para no bloquear el uC.

De ese código yo entendí esto:


Definís los puertos para las filas y columnas.
Las columnas funcionan como salida, como no uso PIC, no sé si su configuración es correcta.
Las filas como entradas, nuevamente, como no uso PIC, no sé si su configuración es correcta.
En la función "Keypad_Check" usando el for vas rotando el bit de las columnas en el puerto B (negás el valor y vas asignando 0b 0111 1111 -> 0b 1011 1111 -> 0b 1101 1111); pero hay un problema, las filas también son el puerto "B" y cuando asignas "PORTB = ~columna;", estás pisando momentáneamente el valor físico de las filas (no sé que efecto puede traerte esto en la familia PIC) por "1111".
Con el bit de la columna en "0", preguntás por el estado de c/fila y cortás el for cuando detectás un "0" en una cierta fila.
Es raro el uso del índice key, ya que por ej. si estamos en la columna 1 y en la fila 2 obtenemos el valor de índice 2, pero ese indice hace referencia al nº 2 y no al nº 4 (teclado típico telefónico).

Lo que te propongo corregir:


Es vital el uso de un antirrebote. Para facilitar la implementación te propongo algo muy burdo, cuando detectes una fila, en vez de hacer solamente un break, implementá un delay de 300mS (después empezá a bajar ese tiempo hasta sentirte cómodo). *Es importante que solo se implemente ese delay cuando se detecta una pulsación.*
El problema del punto 2 lo resolvés usando máscaras, es decir en vez de:


```
PORTB = ~columna;
```

Usás esto:


```
PORTB &= ~columna;
```

Esa línea te permite mantener el valor del resto del puerto B y solo pone en 0 el bit de rotación. Sin embargo las columnas anteriores no vuelven a 1, por lo tanto el código final debería ser así:


```
PORTB |= 0b11100000; //Forzas a "1" todas las columnas
PORTB &= ~columna; //Forzas a "0" la columna que usas para medir el estado de las filas.
```

 El problema del punto 6 se arregla reordenando el contenido del vector "keypad_array", nuevamente yo estoy pensando que el teclado es el típico telefónico.

Eso sería lo que probaría.


----------



## kraw (May 24, 2014)

Primero de todo agradecerte la ayuda, ya que me está ayudando mucho a entender cómo programar los pics.
He realizado los cambios propuestos y sigue sin funcionar, subo una imagen de la conexión del pic con el keypad.






Un saludo!.


----------



## cosmefulanito04 (May 24, 2014)

Viendo el hard noto que las modificaciones que te puse en las columnas no se corresponden. El código debería quedar así:


```
PORTB |= 0b01110000; //Forzas a "1" todas las columnas
PORTB &= ~columna; //Forzas a "0" la columna que usas para medir el estado de las filas.
```

Antes faltaba forzar una columna a 1.

Otra cosa, ¿las filas la configurás como entradas con pull-up? y las columnas ¿cómo configurás la salida?

Yo lo configuraría:

- Fila como entrada con pull-up.
- Columnas, salida sin pull-up (si se puede).

Sobre el punto 6 que puse antes, me equivoqué, si se presiona el pulsador cuando estamos en la columna 1 y en la fila 2, el valor de la variable "key" será simplemente 1, como resultado la función devolverá el nº 1.

¿Los delay te quedaron bien? Así debería quedarte esa rutina:


```
for (columna = 0b01000000; columna > 0b00001000; columna >>= 1)
    {
        PORTB |= 0b01110000; //Forzas a "1" todas las columnas
        PORTB &= ~columna; //Forzas a "0" la columna que usas para medir el estado de las filas.

        if (PORTBbits.KEYPAD_ROW1 == 0){
           delay_ms(300); 
           break;
        }
        key++;

        if (PORTBbits.KEYPAD_ROW2 == 0){
            delay_ms(300); 
            break;
        }
        key++;

        if (PORTBbits.KEYPAD_ROW3 == 0){
            delay_ms(300); 
            break;
        }
        key++;

        if (PORTBbits.KEYPAD_ROW4 == 0){
            delay_ms(300); 
            break;
        }
        key++;
        
    }
```

Y si no me equivoco, el vector debería quedarte así:


```
const unsigned int keypad_array[] =
        {1,4,7,10,2,5,8,0,3,6,9,11};
```

Y en caso de no haber presionado nada, deberías descartar el dato sabiendo que key será igual a 12.


----------



## kraw (May 24, 2014)

??? mm vale cosmefulanito, he ido a realizar las modificaciones en el codigo tal como me has comentado, y lo curioso es que antes no me iba, y al añadir los retardos, ha funcionado perfectamente, de que manera influyen los retardos en el valor? :/

Muchisimas gracias de nuevo por todo, no se si lo habria conseguido sin tu ayuda!


----------



## cosmefulanito04 (May 24, 2014)

Como te dije, esos delay estan pensados para evitar rebotes que es el gran problema que tenés cuando empleas un pulsador.

Para que tengas una idea de lo que lee el uC cuando presionas un pulsador:






Ese problema hacía que tu variable "key" vaya tomando valores distintos en c/rebote y aparecían datos incorrectos.

Pero como te dije, ese antirrebote es muuuuuy precario y estaría bueno que lo implementes con timers. Para que te des una idea de como se debería implementar un buen antirrebote por soft:



			
				Cosmefulanito04 dijo:
			
		

> Por lo tanto un método para saber si el pulsador realmente fue presionado y descartar rebotes y ruido es hacer esto:
> 
> 1- Detectada la pulsación esperar 5mSeg.
> 2- Pasados 5mSeg, preguntar si el PIN se encuentra en el estado correcto (en este caso debe estar en estado bajo, por ser flanco descendente), para agregar mayor confiabilidad esperar otros 5mSeg.
> ...


----------



## kraw (Jun 4, 2014)

Primero de todo, perdón por tardar tanto en responder, no he podido acceder estos días y no sabía de tu respuesta.
Sí, sabía que los pulsadores funcionaban así, pero pensaba que al ser simulado en proteus sería en un funcionamiento ideal (sin rebotes), pero ya veo que no es así ^^.

Quería comentar que estoy trabajando en diseñar una librería para utilizar pantallas GLCD.

He conseguido que muestre cosas en pantalla aunque lo que muestra son caracteres que no tienen mucho sentido, adjunto el código e imagen de mi conexionado para ver si alguien puede ayudarme.

No hace falta decir que si puedo ayudar a alguien con las librerías que ya tengo no hay mas que pedírmelo!.

Código GLCD.h


```
/* 
 * File:   GLCD.h
 * Author: Manuel
 *
 * Created on 2 de junio de 2014, 22:39
 */

#ifndef GLCD_H
#define    GLCD_H

#include <xc.h>
#include <stdint.h>

#ifdef    __cplusplus
extern "C" {
#endif


    unsigned char __cgram[]=
{
    0x0C, 0x12, 0x12, 0x0C, 0x00, 0x00, 0x00, 0x00, //Char0 degree symbol
    0x00, 0x04, 0x0E, 0x1F, 0x0E, 0x04, 0x00, 0x00, //Char1
    0x04, 0x04, 0x04, 0x04, 0x1F, 0x0E, 0x04, 0x00, //Char2
    0x0A, 0x15, 0x11, 0x0A, 0x04, 0x00, 0x00, 0x00, //Char3
    0x0A, 0x1F, 0x1F, 0x0E, 0x04, 0x00, 0x00, 0x00, //Char4
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //Char5
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //Char6
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //Char7
};





#define _CONCAT(a,b) a##b
#define _CONCAT2(port,pos)  TRIS##port##bits.TRIS##port##pos
#define _CONCAT3(port,pos)  R##port##pos
#define PORT(x) _CONCAT(PORT,x)
#define TRIS(x) _CONCAT(TRIS,x)
#define TRISBIT(__port,__pos) _CONCAT2(__port,__pos)
#define PORTBIT(__port,__pos) _CONCAT3(__port,__pos)


#define GLCD_DATA        D


//Register Select (RS)
#define GLCD_RS_PORT     C
#define GLCD_RS_POS      5

//Read/Write (RW)
#define GLCD_RW_PORT     C
#define GLCD_RW_POS      6

//Enable signal (E)
#define GLCD_E_PORT      C
#define GLCD_E_POS       7

#define LS_NONE     0B00000000


void GLCDInit(uint8_t style);
void GLCDGotoXY(uint8_t x,uint8_t y);
void GLCDWriteInt(int val,int8_t field_length);

void GLCDByte(uint8_t,uint8_t);

#define GLCDCmd(c) (GLCDByte(c,0))
#define GLCDData(d) (GLCDByte(d,1))


void GLCDBusyLoop();




#ifdef    __cplusplus
}
#endif

#endif    /* GLCD_H */
```
código GLCD.c


```
#include <xc.h>
#include <stdint.h>

#include "GLCD.h"

#define GLCD_DATA_PORT     PORT(GLCD_DATA)
#define GLCD_DATA_TRIS     TRIS(GLCD_DATA)

#define GLCD_E           PORTBIT(GLCD_E_PORT,GLCD_E_POS)
#define GLCD_E_TRIS      TRISBIT(GLCD_E_PORT,GLCD_E_POS)

#define GLCD_RS          PORTBIT(GLCD_RS_PORT,GLCD_RS_POS)
#define GLCD_RS_TRIS     TRISBIT(GLCD_RS_PORT,GLCD_RS_POS)

#define GLCD_RW          PORTBIT(GLCD_RW_PORT,GLCD_RW_POS)
#define GLCD_RW_TRIS     TRISBIT(GLCD_RW_PORT,GLCD_RW_POS)



#define SET_ENABLE() (GLCD_E=1)
#define SET_RS() (GLCD_RS=1)
#define SET_RW() (GLCD_RW=1)

#define CLEAR_ENABLE() (GLCD_E=0)
#define CLEAR_RS() (GLCD_RS=0)
#define CLEAR_RW() (GLCD_RW=0)



void GLCDInit(uint8_t style)
{
    /*****************************************************************

    This function Initializes the lcd module
    must be called before calling lcd related functions

    Arguments:
    style = LS_BLINK,LS_ULINE(can be "OR"ed for combination)
    LS_BLINK : The cursor is blinking type
    LS_ULINE : Cursor is "underline" type else "block" type
        LS_NONE : No visible cursor

    *****************************************************************/

    //After power on Wait for LCD to Initialize
    __delay_ms(30);

    //Set IO Ports
    GLCD_DATA_TRIS=~(0xFF); //Output

        GLCD_E_TRIS=0;   //Output
        GLCD_RS_TRIS=0;  //Output
        GLCD_RW_TRIS=0;  //Output

    GLCD_DATA_PORT= ~(0xFF);//Clear data port

        CLEAR_ENABLE();
    CLEAR_RW();
    CLEAR_RS();


    __delay_us(0.5);    //tAS

    SET_ENABLE();
    GLCD_DATA_PORT|=(0b00000010); //[B] To transfer 0b00100000 i was using LCD_DATA_PORT|=0b00100000

        __delay_us(1);

        CLEAR_ENABLE();

        __delay_us(1);

    //Wait for LCD to execute the Functionset Command
    GLCDBusyLoop();                                    //[B] Forgot this delay

    //Now the LCD is in 4-bit mode


    GLCDCmd(0b00101000);             //function set 4-bit,2 line 5x7 dot format
        GLCDCmd(0b00111111|style);    //Display On

        /* Custom Char */
        GLCDCmd(0b01000000);
        //GLCDCmd(0b00000010);

    uint8_t i;
    for(i=0;i<sizeof(__cgram);i++)
        GLCDData(__cgram[i]);



}




void GLCDGotoXY(uint8_t x,uint8_t y)
{

}





void GLCDByte(uint8_t c,uint8_t isdata)
{
//Sends a byte to the LCD in 4bit mode
//cmd=0 for data
//cmd=1 for command


if(isdata==0)
    CLEAR_RS();
else
    SET_RS();

__delay_us(0.5);        //tAS

SET_ENABLE();

//Send high nibble

GLCD_DATA_PORT = c;

__delay_us(1);            //tEH

//Now data lines are stable pull E low for transmission

CLEAR_ENABLE();


__delay_us(1);            //tEL

GLCDBusyLoop();
}


void GLCDBusyLoop()
{
    
}


void GLCDWriteInt(int val,int8_t field_length)
{

    /***************************************************************
    This function writes a integer type value to LCD module

    Arguments:
    1)int val    : Value to print

    2)unsigned int field_length :total length of field in which the value is printed
    must be between 1-5 if it is -1 the field length is no of digits in the val

    ****************************************************************/

    char str[5]={0,0,0,0,0};
    int i=4,j=0;

        //Handle negative integers
        if(val<0)
        {
            GLCDData('-');   //Write Negative sign
            val=val*-1;     //convert to positive
        }

    while(val)
    {
            str[i]=val%10;
            val=val/10;
            i--;
    }
    if(field_length==-1)
        while(str[j]==0) j++;
    else
        j=5-field_length;


    for(i=j;i<5;i++)
    {
    GLCDData(48+str[i]);
    }
}
```
Main

```
#include <xc.h>

#include "GLCD.h"

void main(void) {
    GLCDInit(LS_NONE);
    GLCDWriteInt(10,1);

    while(1)
    {
        
    }

}
```
Mi duda es, la matriz __cgram que estoy utilizando es la que obtuve de una libreria para la lcd, para glcd es la misma?
Sea o no la misma, ¿cómo puedo yo saber que valores van en cada casilla para entender mejor el código y el funcionamiento de esa matriz?

Adjunto lo que muestra mi pantalla GLCD en la simulación en proteus.







Muchas gracias.

Un saludo!.


----------



## espochDavid (Mar 24, 2016)

Si alguien que lea este mensaje me podria ayudar estaria muy agradecido, ultimamente es estado por mi propia cuenta tratando de aprende a programa con el compilador CX8 en MPLAB X, y ya entiendo algunas cosas, y ya compile el primer codigo que hice, el parpadear un LED conectado a un pin, cuando lo simulo en ISIS de proteus funciona, pero al gravarle a un pic en la protoboard este no realiza ninguna accion, y noce que puede estar mal, adjunto el archivo del proyecto por siacaso les sirve.

Pd: el programador que utilizo es el PicKit 2, y la version del compilador CX8 es v1.37


----------



## D@rkbytes (Mar 24, 2016)

Saludos.
Prueba el siguiente código con esta palabra de configuración.
Si te funciona, entonces podré corroborar a qué se debió el error.


```
#include <xc.h>
#define _XTAL_FREQ 4000000

#pragma config FOSC = INTOSCCLK,WDTE = OFF,PWRTE = ON,MCLRE = OFF,LVP = OFF

void main (void)
{
    TRISBbits.TRISB0 = 0;   // RB0 como salida
    
    while(1)
    {
        RB0 =~ RB0;
        __delay_ms(500);
    }
}
```


----------



## espochDavid (Mar 26, 2016)

Estaba revisando los dos códigos y vi algo interesante, los dos códigos si funcionan pero con una velocidad muy muy lenta, por eso pensaba que algo estaba mal, porque al inicio el led conectado estaba apagado por mucho tiempo, cuando escribo __delay_ms(100); no me da un retardo de 100 mili segundos sino de unos 10 o 15 segundos, dejo el código tal ves sirva, me ayudaría mucho saber el porque no me da el retardo que yo quiero de 100 mili segundo al usar esta linea de código "__delay_ms(100);"


----------



## D@rkbytes (Mar 26, 2016)

OK. Entonces se tiene que configurar el registro OSCCON para que el oscilador funcione a 4 MHz.
Ya que por defecto en el PIC16F819, el oscilador trabaja a una frecuencia de 31.25 KHz.

Agrega estas líneas en el main, que pueden ser de la siguiente forma:

Así:
OSCCON = 0b01100000;
O así:
OSCCONbits.IRCF2 = 1;
OSCCONbits.IRCF1 = 1;

Como el bit IRCF0 por defecto es 0, no tiene caso configurarlo.
Opcionalmente también puedes poner lo siguiente:
while(!OSCCONbits.IOFS);
Ésto es para esperar hasta que el oscilador interno se encuentre estable.

Suerte.


----------



## espochDavid (Mar 27, 2016)

Si muchas gracias ya funciono correctamente el circuito, me agrada MPLAB X mas que los otros programas como el CCS o el que funcionaba con el compilador pbp, Y e intentado aprender sobre este programa, talves alguien tenga un ejemplo que contenga varias cosas utiles para seguir aprendiendo, estaria genial, como un ejemplo con los ADC, comunicacion serial o tambien utilizando los timer, poniendo el pic en modo sleep, o usando PWM, cualquier cosa les agradeceria y me ayudaria a conocer mas como funciona


----------



## george.manson.69 (Mar 30, 2016)

Hola,

Pues si quieren ver mis videos sobre MPLABX usando el compilador XC8, aqui estan,
empezare a ver el microcontrolador PIC18F25K80 las caracteristicas de este es que puede operar hasta 64Mhz es decir 16 MIPS, y tiene una memoria de programa de 32kb y memoria RAM de 3.6 Kb, por ahora en el video muestro el PIC18F25K20.








¡Saludos!


----------



## barraelectronic (Mar 8, 2019)

hola amigos buen día hoy les escribo porque tengo una duda que me tiene loco y no se como resolver.. tengo poco tiempo trabando con el xc8.. sinceramente un poco fastidioso sobretodo al compilar pero bueno ahí vamos.. les escribo por algo quizá un poco tonto pero que quiero resolver.. es que al escribir en mi código lo mas básico #include <xc.h> tengo un bombillo de alerta en el lado izquierdo.. por que sera eso? a que se deberá? y como podre resolverlo?? espero puedan ayudarme.. les adjunto una  imagen.. saludos cordiales y gracias de antemano


----------



## Miembro eliminado 356005 (Mar 8, 2019)

Si colocas el ratón encima de la bombilla (bombillo) y esperas unos segundos, saldrá el mensaje de error (o de advertencia) en un globo o mensaje flotante y sabrás el porqué de la presencia de la bombilla.

El mensaje quizás salga también si colocas el ratón encima del "#include"


----------



## barraelectronic (Mar 9, 2019)

hola buen día. gracias Joaquin por contestar. Si ya sabia que daba el mensaje si le pones el cursor sobre el bombillito solo que se me olvido agregar el mensaje.. el mismo es: "there are unresolved include inside <xc.h>". en español seria algo como que hay algo sin resolver dentro del include. no es muy claro por eso les pido la ayuda.. espero puedan ayudarme.. saludos y gracias de nuevo.


----------



## barraelectronic (Mar 21, 2019)

hola amigos buenos días.. Hoy escribo por aquí porque tengo una gran duda de la cual no consigo información,  es que estoy aprendiendo algunas cosas en xc8 y veo que en  muchos casos de los ejemplos que veo (sobre todo cuando se habla de string) en las funciones o en los parámetros de la misma se usa un asterisco (*) junto a la variable. pongo algunos ejemplos:

void Lcd_printf(char *data)
Lcd_write_data_port(*data) 


mi duda es por que se usan los asteriscos en las variables?? para que sirven??
espero puedan ayudarme con esta duda.. gracias de antemano.. saludos


----------



## D@rkbytes (Mar 21, 2019)

Significa que son punteros directos de variables en memoria.
El compilador interpreta que se pueden usar para ocupar un espacio dedicado a una cadena en este caso "char"
Depende de cada tipo designado, la interpretación, ya sea de ingreso o de retorno.
De cualquier forma el * asigna un puntero con longitud especificada por el máximo permitido por el compilador.

Es decir...
char data* = 'Hola';
printf (*data);
Escribe: "Hola"

Algo así como:
char *data [5] = {'H', 'o', 'l', 'a'};
printf (*data);
Escribe: "Hola"


----------



## barraelectronic (Mar 26, 2019)

hola de nuevo amigos..  Darkbytes gracias por la explicación me ilustro bastante.. con lo que me diste y mas info que busque por google pude avanzar en mi proyecto..
hoy escribo porque tengo de nuevo una duda. 
pongamos el mismo ejemplo anterior pero supongamos que no quiero que se escriba "hola" sino quiero que se escriba el valor de una variable x.
me explico mas, supongamos que en una variable por ejemplo "temp" tengo un valor en binario de "00001011"  (decimal = 11) como hago para escribir ese valor desde la variable???
espero que quede clara mi explicacion.. 
gracias de antemano por su ayuda.. 
saludos..


----------



## D@rkbytes (Mar 26, 2019)

Seguramente la librería que usas para la pantalla tenga una rutina para escribirla directamente.


----------



## barraelectronic (Mar 26, 2019)

el problema radica en que no uso ninguna librería especifica sino una que yo mismo hice y no contemple eso.. quiza me toque agregarle pero necesito saber cual es el proceso.. creo que para hacer lo que necesito se usa algo como esto= printf ("*%.3g", variable) pero no estoy seguro y tampoco se el significado de eso.. lo se porque lo vi en algún vídeo..
si alguien mas puede darme algo de info seria genial.. 
espero puedan ayudarme.
saludos cordiales..


----------

