CH 4 Cprog
CH 4 Cprog
C Programming
In C, the starting location of the program is defined when you compile the program, not in the program itself. C always uses
the stack and automatically loads the stack pointer. Assembly code can be included (embedded) within the C code using
the construct: asm(). Here’s a comparison of some Assembly language and C constructs:
Assembly C
; Define a constant COUNT
COUNT EQU 5 #define COUNT 5
; Start a program
org $2000 main(){
lds 0x2000 }
;Allocate two bytes for a signed number
org $1000
i ds.w 1 int i;
j dc.w $1A00 int j = 0x1A00;
;Allocate two bytes for an unsigned number
i ds.w 1 unsigned int i;
j dc.w $1A00 unsigned int j = 0x1A00;
;Allocate one byte for a signed number
i ds.b 1 signed char i;
j dc.b $1F signed char j = 0x1F;
;Get a value from an address, Put contents of
; address $E000 into variable i
i ds.b 1 unsigned char i;
ldaa $E000 i = *(unsigned char *) 0xE000;
staa i
/* Use a variable as a pointer (address) */
unsigned char *ptr, i;
ptr = (unsigned char *) 0xE000;
i = *ptr;
*ptr = 0x55;
;To call a subroutine /* To call a function */
ldaa i sqrt(i);
jsr sqrt
;To return from a subroutine /* To return from a function */
ldaa j return j;
rts
;Flow control
blo if (i < j)
blt if (i < j)
bhs if (i >= j)
bge if (i >= j)
Here is a simple program written in C and assembly. It simply divides 16 by 2. It does the division in a function.
41
42 Chapter 4 6812 C Programming
Assembly C
org $1000
i ds.b 1 signed char i;
signed char div(signed char j);
org $2000 main()
lds #$2000 {
ldaa #16 i = div(16);
jsr div }
staa i
swi
4.1 C Pointers
The construct *(number) treats number as an address, and to work with the contents of that address. The C runtime needs
to how many bytes we want and is it signed or unsigned as follow (*(type *) address).
i = *(unsigned char *) 0xE000; : take one byte from address 0xE000 (as unsigned) and store it in variable i.
j = *(int *) 0xE000; : take two bytes from address 0xE000, treat it as signed, and store that value in variable j.
*(char *) 0xE000 = 0xAA; : write the number 0xAA to a single byte at address 0xE000.
*(int *) 0xE000 = 0xAA; : write the number 0x00AA to two bytes starting at address 0xE000.
Operators in C
The third element in the table can be accessed as table[2] or *(table+2)
Operator
To set up a table of constant data: | Action | example
-----------------------------|---------------------------------------
const unsigned char table[] |= {0x00, 0x01, 0x03,
| Bitwise OR |0x07,%00001010
0x0f; } | %01011111 = % 01011111
& | Bitwise AND | %00001010 & %01011111 = % 00001010
^ | Bitwise XOR | %00001010 ^ %01011111 = % 01010101
4.2 Setting and Clearing Bits ~ in C | Bitwise COMP | ~%00000101 = %11111010
% | Modulo | 10 % 8 = 2
| |
It is often needed to set or clear bits of a hardware register. A ”mask” is used to select bit(s) to be altered:
|| | Logical OR | %00000000 || %00100000 = 1
- The easiest way to set bits in C&&is to use the bitwise
| Logical ANDOR|(|) operator:
%11000000 && %00000011 = 1
DDRB = DDRB | 0x0F; /* Make 4 LSBs of Port B outputs, | %11000000 && %00000000
0x0F is the mask */ = 0
- The easiest way to clear bits in C is to use the bitwise AND (&) operator:
PORTA = PORTA & 0x1F; /* Clear 3 MSBs of Port Setting
A */ and Clearing Bits in C
assembly | C | action
----------------------|-------------------------------|---------------------
bset DDRB,$0F | DDRB = DDRB | 0x0f; | Set 4 LSB of DDRB
bclr DDRB,$F0 | DDRB = DDRB & ~0xf0; | Clear 4 MSB of DDRB
| |
l1: brset PTB,$01,l1 | while ((PTB & 0x01) == 0x01) | Wait until bit clear
| |
l2: brclr PTB,$02,l2 | while ((PTB & 0x02) == 0x00) | Wait until bit set
Pointers in C
Operators in C
Chapter 4 6812 C Programming 43
4.3 Setting
Basic C Program Structure for Embedded and Clearing Bits in C
Systems
# include < mc9s12dp512 .h > /* I / O port / register names / addresses for the MC9S12DP512 m i c r o c o n t r o l l e r s */
assembly | C | action
/* Global variables ----------------------|-------------------------------|---------------------
accessible by all functions */
int count , bob ; bset
// global DDRB,$0F
( static ) variables | p lDDRB
aced =
in DDRB
RAM | 0x0f; | Set 4 LSB of DDRB
bclr DDRB,$F0 | DDRB = DDRB & ~0xf0; | Clear 4 MSB of DDRB
/* Function definitions */
| |
int function1 ( char x ) { // parameter x passed to the function , function returns an integer value
int i , j ; l1: brset
// local PTB,$01,l1 | while ((PTB & 0x01) == 0x01) | Wait until bit clear
variables declaration
// -- instructions to implement function1 | |
}
l2: brclr PTB,$02,l2 | while ((PTB & 0x02) == 0x00) | Wait until bit set
/* Main program */
void main ( void ) {
unsigned char sw1 ;
Pointers in C
// local variable declaration
int k ; // local variable declaration
/* In itializ ation section */
To read
// -- instructions to a byte fromvariables
initialize memory, Ilocation 0xE000:
/ O ports , devices , function registers
/* Infinite loop */
while (1) { var// repeat forever
= *(char *), 0xE000;
can also use : for (;;) {
// -- instructions to be repeated to implement body of the program
}
} To write a 16-bit word to memory location 0xE002:
Freescale Codewarrior provides a derivative-specific ’header file’ (e.g. mc9s12dp512.h) for each microcontroller, which defines
memory addresses and symbolic labels for CPU and peripheral function register addresses.
4.5 Examples:
A program to increment LEDs connected to PORTB, and delay for 50 ms between changes
main () {
DDRB = 0 xff ; /* Make PORTB output */
PORTB = 0; /* Start with all off */
while (1) {
PORTB = PORTB + 1;
delay (50);
}
}
44 Chapter 4 6812 C Programming
A Program to count the number of negative numbers in an array of bytes in memory from address 0xE000 to 0xEFFF.
# include < hidef .h > /* common defines and macros */
# include " derivative . h " /* derivative - specific definitions */
main () {
char * ptr ,* start ,* end ;
start = ( char *) 0 xE000 ; /* Address of first element */
end = ( char *) 0 xEFFF ; /* Address of last element */
num_neg = 0;
for ( ptr = start ; ptr <= end ; ptr = ptr +1) {
if (* ptr < 0) num_neg = num_neg + 1;
}
}