PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Interrupt wird nicht ausgelöst



PcVirus
04.04.2008, 20:38
Hi,
ich möchte mit meinem I2C Slave einen SRF05 auslesen.
Nur wird die Variable "us_time" nicht hochgezählt. Die Kommunikation mit dem Master funktioniert und wenn ich bei "return" der Funktion "readUS" z.B.
eine "45" direkt zurückgebe, kommt sie auch bei meinem Master an.
Der Sensor an sich funktioniert auch, weil die rote LED bei jedem Aufruf der Funktion leuchtet und ich das Signal mit einem Oszilloskop geprüft habe.

Mit dem jetztigen Code bekomme ich allerdings nur eine "0" zurück.


#include <avr/io.h>
#include <util/delay.h>
#include <util/twi.h>
#include <avr/interrupt.h>

#define LO_BYTE(a) ((uint8_t) (a & 0xFF))
#define HI_BYTE(a) ((uint8_t) ((a>>8)&0xFF))

//US-Defines
#define US1 US1_PIN
#define US2 US2_PIN
#define US_DDR DDRD
#define US_PORT PORTD
#define US1_PIN PD4
#define US2_PIN PD5
#define TIMER0_AN TIMSK |= (1<<OCIE0); //Timer interrupt aktivieren
#define TIMER0_AUS TIMSK &= ~(1<<OCIE0); //Timer interrupt deaktivieren

#define SLAVE_ADRESSE 0x50 //Die Slave-Adresse

//ACK nach empfangenen Daten senden/ ACK nach gesendeten Daten erwarten
#define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
//NACK nach empfangenen Daten senden/ NACK nach gesendeten Daten erwarten
#define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
//switched to the non adressed slave mode...
#define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);

//Datenstatuscodes
#define DEFAULT 0 //Normaler status (keine aktion)
#define READ_ENC_A 1 //Schritte vom linken Motor auslesen
#define READ_ENC_B 2 //Schritte vom rechten Motor auslesen
#define RESET_ENC_A 3 //Schritte vom linken Motor löschen
#define RESET_ENC_B 4 //Schritte vom rechten Motor löschen
#define READ_DIST_A 5 //Gefahrene Strecke auslesen (A)
#define READ_DIST_B 6 //Gefahrene Strecke auslesen (B)
#define RESET_DIST_A 7 //Gefahrene Strecke löschen (A)
#define RESET_DIST_B 8 //Gefahrene Strecke löschen (B)
#define READ_US1 9 //Ultraschall 1 Auslesen
#define READ_US2 10 //Ultraschall 2 Auslesen

void init_twi_slave (uint8_t adr);

void initTimer0(void);
uint16_t readUS(uint8_t us);

volatile uint8_t status = DEFAULT; //status was der master will (z.B. US auslesen)
volatile uint16_t us_time=0;

int main (void){
//TWI als Slave mit Adresse slaveadr starten
init_twi_slave(SLAVE_ADRESSE);
initTimer0();
sei();
while(1){

}
}


void init_twi_slave (uint8_t adr){
cli();
TWAR = adr; // Set own TWI slave address.
TWDR = 0xFF; // Default content = SDA released.
TWCR = (1<<TWEN);
sei();
// Start the TWI transceiver to enable reception of the first command from the TWI Master.
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
}


SIGNAL(SIG_2WIRE_SERIAL){

static uint8_t teil=0; //Welcher teil der Variable übertragen wurde
static uint16_t daten=0; //entählt die daten die zum Master gesendet werden
switch (TW_STATUS){ //TWI-Statusregister prüfen und nötige Aktion bestimmen

case TW_ST_SLA_ACK: //SLA+R, adressiert
//kein ACk/Nack/break -> sonst geht nix
case TW_ST_DATA_ACK: // SLA+R received, ACK returned (Master fordert Daten an)
if(status==READ_US2){ //Ultraschall 2
if(teil==0){
daten = readUS(US2);
TWDR = LO_BYTE(daten); //Ersten 8 Bit übertragen
TWCR_ACK;
teil=1;
}
else{
TWDR = HI_BYTE(daten); //Zweiten 8 Bit übertragen
TWCR_ACK;
teil=0;
status = DEFAULT;
}
}
if(status==READ_US1){ //Ultraschall 1
if(teil==0){
daten = readUS(US1);
TWDR = LO_BYTE(daten); //Ersten 8 Bit übertragen
TWCR_ACK;
teil=1;
}
else{
TWDR = HI_BYTE(daten); //Zweiten 8 Bit übertragen
TWCR_ACK;
teil=0;
status = DEFAULT;
}
}
break;
case TW_SR_SLA_ACK: //SLA+W, adressiert
TWCR_ACK;
case TW_SR_DATA_ACK: //SLA+W received, ACK returned (Master sendet Daten)
status = TWDR; //Geforderte aktion vom master speichern
TWCR_ACK;
break;
default:
//TWCR=0x00;
TWCR_RESET;
break;
}
}


/* Ließt den Ultraschall sensor aus
US1 = Ultreaschall 1 (front)
US2 = Ultraschall 2 (side)
*/
uint16_t readUS(uint8_t us){
US_DDR |= (1<<us); //Pin auf Ausgang
US_PORT |=(1<<us); //Pin high
_delay_us(10); //15µs warten
US_PORT &= ~(1<<us); //Pin low
US_DDR &= ~(1<<us); //Pin auf Eingang
while(!(PIND & (1<<us))){} //Solange der Pin low
us_time = 0;
TIMER0_AN;
while(PIND & (1<<us)){} //Solange der Pin high
TIMER0_AUS;
return us_time/58;
}

/* Timer0 für den US Sensor konfigurieren
Alle 1us einen Interrupt = Freq 1000000 (1000khz)
OCR0 = 16000000/1/1000000=16
16Mhz Quarz, Prescaler 1, Frequenz
*/
void initTimer0(void){
TCCR0 |= (1<<WGM01) | (1<<CS00); //CTC, Prescaler 1
OCR0 = 16;
}



/*Interrupt für den US*/
SIGNAL(SIG_OUTPUT_COMPARE0){
us_time++;
}





Wo ist der Fehler?

MfG Jörn

McJenso
05.04.2008, 15:20
Hallo,

hier mal was mir so beim ersten drüber schauen aufgefallen ist.
us_time hat 16Bit, der Controller kann pro Takt aber nur 8 Bit bearbeiten. Daher solltest du vor jedem Zugriff auf us_time ein cli(); und danach ein sei(); schreiben, außer in der Interruptroutine selber. Wenn du sonst Pech hast findet mitten im Lesen von us_time ein Interrupt statt. Daran wird es aber wohl nicht liegen.

return us_time/58;
Wofür ist das? Erst quälst du den Controller alle 16 Takte ein Interrupt ab, um dann durch 58 zu teilen? Das wird übrigens als integer berechnet. Wenn us_time = 45 ist, bekommst du eine 0 Zurück. Welche Werte erwartest du für us_time? Das ist hier übrigens mein Fehlerfavorit.

Wenn du den Code optimieren möchtest, schreib noch ein asm("nop"); in die while- Schleife. Und wenn du es wirklich gut meinst, noch ein return 0; am Ende des Programms, da int main (void) ja einen Rückgabewert haben sollte.

Gruß

Jens

PcVirus
10.04.2008, 16:14
Danke für die Antwort.
Ich konnte erst jetzt antworten, da noch ein anderes Problem dazwischen gekommen ist. Der Code funktioniert jetzt. Ich glaube es lag an einem defekten Controller.
Ich habe den Code noch so geändert, dass alle 58us ein Interrupt erfolgt. Nun wird mein Ultraschallsensor richtig ausgelesen.

MfG Jörn