|
The purpose of these rules is to structure and to standardize the code wrote in C for embedded applications in order to give enough documentation and to trace the modifications.
These rules are not a reference but it's a compilation of rules and tips which will be useful and will garant that all projects will be designed in the same way. As I'm not a senior software engineer, this may be improved.
Structure of a C project
An embedded software should be cut in as many files as function groups. A function group is the set of functions dealing with the same hardware ressoruces or the same functionalities.
For example, all the timer functions will be in the same file. The purpose is to make easier the functions localisation and of course to bring an application layer file to an other project without modification.
Of course, each project contains a MAIN.C file. This file has an single function ; main (), ... AND THAT'S ALL ! Usually this function calls a real time sequencer or a main loop.This is a general rule to write with ANSI.
It's also the use to write a function without direct hardware adressing but by using a driver function. For example, a routine used to control a motor with PWM shouldn't refer to an hardware register or port. The output will applied for example to a 'MotorControlOutput' label and this one will be defined as a register or a port name in the header file.
Project Example :
|
MAIN.C
|
This function calls the hardware and software initialization routines. Next it call the real time sequencer.
|
|
RREX.C
|
This file contains the real time sequencer. All the application routines will be called from this file.
|
|
RREX.H
|
Contains al the external function prototypes and definition
|
|
HLCD.C
|
Contains the character LCD driver
|
|
HLCD.H
|
Contains al the external function prototypes and definition
|
|
TDEF.H
|
Describes the equivalences (type definitions ...)
|
|
REG51.H
|
Microcontroller registers definitions
|
|
INIT.C
|
Initialization routines
|
|
INIT.H
|
Contains al the external function prototypes and definition
|
Coding rules
The use it to write in English. This allows of course to work with everybody anywhere. This is needed on international projects but it's also a standardization token. The code could be easily modified by a foreign trainee or be used later on a foreign project. The other interrest of English when it's not the mother langage is that it forces you to be concise. Please, use an easily readable english without any acronym and without prose style.
The code comments should be enough detailled to let somebody to understand a function without re-write it. It's useful to comment an evident variable or a trick.
File names
The file name should have only 4 characters. Please, use a name easily understandable. The 4 characters limitation will allow to include the file name in the functions names. We will see below.
Examples
| MAIN.C |
contains main() |
| DSIP.C |
For Digital Signal Input Processing, for digital sampling. |
| ASIP.C |
For Analog Signal Input Processing, for analog sampling |
| RREX.C |
For Regular Runtime EXecutive. Real Time Sequencer |
Header files
The headers must be complete and clear. It allows to trace the modifications or to explain some functions purpose.
The following template includes all the needed informations :
/********************************************************************************
NAME : GLCD.C
EXTENDED NAME : Graphic LCD functions
LAYER : Application
DESCRIPTION : the purpose of this function is to manage a graphic LCD
by providing function for control and display texts and graphics
AUTHOR : Stephane REY
REVISIONS :
--------------------------------------------------------------------------------
DATE VERSION REVISOR DESCRIPTION
--------------------------------------------------------------------------------
11.07.2001 V1.0 SR Initialization
--------------------------------------------------------------------------------
********************************************************************************/
Declarations and definitions
There is several kinds of declarations :
- The platform used
- the header files included
- the local or global functions
- the local or global variables
/*******************************************************************************/
/* DECLARATIONS / DEFINITIONS */
/*******************************************************************************/
/* Platform Type Definitions. */
#include "reg51f.h"
#include "tdef.h"
/* Family Declaration(s). */
#include <glcd.h>
#include <uart.h>
/* External Declaration(s). */
/* Local functions prototypes */
void LcdSelectSide(U8);
void LcdDataWrite (U8);
void LcdInstructionWrite (U8);
U8 LcdDataRead (void);
void LcdSetDot (U8, U8);
/* Local variables */
/*******************************************************************************/
/* PROGRAM CODE */
/*******************************************************************************/
Types
Some compilers doesn't assign the same type to a variable defined in the same way. For example, the 'int' type may be a 8 or 16 bits lenght according to the microcontroller used. This is the same for the 'long' type which may be a 32 or 64 bits lenght.
This is why it's needed to standardize the types to make easier the use of a source in an other project on an other hardware target.
We could define as :
typedef unsigned int BOOL; /* 1-Bit. */
typedef signed char S8; /* 8-Bit Signed. */
typedef unsigned char U8; /* 8-Bit Unsigned. */
typedef signed short S16; /* 16-Bit Signed. */
typedef unsigned short U16; /* 16-Bit Unsigned. */
typedef signed long S32; /* 32-Bit Signed. */
typedef unsigned long U32; /* 32-Bit Unsigned. */
Thus a variable declaration should be :
U16 nom_variable;
Functions
The name of the external functions will be made up of the name file and the function name. The internal functions havn't the name file in their name. This allows to distinguish quickly is a function is an internal one or if it may be called from an other module.
The external function prototypes are defined in the header file whereas the internal function prototype are declared in the header of the C file.
Examples :
HLCD_Locate (U8 u8Column, U8 u8Line) is an external function coded in the HLCD file and declared in the HLCD.H
LcdWrite(U8 u8Function,U8 *au8String)is an internal function declared and wrote in the HLCD.C file.
The funtion should start with the function I/O description :
Example 1 :
/*-------------------------------------------------------------------------------
Set the cursor position on the LCD display
HLCD_LcdLocate (U8 u8Column, U8 lcd_line)
u8Column : column number
u8Line : line number
-------------------------------------------------------------------------------*/
void HLCD_Locate (U8 u8Column, U8 u8Line)
{
....
}
Example 2 :
/*-------------------------------------------------------------------------------
Convert a digital value into an ASCII string
HLCD_DisplayValue (U32 u32Value, U8 u8NumberOfIntegerDigits,
U8 u8NumberOfDecimalDigits)
u32Value = 32 bits Value to display
u8NumberOfIntegerDigits = Number of interger digits.If this number is higher than the number of integer digits, it will display the non significant '0'
u8NumberOfDecimalDigits = Number of decimal digits
-------------------------------------------------------------------------------*/
void HLCD_DisplayValue (U32 u32Value, U8 u8NumberOfIntegerDigits,
U8 u8NumberOfDecimalDigits)
{
....
}
Variables names
The variables names are preceded by their type. This allows to identify quickly a variable type and to avoid to try to fit a U32 in a U8 !
The variable name should be in clear.
Examples :
au16MinIdleTime[u16PathNumber]
MinIdleTime is an array of U16 (Array Unsigned 16 bits = au16)
u16StartDate
StartDate is an U16 variable
*au8Text
Text is an array of U8 (au8)
|