Forum: Mikrocontroller und Digitale Elektronik Pic Zeitschleife geht nich, verstehe nicht wieso


von Pascal (Gast)


Lesenswert?

Hallo,

also ich habe einige Zeitschleifen geschrieben, nur passiert nichts wenn 
sie aufgerufen werden... also nie wieder.
Hab ich da irgentwie eine Endlosschleife gebaut?
Oder Funktioniert das mit dem _asm ... _endasm so nicht?
Ich verstehe nicht warum es so nicht funktioniert.

Ich benutze MPLAB mit dem C18 Compiler.

Hier die 3 Verzögerungen, vom Takt her habe ich 4MHz das erstmal fest 
gelegt, da es zur Zeit nur diesen Aufbau gibt.

void DelayUs(unsigned int x);
void DelayMs(unsigned int x);
void DelayS(unsigned int x);

void DelayUs(unsigned int x)
{
  // 4MHz -> 1 Zyklus = 1us!
  while(x>0)
  {
    x--;
    _asm NOP _endasm
  }
}
void DelayMs(unsigned int x)
{
  int i,j;
  for(i=0;i<x;i++)
  {
    for(j=0;j<4;j++)
      DelayUs(250);
  }
}
void DelayS(unsigned int x)
{
  int i,j;
  for(i=0;i<x;i++)
  {
    for(j=0;j<4;j++)
      DelayMs(250);
  }
}

Dann habe ich noch ein kleines Testprogramm, das eine LED an Port-A 
blinken lassen soll.

#include <p18f458.h>
#pragma config OSC=EC, PWRT=ON, WDT=OFF

// Hier stehen die Zeitfunktionen von oben zwischen.

void main(void)
{
  TRISA = 0;
  while(1)
  {
    PORTAbits.RA0 = 1;
    DelayS(1);
    PORTAbits.RA0 = 0;
    DelayS(1);
  }
}

von holger (Gast)


Lesenswert?

#pragma config OSC=EC...

Hast du auch einen externen Taktgenerator dran?

von Severino R. (severino)


Lesenswert?

Pascal schrieb:
> Hallo,
>
> also ich habe einige Zeitschleifen geschrieben, nur passiert nichts wenn
> sie aufgerufen werden... also nie wieder.
> Hab ich da irgentwie eine Endlosschleife gebaut?
> Oder Funktioniert das mit dem _asm ... _endasm so nicht?
> Ich verstehe nicht warum es so nicht funktioniert.

Funktioniert es in echter Hardware nicht, oder im Simulator nicht, oder 
in beiden nicht?

> void DelayUs(unsigned int x)
> {
>   // 4MHz -> 1 Zyklus = 1us!
>   while(x>0)
>   {
>     x--;
>     _asm NOP _endasm

Du führst ja nicht nur NOP aus, sondern auch x--, das braucht auch noch 
ein paar Zyklen.

von Uwe N. (ulegan)


Lesenswert?

Mach mal die Verzögerung kürzer, denn dein DelayUs dauert sicher 
deutlich länger als eine Mikrosekunde. Nicht nur der nop frisst Zeit, 
x-- braucht auch und das x>0 will ausgewertet werden. Dazu kommt der 
Aufruf und die Rückkehr aus dem Unterprogramm. Selbst ohne das irgendwas 
auf dem Stack gesichert wird, und das wird es ganz bestimmt, würde ein 
CALL und ein RETURN schon 4 Zyklen brauchen.
Ich schätze ein DelayUs(1) mal auf mindestens 30 Zyklen = 30 µs.
Betrachte mal den erzeugten Assemblercode.

Uwe

von RoGerZ (Gast)


Lesenswert?

... while (x>0) ist immer wahr,
wenn x eine unsigned int ist...

Kleine Ursache, große wirkung!

Gruß,
R.

von RoGerZ (Gast)


Lesenswert?

Sorry, zu schnell geantwortet:
Das geschriebene stimmt natürlich nur, wenn da stehen würde "while 
(x>=0)" ... steht da aber nicht, muß also ander Ursache haben ...

Gruß,
R.

von holger (Gast)


Lesenswert?

Versuchs mal so:
1
void main(void)
2
{
3
 ADCON0=0;          //AD-Wandler aus
4
 ADCON1=0x0F;       //Alle Analogeingänge auf digital
5
 CMCON=0x07;        //Komparatoren aus
6
7
  TRISA = 0;
8
  while(1)
9
  {
10
    PORTAbits.RA0 = 1;
11
    DelayS(1);
12
    PORTAbits.RA0 = 0;
13
    DelayS(1);
14
  }
15
}

Und wie oben schon gesagt wurde, werden deine
Delays länger sein als erwartet.

>Oder Funktioniert das mit dem _asm ... _endasm so nicht?

Doch, das geht so.

von Pascal (Gast)


Lesenswert?

Ja hab einen externen Takt angeschlossen.

Es funktioniert in der Hardware nicht, wie man simuliert hab ich noch 
nicht rausgefunden.

Ok, in Asm sieht das ganze schon etwas anders aus. Also die Us Funktion 
zumindest:

void DelayUs(unsigned int x)
  0008    CFD9     MOVFF 0xfd9, 0xfe6             // 2 Zyklen
  000A    FFE6     NOP
  000C    CFE1     MOVFF 0xfe1, 0xfd9             // 2 Zyklen
  000E    FFD9     NOP
27:                {
28:                  // 4MHz -> 1 Zyklus = 1us!
29:                  while(x>0)
  0010    50D9     MOVF 0xfd9, W, ACCESS          // 1 Zyklus
  0012    0FFD     ADDLW 0xfd                     // 1 Zyklus
  0014    6EE9     MOVWF 0xfe9, ACCESS            // 1 Zyklus
  0016    0EFF     MOVLW 0xff                     // 1 Zyklus
  0018    20DA     ADDWFC 0xfda, W, ACCESS        // 1 Zyklus
  001A    6EEA     MOVWF 0xfea, ACCESS            // 1 Zyklus
  001C    0E00     MOVLW 0                        // 1 Zyklus
  001E    80D8     BSF 0xfd8, 0, ACCESS           // 1 Zyklus
  0020    54EE     SUBFWB 0xfee, W, ACCESS
  0022    0E00     MOVLW 0                        // 1 Zyklus
  0024    54ED     SUBFWB 0xfed, W, ACCESS
  0026    E207     BC 0x36
  0034    D7ED     BRA 0x10                       // 1 Zyklus
30:                  {
31:                    x--;
  0028    0EFD     MOVLW 0xfd                     // 1 Zyklus
  002A    06DB     DECF 0xfdb, F, ACCESS          // 1-2 Zyklus
  002C    0EFE     MOVLW 0xfe                     // 1 Zyklus
  002E    E201     BC 0x32                        // 1 Zyklus
  0030    06DB     DECF 0xfdb, F, ACCESS          // 1-2 Zyklus
32:                    _asm NOP _endasm
  0032    0000     NOP                            // 1 Zyklus
33:                  }
34:                }
  0036    52E5     MOVF 0xfe5, F, ACCESS          // 1 Zyklus
  0038    CFE7     MOVFF 0xfe7, 0xfd9             // 2 Zyklus
  003A    FFD9     NOP
  003C    0012     RETURN 0                       // 2 Zyklus


so gob über den Daumen insgesamt 27 Zyklen... anstatt 1 wie gedacht.

Bei den anderen Funktionen für Ms und S, ist das dann genauso, das 
heisst es wird "etwas" länger dauern... wenn ich dann noch die for() 
Schleifen in Asm übersetzt sehe, wird mir klar warum nichts passiert, es 
dauert einfach zu lange...

Hm, ok hab jetzt versucht eine Us Funktion in Asm zu schreiben, mit dem 
Schluss das das woll nichts wird, weil der Aufruf und der Rücksprung bei 
4Mhz schon länger wie 1us dauert.

Gibts nicht irgentwo eine Art Bibiotek die fertige Zeitfunktionen hat, 
die auch ohne größere Schwierigkeiten in MPLAB zum laufen gebraucht 
werden können?

von Sebastian B. (mircobolle)


Lesenswert?

Hat dein PIC einen freien Timer, oder eine Real Time Clock?

Warum realisierst du die Wartefunktion nicht mit einer Interrupt 
Funktion?

etwa so:
1
static volatile unsigned int s_v_u16_counter=0;
2
3
void wait_ms (unsigned int u16_wait_cnt)
4
{
5
   s_v_u16_counter = u16_wait_cnt;
6
7
   while (s_v_u16_counter > 0)
8
   {
9
      _asm{"nop"};
10
   }
11
}

und dann in der Timer ISR
1
void isr_timer_overflow (void)
2
{
3
   reset_overflow_flag(); // Makro
4
   if (s_v_u16_counter > 0)
5
   {
6
     s_v_u16_counter--;
7
   }
8
}

Die "Wartezeit" wird dann ueber den Timer Counter Wert bestimmt.
So bekommt man allerdings keine Genauigkeit im us Bereich hin. Aber für 
ms und s reicht es.

Gruß

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.