I have always steered away from using interrupts, as I was never confident I knew what I was doing and found myself confused whenever I tried to read how to use them. As things are not too busy this week, I thought I'd have a look at trying to make sense of them. I am also experimenting with Chris Roper's millis() function. That section works very well, and I'm grateful to Chris for his excellent work and generousity in sharing it. I'm rather less confident in my work on the Interrupt, although it does seem to 'work'...
Here's my code:
'#Chip 16F874, 20 'This selects Crystal Oscillator of 20MHz#Optionexplicit#ConfigOSC=RC'This selects RC Oscillator#Chip16F874,4'2k7 and 30pf on pin 13 just over 4MHz#include"millis.h"' Include the Millis() Library'Note:'Pin 1 MUST connect to +5V to prevent being held in reset.#DefineLED_PinPortA.0'Pin2#DefineLED_Pin2PortA.1'Pin3#DefineLEDRate1000'Flash rate in mS#DefineInt_PinPortB.4'Pin37'This includes an example of the use of the 'Millis() library'millis() returns the number of milliseconds elapsed since the'processor was powered up. It returns a Long variable value'that will return to zero after 49 days of running. If checking'for values being greater than millis() in programs intended to'run for long periods, remember to watch for it resetting to zero.DimCurMsAsWordDimLstMsAsWordDimInt_EnAsByteDirLED_PinOutDirLED_Pin2OutDirInt_PinIn'**********************************************************************'Interrupt setup'**********************************************************************LetInt_En=INTCON'Get Interrupt status'INTCON.0 Change on PortB happened'INTCON.1 External Interrupt on PortB'INTCON.2 Timer0'INTCON.3 PortB Change Enable'INTCON.4 External Interrupt PortB Enable'INTCON.5 Timer0 Enable'INTCON.6 Peripheral Interrupt Enable'INTCON.7 Global Interrupt EnableLetInt_En.3=1'Enable IOC for PortBLetInt_En.0=0'Clear any InterruptsLetINTCON=Int_En'Set Interrupt statusOnInterruptPortBChangeCallInterrupt_Sub'**********************************************************************'Interrupt setup'**********************************************************************LetCurMs=0LetLstMs=0DoCurMs=millis()IfCurMs-LstMs>=LEDRateThen'Required Time has ElapsedLetLED_Pin=!LED_Pin'So Toggle state of LEDLetLstMs=CurMs'And Record Toggle TimeEndIf'This section tests to see if the IOC interrupts have been disabled.'They are turned off once we've responded to the button press.'We only want to re-enable them once the button has been released to'prevent multiple presses being recorded when only one has ocurred.IfInt_En.3=0Then'IOC Interrupts are disabledReset_Interrupt_SubEndIfLoopSubInterrupt_SubLetInt_En=INTCON'Get Interrupt statusIfInt_En.0=1ThenIfInt_Pin=1Then'Button pressedWait10mSIfInt_Pin=1Then'Still pressedLetLED_Pin2=!LED_Pin2LetInt_En.0=0'Reset the Interrupt On ChangeLetInt_En.3=0'Stop the Interrupt On Change ServiceEndIfEndIfEndIfLetINTCON=Int_EnEndSubSubReset_Interrupt_SubIfInt_Pin=0Then'Button releasedWait10mSIfInt_Pin=0Then'Still releasedLetInt_En=INTCON'Get Interrupt statusLetInt_En.3=1'Enable IOC for PortBLetInt_En.0=0'Clear any InterruptsLetINTCON=Int_En'Set Interrupt statusEndIfEndIfEndSub
As I said, this does work. If I press my button, I can toggle the state of the LED on Pin3 (PortA.1) whilst the LED on Pin2 (PortA.0) flashes under control of Chris's millis() function. If the button is held in, it is ignored until it has been released, and then presssed again. Super.
My lack of confidence is that the setup and implementation of the interrupt all seems a little 'messy'. I keep thinking that there should be a simpler way of doing this than the one I'm using.
I tried using one of the examples from the help pages that used this:
'Setup the InterruptSetIOCA.3onDirporta.3inOnInterruptPORTABCHANGECallSetir
I changed it to:
'Setup the InterruptSetIOCB.4onDirPortB.4inOnInterruptPORTBCHANGECallInterrupt_Sub
But this fails to compile, giving the error message "Error: Variable IOCB was not explicitly declared".
I just wondered if my approach could be improved?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have managed to cobble something similar for the 16F1825, but again, it all seems rather untidy. The 16F1825 and 1829 seem to only have one external interrupt available (or I really misunderstood the datasheet) INTE, interrupt on edge. This requires two registers to be set, INTCON (bit 4) and the OPTION_REG (bit 6) which if set to 1 interrupts on a rising edge, if set to 0 interrupts on a falling edge. All of this assumes I did interpret the datasheet correctly, although it does seem to be working...
Any help would be most useful.
#Optionexplicit#Chip16F1825,32#DefineOutPinPortC.5'Pin 5#DefineInt_PinPortA.2'Pin 11DimInt_EnAsByte'Set pin directionsDirOutPinOut'Pin 5'**********************************************************************'Interrupt setup'**********************************************************************LetInt_En=OPTION_REG'Get Option statusLetInt_En.6=1'Interrupt on rising edgeLetOPTION_REG=Int_EnLetInt_En=INTCON'Get Interrupt status'INTCON.0 Change on PortA happened'INTCON.1 External Interrupt on PortA'INTCON.2 Timer0'INTCON.3 PortA Change Enable'INTCON.4 External Interrupt PortA Enable'INTCON.5 Timer0 Enable'INTCON.6 Peripheral Interrupt Enable'INTCON.7 Global Interrupt EnableLetInt_En.4=1'Enable INTE for PortA - Only Pin = Pin 11LetInt_En.1=0'Clear any InterruptsLetINTCON=Int_En'Set Interrupt statusOnInterruptExtInt0CallInterrupt_Sub'**********************************************************************'Interrupt setup'**********************************************************************Do'Do useful stuff here'This section tests to see if the INTE interrupts have been disabled.'They are turned off once we've responded to the button press.'We only want to re-enable them once the button has been released to'prevent multiple presses being recorded when only one has ocurred.IfInt_En.4=0Then'INTE Interrupts are disabledReset_Interrupt_SubEndIfLoopSubInterrupt_SubLetInt_En=INTCON'Get Interrupt statusIfInt_En.1=1ThenIfInt_Pin=1Then'Button pressedWait10mSIfInt_Pin=1Then'Still pressedLetOutPin=!OutPinLetInt_En.1=0'Reset the Interrupt On EdgeLetInt_En.4=0'Stop the Interrupt On Edge ServiceEndIfEndIfEndIfLetINTCON=Int_EnEndSubSubReset_Interrupt_SubIfInt_Pin=0Then'Button releasedWait10mSIfInt_Pin=0Then'Still releasedLetInt_En=INTCON'Get Interrupt statusLetInt_En.1=0'Reset the Interrupt On EdgeLetInt_En.4=1'Start the Interrupt On Edge ServiceLetINTCON=Int_En'Set Interrupt statusEndIfEndIfEndSub
Thanks for looking.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
What I'm initially aiming for is to familiarise myself with using interrupts triggered by an external source such as a switch.
At the moment everything I've designed and written the software for, continually polls the input(s) if a 'pulse' arrives, counts it once only, by waiting for the pulse to return to it's rest state then returns to updating the display, polling the input(s), sending serial data out if required and so on.
I was thinking that my software might be more elegant if I could use interrupts to monitor the input(s) which would count each pulse once only, whilst remaining vigilant for further potential pulses instead of hoping that any time taken updating the displays and whatever else didn't exceed the few mS of any pulse widths that might arrive at any time.
So something that allows me to catch a pulse width of between 10 mS - 500 mS without hogging the entire processor for the duration of that pulse, count each pulse once only and then be ready for another pulse almost immediately after the preceeding pulse finishes.
Which the above code does manage, if not very elegantly.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The code is a lot easier. Look at the demos: C:\GCB@Syn\GreatCowBasic\Demos\vendor_boards\microchip_low_pin_count_demo_board\pickit2_board\16f1825\13_eeprom.gcb
This demo has a switch on a.3. Same chip also.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Inspired by the example from the demos folder pointed out by Anobium, I have adjusted my program for the 16F1825. I couldn't get the Interrupt on Change example from the demos folder to work well for me. This seemed to fire the interrupt when the 'millis' function changed the LED state, and sometimes when the timer overflowed within the 'millis' function too. Whilst the interrupt still worked, the button needed to be pressed very firmly, and for at least 500mS. As I was hoping to capture short(ish) pulses in my final version this was a retrograde step.
I then looked at the example and wondered where the definitions for the interrupt constants were listed. I opened up the 16F1825.dat file and lo and behold, there they were.
Taking the defined constants as opposed to reading the entire contents of the INTCON register and the OPTION_REG regiter, setting the relevant bits and then writing them back to the PIC has tidied up the code by some measure. I also took the time to swap the interrupt from a rising to a falling edge to detect button presses and releases to ensure each button press is registered only once.
The changes have sped the detection of the button press then release quite significantly, keeping the button pressed and then held does not slow the operation of the program down either.
Whilst I'm not confident in using interrupts, I'm vastly less reluctant to use them now!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
'Uses 16F1825 and Millis_Zero#Chip16F1825,32#Optionexplicit#ConfigCP=On#Include"millis_zero.h"'This includes an example of the use of the Millis() library'millis() returns the number of milliseconds elapsed since the'processor was powered up. It returns a Long variable value'that will return to zero after 49 days of running. If checking'for values being greater than millis() in programs intended to'run for long periods, remember to watch for it resetting to zero.'The version millis_zero.h starts from zero'each time the processor is powered on.#DefineOutPinPortC.5'Pin 5#DefineButtonPortA.2'Pin 11#DefineBeeperPortC.3'Pin 7#DefineLEDRate1000'mSDimCountAsByteDimPressedAsBitDimCurMsAsWordDimLstMsAsWordDimCur_MillisAsLongDimInt_MillisAsLongDimRel_MillisAsLongDimMilli_DelAsWordDimReset_TriggerAsBitDimTriggerAsBit'Set pin directionsDirOutPinOut'Pin 5DirBeeperOut'Pin 7DirButtonIn'Pin 11LetCurMs=0LetLstMs=0LetReset_Trigger=0LetTrigger=0LetCount=0InitialiseTest_MillisSubTest_MillisDoIfTrigger=1ThenLetTrigger=0DoBip(1,25)'Sound the buzzerEndIfIfReset_Trigger=1ThenLetReset_Trigger=0DoBip(1,25)'Sound the buzzerEndIfCurMs=millis()IfCurMs-LstMs>=LEDRateThen'Required Time has ElapsedLetOutPin=!OutPin'So Toggle state of LEDLetLstMs=CurMs'And Record Toggle TimeEndIfLoopEndSubSubInitialiseDoIfButton=PressedThenLetPressed=!ButtonLetCount=0EndIfWait5mSCount++LoopUntilCount>125'Get the idle state of the pin'**********************************************************************'Interrupt setup'**********************************************************************'Interrupt flags'PS0,OPTION_REG,0'PS1,OPTION_REG,1'PS2,OPTION_REG,2'PSA,OPTION_REG,3'TMR0SE,OPTION_REG,4'T0SE,OPTION_REG,4 'Alias?'TMR0CS,OPTION_REG,5'T0CS,OPTION_REG,5 'Alias?'INTEDG,OPTION_REG,6'NOT_WPUEN,OPTION_REG,7'Option_Reg for rising/falling edge'INTEDG''INTEDG = 1 'Rising Edge'INTEDG = 0 'Falling EdgeLetINTEDG=Pressed'Interrupt on switch pressed state'ExtInt0:INTE,INTF'IOCIF,INTCON,0'INTF,INTCON,1'TMR0IF,INTCON,2'IOCIE,INTCON,3'INTE,INTCON,4'TMR0IE,INTCON,5'PEIE,INTCON,6'GIE,INTCON,7'T0IF,INTCON,2'T0IE,INTCON,5'INTE = 1 'Interrupt on Edge enabled'INTE = 0 'Interrupt on Edge disabled'INTF = 1 'Edge Interrupt happened'INTF = 0 'No Edge InterruptLetINTE=1'Interrupt on Edge enabledLetINTF=0'Clear any interruptsOnInterruptExtInt0CallInterrupt_Sub'**********************************************************************'Interrupt setup'**********************************************************************EndSubSubInterrupt_SubIfINTF=1ThenIfButton=PressedThen'Button pressedWait10mSIfButton=PressedThen'Still pressedLetTrigger=1LetINTEDG=!Pressed'Change to interrupt on releaseEndIfEndIfIfButton<>PressedThen'Button releasedWait10mSIfButton<>PressedThen'Still releasedLetReset_Trigger=1LetINTEDG=Pressed'Change back to interrupt on pressEndIfEndIfLetINTF=0'Clear interruptEndIfEndSubSubDoBip(InNumberOfBipsAsByte,LengthOfBipsAsWord)ForCount=1ToNumberOfBipsSoundBeep(1)'Beep onWaitLengthOfBipsmSSoundBeep(0)'Beep offWaitLengthOfBipsmSNextEndSubSubSoundBeep(InSoundAsBit)LetBeeper=Sound'Turn on or off the beeperEndSub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I removed all the code that was not needed show below.
A few points.
1. Not sure what millis_one.h is but I may be out of the loop with version of millis.h posted.
2. Let INTF = 0 'Clear interrupt. This may be needed initially but the interrupt service handler built in with Great Cow BASIC will clear INF for you. Try removing from your interrupt handler to verify the clear is happening (I can see it in the ASM but do check yourselve).
Looks very good! A demo in the making!!
'Basic'Uses 16F1825 and Millis_Zero#Chip 16F1825, 32#Option explicit#Config CP=On#Include <millis.h>'This includes an example of the use of the Millis() library'millis() returns the number of milliseconds elapsed since the'processor was powered up. It returns a Long variable value'that will return to zero after 49 days of running. If checking'for values being greater than millis() in programs intended to'run for long periods, remember to watch for it resetting to zero.'The version millis_zero.h starts from zero'each time the processor is powered on.#Define OutPin PortC.5 'Pin 5#Define Button PortA.2 'Pin 11#Define Beeper PortC.3 'Pin 7#Define LEDRate 1000 'mSDimCountAsByteDimPressedAsBitDimCurMsAsWordDimLstMsAsWordDimCur_MillisAsLongDimInt_MillisAsLongDimRel_MillisAsLongDimMilli_DelAsWordDimReset_TriggerAsBitDimTriggerAsBit'Set pin directionsDirOutPinOut'Pin 5DirBeeperOut'Pin 7DirButtonIn'Pin 11LetCurMs=0LetLstMs=0LetReset_Trigger=0LetTrigger=0LetCount=0InitialiseTest_MillisSubTest_MillisDoIfTrigger=1ThenLetTrigger=0DoBip(1,25)'Sound the buzzerEndIfIfReset_Trigger=1ThenLetReset_Trigger=0DoBip(1,25)'Sound the buzzerEndIfCurMs=millis()IfCurMs-LstMs>=LEDRateThen'Required Time has ElapsedLetOutPin=!OutPin'So Toggle state of LEDLetLstMs=CurMs'And Record Toggle TimeEndIfLoopEndSubSubInitialiseDoIfButton=PressedThenLetPressed=!ButtonLetCount=0EndIfWait5mSCount++LoopUntilCount>125'Get the idle state of the pinLetINTEDG=Pressed'Interrupt on switch pressed stateLetINTE=1'Interrupt on Edge enabledLetINTF=0'Clear any interruptsOnInterruptExtInt0CallInterrupt_Sub'**********************************************************************'Interrupt setup'**********************************************************************EndSubSubInterrupt_SubIfINTF=1ThenIfButton=PressedThen'Button pressedWait10mSIfButton=PressedThen'Still pressedLetTrigger=1LetINTEDG=!Pressed'Change to interrupt on releaseEndIfEndIfIfButton<>PressedThen'Button releasedWait10mSIfButton<>PressedThen'Still releasedLetReset_Trigger=1LetINTEDG=Pressed'Change back to interrupt on pressEndIfEndIfLetINTF=0'Clear interruptEndIfEndSubSubDoBip(InNumberOfBipsAsByte,LengthOfBipsAsWord)ForCount=1ToNumberOfBipsSoundBeep(1)'Beep onWaitLengthOfBipsmSSoundBeep(0)'Beep offWaitLengthOfBipsmSNextEndSubSubSoundBeep(InSoundAsBit)LetBeeper=Sound'Turn on or off the beeperEndSub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have removed the "Let INTF = 0 'Clear interrupt" statement as suggested. I hadn't realised the interrupt was cleared by GCB automatically. Is that cleared when exiting the interrupt handling sub routine?
I have also removed the references to 'Millis_Zero.h' and have re-incorporated the original 'millis.h'. I had been experimenting with setting the value returned by the millis() funtion to zero when the processor is first started. 'Millis_Zero.h' was a modified version of the original. I have moved the command that resets milis() to zero into my code, leaving the original unmodified.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Yes, the Great Cow BASIC does clear the interrupt flags it handles. So, if INTE is enabled via the On Interrupt then the related INTF is cleared upon exit.
Good to read about the tidy up - when you are good and ready it would be very good to publish as a demonstration.
:-)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
'**************************************************************************'Enhanced 16F1825 version'Uses 16F1825, millis and interrupts for a button.'The interrupt triggers on a rising then falling edge to enable 'counting of buttons only when a button is pressed and released.'The button state is stored at startup to allow for buttons that'may idle high or low automatically.#Chip16F1825,32#Optionexplicit#ConfigCP=On#Include"millis.h"'This includes an example of the use of the 'Millis() library'millis() returns the number of milliseconds elapsed since the'processor was powered up. It returns a Long variable value'that will return to zero after 49 days of running. If checking'for values being greater than millis() in programs intended to'run for long periods, remember to watch for it resetting to zero.#DefineOutPinPortC.5'Pin 5#DefineButtonPortA.2'Pin 11#DefineBeeperPortC.3'Pin 7 'This connects directly to the positive connection'of 12V Piezo buzzer. The fact that a 12V buzzer'is driven from a 5V pin does not matter.'It is loud enough to hear!#DefineLEDRate1000'mSDimCountAsByteDimPressedAsBitDimCurMsAsWordDimLstMsAsWordDimReset_TriggerAsBitDimTriggerAsBit'Set pin directionsDirOutPinOut'Pin 5DirBeeperOut'Pin 7DirButtonIn'Pin 11LetCurMs=0LetLstMs=0LetReset_Trigger=0LetTrigger=0LetCount=0InitialiseTest_MillisSubTest_MillisDoIfTrigger=1ThenLetTrigger=0DoBip(1,25)EndIfIfReset_Trigger=1ThenLetReset_Trigger=0DoBip(1,25)EndIfCurMs=millis()IfCurMs-LstMs>=LEDRateThen'Required Time has ElapsedLetOutPin=!OutPin'So Toggle state of LEDLetLstMs=CurMs'And Record Toggle TimeEndIfLoopEndSubSubInitialiseLetMsCtr_=4294967295'Set the value returned by the millis() function to it's'maximum value. This effectively resets millis() to zero.'If 'millis.h' cannot be found, this raises an error that'a byte value cannot be set to 4294967295, that is why'MsCtr_ is not set to 0 (zero) here.DoIfButton=PressedThenLetPressed=!ButtonLetCount=0EndIfWait5mSCount++LoopUntilCount>125'Get the idle state of the button pin'**********************************************************************'Interrupt setup'**********************************************************************'Option_Reg for rising/falling edge'INTEDG'INTEDG = 1 'Rising Edge'INTEDG = 0 'Falling EdgeLetINTEDG=Pressed'Interrupt on switch pressed state'INTE = 1 'Interrupt on Edge enabled'INTE = 0 'Interrupt on Edge disabled'INTF = 1 'Edge Interrupt happened'INTF = 0 'No Edge Interrupt'INTE = 1 'Interrupt on Edge enabled'INTE = 0 'Interrupt on Edge disabledLetINTE=1'Interrupt on Edge enabledLetINTF=0'Clear any interruptsOnInterruptExtInt0CallInterrupt_Sub'**********************************************************************'Interrupt setup'**********************************************************************EndSubSubInterrupt_SubIfINTF=1ThenIfButton=PressedThen'Button pressedWait10mSIfButton=PressedThen'Still pressedLetTrigger=1LetINTEDG=!Pressed'Set the interrupt to trigger on releaseEndIfEndIfIfButton<>PressedThen'Button releasedWait10mSIfButton<>PressedThen'Still releasedLetReset_Trigger=1LetINTEDG=Pressed'Set the interrupt back to trigger on pressEndIfEndIfEndIfEndSubSubDoBip(InNumberOfBipsAsByte,LengthOfBipsAsWord)ForCount=1ToNumberOfBipsSoundBeep(1)'Beep onWaitLengthOfBipsmSSoundBeep(0)'Beep offWaitLengthOfBipsmSNextEndSubSubSoundBeep(InSoundAsBit)LetBeeper=Sound'Turn on or off the beeperEndSub
Last edit: mkstevo 2019-01-12
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have always steered away from using interrupts, as I was never confident I knew what I was doing and found myself confused whenever I tried to read how to use them. As things are not too busy this week, I thought I'd have a look at trying to make sense of them. I am also experimenting with Chris Roper's millis() function. That section works very well, and I'm grateful to Chris for his excellent work and generousity in sharing it. I'm rather less confident in my work on the Interrupt, although it does seem to 'work'...
Here's my code:
As I said, this does work. If I press my button, I can toggle the state of the LED on Pin3 (PortA.1) whilst the LED on Pin2 (PortA.0) flashes under control of Chris's millis() function. If the button is held in, it is ignored until it has been released, and then presssed again. Super.
My lack of confidence is that the setup and implementation of the interrupt all seems a little 'messy'. I keep thinking that there should be a simpler way of doing this than the one I'm using.
I tried using one of the examples from the help pages that used this:
I changed it to:
But this fails to compile, giving the error message "Error: Variable IOCB was not explicitly declared".
I just wondered if my approach could be improved?
I have managed to cobble something similar for the 16F1825, but again, it all seems rather untidy. The 16F1825 and 1829 seem to only have one external interrupt available (or I really misunderstood the datasheet) INTE, interrupt on edge. This requires two registers to be set, INTCON (bit 4) and the OPTION_REG (bit 6) which if set to 1 interrupts on a rising edge, if set to 0 interrupts on a falling edge. All of this assumes I did interpret the datasheet correctly, although it does seem to be working...
Any help would be most useful.
Thanks for looking.
I think a little simplification of the code may help.
Can I just check? What exactly is the result you need?
What I'm initially aiming for is to familiarise myself with using interrupts triggered by an external source such as a switch.
At the moment everything I've designed and written the software for, continually polls the input(s) if a 'pulse' arrives, counts it once only, by waiting for the pulse to return to it's rest state then returns to updating the display, polling the input(s), sending serial data out if required and so on.
I was thinking that my software might be more elegant if I could use interrupts to monitor the input(s) which would count each pulse once only, whilst remaining vigilant for further potential pulses instead of hoping that any time taken updating the displays and whatever else didn't exceed the few mS of any pulse widths that might arrive at any time.
So something that allows me to catch a pulse width of between 10 mS - 500 mS without hogging the entire processor for the duration of that pulse, count each pulse once only and then be ready for another pulse almost immediately after the preceeding pulse finishes.
Which the above code does manage, if not very elegantly.
The code is a lot easier. Look at the demos: C:\GCB@Syn\GreatCowBasic\Demos\vendor_boards\microchip_low_pin_count_demo_board\pickit2_board\16f1825\13_eeprom.gcb
This demo has a switch on a.3. Same chip also.
Thanks, I'll check that out next week.
I looked at the 'Help' but found it rather confusing. I never thought of looking at the examples after not finding much in the 'Help'.
I appreciate your reply and will report back once I've had another look.
Inspired by the example from the demos folder pointed out by Anobium, I have adjusted my program for the 16F1825. I couldn't get the Interrupt on Change example from the demos folder to work well for me. This seemed to fire the interrupt when the 'millis' function changed the LED state, and sometimes when the timer overflowed within the 'millis' function too. Whilst the interrupt still worked, the button needed to be pressed very firmly, and for at least 500mS. As I was hoping to capture short(ish) pulses in my final version this was a retrograde step.
I then looked at the example and wondered where the definitions for the interrupt constants were listed. I opened up the 16F1825.dat file and lo and behold, there they were.
Taking the defined constants as opposed to reading the entire contents of the INTCON register and the OPTION_REG regiter, setting the relevant bits and then writing them back to the PIC has tidied up the code by some measure. I also took the time to swap the interrupt from a rising to a falling edge to detect button presses and releases to ensure each button press is registered only once.
The changes have sped the detection of the button press then release quite significantly, keeping the button pressed and then held does not slow the operation of the program down either.
Whilst I'm not confident in using interrupts, I'm vastly less reluctant to use them now!
Here is the new and improved version:
I removed all the code that was not needed show below.
A few points.
1. Not sure what millis_one.h is but I may be out of the loop with version of millis.h posted.
2. Let INTF = 0 'Clear interrupt. This may be needed initially but the interrupt service handler built in with Great Cow BASIC will clear INF for you. Try removing from your interrupt handler to verify the clear is happening (I can see it in the ASM but do check yourselve).
Looks very good! A demo in the making!!
Thanks for your suggestions.
I have removed the "Let INTF = 0 'Clear interrupt" statement as suggested. I hadn't realised the interrupt was cleared by GCB automatically. Is that cleared when exiting the interrupt handling sub routine?
I have also removed the references to 'Millis_Zero.h' and have re-incorporated the original 'millis.h'. I had been experimenting with setting the value returned by the millis() funtion to zero when the processor is first started. 'Millis_Zero.h' was a modified version of the original. I have moved the command that resets milis() to zero into my code, leaving the original unmodified.
Yes, the Great Cow BASIC does clear the interrupt flags it handles. So, if INTE is enabled via the On Interrupt then the related INTF is cleared upon exit.
Good to read about the tidy up - when you are good and ready it would be very good to publish as a demonstration.
:-)
Last edit: mkstevo 2019-01-12