Thursday, June 02, 2011

RS Servo Tester

Progetto per movimentare un servo RC da aeromodelli con un Pic 12F628A (8Pin)

Il progetto è alquanto semplice usare un timer del pic per generare un PWM idoneo a controllare la posizione del servomotore. Il servo alla accensione si posiziona al centro della corsa e con due tasti Destro e Sinistro raggiunge la posizione -120° e +120°.
Alla pressione di ambedue i tasti ritorna alla posizione centrale.
Qualcuno mi ha domandato perchè non usare il PWM del Chip? La spiegazione è semplice i servi RC hanno una temporizzazione alquanto delicata e il PWM Hardware del pic non ha una risoluzione adeguata alla richiesta di posizionamento di precisione dei Servi RC digitali.
Quindi vista la velocità di esecuzione del microcodice dei pic e optando per un generatore di clock interno a 4mhz disponibile nel CHIP ( nessun quarzo esterno ) ho scritto il codice e mi sono messo a provarlo. Confesso che sono partito da una versione in basic scritta per PIC che funzionava alquanto male, della quale nel source OPEN ho mantenuto l'intestazione originale del writer.
Tradotto in "C" e corretto il codice, usando il timer il comparatore gli interrupt e un po di calcoli svolge splendidamente il suo lavoro. Ha una risoluzione di posizionamento dei contatori di 1microsecondo pari a circa 0,07° gradi, con i controllo tasti a 0,3° per step.
Il codice è scritto in MickroC che è free per impieghi con tutti i PIC 12/16/18/24/32 e la loro bella libreria compilando codice fino a 2Kbyte in ROM (download). Consiglio per chi volesse un approccio soft al PIC di adottarlo usando la probe PICKIT2 o 3 della Microchip che trovate presso qualsiasi distributore elettronico a €37,00(circa)
Con questo investimento potete sperimentare una serie di progetti che sono veramente interessanti con il PIC e che pubblico qui sul mio Blog.

Per reneder ancora più intrigante il codice stò elaborandone una versione per controllarlo da I2Bus ( non supportato da PIC12F628) in versione slave 10bit per comandare la posizione di strumenti analogici virtuali in Xplane.

Il codice:

/***************************************************************************
***** *****
***** 50Hz SINGLE SERVO TESTER USING 2 BUTTONS *****
***** 16F628A @ 4MHz INTOSC_NoClkout *****
***** Written By Warren Schroeder on 12.31.08 Mikrobasic 7.2 *****
***** Rewrite By mcmax on 10-05-2011 MikroC *****
***** software tested and run with *****
***** 1 microsecond position accuracy *****
***** Range of 1us to 19,999us *****
***** User can setup Min, Max, & Center Sweep Range as needed *****
***** *****
***** Features 2 Button Control For 3 Main Functions: *****
***** *****
***** Button1 = move to min position by user declared Step Value *****
***** Button2 = move to max position by user declared Step Value *****
***** Button1+Button2 = move to center position *****
***** *****
***** HOLDING a BUTTON WILL AUTO INCREMENT/DECREMENT Till MAX/MIN *****
***** *****
****************************************************************************/

// macro

typedef unsigned char uchar;
typedef unsigned int uint;

#define delay30() Delay_ms(30)
#define SetTMR1(t) { CCPR1L = (uchar)(t & 0x00FF); \
CCPR1H = (uchar)((t & 0xFF00) >> 8 ); }
#define GetTMR1() (int)CCPR1L + ((int)CCPR1H << 8 )
#define ClearTimer1() TMR1L=0; TMR1H=0;

// definition

#define _STEPVAL 5 // in microseconds Step ogni 30ms
#define _MAXPWM 20000 // 20ms (valori in millisecondi)
#define _MINPOS 600 // 0,6ms -90 -+
#define _CENTER 1500 // 1,5ms 0 -+----position servo centrale
#define _MAXPOS 2400 // 2,4ms +90 -+

// global var

unsigned int ServoPos;

//***** I N T E R R U P T ************************************************

void Interrupt( void )
{
if ( CCP1IF_bit == 1) {
if ( GP4_bit == 1 ){ // bit ccp1 bit 5 pin 3
GP4_bit = 0; // turn servo off
SetTMR1( _MAXPWM - ServoPos ); // off time to finish 20ms
}
else {
GP4_bit = 1; // turn servo on
SetTMR1( ServoPos); // on time in microseconds
}
ClearTimer1(); // rimette a 0 il timer1
PIR1.CCP1IF = 0; // clear int flag
}
}

//-------------------------------------------------------------------------

void CCP_Setup( void )
{
T1CON = 0; // no prescale; off; 1us ticks
ClearTimer1(); // clear timer1

ServoPos = _MINPOS; // posizione iniziale

CCP1CON = 0b00001010; // compare-match no ADC start or
// reset timer1 when match
SetTMR1( ServoPos ); // set intitial position

PIR1.CCP1IF = 0; // clear int flag
PIE1.CCP1IE = 1; // enable int
T1CON.TMR1ON = 1; // timer1 run

PEIE_bit = 1; // start periferical int
GIE_bit = 1; // GIE, PEIE enabled
}

/*********************************************************
***** *****
***** Buttons Inputs are Pulled Low on RA0 and RA1 *****
***** *****
*********************************************************/


void KeyCtrl(void)
{
char Temp;

if ((GPIO & 3) != 0x03 ) { // check for active buttons

Delay_Ms(30); // debounce delay
Temp = GPIO & 0x03; // save button value

while ( Temp != 0) { // while a button is active do

if ( Temp == 3) { // both buttons active
ServoPos = _CENTER; // goto center position
}
else {
if ( Temp == 1) { // dec position by stepval
ServoPos = ServoPos - _STEPVAL;
if ( ServoPos < _MINPOS )
ServoPos = _MINPOS;
}
else { // inc position by stepval
ServoPos = ServoPos + _STEPVAL;
if ( ServoPos > _MAXPOS)
ServoPos = _MAXPOS;
}
}
Delay_Ms(30); // button release delay
Temp = GPIO & 3 ; // check again for release
}
} // if not released will inc or dec more
}

/****** M A I N ***********/

void main(void)
{
INTCON = 0; // disable alla interrupt

OSCCON = 0b01100000; // work at 4Mhz of internal
// clock without ext clk
ANSEL = 0x00; // disable analog ad digital I/O
CMCON0 = 0x07; // disable comparator

GPIO = 0x00; // init port setup
TRISIO = 0x03; // bit 0 = 7 Key UP
// bit 1 = 6 Key DW
// pwm su pin 3 al servo motor

CCP_Setup(); // setup value application and timing

while(1) // main loop
KeyCtrl(); // key controll

}

// end source

Lo schema del prototipo

Il PCB

Le foto del prototipo

Buon divertimento.