|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 seewolf 于 2021-6-9 18:11 编辑 ) C1 M6 m9 G4 n) z a
* T5 k" q2 u9 Y& G+ c自12年毕业至今工作将近一年,也积累了一些经验,接下来会一一分享出来,算是对阿莫的感恩吧!第一篇是关于手机音频通信方面的,12年上半年从事过几个月的手机音频通信的开发(我主要负责设备一端的程序和电路,手机软件部分不负责),积累了一点经验,在这里献丑了。3 l% T2 q; L, I$ ]4 U& P
一、手机音频通信的特点
/ Y# l/ p& p q: j/ D; O5 X6 @) D1、通用性强:在智能手机普及的今天,手机的对外通信接口多种多样,而其中以3.5mm的音频接口通用新最强,基本所有的手机、平板电脑都会有这个接口,所以在一些要求通用性的设备上,音频接口登上了舞台。
! Q3 j# S4 T1 W$ h1 ?2、速率低:由于手机音频部分的采样频率一般为44.1KHZ(部分国产山寨为8KHZ),这极大的限制了音频通讯的速率。我们都知道44.1KHZ的采样频率,那么最高的信号频率只能为20KHZ左右,而信号周期也不可能只有2个采样点,通常要到10个以上,这样层层下来通讯速率可想而知。% J0 O7 u. x$ q, E
3、小信号:音频通信的信号都是毫伏级的,各个手机厂商略有不同,但通常最大不超过200mv,通常我们通信使用的信号强度也就100mv左右,这导致信号比较容易受干扰,且在开发阶段对工具有着种种限制。" N) S" M1 q: U! Z7 C, I
二、手机音频通信分类3 ?; o' \! @; _1 }6 {. X
1、无线方式:
* `% {$ [ T+ b: W; S( ja) 无线方式大家可能不太熟悉,容我慢慢道来。我们都知道人耳能听到的声音频率为20HZ~20KHZ,而手机通信的信号频率最高也就20KHZ,所以无线通信方式是可行的。因为虽然人耳的极限听力能到20KHZ,但普通人一般在19KHZ以上时基本就听不到了,所以如果信号的强度比较弱,且控制在19KHZ到20KHZ之间,那么我们就可以将之当做是“超声波”来看待了。
9 T5 L9 K! g1 Q5 O* H! W' N: Lb) 其实在此提到手机音频通信的无线方式,算是给大家一种产品开发思路吧。它的通讯半径在10M左右,前景还是很广阔的,大家有兴趣的可以试试。(其实已经有这方面的产品了)
8 r L3 ?) s Z: y5 @1 {4 i2、有线方式:7 w0 @/ S$ Q. R2 j. A* H* C, e1 {
a) 有线方式分为单向(设备→手机)和双向两种,单向的限制少,开发难度也小一些,但实际应用时会受限制。而双向通信限制多,开发难度也大一些,但实际应用时更方便些。# ]4 Y6 n" c7 k' R: D
b) 设备→手机:曼彻斯特编码;FSK;DTMF;自定义正弦波9 {7 Y# t( f4 p$ P2 ?6 \
c) 手机→设备:由于手机输出的音频信号很小,无法直接使用,要么用运放发大到合适的范围,要么用电压比较器转换成TTL方波。; R" A/ g# b( e" m
三、手机音频通信硬件通信方式分类:手机音频通信的硬件通信方式大体可分为方波和正弦波两种。! d# ?2 F" m1 a! p( b
1、方波:方波通常使用的是曼彻斯特编码方式(什么是曼彻斯特编码自己去查),它的好处是可以用单片机直接输出方波,经过衰减后即可使用,方便简单。缺点是兼容性不好,因为手机音频部分有这样一个特性,它只识别变化的电平信号,当麦克输入的信号长时间保持在某一非零电平时,手机会将其视为零,而强行拉回零电位。这就是采用方波通讯方式的兼容性不好的最大原因了,并且方波也容易受干扰。
& m+ P2 n4 Y% _( F, ]7 [& W2、正弦波:正弦波不会出现上面所说的方波的问题,故正弦波的兼容性和稳定性更好一些。通常采用方案有FSK、DTMF、信号发生器、或方波转正弦波等。(后面会对以上方案逐一分析)
! r5 ^) T3 m1 ?4 ]& r- P6 w" e3、通信信道分析
6 E( }) [. [( ja) 我们知道音频接口有4根线,MIC、地、左、右声道。设备→手机用MIC,手机→设备用地、左、右声道中的任意一个。这里说一下,实际产品中,有一些厂家会更换地线,即将原本左、有声道中的一根改为地线来用,其实道理是一样的。因为音频通信的信号时交流信号,而地其实也是悬浮地,即便地线换了,最终的波形还是一样的,因为最终手机解析信号时需要的是频率和幅值。这样还剩下一个声道,通常被用来帮助设备进行上电识别,因为音频通信的设备通常都是电池供电的。
" B, H, k) ^" W2 A$ ` lb) 另外还要在MIC和地之间并联一个4.99K的电阻,因为手机是通过检测MIC和地之间的阻抗是否为4.99K(也有其他阻值的)来判断是否有设备(耳机)插入,这一点要谨记。
( q" J# T4 y( M3 r6 `四、各个通信方案对比分析
/ p( |2 b! ^ ]4 | v$ D% W1、设备→手机:0 e1 v8 y1 L+ N2 o* z
a) 曼彻斯特编码:在诸多通信方式中,曼彻斯特编码是最灵活简便的一种方法,编码信号可由单片机直接产生,经衰减电路衰减后便可直接使用。注意事项:曼彻斯特编码信号的生成有两种方式,一种是用PWM生成,一种是用定时器中断翻转IO,我个人比较倾向于定时器中断方式。因为我们知道曼彻斯特编码中有宽沿河窄沿之分,且宽沿和窄沿可能会灵活变化,而用PWM方式不容易精确控制宽沿、窄沿输出的变化,而定时器中断方式则非常灵活且容易控制。(后面会送上我自己写的曼彻斯特编码、解码函数)
1 s) c4 T+ i( Fb) FSK、DTMF方式:FSK和DTMF两种方式大同小异,使用时通常都是用集成的芯片来生成的,而这些芯片通常都是遵守固定的通信协议的的要求(FSK为Bell202或V.23协议,DTMF记不清名字了)。这两种通信方式的优点是采用正弦波通信、稳定性好且使用简便。但由于固定通信协议的限制导致通信速率、比特率也受到限制而缺乏灵活性。在这里跟他家推荐一款英国的通信芯片CMX系列,这个系列的芯片融合的FSK、DTMF的编码、解码,还是很不错的,大家有兴趣可以试试。(相关手册在附件里)
2 U' d. B7 d" |8 d% uc) 信号发生器、锁相环方式:这种方式用信号发生器或者锁相环来产生方波或正玄波,由单片机来控制波形的输出,也可以实现音频通信,且十分灵活。但缺点是电路较复杂,且不同频率信号之间衔接不好掌握,用不好反而是麻烦。(相关手册在附件里)
5 S: R4 C; H* i! ` J, e Td) 在这里送上一种我个人认为比较好的方案:就是曼彻斯特编码加低通滤波器,由单片机输出曼彻斯特编码,再经由低通滤波器将方波滤成正弦波后输出。既解决了FSK、DTMF灵活性的问题,又解决了曼彻斯特编码方波稳定性、通用性的问题。在低通滤波器方面我个人采用的是“集成低通开关电容滤波器”,它成本虽然高一些,但好处也是明显的,电路简单,使用方便,且占用的空间亦很小。(相关手册在附件里)
& B4 @7 E) }5 q) ?* @( y2 |2、手机→设备:3 {: V9 N# a8 M) l) G, W5 \
a) 放大电路方式:将手机输出信号经放大电路放大到合适的幅值,然后有锁相环或者结成FSK、DTMF芯片进行解析。该中方式难度最大,需要非常强的模拟电路功底,我个人水平有限,故采用的另一种方式。
- f* u5 j: {+ ib) 电压比较器方式:将手机输出的交流信号经电路强行拉到Vcc/2级别,然后加到电压比较器一端,另一段接比较电压Vcc/2,这样交流信号即被转化为TTL方波信号,此时再进行解析就变得很简单了。' ?" v5 L* w6 `+ Z' F8 |
五、研发注意事项(通讯方案分析部分由于过长,放到最后来讲)9 B6 A' X& \) F* ]
1、一个好手机录音软件是必须的,最好能在手机上直接看到波形的。
5 v, M. G8 y+ D2、建议用笔记本电脑进行开发,而非台式机。因为音频信号很小,容易受干扰,而台式机干扰较大,笔记本还有一个好处是必要时可将外接电源拔掉,用电池供电。3 f \) c; z3 j9 E8 Y3 V9 \
3、一个好录音笔必不可少,有时需要得到纯净的音频信号,方便更加准确的分析。
, d8 O! Y7 s2 j; k4、做一个转接板,一边接音频母座,一边接音频公头,将MIC、地、左、右声道4跟线用排阵引出,方便录音。
4 M7 Z: a" w. @* O* [5、做一个信号衰减电路,可将设备电路产生的信号衰减至音频接口能承受的范围内。前期调试时,我们可以用该电路将信号录进电脑进行信号分析。(推荐一个电脑音频信号分析软件:Goldwave); c7 R. R3 z) s- Z
6、录音用的音频线切记不要太长,不然会给你带来不少麻烦。最好自己做,用音频裸头、杜邦线、排阵即可制作,方便好用。
8 N/ u! q3 T: e: S X$ t* R( F9 H* E4 |1 L# c' i
曼彻斯特编码的编码解码函数如下:
9 p L; j3 Y+ E4 }. h- /**********************************************************************
P, C0 u6 T* P/ [4 }/ ` - 注释:编码函数都是采用定时器中断的形式,以曼彻斯特编码的窄沿作为定时器周期。5 z" e/ E# c6 c1 V$ W9 L
- 发送的数据包括1个起始位、8个数据位、1个奇偶校验位、3个停止位。* N# h+ \) _- _( U' b8 g
- ***********************************************************************/+ t& }: ^' {, o+ _
- static void VIC_VECT_Fucton_00(void)//发送编码数据中断函数
1 E3 p. y' e, C* [9 b - {
4 s8 W9 v+ z2 H: [" ~5 k. H8 [- I9 r - TIMER0IS =0x0;
; N a. K W4 B0 Q - if((send_time%2==0) && (send_start==1))
9 N9 i5 u5 e4 \" \7 W - {5 a" K% l- D4 ?4 P
- switch(FSK_txState)$ S b7 q, k$ M* r0 w$ ^( o
- { H) W! ?5 _% `5 X9 l% j
- case STARTBIT:9 W/ {$ ^- S i
- if((GPIODATA&0x00000002)==0x00000000)//如果检测到数据发送管脚为零; d1 N; s5 Y: V$ L9 o1 F& @& O0 D
- send_time++;
& a7 C6 E1 I4 l6 l7 P, w& F/ q - else
2 Z2 t+ K6 \: n% X6 s( Z - {
1 `& o( h+ f: J! `+ h& o/ z - currentSym=0;/ K3 X5 k4 [- y: o# I
- FSK_txState = BYTE;
/ ]8 p, T" \ @! Q% d. N - }
5 F: E# f* o5 p$ A1 | - break;+ S" g( h& Q" _/ j0 l% z
- case BYTE:
. k$ t" f: c4 J, F3 Q - if(txBit < 8): u$ R. p M$ A
- {1 l; C, p3 `9 @
- currentSym = (send_byte >> txBit) & 0x01;
5 M9 E2 F1 t+ q - txBit++;
- X/ l) @& Z [& M: E- y - txParity += currentSym; //奇偶校验位
/ x( C4 z: I* U - }
4 B0 \! x" E2 a: n, w' r - else if (txBit == 8)
X6 }* n2 `+ { - {
4 c& Q1 S4 c9 h2 V8 l W - currentSym = txParity & 0x01; //发送奇偶校验位. S% y& J; L& B1 W+ a4 O; k
- txBit++;
. Z. l1 G3 W9 Z+ Y6 s5 Z, x3 y - } 5 g1 V, q6 Z f( A f
- else if(txBit>8 && txBit<12)7 a2 [3 C' _3 a1 `' Y
- {# D( t& {$ f" O9 b# ?" w. Q9 P
- // next bit is the stop bit. S2 t% h O# }; _4 x T
- currentSym = 1; //发送停止位
3 Y/ J8 [6 q' u+ h, T$ X6 e3 d% { - txBit++;
, H% |% h9 m% u) ^2 U: ]9 n - }
$ |7 ?, B6 Z t2 v3 ` c, [ - else if(txBit == 12)! b, v4 ]" w$ {5 U/ h6 _
- FSK_txState = STOPBIT;
/ v& v6 p8 ]8 u3 y, W+ y* z& }: ^: Q( F - break;8 v, P8 ]: y6 w- j8 R- o
- case STOPBIT :0 }6 @0 [3 U) ?5 ~
- txBit=0;
, U/ ]. f3 X* Z6 {/ X# N& A - FSK_txState=IDLE; H7 e6 Y+ k. [1 k* c
- send_start=0;6 }+ P2 s$ C" @+ L. ~
- txParity=0;
) [0 w2 i* J: b/ y# [1 T& W9 f - send_byte=0;: \6 S) c B' [! q M
- break;) q# V5 f( ?" _0 k. N
- }
& Y$ u) w* e8 ?5 n: j# ^ - if(lastSym!=currentSym)- l: O, l; t% N' _4 K0 \6 h
- {6 S1 L+ }% h+ E# y$ @# u1 ?
- timer1_num++;) T5 `+ ]8 W0 M
- lastSym=currentSym;
. w: @3 {, U, T0 Q9 u - }
9 |$ A% n- N8 [1 l2 ] - }6 A0 o; ]6 v4 Y \$ P
- if(timer1_num%2==0)- d' s8 _9 ?% l
- GPIODATA&=0xFFFFFFFD;//输出管脚复位' ^6 a8 a9 ^ i$ Q4 W5 M
- else
- v- K% p, t* @* R - GPIODATA|=0x00000002;//输出管脚置位
4 F2 ~6 E1 b2 w# ? - $ H. q0 ~5 v" |' B4 ?
- timer1_num++;//用来控制IO口的电平翻转 Z8 B. s; h$ S I! p
- send_time++;//用来控制发送的字节的每一位
7 ?0 y; N- U& A - Delay++;//Delay就是延时函数5 K$ r3 u' @. K& [& s2 N
- }! A) L7 y( n) m; r* r7 K0 z' m& u
- /**********************************************************************
! ^& e9 r5 F& s$ L& y, M9 d - 注释:解码函数采用外部IO中断形式(上升沿或下降沿中断,即电平电平跳变中断),
& Z9 o$ h, Y+ f8 D2 v% p9 C - 用一个定时器作为时钟,每次产生中断时便从定时器见时间值取出,并和上一次的) j! F- E/ s3 j& T `8 r8 P5 a$ _, n
- 记录做差求出时间间隔,以此来判断当前为宽沿还是窄沿。
: H6 Q! i! a6 I - ***********************************************************************/: S% W g' a. _. b% Y p& S
- static void VIC_VECT_Fucton_04(void)//接受解码数据中断函数
' [: t( ~: [3 R" Z - {
' b6 Z& ~) _; f0 Y7 F" ?* Q+ l3 u - GPIOIC|=0x00000001;//清楚上一次中断内容
) \% T3 y+ Q& y: `# C- D% `4 K - RX_time=TIMER1VALUE;# _# Q7 E! j- [
- if(RX_lasttime>=RX_time)
) i' Q$ R- S7 f - RX_diff=RX_lasttime-RX_time; //lasttime初始值为0
+ U: V3 M. K7 b2 y8 i# m% r6 N& s - else8 s& r; q- u" ]3 A- J+ N2 v5 K/ S8 f
- RX_diff=65535-RX_time+RX_lasttime;5 b/ D5 P1 G1 S( a
- RX_lasttime=RX_time;
) I; O4 o& C+ I% x H, o; y - switch(RX_state) //启动代码时state已经被配置为STARTBIT
0 T' t6 `+ R. g: X0 H) o1 u - {
+ P6 j# F7 E# h - case STARTBIT_FALL:
. W9 u- {9 Q) r* d( A! F, W" T; \ - if ((SHORTINTERVAL<RX_diff) && (RX_diff<LONGINTERVAL))
% {5 M7 K8 e9 F* z! ?8 v$ c3 } - {$ z1 P" o# x, T \
- if(RX_ones<5) //ones初始值为0
) a0 H/ Z7 y8 X" D' j/ w - {
! ^. e8 _# B9 i1 f \& i" u; \ - RX_ones = 0;$ K4 p5 r6 {: N; S6 e2 E
- } ) W7 k9 Y: O* f
- else
% D: ^8 ~9 {; `4 ^! k1 O5 g/ O - {
. t3 d# Z/ L8 W9 |9 _7 z7 n - RX_state = DECODE; //将状态配置为解码
5 y# }. l, S8 Z0 v - }
1 \5 e# `# u" {1 e% p R - }6 j1 e8 `9 l' w6 V8 r0 a
- else if(RX_diff < SHORTINTERVAL)
# f' X8 n) l$ p! A/ m- Q - RX_ones++;, Y/ i$ ?/ F; l9 J: u/ X+ t3 |
- else! h% Q; R; B3 W, _* G7 p9 A
- RX_ones=0;
+ }: A9 v# u. l, ^, e - break;
$ J6 w: ?* B# x4 ~* R6 @* w - case DECODE:9 k$ R7 W8 c7 U% G6 [
- /**************通过间隔长短来判定数据**************/
1 y( B/ o$ E) W7 I1 o& C( P& E" B - if ((SHORTINTERVAL<RX_diff) && (RX_diff<LONGINTERVAL))// 若间距在范围内则当前数据位值和前一个相反+ }; x4 E8 f m9 f
- {
# e6 v; u+ K( H( y - currentbit=(currentbit+1)&0x01;
# n* S8 E) R( N ?$ S1 }$ C, i - RX_times+=2;# C$ B- w5 k2 d4 |
- }; V8 f8 P q5 Q; r7 Z
- else if( RX_diff < SHORTINTERVAL) & a! s# |4 C9 _4 g
- {5 b+ o4 e: K/ [+ F
- currentbit=currentbit;
& ^+ [2 Y3 {, U: _& F - RX_times++;
0 v* Y7 t9 V( c8 _1 O3 y( K2 F - }
) l& j* I! r& r V: d' v; \ - else8 E4 W- C3 S2 T" u& y4 o
- RX_state = DATAINIT;
& y1 n3 Y1 h/ |
2 L2 I& B, M' d/ h" X8 e- /****************接受数据位,从低位接起****************/+ a' g9 B7 R$ H, e
- if(RX_times%2==0)
4 E5 q; U/ z! s - {; J4 \& k% t9 c5 z: r) f
- if(RX_bitcounter<8)' o7 Q% x2 S: t, @. K1 P2 w# Y& G
- {- w2 B# }: f) E) K3 d0 f
- if (currentbit==1)
1 I/ y9 r! \7 n - {$ E0 D2 J% H& d. R
- uartByteRx = (uartByteRx >> 1) + (1<<7);
, {! q2 |' e. T3 }2 `5 R5 Y* P - rxParity++; //奇偶校验位
" O0 c6 t' K- a, n" Q - RX_bitcounter++; //接受数据位数; u: z2 j) | v5 U
- } f f) X0 E3 X+ c$ L( W( y* {
- else
1 M Y" ?2 J l8 H$ t1 k - {
+ X$ M' `' v3 Q- w - uartByteRx = (uartByteRx >> 1);( T2 y" [4 B1 {1 d/ H% D( R; R
- RX_bitcounter++;1 `2 }5 Y- ]+ k3 t& p y
- }6 D& E: u6 ] X6 Y n' N
- }, G$ B! ^& l5 f H5 X7 t
- else2 L5 D1 [; l2 h" w4 |* \
- {
) C, h4 m' d2 B6 b. D - rxParity&=0x01; //进行奇偶校验: Z! G; @8 J5 Z }$ q# h h& D
- if(rxParity==currentbit)
6 x8 W' i( O2 }* a4 u# e - {2 [$ g( h' [9 J5 m( w
- RX_bitcounter++;! h+ s+ R7 ^* X# i0 s4 p! x/ w
- RX_finish=1;
( s3 u. d6 @6 Q" \4 V, o) E - RX_state=DATAINIT;
( _! ^; y( G% L+ t% `- o - }( s. e3 X2 O3 p
- else
+ U0 x0 {; D1 w0 g - RX_state=DATAINIT; //若奇偶校验错误则,重新检测& o8 Q5 n4 ~; ^6 s0 Z Q+ A! o/ E$ \1 W
- }
! z6 v }& N9 a8 [ A - }# w4 _( r3 w" M& e- V; h6 g
- break;. ^. d6 `8 `' ~% w% a# \( i
- case DATAINIT : //初始化参数状态
* U/ {, z8 g! W" T: f6 l9 }- O7 A - RX_bitcounter=0;
/ E: n1 q6 t- d( L% K - RX_ones=0;0 S4 X& k1 N, {; X- P
- rxParity=0;
, z m, ]. m" `" N+ \1 A - currentbit=0;: Y' z7 u/ M, E* Z+ c1 t- i7 F3 @& q. p
- RX_state=STARTBIT_FALL;2 a& Y$ R% K1 Y& w8 O* w& t
- RX_times=0;
- n! M' O& {: }; y1 e. F) d - break;* y6 `4 G! z3 P* `5 X
- default:/ @( m+ k$ ~+ @. P; x1 W- k3 E, Q- T
- break;! }$ j/ W: g, R( A! @
- }
: E1 |. ]' R) U1 }8 b5 x! z - }
复制代码 7 t8 x3 d; T" n2 f
+ @% {4 q; O) c
|
-
-
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
|