PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I2C Master / Slave 16F887/16F883



Ja ne, is klar
16.05.2012, 15:07
Hi zusammen,

Zur Zeit versuche ich eine Kommunikation zwischen zwei uC hin zubekommen. Da es mein erstes I2C Projekt ist, habe ich den Code aus dem Internet kopiert und an meine PIC's angepasst. Original sind die Code's für den 16F876A.

Hier der Mastercode. [16F887]


// 16F887

const Slave_Addy = 0x69;

void send(unsigned short send_data){
I2C1_Init(100000);
I2C1_Start();
I2C1_Wr(Slave_Addy);
I2C1_Wr(send_data);
I2C1_Stop();
}

unsigned short read(){
unsigned short read_data;
I2C1_Init(100000);
I2C1_Start();
I2C1_Wr(Slave_Addy + 1);
read_data = I2C1_Rd(0);
delay_ms(100);
I2C1_Stop();
return read_data;
}

void main(){
ANSEL = 0;
ANSELH = 0;
TRISA = 0;
PORTA = 0b00001111;
TRISB = 0;
PORTB = 0;
PORTC = 255;

while (1) {
send(166);
PORTA != PORTA;
delay_ms(2000);
}

// Main program code place here.
// Use sub-routine "send" to send data to slave.
// Use "read" to read data from slave.

Hier der Slavecode [16F883]


// 16F883

//------------------------------------------------------------------------------
const Addy = 0x69; // set I2C device address
const Delay_Time = 250; // port check delay
//------------------------------------------------------------------------------
// Global Processing Variables
//------------------------------------------------------------------------------
unsigned short j; // just dummy for buffer read
unsigned short rxbuffer; //
unsigned short tx_data; //
//------------------------------------------------------------------------------
void Init(){
ANSEL = 0; // All ports set to digital
ANSELH = 0;
TRISA = 0; // Set PORTA as output
PORTA = 0;
TRISB = 0; // Set PORTB as output
PORTB = 0;
TRISC = 0b00011000; // Set PORTC as input
PORTC = 0;
SSPADD = Addy; // Get address (7bit). Lsb is read/write flag
SSPCON = 0x36; // Set to I2C slave with 7-bit address
PIE1.SSPIE = 1; // enable SSP interrupts
PIR1.SSPIF = 0;
SSPSTAT.R_W = 0;
SSPSTAT.BF = 1;
SSPSTAT.D_A = 0;
INTCON = 0xC0; // enable INTCON.GIE
}
//------------------------------------------------------------------------------
void interrupt(){ // I2C slave interrupt handler
if (PIR1.SSPIF == 1){ // I2C Interrupt
PIR1.SSPIF = 0; // reset SSP interrupt flag
RB7_bit = 1; // Nur zum Debugen
//transmit data to master
if (SSPSTAT.R_W == 1){ // Read request from master
SSPBUF = tx_data; // Get data to send
SSPCON.CKP = 1; // Release SCL line
j = SSPBUF;
RB6_bit = 1; // Nur zum Debugen
return;
}
if (SSPSTAT.BF == 0){ // all done,
j = SSPBUF; // Nothing in buffer so exit
RB5_bit = 1; // Nur zum Debugen
return;
}

//recieve data from master
if (SSPSTAT.D_A == 1){ // Data [not address]
rxbuffer = SSPBUF; // get data
j = SSPBUF; // read buffer to clear flag [address]
RB4_bit = 1; // Nur zum Debugen
return;
}
}
RB3_bit = 1; // Nur zum Debugen
j = SSPBUF; // read buffer to clear flag [address]
}
//------------------------------------------------------------------------------
void main(){
Init();
while(1){
PORTC = rxbuffer;
tx_data = 170;
Delay_ms(Delay_Time);
RB2_bit = 1;
}
}


Nun das Problem:
Der Master sendet den Wert "166" welche beim Slave nie wirklich ankommen. SDA bleibt nach diesem Versuch auf low.
Beim Slave setze ich die Ausgänge vom PORTB, um zu debugen :cheesy: So habe ich erkannt das ein Interrupt stattfinden, jedoch scheint mir das SSPSTAT.R_W bit fehlerhaft. Dieses Bit wird als "1" gelesen, als ob der Master vom Slave lesen will...will er aber nicht.

Habt ihr eine Idee warum es nicht funktioniert? Etwas Hilfe könnte ich gut gebrauchen ;)

Ps. Ich programmiere in MikroC mit dem EasyPic7 Board. Die Kommunikation zwischen Master und Eeprom funktioniert. Pull-Ups sind auch drin und Verdrahtung habe ich geprüft. Ach ja, der Slave ist mit etwa 30cm Litzen zum Board verdrahtet (Problem?)

Ritchie
17.05.2012, 17:59
Hi,
ich hatte I2C immer in ASM für Slave-PICs programmiert. Die Sachen in C sind mir nicht so geläufig.
Hier aber eine gute PIC Seite: http://www.sprut.de/electronic/pic/grund/i2c.htm

Irgendwie habe ich das Gefühl, Du hast Deine Adressangabe falsch gemacht:




const Slave_Addy = 0x69;
void send(unsigned short send_data)
{
I2C1_Init(100000);
I2C1_Start();
I2C1_Wr(Slave_Addy); <----- Wird hier verwendet!!!!
I2C1_Wr(send_data);
I2C1_Stop();


Hier ist das Bit 0 in der Addresse gesetzt und sagt aus, das es sich um einen Lese Befehl handelt.

Prüfe Deine Adressen nochmals.

Gruss R.

Ja ne, is klar
17.05.2012, 19:28
Hab deinen Rat befolgt und die Adresse auf den Wert 0x68 geändert (damit ist das erste Bit auf low), und siehe da, es funktioniert!\\:D/
Auch das Auslesen vom Slave hat geklappt. Schöne Sache.
Die Seite "Sprut" ist mir bekannt, aber leider sind keine Slave Beispiele aufgeführt.

Vielen Dank Ritchie