View previous topic :: View next topic |
Author |
Message |
IceMetal
Joined: 20 Nov 2008 Posts: 79 Location: white Plains, NY
|
loop problem :( |
Posted: Thu Jan 08, 2009 5:21 pm |
|
|
Hi guys I'm having problem with something that to you might be very simple, I'm using the pickit2 with the ccs compiler and I just wanted to know how can I jump from one loop to the other. I created this simple program but it won't let me. The compiler gives me the error because it won't jump unless the loop I want to go is on top, I hope this makes sense to you. Thank you.
Code: | #include <16F887.h> // header file for the PIC16F887
// includes built-in functions and constants
// for arguments/returns.
#FUSES NOWDT
#FUSES NOMCLR
#FUSES NOCPD
#FUSES NOBROWNOUT
#FUSES XT
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
/////////////////////////////////////////////////////////////////////////////////
void firstloop()
{
while(1){
output_d(0xf0);
if (getc()=='2')secondloop();
}
}
void secondloop()
{
while(1){
output_d(0x0f);
if (getc()=='1')firstloop();
}
}
void main()
{
while(true)
{
printf("Welcome:,\n\r");
printf(" \n\r");
printf("Press 1 for first loop\r");
printf("Press 2 for second loop\r");
if (getc()=='1')firstloop();
if (getc()=='2')secondloop();
}
} |
|
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Thu Jan 08, 2009 5:33 pm |
|
|
you just need a prototype to show what the function looks like.
But then you have recursive problem.
try something more like this
Code: | #include <16F887.h> // header file for the PIC16F887
// includes built-in functions and constants
// for arguments/returns.
#FUSES NOWDT
#FUSES NOMCLR
#FUSES NOCPD
#FUSES NOBROWNOUT
#FUSES XT
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
//prototypes//
void firstloop();
void secondloop();
//funtions
void firstloop()
{
output_d(0xf0);
}
void secondloop()
{
output_d(0x0f);
}
//main//
void main()
{
int8 getc_val;
printf("Welcome:,\n\r");
printf(" \n\r");
printf("Press 1 for first loop\r");
printf("Press 2 for second loop\r");
while(true)
{
getc_val=getc();
if (getc_val=='1')firstloop();
if (getc_val=='2')secondloop();
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jan 08, 2009 5:36 pm |
|
|
You can't do recursion. That's what you're attempting to do. You'll
get this error message:
Quote: | *** Error 69 "pcm_test.c" Line 58(0,1): Recursion not permitted [firstloop] |
|
|
|
IceMetal
Joined: 20 Nov 2008 Posts: 79 Location: white Plains, NY
|
|
Posted: Thu Jan 08, 2009 5:41 pm |
|
|
THANK YOU SO MUCH!!!!!!!!!!!!!!!!!!!!! IT WORKS!!!!!!!!!!!!!!!!!!! |
|
|
IceMetal
Joined: 20 Nov 2008 Posts: 79 Location: white Plains, NY
|
|
Posted: Thu Jan 08, 2009 9:07 pm |
|
|
it worked but is not what I was trying to do but thanx...this what I'm trying to do, I have a robot that I need it to work in remote and autonomous mode, so when I send a command it has to stay in the remote loop with all the features, and when I hit another command it has to stay in the autonomous mode with diferent features, thats why I'm trying to do 2 diferent loops. make sence?? |
|
|
RLScott
Joined: 10 Jul 2007 Posts: 465
|
|
Posted: Thu Jan 08, 2009 10:13 pm |
|
|
IceMetal wrote: | ...when I send a command it has to stay in the remote loop with all the features, and when I hit another command it has to stay in the autonomous mode with diferent features, thats why I'm trying to do 2 diferent loops. make sense?? |
Yes, but don't use getc() because it is blocking. Use kbhit() to check for a new command without blocking. If you want to use a function for loop 1 and another function for loop 2, then just have those functions return whenever kbhit() is true. Then let the main command dispatcher loop in main decide which loop to call based on a reading of getc(), which you can do without blocking after kbhit() returns true. _________________ Robert Scott
Real-Time Specialties
Embedded Systems Consulting |
|
|
IceMetal
Joined: 20 Nov 2008 Posts: 79 Location: white Plains, NY
|
|
Posted: Thu Jan 08, 2009 10:16 pm |
|
|
but how do I go to the loop that is at the bottom when I'm on the top loop? cuz when I'm trying to do that I get an error |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Jan 09, 2009 12:18 am |
|
|
If you advance from the present very simple example to a real application, you most likely notice, that there are more things to do than stay in mutual exclusive loops representing different machine states.
To my opinion, it's more suitable to have a variable representing the different states, perform conditional code depending on the variable value, e. g. in a switch construct, and change the variable value to transit to another state. The technique is called finite state machine (FSM). In contrast to your loop example, you can divide the total system state into several substates, each representec by a FSM.
If this sounds too complex for your application, keep your intial loop example, place all loops in one function block and transit by C goto statements. This works without causing recursion issues. As a basic disadvantage, you can't perform other actions at the main program level while staying in the loop. |
|
|
IceMetal
Joined: 20 Nov 2008 Posts: 79 Location: white Plains, NY
|
|
Posted: Fri Jan 09, 2009 2:09 am |
|
|
well this is what I'm trying to do I mean I will replace the printf with output commands but just to give you an idea why I want to stay in the same loop,
Code: | #include <16F887.h> // header file for the PIC16F887
// includes built-in functions and constants
// for arguments/returns.
#FUSES NOWDT
#FUSES NOMCLR
#FUSES NOCPD
#FUSES NOBROWNOUT
#FUSES XT
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
/////////////////////////////////////////////////////////////////////////////////
//remote loop
void remote()
{
while(1){
if (getc()=='4')printf("go foward\r");
if (getc()=='5')printf("go left\r");
if (getc()=='6')printf("go right\r");
if (getc()=='2')autonomous();
}
}
//autonomous loop
void autonomous()
{
while(1){
printf("go foward\r");
while(Input(PIN_A1))printf("go left\r");
while(Input(PIN_A2))printf("go right\r");
if (getc()=='1')remote();
}
}
//main//
void main()
{
printf("Welcome:,\n\r");
printf(" \n\r");
printf("Press 1 for remote\r");
printf("Press 2 for autonomous\r");
while(true)
{
if (getc()=='1')remote();
if (getc()=='2')autonomous();
}
} |
|
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Fri Jan 09, 2009 3:53 am |
|
|
I can't believe FvM sugested using goto to fix your problem!
You have 2 options, The first requires very little change to the way your are doing it but will limit you to only the 2 loops. And is basically a really silly way to do it.
The break instruction will exit a while loop!
Code: |
//remote loop
void remote()
{
while(1){
if (getc()=='4')printf("go foward\r");
if (getc()=='5')printf("go left\r");
if (getc()=='6')printf("go right\r");
if (getc()=='2')break;
}
}
//autonomous loop
void autonomous()
{
while(1){
printf("go foward\r");
while(Input(PIN_A1))printf("go left\r");
while(Input(PIN_A2))printf("go right\r");
if (getc()=='1')break;
}
}
//main//
void main()
{
printf("Welcome:,\n\r");
printf(" \n\r");
printf("Press 1 for remote\r");
printf("Press 2 for autonomous\r");
while(true)
{
if (getc()=='1') {
while(true) {
remote();
autonomous();
}
if (getc()=='2') {
while(true) {
autonomous();
remote();
}
}
}
|
I was just going to try and show you the second way but before I do that there are really big problems with your code. As pointed out, by using getc you code will stop and wait for a keypress before continuing, it may appear to be working ok but you should have noticed that you need to send the same value several times for it to perform the correct action!
Also by fixing this you will simplify your code:-
Code: |
//remote loop
void remote(int key)
{
if (key=='4')printf("go foward\r");
if (key=='5')printf("go left\r");
if (key=='6')printf("go right\r");
}
//autonomous loop
void autonomous()
{
printf("go foward\r");
while(Input(PIN_A1))printf("go left\r");
while(Input(PIN_A2))printf("go right\r");
}
//main//
void main()
{
int mode = 0
int key;
printf("Welcome:,\n\r");
printf(" \n\r");
printf("Press 1 for remote\r");
printf("Press 2 for autonomous\r");
while(true)
{
if (kbhit()) // If a key has been pressed
key = getc(); // Save the key
else
key = 0;
if (key == '1')
mode = 1;
else if (key == '2')
mode = 2;
if (mode==1)remote(key);
if (mode==2)autonomous();
}
}
|
This will make it work the same way where you have to hold a key down to make it perform that action continously, but if you want it to continue the same action even if you let go of the key then just remove the
else
key = 0;
lines. |
|
|
IceMetal
Joined: 20 Nov 2008 Posts: 79 Location: white Plains, NY
|
|
Posted: Fri Jan 09, 2009 12:35 pm |
|
|
thank you so much Wayne that really helped me alot!!!!!!!!!!!!!!!!!!!! |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Jan 09, 2009 12:45 pm |
|
|
Quote: | I can't believe FvM sugested using goto to fix your problem! |
Believe it or not! Basically, I mentioned why staying in a loop most likely isn't a solution for a real application. But if it would be, goto is a suitable solution, you can use a lot of others too. It's legal C code.
Code: | void main()
{
char c;
printf("Welcome:,\n\r");
printf(" \n\r");
printf("Press 1 for remote\r");
printf("Press 2 for autonomous\r");
while(true)
{
c=getc();
if (c =='1')
while(1){
remote:
c=getc();
if (c =='4')printf("go foward\r");
if (c =='5')printf("go left\r");
if (c =='6')printf("go right\r");
if (c =='2') goto autonomous;
}
if (c =='2')
while(1){
autonomous:
printf("go foward\r");
while(Input(PIN_A1))printf("go left\r");
while(Input(PIN_A2))printf("go right\r");
if (kbhit() && getc()=='1') goto remote;
}
}
} |
|
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Fri Jan 09, 2009 9:29 pm |
|
|
Gotos really should be avoided, particularly for such a simple loop. My first take was: Code: | void main()
{
int1 remote = TRUE;
printf("Press 1 for remote\r");
printf("Press 2 for autonomous\r");
for (;;)
{
if (kbhit())
{
switch (getc())
{
case '1':
remote = TRUE;
break;
case '2':
remote = FALSE;
break;
case '4':
if (remote) printf("go forward\r");
break;
case '5':
if (remote) printf("go left\r");
break;
case '6':
if (remote) printf("go right\r");
break;
}
}
if (!remote)
{
printf("go forward\r");
if (input(PIN_A1)) printf("go left\r");
if (input(PIN_A2)) printf("go right\r");
}
}
} | but I didn't like the duplicate code for left/right/forwards. So then I came up with: Code: | void main()
{
int1 remote = TRUE;
printf("Press 1 for remote\r");
printf("Press 2 for autonomous\r");
for (;;)
{
int8 c = 0;
if (kbhit())
{
c = getc();
if (!remote && c >= '4') c = 0; // no remote control in autonomous mode
}
else if (!remote)
{
c = '4';
if (input(PIN_A1)) c = '5';
if (input(PIN_A2)) c = '6';
}
switch (c)
{
case '1':
remote = TRUE;
break;
case '2':
remote = FALSE;
break;
case '4':
printf("go forward\r");
break;
case '5':
printf("go left\r");
break;
case '6':
printf("go right\r");
break;
}
}
} | All the previous code examples suffer from the potential problem in autonomous mode where if the inputs stay high, you'll never be able to switch to remote mode. _________________ Andrew |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sat Jan 10, 2009 3:43 am |
|
|
Quote: | Gotos really should be avoided | Any arguments?
To my opinion,you really should avoid to code state machines in an unstructurized way. For this reason, any of the suggested examples is effectively bad coding style (at least from an embedded application point of view). My goto version simply emphasizes this bad style instead of hiding it. You immediately see, that you're stuck in a loop, as apparently intended.
To find a better coding style, you should analyze the application purpose first and define a meaningful behaviour. The original post indicates, that this hasn't been done yet. It's generally difficult to apply improvements to an inconsistent code. |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Sat Jan 10, 2009 7:59 pm |
|
|
Speaking of coding style, something I meant to mention before relates to the first two code samples provided by IceMetal:
http://www.ccsinfo.com/forum/viewtopic.php?p=109099#109099
http://www.ccsinfo.com/forum/viewtopic.php?p=109115#109115
They are just plain wrong under all circumstances, from embedded systems to supercomputers. The problem is that firstloop() and secondloop() are always calling each other and never returning. This will eventually cause any computer to run out of memory and crash. Embedded systems will just get there first due to less memory. _________________ Andrew |
|
|
|