fbpx

Expresate

Si además quieres enviarnos un Artículo para el Blog y redes sociales, pulsa el siguiente botón:

Programación veloci...
 
Avisos
Vaciar todo

Programación velocista, regulador P, dudas tipos de variable

15 Respuestas
3 Usuarios
0 Reactions
14.2 K Visitas
_jm_
Respuestas: 961
 JM
Topic starter
(@_jm_)
Prominent Member
Registrado: hace 20 años

Hola, ando programando el velocista para probar la placa de sensores con un 18f452 en C y el compilador de microchip, y como mi C está un poco olvidado me salen unas cuantas dudas sobre el tipo de variables que puedo usar.

Lo primero es que estoy usando variables de tipo float, da algún problema usar este tipo de variable en un 18f?

Luego estoy haciendo lo siguiente servo= 44 - errort*3;

Donde servo es un char, errort es un float, y en Delay100TCYx(servo); el argumento que va ahí es un unsigned char me parece, servo en la asignación va a salir siempre positivo.

Lo he puesto así directamente y parece ser que funciona... debo hacer algún tipo de conversión por el medio?

Adjunto todo el código, el regulador P os parece correcto?

Luego otra duda, si declaro las variables errors, errort, y contador dentro del main me da un error, lo soluciono poniendolas fuera, pero no sé el motivo.

Gracias. Saludos.

Video del funcionamiento:

http://www.youtube.com/watch?v=2lDU1N9XuXU
/***************************************************************************************
****************************************************************************************
** Programa para probar la placa de sensores, regulador proporcional.
** Pic18f452
** Cristal 16 MHz
** 18/12/2008 www.jmnlab.com
****************************************************************************************
***************************************************************************************/

#include <p18f452>
#include <delays>
#include <timers>

#pragma config WDT=OFF, LVP=OFF, OSC=HS, OSCS=OFF, PWRT=ON, BOR=OFF, STVR=ON

void inicializar (void);
void reseteo (void);
void timer2_isr (void);

#pragma code high_vector=0x08 // high interrupt vector en 0008h
void interrupt (void)
{
_asm GOTO timer2_isr _endasm // Salta a la ISR
}
#pragma code // default code section

#define LED1 PORTEbits.RE0 // Ambar
#define LED2 PORTEbits.RE1 // Rojo
#define SENSORES PORTEbits.RE2 // Placa de sensores
#define MINIZ PORTBbits.RB4 // Control miniz

#define R7 PORTCbits.RC0 //Extremo derecho
#define R6 PORTCbits.RC1
#define R5 PORTCbits.RC2
#define R4 PORTCbits.RC3
#define R3 PORTDbits.RD0
#define R2 PORTDbits.RD1
#define R1 PORTDbits.RD2
#define R0 PORTDbits.RD3 // Centrales
#define L0 PORTCbits.RC4 //
#define L1 PORTCbits.RC5
#define L2 PORTCbits.RC6
#define L3 PORTCbits.RC7
#define L4 PORTDbits.RD4
#define L5 PORTDbits.RD5
#define L6 PORTDbits.RD6
#define L7 PORTDbits.RD7 // Extremo izquierdo

//Variables
unsigned char DelayCounter1;
char servo = 44, velocidad = 44;
int contador=0;
int errors=0;
float errort=0;

//Programa principal

void main (void)
{
inicializar();
reseteo();
LED1 = 1;
SENSORES=1;

while(1)
{
errors=0;
contador=0;
errort=0;

if(L7==1) // Asignación de error
{
errors+=7;
contador++;
}
if(L6==1)
{
errors+=6;
contador++;
}
if(L5==1)
{
errors+=5;
contador++;
}
if(L4==1)
{
errors+=4;
contador++;
}
if(L3==1)
{
errors+=3;
contador++;
}
if(L2==1)
{
errors+=2;
contador++;
}
if(L1==1)
{
errors+=1;
contador++;
}
if(L0==1)
{
errors+=0;
contador++;
}
if(R0==1)
{
errors+=0;
contador++;
}
if(R1==1)
{
errors+=(-1);
contador++;
}
if(R2==1)
{
errors+=(-2);
contador++;
}
if(R3==1)
{
errors+=(-3);
contador++;
}
if(R4==1)
{
errors+=(-4);
contador++;
}
if(R5==1)
{
errors+=(-5);
contador++;
}
if(R6==1)
{
errors+=(-6);
contador++;
}
if(R7==1)
{
errors+=(-7);
contador++;
}
if (contador!=0)
{
errort=errors/contador;
servo= 44 - errort*3; //servo=centro-error*constante proporcional
}
else
servo=44;
}
}

//***************************FUNCIONES****************************************
void inicializar (void)
{
TRISA = 0b11111111; // Configuración de los puertos
TRISB = 0b11101111; //
TRISC = 0b11111111; //
TRISD = 0b11111111; //
TRISE = 0b00000000; // Puerto E como salidas.
ADCON1 = 0b00001111; // Todo puerto A como digitales.
PORTB = 0;
PORTE = 0;
OpenTimer2 (TIMER_INT_ON & T2_PS_1_16 & T2_POST_1_16); //TMR2IF=0 TMR2IE=1 TMR2ON=1 TMR2=0
RCONbits.IPEN = 0;
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
PR2 = 250;
}

void reseteo (void)
{
INTCONbits.GIE = 0;
LED2 = 1; //3 parpadeos para detectar los posibles resets del pic
LED1 = 0;
Delay10KTCYx(200);
LED2 = 0;
Delay10KTCYx(200);
LED2 = 1;
Delay10KTCYx(200);
LED2 = 0;
Delay10KTCYx(200);
LED2 = 1;
Delay10KTCYx(200);
LED2 = 0;
INTCONbits.GIE = 1;
}

#pragma interrupt timer2_isr save=DelayCounter1 // interrupción, salvamos la variable de los delays

void timer2_isr ( void)
{
PIR1bits.TMR2IF = 0; //Limpia el flag de interrupción del timer2
MINIZ = 1;
Delay100TCYx(16); // 400 uS
MINIZ = 0;
Delay100TCYx(servo);
MINIZ = 1;
Delay100TCYx(16); //400 uS
MINIZ = 0;
Delay100TCYx(velocidad);
MINIZ = 1;
Delay100TCYx(16);
MINIZ = 0;
}

Responder
14 respuestas
dragonet80
Respuestas: 1328
(@dragonet80)
Ardero
Registrado: hace 17 años

Todo lo que sean "divisiones y multiplicaciones" suelen tardar bastante más que una suma. Si quieres prueba a medir cuanto tarda en hacer la lectura y el cálculo del error. Yo lo haría de manera indirecta, por ejemplo: encendiendo un led antes y apagandolo después, acontinuación haces un delay y vuelves a repetir todo, desactivando las interrupciones y todo lo demás. Así podrás medir el Tiempo en ON facilmente con el osciloscopio.

Respecto a esos errores "raros", no se, uso el ccs y es un poquito diferente en cuanto a definiciones de tipos, así que no puedo probarlo.

Responder
_jm_
Respuestas: 961
 JM
Topic starter
(@_jm_)
Prominent Member
Registrado: hace 20 años

Los tiempos los he medido encendiendo un led al principio del búcle y apagandolo a la mitad, la frecuencia del búcle es de 50 KHz y cuando entra aquí:

if (contador!=0)
{
errort=errors/contador;
servo= 44 - errort*3; //servo=centro-error*constante proporcional
}

Baja hasta 3 KHz, yo tengo que mandar la señal cada 62.5 Hz por lo que tengo mucho margén, pero según se vaya haciendo operaciones hay que mirarlo, que también tendré que hacer un regulador para la velocidad y además añadir la D a la posición y velocidad, por lo que se puede hace mucho más lento.

Responder
beamspot
Respuestas: 1132
(@beamspot)
Noble Member
Registrado: hace 17 años

JM, procura evitar al máximo posible la coma flotante. Con simple matemática en coma fija deberías tener suficiente, al fin y al cabo, el rango en que se mueve un control no es tan amplio que no puedas cubrirlo con 16 o 32 bits de entero. Sólo es cuestión de escalar, y estrujarse un poco los sesos.

Sin embargo, la recompensa puede ser generosa.

Por otro lado, los AVR a 16MHz dan alrededor de 60KFLOPS...

Un consejo simple para la coma fija suele ser el de primero multiplicar, sumar, restar, y dejar la división para lo último. Y a ser posible, dividir por potencias de 2. O sea: servo=44+(errors*3)/contador.

Responder
_jm_
Respuestas: 961
 JM
Topic starter
(@_jm_)
Prominent Member
Registrado: hace 20 años

No sé cuantos flops tendrán estos, lo de evitar la coma flotante creo que una vez en este caso pense como hacerlo, pero como hago las cosas de tanto tiempo en tanto ya ni me acuerdo.

Lo único que se me ocurre ahora es lo siguiente, si tengo 16 sensores, todos separados por la misma distancia, buscando como el punto a seguir el del medio, entre los sensores 8 y 9 (L0 y R0), a esta posición le asigno el valor cero, hacía un lado de esa posición doy valores positivos y hacía el otro negativo.

L7 L6 L5 L4 L3 L2 L1 L0 R0 R1 R2 R3 R4 R5 R6 R7

Luego el error total será la suma de todos los sensores activados entre el número de sensores activados. El número de sensores activados es el que me determina si la operación va a acabar en decimales, es decir por lo que los incrementos que asigne a cada sensor debe de ser divisible entre los primos comprendidos entre el rango de sensores activados.

Por ejemplo si puedo tener hasta 4 sensores activados, los incrementos deberían ser de seis, si puedo tener de 5 a 6, de 30, de 7 a 10 incrementos de 210. Pongo el caso de 5 que ya es un valor bastante por encima del grosor de la línea, tendría que dar incrementos de 30.

L7 L6 L5 L4 L3 L2 L1 L0 R0 R1 R2 R3 R4 R5 R6 R7
-240 -210 -180 -150 -120 -90 -60 -30 30 60 90 120 150 180 210 240

De esta forma al sumar y dividir por el número de sensores activados (restricción de máximo 5) siempre obtengo como resultado un número entero.

Lo que si tendría que hacerme yo una función de delay para poder trabajar con esos valores de error, porque la que trae ese compilador sólo aceptan unsigned char como argumentos, o tengo que multiplicar al valor máximo de error posible 240* x para hacer lo coincidir con el valor máximo del unsigned char y mis tiempos necesarioa máximo para el servo, y creo que me valdría.

No sé si te refieres a hacer algo así con lo que me dices de escalar, creo que una vez pense una forma sencillita de hacerlo, pero ahora no recuerdo. Se os ocurre algo más sencillo?

La verdad es que si puedo usar float simplifica bastante el código, aunque lo haga así y me den los tiempos debo evitarla? por qué siempre aconsejan no usarla?

Gracias.

Responder
Página 1 / 3
Compartir: