//#include <16F887.h> #include <16F877a.h> //#include <16C62a.h> #device ICD=TRUE #device *=16 //#use delay(clock=8000000) #fuses NOWDT,HS, NOPUT, NOPROTECT, BROWNOUT //#define CLOCK ((int32)19660800) #use delay(clock=20M, oscillator ) #define CLOCK ((int32)20000000) #define STEP_A PIN_A0 #define STEP_B PIN_A1 #define STEP_C PIN_A2 #define STEP_D PIN_A3 #define ENC_I PIN_B6 #define ENC_B PIN_B4 #define ENC_A PIN_B5 #define STEP_LED PIN_D0 #define ENC_LED PIN_D1 #define TRIS_C 0x87 #byte SSPBUF = 0x13 #use i2c(Slave,slow,sda=PIN_C4,scl=PIN_C3,force_hw,address=0xd8) //Setup TRIS in init sequence. #use fast_io(ALL) //#use fast_io(B) //#use fast_io(C) //Global variables //Interrupt States byte interruptStatus; #define TMR1_TIMEDOUT 0x01 #define TMR2_TIMEDOUT 0x02 #define I2C_READ_PENDING 0x04 #define I2C_READ_READY 0x08 #define I2C_CMD_READY 0x10 #define TMR1_TIMEDOUT_MASK 0x01 #define TMR2_TIMEDOUT_MASK 0x02 #define I2C_READ_PENDING_MASK 0x04 #define I2C_READ_READY_MASK 0x08 #define I2C_CMD_READY_MASK 0x10 //copy from telcontrol.h //enum deviceType { NULL, RTCC, MOTOR, MOTOR_WITH_ENCODER, ENCODER, FOCUSER, FOCUSER_WITH_ENCODER, SHUTTER, CAMERA, DC_SERVO }; #ifdef ENABLE_HW_ENCODER #define DEVICE_NAME 0x0003 //From device type enum in telcontroller.h #else #define DEVICE_NAME 0x0002 //From device type enum in telcontroller.h #endif #define DEVICE_VERSION 0x0100 //software Version number, High byte is major, low byte is minor. #byte SSPBUF = 0x13 #define SSPSTATMASK 0x3F struct SSPSTATStruct { //Buffer Full : (receive) 1 = receive complete SSPBUFF full //Buffer Full : (transmit) 1 = transmit in progress, SSPBUFF full int BF:1; //Update address , 1 indicates that user needs to update the address in the 10 bit SSPADD field int UA:1; //Write Low, holds R/WL bit of last address match. 1=read int RWL:1; //Start bit, 1 = start detected last. int S:1; //Stop bit, 1=stop detected last int P:1; //D/AL 1 - last byte received was data int DAL:1; //SMBus inputs enable int CKE:1; //Slew rate control bit - 1 disables for 100KHz and 1MHz int SMP:1; }; struct SSPSTATStruct SSPSTAT; #pragma BYTE SSPSTAT = 0x94 // Place structure right over SSPSTAT at location 0x94 #define SSPCONMASK 0xF0 struct SSPCONTROLStruct { //SSP select int SSPSEL:4; //SSP Clock polarity int CKP:1; //Sync Serial port Enable - in I2C mode enables SSP as I2C using SDA and SCL int SSPEN:1; //SSP overflow, 1 when I2C byte received while SSPBUFF full, don't care in transmit. //Must be cleared by software in either case int SSPOV:1; //Write collision, SSPBUF written while still transmitting previous byte, 1= collision int WCOL:1; }; struct SSPCONTROLStruct SSPCON; #pragma BYTE SSPCON = 0x14 #define CMD 0 #define DATA0 1 #define DATA1 2 #define DATA2 3 #define DATA3 4 #define SERIAL_BUFF_SIZE 10 byte serialCmd; //Used to identify the I2C command byte serialInCount = 0; //How many bytes have been processed inwards by the ISR byte serialOutcount = 0; //How many bytes have been processed outwards by the ISR byte serialBuffIn[SERIAL_BUFF_SIZE]; byte serialBuffOut[SERIAL_BUFF_SIZE]; byte serialBuffOutLength = 0; /* These defines are the command IDS of the I2C data commands. They should attempt to lign up so that the Commadn ID is also the register address for the data. Hence Device name is always at register 00 length 2 Hence device type is always at register 02 length 2 The register concept does not map onto the file register they are stroed at but there is no reason why not.... */ //Device Commands #define SERIAL_CMD_DEVICE_NAME_GET 0x00 #define SERIAL_CMD_DEVICE_VERSION_GET 0x01 //Stepper CMDs #define SERIAL_CMD_STEPPER_STEPS_SET 0x10 #define SERIAL_CMD_STEPPER_STEPS_GET 0x11 #define SERIAL_CMD_STEPPER_DIRECTION_SET 0x12 #define SERIAL_CMD_STEPPER_DIRECTION_GET 0x13 #define SERIAL_CMD_STEPPER_MICROSTEPS_SET 0x14 //Use this to accelerate by factor two's #define SERIAL_CMD_STEPPER_MICROSTEPS_GET 0x15 #define SERIAL_CMD_STEPPER_MODE_SET 0x16 #define SERIAL_CMD_STEPPER_MODE_GET 0x17 #define SERIAL_CMD_STEPPER_ACCEL_SET 0x18 #define SERIAL_CMD_STEPPER_ACCEL_GET 0x19 #define SERIAL_CMD_STEPPER_ENABLE_SET 0x1A #define SERIAL_CMD_STEPPER_ENABLE_GET 0x1B #define SERIAL_CMD_STEPPER_CTR_SET 0x1C #define SERIAL_CMD_STEPPER_CTR_GET 0x1D #define SERIAL_CMD_STEPPER_CTR_RESET 0x1E #define SERIAL_CMD_STEPPER_CTR_ROLLOVER_SET 0x1F #define SERIAL_CMD_STEPPER_CTR_ROLLOVER_GET 0x20 #define SERIAL_CMD_STEPPER_CTR_TARGET_SET 0x21 #define SERIAL_CMD_STEPPER_CTR_TARGET_GET 0x22 #define SERIAL_CMD_STEPPER_STOP_ENABLE_SET 0x23 #define SERIAL_CMD_STEPPER_STOP_ENABLE_GET 0x24 #define SERIAL_CMD_STEPPER_STEPSPERREV_SET 0x25 #define SERIAL_CMD_STEPPER_STEPSPERREV_GET 0x26 //encoder CMDs #define SERIAL_CMD_ENCODER_SET 0x30 #define SERIAL_CMD_ENCODER_GET 0x31 #define SERIAL_CMD_ENCODER_ROLLOVER_SET 0x32 #define SERIAL_CMD_ENCODER_ROLLOVER_GET 0x33 #define SERIAL_CMD_ENCODER_TARGET_SET 0x34 #define SERIAL_CMD_ENCODER_TARGET_GET 0x35 #define SERIAL_CMD_ENCODER_COUNTS_PER_STEP_SET 0x36 #define SERIAL_CMD_ENCODER_COUNTS_PER_STEP_GET 0x37 #define SERIAL_CMD_ENCODER_RESET 0x38 //TIMEBASE CMDS #define SERIAL_CMD_TIMEBASE_SET 0x40 #define SERIAL_CMD_TIMEBASE_GET 0x41 #define SERIAL_CMD_TIME_ACCUMULATOR_SET 0x42 #define SERIAL_CMD_TIME_ACCUMULATOR_GET 0x43 #define SERIAL_CMD_TIME_PRESCALER_SET 0x44 #define SERIAL_CMD_TIME_PRESCALER_GET 0x45 //Application CMDs #define SERIAL_CMD_APP_RESET 0xDB #define SERIAL_CMD_APP_INIT 0xDE #define SERIAL_CMD_APP_SHUT 0xDF #ifdef ENABLE_HW_ENCODER //Encoder status in & out struct RotaryEncoderStruct { int unused:4; // RB[0:3] int A:1; // RB4 int B:1; // RB5 int Index:1; //RB6 int unused2:1; // RB7 }; struct RotaryEncoderStruct RotaryEncoder; #pragma BYTE RotaryEncoder = 0x06 // Place structure right over PORTB at location 0x06 static BYTE OldPortB; static struct RotaryEncoderStruct OldEncoder; int32 encoderCount; int32 encoderTarget; int32 encoderRollover; int32 encoderCountsPerStep; int32 encoderOld; int32 encoderDelta; #endif //Stepper status variables and masks enum STEPPER_TYPE { UNIPOLAR_A,//4-phase 5,6 or 8 wires, full step UNIPOLAR_B,//alternate form to A UNIPOLAR_HALF,//half step BIPOLAR_A, //serial bipolar 8 wires BIPOLAR_B, //parallel bipolar 8 wires BIPOLAR_C}; int const STEPSPERPHASE = 8; #define MAXMICROSTEPINCREMENT 64 #define MAXMICROSTEPSPERSTEP 64 //Table of unipolar step phases, bipolar parallel and bipolar serial are the same.( read 1=+, 0=- ) //table of ptrs to phase tables for the respective motor types. //int16* const stepPtrTable[6] = { stepTable, stepTable, stepTable, stepTable, stepTable, stepTable }; byte const fullstepTable1[STEPSPERPHASE]={ 0b00000011, 0b00000110, 0b00001100, 0b00001001, 0b00000011, 0b00000110, 0b00001100, 0b00001001 }; /*Jones Full step table*/ byte const fullstepTable2[STEPSPERPHASE]={ 0b00000001, 0b00000100, 0b00000010, 0b00001000, 0b00000001, 0b00000100, 0b00000010, 0b00001000 }; /*Jones Half stepping table */ byte const halfstepTable[STEPSPERPHASE]={ 0b00000001, 0b00000101, 0b00000100, 0b00000110, 0b00000010, 0b00001010, 0b00001000, 0b00001001 }; /*Original*/ byte const bipolarstepTable[STEPSPERPHASE]={ 0b00001010, 0b00000110, 0b00000101, 0b00001001, 0b00001010, 0b00000110, 0b00000101, 0b00001001 }; const byte *stepTable;// = { fullStepTable1, fullStepTable2, halfStepTable, bipolarStepTable, fullstepTable}; int16 const pwmTable[MAXMICROSTEPSPERSTEP+1] = {0,1,2,6,10,15,22,30,39,49,60,73,86,101,116,133,150,168,187,207,228,249,271,293,316,340,363,388,412, 437,462,487,512,537,562,587,612,636,661,684,708,731,753,775,796,817,837,856,874,891,908,923,938,951,964,975,985,994,1002,1009, 1014,1018,1022,1023,1024 }; enum STEPPER_TYPE stepperType; int stepperStatus; //Current status int stepperStatusTarget; //Desired status int stepperStepCount; //Current steps per phase int stepperStepCountCurrent; //Current step count per phase int stepperStepCountTarget; //Target step count per phase int stepperMicrostepCount; //Current microstep count signed int stepperMicrostepCountIncrement; //Current microstep increment size int stepperMicrostepCountIncrementTarget; //Desired increment for microstepping - sets speed along with timebase. int stepperMicrostepsPerStep; //Stepper number of microsteps per step - used to generate microstep increment and timebase int stepperMicrostepsPerStepTarget; //Desired number of microsteps per step //For debugging WATCH purposes int pwmMask; int16 pwmVal; int stepMask; #if defined ENABLE_STEPPER_CTR //If an encoder is not fitted, these variable can be usaed for 'open-loop' tracking int32 stepperPositionCount; int32 stepperPositionTarget; int32 stepperPositionRollover; int32 stepperPositionLast; int32 stepperPositionDelta; #endif //CMD Arguments ( status bits 0 ) for stepper clock direction #define STEPPER_CLOCK_TOGGLE_MASK 0x01 #define STEPPER_CLOCK_TOGGLE_LOW 0x00 #define STEPPER_CLOCK_TOGGLE_HIGH 0x00 //CMD Arguments ( status bits 1 ) for stepper direction #define STEPPER_DIRN_MASK 0x02 #define STEPPER_DIRN_FORWARD 0x02 #define STEPPER_DIRN_REVERSE 0x00 //CMD Arguments ( status bits 2 )for open-loop position counting #define STEPPER_COUNT_MASK 0x04 #define STEPPER_COUNT_ENABLE 0x04 #define STEPPER_COUNT_DISABLE 0x04 //CMD Arguments ( status bits 3 )for open-loop position counting //CMD Arguments (status bits 5-6 ) for stepper mode #define STEPPER_MODE_MASK 0x60 //Move uniformly at rate specified by timebase and microstep increment, continuously. #define STEPPER_MODE_MOTION 0x00 //Seek to encoder target value . #define STEPPER_MODE_POSITION_CONSTANT 0x40 //Seek to encoder target value using ramping profile #define STEPPER_MODE_POSITION_RAMPED 0x60 //CMD Arguments (status bits 7 ) for stepper enable #define STEPPER_ENABLE_MASK 0x80 #define STEPPER_ENABLE_ON 0x80 #define STEPPER_ENABLE_OFF 0x00 //PWM status variables and settings //int16 dutyCycle; // up to 10 bits of resolution of duty cycle. //int incrementSign; //Add or delete the increment. //TMR1 timing variables. int32 phaseAccum; //the decimal remainder added until it is significant and then subtracted from the reset value on use. int t1Prescaler = 0; int16 t1ResetCount; //the value to reset the timer to. int16 t1ResetLoopCount; //the value to reset the timer timeout loop counter to int16 t1LoopCount; //How many times we have looped around the TMR1 16 bit timeout. int16 newResetCount; //Holders for new values int16 newResetLoopCount;//Holders for new values. //TMR2 Timing variables //TMR2 is owned by PWM prescaler, however can count loops. Use time increment to measure encoder deltas int16 t2LoopCount; int16 t2ResetLoopCount; int16 t2ResetCount; /* Timing considerations for star-tracking Sidereal day is 86400-3m56 secs per day = 86164 secs; Clock frequency is 19660800 Hz, each clock is 50.999 ns Hence Tosc frequency is 4915200 Hz Need to do 1 rev of the telescope in 86164 secs per day, or 1 worm rev in 86164/360 secs = 239.3444R secs With a 200 step stepper need to do 200 steps in 239.3444R secs, each with up to 32 microsteps Thus each microstep is ( at sidereal stepping rate ) 239.3444R/( 200*32)=0.0373975694444375 secs long Which is 183323.216128 Tosc clocks OR 44.7564456 (Tosc 255 clock timeouts and x16 postscaler timeouts). OR 716.10631301 256 count timeouts. OR 2.7972902851 which is 2 full 16bit timeouts and 52251.2161 counts OR 1 full 16 bit timeout with div 2 prescaler and 26125.608064 counts Table : steppers and microstep time 100 200 400 time(s) 0.037397569 TMR1 1 & 26125.608064 The PWM period = [(PR2) + 1] • 4 • TOSC • (TMR2 prescale value) Hence the PWM period is 256 * 4*50.999*1 = 53476327.424 or 19.148 KHz */ /* Function prototypes */ void setup_timebase( int16 newResetCount, int16 newLoopCount ); void setup_DeltaTimer(int32 incrementTime ); void setup_stepper(STEPPER_TYPE s, int steps, int microsteps, int status ); void setup_pwm(); void setMicrostepPWM( int16 count ); void setup_encoder( int32 rollover, int32 current ); void setup_encoder( int32 rollover, int32 initial, int countsPerStep); void step_motor(); //Indicators void flashLed( int, int16, int );