|
|
View previous topic :: View next topic |
Author |
Message |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Aug 07, 2007 2:21 pm |
|
|
I'm not sure how to reference a function pointer as a structure element.
I mean, when you call the function. It kept giving me an "Expect ;" error.
So, I just moved the function pointer from the structure element into
a temp variable (declared as a function pointer), and had it call the
"Hello" function. Then it compiled, and it worked. It displays this:
There may be a way to do it. I just don't have any more time to spend
on it. Here's the working test program. This was tested with vs. 4.049.
Code: |
#include <18F452.h>
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
void Hello(void)
{
printf("Hello World\n\r");
}
typedef void (*_fptr)(void);
struct
{
int8 Set1;
int8 call;
_fptr func_ptr;
}Call_struct;
//====================================
void main()
{
_fptr temp;
Call_struct.func_ptr = Hello;
temp = Call_struct.func_ptr;
(*temp)();
while(1);
} |
|
|
|
Storic
Joined: 03 Dec 2005 Posts: 182 Location: Australia SA
|
|
Posted: Tue Aug 07, 2007 6:10 pm |
|
|
Thankyou,
I have slightly modified your code to expand on the function call
Code: | #include <18f67J10.h>
#device *=16
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES H4_SW //High speed osc with SW enabled 4x PLL
#FUSES NODEBUG //No Debug mode for ICD
//#FUSES NOXINST //Extended set extension and Indexed Addressing mode enabled
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NOPROTECT //Code not protected from reading
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES PRIMARY //Primary clock is system clock when scs=00
#FUSES RESERVED //Used to set the reserved FUSE bits
#use delay(clock=20000000)
#use rs232(baud=38400, xmit=PIN_C6, rcv=PIN_C7,enable = PIN_C1, ERRORS)
void Hello(void)
{
printf("Hello World\n\r");
}
void Thankyou(void)
{
printf("thankyou for your help\n\r");
}
void Goodby(void)
{
printf("coding on \n\n\r");
}
typedef void (*_ptr)(void);
typedef struct
{
int8 Set1;
int8 call;
void *func_ptr;
}Call_struct;
Call_struct key[3];
//====================================
void main()
{
int i,j =0;
_ptr temp[3];
key[0].func_ptr = Hello;
key[1].func_ptr = Thankyou;
key[2].func_ptr = Goodby;
for (i=0;i<=2;++i) {temp[i] = key[i].func_ptr;}
(*temp[0])();
delay_ms(1000);
(*temp[1])();
delay_ms(2000);
(*temp[2])();
while(1);
}
|
Thanks _________________ What has been learnt if you make the same mistake? |
|
|
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Wed Aug 08, 2007 12:33 am |
|
|
Anyway.... function pointers is not supported by CCS due the PIC lack of stack. Sice all local variables are stored as global, compiler must know the entire calling tree before. A function pointer breaks this roule.
In the above example, compile makes an workaround. Internally he's saving tags to functions instead pointers. When a call occurs, internally he substitute with switch (tag) and calls the right function. You can find this in CCS help. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Aug 08, 2007 1:22 am |
|
|
Actually, the compiler does create a pointer to the function, as you can
see in the .LST file code below. This is generated from the program
that I posted earlier in this thread.
Unfortunately, there's a bug in it. It's not storing the MSB of the 'Hello()'
function address. The program works if the function is in the first 256
bytes of program memory, but it fails if it's located higher in program
memory.
Code: |
... void Hello(void)
... {
.... printf("Hello World\n\r");
0030: CLRF 0C
0032: MOVF 0C,W
0034: RCALL 0004
0036: INCF 0C,F
0038: MOVWF 00
003A: MOVF 00,W
003C: BTFSS F9E.4
003E: BRA 003C
0040: MOVWF FAD
0042: MOVLW 0D
0044: SUBWF 0C,W
0046: BNZ 0032
.... }
0048: RETLW 00
....
... Call_struct.func_ptr = Hello;
0068: MOVLW 00 // *** BUG -- MSB of address is not saved.
006A: MOVLW 30
006C: MOVWF 08
... temp = Call_struct.func_ptr;
006E: CLRF 0B
0070: MOVFF 08,0A
....
.... (*temp)();
0074: CLRF FEA
0076: MOVLW 0A
0078: MOVWF FE9
007A: RCALL 0022
.................... |
So, I came up with a fix for that. I declared the function pointer
in the structure as an 'int16'. Then in main(), when I assign the
the function pointer to 'temp', I cast it to an _fptr. In fact, that
last part doesn't seem to be needed.
Here's a revised program with the changes given above.
Code: | #include <18F452.h>
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#org 0x1000,0x1030
void Hello(void)
{
printf("Hello World\n\r");
}
typedef void (*_fptr)(void);
struct
{
int8 Set1;
int8 call;
int16 func_ptr;
}Call_struct;
//====================================
void main()
{
_fptr temp;
Call_struct.func_ptr = Hello;
temp = (_fptr)Call_struct.func_ptr;
(*temp)();
while(1);
} |
Here's part of the .LST file for the revised program. You'll note that
the 'Hello()' function is at 0x1000, because it's now org'ed there.
If you look at the line where the address of 'Hello' is loaded into the
structure element, you'll see that it's getting the full 16-bit address now.
It works when I run it in MPLAB simulator. I tested this with vs. 4.046.
Code: | .... printf("Hello World\n\r");
*
1000: CLRF 0C
1002: MOVF 0C,W
1004: CALL 0008
1008: INCF 0C,F
100A: MOVWF 00
100C: MOVF 00,W
100E: BTFSS F9E.4
1010: BRA 100E
1012: MOVWF FAD
1014: MOVLW 0D
1016: SUBWF 0C,W
1018: BNZ 1002
.................... }
101A: RETLW 00
.................... Call_struct.func_ptr = Hello;
0052: MOVLW 10
0054: MOVWF 03
0056: MOVLW 00
0058: MOVWF 08
005A: MOVFF 03,09
.................... temp = (_fptr)Call_struct.func_ptr;
005E: MOVFF 09,0B
0062: MOVFF 08,0A
....................
.................... (*temp)();
0066: CLRF FEA
0068: MOVLW 0A
006A: MOVWF FE9
006C: RCALL 0026
.................... |
|
|
|
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Wed Aug 08, 2007 2:58 am |
|
|
Interesting...but: Quote: | The compiler does not permit pointers to functions so that the compiler can know at compile time the complete call tree. This is used to allocate memory for full RAM re-use. Functions that could not be in execution at the same time will use the same RAM locations. In addition since there is no data stack in the PICĀ®, function parameters are passed in a special way that requires knowledge at compile time of what function is being called. Calling a function via a pointer will prevent knowing both of these things at compile time. Users sometimes will want function pointers to create a state machine. The following is an example of how to do this without pointers:
enum tasks {taskA, taskB, taskC};
run_task(tasks task_to_run) {
switch(task_to_run) {
case taskA : taskA_main(); break;
case taskB : taskB_main(); break;
case taskC : taskC_main(); break;
}
} |
Anyway, i tried some time ago to make a generic timer that take a pointer to a function to execute it recurrently. This was not working. Then after i found the reason from help. Maybe for simple and predictable calls works... |
|
|
|
|
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
|