Haz una pregunta
  Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos
Foros Registrarse ¿Olvidaste tu contraseña?

Temas similares

26/11/2008 #1


Interrupciones (multiples) con C18
Hola necesito A Y U D A
Estoy utilizando PIC18f452 y el MPLAB con el C18.
Se supone que voy a usar varias interrupciones, tanto externas como de timer, el problema es que no se como incluirlas todas y como asociar una rutina a una interrupcion en particular.

El único ejemplo que he encontrado para el C18 es:

/////////////////////////////////////////////////////////////////////
void timer_isr( void );

#pragma code low_vector = 0x18
void low_vector( void )
{ _asm GOTO timer_isr _ensasm
}
#pragma code

#pragma interruptlow timer_isr
void timer_isr( void )
{ ........
}
/////////////////////////////////////////////////////////////

-Para crear varias interrupciones de baja prioridad debo crear varios low_vector?
Si es asi, la direccion 0x18 debo cambiarla para cada nueva interrupccion?
-No veo en donde esta asociada a un timer especifico, en el main del ejemplo utilizan el timer0, pero si tambien utilizo los demas timers tambien se me activaria esta rutina de interrupcion?

- En mi caso creo que tengo los 3 INTCON bien, pero aqui estan por si a caso
RCONbits.IPEN = 1; //no se si ponerlo en 0
INTCON = 0b11111000;
INTCON2 = 0b01110000;
INTCON3 = 0b11011000;

Gracias.
26/11/2008 #2

Avatar de Ardogan

El vector de interrupción es uno solo siempre, mejor dicho dos: uno de alta prioridad y otro de baja.
Digamos que sería:
" _asm GOTO Interrupcion_BajaPrioridad" en vez de " _asm GOTO timer_isr _ensasm "

Dentro de la rutina de interrupción tenés que chequear los flags/banderas de interrupción para saber de donde vino y ejecutar el código correspondiente.

Entonces, supongamos que definimos interrupciones de baja prioridad. A través de los registros INTCON seteamos la prioridad, luego habilitamos las interrupciones que vayamos a usar bits xxIE de registros INTCON. Limpiamos todos los flags de interrupciones (bits xxIF =0), y habilitamos las interrupciones de baja prioridad (GIEL=1).

A partir de este punto cualquier interrupción de baja prioridad que hayamos habilitado (a través de los bits xxIE) nos llevará a ejecutar la rutina Interrupcion_BajaPrioridad; que podría tener una estructura de este estilo:
Código:
void Interrupcion_BajaPrioridad(void){ //IMPORTANTE: nunca una rutina de interrupción toma parámetros 
    //ni devuelve nada, siempre es void Nombrefuncion(void). Para leer o
   //escribir valores se usan variables globales declaradas con la directiva volatile

  if (xxIF == 1){
    xxIF==0;//siempre limpiar el flag al principio, a veces lo hace el mismo hard
   //Codigo de atensión de interrupcion xx
  }
  else if (yyIF==1){//idem que en el if anterior
  }
  //-------  se hacen la cantidad de "else if(){} " que se precise
  else if (zzIF==1){
  }
  else{
  //descartadas todas las interrupciones menos una, 
  //solo queda la posibilidad de la interrupción
  //que provocó la llamada sea la que no se chequeo, 
  //por eso un "else{}" y no un "else if{}"
  }//fin cadena de if's

}//fin rutina interrupción
Lo que no recuerdo era si el bit GIEL lo cambiaba directamente el compilador, o si lo tenía que hacer uno a mano... no, se deshabilita GIEL automáticamente y se vuelve a habilitar cuando se termina de ejecutar la rutina de interrupción.
Si uno habilita el GIEL en la rutina de interrupción bien puede pasar que mientras se atiende una interrupción se de otro evento de interrupción y se ejecute nuevamente la rutina de interrupción, que se interrumpiría a sí misma .

RCONbits.IPEN habilita prioridad de interrupciones: solo dos prioridades alta y baja. Los bits xxIP configuran la prioridad de cada generador de interrupciones.

Bueno, contanos como te va...
27/11/2008 #3


Muchas gracias Ardogan

Estaba hace tiempo buscando como hacerlo.
Ha funcionado a la perfección.

27/11/2008 #4

Avatar de Ardogan

Qué bien! me alegro mucho. Estaría bueno que pongas el código fuente de las interrupciones así queda como ejemplo para otros que tengan la misma duda.

Saludos
12/12/2008 #5


Hola
Sorry por la demora pero estuve fuera un tiempo.
Aca va el codigo que utilice.
Utilizo las interrupciones externas, y ademas necesitaba que se ocurrieran tanto en los cantos de subida como los de bajada por lo que cambio los INTEDGX segun sea el caso.
Lo mismo hice para las de baja donde solo cambia el vector = 0x18 y el pragama interrupt por interruptlow.
Espero que le sea de ayuda a alguna persona.

Código:
////////////////////////////////////////////////////////////////////////////////////////
void Alta_isr( void );


#pragma code high_vector = 0x08
void H_interrupt( void )
{	_asm     GOTO Alta_isr    _endasm
}
#pragma code

#pragma interrupt Alta_isr
void Alta_isr( void )
{	if( INTCONbits.INT0IF )				
	{	INTCONbits.INT0IF = 0;
		if( INTCON2bits.INTEDG0 )
		{	INTCON2bits.INTEDG0 = 0;
			// Codigo					
		}
		else
		{	INTCON2bits.INTEDG0 = 1;
			//..
		}
		
	}

	if( INTCON3bits.INT1IF )			//S
	{	INTCON3bits.INT1IF = 0;
		if( INTCON2bits.INTEDG1 )
		{	INTCON2bits.INTEDG1 = 0;
			//...
		}
		else
		{	INTCON2bits.INTEDG1 = 1;
			//...	
		}
	}

	if( INTCON3bits.INT2IF )			
	{	INTCON3bits.INT2IF = 0;
		if( INTCON2bits.INTEDG2 )
		{	INTCON2bits.INTEDG2 = 0;
		        //...		
		}
		else
		{	INTCON2bits.INTEDG2 = 1;
			//...	
		}
	}
}
20/02/2009 #6


Ejemplo de interrupcion con RBO usando C18
Hola,
espero les sirva como template para hacer sus propios programas, el programa esta completo y probado en C18 v3.22
Código:
/*************************************************************************************
/*	Programa que trabaja con interrupcion por RB0
/*	sin hacer uso de libreria - cambia el estado del pin RA0 cada vez
/* 	que se pulsa en el pin RB0
/*************************************************************************************
/*	desarrollado por Luis Becerra para roboticaID
/************************************************************************************/
#include <p18f4520.h>
#include <timers.h>
/************************************************************************************/
#pragma config OSC = HSPLL, FCMEN = OFF, IESO = OFF                       // CONFIG1H
#pragma config PWRT = OFF, BOREN = SBORDIS, BORV = 3                      // CONFIG2L
#pragma config WDT = OFF, WDTPS = 32768                                   // CONFIG2H
#pragma config MCLRE = ON, LPT1OSC = OFF, PBADEN = OFF, CCP2MX = PORTC    // CONFIG3H
#pragma config STVREN = ON, LVP = OFF, XINST = OFF, DEBUG = ON            // CONFIG4L
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF                 // CONFIG5L
#pragma config CPB = OFF, CPD = OFF                                       // CONFIG5H
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF             // CONFIG6L
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF                         // CONFIG6H
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF         // CONFIG7L
#pragma config EBTRB = OFF                                                // CONFIG7H
//****************************************************************************************************************************
//				TIPOS DE DATOS
// ****************************************************************************************************************************
#define	LED	LATAbits.LATA0
/*******************************************************************************************************
/*	variables globales
/*******************************************************************************************************/
	char contador;
/******************************************************************************************************* 
/*	Interrupcion con direccion 0x08
/***************************************************************************************************** */
void InterruptServiceHigh(void);
#pragma code InterruptVectorHigh = 0x08
void InterruptVectorHigh (void)
{
  _asm
    goto InterruptServiceHigh //Salta a la direccion de interrupcion ALTA
  _endasm
}
/******************************************************************************************************* 
/*	Interrupcion con direccion 0x18
/***************************************************************************************************** */
void InterruptServiceLow(void);
#pragma code InterruptVectorLow = 0x18
void InterruptVectorLow (void)
{
  _asm
    goto InterruptServiceLow //Salta a la direccion de interrupcion BAJA
  _endasm
}
/*************************************************************************************
/* 	Programa Principal
/*************************************************************************************/
#pragma code
void main(void)
{
	/* *******************************************
	/* 	Configuro el puerto A como salida digital
	/* ****************************************** */
	ADCON0 = 0X00;		// Manual del pic 18F4520 - DS39631D-page 223 - Modo Analogo
	ADCON1 = 0X0F;		// Manual del pic 18F4520 - DS39631D-page 224 - Modo Analogo
	CMCON = 0X07;		// Manual del pic 18F4520 - DS39631D-page 233 - Modo Comparador
	TRISA = 0X00;
	TRISB = 0X01;		// debo colocar el RB0 como entrada para trabajar la interrupcion
	TRISD = 0X00;	
	PORTA = 0X00;
	PORTB = 0X00;
	PORTD = 0X00;
	/**********************************************************************
	/* 	Interrupcion debido a los pines RB0
	/* ********************************************************************/
	INTCONbits.INT0IE=1;		// INTCON(4); Habilito la interrupcion por el pin RB0
	INTCONbits.INT0IF=0;		// INTCON(1); Coloco el cero el flag de interrupcion por el pin RB0
	INTCON2bits.INTEDG0=1;		// INTCON2(6); Decido con que flanco trabajo; 1: Subida; 0: Bajada
	INTCONbits.GIE=1;			// INTCON(7); Habilito la interrupcion global
	while(1);
  }

/******************************************************************************************************* 
/*	Interrupcion con direccion 0x08
/***************************************************************************************************** */
#pragma interrupt InterruptServiceHigh  // Directiva pragma "interrupt" para interrupcion de alta prioridad
void InterruptServiceHigh(void)
{
	if(INTCONbits.INT0IF)
	{
		LED=~LED;				// invierto el estado del LED
		INTCONbits.INT0IF=0;	// Coloco el cero el flag de interrupcion por el pin RB0
	}
}
/*******************************************************************************************************
******************************************************************************************************** 
/*	Interrupcion con direccion 0x18
/***************************************************************************************************** */
#pragma interruptlow InterruptServiceLow// Directiva pragma "interruptlow" para interrupcion de baja prioridad
void InterruptServiceLow(void)
{
  /**********************
    /* aqui va el programa que corresponde a la interrupcion de baja prioridad
    ***********************/
}
Ojla les sirva.
Feliz dia
MordorInc
24/02/2011 #7


Gracias por compartir.
Saludos.
Miguel
26/07/2013 #8


Ando trabajando en la generación de una señal pwm desde hace uuff jeje con el timer 0 la idea es ir variando el ciclo de trabajo, no voy a utilizar los modulos CCP por que necesito generar mas de 2 señales pwm, para arrancar he estado cacharreando con el timer 0 generando una señal cuadrada de frecuencia de 20kHZ, en el momento de hacer el código y simularlo en proteus, no concuerda con los cálculos hechos.. Quiero un desbordamiento de 25us PERO al poner los cursores en el osciloscopio en proteus me sale de 30us Aprox. No se que ando haciendo mal, espero me puedan ayudar anexo código
Código:
#include <p18f4550.h>
#include <delays.h>

//////////////////Configuaracion de bits//////////////////////////

#pragma config PLLDIV = 1 //En este caso no importa por que vamos a utilizar Oscilador Interno
#pragma config CPUDIV = OSC1_PLL2 ////En este caso no importa por que vamos a utilizar Oscilador Interno
#pragma config USBDIV = 1   /////En este caso no importa por que vamos a utilizar Oscilador Interno
#pragma config FOSC = INTOSCIO_EC  //Configurando oscilador interno_ si se deja por default trabajará a 1Mhz
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRT = OFF
#pragma config BOR = OFF
#pragma config BORV = 0
#pragma config VREGEN = OFF
#pragma config WDT = OFF
#pragma config WDTPS = 16384
#pragma config MCLRE = OFF
#pragma config LPT1OSC = OFF
#pragma config PBADEN = ON
#pragma config CCP2MX = OFF
#pragma config STVREN = OFF
#pragma config LVP = OFF
#pragma config ICPRT = OFF
#pragma config XINST = OFF
#pragma config DEBUG = OFF
#pragma config CP0 = OFF,CP1 = OFF,CP2 = OFF,CP3 = OFF
#pragma config CPB = OFF
#pragma config CPD = OFF
#pragma config WRT0 = OFF,WRT1 = OFF,WRT2 = OFF,WRT3 = OFF
#pragma config WRTB = OFF
#pragma config WRTC = OFF
#pragma config WRTD = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF,EBTR2 = OFF,EBTR3 = OFF

#define  bandera INTCONbits.TMR0IF

void Interrupt_isr_TMR0(void);

//-------------------------------------------------------

void main (void)
{
 //------------Configuracion de puertos--------------------------
    TRISB=0x00;
    LATB=0x00;
    ADCON1=0x0F;  //Todos los pines digitales.

//----------------Configuracion de oscilador interno------------------
    OSCCON=0b01110110;  //Oscilador Interno a 8Mhz
//--------------------------------------------------------
    RCONbits.IPEN=1; //Habilito prioridad de interrupcion.
    INTCONbits.GIE_GIEH=1; //Habilito todas las interrupciones de alta prioridad
    INTCONbits.TMR0IE=1; //Habilito Interrupcion TMR0 por desbordamiento
    bandera=0; //Pongo a cero la bandera de desbordamiento.
//-------------------------------------------------------------
//------------Configurando el Timer0--------------------------
    T0CON=0b11001000;   //Configurado a 8 bits sin prescales
    TMR0L=00;

    while(1){}

    
}

#pragma code HighVector = 0x08

void high_ISR(void){
    _asm goto Interrupt_isr_TMR0 _endasm
}
//Rutina de Interrupciones de alta prioridad

#pragma code
#pragma interrupt Interrupt_isr_TMR0

void Interrupt_isr_TMR0 (void){
    TMR0L=206;   // 256-206= 50 paso: Como se sabe que cada paso es de 500ns 500ns*50=25us el desbordamiento.
    if(bandera==1){
        bandera=0;
        LATBbits.LATB0=!LATBbits.LATB0;
        
    }

 }
Gracias.

Éxitos a todos
26/07/2013 #9

Avatar de Ardogan

¿La frecuencia con la que está trabajando el pic es de 1 MHz?.
TMR0 solo puede tener una frecuencia de fosc/2 -> 500KHz
1 cuenta de TMR0 = 2 us en vez de 500 ns como dice en los comentarios.

Pero si ese fuera el problema deberías ver el doble de tiempo y no los 30 us. Alguna configuración debe hacer que el pic este a 2 MHz en vez de 1 MHz.
Ahí me doy cuenta que usas 50 cuentas de TMR0 => la frecuencia es de 2 MHz

Esos 5 us "sobrantes" pueden deberse a que es el tiempo necesario que precisa el pic para disparar la rutina de interrupción (salvar contexto: guardar el contador de programa y quizás algo más, ir al vector de interrupción, ejecutar el goto interrupción) y ejecutar el código en la misma (la asignación de TMR0L + evaluación del if y asignación del puerto).

Una prueba que podés hacer si el problema es ese es poner dentro del while(1) del main un retardo del tiempo deseado (25 us) y ver cuanto tiempo tarda, es decir:
  1. Poner a 0 pin del puerto
  2. Poner a 1 pin del puerto -->> generamos un flanco ascendente para el osciloscopio
  3. Llamar a rutina delay optimizada: como el tiempo es pocos ciclos de reloj te diría de poner NOPs uno debajo del otro. Cada NOP requiere 4 ciclos de fosc = 1 fcy -> 50/4 -> 12 NOPs. Pero 1 menos debido a la instrucción siguiente. 11 NOPs => 44 ciclos de reloj
  4. Poner a 0 pin del puerto -> 4 ciclos de reloj.
El tiempo en alto sería el retardo. Eso en teoría debería dar 44 + 4 = 48 ciclos de reloj, con reloj a 2 MHz => 24 us

Por último, la exactitud va a ser tan buena como la del oscilador usado, que para el oscilador interno puede ser tan mala como 10%.
26/07/2013 #10


Ardogan Gracias por responder... Bueno, esos 1MHZ se me olvido borrarlo, eso fue una prueba que hice inicialmente para ver si lo que había leído era cierto, que era que cuando el oscilador se configura como interno (FOSC = INTOSCIO_EC) y no se especifica por medio de registro OSCCON la frecuencia de trabajo, el mismo tomaba como default una frecuencia de 1Mhz.. Pero si nos fijamos bien yo configuro el oscilador a 8Mhz activando los bits del registro OSCCON..

Voy analizar bn lo que dices para ver si puedo solucionar el problema..

Gracias

Exitos a Todos.
Respuesta
¿Tienes una mejor respuesta a este tema? ¿Quieres hacerle una pregunta a nuestra comunidad y sus expertos? Registrate

Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO ©2011, Crawlability, Inc.