control de 8 servos con pic
TRANSCRIPT
#include <16f877.h>#fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT,PUT#use delay (clock=20000000)#USE RS232 (baud=9600,bits=8,parity=N,xmit=PIN_C6,rcv=PIN_C7)
#byte RCSTA= 0x018#bit CREN= RCSTA.4 // Se activa para recepción continua#bit OERR= RCSTA.1 // Error de Overrun
#use fast_io(A)#use fast_io(B)#use fast_io(C)#use fast_io(D)#use fast_io(E)
#byte PORTA = 0x05#byte PORTB = 0x06#byte PORTC = 0x07#byte PORTD = 0x08#byte PORTE = 0x09
#bit servo_00 = PORTB.0#bit servo_01 = PORTB.1#bit servo_02 = PORTB.2#bit servo_03 = PORTB.3#bit servo_04 = PORTB.4#bit servo_05 = PORTB.5#bit servo_06 = PORTB.6#bit servo_07 = PORTB.7
#bit servo_08 = PORTD.0#bit servo_09 = PORTD.1#bit servo_10 = PORTD.2#bit servo_11 = PORTD.3#bit servo_12 = PORTD.4#bit servo_13 = PORTD.5#bit servo_14 = PORTD.6#bit servo_15 = PORTD.7
#define n 16// número de servos, para otro número de servos hay que hacer mediciones de tiempo
#define max_theCount 200// 200*100us=20ms#define derecha 25// 25*100us=2,5ms#define centro 15// 15*100us=1,5ms#define izquierda 5// 5*100us =0,5ms
/////////////////////////////////////// PRINCIPAL /////////////////////////////////////
void main(){ int8 theCount=1; int k; int8 duty[n]; int8 i=0;// es el índice exclusivo de duty[] en la recepción serial int1 band=0; set_tris_b(0x00);
set_tris_c(0b10000000); set_tris_d(0x00); PORTB=0x00; PORTD=0x00; port_b_pullups(FALSE); for(k=0;k<=(n-1);k++) duty[k]=izquierda;//
setup_adc_ports(NO_ANALOGS); setup_adc(ADC_OFF); setup_timer_1(T1_DISABLED); setup_timer_2(T2_DISABLED,0,1);
disable_interrupts(global);
while (1) { delay_us(70); #asm nop nop nop nop #endasm// Cada 100us llega aqui de forma cíclica if (duty[0] >= theCount) { servo_00=1; } else { servo_00=0; #asm nop #endasm } if (duty[1] >= theCount) { servo_01=1; } else { servo_01=0; #asm nop #endasm } if (duty[2] >= theCount) { servo_02=1; } else { servo_02=0; #asm
nop #endasm } if (duty[3] >= theCount) { servo_03=1; } else { servo_03=0; #asm nop #endasm } if (duty[4] >= theCount) { servo_04=1; } else { servo_04=0; #asm nop #endasm } if (duty[5] >= theCount) { servo_05=1; } else { servo_05=0; #asm nop #endasm } if (duty[6] >= theCount) { servo_06=1; } else { servo_06=0; #asm nop #endasm } if (duty[7] >= theCount) { servo_07=1; } else { servo_07=0; #asm nop
#endasm } if (duty[8] >= theCount) { servo_08=1; } else { servo_08=0; #asm nop #endasm } if (duty[9] >= theCount) { servo_09=1; } else { servo_09=0; #asm nop #endasm } if (duty[10] >= theCount) { servo_10=1; } else { servo_10=0; #asm nop #endasm } if (duty[11] >= theCount) { servo_11=1; } else { servo_11=0; #asm nop #endasm } if (duty[12] >= theCount) { servo_12=1; } else { servo_12=0; #asm nop #endasm
} if (duty[13] >= theCount) { servo_13=1; } else { servo_13=0; #asm nop #endasm } if (duty[14] >= theCount) { servo_14=1; } else { servo_14=0; #asm nop #endasm } if (duty[15] >= theCount) { servo_15=1; } else { servo_15=0; #asm nop #endasm } theCount=theCount+1; if (theCount>max_theCount) { theCount=1; } else { delay_us(1); #asm nop #endasm }
// Recepción de datos// Las rutinas delays y los nop son para normalizar los tiempos if (kbhit()){ if (band==0){ i=getc(); band=1; delay_us(1); #asm nop nop
#endasm } else{ duty[i]=getc(); band=0; } } else{ delay_us(3); #asm nop #endasm } }}
La trama de envío es (Servo, Posición) dos bytes, el extremo izquierdo se logra con una posición igual a 5 y el extremo derecho con una posición igual a 25, y para el centro=15.
Bueno aquí está el código para controlar 16 servos con el pic18f4550, le podemos enviar comandos tanto vía serial RS232 como vía USB, la trama es (SERVO,POSICIÓN), SERVO=[0..15] y POSICIÓN=[5..25], donde 5=extremo izquierdo y 25=extremo derecho.
#use delay(clock=48000000)//48MHz
#USE RS232 (baud=9600,bits=8,parity=N,xmit=PIN_C6,rcv=PIN_C7)
//#build(reset=0x000800,interrupt=0x000808:0x000818)// Necesario para indicarle al compilador a partir de donde alojar mi programa// Si se quiere usar bootloader se pueden habilitar estás dos líneas//#ORG 0x000, 0x07FF {} // Espacio reservado para alojar el bootloader
#byte PORTA = 0xF80// Son las direcciones de memoria de los puertos en este PIC#byte PORTB = 0xF81#byte PORTC = 0xF82#byte PORTD = 0xF83#byte PORTE = 0xF84
///////////////////////////////////////////////////////////////////////////////// CCS Library dynamic defines. For dynamic configuration of the CCS Library// for your application several defines need to be made. See the comments// at usb.h for more information///////////////////////////////////////////////////////////////////////////////#define USB_HID_DEVICE FALSE //deshabilitamos el uso de las directivas HID#define USB_EP1_TX_ENABLE USB_ENABLE_BULK //turn on EP1(EndPoint1) for IN bulk/interrupt transfers#define USB_EP1_RX_ENABLE USB_ENABLE_BULK //turn on EP1(EndPoint1) for OUT bulk/interrupt transfers#define USB_EP1_TX_SIZE 2 //size to allocate for the tx endpoint 1 buffer#define USB_EP1_RX_SIZE 2 //size to allocate for the rx endpoint 1 buffer
///////////////////////////////////////////////////////////////////////////////// If you are using a USB connection sense pin, define it here. If you are// not using connection sense, comment out this line. Without connection// sense you will not know if the device gets disconnected.// (connection sense should look like this:// 100k// VBUS-----+----/\/\/\/\/\----- (I/O PIN ON PIC)// |// +----/\/\/\/\/\-----GND// 100k// (where VBUS is pin1 of the USB connector)/////////////////////////////////////////////////////////////////////////////////#define USB_CON_SENSE_PIN PIN_B2 //CCS 18F4550 development kit has optional conection sense pin
///////////////////////////////////////////////////////////////////////////////
// Include the CCS USB Libraries. See the comments at the top of these// files for more information///////////////////////////////////////////////////////////////////////////////#include <pic18_usb.h> //Microchip PIC18Fxx5x Hardware layer for CCS's PIC USB driver#include <PicUSB.h> //Configuración del USB y los descriptores para este dispositivo#include <usb.c> //handles usb setup tokens and get descriptor reports
#use fast_io(A)#use fast_io(B)#use fast_io(C)#use fast_io(D)#use fast_io(E)
#bit servo_00 = PORTB.0#bit servo_01 = PORTB.1#bit servo_02 = PORTB.2#bit servo_03 = PORTB.3#bit servo_04 = PORTB.4#bit servo_05 = PORTB.5#bit servo_06 = PORTB.6#bit servo_07 = PORTB.7
#bit servo_08 = PORTD.0#bit servo_09 = PORTD.1#bit servo_10 = PORTD.2#bit servo_11 = PORTD.3#bit servo_12 = PORTD.4#bit servo_13 = PORTD.5#bit servo_14 = PORTD.6#bit servo_15 = PORTD.7
#define i_usb recibe[0]// es el índice que se recibe vía usb#define pos_usb recibe[1]// es la posición que se recibe vía usb
#define n 16// número de servos //para otro número de servos hay que hacer mediciones de tiempo
#define max_theCount 200// 200*100us=20ms#define derecha 25// 25*100us=2,5ms#define centro 15// 15*100us=1,5ms#define izquierda 5// 5*100us =0,5ms
#define val_timer0 127
int8 theCount=1;int8 duty[n];
#INT_TIMER0void isr_timer0(){ delay_cycles(5); if (duty[0] >= theCount)// Cada 100us llega aqui de forma cíclica { servo_00=1; }
else { servo_00=0; #asm nop #endasm } if (duty[1] >= theCount) { servo_01=1; } else { servo_01=0; #asm nop #endasm } if (duty[2] >= theCount) { servo_02=1; } else { servo_02=0; #asm nop #endasm } if (duty[3] >= theCount) { servo_03=1; } else { servo_03=0; #asm nop #endasm } if (duty[4] >= theCount) { servo_04=1; } else { servo_04=0; #asm nop #endasm } if (duty[5] >= theCount) { servo_05=1; } else
{ servo_05=0; #asm nop #endasm } if (duty[6] >= theCount) { servo_06=1; } else { servo_06=0; #asm nop #endasm } if (duty[7] >= theCount) { servo_07=1; } else { servo_07=0; #asm nop #endasm } if (duty[8] >= theCount) { servo_08=1; } else { servo_08=0; #asm nop #endasm } if (duty[9] >= theCount) { servo_09=1; } else { servo_09=0; #asm nop #endasm } if (duty[10] >= theCount) { servo_10=1; } else {
servo_10=0; #asm nop #endasm } if (duty[11] >= theCount) { servo_11=1; } else { servo_11=0; #asm nop #endasm } if (duty[12] >= theCount) { servo_12=1; } else { servo_12=0; #asm nop #endasm } if (duty[13] >= theCount) { servo_13=1; } else { servo_13=0; #asm nop #endasm } if (duty[14] >= theCount) { servo_14=1; } else { servo_14=0; #asm nop #endasm } if (duty[15] >= theCount) { servo_15=1; } else { servo_15=0;
#asm nop #endasm } theCount=theCount+1; if (theCount>max_theCount) { theCount=1; } else { delay_us(1); #asm nop #endasm } set_timer0(val_timer0);}
/////////////////////////////////////// PRINCIPAL /////////////////////////////////////
void main(){ int k; int8 i=0;// es el índice exclusivo de duty[] en la recepción serial int1 band=0; int8 recibe[2];// Buffer de recepción vía usb //int8 envia[2];// Habilitar en caso de necesitar set_tris_b(0x00); set_tris_c(0b10000000); set_tris_d(0x00); PORTB=0x00; PORTD=0x00; port_b_pullups(FALSE); for(k=0;k<=(n-1);k++) duty[k]=centro;//
setup_adc_ports(NO_ANALOGS); setup_adc(ADC_OFF);
setup_timer_0(RTCC_DIV_8 | RTCC_8_BIT);
set_timer0(val_timer0); enable_interrupts(INT_TIMER0); enable_interrupts(GLOBAL); usb_init();//inicializamos el USB
usb_task();//habilita periférico usb e interrupciones usb_wait_for_enumeration();//esperamos hasta que el PicUSB sea configurado por el host
while (TRUE)
{ if(usb_enumerated())//si el PicUSB está configurado //if (TRUE) {// Recepción de datos via rs232 if (kbhit()){ if (band==0){ i=getc(); band=1; } else{ duty[i]=getc(); band=0; } }// Recepción vía USB if (usb_kbhit(1))//El endpoint de salida contiene datos del host (EP1)? { usb_get_packet(1, recibe, 2);// Recibimos los 2 bytes: (servo,pos) duty[i_usb]=pos_usb; } } }}