Ja PicNick hat recht. Es wird einfach ein TWI Interrupt gestartet. Dort kann man das TWBR Register abfragen.
Theoretisch hab ich sowas mal gemacht mit WinAVR. Vielleicht hilfts dir.
Es gibt 5 read only Register und 5 write only Register.
Ich hab auch mal was für SPI geschrieben. Dabei können beide Master und Slave werden. Allerdings auch nur theoretisch, also ich hatte noch keine Möglichkeit es zu testen. Hab leider keine zwei ATmega.Code:#include <avr/io.h> #include <avr/signal.h> #include <avr/interrupt.h> #include <avr/twi.h> #define i2c_slave_init TWCR= _BV(TWEA) | _BV(TWEN) | _BV(TWIE) // Slave init und I2C Interrupt enable #define slave_addr_init TWAR |= _BV(TWA0) // Slave addresse auf 0x10 also auf 10, keine reaktion auf globale anfragen // Die read_only Register werden im Hauptprogramm regelmäßig mit z.B. Sensorwerten aktuallisiert // Die write_only Register werden regelmäßig im Hauptprogramm ausgelesen um auf deren Werte zu reagieren volatile unsigned char read_register1,read_register2,read_register3,read_register4,read_register5; volatile unsigned char write_register1,write_register2,write_register3,write_register4; volatile unsigned char regwrite_flag=0; volatile unsigned char regvalue=0; SIGNAL(SIG_2WIRE_SERIAL) { if(TWSR==TW_SR_SLA_ACK|TWSR==TW_SR_ARB_LOST_SLA_ACK|TWSR==TW_SR_DATA_ACK) // Slave Reciever Datenpaket empfangen { if(regwrite_flag==1) { if(regvalue==6){ write_register1=TWDR; regwrite_flag=0; regvalue=0;} if(regvalue==7){ write_register1=TWDR; regwrite_flag=0; regvalue=0;} if(regvalue==8){ write_register1=TWDR; regwrite_flag=0; regvalue=0;} if(regvalue==9){ write_register1=TWDR; regwrite_flag=0; regvalue=0;} if(regvalue==10){ write_register1=TWDR; regwrite_flag=0; regvalue=0;} } else { if(TWDR==1){ // Register 1 until 5 only read; TWDR=read_register1; TWCR|=(1<<TWINT);} else if(TWDR==2){ TWDR=read_register2; TWCR|=(1<<TWINT);} else if(TWDR==3){ TWDR=read_register3; TWCR|=(1<<TWINT);} else if(TWDR==4){ TWDR=read_register4; TWCR|=(1<<TWINT);} else if(TWDR==5){ TWDR=read_register5; TWCR|=(1<<TWINT);} else if(TWDR==6||TWDR==7||TWDR==8||TWDR==9||TWDR==10){ // Register 6-10 write only register. regwrite_flag=1; // Flag wird gesetzt damit beim nächsten mal der TWDR Wert als Registerinhalt regvalue=TWDR; // und nicht als Registernummer interpretiert wird. TWCR|=(1<<TWINT);} // Hier könnte man noch weiter Befehle eingeben die dann mit der Entsprechenden TWDR ausgeführt werden } } else if(TWSR==TW_SR_DATA_NACK) TWCR = (1<<TWINT) | (1<<TWEA); else if(TWSR==TW_ST_SLA_ACK|TWSR==TW_ST_ARB_LOST_SLA_ACK|TWSR==TW_ST_DATA_ACK) // Dann ist Slave Transmitter mode und es wird einfach das byte in TWDR TWCR |= (1<<TWINT); // Versand else if(TWSR==TW_ST_DATA_NACK|TWSR==TW_ST_LAST_DATA) TWCR = (1<<TWINT) | (1<<TWEA); else if(TWSR==TW_SR_STOP) // STOP condition has been recevied TWCR=(1<<TWINT) | (1<<TWEA); TWCR |= 0b10000000; } void main(void) { i2c_slave_init; slave_addr_init; for(;;) { /* read_register1= ; read_register2= ; read_register3= ; read_register4= ; read_register5= ; if(write_register1== ) if(write_register2== ) if(write_register3== ) if(write_register4== ) if(write_register5== ) */ } }
Also vielleicht hilfts dir ja weiter, wenn du kein C dann ist es näturlich schade.Code:/* Es gibt hier keinen Slave oder Master. Beide können beides werden. Es wird jeweils der SS_Master Pin des einen mit dem SS_Slave Pin des anderen verbunden. In SPI_init wird der SS_Master Pin auf high gesetzt womit der SS_Slave Pin(SSPin/PB4 beim ATMEga32) des anderen auf high ist. In SPI_Transmitt wird der SS_Master auf low gesetzt und damit SS_Slave des anderen auch auf low. Damit geht der mit SS_Slave auf low in den Interrupt. Im Interrupt werden erst die angekommenen Daten dem Empfangsbuffer angehängt, dann wird wieder in den Master Modus geschaltet, außer der SS_Slave Pin ist noch auf low, d.h. der aktuelle Master will noch was senden. Wird etwas versand geht der andere Mikrocontroller in den Interrupt und bei ihm geschieht das gleiche. */ #include <avr/io.h> #define SS_Master PB3 // Pin zum Slave #define SS_Slave PB4 // Pin vom Slave #define MOSI PB5 #define MISO PB6 #define SCK PB7 #define DDR_SPI DDRB #define PORT_SPI PORTB #define MAX 99 // Bytes des SPI Lesebuffers max. 255 !! 255 sind 256Bytes volatile unsigned char data; volatile unsigned char Buffer[MAX]; // Empfangs buffer volatile unsigned char Buffer_count=0; // Wieviele Bytes sind im Buffer SIGNAL (SIG_SPI) // SPI Recieve { data=SPDR; // SPI Datenregister in data laden. Buffer[Buffer_count]=data; // data in Buffer laden Buffer_count++; // 1 Byte mehr im Empfangsbuffer // Prüfen ob SS_Slave schon wieder high ist --> empfang vorbei if(PORT_SPI & (1<<SS_Slave)) { // Wieder Master werden SPCR|=(1<<MSTR); // Daten versenden oder gleich raus aus Interrupt und nur wieder Master // SPI_Transmitt(' '); } } void SPI_Init(void) { // Set MOSI and SCK output, all others input DDR_SPI = (1<<MOSI) | (1<<SCK) | (1<<SS_Master); PORT_SPI|=(1<<SS_Master); //SS Pin zum SPI Slave auf high // SPI enable, Master enable, fck/16, SPI Interrupt enable SPCR= (1<<SPE) | (1<<MSTR) | (1<<SPR0) | (1<<SPIE); } unsigned char SPI_getc(void) // holt das letzte Byte seit dem letzten Aufruf { unsigned char data,i=1; if(Buffe_count!=0) // Neue Daten seit dem letzten Aufruf { data = Buffer[0]; // Buffer neu ordnen damit letztes Byte wieder auf Buffer[0] ist. for(i;i<=Buffer_count;i++) Buffer[i-1]=Buffer[i]; Buffer_count--; // 1 Byte weniger im Empfangsbuffer return data; } } void SPI_Transmitt_Raw(unsigned char data) // Sollte im eigenen Programm nicht verwendet werden { SPDR = data; while(!(SPSR & (1<<SPDIF))) asm volatile ("nop"); } void SPI_putc(unsigned char data) // Das ist die Funktion um ein Byte zu senden { // z.B. SPI_putc('c'); --> sendet ein c // unsigend char c; PORT_SPI &= ~(1<<SS_Master); // SPI_putc(c); --> sendet den Inhalt der Variable c SPDR = data; while(!(SPSR & (1<<SPDIF))) asm volatile ("nop"); PORT_SPI|=(1<<SS_Master); } void SPI_puts (unsigned char *s) // sendet einen Buffer aus mehreren Bytes { // z.B. SPI_puts("hallo"); --> ist aber blödes Beispiel mit hallo PORT_SPI &= ~(1<<SS_Master); // unsigned char buffer[100]; while (*s) // SPI_puts(buffer) { /* so lange *s != NULL */ SPI_Transmitt_Raw(*s); s++; } PORT_SPI|=(1<<SS_Master); }
Gruß Muraad







Zitieren

Lesezeichen