單片機實例分享,通過手勢控制的體感音響

2021-01-11 電子工程師小李

在一些科幻電影中,我們經常能看到人們用手指在空中划動幾下就可以控制一臺機器。現在我要介紹一款音響,它不是一臺普通的音響,而是一款能感知手勢的音響。沒有開關,沒有按鍵,甚至連一個音量控制旋鈕都沒有,完全通過探測你的手勢來實現開/關機、音量的增/減等操作。

你一定想知道它是怎麼工作的,原理其實很簡單,就是使用傳感器來測量手與機器的距離,根據不同的距離來控制音響,整個系統的構成如圖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. 超聲波傳感器

我使用的是深圳捷深公司設計的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所示。

4. 組裝

外殼可以購買現成的機殼,我用的是一尺寸為20cm(長)×15.5cm(寬)×6.5cm(高)的白色塑料外殼,如圖2.16所示。當然,如果用金屬外殼,屏蔽效果會更好。如果你沒有買到合適的外殼,也可以用大一點的塑料餐盒或者紙質包裝盒。

我們先要用一個大一點的萬用板來連接各個模塊,完成後就可以安裝在機殼內了。因為外殼底部有很多螺絲孔,因此很容易固定在外殼上。在外殼背面,再用電鑽鑽一個孔,用來連接電源線及數據線。

最麻煩的要數固定測距模塊和LED了。準備一套AB膠用來固定。因為這種外殼的前後面板可以從槽內抽出,鑽孔又方便了一些。抽出前面板後,測量好超聲波發射和接收元件間的距離,然後打孔。我在這裡遇到一個小麻煩——最大的鑽頭直徑為10mm,而元件的直徑為20mm,因此只能用刀片來擴孔。當兩個超聲波探頭恰好能通過孔露在外面時,就大功告成啦,如圖2.17所示。然後鑽LED的孔,一共有5個,因為有合適的鑽頭,所以這一步是很輕鬆的,只是要注意順序不要接錯(LED從右往左依次為LED1到LED5),其中LED1兼作電源開關和音量開關的開啟指示燈。這一切工作完成後,我們就可以舒服地坐在椅子上「遠程」控制我們的音響啦!

二維手勢控制體感音響大升級

前面向大家介紹了一維方式的體感音響,它的升級版不但可以感應到手距離傳感器的遠近,還能探測出水平偏移(即手在音箱的左側、右側還是中間位置)。現在讓我介紹一下它吧!

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

開啟/關閉電源:電路板左右各有一個超聲波傳感器(見圖2.18),準確地說,是兩個接收模塊。讓你的手心對著電路板,然後從左到右移動,注意手到電路板的距離不要超過30mm,這時你會看到最底下那一排(5個)LED也從左向右跟著你手的移動而依次亮了起來。當LED全部都亮了之後,手再從右向左移動,這時LED又隨著手勢從右向左依次熄滅。當LED全都熄滅大約1s後,你會聽到輕微的「噠」的一聲,這是繼電器接通,電磁鐵觸點接觸時的聲音,也表明電源開啟了。當你想關閉電源時,很簡單,重複一次上面的動作就行啦!

音量控制:控制音量要有一個前提,那就是電源需要處於開啟狀態。電源開啟後,手從右向左,再從左向右(這和開啟/關閉電源時的動作相反),會告訴微控制器啟動音量控制程序。現在手不要急著離開,正對著右側的傳感器,你會發現當你的手前後移動時,右側的一排LED也根據距離的不同而點亮不同的數目。如果正在播放音樂,你會聽到其音量隨著距離的變遠而減小。當調到適合的音量,繼續讓手水平向右移,到一定的距離後,右側LED突然全部熄滅,音量就會「定格」在那裡。

經過我的介紹,你一定迫不及待地想知道其工作原理,並親手製作一臺了吧?不要著急,我會詳細講解的,不光是工作原理,還會包含在實驗過程中可能遇到的問題。這些都是本人的親身經歷,獨家秘笈哦。

升級版硬體

升級版體感音響的材料基本和第一版的一樣,只是多了兩個接收傳感器模塊(見圖2.19)。如果不想全部自己設計硬體,在網上買現成的模塊也是一個很好的選擇。其實我比較推薦這種方案,因為我們的重點在於軟體,而硬體方面在技術上是很成熟的,沒必要做一些重複性的工作。當然,如果是為了學習硬體方面的知識,那就是另一回事啦。

雖然材料沒有多用很多,但是整個系統的布局相比於第一版有了很大的變化。一是為了適應二維控制的特殊性,二來也大大提高了抗幹擾能力,並降低了功率放大器的噪聲。具體設計如下:首先,我使用了兩片比較大(大概是10cm×15cm)的萬用板,頂板用來安裝指示燈電路和超聲波發射、接收模塊,底板則包含了整個系統的核心電路,包括數字音量控制電路、電源控制電路、功率放大模塊以及微控制器模塊(見圖2.20)。頂板與底板的連接是這樣的,發射模塊及接收模塊使用自帶的排線連接,而考慮到LED指示電路需要的連線比較多,就直接用長一點的單排針來連接了(見圖2.21)。

另外,還需要提醒兩點:一是在線路排布上,由於涉及的元器件比較多,連線難免會搭在一起(見圖2.22),一定要注意絕緣。我就遇到過下面這樣的問題:在組裝電源控制電路時,考慮到電路很簡單,只有一個三極體、一個電阻、一個繼電器,因此就直接用元器件引腳多出來的部分來連接,但我當時沒有注意到,在焊接時引腳會很熱,結果恰好熔化了旁邊的紅色塑料絕緣導線,從而造成了三極體基極和VDD之間短路。這個短路確實很「坑爹」,因為引腳導線很細,而且其溫度又不至於使塑料絕緣體冒煙,結果兩秒鐘可以解決的問題,我花了好幾個小時才解決。看來搞硬體的個個都要粗中有細才行。

二是關於數字地與模擬地,如果處理不好,很容易導致數字電路工作不穩定,模擬電路出現很大噪聲。這在第一版時沒有考慮周到,當揚聲器接到放大器的輸出端時總能聽到很討厭的噪聲。為了避免以上情況,首先要用電感隔離數字地和模擬地。另外大家都比較喜歡用電腦的USB供電,但最好外接電源,因為計算機的音頻插孔的地線也是來自計算機,這會造成數字和模擬電平不一致,帶來很大幹擾。

升級版軟體

下面結合圖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。

在設計之初,我為想出這種方法興奮得不得了,可是真正應用到實踐中時,麻煩就來了。首先就是晶片的計算能力的問題。從海倫公式中可看出,不但要計算出二次方根,還要連續做3次乘法運算,數值稍微大一點,就溢出了。我一開始測試時,結果總是零,查了很久,最後才發現是因為數值太大,程序「罷工」了。事實上,即使降低精度,最後得到的結果也是相當不穩定的,因為手本身是一個不規則物體,而且還在不斷運動。

2. 信號強度檢測法

我研究了將近一個星期,還是沒搞定,眼看計劃就要泡湯了,最後終於想到了另一個方法——既然距離計算法不行,那就用信號強度檢測法。這個方法非常接近蝙蝠的定位原理,因為蝙蝠的大腦沒有那麼快的處理速度,不可能計算出物體的距離。這個方法的原理非常簡單:首先,發射器發射出一束超聲波,請注意,這束超聲波在同一水平面內,越接近中軸線的位置,信號強度越大。遇到手後反射的聲波也同樣如此(見圖2.25)。如果手向左側水平移動,左側接收器接到的信號強度就會更強。根據兩傳感器的強度差即可知道偏移量。

以上方法雖然在軟體上很容易實現,但在硬體上比較難實現,因為市面上大多數超聲波接收模塊都是以電平高低來觸發處理器的Timer,並不能指示信號強度。難道我們真的要重新設計接收器嗎?有沒有替代方案呢?答案是肯定的。有很多接收模塊都可以通過數位訊號控制放大電路的增益,我們雖然不能直接得到信號強度,但可以間接測得。

同樣請看圖2.24,當左、右兩接收器的增益很大時都能收到信號,儘管右側的接收器距離目標物更遠一點,但還不至於使信號衰減到收不到的程度。現在我們同步降低兩個接收器的增益,直到左側傳感器恰好能夠觸發處理器的Timer,由於兩接收模塊的放大倍數本身就小,而且右側信號強度又比左側弱很多,顯然右側接收器不會觸發處理器的Timer。如果手水平移動到中間,兩傳感器則會同時有或無信號;而移動到右邊,情況就和左邊相反了。這樣,通過信號的有無,我們就間接地知道了手的水平位置。事實上,我們還可以根據此原理起到「無關物體過濾」功能。如果波是從身體反射過來的,那麼信號強度會大於同距離時從手反射過來的聲波。「原來用800倍的放大倍數就沒反射信號,現在同樣距離用500倍的放大倍數仍然還沒有,一定是無關物體,」我們可以讓處理器這樣「想」。

3. 兩種方法的結合

在實際的代碼中,我將信號的有無,即偏移值分為5類情況,並對應地接上了5個LED來顯示(圖2.18中最下邊那一排就是)。

LED1亮:手處於最左邊,左接收器能收到,但右接收器收不到。

LED2亮:手處於最右邊,左接收器收不到,但右接收器能收到。

LED3亮:手處於中間位置,兩接收器均能收到,且距離基本相等。

LED4亮:手處於中間偏左位置,兩接收器均能收到,但左邊收到信號的時間更短。

LED5亮:手處於中間偏右位置,兩接收器均能收到,但右邊收到信號的時間更短。

事實上還有一個隱含狀態——左右兩邊都沒有收到信號,這樣就沒法探測手勢啦,不過它可以幫助我們關閉音量控制程序。

這樣看來,我們既使用了距離計算法,又使用了信號強度檢測法——魚和熊掌並不總是不可兼得的哦。

4. 音量控制算法的設計

在完成了水平位置的探測後,我們就可以通過手勢來開關音響的電源了。不過這還不夠,因為我們經常需要調節音量。我是這樣設計音量控制算法的:以手到傳感器的距離變化來控制音量,當距離變近時,音量變小,反過來則變大。

在這之前還有一個步驟,由於我們在開/關機時不能保證手的移動絕對水平,或者說探測的垂直距離值始終不變,這會導致音量也跟著變了,這並不是我們想要的。因此我們要有一個音量控制「開關」,當然它不必是真正的開關,而是一組程序。其功能類似於手機的鎖定鍵,如果手機放在口袋裡,很容易按下不可預知的鍵,加上鎖定功能,就不會對誤按做出反應。不過在這裡我們不用按鍵,只需要用手揮一揮就可以。從左到右的手勢是用來開機的,那麼用於解鎖的手勢就從右向左吧!

當我們選好了想要的音量後,手總不能一直留在那兒吧?手一動音量值就又變了,因此還要吧「音量控制開關」關掉。其實很簡單,不用再設計手勢了,在控制音量時設定一個條件就可以了:當左側傳感器收不到信號,而右側傳感器能收到信號,也就是說,手在最右邊時,距離值才有效。當我們要關閉音量程序時,接著把手往右移,直到右邊的傳感器也接收不到信號,就認為關閉此段程序了。之後只要我們不做出解鎖的手勢,再怎麼張牙舞爪,音響也沒任何反應。

以上內容我其實是以自然語言的方式來講解計算機語言,因為現在的高級語言是很接近自然語言的。在實際編程中,我也是先將想法、注意點等寫在筆記本上,至於畫流程圖、先寫出偽代碼之類方法,倒是基本沒用過。不過流程圖對於理解整體思路確實很有幫助,最後我還是畫了一個給大家參考(見圖2.26)。

相關焦點

  • 用手勢操控!惠普PC或引入體感控制傳感器
    【PConline 資訊】體感控制傳感器開發者Leap Motion公司今天宣布,已經和惠普達成共識,將自己的體感技術引入到惠普PC中。它可以給用戶帶來手勢與電腦互動的功能。這是一次非常值得關注的嘗試,這也是全球首次將體感與電腦整合。Leap Motion已經計劃將Leap作為單機設備銷售,定價80美元。
  • 揮手操控 五款手勢/體感控制電視推薦
    手勢操作對於電視來說是一項比較新的操控技術,往往會出現在一些性能比較強大的智能電視上。手勢控制實現了一種新型的人機互動模式,擺脫遙控器的限制。並且手勢控制的適用範圍比較廣,不僅能夠點選、滑動,還能夠實現拖拽等豐富的操控,理論上能夠完全代替遙控器實現電視的各項操控。
  • 基於proteus的51單片機開發實例37-DAC0832
    設計思路圖1 DAC0832電路本例中使用51單片機控制D/A轉換晶片DAC0832,通過單片機輸出一系列的數位訊號到DAC0832,DAC0832把這些數位訊號轉換成模擬信號,以電流的形式輸出。1、選中DAC0832,單片機通過P2.7引腳送出一個低電平到DAC0832的CE和XFER,P3.6引腳送低電平到WR1和WR2。DAC0832就被選中。2、向DAC0832寫入數據,單片機通過P0口送入數據。3、DAC0832對送來的數字量進行數模轉換,並從IOUT1引腳輸出信號電流。
  • LED燈的51單片機pwm控制實例
    我們知道 51單片機本身是沒有pwm接口的,這個程序是通過軟體模擬pwm.在一定的頻率的方波中,調整高電平和低電平的佔空比,即可實現LED燈亮度控制
  • 樂視體感電視機怎麼樣 樂視體感電視機詳細介紹【圖文】
    電視的種類也越來越多了,例如數位電視,網絡電視,體感電視。我要大家對數位電視,網絡電視都是比較熟悉的,但是體感電視在我生活中還是屬於少見的。甚至有些朋友對體感電視都沒有停過。而體感電視是一款 智能電視 機,它能通過語音或簡單的手勢,用戶就可以完成 開關 機、調節音量、換臺甚至上網瀏覽或搜索等複雜的功能,通過面部識別,用戶可以直接登錄網絡。
  • 單片機數據存儲器RAM的擴展實例
    RAM是用來存放各種數據的,MCS-51系列8位單片機內部有128 B RAM存儲器,CPU對內部RAM具有豐富的操作指令。但是,當單片機用於實時數據採集或處理大批量數據時,僅靠片內提供的RAM是遠遠不夠的。
  • 手勢識別發光圈-體感互動裝置介紹「振邦視界」
    隨著現代科學技術的發展,智能體驗設備越來越多,和以往通過按鍵的形式來控制場景相比,如今交互式的體驗設備越受青睞。近日,多媒體互動廠家-深圳振邦視界推出了手勢識別互動裝置,該設備有助於增加人機互動的友好性及趣味性,運用於商場等各展覽展示場所中都可增加不少的吸引力。那麼這款高大上的體感互動裝置如何操作呢?小編帶大家一起來了解吧!
  • 單片機實例分享,基於HMC5883L的電子羅盤
    TXD與RXD為串口接口,與單片機直接連接,無需做電平轉換。模塊內部同時集成了降壓模塊,可以輸出3.3V電壓,但由於已經使用了HMC5883L模塊的降壓功能,本系統中該輸出引腳懸空。4. 底板模塊各模塊之間需要通過底板進行連接,其原理圖如圖21.6所示。
  • 51單片機玩轉物聯網基礎篇05-控制繼電器
    前言本節我們開始學習如何使用51單片機控制繼電器,有了繼電器,我們可以使用單片機輸出的低電平控制高電平期間工作,比如繼電器接到220V用電器上,可通過單片機智能控制用電器。,繼電器輸出需要單獨提供電源,可以使用220V供電,然後迴路通過繼電器輸出埠,分別接NO和COM埠,如此繼電器輸出控制相當於一個開關,可以控制輸出電路的通斷。
  • 基於proteus的51單片機開發實例33-單片機的編程規範
    基於proteus的51單片機開發實例33-單片機程序的編程規範說明:本文中所說的編程規範只是我個人的一些想法和實踐,有些經驗可能並不能適合所有場合,當然也不可避免的有比較偏頗的看法,請大家多多批評指正。
  • PIC單片機C語言程序實例
    編者按:為了幫助具有PIC單片機彙編語言知識的技術人員或工程師,快速掌握利用C語言編寫PIC單片機程序的方法,本刊特推出《PIC單片機C語言程序設計》系列連載文章。丈中給出的C語言程序實例,均是可執行的,讀者可以放心引用。      一、彙編語言與C語言      早期的單片機程序多採用彙編語言編寫。
  • 8個遙控設計實例推薦,包含原始碼、電路圖
    在這個DIY精神遍布的時代,自己能做點什麼已經不足為其,特別是遙控類的小製作也舉不勝舉,本人也是DIY愛好者,業餘時間也經常做些帶遙控的小製作,所以也收集了不少實例。
  • 單片機C語言編程實現對舵機控制
    單片機通過控制舵機實現小車的轉向。本文主要介紹如何使用51單片機實現對舵機進行偏轉角度控制。所使用舵機型號為MG996R,使用晶片為STC89C52。周期20ms主要藉助51單片機定時器1設置在0.5ms產生中斷,在中斷處理函數中設置高低電平。同時通過變量記錄中斷執行次數,當次數達到40時即為一個周期20ms。本例測試使用51單片機開發板,按鍵K2與K3控制舵機角度增加與減少,其中K2對應P3.4引腳,K3對應P3.5引腳。
  • 波形發生器設計,單片機、CPLD控制的任意波形發生器設計實例
    電路設計中充分利用MATLAB的仿真功能,將希望得到的波形信號在MATLAB中完成信號的產生、抽樣和模數轉換,並將得到的數字波形數據存放在數據存儲器中,通過單片機和CPLD控制,將波形數據讀出,送入後向通道進行A/D轉換和放大處理後得到所需的模擬信號波形。利用上述方法設計的任意波形發生器,信號產生靈活方便、功能擴展靈活、信號參數可調,實現了硬體電路的軟體化設計。
  • MCS-51單片機控制跑馬燈的三種方法
    在MCS一51單片機的控制系統中,它的四個並行8位輸入輸出埠P0一P3是我們經常使用的。在並行埠的編程學習中,「跑馬燈」是單片機並行埠輸出控制的典型實例。所謂跑馬燈,是指將八個發光二極體分別連接到單片機的某一併行埠的八根線上,通過編程控制這八個發光二極體從低到高或從高到低依次點亮。
  • 從一個詳細的實例來知道單片機編程,你照著做就行了
    工作,就需要編寫程序,再將程序寫入單片機,單片機在程序的控制下工作以完成指定的任務。沒有程序的控制,單片機就無法工作。那麼如何編寫單片機程序呢?1.從一個實例初步了解編程將上面的彙編語言程序彙編成機器語言程序並寫入單片機後,在程序的控制下,單片機內部電路不斷將P3埠8個寄存器中的數據送給P1埠的8個寄存器。圖示的單片機應用電路的工作過程分析如下。在沒有按下任何按鍵時,P3埠8個寄存器的數據都為「1」,所以P1埠8個寄存器的數據也為「1」,P1.0~P1.7這8個引腳都為高電平,發光二極體VD1~VD4全部不亮。
  • 海信智能電視,超強音響效果,聲控體感都在線?
    超強音響效果 聲控體感都在線至於它的音響效果,更是讓我嘆服!歌聲傳出來的時候,我還以為自己在歌劇院裡,這種立體環繞的重低音聲控讓我仿佛置身在音樂會中。既然談到了聲音,我就趕緊試試它的聲控效果。於是我躺在沙發上開始了自言自語,我發現它捕捉聲控非常智能而且精準。
  • 基於proteus的51單片機開發實例24-矩陣鍵盤(行列式鍵盤)
    基於proteus的51單片機開發實例24-矩陣鍵盤1.1.目的是通過較少的I/O口來識別多個按鍵。1.2. 設計思路我們在前面已經學習過獨立按鍵,在獨立按鍵電路中,一個按鍵連接單片機的一位I/O埠。這樣通過檢測I/O的狀態就能很方便的識別該按鍵是否按下。這種電路的優點是:電路簡單,程序簡單,缺點是一個按鍵就要佔用一個I/O口。
  • 「工具書+配套視頻」深入淺出STM8單片機入門進階與應用實例
    【經典工具書+配套視頻】深入淺出STM8單片機入門、進階與應用實例(825頁資料書+9.6G深入淺出STM8單片機入門、進階與應用實例(825頁經典工具書 )
  • 基於proteus的51單片機開發實例30-模塊化程序設計
    基於proteus的51單片機開發實例30-模塊化程序設計1.1.實驗目的模塊化程序設計不知不覺我們的51單片機開發實例已經進行到第三十篇了設計思路本實例的設計思路是:將《基於proteus的51單片機開發實例29-單總線DS18B20的讀寫》中的程序代碼按照延時功能、LCD1602液晶顯示功能、DS18B20的讀寫控制功能這三個部分,使用模塊化程序設計的方法,將這三個部分分別封裝為三個.c和.h文件