Hallo Leute :) Ich beschäftige mich zurzeit damit, über TWI (I2C) mit einem Sensor zu kommunizieren. Jedoch komme ich nicht so wirklich klar damit. Die gesamte Kommunikation soll später über 3 Funktionen (TWI_initTWI, TWI_ReceiveData und TWI_SendData) erfolgen. Hierfür möchte ich gerne die Nebenfunktionen in die Receive und Send Funktion einbauen, jedoch klappt das nicht so recht. Könnt Ihr mir evtl weiterhelfen und sagen, wo meine Fehler liegen? Hier der Code: /*********************************************************************** ******** *Funktion void TWI_InitTWI_v(uint8_t BitRate, uint8_t PrescalerHighBit, uint8_t PrescalerLowBit) * *Beschreibung Initialiesiert das TWI-Modul des Mikrocontrollers * *Parameter BitRate: Bitrate die im Register TWBR eingestellt werden soll * PrescalerHighBit: Wert der fuer TWPS1 eingestellt werden soll * PrescalerLowBit: Wert der fuer TWPS0 eingestellt werden soll * *Rueckgabe keine * ************************************************************************ *******/ void TWI_InitTWI(uint8_t BitRate, uint8_t PrescalerHighBit, uint8_t PrescalerLowBit) { // TWIFrequenz auswaehlen freq= F_CPU/(16+2(TWBR)*4^TWPS) TWBR=BitRate; //Bitrate setzen TWSR=(PrescalerHighBit<<TWPS1)|(PrescalerLowBit<<TWPS0); // Setzen der prescalar bits } /*********************************************************************** ******** *Funktion void TWI_StartCondition(void) * *Beschreibung Sendet eine Startbedingung fuer eine TWI Kommunikation * *Parameter keine * *Rueckgabe keine * ************************************************************************ *******/ void TWI_StartCondition(void) { // Setzt TWI interrupt flag zurueck, legt Startbedingung an SDA, Enable TWI TWCR= (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); while(!(TWCR & (1<<TWINT))); // wartet bis die Startbedingung gesendet ist while((TWSR & 0xF8)!= 0x08); // prueft acknowledgement } /*********************************************************************** ******** *Funktion void TWI_RepeatedStartCondition(void) * *Beschreibung Sendet eine erneute Startbedingung * *Parameter keine * *Rueckgabe keine * ************************************************************************ *******/ void TWI_RepeatedStartCondition(void) { // Setzt TWI interrupt flag zurueck, legt Startbedingung an SDA, Enable TWI TWCR= (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); while(!(TWCR & (1<<TWINT))); // wartet bis die Startbedingung gesendet ist while((TWSR & 0xF8)!= 0x10); // prueft acknowledgement } /*********************************************************************** ******** *Funktion void TWI_SendAddress(uint8_t Adress, uint8_t Direction) * *Beschreibung Sendet die Slave Adresse, ob anschließend gelesen oder geschriben werden soll und wartet ACK ab * *Parameter Adress: Adresse des Slaves im 8-Bit Format (letztes Bit egal) * Direction: Read=1; Write=0 * *Rueckgabe keine * ************************************************************************ *******/ void TWI_SendAddress(uint8_t Adress, uint8_t Direction) { if (Direction==0) { Adress&=0xFE; } else { Adress|=0x01; } TWDR=Adress; // Addresse and Richtung senden TWCR=(1<<TWINT)|(1<<TWEN); // Setzt TWI interrupt flag zurueck, Enable TWI while (!(TWCR & (1<<TWINT))); // wartet bis TWDR uebertragen ist if (Direction==0) { while((TWSR & 0xF8)!= 0x18); // prueft acknoledgement fuer lesen } else { while((TWSR & 0xF8)!= 0x40); // prueft acknoledgement fuer schreiben } } /*********************************************************************** ******** *Funktion void TWI_WriteData(uint8_t char Data) * *Beschreibung Sendet 8-Bit Daten und wartet auf ACK * *Parameter Data: 8-Bit Daten, die gesendet werden sollen * *Rueckgabe keine * ************************************************************************ *******/ void TWI_WriteData(uint8_t Data) { TWDR=Data; // legt Data ins Senderegister TWCR=(1<<TWINT)|(1<<TWEN); // Setzt TWI interrupt flag zurueck, Enable TWI while (!(TWCR & (1<<TWINT))); // wartet bis TWDR uebertragen ist while((TWSR & 0xF8) != 0x28); // prueft acknoledgement } /*********************************************************************** ******** *Funktion uint8_t TWI_ReadData(void) * *Beschreibung Empfaengt 8-Bit Daten ueber TWI * *Parameter keine * *Rueckgabe 8Bit Daten * ************************************************************************ *******/ uint8_t TWI_ReadData(void) { uint8_t ReciveData; //Variable fuer die empfangenden Daten TWCR=(1<<TWINT)|(1<<TWEN); // Setzt TWI interrupt flag zurueck, Enable TWI while (!(TWCR & (1<<TWINT))); // wartet bis das TWDR-Byte uebermittelt wurde while((TWSR & 0xF8) != 0x58); // prueft acknoledgement ReciveData=TWDR; // liest TWDR-Byte aus return (ReciveData); // Rueckgabe der Daten } /*********************************************************************** ******** *Funktion void TWI_StopCondition(void) * *Beschreibung Sendet Stopp-Bedingung nach TWI-Kommunikation * *Parameter keine * *Rueckgabe keine * ************************************************************************ *******/ void TWI_StopCondition(void) { // Setzt TWI interrupt flag zurueck, legt Stoppbedingung an SDA, Enable TWI TWCR= (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); while(!(TWCR & (1<<TWSTO))); // wartet bis Stoppbedingung uebermittelt wurde } /*********************************************************************** ******** *Funktion void TWI_SendData(uint8_t SlaveAdress, uint8_t RegisterAdress, uint8_t Data) * *Beschreibung Schreibt Daten ins das abgegebene Register des Slaves mit der angegebenen Adresse * *Parameter SlaveAdress: Adresse des Slaves, der angesprochen werden soll * Registeradress: Register, in das geschrieben werden soll * Data: Daten, die in das Register geschrieben werden sollen * *Rueckgabe keine * ************************************************************************ *******/ void TWI_SendData(uint8_t SlaveAdress, uint8_t RegisterAdress, uint8_t Data) { /*Funktion mit Hilfe der oben gegeben Funktionen schreiben*/ TWI_StartCondition(); TWI_SendAddress(SlaveAdress, RegisterAdress); TWI_WriteData(Data); TWI_WriteData(Data); TWI_StopCondition(); } /*********************************************************************** ******** *Funktion uint8_t TWI_ReciveData(uint8_t SlaveAdress, uint8_t RegisterAdress) * *Beschreibung Empfaengt Daten des Slaves, welche unter der angebenen Registeradresse zu finden sind * *Parameter SlaveAdresse: Adresse des angeschlossenen Slaves im 8-Bit Format * RegisterAdress: Adresse des Registers, das gelesen werden soll * *Rueckgabe 8-Bit Daten * ************************************************************************ *******/ uint8_t TWI_ReciveData(uint8_t SlaveAdress, uint8_t RegisterAdress) { /*Funktion mit Hilfe der oben gegeben Funktionen schreiben*/ TWI_StartCondition(); TWI_SendAddress(SlaveAdress, RegisterAdress); TWI_ReadData(); TWI_RepeatedStartCondition(); TWI_StopCondition(); } Ich hoffe, dass mir jemand weiterhelfen kann :) LG
Hi Du solltest dich mal über I2C schlau machen: http://www.nxp.com/documents/user_manual/UM10204.pdf
1 | uint8_t TWI_ReciveData(uint8_t SlaveAdress, uint8_t RegisterAdress) |
2 | {
|
3 | /*Funktion mit Hilfe der oben gegeben Funktionen schreiben*/
|
4 | TWI_StartCondition(); |
5 | TWI_SendAddress(SlaveAdress, RegisterAdress); |
6 | TWI_ReadData(); |
7 | TWI_RepeatedStartCondition(); |
8 | TWI_StopCondition(); |
9 | }
|
Wie passt z.B. TWI_SendAddress(SlaveAdress, RegisterAdress); mit void TWI_SendAddress(uint8_t Adress, uint8_t Direction) zusammen? Und was soll das TWI_RepeatedStartCondition(); in dem Code? ... MfG Spess
Ich mach das alles mit einer einzigen Funktion. Diese Idee habe ich von einer Java implementierung (Lejos) abgeguckt. Dort wird sie im Bereich Robotics verwendet und hat sich bewährt:
1 | //======================================================================== |
2 | // I2C Bus |
3 | //======================================================================== |
4 | // Wenn der I2C Bus nicht verwendet wird, stehen dessen Pins als reguläre |
5 | // I/O Pins zur Verfügung. Pull-Up Widerstände nicht vergessen! |
6 | |
7 | // Sendet beliebig viele Bytes an den adressierten Slave und empfängt |
8 | // anschließend beliebig viele Bytes von dem Slave. |
9 | |
10 | // slave_address ist die Adresse des Slave in 7bit Schreibweise (0-127). |
11 | // send_data zeigt auf die zu sendenden Daten, z.B. ein Array von Bytes. |
12 | // send_bytes gibt an, wieviele Bytes gesendet werden sollen. |
13 | // rcv_data zeigt auf einen Puffer, wo die empfangenen Daten abgelegt |
14 | // werden sollen, z.B. ein Array von Bytes. |
15 | // rcv_Bytes gibt an, wieviele Bytes empfangen werden sollen. |
16 | // Der Rückgabewert zeigt an, wie viele Bytes tatsächlich empfangen wurden. |
17 | |
18 | // Wenn man nur senden will, gibt man rcv_data=0 und rcv_bytes=0 an. |
19 | // Wenn man nur empfangen will, gibt man send_data=0 und send_bytes=0 an. |
20 | // Es ist erlaubt, bei send_bytes und rcv_bytes Zeiger auf den selben |
21 | // Puffer zu übergeben. |
22 | |
23 | uint8_t i2c_communicate(uint8_t slave_address, void* send_data, uint8_t send_bytes, void* rcv_data, uint8_t rcv_bytes) { |
24 | uint8_t rcv_count=0; |
25 | |
26 | // Adresse ein Bit nach links verschieben, um Platz für das r/w Flag zu schaffen |
27 | slave_address=slave_address<<1; |
28 | |
29 | if (send_bytes>0) { |
30 | // Sende Start |
31 | TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTA); |
32 | while (!(TWCR & (1<<TWINT))); |
33 | uint8_t status=TWSR & 0xf8; |
34 | if (status != 0x08 && status != 0x10) goto error; |
35 | |
36 | // Sende Adresse (write mode) |
37 | TWDR=slave_address; |
38 | TWCR=(1<<TWINT) | (1<<TWEN); |
39 | while (!(TWCR & (1<<TWINT))); |
40 | if ((TWSR & 0xf8) != 0x18) goto error; |
41 | |
42 | // Sende Daten |
43 | while (send_bytes>0) { |
44 | TWDR=*((uint8_t*)send_data); |
45 | TWCR=(1<<TWINT) | (1<<TWEN); |
46 | while (!(TWCR & (1<<TWINT))); |
47 | if ((TWSR & 0xf8) != 0x28) goto error; |
48 | send_data++; |
49 | send_bytes--; |
50 | } |
51 | } |
52 | |
53 | if (rcv_bytes>0) { |
54 | // Sende START |
55 | TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTA); |
56 | while (!(TWCR & (1<<TWINT))); |
57 | uint8_t status=TWSR & 0xf8; |
58 | if (status != 0x08 && status != 0x10) goto error; |
59 | |
60 | // Sende Adresse (read mode) |
61 | TWDR=slave_address + 1; |
62 | TWCR=(1<<TWINT) | (1<<TWEN); |
63 | while (!(TWCR & (1<<TWINT))); |
64 | if ((TWSR & 0xf8) != 0x40) goto error; |
65 | |
66 | // Empfange Daten |
67 | while (rcv_bytes>0) { |
68 | if (rcv_bytes==1) { |
69 | // das letzte Byte nicht mit ACK quittieren |
70 | TWCR=(1<<TWINT) | (1<<TWEN); |
71 | } |
72 | else { |
73 | // alle anderen Bytes mit ACK quittieren |
74 | TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWEA); |
75 | } |
76 | while (!(TWCR & (1<<TWINT))); |
77 | uint8_t status=TWSR & 0xf8; |
78 | if (status!=0x50 && status != 0x58) goto error; |
79 | *((uint8_t*)rcv_data)=TWDR; |
80 | rcv_data++; |
81 | rcv_bytes--; |
82 | rcv_count++; |
83 | } |
84 | |
85 | } |
86 | |
87 | // Sende STOP |
88 | TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO); |
89 | return rcv_count; |
90 | |
91 | error: |
92 | // Sende STOP |
93 | TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO); |
94 | return 0; |
95 | } |
Was da noch fehlt, ist die Initialisierung der Bitrate:
1 | // TWI Interface ungefähr 100kbit/section, bei 15Mhz |
2 | TWBR=75; |
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.