1)which 2 functions1) If you flowchart both functions, you might get some ideas.
2) Why can't you used the interrupt delay for your debounce period too?
movlw .33 ;state 0
btfsc <some flag bit>
movlw .20 ;state 1
movwf INTDELAY
Thanks.Nicely done flow chart. Generally speaking, one would detect the button being pressed, wait for the signal to settle, and then effect the change. The reason for that is because the cycle time of the program may be faster than the bounce time. For example. let's say you are entering control words as binary bits, and one button is a 1 and another is 0. That data entry routine is likely fast , and pressing the 1 may end up with multiple 1's being entered as the bounces are detected.
In your program, the loop time is roughly 30 ms for the interrupt. Bouncing may not affect the change you make in delay variables, e.g., your presets for TMR0 and INTDELAY.
My thought was to use the interrupt delay to also time your debounce. For example, if the switch read* is outside of the interrupt, e.g., you poll the switch in the PROGRAM/NOP/PROGRAM loop, you could read INTDELAY and keep reading it until it decrements by 2 (minimum delay a little more than 30 ms to about 60 ms depending on when the button was pressed relative to TMR0 rolling over).
You could also test the switch on each entry into the interruptand require that two reads be the same to effect a change, which would give you a built in delay of at least 30 ms, so the chance of a double read is remote. Of course, anything you do in the interrupt will affect its period slightly by a few μs. I would prefer this approach.
Are you planning to have release of the switch affect flash rate too? That is, press the button and flash rate changes. Will it require another press of the button to change the rate back or will that happen on release?
How are you planning to change flash rate? If possible, I would recommend only changing INTDELAY and not TMR0 preset. You will need to have two states and switch between those states. That is, in your steps: movlw .33 ; movwf INTDELAY , you cannot actually change the .33 on the fly. You would have to have 2 states: 1) movlw .33 and 2) movlw <something else> and switch between the two based on the status of your switch.**
*By switch "read," you can read the switch, but if it is bouncing, you may get a wrong reading. I often read the port interrupt flags. Those change, but do not bounce back. You must clear them in your software. So if you see a change in RBIF, you can be sure there is a change and visa versa. If you do not see a change when reading the port, it may just be bouncing. Newer chips allow you to actually read an IF flag for each pin, and you can set which or both edges are detected.
** For example,
Code:movlw .33 ;state 0 btfsc <some flag bit> movlw .20 ;state 1 movwf INTDELAY
Using 1 & 0 is bad practice. W & F are explicit instead.It is always wise to use the destination when needed and not rely on the default. Standardize on using 0,1 or W,F, respectively. I prefer W,F.
In your case or any other kind of program the main has to do its own tasks but never be "waiting for interrupts". These (interrupts) will occurr as they are programmed, interrupting actually, the main. Pretty much what happens in real life in a dynamic environment where a wife, a boss, a policeman, can have the power to interrupt whatever you are doing. The difference is that here, these interrupts will keep happening.Ok let me re-phrase it.
My main program now does nothing and waits every 30ms to get an interrupt.
The mothership seems to prefer 0 and 1:Using 1 & 0 is bad practice. W & F are explicit instead.
Mnemonics are the way to go. The same with variables with obfuscated names that even their creator cannot recognize three days after. Think of revisiting your code in five months time...
The purpose is to flash an LED. That's all. Of course, an interrupt is not needed, but the lesson is apparently about how to use an interrupt. Thus, I don't see anything wrong with following directions. What else would you suggest doing in the "Main?"In your case or any other kind of program the main has to do its own tasks but never be "waiting for interrupts". These (interrupts) will occurr as they are programmed, interrupting actually, the main. Pretty much what happens in real life in a dynamic environment where a wife, a boss, a policeman, can have the power to interrupt whatever you are doing. The difference is that here, these interrupts will keep happening.
I did not check the actual details of the thread but if the main is doing nothing and all depends of you ISR, something is wrong.
Hola @jpanhaltThe purpose is to flash an LED. That's all. Of course, an interrupt is not needed, but the lesson is apparently about how to use an interrupt. Thus, I don't see anything wrong with following directions. What else would you suggest doing in the "Main?"
That's what my main intention was. Make the main program do something and then let the interrupt stop the program and do it's own thing that it creates a square wave where the main program is setting the program to high and the interrupt setting it to low. but it didn't work and now I have reached a point where the main program will do nothing and the interrupt will toggle the light right now my latest work is checking for button presses in the interrupt and do the action in main.Hola @jpanhalt
Caveat to the OP: let us make clear that I am not replying other than John's question.
It is obvious that just to blink a LED, an on_line delay would be more than enough (and simpler), repeating forever inside the main loop.
To show how an interrupt works with all this, I would do something additional (inside the ISR) while blinking that proverbial LED in the main loop.
I propose this (which, BTW, is something I've implemented when I learnt to use interrupts and kept doing for every micro):
You enter the ISR and:
A) Save the environment.
B) Set PIN_DEBUG (you can see it whith a scope going high).
C) Do whatever the interrupt is intended for.
D) Clear PIN_DEBUG (you can see it whith a scope going low).
E) Retrieve the environment.
You leave the ISR
View attachment 194642
#include <p16f72.inc>
__config (_HS_OSC & _WDT_OFF & _PWRTE_OFF & _CP_OFF)
; /////////////////////////////////////////////////////////////////////////
CBLOCK h'25'
W_SAVE
STATUS_SAVE
INTDELAY
ISPRESSED
ENDC
;******************************************************************
list P=16F72
ORG 000H
GOTO MAIN
ORG 004H
GOTO INTFUNCT
; /////////////////////////////////////////////////////////////////////////
; Initialize all variables and port pins here!
; /////////////////////////////////////////////////////////////////////////
MAIN:
BSF STATUS, RP0
MOVLW B'00000000'
MOVWF TRISB
MOVLW B'11111111'
MOVWF TRISA
MOVLW B'10000110'
MOVWF OPTION_REG
BCF STATUS, RP0
CLRF PORTB
MOVLW .178
MOVWF TMR0
BCF INTCON, TMR0IF
BSF INTCON, TMR0IE
BSF INTCON, GIE
BSF PORTB, 0
MOVLW .33
MOVWF INTDELAY
PROGRAM:
BTFSS ISPRESSED,0
GOTO PROGRAM
CALL FREQUENCY1
TEMPSTOP:
BTFSC ISPRESSED,0
GOTO TEMPSTOP
GOTO PROGRAM
INTFUNCT:
MOVWF W_SAVE ; save W
SWAPF STATUS, W ; save STATUS
MOVWF STATUS_SAVE
BCF STATUS, RP0
BTFSC INTCON, TMR0IF
GOTO ENDIR
BTFSC PORTA,0
GOTO SETBIT1
GOTO CLEARBIT1
SETBIT1:
MOVLW 1
MOVWF ISPRESSED,0
GOTO CONTINUE
CLEARBIT1:
MOVLW 0
MOVWF ISPRESSED,0
GOTO CONTINUE
CONTINUE:
BCF INTCON, TMR0IF
DECFSZ INTDELAY,f
GOTO ENDIR ;once it reaches 0, then do the main part of the interrupt and then reset intdelay
MOVLW .1
XORWF PORTB,f
MOVLW .178
MOVWF TMR0
MOVLW .33
MOVWF INTDELAY
GOTO ENDIR
ENDIR:
SWAPF STATUS_SAVE, W
MOVWF STATUS
SWAPF W_SAVE, F
SWAPF W_SAVE, W
RETFIE
FREQUENCY1:
MOVLW .32
MOVWF INTDELAY
END
The interrupt code takes 18 us, not ms. The code stops at that external loop while TMR0 counts up.Thanks.
Interesting thought of testing switch in the interrupt. Testing it at the start of the interrupt if button is pressed. if it is there is already the 30ms time it takes for the next interrupt to take place. But the interrupt routine itself takes 20ms and there is an approx 10ms rollover time before interrupt kicks in.
20 ms to 30 ms is probably long enough, some people use just 10 ms.So I guess 20ms is ample delay and that a flag variable should be set to indicate button was detected and delay has taken place. so outside of the interrupt we can check for the flag and execute the change without delay. then when interrupt happens again the switch would be unpressed and flag cleared. which i would check it is cleared outside of the interrupt and keep looping in that area till flag is cleared. switches are in portA so I can't check the RBIF flag.
A button press would change the frequency and the release does nothing only the pressing.
Port B has lights on them and the switches are on PortA. so I won't be able to use the switch as interrupts. Teacher had configured it that way.The interrupt code takes 18 us, not ms. The code stops at that external loop while TMR0 counts up.
20 ms to 30 ms is probably long enough, some people use just 10 ms.
With your clarification of the toggle vs. action on release, I would probably change from IOC on RB4..7 to the INT pin (RB0) where you can choose the edge. Say you set it to a rising edge.
I am still learning Google's Draw.io so my flowchart may not be clear. My criteria were: 1) There are two states; one flashes the LED faster than the other and duty cycle for each is about 50%; 2) It can remain in either state for an indeterminate time until the button is pushed again; 3) It never changes state upon release of the button; and 4) Only one button is involved and it will be held a minimum of two rollovers of TMR0 (faster presses (>30 ms) may work, but not consistently). Here goes on my attempt to toggle the state with each press of a button switch on the INT pin (RB0) set to rising edge and without enabling its interrupt.
BTW, It looks like the code you just posted will reset to the slower state as soon as the button is released or sooner as INTDELAY is refreshed to the old value in the interrupt..
EDIT: Ignore step 3 under Cycle bit set decision.
Oh yeah I forgot about that. I will have to use another temp variable, which I can decrement and then after the countdown reaches 0 copy the original value of intdelay to the temp variable and decrement count delay so something likeBTW, It looks like the code you just posted will reset to the slower state as soon as the button is released or sooner as INTDELAY is refreshed to the old value in the interrupt..
by Jake Hertz
by Jake Hertz
by Jake Hertz