//;**********************************************************************
//; *
//; 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
Copyright © 2002-2006 SourceBoost Technologies