久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

MSC-51單片機(jī)學(xué)習(xí)筆記之1

 昵稱7419213 2011-09-07

MSC-51單片機(jī)學(xué)習(xí)筆記之4

標(biāo)簽單片機(jī)  2011-06-04 23:04
                               第5 MCS-51 C語(yǔ)言程序設(shè)計(jì)
   不知道一本學(xué)習(xí)匯編語(yǔ)言的書(shū)怎么會(huì)花一章的時(shí)間帶上C語(yǔ)言,,不過(guò)也但是給自己的C語(yǔ)言鞏固下
本章要點(diǎn)
         MCS-51 C語(yǔ)言的特殊數(shù)據(jù)類型
         MCS-51 C語(yǔ)言程序的存儲(chǔ)模式
         MCS-51 C語(yǔ)言程序的結(jié)構(gòu)
         C語(yǔ)言與匯編語(yǔ)言的混合編程
 
5.1 C語(yǔ)言與MCS-51單片機(jī)
5.1.1 C語(yǔ)言的開(kāi)發(fā)過(guò)程
    一般的C語(yǔ)言開(kāi)發(fā)套件中,,包括編譯器,、連接器和符號(hào)轉(zhuǎn)換程序,,編譯器將源程序翻譯為可重定位的目標(biāo)代碼文件(也可產(chǎn)生等價(jià)的匯編語(yǔ)言程序),;連接器將目標(biāo)代碼文件連接為絕對(duì)目標(biāo)文件,;符號(hào)轉(zhuǎn)換程序可將絕對(duì)目標(biāo)文件轉(zhuǎn)換為Intel HEX格式文件,,編程到程序存儲(chǔ)器中運(yùn)行,,若使用提供了集成開(kāi)發(fā)環(huán)境(IDE)的套件,,則編輯、編譯,、連接,、符號(hào)轉(zhuǎn)換,甚至調(diào)試可在一個(gè)窗口中完成,。
5.1.2 C語(yǔ)言的特點(diǎn)
單片機(jī)的C語(yǔ)言符合ANSI C標(biāo)準(zhǔn),,可以產(chǎn)生緊湊的目標(biāo)碼,效率可以與匯編媲美,,與匯編語(yǔ)言相比,,C語(yǔ)言不有以下優(yōu)點(diǎn)
1,、不必詳細(xì)了解單片機(jī)的指令系統(tǒng)
2、僅要求對(duì)MCS-51存儲(chǔ)器結(jié)構(gòu)有初步了解
3,、寄存器分配,、不同存儲(chǔ)器區(qū)域的尋址及數(shù)據(jù)類型等細(xì)節(jié)由編譯程序管理
4、程序具有規(guī)范的結(jié)構(gòu)和固有的模塊化思想
5,、運(yùn)算符和關(guān)鍵字用接近于自然語(yǔ)言的方式表示
6,、提供包含大量標(biāo)準(zhǔn)子程序的函數(shù)庫(kù),具有較強(qiáng)的數(shù)據(jù)處理能力
7,、在對(duì)執(zhí)行效率要求較高的場(chǎng)合,,可以嵌入?yún)R編,也可以與匯編語(yǔ)言協(xié)同開(kāi)發(fā)
5.1.3單片機(jī)C語(yǔ)言的移植
移植的難點(diǎn)就是單片機(jī)C語(yǔ)言要解決的問(wèn)題
1,、MCS-51存儲(chǔ)器的非馮·諾依曼結(jié)構(gòu),,加上內(nèi)部有位尋址空間,對(duì)存儲(chǔ)器變量的使用提出了挑戰(zhàn)
2,、內(nèi)部的數(shù)據(jù)存儲(chǔ)器存儲(chǔ)空間太小,,而外部還可擴(kuò)展存儲(chǔ)容量,編譯程序如何根據(jù)實(shí)際情況合理使用這些空間
3,、內(nèi)部各功能單元采用特殊功能寄存器集中管理,,在C語(yǔ)言中如何實(shí)現(xiàn)寄存器訪問(wèn)
4、MCS-51單片機(jī)派生各類繁多,,硬件配置不統(tǒng)一,,但要求必須能夠使用C語(yǔ)言操控所有硬件資源
5、MXD-51內(nèi)部只有一個(gè)堆棧,,且存儲(chǔ)空間有限,,傳統(tǒng)的利用堆棧傳遞參數(shù)的方法難以奏效
隨著技術(shù)的發(fā)展和各軟件廠商的努力,以上問(wèn)題都得到了解決,,C語(yǔ)言日趨成熟,,成為專業(yè)化的實(shí)用高級(jí)語(yǔ)言
 
5.2單片機(jī)C語(yǔ)言的擴(kuò)充
5.2.1數(shù)據(jù)類型
無(wú)論是出現(xiàn)在表達(dá)式中的常量,還是程序自己定義的變量,,都有數(shù)據(jù)類型,,特別是變量,數(shù)據(jù)類型是編譯程序進(jìn)行存儲(chǔ)器分配的依據(jù)之一
數(shù)據(jù)類型 位數(shù) 字節(jié)數(shù) 范圍
bit 1   0~1
signed char 8 1 -128~+127
unsinged char 8 1 0~255
enum 8/16 1/2 -128~+127或-32768~+32767
signed short 16 2 -32768~+32767
unsinged short 16 2 0~+65535
signed int 16 2 -32768~+32767
unsigned int 16 2 0~+65535
signed long 32 4 -2147483648~+21473647
unsigned long 32 4 0~4294967295
float 32 4 ±1.175494E-38~±3.402823E+38
sbit 1   0~1
sfr 8 1 0~255
sfr16 16 2 0~65535
表中大部分類型是C語(yǔ)言中的標(biāo)準(zhǔn)類型,,像字符型,、枚舉型、各種整形和單精度浮點(diǎn)型等,,枚舉型根據(jù)實(shí)際枚舉常量的多少同編譯程序確定其長(zhǎng)度,,而bit、sbit、sfr和sfr16是為訪問(wèn)MCS-51硬件中的內(nèi)部RAM中的位,、SRF中的位以及8位SRF和16位SFR(如DPTR)所特有的類型,,它們不是ANSI C的一部分,不能用指針對(duì)它們進(jìn)行訪問(wèn),,也不能定義包含這些類型元素的數(shù)組,、結(jié)構(gòu)體、聯(lián)合體等
例:MCS-51系統(tǒng)中需要處理以下幾個(gè)數(shù)據(jù):一個(gè)是從擴(kuò)展的I/O端口輸入的8位開(kāi)關(guān)量狀態(tài)數(shù)據(jù)in_data,,一個(gè)是記錄系統(tǒng)運(yùn)行時(shí)間的log_time(以秒為單位),還有一個(gè)是保存設(shè)備是否正常運(yùn)行的標(biāo)志ok_flag,,它們以變量形式存儲(chǔ),,使用哪種類型最合適?
  in_data為8位無(wú)符號(hào)數(shù)據(jù),,使用unsingned char最合適,;log_time需要記錄較長(zhǎng)時(shí)間若用16位的整形變量,只能累計(jì)幾個(gè)小時(shí),,用long型最好,,也應(yīng)該是無(wú)符號(hào)的;log_time有一位即可,,可用bit型,,具體變量定義時(shí),可使用以下語(yǔ)句
  unsigned char  in_data;
  unsigned long  log_time;
  bit            ok_flag;
實(shí)際上,,只要不是必需,,在MCS-51的C語(yǔ)言程序中應(yīng)該盡量使用較短的、無(wú)符號(hào)的類型,,unsigned char是第一選擇,,因?yàn)榫幾g成機(jī)器碼后最適合單片機(jī)處理的是字節(jié)數(shù)據(jù)。
5.2.2存儲(chǔ)器類型
C語(yǔ)言中的變量的存儲(chǔ)位置通常同編譯程序根據(jù)一定的約定進(jìn)行分配,,如果編程時(shí)比較清楚某些變量的屬性,,程序員也可在變量定義進(jìn)指定其存儲(chǔ)區(qū)域
存儲(chǔ)類型 與硬件存儲(chǔ)器空間的對(duì)應(yīng)關(guān)系
code 程序存儲(chǔ)器:使用MOVC @A+DPTR指令訪問(wèn)
data 直接尋址的內(nèi)部數(shù)據(jù)存儲(chǔ)器:訪問(wèn)速度最快(128字節(jié))
idata 間接訪問(wèn)的內(nèi)部數(shù)據(jù)存儲(chǔ)器:可以訪問(wèn)所有的內(nèi)部存儲(chǔ)器空間(256字節(jié))
bdata 可位尋址的內(nèi)部數(shù)據(jù)存儲(chǔ)器:可以字節(jié)方式也可以位方式訪問(wèn)(16字節(jié))
xdata 外部數(shù)據(jù)存儲(chǔ)器(64KB),能過(guò)MOVX @DPTR指令訪問(wèn)
pdata 外部數(shù)據(jù)存儲(chǔ)器的一頁(yè)(256字節(jié)),,使用MOVX @Ri指令訪問(wèn)
例:指出以下變量的存儲(chǔ)位置
  char data            varl;
  char code            text[]="ENTER PARAMETER";
  unsigned long xdata  array[100];
  float idata          x,y,z;
  unsigned int pdata   dimension;
  unsigned char xdata  vector[10][4][4];
  char bdata           flags;
varl保存于內(nèi)部RAM中,;"ENTER PARAMETER"存儲(chǔ)于程序存儲(chǔ)器中;其首地址以text表示,,程序運(yùn)行期間該符號(hào)串不能修改,;100個(gè)長(zhǎng)整形元素的數(shù)組array只能存于外部RAM中,占400個(gè)字節(jié),;單精度浮點(diǎn)數(shù)變量XYZ保存于內(nèi)部RAM內(nèi),;無(wú)符號(hào)數(shù)變量dimension則存儲(chǔ)于外部RAM的某一頁(yè)內(nèi);有160個(gè)字節(jié)數(shù)據(jù)的三維數(shù)組vector也只能存儲(chǔ)于外部RAM中;由多個(gè)標(biāo)志位組成的標(biāo)志字節(jié)flags存儲(chǔ)于位尋址區(qū),。
若定義變量時(shí)指定了存儲(chǔ)器的類型,,編譯程序按要求為其分配存儲(chǔ)空間;若未指定,,編譯程序按照存儲(chǔ)器模式自動(dòng)為變量選擇默認(rèn)存儲(chǔ)器類型,。
5.2.3存儲(chǔ)模式
常用的存儲(chǔ)模式有以下幾種,
1,、SMALL模式
SMALL模式下,,所有的變量默認(rèn)存放于內(nèi)部RAM中,相當(dāng)于定義時(shí)使用了data類型,,這時(shí)的變量訪問(wèn)速度最快,、效率最高,但是所有對(duì)像(包括堆棧)必須能夠存入內(nèi)部RAM的128字節(jié)
2,、COMPACT模式
COMPACT模式下,,所有變量默認(rèn)存放于外部RAM的一頁(yè)中,相當(dāng)于定義時(shí)使用了pdata類型,,這種存儲(chǔ)模式可以滿足最多256字節(jié)的變量,,由于對(duì)變量的訪問(wèn)必須使用間接尋址方式,所以速度也比訪問(wèn)內(nèi)部RAM慢一些,,COMPACT模式產(chǎn)生的機(jī)器碼不如SMALL模式的快,,但是比LARGE模式要好
3、LARGE模式
LARGE械下,,所有變量默認(rèn)存放于外部RAM中,,最多可以有64KB,相當(dāng)于定義時(shí)使用了xdata類型,,數(shù)據(jù)指針DPTR用來(lái)尋址變量,。這種訪問(wèn)方式效率不高,特別是當(dāng)變量長(zhǎng)度超過(guò)一個(gè)字節(jié)時(shí),。尋址方式直接影響代碼長(zhǎng)度,,產(chǎn)生的機(jī)器碼比SMALL和COMPACT模式產(chǎn)生的都要多
如果沒(méi)有說(shuō)明,編譯程序默認(rèn)使用SMALL模式,,由于各種存儲(chǔ)模式在訪問(wèn)效率,、代碼長(zhǎng)度、變量總長(zhǎng)度等方面各有優(yōu)缺點(diǎn),,現(xiàn)在常用的C編譯程序通常允許使用混合模式,,即不管存儲(chǔ)模式如何,把經(jīng)常使用的變量強(qiáng)制存放于內(nèi)部RAM,,大塊數(shù)據(jù)則存放于外部RAM而將其指針存放于內(nèi)部RAM中,,可以使用存儲(chǔ)器類型說(shuō)明符指定。
5.2.4硬件資料訪問(wèn)
1、特殊功能寄存器
MCS-51 C語(yǔ)言使用sfr,、sfr16和sbit數(shù)據(jù)類型訪問(wèn)特殊功能寄存器
sfr P0=0x80;  /*P0口,,地址為80H*/
sfr P1=0x90;  /*P1口,地址為90H*/
sfr P2=0xA0;  /*P2口,,地址為A0H*/
sfr P3=0xB0;  /*P3口,,地址為B0H*/
其中,P0,、P1,、P2、P3是定義的特殊功能寄存器名字,。實(shí)際上任何合法的標(biāo)識(shí)符號(hào)都可以做為sfr定義中的特殊功能寄存器的變量名,,等號(hào)后的地址必須是數(shù)值常數(shù),而且一定要在特殊功能寄存器區(qū)域內(nèi)(0x80~0xFF).
大多數(shù)C環(huán)境附帶了一些C頭文件,,比較典型的是在reg51.h中對(duì)所有51子系統(tǒng)中的特殊功能寄存器進(jìn)行了sfr定義。
2,、特殊功能寄存器中的位
任何合法的標(biāo)識(shí)符都可以作為sbit名字,,等號(hào)右邊的表達(dá)式為該標(biāo)識(shí)符賦予了一個(gè)位地址,指定地址有三種方式
A,、sfr名字^整形常,,該方式使用先前已經(jīng)定義的sfr名字作為sbit的基地址,要求該sfr地址必須為8位的倍數(shù)(即該sfr確實(shí)是可以按位訪問(wèn)的),。在^符號(hào)后的整形常數(shù)指定該sbit在sfr中的位置,,范圍是0~7,其中0為最低有效位,。
例:下面定義的三個(gè)符號(hào)名稱的含義各是什么,?
srf  PSW   =0xD0;
sbit OV    =PWS^2;
sbit P     =PWS^0;
它們分別代表程序狀態(tài)字PSW(地址為D0H)、溢出標(biāo)志OV和奇偶標(biāo)志P
B,、整形常數(shù)^整形常數(shù)
sbit OV    =0xD0^2;
sbit P     =0xD0^0;
C,、整形常數(shù),這種方式直接指定位變量的位地址
sbit OV    =0xD2;
sbit P     =0xD0;
3,、內(nèi)部RAM中的位尋址資源
將一個(gè)變量定義為bit型后,,C編譯程序就會(huì)在位尋址區(qū)為其分配一位的空間,定義一個(gè)其他類型變量時(shí)若指定了bdata存儲(chǔ)器類型,,C編譯程序也會(huì)在內(nèi)部RAM的位尋址地區(qū)為其分配存儲(chǔ)空間,,這個(gè)變量中的位也可以單獨(dú)訪問(wèn),但必須先行定義,。
4,、指定絕對(duì)地址的變量
在某些與硬件密切相關(guān)的應(yīng)用中,可能需要指定變量在系統(tǒng)中的絕對(duì)地址,而不是讓編譯程序自行分配,。在MCS-51的C語(yǔ)言程序中,,可使用_at_滿足這一要求,其格式如下:
[存儲(chǔ)器類型]  變量類型  變量名  _at_  地址常數(shù),;
例:在某MCS-51系統(tǒng)中,,擴(kuò)展的外部數(shù)據(jù)存儲(chǔ)器地址2000H~20FFH共256個(gè)字節(jié)單元作為通信中的接收緩沖區(qū),請(qǐng)對(duì)該區(qū)域進(jìn)行定義,。
 若以r_buf命名該區(qū)域,,可以如下定義
 xdata  nusigned char r_buf[256]  _at_  ox20000;
對(duì)于外部擴(kuò)展的I/O口,所占外部RAM空間的地址已由硬件設(shè)計(jì)決定,,必須指定絕對(duì)地址
5,、存儲(chǔ)器絕對(duì)地址的訪問(wèn)
單片機(jī)C語(yǔ)言頭文件absacc.h中包含了一些宏定義,使用這些宏可以顯示使用存儲(chǔ)器絕對(duì)地址,,把每個(gè)存儲(chǔ)區(qū)定義成一個(gè)字節(jié)或字?jǐn)?shù)組,,對(duì)指定地址的訪問(wèn)使用數(shù)組元素引用的形式
例:使用存儲(chǔ)器絕對(duì)地址訪問(wèn)的方式,怎么實(shí)現(xiàn)以上兩個(gè)例子的功能》
#include <absaacc.h>
#define  r_buf   (XBYTE+0x20000)
#define  data_reg XBYTE[0xFF80]
#define  con_reg  XBYTE[0xFF81]
定義后,,對(duì)數(shù)組r_buf和寄存器data_reg,、con_reg的訪問(wèn)方式?jīng)]有變化
5.2.5指針
C語(yǔ)言程序中可以使用指針變量或指針常量,其值為所指類型變量的地址,,也可以是該類型數(shù)組的起始地址
1,、基于存儲(chǔ)器的指針
基于存儲(chǔ)器的指針類型與源程序中存儲(chǔ)器類型有關(guān),編譯進(jìn)即可確定其長(zhǎng)度,。這種指針的長(zhǎng)度可以為1個(gè)字節(jié)(dtat*,、idtat*、pdata*)或2個(gè)字節(jié)(code*,、xdata*)
例:指出下面指針定義的作用
char   data   *str;    /*指向data字符的指針*/
int    xdata  *numtab; /*指向xdata整形數(shù)據(jù)的指針*/
long   code   *powtab; /*指向data長(zhǎng)整形的指針*/
所定義的str numtab powtab三個(gè)指針變量長(zhǎng)度分別為1個(gè)字節(jié),、2字節(jié)、2字節(jié),,它們自身所占用的存儲(chǔ)位置由存儲(chǔ)模式確定,。
同普通變量一樣,在定義指針變量時(shí)可以指定其存儲(chǔ)類型
例:指出下面指針定義的含義
char   data  *xdata  str;   /*指針變量位于xdata*/
int    xdata *data   numtab;/*指針變量位于data*/
long   code  *idata  powtab;/*指針變量位于idata*/
2,、通用指針
定義和標(biāo)準(zhǔn)C指針定義相同,,凡是指針定義中未對(duì)指向的對(duì)象存儲(chǔ)器類型進(jìn)行修飾說(shuō)明的,編譯程序都將其作為通用指針,,使用3個(gè)字節(jié)存儲(chǔ)指針內(nèi)部,,第一個(gè)字節(jié)存放存儲(chǔ)器類型,第二和第三個(gè)字節(jié)分別存放該指針?biāo)笇?duì)象地址的高字節(jié)和低字節(jié)
例:指出以下代碼段中各變量的含義以及變化情況
xdata  int  x;
int    *data px,*data py;
px=&x;
py=0x021234;
*px=1000;
*py=-1;
整形變量X位于外部RAM中,;兩個(gè)通用指針px和py,,通過(guò)賦值語(yǔ)句使px指向x,,而py指向外部RAM的1234H單元,最后兩條賦值語(yǔ)句使x值成為1000,,1234單元內(nèi)容成為FFFFH,。
 
這兩節(jié)的內(nèi)部概念性的東西太多了,一時(shí)很難記的住,,我都看幾邊了也沒(méi)有記住不知道是不是方法有問(wèn)題,。
繼續(xù)這章內(nèi)容

5.3 C語(yǔ)言程序結(jié)構(gòu)

程序入口為main函數(shù),每個(gè)函數(shù)內(nèi)部可以使用結(jié)構(gòu)化程序設(shè)計(jì)技術(shù)的三種結(jié)構(gòu)

5.3.1函數(shù)

1,、函數(shù)定義

C語(yǔ)言一般采用模塊化設(shè)計(jì),,最基本的模塊就是同函數(shù)表示,MCS-51C語(yǔ)言程序中,,在定義函數(shù)時(shí)還可以指定是否為中斷算是函數(shù),、是否為可重入函數(shù),可以選擇工作寄存器組以及確定其存儲(chǔ)模式,,函數(shù)定義的基本格式如下

[返回值類型]   函數(shù)名稱(表達(dá)式)  [{small compact large}]

                            [reentrant] [interrupt n] [using n]

若省略返回值類型部分,,則默認(rèn)為整形( int),可以指定該函數(shù)的存儲(chǔ)模式,,以取代默認(rèn)值,;若使用using,編譯程序?qū)a(chǎn)生切換工作寄存器組的代碼,;對(duì)于有返回值的函數(shù),不能使用using,,因?yàn)榉祷刂凳峭ㄟ^(guò)寄存器傳遞的,。

2、參數(shù)傳遞

參數(shù)用于幾函數(shù)傳遞數(shù)據(jù),,作為函數(shù)的輸入,,MSC-51參數(shù)傳遞是通過(guò)存儲(chǔ)器和寄存器傳遞的,通過(guò)寄存器傳遞速度快是默認(rèn)的傳遞方式,,傳遞時(shí)所使用的寄存器分配如下表,,這時(shí)最多能3個(gè)參數(shù),若函數(shù)參數(shù)較多,,寄存器不足以傳遞所有參數(shù)則使用固定地址的存儲(chǔ)器單元作為函數(shù)的存放位置,,當(dāng)?shù)谝粋€(gè)參數(shù)是bit型時(shí),無(wú)法用寄存器傳遞參數(shù),。若參數(shù)個(gè)數(shù)不超過(guò)3個(gè),,可以將bit型參數(shù)放在參數(shù)表最后

                       5-4傳遞參數(shù)的寄存器分配

參數(shù)個(gè)數(shù)

char或字節(jié)指針

int2個(gè)字節(jié)指針

longfloat

通用指針

1

R7

R6&R7

R4R7

R1R3

2

R5

R4&R5

R4R7

R1R3

3

R3

R2&R3

 

R1R3

3、返回值

與傳遞參數(shù)不同,,函數(shù)的返回值總是通過(guò)寄存器送回的如下表

                            5-5函數(shù)返回值所用寄存器分配

返回值類型

寄存器

描述

 bit

CY標(biāo)志

無(wú)

char,unsigned char,1個(gè)字節(jié)指針

R7

無(wú)

int,unsigned int,2個(gè)字節(jié)指針

R6&R7

最高有效位在R6中,,最低有效位在R7

longunsigned long

R4R7

最高有效位在R4中,,最低有效位在R7

float

R4R7

32IEEE格式

通用指針

R1R3

存儲(chǔ)器類型在R3中,最高有效位在R2中,,最低有效位在R1

4,、內(nèi)部函數(shù)和外部函數(shù)

如果一個(gè)函數(shù)只能在其定義的文件中被調(diào)用,則稱為內(nèi)部函數(shù),,也稱為靜太函數(shù),,定義內(nèi)部函數(shù)時(shí)需要用static存儲(chǔ)類型說(shuō)明

Static unsigned int fun(unsigned char the_byte,bit the_flag)

函數(shù)fun在包含其定義的文件外不可訪問(wèn)。

允許在其它文件中調(diào)用的函數(shù)為外部函數(shù),,可以使用extern存儲(chǔ)類型說(shuō)明符指明,。函數(shù)定義時(shí)若無(wú)存儲(chǔ)類型說(shuō)明,默認(rèn)為外部函數(shù),。

5,、可重入函數(shù)

 單片機(jī)的C編譯程序通常的局部變量分配在存儲(chǔ)器的固定位置,如果正在執(zhí)行該函數(shù)時(shí)發(fā)生了中斷,,而中斷服務(wù)程序中也調(diào)用該函數(shù),,先前的局部變量值便會(huì)被破壞,類似的情況在實(shí)現(xiàn)函數(shù)遞歸調(diào)用時(shí)也會(huì)發(fā)生,,對(duì)于一個(gè)函數(shù),,如果確實(shí)需要遞歸調(diào)用,或者確實(shí)非中斷服務(wù)程序代碼與中斷服務(wù)程序都要調(diào)用,,應(yīng)當(dāng)將它定義為可重入函數(shù),,使編譯程序產(chǎn)生能夠保護(hù)局部變量的代碼,可以重入函數(shù)是使用reentrant來(lái)說(shuō)明,。

例:有一個(gè)延時(shí)函數(shù),,在程序中多次被調(diào)用,包括中斷服務(wù)程序,,請(qǐng)將其定義為可重入函數(shù),。

void delay(void)reentrant

{

    int i;

    for(i=0;i<1000;i++)

    ;

}

其實(shí)若非遞歸調(diào)用,也可以不編寫可重入函數(shù),,而是將同一函數(shù)改寫為非中斷服務(wù)程序調(diào)用和中斷服務(wù)程序調(diào)用的兩個(gè)函數(shù),,變量所需存儲(chǔ)空間沒(méi)有顯著減少,代碼腳加長(zhǎng)了

6,、中斷處理函數(shù)

中斷處理函數(shù)也稱作中斷服務(wù)程序,,是CPU響應(yīng)中斷后要執(zhí)行的一段程序,在C語(yǔ)言中組織成一個(gè)函數(shù)的形式,,編寫中斷處理函數(shù)時(shí),,程序員只需要中斷類型號(hào)和寄存器組的選擇,編譯程序會(huì)自動(dòng)產(chǎn)生中斷向量和返回地址的入棧及出棧代碼,。在函數(shù)定義時(shí)可以使用interrupt將其指定為一個(gè)中斷處理函數(shù),,還可以用using分配中斷處理函數(shù)所使用的寄存器組,。

例:說(shuō)明下面函數(shù)定義的作用

unsigned int interruptcnt;

unsigned char second;

void timer0 (void) interrupt 1 using 2

{

       if(++interruptcnt= =1000)

       {

              second++;

              interruptcnt=0;

}

}

函數(shù)timer0是一個(gè)中斷處理函數(shù),所對(duì)應(yīng)的中斷類型號(hào)為1,,使用第二組工作寄存器

7,、intrinsic函數(shù)

MSC-51 C語(yǔ)言中,intrinsic函數(shù)是一類用匯編語(yǔ)言代碼實(shí)現(xiàn)的短小函數(shù),,若C語(yǔ)言程序中有對(duì)intrinsic函數(shù)的調(diào)用,,編譯程序?qū)?huì)直接用被調(diào)用函數(shù)代碼替換函數(shù)調(diào)用語(yǔ)句。

常見(jiàn)intrinsic函數(shù)的原型如下,,它們一般在intris.h文件中

extern void          _nop_    (void);

extern bit           _testbit_   (bit);

extern unsigned char  _cror_    (unsigned char,unsigned char);

extern unsigned int   _iror_     (unsigned int,unsigned int);

extern unsigned long  _lror_     (unsigned long,unsigned long);

extern unsigned char  _crol_     (unsigned char,unsigned char);

extern unsigned int    _irol_     (unsigned int,unsigned int);

extern unsigned long   _lrol_    (unsigned long,unsigned long);

這些函數(shù)名稱前后都有下劃線,,這是與其它庫(kù)函數(shù)的最明顯區(qū)別,以上函數(shù)實(shí)現(xiàn)的功能分別是空操作,、位測(cè)試以及字符型,、整形和長(zhǎng)整形數(shù)據(jù)的左、右移位,。

例:編寫代碼,,若位變量flag值為1,則8位位數(shù)據(jù)data8右移兩位并將flag清零,,否則左移3位,。

if(_teatbit_(flag))

       data8=_cror_(data8,2);

else

       data8=_crol_(data8,3);

 

5.3.2流程控制

1、分支,,C語(yǔ)言有兩種分支方式

A,、if語(yǔ)句

If(表達(dá)式) 語(yǔ)句1

這種形式實(shí)現(xiàn)了單分?jǐn)偨Y(jié)構(gòu),若表達(dá)式值非0,,則執(zhí)行后面的語(yǔ)句1,,然后繼續(xù)往下執(zhí)行,若表達(dá)式的值為0,,則跳過(guò)語(yǔ)句1直接往下執(zhí)行

兩個(gè)分支的if語(yǔ)句形式為

if(表達(dá)式)

       語(yǔ)句1

else

       語(yǔ)句2

若表達(dá)式值是非0,,則執(zhí)行后的語(yǔ)句1,,然后執(zhí)行表達(dá)式語(yǔ)句2后面的語(yǔ)句,,若表過(guò)式的值為0則跳過(guò)語(yǔ)句1執(zhí)行語(yǔ)句2,然后繼續(xù)執(zhí)行下面語(yǔ)句

多分支if語(yǔ)句形式為

if(表達(dá)式)

       語(yǔ)句1

else if(表達(dá)式2)

       語(yǔ)句2

else if(表達(dá)式3)

       語(yǔ)句3

…………..

else

       語(yǔ)句n

多選結(jié)構(gòu)n個(gè)語(yǔ)句中只能執(zhí)行一個(gè),,即第一個(gè)值非0表達(dá)式后面的語(yǔ)句,。

以上三種形式中,所有語(yǔ)句都可以是復(fù)合語(yǔ)句,,即用花括號(hào)引起來(lái)的語(yǔ)句組,。

Bswitch-case結(jié)構(gòu)

當(dāng)選擇較多時(shí)使用if語(yǔ)句和程序結(jié)構(gòu)會(huì)變得臃腫,,switch-case結(jié)構(gòu)是比較簡(jiǎn)潔的寫法形式為

switch(表達(dá)式)

{

       csae   常量表達(dá)式1:語(yǔ)句組1,;break;

csae   常量表達(dá)式2:語(yǔ)句組2,;break;

………

csae   常量表達(dá)式n:語(yǔ)句組nbreak;

default;              語(yǔ)句組n+1,;break;

}    

Switch后的表達(dá)式可以是整形或字符型,、枚舉型數(shù)據(jù),case后的各常量大達(dá)式須與其類型相同或可以相互轉(zhuǎn)換,,當(dāng)前者的值與某一case后表達(dá)式的值相等時(shí),,執(zhí)行其后的語(yǔ)句組,然后執(zhí)行break退出switch語(yǔ)句,,若所有case后表達(dá)式與之皆不相等,,則執(zhí)行default后語(yǔ)句組,case后表達(dá)式須各不相乖,。

2,、循環(huán)

C語(yǔ)言中實(shí)現(xiàn)循環(huán)結(jié)構(gòu)的語(yǔ)句也有多種

A、 goto語(yǔ)句:用來(lái)實(shí)現(xiàn)轉(zhuǎn)移,,結(jié)合if語(yǔ)句,,可以實(shí)現(xiàn)簡(jiǎn)單的循環(huán),類似于指令系統(tǒng)中的條件轉(zhuǎn)移指令的作用,,但是goto語(yǔ)句可以轉(zhuǎn)向程序中任何位置,,所以受到結(jié)構(gòu)化程序設(shè)計(jì)支持者的強(qiáng)烈抵制

B、 while結(jié)構(gòu),,形式為

while(表達(dá)式)

       語(yǔ)句

其中表達(dá)式為循環(huán)條件,,語(yǔ)句構(gòu)成循環(huán)體。若循環(huán)條件值非0,,則執(zhí)行循環(huán)體,,一種常見(jiàn)的形式為

while(1)

{

       ……….

}

這種形式可以稱為無(wú)限循環(huán),一般單片機(jī)軟件就是這種形式,,如下代碼

while(!(P1&0x01))

;

實(shí)現(xiàn)的是等待P1.01,,循環(huán)體部分為空語(yǔ)句,循環(huán)條件是輸入的P1值最低有效位為0.

C,、 do….while結(jié)構(gòu),,形式為

do

       語(yǔ)句

While(表達(dá)式)

不像while結(jié)構(gòu)先判斷條件,,do….while結(jié)構(gòu)是先執(zhí)行一次語(yǔ)句(循環(huán)體),然后再判斷條件,,若條件表達(dá)式值非0,則繼續(xù)下次循環(huán),。

D,、for結(jié)構(gòu),for結(jié)構(gòu)是使用最靈活的循環(huán)控制語(yǔ)句,,形式為

for(表達(dá)式1,;表達(dá)式2,;表達(dá)式3)

     語(yǔ)句

for結(jié)構(gòu)的執(zhí)行過(guò)程為:先對(duì)表達(dá)式1求值;再對(duì)表達(dá)式2求值,,若表達(dá)式2的值是非0,,則執(zhí)行一次語(yǔ)句,然后對(duì)表達(dá)式3求值,,再一次對(duì)表達(dá)式2求值,,若非0,則在此形成循環(huán),,直到表達(dá)式2的值為0,,則循環(huán)結(jié)束。如下代碼

for(;P1&0x01;)

     ;

 實(shí)現(xiàn)的也是等待P1.0輸入為1,,而

for(i=0;(i<10000)&&(P1&0x01);i++)

     ;

實(shí)現(xiàn)的是有時(shí)間限制的等待P1.01,,具體時(shí)間可以通過(guò)檢查編譯產(chǎn)生的代碼計(jì)算得到,或者在仿真器上設(shè)置斷點(diǎn)觀察得知,。

E,、 breakcontinue語(yǔ)句

break語(yǔ)句不公能夠跳出switch結(jié)構(gòu),還可以從循環(huán)體中跳出,,提前結(jié)束循環(huán)而執(zhí)行循環(huán)后面的語(yǔ)句,。Break只能用在循環(huán)語(yǔ)句(包括whiledo….whiletfor結(jié)構(gòu))和switch語(yǔ)句中,。

Continue語(yǔ)句則是提前結(jié)束本次循環(huán),,跳過(guò)循環(huán)體中continue后面未執(zhí)行的語(yǔ)句,接著進(jìn)行一次循環(huán)條件的判定,。

breakcontinue語(yǔ)句其實(shí)是結(jié)構(gòu)化程序設(shè)計(jì)方法中實(shí)現(xiàn)非結(jié)構(gòu)化的一種手段,,在退出循環(huán)或提前結(jié)束循環(huán)的條件不易表達(dá)時(shí),這類語(yǔ)句可以使程序更容易理解,。

 

5.3.3輸入與輸出

一些C開(kāi)發(fā)環(huán)境提供了流式輸入/輸出函數(shù),,可以實(shí)現(xiàn)通過(guò)串口或用戶自定義I/O接口的輸入/輸出操作,例如getchar,、gets,、scanfputchar,、puts,、printf等,,輸入/輸出功能需要調(diào)用_getkeyputchar兩個(gè)函數(shù),,這兩個(gè)函數(shù)的默認(rèn)實(shí)現(xiàn)是通過(guò)串行口實(shí)現(xiàn)的,所以如果使用輸入/輸出函數(shù),,還需要在程序中加入一些代碼,,以便調(diào)用時(shí)已經(jīng)對(duì)串行口進(jìn)行了適當(dāng)?shù)某跏脊ぷ鳌?/span>

例:說(shuō)明以下代碼的運(yùn)行結(jié)果

#include   <reg51.h>    /*初始化時(shí)要用到SFR*/

#include   <stdio.h>    /*引入輸入/輸出函數(shù)原型*/

Void main(void)

{

       int x,y            /*變量*/

       SCON  =0x50;    /*開(kāi)始對(duì)串行口的初始化代碼*/

       PCON &=0x7F;

       TMOD &=0xCF;

       TMOD &=0x20;

       TH1   =0xFD;

       TR1   =1;

       TI     =1;        /*初始化結(jié)束*/

       While(1)

       {

              scanf(“%d%d,&x,&y);              /*輸入*/

              printf(“x=%04x,y=%04x\n”,x,y);     /*輸出*/

}

}

該程序接收用戶輸入的十進(jìn)制數(shù)值,,然后從串行口以十六進(jìn)制格式輸出

程序員可以根據(jù)系統(tǒng)輸入/輸出接口的配置情況重寫_getkeyputchar兩個(gè)函數(shù),其他函數(shù)功能保持不變,。

 

5.3.4程序的入口

C語(yǔ)言程序的入口是main函數(shù),,而單片機(jī)復(fù)位后是從0000H開(kāi)始執(zhí)行代碼程序,main函數(shù)位于系統(tǒng)程序存儲(chǔ)器的何處呢,?下面觀察一下例子程序的可執(zhí)行代碼

0000H

010012

LJMP

0012H

0003H

EF

MOV

A,R7

0004H

C4

SWAP

A

0005H

540F

ANL

A,#0FH

0007H

75F00A

MOV

B,#0AH

000AH

A4

MUL

AB

000BH

FE

MOV

R6,A

000CH

EF

MOV

A,R7

000DH

540F

ANL

A,#0FH

000EH

2E

ADD

A,R6

000FH

FF

MOV

R7,A

0010H

22

RET

 

0012H

787F

MOV

R0,7FH

0014H

E4

CLR

A

0015H

F6

MOV

@R0,A

0016H

DBFD

DJNZ

R0,0015H

0018H

758108

MOV

SP,#08H

001BH

02001E

LJMP

001EH

001EH

7F56

MOV

R7,#56H

0020H

120003

LCALL

0003H

0023H

8F08

MOV

08H,R7

0025H

80FE

SJMP

0025H

最左邊一列是程序存儲(chǔ)器地址,,第二列是指令機(jī)器碼,最右邊一列為助記符表示,,可以看到單片機(jī)復(fù)位后,,先轉(zhuǎn)移到0012H,將內(nèi)部RAM單元00H7FH清零,,置SP08H后,,轉(zhuǎn)移到main函數(shù)(001EH)處執(zhí)行,即在main函數(shù)執(zhí)行之前,,已經(jīng)做了一些初始化處理,。

這是默認(rèn)的初始化操作,至于堆棧,,取決于編譯程序在內(nèi)部RAM中為局部變量分配空間的大小,,若有在main函數(shù)執(zhí)行之前就應(yīng)當(dāng)初始化的資源,或者需要將存儲(chǔ)區(qū)初始化謎團(tuán)特定的值,,程序員可以在匯編語(yǔ)言程序STARTUP.A51中修改或添加代碼,,在使用C語(yǔ)言開(kāi)發(fā)的單片機(jī)軟件中,單片機(jī)程序的入口其實(shí)還是0000H,,在STARTUP.51中初始化代碼的最后一條指令才轉(zhuǎn)向main函數(shù)執(zhí)行,。

 

5.4 C語(yǔ)言與匯編語(yǔ)言的混合編程

C語(yǔ)言和匯編語(yǔ)言各有優(yōu)缺點(diǎn),C語(yǔ)言中數(shù)據(jù)類型豐富,,程序結(jié)構(gòu)清晰,,但是在執(zhí)行速度、精確定時(shí),、控制硬件等方面不如匯編語(yǔ)言方便,,如果要在各方面都獲得滿意的結(jié)果,可以使用C語(yǔ)言與匯編語(yǔ)言的混合編程,。

C語(yǔ)言調(diào)用匯編語(yǔ)言程序時(shí),,被調(diào)用函數(shù)(匯編語(yǔ)言函數(shù))要在調(diào)用函數(shù)(C語(yǔ)言函數(shù))所在文件中說(shuō)明,對(duì)于匯編語(yǔ)言程序有以下要求

1,、  要使用SEGMENT偽指令定義可重定的CODE段,。

2、  要根據(jù)不同的情況對(duì)函數(shù)名進(jìn)行轉(zhuǎn)換,見(jiàn)下表5-6.

3,、  須使用PUBLIC偽指令將被調(diào)用函數(shù)說(shuō)明為外部可用函數(shù)

4,、  若有參數(shù)傳遞,按照表5-4所列的規(guī)則使用參數(shù),。

5,、  若有返回值,按照表5-5所列的規(guī)則存儲(chǔ)寄存器,。

              5-6函數(shù)名轉(zhuǎn)換規(guī)則

函數(shù)首部

符號(hào)名

說(shuō)明

void func(void)

FUNC

無(wú)參數(shù)傳遞或不含寄存器參數(shù)的函數(shù)名不作改變

void func(char)

_FUNC

帶寄存器參數(shù)的函數(shù)名加“_

void func(void) reentrant

_?FUNC

可重入函數(shù)前加“_?

例:編寫匯編語(yǔ)言函數(shù)max,,參數(shù)為兩個(gè)8位無(wú)符號(hào)數(shù),功能是求出其中的大數(shù)返回,。

    C語(yǔ)言中可按如下方式聲明和調(diào)用

    extern   unsigned  char  max(unsigned, unsigned); /*聲明*/

    void  main(void)

    {

        unsigned char  x,y;

        x=130;y=131;

        x=max(x,y);               /*調(diào)用*/

        while(1);

}

兩個(gè)參數(shù)分別在R7R5中傳遞到子程序,,返回值應(yīng)保存在R7中,匯編語(yǔ)言程序文件可如下編寫,

PUBLIC  _MAX               ;聲明

MIXED   SEGMENT   CODE     ,;定義一個(gè)可重定位的段MIXED

        ESEG      MIXED     ,;選擇MIXED為當(dāng)前段

_MAX:             

        MOV       A,R7      ;第一個(gè)參數(shù)

        CLR       C

        SUBB      A,R5      ,;減去第二個(gè)參數(shù)

        JNC       _MAX_RET  ,;無(wú)借位,第一個(gè)參數(shù)值大

        MOV       A,R5      ,;有借位,,第二個(gè)參數(shù)值大

        MOV       R7,A      ;返回值在R7

_MAX_RET:

        RET

        EDN

 

:編寫匯編語(yǔ)言函數(shù)delayms,,參數(shù)為一個(gè)8位無(wú)符號(hào)數(shù),,功能是按照參數(shù)指定的毫秒數(shù)實(shí)現(xiàn)延時(shí)。這個(gè)函數(shù)有參數(shù)傳遞,,但是無(wú)返回值,。

匯編語(yǔ)言文件可如下編寫

PUBLIC  _DELAYMS                  ;聲明

HAHA    SEGMENT   CODE            ;定義一個(gè)可重定位的段HAHA

        RSEG      HAHA            ,;選擇HAHA為當(dāng)前段

_DELAYMS:

        MOV   R6,#2               ,;以下實(shí)現(xiàn)約1ms的延時(shí)

_DELAY_NEXT:

        MOV   R5,#248

        DJNZ  R5,$

        DJNZ  R6,_DELAY_NEXT

        DJNZ  R7,_DELAYMS

        RET

        END                        ;返回

例:編寫匯編語(yǔ)言函數(shù)delay10ms,沒(méi)有參數(shù),,功能是延時(shí)10ms,,這個(gè)問(wèn)題與上例的區(qū)別在于無(wú)參數(shù)傳遞,所以函數(shù)名無(wú)需加“_”,。

匯編語(yǔ)言文件可寫成如下形式

PUBILIC  EDLAY10MS

MIXED    SEGMENT     CODE

         RSEG        MIXED

DELAY10MS:

         MOV     R6,#20

DELAY_NEXT:

         MOV     R5,#248

         DJNZ    R5,$

         DJNZ    R6,DELAY_NEXT

         RET

         END

以上例子中,,只是各編寫了一個(gè)供C語(yǔ)言程序調(diào)用的匯編語(yǔ)言函數(shù),若需要多個(gè),,也是可以寫在同一個(gè)匯編語(yǔ)言程序文件中,,匯編語(yǔ)言程序中也可以調(diào)用C語(yǔ)言函數(shù),,但不常用。 

 
 
 
 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多