ATMEL 89S52 - zpoždění

Diskuze a poradna o programátorech a programování různých obvodů

Moderátor: Moderátoři

Odpovědět
Zpráva
Autor
Uživatelský avatar
MirrA1
Příspěvky: 531
Registrován: 30 srp 2006, 00:00

ATMEL 89S52 - zpoždění

#1 Příspěvek od MirrA1 »

Dobrý večer
potřeboval bych trošku poradit a nakopnout jak vypočítat a naprogramovat zpoždění pro ATMEL 89S52, programuji v C v prostředí KEIL.

U procesoru 8051 jeden strojní cyklus (SC) zabere 12 taktů - takže při použitý krystalu 24MHz trvá jeden SC 500ns. Dejme tomu, že chci dosáhnout zpoždění 20us - což bude 40 SC.
Pro zpoždění jsem použil tento kód:

#include <REGX52.h>
#include <math.h>

delay(unsigned char y){
unsigned char i;
for(i=0;i<y;i++){;}
}

main(){
while(1){
delay(40);
P0_1 = 0;
delay(40);
P0_1 = 1;
}
}

který by měl pokud to dobře chápu fungovat tak, že i by se mělo inkrementovat do 40 a poté se vykoná další instrukce (rožnutí/zhasnutí LED). Dle logiky na začátku uvedeného výpočtu by mělo díky inkrementování do 40 dojít ke zpoždění 40 SC což by mělo být oněch 20us kterých chci dosáhnout.
Nicméně v praxi mi vychází dle osciloskopu doba zpoždění přesně 160us.

Nenapadá někoho čím to může být způsobeno? Moc díky za případné reakce.
Andrea
Příspěvky: 9340
Registrován: 07 zář 2007, 00:00

#2 Příspěvek od Andrea »

Ten cyklus není jedna instrukce, tak jeden průchod trvá víc než 1 SC. Ani to volání procedury a návrat nejde zanedbat. Podívej se, jak je to přeložené do assembleru a uvidíš tu kupu instrukcí.
Uživatelský avatar
procesor
Příspěvky: 5286
Registrován: 02 říj 2009, 00:00
Bydliště: PO

#3 Příspěvek od procesor »

Pre toto mám rád assembler, v tom cykle ti prefrčí aj cez 300 instrucií.
Uživatelský avatar
MirrA1
Příspěvky: 531
Registrován: 30 srp 2006, 00:00

#4 Příspěvek od MirrA1 »

NO tak je to tak. Když se kouknu do assembléru a odkrokuju si program v něm, tak mi dle počtu SC v simulátoru výjde přesný čas kterému odpovídá reálné chování.

Teď je ale otázka jak jednoduše spočítat kolik cyklů budu potřebovat pro požadované zpoždění protože to ještě závisí na tom jak si nadefinuji typ použitého čísla (v tomto případě: unsigned char )
Naposledy upravil(a) MirrA1 dne 26 kvě 2010, 23:02, celkem upraveno 1 x.
Uživatelský avatar
MirrA1
Příspěvky: 531
Registrován: 30 srp 2006, 00:00

#5 Příspěvek od MirrA1 »

procesor píše:Pre toto mám rád assembler, v tom cykle ti prefrčí aj cez 300 instrucií.


Je to tak, zlatej assembler ve kterym si vsechno v procesoru manualne posilas kam zrovna chces :-)
Uživatelský avatar
procesor
Příspěvky: 5286
Registrován: 02 říj 2009, 00:00
Bydliště: PO

#6 Příspěvek od procesor »

40cyc....160us
x?cyc......20us
--------------------
x=800/160=5
Uživatelský avatar
rnbw
Příspěvky: 37419
Registrován: 21 bře 2006, 00:00
Bydliště: Bratislava

#7 Příspěvek od rnbw »

A nie je tam v kniznici funkcia, ktora robi presne oneskorenie?
Uživatelský avatar
MirrA1
Příspěvky: 531
Registrován: 30 srp 2006, 00:00

#8 Příspěvek od MirrA1 »

procesor píše:40cyc....160us
x?cyc......20us
--------------------
x=800/160=5


no kéžby to bylo takhle jednoduše vypočitatelné, problém je v tom, že to není lineární.
čítání do 1 zabere 20 SC = 10us
čítání do 2 zabere 27SC = 13,5us
čítání do 3 zabere 35SC = 17,5us
Uživatelský avatar
MirrA1
Příspěvky: 531
Registrován: 30 srp 2006, 00:00

#9 Příspěvek od MirrA1 »

rnbw píše:A nie je tam v kniznici funkcia, ktora robi presne oneskorenie?


no právěže jediné zpoždění je dělané dle toho co jsem napsal - a to jsem prohledával i internet. Zpoždění jsou řešená jen dle této struktury, ale jak přesný čas vypočítat jsem nikde nenašel.

Druhou možností jak realizovat zpoždění je použít časovač - což je ale pro tak krátké časy nesmysl.
Uživatelský avatar
Atlan
Příspěvky: 4514
Registrován: 10 kvě 2004, 00:00
Bydliště: Košice

#10 Příspěvek od Atlan »

ides pokus omyl.... alebo vytvor kniznicu s oneskorenim v ASM, volanie tej knicnice uz by malo byt konstatne...
Uživatelský avatar
AB1
Příspěvky: 312
Registrován: 23 lis 2009, 00:00

#11 Příspěvek od AB1 »

Můžeš počítat takto:

unsigned char i;

Kód: Vybrat vše

for(i=0; i<n; i++) {}  //        n = (cykly-2)/3       5 <= n <= 769

Přidáme tolik nopů, kolik je zbytek po dělení.

Příklad:
delay 300 cyklů
(300-2)/3 = 99 ; zbytek=2

Kód: Vybrat vše

for(i=0; i<99; i++) {}
  _nop_();
  _nop_();


Při 12MHz je jeden instrukční cykl 1 mikrosekunda.
Andrea
Příspěvky: 9340
Registrován: 07 zář 2007, 00:00

#12 Příspěvek od Andrea »

Dělat mikrosekundová zpoždění voláním nějaké funkce v C dost dobře nejde, jenom ta režie volání je nějakých 7us. Pokud to má být aspoň trochu přesné a stačí rozsah do 256us, tak by se asi dalo použít makro s parametrem a v makru vložený assembler. Instrukce DJNZ trvá při 24MHz právě tu jednu us.
Uživatelský avatar
AB1
Příspěvky: 312
Registrován: 23 lis 2009, 00:00

#13 Příspěvek od AB1 »

Souhlasím s Andreou.
Pokud některé překladače mají funkce delay(), tak stejně nebývají přesné.

Ani na kód, který jsem napsal výše nejde spolehnout, protože teď jsem zjistil že funguje přesně jenom při určité úrovni optimalizace.

Pokud je třeba přesný počet cyklů, je asi nejlepší použít čítač.
Odpovědět

Zpět na „Programování PIC, ATMEL, EEPROM a dalších obvodů“