一种简单的信号量实现:
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; //应用退出
}
}
以下为借住定时器和任务队列实现的一种模拟多任务:
#include
#include "timTask.h"
#include "disp.h"
/*=====================================================
= 变量定义
=====================================================*/
//任务队列
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
更为巧妙的是,可以借住函数指针实现一种灵活的菜单和按键实时处理结构。类似于windows下win32的消息驱动机制,
#ifndef __PAGE_H_
#define __PAGE_H_
#include "heads.h"
/*=====================================================
=
=====================================================*/
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);
#include "pageWnd.h"
/*=====================================================
=
=====================================================*/
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
#include "PageMenu.h"
/*=====================================================
=
=====================================================*/
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;
}
}
CommPclink函数是自己想要实现的功能,可以自己定义。
#include "pagePclink.h"
/*=====================================================
=
=====================================================*/
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;
}
}
#ifndef __PAGE_POWER_H_
#define __PAGE_POWER_H_
#include "pageWnd.h"
/*=====================================================
=
=====================================================*/
extern const TypePage pagePower;
#endif
#include "PagePower.h"
#include "disp.h"
/*=====================================================
=
=====================================================*/
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();
}
}
}