T
h
e
H
o
l
y
G
u
'
r
a
n
2017 MIDTERM
1A) Write an instruction to add the
two 8-bit numbers stored in
program memory at
0x100A and 0x100F together and
leave the sum in the data memory at
0x2000.
ANS:
ldi ZL,0x0A
ldi ZH,0x10
ldi YL,0x00
ldi YL,0x20
lpm r0,Z
lpm r1,Z+5
add r1,r0
st Y,r1
1B) Write a sequence of
instructions to subtract 100 from
data memory locations at 0x200A.
ANS:
ldi YL,0x0A
ldi YH,0x20
ldi r20,100
ld r0,Y
sub r0,r20
st Y,r0
2A) Write a macro to find the square
of the value from register R16, and
store the results in R17 (MSB Byte)
and R18 (LSB byte), respectively.
ANS:
.macro squarer16
Mov @1, @0
mul @0, @1
mov @1, r0
mov @2, r1
.endmacro
2B) Invoke the micro defined in a to
calculate square of 5
ANS:
ldi r16,5
Squarer16 R16,R17,R18
3) Read following program and
determine the value of r16, r17 and
r18 when the program is done.
.include <m2560def.inc>
.def count = r16
.def lpcnt = r17
.equ NN = 40
.cseg
.org 0x00
rjmp start
.org 0xF6
start: ldi ZL,low(array<<1)
ldi ZH,high(array<<1) "
ldi count,0 ;
ldi lpcnt,NN
loop: cpi lpcnt,0
breq done
lpm r18,z+ ;
andi r18,0x07 ;
brne next ;
inc count ;
next: dec lpcnt ;
rjmp loop
done: rjmp done
array: .db 1,2,3,4,5,6,7,8,9,10
.db 11,12,13,14,15,16,17,18,19,20
.db 21,22,23,24,25,26,27,28,29,30
.db 31,32,33,34,35,36,37,38,39,40
// end of program
ANS:
R16 → 0x05.
R17 → 0x00
R18 → 0x00
4) Write a C function to test whether
an integer between 100 and 1000 is
a prime number.
ANS:
#include <avr\io.h>
unsigned int prim_num[6]; // array for
prime numbers
#define yes 1
#define no 0
char isprime(unsigned int x);
unsigned char sqroot(unsigned int y);
void main(void)
{
unsigned count;
unsigned int testnum; // no. to be
tested
testnum = 999; // first number to be
tested for prime under 1000
count = 450; // total tests
while (count)
{
if (isprime(testnum)) // if the
number is prime, then save it
{
prim_num[i] = testnum;
}
testnum -= 2;
count--;
}
while (1);
}
//-------------------------------// This function tests whether the
unsigned integer k is a prime number.
char isprime(unsigned int k)
{
int i;
char limit;
if (k < 2)
return 0;
else if (k < 4)
return 1;
limit = sqroot(k); // use the square
root as prime test limit
for (i = 2; i <= limit; i++)
{
if ((k % i) == 0)
return 0; // divisible?
}
return 1;
ANS:
.include <m644Adef.inc>
.equ FSTEP1 = 0x0C
.equ FSTEP2 = 0x06
}
.equ FSTEP3 = 0x03
//-------------------------------.equ FSTEP4 = 0x09
// This function finds the closest
FSccw: ldi r20,FSTEP4
integral square root of the unsigned
out PORTA,r20
integer y.
rcall wait10ms
unsigned char sqroot(unsigned int y)
ldi r20,FSTEP3
{
out PORTA,r20
unsigned int i, sar, mask, test;
rcall wait10ms
sar = 0;
ldi r20,FSTEP2
mask = 0x80;
out PORTA,r20
for (i = 0; i < 8; i++)
rcall wait10ms
{
ldi r20,FSTEP1
test = sar | mask;
out PORTA,r20
if ((test * test) <= y)
rcall wait10ms
sar = test;
ret
mask = mask >> 1;
10) Configure even interrupt pins
}
(INTn) to interrupt on the rising
if ((y - sar * sar) < ((sar + 1) * (sar + edge and the odd interrupt pins to
1) - y))
interrupt on the falling edge.
return sar;
ANS:
else
ldi r16,0xBB
return (sar + 1);
sts EICRA,r16
5) Execute each following
sts EICRB,r16
instruction and write out the new Rd ldi r16,0xFF
value assume carry has the value of sts EIMSK,r16
1. And Rd=11001100
sei
ANS:
BQ1) Which of following timer is 8
A) lsl Rd
bit timer?
Rd→10011000 C→1
(a) timer 1 (b) timer 2
B) lsr Rd
(c) timer 3
Rd→01100110 C→0
BQ2) Which of following timer has
C) rol Rd
input capture function?
Rd→10011001 C→1
(a) timer 0 (b) timer 1
D) ror Rd Rd→11100110 C→0
(c) timer 2
E) asr Rd Rd→11100110 C→1
BQ3) How many interrupt sources
F) swap Rd Rd→11001100 C→1
does timer 1 have?(a) 3 (b) 4 (c) 5
G) inc Rd Rd→11001101 C→1
BQ4) How many operation modes
H) push Rd Rd→11001100 C→1
does timer 1 have?(a) 8 (b) 16 (c) 5
I) ser Rd
BQ5) What can CTC mode do?(a)
Rd→11111111 C→1
measure duty cycle (b) measure
J) dec Rd
signal period (c) create delay
Rd→11001011 C→1
2018 MIDTERM
6) What are the contents of PORTA 1) Write an instruction sequence to
after the following AVR program is
add the 24-bit value stored at data
assembled:
memory locations
0x2000~0x2002 and the 24-bit value
ldi r16, 1<<1
andi r16, 0x0F
stored at data memory locations
out PORTA, r16
0x2010~0x2012 and store the sum
ANS:
at data memory locations
0x2020~0x2022.
PortA=0x02
7) Write an ASM subroutine to
ANS:
𝟏𝟎𝟎
ldi YH,0x20
calculate S where 𝑺 = ∑𝑲=𝟏 𝑲
ldi YL,0
ANS:
ld r0,Y
.include "m644Adef.inc"
ldd r1,Y+0x10
.def lpcnt = r17
ldd r2,Y+1
.def SUMH = r25
ldd r3,Y+0x11
.def SUML = r24
ldd r4,Y+2
.equ NN = 100
ldd r5,Y+0x12
.cseg
add r0,r1
.org 0x00
adc r2,r3
rjmp start
adc r4,r5
.org 0xF6
std Y+0x20,r0
start: ldi lpcnt,NN
std Y+0x21,r2
ldi r24,0
std Y+0x22,r4
ldi r25,0
2A) Write a sequence of
loop: cpi lpcnt,0
instructions to copy the four bytes
breq done
from program memory locations
add suml,lpcnt
0x2000 ~ 0x2003 to data memory
adc sumh,r16
locations at 0x2000 ~0x2003,
dec lpcnt
respectively.
rjmp loop
ANS:
done: rjmp done
Ldi YL,0x00
8) Write an ASM subroutine to find
ldi YH,0x20
numbers of elements in a program
ldi ZL,0x00
array that are odd integers.
ldi ZH,0x20
ANS:
lpm r0,Z+
.include <m2560def.inc>
st Y+,r0
.def count = r16
lpm r0,Z+
.def lpcnt = r17
st Y+,r0
.equ NN = 40
lpm r0,Z+
.cseg
st Y,r0
.org 0x00
lpm r0,Z
rjmp start
st Y,r0
.org 0xF6
2B) Write a sequence of
start: ldi ZL,low(array<<1)
instructions to subtract 5 from data
ldi ZH,high(array<<1)
memory locations at
ldi count,0
0x2000~0x2003,
ldi lpcnt,NN
respectively.
loop: cpi lpcnt,0
ANS:
breq done
ldi YL,0x00
lpm r18,z+
ldi YH,0x20
andi r18,0x01
ldi r20,5
brne next
ld r0,Y
inc count
sub r0,r20
next: dec lpcnt
st Y,r0
rjmp loop
ldd r0,Y+1
done: rjmp done
sub r0,r20
array: .db 1,2,3,4,5,6,7,8,9,10
std Y+1,r0
.db 11,12,13,14,15,16,17,18,19,20
ldd r0,Y+2
.db 21,22,23,24,25,26,27,28,29,30
sub r0,r20
.db 31,32,33,34,35,36,37,38,39,40
std Y+2,r0
// end of program
ldd r0,Y+3
9) Write a subroutine that rotates
sub r0,r20
the stepper motor shown in figure
std Y+3,r0
counterclockwise in full steps.
Assume the subroutine for delay is 3) Read following program and
determine the value of r16, r17, r18,
available delayby10ms
N1 and N2 when the program is
done.
.equ N1 = 0
.equ N2 = 30
.def ii = r16
.def count = r17
.def tmp = r18
.macro setPointer
ldi @0,low(@2)
ldi @1,high(@2)
.endmacro
.cseg
.org 0x00
rjmp start
.org 0xF6
start: clr ii
clr count
ldi tmp,15
setPointer ZL,ZH,(array<<1)
floop: cpi ii,N2
breq done
lpm r0,z+
cp tmp,r0
brlt yes
rjmp next
yes: inc count
next: inc ii
rjmp floop
done: rjmp done
array: .db
10,11,12,13,14,15,16,17,18,19
.db 50,21,22,23,24,25,26,27,28,29
.db 30,31,32,33,34,35,36,37,38,39
ANS:
r16→0x1E N1→0b
r17→0x18 N2→11110b
r18→0x0F
4) Write a loop in c to compute the
sum of the square of the first one
hundred odd numbers.
ANS:
long int oddSum;
int ix;
oddSum = 0;
for (ix = 1; ix < 201; ix++2){
oddSum += (unsigned long)ix *
(unsigned long)ix;
}
5) Write a program in ASM to
compute the sum of the square of
the first one hundred odd numbers.
ANS:
.include <m2560def.inc>
.equ n1 = 1
.equ n2 =200
.dseg
.org 0x200
sum: .byte 2
.def ii = r16
.def sumTH = r20; third data byte
.def sumHi = r19
.def sumLo = r18
.cseg
.org 0x00
jmp start
.org 0xF6
start: ldi ii,n1 ; initialize ii to n1
ldi sumTH,0 ;
ldi sumHi,0 ; initialize sum to 0
ldi sumLo,0 ; "
ldi r25,0 ; place 0 in r25 for use in the
for-loop
loop: cpi ii,n2+1 ; check for-loop index
limit
breq done ; "
mul ii,ii
add sumLo,r0 ; add ii to the low byte of
sum
adc sumHi,r1 ; add carry to high byte
(r25 holds 0)
adc sumTH, r25
inc ii
inc ii
rjmp loop
done: sts sum,sumLo ; save the sum
in data memory
sts sum+1,sumHi ; "
rjmp done
// end of program
6) Write a subroutine that can divide
an 8-bit unsigned integer into
another 8-bit unsigned integer and
write a testing main program for it.
ANS:
.equ dd0 = 0x1F
.equ dr0 = 0x09
.cseg
.org 0x00
rjmp start
.org 0xF6
start:
ldi r28,dr0 ; "
ldi r16,
call div8U ;
nop
forever: rjmp forever
*****************************
.def lpcnt = r21
.def tmp0 = r8
div8U: ldi lpcnt,8
mov r22,r16
clr r16
dvloop8: lsl r22
rol r16
mov tmp0,r16
sub tmp0,r28
brmi less8
mov r16,tmp0
ori r22,0x01
rjmp nextb
less8: andi r22,0xFE
nextb: dec lpcnt
brne dvloop8
ret
// End of program
7) What are the contents of PORTA
after the following AVR program is
assembled.
Please write the content of PORTA
binary value for line 4, 5, 8
respectively.
ANS:
LN||Instruction
(1) ldi r16, 0xFF
(2) out DDRA, r16
(3) ldi r16, 0x33
(4) out PORTA, r16 00110011b
(5) cbi PORTA , 1 00110001b
(6) sbi PORTA, 0 00110001b
(7) swap r16
(8) out PORTA, r16 00110011b
8) Use the AVR Mega PORTB to
drive seven -segment display. Write
a subroutine to display
decimal 5.
lds R2,0x105
lds R3, 0x205
mul R3,R2
sts 0x305,R0
sts 0x306,R1
2) Read following
program and determine
the hexadecimal value of
r16, r18 and r19 when the
program is done.
.include “./m328Pdef.inc”
.equ n1 = 1
.equ n2 = 50
.dseg
.org 0x200
sum: .byte 2
.def ii = r16
.def sumHi = r19
.def sumLo = r18
ANS:
.cseg
ldi r16, 0xFF
.org 0x00
out DDRB, r16
jmp start
ldi r16, 0x5B
.org 0xF6
out PORTB, r16
start: ldi ii,n1
9) Write a sequence of ASM
ldi sumHi,0
statements to configure PCINT1,
ldi sumLo,0
PCINT2, PCINT3, PCINT4, PCINT5,
ldi r25,0
PCINT11, PCINT12, PCINT13,
loop: cpi ii,n2+1
PCINT14 and PCINT15 to interrupt
breq done
the MEGA CPU.
add sumLo,ii
ANS:
adc sumHi,r25
ldi r16, 0x03
inc ii
sts PCICR, r16
rjmp loop
ldi r16, 0x3E
done: sts sum,sumLo
sts PCMSK0, r16
sts sum+1,sumHi
ldi r16, 0xF8
rjmp done
sts PCMSK1, r16
// end of program
sei
10) Following subroutine rotates the ANS
r16=0x33, r18=0xfb,
stepper motor shown in figure
r19=0x04
clockwise in full steps. assume
3) Write a complete program to shift
wait10ms subroutine is available.
the 32-bit number from program
Please found out the errors in the
memory with
subroutine.
address array to the left four places
and store the results at
0x200~0x203 in data
memory. The MSB to LSB are
stored from 0x203 toward 0x200,
respectively.
ANS
.include “./m328Pdef.inc”
.macro setPointer
ldi @0,low(@2)
ldi @1,high(@2)
.endmacro
.def lpcnt=r16
.dseg
.org 0x200
buf: .byte 4
.cseg
.equ FSTEP1 = 0x0C
.org 0x00
.equ FSTEP2 = 0x06
rjmp start
.equ FSTEP3 = 0x03
.org 0xF6
.equ FSTEP4 = 0x08
start: setPointer ZL,ZH,(array<<1)
.def temp = r20
ldi lpcnt,4
FScw ldi temp,FSTEP1
lpm r0,z+
out PORTA,temp
lpm r1,z+
rcall wait10ms
lpm r2,z+
ldi temp,FSTEP2
lpm r3,z
out PORTB,temp
slLoop: lsl r0
rcall wait10ms
rol r1
ldi temp,FSTEP3
rol r2
out PORTA,temp
rol r3
rcall wait10ms
dec lpcnt
ldi temp,FSTEP4
brne slLoop
out PORTA,temp
sts buf,r0
rcall wait10ms
sts buf+1,r1
reti
sts buf+2,r2
ANS
sts buf+3,r3
.equ FSTEP1 = 0x0C
nop
.equ FSTEP2 = 0x06
array: .db 0x23,0x34,0x45,0x56
.equ FSTEP3 = 0x03
// end of program
.equ FSTEP4 = 0x09
4) What are the contents of PORTA
----------------------after the following AVR program is
rotates clockwise in full step
assembled:
sequence.
in r16, PORTB
---------------------------------ori r16, 0x03
.def temp = r20
out PORTB, r16
FScw: ldi temp,FSTEP1
ANS
out PORTA,temp
set bit 1 and bit 0 of PORTB to 1
rcall wait10ms
5) Write an ASM subroutine to find
ldi temp,FSTEP2
numbers of elements in an array
out PORTA,temp
that are a
rcall wait10ms
multiple of 16.
ldi temp,FSTEP3
ANS
out PORTA,temp
.include “./m328Pdef.inc”
rcall wait10ms
.equ NN = 30
ldi temp,FSTEP4
.def j = r16
out PORTA,temp
.def Cnt = r17
rcall wait10ms
.def tmp = r18
ret
.cseg
2019 MIDTERM.
.org 0x00
1A) Use the byte
rjmp start
directive to reserve 15
.org 0xF6
bytes in the data
start: ldi ZL,low(array<<1)
memory and write a
ldi ZH,high(array<<1)
instructions to load the
ldi j,0
first byte of this buffer
ldi Cnt,0
into register R16
loop: lpm tmp,z+
ANS
andi tmp, 0x0f
.dseg
brne next
buf: .byte 15
inc Cnt
.cseg
next: inc j
ldi YL, low(buf)
cpi j,NN-1
ldi YH, high(buf)
brne loop
ld R16,Y
ldi Xl,0x00
1B) Write instruction to
ldi XH,0x10
multiply content of data
mov X,Cnt
memory location at
here: rjmp here
0x105,0x205 and store at
array: .db
0x305 and 0x306.
11,12,13,14,15,16,17,18,19,20
ANS
.db 21,22,23,24,25,26,27,28,29,30
.db 31,92,33,34,35,67,40,50,52,99
// end of program
6) Use the AVR Mega PORTE to
drive eight LEDs and output the
value 0x99 to
PORTE. Write code both in
assembling and C.
ANS
ldi r16,0xFF
out DDRE,r16
ldi r16,0x99
sts PORTE,r16
DDRE=0xFF;
PORTE=0x99;
********C Code************
7) Write a sequence of ASM
statements to configure PCINT3,
PCINT4, PCINT7,
PCINT11, PCINT12, PCINT15,
PCINT17, PCINT19, and PCINT22 to
interrupt the
MEGA CPU.
ANS
PCMSK2 = 0x4A
PCMSK1 = 0x98
PCMSK0 = 0x98
PCICR = 0x07
sei()
8) Write a C program function
creates a time delay that is a
multiple of 10 ms using
Timer 1 OC1A function.
ANS
void delayby10msOC(unsigned char k)
{
TCCR1A = 0;
TCCR1B = 0x02;
OCR1A = TCNT1 + 20000;
TIFR1 = 1 << OCF1A;
while (k) {
while (!(TIFR1 & (1 << OCF1A)));
OCR1A += 20000;
TIFR1 = 1 << OCF1A;
k--;
}
}
2022 MIDTERM
1A) Load the contents of program
memory location at the address
0x1000 into R1. Then store the R1
content at data memory location at
the address 0x2000, using data
indirect mode.
ANS
ldi ZL,0x00
ldi ZH,0x10
lpm R1, Z
ldi XL, 0x00
ldi XH, 0x20
st X, R1
1B) Write an instruction sequence
to add the 16-bit value stored at
data memory locations
0x3000~0x3001 and the 16-bit value
stored at data memory locations
0x3010~0x3011 and store the sum
at data memory locations
0x3020~0x3021. (Lower byte of the
16 bit will be stored at the lower
address)
ANS
ldi YH,0x30
ldi YL,0x00
ld r0,Y
ldd r1,Y+0x10
ldd r2,Y+1
ldd r3,Y+0x11
add r0,r1
adc r2,r3
std Y+0x20,r0
std Y+0x21,r2
2) Write a macro to find the sum of
X and Y and store the results at R0
(lower byte) and R1 (higher byte).
ANS
.macro sumxy
Mov R0, XL
Add R0, YL
Mov R1, XH
ADC R1, YH
.endmacro
sumxy
3) Assume that the contents of
register R0 and carry flag are 0xF9
and 0, respectively. What are the
new values for R0 and C after the
execution of each of the
instructions listed in Table.
ANS
Lsl R0 R0→0xF2 C→1
Lsr R0 R0→0x7C C→1
Rol R0 R0→0xF2 C→1
Ror R0 R0→0x7C C-->1
Asr R0 R0→0xFC C→1
4) Write a C loop to compute the
sum of the square of the first one
hundred even numbers.
ANS:
long int evenSum;
int ix;
evenSum = 0;
for (ix = 2; ix < 202; ix += 2) {
evenSum += (unsigned long)ix *
(unsigned long)ix;
}
5) Read following program and
determine the Hex value of r16, r17
and r18 when the program is done.
.include "./m328Pdef.inc"
.equ NN = 40
.def j = r16
.def maxVal = r17
.def tmp = r18
.cseg
.org 0x00
rjmp start
.org 0xF6
start:ldi ZL, low(array<<1)
ldi ZH, high(array<<1)
ldi j, 0
lpm maxVal, Z+ ; Load program
memory into maxVal
loop:lpm tmp, Z+
cp tmp, maxVal
brlt next ; If tmp < maxVal, branch to
next
mov maxVal, tmp ; Otherwise, update
maxVal
next:inc j
cpi j, NN-1
brne loop
here:rjmp here
array:
.db 11,12,13,14,15,16,17,18,19,20
.db 21,22,23,24,25,26,27,28,29,30
.db 31,92,33,34,35,67,40,50,52,99
.db 41,42,43,44,45,46,47,48,49,50
ANS
r16=0x27, r17=0x63, r18=0x32
Q6) Use the AVR Mega PORTC to
drive seven-segment displays. Write
both instructions in assembling
code and C to show 3 on display.
ANS:
************asm***********
ldi r16,0xFF
out DDRC, r16
ldi r16, 0x79
out PORTC, r16
***********C code**********
DDRC = 0xFF;
PORTC = 0x79;
Q7) Following subroutine rotates the
stepper motor shown in figure
clockwise in full steps. Assume
wait10ms subroutine is available.
Please found out the errors in the
subroutine.
.equ FSTEP1 = 0x0C
.equ FSTEP2 = 0x06
.equ FSTEP3 = 0x03
.equ FSTEP4 = 0x08
.def temp = r20
FScw: ldi temp,FSTEP1
out PORTA,temp
rcall wait10ms
ldi temp,FSTEP2
out PORTA,temp
rcall wait10ms
ldi temp,FSTEP3
out PORTC,temp
rcall wait10ms
ldi temp,FSTEP4
out PORTC,temp
rcall wait10ms
reti
ANS
.equ FSTEP4 = 0x08
FScw: ldi temp,FSTEP1
out PORTC,temp
out PORTC,temp
reti
Q8) Write a complete program to
find the numbers of elements in an
array that a multiple of 8. Following
array will be in program memory.
ANS
.db 11,12,13,14,15,16,17,18,19,20
.db 21,22,23,24,25,26,27,28,29,30
.db 31,92,33,34,35,67,40,50,52,99
.db 41,42,43,44,45,46,47,48,49,50
.include "./m328Pdef.inc"
.equ NN = 40
.def j = r16
.def num = r17
.def tmp = r18
.cseg
.org 0x00
rjmp start
.org 0xF6
start:ldi ZL, low(array<<1)
ldi ZH, high(array<<1)
ldi j, 0
ldi num, 0
loop:lpm tmp, z+
andi tmp, 0x07
brne next
inc num
next:inc j
cpi j, NN-1
brne loop
here:rjmp hereZ
PUT LIST AGAIN !!
Q9) Configure odd interrupt pins
(INTn) to interrupt on the rising
edge and the even interrupt pins to
interrupt on the falling edge.
ANS
Each interrupt pin (eight in total) uses
two bits to configure the interrupt
edge. The following instruction
sequence will configure the odd
interrupt pins to interrupt on the rising
edge and the even interrupt pins to
interrupt on the falling edge:
ldi r16,0xEE
sts EICRA,r16
sts EICRB,r16
ldi r16,0xFF
sts EIMSK,r16
sei
Q10) What is the different between
8-bit timer and 16-bit timer?
ANS
program to find the total elements of
an array of 8-bit integers that have bit
2, 3, and 4 set to 1. Use the repeatuntil looping construct. Assume the
array is in the program memory.
.include <m2560def.inc>
.def count = r16
.def lpcnt = r17
.def temp=r18
.equ NN = 30
.cseg
.org 0x00
rjmp start
.org 0xF6
start: ldi ZL,low(array<<1)
ldi ZH,high(array<<1)
ldi count,0
ldi lpcnt,NN
loop: lpm temp,z+
andi temp,0x1C
cpi temp,0x1C
brne next
inc count
next: dec lpcnt
brne loop
done: rjmp done
array:
.db11,12,13,14,15,16,17,18,19,20
.db 21,22,23,24,25,26,27,28,29,30
.db 31,32,33,34,35,36,37,38,39,40
E3.11 Write a program to swap the
upper 4 bits with the lower 4 bits of
every element of an array of 8-bit
integers. The initial array is stored in
the program memory and you must
copy this array to the data memory for
testing purpose
.include <m2560def.inc>
.equ NN=30
.dseg
.org 0x200
buf1: .byteNN
.def lpcnt = r17
.cseg
.org 0x00
rjmp start
.org 0xF6
start: ldi XL,low(buf1)
ldi XH,high(buf1)
ldi ZL,low(array<<1)
ldi ZH,high(array<<1)
ldi lpcnt,NN
cloop: lpm r0,z+
swap r0
st x+,r0
dec lpcnt
brne cloop
here: rjmp here
array:
.db0x11,0x12,0x13,0x14,0x15,0x16,0x
17,0x18,0x19,0x20
.db0x21,0x22,0x23,0x24,0x25,0x26,0x
27,0x28,0x29,0x30
.db0x31,0x32,0x33,0x34,0x35,0x36,
else if(((ax%6) == 1) && ((ax%7) ==
0))
return 1;
else
return 0;}
2023 Midterm
1) This problem has following two
sub problems:
a. Write an instruction sequence to
swap the contents of data memory
locations at
0x3FFA and 0x3FFF.
[6 points]
Solution: The following instruction
sequence will perform the swap
operation:
ldi YL,0xFA ; let Y point to data
memory location 0x3FFA
ldi YH,0x3F ; "
ld r0,Y ; place the contents of data
memory location 0x3FFA in r0
ldd r1,Y+5 ; place the contents of data
memory location 0x3FFF in r1
st Y,r1 ; perform the swap
std Y+5,r0 ; "
b. Write a sequence of instructions
to subtract 32 from data memory
locations at 0x21FF, 0x21FA, and
0x21F5, respectively.
ldi YL,0xF5 ; use Y to point to data
memory location 0x21F5
ldi YH,0x21 ; "
ldi r20,32 ; place 32 in r20
ld r0,Y ; fetch data memory location
0x21F5
sub r0,r20 ; subtract 32 from data
memory location 0x21F5
st Y,r0 ; save the difference back to
data memory location 0x21F5
ldd r0,Y+5 ; fetch data memory
location 0x20FA
sub r0,r20 ; subtract 32 from 0x20FA
std Y+5,r0 ; "
ldd r0,Y+10; fetch data memory
location 0x21FF
sub r0,r20 ; subtract 32 from data
memory location 0x21FF
std Y+10,r0 ; "
2) Write a program to add the 32-bit
numbers stored at data memory
locations 0x3000~0x3003 and
0x3004~0x3007, respectively, and
store the sum at 0x3008~0x300B.
Please use Y pointer to load and
store data.
include “./m328Pdef.inc”
.cseg
.org 0x00
rjmp start
.org 0xF6
start:
Ldi YL, 0x00
Ldi YH, 0x30
ld r0,Y ; fetch the lsbs
ldd r1,Y+4 ; "
add r0,r1 ; add them
std Y+8,r0 ; save the lsb of sum
ldd r0,Y+1 ;
ldd r1,Y+5 ; "
adc r0,r1 ; add them
std Y+9,r0 ; save sum
//
ldd r0,Y+2 ;
ldd r1,Y+6 ; "
adc r0,r1 ; add them
std Y+10,r0 ;
//
ldd r0,Y+3 ; fetch the msbs
ldd r1,Y+7 ; "
adc r0,r1 ; add them
std Y+11,r0 ; save the msb of sum
Here: jmp Here
// end of program
3) Write a program to set the bit 6
and bit 0 of all the elements of an
array to 1. The initial array is
stored in the program memory and
you must copy this array to the data
memory for testing
purpose. Following Macro has to be
used in the program:
macro setPointer
ldi @0,low(@2)
ldi @1,high(@2)
.endmacro
.include “./m328Pdef.inc”
.macro setPointer
ldi @0,low(@2)
ldi @1,high(@2)
.endmacro
.def lpcnt=r16 ; loop count for
performing left-shifting
.def tmp = r17
.equ NN=20
.dseg
.org 0x200
buffer: .byte 30
.cseg
.org 0x00
rjmp start
.org 0xF6
start: ldi lpcnt,NN
setPointer ZL,ZH,(tstdat<<1) ; Z is the
pointer to test data
setPointer XL,XH,buffer
again: lpm tmp,z+ ; read one array
element
ori tmp,0x41 ; set bit 6 and bit 0 to 1
st x+,tmp ; store the result in
destination
dec lpcnt
brne again
Here: jmp Here
tstdat: .db
0x12,0x14,0x16,0x26,0x35,0x33,0x18,
0x46,0x56,0x38
.db
0x2A,0x3B,0x4A,0x5C,0x6C,0x78,0x7
8,0x82,0x6A,0x5C
// end of the program
4) Write a function that converts a
lowercase letter to uppercase and
then write a main program to
test the function.
Solution:
#include <io.h>
unsigned char low2upper(unsigned
char cx);
unsigned char carr [] =
{'a','b','c','d','e','f'};
void main (void)
{
unsigned char i;
for (i = 0; i < 6; i++){
carr[i] = low2upper(carr[i]);
}
while(1);
}
unsigned char low2upper(unsigned
char cx)
{
if ((cx > 0x60) && (cx < 0x7B))
cx &= 0xDF;
return cx;
}
5) Read the following program and
determine the Hex value of r0, r1, r2,
r3, lpcnt, YL, YH when
the program is done.
.include "./m328Pdef.inc"
.macro setPointer
ldi @0,low(@2)
ldi @1,high(@2)
.endmacro
.def lpcnt=r16
.dseg
.org 0x200
buf: .byte 4
.cseg
.org 0x00
rjmp start
.org 0xF6
start:
setPointer ZL,ZH,(array<<1)
setPointer YL,YH,(buf<<0)
ldi lpcnt,4
lpm r0,z+ ;
lpm r1,z+ ; "
lpm r2,z+ ; "
lpm r3,z ; "
slLoop:lsl r0 ;
rol r1 ;
rol r2 ;
rol r3 ;
dec lpcnt
brne slLoop
st Y,r0 ;
std Y+1,r1
std Y+2,r2
std Y+3,r3 ;
Here: jmp Here
array: .db 0x23,0x34,0x45,0x56
// end of program
6) Write an assembling program to
display the following patterns from
the seven-segment display
circuit shown in Figure from display
#5 to #0,
123456
.include "./m328Pdef.inc"
.def digCnt = r21
.cseg
.org 0x00
rjmp start
.org 0xF6
start: ldi ZL,low(segTable << 1)
ldi ZH,high(segTable << 1)
repLp: ldi digCnt,6 ; six digits
digLp: lpm r16,z+
out PORTC,r16 ; output segment
pattern
lpm r16,z+
out PORTB,r16 ; output digit select
ldi r16,1
dec digCnt
brne digLp ; reach the end of a
sequence?
forever: jmp forever
segTable: .db
0x30,0xDF,0x6D,0xEF,0x79,0xF7,0x3
3,0xFB,0x5B,0xFD,0x5F,0xFE
7) Write a subroutine that rotates
the stepper motor shown in Figure
counterclockwise in half
steps
.include "./m328Pdef.inc"
.equ HSTEP1 = 0x08 ; values to rotate
a half step
.equ HSTEP2 = 0x0C ; "
.equ HSTEP3 = 0x04 ; "
.equ HSTEP4 = 0x06 ; "
.equ HSTEP5 = 0x02 ; "
.equ HSTEP6 = 0x03 ; "
.equ HSTEP7 = 0x01 ; "
.equ HSTEP8 = 0x09 ; "
; -------------------------------; This subroutine rotates the stepper
motor counterclockwise in half step
sequence. The lower 4 pins
; of PORTA must be configured for
output before calling this subroutine.
; -------------------------------.def temp1 = r21
HScw: ldi temp1,HSTEP8 ; send out
the first step pattern
out PORTA,temp1 ; "
rcall wait10ms ; provide time for motor
to react
ldi temp1,HSTEP7
out PORTA,temp1
rcall wait10ms
ldi temp1,HSTEP6
out PORTA,temp1
rcall wait10ms
ldi temp1,HSTEP5
out PORTA,temp1
rcall wait10ms
ldi temp1,HSTEP4
out PORTA,temp1
rcall wait10ms
ldi temp1,HSTEP3
out PORTA,temp1
rcall wait10ms
ldi temp1,HSTEP2
out PORTA,temp1
rcall wait10ms
ldi temp1,HSTEP1
out PORTA,temp1
rcall wait10ms
ret
.include"delays_mega.asm"
8) Write an instruction sequence to
configure the Mega328P odd
interrupt pins (INT1) to interrupt
the CPU on the rising edge and the
even interrupt pins (INT0) to
interrupt the CPU on the falling
edge.
.include "./m328pdef.inc"
.def tmp = r16
.cseg
.org 0x00
jmp start
jmp INT0_Vect
.org 0xF6
Start:
ldi tmp, low(RAMEND)
out SPL,tmp
ldi tmp, high(RAMEND)
out SPH, tmp
lds tmp,DDRD ; configure PD2/INT0,
PD3/INT1 for input
andi tmp,0xF3
sts DDRD,tmp
ldi tmp, 0x0E
sts EICRA, tmp ; //INT0 on falling
edge, INT1 on rising
edge
ldi tmp,0x03 ; "
sts EIMSK,tmp ; // enable INT0,INT1
sei
again: jmp again ;// loop
INT0_Vect: nop
reti
9) How does the PWM Module
work?
PWM (Pulse Width Modulation) works
by generating a square wave signal
that switches between high (ON) and
low (OFF) states. The percentage of
time the signal stays ON during each
cycle is called the duty cycle, which
controls the output.Timer Setup: A
timer counts up to a set value, defining
the PWM cycle.Duty Cycle: The duty
cycle is adjusted by writing a value to
the compare register. A higher value
means the signal stays ON longer.
Output: The signal toggles between
ON and OFF based on the duty cycle,
generating a PWM
waveform.Applications: PWM is used
to control motor speed, LED
brightness, and power regulation.
Types:Fast PWM: Immediate toggle
after each compare.Phase Correct
PWM: Symmetrical signal
Midterm 2016.1) Write an instruction
sequence to add 35 to the two-byte
value stored at data
memoryLocations0x2000~0x2001
Solution: The following instruction
sequence will add 35 to the data
memory locations 0x2000~0x2001:
ldi YL,0x00 ; use Y to point to data
memory location 0x2000
ldi YH,0x20 ; "
ld r24,Y ; fetch data memory location
0x2000
ldd r25,Y+1 ; "
adiw r24,35 ; add 35 to r25:r24
st Y,r24 ; store the sum back to the
original data memory
std Y+1,r25 ; locations
2) Read following program and
determine the value of r17, r18, r19
and r20, and the
content at address buf buf+1 buf+2,
and buf+3 when the program is
done.
.include <m2560def.inc>
.equ bt3 = 0x79 ; msb of test data
.equ bt2 = 0x86 ; "
.equ bt1 = 0x53 ; "
.equ bt0 = 0x42 ; lsb of test data
.def lpcnt = r16
.dseg
.org 0x200 ; set to 0x2000 for Xmega
devices
buf: .byte 4 ; buffer to hold right-shift
result
.cseg
.org 0x00
rjmp start
.org 0xF6
start: ldi r17,bt3 ; msb
ldi r18,bt2 ; second to msb
ldi r19,bt1 ; second to lsb
ldi r20,bt0 ; lsb
sts buf+3,r17 ; initialize msb in data
memory
sts buf+2,r18 ; initialize second to msb
in data memory
sts buf+1,r19 ; initialize second to lsb
in data memory
sts buf,r20 ; initialize lsb in data
memory
ldi lpcnt,4 ; set up loop count
srloop: lsr r17 ; shift the msb to the
right one place
ror r18 ; rotate the second to msb to
the right one place
ror r19 ; rotate the second to lsb to the
right one place
ror r20 ; rotate the lsb to the right one
place
dec lpcnt ; decrement loop count
brne srloop
nop
// end of program
3) Write a loop to compute the sum
of the square of the first one
hundred odd
numbers. [10 points]
Solution:
long int oddSum;
int ix;
…
oddSum = 0;
for (ix = 1; ix < 201; ix++2){
oddSum = (unsigned long)ix *
(unsigned long)ix;
}
4) Load your last two digit banner
number in hexadecimal format to
register Rd then
execute each following instructions
and write out the new Rd value.
Assume K=0x53
; -------------------------------------------------------------------------------------------------------------.def lpcnt = r21 ; loop count for
repeated shifted-subtraction
.def tmp2 = r10 ; used to hold
difference temporarily
.def tmp1 = r9 ; "
.def tmp0 = r8 ; "
.equ dvr2 = 7 ; offset of msb of divisor
from stack pointer
.equ dvr1 = 6 ; "
.equ dvr0 = 5 ;
Div24U: push YH ;
push YL ; "
in YL,SPL ; use Y register as pointer to
the stack top
in YH,SPH ; "
ldi lpcnt,24 ; there should be 24
iterations
movw r22,r16 ; transfer dividend to Q
register
mov r24,r18 ; “
ldd r0,Y+dvr0 ; place divisor in
registers r0~r2
ldd r1,Y+dvr1 ; "
ldd r2,Y+dvr2 ; "
clr r16 ; use registers r16~r18 as R
register and
clr r17 ; initialize them to 0
clr r18 ; "
dvloop24: lsl r22 ; shift R:Q to the left
one plce
rol r23 ; "
rol r24 ; "
rol r16 ; "
rol r17 ; "
rol r18 ; "
movw tmp0,r16 ; transfer R register to
tmp0~tmp3
mov tmp2,r18 ; "
sub tmp0,r0
sbc tmp1,r1
sbc tmp2,r2
brmi less24
movw r16,tmp0 ; save the difference in
R register
mov r18,tmp2 ; "
ori r22,0x01 ; set the lsb of Q register
to 1
rjmp nextb
less24: andi r22,0xFE ; clear the lsb of
Q register to 0
nextb: dec lpcnt
brne dvloop24
pop YL ; restore Y from stack
pop YH ; "
ret
// End of program
7.Write a function to find numbers
of odd integers from an array and
store the results at 0x1100.
.include <m644Adef.inc>
5) What are the contents of PORTA
.equ NN = 20
after the following AVR program is
.def j = r16 ;
assembled:
.def Cnt = r17
out PORTA,0x53
.def tmp = r18 ;
sbi PORTA,2
.cseg
cbi PORTA,1
.org 0x00
solution: 01010101
rjmp start
6) Write a subroutine that can divide .org 0xF6
a 24-bit unsigned integer into
start: ldi ZL,low(array<<1) ;
another 24-bit unsigned integer.
ldi ZH,high(array<<1) ; "
Please also write a test program for ldi j,0
the subroutine.
ldi Cnt,0
.include <atmega644def.inc>
loop: lpm tmp,z+ ;
.macro dealloc_stk
sbrs tmp,1 ;
in r28,SPL
inc Cnt
in r29,SPH
next: inc j
adiw r28,@0 ; allocate k bytes in the
cpi j,NN-1 ;
stack
brne loop
out SPL,r28
ldi Xl,0x00
out SPH,r29
ldi XH,0x11
.endmacro
mov X,Cnt
.equ dd2 = 0x58 ; test data for
here: rjmp here ;
dividend
array: .db
.equ dd1 = 0x41 ; "
11,12,13,14,15,16,17,18,19,20
.equ dd0 = 0x70 ; "
.db 21,22,23,24,25,26,27,28,29,30
.equ dr2 = 0x00 ; test data for divisor " // end of program
.equ dr1 = 0x21 ; "
8) Use the AVR Mega PORTA to
.equ dr0 = 0x98 ; "
drive a single seven-segment
.cseg
display. Please write assembling
.org 0x00
code to display decimal digits
rjmp start
2,0,1,6 with 100 ms delay between
.org 0xF6
digits.Assume the subroutine for
start: ldi YL,low(RAMEND) ; initialize
delay is available delayby100ms.
stack pointer SP
ldi YH,high(RAMEND) ; "
out SPL,YL ; "
out SPH,YH ; "
ldi r28,dr2 ; pass divisor in the stack
push r28 ; "
ldi r28,dr1 ; "
push r28 ; "
.cseg
ldi r28,dr0 ; "
.org 0x00
push r28 ; "
jmp start
ldi r16,dd0 ; pass dividend in r16~r18
.org 0xF6
ldi r17,dd1 ; "
Start: ldi tmp, low(RAMEND)
ldi r18,dd2 ; "
out SPL,tmp
call div24U ;
ldi tmp, high(RAMEND)
dealloc_stk 3
out SPH, tmp
forever: rjmp forever
ldi r16, 0xFF ;
The subroutine divides a 24-bit
out DDRA, r16
unsigned integer into another 24-bit
Display: ldi r16, 0x6D
unsigned
sts PORTA, r16
; integer. The 24-bit divisor is passed
call delayby100ms
in the stack whereas the 24-bit
ldi r16, 0x7E
; unsigned dividend is passed in
sts PORTA, r16
registers r16~r18. The quotient is
call delayby100ms
returned in
ldi r16, 0x30
; registers r22~r24 and the remainder
sts PORTA, r16
is returned in registers r16~r18.
call delayby100ms
ldi r16, 0x5F
sts PORTA, r16
call delayby100ms
jmp display
9) Configure odd interrupt pins
(INTn) to interrupt on the rising
edge and the even interrupt pins to
interrupt on the falling edge.
Solution: Each interrupt pin (eight in
total) uses two bits to configure the
interrupt
edge. The following instruction
sequence will configure the odd
interrupt pins to
interrupt on the rising edge and the
even interrupt pins to interrupt on the
falling
edge:
ldi r16,0xEE ; configure odd interrupt
pins to interrupt on the rising edge
sts EICRA,r16 ; and even interrupt to
interrupt on the falling edge
sts EICRB,r16 ; “
ldi r16,0xFF ; enable all INTn pin to
interrupt locally
sts EIMSK,r16 ; “
sei ; enable global interrupt
ASSIG3 E5.3 Write a subroutine that
can divide a 16-bit signed integer
into another 16-bit signed integer.
The dividend and divisor are passed
in registers r16-r17, and r18-r19,
respectively. The quotient is
returned in registers r24-r25, and
the remainder is returned in
registers r22-r23, respectively.
The following subroutine can divide a
16-bit signed integer into another 16bit signed integer.
.include "./m328Pdef.inc"
.equ num1H = 0x76 ; high byte of the
first test data
.equ num1L = 0x00 ; low byte of the
first test data
.equ num2H = 0x00 ; high byte of the
second test data
.equ num2L = 0x64 ; low byte of the
second test data
.cseg
.org 0x00
rjmp start
.org 0xF6
start: ldi r16,low(RAMEND)
out SPL,r16
ldi r16,high(RAMEND)
out SPH,r16
ldi r16,num1L ; pass the dividend in
r16~r17
ldi r17,num1H ; "
ldi r18,num2L ; pass the divisor in
r18~r19
ldi r19,num2H ; "
call div16S
forever: nop
rjmp forever
; The next subroutine divides the 16-bit
signed numbers contained in r18~r19
; into the 16-bit signed number
contained in r16~r17 and returns the
quotient
; in r25~r24 and the remainder in
r23~r22.
.def lpcnt = r20
.def tmpL = r0
.def tmpH = r1
.def signD = r8 ; sign of dividend
.def sign = r21 ; sign of quotient
div16S: push r27 ; save XH register
push r26 ; save XL register
ldi lpcnt,16 ; set up divide iteration
count
clr signD
clr sign
sbrs r17,7 ; check the sign bit of the
dividend
rjmp chkdvr ; go to check the sign of
divisor
inc signD ; record the sign of dividend
to be negative
inc sign ; record the sign of quotient to
be negative
movw r26,r16
com r26 ; find the magnitude of the
dividend
com r27 ; "
adiw r26,1
movw r16,r26 ; transfer the magnitude
of the dividend back to r16~r17
chkdvr: sbrs r19,7 ; check the sign of
the divisor
rjmp startD ; no need to change
anything
ldi r27,0x01 ; toggle the sign bit of
quotient
eor sign,r27; "
movw r26,r18 ; compute the
magnitude of the divisor
com r26 ; "
com r27 ; "
adiw r26,1 ; "
movw r18,r26 ; transfer the magnitude
of divisor back to r18~r19
startD: movw r24,r16 ; place dividend
in Q register
clr r23 ; load 0 in R register
clr r22 ; "
dvloop: lsl r24 ; shift R:Q to the left one
place
rol r25 ; "
rol r22 ; "
rol r23 ; "
movw tmpL,r22 ; save R in temporary
registers
sub tmpL,r18 ; compute R - S
sbc tmpH,r19 ; "
brmi less ; branch if divisor is larger
movw r22,tmpL ; save the difference in
R
ori r24,0x01 ; set the lsb of Q to 1
rjmp nxtb
less: andi r24,0xFE ; set the lsb of Q to
0
nxtb: dec lpcnt
brne dvloop
sbrs signD,0
rjmp chkSoQ
movw r26,r22 ; change the remainder
to it's two's complement if
com r26 ; the dividend is negative
com r27 ; "
adiw r26,1 ; "
movw r22,r26 ; "
chkSoQ: sbrs sign,0 ; check the sign
of quotient
rjmp doneDS ; nothing need to be
done on quotient when it is positive
movw r26,r24 ; quotient is negative,
compute it's two's complement
com r26 ; "
com r27 ; "
adiw r26,1 ; "
movw r24,r26 ; "
doneDS: pop r26
pop r27
ret
// end of program
E5.5 Write a subroutine that can
divide a 32-bit signed integer into
another 32-bit signed integer. The
dividend is passed in registers r16r19, and the divisor is passed in the
stack. The quotient is returned in
registers r22-r25, and the remainder
is returned in registers r16-r19.
.include "./m328Pdef.inc"
.macro dealloc_stk
in r28,SPL
in r29,SPH
adiw r28,@0 ; allocate k bytes in the
stack
out SPL,r28
out SPH,r29
.endmacro
.equ dd3 = 0xF1 ; test data for
dividend
.equ dd2 = 0x18 ; "
.equ dd1 = 0x65 ; "
.equ dd0 = 0x7B ; "
.equ dr3 = 0x00 ; test data for divisor
.equ dr2 = 0x00 ; "
.equ dr1 = 0xF4 ; "
.equ dr0 = 0x24 ; "
.cseg
.org 0x00
rjmp start
.org 0xF6
start: ldi YL,low(RAMEND) ; initialize
stack pointer SP
ldi YH,high(RAMEND) ; "
out SPL,YL ; "
out SPH,YH ; "
ldi r28,dr3 ; pass divisor in the stack
push r28 ; "
ldi r28,dr2 ; "
push r28 ; "
ldi r28,dr1 ; "
push r28 ; "
ldi r28,dr0 ; "
push r28 ; "
ldi r16,dd0 ; pass dividend in r16~r19
ldi r17,dd1 ; "
ldi r18,dd2 ; "
ldi r19,dd3 ; "
call div32S ;
dealloc_stk 4
forever: rjmp forever
; ----------------------------------------------------------------------------------------------------------------; The subroutine divides a 32-bit
unsigned integer into another 32-bit
unsigned integer.
; The 32-bit divisor is passed in the
stack whereas the 32-bit unsigned
dividend is passed
; in registers r16~r19. The quotient is
returned in registers r22~r25 and the
remainder
; is returned in registers r16~r19.
; ----------------------------------------------------------------------------------------------------------------.def lpcnt = r21 ; loop count for
repeated shifted-subtraction
.def tmp3 = r11 ; used to hold
difference temporarily
.def tmp2 = r10 ; "
.def tmp1 = r9 ; "
.def tmp0 = r8 ; "
.def signD = r3 ; record the sign of the
dividend
.def sign = r4 ; record the sign of the
quotient
.equ dvr3 = 12 ; offset of msb of divisor
from stack pointer
.equ dvr2 = 11 ; "
.equ dvr1 = 10 ; "
.equ dvr0 = 9 ; ()
div32S: push YH ;
push YL ; "
push r31 ; save Z register in stack
push r30
push r27 ; save X register in stack
push r26
in YL,SPL ; use Y register as pointer to
the stack top
in YH,SPH ; "
clr signD ; assume the dividend is
positive
clr sign ; assume the quotient is
positive
sbrs r19,7 ; check the sign of dividend
rjmp chkDvr
inc signD ; change the sign of dividend
to negative
inc sign ; change the sign of quotient
to negative
com r16 ; compute the magnitude of
dividend
com r17 ; "
com r18 ; "
com r19 ; "
movw r26,r16 ; "
adiw r26,1 ; "
movw r16,r26 ; "
clr r27 ; "
adc r18,r27 ; "
adc r19,r27 ; "
chkDvr: ldd r0,Y+dvr0 ; place divisor in
registers r0~r3
ldd r1,Y+dvr1 ; "
ldd r2,Y+dvr2 ; "
ldd r3,Y+dvr3 ; "
sbrs r3,7 ; check the sign of divisor
rjmp startDv
com r0 ; compute the magnitude of the
divisor
com r1 ; "
com r2 ; "
com r3 ; "
movw r26,r0 ; "
adiw r26,1 ; "
movw r0,r26 ; "
clr r27 ; "
adc r2,r27 ; "
adc r3,r27 ; "
ldi r27,1 ; ; toggle the sign of the
quotient
eor sign,r27 ; "
startDv:
ldi lpcnt,32 ; there should be 32
iterations
movw r24,r18 ; transfer dividend to Q
register
movw r22,r16 ; "
clr r16 ; use registers r16~r19 as R
register and
clr r17 ; initialize them to 0
clr r18 ; "
clr r19 ; "
dvloop32:
lsl r22 ; shift R:Q to the left one place
rol r23 ; "
rol r24 ; "
rol r25 ; "
rol r16 ; "
rol r17 ; "
rol r18 ; "
rol r19 ; "
movw tmp0,r16 ; transfer R register to
tmp0~tmp3
movw tmp2,r18 ; "
sub tmp0,r0
sbc tmp1,r1
sbc tmp2,r2
sbc tmp3,r3
brmi less32
movw r16,tmp0 ; save the difference in
R register
movw r18,tmp2 ; "
ori r22,0x01 ; set the lsb of Q register
to 1
rjmp nextb
less32: andi r22,0xFE ; clear the lsb of
Q register to 0
nextb: dec lpcnt
brne dvloop32
sbrs signD,0
rjmp chkSoQ
com r16 ; compute the 2's complement
of the remainder
com r17 ; if the dividend is negative
com r18 ; "
com r19 ; "
movw r26,r16 ; "
adiw r26,1 ; "
movw r16,r26 ; "
clr r27 ; "
adc r18,r27 ; "
adc r19,r27 ; "
chkSoQ: sbrs sign,0
rjmp doneD32 ; quotient is positive, so
do nothing
com r22 ; quotient is negative, so
compute its
com r23 ; two's complement
com r24 ; "
com r25 ; "
movw r26,r22 ; "
adiw r26,1 ; "
movw r22,r26 ; "
clr r27 ; "
adc r24,r27 ; "
adc r25,r27 ; "
doneD32: pop r26
pop r27
pop r30
pop r31
pop YL ; restore Y from stack
pop YH ; "
ret
// End of program
E5.7 Write a subroutine that finds
the greatest common divisor of two
16-bit unsigned integers.
Two registers are passed in registers
r16-r17 and r18-r19, respectivly. The
gcd is returned in registers r22-r23.
Write a subroutine that finds the
greatest common divisor of two 16-bit
unsigned integers.
The GCD of two integers can be found
by using the Euclidian method:
Step 1
If m = n then
gcd arrow towards m;
return;
Step 2
If n < m then swap m and n.
Step 3
gcd arrow towards 1.
If m = 1 or n = 1 then return.
Step 4
p = n % m;
Step 5
if (p == 0) then m is the gcd.
else
n arrow towards m;
m arrow towards p;
go to step 4.
The assembly subroutine that finds the
gcd and the test program are as
follows:
.include "./m328Pdef.inc"
.equ n1 = 18000 ; test number 1
.equ n2 = 9000 ; test number 2
.cseg
.org 0x00
rjmp start
.org 0xF6
start: ldi r16,low(RAMEND) ; initialize
SP
out SPL,r16 ; "
ldi r16,high(RAMEND) ; "
out SPH,r16 ; "
ldi r16,low(n1) ; pass the first number
ldi r17,high(n1) ; "
ldi r18,low(n2) ; pass the second
number
ldi r19,high(n2) ; "
call findGCD
nop
again: rjmp again
; -------------------------------------------------; The findGCD subroutine computes
the gcd of two 16-bit unsigned 16-bit
integers held
; in r16~r17 and r18~r19, respectively.
The GCD us returned in registers
r22~r23.
; -------------------------------------------------.def tH = r3
.def tL = r2
findGCD: cp r16,r18
cpc r17,r19
brne normal
movw r22,r16 ; if (m == n), then gcd =
n
ret
normal: ldi r22,1 ; initialize gcd to 1
clr r23
cp r16,r22 ; if (n == 1), then return
cpc r17,r23
brne chkN
ret
chkN: cp r18,r22 ; if (m == 1), then
return
cpc r19,r23
brne doIt
ret
doIt: movw tL,r18 ; save a copy of
divisor
call div16U ; compute
cpi r23,0
brne next1
cpi r22,0
brne next1
movw r22,tL
ret
next1: movw r16,tL ; make the divisor
as the dividend
movw r18,r22 ; make the remainder as
the divisor
rjmp doIt
.include "div16U.asm"
// End of program
E5.9 Write a program to find out all
the four-digit decimal numbers
(1000 to 9999) that have the
property specified in problem E5.8.
Solution: The program is as follows:
.include "./m328Pdef.inc"
.equ lastVal = 9999
.dseg
.org 0x100
buf: .byte 20 ; reserve 20 bytes to hold
numbers with specified property
.cseg
.org 0x00
rjmp start
.org 0xF6
start: ldi r16,low(RAMEND)
out SPL,r16
ldi r16,high(RAMEND)
out SPH,r16
ldi XL,low(lastVal)
ldi XH,high(lastVal)
movw r4,XL ; use r4~r5 to hold the
upper limit
ldi YL,low(1000) ; Y holds the number
to be tested
ldi YH,high(1000) ; "
ldi ZL,low(buf) ; use Z as the pointer to
the buffer
ldi ZH,high(buf) ; "
loop: movw r16,r28
call sumSqEqu
cpi r22,1
brne next
st Z+,YL ; save the number with the
specified property
st Z+,YH ; "
next: adiw YL,1 ; try the next number
cp YL,r4
cpc YH,r5
brne loop
nop
again: rjmp again
; -------------------------------------------------; The sumSqEqu subroutine tests
whether the square of the sum of the
upper and
; lower half equals the original number.
The number is passed in r16~r17 and
the
; result is returned in r22.
; -------------------------------------------------sumSqEqu: push r17 ; save a copy of
the number to be tested
push r16 ; “
ldi r18,100 ; separate the upper and
lower half by
clr r19 ; dividing the given number by
100
call div16U ; “
add r22,r24 ; add the upper and lower
halves
mul r22,r22 ; compute the square of
the sum
pop r16
pop r17
cp r0,r16
cpc r1,r17
brne false
ldi r22,1
ret
false: clr r22
ret
.include "div16U.asm"
//end of program
Assignment #4
E6.1 What is the value of ax/bx,
assuming that ax=93, bx=19?
ax / bx = 93 / 19 = 4
E6.6 Write a program to find the
median of an array of 8 bit unsigned
integers. When the
array has an even number of
elements, the median is defined as
the average of the middle
two elements. Otherwise, it is
defined as the middle element of the
array. You need to
sort the array in order to find the
median.
Solution: We need to sort the array in
order to find its median. We will invoke
the bubble sort function to
sort the given array.
#include <io.h>
void swap (unsigned char *px,
unsigned char *py);
void bubble (unsigned char a[ ],
unsigned char n);
#define N 30
unsigned char xa[] =
{10,9,8,7,6,5,4,3,12,15,
20,29,28,21,27,25,24,23,99,43,
30,41,53,89,76,54,65,49,46,55};
unsigned char median;
void main (void)
{
bubble(xa, N);
if (N == ((N / 2) * 2)) { // is N an even
value?
median = (xa[N/2] + xa[N/2 - 1])/2;
}
else
median = xa[N/2];
while(1);
}
void bubble (unsigned char a[ ],
unsigned char n) // n is the array count
{
unsigned char i, j;
char inorder; // array in order flag
for (i = 0; i < n - 1; i++){ // up to n - 1
iterations are performed
inorder = 1; // assume array is in order
at the start of a new iteration
for (j = 0; j < n - i - 1; j++)
if (a[j] > a[j+1]){ // are two adjacent
elements not in order?
swap (&a[j], &a[j+1]);
inorder = 0; // array not in order
}
if (inorder) // array is in order, there is
no need to continue.
break;
}
}
void swap (unsigned char *px,
unsigned char *py)
{
unsigned char temp;
temp = *px;
*px = *py;
*py = temp;
}
E6.11 Write a switch statement that
will examine the value of an integer
variable yy and
assign one of the following values
to the variable dd, depending on the
value of yy:
a) 15, if yy==1
b) 25, if yy==2
c) 35, if yy==3
d) 45, if yy==4
e) 55, if yy==5
Solution:
switch (yy) {
case 1:
dd = 15;
break;
case 2:
dd = 25;
break;
case 3:
dd = 35;
break;
case 4:
dd = 45;
break;
case 5:
dd = 55;
break;
default:
dd = 10;
}
E6.16 Write a function to determine
whether a three-digit number is an
Armstrong
number and a main program to find
all the 3-digit (> 100) Armstrong
numbers and store
them in an array. (An Armstrong
number is a number that is equal to
the sum of each
digit raised to the nth power. For
example, 153 equals 13+53+33
)
unsigned int armStrong[6];
char ArmStrong3Test(unsigned int ax);
void main (void)
{
unsigned int ax;
unsigned char ix;
ix = 0;
for (ax = 100; ax < 1000; ax++){
if(ArmStrong3Test(ax)){
armStrong[ix] = ax;
ix++;
}
}
while(1);
}
char ArmStrong3Test(unsigned int ax)
{
unsigned int x1, x2, x3, tmp;
x3 = ax % 10; // one's digit
tmp = ax / 10; // hundred's and ten's
digits
x2 = tmp % 10; // ten's digit
x1 = tmp / 10; // hundred's digit
if ((x1 * x1 * x1 + x2 * x2 * x2 + x3 * x3
* x3) == ax)
return 1;
else
return 0;
}
E6.21 Write a function that can convert
a binary number into a NULLterminated BCD
string that represents the given binary
number.
#include <io.h>
void i2s (int i,char *s);
char obuf[10];
void main (void)
{
int ax;
ax = -32000;
i2s(ax, &obuf[0]);
while(1);
}
void i2s(int i,char *s) // Convert Integer
to String
{
char sign;
short len;
char *p;
sign = '+';
len = 0;
p = s; // save a copy of the pointer
if(I < 0) {
sign = '-';
i = -i;
}
do { // separate each decimal digit with
lsd first
*s = (I % 10) + '0';
s++;
len++;
i /= 10;
} while (i != 0);
if(sign == '-') {
*s = '-';
s++;
len++;
}
for(i = 0;i < len/2; i++){ // reverse the
string
p[len] = p[i];
p[i] = p[len – 1 - i];
p[len-1-i] = p[len];
}
p[len] = 0;
}
Assignment #2
E3.1 Write assembler directives to
define the ASCII codes of letters a
to z in program
memory.
.cseg
.db “abcdefghijklmnopqrstuvwxyz”,0
E3.3 Invoke the SetPointer macro
defined as following to load the
address 0x3000 into
Y register.
macro setPointer
ldi @0, low(@2)
ldi @1, high(@2)
endmacro
setPointer YL,YH,0x3000
E3.5 Write a program to add the 24bit numbers stored at data memory
locations
0x200-0x202 and 0x203-0x205,
respectively, and store the sum at
0x206-0x208
.cseg
.org 0x00
rjmp start
.org 0xF6
start: lds r0,0x200 ; fetch the lsbs
lds r1,0x203 ; “
add r0,r1 ; add them
sts 0x206,r0 ; save the lsb of the sum
lds r0,0x201 ; fetch the middle bytes
lds r1,0x204 ; “
adc r0,r1 ; add them
sts 0x207,r0 ; save the middle byte of
the sum
lds r0,0x202 ; fetch the msbs
lds r1,0x205 ; “
adc r0,r1 ; add them
sts 0x208,r0 ; save the msbs of the
sum
// end of program
E3.9 Write a program to subtract the
32 bit number stored at 0x200-0x203
from the 32
bit number stored at 0x204-0x207,
and stored the difference at 0x2080x20B.
.include “./m328pdef.inc”
.cseg
.org 0x00
rjmp start
.org 0xF6
start: lds r1,0x204 ; fetch the lsb of the
minuend
lds r0,0x200 ; fetch the lab of the
subtrahend
sub r1,r0
sts 0x208,r1 ; save the lsb of
difference
lds r1,0x205
lds r0,0x201
sbc r1,r0
sts 0x209,r1
lds r1,0x206
lds r0,0x202
sbc r1,r0
sts 0x20A,r1
lds r1,0x207 ; fetch the high byte of
minuend
lds r0,0x203 ; fetch the high byte of
subtrahend
sbc r1,r0 ; subtract with borrow
sts 0x20B,r1 ; save the msb of
difference
// End of program
E3.11 Write a program to swap the
upper 4 bis with the lower 4 bits of
every element of an array of 8-bit
integers. The initial array is stored
in the program memory and you
must copy this array to the data
memory for testing purpose.
We can use the Z register to point to
the array in the program memory and
use the register X
to point to the buffer to receive the
array after swapping the upper and
lower nibbles.
.include “./m328pdef.inc”
.equ NN=30
.dseg
.org 0x200
buf1: .byte NN ; buffer to hold the
array
.def lpcnt = r17
.cseg
.org 0x00
rjmp start
.org 0xF6
start: ldi XL,low(buf1) ; set up pointer
to buf1
ldi XH,high(buf1) ; "
ldi ZL,low(array<<1) ; set up pointer to
array
ldi ZH,high(array<<1) ; "
ldi lpcnt,NN ; set up loop count to copy
array
cloop: lpm r0,z+ ; loop to copy array to
data memory
swap r0 ; swap the upper and lower
nibbles
st x+,r0 ; store the resultant element in
data memory
dec lpcnt
brne cloop
here: rjmp here
array: .db
0x11,0x12,0x13,0x14,0x15,0x16,0x17,
0x18,0x19,0x20
.db
0x21,0x22,0x23,0x24,0x25,0x26,0x27,
0x28,0x29,0x30
.db
0x31,0x32,0x33,0x34,0x35,0x36,0x37,
0x38,0x39,0x40
// end of program
E3.13 Write a program to find the
total number of elements in an array
of 8-bit integers
that are greater than 30 and less
than 100. Use for loop looping
construct.
// ------------------------------------------------// This program finds the number of
elements that are greater than 30 and
less than
// 100 and leaves count in r17. The
array is in program memory.
// ------------------------------------------------.include “./m328pdef.inc”
.equ N1 = 0
.equ N2 = 40
.def ii = r16
.def count = r17
.def tmp1 = r18
.def tmp2 = r19
.macro setPointer
ldi @0,low(@2)
ldi @1,high(@2)
.endmacro
.cseg
.org 0x00
rjmp start
.org 0xF6
start: clr ii ; initialize ii to N1
clr count ; initialize count to 0
ldi tmp1,30 ; values to be compared
ldi tmp2,100 ; "
setPointer ZL,ZH,(array<<1) ; use the
register Z as the array pointer
floop: cpi ii,N2 ; check looping
condition
breq done
lpm r0,z+ ; read the next array element
cp tmp1,r0 ; is the element larger than
20?
brlt yes ; if yes, then branch to check
upper bound
rjmp next
yes: cp r0,tmp2
brge next ; branch if array element is
greater than or equal to 100
inc count
next: inc ii ; prepare to check next
array element
rjmp floop
done: rjmp done
array: .db
10,11,12,13,14,15,16,17,18,19
.db 50,21,52,23,24,25,26,27,28,29
.db 30,31,32,33,34,35,36,37,38,39
.db 60,62,56,99,102,103,104,89,78,59
// End of program
Assignment1
E2.1 Write an instruction sequence
to swap the contents of registers r0
and r1. A third
register such as r2 or other can be
used to facilitate the swap
operation.
Solution: The following instruction
sequence will perform the swap
operation:
mov r2,r0 ; save the contents of r0 in
r2
mov r0,r1 ; r0 gets the value of r1
mov r1,r2 ; r1 gets the value of r0
E2.4 Write an instruction sequence to
store 1, 3, and 5 at data memory
locations at 0x2000,
0x2005, and 0x200A, respectively.
Solution: The following instruction
sequence will perform the specified
initialization:
ldi YL,0x00 ; use Y to point to data
memory location 0x2000.
ldi YH,0x20 ; "
ldi r16,1 ; store 1 in data memory
location 0x2000
st Y,r16 ; "
ldi r16,3 ; store 3 in data memory
location 0x2005
std Y+5,r16 ; "
ldi r16,5 ; store 5 in data memory
location 0x200A
std Y+10,r16 ; "
E2.7 Write a sequence of
instructions to add the three
numbers stored in 0x2000, 0x2001,
and 0x2002 and store the sum at
data memory location at 0x2010.
Solution: The following instruction
sequence can perform the specified
operation:
ldi YL,0x00 ; use Y to point to data
memory location 0x2000
ldi YH,0x20 ; "
ld r0,Y ; fetch data memory location
0x2000
ldd r1,Y+1 ; fetch data memory
location 0x2001
add r0,r1 ; add data memory locations
0x2000 and 0x2001
ldd r1,Y+2 ; fetch data memory
locations 0x2002
add r0,r1 ; add 0x2000, 0x2001, and
0x2002
std Y+16,r0 ; store at 0x2010
E2.10 Write a sequence of
instructions to copy the three bytes
from program memory
locations 0x2000~0x2002 to data
memory locations at
0x2000~0x2002, respectively.
Solution: We need one pointer to point
to data memory and another pointer to
point to
program memory. The following
instruction sequence will copy data
from program memory
to data memory:
ldi YL,0x00 ; use Y to point to data
memory location 0x2000
ldi YH,0x20 ; "
ldi ZL,0x00 ; use Z to point to program
memory location 0x2000
ldi ZH,0x20 ; "
lpm r0,Z+ ; fetch program memory at
0x2000 and move pointer
st Y+,r0 ; store program memory
contents in data memory
lpm r0,Z+ ; fetch program memory at
0x2001 and move pointer
st Y+,r0 ; store in data memory
lpm r0,Z ; fetch program memory at
0x2002
st Y,r0 ; store at data memory
E2.13 Write an instruction sequence
to subtract the value stored at data
memory location
0x2000 from the sum of the values
stored at data memory locations
0x2010 and 0x2011 and
leave the difference in r0.
Solution: The instruction sequence
that can perform the specified
operation is as follows:
ldi YL,0x00
ldi YH,0x20
ldd r0,Y+0x10 ; fetch data memory
location 0x2010
ldd r1,Y+0x11 ; fetch data memory
location 0x2011
add r0,r1 ; add these two bytes
ld r1,Y ; fetch data memory location
0x2000
sub r0,r1 ; leave the difference in r0
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )