So mach ich das auch, nur mit nem normalen i2c_start statt i2c-start_wait.
Ah okay, ich hab festgestellt ist ja assembler. Ausserdem da ich Atmega8 benutze, kann ich die twimaster.c file benutzen...
Leider klappt es immer noch nicht. Ich habe meinem Slave die Adresse 0x02 zugewiesen und versuche also mit
auf den Slave zu schreiben.Code:i2c_start_wait(0x02+I2C_WRITE); // set device address and write mode i2c_write(0x01); // write address = 5 i2c_write(0x0E); // write value 0x75 to EEPROM i2c_stop(); // set stop conditon = release bus
Im Slave möchte ich dann diesen Wert mit
xyz = rxbuffer[1];
auslesen....ist das richtig so?
So mach ich das auch, nur mit nem normalen i2c_start statt i2c-start_wait.
Es funktioniert! JuhuuuuuuuuU!![]()
Ich bin so glücklich! Benutzt habe ich wie gesagt die Libs von P.Fleury und Uwegw
Aber: Mein Slave scheint nach der ersten Übertragung keinen weiteren Wert mehr akzeptieren zu wollen...![]()
So soll es aussehen. Ich drück am Master einen Knopf -> der erste Wert wird zum Slave übertragen und angezeigt (per Ziffern) -> Ich drücke noch einmal, und es sollte der 2.Wert übertragen und angezeigt werden...
Kurze Anregung woran das liegen könnte? Quellcode reiche ich nach...
Apropos: Danke für die Hilfe bis hier her! =D>
Hatt ich in der Freude vergessen zu schreiben![]()
Also es ist mittlerweile so weit gediehen, dass immer wieder übertragen wird. Manchmal scheint das ganze aber zu hängen, sprich der Master sendet nach einer Übertragung kein Stoppsignal mehr. Auf welche Fehlerquellen könnte das deuten?
Hier nun die Codes für Master:
Und für den Slave:Code:#include <avr/io.h> #include <avr/interrupt.h> #include "i2cmaster.h" #include <compat/twi.h> void timer_init(void){ TCCR0 = (1 << CS02); //Frequenzteilung durch 256 } void main(void){ DDRD = 0x00; //PORTD als Eingang PORTD = 0xFF; // Pull-Up Widerstände an Port D aktiviert -> Schalter als Active-Low ausführen DDRB = 0xFF; PORTB = 0x00; //hier hängen LEDs dran, um eventuell beim Fehlersuchen zu helfen unsigned int overflow_counter = 0; unsigned char goal1[2]; goal1[0] = 0; goal1[1] = 0; timer_init(); i2c_init(); PORTB = (1 <<PB0); for(;;){ PORTB = 0x00; if ( TIFR & (1<<TOV0) ) {//wenn die timer/counter0 overflow Fahne '1' ist, dass ist immer wenn 1/152 sec erreicht sind (10Mhz/(256*256)) TIFR |= (1<<TOV0) ; //Overflow Bit wieder auf null setzen overflow_counter++; //overflow counter inkrementieren } if (!(PIND & (1 << PD7)) && (overflow_counter > 100)){ PORTB = (1<<PB0); goal[1]++; i2c_start_wait(0x02+I2C_WRITE); // set device address and write mode i2c_write(0x02); // write address = 2 i2c_write(goal1[1]); // write value goal[i] to Slave i2c_stop(); i++; overflow_counter = 0; } } } //end of bedienfeld.cCode://clockspeed 4Mhz -> /* Dies ist das C-File für die Anzeigensteuerung, das I2C wird über einen Interrupt ausgelöst*/ #include <avr/io.h> #include "show_digits.h" //File für die Umwandlung von Zehner- und Einserdezimal in BCD #include <compat/twi.h> #include <avr/interrupt.h> #include "i2cnew/twislave.h" #include <util/twi.h> volatile unsigned char goal1 = 0; volatile unsigned char goal2 = 0; void timer_init(void){ TCCR0 = (1 << CS00); //Timer / Counter Control Register is set to devide by 8 } void main(void){ int overflow_counter = 0; //overflow counter zählt die counter bit overflows int pin_counter = 0; DDRB = 0xFF; PORTB = 0x00; DDRD = 0xFF; //Alle PortD Pins auf Ausgang gesetzt (PD0-3 für BCD, PD4-7 für Ziffer 1-4) PORTD = 0x00; //Alles auf Low, Anzeige aus timer_init(); //timer wird gestartet int i = 0; init_twi_slave(0x02); //Alles für TWI Übertragung fertig machen rxbuffer[6] = 78; rxbuffer[2] = 00; for(;;){ PORTB = 0x00; goal1 = rxbuffer[2]; if ( TIFR & (1<<TOV0) ) {//wenn die timer/counter0 overflow Fahne '1' ist, dass ist immer wenn 1/195 sec erreicht sind (4Mhz/(8*256)) TIFR |= (1<<TOV0) ; //Overflow Bit wieder auf null setzen overflow_counter++; //overflow counter inkrementieren } if (overflow_counter==30) {//Nach 10x256x8 = 20480 overflows oder 50ms PORTD = 0x00; //Alle Ausgänge ausschalten PORTD |= (1 << PD4); //Tor 1 Zehner anschalten show_ten(goal1); } else if (overflow_counter==60) { PORTD = 0x00; //Alle Ausgänge ausschalten PORTD |= (1 << PD5); //Tor 1 Einser anschalten show_one(goal1); } else if (overflow_counter==90) { PORTD = 0x00; //Alle Ausgänge ausschalten PORTD |= (1 << PD6); //Tor 2 Zehner anschalten show_ten(goal2); } else if (overflow_counter==120) { PORTD = 0x00; //Alle Ausgänge ausschalten PORTD |= (1 << PD7); //Tor 2 Einser anschalten show_one(goal2); overflow_counter=0; pin_counter++; } if (pin_counter > 60){ i++; pin_counter = 0; } if (i == 7){ i=0; } } }
Hallo, wenn ich an dieses Thread mal anknüpfen darf ....
Ich möchte ebenfalls einen ATmega8 als Slave verwenden (RN-Mini Control), nun habe ich das Problem, dass jedes mal wenn ich vom Master aus was senden möchte scheinbar ein Reset an dem ATmega8 ausgeführt wird. Ich sende vom Master aus an den Slave (Code für Slave steht unten) ein Byte in das register rxbuffer[0]. Jedoch schaltet sich die Diode die an Port PC1 hängt über die If-Abfrage in der for-Schleife nie ein, sondern der AVR startet anscheinden neu weil sie dann kurz aufblinkt.
Was mache ich falsch bitte um Hilfe ...![]()
P.S. benutze auch die Libs von P.Fleury und Uwegw, nur die i2cmaster.S habe ich gelöscht da ich die twimaster.c verwende.
Code:#include <avr/interrupt.h> #include <avr/signal.h> #include <compat/twi.h> #include <avr/io.h> #include <compat/twi.h> #define F_CPU 16000000 volatile uint8_t rxbuffer[8]; #define rx_PWM_L 2 #define rx_PWM_R 3 #define rx_DIR 1 volatile uint8_t txbuffer[8] void init_twi_slave (uint8_t adr) { TWAR= adr; //Adresse setzen TWCR|= (1<<TWEA) | (1<<TWEN)|(1<<TWIE); TWCR &= ~(1<<TWSTA)|(1<<TWSTO); buffer_adr=0xFF; sei(); } int main(void) { /*******************************************************************************************************************/ /* Initialisierung */ /*******************************************************************************************************************/ //*** Alle Ports an PortD als Ausgang definieren DDRB = 0xFF; PORTB = 0x00; DDRD = 0xFF; PORTD = 0x00; DDRC = 0xFF; PORTC= 0x00; PORTC &= ~(1<<DDC1); init_twi_slave(0x60); // Init I2C interface Delay(1000); // Diode einmal anblicken ob sie funktioniert PORTC |= (1<<DDC1); Delay(400); PORTC &= ~(1<<DDC1); Delay(400); rxbuffer[0]=0; for(;;){ if (rxbuffer[0]!= 0){ PORTC |= (1<<DDC1); Delay(2000); } }
Hallo,
Es gibt keine ISR, das Bit wird aber aktiviert, deshalb gehts bei einem IRQ dann ab zum Reset !
Und es macht sich nicht Gut, das TWCR per OR oder AND zu manipulieren (bzw. in zwei Zeilen aufeinander), denn jeder Schreibzugriff löst eine Aktion aus, also immer die benötigten Bits setzen und alles auf einmal ans TWCR übergeben !
Ups sorry, die ISR muss wohl beim "copy pasten" unter den Tisch gefallen sein. Hier nochmal dem komplette Code Problem wie beschrieben
Code:#include <avr/interrupt.h> #include <avr/signal.h> #include <compat/twi.h> #include <avr/io.h> #include <compat/twi.h> #define F_CPU 16000000 volatile uint8_t rxbuffer[8]; #define rx_PWM_L 2 #define rx_PWM_R 3 #define rx_DIR 1 volatile uint8_t txbuffer[8] void init_twi_slave (uint8_t adr) { TWAR= adr; //Adresse setzen TWCR|= (1<<TWEA) | (1<<TWEN)|(1<<TWIE); TWCR &= ~(1<<TWSTA)|(1<<TWSTO); buffer_adr=0xFF; sei(); } int main(void) { /*******************************************************************************************************************/ /* Initialisierung */ /*******************************************************************************************************************/ //*** Alle Ports an PortD als Ausgang definieren DDRB = 0xFF; PORTB = 0x00; DDRD = 0xFF; PORTD = 0x00; DDRC = 0xFF; PORTC= 0x00; PORTC &= ~(1<<DDC1); init_twi_slave(0x60); // Init I2C interface Delay(1000); // Diode einmal anblicken ob sie funktioniert PORTC |= (1<<DDC1); Delay(400); PORTC &= ~(1<<DDC1); Delay(400); rxbuffer[0]=0; for(;;){ if (rxbuffer[0]!= 0){ PORTC |= (1<<DDC1); Delay(2000); } } ISR (TWI_vect) { //ISR, die bei einem Ereignis auf dem Bus ausgelöst wird. Im Register TWSR befindet sich dann //ein Statuscode, anhand dessen die Situation festgestellt werden kann. uint8_t data=0; switch (TWSR) //TWI-Statusregister prüfen und nötige Aktion bestimmen { case TW_SR_SLA_ACK: // 0x60 Slave Receiver, wurde adressiert TWCR = (1<<TWEN)| // TWI Interface enabled (1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Expect ACK on this transmission (0<<TWWC); // buffer_adr=0xFF; //Bufferposition ist undefiniert break; case TW_SR_DATA_ACK: // 0x80 Slave Receiver,Daten empfangen data=TWDR; if (buffer_adr == 0xFF) //erster Zugriff, Bufferposition setzen { buffer_adr= data; //Bufferposition wie adressiert setzen TWCR = (1<<TWEN)| // TWI Interface enabled (1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send ACK after next reception (0<<TWWC); } else //weiterer Zugriff, Daten empfangen { rxbuffer[buffer_adr]=data; //Daten in Buffer schreiben buffer_adr++; //autoincrement Buffer-Adresse if(buffer_adr<7) { //nächstes Byte lesen, ACK danach TWCR = (1<<TWEN)| // TWI Interface enabled (1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send ACK after next reception (0<<TWWC); } else { //letztes Byte lesen, dann NACK TWCR = (1<<TWEN)| // TWI Interface enabled (1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte (0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| (0<<TWWC); } } break; case TW_ST_SLA_ACK: case TW_ST_DATA_ACK: //0xB0 weitere Daten gefordert TWDR = txbuffer[buffer_adr]; buffer_adr++; TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| (0<<TWWC); break; case TW_ST_DATA_NACK: //0xC0 Keine Daten mehr gefordert case TW_SR_DATA_NACK: //0x88 case TW_ST_LAST_DATA: //0xC8 Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received case TW_SR_STOP: // 0xA0 STOP empfangen default: TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| (0<<TWWC); //buffer_adr=0xFF; //Bufferposition ist undefiniert break; } //end.switch } //end.twi_ISR
Mich wundert, dass du das programm überhaupt kompiliert bekommst. Du hast die Deklaration von buffer_adr nicht drin. Eigentlich müsste der Compiler an zig Stellen meckern.
Pack am besten mal meinen Code (aber komplett!) in ne separate Datei, wie ich es in den Kommentaren geschreiben habe.
So hab ich gemacht komplett rauskopiert und in i2cslave.c gespeichert und im programm included. Hab nur den Pfad für #include <compat/twi.h> angepasst.
Immer noch gleiches Problem
main.c
i2cslave.cCode:// AVR Bibs #include <stdio.h> #include <stdlib.h> #include <avr/io.h> // I/O Ports #include <inttypes.h> // Datentypen #include <avr/pgmspace.h> // Stringfunktionen #include <string.h> // Stringfunktionen #include <avr/interrupt.h> // Interrupts #include <avr/signal.h> // Timer #include <math.h> /*************************************************** Globale Variablen ************************************************/ /*************************************************** Init defines *******************************************************/ // Werte zur Berechnung der Interrupt-Rate bei AVR-Fuses, // die auf 1MHz eingestellt sind (Werkseinstellung für internen RC-Oszillator) #define F_CPU 16000000 // Geräteadressen #define KEYLCD 0x40 #define RELAIS 0x76 #define Servos 0x68 #define PCFA 0x9E #define PCF1 0x72 #define PCF2 0x7E #define PCF3 0x74 #define PCF4 0x7C #define PCF5 0x7A #define PCF6 0x78 // Eigene Bibs #include "func.h" // Allgemeine Funktionen #include "sens.h" // Sensorfunktionen #include "i2cslave.c" int main(void) { /*******************************************************************************************************************/ /* Initialisierung */ /*******************************************************************************************************************/ //*** Alle Ports an PortD als Ausgang definieren DDRB = 0xFF; PORTB = 0x00; DDRD = 0xFF; //Alle PortD Pins auf Ausgang gesetzt (PD0-3 für BCD, PD4-7 für Ziffer 1-4) PORTD = 0x00; //Alles auf Low, Anzeige aus DDRC = 0xFF; PORTC= 0x00; PORTC &= ~(1<<DDC1); init_twi_slave(0x60); // Init I2C interface Delay(1000); PORTC |= (1<<DDC1); Delay(400); PORTC &= ~(1<<DDC1); Delay(400); rxbuffer[0]=0; for(;;){ if (rxbuffer[0]!= 0){ PORTC |= (1<<DDC1); Delay(2000); } } /*********************************************************************************************************************/ }
Code:/* Dieses Programm kann in einer separaten Datei (z.B. twislave.c) abgespeichert und in anderen Programmen eingebunden werden. Betrieb eines AVRs mit Hardware-TWI-Schnittstelle als Slave. Zu Beginn muss init_twi_slave mit der gewünschten Slave-Adresse als Parameter aufgerufen werden. Der Datenaustausch mit dem Master erfolgt über die Buffer rxbuffer und txbuffer, auf die von Master und Slave zugegriffen werden kann. rxbuffer und txbuffer sind globale Variablen (Array aus uint8_t). Die Ansteuerung des rxbuffers, in den der Master schreiben kann, erfolgt ähnlich wie bei einem normalen I2C-EEPROM. Man sendet zunächst die Bufferposition, an die man schreiben will, und dann die Daten. Die Bufferposition wird automatisch hochgezählt, sodass man mehrere Datenbytes hintereinander schreiben kann, ohne jedesmal die Bufferadresse zu schreiben. Um den zxbuffer vom Amster aus zu lesen, überträgt man zunächst in einem Schreibzugriff die gewünschte Bufferposition und liest dann nach einem repeated start die Daten aus. Die Bufferposition wird automatisch hochgezählt, sodass man mehrere Datenbytes hintereinander lesen kann, ohne jedesmal die Bufferposition zu schreiben. Autor: Uwe Große-Wortmann (uwegw), Juli 2006. Status: Testphase, keine Garantie für ordnungsgemäße Funktion! Empfangen scheint zu funktionieren. letze Änderungen: Senden über den txbuffer implementiert, noch weitgehend ungetestet! */ #include <avr/interrupt.h> #include <avr/io.h> #include <compat/twi.h> uint8_t buffer_adr; //"Adressregister" für den Buffer /*Der Buffer, in dem die empfangenen Daten gespeichert werden. Der Slave funktioniert ähnlich wie ein normales Speicher-IC [I2C-EEPROM], man sendet die Adresse, an die man schreiben will, dann die Daten, die interne Speicher-Adresse wird dabei automatisch hochgezählt*/ volatile uint8_t rxbuffer[8]; #define rx_PWM_L 2 #define rx_PWM_R 3 #define rx_DIR 1 /*Der Sendebuffer, der vom Master ausgelesen werden kann. [noch nicht implementiert!]*/ volatile uint8_t txbuffer[8]; void init_twi_slave (uint8_t adr) { TWAR= adr; //Adresse setzen TWCR|= (1<<TWEA) | (1<<TWEN)|(1<<TWIE); TWCR &= ~(1<<TWSTA)|(1<<TWSTO); buffer_adr=0xFF; sei(); } ISR (TWI_vect) //ISR, die bei einem Ereignis auf dem Bus ausgelöst wird. Im Register TWSR befindet sich dann //ein Statuscode, anhand dessen die Situation festgestellt werden kann. { uint8_t data=0; switch (TWSR) //TWI-Statusregister prüfen und nötige Aktion bestimmen { case TW_SR_SLA_ACK: // 0x60 Slave Receiver, wurde adressiert TWCR = (1<<TWEN)| // TWI Interface enabled (1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Expect ACK on this transmission (0<<TWWC); // buffer_adr=0xFF; //Bufferposition ist undefiniert break; case TW_SR_DATA_ACK: // 0x80 Slave Receiver,Daten empfangen data=TWDR; if (buffer_adr == 0xFF) //erster Zugriff, Bufferposition setzen { buffer_adr= data; //Bufferposition wie adressiert setzen TWCR = (1<<TWEN)| // TWI Interface enabled (1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send ACK after next reception (0<<TWWC); } else //weiterer Zugriff, Daten empfangen { rxbuffer[buffer_adr]=data; //Daten in Buffer schreiben buffer_adr++; //autoincrement Buffer-Adresse if(buffer_adr<7) { //nächstes Byte lesen, ACK danach TWCR = (1<<TWEN)| // TWI Interface enabled (1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send ACK after next reception (0<<TWWC); } else { //letztes Byte lesen, dann NACK TWCR = (1<<TWEN)| // TWI Interface enabled (1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte (0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| (0<<TWWC); } } break; case TW_ST_SLA_ACK: case TW_ST_DATA_ACK: //0xB0 weitere Daten gefordert TWDR = txbuffer[buffer_adr]; buffer_adr++; TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| (0<<TWWC); break; case TW_ST_DATA_NACK: //0xC0 Keine Daten mehr gefordert case TW_SR_DATA_NACK: //0x88 case TW_ST_LAST_DATA: //0xC8 Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received case TW_SR_STOP: // 0xA0 STOP empfangen default: TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| (0<<TWWC); //buffer_adr=0xFF; //Bufferposition ist undefiniert break; } //end.switch } //end.twi_ISR
Lesezeichen