#include <stdio.h>
void func1(void);
void func2(void);
void main(void)
{
.......
.......
}
void func1(void)
{
func2();
}
void func2(void)
{
func1();
}
Your code demonstrates a form of Recursion.
Both func1() and func2() are recursive function in respect to each other.
The compiler error can be eliminated by the use of function prototypes:
Code:#include <stdio.h> void func1(void); void func2(void); void main(void) { ....... ....... } void func1(void) { func2(); } void func2(void) { func1(); }
Recursion in C and C++
Be aware that each call of either function result in a PUSH on the STACK and eventually there maybe a STACK Overflow if allowed to continue indefinitely.
BigDog
By the way #include <stdio.h> was not nessasary, I think its nessasary only for PC programs.
And since you mentioned stack overflows, I always had the problem whether nested while loops or if conditions can cause stack overflows. Do they?
The #include <stdio.h> was provide just to give you a reference point of where the function prototypes should be located. The selection of "stdio.h" was just a commonly used header file which came to mind.
It depends on what is in the nested loops.
"If" conditional statements rarely, if ever, unless there is a double recursive function such as your example above contained within.
Do you have an example program you could post which results in a stack overflow?
BigDog
unsigned short i, current_duty, number,d1,d2,d3,dtmf;
//bitwise declaration for dtmf inputs
sbit std at PORTD.B0;
sbit q4 at PORTD.B1;
sbit q3 at PORTD.B2;
sbit q2 at PORTD.B3;
sbit q1 at PORTD.B4;
//bitwise declaration for L293B outputs
sbit lm1 at PORTC.B4; //left motor positive
sbit lm2 at PORTC.B5;
sbit rm1 at PORTC.B6;
sbit rm2 at PORTC.B7;
void dtmfToNumber(void);
void manualMode(void);
void modeSelection(void);
void accelerate(void);
void decelerate(void);
void turnLeft(void);
void turnRight(void);
//main function
void main(void)
{
TRISD = 0b00011111; // Configure PORTD
TRISC = 0;
for (i = 0; i <= 5; i++)
{
PORTD.F7 = ~PORTD.F7; // Initialize RD7
Delay_ms(1000); // one second delay
}
Pwm1_Init(5000);
current_duty = 0;
Pwm1_Set_Duty(0);
PORTD.F7 = 1;
Pwm1_Start();
//call the password func!
modeSelection();
}
void dtmfToNumber(void) //number recognition
{
dtmf.f0 = q1; // assigning bits
dtmf.f1 = q2;
dtmf.f2 = q3;
dtmf.f3 = q4;
//recognizing
if(dtmf == 0b0010) number = 2;
if(dtmf == 0b0100) number = 4;
if(dtmf == 0b0110) number = 6;
if(dtmf == 0b0101) number = 5;
if(dtmf == 0b1011) number = 11; // *key
return;
}
/*removed - recursive stackoverflow problem
short dtmfToNumber(void) //number recognition
{
dtmf.f0 = q1; // assigning bits
dtmf.f1 = q2;
dtmf.f2 = q3;
dtmf.f3 = q4;
//recognizing
if(dtmf == 0b0010) return 2;
if(dtmf == 0b0100) return 4;
if(dtmf == 0b0110) return 6;
if(dtmf == 0b0101) return 5;
if(dtmf == 0b1011) return 11; // *key
}
*/
void modeSelection(void)
{
Pwm1_Set_Duty(0); //stop the robot
while(1)
{
if(std == 1) //if user pressed a key
{
dtmfToNumber();
if(number == 1) manualMode();
}
}
}
void manualMode(void) // manual mode
{
while(1)
{
if(std == 1) dtmfToNumber();
if(number == 2) accelerate();
if(number == 4) turnLeft();
if(number == 5) decelerate();
if(number == 6) turnRight();
if(number == 11) modeSelection();
}
}
void accelerate(void)
{
lm1 = 1;
lm2 = 0;
rm1 = 1;
rm2 = 0;
if (current_duty < 255)
{
current_duty++;
Pwm1_Set_Duty(current_duty);
Delay_ms(30);
}
number = 10; // assign a non defined number to stop automatically coming back to this func even when key is released.
return;
}
void turnLeft(void)
{
lm1 = 0;
lm2 = 0;
rm1 = 1;
rm2 = 0;
number = 10;
return;
}
void decelerate(void)
{
lm1 = 1;
lm2 = 0;
rm1 = 1;
rm2 = 0;
if(current_duty > 0)
{
current_duty--;
Pwm1_Set_Duty(current_duty);
Delay_ms(30);
}
number = 10;
return;
}
void turnRight(void)
{
lm1 = 1;
lm2 = 0;
rm1 = 0;
rm2 = 0;
number = 10;
return;
}
What is the exact model of PIC which you are compiling the above program, PIC16F877A, etc?
BigDog
What is the exact model of PIC which you are compiling the above program, PIC16F877A, etc?
BigDog
void modeSelection(void)
{
Pwm1_Set_Duty(0); //stop the robot
while(1)
{
if(std == 1) //if user pressed a key
{
dtmfToNumber();
if(number == 1) manualMode();
}
}
}
void manualMode(void) // manual mode
{
while(1)
{
if(std == 1) dtmfToNumber();
if(number == 2) accelerate();
if(number == 4) turnLeft();
if(number == 5) decelerate();
if(number == 6) turnRight();
[COLOR="#FF0000"] if(number == 11) modeSelection();[/COLOR]
}
use the keyword "reentrant" to solve your problem when you declare the function prototype....
Thanks.Hi,
Actually, you problems are stemming from two routines:
Code:void modeSelection(void) { Pwm1_Set_Duty(0); //stop the robot while(1) { if(std == 1) //if user pressed a key { dtmfToNumber(); if(number == 1) manualMode(); } } } void manualMode(void) // manual mode { while(1) { if(std == 1) dtmfToNumber(); if(number == 2) accelerate(); if(number == 4) turnLeft(); if(number == 5) decelerate(); if(number == 6) turnRight(); [COLOR="#FF0000"] if(number == 11) modeSelection();[/COLOR] }
You have double recursion occurring between the above two routines.
If you comment out the last statement in manualMode(), "if(number == 11) modeSelection();", marked in red, your program will compile without error.
I've been looking over your code and trying to figure out the best way to solve the issue.
BigDog
---------- Post added at 12:16 ---------- Previous post was at 12:07 ----------
There is no keyword "reentrant".
Yes, I believe so.
After examining your code I am convinced the flow of the program in general could be improved quite a bit.
Please explain to me the actual purpose of your program in detail, define each task and its requirements.
If you can step by step.
BigDog
Also, can I return data from recursive functions without causing stack overflows?
//bitwise declaration for dtmf inputs
sbit std at PORTD.B0;
sbit q4 at PORTD.B1;
sbit q3 at PORTD.B2;
sbit q2 at PORTD.B3;
sbit q1 at PORTD.B4;
//bitwise declaration for L293B outputs
sbit lm1 at PORTC.B4; //left motor positive
sbit lm2 at PORTC.B5;
sbit rm1 at PORTC.B6;
sbit rm2 at PORTC.B7;
struct CNTRL{
unsigned short chgmode;
unsigned short current_duty;
unsigned short mode;
unsigned short d1;
unsigned short d2;
unsigned short d3;
unsigned short dtmf;
};
void dtmfTomode(struct CNTRL * pCntrl);
void manualMode(struct CNTRL * pCntrl);
void modeSelection(struct CNTRL * pCntrl);
void accelerate(struct CNTRL * pCntrl);
void decelerate(struct CNTRL * pCntrl);
void turnLeft(struct CNTRL * pCntrl);
void turnRight(struct CNTRL * pCntrl);
//main function
void main(void)
{
struct CNTRL control;
unsigned short i;
TRISD = 0b00011111; // Configure PORTD
TRISC = 0b00000000;
for (i = 0; i <= 5; i++)
{
PORTD.F7 = ~PORTD.F7; // Initialize RD7
Delay_ms(1000); // one second delay
}
PWM1_Init(5000);
control.current_duty = 0;
PWM1_Set_Duty(0);
PORTD.F7 = 1;
PWM1_Start();
//call the password func!
modeSelection(&control);
}
void dtmfToMode(struct CNTRL * pCntrl) //Mode recognition
{
pCntrl->dtmf.f0 = q1; // assigning bits
pCntrl->dtmf.f1 = q2;
pCntrl->dtmf.f2 = q3;
pCntrl->dtmf.f3 = q4;
//recognizing
if(pCntrl->dtmf == 0b0010) pCntrl->mode = 2;
if(pCntrl->dtmf == 0b0100) pCntrl->mode = 4;
if(pCntrl->dtmf == 0b0110) pCntrl->mode = 6;
if(pCntrl->dtmf == 0b0101) pCntrl->mode = 5;
if(pCntrl->dtmf == 0b1011) pCntrl->mode = 11; // *key
}
void modeSelection(struct CNTRL * pCntrl)
{
PWM1_Set_Duty(0); //stop the robot
while(1)
{
if(std == 1) //if user pressed a key
{
dtmfTomode(pCntrl);
if(pCntrl->mode == 1) manualMode(pCntrl);
}
}
}
void manualMode(struct CNTRL * pCntrl) // manual mode
{
while(1)
{
if(std == 1) dtmfTomode(pCntrl);
if(pCntrl->mode == 2) accelerate(pCntrl);
if(pCntrl->mode == 4) turnLeft(pCntrl);
if(pCntrl->mode == 5) decelerate(pCntrl);
if(pCntrl->mode == 6) turnRight(pCntrl);
//if(pCntrl->mode == 11) modeSelection(pCntrl);
}
}
void accelerate(struct CNTRL * pCntrl)
{
lm1 = 1;
lm2 = 0;
rm1 = 1;
rm2 = 0;
if (pCntrl->current_duty < 255)
{
pCntrl->current_duty++;
PWM1_Set_Duty(pCntrl->current_duty);
Delay_ms(30);
}
pCntrl->mode = 10; // assign a non defined mode to stop automatically coming back to this func even when key is released.
}
void turnLeft(struct CNTRL * pCntrl)
{
lm1 = 0;
lm2 = 0;
rm1 = 1;
rm2 = 0;
pCntrl->mode = 10;
}
void decelerate(struct CNTRL * pCntrl)
{
lm1 = 1;
lm2 = 0;
rm1 = 1;
rm2 = 0;
if(pCntrl->current_duty > 0)
{
pCntrl->current_duty--;
PWM1_Set_Duty(pCntrl->current_duty);
Delay_ms(30);
}
pCntrl->mode = 10;
}
void turnRight(struct CNTRL * pCntrl)
{
lm1 = 1;
lm2 = 0;
rm1 = 0;
rm2 = 0;
pCntrl->mode = 10;
}
Ok,
Here is my first revision of your program.
I have implemented a structure which is named "control", it contains any required data, current states, etc of the control process of your device.
You can add or remove any number of features simply by change the STRUCT definition located at the top of the listing. The actual structure is not extern/global, therefore a pointer to the structure is passed to each and every routine. Any changes made to the contents of the structure in these routines will direct effect the actual "control" structure.
In other words this is an efficient method of passing data back to main() and all other routines.
The code compiles without error, although I have left the statement with recursive issues commented out for the moment. I will deal with it during my next revision.
Take a look at the code, test it and understand the changes I have made. I do not want to make all the changes at once, without you understanding each change made. After all you will be maintaining the code, not I.
Code://bitwise declaration for dtmf inputs sbit std at PORTD.B0; sbit q4 at PORTD.B1; sbit q3 at PORTD.B2; sbit q2 at PORTD.B3; sbit q1 at PORTD.B4; //bitwise declaration for L293B outputs sbit lm1 at PORTC.B4; //left motor positive sbit lm2 at PORTC.B5; sbit rm1 at PORTC.B6; sbit rm2 at PORTC.B7; struct CNTRL{ unsigned short chgmode; unsigned short current_duty; unsigned short mode; unsigned short d1; unsigned short d2; unsigned short d3; unsigned short dtmf; }; void dtmfTomode(struct CNTRL * pCntrl); void manualMode(struct CNTRL * pCntrl); void modeSelection(struct CNTRL * pCntrl); void accelerate(struct CNTRL * pCntrl); void decelerate(struct CNTRL * pCntrl); void turnLeft(struct CNTRL * pCntrl); void turnRight(struct CNTRL * pCntrl); //main function void main(void) { struct CNTRL control; unsigned short i; TRISD = 0b00011111; // Configure PORTD TRISC = 0b00000000; for (i = 0; i <= 5; i++) { PORTD.F7 = ~PORTD.F7; // Initialize RD7 Delay_ms(1000); // one second delay } PWM1_Init(5000); control.current_duty = 0; PWM1_Set_Duty(0); PORTD.F7 = 1; PWM1_Start(); //call the password func! modeSelection(&control); } void dtmfToMode(struct CNTRL * pCntrl) //Mode recognition { pCntrl->dtmf.f0 = q1; // assigning bits pCntrl->dtmf.f1 = q2; pCntrl->dtmf.f2 = q3; pCntrl->dtmf.f3 = q4; //recognizing if(pCntrl->dtmf == 0b0010) pCntrl->mode = 2; if(pCntrl->dtmf == 0b0100) pCntrl->mode = 4; if(pCntrl->dtmf == 0b0110) pCntrl->mode = 6; if(pCntrl->dtmf == 0b0101) pCntrl->mode = 5; if(pCntrl->dtmf == 0b1011) pCntrl->mode = 11; // *key } void modeSelection(struct CNTRL * pCntrl) { PWM1_Set_Duty(0); //stop the robot while(1) { if(std == 1) //if user pressed a key { dtmfTomode(pCntrl); if(pCntrl->mode == 1) manualMode(pCntrl); } } } void manualMode(struct CNTRL * pCntrl) // manual mode { while(1) { if(std == 1) dtmfTomode(pCntrl); if(pCntrl->mode == 2) accelerate(pCntrl); if(pCntrl->mode == 4) turnLeft(pCntrl); if(pCntrl->mode == 5) decelerate(pCntrl); if(pCntrl->mode == 6) turnRight(pCntrl); //if(pCntrl->mode == 11) modeSelection(pCntrl); } } void accelerate(struct CNTRL * pCntrl) { lm1 = 1; lm2 = 0; rm1 = 1; rm2 = 0; if (pCntrl->current_duty < 255) { pCntrl->current_duty++; PWM1_Set_Duty(pCntrl->current_duty); Delay_ms(30); } pCntrl->mode = 10; // assign a non defined mode to stop automatically coming back to this func even when key is released. } void turnLeft(struct CNTRL * pCntrl) { lm1 = 0; lm2 = 0; rm1 = 1; rm2 = 0; pCntrl->mode = 10; } void decelerate(struct CNTRL * pCntrl) { lm1 = 1; lm2 = 0; rm1 = 1; rm2 = 0; if(pCntrl->current_duty > 0) { pCntrl->current_duty--; PWM1_Set_Duty(pCntrl->current_duty); Delay_ms(30); } pCntrl->mode = 10; } void turnRight(struct CNTRL * pCntrl) { lm1 = 1; lm2 = 0; rm1 = 0; rm2 = 0; pCntrl->mode = 10; }
Let me know if you have any questions.
BigDog
I haven't done structures before, now I'm trying to understand structures.
By the way, in my recursive functions, manualMode and modeSelection dont depend on each other, if manualMode is called by modeSelection function, modeSelection function might get pushed by the manualMode function, but it doesnt do any change to operation of manualMode function right? So if I reset all variables in those two functions at the begining of the function, what damage it can do?
Yes, this is why I want to present these C techniques to you in phases, rather than overwhelm you with a total rewrite of you program.
The use of a structure greatly simplifies the passing of various parameters to the routine calls. You can add or delete virtually any type to the structure definition and access like any of the existing variables within the structure.
There is a method to my madness as they say.
The MikroC Pro User Manual does a fair job of discussing structures, if you need additional reference material let me know and I will point you in the right direction.
Give it a try.
Actually, my next step will be implementing an Interrupt Service Routine (ISR), which is a much more efficient way of monitoring for mode changes. It will also eliminate the recursion issue in your program.
Actually, the STD signal of a valid decode of DTMF is perfect for an ISR.
Do you have any questions I can answer at the moment?
BigDog
Yes, give some tutes for structures. I got more confused after reading the manual.
void dtmfToMode(struct CNTRL * pCntrl) //Mode recognition
{
pCntrl->dtmf.f0 = q1; // assigning bits
pCntrl->dtmf.f1 = q2;
pCntrl->dtmf.f2 = q3;
pCntrl->dtmf.f3 = q4;
//recognizing
if(pCntrl->dtmf == 0b0010) pCntrl->mode = 2;
if(pCntrl->dtmf == 0b0100) pCntrl->mode = 4;
if(pCntrl->dtmf == 0b0110) pCntrl->mode = 6;
if(pCntrl->dtmf == 0b0101) pCntrl->mode = 5;
if(pCntrl->dtmf == 0b1011) pCntrl->mode = 11; // *key
}
Hmm, I thought about using ISR, But when using ISR the microcontroller wont wait for user input right?
The structure is simply a collection of various types, variables, arrays, other structures, etc.
The structure declaration is similar to a normal variable declaration:
struct CNTRL control;
"struct CNTRL" is the type, similar to int or short.
To access a member of the structure you simply:
control.current_duty = 0; // sets the control_duty member to zero.
I have passed the pointer to the "control" structure to the various routines.
The pointer being pCntrl. To access a member of the structure using the structures pointer you simply replace the "." with "->".
Example:
pCntrl->mode = 2;
The pointer to a type is simply the physical address in storage of its location, somewhat like a street address number.
To obtain the address/pointer of a type, including structures you simply:
&control
The "&" means get the address or pointer of the following structure.
Does this help?
Please feel free to ask me questions, I should be able to help you understand.
I'll also dig up some good tutorials for you.
Correct.
But not waiting is a benefit, when the STD line signals a successful decode, the PIC execution immediate jumps to the ISR which can then update the current mode variable and set a flag to alert the main process that a mode change has occurred. The PIC execution then jumps back to its original position finishes the task it was undertaking before the ISR, then checking the flag changes to the appropriate mode.
Implementing an ISR would effectively eliminate the constant polling of the STD line, but would allow mode changes to occur in a timely manner. This scheme would also remove the current reliance on the recursive routines.
Does this explanation of ISRs help? Or do you need an example?
BigDog
check these
**broken link removed**
Cprogramming.com - Programming Tutorials: C++ Made Easy and C Made Easy
C Programming - Structures and Unions
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?