|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
在研制单片机应用系统时,汇编语言是一种常用的软件工具。它能直接操作硬件,指令的执行速度快。但其指令系统的固有格式受硬件结构的限制很大,且难于编写与调试,可移植性也差。随着单片机硬件性能的提高,其工作速度越来越快,因此在编写单片机应用系统程序时,更着重于程序本身的编写效率。而Franklin C51交叉编译器是专为80C51系列单片机设计的一种高效的C语言编译器,使用它可以缩短开发周期,降低开发成本,而且开发出的系统易于维护,可靠性高,可移植性好,即使在代码的使用效率上,也完全可以和汇编语言相比,因此目前它已成为开发80C51系列单片机的流行工具。% ^. p0 x5 v. N: ? g
& J7 {! w- a9 Z f& m1 C51语言程序设计的基本技巧
3 A- X4 m" i1 m K) ~' Z7 P* s+ @6 [. B
C语言是一种高级程序设计语言,它提供了十分完备的规范化流程控制结构。因此采用C51语言设计单片机应用系统程序时,首先要尽可能地采用结构化的程序设计方法,这样可使整个应用系统程序结构清晰,易于调试和维护。对于一个较大的程序,可将整个程序按功能分成若干个模块,不同的模块完成不同的功能。对于不同的功能模块,分别指定相应的入口参数和出口参数,而经常使用的一些程序最好编成函数,这样既不会引起整个程序管理的混乱,还可增强可读性,移植性也好。& }3 a2 X4 T/ B* p' A* r% n& j
8 B! x9 g, J& {9 d 在程序设计过程中,要充分利用C51语言的预处理命令。对于一些常用的常数,如TRUE,FALSE,PI以及各种特殊功能寄存器,或程序中一些重要的依据外界条件可变的常量,可采用宏定义"#define"或集中起来放在一个头文件中进行定义,再采用文件包含命令"#include"将其加入到程序中去。这样当需要修改某个参量时,只须修改相应的包含文件或宏定义,而不必对使用它们的每个程序文件都作修改,从而有利于文件的维护和更新。现举例说明如下:
- d$ w4 I7 S2 D7 c( F9 h
$ Y Q( `: \ `) r! }1 l 例1 对于不同的单片机晶振,程序取不同的延时时间,而且可根据外界条件的变化修改延时时间的长短。对于这样的程序,可利用宏定义和条件编译来实现。程序如下:
/ ?( U% _ M" ~# o& i
; Q7 J+ y' u X, M/ N- W; j#define flag 1, n$ T' o' w/ R# e" d' _; _
#ifdef flag==1
) P8 b, s2 w/ A# X #define fosc 6M9 u3 z5 }( g' v
delay=10;$ ~( N9 \' N# z G% A
#elif flag = = 0
4 z* _- I0 n4 f5 ~#define fosc 8M
! B% `* X; b2 T7 r2 R$ U delay=12;/ i. x& P5 [ D3 ^# s* m3 m' v
#else
/ ]0 }) s; L! O6 D4 v# ~#define fosc 12M ?$ I: g/ r2 R- \) ?
delay=20;% } D0 ^ ~4 b V
#endif% j% D) F. ~9 Y+ D1 j
main()
" T- r" j# t- r! K! S# F) N{
G8 [0 i6 d' z& j2 ifor(I=0;I<delay;I++);% \# Y7 F1 f# q- i
}/ t4 i# T( m$ u5 g) v; a& h' ~4 T& j5 I
这样源程序不作任何修改就可适用于不同时钟频率的单片机系统,并可根据情况的不同取不同的delay值,完成不同的目的。
2 R+ v; I# T& w# O
8 ^; K& E' f2 q" }0 ^* |2 C51语言与汇编语言程序的混合编程
& c6 j/ a1 I) W' Q
) D0 c1 r; e/ [5 Y( Q C51编译器能对C语言源程序进行高效率的编译,生成高效简洁的代码,在绝大多数场合采用C语言编程即可完成预期的目的。但有时为了编程直观或某些特殊地址的处理,还须采用一定的汇编语言编程。而在另一些场合,出于某种目的,汇编语言也可调用C语言。在这种混合编程中,关键是参数的传递和函数的返回值。它们必须有完整的约定,否则数据的交换就可能出错。下面就以力源公司的10位串行A/D转换器TLC1549 为例说明C语言程序与汇编语言程序的调用。 tjk_1.gif (1043 字节)6 G3 C3 J* f/ e5 H) {% m( ?
图1 TLC1549管脚图- ~# P( p+ ~; S6 ~- x; ~
5 j+ U( s* Z- z9 a. o; D 1549的管脚图和时序图分别如图1和图2所示,假定DATA OUT接P1.0,CS 接P1.1,CLOCK接P1.2。
9 B; |% D3 W6 O% E3 \1549的具体特性请查阅有关资料。
4 q3 A; @& u/ w* b& ~
0 z" e3 g7 b7 I1 s/ V" i% [ @ tjk_2.gif (3208 字节)
3 P% N6 n) y7 n4 J, u7 e
- a* c1 \4 L, r S2 C$ f& N5 Q# U' j- X图2 TLC1549时序图% [8 p" {' i4 x! g( c5 N
/ L# ^( W! z4 Z# {
例2 C语言程序与汇编语言程序的调用,其子程序如下:
. n0 v4 D. ^. U+ y
0 i5 F" t7 n6 ~# qPUBLIC AD ;入口地址
6 ~1 S( O: z; F" P2 ]" h% wSEG_AD SEGMENT CODE ;程序段
. Q c" L1 }- O6 H" Y- ]RSEG SEG_AD' ?2 L0 k6 x+ D
USING 01 C4 N9 d0 d3 T$ {
AD: MOV R6,#00
4 H3 } A/ P3 c, M# z8 hMOV R7,#00$ q) s) V6 V$ s/ K5 X
SETB P1.19 H/ z; N9 i; k" @; F+ a. e
ACALL DELAY
/ g5 m! S: w/ a6 HCLR P1.1# u9 ~4 K/ Q- E
ACALL DELAY
3 |% E6 Q3 f: H' j4 U* [MOV R0,#101 W4 a- J j8 {, g
RR0: SETB P1.2
3 ~4 v7 v/ M9 ^. b- t; Y3 s& cNOP, d+ P& K4 o9 G6 [
CLR P1.2
4 l! Z- V! ?4 e) F) wDJNZ R0,RR0: v7 f5 V4 u5 a0 Q
ACALL DELAY
: E5 X x2 ]7 A+ B1 qMOV 30H,R6 ;A/D转换的高
! Q. @8 p: n: B+ V' M+ b ;两位保存在R6中
1 Y2 y$ o1 s5 I- z& @$ b" Y: t$ cACALL CIR
( R" [6 z$ x; x+ L% ?( p& l1 t) ~MOV R6,30H" W1 L* O2 d$ \7 B( ~" o# m$ ~7 w
SETB P1.2
$ ~3 L3 ^, i; ^3 |; g5 WNOP. k: @$ L3 v8 L, a7 g; [7 L4 Y0 f
CLR P1.23 q& e: v8 W8 b0 D0 ]. W
MOV 30H,R6/ C$ M1 W- t4 p! U
ACALL CIR& S. G# |8 j4 I& D1 h( U# V( K; u; k
MOV R6,30H
4 ?# P% j/ D, D% yMOV R0,#8 ;A/D转换的低
9 E% F+ p# m5 s5 I) G ;8位保存在R7中
0 O: U8 b6 ~! K RR2: SETB P1.20 I7 r: J# @+ V2 E6 l
NOP3 f' k+ Q' ^( r, B8 {
CLR P1.2
* m0 N1 _" e+ Z3 lMOV 30H,R7: N5 O/ p+ U" M; o3 y7 e3 s* i+ c
ACALL CIR
2 \3 K9 z% e2 o! l: U: Z, XMOV R7,30H
! U3 W3 D' f1 q3 ^DJNZ R0,RR2
. j# m3 `+ J* B% w9 rRET
) l4 u% {9 T) _" ~ CIR: CLR C
7 ? U) @; }. A$ oMOV C,P1.0
. O% ^+ H+ B. |# `' tMOV A,30H
- ~+ e! U B* ?) n# j8 fRLC A
/ D; a& x& v/ n' [! d+ V# jMOV 30H,A% h3 |$ ]. S5 ^. H* @" K
RET" y d5 k6 s" k J/ {" W. K5 \
END; K8 M- u5 R# U5 n
在以上程序中,函数的返回值为一无符号整型数,根据调用规则,返回值的高位必须在R6中,低位在R7中,这样才可保证数据的传递不出错。另外,在调用过程中,必须注意寄存器的入栈。这样在以后用到A/D转换时,在C语言中调用汇编语言子程序AD()即可。
& o( D" S; x/ ]$ B/ K. L( X+ c
1 `/ t; q/ x! u0 t8 |3 C51中断处理过程
' d% k/ O' @7 w+ L2 X- y( Y- F& z6 i. r- E
C51编译器支持在C源程序中直接开发中断过程,因此减轻了使用汇编语言的繁琐工作,提高了开发效率。中断服务函数的完整语法如下:
9 a5 j0 ]! @ Z; G! k7 k
) o' W9 I6 G3 z void 函数名(void)[模式]* k! H& P8 E5 d" a$ C( O
[再入]interrupt n [using r]
6 o1 p6 c6 Y1 Q2 P+ U6 {2 B4 h, m$ e$ n/ d! W
其中n(0~31)代表中断号。C51编译器允许32个中断,具体使用哪个中断由80C51系列的芯片决定。r(0~3)代表第r组寄存器。在调用中断函数时,要求中断过程调用的函数所使用的寄存器组必须与其相同。"再入"用于说明中断处理函数有无"再入"能力。C51编译器及其对C语言的扩充允许编程者对中断所有方面的控制和寄存器组的使用。这种支持能使编程者创建高效的中断服务程序,用户只须在C语言下关心中断和必要的寄存器组切换操作。4 W% h+ \) j- \% s. Q) W. {
( U5 R! u% N5 y: h) K
例3 设单片机的fosc=12MHz,要求用T0的方式1编程,在P1.0脚输出周期为2ms的方波。
# f6 y# n- [) [# n% l) E$ s0 B2 ^& y. [; K& L' J' d
用C语言编写的中断服务程序如下:
* q4 g* |% X& I# c/ J6 \1 ]1 M9 l1 ^ n: D7 n- `! `8 \9 h
#include <reg51.h>( s2 d% _. L/ O+ r8 y: M5 x5 ], U8 U* R
sbit P1_0=P1^0;
/ @9 z. ?% F$ evoid timer0(void)interrupt 1 using 1 {) _$ d: W: b1 A+ ]
/*T0中断服务程序入口*/
8 ^) z# Q5 B& g" |- ~P1_0=!P1_0;- q; ^( Z9 K9 B/ K! c/ ]' Z7 w
TH0=-(1000/256); /*计数初值重装*/
+ t/ \2 V, x" k, A' D/ yTL0=-(1000%256);
4 `3 C3 v2 L, g( t' @}" Z) Y5 v% _ J, T7 J7 E
void main(void)0 }3 O6 w7 W8 D
{ X6 V9 w9 h: Y$ }! A/ @& W
TMOD=0x01; /*T0工作在定时器方式1*/# V2 y6 a. J' Q8 \( |
P1_0=0;
/ }4 k) h5 [! [, w/ cTH0=-(1000/256); /*预置计数初值*/
; |' x/ l) Y' A: z# {3 v( OTL0=-(1000%256);
) P9 t1 w: G: W! o$ LEA=1; /*CPU开中断*/
: G. F6 G% O" R9 I# X0 G9 ]ET0=1; /*T0开中断*/
1 f7 z( @1 w: ~! a; h) A, h" vTR0=1; /*启动T0*/, v0 H" J6 w% M, |: O0 s2 }
do{}while(1);; N$ V' h# a3 K6 I8 Z# o
}
. N( Q$ R" \, U5 _% g/ f 在编写中断服务程序时必须注意不能进行参数传递,不能有返回值。1 {. [& q3 h) f$ ]9 M0 {& V8 h
& J5 M9 H1 E" X8 q6 J4 D7 @4 J4 结论# `6 Q# x. w, C& |
5 F2 V5 Y# E4 Z
C51编译器不但可以缩短单片机控制系统的开发周期,而且易于调试和维护。此外,C51语言还有许多强大的功能,如提供丰富的库函数供用户直接调用,完整的编译控制指令为程序调试提供必要的符号信息等等。总之,C51语言是广大单片机开发人员的强有力的工具。 |
|