- Labornetzteil AliExpress         
Ergebnis 1 bis 8 von 8

Thema: Problem mit externem Interrupt / Timer

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    01.06.2006
    Ort
    Gernrode-Ilmenau
    Beiträge
    48

    Problem mit externem Interrupt / Timer

    Anzeige

    Praxistest und DIY Projekte
    Hallo,
    ich will für eine CarreraBahn eine Zeitmessanlage bauen. Dazu habe ich 2 Auslöser an der Bahn die an einen Mega8 als externer Interrupteingang angschlossen sind. Nun will ich jeweils nur die Rundenzeit und die Rundenanzahl anzeigen. Da der Kontakt jedoch für einige ms besteht, wird der Interrupt ja quasi mehrmals ausgelöst. Mein frage ist nun, kann ich wenn jeweils der entsprechende Interrupt 1 oder 2 ausgelöst wurde den für zB. 250ms sperren, mit nem Timer oder so? Die Zeit soll aber weiterzählen.
    Hier ein einfacher Code der bis dahin funkioniert, jedoch mehrmals auslöst: (soll noch weiterentwickelt werden, wenn dieses Problem gelöst ist)
    Code:
    #include <avr/io.h>
    #include <inttypes.h>
    #include <avr/interrupt.h>
    #define F_CPU 4000000UL  // 4 MHz
    #include <util/delay.h>
    #include "lcd.c"
    #include "lcd_hw.h"
    #include <string.h> 
    
    uint16_t time,time1,time2; 
    int rd1,rd2;//Rundenanzahl
    char zeichen,output[20+1];
    
    void delay_ms(unsigned int ms)
    /* delay for a minimum of <ms> */
    {    while(ms){ _delay_ms(0.96);ms--;}}
    static void int_to_ascii(uint16_t inum,char *outbuf,signed char decimalpoint_pos,signed char spacepadd){
    	signed char i,j;
    	char chbuf[8];
    	j=0;
    	while(inum>9 && j<7){
    		// zero is ascii 48:
    		chbuf[j]=(char)48+ inum-((inum/10)*10);
    		inum=inum/10;
    		j++;
    		if(decimalpoint_pos==j){
    			chbuf[j]='.';
    			j++;}
    			}
    	chbuf[j]=(char)48+inum; // most significant digit
    	decimalpoint_pos--;
    	while(j<decimalpoint_pos){
    		j++;
    		chbuf[j]='0';}
    	if (spacepadd && j > (decimalpoint_pos+2)){
    		spacepadd=0;
    	}
    	if(decimalpoint_pos==j){
    		j++;
    		chbuf[j]='.';
    		j++;
    		chbuf[j]='0'; // leading zero
    	}
    	if (spacepadd){
    		j++;
    		chbuf[j]=' '; // leading space padding: "9.50" becomes " 9.50"
    	}
    	// now reverse the order 
    	i=0;
    	while(j>=0){
    		outbuf[i]=chbuf[j];
    		j--;
    		i++;	}
    	outbuf[i]='\0';
    }
    
    
    
    
    
    ISR(INT0_vect) {lcd_gotoxy(0,0);lcd_puts("P1: ");// in Zeile 1 P1: schreiben
        int_to_ascii(rd1,output,0,1);lcd_puts(output);//in Zeile 1 Rundenanzahl1 schreiben
    	int_to_ascii(time1,output,3,1);lcd_puts(output);time1=0;//im Zeile 1 Rundenzeit1 schreiben
    	rd1++;//Rundenanzahl erhöhen
    	}
    ISR(INT1_vect) {lcd_gotoxy(0,1);lcd_puts("P2: ");
    	int_to_ascii(rd2,output,0,1);lcd_puts(output);
    	int_to_ascii(time2,output,3,1);lcd_puts(output);time2=0;
    	rd2++;
    
    }
    
    
    
    
    int main(void)
    {	DDRD |= (1<<PD2);	//Register D für PD2 (auf 1) als Ausgang geschaltet
    	DDRD |= (1<<PD3);
    	PORTD |= (1 << PD2);
    	PORTD |= (1 << PD3);
    	GICR |= (1<<6)|(1<<7);	//INT0 als Interrupt aktivieren
        
    	lcd_init(LCD_DISP_ON);
    	lcd_puts(" Los gehts ");delay_ms(2750);lcd_clrscr();
    	
    	time=0;time1=0;time2=0;rd1=0;rd2=0;
    	sei();	//Interups Global an
    
    	while (1) {
    		_delay_us(980);time1++;time2++;
    		//time++ //Gesamtzeit
    		
    		//int_to_ascii(integer wert,output char,kommastelleverschieben wert,leerzeichen vor dem wert) 
    		/*lcd_puts("out_buf");
    		lcd_puts("V ");
    		lcd_putc('[');
    		lcd_puts("lool");
    		lcd_gotoxy(0,1);*/
    					}
    	return(0);
    }

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    02.11.2005
    Alter
    49
    Beiträge
    1.146
    Wenn Du die ISC-Bits im MCUCR-Register entsprechend einstellst, reagieren die Interrupts nicht mehr auf einen Pegel, sondern auf eine Flanke. Damit sollte Dein Problem zu beheben sein.

    Gruß,
    askazo

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    01.06.2006
    Ort
    Gernrode-Ilmenau
    Beiträge
    48

    Problem mit externem/internen Interrupt

    habe die Bits gesetzt, nur muss ich ja den Kontakt der den Impuls gibt irgendwie entprellen, da ein schleifkontakt ja bei drüberfahren doch mehrmals auslösen kann. Deshalb möchte ich die Externen Interrupts für eine gewisse Zeit deaktivieren, d.h. immer den Interupt der ausgelöst wurde. Wenn eine gewisse Zeit vergangen ist, soll er wieder aktiviert werden. Dies wollte ich mit einem Overflow Timer machen, wenn eine gewisse anzahl von Overflows existiert und der Externe Interrupt auf "aus" steht, dann soll er wieder aktiviert werden.
    Leider funktioniert dieses insofern nicht, das der externe Interrupt wenn der Kontakt prellt trotzdem auslöst.
    Hier mein Quellcode:
    Code:
    #include <avr/io.h>
    #include <inttypes.h>
    #include <avr/interrupt.h>
    #define F_CPU 4000000UL  // 4 MHz
    #include <util/delay.h>
    #include "lcd.c"
    #include "lcd_hw.h"
    #include <string.h> 
    
    uint16_t time,time1,time2; 
    uint8_t isr1,isr0,overflow1,overflow2,rd1,rd2;//Rundenanzahl
    char zeichen,output[20+1];
    
    void delay_ms(unsigned int ms)
    /* delay for a minimum of <ms> */
    {    while(ms){ _delay_ms(0.96);ms--;}}
    static void int_to_ascii(uint16_t inum,char *outbuf,signed char decimalpoint_pos,signed char spacepadd){
    	signed char i,j;
    	char chbuf[8];
    	j=0;
    	while(inum>9 && j<7){
    		// zero is ascii 48:
    		chbuf[j]=(char)48+ inum-((inum/10)*10);
    		inum=inum/10;
    		j++;
    		if(decimalpoint_pos==j){
    			chbuf[j]='.';
    			j++;}
    			}
    	chbuf[j]=(char)48+inum; // most significant digit
    	decimalpoint_pos--;
    	while(j<decimalpoint_pos){
    		j++;
    		chbuf[j]='0';}
    	if (spacepadd && j > (decimalpoint_pos+2)){
    		spacepadd=0;
    	}
    	if(decimalpoint_pos==j){
    		j++;
    		chbuf[j]='.';
    		j++;
    		chbuf[j]='0'; // leading zero
    	}
    	if (spacepadd){
    		j++;
    		chbuf[j]=' '; // leading space padding: "9.50" becomes " 9.50"
    	}
    	// now reverse the order 
    	i=0;
    	while(j>=0){
    		outbuf[i]=chbuf[j];
    		j--;
    		i++;	}
    	outbuf[i]='\0';
    }
    
    ISR(TIMER0_OVF_vect) /*Interrupt Timer0 Overflow*/ 
    
    { 
    	if(isr0==0){overflow1++;if(overflow1==50){GICR|=GICR|(1<<6);overflow1=0;isr0=1;}};//wenn genügend zeit vergangen ist Interrupts wieder anschalten
    	if(isr1==0){overflow2++;if(overflow2==50){GICR|=GICR|(1<<7);overflow2=0;isr1=1;}};
      }
    
    
    
    ISR(INT0_vect) {lcd_gotoxy(0,0);lcd_puts("P1: ");// in Zeile 1 P1: schreiben
        int_to_ascii(rd1,output,0,1);lcd_puts(output);//in Zeile 1 Rundenanzahl1 schreiben
    	int_to_ascii(time1,output,3,1);lcd_puts(output);time1=0;//im Zeile 1 Rundenzeit1 schreiben
    	rd1++;//Rundenanzahl erhöhen
    	isr0=0;GICR |=(1<<7);//externen interrupt 0 deaktivieren
    	}
    ISR(INT1_vect) {lcd_gotoxy(0,1);lcd_puts("P2: ");
    	int_to_ascii(rd2,output,0,1);lcd_puts(output);
    	int_to_ascii(time2,output,3,1);lcd_puts(output);time2=0;
    	rd2++;
    	isr1=0;GICR |=(1<<6);
    }
    
    
    
    
    int main(void)
    {	DDRD |= (1<<PD2);	//Register D für PD2 (auf 1) als Ausgang geschaltet
    	DDRD |= (1<<PD3);
    	PORTD |= (1 << PD2);
    	PORTD |= (1 << PD3);
    	GICR |= (1<<6)|(1<<7);	//INT0,INT1 als Interrupt aktivieren
    	MCUCR|=(1<<ISC11)|(1<<ISC10)|(1<<ISC00)|(1<<ISC01);//Auf steigende Flanke initialisieren
        
    	TCCR0 |= (1<<CS00) | (1<<CS02); /*Prescaling /1024*/ 
      	TIMSK |= (1<<TOIE0); /*Overflowinterrupt aktivieren*/ 
    
    	lcd_init(LCD_DISP_ON);
    	lcd_puts(" Los gehts ");delay_ms(2750);lcd_clrscr();
    	
    	time=0;time1=0;time2=0;rd1=0;rd2=0;
    	sei();	//Interups Global an
    
    	while (1) {
    		_delay_us(980);
    		cli();time1++;time2++;sei();
    		//time++ //Gesamtzeit
    		
    		//int_to_ascii(integer wert,output char,kommastelleverschieben wert,leerzeichen vor dem wert) 
    		/*lcd_puts("out_buf");
    		lcd_puts("V ");
    		lcd_putc('[');
    		lcd_puts("lool");
    		lcd_gotoxy(0,1);*/
    					}
    	return(0);
    }

  4. #4
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    02.11.2005
    Alter
    49
    Beiträge
    1.146
    Wenn Du das Prellen verhindern willst, musst Du die Interrupts in der ISR gleich als erstes deaktivieren. Das ganze Umrechnen und aufs LCD schreiben dauert ja im Vergleich zum Prellen ziemlich lange.

    Gruß,
    askazo

  5. #5
    Benutzer Stammmitglied
    Registriert seit
    01.06.2006
    Ort
    Gernrode-Ilmenau
    Beiträge
    48
    okhabe ich gamacht, macht aber anscheinend keinen Unterschied. Geht das erstmal prinzipiell mit dem deaktivieren und besonders das reaktivieren so?
    also das GICR|=GICR|(1<<6);habe ich mir mal aus dem Hut gezaubert,
    weiß aber nicht ob das so geht und zulässig ist.

  6. #6
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    02.11.2005
    Alter
    49
    Beiträge
    1.146
    Achso, da habe ich eben gar nicht so drauf geachtet....
    Mit
    GICR |= (1<<6)
    aktivierst Du den Interrupt.
    Um ihn zu deaktivieren, müsstest Du
    GICR &= ~(1<<6)
    schreiben.

    Was mir noch aufgefallen ist:
    Warum verwendest Du für die Zeitmessung keinen Timer? Das ist doch die Paradeanwendung für einen Timer. Und viel genauer als mit delay.

    askazo

  7. #7
    Benutzer Stammmitglied
    Registriert seit
    09.09.2006
    Ort
    Bayer/Unterfranken
    Beiträge
    31
    Hallo,

    vllt ne blöde Idee aber hast du schon mal cli(); probiert?

    Gruß
    Manu

  8. #8
    Benutzer Stammmitglied
    Registriert seit
    01.06.2006
    Ort
    Gernrode-Ilmenau
    Beiträge
    48
    mit cli deaktiviere ich ja global die interrupts, dann werden ja beide externen interrupts lahmgelegt. Ich möchte aber nur jeweils einen ausschalten, da der anderen noch für die zeitmessung des anderen Kontakts benötigt wird. Wenn jetzt der zweite externe Interrupt ausgelöst werden soll und der erste ist noch im Entprellungszeitraum, dann soll das ja auch gehen. Mit cli() geht das meines Wissens nach nicht.

Berechtigungen

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

12V Akku bauen