www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Zeitschleife Feintunning


Autor: Schnurzelpurzel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
   ANL   A,#00000111b   ;ACC = ACC modulo 8
   MOV   DPTR,#My_Jump_Tab
   JMP   @A + DPTR
My_Jump_Tab:
   NOP   ;0
   NOP   ;1
   NOP   ;2
   NOP   ;3
   NOP   ;4
   NOP   ;5
   NOP   ;6
   RET   ;7
Wie würde ich das in C für einen AVR programmieren?

Autor: Uwe ... (uwegw)
Datum:

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

Autor: Christopher G. (cbg)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: MarioT (Gast)
Datum:
Angehängte Dateien:

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

Autor: Schnurzelpurzel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: fnbfxn (Gast)
Datum:

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

Dann lass mal die speziellen Anforderugen hoeren.

Gast

Autor: MarioT (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Rainer Unsinn (r-u)
Datum:

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

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rainer Unsinn (r-u)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das "variable hochzählen" dauert ggf. viel zu lange...?

Autor: Heiko (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Link zu (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: csalkh (Gast)
Datum:

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

Gast

Autor: Schnurzelpurzel (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.
   ANL   A,#00000111b   ;ACC = ACC modulo 8
   MOV   DPTR,#My_Jump_Tab
   JMP   @A + DPTR
My_Jump_Tab:
   NOP   ;0
   NOP   ;1
   NOP   ;2
   NOP   ;3
   NOP   ;4
   NOP   ;5
   NOP   ;6
   RET   ;7
Dieses 8051-Programmbeispiel macht eine Verzögerung in 1/XTAL 
Schrittweite.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
>
>    ANL   A,#00000111b   ;ACC = ACC modulo 8
>    MOV   DPTR,#My_Jump_Tab
>    JMP   @A + DPTR
> My_Jump_Tab:
>    NOP   ;0
>    NOP   ;1
>    NOP   ;2
>    NOP   ;3
>    NOP   ;4
>    NOP   ;5
>    NOP   ;6
>    RET   ;7
> 
> 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.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

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

Dieses AVR-Programmbeispiel in (AVR-GCC) C macht eine Verzögerung in 
2/XTAL Schrittweite:
  asm volatile("NOP");
  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__...
  _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:
#define XTAL F_CPU

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Schnurzelpurzel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!!!
//***********************************************
// (c) 08.03.2010 by Schnurzelpurzel
void Delay(unsigned long int Zeit)
{
  PINB = (1 << PIN4); //Nur zu Testzwecken an Portleitung klappern!

  if(Zeit & 0x00000001)
  {
    asm volatile("NOP");
    asm volatile("NOP");1
  }
  if(Zeit & 0x00000002)
  {
    asm volatile("NOP");
    asm volatile("NOP");1
    asm volatile("NOP");2
  }
  if(Zeit & 0x00000004)
  {
    asm volatile("NOP");
    asm volatile("NOP");1
    asm volatile("NOP");2
    asm volatile("NOP");3
    asm volatile("NOP");4
  }
  if(Zeit & 0x00000008)
  {
    asm volatile("NOP");
    asm volatile("NOP");1
    asm volatile("NOP");2
    asm volatile("NOP");3
    asm volatile("NOP");4
    asm volatile("NOP");5
    asm volatile("NOP");6
    asm volatile("NOP");7
    asm volatile("NOP");8
  }

  Zeit >>= 4;
  while(Zeit > 0)
  {
    asm volatile("NOP");1
    asm volatile("NOP");2
    asm volatile("NOP");3
    asm volatile("NOP");4
    asm volatile("NOP");5
    asm volatile("NOP");6
    Zeit--;
  }

  PINB = (1 << PIN4); //Nur zu Testzwecken an Portleitung klappern!
}
//***********************************************


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!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schnurzelpurzel schrieb:

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

Der Rest googelt nach "Duffs Device"

Autor: Schnurzelpurzel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, hab eben die Kommentare falsch gemacht,
hab irgendwie gedacht ich bin in Assembler, muss natürlich so sein:
//***********************************************
void Delay(unsigned long int Zeit)
{
  PINB = (1 << PIN4); //Nur zu Testzwecken an Portleitung klappern!

  if(Zeit & 0x00000001)
  {
    asm volatile("NOP");
    asm volatile("NOP");//1
  }
  if(Zeit & 0x00000002)
  {
    asm volatile("NOP");
    asm volatile("NOP");//1
    asm volatile("NOP");//2
  }
  if(Zeit & 0x00000004)
  {
    asm volatile("NOP");
    asm volatile("NOP");//1
    asm volatile("NOP");//2
    asm volatile("NOP");//3
    asm volatile("NOP");//4
  }
  if(Zeit & 0x00000008)
  {
    asm volatile("NOP");
    asm volatile("NOP");//1
    asm volatile("NOP");//2
    asm volatile("NOP");//3
    asm volatile("NOP");//4
    asm volatile("NOP");//5
    asm volatile("NOP");//6
    asm volatile("NOP");//7
    asm volatile("NOP");//8
  }

  Zeit >>= 4;
  while(Zeit > 0)
  {
    asm volatile("NOP");//1
    asm volatile("NOP");//2
    asm volatile("NOP");//3
    asm volatile("NOP");//4
    asm volatile("NOP");//5
    asm volatile("NOP");//6
    Zeit--;
  }

  PINB = (1 << PIN4); //Nur zu Testzwecken an Portleitung klappern!
}
//***********************************************
:-)

Autor: Schnurzelpurzel (Gast)
Datum:

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

Habe mir das Hex-File mal mit ReAVR angesehen
(kann ich mir das auch von AVR-Studio aus ansehen???)
  ijmp
;  -----------  jump on last line
L0053:
  nop
L0054:
  nop
L0055:
  nop
L0056:
  nop
L0057:
  nop
L0058:
  nop
L0059:
  nop
L005A:
  nop
L005B:
So geht's auch :-)
Der Karl heinz Buchegger is so'n ganz schlauer, der müsste nur mal eher 
damit rausrücken!

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum so umständlich?

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


Peter

Autor: Schnurzelpurzel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Der Rest googelt nach "Duffs Device"

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

Habe mir das Hex-File mal mit ReAVR angesehen
(kann ich mir das auch von AVR-Studio aus ansehen???)
  ijmp
;  -----------  jump on last line
L0053:
  nop
L0054:
  nop
L0055:
  nop
L0056:
  nop
L0057:
  nop
L0058:
  nop
L0059:
  nop
L005A:
  nop
L005B:
So geht's auch :-)
Der Karl heinz Buchegger is so'n ganz schlauer,
der müsste nur mal eher damit rausrücken!

Autor: Schnurzelpurzel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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  :-(

Antwort schreiben

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

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.