2410開(kāi)發(fā)板實(shí)驗(yàn)參考書_第1頁(yè)
2410開(kāi)發(fā)板實(shí)驗(yàn)參考書_第2頁(yè)
2410開(kāi)發(fā)板實(shí)驗(yàn)參考書_第3頁(yè)
2410開(kāi)發(fā)板實(shí)驗(yàn)參考書_第4頁(yè)
2410開(kāi)發(fā)板實(shí)驗(yàn)參考書_第5頁(yè)
已閱讀5頁(yè),還剩274頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

BeijingUniversalPioneeringTechnologyCo.,LTD.PAGE84TEL:010-82110740821107418211074282110743FAX:總機(jī)轉(zhuǎn)828TOC\o"1-2"\h\z\u第一章嵌入式Linux開(kāi)發(fā)基礎(chǔ)知識(shí) 21.1嵌入式Linux簡(jiǎn)介 21.2嵌入式Linux開(kāi)發(fā)平臺(tái)簡(jiǎn)介 41.3嵌入式Linux開(kāi)發(fā)流程 91.4嵌入式Linux開(kāi)發(fā)環(huán)境的建立 11第二章基礎(chǔ)實(shí)驗(yàn) 232.1熟悉Linux開(kāi)發(fā)環(huán)境 232.2多線程應(yīng)用程序設(shè)計(jì) 272.3串行端口程序設(shè)計(jì) 402.4CAN總線通訊實(shí)驗(yàn) 512.5簡(jiǎn)單嵌入式WEB服務(wù)器實(shí)驗(yàn) 64第三章圖形界面應(yīng)用程序設(shè)計(jì) 793.1安裝與建立Qt桌面運(yùn)行環(huán)境 793.2QtDesigner簡(jiǎn)介以及Qt/E的交叉編譯 863.3建立本機(jī)Qtopia虛擬平臺(tái) 943.4Qtopia2.1.1在2410上的移植 99第四章內(nèi)核實(shí)驗(yàn) 1034.1Linux內(nèi)核移植與編譯實(shí)驗(yàn) 103第五章驅(qū)動(dòng)模塊實(shí)驗(yàn) 1305.1內(nèi)核驅(qū)動(dòng)設(shè)計(jì)入門-模塊方式驅(qū)動(dòng)實(shí)驗(yàn) 1305.2內(nèi)核驅(qū)動(dòng)設(shè)計(jì)實(shí)驗(yàn)-觸摸屏驅(qū)動(dòng) 1615.3SD卡使用實(shí)驗(yàn) 1855.4IDE_硬盤讀寫實(shí)驗(yàn) 2115.5音頻驅(qū)動(dòng)及應(yīng)用實(shí)驗(yàn) 2245.6藍(lán)牙無(wú)線通訊實(shí)驗(yàn) 240第六章附錄 2536.1常用LINUX命令的使用 2536.2VI簡(jiǎn)介 2606.3GCC與GDB 2626.4GNU通用公共許可證(GPL1991.6第二版) 2656.5北京博創(chuàng)興業(yè)科技嵌入式系統(tǒng)培訓(xùn)中心 271

第一章嵌入式Linux

開(kāi)發(fā)基礎(chǔ)知識(shí)隨著后PC時(shí)代的到來(lái),嵌入式系統(tǒng)技術(shù)已經(jīng)成為了一個(gè)萬(wàn)眾矚目的焦點(diǎn)。目前已廣泛應(yīng)用于信息家電、數(shù)據(jù)網(wǎng)絡(luò)、工業(yè)控制、醫(yī)療衛(wèi)生、航空航天等眾多領(lǐng)域。巨大的市場(chǎng)潛力,無(wú)窮的商機(jī),吸引了各路英豪紛踵沓來(lái)。硬件方面,各大電子廠商相繼推出了自己的專用嵌入式芯片,漫天而至的是mp3,PDA,無(wú)線上網(wǎng)裝置,讓人們充分感受到了這股強(qiáng)勁之勢(shì);軟件方面,在Vxworks、pSOS、Neculeus和WindowsCE等嵌入式操作系統(tǒng)引領(lǐng)下,也出現(xiàn)了空前繁榮的局面,但這些專用操作系統(tǒng)都是商業(yè)化產(chǎn)品,其高昂的價(jià)格使許多面向低端產(chǎn)品的小公司望而卻步,并且其源代碼的封閉性也大大限制了開(kāi)發(fā)者的積極性。近兩年在我國(guó)登陸并蓬勃發(fā)展的Linux,也已廣泛應(yīng)用于各類計(jì)算應(yīng)用,不僅包括IBM的微型Linux腕表、手持設(shè)備(PDA和蜂窩電話)、因特網(wǎng)裝置、客戶機(jī)、防火墻、工業(yè)機(jī)器人和電話基礎(chǔ)設(shè)施設(shè)備,甚至還包括了基于集群的超級(jí)計(jì)算機(jī)。Linux在高端服務(wù)器的優(yōu)越表現(xiàn)及其天生具有的突出特點(diǎn),就注定它必將在低端嵌入式系統(tǒng)中再次給人們以驚喜,而基于嵌入式Linux操作系統(tǒng)的應(yīng)用,必定給我們未來(lái)的工作和生活帶來(lái)翻天覆地的變化。1.1嵌入式Linux簡(jiǎn)介L(zhǎng)inux正在嵌入式開(kāi)發(fā)領(lǐng)域穩(wěn)步發(fā)展。Linux使用GPL,所有對(duì)特定開(kāi)發(fā)板、PDA、掌上機(jī)、可攜帶設(shè)備等使用嵌入式Linux感興趣的人都可以從因特網(wǎng)上免費(fèi)下載其內(nèi)核和應(yīng)用程序,并開(kāi)始移植和開(kāi)發(fā)。許多Linux改良品種迎合了嵌入式市場(chǎng),它們包括RTLinux(實(shí)時(shí)Linux)、uclinux(用于非MMU設(shè)備的Linux)、MontavistaLinux(用于ARM、MIPS、PPC的Linux分發(fā)版)、ARM-Linux(ARM上的Linux)和其它Linux系統(tǒng)。嵌入式Linux的發(fā)展比較迅速。NEC、索尼已經(jīng)在銷售個(gè)人視頻錄像機(jī)等基于Linux的消費(fèi)類電子產(chǎn)品,摩托羅拉則計(jì)劃在其未來(lái)的大多數(shù)手機(jī)上使用Linux,IBM也制定了在手持機(jī)上運(yùn)行Linux的計(jì)劃。數(shù)年來(lái),“Linux標(biāo)準(zhǔn)庫(kù)”組織一直在從事對(duì)在服務(wù)器上運(yùn)行的Linux進(jìn)行標(biāo)準(zhǔn)化的工作,現(xiàn)在,嵌入式計(jì)算領(lǐng)域也開(kāi)始了這一工作。嵌入式Linux標(biāo)準(zhǔn)吸引了“Linux標(biāo)準(zhǔn)庫(kù)”以及Unix組織中有益的元素。在嵌入式系統(tǒng)中使用Linux的優(yōu)點(diǎn)和缺點(diǎn)雖然大多數(shù)Linux系統(tǒng)運(yùn)行在PC平臺(tái)上,但Linux也是嵌入式系統(tǒng)的可靠主力。Linux的安裝和管理比UNIX更加簡(jiǎn)單靈活,這對(duì)于那些UNIX專家們來(lái)說(shuō)又是一個(gè)優(yōu)點(diǎn),因?yàn)長(zhǎng)inux中有許多命令和編程接口同傳統(tǒng)的UNIX一樣。但是對(duì)于習(xí)慣于WINDOWS操作系統(tǒng)的人來(lái)說(shuō),需要記憶大量的命令行參數(shù)卻是一個(gè)缺點(diǎn)。隨著LINUX社團(tuán)的不斷努力,linux的人機(jī)界面開(kāi)發(fā)環(huán)境正在不斷完善。典型的Linux系統(tǒng)經(jīng)過(guò)打包,在擁有硬盤和大容量?jī)?nèi)存的PC機(jī)上運(yùn)行,嵌入式系統(tǒng)不需要這么高的配置。一個(gè)功能完備的Linux內(nèi)核要求大約1MB內(nèi)存。而Linux微內(nèi)核只占用其中很小一部分內(nèi)存,包括虛擬內(nèi)存和所有核心的操作系統(tǒng)功能在內(nèi),只需占用系統(tǒng)約100K內(nèi)存。只要有500K的內(nèi)存,一個(gè)有網(wǎng)絡(luò)棧和基本實(shí)用程序的完全的Linux系統(tǒng)就可以在一臺(tái)8位總線(SX)的Intel386微處理器上運(yùn)行的很好了。由于內(nèi)存要求常常是需要的應(yīng)用所決定的,比如Web服務(wù)器或者SNMP代理,Linux系統(tǒng)甚至可以僅使用256KBROM和512KBRAM進(jìn)行工作。因此它是一個(gè)瞄準(zhǔn)嵌入式市場(chǎng)的輕量級(jí)操作系統(tǒng)。與傳統(tǒng)的實(shí)時(shí)操作系統(tǒng)相比(RTOS),采用象嵌入式Linux這樣的開(kāi)放源碼的操作系統(tǒng)的另外一個(gè)好處是Linux開(kāi)發(fā)團(tuán)體看來(lái)會(huì)比RTOS的供應(yīng)商更快地支持新的IP協(xié)議和其它協(xié)議。例如,用于Linux的設(shè)備驅(qū)動(dòng)程序要比用于商業(yè)操作系統(tǒng)的設(shè)備驅(qū)動(dòng)程序多,如網(wǎng)絡(luò)接口卡(NIC)驅(qū)動(dòng)程序以及并口和串口驅(qū)動(dòng)程序。核心Linux操作系統(tǒng)本身的微內(nèi)核體系結(jié)構(gòu)相當(dāng)簡(jiǎn)單。網(wǎng)絡(luò)和文件系統(tǒng)以模塊形式置于微內(nèi)核的上層。驅(qū)動(dòng)程序和其它部件可在運(yùn)行時(shí)作為可加載模塊編譯到或者是添加到內(nèi)核。這為構(gòu)造定制的可嵌入系統(tǒng)提供了高度模塊化的構(gòu)件方法。而在典型情況下該系統(tǒng)需結(jié)合定制的驅(qū)動(dòng)程序和應(yīng)用程序以提供附加功能。嵌入式系統(tǒng)也常常要求通用的功能,為了避免重復(fù)勞動(dòng),這些功能的實(shí)現(xiàn)運(yùn)用了許多現(xiàn)成的程序和驅(qū)動(dòng)程序,它們可以用于公共外設(shè)和應(yīng)用。Linux可以在外設(shè)范圍廣泛的多數(shù)微處理器上運(yùn)行,并早已經(jīng)有了現(xiàn)成的應(yīng)用庫(kù)。Linux用于嵌入式的因特網(wǎng)設(shè)備也是很合適的,原因是它支持多處理器系統(tǒng),該特性使Linux具有了伸縮性。因而設(shè)計(jì)人員可以選擇在雙處理器系統(tǒng)上運(yùn)行實(shí)時(shí)應(yīng)用,提高整體的處理能力。例如,您可以在一個(gè)處理器運(yùn)行GUI,同時(shí)在另一個(gè)處理器上運(yùn)行Linux系統(tǒng)。在嵌入式系統(tǒng)上運(yùn)行Linux的一個(gè)缺點(diǎn)是Linux體系提供實(shí)時(shí)性能需要添加實(shí)時(shí)軟件模塊。而這些模塊運(yùn)行的內(nèi)核空間正是操作系統(tǒng)實(shí)現(xiàn)調(diào)度策略、硬件中斷異常和執(zhí)行程序的部分。由于這些實(shí)時(shí)軟件模塊是在內(nèi)核空間運(yùn)行的,因此代碼錯(cuò)誤可能會(huì)破壞操作系統(tǒng)從而影響整個(gè)系統(tǒng)的可靠性,這對(duì)于實(shí)時(shí)應(yīng)用將是一個(gè)非常嚴(yán)重的弱點(diǎn)。已經(jīng)有許多嵌入式Linux系統(tǒng)的示例;可以有把握地說(shuō),某種形式的Linux能在幾乎任一臺(tái)執(zhí)行代碼的計(jì)算機(jī)上運(yùn)行。1.2嵌入式Linux開(kāi)發(fā)平臺(tái)簡(jiǎn)介L(zhǎng)inux價(jià)格低廉、功能強(qiáng)大,可以運(yùn)行在X86,Alpha,Sparc,MIPS,PPC,MOTOROLA,NEC,ARM等硬件平臺(tái)上,而且開(kāi)放源代碼,可以定制。我們所介紹的硬件平臺(tái)是基于ARM體系結(jié)構(gòu),由北京博創(chuàng)興業(yè)科技有限公司開(kāi)發(fā)的UP-NetARM3000和UP-NetARM2410開(kāi)發(fā)板。UP-NetARM3000的CPU為ARM7TDMI內(nèi)核的三星S3C44B0X01芯片,由于沒(méi)有MMU(內(nèi)存管理單元)只能運(yùn)行uClinux,UP-NetARM2410開(kāi)發(fā)板的CPU為ARM920T內(nèi)核的三星S3c2410芯片,由于有MMU可以運(yùn)行標(biāo)準(zhǔn)的ARM-LINUX內(nèi)核。通過(guò)這兩個(gè)平臺(tái),我們可以學(xué)習(xí)嵌入式LINUX中的針對(duì)有MMU和無(wú)MMU的不同開(kāi)發(fā)過(guò)程。UP-NetARM3000及相關(guān)產(chǎn)品的資料可以訪問(wèn)博創(chuàng)公司的網(wǎng)站獲得。本書以UP-NetARM2410開(kāi)發(fā)板為例,詳細(xì)介紹嵌入式Linux的開(kāi)發(fā)過(guò)程。UP-NetARM2410開(kāi)發(fā)板實(shí)驗(yàn)儀器介紹硬件配置UP-NetARM2410開(kāi)發(fā)板的硬件配置如表1.2.1所示,實(shí)物如圖1配置名稱型號(hào)說(shuō)明CPUARM920T結(jié)構(gòu)芯片三星S3c2410X工作頻率203MHzFLASHSAMSUNGK9F120864MSDRAMHY57V561620AT-H32M×2=64MEtherNet網(wǎng)卡DM9000AEP10/100M自適應(yīng)LCD(可選)一個(gè)32腳薄膜線插座觸摸屏(可選)一個(gè)8腳觸摸屏插座FM7843驅(qū)動(dòng)LED兩個(gè)小數(shù)碼管和3個(gè)發(fā)光二極管USB接口1個(gè)HOST/1個(gè)DEVICEUART2個(gè)RS232從處理器的UART2引出AD由S3C2410芯片引出板載兩個(gè)分壓精密電位器AUDIOIIS總線,UDA1341芯片44.1KHz音頻擴(kuò)展插座3個(gè)40PinEXPORT總線直接擴(kuò)展IDE/CF卡接口IDE硬盤接口,CF(IDE模式)卡MMC和SD卡接口調(diào)試接口JTAG14針按鍵三個(gè)可產(chǎn)生中斷的按鍵2片IIC存儲(chǔ)器AT24C01CANBUS由MCP2510和TJA1050構(gòu)成PWM和DA輸出MAX504兩路PWM輸出和DA電路DC5V電源輸入具備LDO產(chǎn)生3.3V和1.8V的電壓備有RESET、RTC電路表1.2.1UP-NetARM2410的硬件配置圖1.2.1UP-NetARM2410S3c2410芯片介紹S3c2410X芯片集成了大量的功能單元,包括:1.內(nèi)部1.8V,存儲(chǔ)器3.3V,外部IO3.3V,16KB數(shù)據(jù)CACH,16KB指令CACH,MMU;2.內(nèi)置外部存儲(chǔ)器控制器(SDRAM控制和芯片選擇邏輯);3.LCD控制器(最高4K色STN和256K彩色TFT),一個(gè)LCD專用DMA;4.4路帶外部請(qǐng)求線的DMA;5.三個(gè)通用異步串行端口(IrDA1.0,16-ByteTxFIFO,and16-ByteRxFIFO),2通道SPI;6.一個(gè)多主IIC總線,一個(gè)IIS總線控制器;7.SD主接口版本1.0和多媒體卡協(xié)議版本2.11兼容;8.2個(gè)USBHOST,一個(gè)USBDEVICE(VER1.1);9.4個(gè)PWM定時(shí)器和一個(gè)內(nèi)部定時(shí)器;10.看門狗定時(shí)器;11.117個(gè)通用IO;12.24個(gè)外部中斷;13.電源控制模式:標(biāo)準(zhǔn)、慢速、休眠、掉電;14.8通道10位ADC和觸摸屏接口;15.帶日歷功能的實(shí)時(shí)時(shí)鐘;16.芯片內(nèi)置PLL;17.設(shè)計(jì)用于手持設(shè)備和通用嵌入式系統(tǒng);18.16/32位RISC體系結(jié)構(gòu),使用ARM920TCPU核的強(qiáng)大指令集;19.ARM帶MMU的先進(jìn)的體系結(jié)構(gòu)支持WINCE、EPOC32、LINUX;20.指令緩存(cache)、數(shù)據(jù)緩存、寫緩沖和物理地址TAGRAM,減小了對(duì)主存儲(chǔ)器帶寬和性能的影響;21.ARM920TCPU核支持ARM調(diào)試的體系結(jié)構(gòu);22.內(nèi)部先進(jìn)的位控制器總線(AMBA2.0,AHB/APB).其結(jié)構(gòu)圖如圖1.2.圖1.2.2S3c2410系統(tǒng)管理:1.小端/大端支持;2.地址空間:每個(gè)BANK128MB(全部1G字節(jié));3.每個(gè)BANK可編程為8/16/32位數(shù)據(jù)總線;4.bank0到bank6為固定起始地址;5.bank7可編程BANK起始地址和大??;6.一共8個(gè)存儲(chǔ)器BANK;7.6個(gè)存儲(chǔ)器BANK用于ROM,SRAM和其他;8.2個(gè)存儲(chǔ)器BANK用于ROM,SRAM和同步DRAM;9.每個(gè)存儲(chǔ)器BANK可編程存取周期;10.支持等待信號(hào)用以擴(kuò)展總線周期;11.支持SDRAM掉電模式下的自刷新;12.支持不同類型的ROM用于啟動(dòng)NOR/NANDFlash,EEPROM和其他。芯片封裝:272-FBGA封裝圖如圖1.2.圖1.2.3272-FBGA封裝1.3嵌入式Linux開(kāi)發(fā)流程嵌入式linux開(kāi)發(fā),根據(jù)應(yīng)用需求的不同有不同的配置開(kāi)發(fā)方法,但是一般都要經(jīng)過(guò)以下過(guò)程:建立開(kāi)發(fā)環(huán)境。操作系統(tǒng)一般使用REDHAT-LINUX,版本7到9都可以,選擇定制安裝或全部安裝,通過(guò)網(wǎng)絡(luò)下載相應(yīng)的GCC交叉編譯器進(jìn)行安裝(比如arm-linux-gcc、arm-uclibc-gcc),或者安裝產(chǎn)品廠家提供的交叉編譯器。配置開(kāi)發(fā)主機(jī)。配置MINICOM,一般參數(shù)為波特率115200,數(shù)據(jù)位8位,停止位1,無(wú)奇偶校驗(yàn),軟硬件控制流設(shè)為無(wú)。在WINDOWS下的超級(jí)終端的配置也是這樣。MINICOM軟件的作用是作為調(diào)試嵌入式開(kāi)發(fā)板信息輸出的監(jiān)視器和鍵盤輸入的工具;配置網(wǎng)絡(luò),主要是配置NFS網(wǎng)絡(luò)文件系統(tǒng),需要關(guān)閉防火墻,簡(jiǎn)化嵌入式網(wǎng)絡(luò)調(diào)試環(huán)境設(shè)置過(guò)程。建立引導(dǎo)裝載程序BOOTLOADER,從網(wǎng)絡(luò)上下載一些公開(kāi)源代碼的BOOTLOADER,如U-BOOT、BLOB、VIVI、LILO、ARM-BOOT、RED-BOOT等,根據(jù)自己具體芯片進(jìn)行移植修改。有些芯片沒(méi)有內(nèi)置引導(dǎo)裝載程序,比如三星的ARM7、ARM9系列芯片,這樣就需要編寫燒寫開(kāi)發(fā)板上flash的燒寫程序,網(wǎng)絡(luò)上有免費(fèi)下載的WINDOWS下通過(guò)JTAG并口簡(jiǎn)易仿真器燒寫ARM外圍flash芯片的程序。也有LINUX下公開(kāi)源代碼的J-FLASH程序。如果不能燒寫自己的開(kāi)發(fā)板,就需要根據(jù)自己的具體電路進(jìn)行源代碼修改。這是讓系統(tǒng)可以正常運(yùn)行的第一步。如果你購(gòu)買了廠家的仿真器當(dāng)然比較容易燒寫flash了,但是其中的核心技術(shù)是無(wú)法了解的。這對(duì)于需要迅速開(kāi)發(fā)應(yīng)用的人來(lái)說(shuō)可以極大地提高開(kāi)發(fā)速度。下載別人已經(jīng)移植好的LINUX操作系統(tǒng),如UCLINUX、ARM-LINUX、PPC-LINUX等,如果有專門針對(duì)你所使用的CPU移植好的LINUX操作系統(tǒng)那是再好不過(guò),下載后再添加自己的特定硬件的驅(qū)動(dòng)程序,進(jìn)行調(diào)試修改,對(duì)于帶MMU的CPU可以使用模塊方式調(diào)試驅(qū)動(dòng),對(duì)于UCLINUX這樣的系統(tǒng)好像只能編譯進(jìn)內(nèi)核進(jìn)行調(diào)試。建立根文件系統(tǒng),從下載使用BUSYBOX軟件進(jìn)行功能裁減,產(chǎn)生一個(gè)最基本的根文件系統(tǒng),再根據(jù)自己的應(yīng)用需要添加其他的程序。默認(rèn)的啟動(dòng)腳本一般都不會(huì)符合應(yīng)用的需要,所以就要修改根文件系統(tǒng)中的啟動(dòng)腳本,它的存放位置位于/etc目錄下,包括:/etc/init.d/rc.S、/etc/profile、/etc/.profile等,自動(dòng)掛裝文件系統(tǒng)的配置文件/etc/fstab,具體情況會(huì)隨系統(tǒng)不同而不同。根文件系統(tǒng)在嵌入式系統(tǒng)中一般設(shè)為只讀,需要使用mkcramfs、genromfs等工具產(chǎn)生燒寫映象文件。建立應(yīng)用程序的flash磁盤分區(qū),一般使用JFFS2或YAFFS文件系統(tǒng),這需要在內(nèi)核中提供這些文件系統(tǒng)的驅(qū)動(dòng),有的系統(tǒng)使用一個(gè)線性flash(NOR型)512K-32M,有的系統(tǒng)使用非線性flash(NAND型)8-512M,有的兩個(gè)同時(shí)使用,需要根據(jù)應(yīng)用規(guī)劃flash的分區(qū)方案。開(kāi)發(fā)應(yīng)用程序,可以下載到根文件系統(tǒng)中,也可以放入YAFFS、JFFS2文件系統(tǒng)中,有的應(yīng)用程序不使用根文件系統(tǒng),而是直接將應(yīng)用程序和內(nèi)核設(shè)計(jì)在一起,這有點(diǎn)類似于UCOS-II的方式。燒寫內(nèi)核、根文件系統(tǒng)、應(yīng)用程序。發(fā)布產(chǎn)品。1.4嵌入式Linux開(kāi)發(fā)環(huán)境的建立嵌入式LINUX開(kāi)發(fā)環(huán)境有幾個(gè)方案:1、基于PC機(jī)WINDOWS操作系統(tǒng)下的CYGWIN;2、在WINDOWS下安裝虛擬機(jī)后,再在虛擬機(jī)中安裝LINXUX操作系統(tǒng);3、直接安裝LINUX操作系統(tǒng)。基于WINDOWS的環(huán)境要么有兼容性問(wèn)題,要么速度有影響,所以推薦大家使用純LINUX操作系統(tǒng)開(kāi)發(fā)環(huán)境。我們實(shí)際的開(kāi)發(fā)環(huán)境為REDHAT9,它已經(jīng)支持中文,并且包含了絕大部分的開(kāi)發(fā)工具,不用擔(dān)心裝了LINUX就不能使用WINDOWS的問(wèn)題。一般的情況都是用戶已經(jīng)有了WINDOWS操作系統(tǒng),再安裝LINUX,LINUX會(huì)自動(dòng)安裝一個(gè)叫作GRUB的啟動(dòng)引導(dǎo)軟件,可以選擇引導(dǎo)多個(gè)操作系統(tǒng)。預(yù)備知識(shí)絕大多數(shù)Linux軟件開(kāi)發(fā)都是以native方式進(jìn)行的,即本機(jī)(HOST)開(kāi)發(fā)、調(diào)試,本機(jī)運(yùn)行的方式。這種方式通常不適合于嵌入式系統(tǒng)的軟件開(kāi)發(fā),因?yàn)閷?duì)于嵌入式系統(tǒng)的開(kāi)發(fā),沒(méi)有足夠的資源在本機(jī)(即板子上系統(tǒng))運(yùn)行開(kāi)發(fā)工具和調(diào)試工具。通常的嵌入式系統(tǒng)的軟件開(kāi)發(fā)采用一種交叉編譯調(diào)試的方式。交叉編譯調(diào)試環(huán)境建立在宿主機(jī)(即一臺(tái)PC機(jī))上,對(duì)應(yīng)的開(kāi)發(fā)板叫做目標(biāo)板。運(yùn)行Linux的PC【宿主機(jī)】開(kāi)發(fā)時(shí)使用宿主機(jī)上的交叉編譯、匯編及連接工具形成可執(zhí)行的二進(jìn)制代碼(這種可執(zhí)行代碼并不能在宿主機(jī)上執(zhí)行,而只能在目標(biāo)板上執(zhí)行),然后把可執(zhí)行文件下載到目標(biāo)機(jī)上運(yùn)行。調(diào)試時(shí)的方法很多,可以使用串口,以太網(wǎng)口等,具體使用哪種調(diào)試方法可以根據(jù)目標(biāo)機(jī)處理器提供的支持作出選擇。宿主機(jī)和目標(biāo)板的處理器一般不相同,宿主機(jī)為Intel處理器,而目標(biāo)板如UP-NetARM2410開(kāi)發(fā)板為三星S3c2410.GNU編譯器提供這樣的功能,在編譯器編譯時(shí)可以選擇開(kāi)發(fā)所需的宿主機(jī)和目標(biāo)機(jī)從而建立開(kāi)發(fā)環(huán)境。所以在進(jìn)行嵌入式開(kāi)發(fā)前第一步的工作就是要安裝一臺(tái)裝有指定操作系統(tǒng)的PC機(jī)作宿主開(kāi)發(fā)機(jī),對(duì)于嵌入式LINUX,宿主機(jī)上的操作系統(tǒng)一般要求為REDHATLINUX。嵌入式開(kāi)發(fā)通常要求宿主機(jī)配置有網(wǎng)絡(luò),支持NFS(為交叉開(kāi)發(fā)時(shí)mount所用)。然后要在宿主機(jī)上建立交叉編譯調(diào)試的開(kāi)發(fā)環(huán)境。環(huán)境的建立需要許多的軟件模塊協(xié)同工作,這將是一個(gè)比較繁雜的工作,但現(xiàn)在已通過(guò)博創(chuàng)嵌入式教學(xué)套件中光盤的安裝而自動(dòng)完成了。對(duì)開(kāi)發(fā)PC機(jī)的性能要求由于Redhat9.0安裝后占用空間約為2.4G-5G之間,還要安裝ARM-LINUX硬件要求:CPU:高于奔騰500M,推薦高于賽揚(yáng)1.7G;內(nèi)存:大于128M,推薦256M;硬盤:大于10G,推薦高于40G。開(kāi)發(fā)工具軟件的安裝與配置1.REDHATLINUX9.0的安裝在一臺(tái)PC上安裝RedHatLINUX9.0,選擇Custom定制安裝,在選擇軟件Package時(shí)最好將所有包都安裝,需要空間約2.7G,如果選擇最后一項(xiàng):everything,即完全安裝,將安裝3張光盤的全部軟件,需要磁盤空間大約5G。因此建議提前為REDHATLINUX的安裝預(yù)留大約5-15G的空間,具體視用戶的硬盤空間大小來(lái)確定,在安裝完Redhat后還要安裝Linux的編譯器和開(kāi)發(fā)庫(kù)以及ARM-Linux的所有源代碼,這些包安裝后的總共需要空間大約為800M。2.開(kāi)發(fā)工具軟件的安裝將博創(chuàng)興業(yè)科技有限公司提供的附帶開(kāi)發(fā)工具光盤插入CDROM,然后執(zhí)行以下命令:mount/dev/cdrom/mnt若系統(tǒng)不識(shí)別/dev/cdrom的話,可以用如下命令,假設(shè)CDROM為從盤,即為/dev/hdb,則:mount–tiso9660/dev/hdb/mnt安裝腳本程序?qū)⒆詣?dòng)建立/arm2410s目錄,并將所有開(kāi)發(fā)軟件包安裝到/arm2410s目錄下,同時(shí)自動(dòng)配置編譯環(huán)境,建立合適的符號(hào)連接。注意:安裝完成后看一下主編譯器Armv4l-unknown-linux-gcc是否在/opt/host/armv4l/bin/,如果不是這個(gè)路徑,請(qǐng)使用vi修改/root/.bash_profile文件中PATH變量為PATH=$PATH:$HOME/bin:/opt/host/armv4l/bin/,存盤后執(zhí)行:source/root/.bash_profile,則以后armv4l-unknown-linux-gcc會(huì)自動(dòng)搜索到,可以在終端上輸入armv,然后按tab鍵,會(huì)自動(dòng)顯示armv4l-unknown-linux-3.開(kāi)發(fā)環(huán)境配置配置網(wǎng)絡(luò),包括配置IP地址、NFS服務(wù)、防火墻。網(wǎng)絡(luò)配置主要是要安裝好以太網(wǎng)卡,對(duì)于一般常見(jiàn)的RTL8139網(wǎng)卡,REDHAT9.0可以自動(dòng)識(shí)別并自動(dòng)安裝好,完全不要用戶參與,因此建議使用該網(wǎng)卡。然后配置宿主機(jī)IP為21。如果是在有多臺(tái)計(jì)算機(jī)使用的局域網(wǎng)環(huán)境使用此開(kāi)發(fā)設(shè)備,IP地址可以根據(jù)具體情況設(shè)置。如圖1.4.1圖1.4.1雙擊設(shè)備eth0的藍(lán)色區(qū)域,進(jìn)入以太網(wǎng)設(shè)置界面,如圖1.4.2,1.4.3圖1.4.2圖1.4.3對(duì)于REDHAT9.0,它默認(rèn)的是打開(kāi)了防火墻,因此對(duì)于外來(lái)的IP訪問(wèn)它全部拒絕,這樣其它網(wǎng)絡(luò)設(shè)備根本無(wú)法訪問(wèn)它,即無(wú)法用NFSmount它,許多網(wǎng)絡(luò)功能都將無(wú)法使用。因此網(wǎng)絡(luò)安裝完畢后,應(yīng)立即關(guān)閉防火墻。操作如下:點(diǎn)擊紅帽子開(kāi)始菜單,選擇安全級(jí)別設(shè)置,選中無(wú)防火墻。如圖1.4.4圖1.4.4在系統(tǒng)設(shè)置菜單中選擇服務(wù)器設(shè)置菜單,再選中服務(wù)菜單,將iptables服務(wù)的勾去掉,并確保nfs選項(xiàng)選中。配置NFS:點(diǎn)擊主菜單運(yùn)行系統(tǒng)設(shè)置->服務(wù)器設(shè)置->NFS服務(wù)器(英文為:SETUP->SYSTEMSERVICE->NFS),點(diǎn)擊增加出現(xiàn)如下在界面,在目錄(Drictory):中填入需要共享的路徑,在主機(jī)(Hosts):中填入允許進(jìn)行連接的主機(jī)IP地址。并選擇允許客戶對(duì)共享目錄的操作為只讀(Read-only)或讀寫(Read/write)。如圖1.4.5圖1.4.5NFS圖1.4.圖1.4.6當(dāng)將遠(yuǎn)程根用戶當(dāng)作本地根用戶時(shí),對(duì)于操作比較方便,但是安全性較差。最后退出時(shí)則完成NFS配置。配置好后,界面應(yīng)顯示如圖1.4.圖1.4.7圖1.4.8我們也可以手工編寫/etc/exports文件,其格式如下:共享目錄可以連接的主機(jī)(讀寫權(quán)限,其他參數(shù))例如:/arm2410s192.168.0.*(rw,sync)表示將本機(jī)的/arm2410s目錄共享給ip地址為-54的所有計(jì)算機(jī),可以讀取和寫入。配置完成后,可用如下辦法簡(jiǎn)單測(cè)試一下NFS是否配置好了:在宿主機(jī)上自己mount自己,看是否成功就可以判斷NFS是否配好了。例如在宿主機(jī)/目錄下執(zhí)行:mount0:/arm2410s/mnt其中0應(yīng)為主機(jī)的IP地址。然后到/mnt/目錄下看是否可以列出/arm2410s目錄下的所有文件和目錄,可以則說(shuō)明mount成功,NFS配置成功。配置MINICOM:1.在linux操作系統(tǒng)Xwindow界面下建立終端(在桌面上點(diǎn)擊右鍵——>新建終端),在終端的命令行提示符后輸入minicom,圖1.4.9minicom啟動(dòng)畫面2.minicom啟動(dòng)后,先按Ctrl+A鍵,再按Z鍵(注意不是連續(xù)按,Ctrl+A松開(kāi)后才按Z),進(jìn)入主配置界面(見(jiàn)圖1.4.10)。圖1.4.10主配置界面按“O”進(jìn)入配置界面,如圖1.4.11配置界面圖1.4.11按上下鍵選擇Serialportsetup,進(jìn)入端口設(shè)置界面,這里有幾個(gè)重要選項(xiàng)改為如下值(見(jiàn)圖1.4.12):(在Changewhichsetting后按哪個(gè)字母就進(jìn)入哪項(xiàng)的配置,如按A進(jìn)行端口號(hào)配置。)A————SerialDevice:/dev/ttyS0(端口號(hào)使用串口1)E————BPS/par/bits:/1152008N1(波特率)F,E硬件流,軟件流都改為NO,若要使用PC機(jī)的串口2來(lái)接板子的串口1做監(jiān)控,改為:/dev/ttyS1即可。3.選好后按ESC鍵退出到圖1.4.11所示畫面,選擇Savesetupasdf1保存退出,以后只要啟動(dòng)minicom就是該配置,無(wú)需再做改動(dòng)。4.配置完成后,用串口線連接好pc機(jī)和2410開(kāi)發(fā)板,啟動(dòng)2410開(kāi)發(fā)板,即可在minicom上看到啟動(dòng)信息,并可以執(zhí)行操作控制。圖1.4.12端口設(shè)置界面

Linux開(kāi)發(fā)軟件的安裝目錄結(jié)構(gòu)表格1.4.1均以/arm2410s表1.4.1/arm2410s目錄名說(shuō)明busybox-1.00-pre10Busybox-1.00源代碼docarm2410linux使用說(shuō)明書QtQt應(yīng)用程序和庫(kù)的源代碼insight-6.0Linux下源代碼查看器root2410平臺(tái)根文件系統(tǒng)kernel-2410s2410平臺(tái)linux內(nèi)核源代碼demos所有實(shí)驗(yàn)演示程序imgvivi系統(tǒng)引導(dǎo)程序zImageARMLINUX-2.4內(nèi)核壓縮映象文件root.cramfs根文件系統(tǒng)映象文件yaffs.tar.bz2demos演示程序的壓縮文件exp實(shí)驗(yàn)例程源碼shmount-dos.shlinux下掛裝windows的分區(qū)示例腳本 linux下掛裝windows的分區(qū)示例腳本。mnt_udisk.shMOUNTU盤mkroot.sh制作根文件系統(tǒng)的腳本編譯器安裝路徑說(shuō)明如表1.4.2表1.4.2編譯器安裝目錄說(shuō)明arm-elf-gcc-2.95.3/opt/host/armv4l應(yīng)用開(kāi)發(fā)庫(kù)和頭文件Armv4l-unknown-linux-gcc/opt/host/armv4l/bin主編譯器上述諸多程序的源代碼都在光盤中提供.在安裝完成LINUX后,就是對(duì)LINUX的網(wǎng)絡(luò)環(huán)境的配置,最主要是配置NFS服務(wù)器。第二章基礎(chǔ)實(shí)驗(yàn)2.1熟悉Linux開(kāi)發(fā)環(huán)境一、實(shí)驗(yàn)?zāi)康氖煜inux開(kāi)發(fā)環(huán)境,學(xué)會(huì)基于S3C2410的Linux開(kāi)發(fā)環(huán)境的配置和使用。使用Linux的armv4l-unknown-linux-gcc編譯,使用基于NFS方式的下載調(diào)試,了解嵌入式開(kāi)發(fā)的基本過(guò)程。二、實(shí)驗(yàn)內(nèi)容本次實(shí)驗(yàn)使用RedhatLinux9.0操作系統(tǒng)環(huán)境,安裝ARM-Linux的開(kāi)發(fā)庫(kù)及編譯器。創(chuàng)建一個(gè)新目錄,并在其中編寫hello.c和Makefile文件。學(xué)習(xí)在Linux下的編程和編譯過(guò)程,以及ARM開(kāi)發(fā)板的使用和開(kāi)發(fā)環(huán)境的設(shè)置。下載已經(jīng)編譯好的文件到目標(biāo)開(kāi)發(fā)板上運(yùn)行。三、預(yù)備知識(shí)C語(yǔ)言的基礎(chǔ)知識(shí)、程序調(diào)試的基礎(chǔ)知識(shí)和方法,Linux的基本操作。四、實(shí)驗(yàn)設(shè)備及工具(包括軟件調(diào)試工具)硬件:UP-NETARM2410嵌入式實(shí)驗(yàn)平臺(tái)、PC機(jī)Pentium500以上,硬盤10G以上。軟件:PC機(jī)操作系統(tǒng)REDHATLINUX9.0+MINICOM+ARM-LINUX開(kāi)發(fā)環(huán)境五、實(shí)驗(yàn)步驟1、建立工作目錄[root@zxtsmile]#mkdirhello[root@zxtsmile]#cdhello2、編寫程序源代碼在Linux下的文本編輯器有許多,常用的是vim和Xwindow界面下的gedit等,我們?cè)陂_(kāi)發(fā)過(guò)程中推薦使用vim,用戶需要學(xué)習(xí)vim的操作方法,請(qǐng)參考相關(guān)書籍中的關(guān)于vim的操作指南。Kdevelope、anjuta軟件的界面與vc6.0類似,使用它們對(duì)于熟悉windows環(huán)境下開(kāi)發(fā)的用戶更容易上手。實(shí)際的hello.c源代碼較簡(jiǎn)單,如下:#include<stdio.h>main(){ printf(“helloworld\n”);}我們可以是用下面的命令來(lái)編寫hello.c的源代碼,進(jìn)入hello目錄使用vi命令來(lái)編輯代碼:[root@zxthello]#vihello.c按“i”或者“a”進(jìn)入編輯模式,將上面的代碼錄入進(jìn)去,完成后按Esc鍵進(jìn)入命令狀態(tài),再用命令“:wq”保存并退出。這樣我們便在當(dāng)前目錄下建立了一個(gè)名為hello.c的文件。3、編寫Makefile要使上面的hello.c程序能夠運(yùn)行,我們必須要編寫一個(gè)Makefile文件,Makefile文件定義了一系列的規(guī)則,它指明了哪些文件需要編譯,哪些文件需要先編譯,哪些文件需要重新編譯等等更為復(fù)雜的命令。使用它帶來(lái)的好處就是自動(dòng)編譯,你只需要敲一個(gè)“make”命令整個(gè)工程就可以實(shí)現(xiàn)自動(dòng)編譯,當(dāng)然我們本次實(shí)驗(yàn)只有一個(gè)文件,它還不能體現(xiàn)出使用Makefile的優(yōu)越性,但當(dāng)工程比較大文件比較多時(shí),不使用Makefile幾乎是不可能的。下面我們介紹本次實(shí)驗(yàn)用到的Makefile文件。CC=armv4l-unknown-linux-gccEXEC=helloOBJS=hello.oCFLAGS+=LDFLAGS+=–staticall:$(EXEC)$(EXEC):$(OBJS) $(CC)$(LDFLAGS)-o$@$(OBJS)clean: -rm-f$(EXEC)*.elf*.gdb*.o下面我們來(lái)簡(jiǎn)單介紹這個(gè)Makefile文件的幾個(gè)主要部分:CC指明編譯器EXEC表示編譯后生成的執(zhí)行文件名稱OBJS目標(biāo)文件列表CFLAGS編譯參數(shù)LDFLAGS連接參數(shù)all:編譯主入口clean:清除編譯結(jié)果注意:“$(CC)$(LDFLAGS)-o$@$(OBJS)”和“-rm-f$(EXEC)*.elf*.gdb*.o”前空白由一個(gè)Tab制表符生成,不能單純由空格來(lái)代替。與上面編寫hello.c的過(guò)程類似,用vi來(lái)創(chuàng)建一個(gè)Makefile文件并將代碼錄入其中[root@zxthello]#viMakefile4、編譯應(yīng)用程序在上面的步驟完成后,我們就可以在hello目錄下運(yùn)行“make”來(lái)編譯我們的程序了。如果進(jìn)行了修改,重新編譯則運(yùn)行:[root@zxthello]#makeclean[root@zxthello]#make注意:編譯、修改程序都是在宿主機(jī)(本地PC機(jī))上進(jìn)行,不能在MINICOM下進(jìn)行。5、下載調(diào)試在宿主PC計(jì)算機(jī)上啟動(dòng)NFS服務(wù),并設(shè)置好共享的目錄,具體配置請(qǐng)參照前面第一章第四節(jié)中關(guān)于嵌入式Linux環(huán)境開(kāi)發(fā)環(huán)境的建立。在建立好NFS共享目錄以后,我們就可以進(jìn)入MINICOM中建立開(kāi)發(fā)板與宿主PC機(jī)之間的通訊了。[root@zxthello]#minicom[/mnt/yaffs]mount-tnfs-onolock6:/arm2410s/host注意:IP地址需要根據(jù)宿主PC機(jī)的實(shí)際情況修改成功掛接宿主機(jī)的arm2410s目錄后,在開(kāi)發(fā)板上進(jìn)入/host目錄便相應(yīng)進(jìn)入宿主機(jī)的/arm2410s目錄,我們已經(jīng)給出了編輯好的hello.c和Makefile文件,它們?cè)?arm2410s/exp/basic/01_hello目錄下。用戶可以直接在宿主PC上編譯生成可執(zhí)行文件,并通過(guò)上面的命令掛載到開(kāi)發(fā)板上,運(yùn)行程序察看結(jié)果。如果不想使用我們提供的源碼的話,可以再建立一個(gè)NFS共享文件夾。如/root/share,我們把我們自己編譯生成的可執(zhí)行文件復(fù)制到該文件夾下,并通過(guò)MINICOM掛載到開(kāi)發(fā)板上。[root@zxthello]#cphello/root/share[root@zxthello]#minicom[/mnt/yaffs]mount-tnfs-onolock6:/root/share/host再進(jìn)入/host目錄運(yùn)行剛剛編譯好的hello程序,查看運(yùn)行結(jié)果。[/mnt/yaffs]cd/host[/host]./hellohelloworld注意:開(kāi)發(fā)板掛接宿主計(jì)算機(jī)目錄只需要掛接一次便可,只要開(kāi)發(fā)板沒(méi)有重起,就可以一直保持連接。這樣可以反復(fù)修改、編譯、調(diào)試,不需要下載到開(kāi)發(fā)板。六、思考題1.Makefile是如何工作的?其中的宏定義分別是什么意思?

2.2多線程應(yīng)用程序設(shè)計(jì)一、實(shí)驗(yàn)?zāi)康牧私舛嗑€程程序設(shè)計(jì)的基本原理。學(xué)習(xí)pthread庫(kù)函數(shù)的使用。二、實(shí)驗(yàn)內(nèi)容讀懂pthread.c的源代碼,熟悉幾個(gè)重要的PTHREAD庫(kù)函數(shù)的使用。掌握共享鎖和信號(hào)量的使用方法。進(jìn)入/arm2410s/exp/basic/02_pthread目錄,運(yùn)行make產(chǎn)生pthread程序,使用NFS方式連接開(kāi)發(fā)主機(jī)進(jìn)行運(yùn)行實(shí)驗(yàn)。三、預(yù)備知識(shí)有C語(yǔ)言基礎(chǔ)掌握在Linux下常用編輯器的使用掌握Makefile的編寫和使用掌握Linux下的程序編譯與交叉編譯過(guò)程四、實(shí)驗(yàn)設(shè)備及工具硬件:UP-NETARM2410嵌入式實(shí)驗(yàn)平臺(tái),PC機(jī)Pentium500以上,硬盤40G以上,內(nèi)存大于128M。軟件:PC機(jī)操作系統(tǒng)REDHATLINUX9.0+MINICOM+ARM-LINUX開(kāi)發(fā)環(huán)境五、實(shí)驗(yàn)原理及代碼分析1.多線程程序的優(yōu)缺點(diǎn)多線程程序作為一種多任務(wù)、并發(fā)的工作方式,有以下的優(yōu)點(diǎn):1)提高應(yīng)用程序響應(yīng)。這對(duì)圖形界面的程序尤其有意義,當(dāng)一個(gè)操作耗時(shí)很長(zhǎng)時(shí),整個(gè)系統(tǒng)都會(huì)等待這個(gè)操作,此時(shí)程序不會(huì)響應(yīng)鍵盤、鼠標(biāo)、菜單的操作,而使用多線程技術(shù),將耗時(shí)長(zhǎng)的操作(timeconsuming)置于一個(gè)新的線程,可以避免這種尷尬的情況。2)使多CPU系統(tǒng)更加有效。操作系統(tǒng)會(huì)保證當(dāng)線程數(shù)不大于CPU數(shù)目時(shí),不同的線程運(yùn)行于不同的CPU上。3)改善程序結(jié)構(gòu)。一個(gè)既長(zhǎng)又復(fù)雜的進(jìn)程可以考慮分為多個(gè)線程,成為幾個(gè)獨(dú)立或半獨(dú)立的運(yùn)行部分,這樣的程序會(huì)利于理解和修改。LIBC中的pthread庫(kù)提供了大量的API函數(shù),為用戶編寫應(yīng)用程序提供支持。2.實(shí)驗(yàn)源代碼與結(jié)構(gòu)流程圖本實(shí)驗(yàn)為著名的生產(chǎn)者-消費(fèi)者問(wèn)題模型的實(shí)現(xiàn),主程序中分別啟動(dòng)生產(chǎn)者線程和消費(fèi)者線程。生產(chǎn)者線程不斷順序地將0到1000的數(shù)字寫入共享的循環(huán)緩沖區(qū),同時(shí)消費(fèi)者線程不斷地從共享的循環(huán)緩沖區(qū)讀取數(shù)據(jù)。流程圖如圖2.2.1所示:圖2.2.1生產(chǎn)者-消費(fèi)者實(shí)驗(yàn)源代碼結(jié)構(gòu)流程圖本實(shí)驗(yàn)具體代碼如下:/************************************************* Theclassicproducer-consumerexample.* Illustratesmutexesandconditions.*byZoujianguo<ah_zou@>*2003-12-22*************************************************/#include<stdio.h>#include<stdlib.h>#include<time.h>#include"pthread.h"#defineBUFFER_SIZE16/*設(shè)置一個(gè)整數(shù)的圓形緩沖區(qū)*/structprodcons{intbuffer[BUFFER_SIZE];/*緩沖區(qū)數(shù)組*/pthread_mutex_tlock;/*互斥鎖*/intreadpos,writepos;/*讀寫的位置*/pthread_cond_tnotempty;/*緩沖區(qū)非空信號(hào)*/pthread_cond_tnotfull;/*緩沖區(qū)非滿信號(hào)*/};/**//*初始化緩沖區(qū)*/voidinit(structprodcons*b){pthread_mutex_init(&b->lock,NULL);pthread_cond_init(&b->notempty,NULL);pthread_cond_init(&b->notfull,NULL);b->readpos=0;b->writepos=0;}/**//*向緩沖區(qū)中寫入一個(gè)整數(shù)*/voidput(structprodcons*b,intdata){ pthread_mutex_lock(&b->lock); /*等待緩沖區(qū)非滿*/ while((b->writepos+1)%BUFFER_SIZE==b->readpos){ printf("waitfornotfull\n"); pthread_cond_wait(&b->notfull,&b->lock); }/*寫數(shù)據(jù)并且指針前移*/ b->buffer[b->writepos]=data; b->writepos++; if(b->writepos>=BUFFER_SIZE)b->writepos=0;/*設(shè)置緩沖區(qū)非空信號(hào)*/ pthread_cond_signal(&b->notempty); pthread_mutex_unlock(&b->lock);}/**//*從緩沖區(qū)中讀出一個(gè)整數(shù)*/intget(structprodcons*b){ intdata; pthread_mutex_lock(&b->lock); /*等待緩沖區(qū)非空*/ while(b->writepos==b->readpos){ printf("waitfornotempty\n"); pthread_cond_wait(&b->notempty,&b->lock); } /*讀數(shù)據(jù)并且指針前移*/ data=b->buffer[b->readpos]; b->readpos++; if(b->readpos>=BUFFER_SIZE)b->readpos=0; /*設(shè)置緩沖區(qū)非滿信號(hào)*/ pthread_cond_signal(&b->notfull); pthread_mutex_unlock(&b->lock); returndata;}/**/#defineOVER(-1)structprodconsbuffer;/**/void*producer(void*data){ intn; for(n=0;n<1000;n++){ printf("put-->%d\n",n); put(&buffer,n); }put(&buffer,OVER);printf("producerstopped!\n");returnNULL;}/**/void*consumer(void*data){intd;while(1){d=get(&buffer);if(d==OVER)break;printf("%d-->get\n",d);}printf("consumerstopped!\n");returnNULL;}/**/intmain(void){ pthread_tth_a,th_b; void*retval; init(&buffer); pthread_create(&th_a,NULL,producer,0); pthread_create(&th_b,NULL,consumer,0);/*等待生產(chǎn)者和消費(fèi)者結(jié)束*/ pthread_join(th_a,&retval); pthread_join(th_b,&retval); return0;}3.主要函數(shù)分析:下面我們來(lái)看一下,生產(chǎn)者寫入緩沖區(qū)和消費(fèi)者從緩沖區(qū)讀數(shù)的具體流程,生產(chǎn)者首先要獲得互斥鎖,并且判斷寫指針+1后是否等于讀指針,如果相等則進(jìn)入等待狀態(tài),等候條件變量notfull;如果不等則向緩沖區(qū)中寫一個(gè)整數(shù),并且設(shè)置條件變量為notempty,最后釋放互斥鎖。消費(fèi)者線程與生產(chǎn)者線程類似,這里就不再過(guò)多介紹了。流程圖如下:圖2.2.2生產(chǎn)消費(fèi)流程圖生產(chǎn)者寫入共享的循環(huán)緩沖區(qū)函數(shù)PUTvoidput(structprodcons*b,intdata){ pthread_mutex_lock(&b->lock);//獲取互斥鎖 while((b->writepos+1)%BUFFER_SIZE==b->readpos){//如果讀寫位置相同 pthread_cond_wait(&b->notfull,&b->lock);//等待狀態(tài)變量b->notfull,不滿則跳出阻塞 } b->buffer[b->writepos]=data;//寫入數(shù)據(jù) b->writepos++; if(b->writepos>=BUFFER_SIZE)b->writepos=0; pthread_cond_signal(&b->notempty);//設(shè)置狀態(tài)變量 pthread_mutex_unlock(&b->lock);//釋放互斥鎖}消費(fèi)者讀取共享的循環(huán)緩沖區(qū)函數(shù)GETintget(structprodcons*b){ intdata; pthread_mutex_lock(&b->lock);//獲取互斥鎖 while(b->writepos==b->readpos){//如果讀寫位置相同 pthread_cond_wait(&b->notempty,&b->lock);//等待狀態(tài)變量b->notempty,不空則跳出阻塞。否則無(wú)數(shù)據(jù)可讀。 } data=b->buffer[b->readpos];//讀取數(shù)據(jù) b->readpos++; if(b->readpos>=BUFFER_SIZE)b->readpos=0; pthread_cond_signal(&b->notfull);//設(shè)置狀態(tài)變量 pthread_mutex_unlock(&b->lock);//釋放互斥鎖 returndata;}4.主要的多線程API在本程序的代碼中大量的使用了線程函數(shù),如pthread_cond_signal、pthread_mutex_init、pthread_mutex_lock等等,這些函數(shù)的作用是什么,在哪里定義的,我們將在下面的內(nèi)容中為大家做一個(gè)簡(jiǎn)單的介紹,并且為其中比較重要的函數(shù)做一些詳細(xì)的說(shuō)明。線程創(chuàng)建函數(shù):intpthread_create(pthread_t*thread_id,__constpthread_attr_t*__attr, void*(*__start_routine)(void*),void*__restrict__arg)獲得父進(jìn)程ID:pthread_tpthread_self(void)測(cè)試兩個(gè)線程號(hào)是否相同:intpthread_equal(pthread_t__thread1,pthread_t__thread2)線程退出:voidpthread_exit(void*__retval)等待指定的線程結(jié)束:intpthread_join(pthread_t__th,void**__thread_return)互斥量初始化:pthread_mutex_init(pthread_mutex_t*,__constpthread_mutexattr_t*)銷毀互斥量:intpthread_mutex_destroy(pthread_mutex_t*__mutex)再試一次獲得對(duì)互斥量的鎖定(非阻塞):intpthread_mutex_trylock(pthread_mutex_t*__mutex)鎖定互斥量(阻塞):intpthread_mutex_lock(pthread_mutex_t*__mutex)解鎖互斥量:intpthread_mutex_unlock(pthread_mutex_t*__mutex)條件變量初始化:intpthread_cond_init(pthread_cond_t*__restrict__cond,__constpthread_condattr_t*__restrict__cond_attr)銷毀條件變量COND:intpthread_cond_destroy(pthread_cond_t*__cond)喚醒線程等待條件變量:intpthread_cond_signal(pthread_cond_t*__cond)等待條件變量(阻塞):intpthread_cond_wait(pthread_cond_t*__restrict__cond,pthread_mutex_t*__restrict__mutex)在指定的時(shí)間到達(dá)前等待條件變量:intpthread_cond_timedwait(pthread_cond_t*__restrict__cond,pthread_mutex_t*__restrict__mutex,__conststructtimespec*__restrict__abstime)PTHREAD庫(kù)中還有大量的API函數(shù),用戶可以參考其他相關(guān)書籍。下面我們對(duì)幾個(gè)比較重要的函數(shù)做一下詳細(xì)的說(shuō)明:pthread_create線程創(chuàng)建函數(shù)intpthread_create(pthread_t*thread_id,__constpthread_attr_t*__attr, void*(*__start_routine)(void*),void*__restrict__arg)線程創(chuàng)建函數(shù)第一個(gè)參數(shù)為指向線程標(biāo)識(shí)符的指針,第二個(gè)參數(shù)用來(lái)設(shè)置線程屬性,第三個(gè)參數(shù)是線程運(yùn)行函數(shù)的起始地址,最后一個(gè)參數(shù)是運(yùn)行函數(shù)的參數(shù)。這里,我們的函數(shù)thread不需要參數(shù),所以最后一個(gè)參數(shù)設(shè)為空指針。第二個(gè)參數(shù)我們也設(shè)為空指針,這樣將生成默認(rèn)屬性的線程。當(dāng)創(chuàng)建線程成功時(shí),函數(shù)返回0,若不為0則說(shuō)明創(chuàng)建線程失敗,常見(jiàn)的錯(cuò)誤返回代碼為EAGAIN和EINVAL。前者表示系統(tǒng)限制創(chuàng)建新的線程,例如線程數(shù)目過(guò)多了;后者表示第二個(gè)參數(shù)代表的線程屬性值非法。創(chuàng)建線程成功后,新創(chuàng)建的線程則運(yùn)行參數(shù)三和參數(shù)四確定的函數(shù),原來(lái)的線程則繼續(xù)運(yùn)行下一行代碼。pthread_join函數(shù)用來(lái)等待一個(gè)線程的結(jié)束。函數(shù)原型為:intpthread_join(pthread_t__th,void**__thread_return)第一個(gè)參數(shù)為被等待的線程標(biāo)識(shí)符,第二個(gè)參數(shù)為一個(gè)用戶定義的指針,它可以用來(lái)存儲(chǔ)被等待線程的返回值。這個(gè)函數(shù)是一個(gè)線程阻塞的函數(shù),調(diào)用它的函數(shù)將一直等待到被等待的線程結(jié)束為止,當(dāng)函數(shù)返回時(shí),被等待線程的資源被收回。pthread_exit函數(shù)一個(gè)線程的結(jié)束有兩種途徑,一種是象我們上面的例子一樣,函數(shù)結(jié)束了,調(diào)用它的線程也就結(jié)束了;另一種方式是通過(guò)函數(shù)pthread_exit來(lái)實(shí)現(xiàn)。它的函數(shù)原型為:voidpthread_exit(void*__retval)唯一的參數(shù)是函數(shù)的返回代碼,只要pthread_join中的第二個(gè)參數(shù)thread_return不是NULL,這個(gè)值將被傳遞給thread_return。最后要說(shuō)明的是,一個(gè)線程不能被多個(gè)線程等待,否則第一個(gè)接收到信號(hào)的線程成功返回,其余調(diào)用pthread_join的線程則返回錯(cuò)誤代碼ESRCH。下面我們來(lái)介紹有關(guān)條件變量的內(nèi)容。使用互斥鎖來(lái)可實(shí)現(xiàn)線程間數(shù)據(jù)的共享和通信,互斥鎖一個(gè)明顯的缺點(diǎn)是它只有兩種狀態(tài):鎖定和非鎖定。而條件變量通過(guò)允許線程阻塞和等待另一個(gè)線程發(fā)送信號(hào)的方法彌補(bǔ)了互斥鎖的不足,它常和互斥鎖一起使用。使用時(shí),條件變量被用來(lái)阻塞一個(gè)線程,當(dāng)條件不滿足時(shí),線程往往解開(kāi)相應(yīng)的互斥鎖并等待條件發(fā)生變化。一旦其它的某個(gè)線程改變了條件變量,它將通知相應(yīng)的條件變量喚醒一個(gè)或多個(gè)正被此條件變量阻塞的線程。這些線程將重新鎖定互斥鎖并重新測(cè)試條件是否滿足。一般說(shuō)來(lái),條件變量被用來(lái)進(jìn)行線線程間的同步。pthread_cond_init函數(shù)條件變量的結(jié)構(gòu)為pthread_cond_t,函數(shù)pthread_cond_init()被用來(lái)初始化一個(gè)條件變量。它的原型為:intpthread_cond_init(pthread_cond_t*cond,__constpthread_condattr_t*cond_attr)其中cond是一個(gè)指向結(jié)構(gòu)pthread_cond_t的指針,cond_attr是一個(gè)指向結(jié)構(gòu)pthread_condattr_t的指針。結(jié)構(gòu)pthread_condattr_t是條件變量的屬性結(jié)構(gòu),和互斥鎖一樣我們可以用它來(lái)設(shè)置條件變量是進(jìn)程內(nèi)可用還是進(jìn)程間可用,默認(rèn)值是PTHREAD_PROCESS_PRIVATE,即此條件變量被同一進(jìn)程內(nèi)的各個(gè)線程使用。注意初始化條件變量只有未被使用時(shí)才能重新初始化或被釋放。釋放一個(gè)條件變量的函數(shù)為pthread_cond_destroy(pthread_cond_tcond)。pthread_cond_wait函數(shù)使線程阻塞在一個(gè)條件變量上。它的函數(shù)原型為:externintpthread_cond_wait(pthread_cond_t*__restrict__cond,pthread_mutex_t*__restrict__mutex)線程解開(kāi)mutex指向的鎖并被條件變量cond阻塞。線程可以被函數(shù)pthread_cond_signal和函數(shù)pthread_cond_broadcast喚醒,但是要注意的是,條件變量只是起阻塞和喚醒線程的作用,具體的判斷條件還需用戶給出,例如一個(gè)變量是否為0等等,這一點(diǎn)我們從后面的例子中可以看到。線程被喚醒后,它將重新檢查判斷條件是否滿足,如果還不滿足,一般說(shuō)來(lái)線程應(yīng)該仍阻塞在這里,被等待被下一次喚醒。這個(gè)過(guò)程一般用while語(yǔ)句實(shí)現(xiàn)。pthread_cond_timedwait函數(shù)另一個(gè)用來(lái)阻塞線程的函數(shù)是pthread_cond_timedwait(),它的原型為:externintpthread_cond_timedwait__P((pthread_cond_t*__cond,pthread_mutex_t*__mutex,__conststructtimespec*__abstime))它比函數(shù)pthread_cond_wait()多了一個(gè)時(shí)間參數(shù),經(jīng)歷abstime段時(shí)間后,即使條件變量不滿足,阻塞也被解除。pthread_cond_signal函數(shù)它的函數(shù)原型為:externintpthread_cond_signal(pthread_cond_t*__cond)它用來(lái)釋放被阻塞在條件變量cond上的一個(gè)線程。多個(gè)線程阻塞在此條件變量上時(shí),哪一個(gè)線程被喚醒是由線程的調(diào)度策略所決定的。要注意的是,必須用保護(hù)條件變量的互斥鎖來(lái)保護(hù)這個(gè)函數(shù),否則條件滿足信號(hào)又可能在測(cè)試條件和調(diào)用pthread_cond_wait函數(shù)之間被發(fā)出,從而造成無(wú)限制的等待。六、實(shí)驗(yàn)步驟1、閱讀源代及編譯應(yīng)用程序進(jìn)入exp/basic/02_pthread目錄,使用vi編輯器或其他編輯器閱讀理解源代碼。運(yùn)行make產(chǎn)生pthread可執(zhí)行文件。2、下載和調(diào)試切換到minicom終端窗口,使用NFSmount開(kāi)發(fā)主機(jī)的/arm2410s到/host目錄。進(jìn)入/host/exp/basic/pthread目錄,運(yùn)行pthread,觀察運(yùn)行結(jié)果的正確性。運(yùn)行程序最后一部分結(jié)果如下:waitfornotemptyput-->994put-->995put-->996put-->997put-->998put-->999producerstopped!993-->get994-->get995-->get996-->get997-->get998-->get999-->getconsumerstopped![/host/exp/basic/02_pthread]七、思考題1.加入一個(gè)新的線程用于處理鍵盤的輸入,并在按鍵為ESC時(shí)終止所有線程。2.線程的優(yōu)先級(jí)的控制。

2.3串行端口程序設(shè)計(jì)一、實(shí)驗(yàn)?zāi)康牧私庠趌inux環(huán)境下串行程序設(shè)計(jì)的基本方法。掌握終端的主要屬性及設(shè)置方法,熟悉終端I/O函數(shù)的使用。學(xué)習(xí)使用多線程來(lái)完成串口的收發(fā)處理。二、實(shí)驗(yàn)內(nèi)容讀懂程序源代碼,學(xué)習(xí)終端I/O函數(shù)的使用方法,學(xué)習(xí)將多線程編程應(yīng)用到串口的接收和發(fā)送程序設(shè)計(jì)中。三、預(yù)備知識(shí)有C語(yǔ)言基礎(chǔ)。掌握在Linux下常用編輯器的使用。掌握Makefile的編寫和使用。掌握Linux下的程序編譯與交叉編譯過(guò)程四、實(shí)驗(yàn)設(shè)備及工具硬件:UP-NETARM2410嵌入式實(shí)驗(yàn)平臺(tái)、PC機(jī)Pentium500以上,硬盤10G以上。軟件:PC機(jī)操作系統(tǒng)REDHATLINUX9.0+MINICOM+ARM-LINUX開(kāi)發(fā)環(huán)境五、實(shí)驗(yàn)原理異步串行I/O方式是將傳輸數(shù)據(jù)的每個(gè)字符一位接一位(例如先低位、后高位)地傳送。數(shù)據(jù)的各不同位可以分時(shí)使用同一傳輸通道,因此串行I/O可以減少信號(hào)連線,最少用一對(duì)線即可進(jìn)行。接收方對(duì)于同一根線上一連串的數(shù)字信號(hào),首先要分割成位,再按位組成字符。為了恢復(fù)發(fā)送的信息,雙方必須協(xié)調(diào)工作。在微型計(jì)算機(jī)中大量使用異步串行I/O方式,雙方使用各自的時(shí)鐘信號(hào),而且允許時(shí)鐘頻率有一定誤差,因此實(shí)現(xiàn)較容易。但是由于每個(gè)字符都要獨(dú)立確定起始和結(jié)束(即每個(gè)字符都要重新同步),字符和字符間還可能有長(zhǎng)度不定的空閑時(shí)間,因此效率較低。圖2.3.1串行通信字符格式圖2.3.1給出異步串行通信中一個(gè)字符的傳送格式。開(kāi)始前,線路處于空閑狀態(tài),送出連續(xù)“1”。傳送開(kāi)始時(shí)首先發(fā)一個(gè)“0”作為起始位,然后出現(xiàn)在通信線上的是字符的二進(jìn)制編碼數(shù)據(jù)。每個(gè)字符的數(shù)據(jù)位長(zhǎng)可以約定為5位、6位、7位或8位,一般采用ASCII編碼。后面是奇偶校驗(yàn)位,根據(jù)約定,用奇偶校驗(yàn)位將所傳字符中為“1”的位數(shù)湊成奇數(shù)個(gè)或偶數(shù)個(gè)。也可以約定不要奇偶校驗(yàn),這樣就取消奇偶校驗(yàn)位。最后是表示停止位的“1”信號(hào),這個(gè)停止位可以約定持續(xù)1位、1.5位或2位的時(shí)間寬度。至此一個(gè)字符傳送完畢,線路又進(jìn)入空閑,持續(xù)為“1”。經(jīng)過(guò)一段隨機(jī)的時(shí)間后,下一個(gè)字符開(kāi)始傳送才又發(fā)出起始位。每一個(gè)數(shù)據(jù)位的寬度等于傳送波特率的倒數(shù)。微機(jī)異步串行通信中,常用的波特率為50,95,110,150,300,600,1200,2400,4800,9600等。接收方按約定的格式接收數(shù)據(jù),并進(jìn)行檢查,可以查出以下三種錯(cuò)誤:奇偶錯(cuò):在約定奇偶檢查的情況下,接收到的字符奇偶狀態(tài)和約定不符。幀格式錯(cuò):一個(gè)字符從起始位到停止位的總位數(shù)不對(duì)。溢出錯(cuò):若先接收的字符尚未被微機(jī)讀取,后面的字符又傳送過(guò)來(lái),則產(chǎn)生溢出錯(cuò)。每一種錯(cuò)誤都會(huì)給出相應(yīng)的出錯(cuò)信息,提示用戶處理。一般串口調(diào)試都使用空的MODEM連接電纜,其連接方式如下:圖2.3.2實(shí)用RS-232C通訊連線六、程序分析Linux操作系統(tǒng)從一開(kāi)始就對(duì)串行口提供了很好的支持,為進(jìn)行串行通訊提供了大量的函數(shù),我們的實(shí)驗(yàn)主要是為掌握在Linux中進(jìn)行串行通訊編程的基本方法。本實(shí)驗(yàn)的程序流程圖如下:圖2.3.3串口通訊實(shí)驗(yàn)流程圖本實(shí)驗(yàn)的代碼如下:#include<termios.h>#include<stdio.h>#include<unistd.h>#include<fcntl.h>#include<sys/signal.h>#include<pthread.h>#defineBAUDRATEB115200#defineCOM1"/dev/ttyS0"#defineCOM2"/dev/ttyS1"#defineENDMINITERM27/*ESCtoquitminiterm*/#defineFALSE0#defineTRUE1volatileintSTOP=FALSE;volatileintfd;voidchild_handler(ints){printf("stop!!!\n");STOP=TRUE;}/**/void*keyboard(void*data){intc; for(;;){ c=getchar(); if(c==ENDMINITERM){ STOP=TRUE; break; } }returnNULL;}/**//*modeminputhandler*/void*receive(void*data){ intc; printf("readmodem\n"); while(STOP==FALSE) { read(fd,&c,1);/*comport*/ write(1,&c,1);/*stdout*/ } printf("exitfromreadingmodem\n"); returnNULL;}/**/void*send(void*data){ intc='0'; printf("senddata\n"); while(STOP==FALSE)/*modeminputhandler*/ { c++; c%=255; write(fd,&c,1);/*stdout*/ usleep(100000); } returnNULL;}/**/intmain(intargc,char**argv){ structtermiosoldtio,newtio,oldstdtio,newstdtio; structsigactionsa; intok; pthread_tth_a,th_b,th_c; void*retval; if(argc>1) fd=open(COM2,O_RDWR); else fd=open(COM1,O_RDWR);//|O_NOCTTY|O_NONBLOCK); if(fd<0){ error(COM1); exit(-1); } tcgetattr(0,&oldstdtio); tcgetattr(fd,&oldtio);/*savecurrentmodemsettings*/ tcgetattr(fd,&newstdtio);/*getworkingstdtio*/ newtio.c_cflag=BAUDRATE|CRTSCTS|CS8|CLOCAL|CREAD;/*ctrolflag*/ newtio.c_iflag=IGNPAR;/*inputflag*/ newtio.c_oflag=0; /*outputflag*/ newtio.c_lflag=0; newtio.c_cc[VMIN]=1; newtio.c_cc[VTIME]=0;/*nowcleanthemodemlineandactivatethesettingsformodem*/ tcflush(fd,TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio);/*setattrib*/ sa.sa_handler=child_handler; sa.sa_flags=0; sigaction(SIGCHLD,&sa,NULL);/*handledyingchild*/ pthread_create(&th_a,NULL,keyboard,0); pthread_create(&th_b,NULL,receive,0); pthread_create(&th_c,NULL,send,0); pthread_join(th_a,&retval); pthread_join(th_b,&retval); pthread_join(th_c,&retval); tcsetattr(fd,TCSANOW,&oldtio);/*restoreoldmodemsetings*/ tcsetattr(0,TCSANOW,&oldstdtio);/*restoreoldttysetings*/ close(fd); exit(0);}下面我們對(duì)這個(gè)程序的主要部分做一下簡(jiǎn)單的分析頭文件#include<stdio.h>/*標(biāo)準(zhǔn)輸入輸出定義*/#include<stdlib.h>/*標(biāo)準(zhǔn)函數(shù)庫(kù)定義*/#include<unistd.h>/*linux標(biāo)準(zhǔn)函數(shù)定義*/#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>/*文件控制定義*/#include<termios.h>/*PPSIX終端控制定義*/#include<errno.h>/*錯(cuò)誤號(hào)定義*/#include <pthread.h> /*線程庫(kù)定義*/打開(kāi)串口在Linux下串口文件位于/dev下,一般在老版本的內(nèi)核中串口一為/dev/ttyS0,串口二為/dev/ttyS1,在我們的開(kāi)發(fā)板中串口設(shè)備位于/dev/tts/下,因?yàn)殚_(kāi)發(fā)板中沒(méi)有ttyS0這個(gè)設(shè)備,所以我們要建立一個(gè)連接,方法如下:[/mnt/yaffs]cd/dev[/dev]ln–sf/dev/tts/0ttyS0打開(kāi)串口是通過(guò)標(biāo)準(zhǔn)的文件打開(kāi)函數(shù)來(lái)實(shí)現(xiàn)的intfd;fd=open("/dev/ttyS0",O_RDWR);/*以讀寫方式打開(kāi)串口*/if(-1==fd){/*不能打開(kāi)串口一*/ perror("提示錯(cuò)誤!");}串口設(shè)置最基本的設(shè)置串口包括波特率設(shè)置,效驗(yàn)位和停止位設(shè)置。串口的設(shè)置主要是設(shè)置structtermios結(jié)構(gòu)體的各成員值,關(guān)于該結(jié)構(gòu)體的定義可以查看/arm2410s/kernel-2410s/include/asm/termios.h文件。structtermio{ unsignedshortc_iflag; /*輸入模式標(biāo)志*/ unsignedshortc_oflag; /*輸出模式標(biāo)志*/ unsignedshortc_cflag; /*控制模式標(biāo)志*/ unsignedshortc_lflag; /*localmodeflags*/ unsignedcharc_line; /*linediscipline*/ unsignedcharc_cc[NCC];/*controlcharacters*/};設(shè)置這個(gè)結(jié)構(gòu)體很復(fù)雜,可以參考man手冊(cè)或者由趙克佳、沈志宇編寫的《UNIX程序編寫教程》,我這里就只

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論