Wenn Du unsicher bist, ob es vielleicht gar ein Hardwarefehler sein könnte, dann probiere doch einfach mal meinen Source aus.
Du musst aber vermutlich ein bisschen anpassen, weil er für einen SRF02 geschrieben wurde. Der folgende Source kommt ohne Interrupts aus.
Du musst mit den folgenden Optionen compilieren:
-DF_CPU=20000000 (oder wie auch immer)
-DBAUD=19200 (oder wie gewünscht)
Ich bin nicht 100% sicher, aber ich glaube, für printf sind die folgenden LDFLAGS nötig:
-Wl,-u,vfprintf -lprintf_min -lm
Code:
#define US_SENSOR 0xE0
#define US_START_CMD 81
static int serial_write(char, FILE *);
static int serial_read(FILE *);
static FILE serialPort = FDEV_SETUP_STREAM(serial_write, serial_read, _FDEV_SETUP_RW);
// Sende ein Zeichen
static int serial_write(char c, FILE *f) {
loop_until_bit_is_set(UCSRA, UDRE);
UDR = c;
return 0;
}
// Lese ein Zeichen
static int serial_read(FILE *f) {
while (readBit(UCSRA, RXC)==0);
char c=UDR;
return c;
}
// Initialisiere den seriellen Port
void initserial(void) {
// set baudrate
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1 << U2X);
#else
UCSRA &= ~(1 << U2X);
#endif
// enable receiver and transmitter
UCSRB = (1<<RXEN) | (1<<TXEN);
// framing format 8N1
#ifdef URSEL
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
#else
UCSRC = (1<<UCSZ1) | (1<<UCSZ0);
#endif
// Bind stdout and stdin to the serial port
stdout = &serialPort;
stdin = &serialPort;
}
// Schreibe ein Byte in ein Register eines Slave Gerätes.
// Der Rückgabewert ist 0, wenn die Kommunikation erfolgreich war.
uint8_t i2c_write(uint8_t slave_id, uint8_t address, uint8_t data) {
// Sende START
TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
while (!(TWCR & (1<<TWINT)));
uint8_t status=TWSR & 0xf8;
if (status != 0x08 && status != 0x10) goto error;
// Sende Adresse des Sensors
TWDR=slave_id;
TWCR=(1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xf8) != 0x18) goto error;
// Sende Register Nummer
TWDR=address;
TWCR=(1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xf8) != 0x28) goto error;
// Sende Befehl (Messen in Zentimeter)
TWDR=data;
TWCR=(1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xf8) != 0x28) goto error;
// Sende STOP
TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
return 0;
error:
// Sende STOP
TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
return 255;
}
// Lese ein Byte aus einem Register eines Slave Gerätes
// Der Rückgabewert ist 255, wenn die Kommunikation fehlgeschlagen ist.
uint8_t i2c_read(uint8_t slave_id, uint8_t address) {
uint8_t result=0;
// Sende START
TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
while (!(TWCR & (1<<TWINT)));
uint8_t status=TWSR & 0xf8;
if (status != 0x08 && status != 0x10) goto error;
// Sende Adresse des Sensors
TWDR=slave_id;
TWCR=(1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xf8) != 0x18) goto error;
// Sende Register Nummer
TWDR=address;
TWCR=(1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xf8) != 0x28) goto error;
// Sende wiederholt START
TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
while (!(TWCR & (1<<TWINT)));
status=TWSR & 0xf8;
if (status != 0x08 && status != 0x10) goto error;
// Sende Adresse des Sensors (read mode)
TWDR=slave_id+1;
TWCR=(1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xf8) != 0x40) goto error;
// lese ein Byte ohne ACK
TWCR=(1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xf8) != 0x58) goto error;
result=TWDR;
// Sende STOP
TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
return result;
error:
// Sende STOP
TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
return 255;
}
// Führt eine Ultraschall-Messung durch.
// Das Ergebnis ist die gemessene Distanz in Zentimeter
uint16_t distance() {
// Sende Ping Befehl
i2c_write(US_SENSOR,0,US_START_CMD);
// Warte, bis Ergebnis verfügbar ist
do {
_delay_ms(1000);
} while (i2c_read(US_SENSOR,0)==255);
// Lese das Ergebnis aus
return (uint16_t) i2c_read(US_SENSOR,2)*255 +i2c_read(US_SENSOR,3);
}
// Hauptprogramm
int main() {
initserial();
puts_P(PSTR("reset"));
while (1) {
// Führe jede Sekunde eine Ultraschall-Messung durch
_delay_ms(1000);
printf_P(PSTR("Firmware: %i\n"),i2c_read(US_SENSOR,0));
printf_P(PSTR("Kalibrier-Wert: %i\n"),(uint16_t) i2c_read(US_SENSOR,4)*255 +i2c_read(US_SENSOR,5));
printf_P(PSTR("Distanz: %i cm\n"),distance());
}
}
Lesezeichen