/* Servo Bank controller This file gets position data from the main controller and keeps the servos updated Interrupt Version (C) 2004 Jason Hunt */ #include #pragma config |= 0x3FF0 /* assign names to port pins */ bit led @ PORTB.5; bit data @ PORTB.1; bit clock @ PORTB.2; bit ready @ PORTB.3; // Base time offsets const unsigned servo_base[] = {200, 200, 200, 200}; // or with this to turn servo[x] on const unsigned servo_on_mask[] = {0x01, 0x02, 0x04, 0x08}; // and with this to turn servo[x] off const unsigned servo_off_mask[] = {0xff - 0x01, 0xff - 0x02, 0xff - 0x04, 0xff - 0x08 }; unsigned servo_pos[4]; // positions of servos unsigned cur_servo; // the servo that the int is working on unsigned int_mode; // the state of the intrrupt handler /* the ISR to update the servos */ #pragma interruptSaveCheck n #pragma origin 4 interrupt ISR(void) { int_save_registers if (int_mode == 0) // setupup for base pos wait { int_mode = 1; // next trigger we will setup for base delay OPTION = 2; // reset back into 1:4 prescaled mode TMR0 = servo_base[cur_servo]; // set base time delay PORTA |= servo_on_mask[cur_servo]; // turn this one on } else if (int_mode == 1) { OPTION = 1; // set to prescale for pos timer 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) { int_mode = 0; // reset back to base mode PORTA &= servo_off_mask[cur_servo]; // turn the current servo off cur_servo++; // next servo // check for the longer delay to fill the 20 ms window if (cur_servo == 4) { cur_servo = 0; // reset back the first servo OPTION = 5; // ser the prescale for a longer delay time TMR0 = 30; // set the value for the longer delay } } T0IF = 0; // clear int flag int_restore_registers } /* end of ISR */ /* reset all servoes to middle positions */ void home_servos( void ) { // home the servos servo_pos[0] = 128; servo_pos[1] = 128; servo_pos[2] = 128; servo_pos[3] = 128; } /* end of home_servos */ /* gets a clocked byte from the data and clock lines */ /* data is send LSB first */ char get_byte(void) { char count = 8; // the number of bits char ch = 0; // the temporary char while (count) { ch = ch >> 1; // shift the byte right while (!clock); ready = 0; if (data) ch |= 0x80; // data is ored with the MSB while (clock); ready = 1; count--; } return(ch); } /* end of get byte */ /* main function */ void main(void) { PORTA = 0; // clear the ports PORTB = 0; TRISB = 0xD7; // bit 6, 7 input all others, output TRISA = 0x00; CMCON = 0x07; // switch comparators off cur_servo = 0; int_mode = 0; home_servos(); // reset to base positions TMR0 = 0; /* 45 * 2 = 90 periods */ T0IE = 1; /* enable TMR0 interrupt */ GIE = 1; /* interrupts allowed */ OPTION = 2; /* prescaler divide by 2 */ ready = 1; while (1) { // see of the master is sending a command if (clock) { led = 1; char command = get_byte(); if (command == 0x00) // start byte { char i,t; for (i = 0; i < 4; i++) { t = get_byte(); servo_pos[i] = t; } } led = 0; } } } /* end of main */