-
        

Ergebnis 1 bis 5 von 5

Thema: ATmega8 mit TWI-Interrupts, was mache ich falsch?

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    13.06.2007
    Ort
    Mainz
    Beiträge
    23

    ATmega8 mit TWI-Interrupts, was mache ich falsch?

    Anzeige

    Hallo Zusammen,

    ich habe eine Schaltung aufgebaut, in der ein ATmega8 über I2C mit einem SRF02 Ultraschallmodul redet. Ich benutze im Code die I2C-Master Implementierung von peter fleury.

    Ich hatte jetzt schon öfter den Effekt, dass die Kommunikation im i2c_readAck() einfriert, was vermutlich darauf zurückzuführen ist, dass vom Slave (SRF02) keine Antwort zurück kommt.

    Ich wollte nun also versuchen, das Ganze interrupt-basiert anzugehen. Leider bekomme ich es nicht mal auf die Reihe, einen Interrupt für Aktivitäten auf dem I2C-Bus zu aktivieren. Ich habe folgenden Code:
    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <stdarg.h>
    #include <string.h>
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/pgmspace.h>
    #include "delay.h"
    #include "lcd.h"
    #include "i2cmaster.h"
    
    #ifndef SIGNAL
    #include <avr/signal.h>
    #endif /* SIGNAL */
    
    ISR (TWI_vect)
    {
    	PORTB &= ~(1 << PB0);
    	delayms(500);
    	PORTB |= (1 << PB0);
    }
    
    unsigned int read_cm(unsigned char address)
    {
    	unsigned char lowbyte,highbyte;
    	unsigned int distance;
    
    	i2c_start_wait(address+I2C_WRITE);
    
    	while (i2c_write(0));
    	while (i2c_write(81));
    	i2c_stop();
    
    	i2c_start_wait(address+I2C_WRITE);
    	while (i2c_write(2));
    	i2c_stop();
    	
    	delayms(65);
    	
    	i2c_start_wait(address+I2C_READ);
    	highbyte = i2c_readAck();
    	lowbyte = i2c_readNak();
    	distance = (highbyte<<8)+lowbyte;
    	i2c_stop();
    	if(distance > 150) {
    		PORTC = 0x00;
    	}
    	return distance;
    }
    
    int main(void)
    {
    	...
    	i2c_init();
    	...
    	TWCR |= (1<<TWIE) | (1<<TWINT);
    	sei();
    
    	for ( ;; ) {
    		dist = read_cm(SRF02_ADDRESS);
    		if (dist >= HEIGHT) {
    			fill_percent = 0;
    		} else {
    			fill_percent = 100 - ((dist * 100) / HEIGHT);
    		}
    		delayms(3000);
    	}
    }
    Was mache ich beim Aktivieren des Interrupts falsch? Es passiert einfach nichts ...

    Wie ist das eigentlich, muss ich als Implementierung nun twimaster.c oder i2cmaster.S verwenden?

    AVR-GCC Version 4.3.0

    Gruss,
    mefiX

  2. #2
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Was mache ich beim Aktivieren des Interrupts falsch? Es passiert einfach nichts ...
    Ich sehe weder, dass du i2c_init aufrufst, noch dass du TWBR selber setzt.

    Wie ist das eigentlich, muss ich als Implementierung nun twimaster.c oder i2cmaster.S verwenden?
    i2cmaster.S ist Software-I2C, twimaster.c ist Hardware-I2C, und du möchtest offensichtlich Hardware-I2C haben.

    Wenn du den TWI-Interrupt benutzen willst, musst du dich von der Fleury-Lib aber sowieso verabschieden. Die macht nämlich Polling, und "mischen" wird nichts werden.
    MfG
    Stefan

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    13.06.2007
    Ort
    Mainz
    Beiträge
    23
    Hallo,

    danke für die schnelle Antwort!

    ich habe den Code zur besseren Lesbarkeit hier im Thread beschnitten, i2c_init() rufe ich direkt zu Beginn von main() auf, das passt also.

    Aber TWBR habe ich mir bisher noch nciht angesehen, allerdings habe ich eben gesehen, dass genau das in i2c_init() gesetzt wird. Zunächst mit 0 initialisiert, danach wird dort die Taktrate in Abhängigkeit von F_CPU gesetzt.

    Ok, dann lag ich bisher auch mit twimaster.c richtig, danke.

    Gibt es eine Alternative zur polling-basierten Lib von Peter Fleury?
    Wäre es eine alternative, das Auslesen des SRF02 nebenläufig zu machen? Ich habe da eine minimalistische Thread-Lib für AVRs im Netz entdeckt?

    Gruss,
    mefiX

  4. #4
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    i2c_start_wait überschreibt deine eigene TWCR-Einstellung wieder.
    Wie gesagt, für Interrupt-Betrieb musst du dich komplett von der Fleury-Lib verabschieden.
    MfG
    Stefan

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    13.06.2007
    Ort
    Mainz
    Beiträge
    23
    ich hab mir jetzt einfach nen timer-interrupt gebastelt, der nach beendigung der read()-routine zurückgesetzt wird. wenn ein gewisses timeout erreicht wurde wird das programm neu initialisiert, ist ein workaround, aber für meine zwecke ok.

    danke für die antworten!

Berechtigungen

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