Forum: Mikrocontroller und Digitale Elektronik TWI mit Atmega: Bitte mal drüber schauen


von Chris (Gast)


Lesenswert?

Hi!

Ich mache erste Gehversuche mit Hardware-TWI und hätte gerne, dass mal 
jemand über meinen Code schaut, ob alles stimmt oder man etwas anders 
lösen sollte. Er funktioniert auf den ersten Blick, aber beim Lesen gibt 
es noch Ungereimtheiten.

Es geht um das Auslesen eines 16 Bit ADCs (MCP 3426A0-E/SN)
Datenblatt:
http://www.reichelt.de/index.html?;ACTION=7;LA=3;OPEN=0;INDEX=0;FILENAME=A200%252FMCP3426-27-28.pdf;SID=15mbpbf6wQAQ8AAErTpj4f6a3708b2c9f2202a217a92c8223acf3

Zunächst das Senden. TWI-Takt ist auf 100khz eingestellt, data ist vom 
Typ uint8_t und die Konfiguration für den ADC. Der Code funktioniert, 
ich kann später das data-Byte wieder aus dem ADC lesen. Der Code 
entspricht im Wesentlichen dem aus dem Datenblatt vom Atmega.
1
#define SLA_W 0b11010000; //4 Bits device code (1101), 3 Bits addres (factory programmed, hier 0), r/!w-Bit
2
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); //Start condition senden
3
while  (!(TWCR & (1<<TWINT))); //Warten bis start condition gesendet wurde.
4
if ((TWSR & 0xF8) != TW_START)  ERROR(1); //Fehler: Status ist nicht Start.
5
TWDR = SLA_W; //Master Transmitter (Slave-Write)
6
TWCR = (1<<TWINT) | (1<<TWEN); //TWINT-Bit löschen um Übertragung zu starten
7
while (!(TWCR & (1<<TWINT))); //Warten bis übertragen
8
if ((TWSR & 0xF8) != TW_MT_SLA_ACK)  ERROR(2); //Fehler: Status ist nicht ACK.
9
10
TWDR = data; //Nutzdaten laden
11
TWCR = (1<<TWINT) | (1<<TWEN); //Senden
12
while (!(TWCR & (1<<TWINT))); //Auf ack des Slaves warten
13
if ((TWSR & 0xF8) != TW_MT_DATA_ACK) ERROR(3); //Status ist nicht ACK
14
15
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Stop-Condition senden
16
//Muss ich die Stop-Condition senden, wenn ich nur einen Master und nur ein Slave auf dem Bus habe?

von Chris (Gast)


Lesenswert?

Und das Auslesen. Hier stimmt noch etwas nicht. Laut dem ADC-Datenblatt 
sollte ich 3 Bytes (Highbyte, Lowbyte, Config-Byte) zurück bekommen, 
wobei das Config-Byte wiederholt wird, wenn man weiter liest. Ich 
bekomme aber vor dem Highbyte den Inhalt von SLA_R zurück.

receivedata1 bis 4 ist uint8_t.
1
#define SLA_R 0b11010001; //4 Bits device code (1101), 3 Bits address (factory programmed: Aufdruck A0 bedeutet 0, A1 bedeutet 1 usw.), r/!w-Bit
2
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); //Start condition senden
3
while  (!(TWCR & (1<<TWINT))); //Warten bis start condition gesendet wurde.
4
if ((TWSR & 0xF8) != TW_START)  ERROR(4); //Fehler: Status ist nicht Start.
5
6
TWDR = SLA_R; //Master Receiver (Slave-Read)
7
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); //TWINT-Bit löschen um Übertragung zu starten
8
while (!(TWCR & (1<<TWINT))); //Warten bis übertragen
9
if ((TWSR & 0xF8) != TW_MR_SLA_ACK)  ERROR(5); //Fehler: Status ist nicht ACK.
10
receivedata1 = TWDR; //Messwert empfangen
11
12
TWDR = SLA_R; //Master Receiver (Slave-Read) Notwendig?
13
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); //TWINT-Bit löschen um Übertragung zu starten
14
while (!(TWCR & (1<<TWINT))); //Warten bis übertragen
15
if ((TWSR & 0xF8) != TW_MR_DATA_ACK) ERROR(6); //Fehler: Status ist nicht ACK.
16
receivedata2 = TWDR; //Messwert empfangen
17
18
TWDR = SLA_R; //Master Receiver (Slave-Read) Notwendig?
19
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); //TWINT-Bit löschen um Übertragung zu starten
20
while (!(TWCR & (1<<TWINT))); //Warten bis übertragen
21
if ((TWSR & 0xF8) != TW_MR_DATA_ACK) ERROR(6); //Fehler: Status ist nicht ACK.
22
receivedata3 = TWDR; //Messwert empfangen
23
24
TWDR = SLA_R; //Master Receiver (Slave-Read) Notwendig?
25
TWCR = (1<<TWINT) | (1<<TWEN); //TWINT-Bit löschen um Übertragung zu starten. Letzte Übertragung, daher ohne TWEA. => Ergibt NACK.
26
while (!(TWCR & (1<<TWINT))); //Warten bis übertragen
27
if ((TWSR & 0xF8) != TW_MR_DATA_NACK) ERROR(6); //Fehler: Status ist nicht ACK.
28
receivedata4 = TWDR; //Messwert empfangen
29
30
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Stop-Condition senden
31
32
uart_putc (receivedata1); //Ergibt SLA_R. Warum?
33
uart_putc (receivedata2); //Ergibt 255 (ADC-Eingänge unbeschaltet)
34
uart_putc (receivedata3); //Ergibt 248 (ADC-Eingänge unbeschaltet)
35
uart_putc (receivedata4); //Ergibt config-Byte

von katastrophenheinz (Gast)


Lesenswert?

Hi,
warum das Rad neu erfinden? Es gibt viele TWI-Bibliotheken für ATmega, 
die zumindest den Master-Mode können:
Von Atmel z.B. AVR Appplication Note AVR315 oder bei Sparkfun.com kannst 
du dir unter dem Suchbegriff BMP085 auch funktionierenden Beispielcode 
für einen anderen TWI-Sensor angucken, wenn du nach "Fleury TWI Master" 
googelst findest du auch was. Und auch bei mikrocontroller.net findest 
du einiges.

UM TWI zu verstehen, ist es wesentlich einfacher sich an den vorhandenen 
Dingern langzuhangeln als auf Basis der Beschreibung im ATmega-Manual 
die Kuh zum Fliegen zu bringen. Just my two cents...

von noname (Gast)


Lesenswert?

So schwierig die Eigenentwicklung von Grund auf sein mag so befriedigend 
ist es dann, das von Grund auf verstandene Produkt fertig in der Hand zu 
haben :-)

von Chris (Gast)


Lesenswert?

So, das Einlesen des ADCs funktioniert, wenn ich ihn anfasse, zappeln 
die Werte herum :)

Warum vor dem Highbyte nochmal die Konfiguration gelesen wird, habe ich 
mir noch nicht näher angeschaut.

Vielen Dank für die Appnote, die habe ich mir heute Morgen angeschaut, 
aber mein eigener Code ist für mich doch verständlicher. Interrupts sind 
für diesen Zweck gut, aber ich kann es wohl einfacher lösen, wenn ich 
meinen Code immer wieder aufrufe. Ich schreibe ihn gerade um, damit er 
nicht blockierend arbeitet.
Da der Controller sonst fast nichts zu tun hat, sollte das fast so 
schnell laufen wie die Interruptlösung.

Gruß,
Chris

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
Noch kein Account? Hier anmelden.