Hi Leutz, ich bin vor einiger Zeit auf den WinAVR umgestiegen (von CodeVision) und breche mir mit dem I2C-Bus ganz schön einen ab. Alle Beispiele, die ich bisher gefunden habe, waren nicht umzusetzen :-( Hat jemand eine in C geschriebene I2C-Routine (Start, Stop, Write, Read), die er zur Verfügung stellen könnte ? Vielen Dank!
Vielleicht hilft das, war für ein ATmega161: #define READ 0x01 // I2C READ bit #define SCLPORT PORTE #define SDAPORT PORTD #define SCL PE2 #define SDA PD2 #define QDEL delay(5) #define HDEL delay(10) #define I2C_SDL_LO cbi( SDAPORT, SDA) #define I2C_SDL_HI sbi( SDAPORT, SDA) #define I2C_SCL_LO cbi( SCLPORT, SCL); #define I2C_SCL_HI sbi( SCLPORT, SCL); void i2ct(void) { HDEL; I2C_SCL_HI; HDEL; I2C_SCL_LO; } void i2cstart(void) { I2C_SDL_LO; QDEL; I2C_SCL_LO; } void i2cstop(void) { HDEL; I2C_SCL_HI; QDEL; I2C_SDL_HI; HDEL; } #define I2C_SCL_TOGGLE i2ct(); #define I2C_START i2cstart(); #define I2C_STOP i2cstop(); u16 i2c_putbyte(u08 b) { s16 i; for (i=7;i>=0;i--) { if ( b & (1<<i) ) I2C_SDL_HI; else I2C_SDL_LO; // address bit I2C_SCL_TOGGLE; // clock HI, delay, then LO } I2C_SDL_HI; // leave SDL HI // added cbi(SDAPORT-1, SDA); // change direction to input on SDA line (may not be needed) HDEL; I2C_SCL_HI; // clock back up b = inp(SDAPORT-2) & (1<<SDA); // get the ACK bit HDEL; I2C_SCL_LO; // not really ?? sbi(SDAPORT-1, SDA); // change direction back to output HDEL; //printf("put: %x\r\n",b); return (b == 0); // return ACK value } u08 i2c_getbyte(u16 last) { s16 i; u08 b = 0; u08 c = 0; I2C_SDL_HI; // make sure pullups are ativated cbi(DDRD, SDA); // change direction to input on SDA line (may not be needed) for (i=7;i>=0;i--) { HDEL; I2C_SCL_HI; // clock HI c = bit_is_set(SDAPORT-2, SDA); b <<= 1; if (c) b |= 1; HDEL; I2C_SCL_LO; // clock LO } sbi(DDRD, SDA); // change direction to output on SDA line if (last) I2C_SDL_HI; // set NAK else I2C_SDL_LO; // set ACK I2C_SCL_TOGGLE; // clock pulse I2C_SDL_HI; // leave with SDL HI return b; // return received byte }
@Tomasz: Ich glaube kaum das Thorsten dieses Bsp. weiterhilft, das der ATmega16 ein TWI hardwareseitig implementiert hat, beim AT90S8535 muss man I2C dagegen komplett in SW entwickeln.
@µC-Anfänger: der Code ist für Atmega161, der KEINEN TWI hat. Ist also ein software I2C. augen auf
Hi, danke für die Hilfe. Hatte schon mal ein Beispiel, wo sbi und cbi genutzt wurden, das kann der WinAVR nicht compilieren. Warum liegen sda und scl an Port D und E ? Hab nur Port D ;-) Meine Leitungen liegen an: SDA PORTD.6 SCL PORTD.7 ------------------ Ein Beispiel habe ich geändert, und es lässt sich auch compilieren. Leider läufts nicht bzw. bekomme ich es nicht zum laufen. Vielleicht wird einer draus schlau ? Leider hab ich von I2C nicht allzuviel Ahnung ;-) /*************************************************** / I2C-Library / / Stellt I2C-Routinen für den MSP430F149 bereit. SDA / ist an Pin 47 angeschlossen, SCL an Pin 48. Wenn / ihr andere Ports benutzt , müsst ihr nur hier in / dieser Datei jeweils "P5OUT=..." passend ersetzen. / Die delay_ms()-Funktion befindet sich in der Datei / http://www.mathar.com/lcd.c. /***************************************************/ //Pin 47 = SDA = P5.3 (0x08) = PORTD.6 = 0x40 (64) //Pin 48 = SCL = P5.4 (0x10) = PORTD.7 = 0x80 (128) //Pin-Table: //0 1 2 4 8 16 32 64 128 256 //- 0 1 2 3 4 5 6 7 - void SCL_low(void); void SCL_high(void); void SCL_clock(void); void SDA_low(void); void SDA_high(void); void SDA_read(void); void SDA_write(void); void SCL_write(void); void SCL_read(void); void I2C_start(void); void I2C_stop(); void I2C_init(char address, char r_w); int I2C_gotACK(void); void I2C_sendbyte(char byte); double I2C_receivebyte(void); void I2C_sendACK(void); void SCL_low(void) // pin 48 (SCL) auf low setzen { PORTD&=~0x80; delay_ms(1); // 1ms warten (rise time, fall time usw.) } void SCL_high(void) // pin 48 (SCL) auf high setzen { PORTD|=0x80; delay_ms(1); } void SCL_clock(void) { SCL_high(); SCL_low(); } void SDA_low(void) // pin 47 (SDA) auf low setzen { PORTD&=~0x40; delay_ms(1); } void SDA_high(void) // pin 47 (SDA) auf high setzen { PORTD|=0x40; delay_ms(1); } void SDA_write(void) // pin 47 (SDA) auf output setzen { DDRD|=0x40; } void SDA_read(void) // pin 47 (SDA) auf input setzen { DDRD&=~0x40; } void SCL_write(void) // pin 48 (SCL) auf output setzen { DDRD|=0x80; } void SCL_read(void) // pin 48 (SCL) auf input setzen { DDRD&=~0x80; } void I2C_start(void) // I2C START condition auf den bus senden { SCL_write(); SDA_write(); SCL_low(); SDA_high(); SCL_high(); SDA_low(); SCL_low(); } void I2C_init(char address, char r_w) // I2C-device mit adresse "address" lesend oder schreibend initialisieren { char i; SDA_write(); // sicherheitshalber erst mal SDA und SCL auf write setzen SCL_write(); SCL_low(); // sicherheitshalber erst mal SCL auf low setzen for (i=7; i>0; i--) // 7-bit-I2C-adresse senden { if (address&(1<<(i-1))) SDA_high(); else SDA_low(); SCL_clock(); } if (r_w=='r') SDA_high(); else SDA_low(); SCL_clock(); // 1 oder 0 senden (read oder write) } int I2C_gotACK(void) // nachschauen, ob ein ACK vom bus empfangen wurde { char gotACK; SCL_write(); SCL_low(); // sicherheitshalber erst mal SCL auf low setzen SDA_read(); // sicherheitshalber erst mal SDA auf read und SCL auf write setzen SCL_high(); // jetzt SCL auf high setzen und damit 9. clockpulse erzeugen if (!(PIND & 0x40)) gotACK=1; else gotACK=0; SCL_low(); // jetzt SCL wieder auf low setzen if (gotACK) return 1; else return 0; } void I2C_sendbyte(char byte) // ein komplettes byte auf den bus schicken { char i; SDA_write(); // sicherheitshalber erst mal SDA und SCL auf write setzen SCL_write(); SCL_low(); // sicherheitshalber erst mal SCL auf low setzen for (i=8; i>0; i--) { if (byte&(1<<(i-1))) SDA_high(); else SDA_low(); SCL_clock(); } } double I2C_receivebyte(void) // ein komplettes byte vom bus empfangen { double byte=0; SCL_low(); SDA_read(); // sicherheitshalber erst mal SCL auf low und SDA auf read setzen SCL_high(); if ((PIND&0x40)>>3) byte+=128; SCL_low(); SCL_high(); if ((PIND&0x40)>>3) byte+=64; SCL_low(); SCL_high(); if ((PIND&0x40)>>3) byte+=32; SCL_low(); SCL_high(); if ((PIND&0x40)>>3) byte+=16; SCL_low(); SCL_high(); if ((PIND&0x40)>>3) byte+=8; SCL_low(); SCL_high(); if ((PIND&0x40)>>3) byte+=4; SCL_low(); SCL_high(); if ((PIND&0x40)>>3) byte+=2; SCL_low(); SCL_high(); if ((PIND&0x40)>>3) byte+=1; SCL_low(); return byte; } void I2C_sendACK(void) // ACK auf den bus schicken { SDA_low(); SDA_write(); SDA_low(); SCL_clock(); } void I2C_stop() // I2C STOP condition auf den bus senden { SCL_write(); SCL_low(); SDA_write(); SDA_low(); SCL_high(); SDA_high(); }
Ich benutze WinAVR und damit lässt es sich compilieren. Die von mir benutzten Ports sind aufgrund der Hardwarebeschaltung (Atmega161 hat Port E). Du kannst es natürlich für deine Zwecke anpassen.
Beitrag #5451874 wurde von einem Moderator gelöscht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.