C++之父Bjarne Stroustrup也曾说过:“你使用一个语言特征是因为你需要它,而不是因为它存在”。设计ucClass(uCosII封装类)的初衷是由于过去很多的实现都是在C++中完成,深切感受到面向对象分析、设计乃至编程的独特魅力。回想微软的MFC1为win32程序设计所带来的便利、DriverWork2在PC硬件的驱动开发的高效,促使完成ucClass的设计(这里头没有什么高深的学问),其实更重要的一点是它能改进现有的设计模式,能让今后的uCosII相关开发及维护变得更加轻松和高效!
对于OO我也就几年的开发经验,没有做过什么“巨项”,对于ARM也是接触时间不长,不过有一个概念一直影响着我,“ARM不就是复杂一点的单片机吗”,我想也不应该难到那里去。于是有空就玩玩,对于很多做这行做开发的对C++这样的面向对象编程语言大多不甚了解,要想用OO思想来武装自己又谈何容易啊,这就是一种挑战习惯、挑战思维方式的行为,等于放弃过去曾经为你有效解决难题完成工作的开发模式。在此我也没有什么灵丹妙药可改变这些处境,唯一的建议就是坚持及不断实践、只有这样的思想基础才能提高成功的机会。
下面简单设计一个ucClass的demo程序(当然会可能隐藏了一些bug or error),目标板使用的是菲利普LPC2100芯片(周立功的EasyARM 2100开发板),有些头文件这里就不贴了,旨在看看主程序的结构及设计过程,就让一些软件的大虾们见笑了。
若有机会的我还准备写几个基于OO之上的在嵌入式开发的应用demo……
设计需求:
使用ucClass设计一个demo程序完成下列任务:
任务编号 任务指责和功能描述 物理资源占用
1 每间隔1秒蜂鸣器短促发声两次,每10秒间隔使用信号量通知任务2,随后自身进入挂起等待状态。 蜂鸣器及IO端口
2 无限等待由任务1触发的信号量,当有信号时引发1秒蜂鸣器长鸣,其后恢复任务1,自身再次进入信号量的无限等待状态中。 蜂鸣器及IO端口
3 孤立任务,简单的一秒间隔led1闪烁。 Led1及IO端口
4 孤立任务,通过检查key1按键状态控制led4的二值状态(亮/灭)。 key1,led4及IO端口
// main.cpp文件,ucClass测试主程序
// exdata 2004-8-18
#include "config.h" // 一些硬件相关的声明
#include "GPIO.H" // GPIO类头文件
#include "ucClass.H" // uCosII的收集类库头文件
/*
// 在浏览demo程序时要注意以下几点:
// 1,带参数的对象构造
// 2,静态函数调用
// 3,带参数的派生类构造
// 4,虚拟函数重载
// 5,特别注意一些头文件(不在此文档中)包含写法及原有C函数声明方法,关注extern "C"
// 6,不拘泥于传统的设计思想(模式)
// 7,比较不使用class时候又是如何处理的?分析每个对象背后隐藏了什么?
*/
/************************** 全局变量 *****************************/
// 定义几个task对象,这是实例化对象,隐藏并实现了任务栈的构造
CTask t1(128); // 参数是任务堆栈分配大小(在ARM中以32bit为单位)
CTask t2(64);
CTask t3(64);
CSem t2WaitEvent; // 定义一个信号量对象用于任务t1、t2通信
CGPIO buzz("P0.7",1); // 定义一个GPIO对象,输出模式,用于控制蜂鸣器
/*
// 前置声明几个任务运行函数,这个与C模式下没有什么区别。
// 还保留这种处理方法仅仅为求兼顾一些使用uCosII习惯,建议参考CMyTask的
// 设计及t4的定义,使用子类设计实现具体任务的处理方法要比C模式的的全局
// 孤立启动函数更具有设计上及维护上的优点,当做一个中大型项目时候效果尤
// 为明显。
*/
void t1Run(void *p);
void t2Run(void *p);
void t3Run(void *p);
/*******************************************************************/
/*
// t1任务运行函数。
// 功能:每间隔1秒蜂鸣器短促发声两次,每10秒间隔使用信号量t2WaitEvent通
// 知任务t2,随后自身进入挂起等待状态。
*/
void t1Run(void *p)
{
TargetInit(); // 初始化硬件目标板
INT32U i = 0;
while(1)
{
CuCos::TimeDlyHMSM(0,0,1,0);
if(++i == 10)
{
i = 0;
t2WaitEvent.Post();
t1.Suspend();
}
// 蜂鸣器短促发声两次
buzz.Clear();
CuCos::TimeDlyHMSM(0,0,0,50);
buzz.Set();
CuCos::TimeDlyHMSM(0,0,0,50);
buzz.Clear();
CuCos::TimeDlyHMSM(0,0,0,50);
buzz.Set();
}
p = p;
}
/*
// t2任务运行函数。
// 功能:无限等待信号量t2WaitEvent,当有信号时引发1秒蜂鸣器长鸣,其后恢
// 复t1任务,任务t2再次自身进入信号量t2WaitEvent的无限等待状态。
*/
void t2Run(void *p)
{
INT8U err = 0;
while(1)
{
t2WaitEvent.Pend(0,&err);
buzz.Clear();
CuCos::TimeDlyHMSM(0,0,1,0);
buzz.Set();
CuCos::TimeDlyHMSM(0,0,0,50);
t1.Resume();
}
p = p;
}
/*
// t3任务运行函数。
// 功能:简单的一秒间隔led1闪烁。
*/
void t3Run(void *p)
{
static CGPIO led1("P0.22",1);
while(1)
{
led1.Set();
CuCos::TimeDlyHMSM(0,0,1,0);
led1.Clear();
CuCos::TimeDlyHMSM(0,0,1,0);
}
p = p;
}
/*
// 为求原汁原味体现一个task对象的封装,下面设计一个子类实现一个特定任务
// 的处理,在此我们可以认为一个任务就是一个子系统,通过一个子类表现一个
// 特有任务的具体属性和行为,注意这种设计方法与传统的面向对象编程模式是
// 有区别的。子系统是一个有自主能力主体,例如在MyTask子系统中我们有两
// 个IO资源m_key1和m_led4分别对应着电路板上的按键Key1和发光二极管Led4,
// 通过检查key1按键状态控制led4的二值状态(亮/灭)。重载基类了Run函数为
// 求体现类的封装特性及表现一个任务的内聚能力,它是一个强制的运行接口,
// 当任务启动时便能自动地从重载的Run函数开始运行(具体调用的中转过程在
// 基类中已经实现)。
*/
class CMyTask : public CTask // 注意这里的派生关系!!!
{
public:
CMyTask(INT32U StkSize) : CTask(StkSize),m_key1("P0.16",0),m_led4("P0.25",1,0)
{
// 注意带参数的构造处理方法!!!
}
protected:
virtual void Run(void *p); // 需要重载Run()函数实现任务执行
private:
// 这是任务用到的一些资源定义,当然添加子系统的其他的属性和方法也是允许的
CGPIO m_key1;
CGPIO m_led4;
};
/*
// t4任务运行函数。
// 通过函数重载实现重写Run函数,该函数也就是任务运行函数。
// 功能:通过检查key1按键状态控制led4的二值状态(亮/灭)。
*/
void CMyTask::Run(void *p) // Run函数将会被uCosII系统自动运行!
{
while(1)
{
if(m_key1.GetStatus() == 0) // 判断按键是否按下
{
if(m_led4.GetStatus() == 0)
{
m_led4.Set();
}
else
{
m_led4.Clear();
}
while(m_key1.GetStatus() == 0)
{
CuCos::TimeDly(20); // 等待按键释放
}
}
else
{
CuCos::TimeDly(10);
}
}
p = p;
}
/*
// 注意一般应该把上面的CMyTask定义及实现另行写在其他的文件中!把它写在
// 这里仅仅为求说明方便。
*/
/*-------------------------------------------------------------------------------------------------*/
CMyTask t4(128); //注意任务对象t4是由CMyTask实例化的对象
// 看看这个简洁的main函数,这时候您想到了什么?
int main()
{
CuCos::Init(); // uCosII的系统函数,用于初始化uCosII,等效于OSInit()
t2WaitEvent.Create(); // 创建t2WaitEvent的信号量
// 创建任务(参数指定任务函数启动地址、任务函数参数和优先级)
t1.Create(t1Run,NULL,1);
t2.Create(t2Run,NULL,2);
t3.Create(t3Run,NULL,3);
t4.Create(NULL,4); // 创建任务,注意Create函数的重载
CuCos::Start(); // 等效于OSStart()
return 0;
}
文章评论(0条评论)
登录后参与讨论