PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer verwenden als Wait Funktion



beginner1101
15.07.2008, 16:08
Hallo,

ich hab hier schon viele Threads die zum Thema Timer und Warteschleifen durchgelesen.

Ich blick aber eines nicht: Ich schreib irgendein Programm. Nun komm ich an einen Punkt, z. B. Tastendruck o.ä. und ab jetzt will ich eine gewisse Zeitspanne messen. Wie geht dass? Wenn ich den Timer am Anfang des Programms anstoße und bis zu einem gewissen Punkt laufen lasse, dann kommt der Interrupt. Wie lese ich den Interrupt jetzt aus? (ich hab in der ISR programmiert, dass immer ein PIN seinen Zustand ändert, aber dass will ich ja eigentlich nicht, ich will es von meiner main aus starten...) Und zweitens läuft der Timer ja immer weiter. Wenn ich in einer Endlosschleife bin, wird die Zeitspanne ja sehr ungenau, da der Timer ja dann nicht mehr bei 0 los läuft, sondern bei irgendwas........... Ich wollte mir eine Funktion (soe wie _delay_ms) bauen, die ich in meiner main quasi immer dann aufrufe wenn ich eine bestimmte Zeit brauche ](*,) . Und mein ganzes Programm so aufzubauen dass ich genaue Timestamps hab will ich auch nicht. Ich bin am verzweifeln.

Kann mir irgend jemand erklären wie der ganze Mist funktioniert? ](*,) ](*,) ](*,)

LG Anna

sternst
15.07.2008, 17:00
Deine Wait-Funktion müsste etwa so aussehen:

- Nötigen Timer-Wert berechnen (sofern unterschiedliche Wartezeiten möglich sein sollen)
- Wert in den Timer laden
- Timer starten (Timer zählt jetzt von diesem Wert an aufwärts)
- In einer Schleife warten, bis das Timer-Overflow-Flag gesetzt ist
- Timer anhalten
- Overflow-Flag löschen

Den Interrupt brauchst du nur, wenn das Programm in der Wartezeit etwas anderes erledigen soll. Allerdings wird es dann deutlich komplexer.

PS: Ich sehe aber nicht, welchen Vorteil das gegenüber den Delay-Funktionen haben soll. Oder meinst du vielleicht eher sowas wie einen Timeout?

McJenso
15.07.2008, 17:03
Hallo,

es gibt für die Timer den normalen Modus und den CTC-Modus. Alle Werte beziehen sich jetzt mal auf einen 8Bit Timer.
Im normalen Modus fängt der Timer mit der über den Prescaler eingestellten Geschwindigkeit an zu laufen. Da du bestimmt einen Vergleichswert eingestellt hast wird dieser irgendwann erreicht. In diesem Moment wird ein Compareflag gesetzt. Ist der Interrupt für diese Flag aktiv wird in die Routine gesprungen. Der Zähler läuft weiter bis zum Wert 255. Im nächsten Schritt wird der Wert 0 erreicht und es wird ein Overflowflag gesetzt. Ist der Interrupt aktiv wird wieder in die zugehörige Funktion gesprungen.
Im CTC-Modus läuft der Timer genauso bis zum Vergleichswert. Es wird wieder das Flag gesetzt und der Timer wird automatisch auf 0 Gestellt.

Um jetzt eine Zeit zumessen, kannst du den Timer im CTC-Modus so einstellen, dass die Zeit vom Start bis zum Erreichen des Vergleichswertes eine ms dauert. Dazu musst du einen geeigneten Prescaler wählen und den richtigen Vergleichswert einstellen. Die Formeln dazu findest du im Datenblatt. Es gibt dafür auch ein Tool, habe aber gerade keinen Link zur Hand. Du aktiviertst den OCIE (Interrupt beim Vergleich). In die Interruptfunktion schreibst du einfach Zähler++;
Wenn du jetzt wissen willst, wie viel Zeit verstrichen ist, schaust du dir Zähler an. Du musst nur aufpassen, irgend wann läuft auch Zähler über und wird wieder 0.


Gruß

Jens

izaseba
15.07.2008, 17:18
Hallo,

Ich weiß nicht so genau, ob ich Dein Problem richtig verstanden habe, aber ich habe verschiedene Zeiten und wait Funktionen gleichzeitig gebraucht, und habe eine einfache Lösung bei Butterfly Code gefunden und zwar wird als Basis der Timer 0 verwendet, der alle 10 ms überläuft.


#include "timer0.h"
#include <avr/io.h>
#include <avr/interrupt.h>

static uint8_t CountDownTimer[COUNTDOWNTIMERZAHL];

void Timer0Init(void) {
uint8_t a;
for (a=0;a<COUNTDOWNTIMERZAHL;a++)
CountDownTimer[a] = 255;
TCNT0 = 256-156; /*Ergibt Timing von 10 mS*/
TCCR0 = (1<<CS02)|(1<<CS00); /*Prescaller 1024*/
TIMSK |=(1<<TOIE0);
}

ISR (TIMER0_OVF_vect) {
TCNT0 = 256-156;
uint8_t a;
for (a=0;a<COUNTDOWNTIMERZAHL;a++) {
if (CountDownTimer[a] != 255 && CountDownTimer[a] != 0)
CountDownTimer[a]--;
}
}

uint8_t AllocateCountdownTimer(void) {
uint8_t a;
for (a=0;a<COUNTDOWNTIMERZAHL;a++) {
if(CountDownTimer[a]==255) {
CountDownTimer[a] = 0;
return a+1;
}
}
return 0;
}

void SetCountdownTimer(uint8_t timer, uint8_t value){
cli();
CountDownTimer[timer-1] = value;
sei();
}
uint8_t GetCountdownTimer(uint8_t timer){
uint8_t value;
cli();
value = CountDownTimer[timer-1];
sei();
return value;
}

void ReleaseCountdownTimer(uint8_t timer) {
cli();
CountDownTimer[timer-1] = 255;
sei();
}


und hier die passende Header Datei


#ifndef __TIMER0_H__
#define __TIMER0_H__

#include <avr/io.h>

#define COUNTDOWNTIMERZAHL 5

void Timer0Init(void);
uint8_t AllocateCountdownTimer(void);
uint8_t GetCountdownTimer(uint8_t timer);
void SetCountdownTimer(uint8_t timer, uint8_t value);
void ReleaseCountdownTimer(uint8_t timer);

#endif /*__TIMER0_H__*/


Eine kurze Erklärung:
Timer0Init() setzt den Timer in Gang und macht Platz für maximal COUNTDOWNTIMERZAHL Timer.

AllocateCountdownTimer() reserviert dann einen Timer und wird etwa so aufgerufen



uint8_t my_timer = AllocateCountdownTimer();


mit SetCountdownTimer(uint8_t timer, uint8_t value) kann man dann einen Timer mit einem Wert belegen.
Will ich z.B. einen Timer, der 200ms läuft macht man es so


SetCountdownTimer(my_timer,20); /*20*10mS ergibt 200 mS*/


man kann jetzt hin und wieder im Programm testen, ob der Timer schon abgelaufen ist




if (GetCountdownTimer(my_timer)) {
/*Tue was, die Zeit ist um*/
}


mit


ReleaseCountdownTimer(my_timer);


wird der Timer wieder gelöscht.

Gruß Sebastian

oberallgeier
15.07.2008, 17:30
Hei beginner 1101,


... Thema Timer und Warteschleifen ... z. B. Tastendruck o.ä. und ab jetzt will ich eine gewisse Zeitspanne messen. Wie geht dass? ...
Es gibt wie immer mehrere Möglichkeiten. Ich weiß nicht welchen Controller Du verwendest, ich hab hier mal EINE Möglichkeit für ´nen mega168 (war grad zur Hand), so wie sie mir grad einfällt:

Ich schreib mir zwei Routinen. Eine Initialisierung des Timers (Interrupt bei Compare Match A - es wird KEIN Pin geschaltet). Dazu eine ISR (Interrupt Service Routine) - die mir einen Wert, hier genannt Izeit_1 (uint16 - geht also bis ungefähr 65000) hochzählt von 0 bis 60 000. Bei 60000 wird Izeit_1 wieder auf 0 gesetzt, damit ist kein Überlauf möglich. Die Routinen sind hier:


/* ================================================== ============================ */
/* === Initialisierung fuer Timer2 mega168 ===================================== */
void TC2TMR_init(void) // Init Tmr/Cntr 2, 8-Bit auf 20 kHz = 50 µs
{
TCCR2A |= (1<<WGM21); // Timer im CTC-Mode, Top=OCR2A doc S 157
TCCR2B |= (1<<CS21); // Prescaler 1/8 / Clock <- CPU doc S 158
OCR2A = 125; // Preset 125 für 50µs bei 20Mhz
TIMSK2 |= (1<<OCIE2A); // Tmr/Cntr2 CompareA interrupt enabled
}
/* ================================================== ============================ */


/* ================================================== ============================ */
/* === Nicht unterbrechbare ISR für timer2 ===================================== */
/* Routine zählt hoch im Takt 20 kHz = 50 µs. */
ISR(TIMER2_COMPA_vect) // Vektor 7
{
if (Izeit_1 < 60000) //Timer bis 60 000 - 3 sec Datenerfassung möglich
Izeit_1 ++; // war: alle drei Sekunden wird 60000 erreicht
// und Izeit_1 bleibt in der uint16-Grenze
else
{
Izeit_1 = 0; // ansonsten: Rückstellen auf Null
PORTC ^= (1<<PC5); // Zur Anzeige gLED am PC5/SCL toggeln
}

}
/* ================================================== ============================ */

Soweit meine Vorbereitungen.

Nun kommt (D)ein Tastendruck. Also setze ich im main erstmal cli(); - damit ich gefahrlos die Variable Izeit_1 manipulieren kann - und setze Izeit_1 im main auf 0. Danach natürlich wieder sei();.

Nun kannste jeden beliebigen Wert mit der Genauigkeit meines 50µs-Zeittaktes bis fast 60 000 - das wären 6 Sekunden - abfragen und danach weitergehen im Ablauf.

Dazu würde ich nach dem Tastendruck und nach dem Setzen von Izeit_1 ein Schleife schreiben : cli(); Abfrage ob Izeit_1 > als Wartezeit ist; sei(); und danach fortfahren mit dem Ablauf.

Meine Initialisierungsroutine ist auf Zeiteinheiten von 50 µs abgestimmt (bei m-einen 20 MHz-Quarzen). Du kannstmusstsollst die Initialisierung des Timers auf Deine Bedürfnisse abstimmen. Den Pin auf PC5 toggeln wäre eine Testmöglichkeit - im normalen Leben sollst Du so eine Zeile löschen oder auskommentieren.

Dies ist nur EINE Möglichkeit. Ist die verständlich?

Natürlich ist es auch möglich den Timer für eher kurze Zeiten direkt zu schalten und in der ISR ein Flag zu setzen, das im Main abgefragt wird. Wie gesagt - es führen viele Code-Wege nach Rom.

Viel Erfolg

beginner1101
15.07.2008, 20:04
Hallo an alle,

vielen vielen Dank schon mal für die vielen Infos. Ich werd mir alles in Ruhe durchlesen. Ich meld mich dann wieder ;-).

THX und lG Anna

beginner1101
16.07.2008, 12:57
Hallo,

danke nochmals an alle.

@Joe:
hab mir mal deinen Code angeschaut. Wie kommst du auf deinen OCR2A Wert von 125? Laut Datenblatt ist die Formel doch (OCR2A=(fCLK/(2*N*fOCR))-1= 61.5 (bei deinen gewählten Werten).

@sebastian

Ich hab mal deinen Code verwendet. Hab die Timer_Init auf meinen Controller (AT90CAN) angepasst. Den Rest hab ich gelassen. Ich hab noch ein main-Programm eingefügt. Ich will zur Probe einfach mal eine LED nach einer gewissen Zeit schalten. Es funktioniert nicht. Ich hab den main-Code mal angehängt

int main(void)
{
DDRA = 0xff;
PORTA = 0xff;
uint8_t my_timer = AllocateCountdownTimer();
while(1)
{
SetCountdownTimer(my_timer,200); /*20*10mS ergibt 2000 mS*/
if (GetCountdownTimer(my_timer))
{
PORTA = 0x00;
}
ReleaseCountdownTimer(my_timer);
}
}

Im Prinzip ist der Code von der Funktion her genau dass was ich brauche ;-)

Bis dann lG Anna

oberallgeier
16.07.2008, 15:48
Hei, Anna, beginner1101,


Hallo,

danke nochmals an alle...Gern geschehen.


@Joe:
hab mir mal deinen Code angeschaut. Wie kommst du auf deinen OCR2A Wert von 125? Laut Datenblatt ist die Formel doch (OCR2A=(fCLK/(2*N*fOCR))-1= 61.5 (bei deinen gewählten Werten).Gratuliere - endlich mal jemand der nicht nur Fragen stellt, sondern auch Doc´s liest und nachvollzieht. Leider erschließt sich die Formel weder meinen (mehreren) mega168ern noch mir (im Klartext - die ist nach meiner Ansicht und offenbar auch nach Ansicht meiner ATMEL-mega168er einfach falsch). Wieso? Erstens - und das ist der wichtigste Grund - die Zielfrequenz wird mit dem Ergebnis dieser Formel nicht erreicht. Der zweite Grund - der Text des doc´s beschreibt einen anderen mathematischen Zusammenhang.


17.7.2 Clear Timer on Compare Match (CTC) Mode
In Clear Timer on Compare or CTC mode (WGM22:0 = 2), the OCR2A Register is used to manipulate the counter resolution. Ok, das kennen wir und das können wir nachvollziehen. Keine Probleme. Mein WGM22:0 = 2 - (weil WGM21 = 1).

Weiter im Text:

In CTC mode the counter is cleared to zero when the counter value (TCNT2) matches the OCR2A.Also jedes Mal, wenn mein Timer auf meinen OCR2A stößt, wird er genullt. Clear Timer on Compare A. Der Timer wird aufwärts gezählt entsprechend meinem Vorteiler. Steht auch irgendwo. Als ich mit dem Lesen so weit war (irgendwann mit tiny13 oder so) ,

.........................http://oberallgeier.ob.funpic.de/CTC.jpg

... hatte ich mir ein Excelsheet gemacht - da ich faul bin, besonders rechenfaul. Daher hatte ich nie (tut mir leid) diese Formel angesehen. Nun rechne ich diese Geschichte mal nach der Methode Milchmädchen (bitte um Nachsicht):

20 MHz / 8 (prescaler) = 2,5 MHz und da der Timer von unten nach oben zählt, erreicht er die "125" :
2,5 MHz / 125 (preset) = 20 kHz - voilà

. . . . und diesen Wert glauben auch meine mega168er :). Ok?

izaseba
16.07.2008, 16:25
Hallo Anna,

Drei Sachen,

Am Anfang des Programms mußt Du Timer0Init(); aufrufen.
Du mußt die Interrupts mit sei();erlauben


if (GetCountdownTimer(my_timer))
{
PORTA = 0x00;
}

Wenn Du den Timer mit 200 belädst, zählt der runter bis Null
Außerdem rufst Du die Set Funktion in der Endlosschleife immer wieder auf
So wäre das besser:


int main(void)
{
DDRA = 0xff;
PORTA = 0xff;
Timer0Init();
uint8_t my_timer = AllocateCountdownTimer();
SetCountdownTimer(my_timer,200); /*20*10mS ergibt 2000 mS*/
while(1)
{

if (!GetCountdownTimer(my_timer))
{
PORTA = 0x00;
}
ReleaseCountdownTimer(my_timer);
}
}


Ich hoffe das klappt so ;-)

Gruß Sebastian

beginner1101
03.01.2009, 14:34
Hallo,

nach dem ich nach langem mal wieder Zeit habe mich mit Mikrocontrollern zu beschäftigen, habe ich mich mal wieder um die Timer gekümmert.
Ich hab versucht den Vorschlag von "oberallgaier" zu realisieren. Vom Prinzip her habe ich es verstanden ich bekomm aber immer folgende Fehler meldung:


../Timerfunktion.c:26: error: 'Izeit_1' undeclared (first use in this function)
../Timerfunktion.c:26: error: (Each undeclared identifier is reported only once
../Timerfunktion.c:26: error: for each function it appears in.)
../Timerfunktion.c: In function 'main':
../Timerfunktion.c:52: error: 'Izeit' undeclared (first use in this function)
make: *** [Timerfunktion.o] Error 1
Build failed with 4 errors and 0 warnings...


In meiner main-Routine declariere ich die variable Izeit_1. Warum kennt er dann die Variable nicht in der ISR. Ich rufe die ISR doch erst später, nach der Deklaraqtion auf......


#include <stdlib.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <util/delay.h>


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

/* ================================================== ============================ */
void Timer0_init(void)
{
TCCR0 |= (1<<WGM01) | (1<<CS01);
OCR0 = 125;
TIMSK |= (1<<OCIE0);
}
/* ================================================== ============================ */


/* ================================================== ============================ */
/* === Nicht unterbrechbare ISR für timer2 ===================================== */

ISR(TIMER0_COMP_vect) // Vektor 7
{
if (Izeit_1 <= 60000) //Timer bis 60 000 - 3 sec Datenerfassung möglich
Izeit_1 ++; // war: alle drei Sekunden wird 60000 erreicht
// und Izeit_1 bleibt in der uint16-Grenze
else
{
Izeit_1 = 0; // ansonsten: Rückstellen auf Null
PORTC ^= (1<<PC5); // Zur Anzeige gLED am PC5/SCL toggeln
}

}
/* ================================================== ============================ */

int main(void)
{
uint16 Izeit_1=0;
Timer0_init();
DDRC |= 0xff;
PORTC=0x00;
while(1)
{
cli();
Izeit_1=0;
sei();
if (Izeit>5000)
{
PORTC ^= (1<<PC1);
}
cli();
}
}

Wäre super wenn mir jemand helfen könnte. :-)

Bis dann lG Anna

McJenso
03.01.2009, 14:57
Hallo,

schau dir bitte einmal folgenden Link zur Gültigkeit von Variablen an Link (http://www.hs-augsburg.de/~sandman/c_von_a_bis_z/c_011_005.htm#RxxobKap0110050400276C1F04618C)
Sowohl 11.6, 11.7 und wenn du schon dabei bist passt 11.8 zum Thema.

Du hast Izeit_1 lokal definiert. Es muss aber global definiert sein, um in allen Funktionen gültig zu sein. Für die Mikrocontroller Welt ist dann noch in deinem Fall das Schlüsselwort volatile wichtig. Der Compiler kann aus dem Code nicht Feststellen, dass die ISR ja jederzeit aufgerufen werden kann. Daher kann es durch Optimierungen zu Fehlern kommen. Volatile sagt einfach aus, dass die Variable zur Verwendung immer aus dem Speicher geladen werden muss und nicht in einem Register bevorratet werden darf.
Wenn du es genauer wissen möchtest, im Wissenbereich gibt es einen Artikel zu Interrupts und deren Fallstricke.


Gruß

Jens

beginner1101
03.01.2009, 16:10
Hallo Jens,

danke für deine Info. Hab die Bariable jetzt global deklariert.

Es kommen zwar keine Fehlermeldungen mehr, aber das Programm funktioniert trotzdem nicht :-(

Gruß Anna

oberallgeier
03.01.2009, 16:35
Hallo Anna,

könntest Du mal bitte Deinen Code posten? Dazu natürlich Controllertyp, Quarzfrequenz, halt das ganze Drumrum. Wenns geht weniger als 100 Seiten (ich bin total lese+sonst-faul und verliere schnell die Übersicht) - aber vielleicht können wir zusammen was rausfinden.

McJenso
03.01.2009, 16:42
Hallo,

setzt du Izeit_1 noch in der while auf 0? Das gehört wohl in die main aber nicht in die while. Sonst poste bitte noch einmal den aktuellen Code.

Gruß

Jens

oberallgeier
03.01.2009, 17:00
... total lese+sonst-faul und verliere schnell die Übersicht ...Schlimm schlimm, ich hatte es ja gesagt. Und nun - hab Deinen Code nicht beachtet, entschuldige. Sind ja auch nicht mal 100 Seiten.

Jens hat ja schon dieses "Iz... = 0" im main angemerkt. Warum machst Du das?

PS: Für so Chaotenleser wie mich sieht der code viel besser/lesbarer aus (wenn ich den mal lese), wenn Du ihn mit gestuften Einrückungen versiehst.

beginner1101
03.01.2009, 17:08
Hallo ihr beiden,

also ich hab noch ein bißchen was geändert... (wie Izeit_1 nicht in der while schleife auf 0 setzen ;-) ](*,) ) Ich habe auch noch ne else schleife dazugefügt.
Das komische ist er geht anscheinend nur in die Else-Schleife, da die LED3 (PC2) immer wieder toggelt. Also funktioniert es irgendwie schon aber nicht wirklich befriedigend :-( Die Bedingung in der IF schleife führt er nicht aus....

Rahmenbedingungen: Atmega16 16 MHz
am PortC sind LEDs angeschlossen


#include <stdlib.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <util/delay.h>


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

uint16_t Izeit_1=0;

void Timer0_init(void) // Init Tmr/Cntr 0, 8-Bit auf 20 kHz = 50 µs
{
TCCR0 |= (1<<WGM01) | (1<<CS01); // Timer im CTC-Mode, Top=OCR2A Prescaler 1/8 / Clock <- CPU
OCR0 = 49; // Preset 48 für 50µs bei 16Mhz
TIMSK |= (1<<OCIE0); // Tmr/Cntr CompareA interrupt enabled
}

/* Routine zählt hoch im Takt 20 kHz = 50 µs. */
ISR(TIMER0_COMP_vect) // Vektor 7
{
if (Izeit_1 <= 60000) //Timer bis 60 000 - 3 sec Datenerfassung möglich
Izeit_1 ++; // war: alle drei Sekunden wird 60000 erreicht
// und Izeit_1 bleibt in der uint16-Grenze
else
{
Izeit_1 = 0; // ansonsten: Rückstellen auf Null
PORTC ^= (1<<PC5); // Zur Anzeige gLED am PC5/SCL toggeln
}

}



int main(void)
{
Izeit_1=0;
Timer0_init();
DDRC |= 0xff;
PORTC=0x00;

while(1)
{
cli();
sei();
if (Izeit_1>2)
{
PORTC ^= (1<<PC0);
}
else
{
PORTC ^= (1<<PC2);
}
cli();
}
}

Danke schon mal im vorraus für die Mühe........

Gruß Anna[/code]

oberallgeier
03.01.2009, 17:26
Hi, Anna,

möglicherweise geht es so, ich habe das aber (noch) nicht getestet - muss jetzt essen gehen.


#include <stdlib.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <util/delay.h>


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

/* ================================================== ============================ */
void Timer0_init(void)
{
TCCR0 |= (1<<WGM01) | (1<<CS01);
OCR0 = 124;
TIMSK |= (1<<OCIE0);
}
/* ================================================== ============================ */


/* ================================================== ============================ */
/* === Nicht unterbrechbare ISR für timer2 ===================================== */

ISR(TIMER0_COMP_vect) // Vektor 7
{
if (Izeit_1 <= 60000) //Timer bis 60 000 - 3 sec Datenerfassung möglich
Izeit_1 ++; // war: alle drei Sekunden wird 60000 erreicht
// und Izeit_1 bleibt in der uint16-Grenze
else
{
Izeit_1 = 0; // ansonsten: Rückstellen auf Null
// PORTC ^= (1<<PC5); // Zur Anzeige gLED am PC5/SCL toggeln
// Hallo Anna: das Toggeln hier würde Deinen Schaltvorgang im main
// stören - daher wurde es "auskommentiert".
}

}
/* ================================================== ============================ */

int main(void)
{
uint16 Izeit_1=0;
Timer0_init();
DDRC |= 0xff;
PORTC=0x00;




//####### Grundlegende Initialisierungen der Hardware, Portdefinition -------------
//Pins/Ports als Ein- (0) oder Ausgänge (1) konfigurieren, Pull Ups (1) aktivieren

DDRC = 0b00000001; // PC0 .. 6, (kein PC7 bei m168), NUR Ausgang PC1 aktiv
PORTC = 0b00000000; // Anmerkung: die binäre Codierung der Ports hat den
// Vorteil, dass man/ich gleich sehe, "was los ist".
// So kann ich es mir eben besser vorstellen als in hex.





cli();
Izeit_1=0;
sei();

while(1)
{
if (Izeit>5000)
{
PORTC ^= (1<<PC1);
}
}
}

Wenn Du das in der Zwischenzeit testen kannst wär schön, ansonsten hol ich nachher meine RNControl, dafür habe ich auch einen m16. Es sei denn, wir können uns vorerst mit Tests auf (m)einem m168/20MHz begnügen.

Viel Glück

beginner1101
03.01.2009, 17:42
Hallo Oberallgaier,

danke für den Code. Ich habe ihn getestet. Er funktioniert bei mir leider nicht.
Ich habe Izeit_1 ausserhalb der main routine deklariert und in der while-Schleife Izeit auf Izeit_1 geändert. Es compiliert zwar ohne Fehler, aber es ist nur dauerhaft LED1 an. Sonst passiert nichts.......

Ich muß jetzt leider auch essen gehen. Weiß deshalb nicht ob ich heute noch weiter probieren kann. Aber morgen bin ich wieder online ;-)......

Bis dann Gruß Anna

McJenso
03.01.2009, 18:41
Hallo,

es fehlen bei euch beiden noch die geschweiften Klammern bei



if (Izeit_1 <= 60000) {<- fehlt
Izeit_1 ++; // war: alle drei Sekunden wird 60000 erreicht
// und Izeit_1 bleibt in der uint16-Grenze
fehlt -> } else

und benutzt bitte als globale Definition

volatile uint16 Izeit_1;

@beginner1101 falls das noch nicht zum gewünschten Ergebnis führt, beschreibe vielleicht noch einmal kurz, was du erreichen möchtest. Sorry das steht bestimmt irgendwo, aber ich finde da jetzt nicht durch.

Gruß

Jens

oberallgeier
03.01.2009, 18:50
Hi Anna,

tut mir leid - nun artet das bei mir in experimenteller Softwareentwicklung aus (kann meinen m16 nicht finden *grrrrrrrr* - und der m168 hat andere Registernamen, dann hätten wir hier noch mehr Konfusion). Daher - nochmal ungetestet, aber ohne Fehler compiliert. Ausserdem hat Jens recht - was wollen wir machen? Ich verstehe das so, es soll in einem bestimmbaren, zeitlichen Abstand einfach die LED auf PC1 getoggelt werden.

Hier der code:
#include <stdlib.h>

#include <avr/interrupt.h>

#define MCU = AVR_ATmega16
// #define F_CPU 20000000 // Quarz 20 Mhz-CPU
#define F_CPU 16000000 // Quarz 16 Mhz-CPU

volatile uint16_t Izeit_1; // Timervariable

// ================================================== ==============================
void Timer0_init(void)
{
TCCR0 |= (1<<WGM01) | (1<<CS01);
OCR0 = 125;
TIMSK |= (1<<OCIE0);
}
// ================================================== ==============================


// ================================================== ==============================
// ================================================== ==============================

ISR(TIMER0_COMP_vect) // Vektor 7
{
if (Izeit_1 <= 60000) //Timer bis 60 000 - 3 sec Datenerfassung möglich
Izeit_1 ++; // war: alle drei Sekunden wird 60000 erreicht
// und Izeit_1 bleibt in der uint16-Grenze
else
{
Izeit_1 = 0; // ansonsten: Rückstellen auf Null
PORTC &= ~(1<<PC1); // Port PC1 ausschalten
// Hallo Anna: der Port wird hier bei Izeit_1 = 0 ausgeschaltet
}

}
// ================================================== ==============================

int main(void)
{
//uint16 Izeit_1 = 0;
Timer0_init();
DDRC |= 0xff;
PORTC=0x00;




//####### Grundlegende Initialisierungen der Hardware, Portdefinition -------------
//Pins/Ports als Ein- (0) oder Ausgänge (1) konfigurieren, Pull Ups (1) aktivieren

DDRC = 0b00000010; // PC0 .. 7, NUR Ausgang PC1 aktiv
PORTC = 0b00000000; // Anmerkung: die binäre Codierung der Ports hat den
// Vorteil, dass man/ich gleich sehe, "was los ist".
// So kann ich es mir eben besser vorstellen als in hex.
//####### So werden Ausgänge geschaltet -------------------------------------------
// PORTC |= (1<<PC1); // Port PC1 einschalten
// PORTC &= ~(1<<PC1); // Port PC1 ausschalten
// PORTC ^= (1<<PC1); // Port PC1 toggeln
// ###>>> BEACHTE: die Pins zählen von 0 bis 7, PC1 ist also der ZWEITE PortPin



cli();
Izeit_1 = 0;
sei();

while(1)
{
if (Izeit_1 == 5000)
{
PORTC |= (1<<PC1); // Port PC1 einschalten
// Hallo Anna: der Port wird hier bei Izeit_1 = 5000 eingeschaltet
}
}
}


... es fehlen bei euch beiden noch die geschweiften Klammern ... Ohhh - das ist - bei einem einzigen Statement nach dem "if" soweit ich weiß ANSI-konform.

Edit 23:20: Mein verlorener mega16 ließ mir keine Ruhe. Und als ich ihn gefunden hatte ist mir auch der Fehler aufgefallen. Nun ist der Code ok - und auf meinem fabrikfrischen mega16 läuft er mit 16MHz-Quark auf der RNControl: die LED auf PC1 blinkt.
###>>> Code korrigiert!
Sorry für die ungenaue Bearbeitung.

McJenso
03.01.2009, 19:29
Hallo,



Ohhh - das ist - bei einem einzigen Statement nach dem "if" soweit ich weiß ANSI-konform.


Ohhh, da hast du recht. Ich ließ mich vom else irritieren.

Gruß

Jens

beginner1101
04.01.2009, 15:03
Hallo mal wieder,

hab gerade den Code getestet. ES FUNKTIONIERT! VIELEN DANK ;-).

Ich muß den Code noch ein bißchen anpassen wegen den Zeiten, aber das bekomm ich hin :-)

Also vielen vielen Dank noch mal.

Bis dann lG Anna