PROG: ;RUTINA PARA DETECTAR VISUALMENTE LA INTERRUPCIÓN
HIGH L_verde
pause 500
low l_verde
PAUSE 500
GOTO progEn PBP, si ocurre una interrupción durante pause n no la atiende hasta que termina. La "solución" propuesta por sus autores es descomponerla en intervalos mas cortos, por ejemplo:for k=1 to 1000 : pauseus 500 : NEXT k se pierde exactitud pero por lo menos bloquea durante menos tiempo. LCDOUT $FE, $C4, "CONTEO: ", DEC CONTador ;VISUALIZAR EL CONTEO DE INTERRUPCIONES EN UN LCDLCDOUT no es rápido, demora mas de 20ms la primer vez y casi 3ms después. Usarla dentro de una interrupción que ocurre cada 10ms es mala idea. Más teniendo en cuenta que refrescar un display mas de 5 veces por segundo no tiene sentido porque no se alcanza a distinguir el último dígito (si está cambiando obviamente)
IF CONTADOR = 100 THEN ;SI SUMAN 100 INTERRUPCIONES DE 10 mS (1 SEGUNDO)
GOTO UN_SEGUNDO
ENDIF
INTCON.2 = 0 ;REHABILITAR INTERRUPCIÓN TMR0
RESUME ;REGRESA AL PROGRAMA PRINCIPAL
ENABLE ;HABILITAR INTERRUPCIONES
UN_SEGUNDO:
HIGH L_ROJO
PAUSE 200
LOW L_ROJO
CONTADOR = 0
RETURN
UN_SEGUNDO:
if L_ROJO = 0 THEN
HIGH L_ROJO
ELSE
LOW L_ROJO
ENDIF
CONTADOR = 0
RETURN
...Si sacás "PROG" el programa ejecuta lo que sigue (la interrupción) y retorna a cualquier parte.
Tengo el siguiente comentario: creí que podía eliminar la rutina "PROG", que se encarga de hacer destellar un led de color verde, lo puse para verificar que efectivamente el PIC "dejaba de hacer lo que estaba haciendo" para atender la interrupción. Pero al eliminarla, aparentemente, ya no se producen interrupciones, el led rojo, que se encarga de notificar cuando se ha cumplido un segundo, deja de destellar. ¿Entonces es necesario que el PIC "esté haciendo algo" para que se produzcan las interrupciones? Yo hubiera pensado que simplemente con que el PIC estuviera alimentado, sin estar haciendo una tarea específica habrían interrupciones. :oops: :oops: :oops:
Ahora mi pregunta es, si estoy haciendo destellar el led rojo, que me notifica que se ha cumplido un segundo, con una pausa de 200 mS y, como bien comentó Eduardo2, "Menos que menos usar un PAUSE 200 dentro de una interrupción de período 10ms...", ¿qué valor sería recomendable para la pausa en lugar de 200?Dentro de la interrupción es mala palabra usar PAUSE, hasta un PAUSEUS de pocos us se puede aceptar, pero nunca de milisegundos.
Hola a todos. Este es el avance que llevo, ya funciona bastante bien. Modifiqué la configuración del preescalador a 1:128 y el valor del TMR0 a 4, con lo que se producen interrupciones cada 32,256 mS, ésto multiplicado por 31 da 999,936 uS, ya bastante más cercano a un segundo.
Tengo el siguiente comentario: creí que podía eliminar la rutina "PROG", que se encarga de hacer destellar un led de color verde, lo puse para verificar que efectivamente el PIC "dejaba de hacer lo que estaba haciendo" para atender la interrupción. Pero al eliminarla, aparentemente, ya no se producen interrupciones, el led rojo, que se encarga de notificar cuando se ha cumplido un segundo, deja de destellar. ¿Entonces es necesario que el PIC "esté haciendo algo" para que se produzcan las interrupciones? Yo hubiera pensado que simplemente con que el PIC estuviera alimentado, sin estar haciendo una tarea específica habrían interrupciones. :oops: :oops: :oops:
Ahora mi pregunta es, si estoy haciendo destellar el led rojo, que me notifica que se ha cumplido un segundo, con una pausa de 200 mS y, como bien comentó Eduardo2, "Menos que menos usar un PAUSE 200 dentro de una interrupción de período 10ms...", ¿qué valor sería recomendable para la pausa en lugar de 200?
Aún tengo pendiente investigar lo que comentó DominusDRR acerca de la instrucción DISABLE, que aparece justo antes de ejecutar la RAI y de la instrucción RESUME, casi al final de la RAI, pero que está una línea antes de la instrucción ENABLE. Aparentemente el RESUME dejaría sin ejecutar el ENABLE. Dejo imagen de donde tomé las instrucciones así.
Gracias a todos por adelantado. Saludos.Código: QBasic/QuickBASIC
DEFINE OSC 4 CONTADOR VAR BYTE ;CONTADOR DE INTERRUPCIONES DE 32,256 uS CADA UNA CONTADOR = 0 ;INICIALIZA CONTADOR DE INTERRUPCIONES CONT_PAUSAS VAR BYTE ;CONTADOR DE PAUSAS DE LA RUTINA "PROG" LED_VERDE VAR PORTB.1 ;LED DE LA RUTINA "PROG" PARA VERIFICAR VISUALMENTE ;LA INTERRUPCIÓN DE DICHA RUTINA CUANDO SE CUMPLE ;UN SEGUNDO LED_ROJO VAR PORTB.2 ;EL LED ENCIENDE CADA QUE SE CUMPLE UN SEGUNDO TRISB = 0 ON interrupt GOTO RAI ;RUTINA DE ATENCIÓN A LA INTERRUPCIÓN OPTION_REG = %01010110 ;CONFIGURA PREEESCALADOR TMR0 EN 1:128 TMR0 = 4 ;INICIALIZA TMR0 INTCON= %10100000 ;HABILITA INTERRUPCIÓN TMR0 PROG: ;RUTINA PARA DETECTAR VISUALMENTE LA INTERRUPCIÓN HIGH LED_verde GOSUB pausA low LED_verde GOSUB pausA GOTO prog PAUSA: FOR CONT_PAUSAS = 1 TO 20 ;GENERA PAUSAS DE 10 mS PARA NO PERDER INTERRUPCIONES PAUSE 10 NEXT CONT_PAUSAS RETURN DISABLE ;DESHABILITAR INTERRUPCIONES RAI: TMR0 = 4 CONTADOR = CONTADOR + 1 IF CONTADOR = 31 THEN ;31 INTERRUPCIONES DE 32,256 mS CADA UNA = 999,936 uS GOSUB UN_SEGUNDO ENDIF INTCON.2 = 0 ;RESETEA LA BANDERA DE INTERRUPCIÓN DEL TMR0 RESUME ;REGRESA AL PROGRAMA PRINCIPAL ENABLE ;HABILITAR INTERRUPCIONES UN_SEGUNDO: HIGH LED_ROJO PAUSE 200 LOW LED_ROJO CONTADOR = 0 RETURN
Hola Eduardo2 y DominusDRR, nuevamente, mil gracias por contestar. Voy a poner en práctica lo que comentan... aunque eso de "retardo asincrónico" me suena a "no le voy a entender" :shock: :shock: :shock:
A seguir experimentando para aprender. Gracias a todos. ((:-))
Hola dejo la función MILLIS, lo mismo la puedes adaptar a tu lenguaje.
En este caso usa el timer1 y cuenta cada 1mSeg.Código: Visual Basic
'*********************************************************************** 'MILLIS function, long type geneal counter. 'For replacing absolute pauses generated with WaitMs. 'The _MILLIS function increments every mSec. so it takes 'approximately 49.7 days To reinitialize. 'That is, it will pass through a zero value. '************************************************************************ 'Pic16F88, OshonSoft Pic Basic Compiler v.8.42 'By COS, 03/2023 '************************************************************************ #define CONFIG = 0x2f50 'Fuse definition. #define CONFIG2 = 0x3ffc Define CLOCK_FREQUENCY = 8 'Clock a 8Mhz 'Define SIMULATION_WAITMS_VALUE = 1'Waitms is used activate for simulation. Include "_FuncionesPic16F88.bas" '************************************************************************ main: 'Pin configuration AllDigital ConfigPin PORTA = Output ConfigPin PORTB = Output 'Clock internal 8Mhz. Call _setup_oscillator_mode_select_bit(_oscillator_mode_defined_by_fosc) Call _setup_oscillator(_osc_8mhz) 'Initialize Timer1 desborde 1mSec. Call _setup_timer1(_tmr1_internal, _tmr1_div1) Call _set_timer1(0xf831) 'Interruption every 1mSec. Call _timer1(_on) Call _enable_interrupts(_int_timer1) 'Call _enable_interrupts(_global) 'Assign names to the Leds Symbol LedGreen = RB0 Symbol LedYellow = RA7 '******************************************************************** Call _SetUp_MILLIS() 'Setup _MILLIS functions, before activate interrupts Call _enable_interrupts(_global) Dim PreMillis As Long Dim PreMillis1 As Long 'Loop While True Call _MILLIS() 'Repeat As few times As possible, so As Not To interfere with interruptions. If (_MILLIS - PreMillis) >= 200 Then 'Wait time in mSec. PreMillis = _MILLIS 'The last value of _MILLIS is stored. Toggle LedYellow 'Invers the state of the led. Endif If (_MILLIS - PreMillis1) >= 400 Then 'Wait time in mSec. PreMillis1 = _MILLIS 'The last value of _MILLIS is stored. Toggle LedGreen 'Invers the state of the led. Endif Wend End '******************************************************************** 'Function _MILLIS 'Requires the use of a timer and interrupts. '************************************************** 'Call _SetUp_MILLIS() 'Before triggering interrupts 'Call _MILLIS() 'Update _MILLIS counter 'Call _CounterMillis() 'Incrementa contador Millis '************************************************** 'Inicialize functions Proc _SetUp_MILLIS() _MILLIS = 0 _CounterMillis = 0 End Proc 'Return _MILLIS as Long and global variable Function _MILLIS() As Long Disable 'Stop interruption _MILLIS = _CounterMillis Enable 'Enable interruption End Function 'Increment the counter Millis 'Return _CounterMillis as Long and global variable Function _CounterMillis() As Long _CounterMillis++ 'Increment counter millis End Function '******************************************************************** 'Interrupt vector On Interrupt 'Disable interruptions Save System If _tmr1if Then Call _set_timer1(0xf831) 'Reload TMR1 registers to count 1mSec and clear _tmr1if. Call _CounterMillis() 'Increments _CounterMILLIS every mSec. Endif Resume 'Enable interruptions