1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice
Ian Rogers

Basic 8051 tutorial 3

Basic motor control using ASM and C

  1. Ian Rogers
    The next tutorial I want to look at a stepping motor... To step a stepper motor we need to sequence the coil windings... The windings are arranged so applying current to the coils in a certain sequence we can turn the motor in small steps.
    Motor schematics.png
    The sequence shown in the diagram will step the motor in full steps 0AH, 09H, 05H, 06H..
    The connections are as follows...

    Stepper.png


    To half step the motor then just add a single excitation in between the steps .. As A1 and A2 are on in the first sequence moving to A1 to B2 and turning A2 off.. 0Ah, 08H, 09H …. etc.. so the half step sequence is:-

    0AH, 08H, 09H, 01H, 05H, 04H, 06H, 02H...

    The code to show it's operation is here..

    Code 9
    Code (asm):

    IDX    equ    20H

        org    0        ; Reset vector
        sjmp    Start

        org    30H        ; Code starts here
    Start:
        clr    A        ; A = 0
        mov    IDX,A        ; Store initial array index
        mov    DPTR,#digits    ; Get array start point
    While:
        jnb    P0.0,CCW    ; Counter clockwise?
        jnb    P0.1,CW    ; Clockwise
        sjmp    While        ; do it again ( Forever loop )

    CCW:
        mov    A,IDX        ; get current step
        movc    A,@A+DPTR    ; Get stepper position
        mov    P1,A        ; Move motor
        acall    delay        ; Step delay ( 100mS )
        mov    A,IDX        ; get current step
        inc    A        ; Next index
        jnb    Acc.3,NotOver    ; Check index variable
        clr    A        ; not more than three
    NotOver:
        mov    IDX,A        ; Store current array index
        sjmp    While        ; Back to loop

    CW:
       mov    A,IDX        ; get current step
        movc    A,@A+DPTR    ; Get stepper position
        mov    P1,A        ; Move motor
        acall    delay        ; Step delay ( 100mS )
        mov    A,IDX        ; get current step
        dec    A        ; Previous index
        jnb    Acc.7,NotUnder    ; Check index variable
        add    A,#8        ; not less than zero
    NotUnder:
        mov    IDX,A        ; Store current array index
        sjmp    While        ; Back to loop


    delay:
        mov    R2,#180    ; 2 clock cycles (call)        = 2
        mov    R1,#0        ; 2 clock cycles (loading)    = 2
    d1:
        djnz    R1,d1        ; 2 * 256 clock cycles *180    = 92160
        djnz    R2,d1        ; 2 * 180 clock cycles     = 380
        ret            ; 2 clock cycles (return)    = 2
                        ; * 1.0815 (11.0952 osc)    = 100.07ms

    digits:    db    0AH,08H,09H,01H,05H,04H,06H,02H    ; 8 step patterns 0AH to 02H

        end
     
    And the same code in C
    Code 10
    Code (c):


    #include<8051.h>        // definition file

    unsigned char digits[] = {0xA,0x8,0x9,0x1,0x5,0x4,0x6,0x2};
    char idx;

    void delay(void)        // How to get approximately 100mS..
        {
        int x = 8410;        // The while statement consumes 11.89uS (11 clock cycles )
        while(x--);        // So 8410 * 11.89uS = nearly 100mS
        }        

    void CCW(void)            // Direction Anti
        {
        P1 = digits[idx];        // Get step position
        if(++idx > 7) idx = 0;        // Only 8 steps
        }

    void CW(void)            // Direction Norm
        {
        P1 = digits[idx];        // Get step position    
        if(--idx< 0) idx = 7;        // Only 8 steps
        }

    void main(void)            // Main entry point
        {
        idx = 0;
        while(1)            // Forever loop
            {
            if(!P0_0)CCW();     // Check switch 1
            if(!P0_1)CW();    // Check switch 2
            delay();        // step delay
            }
        }

     
    The Servo motor!!!

    I'm going to jump into a slightly faster river now... I would like to move onto a servo motor... The RC servo motor uses a pulse to determine position... Not PWM ( pulse width modulation ) but we can use PWM to achieve this.

    The pulse needs to be roughly 1.5mS long to sit the motor in a central position, it the pulse is modified to 1mS the servo will turn to a minimum position, if the pulse is increased to 2mS the servo will move to the maximum position.

    Servo RC motors are pretty cheap to get hold of... Most robotic/ hobby websites will stock them for next day delivery.. This is a basic servo motor..

    Servo.png
    The best way to drive a servo is with a CCP module in PWM mode.. The servo period needs to be 6mS ~ 20ms or 166hz to 50hz ...If we use 6mS, we can set 25% duty to represent 1.5mS and 16% and 33% to represent 1mS and 2mS respectively.. If we use a 10 bit resolution, that will be 160 bits of control, 80 positions left and 80 positions right..

    However!! The chip we are using hasn't one of these modules, so I'm going to drive a timer to do the job for me... Here is the connections.... I have two push buttons to change the positions..

    Servomotor.png

    Now simple control is just Left and right... If we want to move the servo with a potentiometer we will need to do the I2C tutorial as the micro hasn't got an ADC onboard....So for now I'll calculate the times for 1mS... 1.5mS...And 2mS.. Pressing a button will move the motor to it's maximum or minimum positions... Releasing will return the motor to the central position..


    The servo consumes very little power from the micro pin so no buffer is needed...

    Code 11
    Code (asm):

    IDX    equ    20H

        org    0        ; Reset vector
        sjmp    Start

        org    30H        ; Code starts here
    Start:
        mov    TMOD,#01H    ; Timer 0 16 bit timer.. 1.5ms / 1.085uS = 1392 ( timer reload values )
                               ; 1ms = 941.. (0xFFFF - d941 = 0xFC52...)
    While:                     ; 2ms = 1843.. ( 0xFFFF - d1843 = 0xF8CC )
        jb    P0.0,cont
        sjmp    left
    cont:
         jb    P0.1,cont1
        sjmp    right
    cont1:
        mov    R7,#090H          ; 0FA90H = 1.5mS  Middle
        mov    R6,#0FAH

    cont2:
        mov    TH0,R6        ; Load selected pulse width
        mov    TL0,R7
        clr    TF0        ; Ensure timer runs
        setb    TR0
        setb    P1.0
        jnb    TF0,$
        mov    TH0,#0C0H    ; 20mS delay
        mov    TL0,#0H
        clr    TF0        ; Ensure timer runs
        setb    TR0
        clr    P1.0
        jnb    TF0,$        ; rest of period
        sjmp    While        ; do it again ( Forever loop )

    left:
        mov    R7,#052H    ; 0FC52 = 1mS.. Fully left
        mov    R6,#0FCH
        sjmp    cont2
    right:
        mov    R7,#0CCH    ; 0F8CC =  2mS.. Fully right
        mov    R6,#0F8H
        sjmp    cont2

        end

     
    I am using R6 and R7 to systematically load the values needed to move the motor..


    To use the timer to give exact timing we need to intervene with its operation.. If we allow the timer to run from 0 ~ 65535 it would take 70.89mS so if we pre-load the timer with a calculated figure we can get it to time out when we need it to.. We need to count 1392 clock cycles to get 1.5mS..

    1392 * 1.0815uS = 1.5mS... You need to deduct 1392 from the maximum count of 65535.... The calculated values are in the code..

    The C code is here..

    Code 12
    Code (c):

    #include<8051.h>        // definition file

    #define LEFT 0xF8CC
    #define    RIGHT 0xFC52
    #define CENTER 0xFA8F
    #define PAUSE 0xC000

    void SetTimer(unsigned int time)
        {
            TH0 = time>>8;
            TL0 = time & 0xFF;
        }

    void main(void)            // Main entry point
        {
        TMOD = 1;            // 16 bit timer
        while(1)            // Forever loop
            {
            if(!P0_0) SetTimer(LEFT);         // Set time for maximum left
            else if(!P0_1) SetTimer(RIGHT); // Right
            else SetTimer(CENTER);            // Or center
            TF0 = 0;
            TR0 = 1;                // Timer on
            P1_0 = 1;
            while(!TF0);            // Wait until timer expires
            P1_0 = 0;
            TR0 = TF0 = 0;            // RESET Flag and timer off
            SetTimer(PAUSE);        // 20mS  period
            TR0 = 1;
            while(!TF0);            // Wait again
            TF0 = 0;
            TR0 = 0;                // Reset... again timer off
            }
        }

     
    I have used a function to change the timer pre-load... Using an “unsigned int“ ensures the value isn't evaluated as a negative..

    I am working on the next two tutorials.... As we speak... a multiline LCD screen, namely a 16 x 2.. and the serial communication to a PC running a terminal program..
    RonaldB, DonPriceTech, absf and 2 others like this.

Recent Reviews

  1. RonaldB
    RonaldB
    5/5,
    Nice tutorial. The short explanation for stepper and servo motors made more sense and understood better than reading long articles about this. Yeah! I have now a project in mind.