單片機(jī)課件單片機(jī)的C語(yǔ)言編程.ppt
《單片機(jī)課件單片機(jī)的C語(yǔ)言編程.ppt》由會(huì)員分享,可在線閱讀,更多相關(guān)《單片機(jī)課件單片機(jī)的C語(yǔ)言編程.ppt(92頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
第10章單片機(jī)的C語(yǔ)言編程 單片機(jī)原理 接口及應(yīng)用 內(nèi)容提要 C51程序結(jié)構(gòu) C51的數(shù)據(jù)類型 數(shù)據(jù)的存貯類型和存貯模式 C51對(duì)SFR 可尋址位 存儲(chǔ)器和I O口的定義 C51的運(yùn)算符 函數(shù) C語(yǔ)言編程實(shí)例 單片機(jī)資源的C語(yǔ)言編程實(shí)例 匯編語(yǔ)言和C語(yǔ)言的混合編程 C語(yǔ)言函數(shù)庫(kù)的管理與使用 小結(jié) 51系列單片機(jī)支持三種高級(jí)語(yǔ)言 即PL M C和BASIC 8052單片機(jī)內(nèi)固化有解釋BASIC語(yǔ)言 BASIC語(yǔ)言適用于簡(jiǎn)單編程而對(duì)編程效率運(yùn)行速度要求不高的場(chǎng)合 PL M是一種結(jié)構(gòu)化的語(yǔ)言 很象PASCAL PL M編譯器好象匯編器一樣產(chǎn)生緊湊的機(jī)器代碼 可以說(shuō)是高級(jí)匯編語(yǔ)言 但它不支持復(fù)雜的算術(shù)運(yùn)算 無(wú)豐富庫(kù)函數(shù)支持 學(xué)習(xí)PL M無(wú)異于學(xué)習(xí)一種新的語(yǔ)言 C語(yǔ)言是一種通用的程序設(shè)計(jì)語(yǔ)言 其代碼率高 數(shù)據(jù)類型及運(yùn)算符豐富 并具有良好的程序結(jié)構(gòu) 適用于各種應(yīng)用的程序設(shè)計(jì) 是目前使用較廣的單片機(jī)編程語(yǔ)言 單片機(jī)的C語(yǔ)言采用C51編譯器 簡(jiǎn)稱C51 由C51產(chǎn)生的目標(biāo)代碼短 運(yùn)行速度高 所需存儲(chǔ)空間小 符合C語(yǔ)言的ANSI標(biāo)準(zhǔn) 生成的代碼遵循Intel目標(biāo)文件格式 而且可與A51匯編語(yǔ)言或PL M51語(yǔ)言目標(biāo)代碼混和使用 應(yīng)用C51編程具有以下優(yōu)點(diǎn) 1 C51管理內(nèi)部寄存器和存貯器的分配 編程時(shí) 無(wú)需考慮不同存儲(chǔ)器的尋址和數(shù)據(jù)類型等細(xì)節(jié)問(wèn)題 程序由若干函數(shù)組成 具有良好的模塊化結(jié)構(gòu) 有豐富的子程序庫(kù)可直接引用 從而大大減少用戶編程的工作量 C語(yǔ)言和匯編語(yǔ)言可以交叉使用 匯編語(yǔ)言程序代碼短 運(yùn)行速度快 但復(fù)雜運(yùn)算編程耗時(shí) 如果用匯編語(yǔ)言編寫與硬件有關(guān)的部分程序 用C語(yǔ)言編寫與硬件無(wú)關(guān)的運(yùn)算部分程序 充分發(fā)揮兩種語(yǔ)言的長(zhǎng)處 可以提高開發(fā)效率 10 1C51程序結(jié)構(gòu) 同標(biāo)準(zhǔn)C一樣 C51的程序由一個(gè)個(gè)函數(shù)組成 這里的函數(shù)和其他語(yǔ)言的 子程序 或 過(guò)程 具有相同的意義 其中必須有一個(gè)主函數(shù)main 程序的執(zhí)行從main 函數(shù)開始 調(diào)用其他函數(shù)后返回主函數(shù)main 最后在主函數(shù)中結(jié)束整個(gè)程序而不管函數(shù)的排列順序如何 C語(yǔ)言程序的組成結(jié)構(gòu)如下所示 全局變量說(shuō)明 可被各函數(shù)引用 main 主函數(shù) 局部變量說(shuō)明 只在本函數(shù)引用 執(zhí)行語(yǔ)句 包括函數(shù)調(diào)用語(yǔ)句 fun1 形式參數(shù)表 函數(shù)1 形式參數(shù)說(shuō)明 局部變量說(shuō)明執(zhí)行語(yǔ)句 包括調(diào)用其他函數(shù)語(yǔ)句 funn 形式參數(shù)表 函數(shù)n 形式參數(shù)說(shuō)明 局部變量說(shuō)明執(zhí)行語(yǔ)句 C語(yǔ)言的語(yǔ)句規(guī)則 1 每個(gè)變量必須先說(shuō)明后引用 變量名英文大小寫是有差別的 2 C語(yǔ)言程序一行可以書寫多條語(yǔ)句 但每個(gè)語(yǔ)句必須以 結(jié)尾 一個(gè)語(yǔ)句也可以多行書寫為好 3 C語(yǔ)言的注釋用 表示 4 花括號(hào)必須成對(duì) 位置隨意 可在緊挨函數(shù)名后 也可另起一行 多個(gè)花括號(hào)可以同行書寫 也可逐行書寫 為層次分明 增加可讀性 同一層的 花括號(hào)對(duì)齊 采用逐層縮進(jìn)方式書寫 10 2C51的數(shù)據(jù)類型 C51的數(shù)據(jù)有常量和變量之分 常量 在程序運(yùn)行中其值不變的量 可以為字符 十進(jìn)制數(shù)或十六進(jìn)制數(shù) 用0 x表示 常量分為數(shù)值型常量和符號(hào)型常量 如果是符號(hào)型常量 需用宏定義指令 define 對(duì)其進(jìn)行定義 相當(dāng)于匯編的 EQU 偽指令 如 definePI3 1415那么程序中只要出現(xiàn)PI的地方 編譯程序都譯為3 1415 變量 在程序運(yùn)行中其值可以改變的量 一個(gè)變量由變量名和變量值構(gòu)成 變量名即是存貯單元地址的符號(hào)表示 而變量的值就是該單元存放的內(nèi)容 定義一個(gè)變量 編譯系統(tǒng)就會(huì)自動(dòng)為它安排一個(gè)存貯單元 具體的地址值用戶不必在意 10 2 1C51變量的數(shù)據(jù)類型 無(wú)論哪種數(shù)據(jù)都是存放在存貯單元中的 每一個(gè)數(shù)據(jù)究竟要占用幾個(gè)單元 即數(shù)據(jù)的長(zhǎng)度 都要提供給編譯系統(tǒng) 正如匯編語(yǔ)言中存放數(shù)據(jù)的單元要用DB或DW偽指令進(jìn)行定義一樣 編譯系統(tǒng)以此為根據(jù)預(yù)留存貯單元 這就是定義數(shù)據(jù)類型的意義 C51編譯器支持?jǐn)?shù)據(jù)類型見表10 1 表10 1C51的數(shù)據(jù)類型 對(duì)表10 1作如下說(shuō)明 1 字符型 char 整型 int 和長(zhǎng)整型 long 均有符號(hào)型 signed 和無(wú)符號(hào)型 unsigned 兩種 如果不是必須 盡可能選擇unsigned型 這將會(huì)使編譯器省卻符號(hào)位的檢測(cè) 使生成的程序代碼比signed類型短得多 2 程序編譯時(shí) C51編譯器會(huì)自動(dòng)進(jìn)行類型轉(zhuǎn)換 例如將一個(gè)位變量賦值給一個(gè)整型變量時(shí) 位型值自動(dòng)轉(zhuǎn)換為整型值 當(dāng)運(yùn)算符兩邊為不同類型的數(shù)據(jù)時(shí) 編譯器先將低級(jí)的數(shù)據(jù)類型轉(zhuǎn)換為較高級(jí)的數(shù)據(jù)類型 運(yùn)算后 運(yùn)算結(jié)果為高級(jí)數(shù)據(jù)類型 3 51單片機(jī)內(nèi)部數(shù)據(jù)存貯器的可尋址位 20H 2FH 定義為bit型 而特殊功能寄存器的可尋址位 即地址為X0H和X8H的SFR的各位 只能定義為sbit類型 10 2 2關(guān)于指針型數(shù)據(jù) 1 關(guān)于指針型變量在匯編語(yǔ)言程序中 要取存貯單元m的內(nèi)容可用直接尋址方式 也可用寄存器間接尋址方式 如果用R1寄存器指示m的地址 用 R1取m單元的內(nèi)容 相對(duì)應(yīng)的在C語(yǔ)言中用變量名表示取變量的值 相當(dāng)于直接尋址 也可用另一個(gè)變量 如P 存放m的地址 P就相當(dāng)于R1寄存器 用 P取得m單元的內(nèi)容 相當(dāng)于匯編的間接尋址方式 這里P即為指針型變量 下面表格表示兩種語(yǔ)言將m單元的內(nèi)容送n單元的對(duì)照語(yǔ)句 注 上表省略了匯編語(yǔ)言程序中對(duì)符號(hào)地址n和m用EQU偽指令進(jìn)行具體地址定義的語(yǔ)句以及C語(yǔ)言對(duì)變量n m和指針變量P進(jìn)行類型定義的語(yǔ)句 實(shí)際程序設(shè)計(jì)中 此步是不可缺少的 表中 為取地址運(yùn)算符 為取內(nèi)容運(yùn)算符 表1O 2匯編語(yǔ)言和C語(yǔ)言的對(duì)照 2 指針型數(shù)據(jù)的類型由于C51是結(jié)合51單片機(jī)硬件的 51單片機(jī)的不同存貯空間 有不同的地址范圍 即使對(duì)于同一外部數(shù)據(jù)存貯器 又有用 Ri分頁(yè)尋址 Ri為八位 和用 DPTR尋址 DPTR為十六位 兩種尋址方式 而指針本身也是一個(gè)變量 有它存放的存貯區(qū)和數(shù)據(jù)長(zhǎng)度 因此 在指針類型的定義中要說(shuō)明 被指的變量的數(shù)據(jù)類型和存貯類型 指針變量本身的數(shù)據(jù)類型 占幾個(gè)字節(jié) 和存貯類型 即指針本身存放在什么存貯區(qū) 例如類型定義為data或idata 表示指針指示內(nèi)部數(shù)據(jù)存貯器 而pdata表示指針指向外部數(shù)據(jù)存貯器 用 Ri間址 以上均為八位地址 而類型code xdata表示指針指向外部程序存貯器或外部數(shù)據(jù)存貯器指針 本身 即被指示地址 應(yīng)為十六位長(zhǎng)度 如果想使指針能適用于指向任何存貯空間 則可以定義指針為通用型 此時(shí)指針長(zhǎng)度為3字節(jié) 第一字節(jié)表示存貯器類型編碼 第二 三字節(jié)分別表示所指地址的高位和低位 第一字節(jié)表示的存貯器類型編碼見表10 3 表10 3通用型指針的存貯類型編碼 10 3數(shù)據(jù)的存貯類型和存貯模式 10 3 1數(shù)據(jù)的存貯類型C51是面向8XX51系列單片機(jī)及硬件控制系統(tǒng)的開發(fā)語(yǔ)言 它定義的任何變量必須以一定的存貯類型的方式定位在8XX51的某一存貯區(qū)中 否則便沒有意義 因此在定義變量類型時(shí) 還必須定義它的存貯類型 C51的變量的存貯類型如表10 4所示 表10 4C51的變量的存貯類型 訪問(wèn)內(nèi)部數(shù)據(jù)存貯器 idata 比訪問(wèn)外部數(shù)據(jù)存貯器 xdata 相對(duì)要快一些 因此 可將經(jīng)常使用的變量置于內(nèi)部數(shù)據(jù)存貯器中 而將較大及很少使用的數(shù)據(jù)變量置于外部數(shù)據(jù)存貯器中 例如定義變量x語(yǔ)句 datacharx 等價(jià)于chardatax 如果用戶不對(duì)變量的存貯類型定義 則編譯器承認(rèn)默認(rèn)存貯類型 默認(rèn)的存貯類型由編譯控制命令的存貯的模式部分決定 10 3 2存貯器模式 存貯器模式?jīng)Q定了變量的默認(rèn)存貯器類型 參數(shù)傳遞區(qū)和無(wú)明確存貯區(qū)類型的說(shuō)明 C51的存貯器模式有SMALL LARGE和COMPACT 見表10 5 在固定的存貯器地址進(jìn)行變量參數(shù)傳遞是C51的一個(gè)標(biāo)準(zhǔn)特征 在SMALL模式下參數(shù)傳遞是在內(nèi)部數(shù)據(jù)存貯區(qū)中完成的 LARGE和COMPACT模式允許參數(shù)在外部存貯器中傳遞 C51同時(shí)也支持混合模式 例如在LARGE模式下生成的程序可將一些函數(shù)分頁(yè)放入SMALL模式中從而加快執(zhí)行速度 例如設(shè)C語(yǔ)言源程序?yàn)镻ROR C 若使程序中的變量類型和參數(shù)傳遞區(qū)限定在外部數(shù)據(jù)存貯區(qū) 有兩種方法 方法1 用C51對(duì)PROR C進(jìn)行編譯時(shí) 使用命令C51PROR CCOMPACT 方法2 在程序的第一句加預(yù)處理命令 pragmacompact 表10 5存貯器模式 10 3 3變量說(shuō)明舉例 datacharvar 字符變量var定位在片內(nèi)數(shù)據(jù)存貯區(qū) charcodeMSG PARAMETER 字符數(shù)組MSG 定位在程序存貯區(qū) unsignedlongxdataarray 100 無(wú)符號(hào)長(zhǎng)型數(shù)組定位在片外RAM區(qū) 每元素占4bytes floatidatax y z 實(shí)型變量x y z 定位在片內(nèi)用間址訪問(wèn)的內(nèi)部RAM區(qū) bitlock 位變量Lock定位在片內(nèi)RAM可位尋址區(qū) unsignedintpdatasion 無(wú)符號(hào)整型變量sion定位在分頁(yè)的外部RAM unsignedcharxdatavector 10 4 4 無(wú)符號(hào)字符型三維數(shù)組 定位在片外RAM區(qū) sfrP0 0 x80 定義P0口 地址為80H charbdataflags 字符變量flags定位在可位尋址內(nèi)部RAM區(qū) sbitflag0 flags 0 定義flag0為flags 0 如果在變量說(shuō)明時(shí)略去存貯器類型標(biāo)志符 編譯器會(huì)自動(dòng)選擇默認(rèn)的存貯器類型 默認(rèn)的存貯器類型由控制指令SMALL COMPACT和LARGE限制 例如如果聲明charvar 則默認(rèn)的存貯器模式為SMALL var放在data存貯區(qū) 如果使用COMPACT模式 var放入idata存貯區(qū) 在使用LARGE模式的情況下 var被放入外部數(shù)據(jù)存貯區(qū) xdata存貯區(qū) 10 3 4指針變量說(shuō)明舉例longxdata px 指針px指向long型xdata區(qū) 每個(gè)數(shù)據(jù)占四個(gè)單元 指針自身在默認(rèn)存貯器 如不指定編譯模式在data區(qū) 指針長(zhǎng)度為2個(gè)字節(jié) charxdata datapd 指針pd指向字符型xdata區(qū) 自身在data區(qū) 長(zhǎng)度2字節(jié) datacharxdata pd 與上例等效 dataint pn 和int datapn及intr pn等效 定義一個(gè)類型為int型的通用型指針 指針自身在data區(qū)長(zhǎng)度為3字節(jié) 在上例的指針聲明中包含如下幾個(gè)內(nèi)容 1 1 指針變量名 如px 前面冠以 表示px為指針型變量 此處 不帶取內(nèi)容之意 2 指針指向的存貯類型 即指向哪個(gè)存貯區(qū) 它決定了指針本身的長(zhǎng)度 見表10 1 存貯類型聲明的位置在數(shù)據(jù)類型和指針名 如 px 之間 如無(wú)次項(xiàng)聲明 則此指針型變量為通用型 3 3 指針指向的存貯區(qū)的數(shù)據(jù)類型 即被指向的存貯區(qū)以多少個(gè)單元作一個(gè)數(shù)據(jù)單位 當(dāng)程序通過(guò)指針對(duì)該區(qū)操作時(shí) 將按此規(guī)定的單元個(gè)數(shù)的內(nèi)容作為一個(gè)數(shù)據(jù)操作 4 指針變量自身的存貯類型 即指針處于什么區(qū)與自身的長(zhǎng)度無(wú)關(guān) 該聲明可位于聲明語(yǔ)句的開頭 也可在 和變量名之間 此項(xiàng)由編譯模式放在默認(rèn)區(qū) 如無(wú)規(guī)定編譯模式 通常在data區(qū) 10 4C51對(duì)SFR 可尋址位 存儲(chǔ)器和I O口的定義 10 4 1特殊功能寄存器SFR定義C51提供了一種自主形式的定義方式 使用特定關(guān)鍵字sfr如sfrSCON 0 x98 串行通信控制寄存器地址98H sfrTMOD 0 x89 定時(shí)器模式控制寄存器地址89H sfrACC 0 xe0 A累加器地址E0H sfrP1 0 x90 P1端口地址90H 定義了以后 程序中就可以直接引用寄存器名 C51也建立了一個(gè)頭文件reg51 h 增強(qiáng)型為reg52 h 在該文件中對(duì)所有的特殊功能寄存器的進(jìn)行了sfr定義 對(duì)特殊功能寄存器的有位名稱的可尋址位進(jìn)行了sbit定義 因此 只要用包含語(yǔ)句 include 就可以直接引用特殊功能寄存器名 或直接引用位名稱 要特別注意 在引用時(shí)特殊功能寄存器或者位名稱必須大寫 10 4 2對(duì)位變量的定義 C51對(duì)位變量的定義有三種方法 1 將變量用bit類型的定義符定義為bit類型 如bitmn mn為位變量 其值只能是 0 或 1 其位地址C51自行安排在可位尋址區(qū)的bdata區(qū) 2 采用字節(jié)尋址變量 位的方法 如bdataintibase ibase定義為整型變量 sbitmybit ibase 15 mybit定義為ibase的D15位 這里位是運(yùn)算符 相當(dāng)于匯編中的 其后的最大取值依賴于該位所在的字節(jié)尋址變量的定義類型 如定義為char最大值只能為7 3 對(duì)特殊功能寄存器的位的定義方法1 使用頭文件及sbit定義符 多用于無(wú)位名的可尋址位 例如 includesbitP1 1 P1 1 P1 1為P1口的第1位 sbitac ACC 7 ac定義為累加器A的第7位 方法2 使用頭文件reg51 h 再直接用位名稱 例如 includeRS1 1 RS0 0 方法3 用字節(jié)地址位表示例如sbitOV 0 xD0 2 方法4 用寄存器名 位定義例如sfrPSW 0 xd0 定義PSW地址為d0H sbitCY PSW 7 CY為PSW 7 10 4 3C51對(duì)存貯器和外接I O口的絕對(duì)地址訪問(wèn) 1 對(duì)存貯器的絕對(duì)地址訪問(wèn)利用絕對(duì)地址訪問(wèn)的頭文件absacc h可對(duì)不同的存貯區(qū)進(jìn)行訪問(wèn) 該頭文件的函數(shù)有 CBYTE 訪問(wèn)code區(qū)字符型 DBYTE 訪問(wèn)data區(qū)字符型 PBYTE 訪問(wèn)pdata或I O區(qū)字符型 XBYTE 訪問(wèn)xdata或I O區(qū)字符型 還有CWORD DWORD PWORD和XWORD四個(gè)函數(shù) 它們的訪問(wèn)區(qū)域同上 只是訪問(wèn)的類型為int型 例10 1 include definecomXBYTE 0 x07ff 那么后面程序com變量出現(xiàn)的地方 就是對(duì)地址為07ffH的外部RAM或I O口進(jìn)行訪問(wèn) 例10 2XWORD 0 0 x9988 即將9988H int類型 送入外部RAM的0號(hào)和1號(hào)單元 使用中要注意 absacc h一定要包含進(jìn)程序 XBYTE必須大寫 2 對(duì)外部I O口的訪問(wèn)由于單片機(jī)的I O口和外部RAM統(tǒng)一編址 因此對(duì)I O口地址的訪問(wèn)可用XBYTE MOVX DPTR 或PBYTE MOVX Ri 進(jìn)行 例10 3XBYTE 0Xefff 0 x10 將10H輸出到地址為EFFFH端口 10 5C51的運(yùn)算符 1 賦值運(yùn)算符 將 的右邊的值賦值給左邊的變量 2 C51的算術(shù)運(yùn)算符 加或正號(hào) 減或負(fù)號(hào) 乘號(hào) 除號(hào) 求余 優(yōu)先級(jí)為 先乘除 后加減 先括號(hào)內(nèi) 再括號(hào)外3 C51的關(guān)系運(yùn)算符有六種 小于 大于 小于等于 大于等于 相等 不相等 優(yōu)先級(jí) 前四個(gè)高 后二個(gè) 和 級(jí)別低 4 C51的邏輯運(yùn)算符有三種 邏輯表達(dá)式和關(guān)系表達(dá)式的值相同 以0代表假 以1代表真 以上三種運(yùn)算的優(yōu)先級(jí)見圖10 1 5 C51的按位操作的運(yùn)算符有六種 按位與 按位或 按位異或 位取反 位右移 注 補(bǔ)零移位 例1 a 0 xf0H 表達(dá)式a a值為0FH例2 a 0 xea 表達(dá)式a 2值為A8H 即a值左移兩位 移位后空白位補(bǔ)0 6 自增 自減運(yùn)算符 i i 在使用i之前 先使i值加1 減1 i i 在使用i之后 再使i值加1 減1 例設(shè)i原值為5j i則j值為6 i值也為6j i 則j值為5 i值為6 非 算術(shù)運(yùn)算 關(guān)系運(yùn)算 和 賦值運(yùn)算 圖10 1運(yùn)算符的優(yōu)先級(jí) 7 復(fù)合賦值運(yùn)算符 例 a b相當(dāng)于a a b a 7 相當(dāng)于a a 7 8 對(duì)指針操作的運(yùn)算符 取地址運(yùn)算 間址運(yùn)算符例a b 取b變量的地址送變量ac b 將以b的內(nèi)容為地址的單元的內(nèi)容送c這里要注意 與按位與運(yùn)算符的差別 如果 為 與 的兩邊必須為變量或常量 與指針定義時(shí)指針前的 的差別 如char pt 這里的 只表示pt為指針變量 不代表間址取內(nèi)容的運(yùn)算 10 6函數(shù) C語(yǔ)言程序由函數(shù)組成 下面介紹函數(shù)的要點(diǎn) 10 6 1函數(shù)的分類及定義從用戶使用角度劃分 函數(shù)分為庫(kù)函數(shù)和用戶自定義函數(shù) 庫(kù)函數(shù)是編譯系統(tǒng)為用戶設(shè)計(jì)的一系列標(biāo)準(zhǔn)函數(shù) 見本書附錄二 用戶只需調(diào)用 而無(wú)需自己去編寫這些復(fù)雜的函數(shù) 如前面所用到的頭文件reg51 h absacc h等 有的頭文件中包括一系列函數(shù) 要使用其中的函數(shù)必須先使用 include包含語(yǔ)句 然后才能調(diào)用 用戶自定義函數(shù)是用戶根據(jù)任務(wù)編寫的函數(shù)從參數(shù)形式上函數(shù)分為無(wú)參函數(shù)和有參函數(shù) 有參函數(shù)即是在在調(diào)用時(shí) 調(diào)用函數(shù)用實(shí)際參數(shù)代替形式參數(shù) 調(diào)用完返回結(jié)果給調(diào)用函數(shù) 10 6 2函數(shù)的定義 函數(shù)以 開始 以 結(jié)束 無(wú)參函數(shù)的定義 返回值類型函數(shù)名 函數(shù)體語(yǔ)句 如果函數(shù)沒有返回值 可以將返回值類型設(shè)為void 有參函數(shù)的定義 返回值類型函數(shù)名 形式參數(shù)表列 形式參數(shù)類型說(shuō)明 函數(shù)體語(yǔ)句return 返回形參名 也可以這樣定義返回值類型函數(shù)名 類型說(shuō)明形式參數(shù)表列 函數(shù)體語(yǔ)句return 返回參形名 其中形式參數(shù)表列的各項(xiàng)要用 隔開 通過(guò)return語(yǔ)句將需返回的值返回給調(diào)用函數(shù) 10 6 3函數(shù)的調(diào)用 函數(shù)調(diào)用的形式為 函數(shù)名 實(shí)際參數(shù)表列 實(shí)參和形參的數(shù)目相等類型一致 對(duì)于無(wú)參函數(shù)當(dāng)然不存在實(shí)際參數(shù)表列 函數(shù)的調(diào)用方式有三種 函數(shù)調(diào)用語(yǔ)句 即把被調(diào)函數(shù)名作為調(diào)用函數(shù)的一個(gè)語(yǔ)句 如fun1 被調(diào)函數(shù)作為表達(dá)式的運(yùn)算對(duì)象 如result 2 get a b 此時(shí)get函數(shù)中的a b應(yīng)為實(shí)參 其以返回值參予式中的運(yùn)算 被調(diào)函數(shù)作為另一個(gè)數(shù)的實(shí)際參數(shù)如m max a get a b 函數(shù)get a b 作為函數(shù)max 的一個(gè)實(shí)際參數(shù) 10 6 4對(duì)被調(diào)函數(shù)的說(shuō)明 如果被調(diào)函數(shù)出現(xiàn)在主調(diào)函數(shù)之后 在主調(diào)函數(shù)前應(yīng)對(duì)被調(diào)函數(shù)作以說(shuō)明 形式為 返回值類型被調(diào)函數(shù)名 形參表列 如果被調(diào)函數(shù)出現(xiàn)在主調(diào)函數(shù)之前 可以不對(duì)被調(diào)函數(shù)說(shuō)明 下面以一個(gè)簡(jiǎn)單例子來(lái)說(shuō)明intfun1 a b inta b intc c a b return c main intd 0u 3 v 2 d 2 fun u v 上例被調(diào)函數(shù)在主調(diào)函數(shù)前 不用說(shuō)明 intfun1 a b main intd u 3 v 2 d 2 fun1 u v intfun1 a b inta b intc c a b return c 上例中被調(diào)函數(shù)在主調(diào)函數(shù)后 在前面對(duì)被調(diào)函數(shù)進(jìn)行說(shuō)明 10 7C語(yǔ)言編程實(shí)例 為了使C語(yǔ)言的編程方法和匯編語(yǔ)言的編程方法有一個(gè)對(duì)比 本節(jié)采用3 1節(jié)的例題 由于C51編譯器是針對(duì)單片機(jī)的 因此ANSIC中的scanf和printf等對(duì)PC電腦的鍵盤和監(jiān)視器的輸入 輸出語(yǔ)句無(wú)效 運(yùn)算的數(shù)據(jù)可以通過(guò)變量置入或取出 這時(shí)C51會(huì)自動(dòng)安排使用的存貯單元 當(dāng)然也可以用戶自行通過(guò)具體的內(nèi)存地址置入數(shù)據(jù)或從特定地址取出數(shù)據(jù) 這就少不了要會(huì)觀察具體地址的內(nèi)容或改變?cè)摰刂返膬?nèi)容 C語(yǔ)言的編程上機(jī)調(diào)試見本教材的實(shí)驗(yàn)部分 下面通過(guò)一個(gè)例子說(shuō)明C語(yǔ)言程序編譯后生成的機(jī)器代碼及對(duì)應(yīng)的反匯編程序 從中引出一些道理 10 7 1順序程序的設(shè)計(jì) 例10 5完成19805 24503的編程分析 兩個(gè)乘數(shù)比較大 其積更大 采用unsignedlong類型 設(shè)乘積存放在外部數(shù)據(jù)存貯器0號(hào)開始的單元 程序如下 main unsignedlongxdata p 設(shè)定指針p指向類型為unsignedlong的外部RAM區(qū) unsignedlonga 19805 設(shè)置a為unsignedlong類型 并賦初值 unsignedlongb 24503 c 設(shè)置b和積為unsignedlong類型 并賦初值 p 0 設(shè)地址指向0號(hào)單元 c a b p c 積存入外部RAM0號(hào)單元 上機(jī)通過(guò)WAVE軟件仿真調(diào)試 在變量觀察窗口看到運(yùn)算結(jié)果c 48528195 即為乘積的十進(jìn)制數(shù) 觀察XDATA區(qū) 外部RAM 的0000H 0003H單元分別為1CECD07B 即存放的為乘積的十六進(jìn)制數(shù) 觀察DATA區(qū) 內(nèi)部RAM區(qū) 地址0405060708090A0B0C0D0E0F1CECD07B00004D5D00005FB7C變量 積 a變量b變量可見定義為unsignedlong類型 給每個(gè)變量分配四個(gè)單元 如果定義類型不對(duì) 將得不到正確的結(jié)果 對(duì)于復(fù)雜的運(yùn)算通常采用查表的方法 如同匯編程序設(shè)計(jì)一樣 在程序存貯器建立一張表 在C語(yǔ)言中表格定義為數(shù)組 表內(nèi)數(shù)據(jù) 元素 的偏移量表現(xiàn)為下標(biāo) 數(shù)組的使用如同變量一樣 要先進(jìn)行定義 說(shuō)明數(shù)組名 維數(shù) 數(shù)據(jù)類型和存貯類型 在定義數(shù)組的同時(shí) 還可以給數(shù)組各元素賦初值 通過(guò)下例說(shuō)明C51數(shù)組的定義方法和用C語(yǔ)言編查表程序的方法 例10 6片內(nèi)RAM20H單元存放著一個(gè)0 05H的數(shù) 用查表法 求出該數(shù)的平方值放入內(nèi)部RAM21H單元 main charx pcharcodetab 6 0 1 4 9 16 25 p 0 x20 x tab p p p x 10 7 2循環(huán)程序的設(shè)計(jì) C語(yǔ)言的循環(huán)語(yǔ)句有以下幾種形式1 while 表達(dá)式 語(yǔ)句 其中表達(dá)式為循環(huán)條件 語(yǔ)句為循環(huán)體 當(dāng)表達(dá)式值為真 值為非0 重復(fù)執(zhí)行 語(yǔ)句 語(yǔ)句可只一條以 結(jié)尾 可以多條組成復(fù)合語(yǔ)句 復(fù)合語(yǔ)句必須用 括起 也可以沒有語(yǔ)句 通常用于等待中斷 或查詢 2 do 語(yǔ)句 while 表達(dá)式 表達(dá)式為真執(zhí)行循環(huán)體 語(yǔ)句 直至表達(dá)式為假 退出循環(huán)執(zhí)行下一個(gè)語(yǔ)句 3 for 表達(dá)式1 表達(dá)式2 表達(dá)式3 語(yǔ)句 其中語(yǔ)句為循環(huán)體 執(zhí)行過(guò)程是 執(zhí)行表達(dá)式1后進(jìn)入循環(huán)體 如表達(dá)式2為假 按表達(dá)式3修改變量 再執(zhí)行循環(huán)體 直到表達(dá)式2為真 語(yǔ)句中的表達(dá)式可以省其中任一項(xiàng)甚至全部 但二個(gè)分號(hào)不可省 如for 語(yǔ)句 為無(wú)限循環(huán) for i 4 i 語(yǔ)句 i從4開始無(wú)限循環(huán) for i 100 相當(dāng)于while i 100 例10 7while P1 本程序完成0 1 2 10的累加 執(zhí)行后sum 55 例10 9將例10 8改用for語(yǔ)句編程main intsum 0 i for i 0 i 10 i sun i 10 7 3分支程序的設(shè)計(jì) C語(yǔ)言的分支選擇語(yǔ)句有以下幾種形式 1 if 表達(dá)式 語(yǔ)句 句中表達(dá)式為真執(zhí)行語(yǔ)句 否則執(zhí)行下一條語(yǔ)句 當(dāng)花括號(hào)中的語(yǔ)句不只一條 花括號(hào)不能省 2 if 表達(dá)式 語(yǔ)句1 else 語(yǔ)句2 句中表達(dá)式為真執(zhí)行語(yǔ)句1 否則執(zhí)行語(yǔ)句2為了能無(wú)論哪種情況 執(zhí)行完后都執(zhí)行下一條語(yǔ)句 if語(yǔ)句可以嵌套 3 switch 表達(dá)式 case常量表達(dá)式1 語(yǔ)句1 break case常量表達(dá)式2 語(yǔ)句2 break case常量表達(dá)式n 語(yǔ)句n break default 語(yǔ)句n 1 說(shuō)明 語(yǔ)句先進(jìn)行表達(dá)式的運(yùn)算 當(dāng)表達(dá)式的值與某一case后面的常量表達(dá)式相等 就執(zhí)行它后面的語(yǔ)句 當(dāng)case語(yǔ)句后有break語(yǔ)句時(shí) 執(zhí)行完這一case語(yǔ)句后 跳出switch語(yǔ)句 當(dāng)case后面無(wú)break語(yǔ)句 程序?qū)?zhí)行下一條case語(yǔ)句 如果case中常量表達(dá)式值和表達(dá)式的值都不匹配 就執(zhí)行default后面的語(yǔ)句 如果無(wú)default語(yǔ)句就退出switch語(yǔ)句 default的次序不影響執(zhí)行的結(jié)果 也可無(wú)此語(yǔ)句 case語(yǔ)句適于多分支轉(zhuǎn)移的情況下使用 例10 10片內(nèi)RAM的20H單元存放一個(gè)有符號(hào)數(shù)x 函數(shù)y與x有如下關(guān)系式 xx 0y 20Hx 0 x 5x 0設(shè)y存放于21H單元 程序如下main charx p y p 0 x20 y 0 x21 for x p if x 0 y x if x 0 y x 5 if x 0 y 0 x20 程序中為觀察不同數(shù)的執(zhí)行結(jié)果 采用了死循環(huán)語(yǔ)句for 上機(jī)調(diào)試時(shí)退出死循環(huán)可用Ctrl C 例10 11有兩個(gè)數(shù)a和b 根據(jù)R3的內(nèi)容轉(zhuǎn)向不同的處理子程序 r3 0 執(zhí)行子程序pr0 完成兩數(shù)相加 r3 1 執(zhí)行子程序pr1 完成兩數(shù)相減 r3 2 執(zhí)行子程序pr2 完成兩數(shù)相乘 r3 3 執(zhí)行子程序pr3 完成兩數(shù)相除 分析 C語(yǔ)言中的子程序即為函數(shù) 因此需編四個(gè)處理的函數(shù) 如果主函數(shù)在前 主函數(shù)要對(duì)子函數(shù)進(jìn)行說(shuō)明 如果子函數(shù)在前 主函數(shù)無(wú)須對(duì)子函數(shù)說(shuō)明 但是無(wú)論子 主函數(shù)的順序如何 程序總是從主函數(shù)開始執(zhí)行 執(zhí)行到調(diào)用子函數(shù)就會(huì)轉(zhuǎn)到子函數(shù)執(zhí)行 在C51編譯器中通過(guò)頭文件reg51 h可以識(shí)別特殊功能寄存器 但不能識(shí)別R0 R7通用寄存器 因此R0 R7只有通過(guò)絕對(duì)地址訪問(wèn)識(shí)別 程序如下 include definer3DBYTE 0 x03 intc c1 a b pr0 c a b pr1 c a b pr2 c a b pr3 c a b main a 90 b 30 for switch r3 case0 pr0 break case1 pr1 break case2 pr2 break case3 pr3 break c1 56 在上述程序中 為便于調(diào)試觀察 加了C1 56語(yǔ)句 并使用了死循環(huán)語(yǔ)句for 用Ctrl C可退出死循環(huán) 10 8單片機(jī)資源的C語(yǔ)言編程實(shí)例 例10 12在3 1節(jié)曾用匯編語(yǔ)言完成了外部RAM的000EH單元和000FH單元的內(nèi)容交換 現(xiàn)改用C語(yǔ)言編程 C語(yǔ)言對(duì)地址的指示方法可以采用指針變量 也可以引用absacc h頭文件作絕對(duì)地址訪問(wèn) 下面采用絕對(duì)地址訪問(wèn)方法 includemain charc for c XBYTE 14 XBYTE 14 XBYTE 15 XBYTE 15 c 程序中為方便反復(fù)觀察 使用了死循環(huán)語(yǔ)句for 只要用Ctrl C即可退出死循環(huán) 上面程序通過(guò)編譯 生成的機(jī)器代碼和反匯編程序如下 0000020014LJMP0014H000390000EMOVDPTR 000EH0006E0MOVXA DPTR0007FFMOVR7 A0008A3INCDPTR0009E0MOVXA DPTR000A90000EMOVDPTR 000EH000DF0MOVX DPTR A000EA3INCDPTR000FEFMOVA R70010F0MOVX DPTR A 001180F0SJMP0003H001322RET0014787FMOVR0 7FH0016E4CLRA0017F6MOV R0 A0018D8FDDJNZR0 0017H001A758107MOVSP 07H001D020003LJMP0003H 例中可見 一進(jìn)入C語(yǔ)言程序 首先執(zhí)行初始化 將內(nèi)部RAM的0 7FH128個(gè)單元清零 然后置SP為07H 視變量多少不同 SP置不同值 依程序而定 因此如果要對(duì)內(nèi)部RAM置初值 一定要在執(zhí)行了一條C語(yǔ)言語(yǔ)句后進(jìn)行 C語(yǔ)言程序設(shè)定的變量 C51自行安排寄存器或存貯器作參數(shù)傳遞區(qū) 通常在R0 R7 一組或兩組 視參數(shù)多少定 因此 如果對(duì)具體地址置數(shù)據(jù) 應(yīng)避開這些R0 R7的地址 如果不特別指定變量的存貯類型 通常被安排在內(nèi)部RAM中 10 8 2并行口及鍵盤的C語(yǔ)言編程 例10 13用P1 0輸出1KHz和500Hz的音頻信號(hào)驅(qū)動(dòng)揚(yáng)聲器 作報(bào)警信號(hào) 要求1KHz信號(hào)響100ms 500Hz信號(hào)響200ms 交替進(jìn)行 P1 7接一開關(guān)進(jìn)行控制 當(dāng)開關(guān)合上 響報(bào)警信號(hào) 當(dāng)開關(guān)斷Kk告警信號(hào)停止 編出程序 分析500Hz信號(hào)周期為2ms 信號(hào)電平為每1ms變反一次 1KHz信號(hào)周期為1ms 信號(hào)電平每500 s變反一次 用C語(yǔ)言編程如下 includesbitP10 P1 0 sbitP17 P1 7 main unsignedchari j while 1 while P17 0 for i 1 i 150 i 控制音響時(shí)間 P10 P10 for j 0 j 50 j 延時(shí)完成信號(hào)gou周期時(shí)間 for i 1 i 100 i 控制音響時(shí)間 P10 P10 for j 0 j 100 j 延時(shí) 完成信號(hào)周期時(shí)間 例10 14在下圖中8XX51接有五個(gè)共陰極數(shù)碼管的動(dòng)態(tài)顯示接口電路 開關(guān)打向位置 1 時(shí) 顯示 12345 字樣 當(dāng)開關(guān)打向 2 時(shí) 顯示 HELLO 字樣 C語(yǔ)言編程程序清單如下 圖10 7接五個(gè)共陰極數(shù)碼管的動(dòng)態(tài)顯示接口 用C語(yǔ)言完成上述功能編程 include defineuintunsignedint deefineucharunsignedcharsbitP17 P1 7 main ucharcodetab1 5 0 x86 0 xdb 0 xcf 0 xe6 0 xed 1 5 的字形碼 因P1 7接的開關(guān) 最高位送的 1 ucharcodetab2 5 0 xf8 0 xf9 0 xb8 0 xb8 0 x bf HELLO 的段碼 1 uchari unitj while 1 p3 0 x011for i 0 i if p17 1 P1 tab1 i elseP1 tab2 i P3 1 for j 0 j 25000 j 例10 15以P1 0 P1 3作輸出線 以P1 4 P1 7作輸入線 如圖4 6所示 C語(yǔ)言編程程序清單如下 include defineucharunsignedchar defineuintunsignedintvoiddlms void ucharkbscan void 函數(shù)說(shuō)明 voidmain void0 ucharkey while 1 key kbscan 鍵盤掃描函數(shù) 返回鍵碼送key保存 dlms voiddlms void 延時(shí) uchari for i 200 i 0 i 圖10 84 4矩陣鍵盤 ucharkbscan void 鍵盤掃描函數(shù) ucharsccode recode P1 0 xf0 P1 0 P1 3發(fā)全0 P1 4 P1 7輸入 if P1 無(wú)鍵按下 返回值為0 10 8 3C51中斷程序的編制 C51使用戶能編寫高效的中斷服務(wù)程序 編譯器在規(guī)定的中斷源的矢量地址中放入無(wú)條件轉(zhuǎn)移指令 使CPU響應(yīng)中斷后自動(dòng)地從矢量地址跳轉(zhuǎn)到中斷服務(wù)程序的實(shí)際地址 而無(wú)需用戶去安排 中斷服務(wù)程序定義為函數(shù) 函數(shù)的完整定義如下 返回值函數(shù)名 參數(shù) 模式 再入 interruptn usingm 其中必選項(xiàng)interruptn表示將函數(shù)聲明為中斷服務(wù)函數(shù) n為中斷源編號(hào) 可以是0 31間的整數(shù) 不允許是帶運(yùn)算符的表達(dá)式 n通常取以下值 0外部中斷0 1定時(shí)器 計(jì)數(shù)器0溢出中斷 2外部中斷1 3定時(shí)器 計(jì)數(shù)器1溢出中斷 4串行口發(fā)送與接收中斷5定時(shí)器 計(jì)數(shù)器2中斷 各可選項(xiàng)的意義如下 usingm定義函數(shù)使用的工作寄存器組 m的取值范圍為0 3 可缺省 它對(duì)目標(biāo)代碼的影響是 函數(shù)入口處將當(dāng)前寄存器保存 使用m指定的寄存器組 函數(shù)退出時(shí)原寄存器組恢復(fù) 選不同的工作寄存器組 可方便實(shí)現(xiàn)寄存器組的現(xiàn)場(chǎng)保護(hù) 再入 屬性關(guān)鍵字reentrant將函數(shù)定義為再入的 在C51中 普通函數(shù) 非再入的 不能遞歸調(diào)用 只有再入函數(shù)才可被遞歸調(diào)用 中斷服務(wù)函數(shù)不允許用于外部函數(shù) 它對(duì)目標(biāo)代碼影響如下 當(dāng)調(diào)用函數(shù)時(shí) SFR中的ACC B DPH DPL和PSW當(dāng)需要時(shí)入棧 如果不使用寄存器組切換 中斷函數(shù)所需的所有工作寄存器Rn都入棧 函數(shù)退出前 所有工作寄存器都出棧 函數(shù)由 RETI 指令終止 下面示例說(shuō)明C語(yǔ)言的編程方法 例10 15對(duì)10 2 3的例10 4 見圖 要求每中斷一次 發(fā)光二極管顯示開關(guān)狀態(tài)用C語(yǔ)言編程 include int0 interrupt0 INT0中斷函數(shù) P1 0 x0f 輸入端先置1 燈滅 P 4 讀入開關(guān)狀態(tài) 并左移四位 使開關(guān)反映在發(fā)光二極管上 main EA 1 開中斷總開關(guān) EX0 1 允許INT0中斷 IT0 1 下降沿產(chǎn)生中斷 while 1 等待中斷 例10 16記錄并顯示中斷次數(shù)用C語(yǔ)言編程 可有兩種編程方法 法1 在主程序中判斷中斷次數(shù) 程序如下 include chari codechartab 16 0 x3f 0 x06 0 x5b 0 x4F 0 x66 0 x6d 0 x7d 0 x07 0 x7f 0 x6f 0 x77 0 x7c 0 x39 0 x5e 0 x79 0 x71 int interrupt2 i 計(jì)中斷次數(shù) P1 tab i 查表 次數(shù)送顯示 main EA 1 EX1 1 IT1 1 ap5 P1 0 x3f 顯示 0 for i 0 i 16 當(dāng)i小于16等待中斷 gotoap5 當(dāng)i 16重復(fù)下一輪16次中斷 法2 在中斷程序中判斷中斷次數(shù) include chari codechartab 16 0 x3f 0 x06 0 x5b 0 x4F 0 x66 0 x6d 0 x7d 0 x07 0 x7f 0 x6f 0 x77 0 x7c 0 x39 0 x5e 0 x79 0 x71 int interrupt1 i if i 16 P1 tab i else i 0 P1 0 x3f main EA 1 EX1 1 IT1 1 P1 0 x3f while 1 等待中斷 10 8 4定時(shí) 計(jì)數(shù)器的C語(yǔ)言編程 例10 17在P1 7端接一個(gè)發(fā)光二極管LED 要求利用定時(shí)控制使LED亮一秒滅一秒周而復(fù)始 設(shè)fosc 6MHz 分析T0定時(shí)100ms初值 100 103 2 50000 即初值為 50000 T1計(jì)數(shù)5個(gè)脈沖工作于方式2 計(jì)數(shù)初值為 5 T0和T1均采用中斷方式 程序如下 include reg51 h sbitP1 0 P1 0 sbitP1 7 P1 7 timer0 interrupt1using1 T0中斷服務(wù)程序 P1 0 P1 0 100ms到P1 0反相 TH0 50000 256 重載計(jì)數(shù)初值 TL0 50000 256 timerl interrupt3using2 T1中斷服務(wù)程序 P1 7 P1 7 1s到 燈改變狀態(tài) main P1 7 0 置燈初始滅 P1 0 1 保證第一次反相便開始計(jì)數(shù) TMOD 0 x61 T0方式1定時(shí) T1方式2計(jì)數(shù) TH0 50000 256 預(yù)置計(jì)數(shù)初值 TL0 50000 256 TH1 5 TL1 5 IP 0 x08 置優(yōu)先級(jí)寄存器 EA 1 ET0 1 ET1 1 開中斷 TR0 1 TR1 1 啟動(dòng)定時(shí) 計(jì)數(shù)器 for 等待中斷 例10 18在內(nèi)部數(shù)據(jù)存貯器20H 3FH單元中共有32個(gè)數(shù)據(jù) 要求采用方式1串行發(fā)送出去 傳送速率為1200波特 設(shè)fosc 12MHZ 方法 T1工作于方式2作波特率發(fā)生器 取SMOD 0 T1的時(shí)間常數(shù)計(jì)算如下 波特率 2SMOD 32 fosc 12 256 x 1200 1 32 12 106 12 256 x x 230 E6H 1 查詢方式編程C語(yǔ)的編程 發(fā)送程序 include main unsingnedchari char p TMOD 0 x20 TH1 0 xe6 TL1 0 xe6 TR1 1 SCON 0 x40 p 0 x20 for i 0 i 32 i SBUF p p while TI TI 0 接收程序 include main unsingnedchari char p TMOD 0 x20 TH1 0 xe6 TL1 0 xe6 TR1 1 SCON 0 x50 p 0 x20 for i 0 i 32 i while RI RI 0 p SBUF p 10 8 6外擴(kuò)并行I O口的C語(yǔ)言編程 例10 19用8155作6位共陰極LED顯示器接口 PB口經(jīng)驅(qū)動(dòng)器7407接LED的段選 PA0 PA5位反相驅(qū)動(dòng)器7406接位選 待顯示字符依次存于dis buf數(shù)組 從右向左順序顯示 8155命令字03 table為段碼表 動(dòng)態(tài)顯示6個(gè)字符 8155和8XX51的接口見圖10 12 圖10 128155和8XX51單片機(jī)的接口電路 各口的地址 A口 7FF1H B口 7FF2HC口 7FF3H命令 狀態(tài)口 7FF0HC語(yǔ)言程序如下 include include defineucharunsignedchar defineCOM8155XBYTE 0 x7ff0 definePA8155XBYTE 0 x7ff1 definePB8155XBYTE 0 x7ff2 definePC8155XBYTE 0 x7ff3 ucharidatadis 6 2 4 6 8 10 12 存放顯示字符2 4 6 8 A C ucharcodetable 18 0 x3f 0 x06 0 x5b 0 x4f 0 x66 0 x6d 0 x7d 0 x07 0 x7f 0 x6f 0 x77 0 x7c 0 x39 0 x5e 0 x79 0 x71 0 x40 0 x00 voiddisplay ucharidata p ucharsel i j COM8155 0 x03 scl 0 x01 送命令字 選最右邊的LED for i 0 i 6 i PB8155 table p PA8155 sel 送段碼和位碼 for j 400 j 0 j 延時(shí) p 地址指針下移位 sel sel 1 左移一位 main display dis 5 10 8 7D A的C語(yǔ)言編程 單級(jí)緩沖工作方式下的DAC0832與51系列單片機(jī)的接口地址為7FFFH 要求輸出端得到鋸齒波電壓信號(hào)用C語(yǔ)言編程 程序如下 include include defineda0832XBYTE 0X7fff main unsignedchari j while 1 for i 0 i 255 i da0832 i 啟動(dòng)轉(zhuǎn)換 for j 0 j 255 j 延時(shí) 圖10 4鋸齒波電壓信號(hào) 10 9匯編語(yǔ)言和C語(yǔ)言的混合編程 本節(jié)介紹不同的模塊 不同的語(yǔ)言相結(jié)合的編程方法 通常情況下以高級(jí)語(yǔ)言編寫主程序 用匯編語(yǔ)言編與硬件有關(guān)的子程序 高級(jí)語(yǔ)言不同的編譯程序?qū)R編的調(diào)用方法不同 在KEILC51中 是將不同的模塊 包括不同語(yǔ)言的模塊 分別匯編或編譯 再通過(guò)連接生成一個(gè)可執(zhí)行文件 C語(yǔ)言程序調(diào)用匯編語(yǔ)言程序要注意以下幾點(diǎn) 1 被調(diào)函數(shù)要在主函數(shù)中說(shuō)明 在匯編程序中 要使用偽指令使CODE選項(xiàng)有效并聲明為可再定位段類型 并且根據(jù)不同情況對(duì)函數(shù)名作轉(zhuǎn)換 見表10 6 表10 6函數(shù)名的轉(zhuǎn)換 2 對(duì)為其他模塊使用的符號(hào)進(jìn)行PUBLIC聲明 對(duì)外來(lái)符號(hào)進(jìn)行EXTRN聲明 3 要注意參數(shù)的正確傳遞 10 9 1C語(yǔ)言程序和匯編語(yǔ)言程序參數(shù)的傳遞 在混合語(yǔ)言編程中 關(guān)鍵是入口參數(shù)和出口參數(shù)的傳遞 KEILC51編譯器可使用寄存器傳遞參數(shù) 也可以使用固定存貯器或使用堆棧 由于8XX51的堆棧深度有限 因此多用寄存器或存貯器傳遞 用寄存器傳遞最多只能傳遞三個(gè)參數(shù) 選擇固定的寄存器 見表10 7 表10 7參數(shù)傳遞的寄存器選擇 例如funcl inta a 是第一個(gè)參數(shù) 在R6 R7傳遞 func2 intb intc int d b 在R6 R7中傳遞 c 在R4 R5中傳遞 指針變量 d 在R1 R2 R3中傳遞 如果傳遞參數(shù)寄存器不夠用 可以使用存貯器傳送 通過(guò)指針取得參數(shù) 匯編語(yǔ)言通過(guò)寄存器或存貯器傳遞參數(shù)給C語(yǔ)言程序 匯編語(yǔ)言通過(guò)寄存器傳遞給C語(yǔ)言的返回值見表10 8 表10 8匯編語(yǔ)言通過(guò)寄存器傳遞給C語(yǔ)言的返回值 下面通過(guò)實(shí)例說(shuō)明混合編程的方法及參數(shù)傳遞過(guò)程 10 9 2C語(yǔ)言程序調(diào)用匯編語(yǔ)言程序舉例 例1 用P1 0產(chǎn)生周期為4ms的方波 同時(shí)用P1 1產(chǎn)生周期為8ms的方波 說(shuō)明 用C語(yǔ)言編寫主程序 使P1 1產(chǎn)生周期為8ms的方波為模塊一 P1 0產(chǎn)生周期為4ms的方波為模塊二 用匯編語(yǔ)言編寫的延時(shí)1ms程序?yàn)槟K三 模塊一調(diào)用模塊二獲得8ms方波 模塊二調(diào)模塊三時(shí)向匯編程序傳遞了字符型參數(shù) x 2 延時(shí)2ms 程序如下 C語(yǔ)言程序模塊一 include defineucharunsignedchar sbitP1 1 P1 1 voiddelay4ms void 定義延時(shí)4ms函數(shù) 模塊二 main uchari for P1 1 0 delay4ms 調(diào)模塊二延時(shí)4ms P1 1 1 delay4ms 調(diào)模塊二延時(shí)4ms 模塊二 include defineucharunsignedchar sbitP1 0 P1 0 delaylms ucharx 定義延時(shí)1ms函數(shù) 模塊三 voiddelay4ms void P1 0 0 delaylms 2 調(diào)匯編函數(shù) 模塊三 P1 0 1 delaylms 2 調(diào)匯編函數(shù) 模塊三 模塊三 PUBLIC DELAY1MS DELAY1MS為其他模塊調(diào)用 DESEGMENTCODE 定義DE段為再定位程序段 RSEGDE 選擇DE為當(dāng)前段 DELAY1MS NOP DELA MOVR1 0F8H 延時(shí) LOP1 NOPNOPDJNZR1 LOP1 DJNZR7 DELA R7為C程序傳遞過(guò)來(lái)的參數(shù) EXIT RET END 上例可見匯編語(yǔ)言程序從R7中獲取參數(shù) x 2 模塊編譯連接方法以上各模塊可以先分別匯編或編譯 選擇DEBUG編譯控制項(xiàng) 生成各自的 OBJ文件 然后運(yùn)行L51將各OBJ文件連接 生成一個(gè)新的文件 在集成環(huán)境下的連接調(diào)試可以連續(xù)進(jìn)行 比上面方法更為方便 現(xiàn)使用wave 偉福 的仿真軟件的編譯連接步驟如下 1 編輯好各個(gè)模塊 保存 2 點(diǎn)擊文件 新建項(xiàng)目 彈出項(xiàng)目窗口 3 點(diǎn)擊項(xiàng)目菜單 選加入模塊 此時(shí)彈出有文件目錄的對(duì)話框 選中要加入剛才編輯好的文件 模塊 并打開 此時(shí)在項(xiàng)目窗口中可以看到加入的模塊文件 4 點(diǎn)擊項(xiàng)目菜單中的全部編輯 并取名保存項(xiàng)目 于是系統(tǒng)對(duì)加入各模塊進(jìn)行編譯 并進(jìn)行連接 5 編譯連接完成會(huì)彈出信息窗口 如編譯連接有錯(cuò) 信息窗口將出現(xiàn)錯(cuò)誤信息 6 模塊連接成功 生成二進(jìn)制文件 BIN 和十六進(jìn)制文件 HEX 7 點(diǎn)擊跟蹤或單步按鈕 就可對(duì)程序進(jìn)行跟蹤調(diào)試 程序運(yùn)行到不同模塊時(shí) wave就會(huì)彈出相應(yīng)的模塊源程序窗口 顯示程序運(yùn)行情況 例2 在匯編程序中比較兩數(shù)大小 將大數(shù)放到指定的存儲(chǔ)區(qū) 由C程序的主調(diào)函數(shù)取出模塊一 C語(yǔ)言程序 defineucharunsignedchar voidmax uchara ucharb 定義匯編函數(shù) main uchara 5 b 35 c d c 0 x30 c指針變量指向內(nèi)部RAM30H單元 max a b 調(diào)匯編函數(shù) a b為傳遞的參數(shù) d c d存放模塊二傳遞過(guò)來(lái)的參數(shù) 模塊二 匯編語(yǔ)言程序PUBLIC MAXMAX為其他模塊調(diào) DESEGMENTCODE 定義DE段為再定位程序段 RSEGDE 選擇DE為當(dāng)前段 MAX MOVA R7 取模塊一的參數(shù)a MOV30H R5 取模塊一的參數(shù)b CJNEA 30H TAG1 比較a b的大小 TAG1 JCEXIT MOV30H R7 大數(shù)存于30H單元 EXIT RET END 此例中 C語(yǔ)言程序通過(guò)R7和R5傳遞字符型參數(shù)a和b到匯編語(yǔ)言程序 匯編語(yǔ)言程序?qū)⒎祷刂捣旁诠潭ù尜A單元 主調(diào)函數(shù)通過(guò)指針取出返回值 10 9 3C和匯編混合編程傳遞的參數(shù)多于三個(gè)的編程方法 C語(yǔ)言程序調(diào)用匯編程序最多只能傳遞三個(gè)參數(shù) 如果多于三個(gè)參數(shù) 就需要通過(guò)存貯區(qū)傳遞 可以通過(guò)數(shù)組 也可以在匯編程序中建立數(shù)據(jù)段 下面例中C語(yǔ)言程序向匯編傳遞的參數(shù)多于三個(gè)的編程方法例3A D采用查詢方式采樣50個(gè)數(shù)據(jù) A D地址為7FF8H 將其求平均并送數(shù)碼管顯示 分析8位A D最大值255 用三個(gè)數(shù)碼管顯示 以P3 4為查詢位 電路設(shè)計(jì)如圖 以匯編編A D轉(zhuǎn)換程序 采集50個(gè)數(shù)據(jù) 以C編求平均值 變十進(jìn)制顯示 程序如下 圖例3電路 include defineuintunsignedint defineucharunsignedcharexternvoidcallasm uchar 定義外部匯編函數(shù) externvoiddayl uint 定義外部匯編函數(shù)dayl voidmain void uinti j m total 0 ucharidatabuf 50 dis 3 ucharcodetab 16 0 x3f 0 x06 0 x5b 0 x4f 0 x66 0 x6d 0 x7d 0 x07 0 x7f 0 x6f 0 x77 0 x7c 0 x39 0 x5e 0 x79 0 x71 段碼表 P1 0 xf8 while 1 total 1 callasm buf 調(diào)匯編函數(shù) 傳遞參數(shù)為數(shù)組首址 for i 50 i 0 i 匯編函數(shù)執(zhí)行完后返回于此 total buf i 1 50個(gè)數(shù)累加 total total 50 求平均 dis 0 total 10 求個(gè)位 并存入顯示緩沖區(qū) total total 10 dis 1 total 10 求十位 并存入顯示緩沖區(qū) dis 2 total 10 求百位 并存入顯示緩沖區(qū) P3 0 x01 P3口位選 for m 0 m 50 m for i 0 i 3 i 顯示 P1 tab dis i dayl 50 調(diào)匯編函數(shù)DAYL 延時(shí) P3 1 匯編語(yǔ)言程序CALLASM ASM 完成50個(gè)數(shù)據(jù)采集并存于BUF為首址的單元 PUBLIC CALLASM 公共符號(hào)定義DFFESEGMENTCODE DFFE定為可再定位段RSEGDFFE DFFE為當(dāng)前段 CALLASM PUSH07HPUSH00H 保護(hù)變量 因在下述程序中要用R7和R0MOVA R7 取BUF地址MOVR0 A R0指示存放地址MOVR7 50MOVDPTR 7FF8H DPTR指向A D地址AGA MOVA 0 MOVX DPTR A 啟動(dòng)轉(zhuǎn)換JBP3 4 等待轉(zhuǎn)換結(jié)束MOVXA DPTR 讀轉(zhuǎn)換數(shù)據(jù)MOV R0 A 存入BUF數(shù)組INCR0DJNZR7 AGAPOP00HPOP07H 恢復(fù)BUF地址RETEND 匯編語(yǔ)言程序DAYL ASM 延時(shí)PUBLIC DAYL 公共符號(hào)定義DTESEGMENTCODE 定義DTE段為再定位程序段 RSEGDTE 選擇DTE為當(dāng)前段 DAYL NOP DELA MOVR1 0F8H 延時(shí) LOP1 NOPNOPDJNZR1 LOP1 DJNZR7 DELA R7為C程序傳遞過(guò)來(lái)的參數(shù) EXIT RET END 10 10C語(yǔ)言函數(shù)庫(kù)的管理與使用 C語(yǔ)言作為一種高級(jí)編程語(yǔ)言 其主要的優(yōu)勢(shì)之一就是有大量的豐富的庫(kù)函數(shù)可直接使用 而庫(kù)函數(shù)的使用是解決程序共享和提高編程效率的最有效的途徑之一 函數(shù)庫(kù)是具有目標(biāo)代碼形式的函數(shù)的集合 雖然在許多方面 庫(kù)就像一個(gè)獨(dú)立編譯的模塊 但它有一個(gè)不同于目標(biāo)文件的特別之處 當(dāng)某個(gè)獨(dú)立編譯的目標(biāo)文件與其它文件連接時(shí) 所有該目標(biāo)文件中的函數(shù) 無(wú)論它們是否真正被程序所用 都成為可執(zhí)行的一部分 而當(dāng)一個(gè)庫(kù)文件與其它文件連接時(shí) 可執(zhí)行程序中只包含那些真正由程序所用的庫(kù)函數(shù) 例如 C51標(biāo)準(zhǔn)庫(kù)中包含很多函數(shù) 而你的程序只包含真正由你的程序所調(diào)用的函數(shù) 10 10 1庫(kù)函數(shù)的編寫庫(kù)函數(shù)的編寫同普通的函數(shù)編寫的方法一樣 需要主要的幾點(diǎn)是 庫(kù)函數(shù)命名時(shí) 不能用主函數(shù)名或C51已有的庫(kù)函數(shù)名 需要改寫C51提供的函數(shù)庫(kù)例外 在采用RTOS時(shí) 多要求系統(tǒng)調(diào)用的函數(shù)為可重入函數(shù) 因此若要編寫可重入的函數(shù) 則需按照可重入函數(shù)的編寫規(guī)則編寫即可 C51的函數(shù)庫(kù)是分存儲(chǔ)模式的 因此 在編寫庫(kù)函數(shù)是一定要注意區(qū)分C51的存儲(chǔ)模式 不同模式下編譯出來(lái)的庫(kù)函數(shù)一般是不能混用的 某些特殊的庫(kù)函數(shù)程序可以采用匯編編寫 而在C51中調(diào)用即可 編輯好庫(kù)函數(shù)對(duì)應(yīng)的頭文件 以便用戶引用 保存好庫(kù)函數(shù)的源程序代碼 以供維護(hù)升級(jí)時(shí)使用 一個(gè)簡(jiǎn)單的加法例子如下所示 includeintadd inta intb ints s a b return s 10 10 2函數(shù)庫(kù)的管理 未經(jīng)特殊說(shuō)明 我們這里的主要討論是針對(duì)小存儲(chǔ)模式的情形 在談函數(shù)庫(kù)管理前 先要獲得在小模式下編譯通過(guò)的二進(jìn)制代碼 常用的函數(shù)庫(kù)管理命令有創(chuàng)建庫(kù)文件 在庫(kù)文件中添加模塊 刪除模塊和替換模塊等 下面分別介紹之 C51庫(kù)管理的執(zhí)行程序?yàn)閘ib51 exe 位于其安裝路徑下bin子目錄中 lib51的操作有兩種 一是運(yùn)行l(wèi)ib51程序 進(jìn)入庫(kù)管理控制臺(tái) 鍵入help 便可顯示所有的操作控制臺(tái)命令 如下圖所示 另一種就是直接以命令行方式一次實(shí)現(xiàn) 這種方式使用靈活 既可以做成批處理一次自動(dòng)完成一批庫(kù)管理的操作 又可以與功能強(qiáng)大的文- 1.請(qǐng)仔細(xì)閱讀文檔,確保文檔完整性,對(duì)于不預(yù)覽、不比對(duì)內(nèi)容而直接下載帶來(lái)的問(wèn)題本站不予受理。
- 2.下載的文檔,不會(huì)出現(xiàn)我們的網(wǎng)址水印。
- 3、該文檔所得收入(下載+內(nèi)容+預(yù)覽)歸上傳者、原創(chuàng)作者;如果您是本文檔原作者,請(qǐng)點(diǎn)此認(rèn)領(lǐng)!既往收益都?xì)w您。
下載文檔到電腦,查找使用更方便
14.9 積分
下載 |
- 配套講稿:
如PPT文件的首頁(yè)顯示word圖標(biāo),表示該P(yáng)PT已包含配套word講稿。雙擊word圖標(biāo)可打開word文檔。
- 特殊限制:
部分文檔作品中含有的國(guó)旗、國(guó)徽等圖片,僅作為作品整體效果示例展示,禁止商用。設(shè)計(jì)者僅對(duì)作品中獨(dú)創(chuàng)性部分享有著作權(quán)。
- 關(guān) 鍵 詞:
- 單片機(jī) 課件 語(yǔ)言 編程
鏈接地址:http://www.hcyjhs8.com/p-6753274.html