fbpx

Expresate

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

Interrupcione en CC...
 
Avisos
Vaciar todo

Interrupcione en CCS

19 Respuestas
5 Usuarios
0 Reactions
8,906 Visitas
vcs
Respuestas: 114
 vcs
Topic starter
(@vcs)
Estimable Member
Registrado: hace 18 años

Buenas a todos

Voy a tratar de usar las interrupciones en un 16f877 y necesito un poco de ayuda, alguien conoce de algun link o manual en el que pueda informarme de en primer lugar en que consisten las interrupciones en un PIC y en segundo lugar como aplicarlas con CCS.

Es decir segun el manual de CCs he visto algunas intrucciones relativas a esto, pero no están nada claras, lo que yo conozco a nivel mas interno respecto a otros sistemas (que me imagino que serán portables) es que cuando realizas una interrupcion internamente en el micro el programa salta a una direccion fisica y real determinada y apartir de ahí empiezas a picar el codigo, si te lo haces todo en lenguaje maquina tienes que guardar el estado de los flag anterior al salto, bla bla bla... ahora leo que existen varios tipos de instrucciones sobre interrupciones en el ccs, entiendo que al igual que en otros sistemas las interrupciones podrian ser por flanco ascendente, descendente, temporizadas (y en determinados sistemas por cambio de flanco), en fin esto me imagino es igual pero es a muy groso modo, me ha parecido entender que en CCS existen ¿instrucciones para programar interrupciones de contador?, bueno hasta ahora lo que habia usado siempre para realizar un conteo es programar una interrupcion por flanco, y una vez hecho el salto a partir de esa direccion de memoria picar un incremento a una variable (la de conteo o contador) y volver a la direccion anterior al salto (asegunrandome de dejar todos los flag como estaban antes del salto) ahora con los PIC no se muy claro como iria ¿existe una instruccion especifica que realiza todo esto en el CCS? o existe alguna entrada hardware que se le pueda asignar esta funcion mientras el programa sigue corriendo, imagino que nó, que sea cual sea el metodo, el programa se parará hará el conteo y continua... en fin lo que estoy probando es hacer un conteo dentro de un recorrido determinado y ademas quiero implementar una señal NOT (Negative OverTravel) y POT (Positive OverTravel) es decir finales de carrera mediante interrupcion, es decir simplificando más necesito un contador por flanco y dos interrupciones de libre programacion por Flanco. o en su defecto tres de estas.

Como es evidente que no estoy muy puesto en el tema, no quiero aburrir a nadie y por eso solicito algun link o manual donde esto se explique con mas o menos detalle y a ser posible acompañado de ejemplos.

SALUDOS Y GRACIAS

Responder
18 respuestas
heli
Respuestas: 748
 Heli
(@heli)
Ardero
Registrado: hace 19 años

Hola vcs, en el programa que estás usando para las pruebas hay varios errores típicos de cuando se trabaja con interrupciones.
Esto es lo que NO se debe hacer:
En primer lugar en main() desconectas todas las interrupciones, conectas las que vas a usar, y pones los set_tris(). ESO ESTÁ MAL. Como usas un PORTA=xxx en la interrupción es necesario que el tris de ese puerto esté ya puesto antes de habilitar la interrupción. En realidad no tiene mucha inportancia, pero si salta la interrupción entre que la has habilitado y antes de que se haya puesto el tris (en main) no hará nada. Más tarde, cuando ya esté puesto el tris, funcionará correctamente. Es importante asegurarse de que en main() se ponen a los valores adecuados todas las variables y configuraciones necesarias para el funcionamiento de la interrupción antes de habilitarla.
El otro error, este si que es importante, es que las interrupciones no deben entretenerse. Es decir, que no debes poner un delay() o un bucle largo, o llamadas a funciones que tarden mucho en procesase. Mientras está procesandose la interrupción no se procesa main() ni se atienden otras interrupciones de menos nivel.

Si lo que quieres es que mientras está temporizando los 5 segundos siga procesandose el programa tienes que usar una técnica distinta, un poco más complicada. Se trata de poner una interrupción por tiempo que decremente unas variables mientras no sean 0. En main() las inicializas a un valores dependiendo tiempo que quieras esperar y cuando llegan a cero haces algo.
Mira este ejemplo:

#include <16F877A> // incluimos el archivo de definicion del PIC
#fuses XT,NOWDT // definimos que es un Crital y el NO Wdog activo (para el ICPROG)
#use delay (clock=1000000) // definimos la frecuencia del cristal

#use fast_io(a) // Elegimos el modo de los puertos
#use fast_io(b) // son de entrada o salida
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)
#byte PORTA=0x05 // 6 patas// Definimos la Variable PORTA y PORTB como los puertos ya que por defecto no viene definido
#byte PORTB=0x06 // 8 patas
#byte PORTC=0x07 // 8 patas
#byte PORTD=0x08 // 8 patas
#byte PORTE=0x09 // 3

int EsperaSeg; // Contador de segundos

/*========================================================================*/
#int_TIMER0 // interrupción cada 4ms 250 Hz
TIMER0_isr()
{
static int Tmr1; // Contador para 1000 milisegundos 1/10 seg 10 Hz

// Procesos cada 4ms: contar hasta 1 segundo

if (++Tmr1<250) return; // no ha llegado a 4*250 = 1000ms 1 Hz

// Procesos cada 1000 ms, 1 seg
Tmr1=0; // inicio el contador de nuevo

if (ContSegundos) ContSegundos--; // Decrementa el contador de segundos
}

/* LA INTERRUPCION */
#int_rb
VOID interrupcion()
{
if (!EsperaSeg) // Si es 0 ya han pasado los 5 segundos
{
PORTA=0X01; // si no estamos esperando pone el puerto al valor adecuado
EsperaSeg=5; // Inicia la cuenta a 5 segundos
}
}
/* Fin del codigo de la interrupcion */

void main(void) // Comienzo de programa, void quiere decir que No se obtendrá ningun valor de esta funcion
{
disable_interrupts(GLOBAL);// deshabilitamos las interrupciones por seguridad puesto que no las usaremos

set_tris_a(0x00); // Puerto a definido como salida
set_tris_b(0xff); // el Puerto e lo definimos como entrada
// Permitiendo aquí las interrupciones aseguramos que tris esté ya puesto cuando entre la interrupción
enable_interrupts(int_rb);
// CUIDADO!! ESTA LINEA ES PARA UN CLOCK DE 4 MHZ !!!!
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16); // interrupción cada 4ms 250 Hz
enable_interrupts(INT_TIMER0); // permito la interrupción del timer
enable_interrupts(GLOBAL);
PORTB=0;

do
{
if (!EsperaSeg) // Si NO está contando los 5 segundos
{
PORTA=0xff; // Enciendo el puerto
Delay_ms(1000); // Espero un Segundo
PORTA=0; // Apago el puerto
Delay_ms(1000); // Espero un Segundo
}
else
{
// Aquí hace otras cosas mientras cuenta los 5 segundos

}
}WHILE(TRUE);
} // Fin

Este programa hace que PORTA sea 0 y FF alternativamente cada segundo. Si se activa una pata del PORTBB salta la interrupción que pone PORTA a 0x01 y carga un retardo de 5 segundos. Mientras se cuentan los 5 segundos la interrupción no hace nada y deja de procesarse el cambio de PORTA de 0x00 a 0xff. Pueden hacerse otras cosas en esos 5 segundos, poniendo el código adecuado en el "else" en main.
Creo que funcionará bién, salvo que el timer está calculado para un clock de 4Mhz (lo he extraido del LaserGame: http://heli.xbot.es/Laser_game/lasergame2.htm
Puedes ver como mi programa hace muchas temporizaciones sin dejar de procesar main(), una especie de pseudo-multitarea.
Creo que es claro como ejemplo, si tienes más dudas aquí estamos...

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

Gracias Heli,

Mas o menos esto ya lo habia entendido (bueno salvo lo del orden del tris que ni se me habia ocurrido), de todas formas ese no era el problema, el programa esta hecho unicamente para aprender a usar una interrupcion, hize un programa que parase los led dentro de la interrupcion solo para asegurarme de que entraba en la interrupcion, en realidad esto no lo usaré, lo que yo preguntaba era que al hacer este programa si la interrupcion la lanzo por cambio de estado de la pata cero del puerto B int_EXT el pic hace lo que tiene que hacer, ahora bien si en lugar de esto lo hago por cambio de estado del puerto B int_RB entra en la interrupcion pero no vuelve luego al programa principal, se queda parado en la interrupcion. ¿Porque es esto?

Responder
heli
Respuestas: 748
 Heli
(@heli)
Ardero
Registrado: hace 19 años

Creo que es un problema de stack. El PIC tiene muy poco stack, si llamas a determinadas funciones desde dentro de una interrupción el stack rebosa y el programa se cuelga. Prueba a usar un bucle de espera, por ejemplo de 40000 vuentas, en vez de la llamada a delay_ms().

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

Buenas a todos, pues despues de bastante tiempo vuelvo por a las andadas, en esta ocasion no para preguntar sino para dar solucion a esta pregunta que quedo en el aire,

Pues resulta que estoy metido en una lista de robotica y hace algun tiempo lei que cuando programabas en ASM y usabas las interrupciones de teclado no era posible quitar el bit de interrupcion a no ser que se hiciera una lectura del puerto en cuestion (B) yo esto lo habia obiado puesto que con CCS es el compilador quien gestiona la el salto, el puntero y los flag, pero mira por donde esto no lo gestiona bien, asi que la solucion para mi problema con las INT_RB se a solucionado haciendo una lectura del puerto, tan solo he añadido una linea a mi programa de interrupcion que dice a=PORTB es decir que leo el puerto y lo almaceno en una variable que uso para pasos intermedios, en principio con cualquier intruccion que haga una lectura del puerto B vale, pero use esta por simplicidad para mi, pues tengo esta variable A que solo uso para cosas muy puntuales, ahora por ejemplo para saber que he pasado almenos una vez por la Interrupcion.

Espero que haya quedada clara mi respuesta.

UN SALUDO A TODOS

Responder
Página 4 / 4
Compartir: