原创 51单片机系统模块化编程的一些想法

2009-8-12 18:46 2698 10 10 分类: MCU/ 嵌入式

51核类型单片机是目前应用较为广泛的一款MCU,编写单片机程序常常成为嵌入式软件开发软件入门级的训练。一般而言,51程序代码量少,考虑模块化程序相对较少。一种常规做法就是主程序采用while循环,再者通过中断中设置一些标志位;笔者在51单片机程序开发过程,发现公司的单片机程序更新很快,基本每个人都要修改一点,一段时间后原有代码想法都很难找到。还有一种是移植操作系统后,然后进行代码规范化,比如移植UCOS-ii等嵌入式操作系统,但是往往代码量增加很快,对存储容量本来就少的51单片机有较大的压力。电子园51单片机学习网r)U\/Wt6|:l0@


51模块化程序设计的最重要问题,笔者认为就是找到一种合理的程序结构,而且它能胜任实际的51单片机程序开发。考虑到文中前面提到的问题,笔者主要针对第一种主程序while循环结构进行修改。首先增加任务结构体定义,其中函数指针pFun指向实际的任务函数,nDelay表示延时时间,以ms为单位,以下涉及时间都一样的。而nRunme表示运行的次数,nPeriod表示运行的时间周期。电子园51单片机学习网.?!u ~-P~6XV


 

vB \Us6W]b5d8B0

struct _TASK_DEFINE

/CS/mv+Ip0

{ 

N(S;od1XUc0

  void (code *pTask)(void);    //指向实际任务函数

+y.Z0E&mnw[0

  UINT16  nDelay;        // 延时时间电子园51单片机学习网l"KF,Q#I2o2Z3L e%w;S


  UBYTE8 nRunme;       // 运行次数

Z8u%|A6V4S0

  UINT16  nPeriod;       // 运行周期

4hYqL1y;MP&V h0

} S_TASK , *pS_TASK;电子园51单片机学习网[#E&g!J&c


 

b i `)qG/^F0

    系统中设定全局的任务列表变量S_TASK SCH_TASK_G[TASK_TOTAL_NUM];其中TASK_TOTAL_NUM为系统设定的任务最大数量。在进入while主循环前,需要添加相应的任务,采用函数SCH_ADD_TASK(…),后面再详细阐述。系统的主循环采用遍历的方法,实现实际任务的运行。

O y4A-{7L%K*C#Y+R0

 

/f9C)Z2m1Ta0

 while(1)

L }v;bI0g0

{电子园51单片机学习网/} [nk"r4w)a];B"F:V


    SCH_DISPATCH_TASK(); /*遍历实现任务切换*/电子园51单片机学习网J3\(F1XL:WO


    /*51系统进入空闲模式,定时中断能唤醒*/

aLY;V d4REn }0

    SCH_Goto_Sleep();  

@w$E$N?k6b5i9@:GRf0

}

TTZ3rN {,o%[0

jN9k#hb!Y.l:A^`_7K0

SCH_DISPATCH_TASK遍历函数的主要实现代码如下,

"m%v.W7|6T] dF0

电子园51单片机学习网m NPo7z.E'dq


 UBYTE nIndex;

x+HL.Qj|/o i0

  for(nIndex=0; nIndex < TASK_TOTAL_NUM; nIndex++)

#kbvzJ1t0

{

{.FN#Dgu3Sn$g \0

  if( (SCH_TASK_G+nIndex)-> nRunme > 0)

f!dlf^J5V5d {0

{电子园51单片机学习网!}V,TEM MW$@/V,V


   (*(SCH_TASK_G+nIndex)->pTask)(); //运行实际的任务

0D B8a r0o1Q8C"kD0

   (SCH_TASK_G+nIndex)-> nRunme--; //运行次数减1

3Q3E f!^%oc0

 

/d"SPbE0

 if((SCH_TASK_G+nIndex)-> nPeriod == 0) /*执行一次型任务后删除之*/电子园51单片机学习网!`O8G&q+y


{  SCH_DEL_TASK(nIndex); }

im\O:["M0Dx0

}

*YLnh@s M1}!\u0

 

2I a/n W1_GQ,y'V-b'T8d0

定时器实现1ms定时中断,在中断中进行任务刷新(SCH_UPDATE_TASK函数),这也是实现系统结构关键一步。定时器可以采用定时Timer0,有的52型单片机也可以采用定时器Timer2,总之实现1ms时间的定时中断。电子园51单片机学习网X@pg?


 SCH_UPDATE_TASK()的主要实现代码如下

+t;M`W&J:S6J0

 

;nK DX"^,ve0

 UBYTE8 nIndex;

~Qd&l&[C s7Im0

 for(nIndex=0; nIndex < TASK_TOTAL_NUM; nIndex++)电子园51单片机学习网)e|:|kAi E#H/j


{电子园51单片机学习网,M"yr&EBP4?D


if( (SCH_TASK_G+nIndex)-> nDelay == 0)

"f qv9JuOA"J"O0

{电子园51单片机学习网@"B V FJC,}!iL


       (SCH_TASK_G+nIndex)-> nRunme++; //运行次数加1电子园51单片机学习网D1e;k [!Fm o


/*获得实际的时间周期*/

6k0AK9K;li ?0

if((SCH_TASK_G+nIndex)-> nPeriod > 0)

!O*L{[]Q0

{

H8nRBOV0

          (SCH_TASK_G+nIndex)-> nDelay = (SCH_TASK_G+nIndex)-> nPeriod;

kVW[/Y~B0

}电子园51单片机学习网$vna^q


}电子园51单片机学习网|6tN`c2WF


else电子园51单片机学习网bl4s1[G#meu3G.f


{ (SCH_TASK_G+nIndex)-> nDelay--; }

uQ9_ zq3@Vx;s(y0

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

Yws#Y,Ms yV;GQp0

 }

Z'_PQ*y u?0

[m ]4W6ht;N"l*X0

 在进行主程序while循环前,必须要添加相应的任务函数SCH_ADD_TASK其主要的实现代码如下:

O$| sT6I0

电子园51单片机学习网@7g7B?dMU A


UBYTE8 SCH_ADD_TASK( void (code *pFun)(void),

U@ {(jIX G%G0

const UINT16 tDelay,电子园51单片机学习网HW*{b y"L%Ni;j


const UINT16 tPeriod)电子园51单片机学习网G1?z!HH\


{

Vde(Vev A)k0

UBYTE8 nIndex;

~4tVz]1_AF^?0

 

t5l GyS])|0

nIndex=0;电子园51单片机学习网`xa$~ LJtm


while( (SCH_TASK_G+nIndex)-> pTask != NULL ) && (nIndex < TASK_TOTAL_NUM) )

X$k Kz-gJ0

{ nIndex ++ ; }电子园51单片机学习网Gj6@6q[ j9[3r.j3qu


if( nIndex == TASK_TOTAL_NUM)电子园51单片机学习网h+F6j|0@].H9N2u


{ return TASK_OVER_FLOW; }电子园51单片机学习网3H3oq0a`7ouA_


 /* 增加任务到列表中*/

$g-^}JB%k0

 SCH_TASK_G[nIndex] ->pTask = pFun;

D.B ~)P!p&r8hw0

 SCH_TASK_G[nIndex]->nDelay = tDelay;电子园51单片机学习网.b,s[+AI-G*vC


 SCH_TASK_G[nIndex]->nRunme = 0;电子园51单片机学习网|sH"g0ry


SCH_TASK_G[nIndex]->nPeriod  = tPeriod;电子园51单片机学习网$I$n*L$^r6uh


return nIndex;电子园51单片机学习网6M8vOB6n-Z-Jy


}

)f/ZK*v&C B c0

电子园51单片机学习网5Gp^D \;G#UF? f-p


      主体代码基本实现,51系统开发主要的工作就是增加一个任务函数,在实际的任务实现相应的功能,这样构成的单片机系统就比较好控制,维护代码也很简单。

*a)NO`_1f;~`0

当然还有就是任务函数的执行时间必须控制1ms以内,即是每1ms时间标度中要执行的任务时间不超过1ms。如果执行时间较长的任务,总有一些办法对其划分为较小的若干个小任务。

DVvl8^a)sR%O C0

笔者在实际开发中也设想过一个问题,假定A任务每2ms执行一次,执行需要的时间为0.5ms;而B任务每4ms执行一次,执行所需的时间为0.5ms。如果两个任务运行在同一个时标(1ms)中,就可能导致运行单个时标运行任务超过1ms的限制;由于4ms的间隔也是2ms延时的整数倍关系,执行完全有可能。一种常见的解决方法是加大定时中断时间的时标,把1ms修改成2ms,但是同时系统的时间敏感度减少了。笔者想到一种方法,设置 两个任务结构体中延时nDelay不同,A任务延时初值0,而B任务延时初值为1;这样实际A任务执行时间标度为2*n,B4*m+1(n, m为正整数),而2*n != 4*m+1(奇偶数),从而使AB任务永远不可能同时在一个时标(1ms)中执行。电子园51单片机学习网EO~0^ Iv


以上是在51单片机开发模块化设计的一些想法,在几个实际项目开发也得到较好的应用,当然可能还会有一些没有考虑的问题,欢迎各位提出更好的建议!

'q z?1So ~-MhPQ0

 

电子园51单片机学习网0Y%zyu.NW,J~

参考文章及网站:

*H Z#U(tgL p6r1J0

1.      Keilc开发文档C51A51电子园51单片机学习网z(P'g7YvQ6H


2.      基于时间触发系统的嵌入式系统模式设计Chaper9, Chapter 13, Michael J. Pont

~n^ ~#Ut _ ?0

   3. www.21ic.com的单片机论坛电子园51单片机学习网"Z j~uV1ny|*Nl3O0L

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
10
关闭 站长推荐上一条 /3 下一条