Hallo,

ik ga een klein testprogrammatje maken. Daarbij moet ik 1 seconde timeout hebben. De pic loopt op 4MHz. Dan duurt 1 NOP instructie dus 0,25uS (1/4e6 = 0.25e-6) ? Dus dan heb ik voor 1 seconde pauze 4 miljoen NOP instructies nodig? Dus dan ziet mijn sleep functie er zo uit?

void sleep(unsigned int time)
{
unsigned int x;
for(x=0;x<=(4000000*time);x++)
{
asm("NOP");
}
};

Dat lijkt mij kloppen. Maar het rare vind ik dat ik in de code van een kennis van mij zie dat hij geen NOP gebruikt, maar CLRWDT(), waarom? Volgens hem duurt die CLRWDT() 10uS, terwijl die PIC ook op 4MHz draait (als het goed is...). Doe ik wat fout?

ik heb er niet zo heel veel verstand van hoor, maar denk je eraan dat je op een gegeven moment misschien een beetje veel instructies hebt staan? 4 miljoen NOPjes gaat toch wel heel hard (qua beschikbaar geheugen voor je code)...

Een NOP instructie duurt 1us bij een kloksnelheid van 4MHz.
Dat komt omdat een NOP instructie 1 machinecyclus duurt.
En een PIC processor heeft 4 klokcyclus nodig voor het uitvoeren van 1 machinecyclus.
Daarnaast je C code, wil je werkelijk het getal 4 miljoen vermenigvuldigen met de unsigned int time.
Volgens mij moet je het hoofdstuk gegevenstype en hun bereik nog eens bestuderen.
Daarnaast duurt de uitvoer van deze C functie veel langer dan telkens 1 NOP instructie.
Er moet namelijk getest, gerekend en gesprongen worden, en dat gaat niet als je moet NOP-en in 1 enkele instructie.
Ik weet niet hoe de functie CLRWDT() werkt.
Maar het lijkt mij dat deze de WatchDogTimer CLeaRt.
Als je wilt weten hoe de watchdog werkt moet je ff de datasheet erbij pakken.
Maar in hoofdlijn komt het hier op neer, de watchdogtimer is een teller die met een vaste interval wordt verhoogd.
Op het moment dat deze zijn maximale waarde + 1 bereikt zal de processor worden gereset.
Het doel hiervan is te voorkomen dat als je programma vastloopt een einde te maken aan een mogelijke impasse of valse programma executie, dit omdat bij normale programma executie de watchdogtimer wordt gereset voordat deze de kans krijgt om de processor te resetten.

ok, het komt voor mij niet zo precies, als ik maar even een sleep heb. Er komen trouwens geen 4 miljoen nopjes hoor, hij doet gewoon 4 miljoen keer een goto nop ;) Maar een goto neemt 2 cycles in, idd... Ff rekening mee houden. Het is trouwens niet zo belangrijk dat het precies komt, het is gewoon een blink a led je :P

Het handigste vind ik nog gewoon de geneste wacht-loepjes.

de delay van het volgende voorbeeld is 1000000 machinecycles:


DELAY                                           ;2 (call naar deze functie) 
                MOVLW   0x62                    ;1
                MOVWF   COUNT0                  ;1
DLY_LOOP0       MOVLW   0xD9                    ;  1
                MOVWF   COUNT1                  ;  1
DLY_LOOP1       MOVLW   0x0E                    ;    1
                MOVWF   COUNT2                  ;    1
DLY_LOOP2       DECFSZ  COUNT2,F                ;      1
                GOTO    DLY_LOOP2               ;      2
                DECFSZ  COUNT1,F                ;    1
                GOTO    DLY_LOOP1               ;    2
                DECFSZ  COUNT0,F                ;  1
                GOTO    DLY_LOOP0               ;  2
                NOP                             ;1
                NOP                             ;1
                RETURN                          ;2

De formule is simpel af te leiden uit de code: ((3 * 0x0E + 5) * 0xD9 + 5) * 0x62 + 8 = 1000000
verander 0x0E, 0xD9 en 0x62 als je een andere delay wilt.

Dit simpele basic programmatje zoekt de 3 waarden voor je op: (voeg wel zelf nopjes toe als het niet helemaal uitkomt)

t = 1000000
max = 0
FOR a = 1 TO 256
  FOR b = 1 TO 256
    FOR c = 1 TO 256
      d = ((3 * a + 5) * b + 5) * c + 6
      IF d > t THEN EXIT FOR
      IF d > max THEN
        max = d
        PRINT "((3 *"; a; "+ 5) *"; b; "+ 5) *"; c; "+ 6 ="; d
      END IF
    NEXT
  NEXT
NEXT

Nog 1 ding: houd er wel rekening mee dat de code om de poort te laten blinken en in de mainloopt te blijven, ook tijd kost. Neem hierom altijd wat minder tijd in de delay loep als de nauwkeurigheid van de delay belangrijk is (zoals bij een stopwatch of klok)

Jah leuk hoor zo'n assembly code, maar ik wil het eigenlijk volledig in C doen he... Ik had dus dit:

void sleep(unsigned int time)
{
	unsigned long x;
	
	for(x=0;x<=(time*333333);x++)	// Een NOP + een GOTO = 3 Cycles
	{				// 1000000uS/3 = 333333
		asm("NOP");		// 1 Cycle
	}				// 2 Cycles
}

maar die 333333 is veel te veel. Wat moet het dan zijn? Op gok lukte het met 3333 maar hoe bereken je dat?

In een hoge taal als c kun je dit heel lastig bepalen, of er moet in de handleiding van je compiler al staan hoeveel asm instucties je kwijt bent voor zo'n for loop. Ik heb geen idee hoe dat je compiler met zulke grote getallen omgaat, maar in asm is de hoogste waarde voor een var 255 (0xFF). Bestaat er trouwens niet gewoon al een standaard delay instructie?

ik heb wat gevonden! In de samples directory zit dit voorbeeld:

#define DelayUs(x) { unsigned char _dcnt; \
_dcnt = (x)/((12MHZ)/(XTAL_FREQ))|1; \
while(--_dcnt != 0) \
continue; }

dan gebruik ik dit wel :)