|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 seewolf 于 2021-6-9 18:11 编辑
# z) u4 E# {+ P2 i g* L# S- o9 k+ T# Z
自12年毕业至今工作将近一年,也积累了一些经验,接下来会一一分享出来,算是对阿莫的感恩吧!第一篇是关于手机音频通信方面的,12年上半年从事过几个月的手机音频通信的开发(我主要负责设备一端的程序和电路,手机软件部分不负责),积累了一点经验,在这里献丑了。
' `6 C" R% L X& S3 U一、手机音频通信的特点. E8 k4 ?& T9 t! x+ q: `
1、通用性强:在智能手机普及的今天,手机的对外通信接口多种多样,而其中以3.5mm的音频接口通用新最强,基本所有的手机、平板电脑都会有这个接口,所以在一些要求通用性的设备上,音频接口登上了舞台。4 f, I/ X; p* h% L |; j3 \
2、速率低:由于手机音频部分的采样频率一般为44.1KHZ(部分国产山寨为8KHZ),这极大的限制了音频通讯的速率。我们都知道44.1KHZ的采样频率,那么最高的信号频率只能为20KHZ左右,而信号周期也不可能只有2个采样点,通常要到10个以上,这样层层下来通讯速率可想而知。
- z: K( K w: [3、小信号:音频通信的信号都是毫伏级的,各个手机厂商略有不同,但通常最大不超过200mv,通常我们通信使用的信号强度也就100mv左右,这导致信号比较容易受干扰,且在开发阶段对工具有着种种限制。% w" _0 Z, Z) y* N; f, {; V
二、手机音频通信分类
# Q8 f: a8 S S. W! B' ~1、无线方式:
+ T8 t$ k# \ H9 K$ u& ta) 无线方式大家可能不太熟悉,容我慢慢道来。我们都知道人耳能听到的声音频率为20HZ~20KHZ,而手机通信的信号频率最高也就20KHZ,所以无线通信方式是可行的。因为虽然人耳的极限听力能到20KHZ,但普通人一般在19KHZ以上时基本就听不到了,所以如果信号的强度比较弱,且控制在19KHZ到20KHZ之间,那么我们就可以将之当做是“超声波”来看待了。$ a2 s. {# u/ z [1 H: |6 _
b) 其实在此提到手机音频通信的无线方式,算是给大家一种产品开发思路吧。它的通讯半径在10M左右,前景还是很广阔的,大家有兴趣的可以试试。(其实已经有这方面的产品了)
. y7 {: b2 F% Q0 _" p. g8 L- U5 ?2、有线方式:* j7 ~. s5 r" V+ n- ^
a) 有线方式分为单向(设备→手机)和双向两种,单向的限制少,开发难度也小一些,但实际应用时会受限制。而双向通信限制多,开发难度也大一些,但实际应用时更方便些。
' g- ^# p& j" W3 |9 lb) 设备→手机:曼彻斯特编码;FSK;DTMF;自定义正弦波
% A& {. d1 _* `7 o4 ?( k, Ic) 手机→设备:由于手机输出的音频信号很小,无法直接使用,要么用运放发大到合适的范围,要么用电压比较器转换成TTL方波。
6 Y0 A- t8 y: N* t% H三、手机音频通信硬件通信方式分类:手机音频通信的硬件通信方式大体可分为方波和正弦波两种。1 Q' v9 a" w9 s: i8 |0 `; \( p
1、方波:方波通常使用的是曼彻斯特编码方式(什么是曼彻斯特编码自己去查),它的好处是可以用单片机直接输出方波,经过衰减后即可使用,方便简单。缺点是兼容性不好,因为手机音频部分有这样一个特性,它只识别变化的电平信号,当麦克输入的信号长时间保持在某一非零电平时,手机会将其视为零,而强行拉回零电位。这就是采用方波通讯方式的兼容性不好的最大原因了,并且方波也容易受干扰。
. v, i; a1 V' V; Z0 T6 \2、正弦波:正弦波不会出现上面所说的方波的问题,故正弦波的兼容性和稳定性更好一些。通常采用方案有FSK、DTMF、信号发生器、或方波转正弦波等。(后面会对以上方案逐一分析)' r% m& p1 ~9 p, L
3、通信信道分析
- _- D# k: ?; k, c! ?/ `a) 我们知道音频接口有4根线,MIC、地、左、右声道。设备→手机用MIC,手机→设备用地、左、右声道中的任意一个。这里说一下,实际产品中,有一些厂家会更换地线,即将原本左、有声道中的一根改为地线来用,其实道理是一样的。因为音频通信的信号时交流信号,而地其实也是悬浮地,即便地线换了,最终的波形还是一样的,因为最终手机解析信号时需要的是频率和幅值。这样还剩下一个声道,通常被用来帮助设备进行上电识别,因为音频通信的设备通常都是电池供电的。
4 L0 A0 h- t) J. Db) 另外还要在MIC和地之间并联一个4.99K的电阻,因为手机是通过检测MIC和地之间的阻抗是否为4.99K(也有其他阻值的)来判断是否有设备(耳机)插入,这一点要谨记。
6 p- c, }; k5 R四、各个通信方案对比分析
1 u$ i# b* ^8 ^, H% r( \, O1、设备→手机:5 v" z: i7 E3 v. j8 u5 {
a) 曼彻斯特编码:在诸多通信方式中,曼彻斯特编码是最灵活简便的一种方法,编码信号可由单片机直接产生,经衰减电路衰减后便可直接使用。注意事项:曼彻斯特编码信号的生成有两种方式,一种是用PWM生成,一种是用定时器中断翻转IO,我个人比较倾向于定时器中断方式。因为我们知道曼彻斯特编码中有宽沿河窄沿之分,且宽沿和窄沿可能会灵活变化,而用PWM方式不容易精确控制宽沿、窄沿输出的变化,而定时器中断方式则非常灵活且容易控制。(后面会送上我自己写的曼彻斯特编码、解码函数)
7 W' x$ \+ v6 d8 ~5 Z/ _b) FSK、DTMF方式:FSK和DTMF两种方式大同小异,使用时通常都是用集成的芯片来生成的,而这些芯片通常都是遵守固定的通信协议的的要求(FSK为Bell202或V.23协议,DTMF记不清名字了)。这两种通信方式的优点是采用正弦波通信、稳定性好且使用简便。但由于固定通信协议的限制导致通信速率、比特率也受到限制而缺乏灵活性。在这里跟他家推荐一款英国的通信芯片CMX系列,这个系列的芯片融合的FSK、DTMF的编码、解码,还是很不错的,大家有兴趣可以试试。(相关手册在附件里). B5 m9 k) U/ u) Y6 I
c) 信号发生器、锁相环方式:这种方式用信号发生器或者锁相环来产生方波或正玄波,由单片机来控制波形的输出,也可以实现音频通信,且十分灵活。但缺点是电路较复杂,且不同频率信号之间衔接不好掌握,用不好反而是麻烦。(相关手册在附件里)
' i' g: ` [" d3 n+ F- ud) 在这里送上一种我个人认为比较好的方案:就是曼彻斯特编码加低通滤波器,由单片机输出曼彻斯特编码,再经由低通滤波器将方波滤成正弦波后输出。既解决了FSK、DTMF灵活性的问题,又解决了曼彻斯特编码方波稳定性、通用性的问题。在低通滤波器方面我个人采用的是“集成低通开关电容滤波器”,它成本虽然高一些,但好处也是明显的,电路简单,使用方便,且占用的空间亦很小。(相关手册在附件里) B2 y3 n) X v$ b: T
2、手机→设备:
7 k5 o* ~$ _$ C9 A! g7 P/ @( `# Ra) 放大电路方式:将手机输出信号经放大电路放大到合适的幅值,然后有锁相环或者结成FSK、DTMF芯片进行解析。该中方式难度最大,需要非常强的模拟电路功底,我个人水平有限,故采用的另一种方式。
4 y% o7 y1 n1 v3 }b) 电压比较器方式:将手机输出的交流信号经电路强行拉到Vcc/2级别,然后加到电压比较器一端,另一段接比较电压Vcc/2,这样交流信号即被转化为TTL方波信号,此时再进行解析就变得很简单了。) y: m$ F- v, ~ q* v9 H
五、研发注意事项(通讯方案分析部分由于过长,放到最后来讲)
3 o0 H" u( `* a1、一个好手机录音软件是必须的,最好能在手机上直接看到波形的。
% v+ O& W C5 u3 H+ B# ~4 i2 f8 n6 A2、建议用笔记本电脑进行开发,而非台式机。因为音频信号很小,容易受干扰,而台式机干扰较大,笔记本还有一个好处是必要时可将外接电源拔掉,用电池供电。
2 d3 r$ U2 c& F" J: K& g3、一个好录音笔必不可少,有时需要得到纯净的音频信号,方便更加准确的分析。
# x' O2 U. |0 M" K3 V; V5 f4、做一个转接板,一边接音频母座,一边接音频公头,将MIC、地、左、右声道4跟线用排阵引出,方便录音。) h% m, R, U4 }7 D4 m5 F# o; n. u
5、做一个信号衰减电路,可将设备电路产生的信号衰减至音频接口能承受的范围内。前期调试时,我们可以用该电路将信号录进电脑进行信号分析。(推荐一个电脑音频信号分析软件:Goldwave)7 \9 S( i/ U j9 G" p
6、录音用的音频线切记不要太长,不然会给你带来不少麻烦。最好自己做,用音频裸头、杜邦线、排阵即可制作,方便好用。( N9 B0 I* j/ C+ t# _# A
, ?$ n, r) I9 M# Q7 Z' e6 i
曼彻斯特编码的编码解码函数如下:
" Z/ \; q$ p, m- /**********************************************************************
) |/ k4 b5 w4 U) w' I/ N - 注释:编码函数都是采用定时器中断的形式,以曼彻斯特编码的窄沿作为定时器周期。
" e9 `% f. ]7 A - 发送的数据包括1个起始位、8个数据位、1个奇偶校验位、3个停止位。
/ z$ | M% `0 G1 ]# i: F% H% x - ***********************************************************************/
|7 G* H1 \+ U" `; y5 R, i+ T - static void VIC_VECT_Fucton_00(void)//发送编码数据中断函数
p2 i8 z5 I$ Y- |8 C% E! B! s# h4 ~ - {1 K4 l; e* w4 Z7 |8 m3 n( _
- TIMER0IS =0x0;
: x1 C8 j# x1 `" c8 { - if((send_time%2==0) && (send_start==1))0 }* t9 x) V- X4 K* `) C( ~; ~: r
- {
" H/ t O# g1 Q6 j- S - switch(FSK_txState)
3 @% B$ n. V! j& ]( g) p& j) I, X { - {& G% a( a9 L# G) k
- case STARTBIT:: G% M; w$ y0 m
- if((GPIODATA&0x00000002)==0x00000000)//如果检测到数据发送管脚为零8 i* z$ f- u' P
- send_time++;
( O! Y3 {; t& d% N# t- O3 w - else! f1 G8 T5 |# m. B$ ~
- {
1 g* n) U2 d+ ^ y - currentSym=0;. J4 L* Q L: i& t; n3 v
- FSK_txState = BYTE;- z( ~ ~& b' `" l! t4 a
- }' K; n3 u7 D1 w- `
- break;* m6 p8 a1 c+ C! R% u
- case BYTE:( L5 H( _- \) i9 R* ?9 X
- if(txBit < 8)7 m6 ]7 k6 b9 k
- {
. l3 ~% T) Z+ A) p' u - currentSym = (send_byte >> txBit) & 0x01;$ i; Y# f9 ~. g+ l$ I& F9 ^( `( ^3 r
- txBit++;
/ T! n R, R% j) ]( w - txParity += currentSym; //奇偶校验位
- y/ D1 C8 l3 ]- T9 M8 @ - }
6 G5 S! o9 y' w, E - else if (txBit == 8)# J/ l% @4 N9 G3 F3 d+ y6 U
- {
) j5 b& X; F8 i: d* w- Q: N - currentSym = txParity & 0x01; //发送奇偶校验位 G! C9 z! e8 [9 k7 S5 V: _
- txBit++;
# |/ |. q9 E( u" [7 W - } / P$ @7 M1 E; U
- else if(txBit>8 && txBit<12)& d9 L/ k6 Z5 Q, C
- {" `1 d* X" k' y# a) }" z* V
- // next bit is the stop bit
* d# [$ y! ^/ K$ W - currentSym = 1; //发送停止位# c& I# ^6 S$ \
- txBit++;1 G% y9 z/ J# X5 [' A; h
- }0 g+ g! o# r8 X9 C" V% t
- else if(txBit == 12)1 ~# F" _1 n* x& l+ O+ u
- FSK_txState = STOPBIT;
7 ^0 [! z3 s& ~* } - break;
3 e( x& q* @0 W" `5 T: M3 Z0 a - case STOPBIT :4 S) d7 \ v8 ^) v4 k) ]9 X
- txBit=0;
8 s( q0 q: H, F3 Q4 Z8 V - FSK_txState=IDLE;
/ w. F( h/ A3 [! } - send_start=0;
. w0 P J3 d, F7 i! G: {# c5 B9 Z# q+ _ - txParity=0;! h; I5 u! Y6 t
- send_byte=0;
$ q; _6 k7 w1 y7 ^; q0 A/ ] v2 O - break;
% `+ i8 n8 b b - }
$ n0 z7 [, L. f- n5 o L) q! u' F - if(lastSym!=currentSym)
2 K- v3 g2 V/ t7 e( _ - {
5 u6 ^0 }: `& [& n) r$ @5 p8 v - timer1_num++;! x+ k+ C" B2 m; I
- lastSym=currentSym;
; S% O8 i6 q" Z4 I# Z( }2 @ - }/ J1 _1 G; L# m! }1 V0 p5 c
- }
1 n- R# D2 }! F6 s6 I) U( e2 \ - if(timer1_num%2==0)" i4 ~! A4 K+ L3 h$ b8 {
- GPIODATA&=0xFFFFFFFD;//输出管脚复位
" M, L* y$ ?( P& S) z* n8 D - else
! b& H) N+ m+ n, o+ o - GPIODATA|=0x00000002;//输出管脚置位
/ i3 S3 |( H+ U9 D
; h2 J* A. J" [- timer1_num++;//用来控制IO口的电平翻转
$ {9 f, ]5 j M/ A7 j+ i0 y% d1 I# e - send_time++;//用来控制发送的字节的每一位$ B; x8 ~/ F- @! F* T
- Delay++;//Delay就是延时函数1 Y1 ]0 W7 x2 K3 B4 R3 J) T1 b* n
- }, w5 [- p5 f& m' H
- /**********************************************************************
8 g" u# ^& Y& Z) t7 \/ Q* E - 注释:解码函数采用外部IO中断形式(上升沿或下降沿中断,即电平电平跳变中断),
% P4 O4 d0 d1 ~* U) x - 用一个定时器作为时钟,每次产生中断时便从定时器见时间值取出,并和上一次的
" S0 _: n6 H6 O9 H% r) d - 记录做差求出时间间隔,以此来判断当前为宽沿还是窄沿。
6 {4 C( P' V4 r) A4 _ - ***********************************************************************/
/ u( t1 s6 @1 @1 a) ~2 @2 f - static void VIC_VECT_Fucton_04(void)//接受解码数据中断函数
/ v6 [# {) _1 F& ~ Y4 Y - {" H D0 g6 m9 k5 t1 c$ p9 x
- GPIOIC|=0x00000001;//清楚上一次中断内容9 N4 P4 K8 B! J1 J5 ^# a; j- D$ c W' _
- RX_time=TIMER1VALUE;/ A% Y7 s( T: J0 x% C- K2 J
- if(RX_lasttime>=RX_time)) K+ Q7 I% F4 g+ K' s' O
- RX_diff=RX_lasttime-RX_time; //lasttime初始值为07 \9 c. ^" A: u+ d# L
- else& J" k# L' S& Y% Y0 h
- RX_diff=65535-RX_time+RX_lasttime;
1 g. I! V/ A$ Y2 z - RX_lasttime=RX_time;
3 c a' L( ?3 L - switch(RX_state) //启动代码时state已经被配置为STARTBIT
: o: M& C( ~, z$ P |4 h4 D$ f - {
6 t l0 F3 B" g' |2 h) ~6 R% H3 s - case STARTBIT_FALL:
$ N, i, e J* [. o3 ~* g - if ((SHORTINTERVAL<RX_diff) && (RX_diff<LONGINTERVAL)): r) S* Y* N7 r. |) |: o
- {/ w8 Y/ E: h2 B( ?' N/ g0 i
- if(RX_ones<5) //ones初始值为08 j/ @" f. ?( J% @* u/ h
- {8 H" [0 N0 w+ u, p2 c" t$ u
- RX_ones = 0;* D+ X# _& D: M0 ~1 y% ~
- } ! ?, G8 @- v0 U/ A
- else
) t- O8 ?) `, S" F4 m- { - {. F9 m- d2 h9 ~
- RX_state = DECODE; //将状态配置为解码
9 L2 u7 f' `0 t3 \! c& g9 H+ m - }
! J1 A, D9 ^. d { `1 z - }5 D( i& `. z: L. U9 s; E9 m4 ^ V
- else if(RX_diff < SHORTINTERVAL)
) [$ C8 y3 c Q ^. T2 g - RX_ones++;
$ w$ ]8 ]% y) C( F - else
- V; k5 Z) C, \/ {0 L4 |! P - RX_ones=0;: Z2 ~! s/ l; }) e7 J
- break;- H6 ^0 p2 o, ]
- case DECODE:8 Q& O* K5 N: k
- /**************通过间隔长短来判定数据**************/* P" l2 o9 A% t1 t
- if ((SHORTINTERVAL<RX_diff) && (RX_diff<LONGINTERVAL))// 若间距在范围内则当前数据位值和前一个相反, r# s* v, @. A9 @
- { $ M' v5 i: \7 z
- currentbit=(currentbit+1)&0x01;0 f. u/ ^6 v8 C7 w4 ?' M- @
- RX_times+=2;" ^* o* x$ h+ u
- }, e2 Q% G- o( A: Q5 V% x' N% Q% R
- else if( RX_diff < SHORTINTERVAL) 4 _4 Q& N, l7 Z( G
- {
" r! _5 F8 @% O. u) l- b8 X - currentbit=currentbit;
2 S5 o1 h" j" l9 i s - RX_times++;
2 X! E& e" J5 b: @; D/ {- O# s0 v5 P - }$ ^7 k5 V z2 W5 q
- else9 d+ e( Q$ A, H( _/ p. O
- RX_state = DATAINIT; ' o0 x; X, R( B1 h; H+ B
( m' F" ^; p. R9 {- /****************接受数据位,从低位接起****************/3 j/ ^, |/ _# y0 e% h
- if(RX_times%2==0)
" r4 ~4 z& t) p% ?- _ - {
5 p8 s0 K1 ?2 Z' f6 R1 t3 f - if(RX_bitcounter<8)% b% i! ~2 S/ l, U' R
- {
8 e! X, g( a. }2 r# P) X - if (currentbit==1)2 L3 y, y9 a: f. E/ ]4 h* R& R
- {
% {, J( D; y4 K! }& j& L5 h2 @ - uartByteRx = (uartByteRx >> 1) + (1<<7);
" F5 U) L% M1 k - rxParity++; //奇偶校验位* S0 c6 ?5 s) w% ]
- RX_bitcounter++; //接受数据位数* Y8 f3 y9 q8 X# c6 f" }& n) y
- }
: B( w+ |. b O/ c - else2 J, _& w' F' T7 |
- {
& d; h8 ~8 S4 y& _ x$ A - uartByteRx = (uartByteRx >> 1);. k2 H/ D4 h' h: q. t6 l7 \
- RX_bitcounter++;/ G/ B8 {3 r& n
- }7 X* ~/ L( i0 q: _- {( h
- }
4 {8 m( _8 L9 \3 q - else* r/ o: u O w8 t% C& _* G
- {8 F$ ]8 f. x) x6 H8 z2 U8 U
- rxParity&=0x01; //进行奇偶校验3 ^( y% M* i: R: ~
- if(rxParity==currentbit)+ {0 r) _0 F3 T
- {
5 T7 ^6 W& _( ~+ t8 O+ ~( n8 w( L3 @ - RX_bitcounter++;
6 g& c8 ^, f) F' |2 T - RX_finish=1;
! Z7 C* _/ h! u - RX_state=DATAINIT;
2 w: s; C, C1 S) [" l; } - }
0 i+ j+ k/ T, I, g% |! U - else2 p A/ y1 J: w$ K2 z [
- RX_state=DATAINIT; //若奇偶校验错误则,重新检测
- O7 |4 q0 `1 F% a" H$ j4 g3 y2 ~ - }
+ c1 G' B# P' f2 \6 v - }
: e% `7 T% g' V - break;
3 G; v5 v% K' D9 r2 l5 n - case DATAINIT : //初始化参数状态6 J4 B6 R `$ \! {% u1 M( j) J0 c- Z ^
- RX_bitcounter=0;
# ` j, Q2 B' x' d W: J - RX_ones=0;; o/ X& P" q7 Y# H
- rxParity=0;% h) r7 j5 M1 @2 `
- currentbit=0;
6 E9 {3 `+ x4 l: j7 y: c; U5 w - RX_state=STARTBIT_FALL;
: J" K' [9 Z: m - RX_times=0; U. K9 d. O4 ~6 t6 L; H# V$ E
- break;. z5 u: M0 B5 D9 o q
- default:
. n0 U0 a( l" g1 f - break;
' f+ k- m4 a3 N4 S- \ - }; {$ T! V" o) I* f' d, k
- }
复制代码
- j+ ]0 X# D4 S8 O- \& T8 c: { A3 u% L0 X) 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
|