2017-05-03 55 views
0

我最近在一个与Arduinos合作的模块中提供了这项任务。我们以前的任务是C语言,但是当涉及到这个时,我根本不知道该怎么做,甚至不知道该如何开始。我们也没有提供任何类型的讲座或其他方式来解决这个问题。任何人都可以帮助或只是让球滚动一点,这样我就能更好地理解它?谢谢。AVR汇编语言 - 交通灯

的,我不得不修改代码的第一位是如下:

"delay_ms%=: nop     ; code to replace nop \n" 
"delay_100us%=: nop     ; code to replace nop \n" 
"delay_1us%=: nop     ; code to replace nop \n" 
"    sbiw r30,1   ; decrement ms count (r31:r30)\n" 
"    brne delay_ms%=  ; loop to delay_ms while > 0 \n" 
"    ret     ; return from subroutine  \n" 

,然后将代码的其余部分是这样的:

" blink%=:        ; start of blink code \n" 
// 
// turn onboard LED on 
// 
"    ldi r18,0x20   ; bit 5 (pin 13) = high \n" 
"    out 5,r18    ; output to port B  \n" 
// 
// delay by value in millisecs variable 
// 
"    lds r30,millisecs  ; r30 = hi byte   \n" 
"    lds r31,millisecs + 1 ; r31 = lo byte   \n" 
"    call delay_ms%=   ; call millisec delay sub \n" 
// 
// turn onboard LED off 
// 
    "    ldi r18,0x00   ; value for all LEDs off \n" 
    "    out 5,r18    ; output to port B  \n" 
// 
// delay by value in millisecs variable 
// 
"    lds r30,millisecs  ; r30 = hi byte   \n" 
"    lds r31,millisecs + 1 ; r31 = lo byte   \n" 
"    call delay_ms%=   ; call millisec delay sub \n" 

::: "r16", "r17", "r18", "r30", "r31"); // clobbered registers 

//-------------------------------------------------------------------------  ------- 
// calculate the execution time of the blink routine, and print details 
long endtime = millis();     // make a note of the end time 
float ms = endtime-starttime;    // calculate the interval 
float expected = 2 * millisecs;   // expected delay is millisecs *  2 (2 delays in blink) 
float overheads = 17;      // overheads due to the timing 
expected = expected + overheads; 
float error_percent = 100.0*(ms-expected)/expected; 
Serial.print("delay="); Serial.print(ms); Serial.print("ms "); 
Serial.print("error: "); 
if(error_percent>0) 
Serial.print("+"); 
Serial.print(error_percent);Serial.println("%"); 
} 

的指令集是在这里:http://www.atmel.com/images/Atmel-0856-AVR-Instruction-Set-Manual.pdf

回答

1

引用的字符串是在您离开的asm()调用中的汇编代码。编译时,字符串将被直接转换为相关的汇编指令。

名称冒号:被称为标签后,函数调用只是跳转到标签。如果以前的结果不为0,也可以跳转到具有分支指令的分支指令内。

asm()调用指示寄存器“r16”,“r17”,“r18”,“r30” “r31”全部使用,但闪烁代码似乎只使用“r18”,“r30”,“r31”。这意味着您打算在您的延迟代码中使用“r16”和“r17”。

延迟码到目前为止仅仅是倒计时的双寄存器R31的值一个循环:R30

"delay_ms%=: nop     ; code to replace nop \n" 
"    sbiw r30,1   ; decrement ms count (r31:r30)\n" 
"    brne delay_ms%=  ; loop to delay_ms while > 0 \n" 
"    ret     ; return from subroutine  \n" 

它分支回到循环,直至数为0的顶部,当它返回。

您需要在该循环内插入一些代码,以计算您自己的需要1毫秒的循环。您需要知道时钟速度以确定数量。使用r17:r16作为计数,类似于延迟计数的设置方式,除非您使用ldi,立即加载。

"delay_ms%=: ldi ...    ; set up r17 and r16 in a few instructions \n" 
"delay_1us%=: sbiw r16,1   ; decrement count n" 
"    brne delay_1us%= ; loop to while > 0 \n" 
"    sbiw r30,1   ; decrement ms count (r31:r30)\n" 
"    brne delay_ms%=  ; loop to delay_ms while > 0 \n" 
"    ret     ; return from subroutine  \n"