B4R Tutorial Stepper motor

derez

Expert
Licensed User
Edit: see post #5 for an updated version.

This application is controlling a stepper motor which can be turned by a wanted angle and speed. I use this motor:
http://www.aliexpress.com/item/Smar...ith-ULN2003-Driver-Board-for/32314913056.html
The motor board is connected to power and ground and to 4 pins.
I use such a motor to turn a remote-control camera.
The code - Main:
B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public Serial1 As Serial
    Private direction As Boolean = True
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
        'define the 4 pin numbers and the time delay for the stepper
    Stepper.Initialize(10,11,12,13,10)
    Stepper.turn(True,90)
End Sub


public Sub turndone(Text As String)
        'change turn direction
    direction = Not(direction)
    Stepper.turn(direction,90)
End Sub
Stepper code module:
B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
 
    Private tmr As Timer
    Private stopcount, endcount  As Int
    Private direction As Boolean
    Private state As Int
 
    Private p1,p2,p3,p4 As Pin
End Sub

Public Sub Initialize(dpin1 As Byte _
                     ,dpin2 As Byte _
                     ,dpin3 As Byte _
                     ,dpin4 As Byte _
                     ,TimeDelay As ULong )
 
    tmr.Initialize("tmr_Tick",TimeDelay)
    p1.Initialize(dpin1,p1.MODE_OUTPUT)
    p2.Initialize(dpin2,p2.MODE_OUTPUT)
    p3.Initialize(dpin3,p3.MODE_OUTPUT)
    p4.Initialize(dpin4,p4.MODE_OUTPUT)
 
End Sub

public Sub turn(forward As Boolean, angle As Float)
    stopcount = 0
    endcount = angle * 2048 /360
    direction = forward
    state = 0
    tmr.Enabled = True
End Sub

Private Sub tmr_Tick
    If direction Then
        rotateRight
    Else
        rotateLeft
    End If
    state = (state + 1) mod 4
    If stopcount >= endcount Then
        tmr.Enabled = False
        zeroall
        Main.turndone("done")
    End If
    stopcount = stopcount + 1
End Sub

Private Sub rotateLeft
Select state
    Case 0                          
        p1.DigitalWrite(True)
        p4.DigitalWrite(False)
    Case 1
        p2.DigitalWrite(True)
        p1.DigitalWrite(False)
    Case 2
        p3.DigitalWrite(True)
        p2.DigitalWrite(False)
    Case 3
        p4.DigitalWrite(True)
        p3.DigitalWrite(False)
End Select
End Sub

Private Sub rotateRight
Select state
    Case 0                          
        p1.DigitalWrite(True)
        p2.DigitalWrite(False)
    Case 1
        p4.DigitalWrite(True)
        p1.DigitalWrite(False)
    Case 2
        p3.DigitalWrite(True)
        p4.DigitalWrite(False)
    Case 3
        p2.DigitalWrite(True)
        p3.DigitalWrite(False)
End Select
End Sub

Private Sub zeroall
    p1.DigitalWrite(False)
    p2.DigitalWrite(False)
    p3.DigitalWrite(False)
    p4.DigitalWrite(False)
End Sub
 
Last edited:

positrom2

Active Member
Licensed User
Stepper.turn(direction,90)
Stepper.Initialize(10,11,12,13,10)
Stepper.turn(True,90)
3 Errors: Undeclared variable: stepper used before it was assigned any value.
Do I miss something?
 

derez

Expert
Licensed User
I wrote a variation of the stepper module using one sub for the rotation sequence, the direction is defined by the value of the angle - positive is for clockwise, negative for counter-clockwise:
B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.

    Private tmr As Timer
    Private stopcount, endcount  As Int
    Private state As Int

    Private p1,p2,p3,p4 As Pin
    Private myangle As Int
End Sub

Public Sub Initialize(dpin1 As Byte _
                     ,dpin2 As Byte _
                     ,dpin3 As Byte _
                     ,dpin4 As Byte _
                     ,TimeDelay As ULong )

    tmr.Initialize("tmr_Tick",TimeDelay)
    p1.Initialize(dpin1,p1.MODE_OUTPUT)
    p2.Initialize(dpin2,p2.MODE_OUTPUT)
    p3.Initialize(dpin3,p3.MODE_OUTPUT)
    p4.Initialize(dpin4,p4.MODE_OUTPUT)

End Sub

public Sub turn( angle As Float)
    myangle = angle
    stopcount = 0
    endcount = Abs(angle * 2048 /360)
    state = 0
    tmr.Enabled = True
End Sub

Private Sub tmr_Tick
  
    state = (state + 1) Mod 4
    If myangle < 0  Then
      rotate(state)
    Else
      rotate(3-state)
    End If

    If stopcount >= endcount Then
        tmr.Enabled = False
        zeroall
        Main.turndone(myangle)
    End If
    stopcount = stopcount + 1
End Sub

Private Sub rotate(mode as int)
Select mode
     Case 0   ' 1000
      p1.DigitalWrite(True)
      p2.DigitalWrite(False)
  '   p3.DigitalWrite(False)
      p4.DigitalWrite(False)

    Case 1     ' 0100
       p1.DigitalWrite(False)
       p2.DigitalWrite(True)
       p3.DigitalWrite(False)
  '    p4.DigitalWrite(False)

    Case 2    ''0010
  '   p1.DigitalWrite(False)
      p2.DigitalWrite(False)
      p3.DigitalWrite(True)
      p4.DigitalWrite(False)

    Case 3   '0001                   
        p1.DigitalWrite(False)
   '    p2.DigitalWrite(False)
        p3.DigitalWrite(False)
        p4.DigitalWrite(True)
End Select
End Sub

Private Sub zeroall
    p1.DigitalWrite(False)
    p2.DigitalWrite(False)
    p3.DigitalWrite(False)
    p4.DigitalWrite(False)
End Sub
The turn command is changed to
B4X:
Stepper.turn(90)
'or
Stepper.turn(-90)
The result is 1 more DigitalWrite command in every timer cycle but simpler use of the turn command.
 
Last edited:
Top