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.