C語言編程在智能化重力加速度測試儀中的應用
摘要在基于單片機的智能化重力加速度測試儀中采用C語言輔程苘化了程序設計任
務,對于匯輔語言難干處理的浮點數(shù)運算及扳字打印輸出可通過C語言箱譯罌的內部庫函數(shù)調
用實現(xiàn)。舟紹了一種專為8051系列單片機設計的C語言輔譯器Franklin C51,它具有代碼優(yōu)化
功能,能產(chǎn)生極高效率的機器碼,并且提供了豐富的內部函數(shù)庫。描述了C51函數(shù)庫所支持的
IEEE標準浮點數(shù)的內存格式 及采用sprintf0函數(shù)處理包括漢字在內的各種字符串的方法。給
出了測試儀的輸出結果。電導計| 水分測定儀| 濁度計| 色度計| 粘度計| 折射計| 滴定儀| 密度計| 熱流計| 濃度計| 折射儀| 采樣儀|
單片機在工業(yè)測量控制領域內獲得了十分廣泛的應用-】J。一般在研制單片機應用系統(tǒng)
時太多采用 編語言作為軟件工具。但是,當程序中需要采用浮點數(shù)運算時,用忙編語言編
寫程序十分麻煩;如果程序中需要進行漢字處理,則用匯編語言編程的效率極低。為了提
高程序的編寫效率,只有采用高級語言編程。c語言是目前公認的一種高效率計算機開發(fā)用
高級程序設計語言口],它既能象匯編語言那樣直接操作機器硬件,又能很方便地進行各種
數(shù)學運算和字符處理。筆者結合實例介紹采用美國Franklin軟件公司推出的c語言編譯器
一C51開發(fā)8051單片機應用系統(tǒng)中浮點數(shù)運算和漢字打印程序的原理和方法。
1 C51編譯器的特殊擴充
C51編譯器采用符合ANSI標準的c語言進行編程,為了滿足8051系列單片機哈福
結構存儲器的需要[3],C51編譯器擴展了說明存儲器類型的關鍵字data:(可直接尋址的內
部RAM 區(qū)O~7FH);bdata:(可位尋址的內部RAM 區(qū)20H 2FH);iclata;(可閫接尋址
的內部RAM 區(qū)0~0FFH);pdata:(分頁尋址的外部RAM 區(qū)256頁×256字節(jié));xdata:
(外部RAM 區(qū)O~0FFFFH);code:(ROM 區(qū)0~0FFFFH)。FranklinC51編譯器對于變量
的定義符合ANSI C標準,即可以定義多維數(shù)組,可以通過指針進行變量訪問,可以將若
干個變量組成為結構和聯(lián)合等。還擴展了可用來簡化對8051單片機內部特殊功能寄存器
及可尋址位訪問的%bit”和“sfr 數(shù)據(jù)類型 在每個變量的聲明中可采用上述關鍵字明確
指定變量的存儲器類型。如果在定義變量時不指定其存儲器類型,則按編譯時給出的存儲
模式來決定變量的存儲區(qū)域。表1列出了Franklin C51編譯器所支持的存儲器模式。這3種存儲器模式各有優(yōu)缺
點,SMALL模式下參數(shù)
的傳遞是在內部RAM 中
完成的,COMPACT 和
LARGE允許參數(shù)傳遞在
外部RAM 中進行。由于
衰1 Franklin C51編譯囂的存儲囂橫式
存儲模式 說 明
SMALl 參數(shù)和局部變量存^可直接尋址的內部RAM(默認值為data)
COMPACT 參數(shù)和局部變量存人分頁外部RAM(默認值為0aat~)
LARGE 參數(shù)和局部變量直接存^外部RAM(默認值為xdata)
8051單片機訪問內部RAM 的速度比訪問模式下外部RAM要快得多,因此可將需要經(jīng)常
使用的變量放在內部RAM 中,而將那些較大及很少使用的變量放在外部RAM 中。另外
若將變量放在外部RAM 中時,還會使程序編譯后產(chǎn)生的有效代碼加長。C51編譯器對于局
部變量采用了靜態(tài)覆蓋技術來提高內部RAM 的使用效率,因此在實際編程時只要有可
能,應盡量采用局部變量。
2 C51編譯器支持的浮點數(shù)格式
C51編譯器支持的浮點數(shù)采用關鍵字float來進行聲明,它是滿足IEEE一754標準的32
位單精度浮點數(shù),占用四個存儲器單元,在內存中按從低到高的地址順序存儲.格式如下
地址 +0 +1 +2 +3
內容MMMMMMMM MMMMMMMM E MMMMMMM S EEEEEEE
其中,最高位S為符號位,0表示正數(shù),1表示負數(shù)。從次高位開始的8位EEEEEEEE占用
了兩個字節(jié),用來表示浮點數(shù)的階碼,為了避免出現(xiàn)負階碼值,并不用實際指數(shù)作為階碼,
而是將實際指數(shù)加上偏移量127之后再作為階碼。指數(shù)可正可負,其范圍是一127~+128,
加上127之后便使階碼在o~255的范圍之內。階碼之后是浮點數(shù)尾數(shù)的小數(shù)部分,共23
位,占用3個字節(jié)。尾數(shù)的整數(shù)部分永遠是1,所以不予表示,但它是隱含存在的,因此尾
數(shù)實際上應視為24位。例如將+124.75用IEEE一754標準的單精度浮點數(shù)表示為(16進
制數(shù))42F98000H,在內存中的存儲格式為
地址 +0 +1 +2 +3
內容00000000 10000000 1 1111001 0 1000010
C51編譯器提供了大量實用的庫函數(shù),C語言源程序經(jīng)過C51編譯器編譯后在連接定
位時,根據(jù)源程序中是否使用了浮點運算以及所采用的編譯模式,連接程序L51會自動選
擇正確的浮點函數(shù)庫加入到目標代碼中去 ]。
3 浮點數(shù)運算結果及漢字打印輸出的實現(xiàn)
在C51的編譯器函數(shù)庫中有一個十分有用的輸出函數(shù)sprintf(),它可將數(shù)值或字符串
以ASIIC碼的形式輸出到內存中的某個地址單元,利用該函數(shù)可十分方便地實現(xiàn)浮點數(shù)運
算結果及漢字字符的顯示或打印輸出。sprintf()函數(shù)的一般格式為
sprintf(字符指針,格式說明,輸出參數(shù)表列)
其中,第一個參數(shù)必須是指針,它可以是數(shù)組,也可以是變量的地址,用于指定內存單元的
首地址。格式說明是一個用雙引號括起來的字符串:“ [flag][width][.precision]type”
其中,flag稱為標志符,用于控制輸出數(shù)據(jù)的符號、空格、小數(shù)點的位置等;width是
一個十進制的正整數(shù),用來指定
最小輸出字符的數(shù)目;precision
用來表示輸出數(shù)據(jù)的精度,由小
數(shù)點和一個非負的十進制整數(shù)組
成;type稱為輸出格式轉換字
符,對于浮點數(shù)type可取3種表
示形式,如表2所示。
裹2 type字符豆其意義
type
f
e. E
g.G
數(shù)據(jù)類型 輸出格式
float [一]dddd dddd形式的浮點數(shù)
float [一]d.ddddE [sign3 dd形式的浮點數(shù)
float e或f形式的浮點數(shù),取其中形式較好者
輸出參數(shù)表列是需要輸出的一些數(shù)據(jù)項,它們可以是變量的值,也可以是照原樣輸出
的字符。由于8051系列單片機存儲器結構的限制,輸出表列中參數(shù)的總字節(jié)數(shù)有一定的限
制,在SMALL和COMPACT模式下,最大可傳遞1 5個字節(jié)的參數(shù)(5個指針,或1個指
針和3個long型數(shù)據(jù)),在LARGE模式下,最多可傳遞4o個字節(jié)的參數(shù)。
在C語言源程序中采用浮點數(shù)運算時,運算結果是按IEEE一754標準格式存儲在內存
單元中的。這種存儲格式不便于顯示和打印輸出。利用sprint{O 函數(shù)可以很容易地將運算
結果轉換成宜于顯示和打印輸出的ASIIC碼。如果單片機應用系統(tǒng)中需要采用漢字輸出,
則可以在漢字操作系統(tǒng)(ga UCDOS)下編寫C語言源程序,將要輸出的漢字作為字符串數(shù)
組直接定義到ROM 區(qū),則該RoM 區(qū)中就存儲了一系列漢字的代碼。從該RoM 區(qū)中按順
序取出各個漢字代碼,輸出到任何一種具有漢字打印功能的打印機上,即可很方便地實現(xiàn)
漢字的打印輸出 。
4 實 例
所研制的智能化重力加速度測試儀的監(jiān)控程序采用C51編程,實現(xiàn)了復雜的浮點數(shù)運
算處理及漢字打印輸出功能 測試儀利用光電轉換器的輸出脈沖觸發(fā)8051單片機的外中斷
0,讀取兩次外部中斷之問定時器0的計數(shù)值,通過計算獲得加速度的值.為了提高計算精
度采用了浮點數(shù)運算。測試儀通過并行口與EPSON—LQ300K打印機相連,可將測量結果
以漢字方式打印輸出。打印機的并行接口為Centronics標準.用8051單片機的P1口作為數(shù)
據(jù)線,P3.3和P3.5分別作為聯(lián)絡信號STROB和BUSY很容易實現(xiàn)與打印機的接口。智能
化重力加速度測試儀已經(jīng)研制成功并通過江漢石油學院設備處組織的鑒定。該儀器操作簡
單,一次測量可獲得多個測量數(shù)據(jù), 自動計算出最終結果和相對誤差值,并可通過打印機
接表3格式輸出測量結果。
裹3 重力加速度測試儀的輸出涮■結果
落球法測量結果 單擺法涮量結果
預置高度:H1—100 00 ram-H2—800 00 ram
下落時問:T1—65 076 m .T2=297.27 ms
重力加速度:g 9.9042 m/s0
相對誤差:Er一0.0186
單攖攖長:I,=l309 ram
攖動周期;TI,一2288.4 Ills
重力加速度:g一9.8752 m/s
相對誤差;Er 0.0096
下面給出了儀器監(jiān)控程序中關于浮點數(shù)處理和漢字打印輸出部分的源程序。其中prn
()是浮點數(shù)打印輸出函數(shù)。對于小于0的浮點數(shù)先將其轉換為正數(shù),再調用sprint{()庫
函數(shù)將其轉換成ASIIC碼,按浮點數(shù)的科學表示法存于數(shù)組array中。如果需要按科學表示
法打印輸出,可直接從數(shù)組array中逐個取出ASIIC碼數(shù)據(jù)進行打印。本例要求按工程表示
法打印輸出,因此先要根據(jù)浮點數(shù)的階碼確定小數(shù)點的位置。prnint O 是單個字符打印輸
出函數(shù)。它用來向打印機輸出各種打印控制命令以及漢字的打印輸出。在ROM 區(qū)中定義了
若干個漢字字符串數(shù)組,打印漢字時只要從各個數(shù)組中取出需要輸出的漢字字符串代碼作
為實際參數(shù)來調用prnint()函數(shù)即可。
C語言源程序如下:
#include< reg51.h>
#include< stdio.h>
#indude< math.h>
#include< stdlib.h>
float g,dscountl·El,E2,s1,s2; /*定義浮點型數(shù)據(jù)變量*/
sbit busy=P3 3 sbit stb=P3 5; /*定義打印機聯(lián)絡信號*/
uns~ned char bdata flag, /*定義其它類型數(shù)據(jù)變量*/
sbit flagl—Ihg OI
unsigned im clockO,count;
unsigned char dsp[8],array E]o3,
char code head1口一“歡迎使用重力加速度測量儀”} /*定義漢字字符串*/
char code head2[]一“落球法測量結果”;
char code head3口一“單擺測量結果”;
char code hl[]= “硬置高度H1一H2= ;
char codeI1[]= 單擺按長L一”;
char codetl[]= 下落時間TI T2= ”}
char codetI[]= “擺動周期TL= ;
char code gg[]; “重力加速度g一”}
char code er[]= “相對誤差Er= ;
exten~char xdata[MtaPortt StaPort; ,*定義8279數(shù)據(jù)、命令口*,
exter~unsigned char keyval(unsigned char va1)} /} 匯編語言鍵值處理子程序*/
extern unsigned char tedseg(unsigned char x); ‘ /*匯編語言顯示段碼處理子程序*/
xint()interrupt 0 using 1 《
/*外部中斷INT0處理函數(shù)*/)
timer0 O interrupt 1 using 1{
/*定時器TO處理函數(shù)*/)
prn (float x){ /*浮點數(shù)打印輸出函數(shù)*/
unsigned cha r i}
if(x<0)x=l x; /*將浮點數(shù)作為正數(shù)處理*/
sprintf(array, 4e”+x)} ^ 轉換為ASIIC碼存于數(shù)組array中*/
arTay E1o]一array[93=array[93~0x0f; /*取階碼}/
j(array[73一=0x2b){ /*正階碼處理*/
for(1—1}i<一8r陽y[93;I++)array[1]=array[i+1]} array[i]一Ox2e,
for(i一0‘i< 6}i+ + )《
P1一array即‘sfb=0‘stb=11 while(busy)})
next; for(1—6‘i<一3‘i一一)array[|]一arrav[j
array[9]一array[9]一1;
if(array[9]>o)goto next i
for(i一2{i—array[10];i++)array[j]一O}
for(i—O{i< 6l i+ + ) {
P1一array[i]‘stb=O}stb=1}while(busy)‘
prnint (unsigned char x){
P1一x}stb—O}stb= 1}while (busy); }
void kbinit()《
/*鍵盤顯示接口韌始化函數(shù)*/)
unsigned char readkey ()f
/*打印輸出*/
rettlrn{ }
1]} /* 負階碼處理*/
/* 打印輸出*/
/* 字符打印輸出函數(shù)*/
/*鍵值處理函數(shù)*/)
/* 其他處理函數(shù)*/
void kg(){ /* 重力加速度及相對誤差計算函數(shù)*/
一2.O* ( ( ( (goat)s2) /E2) 一( ( (float)s1)/E1)) / ( (E2一E1) /1000.O)}
dse~mtl—g; /*計算重力加速度*,
if(d~otmt1<9.781){d~eountl一(9.781-dscount1)/9.781}rettlrn;)
dsc~ntl一(dscountl-9.781)/9.781} /*計算相對誤差*/ )
void kel O { /*測量時間參數(shù)El*/
unsigned char data i;
TL0=0‘TH0=0;TMOD=Ox51;"ICON—o)=O; /* 定時器初始化*/
IE=Ox83~while(!flag1){ /*開中斷.等待*/
El一(clock0*65536.O+cotmt)/1000.O} /*計算E1的值*/ }
d ke2(){ /*測量時間參數(shù)E2*/
unsigned char data l}
TL0— 0;TH0— 0;TMOD一0x51;TCON=Ox0
E2一(crock0*65536.O+count) /1000.0; }
void k0rn O {
IE= 0x83;whi~e (1山g1)
unsigned ch丑r i:
prnint (Oxlb);prnint (0x74)}prnint (0x00);
i一0;while(head[i]j一0){prnint(head D]);i++
l一0;while(hl[j]j一0)tprnint(hi[‘])}i++;)
prn (s1);prn (Ox0a)‘
i一0f while(h2[i]l一0){prnint(h2[i])}i++‘)
prn (s2)4 prn (Ox0a)f
o‘while(tl[1]!一o){ornint(tl[i]);j++})
prn (E1)‘prn (0x0a);
0‘while(t2[1]!一o){ornint(t2[j]);i++;)
prn (E2)}orn (OxOa)4
— o;while(gg[i]!一0){prnint(gg[i]) i++f)
orn (g)}orn (OxOa);
/*打印輸出函數(shù)*/
/*打印機初始化命令*/
/* 打印漢字*/
/*打印浮點數(shù)并換行*/
/*打印漢字*/
/*打印浮點數(shù)并換行*/
/*打印漢字*/
/*打印浮點數(shù)并換行*/
/*打印漢字*/
/*打印浮點數(shù)并換行*/
/*打印漢字*/
/*打印浮點數(shù)并換行*/i—o;while(er Ill!
prn (dscount1);prn
code void (code *keytab
void main (void){
kbinit ():IE— O:
while (1)(*keytab
一0){prnint(er[j]);i++
(0x0a)·
[])()一{kg,/*⋯ */}
[readkey()])(); )
打印漢字*/
打印浮點數(shù)并換行*/ }
鍵值處理*/
主函數(shù)*/