Tải bản đầy đủ (.pdf) (6 trang)

HandBooks Professional Java-C-Scrip-SQL part 202 pdf

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (32.06 KB, 6 trang )

[1] Specifically, it represents the number of clock ticks remaining after all of the
timers ahead of it in the list have expired.
[2] Astute readers might recall that in Chapter 5, I stated that the PCB was located
in the I/O space of the 80188EB processor. However, because memory-mapped
registers are more likely in a device driver situation, I've relocated the entire PCB
to physical address 72000h, in the memory space. This new location will be
assumed for the rest of the book. To see how this relocation was performed, take a
look at the constructor for the i8018xEB class.
[3] A word of caution about waitfor : this implementation spins its wheels waiting
for the software timer to change to the done state. This technique is called busy-
waiting, and it is neither elegant nor an efficient use of the processor. In Chapter 8,
we'll see how the introduction of an operating system allows us to improve upon
this implementation.
Chapter 9. Putting It All Together
 9.1 Application Overview
 9.2 Flashing the LED
 9.3 Printing "Hello, World!"
 9.4 Working with Serial Ports
 9.5 The Zilog 85230 Serial Controller
A sufficiently high level of technology is indistinguishable from magic.
—Arthur C. Clarke
In this chapter, I'll attempt to bring all of the elements we've discussed so far
together into a complete embedded application. I don't have much new material to
add to the discussion at this point, so the body of the chapter is mainly a
description of the code presented herein. My goal is to describe the structure of this
application and its source code in such a way that there is no magic remaining for
you. You should leave this chapter with a complete understanding of the example
program and the ability to develop useful embedded applications of your own.
9.1 Application Overview
The application we're going to discuss is not much more complicated than the
"Hello, World!" example found in most other programming books. It is a testament


to the complexity of embedded software development that this example comes near
the end of this book, rather than at its beginning. We've had to gradually build our
way up to the computing platform that most books, and even high-level language
compilers, take for granted.
Once you're able to write the "Hello, World!" program, your embedded platform
starts to look a lot like any other programming environment. The hardest parts of
the embedded software development process—familiarizing yourself with the
hardware, establishing a software development process for it, and interfacing to the
individual hardware devices—are behind you. You are finally able to focus your
efforts on the algorithms and user interfaces that are specific to the product you're
developing. In many cases, these higher-level aspects of the program can be
developed on another computer platform, in parallel with the lower-level
embedded software development we've been discussing, and merely ported to the
embedded system once both are complete.
Figure 9-1 contains a high-level representation of the "Hello, World!" application.
This application includes three device drivers, the ADEOS operating system, and
two ADEOS tasks. The first task toggles the Arcom board's red LED at a rate of 10
Hz. The second prints the string "Hello, World!" at 10 second intervals to a host
computer or dumb terminal connected to one of the board's serial ports.
Figure 9-1. The "Hello, World!" application

In addition to the two tasks, there are three device drivers shown in the figure.
These control the Arcom board's LEDs, timers, and serial ports, respectively.
Although it is customary to draw device drivers below the operating system, I
chose to place these three on the same level as the operating system to emphasize
that they actually depend more on ADEOS than it does on them. In fact, the
embedded operating system doesn't even know (or care) that these drivers are
present in the system. This is a common feature of the device drivers and other
hardware-specific software in an embedded system.
The implementation of main is shown below. This code simply creates the two

tasks and starts the operating system's scheduler. At such a high level the code
should speak for itself. In fact, we've already discussed a similar code listing in the
previous chapter.
#include "adeos.h"
void flashRed(void);
void helloWorld(void);
/*
* Create the two tasks.
*/
Task taskA(flashRed, 150, 512);
Task taskB(helloWorld, 200, 512);
/******************************************************************
***
*
* Function: main()
*
* Description: This function is responsible for starting the ADEOS
* scheduler only.
*
* Notes:
*
* Returns: This function will never return!
*
******************************************************************
***/
void
main(void)
{
os.start();
// This point will never be reached.

} /* main() */
9.2 Flashing the LED
As I said earlier, one of two things this application does is blink the red LED. This
is done by the code shown below. Here the function flashRed is executed as a task.
However, ignoring that and the new function name, this is almost exactly the same
Blinking LED function we studied in Chapter 7. The only differences at this level
are the new frequency (10 Hz) and LED color (red).
#include "led.h"
#include "timer.h"
/******************************************************************
****
*
* Function: flashRed()
*
* Description: Blink the red LED ten times a second.
*
* Notes: This outer loop is hardware-independent. However, it
* calls the hardware-dependent function toggleLed().
*
* Returns: This routine contains an infinite loop.
*
******************************************************************
****/
void
flashRed(void)
{
Timer timer;
timer.start(50, Periodic); // Start a periodic 50ms timer.
while (1)
{

toggleLed(LED_RED); // Toggle the red LED.
timer.waitfor(); // Wait for the timer to expire.
}
} /* flashRed() */
The most significant changes to the Blinking LED program are not visible in this
code. These are changes made to the toggleLed function and the Timer class to
make them compatible with a multitasking environment. The toggleLed function is
what I am now calling the LED driver. Once you start thinking about it this way, it
might make sense to consider rewriting the driver as a C++ class and add new
methods to set and clear an LED explicitly. However, it is sufficient to leave our
implementation as it was in Chapter 7 and simply use a mutex to protect the
P2LTCH register from simultaneous access by more than one task.
[1]

Here is the modified code:
#include "i8018xEB.h"
#include "adeos.h"
static Mutex gLedMutex;
/******************************************************************
****
*
* Function: toggleLed()
*
* Description: Toggle the state of one or both LEDs.
*
* Notes: This version is ready for multitasking.
*
* Returns: None defined.
*
******************************************************************

****/
void
toggleLed(unsigned char ledMask)
{
gLedMutex.take();
// Read P2LTCH, modify its value, and write the result.
//
gProcessor.pPCB->ioPort[1].latch ^= ledMask;
gLedMutex.release();
} /* toggleLed() */
A similar change must be made to the timer driver from Chapter 7 before it can be
used in a multitasking environment. However, in this case there is no race
condition.
[2]
Rather, we need to use a mutex to eliminate the polling in the waitfor
method. By associating a mutex with each software timer, we can put any task that
is waiting for a timer to sleep and, thereby, free up the processor for the execution
of lower-priority ready tasks. When the awaited timer expires, the sleeping task
will be reawakened by the operating system.
Toward this end, a pointer to a mutex object, called pMutex, will be added to the
class definition:
class Timer

×