fbpx

Expresate

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

Gestion interrupcio...
 
Avisos
Vaciar todo

Gestion interrupciones en C

7 Respuestas
4 Usuarios
0 Reactions
9,450 Visitas
vcs
Respuestas: 114
 vcs
Topic starter
(@vcs)
Estimable Member
Registrado: hace 18 años

Buenas a todos.

Tengo una duda, por llamarlo de alguna forma, o necesito mas bien consejo sobre como he de programar :p , el tema es que tengo una plaquita que mueve un motor que arrastra una carga, encima de esa carga va montado un detector de inducción de estos que ven chapas metálicas, el caso es que el trasto se mueve a 1 m/s, el tamaño de las chapas es de aproximadamente 5 cm.

El detector está conectada a una entrada de interrupción, cuando veo las chapas según las condiciones del programa hago unas operaciones, o bien sumo un contador, o resto, o decelero el motor, o acelero, paro...
El tema es que por un lado para saber que tengo que hacer tengo bastantes bucles IF metidos al hacer la interrupción, lo programo con CCS (Lenguaje C) y el tema es que cuando salta la interrupción leo el Puerto B, compruebo que entrada a provocado la interrupción, deshabilito las interrupción globales, hago todas las comprobaciones mediante if, si voy en un sentido y una variable toma tal valor acelero o si toma este otro decelero... y así bastantes condiciones, actúo según estas y por ultimo habilito interrupciones y salgo de la interrupción.

Claro el tema es que si pillo una chapa bastante alejada de las otras parece que trabaja bien (cada chapa esta a una distancia distinta a las otras, no guardan simetría ni nada por el estilo), ahora si hay dos chapas bastante cercanas la cosa cambia porque se salta detecciones.
He comprobado que el detector lee porque he metido un led a la entrada de la interrupción y se le ve lucir, por descarte imagino que el problema esta en la velocidad, he metido un micro 16f877 al que le he subido a un cristal de 20MHZ, pero aun así falla, yo pensé que con estas velocidades el tamaño del código de dentro de la interrupción no influiría demasiado, pero al parecer debe de ver una chapa, entra en la interrupción y antes de acabar el código y volver a habilitar las interrupciones globales ve la siguiente, con lo cual se la salta.

La distancia entre chapas es de aproximadamente 1 m en el peor de los casos es decir que hay como 1 seg. entre una y otra detección, pensé que a 20MHz era tiempo mas que suficiente, puesto que he trabajado con controladores de Motion y servos industriales y a 1500 Rpm eran capaces de detectar la fase Z del encoder y resetear el contador en cada vuelta, usando interrupciones, es decir capaz de detectar y gestionar 25 interrupciones (y reseteo de contadores) en cada segundo.

Bueno, al tajo, el tema es que he estado pensando la forma de reducir el tiempo de ejecución del código y no termina de mejorar, por un lado se me plantea la duda si quizá el tema de habilitar y deshabilitar las interrupciones provoca un retraso grande, no debería porque no se que hará el compilador pero en principio en lenguaje del PIC solo es cambiar un bit, por otro lado no termino de ver la forma de hacer saltos desde la interrupción, es decir si fuera en lenguaje del PIC, bastaría con ver cual es el bit que hace saltar la interrupción y mandar el puntero a una línea de programa y listo, ahora bien, en C eso se supone que no se debe de hacer, que no es bueno lanzar GOTO a tal linea, además no veo la forma de saltar a una línea de programa con C y luego devuolver el return de la interrupción, total que estoy liado, ¿se os ocurre alguna forma de sacar las comparaciones de la interrupción para hacer el código más rapido? es fundamental que nada más ver la interrupción ejecute las comparaciones porque en ocasiones esto manda que pare el motor, y claro, lo suyo es tener repetitibilida, es decir veo chapa e inmediatamente paro el motor, lo de veo chapa, lo registro, hago lo que estaba haciendo y cuando toque paro el motor no es valido, porque la diferencia en las paradas va a ser muy grande

¿suponer que el problema es por la longitud del código de la interrupción no es erróneo verdad?

Gracias a todos

Responder
6 respuestas
vcs
Respuestas: 114
 vcs
Topic starter
(@vcs)
Estimable Member
Registrado: hace 18 años

Probablemente el problema sea debido al tiempo de respuesta del detector, su histeresis etc.
Si es un detector inductivo comenrcial convencional no está preparado para enviar pulsos a mucha frecuencia...
En vez de probar si funciona bien con un LED conectalo a un osciloscopio, para ver si las señales suben y bajan bien.

Este fragmento de código lo uso para leer un encoder y calcular la posición y la velocidad, es lo más óptimo que he podido conseguir:
//=============================================================================
// interrupcion de cambio de estado del puerto B, cuenta pulsos de encoder * 4
#int_RB
RB_isr()
{
static int8 EncoderAnt;
int8 Encoder,tmp, tmp2;

// Esto es para direccionar los bits individuales
#bit tmp_6 = tmp.6
#bit tmp_4 = tmp.4

Encoder=input_b (); // Lee todas las entradas de encoder a la vez

// Procesa el encoder Derecho, de esta forma rara usa 4 instrucciones menos
tmp=(EncoderAnt>>1)^Encoder;
tmp2=(Encoder^EncoderAnt)&0xC0;
if (tmp2==0xC0) goto NOEncoderD; // imposible, son dos pulsos
if (tmp2==0x00) goto NOEncoderD; // no se ha movido
if (tmp_6) PulsosD--;
else PulsosD++;

NoEncoderD:

// Procesa el encoder izquierdo de la misma forma
tmp2=(Encoder^EncoderAnt)&0x30;
if (tmp2==0x30) goto NOEncoderI; // imposible, son dos pulsos
if (tmp2==0x00) goto NOEncoderI; // no se ha movido
if (tmp_4) PulsosI--; // he correjido el cableado
else PulsosI++;

NoEncoderI:
EncoderAnt=Encoder;
}

//=============================================================================
// interrupcion cada 6.55 ms
#int_TIMER0
TIMER0_isr()
{
PosicionI+=PulsosI; // Calcula la posición absoluta
VelocidadI=PulsosI*2; // Escalado: Para encoder hasta 5khz * 4 cuenta 131 pulsos en 6.55 ms
PulsosI=0;
PosicionD+=PulsosD; // Calcula la posición absoluta
VelocidadD=PulsosD*2; //Escalado
PulsosD=0;
ProcesaPID=1; // Ya hay datos recientes para procesar en el bucle main()
} // Esto tardaba 12 us en completarse

main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128); // genera una interrupcion cada 6,55 ms
// Time = ((256 * 4) / 20.000.000) * 128 = 6.55 ms
enable_interrupts(INT_RB);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
set_tris_b(TRISB); //trisB para leer el encoder, 4 entradas

while (TRUE) // Bucle principal
{
if ( ProcesaPID) // Hay datos frescos, procesarlos
{
ProcesaPID=0;
// procesar aqui
}
// resto del programa
}
}

Gracias por la sugerencia, probaré a ver si fuese esto pero me temo que no van por aqui los tiros, ya que como comenté si paso por cuatro chapas veo cuatro destelleos del led, con lo cual el detector está conmutando (se enciende y se apaga), ademas este led está a la entrada de la interrupción con lo que es linea directa con la interrupcion, es decir si se enciende el led se activa la interrupcion, asi que este no deberia de ser el problema, ademas para desartar esto lo que hice fué poner a modo de prueba una chapa de 12 cm es decir mas del doble de tamaño, con lo que la permanencia del led encedido era mayor y no mejoró, ademas otra cosa que hice fue bajar la velocidad a 0.75 m/s (cambié la polea de arrastre) y algo mejoró pero no se solucionó, luego cambié de nuevo las chapas originales de 5 cm y trabajaba igual, de ahí descarte el funcionamiento del detector, y fue lo que me hizo pensar en problemas de tiempo.

Aun así meteré un osciloscopio, y probaré a darle chicha al motor directamente a 1 m/s y ver que me encuentro, si tengo la mas minima duda (incluso por descartar) meteré un codigo limpio que solo cuente pasos por la interrupcion (como el que escribes) para comprobar el problema no es el detector.

Salu2

Responder
vcs
Respuestas: 114
 vcs
Topic starter
(@vcs)
Estimable Member
Registrado: hace 18 años

Nas a todos, lo de la velocidad descarta, le metí un led a una patica, al entrar en la interrupcion el led se encendia justo antes de salir lo apagaba, lucia tan rapido que casi ni se encendia, asi que le meti un delay de 5 ms en la interrupcion y vi que este entraba y salia de la interrupcion a mucha velocidad, de pasaba por la interrupcion al ver la chapa y al dejar de verla puesto que la interrupcion es de estas de cambio de estado del puerto B.

Lo cual visto esto, pues no me alegra, ya que entonces si que no tengo ni idea de que puede estar pasando, estoy pensando en pillar un analizado digital de esos por USB, al estilo del de Saleae ese de 120 euros que va por usb al Pc, a ver si con esto puedo ver cual es la secuencia que sigue el micro, si tras entrar por la interrupcion se sale y vuelve a entrar o yo que sé, comprobando el estado de la entrada de interrupcion y de la salida del led...

Cosas que se me ocurren , el detector es mecanico, con lo que puede que active la interrupcion, lea el puerto y cuando lo leea este rebotando y a veces capture valor bajo de entrada por lo que no interpreta que ha pasado por la chapa, si le pongo un delay el problema es que me paso la chapa, he pensado en meter un lach, un Flip Flop RS o algo asi para enclavar la entrada pero entonces tengo problemas, porque cuando activo unos contactores que gestiono con el PIC, entra un pico de ruido y capturaria una señales donde no la hay (creo), esto lo corrijo por prog, pero claro si uso un cerrojo para enclavar la señal ya estaria jodio.

¿se os ocurre algo?

asias

Responder
Página 2 / 2
Compartir: