as inline assembly, that separates the programmer from the intricacies of C's function calling and parameter passing conventions but still gives her the full expressive power of assembly language.
#define P2LTCH 0xFF5E /* The offset of the P2LTCH register. */
/**********************************************************************
*
* Function: toggleLed()
*
* Description: Toggle the state of one or both LEDs.
*
* Notes: This function is specific to Arcom's Target188EB board.
*
* Returns: None defined.
*
**********************************************************************/
void toggleLed(unsigned char ledMask) {
asm {
mov dx, P2LTCH /* Load the address of the register. */
in al, dx /* Read the contents of the register. */
mov ah, ledMask /* Move the ledMask into a register. */
xor al, ah /* Toggle the requested bits. */
out dx, al /* Write the new register contents. */
};
} /* toggleLed() */
2.2.2 delay
delay/**********************************************************************
*
* Function: delay()
*
* Description: Busy-wait for the requested number of milliseconds.
*
* Notes: The number of decrement-and-test cycles per millisecond
* was determined through trial and error. This value is
* dependent upon the processor type and speed.
*
* Returns: None defined.
*
**********************************************************************/
void delay(unsigned int nMilliseconds) {
#define CYCLES_PER_MS 260 /* Number of decrement-and-test cycles. */
unsigned long nCycles = nMilliseconds * CYCLES_PER_MS;
while (nCycles--);
} /* delay() */
The hardware-specific constant CYCLES_PER_MS represents the number of decrement-and-test cycles (nCycles-- != 0 ) that the processor can perform in a single millisecond. To determine this number I used trial and error. I made an approximate calculation (I think it came out to around 200), then wrote the remainder of the program, compiled it, and ran it. The LED was indeed blinking but at a rate faster than 1 Hz. So I used my trusty stopwatch to make a series of small changes to CYCLES_PER_MS until the rate of blink was as close to 1 Hz as I cared to test.
That's it! That's all there is to the Blinking LED program. The three functions main , toggleLed , and delay do the whole job. If you want to port this program to some other embedded system, you should read the documentation that came with your hardware, rewrite toggleLed as necessary, and change the value of CYCLES_PER_MS. Of course, we do still need to talk about how to build and execute this program. We'll examine those topics in the next two chapters. But first, I have a little something to say about infinite loops and their role in embedded systems.
2.3 The Role of the Infinite Loop
In addition, most embedded systems have only one piece of software running on them. And although the hardware is important, it is not a digital watch or a cellular phone or a microwave oven without that embedded software. If the software stops running, the hardware is rendered useless. So the functional parts of an embedded program are almost always surrounded by an infinite loop that ensures that
they will run forever.
This behavior is so common that it's almost not worth mentioning. And I wouldn't, except that I've seen quite a few first-time embedded programmers get confused by this subtle difference. So if your first program appears to run, but instead of blinking the LED simply changes its state once, it could be that you forgot to wrap the calls to toggleLed and delay in an infinite loop.
Chapter 3. Compiling, Linking, and Locating
The process of converting the source code representation of your embedded software into an executable binary image involves three distinct steps. First, each of the source files must be compiled or assembled into an object file. Second, all of the object files that result from the first step must be linked together to produce a single object file, called the relocatable program. Finally, physical memory addresses must be assigned to the relative offsets within the relocatable program in a process called relocation. The result of this third step is a file that contains an executable binary image that is ready to be run on the embedded system.