Error al enviar I2C, funciona con PIC16 pero no con PIC18

Hola amigos estoy tratando de comunicar dos pic18f4550 por medio de I2C, conseguí un proyecto que enlazaba varios pic16f876 que pueden descargar en los adjuntos.

Lo que ocurre es que al comenzar la comunicacion I2C el micro (pic18f4550), se bloquea, mas concretamente en la linea

i2c_start();

El micro deja de funcionar.

He aquí el código del maestro simplificado...

Código:
#include <18f4550.h>
 

#FUSES XT,NOPROTECT 

#use delay(clock=20M)
 
#use i2c(Master,fast,sda=PIN_A0,scl=PIN_A1, force_sw)
 
 
 
void Envio_I2C(direccion, posicion, dato){

   i2c_start();            // Comienzo comunicación
   i2c_write(direccion);   // Dirección del esclavo en el bus I2C
   i2c_write(posicion);    // Posición donde se guardara el dato transmitido
   i2c_write(dato);        // Dato a transmitir
   i2c_stop();             // Fin comunicación
   delay_ms(50);
 }

  

void main()
{
 
 
 Envio_I2C(0xA0, 0x01, 0xAA);
 
 
 }


No entiendo porque ocurre ya que en la gama 16 funciona perfectamente.

Adjunto el proyecto de proteus ccs del archivo funcional (16f) y del que no funciona (18f), muchas gracias por cualquier ayuda
 

Adjuntos

  • I2C pic16f.rar
    317.1 KB · Visitas: 10
  • i2c pic18.rar
    94.7 KB · Visitas: 10
pero es que tu falla esta en:

usas delay definido por el cristal del micro, no falla en la familia 16 por que la frecuencia del cristal pasa directo al CPU.

en el 18f4550 al tener puerto USB debe trabajar el hardware a 48Mhz por lo que la frecuencia del cristal va al oscilador, del oscilador a un PLL preescaler, este prescaler modifica la frecuencia del cristal.

y de ahi a un CPUDIV es decir puedes obtener la frecuencia de reloj de diversas fuentes ya se interno, externo o directo del prescaler.

si no configuras estos fuses vas a tener problemas

dira ¡triilobyte no sabes nada! otro que me explique

pues hay que revisar hojas de datos y ver que esta pasando ahi.

haz una prueba , realiza un contador mas o menos asi:


void main()
{
int contador;

while(1)
{
printf("segundos:%d",contador);

contador++;
delay_ms(1000); //un retardo de 1 segundo
}
}


compila para pic16f y durara 1 segundo.
para 18f veraz que dura muchisimo menos que 1 segundo por la configuracion del PLL prescaler y el CPUDIV
 
Agregando a lo que mencionó TRYLO, Seleccionar el fuse XT para 20 MHz, no es correcto.
Faltan resistencias pull-up para el bus I²C.
La librería "jkbd_4x4.c" está en blanco.
La librería "i2chelper.c" no está incluida en los archivos adjuntos. (Aunque es fácil determinar que habrá en ella)
Se habilitan las interrupciones globales, pero el programa carece de ellas.

Hay más cosas, pero lo más importante es que los pines para el bus I²C del Master, tiene otros pines definidos en el programa, que no coinciden con los establecidos en el esquema.
 
Muchas gracias por la pronta respuesta amigos

D@rkbytes: siento la confusion con los archivos adjuntos, el tema es que no quería postear todo el proyecto para simplificar las cosas, y al prepararlo para el foro me hize en la pizza un lio, la libreria jkbd_4x4 es un simple control para el típico keypad, y el I2C helper lo hize yo, era solo para "apartar" las funciones de I2C, del archivo c principal. Y lo de las interrupciones globales, mas de lo mismo, lo siento :/
En unos minutos publicare el codigo bien.

TRILOBYTE: Tratare de buscar la correcta configuracion de fuses y posteo en unos instantes.


Muchas gracias amigos! un saludo



Respondo a mi propio mensaje porque lo solucione.

Al parecer eran pull ups lo que me faltaba, sin embargo, me mosquea lo que mencionó don TRILOBYTE sobre los fuses, ya que en proteus funciona pero no creo que lo haga en la realidad ya que en efecto realizé la prueba que me sugirió y corrió como el predijo.

Adjunto los archivos de ello funcionando.

Tal y como está hace lo que yo quería que hiciese:

- Al pulsar la tecla 'A' del keypad envia un dato int8 al esclavo a una determinada dirección.

- Al pulsar la tecla 'B' del keypad lee un dato int8 del esclavo en la mencionada dirección.

El comentario de Trilobyte me intriga, porque el siguiente paso del proyecto es preparar una interfaz usb, sobre los fuses y el oscilador, ¿ Me pregunto como hacerlo bien sin ir tan a ciegas? creo que voy a imprimir la hoja de datos!!!:unsure:
Un saludo
 

Adjuntos

  • proto.rar
    96.9 KB · Visitas: 4
Última edición:
¿lo del USB?

es facil tan facil como RS232 cuando se trata de CCS.

llamas las librerias de USB protocolo 9 y config

un USB task y metes el codigo


pero solo en CCS

por que en realidad es mas complejo de lo que imaginas.

es preparar todo el protocolo dentro del programa del micro, es muy muy complejo, debes dominar bien el micro si quieres hacer un programa serio.

no todo es como RS232

esta :

CDC que es la emulacion de RS232
HID que es una interfaz humana , teclado, raton , joystick , pero este se puede modificar para leer y escribir datos en tiempo real de manera lenta pero segura.

masstorage se comporta como una memoria, digo como protocolo , puedes enviar y recibir informacion de manera masiva

etc.

es cuestion de estudiarle y mucho
 
el siguiente paso del proyecto es preparar una interfaz usb.
Sobre los fuses y el oscilador, ¿Me pregunto, cómo hacerlo bien sin ir tan a ciegas?
En PIC C Compiler de CCS, establecer la palabra de configuración correcta, es muy sencillo.

Ejemplo partiendo de un cristal de 4 MHz para obtener los 48 MHz, que requiere el módulo USB:
#fuses NOFCMEN, NOWDT
#use delay(crystal = 4MHz, clock = 48MHz, usb_full)

De esta forma se le indica al compilador que se usará un cristal de 4 MHz, que el reloj del CPU debe oscilar a 48 MHz y que el módulo USB tiene que funcionar a su máxima velocidad.

¿Por qué sólo usé dos fuses?
Porque no es necesario siempre colocar todos.
El compilador usará los que tenga por defecto en el archivo .h correspondiente y agregará los que hagan falta.
Eso hará que nuestra palabra de configuración pueda cambiar conforme se vaya editando.

Por eso primero se compila con lo básico, se leen los fuses y se determina cuales son necesarios y cuales no.
Después se procede a editar la palabra de configuración hasta obtener fuses los adecuados.

Aquí se requirió agregar lo siguiente:
El fuse NOFCMEN (FCMEN = OFF) o sea, Fail Safe Clock Monitor Enable Bit, estará desactivado.
Este fuse hará que funcione el oscilador interno cuando falle el oscilador principal.
Pero cuando ésto suceda, lo hará a la frecuencia que está definida en el POR. (Power On Reset)
Que en el PIC18F4550 es de 1 MHz. (Si no se configura el registro OSCCON)

En ciertas ocasiones y dependiendo del programa, este fuse puede ser útil, pero si se desconoce para que sirve, les dará muchos dolores de cabeza al no saber por qué su programa se ejecuta muy lento físicamente.
O por qué, la PC no reconoce el dispositivo USB.
Y es que, al tener incorrecta la palabra de configuración, entrará automáticamente en funcionamiento el oscilador interno.

¿Por qué en ocasiones hay que deshabilitarlo?
Porque no siempre necesitamos que se active el oscilador interno, como en éste caso.
También porque nos sirve para verificar si el oscilador principal está funcionando correctamente.
Si no lo está, simplemente el microcontrolador no hará nada.

Al editar la palabra de configuración, el fuse WDT que es el Watch-Dog Timer, quedó activo, por ese motivo fue agregado.
Por defecto éste fuse casi siempre lo desactiva el compilador, pero en ésta ocasión se tuvo que agregar en OFF. (NOWDT)

Entonces, si quieres usar otro cristal por alguno que tengas, nada más debes de cambiar 4MHz por alguno que tengas disponible.
Pero ojo, no con cualquier frecuencia del cristal se pueden obtener los 48 MHz.
Ya que para obtener esa frecuencia se tiene que pasar por un PLL, un prescaler y un postescaler, no cualquier cristal es admitido.
Para eso sí tienes que ver la hoja de datos, porque ahí viene que cristales se deben usar.
 
Última edición:
Write 0x00 to unimplemented memory address 0x0fb4 does nothing,

Con esa cabecera Proteus entorpece mi obra.

Estoy utilizando un pic18lf14k50, compilo el programa con CCS y corre en proteus.

Trato de hacer que el micro reciba 232 y comunique con un esclavo via I2C.

Este proyecto funciona con otros micros pero con este en concreto me da el mencionado error.

Al parecer no salta la interrupción #int_RDA y no se por donde esté el error,

¿Es recomendable que utilice otro compilador, es decir, es un problema del compilador?
He aquí el código del maestro, y adjunto también los archivos c y dsn, etc.

Código:
#include <18lf14k50.h>
#FUSES XT,NOPROTECT ,NOMCLR

#use delay(clock=16000000)
 
#use i2c(Master,fast,sda=PIN_C0,scl=PIN_C1, force_sw)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stop=2)

 
#byte portb =0xF81
#byte latb =0xF8A
 
#include <i2chelper.c>  
 int request;
 
  
#int_RDA                
void RDA_isr(){
  request=getc();    
     printf("Valor = %u\r\n", request); //En "valor" el dato recibido via RS232
  
   delay_ms(500);
   }
 
 
void main()
{
 
   enable_interrupts(INT_RDA);   //Habilitación interrupción por recepción RS232
    enable_interrupts(GLOBAL);
     printf("Start\r\n"); 
   Envio_I2C(0xA0, 0x01, 0xAA);
   while(true)
   {
     // Envio_I2C(0xA0, 0x01, 0xAA);
      delay_ms(500);
     //Lectura_I2C(0xA0, 0x01) ; 
}
}
Muchas gracias.
 

Adjuntos

  • rs232 & I2C.rar
    66.2 KB · Visitas: 5
Última edición por un moderador:
No todos los PIC son iguales, no es lo mismo un PIC16 que un PIC18, no es lo mismo un PIC18F4550 que un pic18lf14k50. Lo que debes hacer es leer el datasheet del pic18lf14k50 eh ir descartando errores de registro.
 
¿Seguro que elegiste este modelo en el compilador? Por que la data sheet dice que es dirección no está implementada, y eso es lo que dice proteus, que no hace nada intentar escribir 0x00 en una dirección que no tiene función alguna.
 
Atrás
Arriba