之前做過的項目有需要通過音頻口通信用方波來收發數據,由于這方面的資料比較少,下面就介紹下其原理,希望能給大家幫助。
一. 音頻通信簡介
大家應該都知道支付寶聲波支付和拉卡拉吧,它們都是利用手機的音頻口(手機耳機口)來實現全雙工的通信(手機與設備之間的雙向通信)。其優點是低成本,編碼芯片成本低,手機的 3.5mm 通信接口廣泛。
二. 市場應用
支付寶聲波支付
手機刷卡器
皮膚檢測儀
檢測如甲醛、氣壓、溫度、濕度等等
心率、血壓等等
.......................
三. 通信原理
手機上用的耳機大多都是3.5mm的四芯座,在這四個芯中,分別是:地(GND)、左聲道(L)、右聲道(R)和線控開關(MIC)。
左右聲道作用:向外設擴展頭供電和發送數據
MIC作用:接收數據
市場上耳機主要有兩種標準:國內標準(如下圖所示),國際標準(MIC和GND和國內標準是反的,其他一樣)
聲音波形調制有調幅(AM)、調頻(FM)和調相(PM)三種,而調制又有模擬調制和數字調制之分。(模擬調制和數字調制基本知識參考來源)
模擬調制:這種編碼方式是將數字數據調制成模擬信號進行傳輸。通常采用三種模擬信號的載波特性(振幅、頻率和相位)之一來表示被調制的數字數據,并由此產生三種基本調制方式。
(1) 幅移鍵控(ASK)法
ASK(Amplitude Shift Keying)是使用載波頻率的兩個不同振幅來表示兩個二進制值。在一般情況下,用振幅恒定載波的存在與否來表示兩個二進制字。ASK方式的編碼效率較低,容易受增益變化的影響,抗干擾性較差。在音頻電話線路上,一般只能達到 1200 b/s的傳輸速率。
(2) 頻移鍵控(FSK)法
FSK(Frequency Shift Keying)是使用載波頻率附近的兩個不同頻率來表示兩個二進制值。FSK比ASK的編碼效率高,不易受干擾的影響,抗干擾性較強。在音頻電話線路上的傳輸速率可以大于1 200 b/s。
(3) 相移鍵控(PSK)法
PSK(Phase Shift Keying)是使用載波信號的相位移動來表示二進制數據。在PSK方式中,信號相位與前面信號序列同相位的信號表示 0,信號相位與前面信號序列反相位的信號表示 1。PSK方式也可以用于多相的調制,例如在四相調制中可把每個信號序列編碼為兩位。PSK方式具有很強的抗干擾能力,其編碼效率比FSK還要高。在音頻線路上,傳輸速率可達 9600b/s。
這些信號調制技術主要用于調制解調器(Modem)中。在實際的Modem中,一般將這些基本的調制技術組合起來使用,以增強抗干擾能力和編碼效率。常見的組合是PSK和FSK方式的組合或者PSK和ASK方式的組合。
數字信號編碼: 對于傳輸數字信號來說,最簡單的信號編碼方法是用信號的兩個不同電壓值來表示兩個二進制數據。例如,用無電壓來表示 0,用恒定的正電壓表示 1;也可用正電壓表示 1,而用負電壓表示 0。然而,為了提高信號抗干擾能力,并且便于信號接收同步,通常采用更為有效的信號編碼方法。
常用的數字信號編碼有不歸零 NRZ (Non Return to Zero)碼、差分不歸零DNRZ 碼、曼徹斯特(Manchester)碼及差分曼徹斯特(Differential Manchester)碼等。
(1) NRZ碼
NRZ碼是用信號的幅度來表示二進制數據的,通常用正電壓表示數據“1”,用負電壓表示數據“0”,并且在表示一個碼元時,電壓均無需回到零,故稱不歸零碼。NRZ碼的特點是一種全寬碼,即一位碼元占一個單位脈沖的寬度。全寬碼的優點:一是每個脈沖寬度越大,發送信號的能量就越大這對于提高接收端的信噪比有利;二是脈沖時間寬度與傳輸帶寬成反比關系,即全寬碼在信道上占用較窄的頻帶,并且在頻譜中包含了碼位的速度。
NRZ碼的主要缺點是:當數據流中連續出現0 或1時,接收端很難以分辨1個信號位的開始或結束,必須采用某種方法在發送端和接收端之間提供必要的信號定時同步。同時,這種編碼還會產生直流分量的積累問題,這將導致信號的失真與畸變,使傳輸的可靠性降低,并且由于直流分量的存在,使得無法使用一些交流耦合的線路和設備。因此,一般的數據傳輸系統都不采用這種編碼方式。
(2) DNRZ碼
DNRZ碼是一種NRZ碼的改進形式,它是用信號的相位變化來表示二進制數據的,一個信號位的起始處有跳變表示數據“1”,而無跳變表示數據“0”。DNRZ碼不僅保持了全寬碼的優點,同時提高了信號的抗干擾性和易同步性。
近年來,越來越多的高速網絡系統采用了DNRZ碼,成為主流的信號編碼技術,在FDDI、100BASE-T及100VG-AnyLAN等高速網絡中都采用了DNRZ編碼。其原因是在高速網絡中要求盡量降低信號的傳輸帶寬,以利于提高傳輸的可靠性和降低對傳輸介質帶寬的要求。而DNRZ編碼中的碼元速率與編碼時鐘速率相一致,具有很高的編碼效率,符合高速網絡對信號編碼的要求。同時,為了解決數據流中連續出現0 或1時所帶來的信號編碼問題,通常采用兩級編碼方案,第一級是預編碼器,對數據流進行預編碼,使編碼后的數據流不會出現連續 0 或連續 1,常用的預編碼方法有4B5B、5B6B等;第二級是DNRZ編碼,實現物理信號的傳輸。這種兩級編碼方案的編碼效率可達到 80%以上。例如,在4B5B編碼中,每4位數據用5位編碼來表示,即4位數據就會增加 1 位的編碼開銷,編碼效率仍為80%。
(3) 曼徹斯特碼
在曼徹斯特碼中,用一個信號碼元中間電壓跳變的相位不同來區分數據“1”和“0”,它用正的電壓跳變表示“0”;用負的電壓跳變表示“1”。因此,這種編碼也是一種相位碼。由于電壓跳變都發生在每一個碼元的中間,接收端可以方便地利用它作為位同步時鐘,因此這種編碼也稱為自同步碼。10Mb/s 以太網(Ethernet)采用這種曼徹斯特碼。
(4) 差分曼徹斯特碼
差分曼徹斯特碼是一種曼徹斯特碼的改進形式,其差別在于:每個碼元的中間跳變只作為同步時鐘信號;而數據“0”和“1”的取值是用信號位的起始處有無跳變來表示,若有跳變則為“0”;若無跳變則為“1”。這種編碼的特點是每一位均用不同電平的兩個半位來表示,因而始終能保持直流的平衡。這種編碼也是一種自同步編碼。
令牌環(Token-Ring)網采用這種差分曼徹斯特編碼。
這兩種曼徹斯特編碼主要用于中速網絡(Ethernet為 10 Mb/s;Token-Ring最高為16 Mb/s)中,而高速網絡并不采用曼徹斯特編碼技術。其原因是它的信號速率為數據速率的兩倍,即對于 10 Mb/s的數據速率,則編碼后的信號速率為 20 Mb/s,編碼的有效率為 50%。對于 100 Mb/s的高速網絡來說,200 Mb/s的信號速率無論對傳輸介質的帶寬的要求,還是對傳輸可靠性的控制都未免太高了,將會增加信號傳輸技術的復雜性和實現成本,難以推廣應用。因此,高速網絡主要采用兩級的DNRZ編碼方案,而中速網絡采用曼徹斯特編碼方案,盡管它增加了傳輸所需的帶寬,但在實現起來簡單易行。
要實現手機端和擴展頭的全雙工通信,必須滿足2個條件:1.信號必須在音頻頻率之內;2.需要是低功耗的。第一個條件限制了信號帶寬,第二個條件限制了成本和功率。在這2種限制條件下,主要有2種方式實現這種同時的雙向通信:FSK調制和基于曼徹斯特編碼的直接數字通信。
這里主要講解下通過數字調制中的FSK調頻調制方波。FSK有2FSK(2進制調制)、4FSK(4進制調制)、8FSK(8進制調制)等等。
由于在數字系統中,使用的是0、1表示的二進制數據,在這里,我使用了2FSK來作為信號的調制。
2FSK調頻調制方波的原理:用一個頻率表示1,另一個不同的頻率表示0。比如使用613Hz的信號代表0,1226Hz的信號代表1。如下圖所示
方波可以用Cool Edit Pro工具生成,方便調試和研究。具體方法是:
打開工具,新建文件,然后會彈出下面窗口
這里根據你需求設置波形的采樣率,聲道和采樣精度(一般是44100HZ,單聲道,16位采樣精度)
接下來選擇菜單項-生成
你會看到如下界面,這里可以通過設置不同頻率和設置調味為方波生成波形了
那么在iOS下如何接收方波解析和發送方波咧?
每段波形其實是由N(N=采樣率/位持續時間(每位數據頻率))個有符號的數據點組成,這些有正有負的數組成了一段段波形,比如波形0則有N個127組成的波峰波形或者N個-128組成的波底波形,而波形1則有N/2個波峰+N/2個波低組成,這個波峰波底具體數值定義可自已靈活定義,如下圖所示
舉個例子:比如發送個數據5,其二進制數據為0000 0101 ,這里設置采樣率為44100HZ,每段波形時間頻率1000HZ,定義波形為0 波峰上全是44個127,波形為0 波底上全是44個-128,波形為1的數據 半個 波峰上全是44/2個127,半個 波底上全是44/2個-128,那么5 生成波形的數據就是 0(44個127) 0 (44個-128) 0(44個127) 0 (44個-128) 0(44個127)1(44/2個-128+44/2個127)0(44個-128)1(44個127)。知道這個原理了方波解析和發送數據就簡單了。
音頻使用的基本步驟如下:
1.設置音頻格式和采樣率
mAudioFormat.mSampleRate=AUDIO_SAMPLE_RATE;//采樣率
mAudioFormat.mFormatID=kAudioFormatLinearPCM;//PCM格式
mAudioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
mAudioFormat.mFramesPerPacket = 1;//每個數據包多少幀
mAudioFormat.mChannelsPerFrame = kChannels/2;//1單聲道,2立體聲
mAudioFormat.mBitsPerChannel = 16;//語音每采樣點占用位數
mAudioFormat.mBytesPerFrame = mAudioFormat.mBitsPerChannel*mAudioFormat.mChannelsPerFrame/8;//每幀的bytes數
mAudioFormat.mBytesPerPacket = mAudioFormat.mBytesPerFrame*mAudioFormat.mFramesPerPacket;//每個數據包的bytes總數,每幀的bytes數*每個數據包的幀數
mAudioFormat.mReserved = 0;
2.設置remote io unit的渲染回調,從輸入硬件獲得采樣傳入到回調函數進行渲染,從而獲得錄音數據解析數據. 向回調函數填數據,從而向輸出硬件提供數據進行放音發送數據.
CheckError(AudioUnitSetProperty(toneUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, disable, &mAudioFormat, sizeof(mAudioFormat)), "couldn't set the remote I/O unit's output client format");
CheckError(AudioUnitSetProperty(toneUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, enable, &mAudioFormat, sizeof(mAudioFormat)), "couldn't set the remote I/O unit's input client format");
回調函數OSStatus RenderTone(
void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData);通過這個回調函數就可以發送數據和解析數據
數據編碼發送具體代碼可參考demo里,知道了編碼原理,解碼對你來說就簡單了
參考文檔:
http://blog.csdn.net/it1988888/article/details/9073767
http://www.seeedstudio.com/wiki/index.php?title=Hijack
http://blog.csdn.net/xiejx618/article/details/9790709