CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Stepper Motor with 16F877A

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
hayate_kun



Joined: 22 Sep 2010
Posts: 8
Location: Malaysia

View user's profile Send private message

Stepper Motor with 16F877A
PostPosted: Thu Nov 18, 2010 3:15 am     Reply with quote

Hello!

Can anyone give me some example of motor stepper coding with 16F877A? Thank you.

I'm using LINIX 6.0kg.cm Stepping Motor.
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Thu Nov 18, 2010 3:37 am     Reply with quote

You already have an example of basic stepper control. EX_STEP.C.

99%, depends on how 'well' you actually want to drive the motor, and what speeds you want to achieve. The simplest stepper control just has transistors driving the phases from their rated voltage, and is limited to a few hundred steps per second. The problem is that the phases are massively inductive, and simple electronic theory, tells you that when you apply voltage to an inductor, the current takes time to rise. So step fast, the current goes down, and the power output of the motor declines. The solution, is to realise that the voltage 'rating' of a stepper is the continuous voltage that can be applied 'stationary', and not overheat the motor. When moving, you can massively increase the end point voltage, so long as the current doesn't rise above the motor rating. It is typical to operate a '6v' stepper, off something like a 50v supply, if you want to move the motor fast, but then you _must_ have software or hardware to limit the maximum current through the coils to the motor rating. Control at this more sophisticated level, can be done directly by some PICs (particularly those with the power PWM module, and a comparator Using the latter to control the PWM being fed to the motor phases. However with the 16F877, all you are really going to be able to do is send pulses to turn on the phases, and if you want more sophistication, you will have to provide this in your driver hardware (there are many dozens of standard chips that automatically generate the PWM signals for you).

Best Wishes
hayate_kun



Joined: 22 Sep 2010
Posts: 8
Location: Malaysia

View user's profile Send private message

PostPosted: Thu Nov 18, 2010 6:30 am     Reply with quote

Hi, thank you for your reply.

I've moved the stepper motor using PWM, however my lecturer told me that is actually incorrect way to move the stepper motor.

This is my code (freq setting=145, pwm=120, delay=700ms) it will move 9 deg per step, thus takes 40 steps per revolution:
Code:

#include <16F877A.h>
#device adc=8
#use delay(clock=20000000)
#fuses hs,noprotect,nowdt,nolvp
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,parity=N)

#byte PORTA=5
#byte PORTB=6
#byte PORTC=7
#byte PORTD=8
#byte PORTE=9


void forsmall();
void revsmall();
void stopsmall();
void delay();

void main()
{
   int pwmvalue=40;
   int step;
   //set_tris_d(0x00);
   //set_tris_b(0x00);
   //set_tris_c(0x80);
   setup_port_a(ALL_ANALOG);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_ccp1(ccp_pwm);
   setup_ccp2(ccp_pwm);
   setup_timer_2(T2_div_by_16,145,1); //149 is Y(freq setting) max=149,min=0 (PWM value), 16 is X

   //=================================
   // MAIN PROGRAM
   //=================================

   step=0;

   do
    {

         while(step<20){
            forsmall();
            stopsmall();
            step++;
         }

     revsmall();
     step=0;




    } while(TRUE);

}


void forsmall()
   {

      //===========================
      // CLOCKWISE 6.0kg.cm
      //===========================

      set_pwm1_duty(120); // RC2 (ccp1)

      output_low(pin_d3); //DIR
      output_high(pin_d2); //EN
      delay_ms(700);  //the higher the longer it turns

   }


void revsmall()
   {


      //===========================
      // COUNTER-CLOCKWISE 6.0kg.cm
      //===========================

      set_pwm1_duty(120); // RC2 (ccp1)

      output_high(pin_d3); //DIR
      output_high(pin_d2); //EN
      delay_ms(14400);  //the higher the longer it turns

   }


void stopsmall()
   {
      //===========================
      // STOP 6.0kg.cm
      //===========================


      set_pwm1_duty(0); // RC2 (ccp1)

      //output_low(pin_d3); //DIR
      output_low(pin_d2); //EN
      delay_ms(2000);

   }

For your information, I'm using a driver to drive the motor. In the datasheet it said something about microstepping, unfortunately, I can't find a clue how to program it.

Therefore, I would appreciate if you can send me some link for stepper motor microstepping.
Thank you.
arunb



Joined: 08 Sep 2003
Posts: 492
Location: India

View user's profile Send private message Send e-mail

RE:
PostPosted: Thu Nov 18, 2010 9:48 pm     Reply with quote

what driver are you using ?? Please post a link to the datasheet.. also what kind of a stepper motor are you using ?

thanks
a
hayate_kun



Joined: 22 Sep 2010
Posts: 8
Location: Malaysia

View user's profile Send private message

PostPosted: Fri Nov 19, 2010 3:23 am     Reply with quote

I'm using LINIX stepping motor: model 57BYGHD451
with driver: SJ-230M2 / 5 phase hybrid stepper motor

Here's the link of driver's datasheet:
http://www.filedropper.com/stepper60kgcmdriverlatestfromcytron
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Fri Nov 19, 2010 10:04 am     Reply with quote

Start with a simple statement. You don't want a stepper driver.....

You already _have_ a stepper driver. The unit you are using already generates the PWM to 'drive' the motor. This is why your instructor is pointing you away from PWM. You _can_ develop the pulse train needed by this controller using PWM, but you should start simpler. Also, there are reasons why this may _not_ be the best solution.

What you have is what is known as a 'step/direction' controller. This expects to see, two signals. Just a signal that is high for rotation in one direction, and low for rotation in the other, combined with a pulse train,who's frequency you change to specify how fast you want the motor to move.

What voltage are you driving the controller from?. It is rated for up to 40v. The voltage will affect just how fast you can step the motor. The data sheet, does not give a 'pull in' step frequency.

Now the controller you have, has a eight way DIP switch. The top three positions of this, need to be set to '101', to program 2A/phase, which is the current your motor is rated for. Then the bottom three positions need to be set according to how many micro-steps you want to use. As a general comment, unless motors are specifically designed for micro-stepping, the accuracy tends to decline when large numbers of micro-steps are used. Something like 4 to 8 micro-steps is normally reliable with good accuracy. Higher numbers become more 'dubious'....
With your existing PWM setup, the PWM will be generating a pulse train at 2140Hz (20MHz/(4*16*146)). The motor will not start with anything approaching it's maximum torque at this sort of step rate, but this might be quite acceptable, if you were using perhaps 8 micro steps.

Generally, because of the inertia in the system, you would not want to start at 'full speed', and this is why the PWM generator is not the way to go to control this motor. Normally you would start slowly, accelerate to the maximum step rate, and then a little way before you want to stop 'ramp down' to a slow rate to avoid overshoot.
One way to do this, would be to have an interrupt at perhaps 5* the maximum rate that you want to step the motor. In this interrupt, decrement a counter, and if it is zero, trigger a pulse. The pulse need only be 5uSec low, so what you do, is as soon as you 'see' that the counter is 0, pull the pulse signal low, then carry out the operations to re-load the counter, by which time > 5uSec will have passed, and you can raise the signal again. The re-load, involves using a look up table of number of counts wanted between pulses. Have it holding a linear sweep of value, from perhaps 50 to 5. Then when you decide to move a number of steps, you set the table counter to '0', load the first value (which starts the pulse train), and the interrupt automatically counts up the table, with the motor accelerating.
At the re-load, you look to see if:
1) Is the table counter above the top of the table?. If so, you just keep going at this maximum rate.
2) You are 'half way' If so, start counting the table counter _down_, instead of up.
So, something like:
Code:

int32 table_position=0;
#define TABLE_MAX (30)  //adjust to uit number of acceleration steps req'd
int8 delay_table[TABLE_MAX] = {70,66,........5}; //number of ticks per step

int32 position=0x80000000;
int32 wanted=0x80000000;
int32 distance;

//Setup to be called by a suitable interrupt - typically perhaps 8000*/sec
void ticker(void) {
    static int8 pulse_count=0;
    static int1 moving=FALSE;
    static int1 first_half;
    if (!moving) {
        //Here stepper not moving
        if (position!=wanted) {
           //Here a movement is required
           if (wanted<position) {
               distance=position-wanted;
               output_low(DIRECTION_PIN);  //set to step 'in'
           }
           else {
               distance=wanted-position;
               output_high(DIRECTION_PIN); //set to step 'out'
           }
           output_low(STEP_PIN);
           table_position=0;
           pulse_count=delay_table(table_position);
           //This array load will take several uSec
           moving=TRUE;
           first_half=TRUE;
           output_high(STEP_PIN);
       }
    }
    else {
          //Now moving
          if (--pulse_count==0) {
              //Next pulse may be needed
              distance--;
              if (distance==0) {
                  //Finished
                  position=wanted;
                  moving=FALSE;
              }
              else {
                  output_low(STEP_PIN);
                  if (first_half) {
                      //Here potentially accelerating
                      table_position++;
                      if (table_position>=distance) {
                          //Half way
                          first_half=FALSE;
                      }
                      if (table_position>=TABLE_MAX) {
                          pulse_count=delay_table(TABLE_MAX-1);
                      }
                      else
                          pulse_count=delay_table(table_position);
                      //Now have the number of interrupts till next pulse
                 }
                 else {
                      if (table_position>0)
                          table_position--;
                       if (table_position>=TABLE_MAX) {
                          pulse_count=delay_table(TABLE_MAX-1);
                      }
                      else
                          pulse_count=delay_table(table_position);
                      //Now have the number of interrupts till next pulse
                 }
                 output_high(STEP_PIN);
             }
         }
     }
}

Now, this is 'as typed', so will have errors, and needs significant 'thought' as to how it is used. You need a 'delay_table', containing a list of interrupt counts to give acceleration/deceleration, a suitable rate interrupt, and to set 'wanted' to the count you want to go to. You will also need to offset the actual positions you want to go to, by 0x80000000 - so that you can potentially move a couple of thousand million steps in both directions if wanted.....

Best Wishes
ntc



Joined: 18 Mar 2015
Posts: 8

View user's profile Send private message Send e-mail AIM Address

Controlling step motor
PostPosted: Sun Feb 21, 2016 9:13 pm     Reply with quote

Hi everybody!
Today I buy 2 motor 48BYJ-5V and driver with ULN280c IC, like as a link to make a clock ( 1 motor drive a second, and another drive a minutues with a mechanics structural have before, I need to control 2 motors with gear as:
- 15 rpm with second motor
- 0.25rpm / 0.3rpm with minutes motor
I have designed a new circuit to assembly 2 driver on one board, using ULN2803 IC and tried to write a program to control them.
I have a problems when the max speed of this motor is near with second motor speed, so that I have a delay with it, also the motor is feel hot.
In this project I'm using PIC16F18345 and CCS C ver 5.051.
Thanks for yours supports.





* Motor and driver specs
https://grahamwideman.wikispaces.com/Motors-+28BYJ-48+Stepper+motor+notes

* Schematic design
https://drive.google.com/file/d/0Bz215_lkn4g-ZldzbWU2c3ZoNUk/view?usp=sharing

* Program ( write on PIC18F starter KIT, if this program is OK , Ill port into PIC16F18345 in new design schematic)
Code:

                                                                                                                           
#include <18F4680.h>
#fuses H4,PUT,NOPROTECT,NOLVP,NOWDT,NOPBADEN
#use delay(clock=40000000)                                                             
                                     
#define EEPROM_SDA  PIN_C4           
#define EEPROM_SCL  PIN_C3   
#include <ds1307.c>   


#define B1  PIN_B5   // blue
#define P1  PIN_B4   // pink
#define Y1  PIN_B3   // yellow
#define O1  PIN_B2   // orange

#define O2  PIN_A0
#define Y2  PIN_A1
#define P2  PIN_A4
#define B2  PIN_A5


unsigned int8 but0=0, but1=0;
unsigned int16 step=0;
unsigned int16 limit=0;
unsigned int16 count_t0=0;
unsigned int8 stp_mt1=0, stp_mt2=0;
unsigned int1 update_mt1=0, mt1_off=0,mt2_off=0, mt1_thuan=1, mt2_nhanh=0;
unsigned int8 update_mt2=0;



void motor_025v(void)
{
   //------ O=1----------------

      switch(stp_mt2)
      {
         case 1:
            output_high(O1); 
            output_low(B1);
            output_low(P1);
            output_low(Y1);   
            break;
         case 2:
            output_high(O1);  //------- O=Y=1------------
            output_high(Y1);
            output_low(P1);
            output_low(B1);   
            break;
         case 3:
            output_high(Y1);  //--- Y=1------------------     
            output_low(P1);
            output_low(O1);
            output_low(B1);   
            break;
         case 4:
            output_high(P1);  //--- Y=P=1------------------
            output_high(Y1);
            output_low(O1);
            output_low(B1);   
            break;   
         case 5:           
            output_high(P1);  //--- P=1------------------
            output_low(B1);
            output_low(O1);
            output_low(Y1);   
            break;
         case 6:
            output_high(B1);  //--- P=B=1------------------ 
            output_high(P1);
            output_low(O1);
            output_low(Y1);     
            break;
         case 7:
            output_high(B1);  //--- B=1----------------- 
            output_low(O1);
            output_low(P1);
            output_low(Y1);   
            break;
         case 8:
            output_high(B1);  //--- 0=B=1-----------------   
            output_high(O1);
            output_low(P1);
            output_low(Y1);       
            break;
         default:
            output_low(B1);
            output_low(O1);
            output_low(Y1);
            output_low(P1);
            break;
      }
 
   
}

void motor_15v(void)
{
   //------ O=1----------------

      switch(stp_mt1)
      {
         case 1:
            output_high(O2); 
            output_low(B2);
            output_low(P2);
            output_low(Y2);   
            break;
         case 2:
            output_high(O2);  //------- O=Y=2------------
            output_high(Y2);
            output_low(P2);
            output_low(B2);   
            break;
         case 3:
            output_high(Y2);  //--- Y=1------------------     
            output_low(P2);
            output_low(O2);
            output_low(B2);   
            break;
         case 4:
            output_high(P2);  //--- Y=P=2------------------
            output_high(Y2);
            output_low(O2);
            output_low(B2);   
            break;   
         case 5:           
            output_high(P2);  //--- P=2------------------
            output_low(B2);
            output_low(O2);
            output_low(Y2);   
            break;
         case 6:
            output_high(B2);  //--- P=B=2------------------ 
            output_high(P2);
            output_low(O2);
            output_low(Y2);     
            break;
         case 7:
            output_high(B2);  //--- B=2----------------- 
            output_low(O2);
            output_low(P2);
            output_low(Y2);   
            break;
         case 8:
            output_high(B2);  //--- 0=B=2-----------------   
            output_high(O2);
            output_low(P2);
            output_low(Y2);       
            break;
         default:
            output_low(B2);
            output_low(O2);
            output_low(Y2);
            output_low(P2);
            break;
      }
 
   
}

#int_timer0
void ngat_t0(void)
{
   set_timer0(215);
   update_mt1=1;

   update_mt2=1;
}


//--------------------------------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------------------------------

void main(void)
{
   
   set_timer0(215);                                                             
   setup_timer_0 (RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_256);   
   enable_interrupts(int_timer0);
   enable_interrupts (global);
   delay_ms(500);   
 
   for(;;)
   { 
   
      //============================================================================================================================
      //============================================================================================================================   
      if(input(PIN_B0)==0)
      {
         while(input(PIN_B0)==0);
         delay_ms(10);
         if(mt1_thuan==0)
         {
            mt1_thuan=1;
         }
         else if(mt1_thuan==1)
         {
            mt1_thuan=0;
         }
      }
   
      else if(input(PIN_B1)==0)
      {
         while(input(PIN_B1)==0);
         delay_ms(10);
         if(mt2_nhanh==1)
         {
            mt2_nhanh=0;
         }
         else if(mt2_nhanh==0)
         {
            mt2_nhanh=1;               
         }
         
      }
     
      //============================================================================================================================
      //============================================================================================================================
      if( update_mt1==1 ) 
      {
         if(mt1_thuan==1)
         {
            stp_mt1++;
            if(stp_mt1==9) stp_mt1=1;
         }
         else if(mt1_thuan==0)
         {
            stp_mt1--;
            if(stp_mt1==0) stp_mt1=8;
         }
         motor_15v();
         update_mt1=0;
      }
     
      if(update_mt2==1)  // motor cham
      { 
         
         if(stp_mt2<9) stp_mt2++;
         if( mt2_nhanh==0)
         { 
            if(stp_mt2==9)
            {
               count_t0++;
               if(count_t0 == 458)  {  count_t0=0; stp_mt2=1;}
            }
         }
         else 
         {
            if(stp_mt2==9) stp_mt2=1;
         }
         motor_025v();
         update_mt2=0;
      }

   }
}
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Feb 22, 2016 12:49 pm     Reply with quote

I've used the step/direction type controller and must say that the NCO module in the 16f1509 make it so easy as to be laughable Laughing Laughing Laughing Laughing
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group