www.mikrocontroller.net

Forum: Mikrocontroller und Elektronik AVR Atmega16 Timer Problem

Autor: Marco M. (marco1987)
Datum: 16.05.2008 14:18
Dateianhang: takt.JPG (21,3 KB, 25 Downloads)
preview image for takt.JPG

Hallo ihr,

erstmal kurz vorab ich habe sehr wenig Kenntnisse in µC Programmierung
und das nach LED an aus schalten meine ersten Versuche, also
entschuldigt meine vllt einfachen Fragen

ich habe ein Problem mit dem 16 bit Timer. Ich sitze schon mehrere Tage
an diesem Problem. Also mein Ziel:

Ich will einen Takt erzeugen. (siehe Bild)

Könnt ihr mir einen Tipp geben wie ich da am besten rangehe. Soweit ich
das mitbekommen habe gehen solche niedrigen Frequenze nicht mit dem 8
Bit Timer sonder nur mit dem 16 bit Timer.

Mein Ansatz nun:
Atmel Timer Calculator Prescaler , TCNT1H und L berchnen. Dies habe ich
dann auch in meinen Quellcode eingetragen leider kam immer die flasche
Frequenz raus bzw gar nichts.

Noch kurz als Info ich Programmiere in C mit dem STK500 und mein µC ist
ein Atemega16.

Quellcode:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <timer_set.h>
#include <avr/delay.h>



SIGNAL (SIG_OVERFLOW1){

  TCNT1L=0x24;   // für 4 sec. Periodendauer
     TCNT1H=0xF4;

}


int main (void) {
   DDRC = 0xff;
   DDRD = 0xff;


PORTD |= (1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5)
| (1<<PD6) | (1<<PD7)  ;

  TCCR1A= (1<<COM1A1) | (0<<COM1A0) |  (0<<WGM11)  | (0<<WGM10);// pwm
aus durch wgm 0


   TCCR1B=(1<<CS10) | (1<<CS12);  // Prescaler 1024


   for (;;) {
}


ist dieser Ansatz völlig falsch?

Wie kann ich die beiden geforderten Signale generieren?


Danke
Autor: Johannes M. (johnny-m)
Datum: 16.05.2008 14:24

SIGNAL ist lange veraltet. signal.h rauswerfen und ISR verwenden.

Was aber echt fatal ist:
  
  TCNT1L=0x24;   // für 4 sec. Periodendauer
  TCNT1H=0xF4;
Das High-Byte muss bei solchen 16-Bit-Registern immer zuerst
geschrieben werden. Schau mal im Datenblatt nach, da ist bei dem
16-Bit-Timer ein extra Abschnitt zum Thema "Accessing 16-bit registers".
Allerdings programmierst Du in C und kannst den Krempel mit der
Zugriffsreihenfolge ganz komfortabel dem Compiler überlassen. Der kennt
nämlich ein 16-Bit-(Pseudo-)Register TCNT1 (ohne L und H), und der macht
daraus automatisch die richtige Zugriffssequenz. Also
TCNT1 = 0xF424;
tut's auch. Oder noch einfacher
TCNT1 = 62500;

Und wenn Du einen Interrupt benutzen willst, dann musst Du den auch
freigeben. In Deinem Code ist aber weder eine lokale Freigabe über das
entsprechende Enable-Bit noch die globale Freigabe zu sehen.

Schau Dir bitte im AVR-GCC-Tutorial an, wie es geht. Da steht
eigentlich alles drin. Es macht so wenig Sinn, in Deinem obigen Code
noch nach irgendwelchen Fehlern zu suchen.

Vor Allem solltest Du Dich über die unterschiedlichen Betriebsarten der
Timer informieren (v.a. CTC und PWM). Die sind für Dein Vorhaben nämlich
wesentlich besser geeignet als ein Timer-Reload, der beim AVR eigentlich
generell keinen großen Sinn macht.

Mit welcher Taktfrequenz läuft Dein Controller überhaupt? 62500 als
Reload-Wert für 4 Sekunden lassen auf eine Taktfrequenz von unter 1 MHz
schließen...

...und da Du das TCNT1 am Anfang nicht initialisierst, läuft der Timer
erst mal von Null an bis zum ersten Overflow. Und das dauert bei einem
Prescaler von 1024 sehr lange (bei 1 MHz mehr als eine Minute)...
Autor: Marco M. (marco1987)
Datum: 16.05.2008 15:24

Vielen Dank für die schnelle Antwort.

Also mein Atmega16 müsste nach meinem Wissenstand mit 16 MHZ laufen.
Ich habe da wie gesagt so ein Tool womit man das ausrechnet, wie TcCNTL
und H aussehen müssen. Das mit dem von = anlaufen ist mir auch schon
aufgefallen das am Anfang das sehr lange dauert.

Also sagst du PWM. Noch eine schwierigkeit mehr:-)

Naja danke erstmal. vllt findet sich ja noch jmd der mir weiterhelfen
kann.
Autor: Karl heinz Buchegger (kbuchegg) (Moderator)
Datum: 16.05.2008 15:45

Marco Müeller wrote:
> vllt findet sich ja noch jmd der mir weiterhelfen
> kann.

Mein Tip.
Leg dieses Berechnungstool erst mal zur Seite und bemüh dich zu
verstehen, wie ein Timer arbeitet und wie der Zusammenhang zum
Prescaler ist. Das ist im Grunde Watscheneinfach.
Und erst dann, wenn du die Prescaler bzw. Comparewerte mit der
hand ausrechnen kannst (und das auch am 'lebenden' Objekt überprüft
hast), dann benutze wieder das Tool um dir die fade Rechnerei zu
ersparen.

Auch das beste Tool hilft nichts, wenn man nicht versteht was da
eigentlich abgeht.
Autor: Joan P. (joan)
Datum: 16.05.2008 15:52

Marco Müeller wrote:
> Ich habe da wie gesagt so ein Tool womit man das ausrechnet, wie TcCNTL
> und H aussehen müssen.

Das kannst Du dir wie schon geschrieben sparen.. das macht der
C-Compiler AUTOMATISCH.

TCNT1 = x; reicht völlig aus und lenkt dich nicht vom wesentlichen ab,
wie zB:

sei(); // Interrupts global ein

oder die Einstellung der fCPU-Register..

Lies Dir wirklich erstmal das Tutorial durch, da klären sich 99% der
Fragen die Du grad hast von selber und ganz andere treten an deren
Stelle ;-)
Autor: Marco M. (marco1987)
Datum: 17.05.2008 10:10

So also das habe ich bisher auf die Beine gestellt:

Ist das mit den Interrupts ausschalten richtig?
wann muss ich die Interrupts mit sei() zulassen?
so wie ich jetzt mein Programm verstanden habe zählt der der zähler von
0 bis 65500 und dann wieder zurück,
jedesmal wenn er den wert im vergleichsregister OCR1A erreicht lösst er
einen Interrrupt aus.

Und mit TCNT1 lade ich den Zähler dann vor, damit er dann nicht wieder
von 0 anfängt oder wie?

kann mir jmd nochmal die Formel hier rein schreiben, mit der ich mir die
frequenz mit prescaler usw ausrechnen kann?

Und im Datenblatt habe ich was von wegen BOTTOM und TOP gelesen für hoch
und runter zählen wofür brauch man das?


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

#include <avr/delay.h>


SIGNAL (SIG_OVERFLOW1){


cli();  //interruptsausschalten
  TCNT1 = 0x1856;   //eigentlich tcntl und h aber das weiss compiler


}


int main (void) {
   DDRC = 0xff;
   DDRD = 0xff;

TCCR1A= (1<<COM1A1) | (0<<COM1A0)  | (1<<WGM11)  | (1<<WGM10);// pwmaus
durch wgm 0
//  Hochzählen OC1 auf 0 runter auf 1| 10-Bit PWM Betriebsart
aktivieren.

TCCR1B=(1<<CS10) | (1<<CS12);  // Prescaler 1024

//TCCR1B=(1<<ICES1) ; //input compare steigende flanke auswertung

//TCCR1B=(1<<CTC1); // Clear Timer/Counter on Compare Match
Timer/Counter 1


OCR1A=6500;  //compare register;
   for (;;) {
}
}
Autor: Johannes M. (johnny-m)
Datum: 17.05.2008 11:39

Noch mal: SIGNAL ist veraltet. Mach es so, wie es im
AVR-GCC-Tutorial steht. Die delay.h steht auch nicht mehr im Ordner
"avr", sondern unter "util". Also
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

//und dann:
ISR(TIMER1_OVF_vect)
{
    //Code
}

Aber der Rest macht auch keinen Sinn! Bitte bitte bitte lies Dir das im
Tutorial genau durch! Das ICES1-Bit hat mit Deiner Anwendung überhaupt
nichts zu tun. Und Du lädst im Interrupt Handler immer noch den Timer
nach, was völliger Unsinn ist. Außerdem gibst Du nach wie vor den
Interrupt nicht frei, weder lokal noch global! Und ich frage mich, was
Du für ein Datenblatt hast. CTC1 ist ein veralteter Bitname, und das
steht in den aktuellen Datenblättern auch drin. Das Sperren der
Interrupts im Interrupt Handler ist ebenfalls überflüssig. Das passiert
automatisch durch die Controller-Hardware.

Deine Ungeduld bringt gar nichts. Setz Dich in aller Ruhe hin und lies
Dir die entsprechenden Passagen in der Literatur durch.
Autor: Marco M. (marco1987)
Datum: 17.05.2008 12:08

So folgendes hier sind auszüge aus dem AVR-GCC-Tutorial

8-Bit Timer zB

zuerst stehen da in welchem register sich was befindet usw, schön und
gut dann kommt dieser Absatz hier:


Der Zähler zählt nun aufwärts bis 255, um dann wieder bei 0 zu beginnen.
Der aktuelle Zählerstand steht in TCNT0. Bei jedem Überlauf von 255 auf
0 wird das Timer Overflow Flag TOV0 im Timer Interrupt Flag
TIFR-Register gesetzt und, falls so konfiguriert, ein entsprechender
Timer-Overflow-Interrupt ausgelöst und die daran gebundene
Interrupt-Routine abgearbeitet. Das TOV Flag lässt sich durch das
Hineinschreiben einer 1 und nicht wie erwartet einer 0 wieder
zurücksetzen.

Kann mir einer sagen was ein blutiger Anfänger mit sowas anfangen soll?
Interrupts kommen auch erst später im Tutorial.

Ich weiss nicht was daran so schwer ist mir ein einfaches Beispiel zu
geben mit dem ich das dann nachvollziehen könnte.


Wenn jmd von mir zum Beispiel Integralrechnung erklärt haben wollte dann
würde ich ihm auchein einfaches Beispiel zeigen und nciht sagen "lies
dir mal das und das buch durch"

Danke
Autor: Marco M. (marco1987)
Datum: 17.05.2008 12:11

> Das ICES1-Bit hat mit Deiner Anwendung überhaupt
> nichts zu tun.

Deshalb ist es ja ausgeklammert

> Und ich frage mich, was
> Du für ein Datenblatt hast. CTC1 ist ein veralteter Bitname, und das
> steht in den aktuellen Datenblättern auch drin.
Deshalb auch ausgeklammert nur damit ich weiss das das eigentlich der
CTC befehl ist
Autor: Johannes M. (johnny-m)
Datum: 17.05.2008 13:33

So, ich hab mir grad mal im Tutorial die betreffenden Passagen
angesehen, und festgestellt, dass da tatsächlich etwas
Überarbeitungsbedarf besteht. Der CTC-Modus wird gar nicht explizit
erwähnt, was mir entgangen war.

Abgesehen davon willst Du etwas mit dem 16-Bit-Timer machen (und nicht
mit nem 8-Bit-Timer), weshalb Du natürlich besser den Abschnitt über den
16-Bit-Timer als Referenz nimmst. Für Dein derzeitiges Vorhaben, ein
Signal an einem Portpin auszugeben, brauchst Du auch zunächst gar keinen
Interrupt. Das Schalten des Portpins kann der µC auch allein machen,
ohne dass das Programm eingreifen muss.

Das Beste ist, sich das Datenblatt des µC (und zwar des Mega16 und
nicht des Mega8, auf den sich das Tutorial bezieht) zur Hand zu nehmen
und dort in den Tabellen nachzuschlagen, welche Bits für welche
Betriebsart gesetzt werden müssen. Das ist in den betreffenden Passagen
eigentlich sehr schön übersichtlich zusammengefasst.

Der CTC-Modus (Clear Timer on Compare match) ist eine Betriebsart, in
der der Timer bei Erreichen des Compare-Wertes in dem betreffenden
Compare-Register zurückgesetzt wird. Beim Compare-Ereignis kann
zusätzlich noch ein bestimmter Portpin automatisch umgeschaltet werden
(was Du ja auch schon versucht hast, über die COM-Bits einzustellen).
CTC bildet im Prinzip die Grundlage für PWM. Bei der PWM kommt dann eben
zusätzlich eine zweite Compare-Einheit ins Spiel.

Wie gesagt: Lass die ganze Interrupt-Sache erst mal weg und versuche, an
einem OC-Pin ein Signal auszugeben.
Autor: Johannes M. (johnny-m)
Datum: 17.05.2008 13:57
Dateianhang: uC_Einfuehrung.pdf (432,4 KB, 326 Downloads)

Anbei mal eine Art "AVR-Tutorial", das zur Verwendung zusammen mit dem
entsprechenden Controller-Datenblatt ausgelegt ist. Ich habe versucht,
die wichtigen Komponenten und ihre Anwendung im Klartext verständlich zu
beschreiben. Es werden dabei allerdings meist keine direkten Beispiele
in Sachen I/O-Register u.ä. gegeben, v.a. weil es recht universell sein
soll, und bei unterschiedlichen AVRs auch unterschiedliche Dinge zu
beachten sind. Die konkreten Bitkonfigurationen für die Steuerregister
muss man sich dann anhand des Datenblattes herleiten. Ist eben
eigentlich für Studenten im Rahmen eines Programmierpraktikums gedacht,
aber vielleicht hilft es Dir auch, gewisse Zusammenhänge zu verstehen.

Antwort schreiben

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

Wichtige Regeln - erst lesen, dann posten!

  • Suchfunktion und Betreffsuche benutzen - vielleicht gibt es schon einen ähnlichen Beitrag
  • Aussagekräftigen Betreff wählen
  • Im Betreff angeben um welchen Controllertyp es geht (AVR, PIC, ...)
  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
  • JPEG-Dateien (.jpg) nur für Fotos und Scans verwenden
  • Schaltpläne, Screenshots usw. als PNG oder GIF anhängen

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [pre]vorformatierter Text (z.B. Code in anderen Sprachen)[/pre]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel






webmaster@mikrocontroller.netImpressumWerbung auf Mikrocontroller.net