这个说明或许对于存在潜在问题和基于 RTOS 的软件设计的对比来说有些太复杂了。
理想的硬件定时器用于调度设备关键控制时间。但是,由于必须等待数据接收和执行复杂的计算使控制功能不适合在中断服务程序中执行。
![]() |
代码小。 |
![]() |
不依赖第三方源码。 |
![]() |
没有 RTOS 的 RAM、ROM 或进程开销。 |
![]() |
难以适合复杂的定时要求。 |
![]() |
增加功能时会大幅度增加复杂性。 |
![]() |
因为函数间相互关系,定时难以评价或者维护。 |
对于小程序,简单的循环可以很好工作 - 但是当系统变得复杂时变得复杂,变得难以分析和维护。
控制函数可以用下面伪代码表示:
void PlantControlCycle( void ) { TransmitRequest(); WaitForFirstSensorResponse(); if( Got data from first sensor ) { WaitForSecondSensorResponse(); if( Got data from second sensor ) { PerformControlAlgorithm(); TransmitResults(); } } }
下面伪代码表示了一个简单的无限循环来控制这些接口。
int main( void ) { Initialise(); for( ;; ) { ScanKeypad(); UpdateLCD(); ProcessRS232Characters(); ProcessHTTPRequests(); } // Should never get here. return 0; }
这里做出了两个假定:首先通信数据是由中断服务程序缓存的,所以不需要轮询外设;其次,每个函数的执行时间足够快,可以满足最大定时的要求。
添加它到无限循环需要引入一些临时控制。例如 ... :
延时或者现场总线的故障将导致设备控制函数执行时间的增加。接口函数需要的定时可能会冲突。 每个周期执行所有的函数也可能导致控制周期定时冲突。 执行时间的差别可能导致错过循环时间。例如,ProcessHTTPRequests() 处理时间在没有收到 HTTP 请求时可以忽略不计,但是在进行页面服务时可能会很长。 这将难以维护 - 它依赖于每个函数执行的最大时间。 通信缓冲区长度在每个循环中只需要使用一次,它的长度比实际需要大。 允许每个函数执行很长时间。这可以防止分割每个函数成为若干个状态,每次调用只有1个状态。使用控制函数的例子如下:
短的定时周期将更灵活。
将控制函数看成状态机(使每个调用很短)允许它可以在定时器中断中调用。定时器周期需要足够短,保证函数调用频率足够高,满足定时的要求。这个选项满足了定时和维护问题。
这一种无限循环的方法可以修改为每个周期调用不同的函数 - 高优先级控制函数调用频率更高一些: 下一节 >>> 方案 #2: 一个完整的占先式系统// Flag used to mark the time at which a
// control cycle should start (mutual exclusion
// issues being ignored for this example).
int TimerExpired;
// Service routine for a timer interrupt. This
// is configured to execute every 10ms.
void TimerInterrupt( void )
{
TimerExpired = true;
}
// Main() still contains the infinite loop -
// within which a call to the plant control
// function has been added.
int main( void )
{
Initialise();
for( ;; )
{
// Spin until it is time for the next
// cycle.
if( TimerExpired )
{
PlantControlCycle();
TimerExpired = false;
ScanKeypad();
UpdateLCD();
// The LEDs could use a count of
// the number of interrupts, or a
// different timer.
ProcessLEDs();
// Comms buffers must be large
// enough to hold 10ms worth of
// data.
ProcessRS232Characters();
ProcessHTTPRequests();
}
// The processor can be put to sleep
// here provided it is woken by any
// interrupt.
}
// Should never get here.
return 0;
}
... 但是这不是一个可以接受的方案:
另外一种结构
两个因素确定了简单循环结构的限制。
// Define the states for the control cycle function.
typdef enum eCONTROL_STATES
{
eStart, // Start new cycle.
eWait1, // Wait for the first sensor response.
eWait2 // Wait for the second sensor response.
} eControlStates;
void PlantControlCycle( void )
{
static eControlState eState = eStart;
switch( eState )
{
case eStart :
TransmitRequest();
eState = eWait1;
break;
case eWait1;
if( Got data from first sensor )
{
eState = eWait2;
}
// How are time outs to be handled?
break;
case eWait2;
if( Got data from first sensor )
{
PerformControlAlgorithm();
TransmitResults();
eState = eStart;
}
// How are time outs to be handled?
break;
}
}
这个函数的结构更复杂了,并引入了更多的调度问题。因为引入了额外的状态,代码本身变得难以理解 - 例如超时处理和错误条件。
int main( void )
{
int Counter = -1;
Initialise();
// Each function is implemented as a state
// machine so is guaranteed to execute
// quickly - but must be called often.
// Note the timer frequency has been raised.
for( ;; )
{
if( TimerExpired )
{
Counter++;
switch( Counter )
{
case 0 : ControlCycle();
ScanKeypad();
break;
case 1 : UpdateLCD();
break;
case 2 : ControlCycle();
ProcessRS232Characters();
break;
case 3 : ProcessHTTPRequests();
// Go back to start
Counter = -1;
break;
}
TimerExpired = false;
}
}
// Should never get here.
return 0;
}
更多状态可以使用事件计数器,这样低优先级函数只有在事件发生时才调用:for( ;; )
{
if( TimerExpired )
{
Counter++;
// Process the control cycle every other loop.
switch( Counter )
{
case 0 : ControlCycle();
break;
case 1 : Counter = -1;
break;
}
// Process just one of the other functions. Only process
// a function if there is something to do. EventStatus()
// checks for events since the last iteration.
switch( EventStatus() )
{
case EVENT_KEY : ScanKeypad();
UpdateLCD();
break;
case EVENT_232 : ProcessRS232Characters();
break;
case EVENT_TCP : ProcessHTTPRequests();
break;
}
TimerExpired = false;
}
这种事件处理的方法可以减少CPU时间的浪费,但是在控制周期的执行过程中仍然存在频率的问题。
翻译: 邵子扬
EMail: shaoziyang@126.com
Blog: http://blog.ednchina.com/shaoziyang
2008年10月