Вы находитесь на странице: 1из 26

;------------- m2-example01: Poll 2 input pins - set 2 output pins -------------

;Purpose: Endless loop with polling of two input flags. When a flag is set, the
; corresponding output is set. Both input and output pins are in the same Port.
; Both input and output pins are activated when set (=1).
;
;Comments:
; - At power-on the state of the input pins is unknown (they are not given an
; initial value). It was considered proper to wait for the input pins to be
; externally cleared before entering the polling loop (it is assumed that no
; alarm case occurs before the flag polling loop starts).
; - PortA2 is set when PinA0 is detected set, PortA3 is set when PinA1 is detected
; set.
; - Since it is not specified otherwise, the output pins are only cleared by
; reset.
;--------------------
;---------- Main program ----------
.include "m128def.inc"
.def temp=R16
.cseg
.org 0
jmp reset
.org $0100
;----------
reset:
; initialization of the Stack Pointer - redundant
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
; initialization of the Data Direction Registers
ldi temp, 0b00001100 ; pins 3 and 2 are outputs
out DDRA, temp
; setting the initial output value to the output pins - redundant
cbi PORTA, 2
cbi PORTA, 3
; wait until input pins initialize to low level
wait_inp_init0:
sbic PINA, 0
rjmp wait_inp_init0
wait_inp_init1:
sbic PINA, 1
rjmp wait_inp_init1
; endless loop that polls the input flags
loop:
sbic PINA, 0
sbi PORTA, 2
sbic PINA, 1
sbi PORTA, 3
rjmp loop
nop
;----- End of main program -----
.undef temp
;-------------------- m2-example02: 1-byte I/O to/from SRAM --------------------
;Purpose: Input - output communication with a peripheral device using interrupts.
; Port A is used to input a 1-byte value from the peripheral device to the SRAM
; and Port B to output. Input's priority is higher. Handshaking is used in both
; cases.
;
;Comments:
; - PortD2 is used for handshaking during input, PortD3 is used for handshaking
; during output. Regarding the handshaking response, in both cases the rising
; edge means that the external request has been sensed and the falling edge
; means that the external request has been processed.
; - Since it is not specified otherwise, the inputted/outputted value is stored
; to/read from an array element indexed by the value in Port C. To simplify
; the calculation of the target address, the array consists of 256 elements
; and the array's starting address low byte equals to $00, therefore the high
; byte of the address of all the array's elements has the same value ($04).
;--------------------
;---------- Main program ----------
.include "m128def.inc"
.def temp=R16
.dseg
.org $0400
io_array: .BYTE 256
.cseg
.org 0
jmp reset
jmp EXT_INT0
.org $004
jmp EXT_INT1
.org $0100
;----------
reset:
; initialization of the Stack Pointer
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
; initialization of the Data Direction Registers
clr temp
out DDRA, temp ; redundant, same as the default value
out DDRC, temp ; redundant, same as the default value
ldi temp, $FF
out DDRB, temp
ldi temp, 0b00001100
out DDRD, temp ; PortD2 and PortD3 are used for the handshaking responses
; initialization of the External Interrupt Control Register
ldi temp, 0b00001011 ; ext_int1: 1->0, ext_int0: 0->1
sts EICRA, temp
; completing any other operation before enabling interrupts
ldi ZH, HIGH(io_array)
; enabling external interrupts
ldi temp, 0b00000011
out EIMSK, temp
sei
; waiting for an external interrupt
set
loop:
brts loop
nop
;----- End of main program -----
;
;
;--------------- EXT_INT0 ISR: read Port A and store to SRAM ---------------
;Title: EXT_INT0
;Purpose: Serve the interrupt caused by the rising edge at INT0 (PD0). Port A is
; read and the read value is stored to an array in SRAM indexed by the current
; value in Port C
;Input Parameters:
; -
;Other variables:
; -
;"Special purpose" Registers used: R31:R30 (Z) for indexing SRAM
;Exit: - (The interrupt is no longer pending (INTF0=0) and storage took place)
;Errors: -
;Comments:
; - Handshaking response is implemented through PortD2
;--------------------
EXT_INT0:
sbi PORTD, 2 ; handshaking: external request detected
in temp, PINA
in ZL, PINC
st Z, temp
cbi PORTD, 2 ; handshaking: external request processed
reti
;----- End of interrupt service routine EXT_INT0 -----
;
;
;------------- EXT_INT1 ISR: write to Port B a value read from SRAM -------------
;Title: EXT_INT1
;Purpose: Serve the interrupt caused by the falling edge at INT1 (PD1). Port B is
; written with a value read from an array in SRAM indexed by the current
; value in Port C
;Input Parameters:
; -
;Other variables:
; -
;"Special purpose" Registers used: R31:R30 (Z) for indexing SRAM
;Exit: - (The interrupt is no longer pending (INTF1=0) and output took place)
;Errors: -
;Comments:
; - Handshaking response is implemented through PortD3
;--------------------
EXT_INT1:
sbi PORTD, 3 ; handshaking: external request detected
in ZL, PINC
ld temp, Z
out PORTB, temp
cbi PORTD, 3 ; handshaking: external request processed
reti
;----- End of interrupt service routine EXT_INT1 -----
;
;
.undef temp
;---------- m2-example03: Count external time using Timer/Counter 2 ----------
;Purpose: Timer/Counter 2 is used to count incoming pulses (1 per second). The
; elapsed time in seconds, minutes, hours and days since reset is kept. The
; Counter is triggered by the rising edge of the pulse. Handshaking is used.
;
;Comments:
; - Since the "processing" of the external pulse is instant (automatic
; increment of Timer/Counter 2), the incoming pulse signal is connected
; (apart from PinD7->T2) also to PinD0 in order to trigger an external
; interrupt for the handshaking implementation. PortD6 is used for the
; handshaking response. The rising edge means that the external pulse has
; been sensed and (since the "processing" is instant) the falling edge
; follows after a short delay (long enough for the pulse's source device).
; - "Seconds" are not stored in a general purpose register. They are counted
; in Timer/Counter2 which can be read anytime.
; - Since "days" are stored in an 1-byte register, the maximum time counted
; by this program is 255 days, 23 hours, 59 minutes and 59 seconds.
;--------------------
;---------- Main program ----------
.include "m128def.inc"
.def temp=R16
.def minutes=R17
.def hours=R18
.def days=R19
.cseg
.org 0
jmp reset
jmp EXT_INT0
.org $012
jmp T2_CMP
.org $0100
;----------
reset:
; initialization of the Stack Pointer
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
; initialization of the Data Direction Registers
sbi DDRD, 6 ; PortD6 is used for the handshaking response
; initialization of the Timer/Counter 2 Control Register
ldi temp, 0b00001111 ; CTC mode (0bx0xx1xxx), OC2 disconnected
(0bxx00xxxx)
; and external clock source on T2 pin clock on rising edge (0bxxxxx111)
out TCCR2, temp
; initialization of the Output Compare Register 2
ldi temp, 59
out OCR2, temp
; clearing the whole clock - redundant
clr days
clr hours
clr minutes
out TCNT2, minutes
; initialization of the External Interrupt Control Register
ldi temp, 0b00000011 ; ext_int0: 0->1
sts EICRA, temp
; enabling interrupts
ldi temp, 0b10000000
out TIMSK, temp ; enabling Timer/Counter2 Compare Match interrupt
ldi temp, 0b00000001
out EIMSK, temp ; enabling external interrupts
sei
; waiting for an external interrupt
set
loop:
brts loop
nop
;----- End of main program -----
;
;
;------------ EXT_INT0 ISR: implementation of handshaking response ------------
;Title: EXT_INT0
;Purpose: Serve the interrupt caused by the rising edge at INT0 (PD0). PortD6
; is set for a short period, long enough to be sensed by the pulse's source
; device, as a handshaking response.
;Input Parameters:
; -
;Other variables:
; -
;Exit: - (The interrupt is no longer pending (INTF0=0) and PortD6 was set for a
; short period)
;Errors: -
;Comments:
; - Handshaking response is implemented through PortD6
;--------------------
EXT_INT0:
sbi PORTD, 6 ; handshaking: external request detected
sei ; since a delay is going to take place, probably other interrupts
; should be allowed. Assuming the other ISRs are short enough, the
; handshaking response is not going to be set too long to cause
; problems. Otherwise, interrupts should not be enabled within EXT_INT0
nop
nop ; or call a delay subroutine if a longer response pulse is required
nop
cbi PORTD, 6 ; handshaking: external request processed
reti
;----- End of interrupt service routine EXT_INT0 -----
;
;
;--------------- T2_CMP ISR: update the registers that keep time ---------------
;Title: T2_CMP
;Purpose: Serve the interrupt caused by the compare match of TCT2 and OCR2. All
; registers that keep the elapsed time are updated.
;Input Parameters:
; -
;Other variables:
; -
;Exit: - (interrupt no longer pending (OCF2=0) and time registers updated)
;Errors: -
;Comments:
; -
;--------------------
T2_CMP:
inc minutes
cpi minutes, 60
brne time_updated
clr minutes
inc hours
cpi hours, 24
brne time_updated
clr hours
inc days
time_updated:
reti
;----- End of interrupt service routine T2_CMP -----
;
;
.undef temp
.undef minutes
.undef hours
.undef days
;----------------- m2-example04: read 12-bit inputs - calc sum -----------------
;Purpose: 6 12-bit values are inputted using PinB3-0:PinA7-0 (i.e. PinA is used
; for the LSByte). The inputted values are stored in an array in SRAM (after
; sign prolongation for their correct representation as 16-bit values) and
; added. Handshaking controls the input of the 6 values.
;
;Comments:
; - PinB7 is used as a flag for handshaking's "initiation" (0->1 signals that
; new data is available to be inputted) and PortB6 is used for the
; handshaking response. At PortB6, the rising edge means that the external
; request has been sensed and the falling edge means that the inputted data
; has been processed.
; - At power-on the state of the input pins is unknown (they are not given an
; initial value). It was considered proper to wait for the input PinB7 to be
; externally cleared and then wait for it to get set.
; - The handshaking initiation needs careful approach, since checking a flag
; reveals only its current state and does not reveal any state transitions.
; The following code is correct if the flag in PinB7 has been cleared by the
; peripheral device before the program has completed processing the inputted
; data and jumped back to check the flag again. If by that time the flag
; hasn't been cleared, the same input will be read twice (or more times).
; In such cases interrupt driven input should be used instead of flag
; driven input, since interrupts can be triggered by state transitions.
; - "Special purpose" Registers used: R31:R30 (Z) for indexing SRAM.
;--------------------
;---------- Main program ----------
.include "m128def.inc"
.def temp=R16
.def count=R17
.def sum_L=R18
.def sum_H=R19
.dseg
msrmnt_array: .BYTE 14 ; (2-byte values, 6 inputs, 1 output)
.cseg
.org 0
jmp reset
.org $0100
;----------
reset:
; initialization of the Stack Pointer - redundant, Stack is not used
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
; initialization of the Data Direction Registers
clr temp
out DDRA, temp ; redundant, same as the default value
out DDRB, temp ; redundant, same as the default value
sbi DDRB, 6 ; PortB6 is used for the handshaking response
; setting the initial output value to the output pins - redundant
cbi PORTB, 6
; initialization before input start
clr sum_L ; redundant, same as the default value
clr sum_H ; redundant, same as the default value
ldi count, 6
ldi ZL, LOW(msrmnt_array)
ldi ZH, HIGH(msrmnt_array)
; wait until flag initialize to low level
wait_inp_init:
sbic PINB, 7
rjmp wait_inp_init
; end of preparation actions
repeat:
sbis PINB, 7 ; check the flag
rjmp repeat ; wait for the flag to be set
sbi PORTB, 6 ; handshaking: flag detected set
in temp, PINA ; read the number's lower byte
st Z+, temp ; store in the array
add sum_L, temp ; add to the sum
brcc cont_1 ; no carry occurred
inc sum_H ; increment due to the carry from the preceding addition
cont_1:
in temp, PINB ; read the 4 higher bits (stored in PinB3-0)
andi temp, $0F ; keep only the useful nibble
sbrc temp, 3 ; check the sign of the number
ori temp, $F0 ; prolong the negative sign
st Z+, temp ; store the higher byte
add sum_H, temp ; add to the sum
cbi PORTB, 6 ; handshaking: ready to receive new input
dec count ; reduce the number of values remaining to be inputted
brne repeat ; go back to input another value
st Z+, sum_L ; store sum's LSByte
st Z, sum_H ; store sum's MSByte
nop
rjmp reset
;----- End of main program -----
.undef temp
.undef count
.undef sum_L
.undef sum_H
;--------- m2-example05: Check IC SN7402 - plain output/input sessions ---------
;Purpose: Check of IC SN7402: a test byte is outputted to SN7402 and the resulting
; nibble is compared against a pre-stored value. The procedure takes place 4
; times (all the possible input-pairs to a logic gate). If one or more times the
; resulting nibble does not match the expected one, $AA is stored at the SRAM
; position "check"; otherwise, "check" is cleared. The whole procedure starts
; when PinA0 gets set (sensed by flag testing).
;Comments:
; - At power-on the state of the input pins is unknown (they are not given an
; initial value). It was considered proper to wait for the input pinA0 to be
; externally cleared and then wait for it to get set.
; - "Special purpose" Registers used: R31:R30 (Z) for indexing Flash memory.
;--------------------
;---------- Main program ----------
.include "m128def.inc"
.def temp=R16
.def count=R17
.def result=R18
.dseg
.org $0100
check: .BYTE 1
.cseg
.org 0
jmp reset
.org $0100
test_pairs: .DB 0b11111111, 0b00000000, 0b10101010, 0b00000000, 0b01010101, \
0b00000000, 0b00000000, 0b11110000
;----------
reset:
; initialization of the Stack Pointer - redundant, Stack is not used
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
; initialization of the Data Direction Registers
clr temp
out DDRA, temp ; redundant, same as the default value
ldi temp, $FF
out DDRB, temp
; wait until flag initialize to low level
wait_inp_init:
sbic PINA, 0
rjmp wait_inp_init
; initialization of auxiliary checking parameters
ldi ZL, LOW(2*test_pairs)
ldi ZH, HIGH(2*test_pairs)
ldi count, 4
; wait for the flag to be set externally
wait_flag_set:
sbis PINA, 0
rjmp wait_flag_set
; perform testing
cnt_test:
lpm temp, Z+
out PORTB, temp
nop ; wait in case there any considerable delays
lpm result, Z+
in temp, PINA
andi temp, $F0
cp result, temp
brne faulty
dec count
brne cnt_test
sts check, count ; here count =0
nop
rjmp reset
;-----
faulty:
ldi temp, $AA
sts check, temp
nop
rjmp reset
;----- End of main program -----
.undef temp
.undef count
.undef result
;---------------- m2-example06: input 3 blocks of measurements ----------------
;Purpose: Three blocks of measurements (pressure, temperature and liquid level)
; are inputted from an external device and stored to the SRAM, each at a
; predefined block starting address. All blocks consist of the same number of
; 1-byte measurements and the maximum number of measurements is 256. Initially
; the number of measurements to be transmitted is inputted, then the first
; measurement's block, the second block and the third block. The whole
; procedure is control by flag checking and handshaking.
;
;Comments:
; - PinB7 is used as a flag for handshaking's "initiation" (0->1 signals that
; new data is available to be inputted) and PortB6 is used for the
; handshaking response. At PortB6, the rising edge means that the external
; request has been sensed and the falling edge means that the inputted data
; has been processed.
; - At power-on the state of the input pins is unknown (they are not given an
; initial value). It was considered proper to wait for the input PinB7 to be
; externally cleared and then wait for it to get set.
; - The handshaking initiation needs careful approach, since checking a flag
; reveals only its current state and does not reveal any state transitions.
; The following code is correct if the flag in PinB7 has been cleared by the
; peripheral device before the program has completed processing the inputted
; data and jumped back to check the flag again. If by that time the flag
; hasn't been cleared, the same input will be read twice (or more times).
; In such cases interrupt driven input should be used instead of flag
; driven input, since interrupts can be triggered by state transitions.
; - Zero value for number of measurements is interpreted as equal to 256 in
; order to avoid using an extra pin and a two-byte counter (inputting 0
; measurements doesn't make sense anyway).
; - "Special purpose" Registers used: R31:R30 (Z) for indexing SRAM.
;--------------------
;---------- Main program ----------
.include "m128def.inc"
.def temp=R16
.def count=R17
.macro FLG_READ_PORTA
sbis PINB, 7 ; check the flag
rjmp @0 ; wait for the flag to be set
sbi PORTB, 6 ; handshaking: flag detected set
in temp, PINA
st Z+, temp ; store the value inputted
cbi PORTB, 6 ; handshaking: ready to receive new input
.endmacro
.dseg
.org $0100
measrmnt_num: .BYTE 1
.org 512
pressr_stad: .BYTE 256
temprt_stad: .BYTE 256
lqd_lvl_stad: .BYTE 256
.cseg
.org 0
jmp reset
.org $0100
;----------
reset:
; initialization of the Stack Pointer - redundant, Stack is not used
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
; initialization of the Data Direction Registers
clr temp
out DDRA, temp ; redundant, same as the default value
cbi DDRB, 7 ; redundant, same as the default value
sbi DDRB, 6 ; PortB6 is used for the handshaking response
; setting the initial output value to the output pins - redundant
cbi PORTB, 6
; wait until flag initialize to low level
wait_inp_init:
sbic PINB, 7
rjmp wait_inp_init
; end of preparation actions
ldi ZL, LOW(measrmnt_num)
ldi ZH, HIGH(measrmnt_num)
get_measrmnt_num:
FLG_READ_PORTA get_measrmnt_num
mov count, temp
ldi ZL, LOW(pressr_stad)
ldi ZH, HIGH(pressr_stad)
pressr_loop:
FLG_READ_PORTA pressr_loop
dec count
brne pressr_loop
ldi ZL, LOW(measrmnt_num)
ldi ZH, HIGH(measrmnt_num)
ld count, Z
ldi ZL, LOW(temprt_stad)
ldi ZH, HIGH(temprt_stad)
temprt_loop:
FLG_READ_PORTA temprt_loop
dec count
brne temprt_loop
ldi ZL, LOW(measrmnt_num)
ldi ZH, HIGH(measrmnt_num)
ld count, Z
ldi ZL, LOW(lqd_lvl_stad)
ldi ZH, HIGH(lqd_lvl_stad)
lqd_lvl_loop:
FLG_READ_PORTA lqd_lvl_loop
dec count
brne lqd_lvl_loop
nop
rjmp reset
;----- End of main program -----
.undef temp
.undef count
;---------------- m2-example07: Sequential activation of 4 motors ----------------
;Purpose: Sequential activation of 4 motors with a short delay of 20 seconds in
; between. The whole procedure starts when a flag (PinB4) gets set (flag polling
; is used). The motors are activated when the corresponding output pin is low
; (equal to zero).
;
;Comments:
; - At power-on the state of the input pins is unknown (they are not given an
; initial value). It was considered proper to wait for the input pinB4 to be
; externally cleared and then wait for it to get set.
; - Subroutine TIME_DEL_A is used in order to achieve 20 seconds' delays. The
; subroutine's total execution time (from "rcall" till after "ret") is :
; 9+5*Ni*No+5*No-1 = 5*Ni*No+5*No+8 and we consider additional 7 clock
; cycles for the execution of the other instruction in the "actv_loop". By
; choosing No=4096 ($1000), Ni=3905 ($0F41) and the clock at 4 MHz, the time
; delay between two sequential activations is 19.9987 seconds.
;--------------------
;---------- Main program ----------
.include "m128def.inc"
.def temp=R16
.def mtr_bit=R17
.cseg
.org 0
jmp reset
.org $0100
;----------
reset:
; initialization of the Stack Pointer
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
; initialization of the Data Direction Registers
ldi temp, $0F
out DDRB, temp
; setting the initial output value to the output pins
out PORTB, temp ; each motor gets activated by setting its pin equal to 0
; wait until flag initialize to low level
wait_inp_init:
sbic PINB, 4
rjmp wait_inp_init
; initialization of auxiliary checking parameters
ldi mtr_bit, 1
; wait for the flag to be set externally
wait_flag_set:
sbis PINB, 4
rjmp wait_flag_set
; perform testing
actv_loop:
eor temp, mtr_bit ; the bit that corresponds to the next motor (to be
; activated) is cleared in "temp"
out PORTB, temp
cpi mtr_bit, $08 ; check if all motors have been activated
breq all_actv
lsl mtr_bit ; prepare for next motor
rcall TIME_DEL_A
rjmp actv_loop
all_actv:
nop
rjmp reset
;----- End of main program -----
;
;
;-------------------- Time Delay A --------------------
;Title: TIME_DEL_A
;Purpose: Create a time delay using two 16-bit counters
; ! Ni: number of times the inner loop is executed ("inner_count"'s initial value)
; ! No: number of times the outer loop is executed ("outer_count"'s initial value)
; ! Ti: inner loop's duration time (in clock cycles)
; ! To: outer loop's duration time (in clock cycles)
; Ti = 5*(Ni-1)+4 = 5*Ni-1
; To = (Ti+6)*(No-1)+(Ti+5) =(Ti+6)*No-1 = (5*Ni-1+6)*No-1 =
5*Ni*No+5*No-1
; Subroutine's total execution time (from "rcall" till after "ret"):
; 9+5*Ni*No+5*No-1 = 5*Ni*No+5*No+8
;Input Parameters: -
;Other variables:
; inner_count: inner loop's counter - stored in R25:R24
; outer_count: outer loop's counter - stored in R27:R26
;Exit: - (return to main program after a specific time delay)
;Errors: -
;Comments:
; - The initial values of the counters may be provided as input parameters if the
; delay needs to be determined during program execution.
; - The register pairs R25:R24 and R27:R26 are used as 16-bit counters, thus
; enabling longer time delays. For small initial values (<256), employment of
; 16-bit counters just increases the clock cycles per inner loop and outer loop.
;--------------------
.def inner_count_L=R24
.def inner_count_H=R25
.def outer_count_L=R26 ; (XL)
.def outer_count_H=R27 ; (XH)
;----------
TIME_DEL_A:
ldi outer_count_L, $00 ; 1 cycle
ldi outer_count_H, $10 ; 1 cycle
outer_loop:
ldi inner_count_L, $41 ; 1 cycle
ldi inner_count_H, $0F ; 1 cycle
inner_loop:
nop ; 1 cycle, possible use of more "nop" instructions for longer
delays
sbiw inner_count_L, 1 ; 2 cycles
brne inner_loop ; 2 cycles if true (Ni-1 times), 1 cycle if false
sbiw outer_count_L, 1 ; 2 cycles
brne outer_loop ; 2 cycles if true (No-1 times), 1 cycle if false
ret ; 4 cycles (plus 3 cycles for rcall)
;----- End of subroutine TIME_DEL_A -----
.undef inner_count_L
.undef inner_count_H
.undef outer_count_L
.undef outer_count_H
;
;
.undef temp
.undef mtr_bit
;---------- m2-example08: Count external events using Timer/Counter 2 ----------
;Purpose: Timer/Counter 2 is used by a subroutine to count incoming pulses
; (derived by a switch (D1) that gets closed by passing-by objects). Either
; when 255 objects have been counted or when switch D2 has been activated the
; value of the counter is outputted to Port C and the subroutine returns. If
; switch D3 is activated the value of the counter is outputted to Port B and
; the subroutine keeps running. Switch D1 is connected to PinD7->T2 to "clock"
; Timer/Counter 2, switch D2 is polled (connected to PinD6) and switch D3 is
; connected to PinD0 in order to trigger an external interrupt. Pin 7 of PORTB
; used as output OC2. This pin is connected as IRQ (INT1).Thus
; the appearance of the object is reconized immediately.
;
;Comments:
; - Since Timer/Counter 2 is cleared at the beginning of the subroutine, the
; Normal mode is used instead of the CTC mode (Clear Timer on Compare match).
; Therefore, a correct value can be read from TCNT2 (by activating switch D3)
; even after the "CNT_OBJCTS" subroutine has been terminated.
;--------------------
;---------- Main program ----------
.include "m128def.inc"
.def temp=R16
.cseg
.org 0
jmp reset
jmp EXT_INT0
jmp EXT_INT1
.org $0100
;----------
reset:
; initialization of the Stack Pointer
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
; initialization of the Data Direction Registers
clr temp
out DDRD, temp ; redundant, same as the default value
ldi temp, $FF
out DDRC, temp
sbi DDRB, 7
; initialization of the Timer/Counter 2 Control Register
ldi temp, 0b00110111 ; normal mode (0bx0xx0xxx), SET OC2 on compare
match(0bxx11xxxx)
; and external clock source on T2 pin clock on rising edge (0bxxxxx111)
out TCCR2, temp
; initialization of the Output Compare Register 2
ldi temp, 255 ; read the last Comment of the Header comments
out OCR2, temp
; initialization of the External Interrupt Control Register
ldi temp, 0b00001111 ; ext_int0, ext_int1: 0->1
sts EICRA, temp
; enabling interrupts
ldi temp, 0b00000011
out EIMSK, temp ; enabling external interrupt 0
sei
; start counting objects passing by
rjmp CNT_OBJCTS
nop
rjmp reset
;----- End of main program -----
;
;
;---------- CNT_OBJCTS: Count external events using Timer/Counter 2 ----------
;Title: CNT_OBJCTS
;Purpose: Timer/Counter 2 is used to count incoming pulses. Either when 255
; pulses have been counted or when PinD6 gets set, the value of the counter
; is outputted to Port B and the subroutine returns.
;Input Parameters:
; -
;Other variables:
; -
;Exit: - (The counted external events have been outputted to Port B)
;Errors: -
;Comments:
; - Looping ends when "T" is cleared either by "T2_CMP_A" (TCNT2=OCR2) or by
; the "clt" instruction that follows the polling of PinD6.
; - In order to avoid the extreme case that TCNT2 is increased after
; "Timer/Counter2 Compare Match" has been detected but before the timer's
; value gets outputted, the outputted value is not read from TCNT2. Instead,
; the max value to be counted ((OCR2)+1) is outputed from within the
; "EXT_INT1" Interrupt routine and "temp" is used as a
; flag in order to skip outputting to Port B from within the "CNT_OBJCTS"
; subroutine.
; - In the extreme case that TCNT2 is increased within 4 clock cycles after
; PinD6 gets set, the value outputted to Port B might be inaccurate (one
; more pulse might be counted). This case is overseen since it is quite
; complicated to be resolved (Timer/Counter 2 should not be used and the
; the switch connected to PinD6 should cause an external interrupt) and is
; rather exceptional to deal with a system for which time resolution of the
; order of 1 microsecond is crusial.
;--------------------
CNT_OBJCTS:
clr temp
out TCNT2, temp ; clearing of the counter
set
loop:
sbic PIND, 6
clt
brts loop
sbrc temp, 0 ; temp=0 means that loopping ended because PinD6 got set
rjmp skip_output ; jump since output took place from withnin "T2_CMP_A"
in temp, TCNT2
out PORTC, temp
skip_output:
ret
;----- End of subroutine CNT_OBJCTS -----
;
;
;---------- EXT_INT0 ISR: output current value of TCNT2 to Port B ----------
;Title: EXT_INT0
;Purpose: Serve the interrupt caused by the rising edge at INT0 (PD0). The
; current value of TCNT2 is outputted to Port B.
;Input Parameters:
; -
;Other variables:
; - temp_a: auxiliary register used to read from TCNT2 and write to Port B
;Exit: - (The interrupt is no longer pending (INTF0=0) and the current value
; of TCNT2 has been outputted to Port B)
;Errors: -
;Comments:
; -
;--------------------
.def temp_a=R17
;----------
EXT_INT0_A:
in temp_a, TCNT2
out PORTC, temp_a
reti
;----- End of interrupt service routine EXT_INT0_A -----
.undef temp_a
;
;
;------ EXT_INT1 ISR: output OC2 to Port D (INT1) and set flags for
"CNT_OBJCTS" ------
;Title: EXT_INT1
;Purpose: Serve the interrupt caused by the compare match of TCT2 and OCR2. The
; max value to be counted (OCR2) is outputed to Port C, "T" is cleared to
; indicate that loopping should end and "temp" is set to indicate that output
; to Port C has taken place.
;Input Parameters:
; -
;Other variables:
; -
;Exit: -
;Errors: -
;Comments:
; - "temp" is set in order to signal that output to Port B has taken place from
; within T2_CMP_A and, therefore, it should be skipped in "CNT_OBJCTS".
;--------------------
EXT_INT1:
in temp, OCR2 ; to make the code more general instead of "ldi temp, 255"
; OCR2 is read
out PORTC, temp
clt
ser temp ; to make the code more general
reti
;----- End of interrupt service routine EXT_INT1 -----
;
;
.undef temp
;----------------- m2-example09: Customizable ON/OF recurrence -----------------
;Purpose: An output pin is repeatedly set and cleared for short time periods
; specified by the user. Initially, the program reads the time period the pin
; will be set (when flag PinC0 gets set), the time period the pin will be
; cleared (when flag PinC1 gets set) and the number of the ON/OFF recurrences
; (when flag PinC2 gets set). Then, when flag PinC3 gets set by the user, it
; repeatedly sets and clears PortC7 for the prespecified time periods and
; number of recurrences while displaying at Port B the number of the current
; recurrence. All flags are polled and the time periods are multiplicates of
; 300 milliseconds (approximately).
;
;Comments:
; - At power-on the state of the input pins is unknown (they are not given an
; initial value). It was considered proper to wait for the input pinC0 to be
; externally cleared and then wait for it to get set.
; - Subroutine TIME_DEL_A is used in order to achieve 300 milliseconds' delays.
; The subroutine's total execution time (from "rcall" till after "ret") is :
; 9+5*Ni*No+5*No-1 = 5*Ni*No+5*No+8 and we consider additional 3 clock
; cycles for the execution of the other instructions in the loops. By
; choosing No=4 , Ni=59999 ($EA5F) and the clock at 4 MHz, the time delay
; of the "on_loop" or the "off_loop" is 300.00275 milliseconds.
; - Zero value for any of the three input parameters is interpreted as equal
; to 256 (which makes sense, since a zero value for any of the input
; parameters abolishes the program's usefulness). Therefore, there are no
; checks for the inputted values (to be non-zero).
;--------------------
;---------- Main program ----------
.include "m128def.inc"
.def temp=R16
.def cnt_on=R17
.def cnt_off=R18
.def repeats=R19
.def current_rep=R20
.cseg
.org 0
jmp reset
.org $0100
;----------
reset:
; initialization of the Stack Pointer
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
; initialization of the Data Direction Registers
clr temp
out DDRA, temp ; redundant, same as the default value
ldi temp, $FF
out DDRB, temp
ldi temp, 0b10000000 ; PinC0-3 are input flags, PortC7 is the output pin
out DDRC, temp
; setting the initial output value to the output pin - redundant
cbi PORTC, 7 ; the output pin is clear until flag PinC3 is gets set
; wait until flag initialize to low level
wait_inp_init:
sbic PINC, 0
rjmp wait_inp_init
; read the input parameters
wait_flag0_set:
sbis PINC, 0
rjmp wait_flag0_set
in cnt_on, PINA
wait_flag1_set:
sbis PINC, 1
rjmp wait_flag1_set
in cnt_off, PINA
wait_flag2_set:
sbis PINC, 2
rjmp wait_flag2_set
in repeats, PINA
; perform ON/OFF recurrences after flag PinC3 gets set
clr current_rep
wait_flag3_set:
sbis PINC, 3
rjmp wait_flag3_set
loop_recurr:
inc current_rep
out PORTB, current_rep
sbi PORTC, 7 ; Output (PortC7) is ON
mov temp, cnt_on
on_loop:
rcall TIME_DEL_A
dec temp
brne on_loop
cbi PORTC, 7 ; Output (PortC7) is OFF
mov temp, cnt_off
off_loop:
rcall TIME_DEL_A
dec temp
brne off_loop
cp current_rep, repeats
brlo loop_recurr
clr current_rep ; to signal that the process has completed
out PORTB, current_rep
nop
rjmp reset
;----- End of main program -----
;
;
;-------------------- Time Delay A --------------------
;Title: TIME_DEL_A
;Purpose: Create a time delay using two 16-bit counters
; ! Ni: number of times inner loop is executed ("inner_count"'s initial value)
; ! No: number of times outer loop is executed ("outer_count"'s initial value)
; ! Ti: inner loop's duration time (in clock cycles)
; ! To: outer loop's duration time (in clock cycles)
; Ti = 5*(Ni-1)+4 = 5*Ni-1
; To = (Ti+6)*(No-1)+(Ti+5) =(Ti+6)*No-1 = (5*Ni-1+6)*No-1 =
5*Ni*No+5*No-1
; Subroutine's total execution time (from "rcall" till after "ret"):
; 9+5*Ni*No+5*No-1 = 5*Ni*No+5*No+8
;Input Parameters: -
;Other variables:
; inner_count: inner loop's counter - stored in R25:R24
; outer_count: outer loop's counter - stored in R27:R26
;Exit: - (return to main program after a specific time delay)
;Errors: -
;Comments:
; - The initial values of the counters may be provided as input parameters if
; the delay needs to be determined during program execution.
; - The register pairs R25:R24 and R27:R26 are used as 16-bit counters, thus
; enabling longer time delays. For small initial values (<256), employment of
; 16-bit counters just increases the clock cycles per inner loop and outer loop.
;--------------------
.def inner_count_L=R24
.def inner_count_H=R25
.def outer_count_L=R26 ; (XL)
.def outer_count_H=R27 ; (XH)
;----------
TIME_DEL_A:
ldi outer_count_L, $04 ; 1 cycle
ldi outer_count_H, $00 ; 1 cycle
outer_loop:
ldi inner_count_L, $5F ; 1 cycle
ldi inner_count_H, $EA ; 1 cycle
inner_loop:
nop ; 1 cycle, possible use of more "nop" instructions for longer delays
sbiw inner_count_L, 1 ; 2 cycles
brne inner_loop ; 2 cycles if true (Ni-1 times), 1 cycle if false
sbiw outer_count_L, 1 ; 2 cycles
brne outer_loop ; 2 cycles if true (No-1 times), 1 cycle if false
ret ; 4 cycles (plus 3 cycles for rcall)
;----- End of subroutine TIME_DEL_A -----
.undef inner_count_L
.undef inner_count_H
.undef outer_count_L
.undef outer_count_H
;
;
.undef temp
.undef cnt_on
.undef cnt_off
.undef repeats
.undef current_rep

Вам также может понравиться