Kuinka saan tehtyä assemblerilla delay funktion (esim 200ms) c -ohjemaan?
delay funktio
12
2116
Vastaukset
- tjooo...
Loopissa vaan tarpeeksi monta kertaa esim NOP (No OPeration) käskyä. Sisäkkäisiäkin looppeja voi käyttää.
Tietysti tällöin ohjelma jököttää 200ms tekemättä mitään hyödyllistä..- nop
Paitsi että tuolla tavalla tehty 'hidastaja' vie eri ajan eritehoisilla prosessoreilla.
- jooh
nop kirjoitti:
Paitsi että tuolla tavalla tehty 'hidastaja' vie eri ajan eritehoisilla prosessoreilla.
oletetaan että kyseessä on joku sulautettu rauta jossa on vakio taajuinen kide
tosin nuo looppaamalla tehdyt hidastajat on vähän kökköjä..mitä sitä suotta prosessoritehoa semmoiseen käyttämään? Löytyyhän niitä ajastimiakin.
- keskytysaliohjelma
RTC-keskeytykselle. Keskeytysaliohjelma laskee
sopivan määrän tulleita keskeytyksiä ja nostaa
lipun.
Sitten asetat RTC:n keskeyttämään 1024
kertaa sekunnissa ja keskeytysmaskin säädät
niin, että RTC-keskeytykset sallitaan.
Tuskin säästät kovin paljon tekemällä tämän
assemblerilla.
Tasan millisekunnin monikertaa tällä tavalla
ei saada, mutta aika lähelle kuitenkin. - ...
sleep(sekunteja) toimii unixilla (unistd.h?). windowsilla sitten..jotain muuta.
- ...
uhh, sori, assylla piti.. silmät ristissä..
- Anonyymi
Delay-funktio voidaan luoda kääntämällä assemblerilla yksinkertainen silmukka, joka odottaa tietyn ajanjakson ennen kuin se siirtyy eteenpäin ohjelmassa. Tässä esimerkissä luodaan 200ms viive käyttämällä x86-arkkitehtuurin NASM-assembleria:
section .data
delay_time equ 200 ; Viiveaika 200ms
section .text
global delay
delay:
mov ecx, delay_time ; Aseta viiveaika rekisteriin
delay_loop:
dec ecx ; Vähennä rekisterin arvoa yhdellä
jnz delay_loop ; Toista silmukka, kunnes rekisteri on 0
ret ; Palauta ohjaus ohjelman päävaiheeseen
Tässä assembler-koodissa delay-funktio luo 200ms viiveen suorittamalla silmukan, joka vähentää rekisterin arvoa yhdellä ja odottaa, kunnes rekisterin arvo on nolla. Sitten funktion ohjaus palautetaan takaisin C-ohjelmaan. Voit kutsua tätä delay-funktiota C-ohjelmassasi seuraavasti:
extern void delay(); // Esittele delay-funktio
int main() {
// Aja delay-funktio viiveen luomiseksi
delay();
// Jatka ohjelman suorittamista
return 0;
}- Anonyymi
Meinaatko että aloittaja odottelee vastaustasi 19 vuotta?
- Anonyymi
Anonyymi kirjoitti:
Meinaatko että aloittaja odottelee vastaustasi 19 vuotta?
No, hyvää kannattaa odottaa.
- Anonyymi
Ohjelmassa on / tulee olla jokin tick timer -keskeytys, josta viiveet ym. ajoitukset on helppo johtaa. PC-koneissa tällainen keskeytys tikitti aikoinaan n. 55 ms, nyttemmin 1 ms välein. Jossakin sulautetussa järjestelmässä keskeytysintervalli voi olla lyhyempikin, mutta sen kerrannaisten ja nanosekuntiluokan viiveiden (nop-luuppi tms.) väliin jää yleensä hankalasti toteutettava viiveen pituus, joka tyypillisesti ratkeaa vain omalla h/w-timerilla.
- Anonyymi
Erittäin lyhyet odottelut voi kannattaa tehdä nop-loopilla. Muistelisin, että avr:ssä nop-käsky on tasan 1 kellojakso ja hyppy siihen takaisn vie 3 kellojaksoa, siispä yksi kierros looppia vie 4 kellokiteen jaksoa. Hiukan pidemmät odottelut voi sitten tehdä h/w-timerilla ilman keskeytysrutiinia. Sitten kun aletaan puhua alle 100-200 keskeytyksestä sekunnissa voi ottaa keskeytysrutiinin käyttöön. Esimerkiksi avr:llä joskus tuli laskettua, että kääntäjä tunkee rutiiniin 68 kellojaksoa koodia ilman, että oma koodi vielä pyörähtää lainkaan: Tämä vie melkoisesti jo kellojaksoja. Nopean rutiinin teko vaatii siis koodin läpikäymistä ja kannattaa mitata rutiinin tyhjäkäyntinopeus eli kuinka nopea kello tarvitaan, jotta rutiinia voidaan kutsua ylipäätään x kertaa sekunnissa.
http://www.rjhcoding.com/avr-asm-delay-subroutine.php
avr-gcc toteutuksessa on valmiiksi assembler-toteutus uint8_t tyyppiselle viiveelle. Muistelisin, että tätä on käytetty uint16_t tyyppisessä hyväksi - joskaan rutiini ei ole enää kellojakson tarkka toisin kuin uint8_t:lle oleva rutiini. Tässäkin tosin on yllätyksiä: inline-koodi edellyttää, että ei käytetä size-optimointia, joka lisää viiveisiin funktiokutsujen ajat. Siispä uint16_t loopin pituus menee heti rikki, jos koodin optimointia muutetaan!
https://www.nongnu.org/avr-libc/user-manual/group__util__delay__basic.html - Anonyymi
Anonyymi kirjoitti:
Erittäin lyhyet odottelut voi kannattaa tehdä nop-loopilla. Muistelisin, että avr:ssä nop-käsky on tasan 1 kellojakso ja hyppy siihen takaisn vie 3 kellojaksoa, siispä yksi kierros looppia vie 4 kellokiteen jaksoa. Hiukan pidemmät odottelut voi sitten tehdä h/w-timerilla ilman keskeytysrutiinia. Sitten kun aletaan puhua alle 100-200 keskeytyksestä sekunnissa voi ottaa keskeytysrutiinin käyttöön. Esimerkiksi avr:llä joskus tuli laskettua, että kääntäjä tunkee rutiiniin 68 kellojaksoa koodia ilman, että oma koodi vielä pyörähtää lainkaan: Tämä vie melkoisesti jo kellojaksoja. Nopean rutiinin teko vaatii siis koodin läpikäymistä ja kannattaa mitata rutiinin tyhjäkäyntinopeus eli kuinka nopea kello tarvitaan, jotta rutiinia voidaan kutsua ylipäätään x kertaa sekunnissa.
http://www.rjhcoding.com/avr-asm-delay-subroutine.php
avr-gcc toteutuksessa on valmiiksi assembler-toteutus uint8_t tyyppiselle viiveelle. Muistelisin, että tätä on käytetty uint16_t tyyppisessä hyväksi - joskaan rutiini ei ole enää kellojakson tarkka toisin kuin uint8_t:lle oleva rutiini. Tässäkin tosin on yllätyksiä: inline-koodi edellyttää, että ei käytetä size-optimointia, joka lisää viiveisiin funktiokutsujen ajat. Siispä uint16_t loopin pituus menee heti rikki, jos koodin optimointia muutetaan!
https://www.nongnu.org/avr-libc/user-manual/group__util__delay__basic.html"Esimerkiksi avr:llä joskus tuli laskettua, että kääntäjä tunkee rutiiniin 68 kellojaksoa koodia ilman, että oma koodi vielä pyörähtää lainkaan"
Enin osa tuosta 68 kellojaksosta lienee rekisterien talletusta ja palautusta. Jos keskeytyskoodista kutsuu mitä tahansa funktiota (toisessa moduulissa), kääntäjällä ei ole muuta vaihtoehtoa kuin työntää kaikki mahdollisesti muuttuvat rekisterit pinoon. Etenkin AVR:ssä työrekistereitä riittää.
Keskeytyskoodit kannattaakin kirjoittaa mahdollisimman yksinkertaisiksi, mielellään ilman ensimmäistäkään funktiokutsua ja jättää varsinainen tekeminen "pääohjelmaan". Aina tämä ei ole mahdollista ja silloin tuo 68 kellojakson overhead on vain hyväksyttävä.
Puheena olevassa tick timer -keskeytyksessä asialla on oleellinen merkitys. Esimerkiksi millisekunnin resoluutiolla ja 8 MHz kellotaajuudella pelkkä 68 kellojakson overhead käyttää lähes prosentin CPU-kapasiteetista.
Ketjusta on poistettu 0 sääntöjenvastaista viestiä.
Luetuimmat keskustelut
Suomessa on meneillään boomereiden kosto
1990-luvun lamassa osumaa saaneet sukupolvet toivovat sen jälkeen syntyneille sukupolville kärsimystä porvareita äänestä462429Petteri Orpon kommentti persujen väkivaltaan?
Hiirenhiljaa taas on, kun Tampereella persulahkon ääriosasto pahoinpiteli kantasuomalaisen tytön. Missä on pääministeri391700Onko sinulla jalostettu koira? Nämä tekijät altistavat koiran sairastumiselle
Moni Suomessa suosittu koirarotu on sairas ulkonäkökeskeisen jalostuksen ja ääripiirteiden vuoksi. Erityisesti tietyt t241463- 891432
IPCC romahtaa
Mitenkäs tässä nyt näin kävi? Ilmastohourimoinnin tukijalka myöntää, ettei mitään ilmastokatastrofia olekaan. Eikös tääl321171- 1351125
Anabaptismin kirous
Uudestikastetut lahkolaiset joutuvat valheen kierteeseen. He joutuvat herjaamaan lapsena saamaanssa kastetta nimeen Isä4171082Pelolla pakottaminen
Kristinusko on tuovinaan valoa ja toivoa, mutta ensin pitää olla pimeyttä ja toivottomutta jotta joku valoa ja toivoa ha624926Robotiikka korvaa tulevaisuudessa seurustelusuhteet
Haluan herättää keskustelua aiheesta. Asiantuntijoiden mukaan robottien kehitys on 10-15 vuoden päässä siitä että voidaa240911kamera hakokylässä
kamera kuvaamassa yleistä tietä laittomasti ristauksessa hakokylä-raatevaara!17863