📄 c515.txt
字号:
/**********************************************************/
#include ".h"
/* Standard ANSI C header files */
/**********************************************************/
/* Global Data Declarations */
/**********************************************************/
#include ".h"
/* Home header file */
/**********************************************************/
/* External Declarations */
/**********************************************************/
#include ".h"
/* Header files for other modules */
/**********************************************************/
/* Functions Details: */
/**********************************************************/
/* Function Name: */
/* Entered From: */
/* Calls: */
/**********************************************************/
/*********************************************************/
/* Purpose: main loop for training program */
/* */
/**********************************************************/
/* Resource Usage: */
/* */
/* CODE CONST DATA IDATA PDATA */
/* n/a n/a n/a n/a n/a */
/* */
/* Performance: */
/* Max Runtime: Min Runtime: */
/* */
/* */
/**********************************************************/
/* Executable functions */
/**********************************************************/
/**********************************************************/
/* End Of STD.c */
/**********************************************************/
Standard Include Header File Template
/**********************************************************/
/* Project: X */
/* Author: X Creation Date: XX\XX\XX */
/* Filename: X Language: X */
/* Rights: X Rights: X */
/* */
/* Compiler: X Assembler: X */
/* Version: X.XX Version: X.XX */
/**********************************************************/
/* Modification History */
/**********************************************************/
/* Name: X Date: XX\XX\XX */
/* Modification: X */
/* */
/* Name: X Date: XX\XX\XX */
/* Modification: X */
/* */
/* Name: X Date: XX\XX\XX */
/* Modification: X */
/* */
/**********************************************************/
/**********************************************************/
/* Global Definitions */
/**********************************************************/
/* Structure and union templates plus other definitions */
#ifdef _STD_
/* Check for inclusion in home module */
/*********************************************************/
/*********************************************************/
/* Within Module Function Prototypes */
/*********************************************************/
/* Function prototypes from home module */
/*********************************************************/
/* Within Module Data Declarations */
/*********************************************************/
/* Data declarations from home module */
/*********************************************************/
#else
/*********************************************************/
/*********************************************************/
/* External Function Prototypes */
/*********************************************************/
/* External function prototypes for use by other modules */
/*********************************************************/
/* External Data Declarations */
/*********************************************************/
/* External data definitions for use by other modules */
/*********************************************************/
#endif
Summary
Provided the necessary module name defines are added to the first line of an
y new module and the new globals placed into the associated ".h" file, the o
verall amount of editing required over a major project is usefully reduced.
Compilation and, more particularly, linking errors are reduced as there is e
ffectively only one external reference for each global item in the entire pr
ogram. For structures and unions the template only appears once, again reduc
ing the potential for compilation and linking problems.
4.4 Task Scheduling
4.4.1 8051 Applications Overview
When most people first start to learn to program, BASIC is used on a PC or s
imilar machine. The programs are not usually too complicated; they start whe
n you type _"RUN" and finish at END or STOP. In between, the PC is totally d
evoted to executing your "HELLO WORLD" program. When it is finished you are
simply thrown back to the BASIC editor/"operating environment".
All this is very good and you think you now know how to program. However, wh
en writing for an embedded microcontroller like the 8051, the problem of whe
re does the program start and finish suddenly presents itself. The average 8
051 software system consists of many individual programs which, when execute
d together, contribute towards the fulfilment of the overall system objectiv
e. A fundamental problem is then how to ensure that each part is actually ru
n.
4.4.2 Simple 8051 Systems
The simplest approach is to call each major sub-function in a simple sequent
ial fashion so that after a given time each function has been executed the s
ame number of times. This constitutes a background loop. In the foreground m
ight be interrupt functions, initiated by real time events such as incoming
signals or timer overflows.
Data is usually passed from background to foreground via global variables an
d flags. This essentially simple program model can be very successful if som
e care is taken over the order and frequency of execution of particular sect
ions.
The background-called functions must be written so that they run a particula
r section of their code on each successive entry from the background loop. T
hus each function is entered, a decision is taken as to what to do this time
, the code is executed and finally the program is exited, probably with some
special control flags set up to tell the routine program what to do next ti
me. Thus each functional block must maintain its own control system to ensur
e that the right code is run on any particular entry.
In this system all functional blocks are considered to be of equal importanc
e and no new block can be entered until its turn is reached by the backgroun
d loop. Only interrupt routines can break this, with each one having its own
priority. Should a block need a certain input signal, it can either keep wa
tching until the signal arrives, so holding up all other parts, or it can wa
it until the next entry, next time round the loop. Now there is the possibil
ity that the event will have been and gone before the next entry occurs. Thi
s type of system is OK for situations where the time-critical parts of the p
rogram are small.
In reality many real time systems are not like this. Typically they will con
sist of some frequently-used code, the execution of which is caused by or ca
uses some real-world event. This code is fed data from other parts of the sy
stem, whose own inputs may be changing rapidly or slowly.
Code which contributes to the system's major functionality must obviously ta
ke precedence over those sections whose purpose is not critical to the succe
ssful completion of the task. However most embedded 8051 applications are ve
ry time-critical, with such parts being attached to interrupts. The need to
service as many interrupts as quickly as possible requires that interrupt co
de run times are short. With most real world events being asynchronous, the
system will ultimately crash when too many interrupt requests occur per unit
time for the cpu to cope with.
Fast runtimes and hence acceptable system performance are normally achieved
by moving complex functions into the background loop, leaving the time-criti
cal sections in interrupts. This gives rise to the problem of communication
between background code and its dependant interrupt routine.
The simple system is very egalitarian, with all parts treated in the same wa
y. When the cpu becomes very heavily loaded with high speed inputs, it is li
kely that major sub-functions will not be run frequently enough for the real
-world interrupt code to be able to run with sufficiently up to date informa
tion from the background. Thus, system transient response is degraded.
4.4.3 Simple Scheduling - A Partial Solution
The problems of the simple loop system can be partially solved by controllin
g the order and frequency of function calling. One approach is to attach a p
riority to each function and allow each function to specify the next one to
be executed. The real-world driven interrupt functions would override this s
teady progression so that the most important (highest priority) jobs are exe
cuted as soon as the current job is completed. This kind of system can yield
useful results, provided that no single function takes too long.
An alternative is to control overall execution from a real time interrupt so
that each job is allocated a certain amount of time in which to run. If a t
imeout does occur, that task is suspended and another begins.
Unfortunately all these tend to be bolt-ons, added late in a project when ru
n times are getting too long. Usually what had been a well-structured progra
m degenerates into spaghetti code, full of fixes and special modes, designed
to overcome the fundamental mismatch between the demands of real time event
s and the response of the program. Moreover, the individual control mechanis
ms of the called functions generate an overhead which simply contributes to
the runtime bottle-neck.
The reality is that real time events are not orderly and predictable. Some j
obs are naturally more important than others. However inconvenient, the real
world produces events that must be responded to immediately.
4.4.4 A Pragmatic Approach
Without resorting to a full real time executive like RTX51, what can be done
?
A simple mechanism to control the running of the background loop can be a si
mple switch statement, with the switch variable controlled by some external
real time event. Ideally this should be the highest priority interrupt routi
ne. The high priority background tasks are placed at the top case, with lowe
r priority tasks located further down the case statement. Thus, on every occ
urrence of the interrupt, the switch is set back to the top. As the backgrou
nd tasks execute, they increment the switch. If the interrupt is absent for
long enough, the switch will reach the lowest level and then return to the h
ighest level automatically.
Should the interrupt occur at level 2, the switch variable is forced back to
zero and so tasks at the lowest levels are simply missed. This is by no mea
ns an ideal system, since only the top level is ever executed.given a high e
nough interrupt frequency.
However under normal conditions it is a useful way of ensuring that low prio
rity tasks are not executed frequently. For example, there would be little p
oint in measuring ambient temperature more than once per second. In a typica
l system this measurement might be at level 100 in a switch scheduler.
To be able to make a judgement about how best to structure the program, it i
s vital to know the run times for each section.
Where this simple method falls down is when a low priority task has a long r
un time. Even though the interrupt has requested that the loop returns back
to the top level to calculate more data, there is no way of exiting the task
until completed. To do so requires a proper time-slice mechanism.
A useful dodge can be to utilise an unused interrupt to guarantee that high
priority tasks will be run on time. By setting the unused interrupt pending
flag within the exiting high priority interrupt routine and placing the back
ground task into the corresponding service routine, the punctual execution o
f the second task will occur. Of course, the unused interrupt priority must
be set to a lower priority in the appropriate interrupt priority register(s)
.
The most important factor overall is to keep run times as short as possible,
particularly in interrupt routines. This means making full use of C51 exten
sions like memory-specific pointers, special function bits and local regsite
r variables.
----------------------------------------------------------------------------
----
--
Ours is essentially a tragic age, so we refuse to take it tragically.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -