一个程序“嵌入式裸奔”
#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) |