Path:
Home =>
AVR overview =>
Applications =>
Steppermotor controller => Source code
(Diese Seite in Deutsch:
)
Source code of the Steppermotor controller with an ATtiny13
; ****************************************************
; * Steppermotor-Driver with an ATtiny13 - Version 1 *
; * (C)2007 by http://www.avr-asm-tutorial.net *
; ****************************************************
;
; Debugging switches
;
.equ debug_calc = 0
.equ debug_const = 0
.equ debug_out = 0
;
.nolist
.include "tn13def.inc"
.list ; ______
; / |
; Hardware: | |
; _______ . . +12V black
; ___ / | | | ___ |
; +5V-|___|--|RES VCC|--+5V B3-|I4 O4|-|___|-+Q4 red
; | | | | ___ |
; B3--|PB3 PB2|---------|I5 O5|-|___|-+Q2 brown
; | | | | ___ |
; Analog-In--|PB4 PB1|---------|I6 O6|-|___|-+Q3 green
; | | | | ___ |
; |--|GND PB0|---------|I7 O7|-|___|-+Q1 white
; |________| | | |
; ATtiny13 |-|GND CD|-------+
; |_______|
; ULN2003
;
; Funktioning:
; A stepper motor is controled by an analog input voltage
; on pin 3. The input voltage ranges from 0 Volt to
; the operating voltage of the processor. The number
; of steps of the motor over that input range are
; adjusted by the constant cSmSteps (1...65535 steps).
; Stepmotor drive sequence and encoding:
; Portbit PB0 PB2 PB1 PB3 | |
; Color wt bn gn rd | Portbit | Byte
; Step Q4 Q3 Q2 Q1 | 3 2 1 0 |
; ------------------------+---------+------
; 1 1 1 0 0 | 0 1 0 1 | 05
; 2 0 1 1 0 | 0 1 1 0 | 06
; 3 0 0 1 1 | 1 0 1 0 | 0A
; 4 1 0 0 1 | 1 0 0 1 | 09
; results in the word table: .dw 0x0605,0x090A
;
; Timer TC0:
; The timer runs with the processor clock of 1.2 Mcs/s
; with a prescaler value of 1024 in normal CTC mode,
; with the CompareA register as TOP value. Interrupt
; at CompareA match resp. at CTC reset.
; The interrupt service routine compares the actual
; value of motor steps with the target value. If the
; actual value is too low, the actual value is
; increased one step, if it is too high the actual
; step value is decreased. If actual and target value
; are equal, the coils of the motor are switched off
; after a certain pre-selectable delay.
; Timing: step frequency = 1.2 Mcs/s / 1024 / CompA,
; with CompA = 255: step frequency = 4.57 cs/s,
; with CompA = 8: step frequency = 146 cs/s
; ADC:
; Conversion of the analogue voltage on pin 3 / PB4 /ADC2,
; summing up 64 measuring results to average results,
; conversion to the target value for the stepper motor
; Timing: clock divider for conversion = 128,
; 1,2 Mcs/s / 128 = 9,375 kcs/s = 106,7 us clock rate,
; Conversion = 13 cycles = 1,387 ms per conversion
; = 721 conversions per second
; Averaging over 64 conversions = 88,75 ms = 11,3 results
; per second
;
; Constants
;
.equ cSmSteps = 1276 ; 2552/2, number of steps for full range
.equ cSmFreq = 145 ; frequency stepper motor
; Minimum: 5 cs/s, Maximum: 1171 cs/s
.equ cSmDelay = 390 ; number of cycles prior to switching off
;
; Derived constants
;
.equ clock = 1200000 ; clock frequency Tiny13 internal
.equ Tc0Ctc = 1024 ; prescaler value TC0
.equ cCmpA = clock / 1024 / cSmFreq ; CompareA value
;
; Checking the constants
;
.IF cCmpA > 255
.ERROR "Steppermotor frequency too low!"
.ENDIF
.IF cCmpA < 1
.ERROR "Steppermotor frequency too high!"
.ENDIF
;
; SRAM (not used, only for stack operation)
;
; Registers
;
; used: R0 for table reading
; used: R8:R1 for calculation of target value
; free: R10:R8
.def rAdcCL = R11 ; ADC calculation value LSB
.def rAdcCH = R12 ; dto., MSB
.def rAdcRL = R13 ; ADC transfer value LSB
.def rAdcRH = R14 ; dto., MSB
.def rSreg = R15 ; status save/restore register
.def rmp = R16 ; Multipurpose outside Int
.def rimp = R17 ; Multipurpose inside Int
.def rFlg = R18 ; Flags
.equ bAdc = 0 ; Adc conversion complete flag
.def rAdcC = R19 ; ADC counter (64 Adc conversions)
.def rAdcL = R20 ; ADC Adder register LSB
.def rAdcH = R21 ; dto., MSB
.def rSmSL = R22 ; Steppermotor target value LSB
.def rSmSH = R23 ; dto., MSB
.def rSmIL = R24 ; Steppermotor actual value LSB
.def rSmIH = R25 ; dto., MSB
; used: X for activation delay of the coils
; free: Y
; used: Z for table access
;
; **********************************
; Code Segment Start, Int - Vector
; **********************************
;
.cseg
.org $0000
;
rjmp Main ; Reset vector
reti ; INT0 vector
reti ; PCINT0 vector
reti ; TIM0_OVF vector
reti ; EE_RDY vector
reti ; ANA_COMP vector
rjmp Tc0IntCA ; TIM0_COMPA vector
reti ; TIM0_COMPB vector
reti ; WDT vector
rjmp AdcInt ; ADC vector
;
; **********************************
; Interrupt Service Routines
; **********************************
;
; Timer-Counter 0 Compare A Interrupt Service Routine
;
Tc0IntCA:
in rSreg,SREG ; save status
cp rSmIL,rSmSL ; compare actual with target value
cpc rSmIH,rSmSH
breq Tc0IntCA0 ; jump if equal
brcs Tc0IntCAF ; actual less than target value
sbiw rSmIL,1 ; actual greater than target, one step back
rjmp Tc0IntCAS
Tc0IntCAF:
adiw rSmIL,1 ; one step forward
Tc0IntCAS:
mov rimp,rSmIL ; copy actual value LSB
andi rimp,0x03 ; isolate lowest two bit
ldi ZH,HIGH(2*SmTab) ; point Z to table in flash memory
ldi ZL,LOW(2*SmTab)
add ZL,rimp ; add the two lowest bits
ldi rimp,0 ; update upper Byte
adc ZH,rimp
lpm ; read next value from table to R0
.IF debug_out == 0
out PORTB,R0 ; write value to port
.ENDIF
ldi XH,HIGH(cSmDelay) ; restart delay counter
ldi XL,LOW(cSmDelay)
out SREG,rSreg ; restore status
reti
Tc0IntCA0:
sbiw XL,1 ; decrease delay counter
brne Tc0IntCAD ; not yet zero
ldi rimp,0 ; switch of current on coils
out PORTB,rimp ; to output driver
ldi XH,HIGH(cSmDelay) ; restart delay counter
ldi XL,LOW(cSmDelay)
Tc0IntCAD:
out SREG,rSreg ; restore status
reti
;
SmTab:
.dw 0x0605,0x090A
;
; Adc Conversion Complete Interrupt Service Routine
;
AdcInt:
in rSreg,SREG ; save status
in rimp,ADCL ; read LSB of ADC result
add rAdcL,rimp ; add to the result register
in rimp,ADCH ; read MSB of ADC result
adc rAdcH,rimp ; add to the result register
dec rAdcC ; decrease counter
brne AdcInt1 ; if not zero, go on converting
mov rAdcRL,rAdcL ; 64 conversions, copy result
mov rAdcRH,rAdcH
clr rAdcH ; clear sum
clr rAdcL
ldi rAdcC,64 ; restart conversion counter
sbr rFlg,1<<bAdc ; set flag
AdcInt1:
ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
out ADCSRA,rmp ; restart conversion
out SREG,rSreg ; restore status
reti
;
; **********************************
; Main program Init and Loop
; **********************************
;
Main:
; Stack init
ldi rmp, LOW(RAMEND)
out SPL,rmp
; Init register
clr rFlg ; clear flag register
clr rSmIL ; clear actual value
clr rSmIH
clr rSmSL ; clear target value
clr rSmSH
ldi XH,HIGH(cSmDelay) ; restart delay counter
ldi XL,LOW(cSmDelay)
; Init output port
ldi rmp,0x0F ; output on portbits 0..3
out DDRB,rmp
ldi rmp,0x05 ; start motor at step 1
out PORTB,rmp
; Debugging session
.IF debug_calc
.equ adc_result = 128
ldi rmp,HIGH(adc_result)
mov rAdcRH,rmp
ldi rmp,LOW(adc_result)
mov rAdcRL,rmp
rjmp dcalc
.ENDIF
.IF debug_const
.equ const = cMSteps
ldi rmp,HIGH(const)
mov rSmSH,rmp
ldi rmp,LOW(const)
mov rSmSL,rmp
.ENDIF
; Init ADC
ldi rAdcC,64 ; restart ADC conversion counter
clr rAdcL ; clear ADC sum value
clr rAdcH
ldi rmp,1<<ADC2D ; Digital Input Disable on channel 2
out DIDR0,rmp
ldi rmp,1<<MUX1 ; ADC mux on channel 2
out ADMUX,rmp
ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
out ADCSRA,rmp ; start conversion
; TC0 init
ldi rmp,cCmpA ; set CTC value
out OCR0A,rmp
ldi rmp,1<<WGM01 ; set CTC mode
out TCCR0A,rmp
ldi rmp,(1<<CS02)|(1<<CS00) ; prescaler = 1024
out TCCR0B,rmp
ldi rmp,1<<OCIE0A ; Interrupt Compare Match A enable
out TIMSK0,rmp
; Sleep Mode and Int Enable
ldi rmp,1<<SE ; sleep enable
out MCUCR,rmp
sei ; Int enable
Loop:
sleep ; sleep
nop ; Dummy for wakeup
sbrc rFlg,bAdc ; ADC flag set?
rcall AdcRdy ; convert ADC result
rjmp Loop ; sleep again
;
; **********************************
; Calculation routine
; **********************************
;
; ADC conversion complete calculate target value
;
AdcRdy:
cbr rFlg,1<<bAdc ; clear ADC flag
.IF debug_const
ret
.ENDIF
dcalc:
mov rAdcCH,rAdcRH ; copy sum value
mov rAdcCL,rAdcRL
ldi rmp,LOW(cSmSteps) ; number of steps to R4:R3:R2:R1
mov R1,rmp
ldi rmp,HIGH(cSmSteps)
mov R2,rmp
clr R3
clr R4
clr R5 ; clear result in R8:R7:R6:R5
clr R6
clr R7
clr R8
AdcRdy1:
lsr rAdcCH ; shift lowest bit to carry flag
ror rAdcCL
brcc AdcRdy2 ; do not add
add R5,R1 ; add to result
adc R6,R2
adc R7,R3
adc R8,R4
AdcRdy2:
lsl R1 ; multiply multiplicator by two
rol R2
rol R3
rol R4
mov rmp,rAdcCL ; = zero?
or rmp,rAdcCH
brne AdcRdy1 ; go on multiplying
ldi rmp,0x80 ; round up
add R5,rmp
adc R6,rmp
ldi rmp,0
adc R7,rmp
adc R8,rmp
cli ; disable interrupts
mov rSmSL,R7 ; set target value LSB
mov rSmSH,R8 ; dto., set MSB
.IF debug_out
out PORTB,rSmSL
.ENDIF
sei ; enable interrupts again
ret
;
; End of Source Code
;
©2007 by http://www.avr-asm-tutorial.net