CH 05
CH 05
Han-Way Huang
September 2009
Introduction to C
A C Program Example
Data Types
- C has five basic data types: void, char, int, float, and double.
- The void type represents nothing and is mainly used with function.
- A variable of type char can hold a single byte of data.
- A variable of type int is an integer that is the natural size for a particular machine.
- The type float refers to a 32-bit single-precision floating-point number.
- The type double refers to a 64-bit double-precision floating-point number.
- Qualifiers short and long can be applied to integers. For GNU C compiler,
short is 16 bits and long is 32 bits.
- Qualifiers signed and unsigned may be applied to data types char and integer.
Declarations
- A declaration specifies a type, and contains a list of one or more variables of that
type.
Examples of declarations
int i, j, k;
char cx, cy;
int m = 0;
char echo = ‘y’; /* the ASCII code of letter y is assigned to variable echo. */
Constants
Arithmetic Operators
Bitwise Operators
C provides six operators for bit manipulations; they may only be applied to
integral operands.
& AND
| OR
^ XOR
~ NOT
>> right shift
<< left shift
>> can be used to shift the involved operand to the right for the specified number
of places.
<< can be used to shift the involved operand to the left for the specified number
of places.
The assignment operator = is often combined with the operator. For example,
- Relational operators are used in expressions to compare the values of two operands.
- The value of the expression is 1 when the result of comparison is true. Otherwise,
the value of the expression is 0.
- Relational and logical operators:
== equal to
!= not equal to
> greater than
>= greater than or equal to
< less than
<= less than or equal to
&& and
|| or
! not (one’s complement)
Control Flow
If-Else Statement
if (expression)
statement1
else -- The else part is optional.
statement2
Example
if (a != 0)
r = b;
else
r = c;
r = (a != 0)? b : c;
if (expression1)
statement1
else if (expression2)
statement2
else if (expression3)
statement3
…
else
statementn
Example
if (abc > 0) return 5;
else if (abc = 0) return 0;
else return -5;
For-Loop Statement
where, expr1 and expr2 are assignments or function calls and expr3 is a
relational expression.
Example
sum = 0;
for (i = 1; i < 10; i++)
sum += i * i;
While Statement
while (expression)
statement
Example
int_cnt = 5;
while (int_cnt); // do nothing while the variable int_cnt 0
do int digit = 9;
statement do
while (expression); printf(“%d “, digit--);
while (digit >= 1);
- Between the % and the conversion character there may be, in order:
1. A minus sign, -- specify left adjustment.
2. A number that specifies the minimum field width.
3. A period that separates the field width from precision.
4. A number, the precision, that specifies the maximum number of characters to
be printed from a string, or the number of digits after the decimal point, or
the minimum of digits for an integer.
5. An h if the integer is to be printed as a short, or l (letter ell) if as a long.
Example
Example 5.4 Write a function to find the square root of a 32-bit integer using the successive
approximation method.
Solution:
Example 5.5 Write a function to test whether a 32-bit nonnegative integer is a prime
number
Solution: An integer is a prime if it cannot be divided by any integer between 2 and its
square root.
unsigned int PrimeTest(unsigned long int xval)
{
unsigned long int TLimit;
unsigned int ptest;
Example 5.6 Write a program to find the number of prime numbers between 100 and
1000.
Solution:
#include "c:\cwHCS12\include\hcs12.h"
unsigned long int FindSqr (unsigned long int xval);
unsigned int PrimeTest(unsigned long int xval);
unsigned int prime_count;
void main(void) {
unsigned long int i;
prime_count = 0;
for (i = 100; i <= 1000; i++) {
if (PrimeTest(i))
prime_count ++;
}
while(1);
}
#Include PrimeTest here
#Include FindSqr here
Function Prototype
A function cannot be called before it has been defined.
This dilemma is resolved by using the function prototype statement.
The syntax for a function prototype statement is as follows:
Exmaple
type_name *pointer_name;
Examples
int *ax;
char *cp;
- Use the unary operator & to assign the address of a variable to a pointer. For example,
int x, y;
int *ip;
ip = &x;
y = *ip; // y gets the value of x
Arrays
An array consists of a sequence of data items that have common characteristics.
Each array is referred to by specifying the array name followed by one or more subscripts,
with each subscript enclosed in brackets. Each subscript is a nonnegative integer.
The number of subscripts determines the dimensionality of the array. For example,
Structures
- A group of related variables that can be accessed through a common name.
- Each item within a structure has its own data type, which can be different.
- The syntax of a structure is as follows:
The struct_name is optional and if it exists, defines a structure tag that defines a type. For
example,
struct catalog_tag {
char author [40];
char title [40];
char pub [40];
unsigned int date;
unsigned char rev;
} card;
Unions
A variable that may hold (at different times) objects of different types and sizes, with
the compiler keeping track of size and alignment requirements.
The syntax is as follows:
union union_name {
type-name1 element1;
type-name2 element2;
…
type-namen elementn;
};
union u_tag {
int i;
char c[4];
} temp;
union-name.member
Example 5.8 Write a program to display one LED at a time from the circuit in Figure
4.16 with each LED to be lighted for 200 ms.
Solution:
#include "c:\cwHCS12\include\hcs12.h"
void SetClk8(void); // need to include SetClk.c to project
void delayby100ms(int k); // include delay.c to project
void main (void)
{
unsigned char led_tab[16]=
{0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
char i;
DDRB = 0xFF; // configure Port B for output
DDRJ |= 0x02;// configure PJ1 pin for output
PTJ &= 0xFD; // enable LEDs to light
SetClk8(); // set E clock to 24-MHz
while (1) {
for (i = 0;i < 16; i++) {
PTB = led_tab[i]; // output a new LED pattern
delayby100ms(2);// wait for 200 ms
}
}
}
Copyright © 2010 Delmar Cengage Learning H. Huang Transparency No.5-33
The HCS12/MC9S12 Microcontroller
Example 5.9 Write a program to display the following patterns from the seven-segment
display circuit shown in Figure 4.18 from display #0 to #5 and repeat with each pattern
lasting for 600 ms:
123456
234567
345678
#0 #1 #5
456789 800 a a . . . a
567890 b b . . . b
.
. .
678901 . 800 g . g
789012 . . . . g
890123 74HC244 common common common
cathode cathode cathode
PB0
PB1
PB6
901234 74HC367
012345
PP0 A0 Y0
Solution:
PP1 A1 Y1
PP2 A2 Y2 .
PP3 A3 Y3 .
.
PP4 A4 Y4
PP5 A5 Y5
Figure 4.18 Port B and Port P together drive six seven-segment displays (MC9S12DG256)
Solution: There are ten different pattern sequences and two adjacent sequences are
offset by 1. The overlapping these sequences are shown in Figure 5.2.
Let SegPat, i, j, and k represent the segment table of 15 segment patterns, the start index
of the sequence to be displayed, the number of times of the current sequence remained
to be repeated, and the display to be lighted at the moment.
#include "c:\cwHCS12\include\hcs12.h"
#include "c:\cwHCS12\include\delay.h“ // include delay.c to the project
void SetClk8(void); // include SetClk.c to the project
unsigned char SegPat[16] = {0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x67,0x3F,
0x06,0x5B,0x4F,0x66,0x6D};
unsigned char digit[6] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF};
void main(void) {
int i, j, k;
SetClk8(); // set E clock frequency to 24 MHz
DDRB = 0xFF; //configure Port B for output
DDRP = 0xFF; //configure Port P for output
while(1) {
for (i = 0; i < 10; i++) { // pattern array start index
for (j = 0; j < 100; j++) { // repeat loop for each pattern sequence
for (k = 0; k < 6; k++) { // select the display # to be lighted
PTB = SegPat[i+k]; // output segment pattern
PTP = digit[k]; // output digit select value
delayby1ms(1); // display one digit for 1 ms
}
}
}
}
}
Copyright © 2010 Delmar Cengage Learning H. Huang Transparency No.5-36
The HCS12/MC9S12 Microcontroller
External Variables
Scope Rules
- The functions and external variables that make up a C program can be compiled separately.
- The source text of the program may be kept in several files.
- The scope of a name is the part of the program within which the name can be used.
- For a variable declared at the beginning of a function, the scope is the function in which the
name is declared.
- Local (internal) variables of the same name in different functions are unrelated.
- The scope of an external variable or a function lasts from the point at which it is declared
to the end of the file being compiled.
In the following program segment The use of external variables are illustrated
in the following 2-file C program
… in file 1
void f1 (…) extern int xy;
{ extern long arr [ ];
… main ( )
} {
…
int a, b, c; }
void f2(…) void foo (int abc) { … }
{ long soo (void) { … }
…
} in file 2
int xy;
Variables a, b, and c are accessible to long arr [100];
function f2 but not f1.
Type Casting
Type casting forces a variable of some type into a variable of different type.
The format is (type) variable.
It is often used to avoid size mismatch among operands for computation.
long result;
int x1, x2;
…
result = x1 * x2;
The value of the product of x1 and x2 would be truncated when it exceeds 16 bits.
The solution to the problem is to use type casting:
Type casting also allows one to treat a variable of certain type as a variable of different
type to simplify the computation.
struct personal {
char name[10];
char addr [20];
char sub1[5];
char sub2[5];
char sub3[5];
char sub4[5];
} ptr1;
char *cp;
One can use type casting technique to treat the variable ptr1 as a string:
cp = (char *)&ptr1;
The HCS12 allows all of the peripheral registers to be relocated as a block. For this reason,
the ImageCraft uses the following method to define peripheral registers:
The header file hcs12.h provided in the complementary CD uses the following format:
Examples
asm(“swi”); // software interrupt
asm(“cli”); // enable interrupt globally
The setting in Figure 5.26 works for the Dragon12 demo board.
After setting up the options and clicking OK, the ICC12 C compiler will remember
all the settings until the user change them.
ICC12 Compiler requires a putchar function for the printf function to work. We
created this function and add it to this example project. This is done by pressing the
Project menu and selecting Add File(s)… to bring up the dialog for adding a file.
The add file dialog is shown in Figure 5.30.
After adding gcd.c and putchar.c into the project, the screen changes to that in
Figure 5.31.
ICC12 IDE does not allow the user to set up a watch list to monitor the change of program
variables. The user needs to find out the address of program variables by looking at the
program map file.
For example, by making result a global variable and recompiling the program and browse
the icctutor.mp file, we find that result is assigned to location $1000 as shown in Figure
5.33.
The user can then use the D-Bug12 command md $1000 to display the value of result.
C Programming Style
Programming style refers to a set of rules and guidelines used when writing a program.
The essence of good programming style is communication.
The objective of a good programming style is to make the program easy to understand
and debug.
A programmer uses three primary tools to communicate their intentions: comment,
naming of variables, constants, and functions, and program appearance (spacing,
alignment, and indentation).
Program Documentation
All programs should include, at the beginning of the program, a comment block that
Includes at least:
The programmer’s name
The date of creation
The operating system and IDE for which the program was written
Hardware environment (circuit connection) to run the program
Program structure (organization)
Algorithm and data structures of the program
How to run the program
// ----------------------------------------------------------------------------------------------------------------
// Program: RtiMultiplex7segs
// Author: Han-Way Huang
// Build Environment: CodeWarrior IDE under Windows XP
// Date: 07/09/2008
// Hardware connection: shown in Figure 4.18 of Huang’s HCS12 text
// Operation: This program shifts seven-segment patterns of 4 consecutive BCD digits
// by using time-multiplexing technique with each pattern lasting for 0.5 s. The
// time-multiplexing operation is controlled by the real-time interrupt. The patterns are
// 1234
// 2345
// 3456
// 4567
// 5678
// 6789
// 7890
// 8901
// 9012
// 0912
// ------------------------------------------------------------------------------------------------------------------
Function Documentation
Every function should be preceded by a comment describing the purpose and use of that
Function. An example is as follows:
//--------------------------------------------------------------------------------------------------------
// Function: FindSquareRoot
// Purpose: Computes and returns the square root of a 32-bit unsigned integer
// Parameter: A 32-bit unsigned integer of which the square root is to be found
// Called by: PrimeTest()
// Returned value: the square root of a 32-bit unsigned integer
// Side effects: none
//---------------------------------------------------------------------------------------------------------
Code Appearance
Program reability can be improved by
Proper spacing
Proper indentation
Vertical alignment
Proper Spacing
Proper Indentation
The following code is hard to read without proper indentation:
while(TRUE) {
for (i = 0; i < 10; i++) { // pattern array start index
for (j = 0; j < 100; j++) { // repeat loop for each pattern sequence
for (k = 0; k < 6; k++) { // select the display # to be lighted
PTB = SegPat[i+k]; // output segment pattern
PTP = digit[k]; // output digit select value
delayby1ms(1); // display one digit for 1 ms
}
}
}
}
Vertical Alignment
It is often helpful to align similar elements vertically, to make typo-generated bugs
more obvious.
Compare the next two sections of code. It is obvious that the second one is easier to
Identify errors: