2017-05-03 5 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() 호출 내부의 어셈블리 코드입니다. 컴파일되면 문자열이 문자 그대로 관련 어셈블리 명령어로 변환됩니다.

레이블을 호출 한 후 콜론 :의 이름이며 함수 호출은 바로 레이블로 건너 뜁니다.

asm() 호출은 "r16", "r17", "r18", "r30"등의 레지스터를 가리킨다는 것을 나타내며, 분기 결과가 brne과 같은 분기 명령어 인 함수 내에서 이동할 수 있습니다. "r31"이 모두 사용되었지만 깜박임 코드는 "r18", "r30", "r31"만 사용하는 것처럼 보입니다. 즉, 지연 코드에서 "r16"과 "r17"을 사용하려고합니다.

지연 코드 지금까지 두 번 레지스터 R31의 값 카운트 다운 단지 루프 :

"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에 도달 할 때까지 루프의 상단에 R30은 .

1 밀리 초가 걸릴 루프를 계산하는 코드를 루프 내에 삽입해야합니다. 숫자를 결정하려면 클럭 속도를 알아야합니다. ldi을 사용하고 즉시로드한다는 점을 제외하고는 지연 카운트가 설정되는 것과 마찬가지로 r17 : r16을 카운트에 사용하십시오.

"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"