|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 seewolf 于 2021-6-9 18:11 编辑
% p8 n* c# D- Q# t( o9 _1 Z; ]) a9 c2 [% |
自12年毕业至今工作将近一年,也积累了一些经验,接下来会一一分享出来,算是对阿莫的感恩吧!第一篇是关于手机音频通信方面的,12年上半年从事过几个月的手机音频通信的开发(我主要负责设备一端的程序和电路,手机软件部分不负责),积累了一点经验,在这里献丑了。9 M" @% C* ~% \/ s% `
一、手机音频通信的特点
* Q0 d. [7 U! G/ J. f$ w1、通用性强:在智能手机普及的今天,手机的对外通信接口多种多样,而其中以3.5mm的音频接口通用新最强,基本所有的手机、平板电脑都会有这个接口,所以在一些要求通用性的设备上,音频接口登上了舞台。
. K* y1 \+ H" l& n3 s: t( t2、速率低:由于手机音频部分的采样频率一般为44.1KHZ(部分国产山寨为8KHZ),这极大的限制了音频通讯的速率。我们都知道44.1KHZ的采样频率,那么最高的信号频率只能为20KHZ左右,而信号周期也不可能只有2个采样点,通常要到10个以上,这样层层下来通讯速率可想而知。
0 R$ X+ i5 j0 r9 C- f$ Y: u3、小信号:音频通信的信号都是毫伏级的,各个手机厂商略有不同,但通常最大不超过200mv,通常我们通信使用的信号强度也就100mv左右,这导致信号比较容易受干扰,且在开发阶段对工具有着种种限制。
9 T9 A4 q+ N T& ~) l; e0 B二、手机音频通信分类# M) R! l! F! D2 l, J5 g& A
1、无线方式:# x% |# D( u9 Y |* x1 w( f
a) 无线方式大家可能不太熟悉,容我慢慢道来。我们都知道人耳能听到的声音频率为20HZ~20KHZ,而手机通信的信号频率最高也就20KHZ,所以无线通信方式是可行的。因为虽然人耳的极限听力能到20KHZ,但普通人一般在19KHZ以上时基本就听不到了,所以如果信号的强度比较弱,且控制在19KHZ到20KHZ之间,那么我们就可以将之当做是“超声波”来看待了。& E, y2 |. |+ P# E
b) 其实在此提到手机音频通信的无线方式,算是给大家一种产品开发思路吧。它的通讯半径在10M左右,前景还是很广阔的,大家有兴趣的可以试试。(其实已经有这方面的产品了)- M' k9 x( C& c n3 c
2、有线方式:
2 f# z, |) i$ C' Y* \a) 有线方式分为单向(设备→手机)和双向两种,单向的限制少,开发难度也小一些,但实际应用时会受限制。而双向通信限制多,开发难度也大一些,但实际应用时更方便些。% z+ C4 t; _0 z: Z! w$ G" r
b) 设备→手机:曼彻斯特编码;FSK;DTMF;自定义正弦波/ e, N) ~$ G7 H
c) 手机→设备:由于手机输出的音频信号很小,无法直接使用,要么用运放发大到合适的范围,要么用电压比较器转换成TTL方波。% e7 X+ |1 l. n; A1 }5 m9 _9 L) @
三、手机音频通信硬件通信方式分类:手机音频通信的硬件通信方式大体可分为方波和正弦波两种。
8 @4 X) [9 h: q" N+ K1、方波:方波通常使用的是曼彻斯特编码方式(什么是曼彻斯特编码自己去查),它的好处是可以用单片机直接输出方波,经过衰减后即可使用,方便简单。缺点是兼容性不好,因为手机音频部分有这样一个特性,它只识别变化的电平信号,当麦克输入的信号长时间保持在某一非零电平时,手机会将其视为零,而强行拉回零电位。这就是采用方波通讯方式的兼容性不好的最大原因了,并且方波也容易受干扰。
5 G$ H, V: p- b6 R8 ?! Y2、正弦波:正弦波不会出现上面所说的方波的问题,故正弦波的兼容性和稳定性更好一些。通常采用方案有FSK、DTMF、信号发生器、或方波转正弦波等。(后面会对以上方案逐一分析)
I1 t3 A* Q' f, _- B/ V, R3、通信信道分析! R0 u' N9 W4 W& I4 r- ^; O+ M( \: c5 _
a) 我们知道音频接口有4根线,MIC、地、左、右声道。设备→手机用MIC,手机→设备用地、左、右声道中的任意一个。这里说一下,实际产品中,有一些厂家会更换地线,即将原本左、有声道中的一根改为地线来用,其实道理是一样的。因为音频通信的信号时交流信号,而地其实也是悬浮地,即便地线换了,最终的波形还是一样的,因为最终手机解析信号时需要的是频率和幅值。这样还剩下一个声道,通常被用来帮助设备进行上电识别,因为音频通信的设备通常都是电池供电的。1 D6 T: u( R7 f5 O. s+ } w- h
b) 另外还要在MIC和地之间并联一个4.99K的电阻,因为手机是通过检测MIC和地之间的阻抗是否为4.99K(也有其他阻值的)来判断是否有设备(耳机)插入,这一点要谨记。. @ [4 j$ o! x0 [, X
四、各个通信方案对比分析6 I S# s1 R, n* b% S
1、设备→手机:# E5 L8 R5 j9 h9 m4 j4 x
a) 曼彻斯特编码:在诸多通信方式中,曼彻斯特编码是最灵活简便的一种方法,编码信号可由单片机直接产生,经衰减电路衰减后便可直接使用。注意事项:曼彻斯特编码信号的生成有两种方式,一种是用PWM生成,一种是用定时器中断翻转IO,我个人比较倾向于定时器中断方式。因为我们知道曼彻斯特编码中有宽沿河窄沿之分,且宽沿和窄沿可能会灵活变化,而用PWM方式不容易精确控制宽沿、窄沿输出的变化,而定时器中断方式则非常灵活且容易控制。(后面会送上我自己写的曼彻斯特编码、解码函数), x+ U1 h- \7 Q5 @
b) FSK、DTMF方式:FSK和DTMF两种方式大同小异,使用时通常都是用集成的芯片来生成的,而这些芯片通常都是遵守固定的通信协议的的要求(FSK为Bell202或V.23协议,DTMF记不清名字了)。这两种通信方式的优点是采用正弦波通信、稳定性好且使用简便。但由于固定通信协议的限制导致通信速率、比特率也受到限制而缺乏灵活性。在这里跟他家推荐一款英国的通信芯片CMX系列,这个系列的芯片融合的FSK、DTMF的编码、解码,还是很不错的,大家有兴趣可以试试。(相关手册在附件里); R- c) } T; M9 c4 U2 t
c) 信号发生器、锁相环方式:这种方式用信号发生器或者锁相环来产生方波或正玄波,由单片机来控制波形的输出,也可以实现音频通信,且十分灵活。但缺点是电路较复杂,且不同频率信号之间衔接不好掌握,用不好反而是麻烦。(相关手册在附件里)
4 I9 Z; b2 q) p: X+ S5 i/ ^ Yd) 在这里送上一种我个人认为比较好的方案:就是曼彻斯特编码加低通滤波器,由单片机输出曼彻斯特编码,再经由低通滤波器将方波滤成正弦波后输出。既解决了FSK、DTMF灵活性的问题,又解决了曼彻斯特编码方波稳定性、通用性的问题。在低通滤波器方面我个人采用的是“集成低通开关电容滤波器”,它成本虽然高一些,但好处也是明显的,电路简单,使用方便,且占用的空间亦很小。(相关手册在附件里)5 B8 M3 V2 V3 C/ ]: l% ]) a6 \
2、手机→设备:
& J! E0 |+ D: D' {+ C( da) 放大电路方式:将手机输出信号经放大电路放大到合适的幅值,然后有锁相环或者结成FSK、DTMF芯片进行解析。该中方式难度最大,需要非常强的模拟电路功底,我个人水平有限,故采用的另一种方式。8 G5 T3 B# }4 w, r# ]. [1 \
b) 电压比较器方式:将手机输出的交流信号经电路强行拉到Vcc/2级别,然后加到电压比较器一端,另一段接比较电压Vcc/2,这样交流信号即被转化为TTL方波信号,此时再进行解析就变得很简单了。
1 }, s4 _% K7 o五、研发注意事项(通讯方案分析部分由于过长,放到最后来讲)
2 t/ \+ A1 Q1 O! x* M1、一个好手机录音软件是必须的,最好能在手机上直接看到波形的。. A7 l% r+ V! L, z
2、建议用笔记本电脑进行开发,而非台式机。因为音频信号很小,容易受干扰,而台式机干扰较大,笔记本还有一个好处是必要时可将外接电源拔掉,用电池供电。
: \ P: X' x8 P6 f9 _/ H1 g2 Q; Y* V, o3、一个好录音笔必不可少,有时需要得到纯净的音频信号,方便更加准确的分析。; \8 z1 Z1 M0 K* @
4、做一个转接板,一边接音频母座,一边接音频公头,将MIC、地、左、右声道4跟线用排阵引出,方便录音。
2 K& X; ]' `* ]! O3 T6 G& P5、做一个信号衰减电路,可将设备电路产生的信号衰减至音频接口能承受的范围内。前期调试时,我们可以用该电路将信号录进电脑进行信号分析。(推荐一个电脑音频信号分析软件:Goldwave)' i6 V7 R. d2 _4 I% d
6、录音用的音频线切记不要太长,不然会给你带来不少麻烦。最好自己做,用音频裸头、杜邦线、排阵即可制作,方便好用。 ~! [5 U4 V3 v1 M0 O# ~
/ `9 }1 i/ M h" D" j8 h) b
曼彻斯特编码的编码解码函数如下:6 B2 Q$ E `5 w( o
- /**********************************************************************
2 j7 p7 z( c: y; j* s6 f; m - 注释:编码函数都是采用定时器中断的形式,以曼彻斯特编码的窄沿作为定时器周期。$ b7 z/ ]9 M5 _% H C
- 发送的数据包括1个起始位、8个数据位、1个奇偶校验位、3个停止位。( R7 n' H9 ~. U& j3 R0 W, T; a
- ***********************************************************************/
2 ^6 ?# e% n( P8 |* I" a% M - static void VIC_VECT_Fucton_00(void)//发送编码数据中断函数: n, ]; J8 x6 p. O. Q5 y
- {
+ R) S0 k' l; b4 G% ]3 N - TIMER0IS =0x0;5 y2 z: J* R6 c- r
- if((send_time%2==0) && (send_start==1))8 t; `# W! R- t) Y
- {
E5 f( A* @! \ - switch(FSK_txState)8 N" F( y' H4 e. T T2 D- U
- {
2 M9 B4 [, h6 Z* n% s; r2 b, E! z - case STARTBIT:' b% S+ ?, k2 {: X" Q9 U2 R
- if((GPIODATA&0x00000002)==0x00000000)//如果检测到数据发送管脚为零& G: @- B2 q a+ s: s, `
- send_time++;
: I; U. t9 |& g- N - else* B' }% ]. A$ C7 K' j8 G$ E
- {
5 a1 ]) \( ?( D2 Q% e& U) f0 i - currentSym=0;' D( n/ Q9 g! t! K4 G: o
- FSK_txState = BYTE;
. ~! m1 y, y% o- D - }5 z/ C# c3 C: Y# H' T7 Z8 s
- break;
( k8 Y3 T5 _$ J. L5 ?, h - case BYTE:
' ^3 }0 |" l# n2 q" _, Q. L- ]! b- E - if(txBit < 8)& @; B/ v b# ?3 v- d0 `
- {
7 i3 J4 Q2 C- U. n7 e - currentSym = (send_byte >> txBit) & 0x01;8 G2 s" n Q3 C6 O! G# N- ]
- txBit++;
4 A, {0 r5 W0 V( F6 K6 P! q# i. u# J - txParity += currentSym; //奇偶校验位; e+ s7 W. a7 E% ]" O; g9 C6 I
- } 2 c8 o' B' e' B/ P) z
- else if (txBit == 8)
6 c" T& ^3 m% T+ Y/ ? - {
. k6 h! E: i! o5 I% O7 a/ I! @ - currentSym = txParity & 0x01; //发送奇偶校验位# C% B% x. x4 `
- txBit++;! g6 }! C" c. I- @' ~2 Z3 g' P
- } $ m5 P+ P* b6 Z+ @$ G+ F+ k, a
- else if(txBit>8 && txBit<12)) q. u% Y# W! H) N
- {" s4 F2 B) }* S8 E+ M, E; y, R
- // next bit is the stop bit
; L) y8 `/ V3 \+ w/ Y$ e - currentSym = 1; //发送停止位
- x& b$ C/ i! E: G$ @- c8 d - txBit++;
% s. {0 i1 ?* c' J6 ?0 f9 z9 _ - }
, g# n& |/ @ d7 p& i X - else if(txBit == 12)
* q, N! A5 s- s! \- ]/ u$ R* p: O5 | - FSK_txState = STOPBIT;
. Q$ c" G! n/ ?; J - break;2 k, t( c) u0 U/ g3 `) r: F
- case STOPBIT :
: U! t/ V4 @' h. E8 [ - txBit=0;
+ X9 g/ Z) l& y- ^ - FSK_txState=IDLE;& h2 V6 H. L! F6 f5 G
- send_start=0;$ [; R' r0 n8 p( `) i, G
- txParity=0;& h( T, w5 @2 M" o; h7 u. u& X
- send_byte=0;6 |; W( S3 }4 E6 Q5 R$ [3 l
- break;9 m# a' s1 }. j& Y9 n6 o7 h; w" d; \
- }( t% F1 Y# f, y l" F$ Z
- if(lastSym!=currentSym)
7 z, N% a1 ^' a( t2 e - {
: A0 Q# C( R" M+ q - timer1_num++;7 D# U# D9 O% @7 X8 N
- lastSym=currentSym;
; h9 r: P9 f* G% ?. x* o: a+ C - }- }3 A' |$ L3 F! ^! |
- }
3 W% }9 H+ Y% g/ f, ?- Z' H2 S - if(timer1_num%2==0); D; v" t* W! i, R6 Q* y% z
- GPIODATA&=0xFFFFFFFD;//输出管脚复位
. S$ J: |0 m- w8 |% h& C - else
% k. ?6 u6 w: o' @, w. e - GPIODATA|=0x00000002;//输出管脚置位
$ F6 S* b& J2 }/ k2 Q U - / k# A* d, H, A" j2 s3 @. P
- timer1_num++;//用来控制IO口的电平翻转
/ F- E- p" D, M4 I6 j - send_time++;//用来控制发送的字节的每一位
/ a" d. F0 q2 w0 w3 i& g - Delay++;//Delay就是延时函数
5 L; K- ^8 y7 N' T - }
- P8 g* e9 `+ N" E: v8 o0 U5 } - /**********************************************************************
$ y+ T$ k: @4 t; @% Q+ E - 注释:解码函数采用外部IO中断形式(上升沿或下降沿中断,即电平电平跳变中断),3 c! O& L: ^) g! C3 H, C% x# `& e
- 用一个定时器作为时钟,每次产生中断时便从定时器见时间值取出,并和上一次的& _ t$ P2 [% G' Z( B% O* ~
- 记录做差求出时间间隔,以此来判断当前为宽沿还是窄沿。
1 t, z4 ?, L( M# f% j3 [ - ***********************************************************************/6 r8 W2 Q* O: [; w
- static void VIC_VECT_Fucton_04(void)//接受解码数据中断函数9 J- y: @3 a' e
- {! c8 i8 ?, i$ D7 R! `+ @
- GPIOIC|=0x00000001;//清楚上一次中断内容4 }& r$ p# O1 N
- RX_time=TIMER1VALUE;
( H% b% S9 N8 ~% Y1 L7 x - if(RX_lasttime>=RX_time)2 G7 |7 y3 h5 p$ M
- RX_diff=RX_lasttime-RX_time; //lasttime初始值为0; @, P* m2 ^ l4 p8 ~# X* m# E
- else
! g5 y; R8 t4 ?/ F j6 [2 y - RX_diff=65535-RX_time+RX_lasttime;. \0 N$ z' c2 ?9 v: W+ q
- RX_lasttime=RX_time; ! O! A; l3 l3 w+ ^0 g) G8 U) Z# g
- switch(RX_state) //启动代码时state已经被配置为STARTBIT
# A' j2 s8 S2 B# r" k7 C" | - {' Q7 [. x$ I7 q" n2 A
- case STARTBIT_FALL:
- i9 C+ x1 B0 x" v ^! ^3 }8 } - if ((SHORTINTERVAL<RX_diff) && (RX_diff<LONGINTERVAL))0 M8 @8 j' e1 W" A$ c2 ?5 s$ G
- {
, F' u: y4 o. w - if(RX_ones<5) //ones初始值为0. G6 G$ H' c" g6 k e5 E2 N
- {, M F* K8 ~: F& Y V* {1 _2 V( v) `5 ^
- RX_ones = 0;
% e, u3 k& V( r - } ! A( d& u6 u- w5 c
- else
. p4 l: R, M: Q% s, P! t, f z- _ - {
; K$ ]2 \. s3 {) K. o8 E; K - RX_state = DECODE; //将状态配置为解码
* i2 b2 x% _) j: {: g5 I - }
' b) P. n; A) d( q) z - }7 U: M6 y# V& g6 Y, [, U1 }
- else if(RX_diff < SHORTINTERVAL)
1 @2 v0 E% {- ~ - RX_ones++;
7 j4 ` D3 k& F! _0 [5 ^ - else
6 b- n4 c0 I7 E* E* M - RX_ones=0;! E; S# ^. R% ?! c% _% t
- break;* k" `2 {& l0 \0 D( z
- case DECODE:
- u7 B" Y B9 {+ l! Q" i4 | - /**************通过间隔长短来判定数据**************/) B; \2 _6 f2 R4 l7 J3 c3 s9 U
- if ((SHORTINTERVAL<RX_diff) && (RX_diff<LONGINTERVAL))// 若间距在范围内则当前数据位值和前一个相反
1 y5 U9 G8 W4 p% K- ]/ p - { 1 P7 D# x" P! K' B
- currentbit=(currentbit+1)&0x01;: ~5 D; A3 Q) M; ?0 b
- RX_times+=2;& ?) P$ a j# g: |* }
- }6 S. R8 L; q* S; \9 K3 }$ Z5 `& _2 M
- else if( RX_diff < SHORTINTERVAL) / J; e9 g4 K& @
- {
$ I+ D2 y/ M* n0 ]/ _# \1 S - currentbit=currentbit;3 q" e# f; G: L
- RX_times++;- S+ G- a+ M1 A
- }
7 R* f ]; l% \$ Q. |& t4 o - else
7 Y( w0 i5 ?' m8 n' u - RX_state = DATAINIT; ! O) s3 m4 K% W7 H% @0 t8 ^
- 8 u) V5 s7 d3 w: ?: r
- /****************接受数据位,从低位接起****************/) p0 V0 w- d7 v1 v! i
- if(RX_times%2==0)
) C/ j/ f- M ^" h - {: {/ X8 C; l9 z1 r8 n+ Y) y
- if(RX_bitcounter<8)/ ]9 M( H% U4 H( P6 d
- {
& q3 Y, q0 y# u6 E# P! y - if (currentbit==1)& ]! e6 Y. R+ \# i) B
- {0 w) m1 E- X+ I6 Q
- uartByteRx = (uartByteRx >> 1) + (1<<7);
9 b: x" ?6 K3 m8 t4 G1 Z - rxParity++; //奇偶校验位# f) k1 {# |1 {) e: w6 ?* t
- RX_bitcounter++; //接受数据位数) X! k( m% y3 y3 C, C
- }
# ]+ f# A0 C6 ~3 U+ K0 D - else. P# n) K0 O( I
- {
/ V$ C; Z4 t4 V) _ - uartByteRx = (uartByteRx >> 1);
% {3 V: j4 b# f0 m+ C - RX_bitcounter++;: j5 h0 [2 U) y# A6 s% b3 n7 }
- }
' {0 m( f E; \ z9 }" t - }
* n+ D2 c- O& X4 u s - else
) \% q2 l9 y8 S, c ^0 m/ { - {
: |1 h N( `8 f - rxParity&=0x01; //进行奇偶校验
8 N* G4 n3 s3 y* Q4 M% A - if(rxParity==currentbit)& w$ n$ d' i- l8 |+ N9 I6 a5 J# i
- {$ G0 a' b. J Y# z* O7 g
- RX_bitcounter++;. x# f- z$ Q% w# v
- RX_finish=1;
1 E9 I! }5 c6 U8 Z7 z - RX_state=DATAINIT;
, y% K y4 N3 k. I; s% o+ D - }+ P5 v9 M# ~ Z' B; ~4 \, U
- else0 ], i' ?8 j; m7 s/ `( t# j
- RX_state=DATAINIT; //若奇偶校验错误则,重新检测
L( B: n! H7 O- b& N/ V# k- t - }* [& M' ^+ \4 b9 p& O$ n
- }
8 [/ [+ ^% ~8 _' \ - break;
9 a/ t7 ]8 N- m) E3 p - case DATAINIT : //初始化参数状态
! G) d7 w: O" t( _" C' c: O - RX_bitcounter=0;9 c3 O# S8 e) p) T+ V& M$ ^
- RX_ones=0;7 j- W/ T2 |% a( M' g# d
- rxParity=0;/ l+ y* J8 Z3 }4 N
- currentbit=0;
5 D& p# r" Q8 y$ D - RX_state=STARTBIT_FALL;6 {' \- u$ F! S' Z5 S
- RX_times=0;9 O0 ?1 ^' d, A! E
- break;
& H5 t% @ O/ i! o3 \; L8 p3 N - default:
/ C6 ^* Q7 |) s7 i0 p* r- s - break;
" Y2 {( r* D( R1 m - }
* ]5 k2 y9 ]- _) `, i- i8 X - }
复制代码
4 W9 ^; x" N2 |; a9 a0 e# E! G: j2 Q7 a0 d. @$ @9 |* f& @
|
-
-
FSK、DTMF通信类.zip
4.56 MB, 下载次数: 0, 下载积分: 威望 -5
-
-
方波信号发生器.zip
1.05 MB, 下载次数: 0, 下载积分: 威望 -5
-
-
开关电容滤波器.zip
1.15 MB, 下载次数: 0, 下载积分: 威望 -5
-
-
耦合电感.zip
2.24 MB, 下载次数: 0, 下载积分: 威望 -5
-
-
锁相环及信号发生.zip
4.05 MB, 下载次数: 0, 下载积分: 威望 -5
|