0tes_Gesetz
27.06.2006, 19:56
Hi, hab wieder einmal ein Problem mit meinem ATmega168..
verwendetes Zeugs:
- m168 @8Mhz
- AVRSTudio mit GCC
- Ponyprog
- JTAG ICE mk2
- nen Oszi
- ein VB2005 I²C Terminalprogramm
- I²C-Serial Adapter von robotikhardware.de
Es geht um den I²C Sklave im Receiver Modus.
Der Chip bekommt über den Bus das Adresspaket und 2 Datenpakete, mittels des hier im Shop erhältlichen I²C-Seriell Übersetzers und einem (von mir geschriebenen) VisualBasic2005 I²C Terminalprogramm.
(welches frei nach dem, dem I²C-Seriell Übersetzer beiligenden Programms (war für VB6 oder so) geschrieben wurde)
In folgendem Bild sieht man, was das Terminalprogramm für Signale auf SCL/SDA erzeugt, wenn man eine bestimmte Befehlsfolge startet.
Alles sauber, auch die Antworten vom m168 - meiner Meinung nach.
Er müsste eigentlich alles haben...
"W255;" bedeutet im übrigen - schreibe 255 an Sklave
http://www.is55.de/I2C%20Befehle%20und%20Antworten%20TempSteu.jpg
In den nachfolgenden Bildern hab ich an dieser Befehlsfolge jeweils nur beim 3. Byte den zu übertragenden Wert geändert - Fehler bleibt gleich.
Beachtet bitte die Zustände im Datenregister TWDR, welche ich rot markiert hab.
Es sieht so aus, als ob die empfangenen Daten (des letzen Bytes) nach links geschiftet werden - aber WIESO?
http://www.is55.de/I2C%20Befehle%20und%20Antworten2%20TempSteu.jpg
http://www.is55.de/I2C%20Befehle%20und%20Antworten3%20TempSteu.jpg
Und bei folgendem Bild hab ich die übertragenen Signale (nebst Antworten vom m168) nochmal mit reingepackt.
http://www.is55.de/I2C%20Befehle%20und%20Antworten4%20TempSteu.jpg
.. und zugeuter Letzt noch den Code-Schnipsel, mit der TWI-Interrupt-Sequenz (glaub nach der Anleitung im GCC-Tutorial oder wars ein dem GCC beiligendes Beispiel?..
ISR (TWI_vect) // I²C Interrupt - 8Bit Solltemperatur einlesen (ohne Fehlercheck!!!)
{
TWSTATUS++; // Schalter um eins erhöhen
switch (TWSTATUS)
{
case 1: // erster Durchlauf
{
if (TW_STATUS != TW_SR_SLA_ACK) { TWSTATUS = 0;} // wenn erkannt weiter, ansonsten Reset
}
case 2:
{
// I²C Temperaturvorgabe gültig oder Analoge Temperaturvorgabe nutzen?
if (TWDR > 0) { I2C_TEMPSOLL = 1;} // der I²C Temp-Vorgabewert gilt
else { I2C_TEMPSOLL = 0;} // Analoger Temp-Vorgabewert gilt, I²C gibt Steuerung ab
}
case 3:
{
if (I2C_TEMPSOLL == 1) // I²C Temp-Vorgabe ist möglich, also los..
{
temp_soll = TWDR; // Soll-Temperatur übernehmen
}
/* else // I²C gibt Temp NICHT mehr vor!!
{
__asm__ __volatile__ (" nop \n" :: ); // nichts tun...
}
*/ TWSTATUS = 0; // Reset des Schalters, Ende erreicht
}
}
// TWI wieder empfangsbereit machen (TWINT-Bit setzen)
// I²C: Sklave, TWI-Enable, TWI-Interrupt-Enable (Pin27 = SDA & Pin28 = SCL)
TWCR = (1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC)|(1<<TWEN)|(1<<TWIE);
}
int main (void)
{
// Pin11(D7)<-I_Anteil ON/OFF, Pin10(D6)<-D_Anteil ON/OFF
// Pin9(D5)->T0_PWM, Pin2(D4)<-T0_CLK, Pin1(D3)->ALIVE-Signal, Pin32(D2)<-INT0,
// Pin31(D1)->Heizen/Kühlen, Pin30(D0)<-Laserdiode oder nicht
DDRD = (0<<DDD7)|(0<<DDD6)|(1<<DDD5)|(0<<DDD4)|(1<<DDD3)|(0<<DDD2)|(1<<DDD1)|(1<<DDD0);
// Pin27(C4)/28(C5)<-SDA/SCL für I²C,
DDRC = (0<<DDC6)|(0<<DDC5)|(0<<DDC4)|(0<<DDC3)|(0<<DDC2)|(0<<DDC1)|(0<<DDC0);
// Pin7,8 & 16,17(B4-B7) für I²C Adresse, Pin15(B3)->T0_CLK, Pin12(B0)<-ICP1,
DDRB = (0<<DDB7)|(0<<DDB6)|(0<<DDB5)|(0<<DDB4)|(1<<DDB3)|(0<<DDB2)|(0<<DDB1)|(0<<DDB0);
...
// I²C: Sklave, TWI-Enable, TWI-Interrupt-Enable (Pin27 = SDA & Pin28 = SCL)
TWCR = (1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC)|(1<<TWEN)|(1<<TWIE);
// ************************************************** *********************************************
// nur in der folgenden Zeile Änderungen an der I²C-Adresse vornehmen!!!
TWAR |= (0<<TWA6)|(0<<TWA5)|(1<<TWA4)|(0<<TWGCE); // Setzen der ersten 3 (TWA) Bits der I²C-Adresse
TWAR = 254;
// in diesem Fall werden die Chips mit den Adressen: [xxx]0000 bis [xxx]1111 erreicht!!!
// die letzten 4 Bits werden durch die hardwareseitige Beschaltung der Pins 7,8, 16 & 17 bestimmt!
// ************************************************** *********************************************
...
}
return (0);
}
Also nochmal: Wieso bekomm ich per Interrupt aus dem Datenregister des TWI nur 7Bit - anstatt der 'üblichen' 8Bit?
Das LSB in TWDR ist immer Zero, außer nach dem einschalten des m168.
"LSB" heißt least significant Bit, "MSB" entsprechend most .. (für Neulinge)
Grüße und besten Dank
0tes_Gesetz
PS: wenn noch irgendwelche Angaben fehlen.. bitte schreibts, ich liefere gerne nach, wenn nur irgendjemand einen Rat hat.. :(
verwendetes Zeugs:
- m168 @8Mhz
- AVRSTudio mit GCC
- Ponyprog
- JTAG ICE mk2
- nen Oszi
- ein VB2005 I²C Terminalprogramm
- I²C-Serial Adapter von robotikhardware.de
Es geht um den I²C Sklave im Receiver Modus.
Der Chip bekommt über den Bus das Adresspaket und 2 Datenpakete, mittels des hier im Shop erhältlichen I²C-Seriell Übersetzers und einem (von mir geschriebenen) VisualBasic2005 I²C Terminalprogramm.
(welches frei nach dem, dem I²C-Seriell Übersetzer beiligenden Programms (war für VB6 oder so) geschrieben wurde)
In folgendem Bild sieht man, was das Terminalprogramm für Signale auf SCL/SDA erzeugt, wenn man eine bestimmte Befehlsfolge startet.
Alles sauber, auch die Antworten vom m168 - meiner Meinung nach.
Er müsste eigentlich alles haben...
"W255;" bedeutet im übrigen - schreibe 255 an Sklave
http://www.is55.de/I2C%20Befehle%20und%20Antworten%20TempSteu.jpg
In den nachfolgenden Bildern hab ich an dieser Befehlsfolge jeweils nur beim 3. Byte den zu übertragenden Wert geändert - Fehler bleibt gleich.
Beachtet bitte die Zustände im Datenregister TWDR, welche ich rot markiert hab.
Es sieht so aus, als ob die empfangenen Daten (des letzen Bytes) nach links geschiftet werden - aber WIESO?
http://www.is55.de/I2C%20Befehle%20und%20Antworten2%20TempSteu.jpg
http://www.is55.de/I2C%20Befehle%20und%20Antworten3%20TempSteu.jpg
Und bei folgendem Bild hab ich die übertragenen Signale (nebst Antworten vom m168) nochmal mit reingepackt.
http://www.is55.de/I2C%20Befehle%20und%20Antworten4%20TempSteu.jpg
.. und zugeuter Letzt noch den Code-Schnipsel, mit der TWI-Interrupt-Sequenz (glaub nach der Anleitung im GCC-Tutorial oder wars ein dem GCC beiligendes Beispiel?..
ISR (TWI_vect) // I²C Interrupt - 8Bit Solltemperatur einlesen (ohne Fehlercheck!!!)
{
TWSTATUS++; // Schalter um eins erhöhen
switch (TWSTATUS)
{
case 1: // erster Durchlauf
{
if (TW_STATUS != TW_SR_SLA_ACK) { TWSTATUS = 0;} // wenn erkannt weiter, ansonsten Reset
}
case 2:
{
// I²C Temperaturvorgabe gültig oder Analoge Temperaturvorgabe nutzen?
if (TWDR > 0) { I2C_TEMPSOLL = 1;} // der I²C Temp-Vorgabewert gilt
else { I2C_TEMPSOLL = 0;} // Analoger Temp-Vorgabewert gilt, I²C gibt Steuerung ab
}
case 3:
{
if (I2C_TEMPSOLL == 1) // I²C Temp-Vorgabe ist möglich, also los..
{
temp_soll = TWDR; // Soll-Temperatur übernehmen
}
/* else // I²C gibt Temp NICHT mehr vor!!
{
__asm__ __volatile__ (" nop \n" :: ); // nichts tun...
}
*/ TWSTATUS = 0; // Reset des Schalters, Ende erreicht
}
}
// TWI wieder empfangsbereit machen (TWINT-Bit setzen)
// I²C: Sklave, TWI-Enable, TWI-Interrupt-Enable (Pin27 = SDA & Pin28 = SCL)
TWCR = (1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC)|(1<<TWEN)|(1<<TWIE);
}
int main (void)
{
// Pin11(D7)<-I_Anteil ON/OFF, Pin10(D6)<-D_Anteil ON/OFF
// Pin9(D5)->T0_PWM, Pin2(D4)<-T0_CLK, Pin1(D3)->ALIVE-Signal, Pin32(D2)<-INT0,
// Pin31(D1)->Heizen/Kühlen, Pin30(D0)<-Laserdiode oder nicht
DDRD = (0<<DDD7)|(0<<DDD6)|(1<<DDD5)|(0<<DDD4)|(1<<DDD3)|(0<<DDD2)|(1<<DDD1)|(1<<DDD0);
// Pin27(C4)/28(C5)<-SDA/SCL für I²C,
DDRC = (0<<DDC6)|(0<<DDC5)|(0<<DDC4)|(0<<DDC3)|(0<<DDC2)|(0<<DDC1)|(0<<DDC0);
// Pin7,8 & 16,17(B4-B7) für I²C Adresse, Pin15(B3)->T0_CLK, Pin12(B0)<-ICP1,
DDRB = (0<<DDB7)|(0<<DDB6)|(0<<DDB5)|(0<<DDB4)|(1<<DDB3)|(0<<DDB2)|(0<<DDB1)|(0<<DDB0);
...
// I²C: Sklave, TWI-Enable, TWI-Interrupt-Enable (Pin27 = SDA & Pin28 = SCL)
TWCR = (1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC)|(1<<TWEN)|(1<<TWIE);
// ************************************************** *********************************************
// nur in der folgenden Zeile Änderungen an der I²C-Adresse vornehmen!!!
TWAR |= (0<<TWA6)|(0<<TWA5)|(1<<TWA4)|(0<<TWGCE); // Setzen der ersten 3 (TWA) Bits der I²C-Adresse
TWAR = 254;
// in diesem Fall werden die Chips mit den Adressen: [xxx]0000 bis [xxx]1111 erreicht!!!
// die letzten 4 Bits werden durch die hardwareseitige Beschaltung der Pins 7,8, 16 & 17 bestimmt!
// ************************************************** *********************************************
...
}
return (0);
}
Also nochmal: Wieso bekomm ich per Interrupt aus dem Datenregister des TWI nur 7Bit - anstatt der 'üblichen' 8Bit?
Das LSB in TWDR ist immer Zero, außer nach dem einschalten des m168.
"LSB" heißt least significant Bit, "MSB" entsprechend most .. (für Neulinge)
Grüße und besten Dank
0tes_Gesetz
PS: wenn noch irgendwelche Angaben fehlen.. bitte schreibts, ich liefere gerne nach, wenn nur irgendjemand einen Rat hat.. :(