View previous topic :: View next topic |
Author |
Message |
jcobreros
Joined: 25 Jun 2009 Posts: 7
|
IF statement executes even when condition is not met |
Posted: Thu Jun 25, 2009 12:27 pm |
|
|
Good evening, I'm having this weird problem with CCS 4.088 in a PIC16F876A.
I have an interrupt that executes when some character is received from the serial port. This interrupt writes the ASCII value received in a variable called Keypress. In the main loop there's a routine that executes only when Keypress!=0 and it sets it back to 0. This has always worked fine for me.
Now I added another IF statement in the main loop. It encloses a simple section of code that was there before and worked fine. It doesn't involve Keypress at all.
Now the keypress routine executes even when Keypress=0.
Let me show the relevant code:
Code: |
#include <16f876a.h>
#fuses NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=20000000)
#use standard_io(b)
#use rs232(baud=19200,xmit=PIN_C6,rcv=PIN_C7)
int Keypress=0x00;
int ready=0;
#int_rda //SERIAL PORT INTERRUPT
void rda_isr() {
Keypress=0x00;
if(kbhit()){
Keypress=getc();
}
}
#int_TIMER1
void TIMER(){
ready=1;
}
void main() {
setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);
enable_interrupts(int_rda);
enable_interrupts(global);
enable_interrupts(INT_TIMER1);
set_TIMER1(0);
do {
//THIS IS THE BUGGY STATEMENT. PRINTF SAYS KEYPRESS=0 WHEN IT SHOULDNT PRINT AT ALL.
if(Keypress!=0) //
{
printf("%d",Keypress);
Keypress=0;
}
//THIS IS THE STATEMENT THAT CREATES THE PROBLEM. THE CODE INSIDE WAS ALREADY THERE, BUT IF I ADD THE "if(ready==1)", THEN THE PREVIOUS IF JUMPS IN FOR NO REASON.
if (ready==1)
{
if (angl>6.28)
{
angl=0;
}
angl+=0.01;
tservo0=2000*sin(angl)+3800;
tservo1=2000*cos(angl)+3800;
ready=0;
}
}
while (TRUE);
}
|
So when I add the condition "if (ready==1)" to the last section of code (it worked properly before, I just want to limit how many times it executes), the if(keypress!=0) statement stops doing its function and the code inside executes even when keypress==0. Its really weird to see that right after evaluating the condition, printf says "0".
I know that the serial port interrupt (INT_RDA) is behaving properly, not executing unless a key is pressed on the computer, so that interrupt is not modifying keypress at all. its the IF statement that's not working properly.
If I delete "if(ready==1)" then the "if(keypress!=0)" works properly and only prints the ASCII code when its different than 0. If I add it again, the other one misbehaves again.
I've tried declaring ready and keypress as volatile, but it doesn't help.
Also I've tried creating a second variable, "copy" of keypress, (let's call it key), so if I do "if(keypress!=0 && key!=0)" everything works fine.
Any idea of why this is happening?? thank you in advance for your help!! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 25, 2009 12:59 pm |
|
|
How are you testing this ? Are you testing this with real hardware
or a simulator ? If a simulator, which one ?
Are you using a debugger with breakpoints ? Or, are you just running
the program in standalone mode on a board.
I need to know this so I can duplicate your testing environment. |
|
|
Guest
|
|
Posted: Thu Jun 25, 2009 1:54 pm |
|
|
The program is running in standalone mode on the board itself (SkyPIC with PIC16f876A) and I use printf's to see what's going on.
When executed on MPLAB SIM it works propperly. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 25, 2009 2:01 pm |
|
|
The program is not compilable. When compile it, I get these missing
variable declarations:
Quote: | *** Error 12 "pcm_test.c" Line 45(10,14): Undefined identifier angl
*** Error 12 "pcm_test.c" Line 47(9,13): Undefined identifier angl
*** Error 12 "pcm_test.c" Line 49(5,9): Undefined identifier angl
*** Error 12 "pcm_test.c" Line 50(5,12): Undefined identifier tservo0
*** Error 12 "pcm_test.c" Line 51(5,12): Undefined identifier tservo1 |
Please edit your code and add the variable declarations so it compiles.
Also, test the program that you post. Make sure it shows the failure. |
|
|
jcobreros
Joined: 25 Jun 2009 Posts: 7
|
|
Posted: Thu Jun 25, 2009 2:13 pm |
|
|
Sorry, let me post the complete code (its not much longer, but I was trying to go to the point).
Code: |
#include <16f876a.h>
#include <math.h>
#fuses NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=20000000)
#use standard_io(b)
#use rs232(baud=19200,xmit=PIN_C6,rcv=PIN_C7)
volatile int Keypress=0;
int servoswitch=0;
volatile int key=0;
float angl=0;
long int tservo0=1900;
long int tservo1=1900;
long int temp0=1900;
long int temp1=1900;
volatile int ready=0;
#int_rda
void rda_isr() {
Keypress=0;
if(kbhit()){
Keypress=getc();
}
}
#int_TIMER1
void TIMER(){
switch(servoswitch)
{
case 0:
{
set_TIMER1(65535-tservo0);
output_bit(PIN_B0,1);
servoswitch++;
break;
}
case 1:
{
set_TIMER1(65535-tservo1);
output_bit(PIN_B0,0);
output_bit(PIN_B1,1);
servoswitch++;
break;
}
case 2:
{
set_TIMER1(15535+tservo1+tservo0);
output_bit(PIN_B1,0);
servoswitch=0;
ready=1;
break;
}
}
}
void main() {
setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);
enable_interrupts(int_rda);
enable_interrupts(global);
enable_interrupts(INT_TIMER1);
set_TIMER1(0);
do {
// CONTROL DESDE LA RS-232
if(keypress!=0){
printf("%d",keypress);
switch(Keypress)
{
case 49:
{
tservo0=1900;
tservo1=1900;
break;
}
case 50:
{
tservo0=5800;
tservo1=5800;
break;
}
}
key=0;
Keypress=0;
}
if (ready==1)
{
ready=0;
if (angl>=6.28)
{
angl=0;
}
angl+=0.1;
tservo0=2000*sin(angl)+3800;
tservo1=2000*sin(angl)+3800;
}
}
while (TRUE);
}
|
|
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Jun 25, 2009 2:15 pm |
|
|
To be sure, that the content of keypress doesn't change between the if(!keypress) and the printf() statement, you must either disable interrupts or copy the value to a shadow variable, that can't be changed during an interrupt event.
Before you try to identify other possible causes for the problem, you should exclude the obvious ones. |
|
|
jcobreros
Joined: 25 Jun 2009 Posts: 7
|
|
Posted: Thu Jun 25, 2009 2:24 pm |
|
|
@FvM: im afraid I dont know how to do that. I see how an interrupt can happen between the IF and the PRINTF, but I assumed its value wouldn't change as the variable is not used by anything else. How do I create a shadow variable?
thank you in advance! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 25, 2009 2:32 pm |
|
|
It's clear that you didn't test this program, because it has no oscillator
fuse (should be HS). If you don't specify the fuse, the compiler defaults
to "RC" mode. I just downloaded your program to my board and it
doesn't run. I don't want to work on this any more. |
|
|
jcobreros
Joined: 25 Jun 2009 Posts: 7
|
|
Posted: Thu Jun 25, 2009 3:00 pm |
|
|
@PCM programmer: I didnt know I had to add an oscillator fuse, all the programs I've done run on my board (SkyPIC with a PIC16F876A).
All I can tell you is that the program compiles on MPLAB with CCS 4.088 and runs on my PIC (with bootloader). I have 2 hobby servos connected to it and they move with the sine and cosine values. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Jun 25, 2009 3:01 pm |
|
|
Code: | save_keypress = keypress;
if(save_keypress!=0){
printf("%d",save_keypress); |
|
|
|
jcobreros
Joined: 25 Jun 2009 Posts: 7
|
|
Posted: Thu Jun 25, 2009 3:13 pm |
|
|
@FvM: I had already tried something similar (the redundancy variable "key"), but the result was the same.
Now I did it exactly your way (assigning the value right before the evaluation) and the result is even worse and I dont understand it.
Now i get a bunch of 0's and some random -128's and 8's...
Hey, thank you all, i've never had people answering me so fast. |
|
|
ttelmah Guest
|
|
Posted: Thu Jun 25, 2009 3:47 pm |
|
|
I suspect your problem is hardware.
The big 'difference', between the working, and faulty code, is that you are adding code that presumably controls a motor or something similar.
What you are describing is realistically a fairly 'classic' description of a processor experiencing noise on it's supply, or RF noise on some of the I/O pins.
Try the test code, with the extra lines, but _without the motor hardware attached_. I suspect you will find it is working fine.
It then comes down to properly decoupling and overshoot clamping the motors. One classic problem is forgeting that a motor, when switched off, is both a freewheeling inductor, and a generator, and the power from this, _has_ to go somewhere. transistors will often route a lot of the energy back to their base connections, and back ito the processor driving them, if the energy is not clamped elsewhere....
Best Wishes |
|
|
jcobreros
Joined: 25 Jun 2009 Posts: 7
|
|
Posted: Fri Jun 26, 2009 12:38 pm |
|
|
@ttelmah: I have unplugged the servos and the result is the same. I still have to try with a different power source (battery pack?) and in a different PIC. Noise seems like a reasonable cause.
I will keep working on this and post any change. Thank you for your help! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jun 26, 2009 1:20 pm |
|
|
I didn't realize you were using a bootloader for the 16F876A. That
means the fuses are preset in the bootloader code. Make sure the
bootloader code has the NOLVP fuse in it.
I don't have vs. 4.088. I only have 4.087 and 4.089. I believe that vs.
4.088 was an in-between version, where CCS discovered a problem with
the installation and quickly came out with vs. 4.089. Here's their note
from the versions page:
Quote: | 4.089 A duplicate filename error on install is fixed |
So I installed vs. 4.089 and ran it. Your case statements check for
a keypress of '1' or '2'. I pressed those repeatedly, and it displayed
the following result:
Quote: | 495049504950495049504950495049 |
If I don't press any keys, it doesn't display anything. So I think it's
working properly for me. This was tested on a PicDem2-Plus board.
There are no motors connected to the board.
The code that I tested was your full program, from post #5. |
|
|
jcobreros
Joined: 25 Jun 2009 Posts: 7
|
|
Posted: Fri Jun 26, 2009 1:32 pm |
|
|
@PCM programmer: hey thanks for taking the time. I guess this narrows it to my hardware. I'll try it on another PIC when I get home and if the result is the same I will just add a redundant variable so the IF statement checks for both of them.
Again thanks for the help. This is a great forum |
|
|
|