2014-10-08 163 views
1

我期待在上升沿信號輸入後發出非常短的脈衝。使用nop彙編精確延遲Arduino?

這裏最難的部分是我想控制(以高分辨率)在我的脈搏之前的延遲時間,以及我的脈搏持續時間。我可以很容易地控制這一點,只需將自己編碼爲一個硬編碼延遲,但我不確定如何以某種任意延遲執行此操作,並且具有相同的準確性。

經過很多頭痛追逐定時器,然後最終意識到我最終受到中斷例程進入/退出時間的限制,現在我正在試圖通過nops來控制我的延遲。

我曾以爲這個C開關語句是我想要的東西(編譯,希望它會成爲有效的,只是改變程序計數器到正確的位置之後),但它產生了一些非常奇怪的行爲...

switch(delayTime){ case 10: __asm__ __volatile__("nop"); case 9: __asm__ __volatile__("nop"); case 8: __asm__ __volatile__("nop"); 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"); } PORTD = 0x10; ...

理想情況下,我想主要是通過一些代碼,將彙編成這樣運行:(這是C語言和彙編的一些奇怪的僞代碼,仍然不知道如何組裝做它的某些)

0x005 Reg1 = 0xFF-val1 %(where somehow 0xFF is known?/found out?) 0x006 Reg2 =0x1FF-val2 0x007 IJMP Reg1 0x008 NOP 0x009 NOP 0x00A NOP ... 0x0FF MOV 0x40, PORTD % assign the value 0x40 to the static variable "PORTD" 0x100 IJMP Reg2 0x101 NOP 0x102 NOP 0x103 NOP 0x104 NOP ... 0x1FF MOV 0x00, PORTD % assign the value 0x00 to the static variable "PORTD"

我只是總體不確定如何在運行時/運行期間找到代碼的內存位置,這樣該程序的「0xFF」和「0x1FF」方面並不是那麼糟糕(它看起來像是超級危險的只是,獲得代碼的彙編,然後硬編碼...我寧願不這樣做)。另外,雖然很容易只用200多個nops來洪泛,但如何讓IJMP cmd按照我想要的方式行事? (我真的不知道,如果這是我想要的命令)..

我想一般我正在尋找一些彙編命令(我似乎無法找到),讓我「添加N到程序計數器「,我可以確保該命令在彙編中運行,至少有N + 1個彙編命令在其之前,硬編碼。

作爲一個附註,所有這些都在一箇中斷程序,所以我不覺得玩電腦很糟糕...另外,我知道是有點不好的阻止多達500個操作,但對於手頭的任務來說,時間比它有多重要更重要作爲一個例程塊。

+0

AVR Libc中的延遲例程有什麼問題? – 2014-10-08 04:57:24

+1

爲了獲得我想要的精度,我想我需要使用類似「__builtin_avr_delay_cycles」的東西。然而,這個函數需要一個常量(它是一個似乎在編譯時構建的宏),而我正在尋找一些函數我可以在運行時調用一個變量。據我所知,只要將PC移到內存中以獲得確切的nops數是最可靠的解決方案,但是它可能會遺漏AVR libc中的某些內容。 (我只能看到每次迭代需要3,4個週期的方法),這對於我想要的16 MHz時鐘而言是不夠的時間分辨率。 – BlueCoconut 2014-10-08 05:16:25

回答

1

我對AVR指令集並不熟悉,但總體思路是使用指令CALL將程序計數器(PC)放入堆棧。然後使用POP將PC移動到Z寄存器。然後你可以將一些號碼ADD加到Z寄存器中,然後用IJMP跳轉到結果地址。

因此就沿着這些線路

delay: call delay1    ; push the PC onto the stack 
delay1: pop r30    ; pop the PC into the Z registers 
     pop r31 
     add r30,r0    ; add some amount to the PC value 
     addc r31,r1 
     ijmp     ; use IJMP to jump to the resulting address 
     nop 
     nop 
     nop 
     ... 

隨想:

  • 在8MB的機器,你需要第三個流行從堆棧中刪除的 第三個字節的PC。
  • Z只有16位,因此該代碼必須位於第一個程序存儲器的012KB中。
  • 我不確定首先應該彈出哪個寄存器(r30或r31) 。
  • 添加到Z的值必須相對於delay1,因爲call是 會將delay1的地址推入堆棧。換句話說, 需要添加的最小數量是6,因爲這是從delay1到第一個nop的 指令數。
  • 最小延遲由最多六個指令決定,而 包括ijmp。您應該相應地增加r1/r0(減少 nops的數量)。

就像我說的,我在AVR指令集方面的專家,所以你應該把這個作爲一個一般的建議,並準備花一些時間鍛鍊的細節。祝你好運!