|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2013-11-1 08:45:32
|
显示全部楼层
太长了。ocr加英文版合着来。
第15章学会以合作的方式思考 240
引言 240
在系统中使用合作式调度器有许多好处,其中之一是它将简化开发过程。然而,要最大限度的受益于调度器,需要学会以合作的方式思考。
例如:被调度的应用程序和桌面应用程序之间的一个主要区别是需要仔细地考虑定时和任务运行时间的问题。更具体地说,正如在第14章看到的,使用合作式调度器的应用程序的关键要求是:对于所有任务,无论在何种情况下,任务的运行时间Durationtask都必须满足以下条件:
Durationtask <时标间隔
本章中的模式用来帮助满足这个条件。该模式将保证,如果任务不能在规定的时段内完成,
就中止该任务。具体地说,这里给出了两个超时模式:
● 循环超时
● 硬件超时
循环超时 240
适用场合
● 用8051系列微控制器开发一种嵌入式系统。
● 该系统使用调度器构造一种时间触发结构。
问题
如何保证当系统在等待(诸如AD转换或串行数据传送)硬件操作完成时不会“挂起”?
背景知识
Philips的8XC552是一种有许多片内模块的扩展8051芯片,它包括一个8通道的10位模数转换器。Philips提供的应用手册(AN93017)描述了如何使用这个微控制器,该应用手册包括下面的代码:
// Wait until AD conversion finishes (checking ADCI) 等待,直到AD转换结束(检查ADCI)
while ((ADCON & ADCI) == 0);
这样的代码有可能不可靠,因为在某些情况下,可能由于如下的原因导致系统被“挂起”:
● 如果模数转换器的初始化不正确,不能确定模数转换将被执行。
● 如果模数转换器的输入电压过高,那么可能根本就不运行。
● 如果没有正确初始化变量ADCON或ADC1.那么可能不按要求运行。
当然,这样的问题不只是这个特殊的微控制器或者模数转换器才有。在嵌入式系统中,这样的代码也是常见的。
如果要求系统很可靠,则必须能够保证没有函数会这样挂起,循环超时提供了一种简单然而有效的方法来提供这样的保证。
解决方案
循环超时很容易创建,其代码结构的基础是软件延迟,创建如下:
unsigned integer Timeout_loop = 0;
...
while (++Timeout_loop);
这个循环将连续运行直到变量Timeout_loop到达它的最大值65535(假定为16位整数),然后溢出。当溢出发生时,程序将继续。注意,不经过一些模拟研究或样机试验,很难确定这个延迟有多长。然而,可以确信循环虽终确实会超时。
这样的循环并不是特别有用。然而,如果再次考虑“背景知识”中给出的模数转换器的例子,则可以很容易地扩展这个方法。回想一下那些最初的代码,如下所示:
// Wait until AD conversion finishes (checking ADCI) 等待,直到AD转换结束(检查ADCI)
while ((ADCON & ADCI) == 0);
Here is a modified version of this code, this time incorporating a loop timeout: 这里是这些代码的改进版本,此时加入了一个循环超时:
tWord Timeout_loop = 0;
// Take sample from ADC 从模数转换器读取采样值
// Wait until conversion finishes (checking ADCI) 等待,直到AD转换结束(检查ADCI)
// - simple loop timeout简单的循环超时
while (((ADCON & ADCI) == 0) && (++Timeout_loop != 0));
Note that this alternative implementation is also useful: 注意:下面这个替代方案同样可用:
tWord Timeout_loop = 1;
// Take sample from ADC从模数转换器读取采样值
// Wait until conversion finishes (checking ADCI) 等待,直到AD转换结束(检查ADCI)
// - simple loop timeout简单的循环超时
while (((ADCON & ADCI) == 0) && (Timeout_loop != 0))
{
Timeout_loop++; // Disable for use in hardware simulator... 在使用硬件模拟器时禁止…
}
第一二种方法的优点是:当该代码运行在硬件模拟器上时,如果需要的话,循环超时可以容易地被注释掉。在两种情况下,现在都能确信循环将小会“永远”继续下去。注意,通过改变加载到循环变量中的韧始值,能够改变循环超时的运行时间。源程序清单15.1中的文件
TimeoutL.H出自CD上与本章有关的目录中。该文件中包括的一组常数非常近似地给出了特定的超时值。
/*------------------------------------------------------------------*-
TimeoutL.H (v1.00)
------------------------------------------------------------------
Simple loop timeout delays for the 8051 family based. 用于基于8051系列芯片的简单的循环超时延迟
* THESE VALUES ARE NOT PRECISE - YOU MUST ADAPT TO YOUR SYSTEM *
*这些值并不精确-必须根据系统修改*
-*------------------------------------------------------------------*/
// ------ Public constants 公用的常数-----------------------------------------
// Vary this value to change the loop duration改变这些值来改变循环的运行时间
// THESE ARE APPROX VALUES FOR VARIOUS TIMEOUT DELAYS
// ON 8051, 12 MHz, 12 Osc / cycle//这些是在12MHz、12振荡周期/指令周期的80 51上各种超时延迟的近似值
// *** MUST BE FINE TUNED FOR YOUR APPLICATION ***必须针对应用做调整
// *** Timings vary with compiler optimization settings ***定时随编译程序优化设置而变
#define LOOP_TIMEOUT_INIT_001ms 65435
#define LOOP_TIMEOUT_INIT_010ms 64535
#define LOOP_TIMEOUT_INIT_500ms 14535
/*------------------------------------------------------------------*-
---- END OF FILE文件结束 ------------------------------------------------
源程序清单15.1 文件TimeoutL.H
在下面几节里,举一个如何使用这些文件的例子。
硬件资源
循环超时不使用定时器,占用的CPU和存储器开销几乎可以忽略。
可靠性和安全性
使用循环超时能够以极小的成本,极大地改善可靠性和安全性。然而在实际系统中,硬件超时通常是一种史好的解决方案。
可移植性
循环超时将工作在任何平台。然而,应用小同的微控制器和编译器,得到的定时将显著变化。
优缺点小结
与没有任何形式的超时保护的执行代码相比,这要好得多。
许多应用程序使用一个定时器用于产生RS232波特率,使用另一个定时器来运行调度器。在许多8051 芯片中,没有更多的定时器可以用来实现硬件超时。在这些情况下,使用循环是实现有效的超时特性的惟一实用方式。
定时很难计算,定时值不可移植。如果有一个卒闲的定时器可用,硬件超时始终是一种最佳解决方案。
相关的模式和替代解决方案
正如在“可靠性和安全性”中提到的,硬件超时往往是循环超时的最好的替代方案。此外,硬件看门狗提供了一个替代方案。然而,比较起来该方案相当粗糙.只能检测系统级的错误(而不是任务级的)。
例子:循环超时代码的测试程序
正如已说明的,循环超时必须仔细手动调整以得到精确的延迟值。源程序清单15.2中的程序可用来测试这样的超时代码。
/*------------------------------------------------------------------*-
Main.C
------------------------------------------------------------------
Testing timeout loops. 测试超时循环
-*------------------------------------------------------------------*/
#include "Main.H"
#include "TimeoutL.H"
// Function prototypes函数原型
void Test_1ms(void);
void Test_10ms(void);
void Test_500ms(void);
/*------------------------------------------------------------------*/
void main(void)
{
while(1)
{
Test_1ms();
Test_10ms();
Test_500ms();
}
}
/*------------------------------------------------------------------*/
void Test_1ms(void)
{
tWord Timeout_loop = LOOP_TIMEOUT_INIT_001ms;
// Simple loop timeout... 简单的循环超时
while (++Timeout_loop != 0);
}
/*------------------------------------------------------------------*/
void Test_10ms(void)
{
tWord Timeout_loop = LOOP_TIMEOUT_INIT_010ms;
// Simple loop timeout... 简单的循环超时
while (++Timeout_loop != 0);
}
/*------------------------------------------------------------------*/
void Test_500ms(void)
{
tWord Timeout_loop = LOOP_TIMEOUT_INIT_500ms;
// Simple loop timeout... 简单的循环超时
while (++Timeout_loop != 0);
}
/*------------------------------------------------------------------*-
---- END OF FILE文件结束 -------------------------------------------------
-*------------------------------------------------------------------*/
源程序清单15.2测试超时代码
源程序在Keil硬件模拟器中运行。用于测试定时(如图15.1所示)。
记住:改变编译程序优化设置或者改变即使在表面上与之无关的程序其余部分也可能
改变这些定时,因为这种改变可能会导致编译程序改变可用存储区的使用方式。
对试验代码进行最终测试时,在超时开始计数的时候将一个端口引脚置为l。并在结
束时清除。使用示波器来测量所得到的延迟。
图15.1使用Keil硬件模拟器测试超时代码
例子:I2C库中的循环超时
本书将在第23章详细讨论I2C总线。简而言之,I2C是一种二线式的串行总线。两根线分
别称为串行数据线(SDA)和串行时钟线(SCL)(如图15.2所示)。当总线空闲时,SCL和SDA都为高。
图15.2 I2C总线
这里讨论在I2C库的一个版本中足如何使用循环超时的。在数据传输的某些阶段,必须“同步时钟”。这意味着需要等待“时钟”线(被一个从机)拉高。一些I2C代码库包括类似以下的代码片段来实现这个功能:
// Synchronize the clock同步时钟
while (_I2C_SCL == 0);
当然,由于本模式中介绍的各种原因,这是一种危险的方法。
下面的代码片段使用1ms超时的循环超时来改进这蝗代码:
#define LOOP_TIMEOUT_INIT_001ms 65435
...
tLong Timeout_loop = LOOP_TIMEOUT_INIT_001ms;
...
// Try to synchronize the clock试图同步时钟
while ((_I2C_SCL == 0) && (++Timeout_loop));
if (!Timeout_loop)
{
return 1; // Error - Timeout condition failed错误:不满足超时条件
}
有关I2C总线和这个库的详细资料请参阅第23章。
进阶阅读
硬件超时 245
适用场合
● 使用8051系列微控制器开发一种嵌入式系统。
● 该系统使用调度器构造一种时间触发结构。
问题
如何生成准确定义的超时特性,以便当某个预期的事件没有发生时,在精确的时间(例如,0.5ms)内响应?
背景知识
相关背景材料参见循环超时。
解决方案
正如在硬件延迟看到的,可以为8051系列创建可移植并易于使用的延迟代码,如下所示:
// Define Timer 0 / Timer 1 reload values for ~1 msec delay定义用于1ms延迟的定时器0/定时器1的重装值
#define PRELOAD_01ms (65536 - (tWord)(OSC_FREQ / (OSC_PER_INST * 1000)))
#define PRELOAD_01ms_H (PRELOAD_01ms / 256)
#define PRELOAD_01ms_L (PRELOAD_01ms % 256)
//
...
void Hardware_Delay_T0(const tLong MS)
{
tLong ms;
// Configure Timer 0 as a 16-bit timer将定时器0配置为16位定时器
TMOD &= 0xF0; // Clear all T0 bits (T1 left unchanged) 清除所有有关TO的位(Tl不变)
TMOD |= 0x01; // Set required T0 bits (T1 left unchanged) 设置所需的TD的位(T1不变)
ET0 = 0; // No interrupts不使用中断
for(ms = 0; ms < MS; ms++)
{
// Note - delay value is *approximately* 1 ms per loop注意,每个循环的延迟值“大约”是1ms
// - see Delay_T0.H for details of PRELOAD_values. - PRELOAD_values的详细资料参见Delay_T0.H
TH0 = PRELOAD_01ms_H;
TL0 = PRELOAD_01ms_L;
TF0 = 0;// clear overflow flag清除溢出标志
TR0 = 1;// start timer 0启动定时器0
while (TF0 == 0);// Loop until Timer 0 overflows (TF0 == 1) 循环直到定时器0溢出(TF0==1)
TR0 = 0;// Stop Timer 0停止定时器0
}
}
硬件超时对这种方法做了一些简单的改变,从而能够很容易地产生精确的超时延迟。
例如:在循环超时中讨论了从Philips的8XC552微控制器中的模数转换器读的过程。
这里是最初的、有潜在危险的代码:
// Wait until AD conversion finishes (checking ADCI) 等待,直到AD转换结束(检查ADCI)
while ((ADCON & ADCI) == 0);
这里是使用循环超时来解决该问题的一个应用例子:
tWord Timeout_loop = 0;
// Take sample from A-D从模数转换器读取采样值
// Wait until AD conversion finishes (checking ADCI) 等待,直到AD转换结束(检查ADCI)
// - simple loop timeout简单的循环超时
while (((ADCON & ADCI) == 0) && (++Timeout_loop));
使用循环超时可以显著改善这些代码的可靠性,然而计算超时的运行时间却不容易。
这里是一个替代方案,以合理的精度提供了l0ms的延迟,适用于整个8051系列(不用修改代码):
// Configure Timer 0 as a 16-bit timer将定时器0配置为16位定时器
TMOD &= 0xF0; // Clear all T0 bits (T1 left unchanged) 清除所有有关T0的位(T1不变)
TMOD |= 0x01; // Set required T0 bits (T1 left unchanged) 设置所需的T0的位(T1不变)
ET0 = 0; // No interrupts不使用中断
// Simple timeout feature - approx 10 ms简单的超时特性——大约l0ms
TH0 = PRELOAD_10ms_H; // See Timeout.H for PRELOAD details PRELOAD的详细资料参见Timeout.H
TL0 = PRELOAD_10ms_L;
TF0 = 0; // Clear flag清除标志
TR0 = 1; // Start timer启动定时器
while (((ADCON & ADCI) == 0) && !TF0);
源程序清单15,3中的文件Timeout.H.中给出了各种可移植的PRELOAD宏指令,该文件包含在CD上。
注意:同样的PRELOAD值可以根据需要用于定时器0或定时器1。
/*------------------------------------------------------------------*-
Timeout.H (v1.00)
------------------------------------------------------------------
Simple timeout delays for the 8051 family based on T0/T1. 用于基于8051系列芯片的T0 /TI的简单超时延迟。
Timer must be correctly configured to use these values: 必须正确配置定时器以使用这些值。
See Chapter 11 for details. 详细资料参见第11章的内容
-*------------------------------------------------------------------*/
// ------ Public constants 公用的常数-----------------------------------------
// Timer T_ values for use in simple (hardware) timeouts用于简单(硬件)超时的定时器T_value值
// - Timers are 16-bit, manual reload ('one shot'). 定时器是16位,手动重装(“单次”)
//
// NOTE: These macros are portable but timings are *approximate*
// and *must* be checked by hand if accurate timing is required.
//注意,这砦左指令是可移植的,然而定时是“近似的”,如果需要精确定时,必须于动复核
// Define initial Timer 0 / Timer 1 values for ~50 µs delay定义用于50微秒延迟的定时器O/定时器1的初始值
#define T_50micros (65536 - (tWord)((OSC_FREQ / 26000)/(OSC_PER_INST)))
#define T_50micros_H (T_50micros / 256)
#define T_50micros_L (T_50micros % 256)
// Define initial Timer 0 / Timer 1 values for ~500 µs delay定义用于到5 00微秒延迟的定时器o!定时器l的初始值
#define T_500micros (65536 - (tWord)(OSC_FREQ / (OSC_PER_INST * 2000)))
#define T_500micros_H (T_500micros / 256)
#define T_500micros_L (T_500micros % 256)
// Define initial Timer 0 / Timer 1 values for ~1 msec delay定义用于1ms延迟的定时器0/定时器1的初始值
#define T_01ms (65536 - (tWord)(OSC_FREQ / (OSC_PER_INST * 1000)))
#define T_01ms_H (T_01ms / 256)
#define T_01ms_L (T_01ms % 256)
//
// Define initial Timer 0 / Timer 1 values for ~10 msec delay定义用于l0ms延迟的定时器0/定时器l的初始值
#define T_10ms (65536 - (tWord)(OSC_FREQ / (OSC_PER_INST * 100)))
#define T_10ms_H (T_10ms / 256)
#define T_10ms_L (T_10ms % 256)
//
// Define initial Timer 0 / Timer 1 values for ~30 msec delay定义用于30ms延迟的定时器0/定叫器l的初始值
#define T_30ms (65536 - (tWord)(OSC_FREQ / (OSC_PER_INST * 33)))
#define T_30ms_H (T_30ms / 256)
#define T_30ms_L (T_30ms % 256)
/*------------------------------------------------------------------*-
---- END OF FILE -文件结束------------------------------------------------
-*------------------------------------------------------------------*/
源程序清单15.3文件Timeout.h
硬件资源
硬件超时需要使用一个定时器。
可靠性和安全性
硬件超时是本书所讨论的最可靠的超时结构
可移植性
和所有基于定时器的模式一样,这些代码可以很容易地移植到8051系列的其他芯片上。
同时,它也可以被移植到其他微控制器上。
优缺点小结
@使用硬件超时可以得到精确的超时延迟。
@系统可用的定时器的数目非常有限。然而,当使用合作式调度器时,任务以合作的方式运行,同一个定时器可以同时用于几个任务。
相关的模式和替代解决方案
不需要使用任何定时器硬件的替代方案参见循环超时。
此外,硬件看门狗提供了一个替代方案。然而,比较起来,该方案相当粗糙,只能检测系
统级的错误(而不是任务级的)。
例子:测试硬件超时
源程序清单15.4说明了使用Keil硬件模拟器利用一些硬件超时得到的延迟(参见图15.3)。
/*------------------------------------------------------------------*-
Main.C
------------------------------------------------------------------
Testing timeout loops. 测试超时循环
-*------------------------------------------------------------------*/
#include "Main.H"
#include "TimeoutH.H"
// Function prototypes
void Test_50micros(void);
void Test_500micros(void);
void Test_1ms(void);
void Test_5ms(void);
void Test_10ms(void);
void Test_15ms(void);
void Test_20ms(void);
void Test_50ms(void);
// TIMEOUT code variable & TIMEOUT code (dummy here)
#define TIMEOUT 0xFF
tByte Error_code_G;
/*------------------------------------------------------------------*/
void main(void)
{
while(1)
{
Test_50micros();
Test_500micros();
Test_1ms();
Test_5ms();
Test_10ms();
Test_15ms();
Test_20ms();
Test_50ms();
}
}
/*------------------------------------------------------------------*/
void Test_50micros(void)
{
// Configure Timer 0 as a 16-bit timer
TMOD &= 0xF0; // Clear all T0 bits (T1 left unchanged)
TMOD |= 0x01; // Set required T0 bits (T1 left unchanged)
ET0 = 0; // No interrupts
// Simple timeout feature - approx 50 µs
TH0 = T_50micros_H; // See TimeoutH.H for T_ details
TL0 = T_50micros_L;
TF0 = 0; // Clear flag
TR0 = 1; // Start timer
while (!TF0);
TR0 = 0;
// Normally need to report timeout TIMEOUTs
// (this test is for demo purposes here)
if (TF0 == 1)
{
// Operation timed out
Error_code_G = TIMEOUT;
}
}
/*------------------------------------------------------------------*/
void Test_500micros(void)
{
// Configure Timer 0 as a 16-bit timer
TMOD &= 0xF0; // Clear all T0 bits (T1 left unchanged)
TMOD |= 0x01; // Set required T0 bits (T1 left unchanged)
ET0 = 0; // No interrupts
// Simple timeout feature - approx 500 µs
TH0 = T_500micros_H; // See TimeoutH.H for T_ details
TL0 = T_500micros_L;
TF0 = 0; // Clear flag
TR0 = 1; // Start timer
while (!TF0);
TR0 = 0;
// Normally need to report timeout TIMEOUTs
// (this test is for demo purposes here)
if (TF0 == 1)
{
// Operation timed out
Error_code_G = TIMEOUT;
}
}
/*------------------------------------------------------------------*/
void Test_1ms(void)
{
// Configure Timer 0 as a 16-bit timer
TMOD &= 0xF0; // Clear all T0 bits (T1 left unchanged)
TMOD |= 0x01; // Set required T0 bits (T1 left unchanged)
ET0 = 0; // No interrupts
// Simple timeout feature - approx 1 ms
TH0 = T_01ms_H; // See TimeoutH.H for T_ details
TL0 = T_01ms_L;
TF0 = 0; // Clear flag
TR0 = 1; // Start timer
while (!TF0);
TR0 = 0;
// Normally need to report timeout TIMEOUTs
// (this test is for demo purposes here)
if (TF0 == 1)
{
// Operation timed out
Error_code_G = TIMEOUT;
}
}
/*------------------------------------------------------------------*/
void Test_5ms(void)
{
// Configure Timer 0 as a 16-bit timer
TMOD &= 0xF0; // Clear all T0 bits (T1 left unchanged)
TMOD |= 0x01; // Set required T0 bits (T1 left unchanged)
ET0 = 0; // No interrupts
// Simple timeout feature - approx 10 ms
TH0 = T_05ms_H; // See TimeoutH.H for T_ details
TL0 = T_05ms_L;
TF0 = 0; // Clear flag
TR0 = 1; // Start timer
while (!TF0);
TR0 = 0;
// Normally need to report timeout TIMEOUTs
// (this test is for demo purposes here)
if (TF0 == 1)
{
// Operation timed out
Error_code_G = TIMEOUT;
}
}
/*------------------------------------------------------------------*/
void Test_10ms(void)
{
// Configure Timer 0 as a 16-bit timer
TMOD &= 0xF0; // Clear all T0 bits (T1 left unchanged)
TMOD |= 0x01; // Set required T0 bits (T1 left unchanged)
ET0 = 0; // No interrupts
// Simple timeout feature - approx 10 ms
TH0 = T_10ms_H; // See TimeoutH.H for T_ details
TL0 = T_10ms_L;
TF0 = 0; // Clear flag
TR0 = 1; // Start timer
while (!TF0);
TR0 = 0;
// Normally need to report timeout TIMEOUTs
// (this test is for demo purposes here)
if (TF0 == 1)
{
// Operation timed out
Error_code_G = TIMEOUT;
}
}
/*------------------------------------------------------------------*/
void Test_15ms(void)
{
// Configure Timer 0 as a 16-bit timer
TMOD &= 0xF0; // Clear all T0 bits (T1 left unchanged)
TMOD |= 0x01; // Set required T0 bits (T1 left unchanged)
ET0 = 0; // No interrupts
// Simple timeout feature - approx 10 ms
TH0 = T_15ms_H; // See TimeoutH.H for T_ details
TL0 = T_15ms_L;
TF0 = 0; // Clear flag
TR0 = 1; // Start timer
while (!TF0);
TR0 = 0;
// Normally need to report timeout TIMEOUTs
// (this test is for demo purposes here)
if (TF0 == 1)
{
// Operation timed out
Error_code_G = TIMEOUT;
}
}
/*------------------------------------------------------------------*/
void Test_20ms(void)
{
// Configure Timer 0 as a 16-bit timer
TMOD &= 0xF0; // Clear all T0 bits (T1 left unchanged)
TMOD |= 0x01; // Set required T0 bits (T1 left unchanged)
ET0 = 0; // No interrupts
// Simple timeout feature - approx 10 ms
TH0 = T_20ms_H; // See TimeoutH.H for T_ details
TL0 = T_20ms_L;
TF0 = 0; // Clear flag
TR0 = 1; // Start timer
while (!TF0);
TR0 = 0;
// Normally need to report timeout TIMEOUTs
// (this test is for demo purposes here)
if (TF0 == 1)
{
// Operation timed out
Error_code_G = TIMEOUT;
}
}
/*------------------------------------------------------------------*/
void Test_50ms(void)
{
HARDWARE TIMEOUT 313
// Configure Timer 0 as a 16-bit timer
TMOD &= 0xF0; // Clear all T0 bits (T1 left unchanged)
TMOD |= 0x01; // Set required T0 bits (T1 left unchanged)
ET0 = 0; // No interrupts
// Simple timeout feature - approx 10 ms
TH0 = T_50ms_H; // See TimeoutH.H for T_ details
TL0 = T_50ms_L;
TF0 = 0; // Clear flag
TR0 = 1; // Start timer
while (!TF0);
TR0 = 0;
// Normally need to report timeout TIMEOUTs
// (this test is for demo purposes here)
if (TF0 == 1)
{
// Operation timed out
Error_code_G = TIMEOUT;
}
}
/*------------------------------------------------------------------*-
---- END OF FILE -------------------------------------------------
-*------------------------------------------------------------------*/
源程序清单15.4测试硬件超时
例子:产生基于超时的延迟
可以很容易地扩展“超时”技术,用作硬件延迟的一种替代方案,参见源程序清单15.5。
void Delay_50micros(void)
{
// Configure Timer 0 as a 16-bit timer
TMOD &= 0xF0; // Clear all T0 bits (T1 left unchanged)
TMOD |= 0x01; // Set required T0 bits (T1 left unchanged)
ET0 = 0; // No interrupts
// Simple timeout feature - approx 50 µs
TH0 = T_50micros_H; // See TimeoutH.H for T_ details
TL0 = T_50micros_L;
TF0 = 0; // Clear flag
TR0 = 1; // Start timer
while (!TF0);
TR0 = 0;
}
源程序清单15.5使用硬件超时来实现延迟
图15.3使用Keil硬件模拟器测试硬件超时
Page254
进阶阅读
|
|