Preloader image
   

8051 Tutorial 3

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    20Horg    0        ; Reset vector
sjmp    Startorg    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    20Horg    0        ; Reset vector
sjmp    Startorg    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 0xC000void 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..

 

Share this post on the following platforms easily:

No Comments

Post A Comment

error: Context Menu disabled!