Chinaunix首页 | 论坛 | 博客
  • 博客访问: 514963
  • 博文数量: 114
  • 博客积分: 5022
  • 博客等级: 大校
  • 技术积分: 1355
  • 用 户 组: 普通用户
  • 注册时间: 2006-08-09 18:01
文章分类

全部博文(114)

文章存档

2012年(1)

2011年(3)

2010年(1)

2009年(16)

2008年(23)

2007年(39)

2006年(31)

我的朋友

分类:

2007-12-14 13:42:49

一个程序“嵌入式裸奔”
#include "libRain_M128.h"
#include "MyLib.h"

#include "Driver\UmIo.h"
#include "Protocol\Protocol.h"

#include "Task\Task.h"
#include "Task\ImportKey.h"
#include "Task\PWM_Wkv.h"
#include "Triggle\Triggle.h"

#include "Task\XPower.h"
#include "Task\WaterLoop.h"


#include "WorkLed\WorkLed.h"


//--------------------------------------------------------
//5ms中断回调函数
//--------------------------------------------------------
void CallBack_5msInterrupt( void )
{
}

//--------------------------------------------------------
//20ms中断回调函数
//--------------------------------------------------------
void CallBack_20msInterrupt( void )
{

}


//--------------------------------------------------------
//析构
//--------------------------------------------------------
void Main_Destory( void )
{
    WatchDog_Destory();

    //--------------------------user---------------------
    Triggle_Destory();
    PWM_Wkv_Destory();
    ImportKey_Destory();
    Task_Destory();

    Protocol_Destory();
    UmIo_Destory();


    //--------------------------System---------------------
    WorkLed_Destory();

    Package_Destory();

    VirtualUart80_Destory();
    Uart80_Destory();
    Uart81_Destory();

    EDataBase_Destory();
    CPU_Eeprom_Destory();

    MyLib_Destory();

}

//--------------------------------------------------------
//初始化
//--------------------------------------------------------
void Main_Init( void )
{
    //--------------------------System---------------------
    MyLib_Init();

    CPU_Eeprom_Init();
    EDataBase_Init( 4, 1, 500, CPU_Eeprom_Cmd );

    Uart80_Setup( OSC_7p3728MHz_4800, (eUart80_NoneChk | eUart80_Stop1Bit), 250, 250 );
    Uart81_Setup( OSC_7p3728MHz_4800, (eUart80_NoneChk | eUart80_Stop1Bit), 250, 250 );
    VirtualUart80_Setup( 200, 200 );                            //配置信息在VirtualUart80_IO.c中

    Package_Init( 3 );                                        //三个协议转换任务

    //--------------------------user---------------------
    UmIo_Init();
    Protocol_Init();

    Task_Init();
    ImportKey_Init();
    PWM_Wkv_Init();
    Triggle_Init();

    XPower_Init();
    WaterLoop_Init();

    WorkLed_Init();
}


//--------------------------------------------------------
//主程序
//--------------------------------------------------------
int main( void )
{
     Main_Init();

    Msg_RunInit();                                            //执行完全部初始化消息
    WatchDog_Init();                                        //看门狗初始化
    sei();

    Package_Send( psUart_Import, eProto_RequAllState );

    //开始主循环
    while(1){
        //--------------------------System---------------------
        MyLib_MainLoop();

        CPU_Eeprom_MainLoop();
        EDataBase_MainLoop();

        VirtualUart80_MainLoop();
        Uart80_MainLoop();
        Uart81_MainLoop();

        Package_MainLoop();

        //--------------------------user---------------------
        UmIo_MainLoop();
        Protocol_MainLoop();

        PWM_Wkv_MainLoop();
        Task_MainLoop();
        ImportKey_MainLoop();
        Triggle_MainLoop();

        XPower_MainLoop();
        WaterLoop_MainLoop();

        WatchDog_MainLoop();

        WorkLed_MainLoop();
    }
}

只要任意再添加一百个任务,即使TCP/IP也可以(当然要改造下),只要MCU能处理过来,同样也可以user下面任何一个任务去掉,而其它任务工作正常。这就是规则和约束的好处。
 
//-----------------------------------------------------------
//计数任务处理
//-----------------------------------------------------------
#ifndef __TriggleH
#define __TriggleH

#include "..\libRain_M128.h"

#include "..\..\WorkTable.h"
#include "..\Driver\UmIo.h"
#include "..\Protocol\Protocol.h"
#include "..\Counter\Counter.h"

#ifndef _TriggleH
    //--------------------------------------------------
    //初始化
    //--------------------------------------------------
    extern void Triggle_Init(void);

    //--------------------------------------------------
    //析构
    //--------------------------------------------------
    #define Triggle_Destory()    do{ Counter_Destory();}while(0)

    //-------------------------------------------------------------
    //循环
    //20ms
    //-------------------------------------------------------------
    extern void Triggle_Loop( void );

    #define Triggle_MainLoop()    do{ if( sSysTimer.bSysTouch){ Triggle_Loop(); }; Counter_MainLoop();  }while(0)
#endif
#endif


//-----------------------------------------------------------
//触发任务处理
//管理触发模式
//管理触发计数
//执行触发功能(自动和手动)
//使用虚拟DA通道    0:触发计数 1:触发频率
//使用虚拟AD通道    3:触发计数 4:触发频率
//结果保存在UmIo的AD、DA缓冲区中
//-----------------------------------------------------------
#include "Triggle.h"

#define TRIGVALIDTIME                2
#define OUT_TRIGGLE                    20

struct InTriggle
{
    U8 mNovalidTime;                //触发失效效的时间间隔设置。=0无。单位:20MS
    
    U8 mTrigModeTemp;                //0=停止,1=手动,2=自动,3=ECG,临时
    
    U8 mTask;
    U8 mTimer;                        //工作用的计时器
};
struct InTriggle sInTriggle;
#define this sInTriggle

enum TrigMode
{
    eStop,
    eManual,
    eAuto,
    eEcg,
    
    eNoValid,
};


//-------------------------------------------------------------
//消息处理
//-------------------------------------------------------------
void InTriggle_MsgProc( void )
{
    switch( Msg_Pop() )
    {
        case Msg_Trig_SetupFreq:            //触发频率设定
            //计算触发脉冲失效时间
            this.mNovalidTime = ((60/20)*1000) / sUmIo.aDaBuf[ eDa_TrigFreq ] - TRIGVALIDTIME;    //1分钟->20ms倍数
            break;
            
        case Msg_Trig_ModeECG:                //心电同步
            this.mTrigModeTemp = eEcg;
            break;
            
        case Msg_Trig_ModeContinuous:        //连续触发
            this.mTrigModeTemp = eAuto;
            break;
            
        case Msg_Trig_ModeManual:            //手动停止
            if( this.mTrigModeTemp == eStop )
            {
                //单次触发
                this.mTrigModeTemp = eManual;
            }
            else {
                //停止
                this.mTrigModeTemp = eStop;
            }
            break;
    }
}

//-------------------------------------------------------------
//触发计数及控制
//-------------------------------------------------------------
void InTrig_Valid( void )
{
    //触发的计数控制
    if( Counter_IsEnable() )
    {
        if( sUmIo.aDaBuf[ eAd_TrigCounter ] < sUmIo.aDaBuf[ eDa_TrigCounter ] )
        {
            //计数-1
            Counter_Dec();
            sUmIo.aDaBuf[ eAd_TrigCounter ]++;
            
            if( UmIo_Out( OUT_TRIGGLE, 0, false ) )
            {
                //发生变化,向所有串口发送
                Package_SendU16( psUart_Pc,     eProto_IoOutChange, OUT_TRIGGLE );
                Package_SendU16( psUart_Hand,     eProto_IoOutChange, OUT_TRIGGLE );
            }
                
            //向PC、HAND发送AD信息
            Package_SendU16( psUart_Pc,     eProto_ADChange,     sUmIo.aAdBuf[ eAd_TrigCounter ] );
            Package_SendU16( psUart_Hand,     eProto_ADChange,     sUmIo.aAdBuf[ eAd_TrigCounter ] );
        }
    }
}

//-------------------------------------------------------------
//触发失效
//-------------------------------------------------------------
void InTrig_NoValid( void )
{
    if( UmIo_Out( OUT_TRIGGLE, 0, false ) )
    {
        //发生变化,向所有串口发送
        Package_SendU16( psUart_Pc,     eProto_IoOutChange, OUT_TRIGGLE | (1<<8) );
        Package_SendU16( psUart_Hand,     eProto_IoOutChange, OUT_TRIGGLE | (1<<8) );
    }
}

//--------------------------------------------------
//初始化
//--------------------------------------------------
void Triggle_Init(void)
{
    Memory_Memset( (U8 *)&this, 0, sizeof( struct InTriggle ) );

    //消息注册
    Msg_Register( InTriggle_MsgProc, Msg_Trig_SetupFreq, Msg_Trig_ModeManual );
    
    Counter_Init();
}

//-------------------------------------------------------------
//循环
//20ms
//-------------------------------------------------------------
void Triggle_Loop( void )
{
    if( this.mTimer )
    {
        if( --this.mTimer == 0 )
        {
            switch( this.mTask )
            {
                case eStop:
                    //进入失效
                    InTrig_NoValid();                        //触发失效
                    break;

                case eManual:
                    InTrig_NoValid();                        //触发失效
                    this.mTask = eNoValid;
                    this.mTimer = this.mNovalidTime;
                    break;
                    
                case eAuto:
                    InTrig_NoValid();                        //触发失效
                    this.mTask = eNoValid;
                    this.mTimer = this.mNovalidTime;
                    break;
                    
                case eEcg:
                    InTrig_NoValid();                        //触发失效
                    this.mTask = eNoValid;
                    this.mTimer = this.mNovalidTime;
                    break;
                    
                case eNoValid:
                    this.mTask = eStop;
                    break;
            }
        }
    }
    else {
        //判断是否加载
        if(  sUmIo.aMessage[eMessage_TriggleMode] != this.mTrigModeTemp )
        {
            //设置发生改变
            sUmIo.aMessage[eMessage_TriggleMode] = this.mTrigModeTemp;
             
            //发生变化,向所有串口发送
            Package_SendU8( psUart_Pc,         eProto_ControlStat, sUmIo.aMessage[eMessage_TriggleMode] );
            Package_SendU8( psUart_Hand,     eProto_ControlStat, sUmIo.aMessage[eMessage_TriggleMode] );
            
            switch( sUmIo.aMessage[eMessage_TriggleMode] )
            {
                case eStop:
                    break;

                case eManual:
                    InTrig_Valid();                        //触发有效
                    this.mTask = eManual;
                    this.mTimer = TRIGVALIDTIME;
                    break;
                    
                case eAuto:
                    InTrig_Valid();                        //触发有效
                    this.mTask = eAuto;
                    this.mTimer = TRIGVALIDTIME;
                    break;
                    
                case eEcg:
                    break;
            }
        }
        else {
            //检测自动、ECG
            switch( sUmIo.aMessage[eMessage_TriggleMode] )
            {
                case eStop:
                    break;

                case eManual:
                    break;
                    
                case eAuto:
                    InTrig_Valid();                        //触发有效
                    this.mTask = eAuto;
                    this.mTimer = TRIGVALIDTIME;
                    break;
                    
                case eEcg:
                    //检测ECG输入触发
                    break;
            }
        }
    }
}

基本没停顿,只在状态改变时发生了事件才去处理,所以效率极其高。换51都可以运行过来。

Msg_Pop()是别的任务传递的消息。/自建库中的消息处理函数中的消息弹出函数


if(  sUmIo.aMessage[eMessage_TriggleMode] != this.mTrigModeTemp )
        {
            //设置发生改变
            sUmIo.aMessage[eMessage_TriggleMode] = this.mTrigModeTemp;

这段可以看到怎么样去检测外部状态改变:只有外部监测状态发生改变,才执行下面代码。而sUmIo.aMessage[eMessage_TriggleMode] 又是IO驱动程序产生的结果。

很多时候不要直接处理,需要各种转换,这样结构清晰,处理效率高,可靠。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
呵呵,对于单片机程序,我也一般都是写成mainloop

全部做成非独占式状态机,通过信号来耦合,通过状态标志来控制流程
写程序时分配好优先级并画好状态迁移图就一切OK了

基本架构都是:
void main(void)
{
    SysInit();

#if (DEBUG)                     //调试//
    Debug();                    //调试程序
#endif
    
    while(1)
    {
        if (inbuf_sign)
            do_serial();        //串口数据处理程序
        if (outbuf_sign)
            sendcmd();          //发送一个命令包
        if (key_sign)
            do_key();           //按键处理程序
        if (ir_sign)
            do_ir();            //红外处理程序
        if (error_sign)
            do_error();         //按键处理程序
        if (out_time_sign)
            timeout();          //超时处理程序,同时承担软狗的作用
        if(DOG1&&DOG2&&DOGn)
            free_dog();         //有条件喂狗程序,free_dog()里还有一层判断
//        delayms(5);           //延时n mS
    }
}

阅读(1490) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2008-04-07 20:59:12

cool

gofiend2008-03-20 21:07:01

加油!