; **************************************************** ; * 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<