Forum: Mikrocontroller und Digitale Elektronik Zeitschleife Feintunning


von Schnurzelpurzel (Gast)


Lesenswert?

Wenn ich ein Feintunning für eine Zeitverzögerungsschleife brauche, also 
die Verzögerungszeit in 1/F_CPU Inkrementen genau einstellbar sein soll, 
hätte ich das in 8051-Assembler etwa so geschrieben:
1
   ANL   A,#00000111b   ;ACC = ACC modulo 8
2
   MOV   DPTR,#My_Jump_Tab
3
   JMP   @A + DPTR
4
My_Jump_Tab:
5
   NOP   ;0
6
   NOP   ;1
7
   NOP   ;2
8
   NOP   ;3
9
   NOP   ;4
10
   NOP   ;5
11
   NOP   ;6
12
   RET   ;7
Wie würde ich das in C für einen AVR programmieren?

von Uwe .. (uwegw)


Lesenswert?

In C würdest du die fertigen Delay-Funktionen aus der avr-libc nehmen.

von Christopher G. (cbg)


Lesenswert?

Wenn dus genau haben willst, dann machs mit einem Timer und schick den 
µC in einen Sleep Modus solange nichts zu tun ist. Alles andere 
vergeudet nur Strom. Im AVR-GCC-Tutorial sollte alles stehen was du 
brauchst

von MarioT (Gast)


Angehängte Dateien:

Lesenswert?

>Wie würde ich das in C für einen AVR programmieren?
Hab ich leider keine Ahnung.
ASM sehe Dir das mal an.

von Schnurzelpurzel (Gast)


Lesenswert?

Uwe schrieb:
>In C würdest du die fertigen Delay-Funktionen aus der avr-libc nehmen.

Im Im AVR-GCC-Tutorial steht:

>_delay_ms() kann mit einem Argument bis 6553,5 ms (= 6,5535 Sekunden) >benutzt 
werden. Wird die früher gültige Grenze von 262,14 ms/F_CPU (in MHz) 
>überschritten, so arbeitet _delay_ms() einfach etwas ungenauer und zählt >nur 
noch mit einer Auflösung von 1/10 ms. Eine Verzögerung von 1000,10 ms >ließe sich 
nicht mehr von einer von 1000,19 ms unterscheiden. Ein Verlust, >der sich *im 
Allgemeinen* verschmerzen lässt.

Ein Verlust der im Speziellen sich nicht verschmerzen lässt.

Christopher G. (cbg) schrieb:
>Wenn dus genau haben willst, dann machs mit einem Timer

Der leider nur ein 8-Bit-Typ ist...

MarioT (Gast) schrieb:
    * AVRdelayloop3.zip (267 KB, 5 Downloads)
>>Wie würde ich das in C für einen AVR programmieren?
>Hab ich leider keine Ahnung.
>ASM sehe Dir das mal an.

Die gewünschte Verzögerung ist erst zur Laufzeit bekannt.

von fnbfxn (Gast)


Lesenswert?

>Ein Verlust der im Speziellen sich nicht verschmerzen lässt.

Dann lass mal die speziellen Anforderugen hoeren.

Gast

von MarioT (Gast)


Lesenswert?

>Die gewünschte Verzögerung ist erst zur Laufzeit bekannt.
Man müßte etwas genauer wissen was Du vorhast. Was es für Möglichkeiten 
gibt. Wo kommt die Entscheidung her wie lange Verzögert werden muß. Das 
dürfte doch kein Problem sein die Register dementsprechend zu 
setzen(oder so ähnlich). Wie lang sollen die Verzögerungen sein 
(min-max).

von Rainer U. (r-u)


Lesenswert?

Kann man denn in C keinen Assembler-Code (der so funktioniert wie oben) 
einbinden..?

von Peter (Gast)


Lesenswert?

Schnurzelpurzel schrieb:
> Der leider nur ein 8-Bit-Typ ist...

was hindert dich daran bei jeden überlauf eine Variable hochzuzählen und 
schon kannst du auch bis 2^64 zählen.

von Rainer U. (r-u)


Lesenswert?

das "variable hochzählen" dauert ggf. viel zu lange...?

von Heiko (Gast)


Lesenswert?

Rainer Unsinn schrieb:
> Kann man denn in C keinen Assembler-Code (der so funktioniert wie oben)
> einbinden..?

Klar kann man. Such mal weiter unter dem Stichwort "Inline assembler" - 
ich hab das noch nicht gemacht, kann dir daher nicht weiterhelfen damit.

Rainer Unsinn schrieb:
> das "variable hochzählen" dauert ggf. viel zu lange...?

Wenn man das im Overflow-IRQ macht, zählt der Timer doch solange weiter?

MfG, Heiko

von Link zu (Gast)


Lesenswert?

Heiko schrieb:
> Rainer Unsinn schrieb:
>> Kann man denn in C keinen Assembler-Code (der so funktioniert wie oben)
>> einbinden..?
>
> Klar kann man. Such mal weiter unter dem Stichwort "Inline assembler" -
> ich hab das noch nicht gemacht, kann dir daher nicht weiterhelfen damit.
Oder  Schnurzelpurzel schaut endlich mal ins 
AVR-GCC-Tutorial: Assembler und Inline-Assembler.

von csalkh (Gast)


Lesenswert?

Schnurzelpurzel hat wohl noch zu tun um die speziellen Anforderungen zu 
formulieren. (Was ja ueblicherweise mindestens schon 50% der Loesung 
ist.)

Gast

von Schnurzelpurzel (Gast)


Angehängte Dateien:

Lesenswert?

Also ich habe an meinem (geplanten) Ticky-Tool-Gerät zwei solche 
Switch_Boards.
Es soll eine Rechteckschwingung erzeugt werden.
Eingestellt wird die High-Zeit und die Low-Zeit.
Sekunden 000..999, ms 000...999, us 000...999
ns 000...900 (hier nur in 100ns Schrittweite)
Also insgesamt 10-Stellen => 10MHz Frequenznormal an XTAL-In

CPU ist ATtiny25, die Kommunikation mit den Switchboards ist SPI.
da die interruptlatenzzeit schwankt, ist nix mit Interrupt.
Da es Zeit braucht, die Switchboards auszulesen ist die kleinste 
Einstellbare Zeit 1ms oder eher größer!
Wichtig ist mir nur, das die Schrittweite 100ns ist.

Leider sind meine C-Kenntnisse zu gering um das 8051-Assembler-Beispiel 
in C zu übersetzen.
1
   ANL   A,#00000111b   ;ACC = ACC modulo 8
2
   MOV   DPTR,#My_Jump_Tab
3
   JMP   @A + DPTR
4
My_Jump_Tab:
5
   NOP   ;0
6
   NOP   ;1
7
   NOP   ;2
8
   NOP   ;3
9
   NOP   ;4
10
   NOP   ;5
11
   NOP   ;6
12
   RET   ;7
Dieses 8051-Programmbeispiel macht eine Verzögerung in 1/XTAL 
Schrittweite.

von Karl H. (kbuchegg)


Lesenswert?

Schnurzelpurzel schrieb:

> CPU ist ATtiny25, die Kommunikation mit den Switchboards ist SPI.
> da die interruptlatenzzeit schwankt, ist nix mit Interrupt.
> Da es Zeit braucht, die Switchboards auszulesen ist die kleinste
> Einstellbare Zeit 1ms oder eher größer!
> Wichtig ist mir nur, das die Schrittweite 100ns ist.

Und dein Quarz ist tatsächlich temperaturkompensiert und aufs Herz 
genau?

>
> Leider sind meine C-Kenntnisse zu gering um das 8051-Assembler-Beispiel
> in C zu übersetzen.
>
1
>    ANL   A,#00000111b   ;ACC = ACC modulo 8
2
>    MOV   DPTR,#My_Jump_Tab
3
>    JMP   @A + DPTR
4
> My_Jump_Tab:
5
>    NOP   ;0
6
>    NOP   ;1
7
>    NOP   ;2
8
>    NOP   ;3
9
>    NOP   ;4
10
>    NOP   ;5
11
>    NOP   ;6
12
>    RET   ;7
13
>
> Dieses 8051-Programmbeispiel macht eine Verzögerung in 1/XTAL
> Schrittweite.

Schön.
Und wie gehts dann weiter? Eine auf den einzelnen Takt genau Verzögerung 
ist wunderbar aber nur die halbe Miete. Da spielt sich ja auch Code 
davor ab. Da spielt sich Code dahinter ab. All das braucht auch seine 
Zeit. Zeit die je nach Compilereinstellung unterschiedlich sein kann.

Wenn du bei C bleiben willst, ist deine beste Option der Einsatz eines 
Timers, wobei der Timer den Pin umschaltet. Dann bist du auf den 
Taktzyklus genau und das auch noch ziemlich trivial, solange High und 
Low Zeit in etwa in der gleichen Größenordnung sind.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Dieses AVR-Programmbeispiel in  (AVR-GCC) C macht eine Verzögerung in 
1/XTAL Schrittweite:
1
  asm volatile("NOP");

Dieses AVR-Programmbeispiel in (AVR-GCC) C macht eine Verzögerung in 
2/XTAL Schrittweite:
1
  asm volatile("NOP");
2
  asm volatile("NOP");

Dieses AVR-Programmbeispiel mit AVR-LIBC macht eine Verzögerung in 
3/XTAL Schrittweite pro Loop (plus Overhead zum Einrichten eines 
Zählregisters):
http://www.nongnu.org/avr-libc/user-manual/group__util__delay__basic.html
1
  _delay_loop_1(2); // Als Anzahl Loops (hier 2 = 6/XTAL) nur Konstanten!

Statt XTAL wird bei AVR meist F_CPU definiert. Um die gewohnten XTAL zu 
benutzen könntest du benutzen:
1
#define XTAL F_CPU

von Peter D. (peda)


Lesenswert?

Schnurzelpurzel schrieb:
> CPU ist ATtiny25, die Kommunikation mit den Switchboards ist SPI.
> da die interruptlatenzzeit schwankt, ist nix mit Interrupt.

Dann schau einfach mal ins Datenblatt.
Der Timer kann zyklusgenau einen Pin umschalten, die 10ns sind also mit 
Interrupt kein Problem.
Und das Main kann derweil in Ruhe die Schalter abfragen und bei ner 
Änderung die Comparewerte umdefinieren.

Etwas tricky wirds mit der Aufteilung der Compareereignise. Wenn der 
Puls 257 Takte lang sein soll kannst du ihn nicht in 256 + 1 Takte 
zerlegen, da ein Interrupthandler schon etwa 50 Takte Zeit haben sollte.
Also 257 zerlegen in 128 + 129 usw.

Du kannst aber auch nen ATtiny24 nehmen, der hat nen 16Bit Timer.


Peter

von Schnurzelpurzel (Gast)


Lesenswert?

Hier jetzt meine Delay-Routine.
Die Verzögerungszeit ist (53 + unsigned long int Zeit) / F_CPU

Die 53 ist die Anzahl an Taktzyklen die das Programm braucht, wenn 
Zeit=0 ist. Da meine Taktfrequenz im Moment vom ATtiny25 selber kommt, 
habe ich dies noch nicht ganz exakt gemessen!!!
1
//***********************************************
2
// (c) 08.03.2010 by Schnurzelpurzel
3
void Delay(unsigned long int Zeit)
4
{
5
  PINB = (1 << PIN4); //Nur zu Testzwecken an Portleitung klappern!
6
7
  if(Zeit & 0x00000001)
8
  {
9
    asm volatile("NOP");
10
    asm volatile("NOP");1
11
  }
12
  if(Zeit & 0x00000002)
13
  {
14
    asm volatile("NOP");
15
    asm volatile("NOP");1
16
    asm volatile("NOP");2
17
  }
18
  if(Zeit & 0x00000004)
19
  {
20
    asm volatile("NOP");
21
    asm volatile("NOP");1
22
    asm volatile("NOP");2
23
    asm volatile("NOP");3
24
    asm volatile("NOP");4
25
  }
26
  if(Zeit & 0x00000008)
27
  {
28
    asm volatile("NOP");
29
    asm volatile("NOP");1
30
    asm volatile("NOP");2
31
    asm volatile("NOP");3
32
    asm volatile("NOP");4
33
    asm volatile("NOP");5
34
    asm volatile("NOP");6
35
    asm volatile("NOP");7
36
    asm volatile("NOP");8
37
  }
38
39
  Zeit >>= 4;
40
  while(Zeit > 0)
41
  {
42
    asm volatile("NOP");1
43
    asm volatile("NOP");2
44
    asm volatile("NOP");3
45
    asm volatile("NOP");4
46
    asm volatile("NOP");5
47
    asm volatile("NOP");6
48
    Zeit--;
49
  }
50
51
  PINB = (1 << PIN4); //Nur zu Testzwecken an Portleitung klappern!
52
}
53
//***********************************************

Ist das nicht toll?
Meine Mama sagt immer "Schnurzelpurzel, du bist der beste"

Ihr dürft diese Routine gern verwenden, wenn ihr das Copyright drin 
lässt.
Wenn nicht, sag ich das mein Onkel, der ist Jäger und schießt euch mit'm 
Schrotgewehr in Hintern!

von Karl H. (kbuchegg)


Lesenswert?

Schnurzelpurzel schrieb:

> Ihr dürft diese Routine gern verwenden, wenn ihr das Copyright drin
> lässt.

Der Rest googelt nach "Duffs Device"

von Schnurzelpurzel (Gast)


Lesenswert?

Sorry, hab eben die Kommentare falsch gemacht,
hab irgendwie gedacht ich bin in Assembler, muss natürlich so sein:
1
//***********************************************
2
void Delay(unsigned long int Zeit)
3
{
4
  PINB = (1 << PIN4); //Nur zu Testzwecken an Portleitung klappern!
5
6
  if(Zeit & 0x00000001)
7
  {
8
    asm volatile("NOP");
9
    asm volatile("NOP");//1
10
  }
11
  if(Zeit & 0x00000002)
12
  {
13
    asm volatile("NOP");
14
    asm volatile("NOP");//1
15
    asm volatile("NOP");//2
16
  }
17
  if(Zeit & 0x00000004)
18
  {
19
    asm volatile("NOP");
20
    asm volatile("NOP");//1
21
    asm volatile("NOP");//2
22
    asm volatile("NOP");//3
23
    asm volatile("NOP");//4
24
  }
25
  if(Zeit & 0x00000008)
26
  {
27
    asm volatile("NOP");
28
    asm volatile("NOP");//1
29
    asm volatile("NOP");//2
30
    asm volatile("NOP");//3
31
    asm volatile("NOP");//4
32
    asm volatile("NOP");//5
33
    asm volatile("NOP");//6
34
    asm volatile("NOP");//7
35
    asm volatile("NOP");//8
36
  }
37
38
  Zeit >>= 4;
39
  while(Zeit > 0)
40
  {
41
    asm volatile("NOP");//1
42
    asm volatile("NOP");//2
43
    asm volatile("NOP");//3
44
    asm volatile("NOP");//4
45
    asm volatile("NOP");//5
46
    asm volatile("NOP");//6
47
    Zeit--;
48
  }
49
50
  PINB = (1 << PIN4); //Nur zu Testzwecken an Portleitung klappern!
51
}
52
//***********************************************
:-)

von Schnurzelpurzel (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Der Rest googelt nach "Duffs Device"
1
switch(Zeit % 8)
2
{
3
      case 7:  asm volatile("NOP");
4
      case 6:  asm volatile("NOP");
5
      case 5:  asm volatile("NOP");
6
      case 4:  asm volatile("NOP");
7
      case 3:  asm volatile("NOP");
8
      case 2:  asm volatile("NOP");
9
      case 1:  asm volatile("NOP");
10
      case 0:  asm volatile("NOP");
11
}

Habe mir das Hex-File mal mit ReAVR angesehen
(kann ich mir das auch von AVR-Studio aus ansehen???)
1
  ijmp
2
;  -----------  jump on last line
3
L0053:
4
  nop
5
L0054:
6
  nop
7
L0055:
8
  nop
9
L0056:
10
  nop
11
L0057:
12
  nop
13
L0058:
14
  nop
15
L0059:
16
  nop
17
L005A:
18
  nop
19
L005B:
So geht's auch :-)
Der Karl heinz Buchegger is so'n ganz schlauer, der müsste nur mal eher 
damit rausrücken!

von Peter D. (peda)


Lesenswert?

Ja, man kanns natürlich umständlich machen.

Es geht aber auch einfacher.
Ich hatte mal was gemacht, bevor die AVRs Compareregister hatten:

Beitrag "AVR: Delay 7 ... 65542 Zyklen"

Mit der set/cear/toggle on Compare Funtion lasse ich das aber den Timer 
selber machen. Dann kann man nebenbei noch anderes machen, ohne den Puls 
zu stören. Und Assembler ist auch nicht mehr nötig.


Peter

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Aha und Methodenaufrufe und Abfragen dauern auf deinem µC also die 
Taktzahl 0... interessant.

von Peter D. (peda)


Lesenswert?

Warum so umständlich?

Beitrag "AVR: Delay 7 ... 65542 Zyklen"


Peter

von Schnurzelpurzel (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Der Rest googelt nach "Duffs Device"

=>
1
switch(Zeit % 8)
2
{
3
      case 7:  asm volatile("NOP");
4
      case 6:  asm volatile("NOP");
5
      case 5:  asm volatile("NOP");
6
      case 4:  asm volatile("NOP");
7
      case 3:  asm volatile("NOP");
8
      case 2:  asm volatile("NOP");
9
      case 1:  asm volatile("NOP");
10
      case 0:  asm volatile("NOP");
11
}

Habe mir das Hex-File mal mit ReAVR angesehen
(kann ich mir das auch von AVR-Studio aus ansehen???)
1
  ijmp
2
;  -----------  jump on last line
3
L0053:
4
  nop
5
L0054:
6
  nop
7
L0055:
8
  nop
9
L0056:
10
  nop
11
L0057:
12
  nop
13
L0058:
14
  nop
15
L0059:
16
  nop
17
L005A:
18
  nop
19
L005B:
So geht's auch :-)
Der Karl heinz Buchegger is so'n ganz schlauer,
der müsste nur mal eher damit rausrücken!

von Schnurzelpurzel (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Warum so umständlich?
>
> Beitrag "AVR: Delay 7 ... 65542 Zyklen"
>
>
> Peter

Ich wollte ein Routine haben die 1 / F_CPU Auflösung hat und bis zu 2^32 
Zyklen verzögern kann.

Habe jetzt zwei Varianten, dank an Karl heinz Buchegger.

Kann einer der Moderatoren hier bitte ein bischen aufräumen?
Sorry, ist irgendwie schiefgegeangen, habe dreimal den selben Beitrag 
gepostet  :-(

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.