www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Timerprogrammierung AVR Butterfly


Autor: Tom Heinrich (dastoem)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,
ich bin grade dabei den Timer1 vom ATMega169 zu programmieren. Doch 
irgendwie gelingt mir die Sache nicht so richtig.

Aber vielleicht fang ich erstmal von vorn an: Ziel meiner Arbeit ist es 
einen kleinen Funktionsgenerator zu programmieren, der an einem 
Ausgangspin eine Rechteckspannung mit variabler Frequenz (10Hz-20KHz) 
erzeugt.

Mein bisheriges Testprogramm:
void init_timer3 (unsigned int wert)
{
  timer_preload(wert); //Wert vorladen
  cli();
  TIMSK1 |= (1 << TOIE1); //Timer1 mit Preloading starten; Interrupt bei Überlauf
  TCCR1B = (0 << CS11)|(1 << CS10); //Prescaler auf 1 stellen
  sei();    //Interrupts erlauben
  
}

void timer_preload (unsigned int wert)
{

  TCNT1 = wert;
}

int main (void)
{
  DDRD |= (1<<PD0);  //Port D für Output konfigurieren
  PORTD=( 1 << PD0);
  init_timer3 (0xFFFE); //Timer initialisieren
  
  while (1) //main loop
  {
    
  }
  
  return 0;
  
}

ISR (SIG_OVERFLOW1)
{
  cli();
  PORTD ^= (1 << PD0); //Wert an PortD_Pin0 invertieren
  timer_preload(0xFFFE); //Timer1 vorladen
  sei();
}


Dazu benötige ich einen Timer, der in bestimmten zeitlichen Abständen 
mit Hilfe einer ISR meinen Ausgangspin toggelt. Ich hab gerade versucht, 
diesen Timer mit oben stehendem Programm zu realisieren. Doch irgendwie 
bekomme ich am Ausgang nur eine Frequenz von 10KHz. Nach meinem 
Dafürhalten, sollte diese doch wesentlich höher sein oder?
Da der Systemtakt ja 1MHz beträgt, sollte sich die Frequenz am Ausgang 
doch in diesem Bereich bewegen oder liege ich da falsch?

Hat jemand von euch Erfahrungen mit diesem uC und könnte mir helfen?

Danke schonmal,
Tom

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tom Heinrich wrote:

> Da der Systemtakt ja 1MHz beträgt, sollte sich die Frequenz am Ausgang
> doch in diesem Bereich bewegen oder liege ich da falsch?

Deine ISR verbraucht ja auch Zeit.
Bei einem preload Wert von 0xFFFE bewegt sich der µC praktisch nur
noch in der ISR. Sobald eine ISR fertig ist, ist der Timer schon
wieder im Überlauf und die ISR startet sofort wieder.
Aber: Wie gesagt vom Auslösen des Interrupt bis dann endlich der
Pin getoggelt wird, vergeht ja auch Zeit, da ja einige Takte
dafür benötigt werden.

Allerdings: 10kHz kommt mir schon etwas wenig vor.
Hast du den Optimizer eingeschaltet?

Was im Programm auffällt:
das cli() und sei() gibst du mal ganz schnell wieder aus der ISR
heraus. Das passiert erstens sowieso automatisch und ist zweitens
kontraproduktiv. Die Interrupts sollen erst dann wieder freigegeben
werden, wenn die ISR tatsächlich zu Ende ist. Also erst mit dem
abschliessenden Return. Und darum kümmert sich der Compiler.

ISR (SIG_OVERFLOW1)

Der Name SIG_OVERFLOW1 ist der alte Name, der mit SIGNAL benutzt
wurde. Die für ISR vorgesehenen Namen enden alle auf *_vect

Und zu guter letzt. Sowas macht man nicht mit Overflow und Timer-
reload. Dafür gibt es den CTC Modus des Timers.
Vorteil: Das ist erstens taktgenau und man muss sich nicht um den
Reload kümmern

Autor: Tom Heinrich (dastoem)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erstmal danke für deine Hilfe.

Mit Compare hatte ich schon herumexperimentiert. Leider mit mäßigem 
Erfolg. Welche Register müssen gesetzt werden, um zuverlässig im 
CTC-Modus zu arbeiten?

Den Preload-Wert hatte ich auf 0XFFFE gesetzt, um herauszufinden mit 
welcher maximalen Frequenz ich den Pin am Ausgang toggeln kann. 
Jedenfalls kommen mir Frequenzen im kHz-Bereich sehr sehr spanisch vor. 
Von welchem Optimizer sprichst du?

Kannst jemand die Taktfrequenz des ATMega169 auf dem Butterfly mit 1MHz 
bestätigen oder hab ich mich da vertan?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tom Heinrich wrote:
> Erstmal danke für deine Hilfe.
>
> Mit Compare hatte ich schon herumexperimentiert. Leider mit mäßigem
> Erfolg. Welche Register müssen gesetzt werden, um zuverlässig im
> CTC-Modus zu arbeiten?

Steht alles im Datenblatt.

>
> Den Preload-Wert hatte ich auf 0XFFFE gesetzt, um herauszufinden mit
> welcher maximalen Frequenz ich den Pin am Ausgang toggeln kann.
> Jedenfalls kommen mir Frequenzen im kHz-Bereich sehr sehr spanisch vor.
> Von welchem Optimizer sprichst du?

Vom Optimizer des Compilers.
Ist der nicht aktiv ist es nicht ungewöhnlich, dass das Ergebnis
des Compilers doppelt so gross ist wie mit Optimizer.

>
> Kannst jemand die Taktfrequenz des ATMega169 auf dem Butterfly mit 1MHz
> bestätigen oder hab ich mich da vertan?

Mach dir ein Testprogramm und sieh nach (da ich den Butterfly
nicht kenne, gehe ich mal davon aus, dass am Port B ein paar
LED sein werden. Falls die woanders sind, musst du anpassen)

#define F_CPU 1000000

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

void Delay()
{
  unsigned char i;

  for( i = 0; i < 100; ++i )
    _delay_ms( 10 );
}

int main()
{
  DDRB = 0xFF;
 
  while( 1 ) {

    PORTB = 0xFF;
    Delay();

    PORTB = 0x00;
    Delay();
  }
}

Wichtig: Hier muss der Optimizer des Compilers eingeschaltet
sein (Option -Os), ansonsten stimmen die Zeiten im _delay_ms
nicht.

Und dann die Frage: Wie lange ist die LED ein bzw. aus.
Wenn das in etwa eine Sekunde ist, dann läuft dein µC auch
tatsächlich mit der unter F_CPU angegebenen Frequenz von
1000000Hz = 1Mhz

Autor: Tom Heinrich (dastoem)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, ich hab das jetzt mit Hilfe eines Compare-Timers realisiert. Damit 
kriege ich Frequenzen bis 20kHz, mehr ist leider nicht drin. Die 
Taktfrequenz des ATMega169 ist offenbar wirklich 1MHz, da bei 
Prescaler=1 der übergebene Zahlenwert 1:1 übernommen wird und mit einem 
Oszi problemlos gemessen werden kann.

Das -Os Flag des GCC war übrigens die ganze Zeit gesetzt. Mein 
Testprogramm sieht somit wiefolgt aus:
void init_timer3 (unsigned int wert)
{
  TCCR1A = (1<< COM1A0)|(1 << FOC1A);
  TIMSK1 |= (1 << OCIE1A); //Timer1 mit CompareA starten; Interrupt bei Gleicheit
  TCCR1B = (1 << WGM12)|(0 << CS11)|(1 << CS10); //Prescaler auf 1 stellen
  setcompare (wert);
    
}

void setcompare(unsigned int wert)
{
  OCR1A = wert;
}

int main (void)
{
  DDRD |= (1<<PD0);  //Port D für Output konfigurieren
  PORTD = ( 1 << PD0);
  
  init_timer3 (50); //Zeit in us an Timer übergeben
  sei();
  while (1) //main loop
  {
  
  }
  
  return 0;
  
}

ISR (TIMER1_COMPA_vect)
{
  PORTD ^= (1 << PD0); //Wert an PortD_Pin0 invertieren
}

Vielen Dank nochmal für deine Hilfe zum Timer und für die Anregungen zur 
korrekten Syntax :)

Autor: Martin Thomas (mthomas) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, üblicherweise "läuft" der ATmega169V auf dem BF mit 1MHz, Grund 
dafür ist aber die Softwareeinstellung des Prescalers für den internen 
R/C-Oszillator (8MHz) in Register CLKPR. Dieser wird vom 
vorinstallierten Bootloader bzw. der Initialisierungsroutine des 
Beispielcodes auf 8 gesetzt wird (8MHz/8=1MHz). ATmega169V ist bis 8MHz 
ab 2,7V Betriebspannung (4MHz ab 1,8V) spezifiziert. Falls es etwas 
schneller werden soll: Prescaler verkleinern. Kann man per Software 
machen, Zugriff aus Fuses ist dafür nicht notwendig. Erhöht allerdings 
auch den Strombedarf. Noch schneller: CTC-Modus und "pinwackeln" per 
Hardware (nicht in einer ISR per Software), vgl. für Timer 1 
Beschreibung Register TCCR1A. Damit sind Frequenzen bis F_CPU/2 möglich 
(also bis zu 8MHz/2=4MHz), allerdings nur an bestimmten Pins. Z.B. sind 
die OC-Pins von Timer1 PB5 und PB6 auf dem BF durch Piezo-"Pieper" bzw. 
Joystick belegt. Nehme an, der Joystick soll zur Frequenzeinstellung 
ohne Einschränkung in Betrieb bleiben, bleibt PB5. Falls das "mitpiepen" 
stört, kann man den Pieper durch auslöten eines klitzekleinen 
Widerstands (R202) relativ problemlos stilllegen. Langer Rede: es ist 
schon "mehr drin".

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.