/********************************************************************* * Description of program: * * C file for letting the robot cruise around, either by pre- * * path or by a path generated by the compiler for generating a list * * of commands. * * * * * * * * * * * * So much for the purpose of this file * ********************************************************************* * Author: * * Max. Heise, 15.03.2002, 16H10 - created * * Max. Heise, 18.03.2002, 12H00 - Changed so that the two pairs of * * LEDs function the opposite way, one is on, the other off by * * default. This is better because the LED on will signal that the * * program was loaded correctly and the PIC is running. * * Max. Heise, 19.03.2002, 14H40 - Copied asm functions from project * * pwm_f877 and converted them to pseudo C(Inline assembler). * * Max. Heise, 19.03.2002, 19H00 - Conversion to pure C complete * * Max. Heise, 20.03.2002, 10H30 - error in generating mask for LSB * * PWM register, added enable and IN2s for PWM, rewrote * * startSwitchIsOn to faster handle the default case that the * * switch is on. Added init for ENs, IN2s and switch to port init * * functions. More comments. * * Max. Heise, 22.03.2002, 13H10 - Changed usage of pins to have SDA * * and SCL free. * * Max. Heise, 22.03.2002, 13H30 - Copied source file to project * * cruise, added blinking LED0 with help of timer1 module * * Max. Heise, 25.03.2002, 10H00 - Added cruising in main * * Max. Heise, 26.03.2002, 16H00 - Added timer type and variable * * globalTimer * * Max. Heise, 27.03.2002, 16H00 - Changed reload value and start of * * programmed cruising course. * * Max. Heise, 28.03.2002, 13H00 - Found typo/bug in initPortD, it * * was setting PORTC=0 instead of PORTD=0. * * Max. Heise, 28.03.2002, 14H20 - Small bug in counter code that * * did not permit waits==0 * * Max. Heise, 02.05.2002, 15H15 - Created cruise2 from cruise * * Added support for 5 A/D channels, they are needed for the scotch * * detection sensors. * * Max. Heise, 06.05.2002, 16H00 - Never ever use the X in the upper * * right corner. It will no always save your file on closure ! * * Redo lost work from today * * Max. Heise, 07.05.2002, 12H20 - Continued * * Created sensor.c, sensor.h, pwm.c, pwm.h, ad.c, ad.h, cruise2.h * * cut 'n paste. Dito for timer.c and timer.h * * MAHE, 13.05.2002, 12H40 - now compiling as project of separated * * source files * * MAHE, 24.05.2002, 16H20 - Created from cruise2.c, added use of * * potis to detect maximum speed because once the inertia of the * * robot has driven the sensors of the scotch - the game is over * * MAHE, 27.05.2002, 15H40 - Spend all day programming support * * to set speed and delta for speeds slow normal and fast while * * cruising. * * MAHE, 03.06.2002, 17H00 - Lots of changes and eeprom support * * today and last week. * * * * * * * ********************************************************************* * TODO/Bugs: * * * *********************************************************************/ #include "cruise3.h" /******************** * externs ********************/ extern Timer globalTimer; extern unsigned char errorno; /******************************************************************************************** * Init the interrupt control * First in INTCON * then in PIE1 ********************************************************************************************/ void initInterrupt(void) { /********************* * Global interrupt * control flag in * INTCON *********************/ GIE=1; /********************* * Peripheral interrupt * control flag in * INTCON *********************/ PEIE=1; /********************* * Enable interrupt * for Timer1 module * in PIE1 *********************/ TMR1IE=1; /********************* * And clear the TMR1IF * flag for the first * time in PIR1 *********************/ TMR1IF=0; } /******************************************************************************************** * Interrupt service routine ********************************************************************************************/ void interrupt isr(void) { if(TMR1IF) { /************************ * Reload timer register * with value 0xD8EF ************************/ TMR1H=TMR1_MSB_RELOAD; TMR1L=TMR1_LSB_RELOAD; /************************ * Toggle LED0 ************************/ LED0 ? LED0=0: LED0=1; /********************* * If timer is running *********************/ if(globalTimer.isRunning) { /********************* * Increment the * timer1 counter and check if >= N *********************/ globalTimer.timer1Counter++; if(globalTimer.timer1Counter>=globalTimer.N) { if(globalTimer.counter > 0) { globalTimer.counter--; } globalTimer.timer1Counter=0; if(globalTimer.counter==0) { /******************* * Stop the timer *******************/ globalTimer.isRunning=0; globalTimer.isTerminated=1; } } } /********************* * And clear the TMR1IF * flag in PIR1 *********************/ TMR1IF=0; } } /******************************************************************************************** * startSwitchIsOn * It is not sufficent that RD4 is HIGH, we need to observe a transition from LOW to HIGH * (positive edge), therefor a bit more logic is needed than for the other two buttons. * There are 3 possibilities: * 1. RD4 is LOW, return 0 * 2. RD4 is HIGH, no pos. edge was ever observed, return 0 * 3. RD4 is HIGH and a pos. edge has once been observed, return 1 ********************************************************************************************/ char startSwitchIsOn(void) { /************************** * Variables **************************/ static bit lastState; static bit currentState; static bit posEdgeObserved; static bit wasHereBefore; char retval=0; /* bits can either be static or global, but never local variables * with this C compiler */ const unsigned int waitTime=20; /* Two seconds */ /************************* * store current state * and get new state *************************/ lastState=currentState; currentState=SWITCH0; /************************* * This to avoid having the * whole thing start on power * up when SWITCH0 is in HIGH * position. *************************/ if( !wasHereBefore ) { wasHereBefore=1; lastState=currentState; } /************************** * Check for pos. edge **************************/ if( (!lastState) && currentState ) { /********************* * This is a pos edge! *********************/ posEdgeObserved=1; /********************* * OK, now that we have * the pos.edge wait two * seconds *********************/ startGlobalTimer(waitTime); while(!isFinishedGlobalTimer()) { // NOP } } /********************************* * Now check the three possibil. * listed above *********************************/ if( (!currentState) || (currentState && (!posEdgeObserved))) { posEdgeObserved=0; retval=0; } else { if( currentState && posEdgeObserved ) { retval=1; } } /************************* * if we return TRUE then * switch on the led RD7 and * enable the two PWM channels * else switch off * and finally return from function .... * Do nothing if an error * occured *************************/ if(retval && !errorno) { LED2=1; PWMChanEN(0, 1); PWMChanEN(1, 1); } else { LED2=0; /* LED for switch */ PWMChanEN(0, 0); PWMChanEN(1, 0); setDutyCycle(0, 0, 0); setDutyCycle(1, 0, 0); } return retval; } /******************************************************************************************** * Main ********************************************************************************************/ void main(void) { /******************** * local variables ********************/ char i,k; static bit firstTime; unsigned int adData=0; unsigned char speedSlow=0, speedNormal=0, speedFast=0, delta=0; unsigned char sensor=0; SensorValue ppmrlSensors[MAXPOTIS+MAXSENSORS]={0, 0, 0, 0, 0}; /****************************** * Unfortunately, not all sensors * are created equal. * The right and left sensor output 0,5V for a detected scotch and 2V for the desk surface * The middle sensor outputs 3V for a detected scotch and 4V for the desk surface * Initializing low and high * to opposite values to that teaching will * always change them * The potis reach their theoretical high and low * values. Therefor there is no need to teach these values * for the first two sensors. ******************************/ SensorValue lowestValue[MAXSENSORS]={ ADMAXVALUE, ADMAXVALUE, ADMAXVALUE }; SensorValue highestValue[MAXSENSORS]={ ADMINVALUE, ADMINVALUE, ADMINVALUE };; /* for(i=0;i1) { k=i-2; if(ppmrlSensors[i] < ( ( (highestValue[k]-lowestValue[k]) /3 ) + lowestValue[k] ) ) { bsf(sensor, k); } else { bcf(sensor, k); } } } /****************************** * Calculate speed for slow, normal and fast. * Scale current poti value to min and max values that were teached. * The formular for speedNormal is current/high which is * the scale between 0 and 1 which in turn represents 0 to 100 percent * times the max value 0xFF == 255 for the high * register of the pwm module being used * The formular for speedSlow and speedFast is different in regard to the max value which * is 100 here. The calculation of the scale between 0 is 1 is the same * Note the multiplication first to avoid having an * integer division with result 0 before the multiplication. * Note that the potis will reach there theoretical low and almost high values. * So there is no need to have highest * and lowest values like for the light sensors. ******************************/ speedNormal=(70L*ppmrlSensors[0])/ADMAXVALUE; delta=(70L*ppmrlSensors[1])/ADMAXVALUE; speedFast=speedNormal+delta; speedSlow=speedNormal-delta; while(speedSlow>speedNormal || speedFastspeedNormal) { speedSlow=speedNormal; } if(speedFasthighestValue[i]) { highestValue[i]=adData; writeUIntToEEprom((i*4)+2, adData); } } } if(!BUTTON0) { initEEprom(); for(i=0;i