|
|
View previous topic :: View next topic |
Author |
Message |
Hsu860041
Joined: 22 Apr 2004 Posts: 1 Location: Taiwan
|
Beginner of CCS |
Posted: Thu Apr 22, 2004 6:57 pm |
|
|
Hello,
I am a beginner of CCS compiler. After read the reference document and checked some example code. I make some practice. However, I got one question here, hope someone can answer for me.
Can I separate the source code into small source file. compile each and link together? It seems the compiler always complain:
"function used, but not defined:". It happened on the line that function which defined on another file.
I already put "extern function" statement. What should I do? |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1933 Location: Norman, OK
|
|
|
RKnapp
Joined: 23 Feb 2004 Posts: 51
|
|
Posted: Thu Apr 22, 2004 8:16 pm |
|
|
PCM has some good links! And I really sympathize with this problem because it is so basic that no one thinks to answer it anywhere in the help file. I suffered a while on this.
What I hit upon is this, and I would love to hear WHY any of this is true from people more knowledgeable (well, that's a lot of people I admit):
- The "extern" keyword is tolerated but causes local copies of whatever you THINK you are linking to, to be created, instead of linking to your target global variable. THIS IS BAD; the compiler should instead flag any occurrence of "extern" as an error. Look out. (And as an aside, this was the one and only time Tech Support ever answered a question I've sent them. Coincidentally...?... I hadn't yet bought the compiler...)
- For some strange reason it is not necessary to declare function prototypes for any function which hangs off the main function.
- But you must declare function prototypes for any function which hangs off a sub-function.
- Function prototypes are generally like ANSI prototypes except when any kind of pointer is used. Then they get weird, and to me, scary because I worry that I'm not getting a prototype but a literal declared & allocated. In the example below, in my parsemsg() prototype, I worry about the fact that "char * pPacket" will compile but "char *" will not. The symbol table, perhaps because I don't know how to read it very well, provides me with no comfort on this score.
Example below (my current project). This section is part of a lengthy header file I keep #fuses and all sorts of other constants and directives in, and I admit that it isn't anything too great to show you except that it's real and works. Stylistically, I happen to define structs but not allocate space for them except in a non-functioning routine called globldat(), thus I have to provide their definitions pretty early. This is not necessary -- each person does what they think best. What this DOES indicate usefully re your original question is that I have lots of modules and am fond of #defines.
Code: |
/* ===========================================================================
Header Name: voterhdv.h
Purpose: main program header: Sets parameters, declares special data
structures -- though all global data is allocated in <global_d>.
Comments: Microchip PIC18F8720 is the target device.
Note: To change pins, edit pin_defs.h.
============================================================================*/
#include <18F8720.h>
....
#fuses, etc. and lots of stuff
...
// Widely-used macros etc: ---------------------------------------------------------
#include <pin_defs.h>
#include <k_macros.h>
// Struct Definitions: ---------------------------------------------------------
// These struct definitions must PRECEDE globaldat.c or compiler will get lost:
#include <structs1.h> // serial data
#include <structs2.h> // error codes
#include <structs3.h> // servo data
#include <globldat.c> // global data instantiations
// Function Prototypes: (note, ISRs are prototyped using #INT_xxxx) -----------
// ...These must PRECEDE the project files below, or the compiler gets confused.
// Note, for some reason, I don't need prototypes of anything called by main():
void parsemsg ( int8 , int8 , char * pPacket, int8 msglength );
//int16 tablecr2 ( char * message, int8 );
//int16 tablecrc ( char * message, int8 );
int16 shiftcrc ( char * message, int8 );
#ifdef CODE4_CORE
void Rspi_a2d ( int8 );
void Wspi_d2a ( int8 );
void getanins ( int8 );
float midvalue ( struct vote_avg_sel * pVAS, float, float, float );
void v_avgsel ( int8,
struct vote_avg_sel * pVAS,
int8 commstatus1, int8 commstatus2, int8 commstatus3,
float command1, float command2, float command3 );
void gd_sched ( int8 );
#endif
// Project Files: --------------------------------------------------------------
#include <ISRdeflt.c> // Handles unexpected interrupts
#include <ISRclock.c> // Clock ticks at 1000 Hz
#include <ISRCOM2R.c> // receive messages COM2
#include <ISRCOM1R.c> // receive messages COM1
#include <ISRCOM2T.c> // transmit messages COM2
#include <ISRCOM1T.c> // transmit messages COM1
#ifdef CODE4_PP
#include <ISRppCTS.c> // IF... I'm a PP, I Tx my PP2CORE msg via an ISR
#endif
#include <whystart.c> // analyzes watchdog startup reason
#include <initialz.c> // startup (chip configuration) code
#include <inputdat.c> // get new inputs
#include <vote_con.c> // controller logic, votes, sets up D/A flag
#include <postoutp.c> // post outputs
#include <waittask.c> // wait until time to begin next cycle
#include <parsemsg.c> // parse serial messages
//#include <tablecr2.c> // calculate CRC-16 via a table lookup
//#include <tablecrc.c> // calculate CRC-16 via a table lookup
#include <shiftcrc.c> // calculate CRC-16 via bit-shifting
#ifdef CODE4_CORE
#include <Rspi_a2d.c> // called only from ISRclock: read A2D inputs
#include <Wspi_d2a.c> // called only from ISRclock: write D2A outputs
#include <getanins.c> // get native 10-bit analog inputs (voltage monitors)
#include <midvalue.c> // don't confuse this with the CC version of voting
#include <v_avgsel.c> // vote / average / select utility
#include <gd_sched.c> // CORE2PP -> V2CC subspeed channel scheduler
#endif
|
What I happen to do is set my #defines, #include this big header file (which itself drags in the chip file in the first line, <, then declare main(). The #defines govern what happens inside the header; the header has lots of details you won't want to clutter your highest-level program with; and it all works. Here's the start of my main function:
Code: |
/* ===========================================================================
Function Name: voterhdv
Purpose: main function
============================================================================*/
// Flags:
#define CODE4_CORE // Most important switch: sets CORE vs PPROC vs MONITOR
//#define CODE4_PP // One of these three should be defined before the
#define PP_FCN_CODE 0x02 // KLUDGE KLUDGE -- no Fcn Code yet available, 1,2,3
//#define CODE4_MON // main header inclusion of #include voterhdv.h.
// Flags which for final design should be #defined:
#define FULL_SPEED_PORTS // ifdef, ports allowed to run at 1MBaud
#define PP2C_PLAN_A // ifdef, PP uses DIRECT ISR output of PP2C message
//#define LVP_ACTIVE // ifdef, low-voltage programming is permitted
//#define SPI_A2D2A_ACTIVE // ifdef, SPI A2D and D2A are performed
//#define NATIVE_A2D_ON // ifdef, native A2D is performed
//#define NDEBUG // ifdef, will NOT generate code for assert() macro
#define EXPLICIT_TRIS // ifdef, uses FAST_IO and explicit TRIS of ports
// Flags which for final design should NOT be #defined:
//#define FIX_THIS // ifdef, breaks compile at areas needing repair
//#define BUFFERED_TX // ifdef, buffers all Tx (PLAN_B REQUIRES THIS)
//#define PP2C_PLAN_B // ifdef, PP uses BUFFERED output of PP2C message
//#define COM1_DEBUG_USE // ifdef, >bytes out (requires FULL_SPEED_PORTS off)
//#define TRIVIAL_PROGRAM // ifdef, program does NOTHING except float pins
//#define PP_COM2_SPITTER // ifdef, PP blasts 'P' bytes at the CORE
#define 8720_PROTO_BOARD // ifdef, the CCS prototyping board is present
#define VERBOSE // ifdef, fprintf can produce dongle-debugging o/p
#include <voterhdv.h> // main header file: affected by #defines above
// -----------------------------------------------------------------------------
void main()
{
// Local Data Definitions:
BOOLEAN lOK = TRUE;
// Begin Procedure ==========================================================
whystart(); // Did I restart from a watchdog timeout?
... and so forth.
|
Now, I still wonder about is the role of "static." In the help file it is stated that anything "static" is automatically global. I think this is true but haven't checked it.
So my basic advice is to get rid of all "extern" in your code, prototype, and yes, definitely break up your code into different functions.
Good luck,
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
|