tbwshc

tbw

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  95 Posts :: 8 Stories :: 3 Comments :: 0 Trackbacks

常用链接

留言簿(4)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

正如我早先说的。这个应用程序所做的两件事之一是使红色指示灯闪烁。这可以通过下面的代码来做到。这里函数flashRed()作为一个任务来执行。然而,如果忽略这一点以及新的函数名,那么这段代码和第七章“外围设备”中我们研究过的LED 闪烁函数几乎是一样的。在这一级上的唯一差别就是新的频率(10HZ)和指示灯的颜色(红色)。
#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 50 ms timer.
while(1)
{
toggleLed(LED_RED); // Toggle the red LED.
timer.waitfor(); // Wait for the timer to expire.
}
} /* flashRed() */
LED 闪烁程序主要的改变在这段代码中是看不见的。这些主要的变化是对toggleLed()函数和Timer 类进行了修改以兼容多任务的环境。toggleLed()函数就是我现在称之为指示灯驱动的东西。一旦你开始这样考虑这个问题,tb也许会考虑把驱动重写成一个C++类,并已加入新的方法以明确地设置和清除指示灯,这个方法也是讲得通的。但是,采用和第七章一样的实现方法,并且仅使用一个互斥体来保护P2LTCH 寄存器不被一个以上的任务同时访问,就已经足够了(注1)。这里是修改后的代码:
#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() */
注 1:在早先的那个toggleLed()函数中存在竞争的情况。为了理解这一点,返回去查看这段代码,并且假想两个任务在共享指示灯,第一个任务恰好调用了那个切换红色指示灯的函数,突然之间,第一个任务被第二个任务占先,此时,在toggleLed()函数中,指示灯的状态都被读入并存入一个处理器的寄存器。现在第二个任务导致两个指示灯的状态都被再次读入并且存入另一个处理器的寄存器,然后两个指示灯的状态都被修改以改变绿色指示灯的状态,并且导致结果写出到P2LTCH 寄存器。当中断的任务重新启动时,它已经有一个指示灯状态的拷贝。但是这个拷贝不再准确了。当发生这个变化后,指示灯变成红灯,并且比新的指示灯状态写到P2LTCH 寄存器。这样,第二个任务的改变将会被撤销。加入一个互斥体可以消除这个潜在的危险。

第七章中的时钟驱动程序在应用于一个多任务的环境之前,tbw必须对它做类似的改动。然而这时不存在竞争的情况(注2)。我们需要利用一个互斥体来消除waitfor 方法中的轮询。通过把一个互斥体和每一个软件时钟关联,我们可以使任何一个在等待时钟的任务休眠,因此,释放了处理器以执行就绪的低优先级的任务。当等待的时钟到期了,休眠的任务会被操作系统唤起。为此,一个指向互斥体的指针,叫做 pMutex,被加入到类的定义中:
class Timer
{
public:
Timer();
~Timer();
int start(unsigned int nMilliseconds, TimerType = OneShot);
int waitfor();
void cancel();
TimerState state;
TimerType type;
unsigned int length;
Mutex * pMutex;
unsigned int count;
Timer * pNext;
private:
static void interrupt Interrupt();
};
每次构造函数创建软件时钟的时候,这个指针被初始化。此后,无论何时一个时钟对象被启动,它的互斥体可以像下面这样获得:
——————————————————————————————————
注 2:记得时钟硬件只初始化一次(在第一次构造函数请求的时候),并且此后时钟专用寄存器只能由一个函数(即中断服务例程)来读写。
/*******************************************************************
*
* Function : start()
*
* Description : Start a software timer, based on the tick from the
* underlying hardware timer.
*
* Notes : This version is ready for multitasking.
*
* Returns : 0 on success, -1 if the timer is already in use.
*
*******************************************************************/
int
Timer::start(unsigned int nMilliseconds, TimerType timerType)
{
if(state != Idle)
{
return(-1);
}
//
// Take the mutex. It will be released when the timer expires.
//
pMutex->take();
//
// Initialize the software timer.
//
state = Active;
type = timerType;
length = nMilliseconds / MS_PER_TICK;
//
// Add this timer to the active timer list.
//
timerList.insert(this);
return(0);
} /* start() */
通过在时钟启动的时候获得互斥体,我们可以保证在同一个互斥体释放之前没有其他任务(甚至是启动时钟的任务)能够再获得它。并且这在时钟自然到期(中断服务程序)或是人为取消(通过取消的办法)之前是不会发生的。所以在waitfor()中的轮询可以由pMutex->take()来替换如下:
/*******************************************************************
*
* Function : waitfor()
*
* Description : Wait for the software timer to finish.
*
* Notes : This version is ready for multitasking.
*
* Returns : 0 on success, -1 if the timer is not running.
*
*******************************************************************/
int
Timer::waitfor()
{
if(state != Active)
{
return(-1);
}
//
// Wait for the timer to expire.
//
pMutex->take();
//
// Restart or idle the timer, depending on its type.
//
if(type == Periodic)
{
state == Active;
timerList.insert(this);
}
else
{
pMutex->release();
state = Idle;
}
return(0);
} /* waitfor() */
当时钟最后到期时,中断服务程序将会释放互斥体,调用的任务会在waitfor()中被唤起。唤起的过程中,互斥体已经为下一个运行的时钟获得。互斥体只有当时钟是OneShot 类型时才会被释放,因此,是不会自动重启的。

 

posted on 2013-08-19 11:53 tbwshc 阅读(345) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理