串口應(yīng)用程序SCBX_第1頁
串口應(yīng)用程序SCBX_第2頁
串口應(yīng)用程序SCBX_第3頁
串口應(yīng)用程序SCBX_第4頁
串口應(yīng)用程序SCBX_第5頁
已閱讀5頁,還剩323頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

本章從一個(gè)針對運(yùn)行在S3C44B0X上的uClinux操作系統(tǒng)進(jìn)行應(yīng)用程序的開發(fā)入手,給出了Windows操作系統(tǒng)平臺(tái)上使用HitoolforuClinux等工具開發(fā)的多種應(yīng)用程序。

本章主要介紹了:

◆串口應(yīng)用程序的編寫方法。

◆TCP/IP協(xié)議以及Socket的編寫方法。

◆基于uClinux音頻接口的應(yīng)用程序的編寫方法。

◆鍵盤和LCD的應(yīng)用程序的編寫方法。

◆漢字音樂點(diǎn)播程序的編寫實(shí)例。11.1串口應(yīng)用程序

S3C44B0X提供2個(gè)UART收發(fā)器,對它們可以操作在中斷方式或DMA方式。 它們內(nèi)置波特率發(fā)生器,波特率發(fā)生器的時(shí)鐘源為S3C44B0X的系統(tǒng)使用,所以最高速率可達(dá)115.2Kbps。

二個(gè)串口有單獨(dú)的波特率發(fā)生器,接收,發(fā)送和控制單元,支持紅外方式的傳送和接收。 同時(shí),在S3C44B0X串口的接收器和發(fā)送器中都有16字節(jié)的FIFO,F(xiàn)IFO可以有效的降低接收器和發(fā)送器對CPU的中斷頻率,提高發(fā)送和接收的效率。

串口設(shè)備的可配置參數(shù)包括波特率,起始位數(shù)量,數(shù)據(jù)位數(shù)量,停止位數(shù)量和流量控制協(xié)議。 一般來講,起始位為1bit,數(shù)據(jù)位為8bit,停止位為1bit,流量控制協(xié)議為“無流量控制”,波特率為115200bit/s。

在Linux操作系統(tǒng)中,設(shè)備驅(qū)動(dòng)是以主設(shè)備號(hào)為主,每個(gè)設(shè)備都有唯一的主設(shè)備號(hào)和從設(shè)備號(hào)。 在Linux內(nèi)核中使用塊設(shè)備表和字符設(shè)備表,根據(jù)設(shè)備的類型和主設(shè)備號(hào)便可以在設(shè)備表中找到相應(yīng)的驅(qū)動(dòng)程序,而從設(shè)備號(hào)則一般只用作同類設(shè)備中具體設(shè)備項(xiàng)的編號(hào)。

作為字符型設(shè)備,串口設(shè)備的設(shè)備主標(biāo)識(shí)為4,次設(shè)備號(hào)從64開始,并隨著串口號(hào)的增加而增加,如/dev/ttyS10對應(yīng)的次設(shè)備號(hào)為74;可以通過ls–al命令,列出/dev目錄下所有設(shè)備文件的設(shè)備類型、主設(shè)備號(hào)和次設(shè)備號(hào)。

在串口設(shè)備初始化函數(shù)中,設(shè)備驅(qū)動(dòng)程序使用設(shè)備類型和主設(shè)備號(hào)將該驅(qū)動(dòng)程序的操作接口注冊到內(nèi)核的設(shè)備表中,該接口表連接了內(nèi)核和設(shè)備驅(qū)動(dòng)程序。 該接口包含設(shè)備打開,設(shè)備釋放,設(shè)備讀和設(shè)備寫等。

設(shè)備文件是用來表示Linux所支持的大多數(shù)設(shè)備的,每個(gè)設(shè)備文件除了設(shè)備名,還有3個(gè)屬性:設(shè)備類型、主設(shè)備號(hào)、從設(shè)備號(hào)。 設(shè)備文件在Linux下可以通過mknod系統(tǒng)調(diào)用來創(chuàng)建;

在Hitool環(huán)境下,可以通過修改/vendor/micetek/EV44B0II/makefile來增加新的設(shè)備文件,在編譯時(shí)會(huì)在/romfs/dev下生成對應(yīng)的設(shè)備文件,然后通過genromfs實(shí)用工具生成romfs.img,這個(gè)文件會(huì)被打包到linux.elf中,作為uClinux的根文件系統(tǒng); 這樣,在uClinux中可以看到新建的設(shè)備文件。

當(dāng)應(yīng)用程序打開或讀取設(shè)備文件時(shí),對應(yīng)的系統(tǒng)調(diào)用將訪問該設(shè)備文件在VFS文件系統(tǒng)中的inode數(shù)據(jù)結(jié)構(gòu), 然后找到該設(shè)備文件對應(yīng)的操作接口,這時(shí)所使用的操作接口一般是同一類型設(shè)備的統(tǒng)一操作接口, 接著通過主設(shè)備號(hào)將找到設(shè)備的實(shí)際操作接口,最后操作將在該設(shè)備的驅(qū)動(dòng)程序中執(zhí)行。11.1串行口主要函數(shù)介紹 1.打開串口 在Linux下串口文件是位于/dev下,串口0為/dev/ttyS0,串口1為/dev/ttyS1,O_RDWR是以讀寫方式打開串口, O_NOCTTY表示該程序不會(huì)成為控制終端,避免了當(dāng)在鍵盤輸入類似ctrl+c的命令后,終止程序的運(yùn)行。

打開串口是通過使用標(biāo)準(zhǔn)的文件打開函數(shù)操作:

intfd; fd=open("/dev/ttyS0",O_RDWR); if(-1==fd){ perror("提示錯(cuò)誤!"); } 2.設(shè)置串口 最基本的設(shè)置串口包括波特率設(shè)置,效驗(yàn)位和停止位設(shè)置。 串口的設(shè)置主要是設(shè)置如下structtermios

結(jié)構(gòu)體的各成員值: structtermios { unsignedshortc_iflag; /*輸入模式標(biāo)志*/ unsignedshortc_oflag; /*輸出模式標(biāo)志*/ unsignedshortc_cflag; /*控制模式標(biāo)志*/ unsignedshortc_lflag; /*localmodeflags*/ unsignedcharc_line; /*linediscipline*/ unsignedcharc_cc[NCC];/*controlcharacters*/ };

通過對c_cflag的賦值,設(shè)置波特率,字符大小,使能本地連接,使能串行口驅(qū)動(dòng)讀取輸入數(shù)據(jù)。 通過設(shè)置c_iflag

,控制端口對字符的輸入處理過程,IGNPAR符號(hào)常量表示忽略奇偶性錯(cuò)誤的字節(jié),并不對輸入數(shù)據(jù)進(jìn)行任何校驗(yàn),ICRNL將回車符映射為換行符。

這里就只考慮常見的一些設(shè)置:

(1)波特率設(shè)置 下面是修改波特率的代碼:

structtermiosOpt; tcgetattr(fd,&Opt); cfsetispeed(&Opt,B19200);/*設(shè)置為19200Bps*/ cfsetospeed(&Opt,B19200); tcsetattr(fd,TCANOW,&Opt); (2)校驗(yàn)位和停止位的設(shè)置:

①無效驗(yàn)8位

Option.c_cflag&=~PARENB; Option.c_cflag&=~CSTOPB; Option.c_cflag&=~CSIZE; Option.c_cflag|=~CS8; ②奇效驗(yàn)(Odd)7位

Option.c_cflag|=~PARENB; Option.c_cflag&=~PARODD; Option.c_cflag&=~CSTOPB; Option.c_cflag&=~CSIZE; Option.c_cflag|=~CS7; ③偶效驗(yàn)(Even)7位

Option.c_cflag&=~PARENB; Option.c_cflag|=~PARODD; Option.c_cflag&=~CSTOPB; Option.c_cflag&=~CSIZE; Option.c_cflag|=~CS7; ④Space效驗(yàn)7位

Option.c_cflag&=~PARENB; Option.c_cflag&=~CSTOPB; Option.c_cflag&=&~CSIZE; Option.c_cflag|=CS8; ⑤設(shè)置停止位

1位:options.c_cflag&=~CSTOPB; 2位:options.c_cflag|=CSTOPB;

需要注意的是,如果不是開發(fā)終端之類的,只是串口傳輸數(shù)據(jù),而不需要串口來處理,

那么使用原始模式(RawMode)方式來通訊,設(shè)置方式如下:

options.c_lflag&=~(ICANON|ECHO| ECHOE|ISIG);/*Input*/ options.c_oflag&=~OPOST;/*Output*/ 3.讀寫串口 設(shè)置好串口之后,讀寫串口就很容易了,把串口當(dāng)作文件讀寫就可以了。

(1)發(fā)送數(shù)據(jù)

charbuffer[1024]; intLength=1024; intnByte; nByte=write(fd,buffer,Length) (2)讀取串口數(shù)據(jù) 使用文件操作read函數(shù)讀取,如果設(shè)置為原始模式(RawMode)傳輸數(shù)據(jù),那么read函數(shù)返回的字符數(shù)是實(shí)際串口收到的字符數(shù)。可以使用操作文件的函數(shù)來實(shí)現(xiàn)異步讀取,如fcntl,或者select等來操作。

charbuff[1024]; intLen=1024; intreadByte=read(fd,buff,Len); 4.關(guān)閉串口 關(guān)閉串口就是關(guān)閉文件。

close(fd);11.1.2串口舉例

例:舉一個(gè)有關(guān)接收和發(fā)送數(shù)據(jù)的程序,通過串口交叉線的連接運(yùn)行在不同設(shè)備(也可以是同一臺(tái)設(shè)備)上的例子。

假設(shè)接收程序readtest.c運(yùn)行在裝有標(biāo)準(zhǔn)Linux的PC機(jī)上,發(fā)送程序writetest.c運(yùn)行在目標(biāo)板S3C44B0X上,兩臺(tái)設(shè)備的串口通過交叉線連接在一起。

接收程序readtest.c的源碼如下:

#include<stdio.h> #include<string.h> #include<malloc.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> #include<termios.h> #include"math.h" intspfd; intmain() { charfname[16],hd[16],*rbuf; intretv,i,ncount=0; structtermiosoldtio; intrealdata=0; spfd=open("/dev/ttyS1",O_RDWR|O_NOCTTY); perror("open/dev/ttyS1") if(spfd<0)return-1; tcgetattr(spfd,&oldtio);保存串口的當(dāng)前設(shè)置

cfmakeraw(&oldtio); cfsetispeed(&oldtio,B19200); cfsetospeed(&oldtio,B19200); tcsetattr(spfd,TCSANOW,&oldtio);選擇新設(shè)置,TCSANOW表示設(shè)置立即生效

rbuf=hd; printf("readyforreceivingdata...\n"); retv=read(spfd,rbuf,1); if(retv==-1)perror("read"); while(*rbuf!='\0') { ncount+=1; rbuf++; retv=read(spfd,rbuf,1); printf("thenumberreceivedis%d\n",retv); if(retv==-1)perror("read"); } for(i=0;i<ncount;i++) { realdata+=(hd[i]-48)*pow(10,ncount-i-1); } printf("completereceivingthedata%d\n",realdata); close(spfd); return0; }

發(fā)送程序writetest.c的源碼如下:

#include<stdio.h> #include<string.h> #include<malloc.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> #include<termios.h>

intspfd; intmain(intargc,char*argv[]) { charfname[16],*sbuf; intsfd,retv,i; structtermiosoldtio; spfd=open("/dev/ttyS0",O_RDWR|O_NOCTTY); perror("open/dev/ttyS0"); if(spfd<0)return-1; printf("readyforsendingdata...\n"); tcgetattr(spfd,&oldtio); cfmakeraw(&oldtio); cfsetispeed(&oldtio,B19200); cfsetospeed(&oldtio,B19200); tcsetattr(spfd,TCSANOW,&oldtio); fname[0]='1'; fname[1]='2'; fname[2]='3'; fname[3]='\0'; sbuf=(char*)malloc(4); strncpy(sbuf,fname,4); retv=write(spfd,sbuf,4); if(retv==-1)perror("write"); printf("thenumberofcharsentis%d\n",retv); close(spfd); return0; }

本例程實(shí)現(xiàn):在發(fā)送端發(fā)送數(shù)字123,在接收端接收并顯示接收到的數(shù)據(jù)。 這里請讀者注意的是,發(fā)送方按字符發(fā)送數(shù)據(jù),接收方將接收的字符相應(yīng)的ascii值與字符0所對應(yīng)的ascii值相減,最終得到實(shí)際的十進(jìn)制數(shù)值。11.2網(wǎng)絡(luò)應(yīng)用11.2.1TCP/IP網(wǎng)絡(luò)應(yīng)用

以太網(wǎng)技術(shù)作為當(dāng)前局域網(wǎng)技術(shù)的主流技術(shù),可以提供從10Mbit/s,100Mbit/s到1000Mbit/s的物理帶寬,以及比較好的抗干擾性、比較大的網(wǎng)絡(luò)半徑和比較低系統(tǒng)維護(hù)費(fèi)用; 同時(shí)在不同速率以太網(wǎng)之間保持比較好的前向兼容性,所以在系統(tǒng)升級(jí)時(shí)很方便。

該技術(shù)的標(biāo)準(zhǔn)由IEEE委員會(huì)的802委員會(huì)的802工作組制定和維護(hù),該標(biāo)準(zhǔn)為IEEE802.3。 在EV44B0II上,我們提供了一個(gè)10M/100M自適應(yīng)以太網(wǎng)口。

以太網(wǎng)只具有MAC(MediumAccessControl)層,它使用CSMA/CD協(xié)議來維護(hù)物理網(wǎng)絡(luò)資源的共享訪問。 通過該協(xié)議,以太網(wǎng)提供了盡最大努力的服務(wù),即不是完全可靠的服務(wù),差錯(cuò)的糾正由協(xié)議棧的高層來完成。

一個(gè)以太網(wǎng)包的最大長度為1536字節(jié),其中包含了6字節(jié)的目的地址,6字節(jié)的源地址,2字節(jié)的長度/類型,用戶數(shù)據(jù)部分的長度為64字節(jié)到1500字節(jié),最后的4字節(jié)是對前面內(nèi)容的CRC32校驗(yàn)和。

MAC層完成了數(shù)據(jù)的以太網(wǎng)包封裝,以太網(wǎng)包的發(fā)送和接收。 但是由于網(wǎng)絡(luò)信號(hào)在電平和編碼等方面與MAC層發(fā)出信號(hào)的不同,所以在MAC層和物理插座之間需要增加變壓器(TRANSFORM)和物理接口電路(PHY)

物理接口電路對發(fā)送的數(shù)據(jù)進(jìn)行編碼,并在發(fā)送數(shù)據(jù)的前面插入7字節(jié)的前同步碼和1字節(jié)的幀定界符; 使用前同步碼同步接收數(shù)據(jù)的時(shí)鐘,對接收的數(shù)據(jù)進(jìn)行解碼;并為MAC層的發(fā)送和接收提供同步信號(hào),變壓器對以太網(wǎng)絡(luò)上的信號(hào)進(jìn)行雙極性的合成和電平變換,整個(gè)電路結(jié)構(gòu)如圖11-1所示。圖11-1以太網(wǎng)電路結(jié)構(gòu)圖

這里我們將MAC層和PHY畫在了一起,這主要是因?yàn)镋V44B0II使用的SMSC91C113是同時(shí)具備MAC層功能和PHY層功能的芯片。 1.

網(wǎng)絡(luò)基礎(chǔ)

(1)TCP/IP協(xié)議分層模型 要接觸到網(wǎng)絡(luò)編程,必須首先了解一下計(jì)算機(jī)網(wǎng)絡(luò)的構(gòu)成框架。 網(wǎng)絡(luò)之所以能夠在不同的機(jī)器和不同的操作系統(tǒng)之間進(jìn)行自由的通信,是由一系列規(guī)范的協(xié)議來保障的。

這些協(xié)議分不同的層次進(jìn)行開發(fā)和運(yùn)作,每一層負(fù)責(zé)一定的通信功能,并且都與其他層次有相關(guān)接口,這樣組合成一個(gè)完整的網(wǎng)絡(luò)傳輸系統(tǒng)如圖11-2所示。 圖11-2TCP/IP網(wǎng)絡(luò)協(xié)議的四個(gè)層次

在實(shí)際操作中接觸到的通常只是網(wǎng)絡(luò)系統(tǒng)的最高層——應(yīng)用層的用戶界面。實(shí)際上要進(jìn)行網(wǎng)際的數(shù)據(jù)傳送,需要經(jīng)過如下的步驟:

①需要發(fā)送的數(shù)據(jù)如E-mail、web頁等,通過用戶界面由應(yīng)用程序傳送到應(yīng)用程序的數(shù)據(jù)發(fā)送緩沖區(qū),并設(shè)置好與下一層連接的參數(shù)等待發(fā)送。 這是在用戶的本地機(jī)上完成的,通常我們稱之為應(yīng)用層的操作。

常用的應(yīng)用層程序與協(xié)議有Telnet遠(yuǎn)程登錄程序、HTTP超文本傳輸協(xié)議、FTP文件傳輸協(xié)議、SMTP簡單郵件傳輸協(xié)議和SNMP簡單網(wǎng)絡(luò)管理協(xié)議等。 ②數(shù)據(jù)做好傳輸前的準(zhǔn)備工作,進(jìn)入傳輸層。傳輸層主要負(fù)責(zé)為兩臺(tái)主機(jī)上的應(yīng)用程序提供端口到端口的通信。 一般由TCP(傳輸控制協(xié)議)和UDP(用戶數(shù)據(jù)報(bào)協(xié)議)來完成這項(xiàng)任務(wù)。

它們的工作就是接收應(yīng)用層發(fā)送數(shù)據(jù)緩沖區(qū)中的待發(fā)送數(shù)據(jù),將這些數(shù)據(jù)分組、打包、標(biāo)識(shí)以便傳輸?shù)较乱粚?,同時(shí)TCP還要負(fù)責(zé)數(shù)據(jù)傳輸成功的確認(rèn)等可靠性工作。 而應(yīng)用層則可以忽略這些細(xì)節(jié),這就是分層傳輸?shù)暮锰幩凇?③然后進(jìn)入網(wǎng)絡(luò)層的范疇。這里主要處理數(shù)據(jù)分組在網(wǎng)絡(luò)中的活動(dòng),例如分組的選路。 一般來說,應(yīng)用在這一層的協(xié)議有IP協(xié)議(網(wǎng)際協(xié)議)、ICMP協(xié)議(Intemet控制報(bào)文協(xié)議)、IGMP協(xié)議(Intemet組管理協(xié)議)等。 這里,由傳輸層分組的數(shù)據(jù)將決定它們的傳輸目的地,并分配傳送路線。 ④當(dāng)然最終數(shù)據(jù)還是要靠物理層的電磁波或光導(dǎo)纖維來傳輸。

⑤在接收的一方是相反的過程,數(shù)據(jù)從最底層一直到應(yīng)用層還原為用戶可以識(shí)別的信息,這一切都是由上面的協(xié)議來規(guī)范的。 (2)數(shù)據(jù)的封裝與分用

①數(shù)據(jù)的封裝 用戶數(shù)據(jù)從應(yīng)用層逐級(jí)傳送到鏈路層,每經(jīng)過一層都要被該層的協(xié)議進(jìn)行一定的封裝、標(biāo)識(shí)和改造,就是給這個(gè)數(shù)據(jù)增加一些頭部信息(或尾部信息)。

我們把每層經(jīng)過封裝的數(shù)據(jù)單元加以識(shí)別,比如TCP傳給IP的成為TCP段(TCPsegment),IP層的稱作IP數(shù)據(jù)報(bào)(IPdatagram)等。 數(shù)據(jù)封裝過程如圖11-3所示。圖11-3數(shù)據(jù)的封裝過程

UDP數(shù)據(jù)與TCP數(shù)據(jù)基本一致,只是它們的頭部長度不同,名稱也不同。 許多應(yīng)用程序都可以使用TCP或UDP來傳送數(shù)據(jù)。傳輸層協(xié)議在生成數(shù)據(jù)段首部時(shí)要加入一個(gè)該應(yīng)用程序的標(biāo)識(shí)符。

TCP和UDP都用一個(gè)16位的端口號(hào)來表示不同的應(yīng)用程序,這些端口號(hào)都標(biāo)識(shí)在數(shù)據(jù)報(bào)的頭部。 ②IP頭部要說明數(shù)據(jù)傳輸?shù)哪康牡匾约吧弦粚訁f(xié)議的類型標(biāo)識(shí)等。

③數(shù)據(jù)的分用(解包)

在接收端接收這些數(shù)據(jù)的時(shí)候,經(jīng)過拆分的數(shù)據(jù)要重新組合,并且去掉各層加上的頭部信息,把數(shù)據(jù)還原。

這是一個(gè)與上面相反的逆過程,具體地說,首先根據(jù)從Ethernet最底層來的數(shù)據(jù)進(jìn)行分用,判斷鏈路層協(xié)議是IP、ARP、RARP等協(xié)議; 而后根據(jù)IP頭部信息判斷傳輸層協(xié)議; 進(jìn)而通過TCP/UDP中應(yīng)用程序端口號(hào)的頭信息進(jìn)行應(yīng)用程序分用,直到最后數(shù)據(jù)達(dá)到最高層交付用戶。 (3)客戶——服務(wù)器模型 目前大多數(shù)網(wǎng)絡(luò)應(yīng)用程序在編寫時(shí)都采用客戶——服務(wù)器模型,假設(shè)—端是客戶,另一端是服務(wù)器,讓服務(wù)器提供給客戶一定的服務(wù)內(nèi)容。 這里可以再分為兩種具體類型:并發(fā)型交互與重復(fù)型交互。 ①并發(fā)型交互 在并發(fā)型交互模式下,程度的主要運(yùn)作步驟如下:

◆等待一個(gè)客戶請求的到來;

◆生成一個(gè)新的進(jìn)程或者任務(wù)來處理這個(gè)客戶請求,同時(shí)這里還可以接收其他客戶的請求。處理結(jié)束后,終止這個(gè)進(jìn)程。

◆反饋客戶端;

◆等待新的客戶請求的到來并進(jìn)行下一次服務(wù),如此循環(huán)運(yùn)作。 ②重復(fù)型交互 重復(fù)型交互摸式下,程序的的主要運(yùn)作步驟如下:

◆等待一個(gè)客戶請求的到來;

◆處理客戶的請求,對客戶進(jìn)行服務(wù);

◆給客戶反饋信息,服務(wù)結(jié)束;

◆等待下一個(gè)請求到來,如此循環(huán)。

這里重復(fù)型交互的缺點(diǎn)就是在服務(wù)器給二個(gè)客戶處理請求服務(wù)的時(shí)候,不能接收和處理其他客戶的請求; 而并發(fā)型交互就可以解決這個(gè)問題,但要多線程操作系統(tǒng)的支持。

—般來說,UDP服務(wù)器采用重復(fù)型交互,TCP服務(wù)器采用并發(fā)型服務(wù)。 2.TCP套接字

Linux系統(tǒng)的套接字是一個(gè)通用的網(wǎng)絡(luò)編程接口。

TCP協(xié)議就是通過套接字來實(shí)現(xiàn)連接的建立的,這里將就這個(gè)過程具體化并對其內(nèi)部的函數(shù)進(jìn)行必要的說明。

一個(gè)TCP連接的建立開始于TCP客戶機(jī)創(chuàng)建一個(gè)套接字,然后調(diào)用connect函數(shù)啟動(dòng)TCP協(xié)議的三方握手操作,并與遠(yuǎn)程服務(wù)器建立連接。

在服務(wù)器方面,當(dāng)套接字建立以后,調(diào)用函數(shù)bind綁定自己的公認(rèn)端口號(hào),然后調(diào)用listen來準(zhǔn)備接收客戶端請求,最后調(diào)用函數(shù)accept完成接收,這樣一次通訊才告結(jié)束。 直到最后需要關(guān)閉連接的時(shí)候,客戶機(jī)與服務(wù)器調(diào)用函數(shù)close來關(guān)閉連接。 (1)套接字地址結(jié)構(gòu)

Linux系統(tǒng)的套接字可以支持多種協(xié)議,每一種協(xié)議都使用不同的套接字地址結(jié)構(gòu)。在頭文件<Linux/socket.h>中定義了以下結(jié)構(gòu)來保持套接字函數(shù)調(diào)用參數(shù)的一致性。

structsockaddr { unsignedshortsa_family;

/*地址類型,格式為AF_xxx*/ charsa_data[14];/*14字節(jié)的協(xié)議地址*/ };

其中的sa_family為套接字的協(xié)議簇地址類型,TCP/IP的協(xié)議對于IPv4地址類型為AF_INET。

sa_data中存儲(chǔ)具體的協(xié)議地址,不同的協(xié)議簇有不同的地址格式。但一般編程中并不直接針對此數(shù)據(jù)結(jié)構(gòu)操作,而是使用另一個(gè)與sockaddr等價(jià)的數(shù)據(jù)結(jié)構(gòu)sockaddr_in(在netinet/in.h中定義):

structsockaddr_in { unsignedshortintsin_len; /*IPv4地址長度*/ shortintsin_family; /*地址類型*/ unsignedshortintsin_port; /*存儲(chǔ)端口號(hào)*/ structin_addrsin_addr; /*存儲(chǔ)IP地址*/ unsignedcharsin_zero[8];/*空字節(jié)*/ };

在編程中大多數(shù)是使用sockaddr_in這個(gè)結(jié)構(gòu)來設(shè)置獲取地址信息。

sin_family指代協(xié)議族,在TCP套接字編程中只能是AF_INET;sin_port存儲(chǔ)端口號(hào)(使用網(wǎng)絡(luò)字節(jié)順序),數(shù)據(jù)類型是一個(gè)16位的無符號(hào)整數(shù)類型; sin_addr存儲(chǔ)IP地址,IP地址使用in_addr這個(gè)數(shù)據(jù)結(jié)構(gòu):

structin_addr{ unsignedlongs_addr;

}; 這個(gè)數(shù)據(jù)結(jié)構(gòu)是由于歷史原因保留下來的,主要用作與以前的格式兼容。 s_addr按照網(wǎng)絡(luò)字節(jié)順序存儲(chǔ)IP地址;sin_zero是為了讓sockaddr與sockaddr_in兩個(gè)數(shù)據(jù)結(jié)構(gòu)保持大小相同而保留的空字節(jié)。

設(shè)置地址信息實(shí)例(IPv4) structsockaddr_inmysock;

/*設(shè)置sockaddr_in的結(jié)構(gòu)體變量mysock*/ mysock.sin_family=AF_INET;

/*TCP地址結(jié)構(gòu)*/ mysock.sin_port=htons(3490);

/*short,NBO*/ mysock.sin_addr.s_addr=inet_addr(“0”);

/*設(shè)置地址為0*/ bzero(&(mysock.sin_zero),8);

/*設(shè)置sin_zero為8位保留字節(jié)*/

注意:如果mysock.sin_addr.s_addr=INADDR_ANY,則不指定IP地址(用于Server程序)。 (2)TCP客戶-服務(wù)器通信模型

TCP客戶-服務(wù)器通信過程如圖11-4所示。 (3)socket主要函數(shù)

①強(qiáng)制類型轉(zhuǎn)換函數(shù)的調(diào)用:

將指向于特定協(xié)議的套接口地址結(jié)構(gòu)的指針類型->

指向通用套接口地址結(jié)構(gòu)的指針。

int

connect(

int,

struct

sockaddr

*,

socklen_t) struct

sockaddr-in

servaddr; connect(sockfd,(sturct

sockaddr

*)

&servaddr,

sizeof(servaddr)); ②主機(jī)字節(jié)序和網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換函數(shù):

#include

<netinet/in.h>

unit16_t

htons(uint16_t

host16bitvalue);

unit32_t

htons(uint32_t

host32bitvalue);

unit16_t

ntohs(uint16_t

net16bitvalue);

unit32_t

ntohs(uint32_t

net32bitvalue);

h

:

host

n

:

network

s

:

short

(16

bits)

l

:

long

(32

bits)

int

socket(int

domain,

int

type,int

protocol)

domain:說明我們網(wǎng)絡(luò)程序所在的主機(jī)采用的通訊協(xié)族(AF_UNIX和AF_INET等)。

type:我們網(wǎng)絡(luò)程序所采用的通訊協(xié)議(SOCK_STREAM,SOCK_DGRAM等)

SOCK_STREAM表明我們用的是TCP協(xié)議,這樣會(huì)提供按順序的,可靠,雙向,面向連接的比特流。SOCK_DGRAM

表明我們用的是UDP協(xié)議,這樣只會(huì)提供定長的,不可靠,無連接的通信。

protocol:由于我們指定了type,所以這個(gè)地方我們一般只要用0來代替就可以了。

socket為網(wǎng)絡(luò)通訊做基本的準(zhǔn)備。成功時(shí)返回文件描述符,失敗時(shí)返回-1,看errno可知道出錯(cuò)的詳細(xì)情況。 ④

int

bind(int

sockfd,

struct

sockaddr

*my_addr,

int

addrlen)

sockfd:是由socket調(diào)用返回的文件描述符。

addrlen:是sockaddr結(jié)構(gòu)的長度。

my_addr:是一個(gè)指向sockaddr的指針。 ⑤

int

listen(int

sockfd,int

backlog)

sockfd:是bind后的文件描述符。

backlog:設(shè)置請求排隊(duì)的最大長度。當(dāng)有多個(gè)客戶端程序和服務(wù)端相連時(shí),

使用這個(gè)表示可以介入的排隊(duì)長度。

listen函數(shù)將bind的文件描述符變?yōu)楸O(jiān)聽套接字,返回的情況和bind一樣。 ⑥

int

accept(int

sockfd,

struct

sockaddr

*addr,int

*addrlen)

sockfd:是listen后的文件描述符。

addr,addrlen是用來給客戶端的程序填寫的,服務(wù)器端只要傳遞指針就可以了。

bind,listen和accept是服務(wù)器端用的函數(shù),accept調(diào)用時(shí),服務(wù)器端的程序會(huì)一直阻塞到有一個(gè)客戶程序發(fā)出了連接。 accept成功時(shí)返回最后的服務(wù)器端的文件描述符,這個(gè)時(shí)候服務(wù)器端可以向該描述符寫信息了,失敗時(shí)返回-1。

int

connect(int

sockfd,

struct

sockaddr

*

serv_addr,int

addrlen)

sockfd:socket返回的文件描述符。

serv_addr:儲(chǔ)存了服務(wù)器端的連接信息,其中sin_add是服務(wù)端的地址。

addrlen:serv_addr的長度

connect函數(shù)是客戶端用來同服務(wù)端連接的。成功時(shí)返回0,sockfd是同服務(wù)端通訊的文件描述符,失敗時(shí)返回-1。 ⑧

ssize_t

write(int

fd,const

void

*buf,size_t

nbytes) write函數(shù)將buf中的nbytes字節(jié)內(nèi)容寫入文件描述符fd。成功時(shí)返回寫的字節(jié)數(shù),失敗時(shí)返回-1。并設(shè)置errno變量,在網(wǎng)絡(luò)程序中,當(dāng)我們向套接字文件描述符寫時(shí)有兩種可能。

◆write的返回值大于0,表示寫了部分或者是全部的數(shù)據(jù)。

◆返回的值小于0,此時(shí)出現(xiàn)了錯(cuò)誤.我們要根據(jù)錯(cuò)誤類型來處理。

ssize_t

read(int

fd,void

*buf,size_t

nbyte)

read函數(shù)是從fd中讀取內(nèi)容。當(dāng)讀成功時(shí),read返回實(shí)際所讀的字節(jié)數(shù),如果返回的值是0

表示已經(jīng)讀到文件的結(jié)束了,小于0表示出現(xiàn)了錯(cuò)誤。

recv和send函數(shù)提供了和read和write差不多的功能,不過提供了第四個(gè)參數(shù)來控制讀寫操作。

int

recv(int

sockfd,void

*buf,int

len,int

flags) int

send(int

sockfd,void

*buf,int

len,int

flags)

前面的三個(gè)參數(shù)和read,write一樣,第四個(gè)參數(shù)可以是0或者是以下的組合: ◆MSG_DONTROUTE:不查找路由表

◆MSG_OOB

:接受或者發(fā)送帶外數(shù)據(jù)

◆MSG_PEEK

:查看數(shù)據(jù),并不從系統(tǒng)緩沖區(qū)移走數(shù)據(jù)

◆MSG_WAITALL

:等待所有數(shù)據(jù) 3.舉例 我們將使用TCP協(xié)議提供的服務(wù),組成一個(gè)簡單的重復(fù)型的網(wǎng)絡(luò)時(shí)間服務(wù)器。 在一臺(tái)EV44B0II系統(tǒng)中啟動(dòng)服務(wù)程序并指定服務(wù)端口。在另外一臺(tái)EV44B0II系統(tǒng)中啟動(dòng)客戶端程序并指定服務(wù)器IP地址和服務(wù)端口。服務(wù)器將接收該服務(wù),并返回服務(wù)器本地的系統(tǒng)時(shí)間。

本程序使用TCP協(xié)議,可以工作在服務(wù)器或客戶端狀態(tài)。 使用的默認(rèn)端口號(hào)為9988。

程序流程圖如下:

附程序清單:

/*TCP/IPnettimeservice*/ #include<sys/param.h> #include<sys/stat.h> #include<sys/ioctl.h> #include<sys/socket.h> #include<sys/time.h> #include<sys/file.h> #include<netinet/in.h> #include<netinet/ip.h> #include<netinet/tcp.h> #include<arpa/inet.h> #include<stdio.h> #include<signal.h> #include<string.h> #include<stdlib.h> #include<unistd.h> #include<errno.h> #include<netdb.h> #include<pwd.h> #include<stdarg.h> externchar*optarg; /*getopt*/ #defineCOM_SERVER1 #defineCOM_CLIENT 2 intComStatus; #definePORT_NUMBER 0x1000 shortComPort; intmain(intargc,char*argv[]) { intfd_listen,fd_client,fd_service; charserver_ip[64]; intport; structsockaddr_insn={AF_INET}; intsa_len; char*buffer; intstart,packet_len,c,counter; intdebug; ComStatus=COM_SERVER; ComPort=PORT_NUMBER; while((c=getopt(argc,argv,"sc:o:"))!=-1) { switch(c) { case'c':/*getserveripaddress*/ memcpy(server_ip,optarg,(strlen(optarg)+1)); ComStatus=COM_CLIENT; break; case's': /*opendebugflag*/ ComStatus=COM_SERVER; break; case'o': ComPort=atoi(optarg); break;

default: /*printusage*/ fprintf(stderr,"Usage:%s[[-c<serverip>]|-s][-p<port>]\n",argv[0]); exit(1); } }

/*setupaddressandport*/ sn.sin_port=__constant_htons(ComPort); sn.sin_addr.s_addr=0; if(argc<2) { fprintf(stderr,"\nargvtooless\n"); exit(1); }

/*allocmemfordatabuffer*/ packet_len=256; buffer=malloc(packet_len); if(buffer<0) { fprintf(stderr,"\nmallocbuffererror\n"); exit(1); } if(ComStatus==COM_SERVER) { /*serverprocess*/ if((fd_listen= socket(AF_INET,SOCK_STREAM,0))<0) { fprintf(stderr,"\ncannotopenserver socket,exit\n"); exit(1); } if(bind(fd_listen,(structsockaddr*)&sn,sizeof(sn))<0) { fprintf(stderr,"\ncannotbinserver,socket,exit\n"); close(fd_listen); exit(1); } if(listen(fd_listen,1)<0) { fprintf(stderr,"listenfailed,exit"); close(fd_listen); exit(1); } sa_len=sizeof(sn); while(1) {/*loopservice*/ fd_service=accept(fd_listen,(structsockaddr*)&sn,&sa_len); if(fd_service<0) { perror("acceptfailed"); exit(1); } else { printf("\ngetservicerequestfrom%s\n",inet_ntoa(sn.sin_addr)); } start=time(0); *(int*)buffer=start; if(write(fd_service,buffer,packet_len)<0) { perror("serverwrite"); close(fd_listen); close(fd_service); exit(1); } printf("\ncurrenttime%ds\n",start); close(fd_service); } close(fd_listen); } else { /*clientprocess*/ if((fd_client=socket(AF_INET,SOCK_STREAM,0))<0) { perror("clientsocket"); exit(1); } sn.sin_addr.s_addr=inet_addr(server_ip); sa_len=sizeof(sn); if(connect(fd_client,(structsockaddr*)&sn,sa_len)<0) { perror("clientconnect"); close(fd_client); exit(1); } if((counter=read(fd_client,buffer,packet_len))<=0) { perror("receivefailed"); close(fd_client); exit(1); } start=*(int*)(buffer); printf("\nnetservertime%d s\n",start); close(fd_client); } free(buffer); exit(0); }

首先配置開發(fā)板IP地址(ifconfigeth020netmask

),配置Hitools的調(diào)試協(xié)議為MDB,啟動(dòng)主機(jī)的TargetServer程序運(yùn)行,選擇Hitools

的loadimagethenforktask窗口的CommandLine中填寫參數(shù)(–s–o8888),然后帶參下載運(yùn)行。

其次啟動(dòng)客戶端程序,在超級(jí)終端中,進(jìn)入目錄/var/tmp,鍵入./nettime–c20–o8888回車。 超級(jí)終端顯示客戶端程序輸出了服務(wù)器端的以秒為單位的時(shí)間:“netservertime333s”。11.2.2web服務(wù)器應(yīng)用 1.Web服務(wù)器的原理 從原理上來說,Web服務(wù)器與其他在socket端口進(jìn)行監(jiān)聽的應(yīng)用程序差別不大,都是監(jiān)聽并接收用戶請求,遵循HTTP協(xié)議,根據(jù)請求內(nèi)容和類型,使用串行和并行方式提供相應(yīng)的服務(wù)。

Web服務(wù)的客戶端一般是Web瀏覽器,如IE、Mozila等。 使用Web服務(wù)的好處是:在提供服務(wù)時(shí),客戶端的軟件是標(biāo)準(zhǔn)的,不需要考慮客戶端軟件的開發(fā)問題,使用者容易上手;服務(wù)器端的開發(fā),也是有很多現(xiàn)成的資源可以利用。

由于HTTP協(xié)議是基于請求/響應(yīng)范式的(相當(dāng)于客戶機(jī)/服務(wù)器)。 一個(gè)客戶機(jī)與服務(wù)器建立連接后,發(fā)送一個(gè)請求給服務(wù)器,請求方式的格式為:統(tǒng)一資源標(biāo)識(shí)符(URL)、協(xié)議版本號(hào),后邊是MIME信息包括請求修飾符、客戶機(jī)信息和可能的內(nèi)容。

服務(wù)器接到請求后,給予相應(yīng)的響應(yīng)信息,其格式為一個(gè)狀態(tài)行,包括信息的協(xié)議版本號(hào)、一個(gè)成功或錯(cuò)誤的代碼,后邊是MIME信息包括服務(wù)器信息、實(shí)體信息和可能的內(nèi)容。 許多HTTP通訊是由一個(gè)用戶代理初始化的并且包括一個(gè)申請?jiān)谠捶?wù)器上資源的請求。

最簡單的情況可能是在用戶代理和服務(wù)器之間通過一個(gè)單獨(dú)的連接來完成。在Internet上,HTTP通訊通常發(fā)生在TCP/IP連接之上。 缺省端口是TCP80,但其它的端口也是可用的。 2.基于uClinux的Web技術(shù)

uClinux下,主要有三個(gè)Web服務(wù)器:httpd,thttpd和boa。

Httpd是最簡單的Web服務(wù)器,功能比較簡單,不支持認(rèn)證和CGI。thttpd和boa均支持認(rèn)證和CGI,功能比較豐富,其中boa是一個(gè)單任務(wù)的http服務(wù)器,源代碼開放,性能比較高,占用系統(tǒng)資源比較少。

boa服務(wù)器在接收到請求時(shí),不啟動(dòng)多個(gè)服務(wù)進(jìn)程處理多個(gè)請求,在一個(gè)進(jìn)程內(nèi)處理所有服務(wù)請求。 對于CFG程序,將生成新的進(jìn)程來處理。所以在嵌入式應(yīng)用中使用boa比較多。

由于目前的uClinux還不支持ASP、PHP等動(dòng)態(tài)網(wǎng)頁技術(shù),所有在uClinux下通過CGI技術(shù)連接web頁和本地程序,提供動(dòng)態(tài)和交互的特性。

CGI程序是本地的程序,需要編譯成可執(zhí)行文件,以便在被CGI調(diào)用時(shí)運(yùn)行。 Web服務(wù)器將用戶數(shù)據(jù)傳遞給CGI程序,并重定向CGI程序的輸出到Web頁,CGI程序在處理時(shí)要將數(shù)據(jù)封裝成HTML形式發(fā)送到輸出,這樣在客戶端將看到對應(yīng)的Web頁。 boa的配置文件boa.conf:在boa.conf中,對boa的一些配置項(xiàng)進(jìn)行了配置,這些配置項(xiàng)大多可以使用默認(rèn)值。 如PORT等。其中DocumentRoot指定了web服務(wù)器的根,所有的web文件的查找都從這個(gè)根開始,所以如果要根據(jù)應(yīng)用中的需要修改。

本程序?qū)⑺麄冃薷臑?tmp

。 在mime.type中,定義了目前boa支持的文件后綴,以及對應(yīng)的類型。 如image/gif――gif。通過這種對應(yīng)關(guān)系,boa確定了如何處理這種后綴的文件,是顯示,還是下載,還是執(zhí)行。

本程序?qū)⒃贓V44B0IIuClinux系統(tǒng)中,啟動(dòng)一個(gè)web服務(wù)器,并添加簡單的網(wǎng)頁和CGI程序。 這里要對EV44B0IILinux程序包中的一些文件進(jìn)行修改:

在對內(nèi)核配置時(shí),選擇boa程序和cgi

。 將cgi_generic文件夾下的cgi.c

和makefile,覆蓋到程序包中的/usr/cgi_generic/。 將boa文件夾下的hash.c,覆蓋到程序包中的/usr/boa/src。 將rc文件,覆蓋到程序包中的/vendor/Miectek/44b0。 EV44B0IIuClinux系統(tǒng)中文件系統(tǒng)使用的是ROMFS和運(yùn)行于RAM的EXT2(RAMDISK),其中ROMFS是只讀的,RAMDISK是可以讀寫的。 為了可以通過FTP等工具更新網(wǎng)頁,rc文件在/tmp下創(chuàng)建文件夾cgi_bin,然后將index.html,boa.conf和mime.type拷貝到/tmp下,將CGI程序拷貝到/tmp/cgi_bin下。到此建立了boa運(yùn)行的基本環(huán)境。 要運(yùn)行boa,使用“>boa–c/tmp/&”命令。 3.程序說明

/*rc*/ /*本腳本將為boa建立運(yùn)行的根目錄,和其他運(yùn)行環(huán)境*/ hostnameSamsung /bin/expand/etc/ramfs.img/dev/ram0 mount-tprocproc/proc mount-text2/dev/ram0/var mkdir/var/config mkdir/var/tmp mkdir/var/log mkdir/var/run mkdir/var/lock cat/etc/motd ifconfiglo routeadd-netnetmasklo dhcpcd-p-aeth0& cd/tmp mkdircgi_bin cd/etc cpindex.html/tmp cpboa.conf/tmp cpmime.types/tmp cpcgi_bin/*/tmp/cgi_bin chmod775/tmp/cgi_bin/* #mount-tjffs/dev/mtdblock1/var #ifconfigeth0hwether00:11:22:33:44:55 #ifconfigeth04 #login

/*cgi.c*/ /*本程序接收boa傳遞的參數(shù),控制數(shù)碼管顯示指定的數(shù)字,并返回網(wǎng)頁*/ #include<stdio.h> #include<string.h> #include"cgivars.h" #include"htmllib.h" #include"template.h" intmain(){ char**postvars=NULL; /*POSTrequestdatarepository*/ char**getvars=NULL;

/*GETrequestdatarepository*/ intform_method; /*POST=1,GET=0*/

form_method=getRequestMethod();

/*decideformrequestmethod,POSTorGET*/ if(form_method==POST) { /*getvarsfromrequeststring*/ getvars=getGETvars(); postvars=getPOSTvars(); }elseif(form_method==GET) {/*Inthisexp,weuseGETinindex.html*/ getvars=getGETvars();

if(getvars) { inti=0;

while(getvars[i]) { if(strcmp(getvars[i],"LampNum")==0) {/*getwhichnumberison*/ /*controlreg*/ staticvolatileunsignedint

*iopmod=(volatileunsignedint*)(0x3ff5000); staticvolatileunsignedint *iopdata=(volatileunsignedint*)(0x3ff5008); intlampnum=0; lampnum= strtoul(getvars[i+1],NULL,0);

/*lightnumber*/ iopmod[0]=0x000000ff; iopdata[0]=(~lampnum); break; } i+=2; } } }

/*writewebpagetostdout*/ htmlHeader("DemoWebPage"); htmlBody(); template_page(postvars,form_method); htmlFooter(); cleanUp(form_method,getvars,postvars);

/*display*/ fflush(stdout); exit(0); } 4.運(yùn)行過程

(1)對程序修改后,重新編譯內(nèi)核并焼寫燒寫到EV44B0II評估板。

(2)啟動(dòng)EV44B0II評估板。確認(rèn)EV44B0II的IP地址。

(3)運(yùn)行boa-c/tmp/&,啟動(dòng)web服務(wù)器。 (4)打開PC上的瀏覽器(如IE6或Netscape)輸入EV44B0II的IP作為網(wǎng)址,例如25/

,這時(shí)就可以看到要測試的網(wǎng)頁內(nèi)容。網(wǎng)頁內(nèi)容是/tmp/index.html文件。 (5)在lampnumber文本框中,寫入“1”,然后點(diǎn)擊“display”。

(6)EV44B0上的數(shù)碼管顯示對應(yīng)數(shù)字。

(7)在瀏覽器上顯示“DemoWebPage”。11.3音頻設(shè)備應(yīng)用

S3C44B0II包含一個(gè)IIS總線接口,它可以作為連接8位或16位立體聲編解碼集成電路的接口,IIS總線接口提供內(nèi)置FIFO的DMA傳送模式,可以同時(shí)接收和發(fā)送,或單獨(dú)接收和發(fā)送。 IIS總線接口可以發(fā)送和接收采樣量化過的聲音數(shù)據(jù),它為外部的CODEC芯片提供工作主時(shí)鐘,數(shù)據(jù)收發(fā)時(shí)鐘和左右聲道選擇信號(hào)。 具體的采樣量化工作留給CODEC芯片完成。在接收方向,CODEC將模擬聲音采樣量化;在發(fā)送方向,CODEC將聲音數(shù)據(jù)還原為模擬聲音。

EV44B0II使用的CODEC芯片是UDA1341TS。 UDA1341和IIS的驅(qū)動(dòng)程序,位于/Linux/drivers/char目錄下。 它們是ev44b0_sound.c、ev44b0_sound.h、l3-ev44b0.c。 音頻設(shè)備文件的設(shè)備名為/dev/audio。11.3.1常用音頻文件格式1.WAV文件(1)概述

WAV是MicrosoftWindows本身提供的音頻格式,由于Windows本身的影響力,這個(gè)格式已經(jīng)成為了事實(shí)上的通用音頻格式。

不客氣地說,它實(shí)際上是Apple電腦的AIFF格式的克隆。 通常我們使用WAV格式都是用來保存一些沒有壓縮的音頻,但實(shí)際上WAV格式的設(shè)計(jì)是非常靈活(非常復(fù)雜)的,該格式本身與任何媒體數(shù)據(jù)都不沖突,換句話說,只要有軟件支持,你甚至可以在WAV格式里面存放圖像。

之所以能這樣,是因?yàn)閃AV文件里面存放的每一塊數(shù)據(jù)都有自己獨(dú)立的標(biāo)識(shí),通過這些標(biāo)識(shí)可以告訴用戶究竟這是什么數(shù)據(jù)。

在WINDOWS平臺(tái)上通過ACM(AudioCompressionManager)結(jié)構(gòu)及相應(yīng)的驅(qū)動(dòng)程序(在這里通常稱為CODEC,編碼/解碼器),可以在WAV文件中存放超過20種的壓縮格式,比如ADPCM、GSM、CCITTG.711、G.723等等,當(dāng)然也包括MP3格式。

雖然WAV文件可以存放壓縮音頻甚至mp3,但由于它本身的結(jié)構(gòu)注定了它的用途是存放音頻數(shù)據(jù)并用作進(jìn)一步的處理,而不是像mp3那樣用于聆聽。

目前所有的音頻播放軟件和編輯軟件都支持這一格式,并將該格式作為默認(rèn)文件保存格式之一。 這些軟件包括:SoundForge,CoolEditPro,WaveLab等等。由于WAV的支持實(shí)在是太廣泛了,可以說,即使Windows退出歷史舞臺(tái),WAV格式也不會(huì)消亡。(2)WAV文件的結(jié)構(gòu) 多媒體技術(shù)近年來發(fā)展很快,較好品質(zhì)的聲卡可以提供16位的立體聲及44KHZ的播放錄制能力.

它不僅可以提供原音逼真的取樣,其合成的音質(zhì)也十分理想,有的聲卡還加入了數(shù)字信號(hào)處理器

可編程控制的DSP具有強(qiáng)大的運(yùn)算能力,它可以用來作聲音信息的壓縮和一些特殊效果的處理。 具有此功能的聲卡提供的WAV文件可以滿足語音特征識(shí)別的要求。

在Windows環(huán)境下,大部分的多媒體文件都遵循著一種結(jié)構(gòu)來存放信息,這種結(jié)構(gòu)稱為"資源互換文件格式"(ResourceslnterchangeFileFormat),簡稱RIFF。

例如聲音的WAV文件、視頻的AVI文件等等均是由此結(jié)構(gòu)衍生出來的。

RIFF可以看做是一種樹狀結(jié)構(gòu),其基本構(gòu)成單位為chunk,猶如樹狀結(jié)構(gòu)中的節(jié)點(diǎn),每個(gè)chunk由"辨別碼"、"數(shù)據(jù)大小"及"數(shù)據(jù)"所組成。

辨別碼由4個(gè)ASCII碼所構(gòu)成,數(shù)據(jù)大小則標(biāo)示出緊跟其后數(shù)據(jù)的長度(單位為Byte),而數(shù)據(jù)大小本身也用掉4個(gè)Byte,所以事實(shí)上一個(gè)chunk的長度為數(shù)據(jù)大小加8。

一般而言,chunk本身并不允許內(nèi)部再包含chunk,但有兩種例外,分別為以“RIFF”及“L1ST”為辨別碼的chunk。 而針對此兩種chunk,RIFF又從原先的"數(shù)據(jù)"中切出4個(gè)Byte。此4個(gè)Byte稱為"格式辨別碼",然而RIFF又規(guī)定文件中僅能有一個(gè)以"RIFF"為辨別碼的chunk。

只要依循此一結(jié)構(gòu)的文件,我們均稱之為RIFF文檔。此種結(jié)構(gòu)提供了一種系統(tǒng)化的分類。 如果和MSDOS文件系統(tǒng)作比較,"RIFF"chunk就好比是一臺(tái)硬盤的根目錄,其格式辨別碼便是此硬盤的邏輯代碼(C:或D:),而"L1ST"chunk即為其下的子目錄,其他的chunk則為一般的文件。

至于在RIFF文件的處理方面,微軟提供了相關(guān)的函數(shù)。 視窗下的各種多媒體文件格式就如同在磁盤機(jī)下規(guī)定僅能放怎樣的目錄,而在該目錄下僅能放何種數(shù)據(jù)。 WAV為WAVEFORM(波形)的縮寫。聲音文件的結(jié)構(gòu)如圖11-6所示,“RIFF”的格式辨別碼為“WAVE”。

整個(gè)文件由兩個(gè)chunk所組成:辨別碼"fmt"(注意,最后一個(gè)是空白字符!)及"data"。 在"fmt"的chunk下包含了一個(gè)PCMWAVEFORMAT數(shù)據(jù)結(jié)構(gòu),其定義如下: typedefstructpcmwaveformat-tag{

WAVEFORMATwf

;

WORDwBitsPerSample;

}PCMWAVEFORMAT; typedefstructwaveformat-tag{

WORDwFormatTag;

WORDnChannels;

DWORDnSamplesPerSec;

DWORDnAvgBytesperSec;

WORDnBlockAlign;

}WAVEFORMAT;

其意義分別為:

wFormatTag:記錄著此聲音的格式代號(hào),例如WAVE_FORMAT_PCM,WAVE_F0RAM_ADPCM等等。

nChannels:記錄聲音的頻道數(shù)。

nSamp1esPerSec:記錄每秒取樣數(shù)。

nAvgBytesPerSec:記錄每秒的數(shù)據(jù)量。

nBlockA1ign:記錄區(qū)塊的對齊單位。

wBitsPerSample:記錄每個(gè)取樣所需的位元數(shù)。 “data”Chunk包含真正的聲音數(shù)據(jù)。Window目前僅提供WAVE_FORMAT_PCM一種數(shù)據(jù)格式,所代表的意義是脈派編碼調(diào)制(Pu1seCodeModulation)。 針對此格式,Windows定義了在"data"的chunk中數(shù)據(jù)的存放情形,列出了四種不同頻道數(shù)及取樣所需的位元數(shù)以及位元位置的安排。

"RIFF"頻道0頻道0頻道0頻道0

xxxxnChannels=1,wBitsPerSample=8

"WAVE"頻0(左)頻道1(右)頻道0(左)頻道1(右)

"fmt"

nChannels=2,wBitsPerSample=8

sizeof(PCMWAVEFORMAT) structofPCMWAVEFORMAT頻道0(低位)頻道0(高位)頻道0(低位)頻道0(高位)

"data"nChannels=1,wBitsPerSample=16

xxxx

頻道0(低位)頻道0(高位)頻道0(低位)頻道0(高位)

(低位)(高位)(低位)(高位)

waveformdata nChannels=2,wBitsPerSample=16 2.mp3格式

(1)概述

mp3是Fraunhofer-IIS研究所的研究成果。mp3是第一個(gè)實(shí)用的有損音頻壓縮編碼。 在mp3出現(xiàn)之前,一般的音頻編碼即使以有損方式進(jìn)行壓縮能達(dá)到4:1的壓縮比例已經(jīng)非常不錯(cuò)了。

但是,mp3可以實(shí)現(xiàn)12:1的壓縮比例,這使得mp3迅速地流行起來。

mp3之所以能夠達(dá)到如此高的壓縮比例同時(shí)又能保持相當(dāng)不錯(cuò)的音質(zhì)是因?yàn)槔昧酥X音頻編碼技術(shù),也就是利用了人耳的特性,削減音樂中人耳聽不到的成分,同時(shí)嘗試盡可能地維持原來的聲音質(zhì)量。

衡量mp3文件的壓縮比例通常使用比特率來表示。 這個(gè)術(shù)語的英文是bps,表示每1秒鐘的音頻可以用多少個(gè)二進(jìn)制比特來表示。通常比特率越高,壓縮文件就越大,但音樂中獲得保留的成分就越多,音質(zhì)就越好。

由于比特率與文件大小音質(zhì)的關(guān)系,所以后來又出現(xiàn)了vbr(VariantBitrate

可變比特率)方式編碼的mp3.

這種編碼方式的特點(diǎn)是可以根據(jù)編碼的內(nèi)容動(dòng)態(tài)地選擇合適的比特率,因此編碼的結(jié)果是在保證了音質(zhì)的同時(shí)又照顧了文件的大小,結(jié)果大受歡迎。

其實(shí)mp3的編碼標(biāo)準(zhǔn)本來就支持這種壓縮方式, 但是第一個(gè)將此功能實(shí)現(xiàn)的反而是一個(gè)第三方工具:曾經(jīng)非常有名的XingTechnology公司。

由于mp3是世界上第一個(gè)有損壓縮的編碼方案,所以可以說所有的播放軟件都支持它,否則就根本沒有生命力。在制作方面,也曾經(jīng)產(chǎn)生了許多第三方的編碼工具。 不過隨著后來Fraunhofer-IIS宣布對編碼器征收版稅之后很多都消失了。

目前屬于開放源代碼并且免費(fèi)的編碼器是LAME(LameAin‘tMp3Encoder,)。 這個(gè)工具是公認(rèn)的壓縮音質(zhì)最好的mp3壓縮工具。 另外,幾乎所有的音頻編輯工具都支持打開和保存mp3文件。

應(yīng)該說,到了現(xiàn)在,MP3確實(shí)顯現(xiàn)出疲態(tài)了。 許多新一代的編碼技術(shù)都已經(jīng)能在相同的比特率下提供比MP3優(yōu)越得多的音質(zhì)。

不過由于mp3的影響力實(shí)在是太大了,支持mp3的軟件多如牛毛,更別提眾多支持mp3的硬件播放器,如MPMAN,DiscMan,CD/VCD/DVD機(jī)等等。 一句話,它依然是世界上最流行的音頻壓縮技術(shù),所以要它真正退出舞臺(tái)相信還有好一段時(shí)間。 (2)MP3的文件結(jié)構(gòu)

MPEG音頻文件沒有文件頭而是由很多獨(dú)立的數(shù)據(jù)幀構(gòu)成,每個(gè)幀都是獨(dú)立的可以被單獨(dú)播放,每個(gè)幀都有自己的幀頭和音頻信息。 這些也就是MPEG文件可以隨意切割成為可能。

幀頭是有32bits(4bytes)構(gòu)成,起始的11bit是幀同步信息。幀可以有CRC校驗(yàn)信息,也可以沒有。 一般來說都沒有CRC校驗(yàn)。CRC校驗(yàn)信息為16bit長,它緊跟在幀頭的后面,在校驗(yàn)信息后就是經(jīng)過壓縮的音樂文件數(shù)據(jù)了。

下面給出

溫馨提示

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

最新文檔

評論

0/150

提交評論