Stroboscope
Designed to be best viewed on 1280 x 800 wide screen
Home
Photo Gallery
My Projects
Resume

 

 

LAB-01 Circuit

Final Circuit (LAB-09)

 

;*******************************************************************
;*
;* Description: This program generates a linear changing frequency
;* that can be used to control the flash rate of
;* a stroboscope using pulses and carefully calculated
;* periods between each pulse. This frequency can be
;* change easily with pushbuttons
;*
;* Author: Muhammad Aman   
;* Version: 3.60
;* Last Updated: 12/12/06
;* Target: ATmega16
;* Number of words: 4302 words
;* Number of cycles:
;* Low registers used: r8, r9, r10, r11, r12, r13, r14, r15
;* High registers used: r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31
;* Parameters:
;*
;* Notes:
;*
;*******************************************************************
.nolist
.include "m16def.inc"
.list

.cseg

.org 0
rjmp reset

.org int0
rjmp isr_0

.org $00C
rjmp isr_pulse

;**************************************************************************
;*
;*"div32u" - 32/32 Bit Unsigned Division
;*
;*Description: This subroutine divides the two 32-bit numbers
;* "dividend32u3:dividend32u0"(dividend) and
;* "div32u3:div32u0"(divisor). The result is placed in
;* "dres32u3:dres32u0" and the remainder in"drem32u3:drem32u0".
;*
;*Author: Muhammad Aman 
;*Version: 1.0
;*Last updated: 11/29/2006
;*Number of Cycles: 792
;*Low Registers Used: r12 - Remainder byte 0
;* r13 - Remainder byte 1
;* r14 - Remainder byte 2
;* r15 - Remainder byte 3
;*High Registers Used: r16 to r19 - (Dividend 0 to 3)
;* r20,r22,r23,r24 - (Divisor 0 to 3)
;* r25 - (Division counter)
;*
;*Notes: Subroutines "d32u_1","d32u_2", and "d32u_3" must be used to
;* properly perform the division
;***************************************************************************
.def drem32u0 =r8
.def drem32u1 =r9
.def drem32u2 =r10
.def drem32u3 =r11
.def dres32u0 =r12
.def dres32u1 =r13
.def dres32u2 =r14
.def dres32u3 =r15
.def dividend32u0 =r16
.def dividend32u1 =r17
.def dividend32u2 =r18
.def dividend32u3 =r19
.def div32u0 =r20
.def div32u1 =r21
.def div32u2 =r22
.def div32u3 =r23
.def dcnt32u =r24

div32u:
ldi r19, $00
push r18 ;pushing all the register in stack and will be poped later
push r19
push r20
push r21
push r22
push r23
push r24
push r25
mov div32u0, r30
mov div32u1, r31
ldi div32u2, $00
ldi div32u3, $00
clr drem32u0 ;clear remainder
clr drem32u1
clr drem32u2
sub drem32u3,drem32u3 ;clear remainder high byte and carry
ldi dcnt32u,33 ;init loop counter
d32u_1:
rol dividend32u0 ;shift left dividend
rol dividend32u1
rol dividend32u2
rol dividend32u3
dec dcnt32u ;decrement counter
brne d32u_2 ;if done
rjmp div_complete
d32u_2:
rol drem32u0 ;shift dividend into remainder
rol drem32u1
rol drem32u2
rol drem32u3
sub drem32u0,div32u0 ;remainder = remainder - divisor
sbc drem32u1,div32u1
sbc drem32u2,div32u2
sbc drem32u3,div32u3
brcc d32u_3 ;if result negative
add drem32u0,div32u0 ;restore remainder
adc drem32u1,div32u1
adc drem32u2,div32u2
adc drem32u3,div32u3
clc ;clear carry to be shifted into result
rjmp d32u_1 ;else
d32u_3:
sec ;set carry to be shifted into result
rjmp d32u_1
div_complete:
pop r25 ;poping all register previously pushed
pop r24
pop r23
pop r22
pop r21
pop r20
pop r19
pop r18
ret


;*******************************************************************************************
;*
;*"bin2BCD16" - 16-bit Binary to BCD conversion
;*
;*Description: This subroutine converts a 16-bit number (fbinH:fbinL)
;* to a 5-digit packed BCD number represented by
;* 3 bytes (tBCD2:tBCD1:tBCD0). MSD of the 5-digit number
;* is placed in the lowermost nibble of tBCD2.

;*
;*Author: Muhammad Aman 
;*Number of words:25
;*Number of cycles:751/768 (Min/Max)
;*Low registers used:3 (tBCD0,tBCD1,tBCD2)
;*High registers used:4(fbinL,fbinH,cnt16a,tmp16a)
;*Pointers used :Z
;*
;*Notes: code taken from ese380 notes
;*******************************************************************************************
.equ AtBCD0 =13 ;address of tBCD0
.equ AtBCD2 =15 ;address of tBCD1

.def tBCD0 =r13 ;BCD value digits 1 and 0
.def tBCD1 =r14 ;BCD value digits 3 and 2
.def tBCD2 =r15 ;BCD value digit 4
.def fbinL =r16 ;binary value Low byte
.def fbinH =r17 ;binary value High byte
.def cnt16a =r18 ;loop counter
.def tmp16a =r19 ;temporary value

bin2bcd16:
mov r16,r30
mov r17,r31
push r16
push r17
push r30
push r31
ldi cnt16a,16 ;Init loop counter
clr tBCD2 ;clear result (3 bytes)
clr tBCD1
clr tBCD0
clr ZH ;clear ZH (not needed for AT90Sxx0x)
bBCDx_1:
lsl fbinL ;shift input value
rol fbinH ;through all bytes
rol tBCD0
rol tBCD1
rol tBCD2
dec cnt16a ;decrement loop counter
brne bBCDx_2 ;if counter not zero
pop r31
pop r30
pop r17 ;Restore the values of r16 and r17
pop r16
ret ; return back to the call
bBCDx_2:
ldi r30,AtBCD2+1 ;Z points to result MSB + 1
bBCDx_3:
ld tmp16a,-Z ;get (Z) with pre-decrement
subi tmp16a,-$03 ;add 0x03
sbrc tmp16a,3 ;if bit 3 not clear
st Z,tmp16a ;store back
ld tmp16a,Z ;get (Z)
subi tmp16a,-$30 ;add 0x30
sbrc tmp16a,7 ;if bit 7 not clear
st Z,tmp16a ;store back
cpi ZL,AtBCD0 ;done all three?
brne bBCDx_3 ;loop again if not
rjmp bBCDx_1

;**************************************************************************
;*
;*"isr_0" - Interrupt Service Routine for Interrupt 0
;*
;*Description: This subroutine is called when Interrupt occurs at INT0
;*
;*Author: Muhammad Aman
;*Version: 1.0
;*Last updated: 12/12/2006
;*High Registers Used: r16 and r19
;*
;***************************************************************************

isr_0:
rcall delay_50ms
pop r16 ;wasting return address
pop r17 ;wasting return address
in r16, PINB ;read button press
andi r16, $E0 ;mask other bits
cpi r16, 0b11100000
breq dec_p1
cpi r16, 0b11000000
breq dec_1
cpi r16, 0b10100000
breq dec_10
rjmp increase_check

;**************************************************************************
;*
;*"dec_p1" - Decrease frequency by point(.) 1 Hz
;*
;*Description: This subroutine decrease the current frequency by point(.) 1 Hz
;*
;*Author: Muhammad Aman
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17, r30, r31
;*
;***************************************************************************

dec_p1: ;decrease frequency by .1Hz
rcall check_freq
subi r30, $01
sbci r31, $00
push r31
push r30
rcall div32u
dec r16
out OCR1AL, r16
out OCR1AH, r17
pop r30
pop r31
rcall bin2bcd16
rjmp display_LCD

;**************************************************************************
;*
;*"dec_1" - Decrease frequency by 1 Hz
;*
;*Description: This subroutine decrease the current frequeny by 1 Hz
;*
;*Author: Muhammad Aman 
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17, r30, r31
;*
;***************************************************************************

dec_1: ;decrease frequency by 1Hz
rcall check_freq
subi r30, $0A
sbci r31, $00
push r31
push r30
rcall div32u
dec r16
out OCR1AH, r17
out OCR1AL, r16
pop r30
pop r31
rcall bin2bcd16
rjmp display_LCD

;**************************************************************************
;*
;*"dec_10" - Decrease frequency by 10 Hz
;*
;*Description: This subroutine decrease the current frequency by 10 Hz
;*
;*Author: Muhammad Aman 
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17, r30, r31
;*
;***************************************************************************

dec_10: ;decrease frequency by 10Hz
rcall check_freq
subi r30, $64
sbci r31, $00
push r31
push r30
rcall div32u
dec r16
out OCR1AH, r17
out OCR1AL, r16
pop r30
pop r31
rcall bin2bcd16
rjmp display_LCD

;**************************************************************************
;*
;*"increase_check" - Check how much frequency has to be incremented
;*
;*Description: This subroutine checks how much frequency has to be incremented
;* by scanning the input from PORTB
;*
;*Author: Muhammad Aman 
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16
;*
;***************************************************************************

increase_check:
cpi r16, 0b10000000
breq inc_p1
cpi r16, 0b01100000
breq inc_1
cpi r16, 0b01000000
breq inc_10
rjmp twice_half

;**************************************************************************
;*
;*"inc_p1" - Increment frequency by point(.) 1 Hz
;*
;*Description: This subroutine increment the current frequency by point(.) 1 Hz
;*
;*Author: Muhammad Aman
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17, r30, r31
;*
;***************************************************************************

inc_p1: ;increase frequency by .1Hz
rcall check_freq
clc
ldi r16, $01
add r30, r16
ldi r16, $00
adc r31, r16
push r31
push r30
rcall div32u
dec r16
out OCR1AH, r17
out OCR1AL, r16
pop r30
pop r31
rcall bin2bcd16
rjmp display_LCD

;**************************************************************************
;*
;*"inc_1" - increment frequency by 1 Hz
;*
;*Description: This subroutine increment the current frequency by 1 Hz
;*
;*Author: Muhammad Aman
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17, r30, r31
;*
;***************************************************************************

inc_1: ;increase frequency by 1Hz
rcall check_freq
clc
ldi r16, $0A
add r30, r16
ldi r16, $00
adc r31, r16
push r31
push r30
rcall div32u
dec r16
out OCR1AH, r17
out OCR1AL, r16
pop r30
pop r31
rcall bin2bcd16
rjmp display_LCD

;**************************************************************************
;*
;*"inc_1" - increment frequency by 10 Hz
;*
;*Description: This subroutine increment the current frequency by 10 Hz
;*
;*Author: Muhammad Aman
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17, r30, r31
;*
;***************************************************************************

inc_10: ;increase frequency by 10Hz
rcall check_freq
clc
ldi r16, $64
add r30, r16
ldi r16, $00
adc r31, r16
push r31
push r30
rcall div32u
dec r16
out OCR1AH, r17
out OCR1AL, r16
pop r30
pop r31
rcall bin2bcd16
rjmp display_LCD

;**************************************************************************
;*
;*"twice_half" - Checks if the frequency has to be doubled or half
;*
;*Description: This subroutine checks how much frequency has to be incremented or decremented
;* by scanning the input from PORTB
;*
;*Author: Muhammad Aman 
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16
;*
;***************************************************************************

twice_half:
cpi r16, 0b00100000
breq twice
cpi r16, 0b00000000
breq half

;**************************************************************************
;*
;*"twice" - Doubles the frequency
;*
;*Description: This subroutine doubles the current frequency
;*
;*Author: Muhammad Aman
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17, r30, r31
;*
;***************************************************************************

twice:
rcall check_freq
clc
lsl r30
rol r31
push r31
push r30
rcall div32u
dec r16
out OCR1AH, r17
out OCR1AL, r16
pop r30
pop r31
rcall bin2bcd16
rjmp display_LCD

;**************************************************************************
;*
;*"half" - Half the current frequency
;*
;*Description: This subroutine divides the frequency to half
;*
;*Author: Muhammad Aman
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17, r30, r31
;*
;***************************************************************************
half:
clc
lsr r31
ror r30
push r31
push r30
rcall check_freq
rcall div32u
dec r16
out OCR1AH, r17
out OCR1AL, r16
pop r30
pop r31
rcall bin2bcd16
rjmp display_LCD

;**************************************************************************
;*
;*"delay_50ms" - 50 ms delay subroutine
;*
;*Description: This subroutine perform delay of 50 ms
;*
;*Author: Muhammad Aman 
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17
;*
;***************************************************************************

delay_50ms:
ldi r17, 65 ;load int 65 to r17
outer_loop:
ldi r16, $FF ;load int 255 to r16
inner_loop:
dec r16 ;r16 = r16 - 1
brne inner_loop ;branch if r16 = 0
dec r17 ;r17 = r17 - 1
brne outer_loop ;branch if r17 = 0
ret

;**************************************************************************
;*
;*"display_LCD" - Display the current frequency on LCD
;*
;*Description: This subroutine displays the current frequency to LCD by the help of bin2bcd16 subroutine
;*
;*Author: Muhammad Aman 
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*Low Register Used: r13, r14
;*
;*High Registers Used: r16
;*
;***************************************************************************

display_LCD:
mov r16, r13
push r16
andi r16, 0b00001111
ori r16, 0b11000000
out PORTA, r16
cbi PORTA, 6
sbi PORTA, 6
pop r16
andi r16, 0b11110000
lsr r16
lsr r16
lsr r16
lsr r16
ori r16, 0b11010000
out PORTA, r16
cbi PORTA, 6
sbi PORTA, 6
mov r16, r14
push r16
andi r16, 0b00001111
ori r16, 0b11100000
out PORTA, r16
cbi PORTA, 6
sbi PORTA, 6
pop r16
andi r16, 0b11110000
lsr r16
lsr r16
lsr r16
lsr r16
ori r16, 0b11110000
out PORTA, r16
cbi PORTA, 6
sbi PORTA, 6
ldi r16, GICR
andi r16, 0b10111111
out GIFR, r16
rjmp main_loop

;**************************************************************************
;*
;*"chech_freq" - Checks the current frequency
;*
;*Description: This subroutine checks the current frequency and performs different tasks
;* for two different frequency namely (10 - 100 Hz) and (100.1 - 999.9 Hz)
;*
;*Author: Muhammad Aman
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r30, r31
;*
;***************************************************************************

check_freq:
push r31
subi r31, 4
brsh prescaling_1_31
pop r31
push r31
cpi r31, 3
brlo prescaling_8_31
pop r31
push r30
subi r30, 0b11101001
brsh prescaling_1_30
pop r30
rjmp prescaling_8_30

;**************************************************************************
;*
;*"prescaling_1_31" - change prescale to 1 with the help of high byte of frequency
;*
;*Description: This subroutine change the prescaling to 1 sets the divider to 10000000
;*
;*Author: Muhammad Aman 
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17
;*
;***************************************************************************

prescaling_1_31:
pop r31
ldi r16, (0<<CS12) | (0<<CS11) | (1<<CS10) | (1<<WGM13) | (1<<WGM12)
out TCCR1B, r16
ldi r16, $80
ldi r17, $96
ldi r18, $98
ldi r27, $01
ret

;**************************************************************************
;*
;*"prescaling_1_30" - change prescale to 1 with the help of low byte of frequency
;*
;*Description: This subroutine change the prescaling to 1 sets the divider to 10000000
;*
;*Author: Muhammad Aman
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17
;*
;***************************************************************************

prescaling_1_30:
pop r30
ldi r16, (0<<CS12) | (0<<CS11) | (1<<CS10) | (1<<WGM13) | (1<<WGM12)
out TCCR1B, r16
ldi r16, $80
ldi r17, $96
ldi r18, $98
ldi r27, $01
ret

;**************************************************************************
;*
;*"prescaling_8_31" - change prescale to 8 with help of low bit of frequency
;*
;*Description: This subroutine change the prescaling to 8 sets the divider to 1250000
;*
;*Author: Muhammad Aman 
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17
;*
;***************************************************************************

prescaling_8_31:
pop r31
ldi r16, (0<<CS12) | (1<<CS11) | (0<<CS10) | (1<<WGM13) | (1<<WGM12)
out TCCR1B, r16
ldi r16, $D0
ldi r17, $12
ldi r18, $13
ldi r27, $08
ret

;**************************************************************************
;*
;*"prescaling_8_30" - change prescale to 0 with the help of high bit of frequency
;*
;*Description: This subroutine change the prescaling to 8 sets the divider to 1250000
;*
;*Author: Muhammad Aman 
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r17
;*
;***************************************************************************

prescaling_8_30:
ldi r16, (0<<CS12) | (1<<CS11) | (0<<CS10) | (1<<WGM13) | (1<<WGM12)
out TCCR1B, r16
ldi r16, $D0
ldi r17, $12
ldi r18, $13
ldi r27, $08
ret

;**************************************************************************
;*
;*"isr_pulse" - Interrupt service routine for OCR1A
;*
;*Description: This subroutine is called when OCR1A equals TCNT1
;*
;*Author: Muhammad Aman
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r26
;*
;***************************************************************************

isr_pulse: ;makes 4us pulse
ldi r16, TCCR1B
ldi r26, $10
clc
lsr r16
sbrc r16, 0
rjmp isr_pulse_1 ;jump to pulse for prescale 1
sbi PORTD, 0
nop
nop
nop
nop
cbi PORTD, 0 ;generate a positive pulse for 4us
ldi r16, $00
out TCNT1H, r16
out TCNT1L, r16 ;clear the timer/counter
rjmp main_loop

;**************************************************************************
;*
;*"isr_pulse_1" - Interrupt service routine for OCR1A
;*
;*Description: This subroutine is called when OCR1A equals TCNT1 and current prescaling is 1
;*
;*Author: Muhammad Aman
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r26
;*
;***************************************************************************

isr_pulse_1:
sbi PORTD,0
rcall delay_50ms
cbi PORTD,0
dec r26
brne isr_pulse_1
ldi r16, $00
out TCNT1H, r16
out TCNT1L, r16 ;clear the timer/counter
rjmp main_loop


;**************************************************************************
;*
;*"reset" - Initializing
;*
;*Description: This subroutine initializes interrupts, pins, stack pointers, initial frequency,
;* initial prescaling and interrupt sense
;*
;*Author: Muhammad Aman
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*Low Registers Used: r09
;*
;*High Registers Used: r16, r28, r29, r30, r31
;* r30 = low bits of frequency throughout the program
;* r31 = high bits of frequency throughout the program
;*
;***************************************************************************

reset:
ser r16 ; Set all bits in register
out DDRA, r16 ; Set Port A as output
ldi r16, $00 ; Clear all bits in register
out DDRB, r16 ; Set Port B as input
ldi r16, $01 ; Set PD0 as output for pulse generation
out DDRD, r16 ; Configure others as input

ldi r16, HIGH(RAMEND) ;initialize stack
out SPH, r16
ldi r16, LOW(RAMEND)
out SPL, r16

ldi r29, $09 ;Initialize r29:r28 (OCR1A to generate 50 Hz frequency)
out OCR1AH, r29
ldi r28, $C3
out OCR1AL, r28

ldi r31, $01 ;Initialize r31:r30 (Freq = 50 Hz)
ldi r30, $F4

ldi r16, 1<<INT0 ;Enable INT0
out GICR, r16
ldi r16, $03 ;Enable INT0 request
out MCUCR, r16

ldi r16, 1<<OCIE1A ;Enable Output Compare A Match Interrupt
out TIMSK, r16

ldi r16, (0<<CS12) | (1<<CS11) | (0<<CS10) | (1<<WGM13) | (1<<WGM12) ;Set Mode: Fast PWM
out TCCR1B, r16
ldi r16, (1<<WGM11) | (1<<WGM10)
out TCCR1A, r16

;**************************************************************************
;*
;*"display_50Hz" - Display 50 Hz on LCD initially
;*
;*Description: This subroutine displays 050.0 on LCD initially
;*
;*Author: Muhammad Aman 
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;*High Registers Used: r16, r26
;*
;***************************************************************************

display_50Hz:
ldi r16, 0b11000000
cbi PORTA, 6
sbi PORTA, 6
out PORTA, r16
ldi r16, 0b11010000
cbi PORTA, 6
sbi PORTA, 6
out PORTA, r16
ldi r16, 0b11100101
cbi PORTA, 6
sbi PORTA, 6
out PORTA, r16
ldi r16, 0b11110000
cbi PORTA, 6
sbi PORTA, 6
out PORTA,r16
cbi PORTA, 6
sbi PORTA, 6

;**************************************************************************
;*
;*"main_loop" - Self Loop
;*
;*Description: This subroutine is a self loop which waits for interrupts
;*
;*Author: Muhammad Aman 
;*Version: 1.0
;*Last updated: 12/12/2006
;*
;***************************************************************************

main_loop:
sei
nop

 

Home | Stroboscope | Advanced VLSI System Design | Intelligent Thermostate | Alert Analyzer