/* Sonar bot source. (C) 2005 Jason Hunt Based on: ORPP Motion Controller Source (C) 2005 Jason Hunt nulluser@gmail.com 16f871.h has been modified as follows: // original // #pragma chip PIC16F871, core 14, code 2048, ram 32 : 0xBF /0 /3 #pragma chip PIC16F871, core 14, code 0x1F00, ram 32 : 0x1FF #pragma cdata[0] = 0x0180 + 0x0A // CLRF PCLATH, prepare for code page change #pragma cdata[1] = 0 // NOP #pragma cdata[2] = 0 // NOP #pragma resetVector 3 // start address for user program This reserves space for the serial bootloader. */ #define start_string "ORPP-1. (C) 2005 Jason Hunt" #include #pragma chip PIC16f871 #pragma config |= 0x3FF2 // for ceramic resinator /* Pin Assignments */ #pragma bit led0 @ PORTB.6 #pragma bit led1 @ PORTB.7 #pragma bit digital_in_0 @ PORTB.0 #pragma bit digital_in_1 @ PORTA.4 #pragma bit digital_in_2 @ PORTE.0 #pragma bit digital_in_3 @ PORTE.1 #pragma bit digital_in_4 @ PORTE.2 #pragma bit radio_in_0 @ PORTD.6 #pragma bit radio_in_1 @ PORTD.7 #pragma bit open_collector_0 @ PORTB.4 #pragma bit open_collector_1 @ PORTB.5 #pragma bit pwm_out_0 @ PORTB.1 #pragma bit pwm_out_1 @ PORTB.2 #define num_servo 6 // number of servos connected to the board unsigned char servo_pos[num_servo]; // positions of the 8 servos unsigned char pwm_value_0; unsigned char pwm_value_1; /******************* ** Interrupt Code ** *******************/ #pragma interruptSaveCheck n #pragma origin 4 unsigned char int_mode; unsigned char cur_servo; unsigned char pwm_cycle; unsigned char counter_h; unsigned char counter_l; /* the ISR to update the servos */ interrupt ISR(void) { int_save_registers // check for timer zero interrupt if (T0IF) { if (int_mode == 0) // setupup for base pos wait { int_mode = 1; // next trigger we will setup for base delay OPTION = 4; // reset back into 1:16 prescaled mode OPTION &= 0xf8; // clear prescaler bits OPTION |= 0x04; // set to 1:32 prescaler TMR0 = 0xa0; // set base time delay unsigned char s = 1 << cur_servo; // create mask PORTC |= s; // turn this one on } else if (int_mode == 1) // setup for position hold { int_mode = 2; // next mode will turn off and check for long delay TMR0 = servo_pos[cur_servo]; // reset the timer to the pos } else if (int_mode == 2) // setupfor next servo { int_mode = 0; // reset back to base mode unsigned char s = 1 << cur_servo; // create mask s = 255 - s; PORTC &= s; // turn the current servo off cur_servo++; // next servo // Setup longer delay to fill the 20 ms window, // we need to burn 11ms on average // 5Mhz clock, 0.0512 MS per increment at 1:256 prescaler // 11ms / 0.0512 ms = 215 cycles to burn, start time at 40 if (cur_servo == num_servo) { cur_servo = 0; // reset back the first servo OPTION &= 0xf8; // clear prescaler bits OPTION |= 0x07; // set to 1:256 prescaler TMR0 = 40; // set the value for the longer delay } } T0IF = 0; // clear timer zero interrupt } else // check for timer one interrupt /* if (TMR1IF) { // TMR1L = 0x00; // reset timer // TMR1H = 0x80; TMR1IF = 0; // clear flag } else*/ if (TMR2IF) { if (pwm_cycle > 0x40) { counter_l++; if (!counter_l) counter_h++; } pwm_cycle++; if (pwm_cycle == 0 && pwm_value_0) pwm_out_0 = 1; // cycle start, make sure pwm is nonzero if (pwm_cycle == 0 && pwm_value_1) pwm_out_1 = 1; // turn outputs off after their duty has passed if (pwm_cycle > pwm_value_0) pwm_out_0 = 0; if (pwm_cycle > pwm_value_1) pwm_out_1 = 0; TMR2 = 0xe0; // reset timer this is about 500 hz TMR2IF = 0; // clear flag } int_restore_registers } /* end of interrupt service routine */ /************************** ** End of interrupt Code ** **************************/ /*********************** ** Serial functions ** ***********************/ /* Set the serial port to 9600 8N1 */ void setup_serial(void) { // SPBRG = 129; // divisor for 9600 baud SPBRG = 64; // divisor for 19200 baud TXSTA = 0b.0010.0100; // transmitt enable, high speed RCSTA = 0b.1001.0000; // serial enable char ch = RCREG; // flush buffer ch = RCREG; ch = RCREG; } /* end of setup serial */ /* sends a byte to the serial port */ void send_serial(unsigned char byte) { while (!TRMT); // wait until buffer is empty TXREG = byte; // send the byte } /* end of send byte */ /* sends a byte to the serial port */ unsigned char get_serial(void) { while (!RCIF); return(RCREG); } /* end of send byte */ /* sends 4 bits in hex format */ void send_nibble( unsigned char n ) { if (n > 9) send_serial(n - 10 + 'A'); else send_serial(n + '0'); } /* end of send_nibble */ /* sends a byte as hex */ void send_hex(unsigned char d) { send_nibble(d >> 4); send_nibble(d & 0xf); } /* end of send_hex */ /* sends a byte as hex */ void linefeed( void ) { send_serial(0x0d); send_serial(0x0a); } /* end of send_hex */ /* gets a hex digit from the serial port */ unsigned char get_hex_nibble( void ) { unsigned char c = get_serial(); // force upper case if (c > '9') { c &= 0xdf; return(c - 'A' + 10); } else return(c - '0'); } /* end of get_hex_nib */ /* gets a byte in hex from the serial port */ unsigned char get_hex(void) { unsigned char val; val = get_hex_nibble() << 4; return(val + get_hex_nibble()); } /* end of get_hex */ /***************************** ** End of serial functions ** *****************************/ /******************* ** Initialization ** *******************/ /* system startup */ void startup( void ) { PORTA = 0; // clear ports PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; TRISA = 0b.1111.1111; // all inputs TRISB = 0b.0000.0001; // bit 0 is digital in 2, bit 3 is led1 TRISC = 0b.1000.0000; // bit 7 is rx TRISD = 0b.1100.0000; // D6, D7 radio in, all others digital out TRISE = 0b.0000.0111; // E0-E2 digital in // setup a/d ADCON1 = 0b.1000.0010; // RE0, 1, 2 : digital RA0,1,2,3,5 : analog ADCS1 = 1; // Fosc/32 clocl ADCS0 = 0; ADON = 1; // turn on converter // ADCON0 = 0b.1000.0001 | mask; // clear core values before interrupts are turned on int_mode = 0; // finite state machine for servo control cur_servo = 0; // current servo number pwm_cycle = 0; // state of pwm system pwm_value_0 = 0; pwm_value_1 = 0; GIE = 1; // interrupts allowed PEIE = 1; // enable periphial interrupts // setup timer 0 OPTION = 4; // prescaler divide by 16 T0CS = 0; // internel clock TMR0 = 0; // clear the timer T0IE = 1; // enable interrupt for timer 0 // setup timer 1 TMR1L = 0; // reset timer TMR1H = 0; TMR1ON = 0; // shut off timer to modify values T1CKPS1 = 1; // setup prescaler T1CKPS0 = 0; T1OSCEN = 0; // shut off oscillator TMR1CS = 0; // internal clock // TMR1IE = 1; // enable interrupt TMR1ON = 1; // turn timer on TMR1IF = 0; // clear interrupt flag TMR2 = 0xe0; TMR2ON = 1; // enable timer 2 TMR2IE = 1; servo_pos[0] = 0x80; // setup inital servo positions servo_pos[1] = 0x80; servo_pos[2] = 0x80; servo_pos[3] = 0x80; servo_pos[4] = 0x80; servo_pos[5] = 0x80; } /* end of startup */ /************************** ** End of Initialization ** **************************/ /*********************** ** Utility functions ** ***********************/ /* general use delay function */ void delay(unsigned char time) { TMR1H = 255 - time; while(TMR1H); } /* end of delay */ /****************************** ** End of Utility functions ** ******************************/ /**************************************** ** Serial command interface functions ** ****************************************/ unsigned int get_sonar( void ) { // unsigned char n = get_hex_nibble(); PORTD |= 0x01; // or mask delay(0xa0); PORTD &= 0xfe; // or mask TMR1H = 0; TMR1L = 0; while(!digital_in_0&& TMR1H < 0x80); TMR1H = 0; TMR1L = 0; while(digital_in_0&& TMR1H < 0x80); unsigned char h = TMR1H; return(h); } void ddelay(unsigned int d) { unsigned int i, k, j; for (i = 0; i < d ; i++); } int turncheck() { servo_pos[1] = 0x40; unsigned int countl = 0; unsigned int counth = 0; while(counth < 0x20) { countl++; if (!countl) counth++; ddelay(4); } unsigned int side_1 = get_sonar(); servo_pos[1] = 0xb0; countl = 0; counth = 0; while(counth < 0x20) {countl++; if (!countl) counth++; ddelay(4); } unsigned int side_2 = get_sonar(); servo_pos[1] = 0x80; while(counth < 0x40) {countl++; if (!countl) counth++; ddelay(4); } return(side_1 - side_2); } void stop(void) { open_collector_0 = 1; // reverse motor dir, stops faster pwm_value_1 = 0; counter_h = 0; while(counter_h < 0x80); } #define sonar_stop 0x0b /* main function */ void main ( void ) { startup(); delay(0xff); // wait for serial to stabilize setup_serial(); linefeed(); // make sure start message is on the same line // infinte loop //int mode = 0; unsigned int countl = 0; unsigned int counth = 0; while (1) { // moving forward checking sonar, wheels straight pwm_value_1 = 0x68; // speed open_collector_0 = 0; // moving forward servo_pos[0] = 0x90; // steering straight servo_pos[1] = 0x80; while(get_sonar() > sonar_stop); // forward // stop stop(); int t = turncheck(); if (t > 0) servo_pos[0] = 0xb0; else servo_pos[0] = 0x50; // reverse pwm_value_1 = 0xa0; open_collector_0 = 1; // delay for reverse counter_h = 0; while(counter_h < 0x60); stop(); if (t < 0) { servo_pos[0] = 0xb0; servo_pos[1] = 0xb0; } else { servo_pos[0] = 0x50; servo_pos[1] = 0x40; } counter_h = 0; while(counter_h < 0x20); // forward and turn pwm_value_1 = 0x90; open_collector_0 = 0; counter_h = 0; while (counter_h < 0x60 && get_sonar() > sonar_stop); // turn } } /* end of main */