- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Ergebnis 1 bis 3 von 3

Thema: Interrupt wird nicht ausgelöst

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    04.02.2005
    Ort
    Hannover
    Beiträge
    174

    Interrupt wird nicht ausgelöst

    Anzeige

    Praxistest und DIY Projekte
    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.
    Code:
    #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

  2. #2
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    20.05.2006
    Ort
    Lippe
    Alter
    55
    Beiträge
    524
    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

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    04.02.2005
    Ort
    Hannover
    Beiträge
    174
    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

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Solar Speicher und Akkus Tests