Emd C Module3 10 June 24

Download as pdf or txt
Download as pdf or txt
You are on page 1of 25

Embedded C

1. Embedded C - Michael J. Pont, 2nd Ed., Pearson Education, 2008


2. Advanced C - Peter D. Hipson, Sams Publishing, USA, 1992
Reference Books
1. PICmicro MCU C- An introduction to programming, The Microchip PIC in CCS C – Nigel Gardner

Course Code : BEI405C


CIE Marks : 50
SEE Marks : 50
Credits : 3
Teaching Hours/Week (L:T:P: S) : 3:0:0:0
Total Hours of Pedagogy : 40

1
OUTCOME OF MODULE

At the end of the course, the student will be able to:


CO1: Know about programming concepts in embedded system design.
CO2: Understand features and concepts of embedded programming languages.
CO3: Able to describe how microcontroller based embedded systems are programmed and implemented
in real time applications.
CO4: Write simple programs and implement the same embedded hardware.

2
Module - 3
Adding Structure to the Code
 Introduction, Object-oriented programming with C,
 The Project Header (MAIN.H), The Port Header (PORT.H),
 Example: Restructuring the ''Hello Embedded World‟ example,
 Example: Restructuring the goat-counting example,
 Further examples, Conclusions,

3
Adding structure to your code
Introduction,
 In previous chapters we have examined key technical issues (such as the use of a Super Loop, or the design
and implementation of an appropriate switch interface).
 This Chapter discusses the following three things.
1. We will describe how to use an object-oriented style of programming with C programs, allowing the
creation of libraries of code that can be easily adapted for use in different embedded projects.
2. We will describe how to create and use a ‘Project Header’ file. This file encapsulates key aspects of the
hardware environment, such as the type of processor to be used, the oscillator frequency and the number of
oscillator cycles required to execute each instruction. This helps to document the system, and makes it
easier to port the code to a different processor.
3. We will describe how to create and use a ‘Port Header’ file. This brings together all details of the port access
from the whole system. Like the Project Header, this helps during porting and also serves as a means of
documenting important system features.

4
Object-oriented programming with C:
The different programming languages may be classified is as a series of generations

A frequent argument is that the O-O approach is more effective than those previously used because it represents
‘a more natural way’ of thinking about problems.
One main claimed advantage of using object orientation is that an OO model closely represents the problem
domain, which makes it easier to produce and understand designs.
Why this book uses C, rather than a language from a later generation (such as C++ or Java). The reason is that
O-O languages are not readily available for small embedded systems, primarily because of the overheads
inherent in the O-O approach.

5
Object-oriented programming with C: continued…
 Suppose, for example, we have a C program with a variable Xyz that we wish to set to some value and then display.
We might do so using the following code:
...
int Xyz;
Xyz = 3;
...
printf("%d", Xyz);
Now, consider the following O-O version, using C++:
class cClass
{
public:
int Get_Xyz(void) const;
void Set_Xyz(const int);
private:
int _Xyz; // Encapsulated data
};
...
cClass abc;
abc.Set_Xyz(3);
...
cout << abc.Get_Xyz();

6
Object-oriented programming with C: continued…:
The C++ version has both strengths and weaknesses:
In the C++ code, the data (_Xyz) are encapsulated in the class: access to these data is controlled because it is
possible only via the two member functions.
By contrast, the data (Xyz) in the C version are ‘global’ variables and can be altered anywhere in the program.
From a design perspective, the C++ code is more elegant. It may also prove easier to maintain.
There is a CPU time overhead associated with the C++ code:C++ implementation is likely to run 25% more
slowly than an equivalent application in FORTRAN.17 This can have implications for embedded projects where
speed of processing is a primary concern.
C programmers used a ‘modular’ style of programming which is well supported by the language. Using this
approach, it is possible to create ‘file based- classes’ in C without imposing a significant memory or CPU load.
// BEGIN: File XYZ.C The change here is minor: simply using the C keyword static to ensure that only
static int Xyz; functions within the file XYZ.c are able to access the data Xyz.
Xyz = 3; As a consequence, the source file becomes our ‘class’ and the ‘static’ data in that
... file become private data members of that class.
printf("%d", Xyz); The functions defined within the file become the member functions in our class,
// END: File XYZ.C and our whole program may be split into a number of clearly-defined (file-based)
classes.

7
Object-oriented programming with C: continued…

Note that we can also create ‘private’ member functions (which are accessible only by functions defined within a
particular file) simply by including the prototypes for the function in the .C file (rather than the .H file) for the
particular class.
This process is illustrated in the following code example. These files are part of a library of code designed to allow
an 8051 microcontroller to use a serial interface.

8
Object-oriented programming with C: continued…
 Consider the following code library structure. As you look at this code, please note the presence of:
public ‘member’ functions, such as PC_LINK_IO_Write_String_To_Buffer(). Such functions have their prototypes in the H
file.
a private ‘member’ function, PC_LINK_IO_Send_Char(). Such static functions have their prototypes in the C file.
a public constant (PC_LINK_IO_NO_CHAR), with a value which must be accessed by the rest of the program.
a limited number of public variables (e.g. In_read_index_G), defined in the C file (without the use of the static keyword).
numerous private constants and private variables (e.g. RECV_BUFFER_LENGTH), which are ‘invisible’ outside the C
file.
An example of a file-based C class (H file).
/* PC_IO.H */
#ifndef _PC_IO_H
#define _PC_IO_H
// ------ public constants ------------
#define PC_LINK_IO_NO_CHAR 127
// ------ public function prototypes --------------------------
void PC_LINK_IO_Write_String_To_Buffer(const char* const);
void PC_LINK_IO_Write_Char_To_Buffer(const char);
char PC_LINK_IO_Get_Char_From_Buffer(void);
// Must call this function frequently...
void PC_LINK_IO_Update(void);
#endif

9
Object-oriented programming with C: continued…
An example of a file-based C class (C file). See text for details
/*---- PC_IO.C -----*/
#include "Main.H"
#include "PC_IO.H"
// ------ public variable definitions -------------------------
tByte In_read_index_G; // Data in buffer that has been read
tByte In_waiting_index_G; // Data in buffer not yet read
// ------ private function prototypes -------------------------
static void PC_LINK_IO_Send_Char(const char);
// ------ private constants -----------------------------------
#define RECV_BUFFER_LENGTH 8
#define TRAN_BUFFER_LENGTH 50
// ------ private variables -----------------------------------
static tByte Recv_buffer[RECV_BUFFER_LENGTH];
static tByte Tran_buffer[TRAN_BUFFER_LENGTH];

void PC_LINK_IO_Update(...) { . . . }
void PC_LINK_IO_Write_Char_To_Buffer(...) { . . . }
void PC_LINK_IO_Send_Char(...) { . . . }

Overall, this approach is very common in C programs. If used with care (and, where necessary) it can provide
many of the benefits of an O-O language without the corresponding performance or memory costs.

10
The Project Header (Main.H):
The ‘Project Header’ is simply a header file, included in all projects, that groups the key information about the
8051 device you have used, along with other key parameters – such as the oscillator frequency – in one file.
 As such, it is a practical implementation of a standard software design guideline: ‘Do not duplicate information in
numerous files; place the information in one place, and refer to it where necessary.’
An example of a typical project header file :

Project Header (Main.H)


#include <AT89S53.H>
...
#define OSC_FREQ(11059200UL)
...
typedef unsigned char tByte;
...

11
The Project Header (Main.H):
/* Main.H (v1.00)*/
// Typedefs
typedef unsigned char tByte;
#ifndef _MAIN_H
typedef unsigned int tWord;
#define _MAIN_H
typedef unsigned long tLong;
// Interrupts (see Chap 7)
// header file
#define INTERRUPT_Timer_0_Overflow 1
#include <reg52.h>
#define INTERRUPT_Timer_1_Overflow 3
#define INTERRUPT_Timer_2_Overflow 5
// Oscillator / resonator frequency (in Hz) e.g.
#endif
(11059200UL)
/*- END OF FILE --*/
#define OSC_FREQ (12000000UL)
// Number of oscillations per instruction (12, etc)
// 12 – Original 8051 / 8052 and numerous modern
versions
// 6 – Various Infineon and Philips devices, etc.
// 4 – Dallas 320, 520 etc.
// 1 – Dallas 420, etc.
#define OSC_PER_INST (12)

12
a) The device header
 The first entry in the project header is the link to the appropriate ‘device header’ file (‘reg52.h’) .
 These files will, in most cases, have been produced by the compiler manufacturer, and will include the addresses
of the special function registers (SFRs) used for port access, plus similar details for other on-chip components
such as analog-to-digital converters.
For example, the following code shows part of the device header for an Extended 8051, the Infineon C515C. This
device has eight ports, a watchdog unit, analog-to-digital converter and other components, all made accessible
through the device header.
/* REG515C.H */
/* Serial Channel */
/* A/D Converter */
sfr SCON = 0x98;
sfr ADCON0 = 0xD8;
...
...
/* Timer0 / Timer1 */
/* Interrupt System */
sfr TCON = 0x88;
sfr IEN0 = 0xA8;
...
...
/* CAP/COM Unit / Timer2 */
/* Ports */
sfr CCEN = 0xC1;
sfr P0 = 0x80;
...
sfr P1 = 0x90;
/* Watchdog */
sfr P2 = 0xA0;
sfr WDTREL = 0x86;
sfr P3 = 0xB0;
/* Power Save Modes */
sfr P4 = 0xE8;
sfr PCON = 0x87;
sfr P5 = 0xF8;
sfr PCON1 = 0x88;
sfr P6 = 0xDB;
sfr P7 = 0xFA;
...
13
b) Oscillator frequency and oscillations per instruction
If we create an application using a particular 8051 device operating at a particular oscillator frequency, with a particular
number of oscillations per instruction, this information will be required when compiling many of the different source files in
your project.
For example – in many cases – we can create code for generating delays (and similar purposes) if we store information about
the oscillator frequency and number of oscillations-per-instruction in an appropriate form.
This is done in the Main.H file as follows:

// Oscillator / resonator frequency (in Hz) e.g. (11059200UL)


#define OSC_FREQ (12000000UL)
// Number of oscillations per instruction (12, etc)
// 12 – Original 8051 / 8052 and numerous modern versions
// 6 – Various Infineon and Philips devices, etc.
// 4 – Dallas 320, 520 etc.
// 1 – Dallas 420, etc.
#define OSC_PER_INST (12)

14
c) Common data types
 The next part of the Project Header file in Listing includes three typedef statements:
typedef unsigned char tByte;
typedef unsigned int tWord;
typedef unsigned long tLong;
 In C, the typedef keyword allows us to provide aliases for data types: we can then use these aliases in place of the
original types. Thus, in the projects we will see code like this:
tWord Temperature;
Rather than:
unsigned int Temperature;
 The main reason for using these typedef statements is to simplify – and promote – the use of unsigned data types. This
is a good idea for two main reasons:
 The 8051 does not support signed arithmetic and extra code is required to manipulate signed data: this reduces your
program speed and increases the program size. Wherever possible, it makes sense to use unsigned data, and these
typedef statements make this easier.
 Use of bitwise operators generally makes sense only with unsigned data types: use of ‘typedef’ variables reduces the
likelihood that programmers will inadvertently apply these operators to signed data.

15
d) Interrupts
 Interrupts are a key component of most embedded systems. The following lines in the Project Header are intended to
make it easier for us to use (timer-based) interrupts in our projects:
#define INTERRUPT_Timer_0_Overflow 1
#define INTERRUPT_Timer_1_Overflow 3
#define INTERRUPT_Timer_2_Overflow 5

e) Summary: Use of a Project Header?


Use of Project Header can help to make our code more readable, not least because anyone using your projects knows
where to find key information, such as the model of microcontroller and the oscillator frequency required to execute the
software.
The use of a Project Header can help to make our code more easily portable, by placing some of the key microcontroller-
dependent data in one place: if you change the processor or the oscillator used then in many cases – we will need to make
changes only to the Project Header.

16
The Port Header (Port.H)
 In a typical embedded project, an user interface created using an LCD, a keypad, and one or more single LEDs.
There may be a serial (RS-485) link to another microcontroller board. There may be one or more high-power
devices (say 3-phase industrial motors) to be controlled. Each of these (software) components in the application
will require exclusive access to one or more port pins.
 The project may include 10–20 different source files, created – perhaps – by five different people. How do you
ensure that changes to port access in one component does not impact on another? How do you ensure that it is
easy to adapt the application to an environment where different port pins must be used?
These issues are addressed through the use of a simple Port Header file (Figure 5.3). Using a Port Header, you
pull together the different port access features for the whole project into a single (header) file. Use of this
technique can ease project development, maintenance and porting.

17
The Port Header (Port.H) : Continued...
The Port Header file is simple to understand and easy to apply. Consider, for example, that we have three C files
in a project (A, B, C), each of which require access to one or more port pins, or to a complete port.
File A may include the following:
// File A
sbit Pin_A = P3^2;
...
File B may include the following:
// File B
#define Port_B P0
...
File C may include the following:
// File C
sbit Pin_C = P2^7;
...
In this version of the code, all of the port access requirements are spread over multiple files. Instead of this, there are
many advantages obtained by integrating all port access in a single Port.H header file:
// ----- Port.H -----
// Port access for File B
#define Port_B P0
// Port access for File A
sbit Pin_A = P3^2;
// Port access for File C
sbit Pin_C = P2^7;
… Each of the remaining project files will then ‘#include’ the file ‘Port.H’. 18
Example: Restructuring the Hello, Embedded World example
We present here the complete source code listing for the ‘Hello, Embedded World’ example
/*Main.H (v1.00) 'Project Header' */ /*Main.C A "Hello Embedded World" test program */
#ifndef _MAIN_H #include "Main.H"
#define _MAIN_H #include "Port.H"
#include <reg52.h> #include "Delay_Loop.h"
// Oscillator frequency (in Hz) #include "LED_Flash.h"
#define OSC_FREQ (12000000UL) void main(void)
// Number of oscillations per instruction (12, etc) {
#define OSC_PER_INST (12) LED_FLASH_Init();
// Typedefs while(1)
typedef unsigned char tByte; {
typedef unsigned int tWord; // Change the LED state (OFF to ON, or vice versa)
typedef unsigned long tLong; LED_FLASH_Change_State();
// Interrupts // Delay for *approx* 1000 ms
#define INTERRUPT_Timer_0_Overflow 1 DELAY_LOOP_Wait(1000);
#define INTERRUPT_Timer_1_Overflow 3 }
#define INTERRUPT_Timer_2_Overflow 5 }
#endif /* END OF FILE */
/* END OF FILE */

19
Example: Restructuring the Hello, Embedded World example
/*LED_flash.C */
/*Port.H 'Port Header'*/
#include "Main.H"
#ifndef _PORT_H
#include "Port.H"
#define _PORT_H
#include "LED_flash.H"
// Connect LED to this pin, via appropriate resistor
//Private variable definitions
sbit LED_pin = P1^5;
static bit LED_state_G;
#endif
void LED_FLASH_Init(void)
/*END OF FILE */
{
LED_state_G = 0;
/*LED_flash.H */
}
void LED_FLASH_Change_State(void)
#ifndef _LED_FLASH_H
{
#define _LED_FLASH_H
// Change the LED from OFF to ON (or vice versa)
//Public function prototypes
if (LED_state_G == 1)
void LED_FLASH_Init(void);
{
void LED_FLASH_Change_State(void);
LED_state_G = 0;
#endif
LED_pin = 0;
/* END OF FILE*/
}
else
{
LED_state_G = 1;
LED_pin = 1;
}
} /*END OF FILE*/ 20
Example: Restructuring the Hello, Embedded World example
/*Delay_Loop.C */
/*Delay_Loop.H */
#include "Main.H"
#ifndef _DELAY_LOOP_H
#include "Port.H"
#define _DELAY_LOOP_H
#include "Delay_loop.h"
// Public function prototype
void DELAY_LOOP_Wait(const tWord);
void DELAY_LOOP_Wait(const tWord DELAY_MS)
#endif
{
/*END OF FILE*/
tWord x, y;
for (x = 0; x <= DELAY_MS; x++)
{
for (y = 0; y <= 120; y++);
}
}
/*END OF FILE */

21
Example: Restructuring the goat-counting example
In Chapter 4, an example in which the number of goats passing a sensor was measured and displayed on a port.
Here another version of this example, restructured according to the guidelines presented in this chapter.
/*Main.H */ /*Port.H */ /*Main.C */
#ifndef _MAIN_H #ifndef _PORT_H #include "Main.H"
#define _MAIN_H #define _PORT_H #include "Port.H"
//include the appropriate header file // Connect switch to this pin #include "Switch_wait.H"
#include <reg52.h> sbit Switch_pin = P1^0; #include "Display_count.H"
//Oscillator frequency (in Hz) // Display count (binary)
#define OSC_FREQ (12000000UL) //on this port void main(void)
#define OSC_PER_INST (12) #define Count_port P3 {
// Typedefs #endif tByte Switch_presses = 0;
typedef unsigned char tByte; /* END OF FILE*/ // Init functions
typedef unsigned int tWord; SWITCH_Init();
typedef unsigned long tLong; DISPLAY_COUNT_Init();
// Interrupts while(1)
#define INTERRUPT_Timer_0_Overflow 1 {
#define INTERRUPT_Timer_1_Overflow 3 if (SWITCH_Get_Input(30) == SWITCH_PRESSED)
#define INTERRUPT_Timer_2_Overflow 5 {
#endif Switch_presses++;
/*END OF FILE */ }
DISPLAY_COUNT_Update(Switch_presses);
}
} /*END OF FILE */ 22
Example: Restructuring the goat-counting example
/*Switch_wait.H */ bit SWITCH_Get_Input(const tByte
/*Switch_Wait.C*/
DEBOUNCE_PERIOD)
#ifndef _SWITCH_WAIT_H #include "Main.H"
{
#define _SWITCH_WAIT_H #include "Port.H"
bit Return_value = SWITCH_NOT_PRESSED;
// Public constants #include "Switch_wait.h"
if (Switch_pin == 0)
// Return values from Switch_Get_Input() #include "Delay_loop.h“
{
void SWITCH_Init(void)
#define SWITCH_NOT_PRESSED (bit) 0 // Switch is pressed
{
#define SWITCH_PRESSED (bit) 1 // Debounce – just wait...
Switch_pin = 1; // Use this pin for input
// Public function prototype DELAY_LOOP_Wait(DEBOUNCE_PERIOD);
}
// Check switch again
void SWITCH_Init(void); /*
if (Switch_pin == 0)
bit SWITCH_Get_Input(const tByte); SWITCH_Get_Input()
{
#endif Reads and debounces a mechanical switch as follows:
// Wait until the switch is released.
/*END OF FILE */ 1. If switch is not pressed, return
while (Switch_pin == 0);
SWITCH_NOT_PRESSED.
Return_value = SWITCH_PRESSED;
2. If switch is pressed, wait for DEBOUNCE_PERIOD
}
(in ms).
}
a. If switch is not pressed, return
return Return_value;
SWITCH_NOT_PRESSED.
}
b. If switch is pressed, wait (indefinitely) for
/*END OF FILE */
switch to be released, then return SWITCH_PRESSED
*/

23
Example: Restructuring the goat-counting example
/*Display_count.H */ /*Delay_Loop.H */
#ifndef _DISPLAY_COUNT_H #ifndef _DELAY_LOOP_H
#define _DISPLAY_COUNT_H #define _DELAY_LOOP_H
// Public function prototypes // Public function prototype
void DISPLAY_COUNT_Init(void); void DELAY_LOOP_Wait(const tWord);
void DISPLAY_COUNT_Update(const) tByte; #endif
#endif /*END OF FILE */
/* END OF FILE*/
/*Delay_Loop.C*/
/*Display_count.C */ #include "Main.H"
#include "Main.H" #include "Port.H"
#include "Port.H" #include "Delay_loop.h"
#include "Display_Count.H"
void DELAY_LOOP_Wait(const tWord DELAY_MS)
void DISPLAY_COUNT_Init(void) {
{ tWord x, y;
Count_port = 0x00; for (x = 0; x <= DELAY_MS; x++)
} {
void DISPLAY_COUNT_Update(const tByte COUNT) for (y = 0; y <= 120; y++);
{ }
Count_port = COUNT; }
} /*END OF FILE */
/* END OF FILE */
24
Module-3 Questions
1. List the classification of programming languages based on different generations and main advantages of object-oriented
(O-O) design – and O-O programming languages.
2. With a code fragment explain the strengths and weaknesses of C++.
3. Explain Turning a monolithic program into object-oriented C along with the block diagram and program example.
4. Discuss The Project Header (Main.H) file.
5. Discuss The Port Header (Port.H) file.
6. Write the restructured complete source code listing for the ‘Hello, Embedded World’ example.
7. Write the restructured complete source code listing for the ‘goat-counting ‘ example.

You might also like