Continue to Site

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.

  • 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.
Resource icon

Basic 8051 tutorial 3 2014-04-16

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:
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
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:
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
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..
  • Servo.png
    Servo.png
    76.4 KB · Views: 3,632
  • Servomotor.png
    Servomotor.png
    13.8 KB · Views: 3,467
  • Motor schematics.png
    Motor schematics.png
    30.7 KB · Views: 4,988
  • Stepper.png
    Stepper.png
    16 KB · Views: 4,080
  • Like
Reactions: sanyaade

Latest reviews

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.

Latest threads

New Articles From Microcontroller Tips

Back
Top