|
|
View previous topic :: View next topic |
Author |
Message |
toddintr
Joined: 21 Nov 2005 Posts: 2
|
Interrupt problem with 12F675 |
Posted: Tue Dec 06, 2005 12:29 pm |
|
|
Hi,
First off: I am new to CCS! I am using PCWH 3.210 on Win XP. I am trying to program a PIC12F675 through a PICkit 1 board.
I have the following code:
Code: | #include <12f675.h>
#include "led_only.h"
#use fast_io(A)
#fuses INTRC_IO,NOWDT,NOMCLR,NOBROWNOUT,NOPROTECT,PUT
#byte OPTION_REG = 0x81
#byte GPIO = 0x05
#byte ADCON0 = 0x1F
#byte ANSEL = 0x9F
#byte CMCON = 0x19
#bit GPIO3 = 0x05.3
#bit GPIF = 0x0B.0
#bit GPIE = 0x0B.3
#bit GIE = 0x0B.7
#bit GPPU = 0x81.7
#bit IOCB3 = 0x96.3
unsigned char Inner;
unsigned char Outer;
int LedDirection;
void Init();
void Led1();
void Led2();
void Led3();
void Led4();
void Led5();
void Led6();
void Led7();
void Led8();
unsigned char Debounce();
void Delay(char value);
void
main ()
{
ext_int_edge(l_to_h);
enable_interrupts(int_ext);
enable_interrupts(global);
Init();
while(TRUE)
{
Led1();
Delay(1000);
if (LedDirection == FORWARD)
Led8();
else
Led4();
Delay(100);
}
}
void
Init ()
{
#asm
call 0x3FF
bsf 0x03,5
movwf 0x90
#endasm
IOCB3 = SET;
GPIE = SET;
GIE = SET;
LedDirection = FORWARD;
}
// Services Timer 0, GPIO bit change and A/D conversion.
#int_ext
Isr()
{
if ((GPIE & GPIF) == SET) // GPIF indicates change in GPIO bits.
{
if (Debounce() == TRUE) // Check if direction change button has been pressed.
{
if (LedDirection == FORWARD)
LedDirection = BACKWARD;
else
LedDirection = FORWARD;
}
GPIF = CLEAR;
}
}
// LED 1 - D0 on schematic.
void
Led1 ()
{
set_tris_A (LED1TRIS);
output_A (LED1ON);
}
// D1
void
Led2 ()
{
set_tris_A (LED2TRIS);
output_A (LED2ON);
}
// D2
void
Led3 ()
{
set_tris_A (LED3TRIS);
output_A (LED3ON);
}
// D3
void
Led4 ()
{
set_tris_A (LED4TRIS);
output_A (LED4ON);
}
// D4
void
Led5 ()
{
set_tris_A (LED5TRIS);
output_A (LED5ON);
}
// D5
void
Led6 ()
{
set_tris_A (LED6TRIS);
output_A (LED6ON);
}
// D6
void
Led7 ()
{
set_tris_A (LED7TRIS);
output_A (LED7ON);
}
// D7
void
Led8 ()
{
set_tris_A (LED8TRIS);
output_A (LED8ON);
}
unsigned char
Debounce()
{
if (GPIO3 == SET)
{
return FALSE;
}
else
{
return TRUE;
}
}
void
Delay (char value)
{
for (Outer = value; Outer != 0; Outer--)
for (Inner = 0xFF; Inner != 0; Inner--)
;
return;
}
header file:
#ifndef LED_ONLY_H
#define LED_ONLY_H
#define LED1TRIS 0b11001111
#define LED2TRIS 0b11001111
#define LED3TRIS 0b11101011
#define LED4TRIS 0b11101011
#define LED5TRIS 0b11011011
#define LED6TRIS 0b11011011
#define LED7TRIS 0b11111001
#define LED8TRIS 0b11111001
#define LED1ON 0b00010000
#define LED2ON 0b00100000
#define LED3ON 0b00010000
#define LED4ON 0b00000100
#define LED5ON 0b00100000
#define LED6ON 0b00000100
#define LED7ON 0b00000100
#define LED8ON 0b00000010
#define OPEN 1
#define CLOSED 0
#define SET 1
#define CLEAR 0
#define FIRSTLED 0
#define LASTLED 7
#define FORWARD 0
#define BACKWARD 1
#endif // LED_ONLY_H
|
The expected behaviour: Led's 1 and 8 flash in an alternating fashion. Once the pushbutton is pressed, Led's 1 and 4 flash. If the pushbutton is pressed again, it's back to Led's 1 and 8 and so on...
Once the program starts, Led's 1 and 8 do flash. However, when I press the pushbutton, system freezes and Led 1 is on permanently (but not flashing).
Here's the funny thing: The EXACT code compiled with Hi-Tech PICC Lite works fine -- that is the pushbutton works as expected. Of course I know there are differences in compiler startup code, but I can't see what the problem is here.
Any help would be appreciated.
Todd |
|
|
RKnapp
Joined: 23 Feb 2004 Posts: 51
|
|
Posted: Tue Dec 06, 2005 12:58 pm |
|
|
Todd,
I'm just starting on my morning coffee so this is sort of a dumb question, but I can't quite see how you'd "lock out" the state change resulting in an interrupt if a person sits on the button.
Pushing a button to us seems fast, but not for these chips. I guess I'm wondering what happens if a button press slams you into the ISR, you perform some action, but then, the button remains pressed for hundreds of milliseconds before one can remove the finger. Does one keep re-entering the ISR, or is the interrupt somehow masked until you let go?
(In POLLING a button, it is easy to construct software that forces one to release the button before the system will listen to the next button press. But the problem is more intricate when interrupts are involved.)
(I am having a problem on some connected 8722s in which an interrupt is serviced a few times just fine, but then stops working. I am apparently not servicing it correctly, so I'm interested in all posts with interrupt problems.)
One of my problems is that I don't know what the little patch of assembly does in your init() routine.
Not much help, I'm afraid. But I urge you to think carefully about the "sit on the line" problem. There may well be a difference between the HiTech compiler and CCS in the "overhead" code for interrupt servicing. HiTech, for example, may enter the ISR and immediately mask the B0 interrupt until one exits the ISR. You appear comfortable in assembly, so you could check out the differences in entry/exit code.
Good luck,
Robert |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Dec 06, 2005 1:37 pm |
|
|
You're using #INT_EXT, but according to other things in your code,
you want to use GPIO change interrupts. Those are two different
types of interrupts. Look near the end of the 12F675.H file, and
you'll see a list of all the interrupt constants that can be used with
that PIC. You likely want to use INT_RA or one of the pin specific
versions of that interrupt. Look at the list. Change your setup
code, and the isr.
Also, you're doing a lot things that are not needed in CCS. All
the interrupt detection (ie., checking flags, etc.) is automatically
done for you by the compiler. You don't need that stuff in your isr.
Also, if you're using interrupt-on-change, you need to read the GPIO
port in the isr, to clear the "change" condition. See section 3.2.2 of
the 12F675 data sheet.
The compiler also will take care of reading the OSCCAL value and
updating the register. You don't need that ASM code in there.
Basically, if you used CCS standard i/o mode, you could reduce the
total line count in your program to at 25% or less, of your current
program size. |
|
|
toddintr
Joined: 21 Nov 2005 Posts: 2
|
|
Posted: Tue Dec 06, 2005 3:40 pm |
|
|
PCM programmer,
THANKS! Per your comments, I changed #int_ext to #int_ra, which immediately solved the problem and enabled the pushbutton. The program now works as expected.
I realize that my code uses the CCS compiler in the least efficient manner (directly twiddling bits and registers). However, I haven't come across documentation that explains the effective methodology for using CCS C. The CCS C Reference Manual has hints in it, but not the big picture.
I know there are the examples that come w/ the code, plus there is this forum, but a central tutorial that explains the CCS way of doing things would be most welcome. (Otherwise, the true strength of the CCS compiler may not be understood. Just some feedback from a customer.)
Regards,
Todd
PS: You are doing an EXCELLENT job. Everyone should be so lucky to have their question answered by PCM programmer!
PCM programmer wrote: | You're using #INT_EXT, but according to other things in your code,
you want to use GPIO change interrupts. Those are two different
types of interrupts. Look near the end of the 12F675.H file, and
you'll see a list of all the interrupt constants that can be used with
that PIC. You likely want to use INT_RA or one of the pin specific
versions of that interrupt. Look at the list. Change your setup
code, and the isr.
Also, you're doing a lot things that are not needed in CCS. All
the interrupt detection (ie., checking flags, etc.) is automatically
done for you by the compiler. You don't need that stuff in your isr.
Also, if you're using interrupt-on-change, you need to read the GPIO
port in the isr, to clear the "change" condition. See section 3.2.2 of
the 12F675 data sheet.
The compiler also will take care of reading the OSCCAL value and
updating the register. You don't need that ASM code in there.
Basically, if you used CCS standard i/o mode, you could reduce the
total line count in your program to at 25% or less, of your current
program size. |
|
|
|
toddintr
Joined: 21 Nov 2005 Posts: 2
|
|
Posted: Tue Dec 06, 2005 3:44 pm |
|
|
Robert,
The assembly code retrieves the calibration value from the last position in memory (where it is stored when leaving the factory) and uses it to set the chip calibration register.
Thanks for your response,
Todd
RKnapp wrote: | Todd,
One of my problems is that I don't know what the little patch of assembly does in your init() routine.
Robert |
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|