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.
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== )
*/
}
}
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:
/* 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);
}
Also vielleicht hilfts dir ja weiter, wenn du kein C dann ist es näturlich schade.
Gruß Muraad
Lesezeichen