¿Podés mostrar el código? Para activar la interrupción creo que en CCS tienes que escribir algo así "enable_interrupt(xxx)" y "enable_interrupt(global)" Siendo xxx la interrupción que quieras activar.
Yo no veo ningún código que corresponda a la interrupción SSP en el esclavo 1. Está la definición, pero no la implementación.
Por lo tanto, si no hay implementación no vas a poder hacer nada.
Void SSP_Interuptel compilador piensa que es otra funcion mas... :mrgreen: :mrgreen:
Los signos de pregunta, se deben a que el debbuger detecta actividad del bus pero no puede interpretarla.
¿Que tipo de resistencia estás colocando en proteus para la simulación?
Generalmente para simular bien el bus I2C no hay que usar las resistencias comunes sino unas llamadas pullups que se encuentran en la categoría "Modelling primitives"
Deberias poner tu ultimo codigo (completo) para ver que puede estar causandote esto, incluso alguno podria compilarlo y ver que pasa para ayudarte.
Si pones el codigo, usa GeShi y la opcion C o C++.
Creo que el nudo lo has creado tu mismo, queriendo hacer todo en librerias externas.
Prueba a hacer un solo programa para cada PIC, porque esta muy enredado y me parece que tienes que poner el codigo de interrupcion directamente dentro de la rutina, porque no soporta declaracion de funciones en la interrupcion.
La verdad es que mi experiencia con el I2C no es de las mas gandes, solo use un IC de reloj y unas memorias, y nunca lo use con interrupciones, asi que no creo ser el mejor para decirte si asi como las usas esta bien o mal, pero en mi opinion deberias arrancar con un solo esclavo y un maestro, sin interrupciones y luego ir creciendo despacio, hasta que le tomes la mano bien al tema.
Viendo las dificultades de este post, hice lo propio pero con el compilador HiTech y pude comprobar que sí entra en la interrupción.
Ahora bien, sucede algo que creo no es lo correcto, lo detallo... Cuando mandaba la dirección del esclavo1, entraba en la interrupción del mismo y por supuesto respondía con ACK. De manera inmediata le enviaba un dato, pero ahora ingresaba en la interrupción de los dos esclavos y me da la sensación que es el segundo esclavo el que está respondiendo con ACK lo cual estaría mal.
si el master indica con quien se quiere comunicar.
¿Quien es el que detecta la direcion o discrimina la direcion,..es el propio esclavo?
Citarsi el master indica con quien se quiere comunicar.
¿Quien es el que detecta la direcion o discrimina la direcion,..es el propio esclavo?
Si fuera el bus SPI, que tiene un pin de ChipSelect o CS, que obliga al esclavo a atender, diria que no, porque el direccionamiento es por hardware.
En el caso del I2C, el maestro envia la direccion del esclavo que debe responder a los comandos (lectura o escritura) y el esclavo (en realidad todos los esclavos que estan en el bus) comparan esa direccion con la suya propia, y responde el que corresponde a esa direccion solamente.
Una cosa que nunca revisamos de tu codigo es eso, que direccion tienen tus esclavos y cuales son las que consulta el maestro !!
Hola AngelGris
La idea es muchos PIC tienen i2c y otros no tienen,
y los que tienen solo tienen un canal, asi que por eso lo intento sin forzar hardware
aunque los pines del i2c son los pines fisico.
Por el momento desconozco si tendra alguna diferencia entre forzar harware,
forzar software o no poner la sentencia que especifica ese estado,
por el contrario no se si al no especificar nada al compilador este le pondra una por defecto y tal caso
cual tomara o que caso le aplicara.
se de leer por ahi que por hardware es el hardware el que configura retardos y tiempos
miestras por software lo tienes que hacer tu de esas maneras.
Tambien desconozco si se pone en el master, o en el esclavo o se pone en ambos,
(no lo confirme o contraste con otras fuentes) tambien deconozco si se puede
combinar dispositivos forzados en harware y dispositivos forzados en sofware
dentro del mismo bus.
La logica me dice que se deberia de poder hacer esto a nivel independiente de dispositivo no de bus,
me gustaria poder probarlo pero con esto de la interrupcion me tiene aqui bien cogido.
¿que es eso de la interrupcion de dispositivo?
Hola
En el codigo de esclavo 1
...
nada = SSPBUF; // Limpio el Buffer
SSPOV = 0; // Limpio el flag de overflow
SSPIE = 1; // Habilito interrupcion por SSP
PEIE = 1; // Habilito interrupcion de perifericos
GIE = 1; // Habilito las interrupciones globales
..
Me referia a lo de interrupcion de periferico
te pregunto porque intento comprender el codigo de tu compilador
para ver si consigo que funcione en el mio que es con ccs..
***Ya probe lo de forzar hardware,
no funciona estamos en las mismas..
¿Que version de proteus usas?
¿Que retardos usas para la inicializacion?
hace un rato lei algo de un enlace y por lo visto el INT_SSP a mas de uno
le dio dolores de cabeza..
encontre unos enlaces:
http://www.todopic.com.ar/foros/index.php?topic=5312.0
http://www.ucontrol.com.ar/forosmf/problemas-con-mis-proyectos/problema-con-pic16f877a-y-pic16f876a-como-esclavos-i2c/?PHPSESSID=lo7u704ntfc07udqs8p0fivpp7
en estos codigos encontre una similitud con el tuyo ambos usais el BF y otras variables
de donde las has obtenido, porque las declaras con esos nombres tan especiales..
en ccs estaran declarados u las tendre que declar para usarlas..
Continuo con el code..
Hola AngelGris
en tu codigo del esclavo,
vi que asignas el dato recibido a una variable
y esa variable la asignas a un puerto,
con ello ¿equivaldria a enceder y apagar los bit de un puerto?
....
else // si no hay overflow proceso el dato
{
if (BF == 1) // si hay dato
{
if (RW == 0) // esclavo para escritura
{
lectura = read_i2c(0);
if (DA == 1) PORTB = lectura; // si llego un dato, lo mando al puerto
}
}
if (RW == 1) write_i2c(0x77); // esclavo para lectura
}
SSPIF = 0;
....
ahora me surgen 4 preguntas...
¿ese dato lo puedes asignar a cualquier "cosa" (variable)?
- igual que lo asignas un puerto lo podrias asignar al comando de definicion del puerto (TRISB)
me esplico:
en principio lo declaras como entradas y mediante ese dato lo redeclaras como salia o al reves.
- otra cosa en tu ejemplo cuando escribes le pasas la direccion del esclavo y el dato.
en algunas otras funciones le pasan una direcion donde escribir
- si le pasaramos la direcion del esclavo ,la direccion del puertox , y el dato funcionaria verdad?
sigo con el codigo...
Angelgris cuando usas BF , RW
lo declaras de alguna forma ?
en el fichero de cabecera lo deberas de tener definido en alguna direcion?
por eso no lo declaras en el programa..!
¿Estoy en lo cierto?
Te dejo el archivo de encabezado...
El número indica la dirección que tiene el registro en el mapa de memoria del pic, no tiene nada que ver que un registro sea de 8 bits.
Si tuviese un registro en última dirección de un mapa de 0xFFFF posiciones, la dirección de dicho registro sería 0xFFFE sin importar que el resto de los registros sea de 8 bits.
No encuentro ningún archivo de cabecera para 18F250
El número indica la dirección que tiene el registro en el mapa de memoria del pic, no tiene nada que ver que un registro sea de 8 bits.
Si tuviese un registro en última dirección de un mapa de 0xFFFF posiciones, la dirección de dicho registro sería 0xFFFE sin importar que el resto de los registros sea de 8 bits.
No encuentro ningún archivo de cabecera para 18F250
............
coasas que me faltan:
me puedes confirma estas cosillas...?
cosas que dudo si se corresponderan:
- SSPIF == 1) // interrupcion SSP
bit 3 del PIR1 y PIR1 es
PIR1: PERIPHERAL INTERRUPT REQUEST (FLAG) REGISTER 1
- SSPOV == 1) // si hay overflow leo el buffer y borro dicho flag
bit 6 del registro del
SSPCON1: MSSP CONTROL REGISTER 1 (I2C™ MODE)
- BF == 1) // si esta lleno el buffer
BF
se corresponde con el bit 0 del registro
SSPSTAT: MSSP STATUS REGISTER (I2C™ MODE)
- RW == 0
rw : RD or WR
de este no encontre nada .... :(
no ser que se coresponda con el bit 2 del
SSPSTAT: MSSP STATUS REGISTER
- DA == 1
da : SPP data write
de este no encontre nada .... :(
- SSPIF = 0; // borro el flag de interrupcion
PIR1: PERIPHERAL INTERRUPT REQUEST (FLAG) REGISTER 1
el bit 3 de este registro es el SSPIF (segun data)
SSPIF: Master Synchronous Serial Port Interrupt Flag bit
1 = The transmission/reception is complete (must be cleared in software)
0 = Waiting to transmit/receive
- SSPIE = 1; // Habilito interrupcion por SSP
enable_interrupts(INT_SSP);
- PEIE = 1; // Habilito interrupcion de perifericos
enable_interrupts(....); // no se con cual se correspondera o su hara falta
lo mas parecido que encontre en le data es el regidstro de control de interrupciones
PIE1,PIE2 estas partenecen a una lista de 10 , las cuales se usan para el control de inerrupciones (pag 99)
pero mas abajo encontre el PEIE:
INTCON: INTERRUPT CONTROL REGISTER(pag_101):
PEIE es el bit 6 del INTCON
pero en el fichero de cabecera de mi pic donde estan definidas los tipos de interrupciones no aparece
o no la reconozco y aparece con otro nombre
- GIE = 1; // Habilito las interrupciones globales
enable_interrupts(GLOBAL);
volvemos al codigo ...
Efectivamente la forma de visualizar los registros es utilizando el watch window.
Corrobora que la forma en que estás utilizando la sentencia "#byte" sea la correcta. Como no utilizo CCS no sé si lleva el "=" o no.
#BYTE id = x
Elements:
id is a valid C identifier, x is a C variable or a constant
Purpose:
If the id is already known as a C variable then this will locate the variable at address x. In this case the variable type does not change from the original definition. If the id is not known a new C variable is created and placed at address x with the type int (8 bit)
Warning:
In both cases memory at x is not exclusive to this variable. Other variables may be located at the same location. In fact when x is a variable, then id and x share the same memory location.
En respuesta a la primer pregunta, PORTB = lectura es para que salga por el puerto B el dato que me llego vía I2C. Simplemente es para corroborar que llegó bien el dato.
En cuanto a la segunda pregunta... i2c_write(0x77).... me refiero a que llega a ésa línea cuando el esclavo es accedido para lectura (es decir que el master quiere leer un dato desde el esclavo) y 0x77 es el dato que el esclavo le envía al master.
Me llama bastante la atencion como usas las instrucciones I2C, por eso refresque un poco lo que habia usado, mirando las librerias actuales de CCS, en este caso para una memoria.
Pongo el codigo que usan para escritura, mira bien como separan las instrucciones, y prueba hacerlo en tus programas a ver como te va...Código: C++
int1 ext_eeprom_ready() { int1 ack; i2c_start(); // If the write command is acknowledged, ack = i2c_write(0xa0); // then the device is ready. i2c_stop(); return !ack; } void write_ext_eeprom(EEPROM_ADDRESS address, BYTE data) { while(!ext_eeprom_ready()); i2c_start(); i2c_write((0xa0|(BYTE)(address>>7))&0xfe); i2c_write(address); i2c_write(data); i2c_stop(); }
Hago los cambios necesarios, seguramente será sólo en lo que respecta a los bits de configuración y te comento.
Tal vez en tu caso no entra en la interrupción porque no está utilizando el módulo SSP.... sino no le encuentro otra explicación... o tal vez la versión de Preoteus. Yo estoy utilizando la 7.8 SP2
Después de tener que cambiar de versión del compilador para PIC18 pude compilar bien el programa y lo pude simular constatando que sí responde bien el esclavo por interrupciones en el PIC18F2550.
De dejo el circuito que estoy utilizando.
Hola
En ccs el while (1) da error algunas veces, yo lo que hago
es sustutuirlo por true
ya que en la libreria tiene sustituido true por 1 y false por 0.
no se si te entendi bien,
¿falta un bucle while por algun lado?,
o es el while del main?
En el master no hay instruccion de while(){..} ni de do{}while()
y en el esclavo tampoco.