Programming Style
Programming 101
You should already know most of this stuff!
Information Hiding
Simplistically
Treat different pieces (modules) of code
as black boxes.
The internal details are unknown outside
the box.
Define an interface to the box
11/09/2015
Visible functions
Visible constants and types
Private variables (with rare exceptions)
EEE20003 Embedded Microcontrollers
Trivial Examples
Charlieplexing code
What is necessary to know to use this code
(apart from the wiring)?
11/09/2015
EEE20003 Embedded Microcontrollers
Trivial Examples
ADC code
What is necessary to know to use this code
(apart from which channel)?
11/09/2015
EEE20003 Embedded Microcontrollers
C Header Files
Header files provide a poor mans
implementation of an interface to a
module.
It makes public all the accessible
elements of the module.
The internal details of the module
remain hidden (information hiding).
Much improved if used with C++ but
still may be used to achieve
information hiding in C.
11/09/2015
EEE20003 Embedded Microcontrollers
Why Use Header Files?
Good style by creating the header file you are defining
the interface to the module. If done properly you are
developing a contract about what the module does. The
internal details of the module are hidden and may be
updated without breaking other code provided the
interface is unchanged.
Consistency checks C is very poor about matching
function calls parameters and return values between
function calls and the actual function (much improved in
C++). There are default rules if none are explicitly given.
This is a significant problem if the default rules are
inappropriate! Use of header files provide a consistency
check between function use and declaration (see later
example).
11/09/2015
EEE20003 Embedded Microcontrollers
Header File Example
ADC.h
Declarations of public functions
Declarations of public variables (to be avoided where possible!)
Definitions of public constants, types etc (#defines, enums etc.)
#include
#include
ADC.c
Definitions
Definitions
Definitions
Definitions
Definitions
of
of
of
of
of
public functions
public variables
private constants
private functions
private variables
main.c
Use of public functions
Use of public variables
Use of public constants
Public means to be available for use by other modules
Private means for use within the module only
Declaration means saying the thing exists but isnt here
Definition means creating the thing itself
11/09/2015
EEE20003 Embedded Microcontrollers
Header file example
ADC.h
extern void initADC();
extern void doADCConversion(int channel);
...
LCD.c
#include "LCD.h"
void initADC() {
...
}
extern void doADCConversion(int channel){
...
}
static void privateFunction(...){
...
}
11/09/2015
EEE20003 Embedded Microcontrollers
Prototypes for
Public functions
The compiler
will check
consistency
between
these.
Public functions
Private function
8
C Header Files
No Code in Header Files
(Unlike C++ where you may have
inline member functions, constructors
etc.)
11/09/2015
EEE20003 Embedded Microcontrollers
Use of #define
Which is easier to understand and maintain?
if ((PORT & 0x02) != 0)
PORT |= 0x20;
else
PORT &= 0xDF;
#define LED
#define SWITCH
(1<<5)
(1<<1)
...
if ((PORT & SWITCH) != 0)
PORT |= LED;
else
PORT &= ~LED;
11/09/2015
EEE20003 Embedded Microcontrollers
10
#define
Using #define improves the readability of
the code as well as making it less likely that
you will make simple errors. You may
confuse 0x02 with 0x20 but are unlikely to
confuse LED with SWITCH.
It also improves the maintenance of the
code. For example, if the hardware is
changed when developing the PCB layout,
say the LED is moved to pin 0, then only
one line of code needs to be changed:
#define LED
11/09/2015
(1<<4)(1<<0)
EEE20003 Embedded Microcontrollers
11
#define
Whats wrong with the following?
What purpose has the pin?
What happens if the switch above is moved
to another pin?
#define PTT_B0 (1<<0) // input pin
#define PTT_B0 (1<<4) // input pin!
The symbol name should reflect the purpose
of the pin or mask not just be a funny way
of writing a pin number!
The above will loose marks in exams and
assignment.
11/09/2015
EEE20003 Embedded Microcontrollers
12
#define Once only
If some constant is dependent upon another
constant then derive it Dont define
independently which creates maintenance
problems. Example
// Port
#define
#define
#define
...
PDDR
T Masks
LEFT_LED
RIGHT_LED
LED_MASK
PDOR
PDOR
(1<<0)
(1<<1)
=======
(3<<0) (LEFT_LED|RIGHT_LED)
|= LED_MASK;
// Set port direction
|= LEFT_LED;
&= ~RIGHT_LED;
// Set stating LED values
Arguably there is no need for LED_MASK at all. Its just an example!
11/09/2015
EEE20003 Embedded Microcontrollers
13
Constant Expressions
It doesnt matter (within reason!) how
complicated a constant expression is. It
does not affect the runtime program since
the expression is evaluated by the compiler
and replaced by a simple constant. It just
represents extra work for the compiler and
usually less work for the programmer.
So there is no reason for getting your
calculator out when writing a program!
11/09/2015
EEE20003 Embedded Microcontrollers
14
Self scaling code #1
Add a value to the array. What
maintenance issues are there? Fix them.
int ar[4] = {10,56,29,18}; // Array of heights
...
for (sub=0; sub<4; sub++) {
// do something with ar[sub]
}
How many arrived at this?
int ar[] = {10,56,29,18};
Note: This is a constant expression = 4!
...
for (sub=0; sub < sizeof(ar)/sizeof(ar[0]); sub++) {
// do something with ar[sub]
}
Changing the array is simplified.
11/09/2015
EEE20003 Embedded Microcontrollers
15
Self scaling code #2
What maintenance issues are there?
int ar[4] = {10,56,29,18}; // Array of heights
...
for (sub=0; sub<4; sub++) {
// do something with ar[sub]
}
Second approach:
#define SENTENEL (-1)
// Array of heights
int ar[] = {10,56,29,18,SENTINEL};
...
for (sub=0; ar[sub]!=SENTENEL; sub++) {
// do something with ar[sub]
}
This approach allows use of more than
one array with the same code.
11/09/2015
EEE20003 Embedded Microcontrollers
16
C Style
Indent properly
Use mixed-case starting with lowercase
for variable names (camelCase)
Use uppercase for #define constants
this is a pain but its the accepted
standard.
emergencySwitch
EMERGENCY_SWITCH
Use a fixed-width font for printing code.
Indent properly!
11/09/2015
EEE20003 Embedded Microcontrollers
17
Meaningful Names
Use meaningful names for functions,
variables and symbols:
Avoid:
initLCD(), checkInputs()
currentNote,
MAX_RETRIES
i, tlas and cryptic abbreviations.
vague names (count what is being counted!)
stupid symbols (#define BIT0 etc.)
Some exceptions:
There are accepted names for hardware registers
and the bits within them e.g. PDDR, PDIR etc.
11/09/2015
EEE20003 Embedded Microcontrollers
18
Commenting
Strategic commenting!
Not every line needs a comment.
Comment pieces of code that work as a
unit.
Use an empty line to separate the pieces.
GPIOC->PDDR |= STOPLIGHT|EMERGENCYLIGHT;
// set port outputs
// Set motor to speed 10
GPIOC->PSOR = MOTOR_ON;
GPIOA->PDOR = (GPIOA->PDOR &~MOTOR_MASK)|MOTOR_VALUE(10);
...
11/09/2015
EEE20003 Embedded Microcontrollers
19
Commenting
Place your comments so they are easily
read:
Spaced apart at end of line.
As a mini-banner line before a block.
;************************
; Main search loop
;
loop:
cmp r0,r3
; compare memory to search key
beq foundIt ; found it exit loop
add r0,r0,#1 ; point to next location
cmp #0x2000 ; at end of range?
bls loop
; no back for more
11/09/2015
EEE20003 Embedded Microcontrollers
20
Commenting
Every function should have a banner!
Description (in English!) of what the
function does not how it does it.
Input conditions what it expects to
receive as parameters and preconditions.
Outputs how it changes any reference
parameters. Any other affects it has.
11/09/2015
EEE20003 Embedded Microcontrollers
21
Commenting
/**
* Turn on the given LED
*
* @param ledNum LED to turn on (0..6)
*
* @note 0 => All LEDs off
*/
void setLED(int ledNum) {
...
}
11/09/2015
EEE20003 Embedded Microcontrollers
22
Commenting
Comments should indicate the purpose
of the code not repeat the code in
English.
Avoid stupid comments
if (z>0)... // check if z is
// greater than 0
i = 0; // Set i to 0
The above is the jackpot It will attract
negative marks for both stupid names
and stupid comments!
11/09/2015
EEE20003 Embedded Microcontrollers
23
Classic Errors
Initialise EVERYTHING (esp. port
direction, port value).
Zero is a value don't assume it
defaults by magic!
Ports, registers, etc may be shared
use bit manipulation where needed.
Inputs may change input skew take
snapshots of a port if the relationship
between bits is important.
11/09/2015
EEE20003 Embedded Microcontrollers
24
#define Errors
#define size (23);
Error here.
but
if (x > size) {...
if (x > (23);) {...
11/09/2015
EEE20003 Embedded Microcontrollers
Syntax error
message here
25
#define Errors
#define width 3+56
i = 2 * width;
i = 2 * 3+56;
11/09/2015
EEE20003 Embedded Microcontrollers
26
Useful Techniques
Table lookup in C and Assembler
Discussed in tutorials.
Event driven
State machine approach
11/09/2015
EEE20003 Embedded Microcontrollers
27