PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : timer problem ms_sleep()



Ceos
24.01.2008, 14:58
in der forumssuche hab cih leider nichts sinnvolles oder funktionierendes gefunden, meine situation ich hab n atmega 16-2 und arbeite mitm avr-studio und wollte ne kleine lichterorgel zur übung, mein probem: ich weis nicht wie ich mit den timern umgehen muss und wie ich ne sinnvolle ms_sleep() funktion implementieren kann Q_Q echt jetzt ich hab zwar kein problem mit c aber die codefetzen die ich aus der asuro-lib habe versteh cih nicht, die sind mir sehr verstrickt ... bitte helft mir doch mal mit nem minimalen code für nen ms_sleep() aus damit ich das kapiere

izaseba
24.01.2008, 17:45
Hallo Ceos,
Ich verstehe nicht ganz recht, was Du machen willst...
Mit Timer arbeiten, oder den Controller eine Weile warten lassen, fang doch einfach mit den normalen delays an z.B. so:



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

#ifndef F_CPU
#define F_CPU 1000000
#endif /*F_CPU*/

void delay(uint16_t zeit) {
while(zeit--)
_delay_ms(1);
}

int main (void) {

DDRB = (1<<PB0);
while(1) {
PORTB |=(1<<PB0);
delay(1000);
PORTB &=~(1<<PB0);
delay(500);
}
return 0;
}

So was ? Es ist natürlich nichts wildes, Du wolltest aber was einfaches ;-)

Gruß Sebastian

P.S. Gehe sicher, daß Optimierung -Os eingeschaltet ist

Ceos
24.01.2008, 18:33
ich wollte was möglichst präzise ... was mich wundert ... die methode _delay_ms(); scheint es bei mir garnet zu geben O_o ? ich fuchs mich nomma rein ... aber eigentlich wollte ich mit den timern 0 bis 3 arbeiten, ich begreife die verwendung der prescaler net Q_Q ! SC00 SC01 SC02 ?!

izaseba
24.01.2008, 19:06
was mich wundert ... die methode _delay_ms();

Weil das keine Methode sondern eine Funktion ist ;-)
Hast Du auch util/delay.h eingebunden ?
Die gibt es sicher und die ist auch genau, na gut wenn es Timer sein muß ...
Was verstehst Du an Prescaller nicht ?
Wenn der Prescaller = 1 ist läuft Dein Timer mit dem µC Takt bei z.B 1MHz
Takt erhöht der Timer seinen Wert jede µS.
Bei Prescaller 8 alle 8 µC Takte -> 8µS
Bei Prescaller 64 alle 64 µC Takte -> 64 µS
usw. usw.

Der Wert des Timers wird im Register TCNT* gespeichert.
Mal schauen...
angenommen wir möchten alle 100 mS irgendwas tun und unser µC läuft mit 1MHz stellen wir den Prescaller auf 1024
damit wird der Timer alle 1,024 mS erhöht...

Ich arbeite im Moment mit einem Tiny2313 und das sieht es so für Timer 0 aus:

TCCR0B = (1<<CS02)|(1<<CS00);
Damit läuft der Timer schon !
Da wir möchten, daß sich alle 100mS was tut müssen wir noch den Timerwert anpassen, weil er sonst bei 0 anfängt also


TCNT0 = 256 -100;

Jetzt steht der Timer auf 156 und in genau 100 Timertakten läuft der über.
Das fangen wir mit einem Interrupt ab ;-)
den müssen wir zuerst freigeben das sieht dann so aus:


TIMSK = (1<<TOIE0);

Jetzt ist der Timer 0 Overflow Interrupt freigegeben, das ist natürlich noch nicht alles, wir müssen Interrupts allgemein zulassen:


sei();


Was noch ?
natürlich die Interrupt Routine, die ausgeführt werden soll, wenn der Timer üerläuft:


ISR (TIMER0_OVF_vect) {
TCNT0 = 256 - 100;
PORTB ^=(1<<PB0);
}
das wars...
ganz wild durcheinander hier nochmal das ganze "Programm"


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

ISR (TIMER0_OVF_vect) {
TCNT0 = 256 - 100;
PORTB ^=(1<<PB0);
}

int main(void) {

DDRB = (1<<PB0);
TCNT0 = 256 -100;
TIMSK = (1<<TOIE0);
TCCR0B = (1<<CS02)|(1<<CS00);
sei();
while(1);
return 0;
}

Es kann sein, daß die Register bei Deinem µC etwas anders heißen, schau einfach ins Dattenblatt.
Ich hoffe, daß es so richtig ist, ich habe mir gerade dieses "Programm" aus den Ärmel geschüttelt ;-)

Gruß Sebastian

Ceos
24.01.2008, 19:26
das iss auf jeden fall mal hilfreich, vielen dank .... aber trotzdem versteh ich die kombination von SC00 SC01 SC02 nich so ganz ... welche kombination ergibt welchen prescaler ... zumal der Atmega 16-2 scheinbar nur bis 256 geht -_- ich wollte halt nen millisekunden genauen timer (u_long) damit ich präzise verzögerungen machen kann ... gut ich schau mir das nochmal an mit dem tcnt aber das mit dem prescaler musst du mir bitte erklären >_<

izaseba
24.01.2008, 20:12
aber trotzdem versteh ich die kombination von SC00 SC01 SC02 nich so ganz ... welche kombination ergibt welchen prescaler ... zumal der Atmega 16-2 scheinbar nur bis 256 geht -_- ich wollte halt nen millisekunden genauen timer (u_long) damit ich präzise verzögerungen machen kann ... gut ich schau mir das nochmal an mit dem tcnt aber das mit dem prescaler musst du mir bitte erklären >_<





:-k ein Bild sagt mehr als 1000 Worte...
Schau Dir bitte die zwei Ausschnitte aus dem Dattenblatt von Tiny2313 an, die ich im Anhang gepostet habe...
Im Ersten Bild siehst Du welche Kombinationen von CS* Bits was ergeben
Bei jedem Timer heißen sie CS irgendwas danach folgt die Timernummer also hier CS0* was auf Timer 0 schliessen läßt, Timer 1 hätte dann irgendwas mit CS1 Timer 2 CS2 usw und danach folgt die Bitnummer 0-2
Im zweitem Bild Siehst Du wie der dazugehörige Timer 0 Control Register aufgebaut ist und findest auch die 3 Prescallerbits wieder ;-)

mit
TCCR0B = (1<<CS00);
stellst Du z.B. Prescaller 1 ein
mit
TCCR0B = (1<<CS01);
Prescaller 8 usw.

Jetzt klarer ?

Gruß Sebastian

Ceos
24.01.2008, 20:59
bild2 machts deutlich ... konnte mir aus dem datenblattwirrwar (bei mir waren 4 bits angegeben obwohl es nur 3 sind) nur keinen reim drauf machen

du bist mein helfer in der not ... jetzt muss ich nur noch rausfinden wieso der timer scheinbar langsamer tickt als die reale zeit (wegen 1024 ???) ok muss ich halt mal bissl rechnen

izaseba
24.01.2008, 21:26
jetzt muss ich nur noch rausfinden wieso der timer scheinbar langsamer tickt als die reale zeit (wegen 1024 ???) ok muss ich halt mal bissl rechnen

Scheinbar ? Warum scheinbar ?
Der Timer tickt in Abhängichkeit von µC Takt, warum der Prescaller so 'krumm' ist liegt daran, daß µC die 2-er Potenzen liebt ;-)
Um genaue Zeit hinzubekommen braucht man dann halt 'krumme' Quarze damit sich das wieder ausgleicht...

Sag mir einfach, was Du vorhast, ind ich seh, ob ich Dir helfen kann, weil für 'normale' Lichtblinkereien brauch mal keine µS Genauigkeit ...

Gruß Sebastian

Ceos
24.01.2008, 22:06
naja halbmilliskekundengenau sollte es schon werden (PWM in und out) aber ich bin sehr zuversichtlich das ich das in die reihe bekomme ... desweiteren wollt ich mir zu übungszwecken ne kleine lichteruhr basteln ... so mit n bissl gemuxe und so ... nur darf die natürlich nicht so höllisch driften wie sie es jetzt noch tut ... ausserdem hat der atmega 16-2 ne interessante schnittstelle für externen speicher mit nem bussystem was ich mir noch anschauen wollte .. leider hab ichh keine AD wandler an dem chip, muss ich mir halt noch paar andere organisieren ...

Ceos
29.01.2008, 13:03
ich glaub ich habs jetzt ... aber es driftet noch immer .. diesmal ist der counter ein klein wenig schneller als die echte zeit, kann aber eventuell am internen schwinger von dem Atmega liegen oder was meint ihr ?


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

volatile unsigned long tenth_ms_count;

SIGNAL(SIG_OUTPUT_COMPARE0)
{
tenth_ms_count++;
}

void init_timer0(void)
{
TCCR0 = 0;
TIFR |= BV(OCIE0);
TIMSK |= BV(OCIE0); /* enable output compare interrupt */
TCCR0 = BV(WGM01)|BV(CS01); /* CTC, prescale = 8 */
TCNT0 = 0;
OCR0 = 100;
sei();
}

void tenth_ms_sleep(unsigned long tenth_ms)
{
TCNT0 = 0;
tenth_ms_count = 0;

while (tenth_ms_count < tenth_ms)
;
}

int main(void)
{
init_timer0();
...
}


EDIT: Ich hab mir anfangs einen beispiel-code ausm Forum gesucht ihn aber net wirklich begriffen .... jetzt hab ich mir ne halbe stunde lang das datenblatt durchgelesen (mehrmals) und so langsam wurde das etwas kryptische englisch doch durchsichtig

kann mir eventuell noch jemand erklären wie cih mit den 2 A/B-Registern von den 16bit Timern umzugehen habe ? wieso haben die 2 Kontrollregister ???? muss ich die einfach beide identisch programmieren und dann die einstellungen für den 8bit timer verwenden ? weil mit o.g. code kann cih maximal 5,6s messen ... obwohl das theoretisch völlig ausreicht :p

EDIT: andere frage, kann man den µC während der sleep anweisung nicht irgendwie ein wenig stromsparender gestalten ? wenn ja, welche funktionen sollte ich abschalten und wie kann ich ihn aus diesem zustand effektiv wieder herausbringen ??? also ich dachte hier die programmausführung in echt zu blockieren und dann per interrupt wieder loszulassen.

also statt den vergleich in der while-schleife den vergleich im interrupt auszuführen und den prozessor dann wieder aufzuwecken ?! oder geht bei der operation zu viel zeit verloren ?

EDIT: Meine Idee wäre es den µC in den Idle Mode zu versetzen und in jedem COMPARE_OUTPUT0 ISR einen timerwert mit dem zielwert zu vergleichen und den µC dann "manuell" aus dem Sleepmode zu kicken ... leider hab ich noch nicht ganz verstanden WIE ich das machen muss ?! also das aufwecken