;;; ;;; stepper.asm ;;; by Neil Gershenfeld ;;; heavily modified by Raffi Krikorian ;;; ;;; drive a motor controller from jameco (part number 117954) to the left ;;; for a given number of clicks, then back to the right for the same number ;;; of clicks. .include "tn15def.inc" ; include the file specific to the attiny15 ;;; ;;; DEFINITIONS ;;; ;;; define certain registers to be temporary storage locations .def temp0 = R16 .def temp1 = R17 .def temp2 = R18 .def temp3 = R19 .def temp4 = R20 ;;; some constants that we are going to be using in the code .equ on_count = 20 ; the length of time the "pulse" is on .equ off_count = 5 ; the length of time the "pulse" is off .equ pulse_count = 20 ; how many times to actually pulse each port ;;; and map the wires going to the stepper controller to some variables that we ;;; are going to be using in the codebase .equ brown_motor = PB2 .equ black_motor = PB1 .equ yellow_motor = PB0 .equ orange_motor = PB3 ;;; ;;; CODE SEGMENT ;;; .cseg ; start the code segment at memory location 0. .org 0 ; because the reset vector places us here, the rjmp main ; first thing is to jump to the main block ;;; ;;; the generic function to pulse a specific stepper motor port ;;; ;;; given a PB number in temp3 that we want to pulse, this function pulses that ;;; motor port (using PWM to current limit). this function is called by the ;;; corresponding pulse_brown, pulse_black, etc., blocks ;;; pulse_motor: ;; convert the temp3 into a bit value that we want to manipulate. b/c ;; it is just a number in R19, we actually want to bit shift that value ;; over ldi temp0, 0x01 ; put a bit in temp0 _pm_shift_loop: dec temp3 ; decrement the number of shifts that we have to brmi _pm_shift_loop_done ; do, and if we are negative (-1) we are done lsl temp0 ; shift the bit over rjmp _pm_shift_loop _pm_shift_loop_done: mov temp3, temp0 ; temp3 <- temp0 in temp4, PORTB ; temp4 <- PORTB------------------------------------------? or temp4, temp3 ; PORTB <- PORTB | temp3 (turn on the motor bit) in temp3, PORTB ; temp3 <- PORTB (like temp4 w/ motor bit off)------------------------------------------? ;; now start the loop for the actual pulsing that we are going to do ldi temp0, pulse_count ; temp0 <- pulse_count _pm_loop_0: ldi temp1, pulse_count ; temp1 <- pulse_count _pm_loop_1: ldi temp2, on_count ; temp2 <- on_count out PORTB, temp4 ; turn on the motor bit in PORTB------------------------------------------? _pm_on: dec temp2 ; temp2 <- temp2 - 1 brne _pm_on ; if temp2 != 0, then goto _pm_on ldi temp2, off_count ; temp2 <- off_count out PORTB, temp3 ; turn off the motor bit in PORTB _pm_off: dec temp2 ; temp2 <- temp2 - 1 brne _pm_off ; if temp2 != 0, then goto _pm_off dec temp1 ; temp1 <- temp1 - 1 brne _pm_loop_1 ; if temp1 != 0, then goto _pm_loop_1 dec temp0 ; temp0 <- temp0 - 1 brne _pm_loop_0 ; if temp0 != 0, then goto _pm_loop_0 ret ; return out of this function ;;; ;;; pulse the yellow motor controller port ;;; pulse_yellow: ldi temp3, yellow_motor ; temp3 <- value yellow_motor rcall pulse_motor ; call pulse_motor to pulse the yellow port ret ;;; ;;; pulse the black motor controller port ;;; pulse_black: ldi temp3, black_motor ; temp3 <- value black_motor rcall pulse_motor ; call pulse_motor to pulse the black port ret ;;; ;;; pulse the brown motor controller port ;;; pulse_brown: ldi temp3, brown_motor ; temp3 <- value brown_motor rcall pulse_motor ; call pulse_motor to pulse the brown port ret ;;; ;;; pulse the orange motor controller port ;;; pulse_orange: ldi temp3, orange_motor ; temp3 <- value orange_motor rcall pulse_motor ; call pulse_motor to pulse the orange port ret ;;; ;;; the function to step the stepper to the right by one click ;;; ;;; this just pulses the appropriate stepper. remember to drive a stepper motor ;;; you have to drive one of the windings, then the other winding, then drive ;;; the windings in the opposite directions. if you are driving a stepper that ;;; you don't know anything about, you can determine which are connected by ;;; taking a multimeter and probing for the connected lines. ;;; step_right: rcall pulse_brown rcall pulse_yellow rcall pulse_black rcall pulse_orange ret ;;; ;;; drive the stepper in the other direction ;;; ;;; see step_right to for a small discussion on how to drive a stepper. ;;; step_left: rcall pulse_brown rcall pulse_orange rcall pulse_black rcall pulse_yellow ret ;;; ;;; the main block ;;; ;;; this block simply sits in a loop and moves the stepper to the right a bunch ;;; of clicks, and then moves to back to the left a bunch of clicks ;;; main: ;; clock the processor as fast as it can go -- this is pretty much safe ;; because we are not going to be communicating or synchronizing with ;; another processor. if we were to be worrying about that, then ;; we would just leave this line out as the processor would load the ;; calibration byte into this location. ldi temp0, 0xFF out OSCCAL, temp0 ;; now we have to configure the "direction" of the I/O pins. remember, ;; setting a bit to 1 in the DDRB (the data direction register) will ;; make the corresponding pin an output. if the bit is a 0, the ;; corresponding pin is an input. ;; ;; we want to make bits 0->3 all 1's (PB0, PB1, PB2, and PB3). that ;; means that we are loading a 0x0F into DDRB. this is because, in ;; binary, 0x0F represents 0b00001111 (with the most significant bit ;; being the left most bit) ldi temp0, 0x0F out DDRB, temp0 ;; now we just have a loop which moves the stepper to the right 8 times, ;; then moes the stepper to the left 8 times. over and over and over. loop: rcall step_right rcall step_right rcall step_right rcall step_right rcall step_right rcall step_right rcall step_right rcall step_right rcall step_left rcall step_left rcall step_left rcall step_left rcall step_left rcall step_left rcall step_left rcall step_left rjmp loop ; and jump back to the loop label to start again