Si además quieres enviarnos un Artículo para el Blog y redes sociales, pulsa el siguiente botón:
Hola a tod@s
Estoy intentando que se comuniquen dos 16F876A mediante I2C (un maestro y un esclavo) en C (CCS) ¿algun@ sabe cómo manejarse con las funciones?... por ejemplo... para enviar un dato al esclavo, según el protocolo I2C debería...
1º) Enviar un pulso de inicio (supuestamente con: i2c_start())
2º) Enviar la dirección a escribir (supongo que con: i2c_write(DIRECCION))
3º) Enviar el bit de escritura (y eso cómo lo hago? :S )
4º) Recibo el pulso de reconocimiento (lo recibo con i2c_write()?... cómo?... si eso ocurre en el paso 2º y el pulso ACK debo recibirlo en el 4º paso? O_o )
5º) Enviar el dato (supongo i2c_write())
6º) Recibir pulso ACK (en este caso es comprensible que me lo pueda dar i2c_write pues no hay bit de lectura escritura de por medio)
7º) Enviar bit de stop (con i2c_stop)
Tengo también una duda sobre el registro sspadd que contiene la dirección del esclavo en modo de 7 bits. Si no recuerdo mal, se comparan los 7 bits más altos de SSPBUF con los correspondientes de SSPADD en modo esclavo... si quisiera meter el bit de lectura/escritura en modo maestro... debería incluirlo en la dirección enviada en el paso 2º?... es decir... el dato de dirección serían los 7 bits de más peso y el octavo sería el de lectura escritura (usando algo así: i2c_write(DIRECCION + BIT);)
En fin... tengo un liiio :S . Agradezco culaquier sugerencia/comentario.
GRACIAS
ja ja ja ja, ¿ves mas facil hacerlo en ASM que en C? sé que Mundobot lo ha manejado con bastante soltura eln su robot Brutus, quiza el nos pueda aclarar un pocoel tema... de momento yo me voy a buscar algun tutorial facilillo de I2C, aunque de momento no le voy a poder sacar partido, porque tengo entre manos mover un robot a distancia, por radio, y eso siempre es RS232, pero mientras no tenga los modulos, investigare este tema, que para domótica es el sistema de comunicación mas empleado...
EUREKA! 😀
Al fin he logrado una comunicación bidireccional en I2C. Lo pude hacer "medio en C"... usé C, con fragmentos en ASM, mediante la directiva: #asm ... #endasm. Para aquellos interesados voy a explicar un poco cómo va el bus...
En principio, el bus I2C sirve para que un integrado maestro (por ejemplo un PIC) se comunique con integrados esclavos (otro PIC, una memoria EEPROM, una pantalla LCD... etc.). El bus I2C también prevee la posibilidad de que exista más de un maestro... pero para no complicar la cosa, pasaremos de este tema por ahora...
¿Qué hardware hace falta para este bus?
Pues dos cables y dos resistencias. Un cable será la "línea de reloj", y ahí se conectarán todos los pines de reloj de los esclavos, y el del maestro. El otro cable es el de datos. En este cable se conectarán todos los pines de datos de todos los esclavos y el del maestro. Además, estas líneas (y esto es muy importante) se conectarán a +5V mediante sendas resistencias de 2K aprox. una para cada línea.
¿Cómo funciona el protocolo?... En primer lugar el bus es controlado por el maestro... eso quiere decir que es el maestro el que inicia las transferencias y las recepciones.
En una transferencia o escritura sobre el esclavo, primeramente el maestro produce el pulso de inicio (START), que alerta a los esclavos de que el maestro quiere usar el bus. Luego el maestro envía la dirección, que consta de de 7 bits que forman la dirección propiamente, más un bit de lectura/escritura (R/W#) que por tratarse de una escritura en este caso vale cero, por la línea de datos, generando él los pulsos de reloj. El esclavo que identifique la dirección produce un pulso de reconocimiento. Tras esto, el maestro envía el primer byte de datos. Cuando el esclavo lo reciba, produce el pulso de reconocimiento, y así sucesivamente hasta que el maestro termine la transferencia produciendo el pulso de STOP.
En el caso de una lectura sobre el esclavo ocurre igual; el maestro produce el pulso de inicio, luego envía la dirección de 7 bits más el bit R/W#=1, el esclavo produce el pulso de reconocimiento, y el maestro genera los pulso de reloj para leer del esclavo el dato. Cuando lo lee, es el maestro el que genera el pulso de reconocimiento. El esclavo entonces prepara el próximo dato y se lo envía al maestro, produciendo éste la señal de reloj... al final... el maestro finaliza la transferencia produciendo el pulso de STOP.
En fin... os pego el código para CCS del maestro y esclavo:
*MAESTRO*
#include "C:TrabajosElectrónicaPICArchivos CCCS PCWI2C_Master_4I2C_Master_4.h"
#include <assert>
#include <ctype>
#include <errno>
#include <float>
#include <limits>
#include <locale>
#include <math>
#include <setjmp>
#include <stdio>
#include <stddef>
#include <stdlib>
#include <stdlibm>
#include <string>
#define DIREC 0xA0
#byte sspcon1 = 20
#byte sspadd = 147
#byte sspstat = 148
#byte sspcon2 = 145
void main()
{
int valor, captura;
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_INTERNAL);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
set_tris_a(0x0F);
set_tris_b(0x00);
set_tris_c(0xFE);
valor = 0;
output_bit(PIN_A5,0);
output_bit(PIN_C0,0);
captura = read_adc();
output_b(captura);
delay_ms(1000);
while(1)
{
captura = read_adc();
if(input(PIN_A1))
{
output_b(valor);
output_bit(PIN_A5,0);
output_bit(PIN_C0,0);
}
else {output_b(captura);}
if(input(PIN_A2))
{
// Rutina de petición de dato
i2c_start();
output_bit(PIN_A5,i2c_write(DIREC + 1)); // Dirección con bit de lectura (1)
valor = i2c_read(0); // Dato recibido del esclavo
i2c_stop();
delay_ms(1000); // Retardo para no enviar varias peticiones
}
if(input(PIN_A3))
{
// Rutina de envío de dato
i2c_start();
output_bit(PIN_A5,i2c_write(DIREC + 0)); // Dirección con bit de escritura (0)
output_bit(PIN_C0,i2c_write(captura)); // Dato
i2c_stop();
delay_ms(1000); // Retardo para no enviar varias peticiones
}
}
}
*ESCLAVO*
#include "C:TrabajosElectrónicaPICArchivos CCCS PCWI2C_Slave_4I2C_Slave_4.h"
#include <assert>
#include <ctype>
#include <errno>
#include <float>
#include <limits>
#include <locale>
#include <math>
#include <setjmp>
#include <stdio>
#include <stddef>
#include <stdlib>
#include <stdlibm>
#include <string>
int valor, captura;
#byte sspcon1 = 20
#byte sspadd = 147
#byte sspstat = 148
#byte sspcon2 = 145
#byte sspbuf = 19
#byte status = 3
#byte pir1 = 12
#int_SSP
SSP_isr()
{
int direcc;
output_bit(PIN_A2,1);
while(!bit_test(pir1,3));
bit_clear(pir1,3);
#asm
movf sspbuf,0
movwf direcc
#endasm
if(bit_test(direcc,0) == 0)
{
bit_set(sspcon1,4); // Desbloqueo de reloj...
while(!bit_test(pir1,3));
bit_clear(pir1,3);
#asm
movf sspbuf,0
movwf valor
#endasm
output_bit(PIN_A3,1);
}else{
#asm
movf captura,0
movwf sspbuf
#endasm
bit_set(sspcon1,4);
while(!bit_test(pir1,3));
bit_clear(pir1,3);
output_bit(PIN_A5,1);
}
bit_set(sspcon1,4);
if(bit_test(sspcon1,4)) output_bit(PIN_C0,1);
while(!bit_test(sspstat,4));
}
void main()
{
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_INTERNAL);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
set_tris_a(0x03);
set_tris_b(0x00);
set_tris_c(0x18);
delay_ms(1500);
valor = 0;
bit_set(sspcon2,0); // Bloqueo de reloj en ambas direcciones...
output_bit(PIN_C0,1);
while(1)
{
captura = read_adc();
if(input(PIN_A1))
{
output_b(valor);
output_bit(PIN_A2,0);
output_bit(PIN_A3,0);
output_bit(PIN_C0,0);
output_bit(PIN_A5,0);
}
else {output_b(captura);}
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
}
}
SALUDOS!
Hola mosvac, ahorita estoy tratando de comunicar dos pic 16F877 via I2C y hasta ahora no lo he podido hacer, coipie estas rutinas que colocastes y nada.. Espero que me puedas ayudar en esto. Gracias
¡Muy buenas compañeros!
Retomo este hilo para pediros un poco de Ayuda...
Voy a empezar esta semana con el protocolo I2C para TupperBot, pero no tengo muy claro como hacerlo, os comento lo que necesito:
TupperBot (TB) va radiocontrolado por modulos ER400TRS, que funcionan con RS232, de modo que mi "placa base" en TB tiene entrada RS232 funcionando sin problemas, con lo que puedo manejar todo, servos focos RGB, direccion... pero me acabo de comprar un LCD en superrobotica, y claro, necesito el RS232 para hacerla funcionar, pero esta conectado al modem... entonces he pensado en el I2C como solucion...
Usar el I2C me va a obligar a mejorar muchas placas de las que lleva, pero tengo dos problemas importantes:
1- No tengo ni idea de como empezar, y me gustaria hacerlo en C puro, sin ASM... ja ja ja, alguien tiene algun tutorial?
2- El radio modem va a seguir estando, de modo que al menos una de mis placas va a usar tanto RS232 como I2C... si para ambos protocolos se usan los mismos pines... qué puedo hacer? La nueva estructura que he pensado para TB es asi:
------------------5 PWMs
---------------------/
---------------------||
Modem<--->Placa principal<--->I2C<--->LCD
---------------------||
---------------------/
------------------Motores
No se si me he explicado...
Mif, que micro usas? el PIC16F877 (y otros con el mismo encapsulado) tienen los pines de RS232 (Tx, Rx) e I2C(SCL, SDA) separados (lo que si que tienen juntos es el I2C y el SPI).
Si no es así no vas a poder usarlo.
S2
Ranganok Schahzaman
Edito: si los tienes juntos si que podrás usarlo pero tendras que implementar el I2C por soft.