Advanced Arduino Assembly – Programming Problems
AVR Assembly Programming Problems
Programming Problems
- The following programming problems are designed for the Arduino Uno (ATmega328P) with the CSULB Shield. Programs may be written in AVR Studio 4 or Atmel Studio 6.
- To display code, open in Chrome browser or download (Firefox).
1) In this programing problem you will write the assembly code needed to display a number between 0 and 9 as defined by the least significant 4 switches on your proto-shield (PINC). If the number is greater than 9 turn ON the discrete LED wired to PORTB bit 0, otherwise turn OFF the LED.
I have written much of the code, including calls to subroutines InitShield, WriteDisplay and BCD_to_7SEG. You should be familiar with the first two from your Lab work. The BCD_to_7SEG subroutine takes as input a number between 0 and 9 in register r0. The subroutine then converts the decimal number into its corresponding 7 segments and displays answer.
As you write your program remember that:
- The least significant 4 switches are wired to PINC.
- The error LED is wired to PORTB bit 0
- BCD_to_7SEG’s calling argument is in register r0
- Do not modify r16 when you check to see if it is less than 10
.INCLUDE RST_VECT: rjmp reset .ORG 0x0100 .INCLUDE "spi_shield.inc" reset: ldi r16,low(RAMEND) out SPL,r16 ldi r16,high(RAMEND) out SPH,r16 ; Initialize Proto-shield call InitShield loop: _____ r16, _____ // Read Switches from GPIO Registers _____ r16, 0x___ // clear most significant nibble _____ r16, 0x___ // Is r16 less than 1010? (see notes) _____ ___________ // unsigned conditional branch _____ ______, ___ // error - turn on the LED rjmp ___________ // see the flowchart no_error: _____ ______, ___ // not an error - turn off the LED display: _____ ____, _____ // send argument to subroutine call BCD_to_7SEG // (see notes) call WriteDisplay rjmp ____________
2) Write a subroutine named BlinkIt to complement a variable named blink and to then send the least significant bit (b0)of blink, in SREG bit T, to a subroutine named TestIt. For the purpose of this exam you do not need to save registers on the stack for this question.
.DSEG Blink: .BYTE 1 .CSEG BlinkIt: ______ _________ // load variable to register 16 ______ _________ // do something ______ _________ // store register 16 back to variable ______ _________ // store bit 0 to SREG T bit ______ _________ // call TestIt using relative addressing mode ret
[expand title=”Solution” tag=”h4″]
; ---------------------------------------- ; BlinkIt - TestIt ; Version 1.0 ; Date: 10/24/2014 ; Written By : Khoi Vu ; ---------------------------------------- .INCLUDE .DSEG blink: .BYTE 1 .CSEG .ORG 0x0000 RST_VECT: rjmp reset .ORG 0x0100 .INCLUDE "spi_shield.inc" reset: call InitShield clr spiLEDS // clear discrete LEDs test: rcall BlinkIt rjmp test BlinkIt: lds r16,blink com r16 // complement r16, since blink=0x00, output= 0xFF sts blink,r16 // store back to blink bst r16,0 // store bit 0 of r16 to T rcall TestIt // call TestIt ret TestIt: mov r16,spiLEDS // move LEDs to register 16 sbr r16,0b10000000 // guessing LED is on brts done // since bit 0 of r16 was 1 T=1 so brts is set. it will branch to done cbr r16,0b10000000 // clear r16 if not on done: mov spiLEDS,r16 // move r16 back to LED rcall WriteDisplay // output to display ret
[/expand]
3) The following flowchart defines a subroutine named TestIt which is called by BlinkIt. TestIt therefore accepts the T bit as an argument. We are working with the Arduino Proto-shield (see Proto-shield Schematic). Translate the following flowchart into its equivalent AVR code. Your code must implement the flowchart on the right. For the purpose of this exam you do not need to save any registers on the stack for this question.
TestIt: ______ _________ ______ _________ ______ _________ ; guess bit is set ;execute next line only if t = 0 ______ _________ ; guess is wrong
done: ______ _________ ______ _________ ret

[expand title=”Solution” tag=”h4″]
; ----------------------------------------
; BlinkIt - TestIt
; Version 1.0
; Date: 10/24/2014
; Written By : Khoi Vu
; ----------------------------------------
.INCLUDE
.DSEG
blink: .BYTE 1
.CSEG
.ORG 0x0000
RST_VECT:
rjmp reset
.ORG 0x0100
.INCLUDE "spi_shield.inc"
reset:
call InitShield
clr spiLEDS // clear discrete LEDs
test:
rcall BlinkIt
rjmp test
BlinkIt:
lds r16,blink
com r16 // complement r16, since blink=0x00, output= 0xFF
sts blink,r16 // store back to blink
bst r16,0 // store bit 0 of r16 to T
rcall TestIt // call TestIt
ret
TestIt:
mov r16,spiLEDS // move LEDs to register 16
sbr r16,0b10000000 // guessing LED is on
brts done // since bit 0 of r16 was 1 T=1 so brts is set. it will branch to done
cbr r16,0b10000000 // clear r16 if not on
done:
mov spiLEDS,r16 // move r16 back to LED
rcall WriteDisplay // output to display
ret
[/expand]
4) Given variables A and B, each holding an 8-bit signed 2’s complement number. Write a program to find the maximum value and put into variable C. Example if A > B then C = A.
Option A: Basic implementation of if-then-else statement using load -> do something -> store structure
[expand title=”Solution” tag=”h4″]
/* Given variables A and B, each holding an 8-bit signed 2's complement number,
* write a program to find the maximum value and put into variable C. For
* example if A > B then C = A.
*
* Solution A: Basic implementation of if-then-else statement
* using load -> do something -> store structure
*/
.INCLUDE
.DSEG
A: .BYTE 1
B: .BYTE 1
C: .BYTE 1
.CSEG
Max1:
lds r16,A ; load
lds r17,B
cp r16,r17
brlt elseMax1 ; if (A >= B) note: if A < B branch to else block
mov r18,r16 ; then C = A
rjmp endMax1
elseMax1:
mov r18,r17
sts C,r18 ; store
endMax1:
rjmp Max1
[/expand]
Option B: Basic implementation of if-then-else statement. Structure modified to immediately
[expand title=”Solution” tag=”h4″]
/* Given variables A and B, each holding an 8-bit signed 2's complement number,
* write a program to find the maximum value and put into variable C. For
* example if A > B then C = A.
*
* Solution B: Basic implementation of if-then-else statement.
* Structure modified to immediately store result.
*/
.INCLUDE
.DSEG
A: .BYTE 1
B: .BYTE 1
C: .BYTE 1
.CSEG
Max2:
lds r16,A ; load
lds r17,B
cp r16,r17
brlt elseMax2 ; if (A >= B)
sts C,r16 ; then C = A
rjmp endMax2
elseMax2:
sts C, r17
endMax2:
[/expand]
Option C: If-then-else statement restructured to if-then with guess. Result immediately stored in SRAM.
[expand title=”Solution” tag=”h4″]
/* Given variables A and B, each holding an 8-bit signed 2's complement number,
* write a program to find the maximum value and put into variable C.
* For example if A > B then C = A.
*
* Solution C: if-then-else statement restructured to if-then with guess
* Result immediately stored in SRAM.
*/
.INCLUDE
.DSEG
A: .BYTE 1
B: .BYTE 1
C: .BYTE 1
.CSEG
Max3:
lds r16, A ; load
lds r17, B
sts C, r16 ; guess A > B
cp r16, r17
brge endMax3
sts C, r17
endMax3:
rjmp Max3
[/expand]
5) Given variable A holds an 8-bit signed 2’s complement number. Write a program to find the absolute value A. Save result back into variable A.
A = |A|
[expand title=”Solution” tag=”h4″]
/* Program 2 Given variable A holds an 8-bit signed 2's complement number,
* write a program to find the absolute value A.
* Save result back into variable A.
* A = |A|
*/
.INCLUDE
.DSEG
A: .BYTE 1
.CSEG
Absolute:
lds r16, A ; load
tst r16 ; if (A < 0)
brpl endAbs
neg r16 ; then convert to a positive number
endAbs:
sts A, r16 ; store
rjmp Absolute
[/expand]
6) Write a program to add 8 bit variables A and B together. Store the sum into 8 bit variable C. For this programming problem you may assume that the sum is less than 255 if A and B are unsigned and between -128 and 127 if signed.
C = A + B
[expand title=”Solution” tag=”h4″]
/* Write a program to add 8 bit variables A and B together, * and storing the sum into 8 bit variable C. * For this programming problem you may assume that the sum is less * than 255 if A and B are unsigned and between -128 and 127 if signed. * C = A + B */ .INCLUDE .DSEG A: .BYTE 1 B: .BYTE 1 C: .BYTE 1 .CSEG Adder88: lds r0,A ; load lds r2,B add r0,r2 ; add sts C,r0 ; store rjmp Adder88
[/expand]
7) Write a program to find the sum of unsigned 8 bit variables A and B. For this programming problem the sum may be greater than 255 if A and B. Store the sum into 16 bit variable C using little endian byte ordering.
C = A + B
[expand title=”Solution” tag=”h4″]
/* Write a program to find the sum of 8 bit variables A and B.
* For this programming problem the sum may be greater than 255 if A and B
* are unsigned or less than -128 and greater than 127 if signed.
* Store the sum into 16 bit variable C using little endian byte ordering.
* C = A + B
*/
.INCLUDE
.DSEG
A: .BYTE 1
B: .BYTE 1
C: .BYTE 2
.CSEG
Adder816:
; load
clr r1 ; r1:r0 = 0:A
lds r0,A
clr r3 ; r3:r2 = 0:B
lds r2,B
; add
add r0,r2 ; add least significant bytes
adc r1,r3 ; add with carry most significant bytes
; store
sts C,r0 ; store least significant byte first
sts C+1,r1
rjmp Adder816
[/expand]
8) Write a program to find the sum of signed 8 bit variables A and B. For this programming problem the sum may be less than -128 and greater than 127. Store the sum into 16 bit variable C using little endian byte ordering.
C = A + B
[expand title=”Solution” tag=”h4″]
/* Write a program to find the sum of 8 bit variables A and B.
* For this programming problem the sum may be less than -128 and greater than 127
* Store the sum into 16 bit variable C using little endian byte ordering.
* C = A + B
*/
.INCLUDE
.DSEG
A: .BYTE 1
B: .BYTE 1
C: .BYTE 2
.CSEG
Adder816s:
; load
clr r17 ; 0:A
lds r16,A ; First 8 bits are A
clr r19 ; 0:B
lds r18,B ; First 8 bits are B
; make variables 16-bit
sbrc r16,7
ser r17
sbrc r18,7
ser r19
;add
add r16,r18
adc r17,r19
;store
sts C,r16 ; store the least significant byte
sts C+1,r17 ; store most significant bytes
rjmp Adder816s
[/expand]
9) Multiply 8-bit unsigned variables A and B placing the product into 16-bit variable C. Save the 16-bit product using little endian byte ordering.
C = A x B
[expand title=”Solution” tag=”h4″]
/* Multiply 8-bit unsigned variables A and B placing
* the product into 16-bit variable C.
* Save the 16-bit product using little endian byte ordering.
* C = A x B
*/
.INCLUDE
.DSEG
A: .BYTE 1
B: .BYTE 1
C: .BYTE 2
.CSEG
Mul8x8_16:
lds r16,A ; load
lds r17,B
mul r16,r17
sts C,r0 ; least significant byte (little end)
sts C+1,r1 ; most significant byte (big end)
rjmp Mul8x8_16
[/expand]
10) Given 8-bit variables A and B, each holding an 8-bit unsigned Write a program to find the average of A and B. Place the result into variable C.
Hint: Shifting (or rotating) a binary number to the left divides the number by 2.
[expand title=”Solution” tag=”h4″]
/* Given 8-bit unsigned variables A and B, each holding an 8-bit signed 2's complement number,
* write a program to find the average of A and B and put the result into variable C.
* Hint: Shifting (or rotating) a binary number to the left is equivalent to dividing by 2.
*/
.INCLUDE
.DSEG
A: .BYTE 1
B: .BYTE 1
C: .BYTE 1
.CSEG
Avg:
lds r16, A ; load
lds r17, B
add r16, r17 ; add
ror r16 ; divide by 2 (include carry)
sts C, r16 ; store
rjmp Avg
[/expand]
11) Given 8-bit variables A and B, each holding an 8-bit signed 2’s complement number. Write a program to find the average of A and B. Place the result into variable C.
Hint: Shifting (or rotating) a binary number to the left divides the number by 2.
[expand title=”Solution” tag=”h4″]
/* Given 8-bit variables A and B, each holding
* an 8-bit signed 2's complement number. Write
* a program to find the average of A and B.
* Place the result into variable C.
*/
.INCLUDE
.DSEG
A: .BYTE 1
B: .BYTE 1
C: .BYTE 2
.CSEG
; inputs: 8-bit variables A and B
; output: 16-bit register C
Avg8s:
; load registers A and B
lds r24,A
lds r26,B
; find average C = A+B/2
rcall Adder816s ; C=A+B
; divide by 2
asr r25 ; least significant bit moved to carry bit C
ror r24 ; carry moves into most significant bit of r24
; store the 8 bit result
sts C,r24
clr r25
sts C+1,r25
rjmp Avg8s
; Add two 8-bit signed 2's complement numbers,
; where sum of A and B may be 9 bits
; input: r24 and r26 are two 8-bit numbers
; output: register pair r25:r24 equals sum of r24 and r25
Adder816s:
; make variables 16-bit
clr r25 ; guess r25 is positive 0x00:A
sbrc r24,7 ; if number is positive guess is correct so skip next instruction
ser r25 ; guess incorrect, number is negative 0xFF:A
clr r27
sbrc r26,7
ser r27
;add
add r24,r26
adc r25,r27
;store
sts C,r24 ; store the least significant byte
sts C+1,r25 ; store most significant bytes
ret
[/expand]
12) Write a function named Div8_8 to divide an unsigned 8 bit number by an unsigned 8 bit number. You can find this program in your textbook (Mazidi). Test your function by writing a program named Div8_8test to test the subroutine Div8_8 by dividing the 8-bit-number: 0xAA by the 8-bit-number 0x55.
[expand title=”Solution” tag=”h4″]
; Div8_8
; Version 1.0
; Date: November 11, 2014
; Written By : Yoseph Yegezu
; From text book 'The AVR Microcontroller and Embedded systems'Chapter 5 Page 167
.INCLUDE
.CSEG
.DEF Num=R20
.DEF Denominator=R21
.DEF Quotient=R22
.ORG 0x0000
ldi Num, 0xAA
ldi Denominator, 0x55
//call the 8 bit division
rcall Div8
ret
/************************************
* subroutine divides unside 8bit by 8bit
* Quotient = Numerator/Denominator *
* r22 = r20 / r21
* with remainder in r20 *
************************************/
Div8:
clr Quotient // r22
// quotient is going to increment by 1 everytime L1 loops
// loop L1 stops when the numerator-denominator = less than the demoninator
L1:
inc Quotient
sub Num,Denominator // r20,r21
brcc L1
//since the quotient is incremented by 1 when the loop began, after the loop quotient is dec
dec Quotient
//notice L1 is going to branch off when the numerator is no lnger divisiable by the denominator
//which means L1 is branching off when numerator-denominator results in a negative value.
//therefore, the denominator is going to be added to the numerator after the loop.
add Num,Denominator // r20,r21
ret
[/expand]
13) Write a function named Div16_8 to divide an unsigned 16 bit number by an unsigned 8 bit number. Test your function by writing a program named Div8_test to test the subroutine Div16_8 by dividing the 16-bit-number: 0xAAAA by the 8-bit-number 0x55.
Option A
[expand title=”Solution” tag=”h4″]
/*
* Write a subroutine named Div8 to divide a 16-bit number by an 8-bit number.
* Next, write a program named Div8_test to test the subroutine Div8
* by dividing the 16-bit-number: 0xAAAA by the 8-bit-number 0x55
*
* Q = N/D Divide a 16-bit-number NH:NL by an 8-bit-number Q
*
* Source:
* 1. Binary division in AVR Assembler
* http://www.avr-asm-tutorial.net/avr_en/calc/DIVISION.html
* 2. Integer division (unsigned) with remainder
* http://en.wikipedia.org/wiki/Division_algorithm
*/
.DEF NL = r0 ; LSB 16-bit-number to be divided
.DEF NH = r1 ; MSB 16-bit-number to be divided
.DEF DIV = r3 ; 8-bit-number to divide with
.DEF QL = r4 ; LSB result
.DEF QH = r5 ; MSB result
Div8_test:
ldi r16,0xAA ; 0xAAAA to be divided
mov NH,r16
mov NL,r16
ldi r16,0x55 ; 0x55 to be divided with
mov DIV,r16
rcall Div8
rjmp Div8_test
/* Div8
* Q = N/D Divide a 16-bit-number NH:NL by an 8-bit-number Q
* input
* N = Numerator (dividend)
* D = Denominator (divisor)
* output
* Q = Quotient
*/
Div8:
push r0
push r1
push r2
clr r2 ; clear interim register
clr QH ; QH:QL = 0b0000 0000 0000 0001
clr QL
inc QL
div8a: ; start of the division loop
clc ; clear carry-bit
rol NL ; rotate the next-upper bit of the numerator
rol NH ; to the interim register (multiply by 2)
rol r2
brcs div8b ; a one has rolled left, so subtract
cp r2,DIV ; Division result 1 or 0?
brcs div8c ; jump over subtraction, if smaller
div8b:
sub r2,DIV ; subtract number to divide with
sec ; set carry-bit, result is a 1
rjmp div8d ; jump to shift of the result bit
div8c:
clc ; clear carry-bit, resulting bit is a 0
div8d:
rol QL ; rotate carry-bit into result registers
rol QH
brcc div8a ; as long as zero rotate out of the result
; registers QH:QL go on with the division loop
pop r2
pop r1
pop r0
ret ; End of the division reached
program8:
[/expand]
Option B
This solution is an extension of Div8_8
[expand title=”Solution” tag=”h4″]
; Div16_8B
; Version 1.0
; Date: November 11, 2014
; Written By : Yoseph Yegezu
.INCLUDE
.CSEG
.DEF Denominator=R19
.DEF NL=r24
.DEF NH=r25
.DEF QL=r21
.DEF QH=r22
.ORG 0x0000
ldi r16,0xAA
mov NH,r16
mov NL,r16
ldi Denominator, 0x55
//Call the 16 bit by 8 bit division
rcall Div16_8
ret
/************************************
* subroutine divides unside 16bit by 8bit
* Quotient = Numerator/Denominator *
* r22:r21 = r25:r24 / r19 *
***************************************/
Div16_8:
clr r22
clr r21
// loop L1 stops when the numerator - denominator = less than the demoninator
L1:
//QL is going to increment by 1, everytime L1 loops
inc QL //r22
//When QL reaches 255 or 0XFF and then goes back to 0, QH is going to increment by 1
cpi r21,0
brne No_Inc
inc QH //r22
No_Inc:
sub r24,Denominator // r19
sbc r25,r2
brcc L1
//Since r21 is incremented by 1 when the loop began, after the loop r21 is decremented
dec QL //r21
//Notice L1 is going to branch off when the numerator is no lnger divisiable by the denominator
//Which means L1 is branching off when r24-denominator results in a negative value.
//Therefore, the denominator is going to be added to the r24 after the loop.
add r24,Denominator //r24,r19
adc r25,r2
ret
[/expand]
14) Write a subroutine that convert a temperature reading in Fahrenheit (variable F)to Celsius (variable C).
[expand title=”Solution” tag=”h4″]
; ConvertCtoF
; Version 1.0
; Date: November 11, 2014
; Written By : Yoseph Yegezu
.INCLUDE
.DSEG
C: .BYTE 1
F: .BYTE 1
.CSEG
.DEF Denominator=R19
.DEF Quotient=R22
.ORG 0x0000
//Input a celsius value into r17
TestConvertCtoF:
ldi r17,74
sts C, R17
//call subroutine ConvertCtoF
rcall ConvertCtoF
rjmp TestConvertCtoF
/****************************
* subroutine converts a temperature reading in Celsius (variable C) to Fahrenheit (variable F).
* F=(C × 9/5) + 32 ==(C × 18/10) + 32
* Range for C input is from (0 to 124), since F max is 255
****************************/
ConvertCtoF:
//Load the C value into r18
lds r18, C
//Input the constant value 18 in reg. 16
ldi r16,18
//This part calculates (C*18)
mul r18, r16
//Move the products into r25H and r24L
movw r25:r24, r1:r0
//Input the denominator into r19
ldi Denominator, 10 //r19,10
//Call the 16 bit by 8 bit division
rcall Div16_8
// add 32 to the quotient (18*C)/10 + 32
ldi r26,32
add Quotient,r26 //r22,r26
adc r23,r2
//Store the answer into F
sts F, r22
ret
/************************************
* Quotient = Numerator/Denominator *
* r23:r22 = r25:r24 / r19
* r24 = remainder *
************************************/
Div16_8:
clr r2
clr r23
clr Quotient // r22
// quotient is going to increment by 1 every time L1 loops
// loop L1 stops when the numerator-denominator is less than the demoninator(10)
//(18*C)/10
L1:
inc Quotient
adc r23,r2
sub r24,Denominator // r24,r19
sbc r25,r2
brcc L1
//since the quotient is incremented by 1 when the loop began, after the loop quotient is dec
dec Quotient
sbc r23,r2
//notice L1 is going to branch off when the numerator is no lnger divisiable by the denominator.
//which means L1 is branching off when r24-denominator results in a negative value.
//therefore, the denominator is going to be added to the r24 after the loop.
add r24,Denominator
adc r25,r2
ret
[/expand]
15) Write a subroutine that convert a temperature reading in Celsius (variable C) to Fahrenheit (variable F).
[expand title=”Solution” tag=”h4″]
; ConvertFtoC
; Version 1.0
; Date: November 11, 2014
; Written By : Yoseph Yegezu
.INCLUDE
.DSEG
C: .BYTE 1
F: .BYTE 1
.CSEG
.DEF Denominator=R19
.DEF Quotient=R22
.ORG 0x0000
// Input a Fahrenheit value into r17
TestConvertFtoC:
ldi r17,124
sts F, R17
// Call subroutine ConvertFtoC
rcall ConvertFtoC
rjmp TestConvertFtoC
/****************************
* Subroutine converts a temperature reading in Fahrenheit (variable F) to Celsius (variable C).
* (F - 32) x 5/9 = C
* Range of F (32 to 255) therefore Cmax is 123.8
****************************/
ConvertFtoC:
//Load the F value into r18
lds r18, F
//Input the constant value 18 in reg. 16
ldi r16, 32
//This part calculates (°F-32)
sub r18, r16
ldi r20, 5
//This part calculates (°F-32)*5
mul r18, r20
//Move the products into r25H and r24L
movw r25:r24, r1:r0
//Input the denominator into r19
ldi Denominator, 9
//Call the 16 bit by 8 bit division
rcall Div16_8
sts C, r22
ret
/************************************
* Quotient = Numerator/Denominator *
* r23:r22 = r25:r24 / r19 *
************************************/
Div16_8:
clr r2
clr r23
clr Quotient // r22
// Quotient is going to increment by 1 everytime L1 loops
// Loop L1 stops when the numerator-denominator = less than 10(the demoninator)
// This part calculates (°F-32)*5/9
L1:
inc Quotient
adc r23,r2
sub r24,Denominator // r19
sbc r25,r2
brcc L1
// Since the quotient is incremented by 1 when the loop began, after the loop quotient is dec
dec Quotient
sbc r23,r2
// Notice L1 is going to branch off when the numerator is no lnger divisiable by the denominator.
// Which means L1 is branching off when r24-denominator results in a negative value.
// Therefore, the denominator is going to be added to the r24 after the loop.
add r24,Denominator
adc r25,r2
ret
[/expand]
16) Given variables A, B, and C; each holding an 8-bit unsigned number. Write a program to find the average of A to C, placing the result into variable D.
D = A + B + C / 3
Allow for a 16-bit interim sum and result.
[expand title=”Solution” tag=”h4″]
/* Given variables A, B and C, each holding an 8-bit signed 2's complement number,
* write a program to find the average of A to C, placing the result into variable D.
* D = A + B + C / 3
* Allow for a 16-bit interim sum and result.
* Tip: Copy and paste Div8 subroutine into the AvgABC.asm program.
*/
.INCLUDE
.DSEG
A: .BYTE 1
B: .BYTE 1
C: .BYTE 1
D: .BYTE 2
.CSEG
Setup:
ldi r16, 0x34 ; 52 variable default values
sts A, r16
ldi r16, 0x78 ; 120
sts B, r16
ldi r16, 0xBC ; 188
sts C, r16 ; sum = 0x168 (360), average = 0x78 (120)
AvgABC:
; load
clr r1 ; r1:r0 = 0:C
lds r0,A
clr r3 ; r3:r2 = 0:B
lds r2,B
clr r5 ; r5:r4 = 0:A
lds r4,C
add r0,r2 ; A = A + B
adc r1,r3
add r0,r4 ; A = A + C
adc r1,r5
; numerator r1:r0 = A + B + C
ldi r16,3 ; divisor /r2 = /3
mov r3,r16
rcall Div8 ; quotient r4:r3 = r1:r0 / r2
sts D,r4
rjmp AvgABC
/* Div8
* Q = N/D Divide a 16-bit-number NH:NL by an 8-bit-number Q
* input
* N = Numerator (dividend)
* D = Denominator (divisor)
* output
* Q = Quotient
*/
.DEF NL = r0 ; LSB 16-bit-number to be divided
.DEF NH = r1 ; MSB 16-bit-number to be divided
.DEF DIV = r3 ; 8-bit-number to divide with
.DEF QL = r4 ; LSB result
.DEF QH = r5 ; MSB result
Div8:
push r0
push r1
push r2
clr r2 ; clear interim register
clr QH ; QH:QL = 0b0000 0000 0000 0001
clr QL
inc QL
div8a: ; start of the division loop
clc ; clear carry-bit
rol NL ; rotate the next-upper bit of the numerator
rol NH ; to the interim register (multiply by 2)
rol r2
brcs div8b ; a one has rolled left, so subtract
cp r2,DIV ; Division result 1 or 0?
brcs div8c ; jump over subtraction, if smaller
div8b:
sub r2,DIV ; subtract number to divide with
sec ; set carry-bit, result is a 1
rjmp div8d ; jump to shift of the result bit
div8c:
clc ; clear carry-bit, resulting bit is a 0
div8d:
rol QL ; rotate carry-bit into result registers
rol QH
brcc div8a ; as long as zero rotate out of the result
; registers QH:QL go on with the division loop
pop r2
pop r1
pop r0
ret ; End of the division reached
[/expand]
More Problems to be added…
Practice Problems: Interrupts
- Initialize Interrupt 1 (INT1) pin to generate an Interrupt on a rising edge. Set all unused bits to default values.
_____ R16, 0x____
_____ EICRA, R16 - Initialize Interrupt 0 (INT0) pin to generate an Interrupt on a falling edge. Do not change the other bits (ISC11, ISC10) in the External Interrupt Control Register A (EICRA). You should assume the previous code (problem 1) has been written (i.e., bits 1 and 0 cleared)
_____ R16, EICRA
_____ R16, 0x____
_____ EICRA, R16 - Configure Pin 15 PB1 (OC1A/PCINT1) to generate an Interrupt whenever the pin changes state. Do not change any other bits. To make things more interesting, do not use the SBR instruction.
_____ R16, PCMSK0 ; load
_____ R17, PCICR
_____ R18, SREG
_____ R16, 0x ; do something
_____ R17, 0x____
_____ R18, 0x____
_____ PCMSK0, R16 ; store
_____ PCICR, R17
_____ SREG, R18




















