PDA

View Full Version : 16f84a running interrupt PICBASIC code



divaker
- 22nd July 2008, 04:09
Please see the attached code.

It has two parts, one to vary the content of a variable using a single button and second an interrupt run to output RB0 based on the variable content.

When it is simed on MPLAB, it is quite OK. But when it is run on the chip, it does not work.
(with WDT switched off)
However the two parts when compiled as separate files to check the code, they function well on the chip.

Please help me solve the prob

Thanks

Archangel
- 22nd July 2008, 06:07
You post your code in PDF format, and the only way anyone can test it is to retype it all over, no thanks.

savnik
- 22nd July 2008, 08:56
You post your code in PDF format, and the only way anyone can test it is to retype it all over, no thanks.
I post the code from PDF.




'16f84a

Symbol OUT_PIN = PORTB.0 ' Output to solenoid RB0
Symbol LED = PORTB.1 ' Control button to RB1
Symbol CNTL_BUTTON = PORTB.7 ' Control button to RB7

spacing var byte
temp var byte

TRISA = $FF
TRISB = $FC ' RB0 and RB1 outputs, others input
spacing = 15
LED = 0
temp = 1

gosub wait_button

LED = 1
pause 2000 ' Wait for two seconds
if CNTL_BUTTON = 1 then spacing = 30: goto direct ' If button is released before 2 secs
' code goes directly into the default spacing
temp = 0
gosub wait_button ' If button is pressed more than 2 secs,
' it gets caught here and waits for release
LED = 0
pause 1000 ' Wait for 100 ms

repeata:
spacing = spacing + 5 ' Increase the spacing count by 2 every time
toggle LED
pause 1000
toggle LED
if spacing = 45 then spacing = 20 ' Till it reaches maximum and reset to minimum
temp = 1
gosub wait_button ' Access the push button state and repeat if short press
pause 2000 ' Delay for 2 seconds
if CNTL_BUTTON = 1 then goto repeata
LED = 1
OUT_PIN = 0
'Calculate the value to be loaded into TMR0 for counting at RA4 connected to the encoder output
'Use a multiplier to convert the spacing in cm to number of pulses to count
'Say if the distance measuring wheel's dia is 40 cm then its circumference = 3.14*40 appr = 125 cm
'For one revolution ie 125 cm distance traveled = 500 pulse outputs of encoder
'Correspondingly 500/125 = 4 pulses/cm distance, therefore set the count as 255 - (spacing * 4)
direct:
spacing = 255 - (spacing * 4)
OPTION_REG = %00110000 ' TMR0 counter on falling edge of RA4
'Cnt = 0 ' Clear the event counter, Cnt
ON INTERRUPT GOTO ISR ' Interrupt service routine
TMR0 = spacing
OUT_PIN = 0
INTCON = %10100000 ' Enable TMR0 overflow interrupt

NXT:
if OUT_PIN = 1 then
pause 300
OUT_PIN =0
endif
GOTO NXT ' Continue

'This is the interrupt service routine, ISR. The program jumps here whenever TMR0 overflow occurs
DISABLE ' Disable interrupts
ISR: ' Entry point of the ISR
OUT_PIN = 1
TMR0 = spacing
INTCON = %10100000 ' Enable TMR0 overflow interrupt
RESUME ' Resume main program
ENABLE ' Enable interrupts

wait_button:
if CNTL_BUTTON && 1 = temp then wait_button
return
end

divaker
- 22nd July 2008, 15:13
You post your code in PDF format, and the only way anyone can test it is to retype it all over, no thanks.

Sorry that I had attached it in pdf
Now I have attached in text.
Please pardon me.

skimask
- 22nd July 2008, 16:03
When it is simed on MPLAB, it is quite OK. But when it is run on the chip, it does not work.
And you're sure the PIC is running in the first place?
How does the 'blinky LED' program run?

divaker
- 22nd July 2008, 17:31
Dear skimask,
Yes, the "blinky and the button" worked as required right on the PIC16f84.
Similarly the interrupt driven routine also worked well separately on the PIC
But when these two are put together on the PIC it odes not work.

Though the MPLAB simulates it well enough and comes thru'.


Divaker

skimask
- 22nd July 2008, 18:12
Looks to me like you have to do some big time reorganization of your program...You've got it jumping all over everything...
Here's how I normally do things...might not be optimal, but it keeps me out of trouble:
Defines
Variable declarations
ASsembly macros
Skip over Int Handler/Subroutines
On Interrupt statement
Int Handler routine
Subroutines
PIC, PIC pins and other hardware Setup/Initialization
Main body

And besides all that, I don't see where you clear the TMR0 overflow flag like it says you have to do in the datasheet. I see you enable the TMR0 interrupt a couple of times which has the side effect of clearing the flag...but probably not at the right time.

divaker
- 23rd July 2008, 03:34
Dear skimask,
Thanks for your time and the suggestions.
Let me reorganize and see. Also I will clear the TMR0 approp.
However, I wonder how come the interrupt routines without the blink button works absolutely alright on the PIC.
And when I removed the whole button routines and rewrote the code to accept the variable 'spacing' from PORTA through a DIP switch, the code worked without hitch on the PIC.

Divaer

skimask
- 23rd July 2008, 03:50
However, I wonder how come the interrupt routines without the blink button works absolutely alright on the PIC.
And when I removed the whole button routines and rewrote the code to accept the variable 'spacing' from PORTA through a DIP switch, the code worked without hitch on the PIC.

Divaer

Probably because the blink button code had PAUSEs in it. The 'On Interrupt' doesn't fire if it's blocked by a PAUSE or any other statement that needs to complete before the next statement can execute. More details about 'On Interrupt' in the manual.

Archangel
- 23rd July 2008, 06:22
I tried it @ 20mhz with code below, I have no provision to increment the timer right now but it does change the outputs on RB0 & RB1 when you switch RB7


@MyConfig = _HS_OSC & _WDT_OFF & _PWRTE_ON

@ __config MyConfig

DEFINE OSC 20


Symbol OUT_PIN = PORTB.0 'Output to solenoid RB0
Symbol LED = PORTB.1 'Control button to RB1
Symbol CNTL_BUTTON = PORTB.7 'Control button to RB7

spacing var byte
temp var byte

TRISA=$FF
TRISB = $FC ' RB0 and RB1 outputs, others input
portB = 0
'* * * * * * * Set initial value to variables * * * * * * * * * * *
'
spacing = 15
LED = 0
temp=1
' Program starts with gosub to Wait_Button
main:
gosub wait_button

LED = 1 ' on return turn on LED
pause 2000 ' Wait for two seconds
if CNTL_BUTTON = 1 then spacing = 30
goto direct 'If button is released before 2 secs
'code goes directly into the default spacing
temp=0

gosub wait_button 'If button is pressed more than 2 secs,
'it gets caught here and waits for release
LED = 0
pause 1000 ' Wait for 100 ms




repeata:
spacing = spacing +5 'Increase the spacing count by 2 every time
toggle LED: pause 1000: toggle LED
if spacing = 45 then spacing = 20 'Till it reaches maximum and reset to minimum
temp=1
gosub wait_button 'Access the push button state and repeat if short press
pause 2000 ' Delay for 2 seconds
if CNTL_BUTTON = 1 then goto repeata

LED = 1
OUT_PIN = 0

'Calculate the value to be loaded into TMR0 for counting at RA4 connected to the encoder output
'Use a multiplier to convert the spacing in cm to number of pulses to count
'Say if the distance measuring wheel's dia is 40 cm then its circumference = 3.14*40 appr = 125 cm
'For one revolution ie 125 cm distance traveled = 500 pulse outputs of encoder
'Correspondingly 500/125 = 4 pulses/cm distance, therefore set the count as 255 - (spacing * 4)



direct:

spacing = 255 - (spacing * 4)
OPTION_REG = %00110000 ' TMR0, counter set option_reg<5> clear for timer
' Option_Reg<4> set for falling edge clear for
' rising edge detection.

ON INTERRUPT GOTO ISR ' Interrupt service routine
TMR0 = spacing
OUT_PIN = 0
INTCON = %10100000 ' Enable TMR0 overflow interrupt




'This is the interrupt service routine, ISR. The program jumps here whenever TMR0 overflow occurs

DISABLE 'Disable interrupts
ISR: 'Entry point of the ISR
OUT_PIN = 1
TMR0 = spacing
INTCON.2 = 0 ' Reset timer interrupt flag
RESUME ' Resume main program
ENABLE ' Enable interrupts

wait_button:
if CNTL_BUTTON && 1 =temp then wait_button
return

end

divaker
- 23rd July 2008, 16:08
Thanks for your effort Joe.
But do you mean that the code is really working for you on the chip as expected?
Then what could be the problem with mine?
Is it something to do with my power supply?
As soon as I make the first press of the button (RB7), the chip seems to reset. (Of course the WDT was off!)

Dear skimask,
But I dont need the interrupts fire when I am setting the variable 'spacing' through the button presses (short and long involving Pauses!). Only after that button part is over, (after the label 'direct') the inerrupt needs to work.

Divaker

skimask
- 23rd July 2008, 16:20
But do you mean that the code is really working for you on the chip as expected?
Then what could be the problem with mine?
Is it something to do with my power supply?
As soon as I make the first press of the button (RB7), the chip seems to reset. (Of course the WDT was off!)

Why don't you post a schematic of EXACTLY what you've got...

And the code that Joe posted is different than the code that you posted...so does it work?

Archangel
- 23rd July 2008, 17:13
Why don't you post a schematic of EXACTLY what you've got...

And the code that Joe posted is different than the code that you posted...so does it work?
I have to agree w/Skimask post your schematic, It is really hard to determine what it is supposed to do. It does turn on the ports and turns them off, not sure if it does as "expected".
Some things to keep in mind,(you probably know already) All unused inputs must be terminated to VCC or VDD through resistors, in this case to ground. The RA4 is open drain so it needs a PULLUP resistor to supply +.

skimask
- 23rd July 2008, 17:36
Let's take another look at the last program posted:


-code-removed-here
............................
if CNTL_BUTTON = 1 then spacing = 30
goto direct 'If button is released before 2 secs
'code goes directly into the default spacing
-more-code-removed-here
............................
direct:
spacing = 255 - (spacing * 4)
OPTION_REG = %00110000 ' TMR0, counter set option_reg<5> clear for timer
' Option_Reg<4> set for falling edge clear for
' rising edge detection.
ON INTERRUPT GOTO ISR ' Interrupt service routine
TMR0 = spacing
OUT_PIN = 0
INTCON = %10100000 ' Enable TMR0 overflow interrupt
'This is the interrupt service routine, ISR. The program jumps here whenever TMR0 overflow occurs
DISABLE 'Disable interrupts
ISR: 'Entry point of the ISR
OUT_PIN = 1
TMR0 = spacing
INTCON.2 = 0 ' Reset timer interrupt flag
RESUME ' Resume main program
end

How can you RESUME if you didn't get there with an interrupt in the first place?
What happens to a program if you RETURN without a GOSUB? Or in this case, RETFIE without an INTERRUPT?
Now re-read post #7 and you'll see why I posted what I did...

Archangel
- 24th July 2008, 07:28
edit: never mind

divaker
- 24th July 2008, 15:34
Am preparing a soft copy of the schematic and also a writeup of what is what in the program?

Meanwhile I found that the chip actually resets everytime while executing the interrupt routine.
Goes to beginning of code and starts executing again.

WDT is OFF and I am not sure why this happening.
Could there be some other reason?

But the code works alright in the MPLAB SIM!!

Divaker

skimask
- 24th July 2008, 17:02
Who cares if it works in the MPLAB SIM or any other SIM.
If a plane test flies well in the simulator, but crashes every time they try to test fly it in real life, which method of testing are you going to believe?

Open up your datasheets, or do a Google search whatever for STACK UNDERFLOW or STACK OVERFLOW.
You explained your problem in your last post, and it almost completely verified what I told you 2 or 3 posts ago.


Meanwhile I found that the chip actually resets everytime while executing the interrupt routine.
Goes to beginning of code and starts executing again.
WDT is OFF and I am not sure why this happening.

Again, how can you RETURN from somewhere you didn't GOSUB to?
Same thing applies with an INTERRUPT. You can't RETFIE (RESUME) without an interrupt. Break out the datasheets and look up RETFIE, then break out your PBP manual and look up RESUME. An INTERRUPT is basically nothing more than a hardware generated CALL (not a GOTO because a CALL remembers where it came from). If you GOTO into your interrupt routine and expect it to come back where it came from, it's probably going to 'come back' to $0000, the RESET vector, whatever you want to call it. But actually, it's not going to do any of that, because you're going to have a STACK UNDERFLOW. You can't pull less than what's not there.
I'm guessing you probably haven't tried rewriting your code yet?
If you would've, you might avoid this problem altogether...

divaker
- 31st July 2008, 15:38
Dear Skimask and Joe,

Thanks guys for your kind suggestions for correcting the prob.
The whole prob was due to the relay that I had connected to the output.
It was the a typical case of not remembering to add a simple flyback diode. The relay was responsible for the prob.
As soon as I corrected it, everything worked like plum.
Thanks once 'gain.

Divaker

skimask
- 31st July 2008, 15:49
Didn't say anything about connecting a RELAY (yes, your code says solenoid, but you don't mention that it's actually hooked up)...
Could've saved 15 posts over a few days...