MainPP.c

This module permits to command a stepper motor with keys or I2C commands (by Serge Gentner).




//;**********************************************************************

//;                                                                     *

//;    Filename:    MainPP.c                                          *

//;    Date:          15/01/03                                          *

//;    File Version:  V1.0                                              *

//;                                                                     *

//;    Author:        S.Gentner                                         *

//;    Company:       SG Product                                        *

//;                                                                     * 

//;                                                                     *

//;**********************************************************************

//;                                                                     *

//;    Notes:  Control a stepper motor in 2 direction                *

//;            Stop the motor with end-of-course switches            *

//;            Control the motor with switches :                       *

//;              - manual / auto position                               *

//;              - up / down                                            *

//;              - speed plus / minus                                   *

//;            and with I2c commands (slave modus):                     *

//;              - reset command (go at begin position)                 *

//;              - by turn number                                       *

//;              - by step number                                       *

//;              - continus modus                                       *

//;              - read control status                                  *

//;**********************************************************************



// i2c rx frame:

// byte   0      1   2  3     4    

//     command speed step direction (0-1-2)

// i2c tx frame (status):

// byte   0    1  2  3  4    

//     command step  turn



#include <system.h>

//#include <p16f872.h>



#pragma CLOCK_FREQ 4000000

asm

{

__CONFIG _CP_OFF & _WDT_ON & _BODEN_ON & _PWRTE_ON & _LP_OSC & _WRT_ENABLE_ON & _LVP_OFF & _CPD_OFF

}



// define the number of step for one turn for this motor

#define NB_STEP_BY_TURN    200      



// motor direction

#define UP_MOTOR     0     

#define DOWN_MOTOR      1

#define STOP_MOTOR      2     



// switches rebound counter

#define CPT_INC      400      



// motor command:

// stop

#define NOTHING         0     

// go to end-course 

#define RESET        1     

// move x step

#define MOVE_S_S     2     

// move x turn

#define MOVE_T_T     3     

// move continusly

#define MOVE         4



// I2C slave address

#define ADD_SLAVE    0x50  



// mask for register test

#define MASK_SSPOV      0x40  

#define MASK_BF         0x01

#define MASK_D_A     0x20

#define MASK_SSPIF      0x08

#define MASK_T0IF    0x04

#define MASK_RBIF    0x01

#define MASK_CKP     0x10

#define MASK_R_W     0x04



// I2C buffers size

#define  NB_RX_MAX      5     

#define  NB_TX_MAX      5



// step index for the stepper motor 

#define STEP_UP      0     

#define STEP_DOWN    4



// macros for port output (command the L298N circuit)

#define     ENA   7        

#define     PENA  portc   

#define     ENB   6    

#define     PENB  portc



#define     IN1   3    

#define     PIN1  portb

#define     IN2   2    

#define     PIN2  portb   



#define     IN3   1    

#define     PIN3  portb   

#define     IN4   0    

#define     PIN4  portb   



// macros for port output (leds)

#define     LEDON    5    

#define     PLEDON   portc   

#define     LEDUP    2    

#define     PLEDUP   portc   

#define     LEDDO    1    

#define     PLEDDO   portc



// option register value 10000101 (portb pull-up disable,1/64 prescaler for timer)

#define     OPTION_VALUE   0x85



char Command;           // command received in the i2c frame

char Speed;             // motor speed (timer value)

int    StepNb;          // number of step 

char Direction;            // motor direction

char CommandStarted;    // last command started

char ManualAuto;        // if in maual or auto. modus

int  CptIncPM;          // switch rebound counter



char Run;               // intermediate flag (see bellow)



char FCUp;              // if end-course up detected

char FCDo;              // if end-course down detected



int  CptStepNb;            // counter for step by step command

int  CptTurnNb;            // counter for turn by turn counter



char I2cTxRx;           // flag for i2c reception (tx or rx frame)



char RxFrame[NB_RX_MAX];   // i2c rx buffer 

char CptRxFrame;        // i2c rx counter



char TxFrame[NB_TX_MAX];   // i2c tx buffer

char CptTxFrame;        // i2c tx counter



char MotorStep;            // motor step counter (0-3 : up, 4-7 : dowmn)



// functions definition

void CmdReset(void);

void CmdMoveSS(void);

void CmdMoveTT(void);

void CmdMove(void);

void SetMotor(char,char);

void AnalyseCommand(void);

void TestComManu(void);

void GoSleep();



// code start here:



// put the micro in sleep modus (don't work)

void GoSleep()

{

// clear_bit( intcon, RBIF );

// set_bit( intcon, RBIE );

// sleep();

}



// set the motor speed and direction

void SetMotor(char Speed, char Direction)

{

   TMR0 = Speed;              // motor speed in timer 0 register

   if (Direction == 0)        // if up

   {

      clear_bit(PLEDDO,LEDDO);   // led down off

      set_bit(PLEDUP,LEDUP);     // led up on



      clear_bit( intcon, T0IF );

      set_bit( intcon, T0IE );   // enable timer 0 interrupt

      MotorStep = 0;          // init motor step counter

   }

   else if (Direction == 1)   // if down

   {

      clear_bit(PLEDUP,LEDUP);   // led up off

      set_bit(PLEDDO,LEDDO);     // led down on



      clear_bit( intcon, T0IF );

      set_bit( intcon, T0IE );   // enable timer 0 interrupt

      MotorStep = 4;          // init motor step counter

   }

   else                 // if stop

   {

      clear_bit(PLEDUP,LEDUP);   // led up off

      clear_bit(PLEDDO,LEDDO);   // led down off



      clear_bit( intcon, T0IE ); // disable timer 0 interrupt

      clear_bit(PENA,ENA);    // disable all output to the L298 circuit

      clear_bit(PENB,ENB);

      clear_bit(PIN1,IN1);

      clear_bit(PIN2,IN2);

      clear_bit(PIN3,IN3);

      clear_bit(PIN4,IN4);

   }

}



// analyse the received i2c command

void AnalyseCommand()

{

   if (CommandStarted == NOTHING)   // if no other command started yet

   {

      switch (Command)

      {

         case RESET:

            CmdReset();

            break;

         case MOVE_S_S:

            CmdMoveSS();

            break;

         case MOVE_T_T:

            CmdMoveTT();

            break;

         case MOVE:

            CmdMove();

            break;

      }

   }

   else if ((Command == MOVE) && (Direction == STOP_MOTOR))

   {  // if must stop the motor

      CmdMove();

   }

}



// command to put the motor at begin position (end-course switch)

void CmdReset()

{

   CommandStarted = Command;  // save command

   SetMotor(Speed,Direction); // start motor in the i2c specified direction and speed

}



// move the motor for x steps

void CmdMoveSS()

{

   CommandStarted = Command;  // save command

   CptStepNb = StepNb;        // init step counter

   SetMotor(Speed,Direction); // start motor

}



// move the motor for x turns

void CmdMoveTT()

{

   CommandStarted = Command;  // save command

   CptStepNb = NB_STEP_BY_TURN;// init step counter for one turn

   CptTurnNb = StepNb;        // init turn counter

   SetMotor(Speed,Direction); // start motor

}



// move the motor continusly

void CmdMove()

{

   if (Direction < STOP_MOTOR)   // if not stop command

   {

      CommandStarted = Command;  // save command

      SetMotor(Speed,Direction); // start motor

   }

   else                 // if stop command

   {

      CommandStarted = NOTHING;  // save command (no more command)

      SetMotor(0,STOP_MOTOR);    // start motor

      GoSleep();              // nothing to do, go sleeping...

   }

}



// manual command analyse (switches)

void TestComManu()

{

   if (PORTA & 0x10) // end-course up ?

   {

      FCUp = 1;      // save switch state

   }

   else

   {

      FCUp = 0;      // save switch state

   }

   if (PORTA & 0x20) // end-course down ?

   {

      FCDo = 1;      // save switch state

   }

   else

   {

      FCDo = 0;      // save switch state

   }



   if ((PORTB & 0x20) == 0)   // Manual modus ?

   {                    // yes

      set_bit(PLEDON,LEDON);  // led on, on

      ManualAuto = 0;         // save manual/auto flag



      if (CptIncPM == 0)      // if rebound switches counter at 0

      {

         CptIncPM = CPT_INC;        // reload rebound counter

         if ((PORTA & 0x04) == 0)   // if up switch selected

         {

            if (Speed < 255)     // and speed value < 255

            {

               Speed++;       // increment the speed counter (timer 0 value)

            }

         }

         if ((PORTA & 0x08) == 0)   // if down switch selected

         {

            if (Speed > 0)       // and speed value > 0

            {

               Speed--;       // decrement speed counter (timer 0 value)

            }

         }

      }

      else              // else decrement rebound counter

      {

         CptIncPM --;

      }



      // stop/up/down switch (3 state position switch)

      if (PORTB & 0x10)    // 'stop' switch selected (idle position)

      {

         Run = 0;             // no more running

         Direction = STOP_MOTOR;    // save new direction 

         SetMotor(0,STOP_MOTOR);    // stop the motor

         GoSleep();              // and go sleeping...

      }

      else              // run (up or down)

      {

         if (PORTA & 0x02) // up

         {

            if (Direction != 0)  // if last position != from up

            {

               Direction = 0; // save new direction

               Run = 0;    // new run mode

            }

         }

         else           // down

         {

            if (Direction != 1)  // if last position != from down

            {

               Direction = 1; // save new direction

               Run = 0;    // new run modus

            }

         }

         if (!Run)         // if new run (for no reentrance)

         {

            Run = 1;       // no more

            SetMotor(Speed,Direction); // start motor

         }

      }

   }

   else  // automatic modus (go in sleep modus)

   {

      if (ManualAuto == 0) // if first time (actual modus = manual)

      {

         clear_bit(PLEDON,LEDON);   // led on, off

         ManualAuto = 1;            // new modus

         SetMotor(0,STOP_MOTOR);    // stop motor

         GoSleep();              // go sleeping (restart with i2c frame or switch)

      }

   }

}



//////// interrupt function

void interrupt( void )

{

   // if i2c interrupt

    if (pir1 & MASK_SSPIF)

    {

      clear_bit( pir1, SSPIF );           // clear interrupt

      if (sspcon & MASK_SSPOV)            // if overflow bit

      {

         clear_bit( sspcon, SSPOV );         // clear it

      }

      else

      {

         if (sspstat & MASK_D_A)          // if data byte received

         {

            if (I2cTxRx == 0)          // if in rx modus

            {

               if (CptRxFrame < NB_RX_MAX)   // save byte

               {

                  RxFrame[CptRxFrame] = sspbuf;

                  CptRxFrame++;

                  if (CptRxFrame == NB_RX_MAX)  // if last byte,

                  {

                     Command = RxFrame[0];      // save values

                     Speed    = RxFrame[1];

                     StepNb   = RxFrame[2];

                     StepNb   <<= 8;

                     StepNb   = StepNb + RxFrame[3];

                     Direction = RxFrame[4];

                     AnalyseCommand();       // and analyse command

                  }

               }

            }

            else                    // else in tx modus

            {

               if (CptTxFrame < NB_TX_MAX)         // save byte

               {

                  sspbuf = TxFrame[CptTxFrame];

                  CptTxFrame++;

               }

               else                 // if overrun byte,

               {

                  sspbuf = 0;          // send 0 byte

               }

               sspcon |= MASK_CKP;        // start byte sending

            }

         }

         else  // else address byte

         {

            if (sspstat & MASK_R_W)       // if write command, send motor status

            {

               I2cTxRx = 1;

               TxFrame[0] = CommandStarted;

               TxFrame[1] = CptStepNb >> 8;

               TxFrame[2] = CptStepNb;

               TxFrame[3] = CptTurnNb >> 8;

               TxFrame[4] = CptTurnNb;



               CptTxFrame = 1;            // init counter

               sspbuf = TxFrame[0];    // first byte to send in tx register

               sspcon |= MASK_CKP;        // start byte sending

            }

            else                    // read command

            {

               I2cTxRx = 0;

               CptRxFrame = 0;            // init counter

               RxFrame[CptRxFrame] = sspbuf; // read buffer (dummy read)

            }

         }

      }

   }

   // port input interrupt (switches) (RB4-7)

/*    if (INTCON & MASK_RBIF)   

    {

      clear_bit( intcon, RBIF ); // clear interrupt

      CptIncPM = CPT_INC;        // reset rebound counter

      clear_bit( intcon, RBIE ); // disable port interrupt

      Direction = STOP_MOTOR;    // direction = stop

      TestComManu();          // analyse switches state

   }*/

   // timer 0 interrupt (motor interrupt)

    if (INTCON & MASK_T0IF)

    {

      clear_bit( intcon, T0IF );  // clear TMR0 overflow flag

      TMR0 = Speed;           // restart timer 0

      if (CommandStarted == MOVE_S_S)  // if step by step command

      {

         CptStepNb--;         // decrement counter

         if (CptStepNb == 0)     // if last step

         {

            CommandStarted = NOTHING;  // no more command

            SetMotor(0,STOP_MOTOR);    // stop motor

            GoSleep();        // go sleeping...

         }

      }

      if (CommandStarted == MOVE_T_T)  // if turn by turn command

      {

         CptStepNb--;         // decrement step counter

         if (CptStepNb == 0)     // if last step 

         {

            CptTurnNb--;      // decrement turn counter

            if (CptTurnNb == 0)  // if last turn

            {

               CommandStarted = NOTHING;  // no more command

               SetMotor(0,STOP_MOTOR);    // stop motor

               GoSleep();              // go sleeping...

            }

            else           // else restart step counter

            {

               CptStepNb = NB_STEP_BY_TURN;

            }

         }

      }

      // motor step:

      // see stepper motor specification for step explain

      if ((MotorStep < 4) && (FCUp == 0)) // if not at end-course

      {

         switch (MotorStep)

         {

            // up

            case 0:

               MotorStep ++;

               clear_bit(PENA,ENA);

               clear_bit(PENB,ENB);

               clear_bit(PIN2,IN2);

               clear_bit(PIN3,IN3);

               clear_bit(PIN4,IN4);

               set_bit(PIN1,IN1);

               set_bit(PENA,ENA);

               break;

            case 1:

               MotorStep ++;

               clear_bit(PENA,ENA);

               clear_bit(PENB,ENB);

               clear_bit(PIN1,IN1);

               clear_bit(PIN2,IN2);

               clear_bit(PIN4,IN4);

               set_bit(PIN3,IN3);

               set_bit(PENB,ENB);

               break;

            case 2:

               MotorStep ++;

               clear_bit(PENA,ENA);

               clear_bit(PENB,ENB);

               clear_bit(PIN1,IN1);

               clear_bit(PIN3,IN3);

               clear_bit(PIN4,IN4);

               set_bit(PIN2,IN2);

               set_bit(PENA,ENA);

               break;

            case 3:

               MotorStep = 0;

               clear_bit(PENA,ENA);

               clear_bit(PENB,ENB);

               clear_bit(PIN1,IN1);

               clear_bit(PIN2,IN2);

               clear_bit(PIN3,IN3);

               set_bit(PIN4,IN4);

               set_bit(PENB,ENB);

               break;

         }

      }

      else if ((MotorStep > 3) && (FCDo == 0))  // if not at end-course

      {

         switch (MotorStep)

         {

            // down

            case 4:

               MotorStep ++;

               clear_bit(PENA,ENA);

               clear_bit(PENB,ENB);

               clear_bit(PIN1,IN1);

               clear_bit(PIN2,IN2);

               clear_bit(PIN3,IN3);

               set_bit(PIN4,IN4);

               set_bit(PENB,ENB);

               break;

            case 5:

               MotorStep ++;

               clear_bit(PENA,ENA);

               clear_bit(PENB,ENB);

               clear_bit(PIN1,IN1);

               clear_bit(PIN3,IN3);

               clear_bit(PIN4,IN4);

               set_bit(PIN2,IN2);

               set_bit(PENA,ENA);

               break;

            case 6:

               MotorStep ++;

               clear_bit(PENA,ENA);

               clear_bit(PENB,ENB);

               clear_bit(PIN1,IN1);

               clear_bit(PIN2,IN2);

               clear_bit(PIN4,IN4);

               set_bit(PIN3,IN3);

               set_bit(PENB,ENB);

               break;

            case 7:

               MotorStep = 4;

               clear_bit(PENA,ENA);

               clear_bit(PENB,ENB);

               clear_bit(PIN2,IN2);

               clear_bit(PIN3,IN3);

               clear_bit(PIN4,IN4);

               set_bit(PIN1,IN1);

               set_bit(PENA,ENA);

               break;

         }

      }

      else  // end-course detected

      {

         CommandStarted = NOTHING;  // no more command

         SetMotor(0,STOP_MOTOR);    // stop motor

         GoSleep();              // go sleeping...

      }

    }

}



//////////// main function

main()

{

   adcon1 = 0x07;             // for current consumption

   set_tris_a(0x3E);          // port configuration (see hardware)

   set_tris_b(0x30);

    set_tris_c( 0x18 );

   option_reg = OPTION_VALUE;    // option register 



   sspstat = 0x00;               // i2c init

   sspadd = ADD_SLAVE;

    set_bit( pie1, SSPIE );

   sspcon = 0x36;



   eeadr = 0x00;                 // for current consumption

   output_port_a(0x00);       // all output to 0

   output_port_b(0x00);

   output_port_c(0x00);



   CptRxFrame = 0;               // init counter

   MotorStep = 0;



   Command = NOTHING;

   CommandStarted = NOTHING;

   ManualAuto = 0;               // Manual modus at begin

   Speed = 10;                // init speed value

   Run = 0;



    enable_interrupt( GIE );     // enable general interrupt



    set_bit( intcon, PEIE );     // init external interrupt

//    set_bit( intcon, RBIE );      // init port interrupt



    clear_bit( pir1, SSPIF );    // clear pending interrupt

    clear_bit( intcon, T0IE );

    clear_bit( intcon, RBIF );



    while(1)   // Infinite Loop

   {

      clear_wdt();      // clear watchdog

      TestComManu();    // test switches

   };

}

// that's all






http://www.sourceboost.com/home.html

Copyright © 2002-2006 SourceBoost Technologies