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.