转自 https://blog.csdn.net/qq8864/article/details/17961375
单片机程序构架
一种简单的信号量实现:
-
void sem_init( volatile U08 *Sem )
-
{
-
(*Sem)= 0;
-
}
-
-
void sem_post( volatile U08 *Sem )
-
{
-
if( 0 == (*Sem) )
-
(*Sem)++;
-
}
-
-
U08 sem_wait( volatile U08 *Sem )
-
{
-
if( 0 == *Sem)
-
return 1;
-
-
(*Sem)--;
-
-
return 0;
-
}
在一个大的while(1)大循环中,利用信号量实现各个函数(任务)的同步。
-
void Task_SysTime( void )
-
{
-
static int TaskInitFlg = 0;
-
U32 Timer1sCount = 0; //时钟计数器个数
-
U32 disstat = 0;
-
static int tmrid0 = 0, tmrid1 = 0, tmrid2 = 0, tmrid3 = 0;
-
-
if( 0 == TaskInitFlg )
-
{
-
OSTimeDlyHMSM( 0, 0, 0, 50 //主要等待任务删除后才创建卡任务
-
-
tmrid0 = TimerSet( 20); //定时器0(毫秒定时器)用于键盘、寻卡、定时器中断服务程序,20ms
-
tmrid1 = TimerSet( 1000); //定时器1(毫秒定时器)用于背显、GPS、定时连接检测、空闲显示
-
tmrid2 = TimerSet( 500); //定时器2(毫秒定时器)用于信号显示,500ms
-
tmrid3 = TimerSet( 500); //定时器3(毫秒定时器)用于电池显示,500ms
-
-
sem_init( &gSem_EVT_CARDFLG_OK ); //初始化为没有卡
-
-
APP_DisIdle( 2 ); //显示一次时间
-
APP_DisVoice();
-
-
TaskInitFlg = 1; //任务初始化完成
-
}
-
else
-
{
-
HW_IWDG_ReloadCounter(); //清看门狗
-
-
if( 0 == TimerCheck(tmrid0) )
-
{
-
tmrid0 = TimerSet( 20); //定时器0重新定时, 20ms
-
-
Timer_ScanKeyboard(); //20MS键盘扫描
-
Timer_FindCard(); //20MS寻卡处理
-
TIM20MS_IRQHandler(); //20MS定时器中断服务程序
-
}
-
}
-
}
-
-
void Task_Tick( void )
-
{
-
Task_SysError();
-
-
Task_CardProc();
-
-
Task_SysTime();
-
-
Task_MenuProc();
-
-
Task_MtnLink();
-
-
Task_CommProc();
-
}
-
int main( void )
-
{
-
Sys_Init(); //系统初始化
-
-
while( 1 )
-
{
-
Task_Tick(); //任务轮询
-
-
if( 0 == sem_wait( &gSem_EVT_QUIT_APP ) )
-
break; //应用退出
-
}
-
}
以上为借助信号量和定时器实现的一种简单的模拟多任务,其实也算不上是多任务,因为如果一个函数执行时间很长,如何打断它?
以下为借住定时器和任务队列实现的一种模拟多任务:
-
-
-
-
-
/*=====================================================
-
= 变量定义
-
=====================================================*/
-
//任务队列
-
typedef struct{
-
char flagState; //运行方式 0: 无任务
-
// 1: 运行
-
char flagRun; //完成状态 0: 正在计数
-
// 1: 计数完成
-
char flagType; //处理方式 0: 主任务处理
-
// 1: 中断处理
-
ulong cntRun; //运行计数器
-
ulong numCircle; //循环计数器
-
void (*pTaskFunc)( void); //任务
-
}TypeTimTask;
-
-
TypeTimTask timTaskTab[TIM_TASK_NUMBER];
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void TimTaskInit(void)
-
{
-
int i;
-
-
for (i= 0; i<TIM_TASK_NUMBER; i++)
-
{
-
timTaskTab[i].pTaskFunc = 0;
-
timTaskTab[i].cntRun = 0;
-
timTaskTab[i].numCircle = 0;
-
timTaskTab[i].flagRun = 0;
-
timTaskTab[i].flagState = 0;
-
}
-
SPT_register_call_back(TimTaskUpdate);
-
SPT_set(TIM_TASK_PERIOD * 64 / 1000);
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
short TimTaskAdd(ulong fsttim, ulong cirtim, void (*pTaskFunc)(void), uchar type)
-
{
-
int i;
-
int pos = -1;
-
//查找位置
-
for (i= 0; i<TIM_TASK_NUMBER; i++)
-
{
-
if (timTaskTab[i].pTaskFunc == pTaskFunc)
-
{
-
pos = i;
-
break;
-
}
-
if ((pos == -1) && (timTaskTab[i].flagState == 0))
-
{
-
pos = i;
-
}
-
}
-
//任务已满
-
if (pos == -1)
-
{
-
return -1;
-
}
-
//
-
timTaskTab[pos].pTaskFunc = pTaskFunc;
-
timTaskTab[pos].cntRun = fsttim / TIM_TASK_PERIOD;
-
timTaskTab[pos].numCircle = cirtim / TIM_TASK_PERIOD;
-
timTaskTab[pos].flagRun = 0;
-
timTaskTab[pos].flagType = type;
-
timTaskTab[pos].flagState = 1;
-
-
return 0;
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void TimTaskDel(void (*pTaskFunc)(void))
-
{
-
int i;
-
-
for (i= 0; i<TIM_TASK_NUMBER; i++)
-
{
-
if (timTaskTab[i].pTaskFunc == pTaskFunc)
-
{
-
timTaskTab[i].flagState = 0;
-
timTaskTab[i].flagRun = 0;
-
return;
-
}
-
}
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void TimTaskUpdate(void)
-
{
-
int i;
-
-
SPT_set(TIM_TASK_PERIOD * 64 / 1000);
-
-
for (i= 0; i<TIM_TASK_NUMBER; i++)
-
{
-
if (timTaskTab[i].flagState != 0)
-
{
-
if (timTaskTab[i].cntRun != 0)
-
{
-
timTaskTab[i].cntRun--;
-
}
-
else
-
{
-
//判断处理位置
-
if (timTaskTab[i].flagType != 0)
-
(*timTaskTab[i].pTaskFunc)();
-
else
-
timTaskTab[i].flagRun = 1;
-
//判断重载
-
if (timTaskTab[i].numCircle)
-
timTaskTab[i].cntRun = timTaskTab[i].numCircle;
-
else
-
timTaskTab[i].flagState = 0;
-
}
-
}
-
}
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void TimTaskProc(void)
-
{
-
int i;
-
-
for (i= 0; i<TIM_TASK_NUMBER; i++)
-
{
-
if (timTaskTab[i].flagRun != 0)
-
{
-
timTaskTab[i].flagRun = 0;
-
(*timTaskTab[i].pTaskFunc)();
-
}
-
}
-
}
通过中断等方式把实时事件封装成消息。以下为定义界面刷新显示和响应按键处理的结构:
-
-
-
-
-
-
/*=====================================================
-
=
-
=====================================================*/
-
typedef struct{
-
void (* OnPaint)( void);
-
void (* OnKey)( short);
-
}TypePage;
-
-
/*=====================================================
-
=
-
=====================================================*/
-
void WndPageSet(const TypePage *pg, int type = 0);
-
TypePage * WndGetPage(void);
-
void WndPageEsc(void);
-
void WndOnKey(short key);
-
void WndOnPaint(void);
-
void WndMenuInit(const char *pmn, char mline);
-
void WndMenuSelet(int m);
-
char WndMenuGetSelet(void);
-
long WndGetPaseword(int x, int y, char *psw, int len, long qevent);
-
-
-
/*=====================================================
-
=
-
=====================================================*/
-
char flagPaint = 0;
-
void (* pOnPaint)( void) = 0;
-
void (* pOnKey)( short) = 0;
-
-
const char *pMenuStr;
-
uchar menuSelect = 0;
-
uchar menuLine = 0;
-
uchar menuTop;
-
-
-
TypePage *pageCurrent;
-
TypePage *pageTreeTab[ 10];
-
uchar pageIndex = 0;
-
-
/*=====================================================
-
=
-
=====================================================*/
-
void WndDrawMenu(void);
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndPageSet(const TypePage *pg, int type)
-
{
-
if (pg == &pageMain) //防止出错
-
{
-
pageIndex = 0;
-
}
-
else if (type == 0)
-
{
-
pageTreeTab[pageIndex++] = pageCurrent;
-
}
-
pageCurrent = (TypePage *)pg;
-
pOnPaint = pg->OnPaint;
-
pOnKey = pg->OnKey;
-
flagPaint = 1;
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
TypePage * WndGetPage(void)
-
{
-
return pageCurrent;
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndPageEsc(void)
-
{
-
TypePage *pg;
-
-
if (pageIndex != 0)
-
{
-
pageIndex--;
-
pg = pageTreeTab[pageIndex];
-
}
-
else
-
{
-
pg = (TypePage *)&pageMain;
-
}
-
pageCurrent = pg;
-
pOnPaint = pg->OnPaint;
-
pOnKey = pg->OnKey;
-
flagPaint = 1;
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndOnPaint(void)
-
{
-
if (flagPaint != 0)
-
{
-
flagPaint = 0;
-
(*pOnPaint)();
-
}
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndOnKey(short key)
-
{
-
if (pOnKey != 0)
-
{
-
(*pOnKey)(key);
-
}
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndMenuInit(const char *pmn, char mline)
-
{
-
menuSelect = 0;
-
pMenuStr = pmn;
-
menuLine = mline;
-
menuTop = 0;
-
WndDrawMenu();
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndMenuSelet(int m)
-
{
-
//光标滑动
-
if (m > 0) //下移
-
{
-
menuSelect++;
-
if (menuSelect == menuLine)
-
menuSelect = 0;
-
-
if (menuSelect > menuTop + 4)
-
{
-
if (menuLine < menuTop + 4)
-
menuTop = menuLine - 4;
-
else
-
menuTop = menuSelect - 4;
-
}
-
}
-
else if (m < 0) //上移
-
{
-
if (menuSelect == 0)
-
menuSelect = menuLine - 1;
-
else
-
menuSelect--;
-
}
-
//图框移动
-
if (menuSelect < menuTop) //上移
-
{
-
menuTop = menuSelect;
-
}
-
else if (menuSelect >= menuTop + 4) //下移
-
{
-
menuTop = menuSelect - 3;
-
}
-
-
WndDrawMenu();
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
char WndMenuGetSelet(void)
-
{
-
return menuSelect + 1;
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndDrawMenu(void)
-
{
-
int i;
-
-
char buf[ 17];
-
const char *pmn = pMenuStr + menuTop * 16;
-
-
DispClr();
-
for (i= 0; i< 4; i++)
-
{
-
if (menuTop + i == menuLine)
-
break;
-
memcpy(buf, pmn, 16);
-
buf[ 16] = '\0';
-
if (menuSelect == menuTop + i)
-
DispSetStyle(DISP_POSITION | DISP_REVERSE | DISP_7x9);
-
else
-
DispSetStyle(DISP_POSITION | DISP_NORMAL | DISP_7x9);
-
DispString( 0, i * 2, buf);
-
pmn += 16;
-
}
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
long WndGetPaseword(int x, int y, char *psw, int len, long qevent)
-
{
-
int pin = 0;
-
long keyevt;
-
char key;
-
char buf[ 20];
-
-
memset(buf, '_', len);
-
buf[len] = '\0';
-
PSW_INPUT_LOOP:
-
DispString(x, y, buf);
-
keyevt = delay_and_wait_key( 0, EXIT_KEY_ALL, 0);
-
if (keyevt == qevent)
-
{
-
psw[ 0] = '\0';
-
return keyevt;
-
}
-
switch (keyevt)
-
{
-
case EXIT_KEY_0:
-
key = '0';
-
break;
-
case EXIT_KEY_1:
-
key = '1';
-
break;
-
case EXIT_KEY_2:
-
key = '2';
-
break;
-
case EXIT_KEY_3:
-
key = '3';
-
break;
-
case EXIT_KEY_4:
-
key = '4';
-
break;
-
case EXIT_KEY_5:
-
key = '5';
-
break;
-
case EXIT_KEY_6:
-
key = '6';
-
break;
-
case EXIT_KEY_7:
-
key = '7';
-
break;
-
case EXIT_KEY_8:
-
key = '8';
-
break;
-
case EXIT_KEY_9:
-
key = '9';
-
break;
-
case EXIT_KEY_COMM:
-
if (pin != 0)
-
{
-
buf[--pin] = '_';
-
}
-
goto PSW_INPUT_LOOP;
-
break;
-
case EXIT_KEY_ENTER:
-
psw[pin] = 0;
-
return 0;
-
default:
-
goto PSW_INPUT_LOOP;
-
}
-
if (pin != len)
-
{
-
psw[pin] = key;
-
buf[pin] = '*';
-
pin++;
-
}
-
goto PSW_INPUT_LOOP;
-
}
在软件设计时,如果添加界面和对应的按键处理,很灵活,只需要新添加一个文件就可以了,文件的内容,只需要实现OnPain和对应的OnKey
-
-
-
-
/*=====================================================
-
=
-
=====================================================*/
-
const char mainMenuTab[] = /*
-
1234567890123456*/ "\
-
1. 现场采集 \
-
2. 数据上传 \
-
3. 存储状态查询 \
-
4. 时间设置 \
-
5. 对比度设置 \
-
6. 恢复出厂设置 \
-
7. 关于 ";
-
-
/*=====================================================
-
=
-
=====================================================*/
-
void PageMenuOnPain(void);
-
void WndMenuOnKey(short key);
-
-
const TypePage pageMenu = {PageMenuOnPain, WndMenuOnKey};
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void PageMenuOnPain(void)
-
{
-
WndMenuInit(mainMenuTab, 7);
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndMenuOnKey(short key)
-
{
-
int res;
-
-
switch (key)
-
{
-
case KEY_F1:
-
case KEY_ENTER:
-
res = WndMenuGetSelet();
-
switch (res)
-
{
-
case 1:
-
WndPageSet(&pageSimp);
-
break;
-
case 2:
-
WndPageSet(&pagePclink);
-
break;
-
case 3:
-
WndPageSet(&pageInquire);
-
break;
-
case 4:
-
WndPageSet(&pageRtc);
-
break;
-
case 5:
-
WndPageSet(&pageGray);
-
break;
-
case 6:
-
SPageInit();
-
WndPageSet(&pageMenu, 1);
-
break;
-
case 7:
-
WndPageSet(&pageAbout);
-
break;
-
}
-
break;
-
case KEY_F2:
-
case KEY_F3:
-
WndPageSet(&pageMain);
-
break;
-
case KEY_1:
-
WndPageSet(&pageSimp);
-
break;
-
case KEY_2:
-
WndPageSet(&pagePclink);
-
break;
-
case KEY_3:
-
WndPageSet(&pageInquire);
-
break;
-
case KEY_4:
-
WndPageSet(&pageRtc);
-
break;
-
case KEY_5:
-
WndPageSet(&pageGray);
-
break;
-
case KEY_6:
-
SPageInit();
-
WndPageSet(&pageMenu, 1);
-
break;
-
case KEY_7:
-
WndPageSet(&pageAbout);
-
break;
-
case KEY_UP:
-
WndMenuSelet( -1);
-
break;
-
case KEY_DOWN:
-
WndMenuSelet( 1);
-
break;
-
case KEY_POWER:
-
WndPageSet(&pagePower);
-
break;
-
}
-
}
pageMain,pageAbout,pageRtc,pagePclink等文件,他们的结构很类似。都是实现了OnPaint和OnKey函数。
如:pagePclink.c文件内容:
实现了PagePclinkOnPaint和PagePclinOnKey函数.
CommPclink函数是自己想要实现的功能,可以自己定义。
-
-
-
/*=====================================================
-
=
-
=====================================================*/
-
void PagePclinkOnPaint(void);
-
void PagePclinOnKey(short key);
-
-
const TypePage pagePclink = {PagePclinkOnPaint, PagePclinOnKey};
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void PagePclinkOnPaint(void)
-
{
-
DispClr();
-
DispSetStyle(DISP_CENTER | DISP_REVERSE | DISP_7x9);
-
DispString( 0, 0, " 数据上传 ");
-
DispSetStyle(DISP_POSITION|DISP_NORMAL|DISP_7x9);
-
DispString( 0, 6, "[连接] [返回]");
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void PagePclinOnKey(short key)
-
{
-
switch (key)
-
{
-
case KEY_F1:
-
CommPclink();
-
break;
-
case KEY_F3:
-
WndPageEsc();
-
break;
-
}
-
}
-
-
-
-
-
-
/*=====================================================
-
=
-
=====================================================*/
-
extern const TypePage pagePower;
-
-
-
-
-
-
-
/*=====================================================
-
=
-
=====================================================*/
-
void PagePowerOnPaint(void);
-
void PagePowerOnKey(short key);
-
-
const TypePage pagePower = {PagePowerOnPaint, PagePowerOnKey};
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void PagePowerOnPaint(void)
-
{
-
DispClr();
-
DispSetStyle(DISP_CENTER | DISP_REVERSE | DISP_7x9);
-
DispString( 0, 0, " 电源管理 ");
-
DispSetStyle(DISP_POSITION|DISP_NORMAL|DISP_7x9);
-
DispString( 0, 2, " [Enter] 关机 ");
-
DispString( 0, 4, " [F3 ] 返回 ");
-
}
-
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void PagePowerOnKey(short key)
-
{
-
switch (key)
-
{
-
case KEY_ENTER:
-
case KEY_POWER:
-
Halt_EH0218( 4);
-
SysInit();
-
break;
-
case KEY_F3:
-
WndPageEsc();
-
break;
-
}
-
}
这样的一种结构,很灵活,在主函数中只需要这样调用:
-
int main(void)
-
{
-
short key;
-
typ_msg_word smw;
-
-
SysInit();
-
-
for ( ; ; )
-
{
-
/*
-
界面刷新
-
*/
-
WndOnPaint();
-
-
/*
-
消息处理
-
*/
-
smw.s_word = sys_msg(SM_STAY_AWAKE); //用SM_GOTO_SLEEP串口就不能用
-
//按键处理
-
if (smw.bits.key_available)
-
{
-
LcdOffDelay(LCD_OFF_DELAY);
-
-
key = KEY_read();
-
if (key != -1)
-
{
-
WndOnKey(key);
-
}
-
}
-
//插入充电电源
-
if (smw.bits.charger_on)
-
{
-
LcdOffDelay(LCD_OFF_DELAY);
-
}
-
//断开充电电源
-
if (smw.bits.charger_off)
-
{
-
LcdOffDelay(LCD_OFF_DELAY);
-
RefreshBattery();
-
}
-
//串口
-
if (smw.bits.comm_data)
-
{
-
CommReceive();
-
}
-
//实时任务
-
if (smw.bits.time_out)
-
{
-
TimTaskProc();
-
}
-
}
-
}
-
一种简单的信号量实现:
-
void sem_init( volatile U08 *Sem )
-
{
-
(*Sem)= 0;
-
}
-
-
void sem_post( volatile U08 *Sem )
-
{
-
if( 0 == (*Sem) )
-
(*Sem)++;
-
}
-
-
U08 sem_wait( volatile U08 *Sem )
-
{
-
if( 0 == *Sem)
-
return 1;
-
-
(*Sem)--;
-
-
return 0;
-
}
在一个大的while(1)大循环中,利用信号量实现各个函数(任务)的同步。
-
void Task_SysTime( void )
-
{
-
static int TaskInitFlg = 0;
-
U32 Timer1sCount = 0; //时钟计数器个数
-
U32 disstat = 0;
-
static int tmrid0 = 0, tmrid1 = 0, tmrid2 = 0, tmrid3 = 0;
-
-
if( 0 == TaskInitFlg )
-
{
-
OSTimeDlyHMSM( 0, 0, 0, 50 //主要等待任务删除后才创建卡任务
-
-
tmrid0 = TimerSet( 20); //定时器0(毫秒定时器)用于键盘、寻卡、定时器中断服务程序,20ms
-
tmrid1 = TimerSet( 1000); //定时器1(毫秒定时器)用于背显、GPS、定时连接检测、空闲显示
-
tmrid2 = TimerSet( 500); //定时器2(毫秒定时器)用于信号显示,500ms
-
tmrid3 = TimerSet( 500); //定时器3(毫秒定时器)用于电池显示,500ms
-
-
sem_init( &gSem_EVT_CARDFLG_OK ); //初始化为没有卡
-
-
APP_DisIdle( 2 ); //显示一次时间
-
APP_DisVoice();
-
-
TaskInitFlg = 1; //任务初始化完成
-
}
-
else
-
{
-
HW_IWDG_ReloadCounter(); //清看门狗
-
-
if( 0 == TimerCheck(tmrid0) )
-
{
-
tmrid0 = TimerSet( 20); //定时器0重新定时, 20ms
-
-
Timer_ScanKeyboard(); //20MS键盘扫描
-
Timer_FindCard(); //20MS寻卡处理
-
TIM20MS_IRQHandler(); //20MS定时器中断服务程序
-
}
-
}
-
}
-
-
void Task_Tick( void )
-
{
-
Task_SysError();
-
-
Task_CardProc();
-
-
Task_SysTime();
-
-
Task_MenuProc();
-
-
Task_MtnLink();
-
-
Task_CommProc();
-
}
-
int main( void )
-
{
-
Sys_Init(); //系统初始化
-
-
while( 1 )
-
{
-
Task_Tick(); //任务轮询
-
-
if( 0 == sem_wait( &gSem_EVT_QUIT_APP ) )
-
break; //应用退出
-
}
-
}
以上为借助信号量和定时器实现的一种简单的模拟多任务,其实也算不上是多任务,因为如果一个函数执行时间很长,如何打断它?
以下为借住定时器和任务队列实现的一种模拟多任务:
-
-
-
-
-
/*=====================================================
-
= 变量定义
-
=====================================================*/
-
//任务队列
-
typedef struct{
-
char flagState; //运行方式 0: 无任务
-
// 1: 运行
-
char flagRun; //完成状态 0: 正在计数
-
// 1: 计数完成
-
char flagType; //处理方式 0: 主任务处理
-
// 1: 中断处理
-
ulong cntRun; //运行计数器
-
ulong numCircle; //循环计数器
-
void (*pTaskFunc)( void); //任务
-
}TypeTimTask;
-
-
TypeTimTask timTaskTab[TIM_TASK_NUMBER];
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void TimTaskInit(void)
-
{
-
int i;
-
-
for (i= 0; i<TIM_TASK_NUMBER; i++)
-
{
-
timTaskTab[i].pTaskFunc = 0;
-
timTaskTab[i].cntRun = 0;
-
timTaskTab[i].numCircle = 0;
-
timTaskTab[i].flagRun = 0;
-
timTaskTab[i].flagState = 0;
-
}
-
SPT_register_call_back(TimTaskUpdate);
-
SPT_set(TIM_TASK_PERIOD * 64 / 1000);
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
short TimTaskAdd(ulong fsttim, ulong cirtim, void (*pTaskFunc)(void), uchar type)
-
{
-
int i;
-
int pos = -1;
-
//查找位置
-
for (i= 0; i<TIM_TASK_NUMBER; i++)
-
{
-
if (timTaskTab[i].pTaskFunc == pTaskFunc)
-
{
-
pos = i;
-
break;
-
}
-
if ((pos == -1) && (timTaskTab[i].flagState == 0))
-
{
-
pos = i;
-
}
-
}
-
//任务已满
-
if (pos == -1)
-
{
-
return -1;
-
}
-
//
-
timTaskTab[pos].pTaskFunc = pTaskFunc;
-
timTaskTab[pos].cntRun = fsttim / TIM_TASK_PERIOD;
-
timTaskTab[pos].numCircle = cirtim / TIM_TASK_PERIOD;
-
timTaskTab[pos].flagRun = 0;
-
timTaskTab[pos].flagType = type;
-
timTaskTab[pos].flagState = 1;
-
-
return 0;
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void TimTaskDel(void (*pTaskFunc)(void))
-
{
-
int i;
-
-
for (i= 0; i<TIM_TASK_NUMBER; i++)
-
{
-
if (timTaskTab[i].pTaskFunc == pTaskFunc)
-
{
-
timTaskTab[i].flagState = 0;
-
timTaskTab[i].flagRun = 0;
-
return;
-
}
-
}
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void TimTaskUpdate(void)
-
{
-
int i;
-
-
SPT_set(TIM_TASK_PERIOD * 64 / 1000);
-
-
for (i= 0; i<TIM_TASK_NUMBER; i++)
-
{
-
if (timTaskTab[i].flagState != 0)
-
{
-
if (timTaskTab[i].cntRun != 0)
-
{
-
timTaskTab[i].cntRun--;
-
}
-
else
-
{
-
//判断处理位置
-
if (timTaskTab[i].flagType != 0)
-
(*timTaskTab[i].pTaskFunc)();
-
else
-
timTaskTab[i].flagRun = 1;
-
//判断重载
-
if (timTaskTab[i].numCircle)
-
timTaskTab[i].cntRun = timTaskTab[i].numCircle;
-
else
-
timTaskTab[i].flagState = 0;
-
}
-
}
-
}
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void TimTaskProc(void)
-
{
-
int i;
-
-
for (i= 0; i<TIM_TASK_NUMBER; i++)
-
{
-
if (timTaskTab[i].flagRun != 0)
-
{
-
timTaskTab[i].flagRun = 0;
-
(*timTaskTab[i].pTaskFunc)();
-
}
-
}
-
}
通过中断等方式把实时事件封装成消息。以下为定义界面刷新显示和响应按键处理的结构:
-
-
-
-
-
-
/*=====================================================
-
=
-
=====================================================*/
-
typedef struct{
-
void (* OnPaint)( void);
-
void (* OnKey)( short);
-
}TypePage;
-
-
/*=====================================================
-
=
-
=====================================================*/
-
void WndPageSet(const TypePage *pg, int type = 0);
-
TypePage * WndGetPage(void);
-
void WndPageEsc(void);
-
void WndOnKey(short key);
-
void WndOnPaint(void);
-
void WndMenuInit(const char *pmn, char mline);
-
void WndMenuSelet(int m);
-
char WndMenuGetSelet(void);
-
long WndGetPaseword(int x, int y, char *psw, int len, long qevent);
-
-
-
/*=====================================================
-
=
-
=====================================================*/
-
char flagPaint = 0;
-
void (* pOnPaint)( void) = 0;
-
void (* pOnKey)( short) = 0;
-
-
const char *pMenuStr;
-
uchar menuSelect = 0;
-
uchar menuLine = 0;
-
uchar menuTop;
-
-
-
TypePage *pageCurrent;
-
TypePage *pageTreeTab[ 10];
-
uchar pageIndex = 0;
-
-
/*=====================================================
-
=
-
=====================================================*/
-
void WndDrawMenu(void);
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndPageSet(const TypePage *pg, int type)
-
{
-
if (pg == &pageMain) //防止出错
-
{
-
pageIndex = 0;
-
}
-
else if (type == 0)
-
{
-
pageTreeTab[pageIndex++] = pageCurrent;
-
}
-
pageCurrent = (TypePage *)pg;
-
pOnPaint = pg->OnPaint;
-
pOnKey = pg->OnKey;
-
flagPaint = 1;
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
TypePage * WndGetPage(void)
-
{
-
return pageCurrent;
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndPageEsc(void)
-
{
-
TypePage *pg;
-
-
if (pageIndex != 0)
-
{
-
pageIndex--;
-
pg = pageTreeTab[pageIndex];
-
}
-
else
-
{
-
pg = (TypePage *)&pageMain;
-
}
-
pageCurrent = pg;
-
pOnPaint = pg->OnPaint;
-
pOnKey = pg->OnKey;
-
flagPaint = 1;
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndOnPaint(void)
-
{
-
if (flagPaint != 0)
-
{
-
flagPaint = 0;
-
(*pOnPaint)();
-
}
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndOnKey(short key)
-
{
-
if (pOnKey != 0)
-
{
-
(*pOnKey)(key);
-
}
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndMenuInit(const char *pmn, char mline)
-
{
-
menuSelect = 0;
-
pMenuStr = pmn;
-
menuLine = mline;
-
menuTop = 0;
-
WndDrawMenu();
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndMenuSelet(int m)
-
{
-
//光标滑动
-
if (m > 0) //下移
-
{
-
menuSelect++;
-
if (menuSelect == menuLine)
-
menuSelect = 0;
-
-
if (menuSelect > menuTop + 4)
-
{
-
if (menuLine < menuTop + 4)
-
menuTop = menuLine - 4;
-
else
-
menuTop = menuSelect - 4;
-
}
-
}
-
else if (m < 0) //上移
-
{
-
if (menuSelect == 0)
-
menuSelect = menuLine - 1;
-
else
-
menuSelect--;
-
}
-
//图框移动
-
if (menuSelect < menuTop) //上移
-
{
-
menuTop = menuSelect;
-
}
-
else if (menuSelect >= menuTop + 4) //下移
-
{
-
menuTop = menuSelect - 3;
-
}
-
-
WndDrawMenu();
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
char WndMenuGetSelet(void)
-
{
-
return menuSelect + 1;
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndDrawMenu(void)
-
{
-
int i;
-
-
char buf[ 17];
-
const char *pmn = pMenuStr + menuTop * 16;
-
-
DispClr();
-
for (i= 0; i< 4; i++)
-
{
-
if (menuTop + i == menuLine)
-
break;
-
memcpy(buf, pmn, 16);
-
buf[ 16] = '\0';
-
if (menuSelect == menuTop + i)
-
DispSetStyle(DISP_POSITION | DISP_REVERSE | DISP_7x9);
-
else
-
DispSetStyle(DISP_POSITION | DISP_NORMAL | DISP_7x9);
-
DispString( 0, i * 2, buf);
-
pmn += 16;
-
}
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
long WndGetPaseword(int x, int y, char *psw, int len, long qevent)
-
{
-
int pin = 0;
-
long keyevt;
-
char key;
-
char buf[ 20];
-
-
memset(buf, '_', len);
-
buf[len] = '\0';
-
PSW_INPUT_LOOP:
-
DispString(x, y, buf);
-
keyevt = delay_and_wait_key( 0, EXIT_KEY_ALL, 0);
-
if (keyevt == qevent)
-
{
-
psw[ 0] = '\0';
-
return keyevt;
-
}
-
switch (keyevt)
-
{
-
case EXIT_KEY_0:
-
key = '0';
-
break;
-
case EXIT_KEY_1:
-
key = '1';
-
break;
-
case EXIT_KEY_2:
-
key = '2';
-
break;
-
case EXIT_KEY_3:
-
key = '3';
-
break;
-
case EXIT_KEY_4:
-
key = '4';
-
break;
-
case EXIT_KEY_5:
-
key = '5';
-
break;
-
case EXIT_KEY_6:
-
key = '6';
-
break;
-
case EXIT_KEY_7:
-
key = '7';
-
break;
-
case EXIT_KEY_8:
-
key = '8';
-
break;
-
case EXIT_KEY_9:
-
key = '9';
-
break;
-
case EXIT_KEY_COMM:
-
if (pin != 0)
-
{
-
buf[--pin] = '_';
-
}
-
goto PSW_INPUT_LOOP;
-
break;
-
case EXIT_KEY_ENTER:
-
psw[pin] = 0;
-
return 0;
-
default:
-
goto PSW_INPUT_LOOP;
-
}
-
if (pin != len)
-
{
-
psw[pin] = key;
-
buf[pin] = '*';
-
pin++;
-
}
-
goto PSW_INPUT_LOOP;
-
}
在软件设计时,如果添加界面和对应的按键处理,很灵活,只需要新添加一个文件就可以了,文件的内容,只需要实现OnPain和对应的OnKey
-
-
-
-
/*=====================================================
-
=
-
=====================================================*/
-
const char mainMenuTab[] = /*
-
1234567890123456*/ "\
-
1. 现场采集 \
-
2. 数据上传 \
-
3. 存储状态查询 \
-
4. 时间设置 \
-
5. 对比度设置 \
-
6. 恢复出厂设置 \
-
7. 关于 ";
-
-
/*=====================================================
-
=
-
=====================================================*/
-
void PageMenuOnPain(void);
-
void WndMenuOnKey(short key);
-
-
const TypePage pageMenu = {PageMenuOnPain, WndMenuOnKey};
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void PageMenuOnPain(void)
-
{
-
WndMenuInit(mainMenuTab, 7);
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void WndMenuOnKey(short key)
-
{
-
int res;
-
-
switch (key)
-
{
-
case KEY_F1:
-
case KEY_ENTER:
-
res = WndMenuGetSelet();
-
switch (res)
-
{
-
case 1:
-
WndPageSet(&pageSimp);
-
break;
-
case 2:
-
WndPageSet(&pagePclink);
-
break;
-
case 3:
-
WndPageSet(&pageInquire);
-
break;
-
case 4:
-
WndPageSet(&pageRtc);
-
break;
-
case 5:
-
WndPageSet(&pageGray);
-
break;
-
case 6:
-
SPageInit();
-
WndPageSet(&pageMenu, 1);
-
break;
-
case 7:
-
WndPageSet(&pageAbout);
-
break;
-
}
-
break;
-
case KEY_F2:
-
case KEY_F3:
-
WndPageSet(&pageMain);
-
break;
-
case KEY_1:
-
WndPageSet(&pageSimp);
-
break;
-
case KEY_2:
-
WndPageSet(&pagePclink);
-
break;
-
case KEY_3:
-
WndPageSet(&pageInquire);
-
break;
-
case KEY_4:
-
WndPageSet(&pageRtc);
-
break;
-
case KEY_5:
-
WndPageSet(&pageGray);
-
break;
-
case KEY_6:
-
SPageInit();
-
WndPageSet(&pageMenu, 1);
-
break;
-
case KEY_7:
-
WndPageSet(&pageAbout);
-
break;
-
case KEY_UP:
-
WndMenuSelet( -1);
-
break;
-
case KEY_DOWN:
-
WndMenuSelet( 1);
-
break;
-
case KEY_POWER:
-
WndPageSet(&pagePower);
-
break;
-
}
-
}
pageMain,pageAbout,pageRtc,pagePclink等文件,他们的结构很类似。都是实现了OnPaint和OnKey函数。
如:pagePclink.c文件内容:
实现了PagePclinkOnPaint和PagePclinOnKey函数.
CommPclink函数是自己想要实现的功能,可以自己定义。
-
-
-
/*=====================================================
-
=
-
=====================================================*/
-
void PagePclinkOnPaint(void);
-
void PagePclinOnKey(short key);
-
-
const TypePage pagePclink = {PagePclinkOnPaint, PagePclinOnKey};
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void PagePclinkOnPaint(void)
-
{
-
DispClr();
-
DispSetStyle(DISP_CENTER | DISP_REVERSE | DISP_7x9);
-
DispString( 0, 0, " 数据上传 ");
-
DispSetStyle(DISP_POSITION|DISP_NORMAL|DISP_7x9);
-
DispString( 0, 6, "[连接] [返回]");
-
}
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void PagePclinOnKey(short key)
-
{
-
switch (key)
-
{
-
case KEY_F1:
-
CommPclink();
-
break;
-
case KEY_F3:
-
WndPageEsc();
-
break;
-
}
-
}
-
-
-
-
-
-
/*=====================================================
-
=
-
=====================================================*/
-
extern const TypePage pagePower;
-
-
-
-
-
-
-
/*=====================================================
-
=
-
=====================================================*/
-
void PagePowerOnPaint(void);
-
void PagePowerOnKey(short key);
-
-
const TypePage pagePower = {PagePowerOnPaint, PagePowerOnKey};
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void PagePowerOnPaint(void)
-
{
-
DispClr();
-
DispSetStyle(DISP_CENTER | DISP_REVERSE | DISP_7x9);
-
DispString( 0, 0, " 电源管理 ");
-
DispSetStyle(DISP_POSITION|DISP_NORMAL|DISP_7x9);
-
DispString( 0, 2, " [Enter] 关机 ");
-
DispString( 0, 4, " [F3 ] 返回 ");
-
}
-
-
-
/*************************************************************************
-
* 函数原型:
-
* 功能描述:
-
* 入口参数:
-
* 出口参数:
-
* 返 回 值:
-
*************************************************************************/
-
void PagePowerOnKey(short key)
-
{
-
switch (key)
-
{
-
case KEY_ENTER:
-
case KEY_POWER:
-
Halt_EH0218( 4);
-
SysInit();
-
break;
-
case KEY_F3:
-
WndPageEsc();
-
break;
-
}
-
}
这样的一种结构,很灵活,在主函数中只需要这样调用:
-
int main(void)
-
{
-
short key;
-
typ_msg_word smw;
-
-
SysInit();
-
-
for ( ; ; )
-
{
-
/*
-
界面刷新
-
*/
-
WndOnPaint();
-
-
/*
-
消息处理
-
*/
-
smw.s_word = sys_msg(SM_STAY_AWAKE); //用SM_GOTO_SLEEP串口就不能用
-
//按键处理
-
if (smw.bits.key_available)
-
{
-
LcdOffDelay(LCD_OFF_DELAY);
-
-
key = KEY_read();
-
if (key != -1)
-
{
-
WndOnKey(key);
-
}
-
}
-
//插入充电电源
-
if (smw.bits.charger_on)
-
{
-
LcdOffDelay(LCD_OFF_DELAY);
-
}
-
//断开充电电源
-
if (smw.bits.charger_off)
-
{
-
LcdOffDelay(LCD_OFF_DELAY);
-
RefreshBattery();
-
}
-
//串口
-
if (smw.bits.comm_data)
-
{
-
CommReceive();
-
}
-
//实时任务
-
if (smw.bits.time_out)
-
{
-
TimTaskProc();
-
}
-
}
-
}
-