Advice needed: splitting a project into modules

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • nigelmercier
    New Member
    • Dec 2009
    • 45

    Advice needed: splitting a project into modules

    I'm having problems trying to split my first project into separate .C modules.

    As I understand it, using #include has the effect of loading that file into the code at that point, whereas modules are compiled separately, is that right?

    Below are the definitions and prototypes as at present. I want to separate this code (plus the associated function definitions) into 4 modules. Turning the included file [1] into a .C file, and each of [2], [3] and [4]. Note that there are function calls from one section to another: for example main() makes a call to tCal() in [2], and tCal() makes a call to testBtn() in [3].

    Everything I have tried causes dozens of errors, can anyone tell me what needs to go where?



    Code:
    // mikroElektronica Libraries used: ADC, CONVERSIONS, EEPROM 
    
    #include "nokia3310.h" // I want this to be a separate .C file [1] 
    #include <built_in.h> 
    
    typedef unsigned short int byte; 
    
    #define ModeControl PORTB        // Step = b0-b2, control = b3, Btn = b4 
    #define TCal_Ena ModeControl.F3  // Go to Tank Cal if b3=0 
    #define Btn_Key ModeControl.F4   // Button pressed if b4=0 
    #define FuelADC 0                // use ADC 0 for fuel sensor 
    
    #define BufSize 128              // Size of array for EEPROM storage 
    #define MaxEntries (BufSize - 8) // maximum number of entries in table 
    #define MaxStore (BufSize - 3)   // EE address: max # data tabMax 
    #define StepStore (BufSize - 2)  // EE address: step switch data gaugeStep 
    #define ChkStore (BufSize - 1)   // EE address: checksum of table 
    
    // Global variables 
    
    byte volatile fuelLevel; // fuel level from ADC made 8 bit 
    byte volatile gaugeStep; // fuel step value, saved in EE StepStore 
    byte fuelCalTab[BufSize]; // lookup table for fuel sensor calibration 
    byte tabMax;              // index of last entry in table, saved in EE MaxStore 
    
    char txt4[4], txt7[7];    // temporary variables to hold conversion strings 
    byte i, j;                  // misc loops 
    
    // Tank Cal Function Prototypes [2] 
    
    void tCal(void); // Calibrate Tank Gauge Step value and calibration points 
    void tCalModeMsg(void); // CLS, LCD line 0 = "TANK CAL SET" 
    void tCalBootMsg(void); // LCD line 1 = "REBOOT TO EXIT" 
    void tCalBtnMsg(void);  // LCD line 5 = "CONTINUE BTN ?" 
    void tCal3Msg(void);    // All 3 messages above to LCD 
    void tCalStMsg(void);   // LCD line 4 = "STORING DATA", 1 S delay, clear line 
    
    // IO Function Prototypes [3] 
    
    byte getFuel(void); // Get ADC for fuel level as 0-255 
    byte testBtn(void); // Return 1 if button pressed, 100ms delay x 2 
    
    // EEPROM Function Prototypes [4] 
    
    void loadEEPROM(void); // EEPROM data GSE: fuelCalTab[], tabMax, gaugeStep 
    void writeEE(byte addr, byte val);// write EEPROM address with val, delay 20mS 
    byte readEE(byte addr);           // return value at EEPROM address, delay 20mS 
    
    // Tank Cal Function Definitions 
    
    // [code snipped] 
    
    /*----------------------------------------- 
                    Main Program 
    -----------------------------------------*/ 
    void main( void ) 
    { 
    // [code snipped] 
    }
  • puneetsardana88
    New Member
    • Aug 2009
    • 57

    #2
    Create a single Project. Create four .C files and four header files. Include the header files needed for particular .C file. Make sure your linker path is correct.

    Comment

    • alexis4
      New Member
      • Dec 2009
      • 113

      #3
      Say you have a header file and 2 source files.
      Code:
      //mydefines.h
      
      #define  five  5
      Code:
      //file1.c
      
      #include "mydefines.h"  //declare the whole path if
      //header and source are not in the same folder
      
      int b;  //global variable, declared outside of function
      extern void func1 (int a);  //external function
      
      void main (void)
      {
        int x = five;  //"five" is from mydefines.h
        func1(x);  //external call, makes b=20
        b++;  //b = 21
      }
      Code:
      //file2.c
      
      #include "mydefines.h"
      
      extern int b;  //must be global in file1 to use it in file2
      
      void func1 (int a)
      {
        a = 2 * five;  //2*5=10
        b = a + 10;  //b=20. It shouldn't be returned
      //because it is a global variable
      }

      This is dummy code, but it contains example for global variable, external function call and custom header file, so this is everything you need.

      Comment

      • Banfa
        Recognized Expert Expert
        • Feb 2006
        • 9067

        #4
        Actually with the file structure you propose alexis the line

        extern void func1 (int a); //external function

        should not be in file1.c but should be in mydefines.h

        This ensures that file1.c that calls the function uses the same prototype as file2.c where func1 is defined.

        The basic principle is that for any function you should declare it once in a place that is visible to everywhere that calls the function as well the place it is defined.

        if you don't do this you run the risk that the function is declared and defined differently where as if you do do this and there is a mismatch between the declaration and definition the compiler will produce an error.

        The same applies to the declaration of b in file2.c

        extern int b; //must be global in file1 to use it in file2

        it should be in mydefines.h

        Comment

        • alexis4
          New Member
          • Dec 2009
          • 113

          #5
          Yeah you are right!!! I always use header files just for the defines and I call functions and variables from source files. That seemed more logical to me, because I split my source files (with their functions and variables) according to their logical operations.
          My solution also works (really, my projects are compiled just fine), but yours is much more structured. Thanks, I will definitely try it starting from the current project I am working!

          Comment

          • Banfa
            Recognized Expert Expert
            • Feb 2006
            • 9067

            #6
            If you would like a suggestion what I do is have a header file for every C file often. Then you declare everything that is defined in a give C file (file1.c for example) in the correspondingly named header file (file1.h for example).

            I normally only do it this way after there are a handful of C files otherwise I use a single header file.

            Comment

            • alexis4
              New Member
              • Dec 2009
              • 113

              #7
              Thanks Banfa, I have seen what you are saying in C-based Real Time Operating Systems, but never thought to try it my self! I concentrated at RTOS's fancy stuff like callbacks and function pointers and missed a simple but yet so important thing like that!
              Thanks again!

              Comment

              • nigelmercier
                New Member
                • Dec 2009
                • 45

                #8
                extern void func1 (int a); //external function

                should not be in file1.c but should be in mydefines.h


                Hi Banfa,

                So this is a mydefines.h file with all the function prototypes and variable declarations (all declared as external) for the whole project?

                If so, then what goes in the individual .C files, just the function bodies?

                Comment

                • Banfa
                  Recognized Expert Expert
                  • Feb 2006
                  • 9067

                  #9
                  Thats right although the normal term is function definition. Also variable definitions go in the C file. The header contains the declarations.

                  A declaration is a statement that says something, a function or variable, exists somewhere, a definition actually creates the function or variable.

                  Code:
                  // Function declaration, says func exists and 
                  // declares how to call it but doesn't define the body
                  extern int func(int x);
                  
                  // Variable declaration says var exists and what its type is
                  extern int var;
                  
                  // Function declaration, says func exists and 
                  // declares how to call it but doesn't define the body
                  extern int func(int x);
                  
                  // Variable declaration says var exists and what its type is
                  extern int var;
                  
                  
                  // Function definition defines the body of the function
                  int func(int x)
                  {
                      return x/2;
                  }
                  
                  // Variable definition causes the compiler and 
                  // linker to actually allocate storage for var
                  int var;
                  As a rule of thumb definitions actual produce some output in the program, function definitions produce executable code, variable definitions produce storeage locations while declarations are just information for the compiler while it compiles the code.


                  And finally although I have talked about variable declarations and definitions it is actually bad practice to use global data and can cause maintenance and debug fixing issues. Best practice is to not use global data, that is variables accessable from all files in a project. Data declared statically at file scope, i.e. available to all the code in a single file is not much better some is sometimes unavoidable.

                  Comment

                  Working...