-
Beginner in need of help !!
Hi everyone, I am completely new to both these forums & pic programming. I am working with the 12f683 which I have managed to flash led 's read potentiometers etc, very basic stuff.
Now to my question. I want to turn an LED on/off with a single tap of a tactile button. So press & release button: led turns on, then repeat to turn led off.
I knio how to turn an LED on/off by holding the button for on & releasing for off, but I can't work out how to do the above.
Any help would be greatly appreciated, I intend to over come any hiccups, not give up.
Thanks,
Rob
-
Re: Beginner in need of help !!
Not sure how much help you need. I'm assuming you know input/ output, high/ low...
Google "Pull down switch" and see how the level goes from high to low when the button is pressed (there is a pull up as well); use standard input technique to read the level change when the switch is pressed. To control the LED output, I think an if/ then will work well:
If Button press = 0 and LED = off then [turn on LED]
If Button press = 0 and LED = on then [turn off LED]
You should also look at "debounce" as there is some issue to mechanical switches.
Also, without some programming to limit the speed, the switch will turn the LED on/ off very quickly. A pause will work (to give the user time to release the button) or, you can look for a "1" on the switch (released) before allowing another button press to register.
HTH,
-
Re: Beginner in need of help !!
Hi Rob,
Welcome to the forum! As you can imaging there are several ways to do this (and most other things). Amoque shows you one, here's another (which also tries to take care of the debounce):
Code:
LED VAR GPIO.0
Switch VAR GPIO.1
ANSEL = 0 ' No analog inputs
CMCON = 7 ' Comparators disabled
TRISIO = %11111110 ' GPIO.0 as output
Main:
IF Switch = 1 THEN ' If the button is pressed...
TOGGLE LED ' ...we toggle the LED.
Pause 20 ' Then we wait for contact bounce on make to die, may need tweaking
WHILE Switch = 1 : WEND ' Then we wait for the user to actually release the button
Pause 20 ' Finally we wait for contact bounce on release to die, may need tweaking
ENDIF
Goto Main
/Henrik.
-
Re: Beginner in need of help !!
Hi Guys, thanks for the help. I will go away & have a play with your examples :)
Thanks again,
Rob
-
Re: Beginner in need of help !!
Quote:
Originally Posted by
HenrikOlsson
Hi Rob,
Welcome to the forum! As you can imaging there are several ways to do this (and most other things). Amoque shows you one, here's another (which also tries to take care of the debounce):
Code:
LED VAR GPIO.0
Switch VAR GPIO.1
ANSEL = 0 ' No analog inputs
CMCON = 7 ' Comparators disabled
TRISIO = %11111110 ' GPIO.0 as output
Main:
IF Switch = 1 THEN ' If the button is pressed...
TOGGLE LED ' ...we toggle the LED.
Pause 20 ' Then we wait for contact bounce on make to die, may need tweaking
WHILE Switch = 1 : WEND ' Then we wait for the user to actually release the button
Pause 20 ' Finally we wait for contact bounce on release to die, may need tweaking
ENDIF
Goto Main
/Henrik.
Thanks for this Henrik, I found this the best way. Another question, what if I wanted to run a different command to just turning on the LED, what about if I wanted to start the LED flashing upon button tap? Could I do this with the same method?
Thanks,
Rob
-
Re: Beginner in need of help !!
Hi,
> what if I wanted to run a different command to just turning on the LED
Don't understand this one, sorry...
> what about if I wanted to start the LED flashing upon button tap?
Well, yes. But as soon as you mention blinking it starts to get a Little bit more complicated. Why?
Because then you need delays in there, during which (if using PAUSE) the button won't be polled so it'll feel unresponsive. Of course there are ways around this but the correct one depends on what you want to do after we get that LED to blink....
Try this (I haven't, hope it works....):
Code:
LEDState VAR BYTE
Time VAR WORD
LED_OFF CON 0
LED_ON CON 1
LED_FLASH CON 2
Rate CON 250 ' Time between LED toggles when blinking
Main:
IF Switch = 1 THEN ' If the button is pressed...
LEDState = LEDState + 1
IF LEDState = 3 THEN LEDState = 0
Pause 20 ' Then we wait for contact bounce on make to die, may need tweaking
WHILE Switch = 1 : WEND ' Then we wait for the user to actually release the button
Pause 20 ' Finally we wait for contact bounce on release to die, may need tweaking
ENDIF
IF (LEDState = LED_OFF) or (LEDState = LED_ON) THEN
LED = LEDState ' Turn LED on or off, solid.
ENDIF
IF LEDState = LED_FLASH THEN
Time = Time + 1
IF Time = Rate THEN
TOGGLE LED
Time = 0
ENDIF
PAUSEUS 1000
ENDIF
Goto Main
/Henrik.
-
Re: Beginner in need of help !!
Hi again, I have been trying to play around with interrupts, both instant asm (which barely makes any sense to me) & basic 'on interrupt'.
I have wrote a very basic code, however what I cant get my head around is how to incorporate the button method we discussed before into an interrupt? So how can one push & release of the button enter an interrupt loop & wait there, until I push & release the button again which would exit back to the main loop? Here is the small code I have written.
Thanks again,
Rob
Code:
ANSEL = 0 'digital I/O
CMCON0 = 7 'comparator off
INTCON = %00010000 'enable pin 4 interrupt
TRISIO = %00010000 'pin 4 input
LED VAR GPIO.0 'pin 7 led
Switch VAR GPIO.4 'pin 3 button
ON INTERRUPT GOTO int1
main:
HIGH LED
PAUSE 500
LOW LED
PAUSE 500
GOTO main
DISABLE
int1:
TOGGLE LED
INTCON.1 = 0
RESUME
ENABLE
-
Re: Beginner in need of help !!
Hi Rob,
If you want the button to enable/disable the blining LED then you can't toggle the LED itself in the interrupt and then just continue to blink it in the main program loop. What you need is flag or semaphore telling the main loop if the LED is supposed to blink or not.
Code:
BLINK VAR BIT
ON INTERRUPT GOTO int1
main:
If Blink = 1 THEN
HIGH LED
PAUSE 500
LOW LED
PAUSE 500
ENDIF
GOTO main
DISABLE
int1:
Blink = !Blink ' Invert the state of the semapore
RESUME
ENABLE
Please note that the PAUSE statement is basically delaying the Int1 routine from executing until the PAUSE statement finishes (that's the drawback of ON INTERRUPT). So if you push the button just as the PAUSE 500 start to exectute the ISR won't execute until 500ms later. This won't matter in this case but please keep that in mind when you start doing more complicated stuff.
Also, the above does not incorporate any debounce, you may want to add that.
/Henrik.
-
Re: Beginner in need of help !!
Hi Henrik, thanks for explaing that to me it will help me a lot :) I am learning more & more as I go on :D
Rob
Quote:
Originally Posted by
HenrikOlsson
Hi Rob,
If you want the button to enable/disable the blining LED then you can't toggle the LED itself in the interrupt and then just continue to blink it in the main program loop. What you need is flag or semaphore telling the main loop if the LED is supposed to blink or not.
Code:
BLINK VAR BIT
ON INTERRUPT GOTO int1
main:
If Blink = 1 THEN
HIGH LED
PAUSE 500
LOW LED
PAUSE 500
ENDIF
GOTO main
DISABLE
int1:
Blink = !Blink ' Invert the state of the semapore
RESUME
ENABLE
Please note that the PAUSE statement is basically delaying the Int1 routine from executing until the PAUSE statement finishes (that's the drawback of ON INTERRUPT). So if you push the button just as the PAUSE 500 start to exectute the ISR won't execute until 500ms later. This won't matter in this case but please keep that in mind when you start doing more complicated stuff.
Also, the above does not incorporate any debounce, you may want to add that.
/Henrik.
-
Re: Beginner in need of help !!
Hi, please can someone tell me how I disable MCLR on gp3 (my pic is 12f683). Ive been researching for the past 2 hours & I have got no closer to disabling it, I just want GP3 as a normal input pin, not this MCLR crap!
If anyone knows could you please help?
Rob
-
Re: Beginner in need of help !!
Hi,
MCLR is disabled by clearing the correct "fuse" in the CONFIG word. With PBP3 you set the CONFIG word(s) with the #CONFIG/#ENDCONFIG compiler directives (more on that in the manual). Your PBP3 installation folder has a subfolder named DEVICE_REFERENCES in which you'll find a file for each and every device the compiler supports. The file contains information about the various CONFIG options and also what defaults PBP uses if you don't include any in your code.
For a 12F683 the defaults are:
Code:
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_ON & _CP_OFF
#ENDCONFIG
If you want to disable MCLR and keep everything else then copy/paste this into your program:
Code:
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_OFF & _CP_OFF
#ENDCONFIG
/Henrik.
-
Re: Beginner in need of help !!
Quote:
Originally Posted by
HenrikOlsson
Hi,
MCLR is disabled by clearing the correct "fuse" in the CONFIG word. With PBP3 you set the CONFIG word(s) with the #CONFIG/#ENDCONFIG compiler directives (more on that in the manual). Your PBP3 installation folder has a subfolder named DEVICE_REFERENCES in which you'll find a file for each and every device the compiler supports. The file contains information about the various CONFIG options and also what defaults PBP uses if you don't include any in your code.
For a 12F683 the defaults are:
Code:
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_ON & _CP_OFF
#ENDCONFIG
If you want to disable MCLR and keep everything else then copy/paste this into your program:
Code:
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_OFF & _CP_OFF
#ENDCONFIG
/Henrik.
Your a life saver mate. I knew I had to write to the config but I just could not find out which way to do it, I was nearly there I was putting @config instead though!
Thanks again,
Rob
-
Re: Beginner in need of help !!
Quote:
Originally Posted by
HenrikOlsson
Hi,
MCLR is disabled by clearing the correct "fuse" in the CONFIG word. With PBP3 you set the CONFIG word(s) with the #CONFIG/#ENDCONFIG compiler directives (more on that in the manual). Your PBP3 installation folder has a subfolder named DEVICE_REFERENCES in which you'll find a file for each and every device the compiler supports. The file contains information about the various CONFIG options and also what defaults PBP uses if you don't include any in your code.
For a 12F683 the defaults are:
Code:
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_ON & _CP_OFF
#ENDCONFIG
If you want to disable MCLR and keep everything else then copy/paste this into your program:
Code:
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_OFF & _CP_OFF
#ENDCONFIG
/Henrik.
Hi Henrik, I am going to start my first project which will hopefully teach me new things along the way. I have question for you before I start though, I am hoping you can give a short answer to this.
Basically I want different modes (say 10) which are each cycled through via a tap of a tactile button (so mode 1, tap button, mode 2, tap, mode 3, etc) & each mode has its own led flashing at a different speed.
My question is, which way is the best to do this? With interrupts or something else? I would also like the chip to watch for other button presses as well not just this one sequence of modes, so its not going to be just a simple sequnce of button tap to next mode etc.
So I need a way of watching for multiple input changes all the time, I am expecting interrupts to be the answer after reading about, but just want to be sure :)
Hope you can help,
Rob
-
Re: Beginner in need of help !!
Hi Rob,
There are several ways - as is the case most of the time.
Interrupts are probably the way to go but there may be other ways.
Do you have a particular chip in mind, is it still the 12F683? I think not since you mention 10 modes, each with its own LED.....
How many switches do you need to monitor?
/Henrik.
-
Re: Beginner in need of help !!
Hi Henrik, I will still be using the pic12f683. This is just a starter project which I am hoping to take to something bigger, but I will be flashing 1 led, the 10 modes are all outputting to the one led. I would like to sense 2 inputs, 1 tactile button & 1 using adc to mintor coltage change.
Thanks,
Rob
-
Re: Beginner in need of help !!
My last post messed up a bit at the end, it was supposed to be monitor voltage lol. Anyway given the things I would like, do you think interrupts are the best route? I would end up adding more outputs to this (in the end 4 outputs, 2 inputs).
Thanks again,
Rob
-
Re: Beginner in need of help !!
Ive decided to go the interrupt route... I am stuck already. Here is my simple code, why isnt my interrupt working?
Code:
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_OFF & _CP_OFF
#ENDCONFIG
DEFINE OCS 4 '4mhz ocsillator
ANSEL = 0 'all I/O digital
CMCON0 = 7 'comparator off
LED VAR GPIO.0 'LED pin 7
LED2 VAR GPIO.1 'LED2 pin 6
ON INTERRUPT GOTO mode1 'interrupt handler is mode1
INTCON = %10001000 'enable gp3 interrupt
main:
ENABLE
HIGH LED 'led on
PAUSE 500 'delay 0.5 second
LOW LED 'led off
PAUSE 500 'delay 0.5 second
GOTO main 'repeat
DISABLE 'disable interrupts in handler
mode1:
HIGH LED2 'led2 on
PAUSE 50
LOW led2 'led2 off
PAUSE 50
RESUME 'return to where left off
ENABLE 'enable interrupts
-
Re: Beginner in need of help !!
Normally in the interrupt routine this is needed.
INTCON.1 = 0
But the data sheet for this chip reads like this is needed.
INTCON.0 = 0
Then at the beginning of your code below
INTCON = %10001000
add
IOC.3=1
I think...
-
Re: Beginner in need of help !!
Quote:
Originally Posted by
mackrackit
Normally in the interrupt routine this is needed.
INTCON.1 = 0
But the data sheet for this chip reads like this is needed.
INTCON.0 = 0
Then at the beginning of your code below
INTCON = %10001000
add
IOC.3=1
I think...
Brilliant, that got it working. I take it IOC.3 = 1 tells the chip when to interrupt & on what pin?
So INTCON = %10001000 tells it to enable interrupts on pin 3 & IOC.3 = 1 tells it to interrupt on pin 3 change ?
Thanks for your help,
Rob
-
Re: Beginner in need of help !!
This should work for you. It works in my simulator.
Also, since PBP's ON INTERRUPT only checks to see if an interrupt has occurred between PBP commands, you may want to use a loop counter in your main routine and use short pauses. This is how I revised your code.
Comments are added to the code below.
Good Luck.
Code:
'PIC 12F683
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_OFF & _CP_OFF
#ENDCONFIG
'DEFINE OCS 4 '4mhz ocsillator
DEFINE OSC 4 '4mhz ocsillator
ANSEL = 0 'all I/O digital
CMCON0 = 7 'comparator off
LED VAR GPIO.0 'LED pin 7
LED2 VAR GPIO.1 'LED2 pin 6
loop1 var byte ' Loop 1 Counter
ON INTERRUPT GOTO mode1 'interrupt handler is mode1
INTCON = %10001000 'enable GIE and GPIE; clear GPIF
IOC = %00001000 ' enable IOC3 (GPIO3 Interrupt on change)
ENABLE
main:
do
for loop1 = 1 to 50
HIGH LED 'led on
'PAUSE 500 'delay 0.5 second
pause 10 '10 ms
next loop1
for loop1 = 1 to 50
LOW LED 'led off
'PAUSE 500 'delay 0.5 second
pause 10 '10 ms
next loop1
'GOTO main 'repeat
loop
DISABLE 'disable interrupts in handler
mode1:
if INTCON.0 = 1 then 'one of the GPIO<5:0> pins changed state (must be cleared in software)
HIGH LED2 'led2 on
PAUSE 50
LOW led2 'led2 off
PAUSE 50
endif
INTCON = %10001000 'enable GIE and GPIE; clear GPIF
RESUME 'return to where left off
ENABLE 'enable interrupts
end 'got here by mistake
-
Re: Beginner in need of help !!
Quote:
Originally Posted by
Tabsoft
This should work for you. It works in my simulator.
Also, since PBP's ON INTERRUPT only checks to see if an interrupt has occurred between PBP commands, you may want to use a loop counter in your main routine and use short pauses. This is how I revised your code.
Comments are added to the code below.
Good Luck.
Code:
'PIC 12F683
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_OFF & _CP_OFF
#ENDCONFIG
'DEFINE OCS 4 '4mhz ocsillator
DEFINE OSC 4 '4mhz ocsillator
ANSEL = 0 'all I/O digital
CMCON0 = 7 'comparator off
LED VAR GPIO.0 'LED pin 7
LED2 VAR GPIO.1 'LED2 pin 6
loop1 var byte ' Loop 1 Counter
ON INTERRUPT GOTO mode1 'interrupt handler is mode1
INTCON = %10001000 'enable GIE and GPIE; clear GPIF
IOC = %00001000 ' enable IOC3 (GPIO3 Interrupt on change)
ENABLE
main:
do
for loop1 = 1 to 50
HIGH LED 'led on
'PAUSE 500 'delay 0.5 second
pause 10 '10 ms
next loop1
for loop1 = 1 to 50
LOW LED 'led off
'PAUSE 500 'delay 0.5 second
pause 10 '10 ms
next loop1
'GOTO main 'repeat
loop
DISABLE 'disable interrupts in handler
mode1:
if INTCON.0 = 1 then 'one of the GPIO<5:0> pins changed state (must be cleared in software)
HIGH LED2 'led2 on
PAUSE 50
LOW led2 'led2 off
PAUSE 50
endif
INTCON = %10001000 'enable GIE and GPIE; clear GPIF
RESUME 'return to where left off
ENABLE 'enable interrupts
end 'got here by mistake
Hi Tabsoft, that worked perfectly. I can see what you mean by using loops instead of pauses, the interrupt is much more reactive.
Now I just need to know how to stay in that interrupt routine until I tap the button again.
Thanks,
Rob
-
Re: Beginner in need of help !!
Hi Rob,
Quote:
Now I just need to know how to stay in that interrupt routine until I tap the button again.
Even though that would work for this particular application that's generally not what you want to do (ie stay in the interrupt routine). Instead you do as I showed earlier, use a flag/semaphore in the interrupt service routine which the main code reads and determines what to do.
The same thing applies to your scenario with ten states. You have a variable which you increment in the interrupt (ie once very time you press the button), once it gets to 10 you reset it to zero. Then, in the main program loop you simply check the value of this variable and act accordingly. With a bit of thought and some math you might even USE the variables value directly as the delay in your loop to blink the LED.
As for the analog input it's important to understand that there is no mechanism to automatically run the ADC and detect (ie interrupt) when the voltage at the input changes. You need to write code to sample the input once every minute, second, millisecond or whatever the requirement may be.
Finally, please don't quote the full message just posted. There's really no need to have the very latest post quoted in full.
/Henrik.
-
Re: Beginner in need of help !!
Rob,
Glad it worked for you.
I'm not sure if you want/need to stay in the ISR as I don't know your final objective.
I would suggest using a flag to determine the state of the IOC.3 interrupt coming from your button.
Then in the ISR change the state of the flag each time the interrupt occurs and then get out of the ISR.
You can then setup a subroutine for what you wanted to accomplish in the ISR.
Finally in your main loop check the state of the flag and gosub to the new subroutine.
Here is a working example. Expanded on what I posted last time.
Code:
'PIC 12F683
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_OFF & _CP_OFF
#ENDCONFIG
'DEFINE OCS 4 '4mhz ocsillator
DEFINE OSC 4 '4mhz ocsillator
ANSEL = 0 'all I/O digital
CMCON0 = 7 'comparator off
LED VAR GPIO.0 'LED pin 7
LED2 VAR GPIO.1 'LED2 pin 6
loop1 var word ' Loop 1 Counter (word for 0 to 65535 increments)
loop2 var byte ' Loop 2 Counter (byte used for 0 to 255 increments)
ModeFlag var bit ' Bit to determine what state of IOC.3 is
'*****Initlaze Vars*****
loop1 = 0
loop2 = 0
ModeFlag = 0
'***********************
ON INTERRUPT GOTO mode1 'interrupt handler is mode1
INTCON = %10001000 'enable GIE and GPIE; clear GPIF
IOC = %00001000 ' enable IOC3 (GPIO3 Interrupt on change)
ENABLE
main:
do
for loop1 = 1 to 500
HIGH LED 'led on
'PAUSE 500 'delay 0.5 second
pause 1 '1 ms
if ModeFlag = 1 then
gosub moderoutine
endif
next loop1
for loop1 = 1 to 500
LOW LED 'led off
'PAUSE 500 'delay 0.5 second
pause 1 '1 ms
if ModeFlag = 1 then
gosub moderoutine
endif
next loop1
'GOTO main 'repeat
loop
moderoutine:
do while ModeFlag = 1
high LED2 'LED2 On
for loop2 = 0 to 50
pause 1 '1ms
next loop2
low LED2 'LED2 Off
for loop2 = 0 to 50
pause 1 '1ms
next loop2
loop
return
DISABLE 'disable interrupts in handler
mode1:
if INTCON.0 = 1 then 'one of the GPIO<5:0> pins changed state (must be cleared in software)
'HIGH LED2 'led2 on
'PAUSE 50
'LOW led2 'led2 off
'PAUSE 50
'Set the ModeFlag
ModeFlag = ~ ModeFlag
endif
INTCON = %10001000 'enable GIE and GPIE; clear GPIF
RESUME 'return to where left off
ENABLE 'enable interrupts
end 'got here by mistake
-
Re: Beginner in need of help !!
Thanks a lot for the help guys, I appreciate it :) I understand now how isr's work now.
Thanks,
Rob
-
Re: Beginner in need of help !!
Hi,
Another aproach is to use the interrupt mechanism as a way to "latch" the buttonpress but then not actually enable the interrupt itself but instead poll the interrupt flag to determine if the button was pressed.
Code:
State VAR BYTE
Main:
If INTCON.1 = 1 THEN ' GP2 input interrupt
INTCON.1 = 0 ' Clear flag
State = State + 1
If State = 3 THEN State = 0
ENDIF
SELECT CASE State
Case 0
HIGH LED
PAUSE 50
LOW LED
PAUSE 50
CASE 1
HIGH LED
PAUSE 100
LOW LED
PAUSE 100
CASE 2
HIGH LED
PAUSE 150
LOW LED
PAUSE 150
GOTO MAIN
-
Re: Beginner in need of help !!
Hi, I like that way as well. Although at some point I need to add a nap command with wdt off so it wakes when a voltage is higher than 0.60v & naps when voltage is less then, so I would have to use an interupt anyway at some point?
Thanks,
Rob
-
Re: Beginner in need of help !!
Right I have changed the code from what Tabsoft last posted, so now there are 3 modes each blinking led at a different rate depending on the mode. Every tap of the button is supposed to goto the next mode.
Something weird is happening though, each tap of the button is reversing the mode lol. So instead of going forwards to the next mode, its going backwards (should go mode 1 > mode 2, but is going Mode 1 > mode 3 > mode 2).
Any ideas? here is the code -
Code:
'PIC 12F683
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_OFF & _CP_OFF
#ENDCONFIG
'DEFINE OCS 4 '4mhz ocsillator
DEFINE OSC 4 '4mhz ocsillator
ANSEL = 0 'all I/O digital
CMCON0 = 7 'comparator off
LED VAR GPIO.0 'LED pin 7
loop1 var word ' Loop 1 Counter (word for 0 to 65535 increments)
ModeFlag var bit ' Bit to determine what state of IOC.3 is
'*****Initlaze Vars*****
loop1 = 0
ModeFlag = 0
'***********************
ON INTERRUPT GOTO modeselect 'interrupt handler is modeselect
INTCON = %10001000 'enable GIE and GPIE; clear GPIF
IOC = %00001000 ' enable IOC3 (GPIO3 Interrupt on change)
ENABLE
mode1:
do
for loop1 = 1 to 1000
HIGH LED 'led on
'PAUSE 1000 'delay 1 second
pause 1 '1 ms
if ModeFlag = 1 then
gosub mode2
endif
next loop1
for loop1 = 1 to 1000
LOW LED 'led off
'PAUSE 1000 'delay 1 second
pause 1 '1 ms
if ModeFlag = 1 then
gosub mode2
endif
next loop1
'GOTO mode1 'repeat
loop
ENABLE
mode2:
do
for loop1 = 1 to 500
HIGH LED 'led on
'PAUSE 500 'delay 0.5 second
pause 1 '1 ms
if ModeFlag = 1 then
gosub mode3
endif
next loop1
for loop1 = 1 to 500
LOW LED 'led off
'PAUSE 500 'delay 0.5 second
pause 1 '1 ms
if ModeFlag = 1 then
gosub mode3
endif
next loop1
'GOTO mode2 'repeat
loop
ENABLE
mode3:
DO
for loop1 = 1 to 50
HIGH LED 'led on
'PAUSE 50 'delay 0.05 second
pause 1 '1 ms
if ModeFlag = 1 then
gosub mode1
endif
next loop1
for loop1 = 1 to 50
LOW LED 'led off
'PAUSE 50 'delay 0.05 second
pause 1 '1 ms
if ModeFlag = 1 then
gosub mode1
endif
next loop1
'GOTO mode3 'repeat
loop
DISABLE 'disable interrupts in handler
modeselect:
if INTCON.0 = 1 then 'one of the GPIO<5:0> pins changed state (must be cleared in software)
'next mode
'Set the ModeFlag
ModeFlag = ~ ModeFlag
endif
INTCON = %10001000 'enable GIE and GPIE; clear GPIF
RESUME 'return to where left off
ENABLE 'enable interrupts
end 'got here by mistake
-
Re: Beginner in need of help !!
UPDATE: I've just worked it out I think, its because I haven't got any debounce in there so every 'tap' could be jumping a couple of modes instead of seeing it as 1 button tap & jumping 1 mode.
Where do I actually add the debounce though? I couldn't add it into the sub modes as it would wreck the routine timing wouldn't it?
-
Re: Beginner in need of help !!
Hi,
No debounce may very well be part of the problem but in THIS case I think the contact bounce is what actually makes it sort of "work".
The real issue, I believe, is that your "loops" looks for ModeFlag being equal to 1 and switches mode. But the flag is not being cleared. So, if you push the button once, the ISR sets the flag. If there are no bounce the flag will be set all the time and the program will keep cycling between the different modes since the flag is never cleared. That's a problem with the implementation.
What's more severe is that you're using GOSUB without a matching RETURN. What you want in this case is GOTO.
Make the ISR set (and only set) the ModeFlag, implement some debounce in the ISR.
In the main loop you check the ModeFlag and IF it's set you first clear it and then act accordingly (ie. jump to the next mode).
Also, there's no need to set the LED high or low 1000 times (ie do it inside the FOR_NEXT loop), one time is enough, I'd rewrite the loop like:
Code:
DO
HIGH LED
for loop1 = 1 to 1000
pause 1 '1 ms
IF ModeFlag = 1 THEN
ModeFlag = 0
GOTO Mode 2
ENDIF
next loop1
LOW LED 'led off
for loop1 = 1 to 1000
pause 1 '1 ms
IF ModeFlag = 1 THEN
ModeFlag = 0
GOTO Mode 2
ENDIF
next loop1
LOOP
/Henrik.
-
Re: Beginner in need of help !!
Hi Henrik, thanks for helping. I have changed to the code to do as you said: goto's instead of gosub's & made the ISR set flag only (i think).
It all seems to work better now, however I still have a problem with the debounce as I think it is actually 'the problem' now instead of actually making the code work as you stated. The isr sees the release of the button as an interrupt & sets a flag again which skips modes. So how do I go about adding the debounce without slowing things down?
Isnt there a way to only interrupt or tell the ISR to flag only if the button is depressed & not when released? Here is the updated code -
Code:
'PIC 12F683
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_OFF & _CP_OFF
#ENDCONFIG
'DEFINE OCS 4 '4mhz ocsillator
DEFINE OSC 4 '4mhz ocsillator
ANSEL = 0 'all I/O digital
CMCON0 = 7 'comparator off
LED VAR GPIO.0 'LED pin 7
loop1 var word ' Loop 1 Counter (word for 0 to 65535 increments)
ModeFlag var bit ' Bit to determine what state of IOC.3 is
'*****Initlaze Vars*****
loop1 = 0
ModeFlag = 0
'***********************
ON INTERRUPT GOTO modeselect 'interrupt handler is modeselect
INTCON = %10001000 'enable GIE and GPIE; clear GPIF
IOC = %00001000 ' enable IOC3 (GPIO3 Interrupt on change)
ENABLE
mode1:
do
for loop1 = 1 to 1000
HIGH LED 'led on
'PAUSE 1000 'delay 1 second
pause 1 '1 ms
if ModeFlag = 1 then
ModeFlag = 0
goTO mode2
ENDIF
next loop1
for loop1 = 1 to 1000
LOW LED 'led off
'PAUSE 1000 'delay 1 second
pause 1 '1 ms
if ModeFlag = 1 then
Modeflag = 0
goTO mode2
endif
next loop1
'GOTO mode1 'repeat
loop
ENABLE
mode2:
do
for loop1 = 1 to 500
HIGH LED 'led on
'PAUSE 500 'delay 0.5 second
pause 1 '1 ms
if ModeFlag = 1 then
modeflag = 0
goTO mode3
endif
next loop1
for loop1 = 1 to 500
LOW LED 'led off
'PAUSE 500 'delay 0.5 second
pause 1 '1 ms
if ModeFlag = 1 then
modeflag = 0
goTO mode3
endif
next loop1
'GOTO mode2 'repeat
loop
ENABLE
mode3:
DO
for loop1 = 1 to 50
HIGH LED 'led on
'PAUSE 50 'delay 0.05 second
pause 1 '1 ms
if ModeFlag = 1 then
modeflag = 0
goTO mode1
endif
next loop1
for loop1 = 1 to 50
LOW LED 'led off
'PAUSE 50 'delay 0.05 second
pause 1 '1 ms
if ModeFlag = 1 then
modeflag = 0
goTO mode1
endif
next loop1
'GOTO mode3 'repeat
loop
DISABLE 'disable interrupts in handler
modeselect:
if INTCON.0 = 1 then 'one of the GPIO<5:0> pins changed state (must be cleared in software)
'next mode
'Set the ModeFlag
ModeFlag = 1
ENDIF
INTCON = %10001000 'enable GIE and GPIE; clear GPIF
RESUME 'return to where left off
ENABLE 'enable interrupts
end 'got here by mistake
-
Re: Beginner in need of help !!
Hi,
You're quite right, it's because you're using the IOC (Interrupt On Change), it'll trip the interrupt both when you push the button and when you release the button. (As well as on all the edges of the contact bounce). Also, when you're using IOC you need to remember to read the port (even if you're not using the value) in order to clear the mismatch condition.
I'd wire the button to GP2 and use the "normal" INT instead of IOC.
/Henrik.
-
Re: Beginner in need of help !!
So if I want to use IOC, I would need to read the button or any other type of input such as the adc?
I'm only asking as I need to be able to use interrupt on like 5 inputs, not just 1. Although gp2 will use adc not any others if that would be easier.
Thanks,
Rob
-
Re: Beginner in need of help !!
Hi Rob,
The IOC trips the interrupt on any change of the state on a digital pin. An interrupt will trip when the pin goes low and again when the pin goes high - provided you read the state of the pin in between. So in the ISR you need to read the state of switch and determine if it was pushed or released (and don't forget about the contact bounce). If it's determined that the interrupt tripped because the button was released you don't set the MODEFLAG.
And, once again, the ADC can NOT generate an interrupt when the analog voltage on the input changes. It won't work with IOC. Any pin configured as analog input will always read '1' and will never trip the IOC or INT interrupts.
Depending on what you want to do you might be able to use the comparator, they can be setup to trip an interrupt when their respective output changes state.
/Henrik.
-
Re: Beginner in need of help !!
Hi Henrik, thanks for explaining that it makes things a lot clearer as to how I'm going to run the code. What I would like to do is have one of the inputs (gp2), taking a reading from ADC every say 0.5 - 1 seconds.
Basically I want the chip to enter low power mode along with the device. When the device is off, one of the component pins goes to 0.00v, then when it is turned on it goes to 0.70v & stays at that. So I would like the ADC to monitor this, then when the voltage drops below 0.60v the chip is in low power mode, then when the voltage is higher than 0.60v I want it to come out of low power mode.
I hope this can be done in some way,
Rob
-
Re: Beginner in need of help !!
Rob,
I don't think the ADC module will accomplish what you are attempting as Henrik stated in his last reply.
You should look into the Comparator of the PIC, again as Henrik suggested.
:D
-
Re: Beginner in need of help !!
You can use the ADC to sample the voltage but the PIC needs to be awake for the ADC to operate and, again, the ADC doesn't run continously and can not automatically generate an interrupt when a given voltage or threshold is detected. You'd need to wake the PIC up every now and then, sample thevoltage at the pin and based on that determine if you should stay awake or go back to sleep. No problems doing that but to me it looks like you'll be better served by using comparator module. Using that you can put the PIC to sleep and it will automatically wake up when the comparator output flips.
/Henrik.
-
Re: Beginner in need of help !!
Oh I see, yes it sounds like the comparator will be the best then. Anyway thanks for your help guys, I have learned a lot.
I will be back lol
Rob
-
Re: Beginner in need of help !!
Back again already, Comparators are mind boggling !!
Firstly I have no idea how to even set the mode of the comparator, let alone working out & setting the VRC. I have been researching all day, the only info that looks helpful is in C so it is all gobbledygook to me as I have only just started learning basic.
I am not looking for someone to spoon feed me a code, I just want to be able to understand it for myself. What does this mean from the data sheet CM<2:0> = 011? How do you get CMCON0 = 2 from that? If I could understand the data sheet enough to put it into basic then it would help me a lot.
Just being able to turn on an LED when the voltage goes under 1.00v using a pot would be a massive accomplishment for me at the moment, as I could understand how it all works.
Any help on this would be great.
Thanks,
Rob
-
Re: Beginner in need of help !!
Quote:
What does this mean from the data sheet CM<2:0> = 011?
It means bits 2 , 1, 0 are set 011
very common nomenclature to use the colon to be inclusive of all the bits in between 2:0
-
Re: Beginner in need of help !!
Rob,
Yes Comparators can be confusing the 1st time using them on the PIC MCU.
First, have a read through this link.
http://www.cuteminds.com/index.php/e...23-comparators
It explains simply how the comparator
on the PIC12F683 can be used. Ignore the C language stuff, but pay attention
to the setup of the Comparator, especially the Second Case.
This case describes what you will probably implement.
This will give you the info on how the Comparator will work by polling the
Comparator output, NOT USING INTERRUPTS.
Once you have this digested, then you can move on to the Interrupt portion.
Use the equation for VRR=1 (Low Range): (VR3:VR0/24) x Vdd to set the "Threshold Voltage"
E.g.
Vdd = +5Vdc
VR3:VR0 = 5 (%1001)
Putting this into the equation above gives this CVref "Threshold voltage"
(5/24) x 5 = 1.042 Vdc
This will be the reference voltage that will be used to compare the input voltage to.
General Rules when using the Comparator:
1. Set the appropriate pins to analog for the Comparator with ANSEL
2. Set the direction of the pins appropriately with TRISIO
3. Configure the Compare Module using CMCON0
4. Configure the reference voltage using VRCON
To use the comparator, poll the value of the status bit in CMCON0.
See if this gets you started.
Regards,