C Atmega2560

http://www.electronicsplanet.ch/mik.../ATMega16/ATmega16-ADC-Autotrigger-Timer0.htm


ich glaube so wie in diesem Beispiel sollte es gehn....

Wenn ich das dort richtig verstehe, dann wird eine ADC-messung ausgelöst, wenn der Compare wert erreicht wird?

Das Beispiel hab ich mit dem Timer0 auch ausprobiert, das scheint zu klappen. Nur ist das ein 8-Bit Timer, und löst bei meinem F_CPU 16Mhz natürlich viel zu schnell die ADC-Messungen bzw. Eingangsumschaltung aus.......... und es wird alles blockiert, da nur noch die interrupts laufen :confused:
 
Das Beispiel hab ich mit dem Timer0 auch ausprobiert, das scheint zu klappen. Nur ist das ein 8-Bit Timer, und löst bei meinem F_CPU 16Mhz natürlich viel zu schnell die ADC-Messungen bzw. Eingangsumschaltung aus.......... und es wird alles blockiert, da nur noch die interrupts laufen :confused:

Nun ja, viel wirst du in der TimerISR nicht ausführen. Wenn die ISR natürlich alle 10us aufgerufen wird, belastet dies das System dann schon ;-)

Kannst du keinen 16 Bit Timer werwenden?

Du kannst es auch ohne AutoTrigger machen. Die Messungen erfolgen im Abstand von 1 Sekunde, das sind ja zeitlich gesehen Ewigkeiten für den Mikrocontroller. Verwende einfach irgendeinen TimerInterrupt, zum Beispiel einen der alle 10ms auftritt (den hast du vielleocht sowieso, weil du den für andere Sachen benötigst, Tasten pollen/entprellen zum Beispiel). Da verwendest du einen Counter in der ISR und vergrößerst dadurch die Zeit für den Start der Messung. Die Belastung von ein paar Maschinenzyklen alle 10ms ist keine Belastung :)

Also entweder mit Autotrigger durch ein geeignetes Event oder manuell alle Sekunde selber starten.
 
die 1s bleibt natürlich nicht - das is nur zum testen ;)

das Problem ist eben, wenn ich die adc-messung vom main aus immer starten muss, dann kann es unter umständen sein, dass die adc-Messung sich leicht verzögert, und das seh ich dann an meinen LED-s, die parallel zur Eingangswahhl-umschaltung laufen, soll heißen, ich seh, welcher eingang gerade aktiv ist.
Bei 1s Umschaltung passiert natürlich nichts - das ist genügend zeit.

wenn ich aber die Zeit verkürze, so wie es später mal laufen soll, dann merk ich, wenn ich zum Beispiel Display-Eingabe mit meinem tollem Keyboard mach :cool: , dann kanns sein, dass man kurz ein stoppen der Umschaltung wahr nimmt, weil der Code im main zu lang dauert. Und das stört mich eben ;)
Deswegen dachte ich mir, ich mach das über Interrupt - und auto triggerung, dann bekommt man davon nichts mit.
 
die 1s bleibt natürlich nicht - das is nur zum testen ;)

...
Deswegen dachte ich mir, ich mach das über Interrupt - und auto triggerung, dann bekommt man davon nichts mit.

Ja genau, kannst du machen. Es spricht auch nichts dagegen. Du musst dir nur überlegen, zu welchem Zeitpunkt du den externen Analog-Multiplexer umschaltest. In der ADC ISR würde es sich sicher anbieten.
 
Irgendwie komm ich mit den zwei Timer Registern TCCR1B und TCCR1A nicht klar.

Wie muss ich die jetzt richtig setzen......


Code:
void init_adc()
{
	ADMUX = 0x00;
	ADMUX  |= (0<<REFS1)|(1<<REFS0); 
	ADCSRA |= ( (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2) );
	//ADCSRA |= (1 << ADSC);
	ADCSRA |= (1 << ADIE);
	ADCSRA |= (1 << ADEN);
	
	ADCSRA |= (1 << ADATE);
		
	ADCSRB |=(1<<ADTS0)|(1<<ADTS2);   //Timer/Counter1 Compare Match B

	sei();                            // Set the I-bit in SREG
	ADCSRA |= (1<<ADSC);              // Start the first conversion
		
	while(ADCSRA &(1<<ADSC))
	{
		;
	}
	volatile uint16_t dummy = 0;
	dummy = ADC;
	cli();
	
	
}

Code:
void timer1_init(void)
{
	TCCR1A = 0;     // set entire TCCR1A register to 0
	TCCR1B = 0;     // same for TCCR1B

	// set compare match register to desired timer count:
	OCR1B = 15624;  //?
	
	// turn on CTC mode
	TCCR1B |= (1 << WGM12);
	// Set CS10 and CS12 bits for 1024 prescaler:
	TCCR1B |= (1 << CS10);
	TCCR1B |= (1 << CS12);



}


Code:
ISR(ADC_vect)
{
	
 //tu was
	 TIFR1 |= (1<<OCF1B);

}


EDIT:

der springt mir nicht in den ADC-Interrupt
 
stimmt das jetzt so .. :confused:


Code:
void timer1_init(void)
{
	TCCR1A = 0;     // set entire TCCR1A register to 0
	TCCR1B = 0;     // same for TCCR1B
	// set compare match register to desired timer count:
	OCR1A = 15624;
	
	// turn on CTC mode
	TCCR1A |= (1 << WGM12);
	// Set CS10 and CS12 bits for 1024 prescaler:
	TCCR1B |= (1 << CS10);
	TCCR1B |= (1 << CS12);
	// enable timer compare interrupt:
	//TIMSK1 |= (1 << OCIE1B);


}
 
Bei der Initialisierung des ADC machst du eine Dummy-Messung und pollst ADSC. Da der ADC Interrupt (ADIE Bit gesetzt) aktiviert ist, wird dessen ISR bei Ende der Wandlung ausgeführt. Zum Schluss schaltest du alle Interrupts global aus. Wenn du danach die Interrupts global nicht wieder frei gibst, wird die ADC ISR nicht ausgerufen.

Bezüglich der Timer-Initialisierung muss ich auch erst mal in das Datenblatt schauen, ich habe nur im Moment leider kaum Zeit. Falls sonst niemand zwischenzeitlich helfen kann, schaue ich später noch einmal danach.

Code:
void init_adc()
{
    ADMUX = 0x00;
    ADMUX  |= (0<<REFS1)|(1<<REFS0); 
    ADCSRA |= ( (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2) );
    //ADCSRA |= (1 << ADSC);
    ADCSRA |= (1 << ADIE);
    ADCSRA |= (1 << ADEN);
    
    ADCSRA |= (1 << ADATE);
        
    ADCSRB |=(1<<ADTS0)|(1<<ADTS2);   //Timer/Counter1 Compare Match B

    [B]sei();[/B]                            // Set the I-bit in SREG
    ADCSRA |= (1<<ADSC);              // Start the first conversion
        
    while(ADCSRA &(1<<ADSC))
    {
        ;
    }
    volatile uint16_t dummy = 0;
    dummy = ADC;
    [B][B]cli();[/B][/B]
    
    
}
 
Bei der Initialisierung des ADC machst du eine Dummy-Messung und pollst ADSC. Da der ADC Interrupt (ADIE Bit gesetzt) aktiviert ist, wird dessen ISR bei Ende der Wandlung ausgeführt. Zum Schluss schaltest du alle Interrupts global aus. Wenn du danach die Interrupts global nicht wieder frei gibst, wird die ADC ISR nicht ausgerufen.

Bezüglich der Timer-Initialisierung muss ich auch erst mal in das Datenblatt schauen, ich habe nur im Moment leider kaum Zeit. Falls sonst niemand zwischenzeitlich helfen kann, schaue ich später noch einmal danach.

Code:
void init_adc()
{
    ADMUX = 0x00;
    ADMUX  |= (0<<REFS1)|(1<<REFS0); 
    ADCSRA |= ( (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2) );
    //ADCSRA |= (1 << ADSC);
    ADCSRA |= (1 << ADIE);
    ADCSRA |= (1 << ADEN);
    
    ADCSRA |= (1 << ADATE);
        
    ADCSRB |=(1<<ADTS0)|(1<<ADTS2);   //Timer/Counter1 Compare Match B

    [B]sei();[/B]                            // Set the I-bit in SREG
    ADCSRA |= (1<<ADSC);              // Start the first conversion
        
    while(ADCSRA &(1<<ADSC))
    {
        ;
    }
    volatile uint16_t dummy = 0;
    dummy = ADC;
    [B][B]cli();[/B][/B]
    
    
}

Interrupt wird im main wieder freigeschaltet, das sollte nicht das Problem sein
Das wäre echt nett, wenn du mir da helfen könntest





EDIT:
Ich denke jetzt hab ichs selbst rausgefunden ....

Aber wäre trotzdem toll, wenn du dir das nochmal anschauen könntest, da ich mir nicht 100% sicher bin.........

Ein Problem hatte ich allerdings, als ich in der ADC-ISR nur zu Testzwecken den ADC-WERT aufs Display ausgegeben hab, ist er manchmal hängen geblieben.....

Code:
void timer1_init(void)
{
	TCCR1A = 0;     // set entire TCCR1A register to 0
	TCCR1B = 0;     // same for TCCR1B
	// set compare match register to desired timer count:
	OCR1A = 977;
	// turn on CTC mode
	TCCR1B |= (1 << WGM12);
	// Set CS10 and CS12 bits for 1024 prescaler:
	TCCR1B |= (1 << CS10);
	TCCR1B |= (1 << CS12);
	
	//beispiel:
	//TCCR1A =                    // Normal mode (no WGMxy-Bits set)
	//(1<<COM1A0)             // Toggle A on match
	//|(1<<COM1B0)            // Toggle B on match

   TCCR1A  |=(1<<COM1B0);			// Toggle B on match
	
	//testoutput
   Display_DisplayBinary16(0,0,TCCR1A);
  
   Display_DisplayBinary16(0,20,TCCR1B);
  _delay_ms(5000);



}

Code:
ISR(ADC_vect)
{
	
	
		adc_val += ADC;
		
		
		ISR_ADC_VECT_COUNTER++;
		//Display_DisplayDecimal16(80,100,ISR_ADC_VECT_COUNTER);
		
		if(ISR_ADC_VECT_COUNTER==16)
		{
			if (adc_counter>128)
			{
				adc_counter=1;
				analog_channel=0;
			}
			analog_channel++;
			pcf8574_set_outputs(0,(255-adc_counter));
			pcf8574_set_outputs(2,(255-adc_counter));
			adc_counter =(adc_counter*2);
			
			ISR_ADC_VECT_COUNTER=0;
			adc_val =adc_val /16;
                        

//hier fehlt noch -> ins fifo - buffer schreiben

			//Display_DisplayDecimal16(80,80,adc_val);
			adc_val=0;
		}
	

	 TIFR1 |= (1<<OCF1B);
	 

   
 
}





Code:
void init_adc()
{
	ADMUX = 0x00;
	ADMUX  |= (0<<REFS1)|(1<<REFS0); 
	ADCSRA |= ( (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2) );
	//ADCSRA |= (1 << ADSC);
	ADCSRA |= (1 << ADIE);
	ADCSRA |= (1 << ADEN);
	
		
	ADCSRA |= (1 << ADATE);
		
		
	ADCSRB |=(1<<ADTS0)|(1<<ADTS2);   //Timer/Counter1 Compare Match B
	
}
 
Ich denke jetzt hab ichs selbst rausgefunden ....

Aber wäre trotzdem toll, wenn du dir das nochmal anschauen könntest, da ich mir nicht 100% sicher bin.........

Ein Problem hatte ich allerdings, als ich in der ADC-ISR nur zu Testzwecken den ADC-WERT aufs Display ausgegeben hab, ist er manchmal hängen geblieben.....

Ja, es müsste so stimmen. Du verwendest den Timer/Counter1 (16bit) im CTC Mode, das heisst, der läuft von 0 bis OCR1A. Der Prescaler ist 64. Der Timer/Counter wird mit 250kHz (4us) getaktet. Erreicht er den Wert OCR1A, wird er auf 0 zurückgesetzt. Da nach Reset OCR1B mit 0x0000 initialisiert wird, gibt es bei 0 das CompareB Ereignis, was den ADC triggert (Den ADC kann man nicht mit CompareA des Timer1 triggern).

In der ADC ISR löscht du dann auch das Anforderungsflag des CompareB Interrupts.

Das CompareB Ereignis tritt periodisch nach knapp 4ms ein (1/16MHz x 64 x (1+OCR1A)). Wichtig wäre, dass eine Wandlung weniger als 4ms dauert (ADC Prescaler Bits) und dass auch die Ausführungszeit der ADC ISR ausreichend kurz ist. Wenn du in der ADC ISR Displayausgaben machst, dann dürfen die erstens nicht so lange dauern und zweitens darfst du nicht im Hauptptogramm parallel zu der Interruptebene auf das Display zugreifen, da ansonsten das Protokoll gestört wird.

Testweise kannst du ja eine weitere globale Variable einführen (volatile uint16_t), die den Mittelwert in der ADC ISR aufnimmt und diese gibts du im Hauptprogramm aus (wichtig wäre im Hauptprogramm: cli(), Variable zwischenspeichern, sei(), dann zwischengespeicherte Variable ausgeben) Danach würde ich das FIFO programmieren.
 
Wie kommst du auf Prescaler 64 ?

Code:
TCCR1B |= (1 << CS10);
TCCR1B |= (1 << CS12);

CSn2 CSn1 CSn0 Description
1 0 1 clk I/O /1024 (From prescaler)

Sollte Prescaler 1024 sein? :confused:

Da habe ich sicher falsch gelesen. (Man sollte nichts schreiben, wenn man eigentlich nicht so die Zeit hat und von seiner Familie andauernd abgelenkt wird :pcguru:. )
Ich hatte mich wegen der knapp 4ms schon gewundert. So sind es 1024 x 62.5ns x (977+1), wobei das auch ein "krummer" Wert ist?!

Den Prescaler würde ich in einem Stück schreiben. Wenn ein Prescaler-Bit auf 1 ist, läuft der Timer.

TCCR1B |= (1 << CS10) | (1 << CS12);
 
:adore::adore::adore::adore::adore::adore::adore::adore::adore::adore::adore::adore:


Wollte nur mal nochmal DANKE sagen :D
Ich schätze deine Hilfe sehr , vorallem wenn man wenig Zeit hat ......

Das klappt jetzt wunderbar (denk ich :) ), hab auch schon den FIFO-Buffer mit drin, das klappt auch schon :cool:
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)