-
Hallo an alle
Ich hab nun die I2C Routine fertig geschrieben :) Jedoch funktioniert sie noc nicht. Ich finde jedoch keinen Fehler :(
Hier der Code
Code:
#include <avr/io.h>
#include <stdlib.h>
#include "lcd.h"
#define TRUE 1
#define FALSE 0
#define ACK TRUE
#define NACK FALSE
#define START 0x08
#define TW_MT_SLA_ACK 0x18
#define TW_MT_DATA_ACK 0x28
void lm75_read(void);
void i2c_init(void);
int i2c_send_start(uint8_t adress);
int i2c_send_byte(uint8_t data);
void i2c_send_stop(void);
int i2c_read(uint8_t adress, uint8_t ackflag);
struct TEMPERATUR {
uint8_t high;
uint8_t low;
} temp;
void i2c_init(void)
{
TWBR |= (1 << 5); //TWBR = 32 = 10 0000
// Prescaler = 1
}
int i2c_send_start(uint8_t adress)
{
TWCR |= ((1 << TWINT) | (1 << TWSTA) | (1 << TWEN)); //Sende start Condition
while(!(TWCR & (1 << TWINT))); //Warte bis ende
if((TWSR & 0xF8) != START)
return -1;
TWDR = adress;
TWCR = (1 << TWINT) | (1 << TWEN);
while(!(TWCR & (1 << TWINT)));
if((TWCR & 0xF8) != TW_MT_SLA_ACK)
return -1;
return 0;
}
int i2c_send_byte(uint8_t data)
{
TWDR = data;
TWCR = (1 << TWINT) | (1 << TWEN);
while(!(TWCR & (1 << TWINT)));
if((TWSR & 0xF8) != TW_MT_DATA_ACK)
return -1;
return 0;
}
void i2c_send_stop(void)
{
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
while(!(TWCR & (1 << TWSTO)));
}
int i2c_read(uint8_t adress, uint8_t ackflag)
{
if(ackflag == ACK)
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
else
TWCR = (1 << TWINT) | (1 << TWEN);
while(!(TWCR & (1 << TWINT)));
return TWDR;
}
void lm75_read(void)
{
i2c_send_stop();
i2c_send_start(0x9E);
temp.high = i2c_read(0x9F,ACK);
temp.low = i2c_read(0x9F, NACK);
i2c_send_stop();
}
int main(void)
{
uint8_t nachkomma, ganzzahl;
i2c_init();
lcd_init(LCD_DISP_ON);
lcd_home();
lcd_clrscr();
lcd_clrscr();
lm75_read();
if(bit_is_set(temp.low, 0))
nachkomma = 5;
else
nachkomma = 0;
temp.low >>= 1;
temp.high <<= 7;
ganzzahl= temp.low | temp.high;
lcd_put_d(ganzzahl);
lcd_putc('A');
lcd_put_d(nachkomma);
return 0;
}
Ich hoffe es kann mir wer helfen.
Danke im Voraus
Gruß Robert
-
Warum sendest Du zu beginn ein STOP, das erzeugt nur Verwirrung,
sollte der Bus nicht frei sein beim START, bekommt man das schon mit, und kann darauf reagieren.
Man sollte aber den Bus wieder freigeben, falls der START nicht geklappt hat,
siehe TWI und TWI_Praxis
ist zwar mit Bascom gemacht, aber die Reihenfolge passt ja trotzdem.
-
Hallo an alle
i2c_start() funktioniert. Nur bei der Receive Routine hakt es. Ich hab Acked und Nacked getrennt.
Ich hab nach jedem Befehl eine Lcd Ausgabe eingeführt, um zu sehen wo es hakt.
Hier der Code:
Code:
int i2c_read_ack(void)
{
lcd_putc('1');
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
lcd_putc('2');
while(!(TWCR & (1<<TWINT)));
lcd_putc('3');
if(!(TWSR & 0x50))
{
lcd_putc('4');
return -1;
}
lcd_putc('5');
return TWDR;
}
Das ist die Funktion mit Acknoledgement. Am Display wird aber nur 12 angezeigt.
Es hängt also bei while(!(TWCR & (1<<TWINT)));
Weiß irgendwer, was da falsch sein könnte. Ich hab je´tzt echt keinen Plan mehr
Danke im Voraus
Gruß Robert
-
So, die Ansteuerung funktioniert jetzt :)
Code:
oid i2c_init(void)
{
TWBR = (1 << 5) | (1 << 1) | (1 << 3); //TWBR = 11
}
void i2c_send_stop(void)
{
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
while(!(TWCR & (1 << TWSTO)));
}
int i2c_read_ack(void)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT)));
if(!(TWSR & 0x50))
return -1;
return TWDR;
}
int i2c_read_nack(void)
{
TWCR = (1<<TWINT) | (1<<TWEN);
while(!(TWCR & (1<<TWINT)));
if(!(TWSR & 0x58))
return -1;
return TWDR;
}
int i2c_send_start(uint8_t adress)
{
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); //Sende start Condition
while(!(TWCR & (1 << TWINT))); //Warte bis ende
if(!(TWSR & 0x08))
return -1;
TWDR = adress;
TWCR = (1 << TWINT) | (1 << TWEN);
while(!(TWCR & (1 << TWINT)));
if(!(TWSR & 0x40))
return(-2);
return 0;
}
void readfromLM75(uint8_t *temp, uint8_t *nachkomma)
{
i2c_send_start(LM75_ADRESS | 1); //Sende Adresse + Read
*temp = i2c_read_ack();
*nachkomma = i2c_read_nack();
i2c_send_stop();
if(bit_is_set(*nachkomma, 7))
*nachkomma = 5;
else
*nachkomma = 0;
}
-
Eine Anmerkung hätte ich noch,
normalerweise wird beim lesen eines Bytes zuerst das TWDR ausgelesen, und dann erst TWCR gesetzt, sonst kanns vorkommen das sich das nächste Byte schon wieder über den Bus reinschiebt, und die Daten nicht mehr aktuell sind in TWDR.
Denn normalerweise kommt das gesendete Stop-Bit auch wieder bei TWDR an und schiebt die Daten ein Bit weiter !
Und es wird aus jeder funktion bei einem Fehler mit return einfach zurückgesprungen, ohne den Bus wieder freizugeben, das kann auch zu komischen Fehlern führen !
Wenn die Startsequenz zB. keinen Erfolg hatte, muss man trotzdem den Bus freigeben, denn sonst kann ein anderer Master auch nicht weitermachen.