Forum: Mikrocontroller und Digitale Elektronik Verständnis TImer und Main-Loop


von philipp (Gast)


Lesenswert?

hallo,
da mir gestern hier so toll geholfen wurde und ich nach stundenlangem 
hin und her versuchen gemerkt hab, dass ich einfach zu dumm dafür bin, 
stell ich die frage einfach mal hier rein:
Ich benutze den Timer1 vom Atmega16, aber das spielt eigentlich keine 
rolle.
ich hab jetzt die Variable "mss" die jede Millisekunde inkrementiert 
wird (vom Timer0!). So jetzt will ich mit einer Funktion in etwa so:
1
void halte_ms(int16_t millis){
2
3
 if (mss <= millis){
4
   TCCR1A |= ((1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0));
5
 }
6
 else {
7
   TCCR1A |= ((1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0));
8
 }
9
}

den PD5 (OC1A) vom Timer1 toogeln lassen. Und wenn eben die millis 
erreicht sind soll er aufhören. Aber da ich nicht weiß wo mss im Moment 
steht ist das ziemlich dumm. Ich könnt jetzt natürlich ein mss = 0 am 
anfang von der funktion schreiben, aber dass wird mir ja immer wieder 
von der Hauptschleife überschrieben, sprich der Pin toogelt immer.
Ich hab auch schon so was versucht, aber das klappt auch nicht:

Timer0:
1
ISR(TIMER0_COMP_vect)             // 1ms for manual movement
2
{
3
    if (mssHelper == 1){
4
5
        mss++;
6
7
        if (mss > millis2){
8
            mss = 0;
9
        }
10
    }
11
}

und main:
1
void halte_ms(int16_t millis){
2
millis = millis2;
3
mssHelper = 1;
4
    if (mss < millis){
5
       TCCR1A |= ((1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0));
6
    }
7
    else {
8
        TCCR1A &= ~((1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0));
9
    }
10
}

geht halt aber auch nicht. Ich weiß dass es geht, aber ich bin eben nur 
zu blöd dafür. Man muss dass irgendwie mit ner Hilfsvariable mssOld 
machen und die glaub außerhalb erst mal null setzten, aber ich blick das 
nicht und würde das halt gern verstehen.
Vielen Dank im Vorraus.
philipp

von philipp (Gast)


Lesenswert?

und sorry für die rechtschreibfehler, aber wir sind ja keine µC's und 
können den falschen Text richtig interpretieren ;)

von Thomas E. (thomase)


Lesenswert?

Du willst einen Pin für eine bestimmte Zeit toggeln?

Dafür brauchst du keine 2 Timer und x Variablen.
Starte Timer1 und lass ihn im CRC toggeln. In  der ISR zählst du eine 
Variable runter und bei 0 hältst du den Timer an.

Ein Timer, eine Variable.
mfg.

von philipp (Gast)


Lesenswert?

hmm, also das ist jetz nicht so dass was ich meinte. Und ich glaub dass 
ich das auch nicht so machen kann wie du das meinst.
Ich brauch den Timer0 sowieso, weil ich damit den Drehencoder auslese. 
Und da kann ich mir auch gerade noch den millisekunden takt abgreifen.
Ich hab halt am OC1A Pin n speaker dran und mit dem ICR1 vom Timer1 
stell ich die Frequenz ein (ich mach da halt WGM 14).
Ich hab jetzt mal im Datenblatt nach CRC gesucht, aber da findet man 
nicht einen treffer :) Komisch, bei den vielen Abkürzungen. Kannste mal 
sagen was das ausgeschrieben heißt? (Compare irgendwas?)

von Matthias L. (Gast)


Lesenswert?

>ich hab jetzt die Variable "mss" die jede Millisekunde inkrementiert
>wird (vom Timer0!).

Beitrag "Re: Programm bzw. Ablaeufe steuern"

Das was bei mit im Programm TCNT0 ist, kann auch deine Variable mss 
sein. Diese erhäht sich ja alle eine Millisekunde um eins.


>CRC gesucht:

CTC   clear timer on compare

von philipp (Gast)


Lesenswert?

also ich versteh nicht wie mir da eine StateMachine weiterhelfen soll.
Ich hab halt 3 variabeln die das ganze beeinlfussen, den momentanen Takt 
vom Timer1 (mss), dann den Takt von der main-schleife und dann die 
Sekunden, wie lang ich das signal halten will (millis)... und 2 
Zustände, aus und ein... aber ich blick das nicht ganz, hab mir auch das 
hier angeschaut:
http://www.humerboard.at/doku/sb8/uc5.pdf
aber bin nicht wirklich weitergekommen?? jemand noch ne idee?

von Matthias L. (Gast)


Lesenswert?

Sag nochmal ganz exakt, was du wielange tun willst

von philipp (Gast)


Lesenswert?

ich will den OC1A (PD5) eine bestimmte zeit ("millis") schwingen lassen, 
also ich erklär dir das am besten mit dem code:
1
void warte_ms(int16_t millis){
2
int mssOld=0;
3
int mssN = mss;
4
5
    if (mss != mssOld) {
6
        mssOld++;    //hier bin ich gerade dran, also das klappt so noch nicht!!!
7
 
8
        TCCR1A &= ~((1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0)); 
9
    }
10
    else {
11
        TCCR1A |= ((1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0));
12
    }
13
14
}
15
16
void halte_ms(int16_t millis){
17
18
19
    if (mss < millis){
20
       TCCR1A |= ((1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0));
21
    }
22
    else {
23
        TCCR1A &= ~((1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0));
24
    }
25
}
26
27
beep(uint16_t note, uint16_t duration){
28
    ICR1 = note;
29
    halte_ms(duration);
30
    warte_ms(20);
31
}
32
33
void play()
34
{
35
    beep(a, 500);
36
    beep(a, 500);
37
    beep(a, 500);
38
    beep(f, 350);
39
    beep(cH, 150);
40
    beep(a, 500);
41
    beep(f, 350);
42
    beep(cH, 150);
43
    beep(a, 650);
44
45
    warte_ms(150);
46
}

Also wenn ich die halte-fkt hab dann hab ich auch die warte fkt. denk 
ich mir...

von philipp (Gast)


Lesenswert?

achso und die definitionen der töne, was ich auch überprüft hab...
{c]
#define c 261
#define d 294
#define e 329
#define f 349
#define g 391
#define gS 415
#define a 440
#define aS 455
#define b 466
#define cH 523
#define cSH 554
#define dH 587
#define dSH 622
#define eH 659
#define fH 698
#define fSH 740
#define gH 784
#define gSH 830
[/c]

von philipp (Gast)


Lesenswert?

bzw.. umgerechnet, sorry für die falsche formatierung

von Matthias L. (Gast)


Lesenswert?

Du willst also Töne erzeugen?

Das macht man aber nicht so. Zumal deine ms-Warteroutine zu langsam 
sind.

Du brauchst zwei Timer. Einenim CTC Mode. Den lässt Du mit jedem 
CTC-Ereignis den Ausgang toggeln. Das macht die Hardware von allein. Du 
musst nur den Timer laufen lassen und den MAX Wert begrenzen mit OCR.
Damit erzeugt du die Frequenzen die du brauchst. Die Tonfrequenzen musst 
du nur vorher in OCR Werte umrechnen.

Mit dem zweiten Timer erzeugst du die Zeitbasis um die verschiedenen 
Töne umzuschalten. Das wäre ebenfalls als CTC, aber ohne Portoperation 
möglich.

von philipp (Gast)


Lesenswert?

hähh aber das ist doch genau das was ich mache ich hab timer1 für den 
CTC oder was immer. also halt im WGM Modus 14 und das ist auch 
hardwaremäßiges toogeln und hab als Vergleichsregister ICR1. das 
funktioniert wunderbar. und dann hab ich noch den timer0 von dem ich mir 
immer die ms sekunden nehme um die noten eine zeitlang abzuspielen.
das funktioniert schon hab das mit dem WGM 14 und dem tonleiter auch 
gemacht, nur da hab ich halt die noten eine sekunde gehabt und das 
klappte auch nur, wenn ich die noten von nullsekunde jeden ton eine 
sekunde laufen gelassen hab, sprich immer wenn sich ss verändert springt 
es in die nächste note aus dem tonleiter:
hier bekomme ist ss auch aus einem timer
1
uint8_t tonleiter[] = {C4, D4, E4, F4, G4, A4, B4, C5, STOP};
2
3
uint8_t notencnt = 0;
4
uint8_t cntold = 0;
5
6
void playtonleiter(void){
7
8
uint8_t cnt = ss;
9
10
if (cntold != cnt) {
11
12
    ICR1 = tonleiter[notencnt];
13
14
    cntold++;
15
    notencnt++;
16
17
        if (notencnt == 9){
18
            notencnt = 0;
19
        }
20
}
21
22
}

von Thomas E. (thomase)


Lesenswert?

Thomas Eckmann schrieb:
> lass ihn im CRC toggeln
Da kannst du auch lange nach suchen. Das sei mal der Tatsache 
geschuldet, daß R und T auf der Tastatur nebeneinander liegen. Das 
heisst natürlich CTC und nicht CRC. Wenn anderen sowas passiert, nenne 
ich das immer Wurstfingereffekt. Bei mir natürlich nicht.

Du willst also variable Töne mit variabler Länge erzeugen ud danach 
willst du noch 20 ms warten. Warum schreibst du das dann nicht einfach.?
In deinem Ausgangspost war das nun nicht wirklich zu erkennen, eher 
überhaupt nicht.

philipp schrieb:
> enn ich die noten von nullsekunde jeden ton eine
> sekunde laufen gelassen hab,
Was ist denn das Problem den Zähler statt von 0 auf 1000 von 0 auf x 
laufen zu lassen?

mfg.

von philipp (Gast)


Lesenswert?

aber das hab ich doch hier versucht:
philipp schrieb:
Timer0:
ISR(TIMER0_COMP_vect)             // 1ms for manual movement
{
    if (mssHelper == 1){

        mss++;

        if (mss > millis2){
            mss = 0;
        }
    }
}

und main:
void halte_ms(int16_t millis){
millis = millis2;
mssHelper = 1;
    if (mss < millis){
       TCCR1A |= ((1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | 
(1<<COM1B0));
    }
    else {
        TCCR1A &= ~((1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | 
(1<<COM1B0));
    }
}

von philipp (Gast)


Lesenswert?

eigentlich ist alles was ich brauch so ne mine funktion wie, wenn sich 
mss erhöt erhöh x auch aber starte bei null. Also erhöh dich im gleichen 
takt aber fang von null an.

von Thomas E. (thomase)


Lesenswert?

philipp schrieb:
> aber das hab ich doch hier versucht:

Du schreibst deine duration in eine Variable, startest den Timer1 mit 
dem richtigen Piep und lässt die Variable in der Timer0-ISR 
runterzählen. Wenn die auf 0 ist, schaltest du den Piep ab.

Währenddessen kannst du in der main noch die Frage nach dem Leben, dem 
Universum und dem ganzen Rest berechnen. Das Gepiepe machen die Timer 
ganz alleine.

mfg.

von Matthias L. (Gast)


Lesenswert?

Das erste was Du dir angewöhnen musst, ist eine vernünftige Grammatik. 
Das ist ja fast nicht zu kapieren.

Nein. WGM14 ist kein CTC Mode.

Etwa so: (für 16MHz Quartz)
1
//** Töne in us: ****************************************
2
#define TON_C   (1000000UL/261)
3
#define TON_D   (1000000UL/294)
4
...
5
6
//** Töne ***********************************************
7
volatile
8
struct
9
{
10
  uint16_t  u16Ton;
11
  uint16_t  u16Len;
12
}
13
scTon;
14
15
scTon    P_ascSound[] PROGMEM = { (TON_C,120), (TON_D,124), (), (), .. };
16
17
//** Variablen ******************************************
18
uint16_t  u16Tick;
19
uint8_t   u8ActTon;
20
21
//** ISR alle 1ms ***************************************
22
ISR ( OCR0 )
23
{
24
  uint16_t  u16Len = pgm_read_word( &P_ascSound[ u8ActTon ].u16Len );
25
  uint8_t   u8Max  = ( sizeof(P_ascSound)/sizeof(P_ascSound[0])  );
26
  //-- Tondauer abgelaufen? -------
27
  if ( ++u16Tick < u16Len ) return;
28
  //-- TonEnde? neu beginnen ------
29
  if ( ++u8ActTon >= u8Max ) u8ActTon = 0;
30
  //-- nächster Ton----------------
31
  u16Tick = 0;
32
  OCR1A = pgm_read_word( &P_ascSound[ u8ActTon ].u16Ton );
33
}
34
35
36
//** Hauptprogramm***************************************
37
void main ( void )
38
{
39
  //-- OC1A Pin als OUT -----------------------------
40
  DDRD |= (1<<PD5);
41
  //-- Timer0 in CTC Mode, clk/64 => CTC alle 1ms
42
  OCR0   = 250;
43
  TCCR0 |= (1<<WGM01) | (3<<CS00);
44
  TIMSK |= (1<<OCIE0);
45
  //-- Timer1 in CTC Mode , clk/2, toggle on CompMatch
46
  TCCR1A |= (1<<COM1A0);
47
  TCCR1B |= (1<<WGM12)| (2<<CS10);
48
49
  //-------------------------------------------------
50
  sei();
51
  while (1)
52
  {
53
    asm volatile ("nop");
54
  }
55
}

von philipp (Gast)


Lesenswert?

ja, ich weiß. Mein Code sieht immer schrecklich aus, weil ich immer 
tausend mal hin und herversuche. Und mehr versuch (glück) als verstand 
hab.
Hast du den Code jetzt gerade echt in der kurzen zeit geschrieben???
Naja vielen dank für die mühe ich werd die tage mal versuchen den zu 
begreifen, bzw. versuch nochmal n ganz ansatz, das "lied" in nen array 
zu klopfen... aber ich glaub dein zeuch wird wohl n bissel flexibler 
sein.
Noch mal so n paar kurze fragen, dann nerv ich auch nimmer für heut:
- was heißt UL am ende der 1000000, müsste das nicht der quarztakt sein 
bzw müsste es nicht 16000000/prescaler/tonfrquenz sein?
- was macht das: pgm_read_word( &P_ascSound[ u8ActTon ].u16Len )?
- und das: pgm_read_word( &P_ascSound[ u8ActTon ].u16Ton )?
und das ganze wird jetzt gestartet wenn man den timer1 anschaltet?

aber wenn du keine lust mehr hast zu antworten, kann ich das verstehen. 
Ihr habt mir schon genug geholfen und danke für die geduld, ich sag mal 
gut nacht und Vielen Dank bis dahin...
philipp

von Matthias L. (Gast)


Lesenswert?

>Hast du den Code jetzt gerade echt in der kurzen zeit geschrieben???

Ja. Deshalb kann es sein, das es Tippfehler gibt. Aber Du willst ja was 
lernen. Dehalb muss man ja nicht alles vorsagen.


>was heißt UL am ende der 1000000,

Das UL heisst unsigned long. Damit der Compiler weiss, das ist eine 
32bit Zahl.


>müsste das nicht der quarztakt sein bzw müsste es nicht 16000000/prescaler>
>/tonfrquenz sein?

Kommt drauf an, was Du berechnen lassen willst. Ich will ja nur den Ton 
(Angegeben in Hz) in eine Periodendauer (Angegeben im Mikrosekunden) 
umrechnen.

Weil: Der Timer1 wird alle 0,5Mikrosekunden erhöht. Lade ich den MAX 
Wert für die CTC-Funktion mit dem obigen Wert in Mikrosekunden, kommt 
ein CTC-Event alle halbe Zeit raus. Das wird zum Toggeln des Pins 
genutzt. Somit entsteht 0,5 mal diese Zeit ein HI am OC1A und 0,5mal die 
Zeit ein LO.


>was macht das: pgm_read_word

Das findest du mit Hilfe von google selbst raus.


>wird jetzt gestartet wenn man den timer1 anschaltet?

Der startet von allein. Das Programm sollte das Tonarray immer wieder 
abspielen.


Optimierungen am Programm können natürlich noch viele gemacht werden...

von philipp (Gast)


Lesenswert?

hallo nochmal,
also ich hab versucht da mal so wie du es vorgeschlagen hast meinen 
eigenen Datentyp mit diesem struct zumachen:

Matthias Lipinsky schrieb:
1
> struct
2
> {
3
>   uint16_t  u16Ton;
4
>   uint16_t  u16Len;
5
> }
6
> scTon;
und auch mal nur zum test wie hier unter Beispiele:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#progmem_und_pgm_read_xxx
1
einfach mal versucht mit const int an Array[] PROGMEM = {14,21,12};
etwas in den Flash zu speichern aber da kommt die fehlermeldung vom 
compiler:
main.c|25|error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before 
‘Array’
Ne idee was ich da falsch mache?

von philipp (Gast)


Lesenswert?

ah sorry, ich hatte den fehler anArray != an Array. klar sorry, jetzt 
geht das mit dem Beispiel von Tutorial abe res kommt immer die 
fehlermeldung:
in der pgmspache.h
/usr/lib/gcc/avr/4.7.2/../../../avr/include/avr/pgmspace.h|1067|error: 
unknown type name ‘uint_farptr_t’|

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.