设计与开发

单片机音响 单片机实例分享,通过手势控制的体感音响

小编 2024-11-24 设计与开发 23 0

单片机实例分享,通过手势控制的体感音响

在一些科幻电影中,我们经常能看到人们用手指在空中划动几下就可以控制一台机器。现在我要介绍一款音响,它不是一台普通的音响,而是一款能感知手势的音响。没有开关,没有按键,甚至连一个音量控制旋钮都没有,完全通过探测你的手势来实现开/关机、音量的增/减等操作。

你一定想知道它是怎么工作的,原理其实很简单,就是使用传感器来测量手与机器的距离,根据不同的距离来控制音响,整个系统的构成如图2.1所示。当然这是一维探测,如果有两个传感器水平放置,通过计算两个传感器与手的距离差就可以进行二维控制。

图2.1 体感音响的系统构成

材料准备

1. 测距传感器

目前市面上比较流行的测距方法有3种:无线电测距(也就是常说的雷达)、激光测距和超声波测距。无线电测距在这里显然不行,我们的测距探头要求达到毫米级的精度,而且长时间的电磁辐射会对身体造成伤害。至于激光测距,探头通常造价不菲,另外过强的激光束可能伤害到眼睛。因此,最合适的要数超声波测距了。超声波只是发射出听不见的声音,精度可以保证,还存在盲区小的优点,不会发生手晃动一下,传感器就失去目标的现象。

为了简化硬件设计,最好购买现成的模块,实物如图2.2所示。

图2.2 超声波测距模块

2. 中央控制器

过去,51内核的单片机牢牢地占据着微控制器市场,直到现在也是初学者入门嵌入式系统的绝佳选择。然而任何事物都有一个生命周期,51内核的“先天不足”越来越明显。CISC的复杂架构使芯片门数增加,从而导致功耗高,时钟频率难以提高。RAM、ROM容量普遍偏小,使其很难运行嵌入式实时操作系统,导致研发周期加长。从目前的形势来看,以ARM公司Coretex-M3为内核的STM32系列微控制器最合适不过了。以STM32F103RBT6芯片为例,仅十余元的价格,就带来很多令人兴奋的配置:最高72MHz的时钟频率,带有USB2.0、I2C、USART、SPI、IIS、CAN等接口,拥有128KB的片内Flash、20KB的RAM,拥有49个I/O口(GPIO)、8个定时器,20mA的灌电流直接驱动LED……最主要的是,可以运行μC/OS-II等流行的嵌入式操作系统。其资料也相当齐全,在网上可以找到很多开发板,有的不但附赠很多源代码,甚至还提供视频教程、配套书籍等。因此,不管你是老手还是新手,都是很值得一学的。

为了节约电路板面积、提高性能,目前大部分芯片都采用了贴片封装。这或许会给手工焊接的质量提出更高的要求,不过购买最小系统模块也是不错的选择,虽然稍微贵点,但是硬件性能能得到保证,使我们不用总是做一些重复性的劳动,而是把精力集中在软件的编写上。已经包含最小系统的RBT6模块如图2.3所示。

图2.3 包含最小系统的RBT6 模块

3. 放大器与数字音量电位器

同样,为了简化硬件,放大器仍用现成的模块,如图2.4所示。现在的音频放大器模块种类很多,具体规格就要看你自己的喜好了。我选用的是一款功放芯片为TEA2025B的3W双声道模块,其增益可通过微调电阻调节,+5~+12V供电,用来做电脑的桌面音箱已经足够了。

至于音量调节电路,就需要自己动手制作了。我选用FM62429作为音量调节模块的核心,完成后的实物如图2.5所示。其制作过程我会在后面详细介绍。

图2.4 基于 TEA2025B的放大器模块

图2.5 自制的音量调节电路

4. 其他

另外还需要LED若干、万用板2片、一些常用的接插件、线材以及焊接工具等,具体就不多说啦,相信DIY爱好者一定早有准备。

软件:前后台还是操作系统 ?

在我学习μC/OS-II嵌入式实时操作系统时,看到过一句话,大致是这样的:当你学会使用操作系统,就再也不想回到前后台的开发方式。这不禁让我想起当初学汇编和C语言时,一开始总是在想,学会了汇编是不是还有必要学C语言,但当我学会了C语言,就再也不想转回汇编语言开发程序。使用操作系统到底有多少优点,我不想多说,这需要自己去实践。我想说的是,有很多知识,我们并没有意识到是需要的,直到我们学会了并且应用了。

常用的嵌入式操作系统有很多,比如大名鼎鼎的VxWorks、当前手机使用最多的Android,以及通过美国航空管理局认证,已经应用在“好奇”号火星车的实时内核μC/OS-II等。在这里我使用μC/OS-II,主要考虑到它源代码开放、结构简单、在国内比较流行,而且有大量的学习资源及代码。

图2.6 嵌入式软件系统的基本模型

嵌入式软件系统的基本模型如图2.6所示。当然,并不是所有软件系统都完全遵循这一模型。然而对于大多数嵌入式设备来说,采用这种层次结构来开发整个系统的软件,具有很强的可操作性和可维护性。

软件原理

1. μC/OS-II 基于任务(task)的软件设计方法

简单单片机系统如图2.7所示,这种软件设计方法将所有代码放在一起,代码层次概念不清晰,且功能简单,因此仅适用于小型系统。

μC/OS-II操作系统下基于任务的软件设计方法则不同。基于操作系统的软件开发抛开了对硬件资源的管理,而将硬件资源的管理交给操作系统,这使得代码的层次关系很清晰。同时,对某个任务的响应时间可以由操作系统控制,从而提高程序的执行效率。

图2.7 简单单片机系统

2. 控制方法

在讲代码之前,我们要先明白让程序干些什么。其实我们要实现的功能很简单——开机、音量增、音量减,但是要知道,探测器探测的距离不一定总是到手的距离,它本身并不具备人手识别的功能,只是探测离它最近的物体的距离。也许你在走路的时候会无意间触发其控制程序,出现不想要的结果。因此我们就要有一个“距离开关”,只有达到特定的距离才能被打开,从而使控制有效。

在本程序中,我采用下限距离法和LED渐亮指示法。先设定一个下限距离,比如5cm。当探测的距离大于或等于5cm时,不进行任何动作;当探测的距离小于5cm时,第一个LED由灭渐渐变亮,此过程大约持续2s,如果在这2s内,探测的距离一直小于5cm,那么就打开电源或音量控制开关(流程图见图2.8)。

图2.8 流程图

之所以这样,是因为如果音响放在桌面上,它离桌面边缘通常会有一定的距离,身体自然会大于这个距离,这样便避免了测错目标。加上2s的渐亮延时是因为手可能会在不经意间进入其临界距离,由于声音传播的速度太快,如果不加延时,便会产生误动作。这就像我们设计键盘扫描程序一样。

图2.8所示的流程只是一个思路,实际的代码是分在不同的任务中,在后面我会详细讲解。另外,音量控制是这样的:有5个LED用来显示由近及远5个不同的距离。超声波测距模块的有效距离为30cm,这样我们可以把距离分成6份,每份5cm,每接近5cm,点亮一个灯。如果距离大于30cm,则认为音量设定完毕。

实际操作时是这样的:假如希望音量衰减为10dB,而当手移动至第二个灯亮时即为音量衰减到10dB,这时可以将手水平移动到探测距离之外的盲区,会关闭音量控制开关,而一直保留10dB音量,LED灯也会全部熄灭。

3. 体感音响的软件部分

整个软件由10个文件夹、29个C源代码文件组成,如图2.9所示。不过不用害怕,有很多都是操作系统代码,没必要理解每一行程序,只需要知道重要函数的用法即可。真正需要自己写的代码,其实只有iCode文件夹中7个与硬件相关的C语言驱动程序以及APP文件夹中名为app. c的应用程序。其他的代码很少需要修改甚至不用修改。

图2.9 整个软件由10个文件夹、29个C源代码文件组成

重要部分在app.c文件中,此文件有启动操作系统的main函数,各个任务的建立及运行函数,如图2.10所示。在我们自己编写的所有代码中,有5个文件是操作芯片的外部设备的:VoiceVolume.c控制数字音量电位器,Capture.c控制雷达模块,Led.c控制距离指示LED,pwm.c利用脉宽调制控制LED亮度、启动电源及音量控制开关。另外还有sys.c和timer.c,这两个文件主要是对芯片内部的配置,比如配置中断向量表、定时器等。在实际调用这些代码时,通常会建立与.c文件同名的.h文件。.h文件包含函数的声明、全局变量的声明。在调用的时候,也是用#include命令包含.h文件的。

图2.10 app.c 文件部分代码解释

μC/OS-II是基于任务的,每个任务都有唯一的优先级。优先级不但代表了这个任务优先运行的程度,还是任务的标识。在μC/OS-II中,优先级的数值越小,其优先程度越大。

一个任务的形式通常如下:

static void任务名 (void *p_arg){

p_arg= p_arg;//避免警告

while(1){

用户代码…… }

OSTimeDlyHMSM(0,0,0,10);

}

每个任务都必须有一个死循环,在循环的末尾会有一个延时函数。当一个任务进入延时函数后,此任务便由运行态转为挂起,从而让优先级次低于它的任务执行。虽然从微观角度看,这些程序仍然是顺序执行的,但由于每一任务的用户代码执行得非常快,因此看起来像是同时运行。

p_arg为任务函数的参数,如果不使用,编译器会发出警告。因为我们用不到它,又为避免难看的(但不影响程序正常运行)警告所以会加上“p_arg= p_arg;”。

任务执行时,有时需要进行任务间通信。μC/OS-II支持信号量、邮箱和消息队列。在这里,我们要将AppRader任务计算的距离值传给LED指示任务AppLedIndicate、亮度调节任务AppPWM以及音量控制任务AppVoiceControl,使用邮箱来传递。我们用OSMboxPend函数阻塞式读取数据,也就是说,只要没有收到数据,此函数所在的任务就一直处于挂起状态。

4. 重要代码详解

为了更好地说明程序的工作原理,请看如下代码。

首先是函数及变量的声明:

#define Task_ControlVoice_PRIO 8

#define VoiceTASK_STK_SIZE 512

OS_STK VoiceStk[VoiceTASK_STK_SIZE];

static void AppVoiceControl(void *p_arg);

#define Task_Rader_PRIO 5

#define RaderTASK_STK_SIZE 512

OS_STK RaderStk[RaderTASK_STK_SIZE];

static void AppRader(void *p_arg);

///////LED indicate

#define Task_LedIndicate_PRIO

#define LedIndicate_STK_SIZE 512

①OS_STK LedIndicateStk[LedIndicate_STK_SIZE];

static void AppLedIndicate(void *p_arg);

/////// PWM Control LED

#define Task_PWM_PRIO 7 //6

#define PWM_STK_SIZE 512

OS_STK PWM_IndicateStk[PWM_STK_SIZE];

static void AppPWM(void *p_arg);

/////////Power control

//#define Task_PowerControl_PRIO 9

//#define PowerControl_STK_SIZE 256

//OS_STK PowerControlStk[PWM_STK_SIZE];

//static void AppPowerControl(void *p_arg);

②OS_EVENT *pmailDistance;

③typedef enum {PowerOff=0,PowerOn=1,VoiceOff=0,VoiceOn=1}eStatues;

int gviPowerStatue=0;//gvi means:global volatile int

int gviVoiceStatue=0;

①为了进行任务调度,每个任务都需要一定的堆栈空间。我们用OS_STK,它实际上就是一个结构体。在这里我们将堆栈空间设为512字节。

②在使用邮箱之前,我们先要进行变量的声明。

③共用体eStatues用来指示电源和音量的开关,1表示开,0表示关。

然后进入main函数,初始化芯片、操作系统,启动内核等。

int main(void)

CPU_IntDis();//禁止CPU中断

OSInit();//UCOS初始化

①BSP_Init();//硬件平台初始化

②OSTaskCreate((void (*) (void *)) App_TaskStart, // 建立主任务

(void *) 0, (OS_STK *) &App_TaskStartStk[APP_TASK_START_STK_SIZE - 1],

(INT8U) APP_TASK_START_PRIO);

OSTimeSet(0);

OSStart(); //启动内核

return (0); }

①对芯片正常运行进行初始化,比如将内核时钟调节至72MHz,设置GPIO端口、中断优先级、波特率,以及开启1号串口。

②在这里我们建立了一个主任务 App_TaskStart。其实我们可以将所有的任务都放在 main函数中建立,但是为了看起来简洁,我们将其他任务放在App_TaskStart中建立。

此后是其他任务的建立:

static void App_TaskStart(void* p_arg)

{ (void) p_arg;

①OS_CPU_SysTickInit();//初始化ucos时钟节拍

#if (OS_TASK_STAT_EN > 0) //使能ucos的统计任务

OSStatInit(); //----统计任务初始化函数

#endif

App_TaskCreate();//建立其他的任务

②while (1) //1秒一次循环

{ OSTimeDlyHMSM(0, 0,1, 0); }

}

static void App_TaskCreate(void)

{ ///////////创建任务

OSTaskCreate(AppVoiceControl,NULL,//数字音量电位器调节音量任务

(OS_STK*)&VoiceStk[VoiceTASK_STK_SIZE-1],Task_ControlVoice_PRIO);

OSTaskCreate(AppRader,NULL, //超声波测距模块任务

(OS_STK*)&RaderStk[RaderTASK_STK_SIZE-1],Task_Rader_PRIO);

OSTaskCreate(AppLedIndicate,NULL,//LED指示灯任务

(OS_STK*)&LedIndicateStk[LedIndicate_STK_SIZE-1],Task_LedIndicate_PRIO);

OSTaskCreate(AppPWM,NULL, //PWM控制LED亮度任务

(OS_STK*)&PWM_IndicateStk[PWM_STK_SIZE-1],Task_PWM_PRIO);

pmailDistance=OSMboxCreate(NULL); //////////////// 创建邮箱

}

①如果操作系统要正常进行任务调度等工作,就必须提供一个稳定的时钟滴答。以前我们经常用芯片的Timer,现在我们有了更方便的定时器——SysTick Timer。此 Timer 直接建在Coretex-M3内部,与内核共用一条时钟信号,是专门为加入操作系统而生的。

②实际上App_TaskStart任务只需运行一次,不能不断地创建任务,因此才加入一条循环程序,并且每秒运行一次。

至于任务间如何通信、各任务如何工作,由于代码量比较大,就不列出来了,其工作流程参照图2.8可以理解。

硬件原理与制作过程

1. 音量控制模块

我们以FM62429作为音量控制模块的核心器件,其原理图如图2.11所示。

要控制 FM62429,我们需要两根线:数据线(DATA)和时钟线(CLOCK)。其时序如图2.12所示。数据位有10位,如图2.13所示,其中D0和D1位为声道选择位。当D1为0时,双通道同时修改。当D1为1时,若D0为0,只修改通道1;若D0为1,只修改通道2。D2~D10为音量控制位,因为音量衰减与数据值递增无关,因此只能查阅其数据手册来获得数据与音量的关系。

图2.11 FM62429 原理图

图2.12 FM62429的时序

最后介绍一下制作时需要注意的地方。从原理图可见,并没有几个元器件,因此制作难度并不大,但是要特别注意干扰。因为在音量控制级上只要有很小的干扰,经过放大器的放大后,就会发出很大的噪声。首先要过滤来自电源的干扰,在这里我用了大容量电解电容和小瓷片电容并联的方式。另外还要注意线路的布局,如图2.14所示。除了要看起来美观、有序外,还要注意模拟信号线要尽量短。最后,由于我们采用模块化的设计,模块之间的模拟信号连线最好不要用普通的杜邦线,而是使用3芯屏蔽导线。

图2.13 FM62429的数据位

图2.14 线路的布局

2. 超声波传感器

我使用的是深圳捷深公司设计的HR40超声波模块(见图2.2)。它共有4根引脚:VCC为5V电源,GND为地线,TRIG为触发控制信号输入,ECHO为回响信号输出。

其基本工作原理如下:用TRIG触发测距,保持最少10μs的高电平信号。模块自动发送8个40kHz的方波,检测是否有信号返回。若有信号返回,则通过I/O口ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。距离=(高电平时间×声速)/2。

由于我们测的距离比较近,在实际编程中,以毫米为单位。又因为芯片定时计数器的捕获时钟设为1ms,这样,只要将测到的时间值乘以0.17即可。

3. 其他

功率放大模块可以自制,也可以购买现成的,不过最好买单电源供电的,这样电平匹配会简单点。最小系统板选用雁凌YL-8。各个模块的硬件连接方法如图2.15所示。

图2.15 各个模块的硬件连接方法

4. 组装

外壳可以购买现成的机壳,我用的是一尺寸为20cm(长)×15.5cm(宽)×6.5cm(高)的白色塑料外壳,如图2.16所示。当然,如果用金属外壳,屏蔽效果会更好。如果你没有买到合适的外壳,也可以用大一点的塑料餐盒或者纸质包装盒。

我们先要用一个大一点的万用板来连接各个模块,完成后就可以安装在机壳内了。因为外壳底部有很多螺丝孔,因此很容易固定在外壳上。在外壳背面,再用电钻钻一个孔,用来连接电源线及数据线。

最麻烦的要数固定测距模块和LED了。准备一套AB胶用来固定。因为这种外壳的前后面板可以从槽内抽出,钻孔又方便了一些。抽出前面板后,测量好超声波发射和接收元件间的距离,然后打孔。我在这里遇到一个小麻烦——最大的钻头直径为10mm,而元件的直径为20mm,因此只能用刀片来扩孔。当两个超声波探头恰好能通过孔露在外面时,就大功告成啦,如图2.17所示。然后钻LED的孔,一共有5个,因为有合适的钻头,所以这一步是很轻松的,只是要注意顺序不要接错(LED从右往左依次为LED1到LED5),其中LED1兼作电源开关和音量开关的开启指示灯。这一切工作完成后,我们就可以舒服地坐在椅子上“远程”控制我们的音响啦!

图2.16 准备一个外壳来容纳部件

图2.17 在前面板上固定好测距模块和LED

二维手势控制体感音响大升级

前面向大家介绍了一维方式的体感音响,它的升级版不但可以感应到手距离传感器的远近,还能探测出水平偏移(即手在音箱的左侧、右侧还是中间位置)。现在让我介绍一下它吧!

在介绍它的原理之前,我先讲一下如何使用它。

开启/关闭电源:电路板左右各有一个超声波传感器(见图2.18),准确地说,是两个接收模块。让你的手心对着电路板,然后从左到右移动,注意手到电路板的距离不要超过30mm,这时你会看到最底下那一排(5个)LED也从左向右跟着你手的移动而依次亮了起来。当LED全部都亮了之后,手再从右向左移动,这时LED又随着手势从右向左依次熄灭。当LED全都熄灭大约1s后,你会听到轻微的“哒”的一声,这是继电器接通,电磁铁触点接触时的声音,也表明电源开启了。当你想关闭电源时,很简单,重复一次上面的动作就行啦!

图2.18 顶板

音量控制:控制音量要有一个前提,那就是电源需要处于开启状态。电源开启后,手从右向左,再从左向右(这和开启/关闭电源时的动作相反),会告诉微控制器启动音量控制程序。现在手不要急着离开,正对着右侧的传感器,你会发现当你的手前后移动时,右侧的一排LED也根据距离的不同而点亮不同的数目。如果正在播放音乐,你会听到其音量随着距离的变远而减小。当调到适合的音量,继续让手水平向右移,到一定的距离后,右侧LED突然全部熄灭,音量就会“定格”在那里。

经过我的介绍,你一定迫不及待地想知道其工作原理,并亲手制作一台了吧?不要着急,我会详细讲解的,不光是工作原理,还会包含在实验过程中可能遇到的问题。这些都是本人的亲身经历,独家秘笈哦。

升级版硬件

升级版体感音响的材料基本和第一版的一样,只是多了两个接收传感器模块(见图2.19)。如果不想全部自己设计硬件,在网上买现成的模块也是一个很好的选择。其实我比较推荐这种方案,因为我们的重点在于软件,而硬件方面在技术上是很成熟的,没必要做一些重复性的工作。当然,如果是为了学习硬件方面的知识,那就是另一回事啦。

图2.19 升级版体感音响的构成

虽然材料没有多用很多,但是整个系统的布局相比于第一版有了很大的变化。一是为了适应二维控制的特殊性,二来也大大提高了抗干扰能力,并降低了功率放大器的噪声。具体设计如下:首先,我使用了两片比较大(大概是10cm×15cm)的万用板,顶板用来安装指示灯电路和超声波发射、接收模块,底板则包含了整个系统的核心电路,包括数字音量控制电路、电源控制电路、功率放大模块以及微控制器模块(见图2.20)。顶板与底板的连接是这样的,发射模块及接收模块使用自带的排线连接,而考虑到LED指示电路需要的连线比较多,就直接用长一点的单排针来连接了(见图2.21)。

图2.20 底板

图2.21 LED 指示电路用长一点的单排针来连接

另外,还需要提醒两点:一是在线路排布上,由于涉及的元器件比较多,连线难免会搭在一起(见图2.22),一定要注意绝缘。我就遇到过下面这样的问题:在组装电源控制电路时,考虑到电路很简单,只有一个三极管、一个电阻、一个继电器,因此就直接用元器件引脚多出来的部分来连接,但我当时没有注意到,在焊接时引脚会很热,结果恰好熔化了旁边的红色塑料绝缘导线,从而造成了三极管基极和VDD之间短路。这个短路确实很“坑爹”,因为引脚导线很细,而且其温度又不至于使塑料绝缘体冒烟,结果两秒钟可以解决的问题,我花了好几个小时才解决。看来搞硬件的个个都要粗中有细才行。

图2.22 连线难免会搭在一起,一定要注意绝缘

二是关于数字地与模拟地,如果处理不好,很容易导致数字电路工作不稳定,模拟电路出现很大噪声。这在第一版时没有考虑周到,当扬声器接到放大器的输出端时总能听到很讨厌的噪声。为了避免以上情况,首先要用电感隔离数字地和模拟地。另外大家都比较喜欢用电脑的USB供电,但最好外接电源,因为计算机的音频插孔的地线也是来自计算机,这会造成数字和模拟电平不一致,带来很大干扰。

升级版软件

下面结合图2.23来介绍一下基本原理。首先,发射器发射一束声波,经过一定的时间,超声波就会反弹回左、右接收器,这时我们便可计算出手与传感器的距离,根据其信号强弱以及左、右接收器接收到距离的差值计算出水平偏移。

图2.23 基本原理

虽说原理讲起来很简单,但现实总是会和理想有一定差距,如果没有巧妙的办法,是很难实现的。下面我就还原一下“现场”,把遇到的问题与解决方法详细地讲一讲。

1. 最初的设想——距离计算法

最重要的要算是算法设计与选择了。我一开始使用的是三角形原理,算法复杂,计算量很大。我当时是这样想的:在图2.23中把两接收器间的距离看成三角形的底边,把目标物体看成是顶角,左/右侧接收器测出三角形的左/右边。因为3边长度都知道了,根据海伦公式便可知其面积s:

,其中p=(a+b+c)/2。a、b、c为各边边长。 由h=2s/c(底边长)可知高。从图2.24中可以看到,整个大三角形被高分成了左、右两个小直角三角形。以左侧小三角形为例,由勾股定理可知

,最后用底边长a4的1/2减去a3即得出手到两接收器中线的偏移a5。

图2.24 距离计算法原理图

在设计之初,我为想出这种方法兴奋得不得了,可是真正应用到实践中时,麻烦就来了。首先就是芯片的计算能力的问题。从海伦公式中可看出,不但要计算出二次方根,还要连续做3次乘法运算,数值稍微大一点,就溢出了。我一开始测试时,结果总是零,查了很久,最后才发现是因为数值太大,程序“罢工”了。事实上,即使降低精度,最后得到的结果也是相当不稳定的,因为手本身是一个不规则物体,而且还在不断运动。

2. 信号强度检测法

我研究了将近一个星期,还是没搞定,眼看计划就要泡汤了,最后终于想到了另一个方法——既然距离计算法不行,那就用信号强度检测法。这个方法非常接近蝙蝠的定位原理,因为蝙蝠的大脑没有那么快的处理速度,不可能计算出物体的距离。这个方法的原理非常简单:首先,发射器发射出一束超声波,请注意,这束超声波在同一水平面内,越接近中轴线的位置,信号强度越大。遇到手后反射的声波也同样如此(见图2.25)。如果手向左侧水平移动,左侧接收器接到的信号强度就会更强。根据两传感器的强度差即可知道偏移量。

图2.25 信号强度检测法原理图

以上方法虽然在软件上很容易实现,但在硬件上比较难实现,因为市面上大多数超声波接收模块都是以电平高低来触发处理器的Timer,并不能指示信号强度。难道我们真的要重新设计接收器吗?有没有替代方案呢?答案是肯定的。有很多接收模块都可以通过数字信号控制放大电路的增益,我们虽然不能直接得到信号强度,但可以间接测得。

同样请看图2.24,当左、右两接收器的增益很大时都能收到信号,尽管右侧的接收器距离目标物更远一点,但还不至于使信号衰减到收不到的程度。现在我们同步降低两个接收器的增益,直到左侧传感器恰好能够触发处理器的Timer,由于两接收模块的放大倍数本身就小,而且右侧信号强度又比左侧弱很多,显然右侧接收器不会触发处理器的Timer。如果手水平移动到中间,两传感器则会同时有或无信号;而移动到右边,情况就和左边相反了。这样,通过信号的有无,我们就间接地知道了手的水平位置。事实上,我们还可以根据此原理起到“无关物体过滤”功能。如果波是从身体反射过来的,那么信号强度会大于同距离时从手反射过来的声波。“原来用800倍的放大倍数就没反射信号,现在同样距离用500倍的放大倍数仍然还没有,一定是无关物体,”我们可以让处理器这样“想”。

3. 两种方法的结合

在实际的代码中,我将信号的有无,即偏移值分为5类情况,并对应地接上了5个LED来显示(图2.18中最下边那一排就是)。

LED1亮:手处于最左边,左接收器能收到,但右接收器收不到。

LED2亮:手处于最右边,左接收器收不到,但右接收器能收到。

LED3亮:手处于中间位置,两接收器均能收到,且距离基本相等。

LED4亮:手处于中间偏左位置,两接收器均能收到,但左边收到信号的时间更短。

LED5亮:手处于中间偏右位置,两接收器均能收到,但右边收到信号的时间更短。

事实上还有一个隐含状态——左右两边都没有收到信号,这样就没法探测手势啦,不过它可以帮助我们关闭音量控制程序。

这样看来,我们既使用了距离计算法,又使用了信号强度检测法——鱼和熊掌并不总是不可兼得的哦。

4. 音量控制算法的设计

在完成了水平位置的探测后,我们就可以通过手势来开关音响的电源了。不过这还不够,因为我们经常需要调节音量。我是这样设计音量控制算法的:以手到传感器的距离变化来控制音量,当距离变近时,音量变小,反过来则变大。

在这之前还有一个步骤,由于我们在开/关机时不能保证手的移动绝对水平,或者说探测的垂直距离值始终不变,这会导致音量也跟着变了,这并不是我们想要的。因此我们要有一个音量控制“开关”,当然它不必是真正的开关,而是一组程序。其功能类似于手机的锁定键,如果手机放在口袋里,很容易按下不可预知的键,加上锁定功能,就不会对误按做出反应。不过在这里我们不用按键,只需要用手挥一挥就可以。从左到右的手势是用来开机的,那么用于解锁的手势就从右向左吧!

当我们选好了想要的音量后,手总不能一直留在那儿吧?手一动音量值就又变了,因此还要吧“音量控制开关”关掉。其实很简单,不用再设计手势了,在控制音量时设定一个条件就可以了:当左侧传感器收不到信号,而右侧传感器能收到信号,也就是说,手在最右边时,距离值才有效。当我们要关闭音量程序时,接着把手往右移,直到右边的传感器也接收不到信号,就认为关闭此段程序了。之后只要我们不做出解锁的手势,再怎么张牙舞爪,音响也没任何反应。

以上内容我其实是以自然语言的方式来讲解计算机语言,因为现在的高级语言是很接近自然语言的。在实际编程中,我也是先将想法、注意点等写在笔记本上,至于画流程图、先写出伪代码之类方法,倒是基本没用过。不过流程图对于理解整体思路确实很有帮助,最后我还是画了一个给大家参考(见图2.26)。

图2.26 程序流程图

单片机创意小制作,ARM7音乐播放器

在校学习期间,教我单片机的王老师时常提起ARM处理器。她提醒我说,我们是计算机专业的,应该研究嵌入式系统。起因是,我喜欢单片机,而单片机偏偏在我们学校是电子系的专业。把单片机玩转了,对于计算机专业的我,就显得偏离专业了。那时,我还是头脑一热,在网上买了一个AT91SAM7S64最小系统。但是,一直没有像样地玩它。只是断断续续地写了几个简单的程序,像学习51单片机一样学它。随着时间的推移,它被遗忘在一边了。不过这几天在整理零碎时,我又开始注意到它了。

这次制作的主题是——做一款能够媲美山寨CD机的音乐播放器。随着MP3、MP4、手机、PMP等便携播放器的出现,在市场上很少看到专门卖CD机的柜台了。想想也是,现在马路上很少看到有人拿个硕大的CD机听音乐。最主要的原因,估计是CD光盘尺寸偏大,携带不便,所以现在听MP3的人越来越多了。但是,不管怎样,CD的音质还是相当好的。还记得去年,我制作了一款M8音乐播放器,朋友听了后,直接评价那音质不行。我解释说,那是8位的播放器,还是被他鄙视了。太伤我心了。于是,我又琢磨着做一款新的播放器,希望它超过普通MP3的音质。这回做好后,又特意给那位朋友试听了一下,这次他评价说,这音质的确超过普通MP3了。下面我会和大家分享制作它的过程。

主要芯片介绍

这次制作的音乐播放器使用了TI公司的PCM1770,它是24位低功耗立体声音频DAC。由于它能够直接驱动耳机,所以选择它作为音频解码器。当耳机的阻抗为16Ω时,它的输出功率为13mW。PCM1770使用的电源范围为1.6~3.6V,支持标准的I2S音频接口。对DAC的操作是通过SPI接口实现的。它的音量也由软件控制,音量控制一共分为64个等级。

电路的处理器使用Atmel公司的AT91SAM7S64。它有64KB的FLASH程序存储器,16KB的内部SRAM,是高性能的32位RISC架构的ARM7处理器,最高工作频率可达55MHz。它一共有64个引脚,PIO控制的I/O驱动电流可以达到8mA,PA0~PA3可以达到16mA,但所有I/O电流之和不能超过150mA。这款处理器具有SSC同步串行控制器,支持I2S标准,也有SPI接口,可以设定8到16位的数据长度,每个SPI接口有4个片选线。这样,处理器与DAC解码器的数据传输、控制命令的发送都可以在硬件上连接实现。

可实现功能

这个制作完成后,将CD音质的WAV文件复制到SD卡内,文件必须存放在根目录下。程序通过AT91SAM7S64的SSC串行控制器,把音频的数据流通过SSC接口传输到TI的音频DAC上。这样,耳机就播放出动听的音乐了。播放器使用普通的微动按钮控制,一共用了5个按钮,分别实现音量、选曲、播放、暂停等控制。

工作原理

整个制作,由图11.1所示的AT91SAM7 S64 最小系统(左边)、洞洞板(中间)和转接成DIP封装的PCM1770 DAC(右边)组成。

图11.1 制作所需的各部分实物

这款音乐播放器的工作原理并不复杂。主要由5大部分组成:

(1)AT91SAM7S64最小系统,比51单片机最小系统稍微复杂些。

(2)PCM1770 I2S音频解码器,用于驱动耳机或音响,播放音乐。

(3)SD卡存储卡,存放44.1kHz/16位的WAV格式的音乐文件。

(4)5个普通的微动按钮,功能分别为:控制音量、前后选择音乐和播放/暂停音乐。

(5)简单的用稳压芯片将5V的USB电源转换成3.3V的电路工作电源。

音乐播放器的原理图如图11.2所示,可分为5大部分:左上角为稳压电路,左下角为5个微动按钮,右上角为SD卡,右下角为TI的音乐DAC芯片,中间的就是AT91SAM7S64的最小系统了。

1.稳压电源

图11.2 电路原理图

它使用1117-3.3V的稳压芯片,把USB接口的5V电源转换成3.3V。4个电容起到滤波作用。稳压芯片可以采用SPX1117-3.3V、LM1117-3.3V或AMS1117-3.3V。如果使用有极性的电解电容,不要粗心地把正负极性弄反。

2. 5个微动按钮

这5个微动按钮排列成经典的上下、左右、中间的十字结构,它的控制功能大家很容易理解,分别是上下为音量控制、左右为切换歌曲控制、中间为暂停/继续播放控制。

3. SD 卡

使用了它的SPI接口,直接和ATM7的SPI接口的NPCS0、MOSI、MISO、SPCK连接,在程序中我使用了系统时钟16.9344MHz作为SPCK时钟,这样它的传输速率才可以超过CD音乐格式标准的数据流速度。

4. TI的DAC

这是这个系统最关键的地方,它需要SPI接口控制它,同时又需要I2S接口给它提供数据流。它的SPI控制接口与AT91SAM7S64的NPCS1、MOSI、MISO、SPCK引脚相连,程序通过拉低 NPCS0 与 NPCS1 这两个引脚来片选 SD 卡或 DAC 芯片。在传输数据时,可以拉低不同的片选信号来指定传输的方向。DAC的LRCK、DATA、BCK接口分别与RAM7的TF、TD、TK连接。但由于DAC芯片还需要系统时钟,它可以是128fs、192fs、256fs或384fs(fs为音乐的采样率,如44.1kHz采样率)。所以,我通过ARM7的PCK0引脚输出384fs频率的时钟。最后,还可以通过控制DAC的PD引脚为0,让DAC休眠,减低它的功耗。

5. AT91SAM7S64 最小系统

正确连接好处理器各内部控制器的电源,如VDDFALSH、VDDIO、VDDCORE、VDDPLL等,确认USB的D+上拉电阻到3.3V。在播放44.1kHz音乐时,确认使用的是16.9344MHz晶体(在下载程序时使用18.432MHz)。最后,在AT91SAM7S64的PLL RC引脚上连接 PLL滤波用的电容。这样,ARM7上电后就能运行代码了。

AT91SAM7S64的电源系统比较复杂,但还好仅仅需要单一的3.3V电压,即可解决所有供电问题。电源使用USB的5V电压,经过1117-3.3V稳压芯片稳压,然后给DAC、AT91SAM7S64、SD卡供电。AT91SAM7S64还需要1.8V的电源电压,好在它内部集成的电压调节功能,能输出1.8V电压。

AT91SAM7S64处理器只要正确连接好需要的2种电源电压(3.3V、1.8V),焊接上18.432MHz的外部晶体,并且连接上简单的USB接口电路,在物理上就能够下载程序了。注意,当使用18.432MHz的外部晶体时,烧录文件才能通过USB接口下载。但由于音乐播放器需要16.9344MHz的外部晶体,才能以正常的速率播放CD采样率(44.1kHz)的音乐。因此,下载好程序后,还需要切换晶体。这一步麻烦些。

程序首先初始化AT91SAM7S64的SPI接口和SSC接口,并使能PIOA引脚(连接按钮的引脚)和SSC接口(I2S接口)的中断。等初始化接口完毕后,程序才能通过已经正确配置的接口,初始化音频DAC、SD卡设备。等这些操作完成后,程序会通过读取SD卡的特定扇区,识别文件系统种类,并搜索根目录下的第1个音乐文件。最后,通过按钮控制,实现音乐的播放。

使用方法

先要格式化SD卡,使用FAT(FAT12与FAT16的合集)或FAT32都可以。然后,复制44.1kHz、16位的WAV音乐到SD卡上(注意,请复制到根目录)。插上USB电源后,按中间的播放/暂停按钮播放音乐(音乐播放器在上电时不能自动播放,还需要按下播放/暂停按钮才能播放)。

烧录文件的下载与使用

1. 引导代码简介

AT91SAM7S64内部含有一段叫SAM-BA BOOT的程序,它在出厂时已被固化,不会被擦除,也不会被改变。在特定的条件下,它会被复制到内部Flash中,这个复制的过程叫系统程序恢复。系统程序恢复后,下一次上电或手动复位时,SAM-BA BOOT代码就会运行了,它使用片上集成的USB或DEBUG串口与上位机通信,实现自编程。

2. 恢复启动代码

在PA0、PA1、PA2、TST这4个引脚保持高电平的状态下,上电并等待10s。由于上电时PA0、PA1、PA2默认上拉电阻使能了,所以这3个引脚可以悬空。而TST引脚内部下拉电阻使能,因此需要通过外部电路将TST引脚拉高。

10秒后当芯片再次上电时(记得恢复TST引脚为低电平),就会运行SAM-BA BOOT程序了。这时,把芯片的USB接口连接上电脑,电脑上就会发现新硬件,并自动安装驱动。当然,前提是你在电脑上已经安装了SAM-BA ISP下载软件。

3. 关于 ERASE 引脚

上电时ERASE引脚的上拉可以用来擦除内部Flash的安全位,并且会在50ms的时间内完成。它的作用是使整个内部Flash存储器的内容被清除掉。当完成这些操作后,安全位才会清除。

当你使用SAM-BA对器件编程后,执行了Enable Security Bit操作,即编程了Flash安全位,那么下一次恢复系统程序前必须拉高ERASE引脚。

4. SAM-BA 软件使用

首先,安装SAM-BA ISP软件,它会连同驱动一起安装的。这样,当把已经恢复启动代码的ARM7插入USB接口时,驱动即可自动安装,并在设备管理器里多出如图11.3所示的设备。

然后,双击软件运行,出现图11.4所示的运行画面。选择图11.4所示的连接方式“\usb\ARM0”和开发环境“AT91SAM7S64-EK”后,按“Connect”后连接。接着,烧录软件的主界面就会跳出,如图11.5所示。

图11.3

图11.4

图11.5

然后,点击“Send File”按钮,选择烧录用的BIN文件。最后,点击“Send”发送即可。期间会弹出扇区解锁确认和扇区锁定确认对话框,点击“Yes”即可。

几秒后,程序就烧录完毕了。重新上电后,音乐播放器的代码就能成功运行了。

制作简介

其实,整个制作对刚学习ARM7处理器的人也不难。买一个AT91SAM7S64的最小系统,它的32个PIO口一般都会引出来的,并用插针连接。只需要自己做底板,焊接好插座,就能方便地合并了。

我做的这个底板是用万用板制作的,尺寸大约是10cm×10cm。仔细观察的朋友,还会发现,这个底板的功能不仅仅是特意用来做音乐播放器的,还可以做许多关于ARM7的小实验。

底板的反面我用绝缘导线连接线路,这也是我目前喜欢的做法(见图11.6)。如果觉得难看,大家还可以自制PCB的底板,这样也能轻松焊接。

为了使自己的制作更美观,我又在网上买了片1.8mm厚的有机玻璃板。用小锯切割成10cm×10cm大小后,用砂纸仔细打磨。打磨好后在合适的位置上钻孔,最后用2mm的螺丝和对应的铜座固定,这个制作的外观就完成了(见图11.7)。

大家会发现制作的正面还有一根飞线,这是由于我买的最小系统,3.3V的电源插针没有向下引出,只好拿了条杜邦线连接到底板了。

图11.6 用绝缘导线连接底板背面的线路

图11.7 用有机玻璃制作播放器的外壳

相关问答

proteus: 单片机 仿真里的晶振频率怎样设置?-ZOL问答

双击单片机就可以设置频率了,有用(0)回复xuzhiyingdahuzi在protues中,晶振电路和复位电路是不需要连接的。有用(0)回复chenchen1983042311.05...

单片机 制作,P2口接键盘,P1.0输出,如图,为什么接上蜂鸣器一直...

1.确定单片机工作~检查复位电路:复位按键按下测量9(RES)脚是否置高(不按为低)~晶振电路是否连接正确,正确则最小系统正常。2.若最小系统正常,确定程序是否烧录...

51 单片机 的应用方向?

单片机广泛应用于仪器仪表、家用电器、医用设备、航空航天、专用设备的智能化管理及过程控制等领域,大致可分如下几个范畴:1.在智能仪器仪表上的应用...单片...

谁知道 单片机 有什么应用啊?

[回答]单片机已普遍实现了家用电器领域的控制,如电饭煲、电冰箱、空调、彩电、音响等等。深圳市凌芯微电子有限公司产品适用范围广,产品规格齐全,欢迎前来...

为何我家电脑关机了还一直嗡嗡响, 音响 也关闭了-ZOL问答

原因分析:这是因为电脑虽然关机了,但实际上电脑还是在运作的,相当于待命的状态,所以电脑还是会有信号输出的,这也就是音响“嗡嗡”响的根源所在。而电脑开机后...

单片机 主要应用于哪些领域? - 潘耶耶- 的回答 - 懂得

1.单片在一个系统中只使用一片机,这是目前应用最多的一种方式。主品单片机与传统的机械产品相结合,使传统的机械产品结构简单化、控制智能化,构成了...

各个 单片机 都可烧写程序吗-ZOL问答

单片机内部程序存储器,如果是FLASH的,就可以反复多次烧写程序的;如果是OTP的,那只能烧写一次,烧写完就不能改动;如果是MASK(掩膜)的,那就不能烧写,因为出厂时就...

单片机 烧不进程序去了,一直显示请给MCU上电-ZOL问答

这样还不行,检查复位电路、晶振电路、烧写程序的连接电路,这些再没问题,换单片机吧。有用(0)回复dxw328970146我推测可能是蜂鸣器与你的下载脚复用了,你把单...

89C51 单片机 芯片有几个引脚?;有几 个几 位的并行输入/输出口...

89C51单片机芯片有几个引脚?;有几个几位的并行输入/输出口;分别为哪三个?举报电子书纽曼纽曼C511人讨论7033次围观关注问题写回答讨论回答(1)q651...

汽车CD不读碟了怎么回事?

[回答]已知数据:车辆加速至50公里/小时(发动机转速为3000转/分钟),空档滑行至5公里/小时,滑行距离为2000多米,滑行时间约3分钟多。车辆加速至50公里/小时...

猜你喜欢