AVR汇编语言 - 交通灯

时间:2017-05-03 21:58:32

标签: assembly avr

我最近在一个与Arduinos合作的模块中提供了这项任务。我们之前的任务是在C中,但是当谈到这一点时,我根本不知道该怎么做,甚至不知道如何在这种情况下开始。我们也没有提供任何类型的讲座或等等来涵盖这一点。任何人都可以帮助或只是让球滚动一点点,这样我可以更好地理解它吗?谢谢。

我必须编辑的第一段代码如下:

"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 个答案:

答案 0 :(得分:1)

引用的字符串是您停止的asm()调用中的汇编代码。编译时,字符串将按字面转换为相关的汇编指令。

在称为标签后带有冒号:的名称,而函数调用只是跳转到标签。您还可以使用分支指令(例如brne)跳转到函数内,如果之前的结果不是0,则跳转。

asm()来电表示注册" r16"," r17"," r18"," r30",& #34; R 31"全部使用,但眨眼代码似乎只使用" 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"