PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : US SRF08 Mega32 Softwareproblem:



B.Rust
02.11.2004, 09:45
Ich benutze folgenden Quellcode:


/************************************************** ************************************************** *
* Originalprogramm war TWI-Example aus der AVR-LibC *
* Original geschrieben von Joerg Wunsch <joerg@FreeBSD.ORG> , mit der Beerware-License *
************************************************** ************************************************** */

/************************************************** ************************************************** *
* *
* Programm für RN V1.4 Board mit Atmega32 *
* *
* geaendert von Merviux *
* *
* Auslösen von US-Messungen, Einlesen der Messwerte, Übermittlung *
* der Daten über RS232 an Konsole *
* *
************************************************** ************************************************** */

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <avr/signal.h>
#include <interrupt.h>
#include <avr/io.h>
#include <avr/twi.h>

#define DEBUG 1
#define OCR_1MS 115
#define SYSCLK 16000000UL

/* Definitionen */

#ifndef UCSRB
# ifdef UCSR1A
# define UCSRA UCSR1A
# define UCSRB UCSR1B
# define UBRR UBRR1L
# define UDR UDR1
# else
# define UCSRA USR
# define UCSRB UCR
# endif
#endif
#ifndef UBRR
# define UBRR UBRRL
#endif


#define SFR_BC 0x00 /* Broadcast Adresse, auf die alle SRF reagieren */
#define SFR_XX 0xe0 /* Default Adresse bei Auslieferung */

/************************************************** ************************************************** *
* Maximale Anzahl der Wiederholungen um auf eine Antwort seitens des *
* I2C-Slaves zu warten. Lang genug, um eine Schreibeoperation auszuführen *
* aber dennoch bei fehlender Rückmeldung abzubrechen. Die Start-Sequenz und *
* Übermittlung der Slave-Adresse, sowie R/W-Befehl, dauert bei 100 kHz *
* TWI Takt ca. 10 µs. Da ein Schreibvorgang etwa 10 ms nicht überschreiten *
* sollte, würden auch 100 Iterationen ausreichen. *
* *
************************************************** ************************************************** */
#define MAX_ITER 255

/************************************************** ************************************************** *
* Sichern des TWI Statusregisters für Fehlermeldungen. Der Status muss in *
* einer Variable gespeichert werden, da das TWSR-Register nur bei aktiven *
* TWINT-Bit des TWCR konsistent bleibt. *
************************************************** ************************************************** */
uint8_t twst;

/************************************************** ************************************************** *
* erg ist eine Zählvariable, buf ein Zeichenfeld für Ausgabe an RS232 *
* ms_count dient dem Timer *
* *
************************************************** ************************************************** */
uint8_t erg;
char buf[8];
volatile uint16_t ms_count;


/************************************************** ************************************************** *
* Ausgabe String *
* Schreibt die einzelnen Zeichen des Zeichenfeldes buf[] in den UDR-Puffer *
* *
************************************************** ************************************************** */
int usartprint(char *buf,int len)
{
int i;

for (i=0;i<len;i++) {
/* wenn das UDRE-Bit gesetzt ist, ist der UDR Puffer leer.
* Neue Daten können übertragen werden. */
while ( !(UCSRA & _BV(UDRE)) )
;
UDR = buf[i];
}

return i;
}

/************************************************** *************************************************
* Die UART-Schnittstelle und der TWI-Takt wird initialisiert *
* *
************************************************** *************************************************/

void
ioinit(void)
{

UCSRB = _BV(TXEN); /* tx enable */
UBRRL=103; /* 9600 Bd */

/* Initialisierung TWI-Takt: 100 kHz Takt, TWPS = 0 => Multiplikator = 1 */
#if defined(TWPS0)
TWSR = 0;
#endif
TWBR = (SYSCLK / 100000UL - 16) / 2;

uint8_t bitrate_div;
// I2C Bitrate
// SCL freq = F_CPU/(16+2*TWBR))
#ifdef TWPS0
cbi(TWSR, TWPS0);
cbi(TWSR, TWPS1);
#endif
// Bitrate ermitteln
bitrate_div = ((16000000/1000l)/100);
if(bitrate_div >= 16)
bitrate_div = (bitrate_div-16)/2;
outb(TWBR, bitrate_div);
}


/************************************************** ************************************************** *
* Zeichen ueber UART ausgeben *
************************************************** ************************************************** */
int
uart_putchar(char c)
{

if (c == '\n')
uart_putchar('\r');
loop_until_bit_is_set(UCSRA, UDRE);
UDR = c;
return 0;
}

/************************************************** ************************************************** *
* US-Sensor beschreiben *
* Der Sensor mit der Adresse modul_addr wird im Register reg_nr mit dem Befehl befehl *
* angestossen. *
* z.B.: *
* modul_addr : 0xe0 (default) *
* Register : 0x00 (Befehlsregister) *
* Befehl : 0x51 (Messung in cm) *
* *
************************************************** ************************************************** */

int
sfr_schreiben(uint8_t modul_addr, uint8_t reg_nr, uint8_t befehl)
{
uint8_t sla, adr, n = 0;
int rv = 0;

/* Slave-Adresse uebergeben */
sla = modul_addr;
switch(sla){
case 0x00:
adr = 0;
break;
case 0xe0:
adr = 1;
break;
case 0xe2:
adr = 2;
break;
case 0xe4:
adr = 3;
break;
case 0xe6:
adr = 4;
break;
case 0xe8:
adr = 5;
break;
case 0xea:
adr = 6;
break;
case 0xec:
adr = 7;
break;
case 0xee:
adr = 8;
break;
case 0xf0:
adr = 9;
break;
case 0xf2:
adr = 10;
break;
case 0xf4:
adr = 11;
break;
case 0xf6:
adr = 11;
break;
default:
adr = 1;
}


restart:
if (n++ >= MAX_ITER){
printf("Max_Iter ! \n");
return -1;}

begin:

TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /* Start Bedingung */
while ((TWCR & _BV(TWINT)) == 0) ; /* Warte auf Uebertragung */
switch ((twst = TW_STATUS))
{
case TW_REP_START:
case TW_START:
break;

case TW_MT_ARB_LOST:
goto begin;

default:
return -1; /* Fehler: nicht in Start-Bedingung */
/* Keine Stop-Bedingung */
}

/* Slave-Adresse und Schreibebefehl uebermitteln */
TWDR = sla | TW_WRITE;
TWCR = _BV(TWINT) | _BV(TWEN); /* Interrupt fuer Uebertragung ruecksetzen */
while ((TWCR & _BV(TWINT)) == 0) ; /* Warte auf Uebertragung */
switch ((twst = TW_STATUS))
{
case TW_MT_SLA_ACK:
break;

case TW_MT_SLA_NACK: /* NACK : Modul schreibt = Busy */
goto restart;

case TW_MT_ARB_LOST: /* neue Arbitration/Zuweisung */
goto begin;

default:
goto error; /* Stop-Bedingung senden */
}


TWDR = reg_nr; /* Registernummer */
TWCR = _BV(TWINT) | _BV(TWEN); /* Interrupt fuer Uebertragung ruecksetzen */
while ((TWCR & _BV(TWINT)) == 0) ; /* Warte auf Uebertragung */
switch ((twst = TW_STATUS))
{
case TW_MT_DATA_ACK:
rv++;
break;

case TW_MT_DATA_NACK:
goto quit;

case TW_MT_ARB_LOST:
goto begin;

default:
goto error; /* Stop-Bedingung senden */
}

TWDR = befehl; /* Befehl */
TWCR = _BV(TWINT) | _BV(TWEN); /* Interrupt fuer Uebertragung ruecksetzen */
while ((TWCR & _BV(TWINT)) == 0) ; /* Warte auf Uebertragung */
switch ((twst = TW_STATUS))
{
case TW_MT_DATA_ACK:
rv++;
break;

case TW_MT_DATA_NACK:
goto quit;

case TW_MT_ARB_LOST:
goto begin;

default:
goto error; /* Stop-Bedingung senden */
}


quit:
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* Stop-Bedingung senden */
/*printf("\nSensor: %d befehligt mit", adr);
printf(" CMD %d ,", reg_nr);
printf(" Befehl %d \n", befehl);*/
return rv;

error:
rv = -1;
goto quit;
}


/************************************************** ************************************************** *
* US-Sensor Lesen *
* Aus dem Sensor mit der Adresse modul_addr wird das Register reg_nr gelesen *
* z.B.: *
* modul_addr : 0xe0 (default) *
* Register : 0x00 (Befehlsregister) *
* *
************************************************** ************************************************** */
int
sfr_lesen(uint8_t modul_addr, uint8_t reg_nr)
{
uint8_t sla, twcr, adr, n = 0;
int rv = 0;
int len =2;

sla = modul_addr ; /* Adresse uebergeben */
switch(sla){
case 0x00:
adr = 0;
break;
case 0xe0:
adr = 1;
break;
case 0xe2:
adr = 2;
break;
case 0xe4:
adr = 3;
break;
case 0xe6:
adr = 4;
break;
case 0xe8:
adr = 5;
break;
case 0xea:
adr = 6;
break;
case 0xec:
adr = 7;
break;
case 0xee:
adr = 8;
break;
case 0xf0:
adr = 9;
break;
case 0xf2:
adr = 10;
break;
case 0xf4:
adr = 11;
break;
case 0xf6:
adr = 11;
break;
default:
adr = 1;
}

/*
* Erster Zyklus: Master-Mode, schreiben auf BUS
*/
restart:
if (n++ >= MAX_ITER)
return -1;
begin:

TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /* Start-Bedingung */
while ((TWCR & _BV(TWINT)) == 0) ; /* Warte auf Uebertragung */
switch ((twst = TW_STATUS))
{
case TW_REP_START:
case TW_START:
break;

case TW_MT_ARB_LOST:
goto begin;

default:
return -1; /* Fehler: nicht in Start-Bedingung */
/* Keine Stop-Bedingung */
}

/* Slave-Adresse und Schreibebefehl uebermitteln */
TWDR = sla | TW_WRITE;
TWCR = _BV(TWINT) | _BV(TWEN); /* Interrupt fuer Uebertragung ruecksetzen */
while ((TWCR & _BV(TWINT)) == 0) ; /* Warte auf Uebertragung */
switch ((twst = TW_STATUS))
{
case TW_MT_SLA_ACK:
break;

case TW_MT_SLA_NACK: /* NACK : Modul schreibt = Busy */

goto restart;

case TW_MT_ARB_LOST: /* erneute Arbitrierung */
goto begin;

default:
goto error; /* Stop-Bedingung senden */
}

TWDR = reg_nr; /* zu lesendes Register */
TWCR = _BV(TWINT) | _BV(TWEN); /* Interrupt fuer Uebertragung ruecksetzen */
while ((TWCR & _BV(TWINT)) == 0) ; /* Warte auf Uebertragung */
switch ((twst = TW_STATUS))
{
case TW_MT_DATA_ACK:
break;

case TW_MT_DATA_NACK:
printf("Lesen NACK \n");
goto quit;

case TW_MT_ARB_LOST:
printf("Lesen BUS weg \n");
goto begin;

default:
printf("Lesen Fehler \n");
goto error; /* Stop-Bedingung senden */
}

/*
* Naechsten Zyklen: Master-Mode, lesen
*/
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /* Wiederholung der Start-Bedingung */
while ((TWCR & _BV(TWINT)) == 0) ; /* Warte auf Uebertragung */
switch ((twst = TW_STATUS))
{
case TW_START:
case TW_REP_START:
break;

case TW_MT_ARB_LOST:
printf("ARB Lost \n");
goto begin;

default:
printf("Fehler Master mode \n");
goto error;
}

/* send SLA+R */
TWDR = sla | TW_READ;
TWCR = _BV(TWINT) | _BV(TWEN); /* Interrupt fuer Uebertragung ruecksetzen */
while ((TWCR & _BV(TWINT)) == 0) ; /* Warte auf Uebertragung */
switch ((twst = TW_STATUS))
{
case TW_MR_SLA_ACK:
break;

case TW_MR_SLA_NACK:
goto quit;

case TW_MR_ARB_LOST:
goto begin;

default:
printf("Fehler Lesebefehl \n");
goto error;
}

for (twcr = _BV(TWINT) | _BV(TWEN) | _BV(TWEA);
len > 0;
len--)
{
if (len == 1)
twcr = _BV(TWINT) | _BV(TWEN); /* NAK setzen */
TWCR = twcr; /* Interrupt fuer Uebertragung ruecksetzen */
while ((TWCR & _BV(TWINT)) == 0) ; /* Warte auf Uebertragung */
switch ((twst = TW_STATUS))
{
case TW_MR_DATA_NACK:
break; /* Schleife beenden */
case TW_MR_DATA_ACK:
erg = TWDR; /* Ausgaben */
rv++;

break;

default:
printf("Fehler Datenerhalt \n");
goto error;
}
}
quit:
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* Stop-Bedingung */

return rv;

error:
printf("Fehler Routinenausgang mit rv-Satus = %d .",rv);
rv = -1;
goto quit;
}


/************************************************** ************************************************** *
* Verzoegerung (Wartezeit) *
* *
************************************************** ************************************************** */
void ms_sleep(uint16_t ms)
{
TCNT0 = 0;
ms_count = 0;

while (ms_count < ms)
;
}



/************************************************** ************************************************** *
* Millisekundenzaehler fuer Unterbrechung *
* *
************************************************** ************************************************** */
SIGNAL(SIG_OUTPUT_COMPARE0)
{
ms_count++;
}

/************************************************** ************************************************** *
* Timer0 initialisieren um den Quarzkristall und den Output-Compare-Interrupt *
* zu benutzen - auf diese Weise erfolgt eine Unterbrechung etwa einmal pro 1 ms. *
* *
************************************************** ************************************************** */
void init_timer0(void)
{
TCCR0 = 0;
TIFR |= BV(OCIE0)|BV(TOIE0);
TIMSK |= BV(TOIE0)|BV(OCIE0); /* enable output compare interrupt */
TCCR0 = BV(WGM01)|BV(CS02)|BV(CS00); /* CTC, prescale = 128 */
TCNT0 = 0;
OCR0 = OCR_1MS; /* match in aprox 1 ms */
}

/************************************************** ************************************************** *
* Fehler *
* *
************************************************** ************************************************** */
void
error(void)
{

printf("error: TWI status %#x\n", twst);
//exit(0); // Unterbrechen des Programms --> Ende
}


/************************************************** ************************************************** *
* Main *
* *
************************************************** ************************************************** */
void main(void)
{
uint16_t a = 0;
int rv;
int regnr;
int addr = 0xe0;

init_timer0();
ioinit();
sei();
fdevopen(uart_putchar, NULL, 0);
ms_sleep(500);
rv = sfr_schreiben(0x00, 0x01, 0x06);
ms_sleep(100);
rv = sfr_schreiben(0x00, 0x02, 0x4a);
ms_sleep(100);
for(;;){
rv = sfr_schreiben(0x00, 0x00, 0x51);
ms_sleep(40);
printf("Sensor %d ", addr);
for(regnr = 3; regnr < 4; ){
rv = sfr_lesen(addr, regnr);
if (rv <= 0)
error();
if (rv < 1)
printf("warning: short read %d\n", rv);
dtostrf(erg,7,3,buf);
printf("Reg. %d ", regnr);
printf("Wert: ");
usartprint(buf,8);
regnr++;
}
printf("\n");
}
putchar('\n');
a++;
printf("Messung %d beendet \n \n ", a);
}


Ich bekomme als Ausgabe folgendes:


nsor 224 Reg. 3 Wert: se}KyaM
Sensor 224 Reg. 3 Wert: se}KyaM
Sensor 224 Reg. 3 Wert: se}KyaM


Könnte es sein, dass irgendwas mit dem US nicht stimmt? Irgendwie bekomme ich keine vernünftigen werte...

Joerg
02.11.2004, 12:37
Hallo,


dtostrf(erg,7,3,buf);
[...]
usartprint(buf,8);

also das gibt bei einem 16bit Wert sonstwas aus, aber sicherlich kein brauchbares Ergebnis. Warum nicht ein einfaches printf, das tut's mit Sicherheit besser.

Die I2C-Routinen sehen sehr komplex aus, aber wozu in den beiden Riesen-switches die Moduladresse (sla) nach adr konvertiert wird (mit offensichtlichem Doppelfehler bei 0xf6) habe ich bis jetzt noch nicht verstanden. Aber die Routinen sollten so eigentlich funktionieren.
Wichtig ist beim Lesen des Entfernungswertes, dass der Wert als 16bit Wert zur Verfügung gestellt wird, deshalb sind 2 Leseoperationen notwendig (fortgesetztes Lesen funktioniert auch).

HTH und Viele Grüße
Jörg