TODOPIC
Microcontroladores PIC => * PROYECTOS * => Mensaje iniciado por: coolkain en 19 de Octubre de 2009, 14:55:47
-
Hola amigos estoy haciendo un proyecto y consiste en controlar un motor de corriente continua implementando un PID en un 16f877,donde también genero una PWM que sale por uno de los pines y va a un puente en H, el problema que tengo es para averiguar la posición en cada momento ya que uso un encoder de dos canales, pero me parece que estoy implementando mal el código y no me toma bien los datos, el puerto que uso es el puerto D (RD0 y RD1), o si alguien ya lo ha hecho y me deja el código se lo agradecedía porque no se donde está el fallo.
-
Hola.
Postea tu código para ver donde puede estar el error.
El control es de posición o de velocidad?
Saludos
-
Podrias utilizar un potenciometro de precision y de giro libre para detectar la posicion.
-
postea tu código y te podremos ayudar, si estas usando el puerto D para el encoder, seguramente ya estas cometiendo un error y grande mejor dicho GRANDE, ya que creo recordar que la entrada con interrupcion de ese pic es el PIN_B0, y deberías gestionar el encoder con la interrupcion para tener muchisisisima mas precisión, supongo que estas usando el generador interno de PWM.
Cual es tu proyecto?? ya que parece que lo que quieres hacer es controlar una posición determinada? o quieres controlar velocidad?? que encoder usas?? el típico sensor optico de ratón???
-
aquí pongo el código, en un principio sólo está funcionando con un controlador proporcional, si el error=0 o muy próximo a 0 funciona bien, pero si ya desplazo el motor un poco pues se vuelve loco se va para el lado opuesto al que lo muevo para corregir el error producido pero o no se para o se para en la posición que le da la gana.Si alguien tiene algún código para un 16f877 y me lo enseña se lo agradecería.
El programa y compilador que estoy usando actualmente es el CCS C, para las pruebas estoy usando una impresora antigua, he aprovechado el motor y el encoder, lo que necesito controlar es la velocidad mediante un PID y una PWM y la posición mediante el encoder
#include <16f877.h>
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP,PROTECT //Tipo de oscilador y frecuencia
#use delay (clock = 4000000, RESTART_WDT)
#USE DELAY
#use fast_io (A)
#use fast_io (B)
#use fast_io (C)
#use fast_io (D)
#use fast_io (E)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#byte porta=5
#byte portb=6
#byte portc=7
#byte portd=8
#byte porte=9
//Librerias
#include <math.h>
#include <float.h>
#define canald PORTD
//Se definen las constantes del controlador PID
signed long long kp=15;
float kd=2;
float ki=8;
signed long long max=100, min=-100;
float I= 0.5;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//float err_ant,err_ant1,err_ant2,err_ant3,sum_err;//A
//Definición de variables
//float sum_int=0;
//Condicion inicial
signed long long integral,proporcional,derivativo, out_PID;
signed long long err_act;//error actual =set_point - posicion
signed long long Duty ; //ciclo de la pwm
signed long long util;
unsigned char bit_ini,j;
signed long long leido = 0,estado = 0;
signed long long posicion= 32000;
unsigned char alarma ;
signed long long set_point= 32000;
//====================================================================
//int lee_alarma(){
//return canal&1;
//}
int lee_encoder() {
return canald&3;
}
void encoder () {
leido = lee_encoder();
if (estado == leido)
return ;
if (estado == 0){//00
if (leido==1){
posicion = posicion-1;
estado = leido;
return;
}
else
if (leido== 2){
posicion=posicion+1;
estado = leido;
return ;
}
else {
estado = leido;
return;
}
}
if (estado==1){
if (leido==3){
posicion=posicion-1;
estado=leido;
return ;
}
else
if (leido==0){
posicion=posicion+1;
estado=leido;
return ;
}
else{
estado=leido;
return;
}
}
if (estado==2){
if (leido==0){
posicion=posicion-1;
estado=leido;
return ;
}
else
if (leido==3){
posicion=posicion+1;
estado=leido;
return;
}
else {
estado=leido;
return;
}
}
if (estado==3){
if (leido==2){
posicion=posicion-1;
estado=leido;
return ;
}
else
if (leido==1){
posicion=posicion+1;
estado=leido;
return;
}
else {
estado=leido;
return;
}
}
}
//====================================================================
//Esta función aproxima el valor de la salida del controlador al entero más proximo
int32 aprox(float rta_controlador) //Funcion aprox
{
float parte_entera,parte_decimal;
int32 ciclo_pwm;
parte_decimal=modf(rta_controlador,&parte_entera);
if(parte_decimal>=0.5)
{
ciclo_pwm=ceil(rta_controlador); //aprox al entero mayor más cercano
}
else
{
ciclo_pwm=floor(rta_controlador); //aprox al entero menor más cercano
}
return (ciclo_pwm);//Regresa el valor de ciclo_pwm,que es un entero de 32 caracteres.
}
//====================================================================
//====================================================================
//------------------------Función principal------------------------------
void main(void){
alarma=0;
//portb=portc=0; //Reset para los puertos
//Configuracion de puertos (E/S)
set_tris_a(0xFF); //entrada
set_tris_b(0x00); //salida
set_tris_c(0x08);
set_tris_d(0xC0); //salida
set_tris_e(0x00); //salida
setup_timer_2(T2_DIV_BY_16, 255, 1); //Pre=1 Periodo=255 Pos=1
setup_ccp1(CCP_PWM);
//Configuracion contador PWM
enable_interrupts(INT_EXT);
//Int. sensor encoder
ext_int_edge( L_TO_H );
//Interrupcion flanco Bajo a alto
enable_interrupts(GLOBAL);
//Activar interrupciones globales
output_high(PIN_D2);//enciendo un led durante 10 milisegundos para
delay_ms(10); // en caso de que se produzca un reseteo del pic detectarlo
output_low(PIN_D2);
/* err_ant=err_act=err_ant1=err_ant2=err_ant3=
out_PID= integral= proporcional= derivativo= 0x00; //Condicion inicial
posicion= bit_ini=16000; //Bandera de inicio
*/
/* if(alarma==1)
{putc(01000001);
putc(1);} //si la alarma se activa envia por el
//puerto serie el texto A1
else
if(alarma==0)
{putc(01000001);
putc(0);} //sino se activa envia por el puerto serie el texto A0
*/
for(;;)
{
// set_point=getc();
encoder();
//set_point=getc();
//delay_ms(100);
//encoder();
//set_point=getc();
// delay_ms(1);
putc(80);//Valor Leido dec=50
encoder(); //leo el encoder y por puerto serie envio la posicion
putc(posicion);
encoder();
putc(posicion >> 8);
encoder();
putc(posicion >> 16);
encoder();
putc(posicion >> 24);
encoder();
/*set_point=getc();
delay_ms(1);
putc(leido);
encoder();
//set_point=getc();
delay_ms(1);
encoder();
delay_ms(10);
putc(01010000);//Valor PWM dec=80
encoder();
delay_ms(1);
putc(out_PID);
delay_ms(1);
encoder(); */
//set_point=getc();
}
//-----Implementación del PID-----------------------------------------//
for (;;) {
err_act = set_point - posicion; //Ecuacion para el error actual
if((10<err_act)&&(10>err_act)){
set_pwm1_duty(0);
output_high(PIN_B2);
continue;}
/* if(err_act>max){err_act=max;}
else{
if (err_act<min){err_act=min;}
}*/
/*---------------Sentido de giro del motor----------------------------------*/
/*--------------------------------------------------------------------------*/
//Si la posición es menor que nuestra consigna avanza hacia la derecha
if(posicion < set_point)
{output_low(PIN_B2);
output_low(PIN_B7);
}
else {
//En caso de que nuestra posición sea mayor que nuestra consigna avanza
//hacia la izquierda
if(posicion > set_point){
output_low(PIN_B2);
output_high(PIN_B7);
} }
//------------------PROPORCIONAL--------------------------------------
proporcional = kp*err_act; //Ecuacion de parte Proporcional
//------------------INTEGRAL------------------------------------------
/*
if(bit_ini==16000) //Si está en condicion inicial 0
{
integral = ki*err_act; //Ecuacion integral
sum_err=err_act;
sum_int=integral;
bit_ini=0xFF;
}
else
{
integral = I*(err_ant+err_act);
integral += sum_err;
integral *= ki;
sum_int+=integral;
sum_err += err_act;
err_ant =err_act;
}
//----------------DERIVATIVO------------------------------------------
derivativo = 3*(err_ant1-err_ant2);
derivativo += err_act;
derivativo -= err_ant3;
derivativo *= kd;
err_ant3=err_ant2; //Memorización para la parte derivativa
err_ant2=err_ant1;
err_ant1=err_act;
//--------------------------------------------------------------------
*/
out_PID = proporcional; //+ sum_int + derivativo;
if (out_PID <0)
out_PID = -1*out_PID;
//out_PID*=60;
Duty = aprox(out_PID);
if(Duty>1023) {
Duty=1022;
util=Duty;
set_pwm1_duty(util);}
else{
util=Duty;
set_pwm1_duty(util);}
}
}
-
TE subo lo que tengo hecho, me queda probarlo en real y no se si iria bien