|
|
View previous topic :: View next topic |
Author |
Message |
opvini
Joined: 27 Apr 2012 Posts: 50 Location: Brazil
|
SERVOS: controlling more than 3 servo motors using any PIN |
Posted: Wed Apr 24, 2013 1:40 pm |
|
|
Hi everyone. I was need control various servos motors but the PIC 18F4550 has just 3 PWM's, then I create this library and test to create various PWM's using TIMER 0 and 4 MHz (if you need change it, change on library) on any PIN that you want. (sorry my bad english, I'm from Brazil).
The use was very simple, as you can see below:
Code: |
#include <18F4550.h>
#fuses HS
#use delay(clock=4000000)
#include "aev_servo.c"
void main(){
// declaration of variables PWM's (all must to be integer)
int pwm1, pwm2, pwm3;
// setup all pwm's that you'll use
pwm1 = pwm_setup(830, PIN_E0); // returns the index of the PWM (the first is 0)
pwm2 = pwm_setup(590, PIN_E1); // returns 1 (second)
pwm3 = pwm_setup(950, PIN_C0); // returns 2 (third)
// init the pwm's
pwm_init();
// update value from pwm2 (PIN_E1) after 10 seconds
delay_ms(10000);
pwm_update(pwm2, 600);
while(1){ }
}
///////////////// METHODS ///////////////////////
//
// pwm_setup ( int16 DUTY_CYCLE, int16 PIN)
// setup the PIN will use PWM
//
// pwm_update( int PWM, int16 NEW_DUTY_CYCLE)
// change the duty cycle from a created PWM
//
// pwm_init()
// initialize the PWM's
//
// pwm_stop()
// stop the PWM's
//
/////////////////////////////////////////////////
|
The aev_servo.c library is below:
Code: |
//****************************************************************
//
// Criado por:
//
// Vinicius Nunes Lage
// UFOP - Universidade Federal de Ouro Preto
// Engenharia de Controle e Automaçao
// Turma 09.1
// Ouro Preto, BRASIL
// Última modificação: 24/04/2013
//
//
// Created by:
//
// Vinicius Nunes Lage
// UFOP - Federal University of Ouro Preto
// Automation Engineer
// Class 09.1
// Ouro Preto, Brazil
// Last modification: 24/04/2013
//
//
//****************************************************************
#ifndef MAX_PWM
#define MAX_PWM 10
#endif
int atual_pwm=0, i=0;
struct _PWM{
int16 duty_cycle;
int16 pin;
int16 duty_escada;
} PWM[MAX_PWM];
int vet_aux_pos_struct[MAX_PWM], vet_pos_struct[MAX_PWM];
// ordena os valores de angulos recebidos
void Ordenar_Seleccao(struct _PWM *V, int N){
int k, kk, pos_menor;
struct _PWM aux;
int aux2;
for (k=0; k < N-1; k++){
pos_menor = k;
for (kk = k+1; kk < N; kk++)
if (V[kk].duty_cycle < V[pos_menor].duty_cycle) pos_menor = kk;
// troca os valores das posicoes k com pos_menor
if (pos_menor != k) {
aux = V[pos_menor];
V[pos_menor] = V[k];
V[k] = aux;
aux2 = vet_aux_pos_struct[pos_menor];
vet_aux_pos_struct[pos_menor] = vet_aux_pos_struct[k];
vet_aux_pos_struct[k] = aux2;
}
}
}
void set_duty_escada(){
int i;
PWM[0].duty_escada = PWM[0].duty_cycle;
for(i=1; i<atual_pwm; i++)
PWM[i].duty_escada = PWM[i].duty_cycle - PWM[i-1].duty_cycle;
}
int pwm_setup(int16 duty_cycle, int16 pin){
PWM[atual_pwm].duty_cycle = duty_cycle;
PWM[atual_pwm].pin = pin;
vet_aux_pos_struct[atual_pwm] = atual_pwm;
return(atual_pwm++);
}
void set_vet_pos(){
int i;
for(i=0; i<atual_pwm; i++){
vet_pos_struct[ vet_aux_pos_struct[i] ] = i;
}
}
void pwm_init(){
if(atual_pwm > 1) Ordenar_Seleccao( PWM, atual_pwm );
if(atual_pwm > 0){
// calcula os duty_escada's
set_duty_escada();
set_vet_pos();
// queremos uma frequencia de 50Hz, ou seja, 20ms!
// (20/4) 5MHz / 16 -> 312500Hz / 50 = 6250 LOGO
// 65536 - 6250 = 59286 (valor inicial)
setup_timer_0( RTCC_INTERNAL | RTCC_DIV_16 );
set_timer0(64286);
enable_interrupts( INT_TIMER0 );
enable_interrupts( GLOBAL );
}
}
void pwm_stop(){
disable_interrupts( INT_TIMER0 );
}
void pwm_update(int id_pwm, int16 duty_cycle){
pwm_stop();
set_vet_pos();
PWM[ vet_pos_struct[id_pwm] ].duty_cycle = duty_cycle;
pwm_init();
}
//***********************************************************************
// define qual timer irá usar (interrupção)
// por padrão usa o timer0
#int_timer0
void pwm_intTimer(){
int i;
set_timer0(64286);
// todos para nivel alto
for(i=0; i<atual_pwm; i++)
output_high( PWM[i].pin );
delay_us( PWM[0].duty_cycle );
output_low( PWM[0].pin );
// vai baixando o nivel em escada
for(i=1; i<atual_pwm; i++){
delay_us( PWM[i].duty_escada );
output_low( PWM[i].pin );
}
}
|
This program uses:
RAM: 7%
ROM: 5%
Please test and if you found any bug, please tell me!
Thanks a lot ;)[/b]
Last edited by opvini on Thu Apr 25, 2013 12:00 pm; edited 1 time in total |
|
|
opvini
Joined: 27 Apr 2012 Posts: 50 Location: Brazil
|
NOTE |
Posted: Thu Apr 25, 2013 11:58 am |
|
|
NOTE: you can calibrate the 0 degrees and 180 degrees from the servo whenever you insert or remove one servo. For example, if you work with 3 servos, it has one zero and one 180. If you work now with 4 servos, it has another zero and another 180 becouse onde servo motor more or less interfere directly in the processing by timer 0, so, always works with the maximum amount of the servo motors in the program. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|