6.1.2 開發所需的軟件包 1、java JDK 6.0最好下載新版。它可從Sun公司的官網下載。
2、Android SDK 這是Android開發必需的。
3、Eclipse 3.5最好使用這個版。它可從Eclipse官網下載。
4、Eclipse所需的插件ADT-0.9.7它可從google網站上下載。
6.1.3 搭建Android開發環境準備好開以上軟件包之后,我們便可以搭建Android的開發環境了。
第一步:安裝java JDK 6.0。
第二步:把下載好的Eclipse 3.5解壓。
第三步:Android SDK 安裝。
Android SDK可以通過SDK下載器自動下載和配置,適合網絡好,下載速度快的情況下;也可以借助工具下載SDK文件,手工配置,適合網絡不是很好,下載速度慢的情況下。
第四步、Eclipse集成開發環境(IDE)搭建
1、打開Eclipse,選擇菜單:Help->Install New Software...
2、彈出“Available Software”對話框,點擊“Add...”按鈕
3、彈出“Add Repository”對話框。中Name中輸入ADT,然后點擊Archive把路徑設置到下載的ADT-0.9.7文件的位置,然后安裝。
4、安裝成功后,安裝提示重啟Eclipse,即完成整個安裝過程。
第五步:Android SDK 配置,即配制Android 虛擬設備,亦即嵌入式開發中常用的模擬器。
6.1.4 測試所配的開發環境- 新建項目:打開Eclipse,選擇File > New > Project > Android Project,便會打開新建項目界面,如圖6.1所示。
在Project name中輸入工程的名字,build target中選擇所用的平臺,Application name為應用程序的名稱,create activity為活動類的名稱。
圖6.1 新建項目
2、配制運行方式:點擊Run Configurations會出現配制運行方式界面,如圖6.2所示。然后點擊Android application新建一個動行方式,在右邊project中輸入要運行的工程名稱。至此運行方式配制完成。
圖6.2 配制運行方式
3、運擊會行,便會出下如下界面,如圖6.3:
圖6.3 運行界面
至此,Android的開發環境已搭建成功。
6.2 Android藍牙通信設計藍牙是一種支持設備短距離通信(一般10m內)的無線電技術。能在包括移動電話、PDA、無線耳機、筆記本電腦、相關外設等眾多設備之間進行無線信息交換。利用“藍牙”技術,能夠有效地簡化移動通信終端設備之間的通信,從而數據傳輸變得更加迅速高效,為無線通信拓寬道路。
本設計分為信號采集模塊和Android顯示終端,兩部分采用藍牙技術進行無線通信。Android顯示終端實現波形的顯示和示波器參數的設置。
6.2.1 Android設備中藍牙模塊的使用[html]view plaincopyprint
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
//直接打開系統的藍牙設置面板
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, 0x1);
//直接打開藍牙
adapter.enable();
//打開本機的藍牙發現功能(默認打開120秒,可以將時間最多延長至300秒)
Intent discoveryIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);//設置持續時間(最多300秒)
使用BluetoothAdapter的startDiscovery()方法來搜索藍牙設備。
startDiscovery()方法是一個異步方法,調用后會立即返回。該方法會進行對其他藍牙設備的搜索,該過程會持續12秒。該方法調用后,搜索過程實際上是在一個System Service中進行的,所以可以調用cancelDiscovery()方法來停止搜索(該方法可以在未執行discovery請求時調用)。請求Discovery后,系統開始搜索藍牙設備,在這個過程中,系統會發送以下三個廣播:
ACTION_DISCOVERY_START:開始搜索
ACTION_DISCOVERY_FINISHED:搜索結束
ACTION_FOUND:找到設備
這個Intent中包含兩個extra fields:EXTRA_DEVICE和EXTRA_CLASS,分別包含BluetooDevice和BluetoothClass。我們可以自己注冊相應的BroadcastReceiver來接收響應的廣播,以便實現某些功能。
功能代碼如下:
// 創建一個接收ACTION_FOUND廣播的BroadcastReceiver
private final BroadcastReceivermReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// 發現設備
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// 從Intent中獲取設備對象
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 將設備名稱和地址放入array adapter,以便在ListView中顯示
mArrayAdapter.add(device.getName() + "" + device.getAddress());
}
}
};
// 注冊BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // 不要忘了之后解除綁定
6.2.2 藍牙數據通信如果打算建議兩個藍牙設備之間的連接,則必須實現服務器端與客戶端的機制。當兩個設備在同一個RFCOMM channel下分別擁有一個連接的BluetoothSocket,這兩個設備才可以說是建立了連接。服務器設備與客戶端設備獲取BluetoothSocket的途徑是不同的。服務器設備是通過accepted一個incoming connection來獲取的,而客戶端設備則是通過打開一個到服務器的RFCOMM channel來獲取的。
通過調用BluetoothAdapter的listenUsingRfcommWithServiceRecord(String, UUID)方法來獲取BluetoothServerSocket,并調用BluetoothServerSocket的accept()方法監聽連接請求,如果收到請求,則返回一個BluetoothSocket實例(此方法為block方法,應置于新線程中)。如果不想在accept其他的連接,則調用BluetoothServerSocket的close()方法釋放資源。
通過搜索可以得到服務器端的BluetoothService,并通過調用BluetoothService的listen
UsingRfcommWithServiceRecord(String, UUID)方法獲取BluetoothSocket(該UUID應該同于服務器端的UUID)。調用BluetoothSocket的connect()方法,如果UUID同服務器端的UUID匹配,并且連接被服務器端accept,則connect()方法返回。
3、數據通信
可以分別通過BluetoothSocket的getInputStream()和getOutputStream()兩種方法獲取InputStream和OutputStream,并使用read(bytes[])和write(bytes[])方法分別進行讀寫操作。其中,read(bytes[])方法會一直block,直到從數據流中讀取到信息;而write(bytes[])方法并不是經常的block,比如在另一設備沒有及時read或者中間緩沖區已滿的情況下,write方法會block。
6.3 Android上繪制波形利用SurfaceView類來實現波形的繪制。SurfaceView是視圖(View)的繼承類,這個視圖里內嵌了一個專門用于繪制的Surface控件。可以通過SurfaceHolder接口訪問這個surface,getHolder()方法可以得到這個接口。surfaceview的核心在于提供了兩個線程:UI線程和渲染線程。SurfaceView的性質決定了其比較適合一些場景:需要界面迅速更新、對幀率要求較高的情況。
6.3.1 SurfaceView的使用只要繼承SurfaceView類并實現SurfaceHolder.Callback接口就可以實現一個自定義的SurfaceView。SurfaceHolder.Callback在底層的Surface狀態發生變化的時候通知View,SurfaceHolder.Callback具有如下的接口:
1、surfaceCreated(SurfaceHolder holder):當Surface第一次創建后會立即調用該函數。程序可以在該函數中做些和繪制界面相關的初始化工作,一般情況下都是在另外的線程來繪制界面,所以不要在這個函數中繪制Surface。
2、surfaceChanged(SurfaceHolder holder,int format,int width,int height):當Surface的狀態(大小和格式)發生變化的時候會調用該函數,在surfaceCreated調用后該函數至少會被調用一次。
3、surfaceDestroyed(SurfaceHolder holder):當Surface被摧毀前會調用該函數,該函數被調用后不能繼續使用Surface,一般在該函數中清理使用的資源。通過SurfaceView的getHolder()函數可以獲取SurfaceHolder對象,Surface就在SurfaceHolder對象內。雖然Surface保存了當前窗口的像素數據,但是在使用過程中是不直接和Surface打交道的,由SurfaceHolder的CanvaslockCanvas( )或Canvas的lockCanvas(Rect dirty)函數來獲取Canvas對象,通過在Canvas上繪制內容來修改Surface中的數據。當在Canvas中繪制完成后,調用函數unlockCanvasAndPost(Canvas canvas)來通知系統Surface已經繪制完成,這樣系統會把繪制完的內容顯示出來。為了充分利用不同平臺的資源,發揮平臺的最優效果,可以通過SurfaceHolder的setType函數來設置繪制的類型,可接收如下的參數:
SURFACE_TYPE_NORMAL:用RAM緩存原生數據的普通Surface。
SURFACE_TYPE_HARDWARE:適用于DMA(Direct memory access )引擎和硬件加速的Surface。
SURFACE_TYPE_GPU:適用于GPU加速的Surface。
SURFACE_TYPE_PUSH_BUFFERS:表明該Surface不包含原生數據,Surface用到的數據由其他對象提供,在Camera圖像預覽中就使用該類型的Surface,有Camera負責提供給預覽Surface數據,這樣圖像預覽會比較流暢。如果設置這種類型則就不能調用lockCanvas來獲取Canvas對象了。
6.3.2 繪制波形子程序該子程序的功能是,先繪制8*8的顯示網格,然后把接收到的波形數據在SurfaceView中顯示出來。功能程序如下:
void DrawWave(int length) {
Canvas canvas = sfh.lockCanvas(new Rect(0, 0, 480,480));//獲取畫布
Canvas.drawColor(Color.BLACK); //清除畫布
Paint mPaint = new Paint(); //獲取畫筆
mPaint.setColor(Color.GRAY); //設置畫筆為黃色
mPaint.setStrokeWidth(1); //設置畫筆粗細
oldY=0;
//繪制8*8的網格
for (int i = 0; i <= 8; i++) {// 繪畫橫線
canvas.drawLine(0, oldY, 479, oldY, mPaint);
oldY = oldY+60;}
oldX=0;
for (int i = 0; i <= 8; i++) {// 繪畫縱線
canvas.drawLine(oldX, 0, oldX, 479, mPaint);
oldX = oldX+60;}
//繪制波形
mPaint.setColor(Color.YELLOW);// 畫筆設置為綠色
for (int x = 0; x < length; x++) {
y = data_osc[ i];//讀取y軸數值,波形數據保存在數組ata_osc[]中
canvas.drawPoint(x, y, mPaint);//描點
}
sfh.unlockCanvasAndPost(canvas);//解鎖畫布,提交畫好的圖像
}
結 論經過三個月的努力,終于完成了本畢業設計。總結這三個月來的工作,主要有以下幾個方面:
1、綜述了現階段數字存儲示波器技術及產品的國內外發展狀況,對數字存儲示波器的原理、工作方式、顯示方式等的基本概念及技術發展進行了介紹。
2、針對設計的任務和要求,確定了存儲示波器波形采樣和數據處理及波形重組的硬件和軟件方案。
3、對整機各部分關鍵電路進行相關理論分析、計算和設計。
4、本系統由單片機主控,高速A/D轉換器ADS830進行模數轉換,用FIFO緩存芯片IDT7203來實現波形的存儲。通過軟件對轉換后的數字信號進行處理,并通過藍牙把波形數據發送到Android設備上進行顯示。
5、完成了作品的制作與調試;論述了儀器的測試方法,完成數據測試及測試結果分析。
采用Android設備作為顯示平臺,是本設計最大的一個特點。本設計的基本思路是,由單片機對ADC采樣到的數據進行處理,再通過藍牙把波形數據發送到Android設備上進行顯示。同時由于Android設備都采用觸摸屏,因此示波器的參數可以很方便的通過觸摸屏進行設置。本設計采用Android設備取代液晶屏,并使用藍牙進行數據傳輸,充分利用了Android設備的硬件資源。其優點是降低了系統開發成本,并大大減小了系統硬件體積,完全實現了本設計小巧便攜的設計宗旨。
本系統的數據采集系統、數據處理系統和波形顯示系統等模塊都經過了軟硬件的調試。雖然整個系統的實現方案基本完成,但是還有一些不夠理想的地方,仍然有不少的工作需要繼續。比如需要進一步改善測量精度、模擬帶寬以及系統噪聲等性能;添加等效采樣、波形回調以及數據導出等功能。
參 考 文 獻
[1] 張永瑞. 電子測量技術基礎[M] . 西安:西安電子科技大學出版社,2006:131-133.
[2] 朱明強. 基于單片機及CPLD的數字存儲示波器的研究與設計[D] . 北京:北京交通大學,2008.
[3] 王彥斌. 數字存儲示波器中模擬通道設計[D] . 成都:電子科技大學,2008.
[4] 馮靜亞,于強,呂朝暉,羅福山. 虛擬示波器的軟件設計與應用[J] . 計算機工程與設計,2007,28(1):211-273.
[5] 張虹. 泰克公司推出可分析帶寬達20GHz信號的Signal Vu軟件[J] . 中國無線電,2008,9(7):23-25.
[6] 趙茂泰. 簡易數字存儲示波器評述[J] . 電子世界,2002,5(11):40-42.
[7] 徐俊毅. 力科推出帶寬可達30GHz的WaveMaster8Zi系列示波器[J] . 電子與電腦,2009,5(13):53-56.
[8] 蒙玉寶. 40Gsps隨機取樣數字示波器關鍵技術預先研究[D] . 成都:電子科技大學,2003.
[9] 楊豐盛. Android應用開發揭秘[M] . 北京:機械工業出版社,2009:15-16.
[10] 陳景波,楊放,姚定江. 基于CompuScope 82G型高速數據采集卡的虛擬示波器設計[J] . 國外電子元器件,2006,11(2):60-62.
[11] H.Troy Nagle,D.Carroll,J.David Irwin . DIGITAL LOGIC CIRCUIT ANALYSIS & DESIGN[M] . 北京:清華大學出版,2009:57-71.
[12] V.V.Panasyuk. Electronic oscillograph unit for recording failure diagrams in the impact testing of metals[J] . Soviet Materials Science,2001,9(5):10-12.
[13] 劉楊斌,劉其峰,華慧. 基于AT89S52單片機的簡易數字示波器設計[J] . 現代電子技術,2011,14(14):17-18.
[14] 賈春霞,張洪艷. 數字存儲示波器現狀初探[J] . 儀器儀表用戶,2004,8(15):25-26.
[15] 張根柱,陳勇鋼. 數字存儲示波器[J] . 現代技術開發,1999,5(12):49-50.
[16] J. Molenaar,R. Voorhorst. Study on Remote Control Techniques to the Digital Storage Oscilloscope[J] . Energy Procedia,2012,16(9):34-35.
[17] 劉巖. 數字示波器的設計[J] . 電腦知識與技術,2008,12(20):21-22.
[18] R. P. Patterson. Design and Implementation of Multifunctional Virtual Oscilloscope Using USB Data-Acquisition Card[J] . Procedia Engineering,2012,10(25):40-42.
[19] W. A. Grind. Patent Application Titled "Oscilloscope with Internally Generated Mixed Signal Oscilloscope Demo Mode Stimulus, and Integrated Demonstration" Under Review[J] . Journal of Engineering,2012,9(17):7-8.
致 謝在這里要衷心感謝我的指導老師蘇成悅教授的悉心指導和多方關懷。蘇老師思維敏銳,視野開闊,創新性強。他淵博的學識,嚴謹的治學作風,執著的敬業精神都深深地影響著我。我深深感受到他對研究的精益求精,對學生的鼓勵和愛護。他對工作和生活的態度將是我一生學習的榜樣。
此外,還需要感謝我身邊的同學們。在設計過程中碰到的問題,我都會找同學一起來討論解決。同學們都很熱情、很積極的參與到討論中,而且大部分問題在討論之后都得到了解決。除了學習之外,在生活上同學們對我的幫助也是非常大的。在此,我衷心感謝各位親愛的同學們。
附錄 A 實物圖
圖A1 信號采集模塊
圖A2 系統測試圖
附錄 B 系統主程序設計源碼
#include "STM32Lib\stm32f10x.h"
#include "hal.h"
extern void SetLevel(u8 pulse);
extern void Adc1_Init(u8 ADC_CH_x,u8 ADC_CH_SMP);
extern u16 Get_Adc(u8 ADC_CH_x);
u16 data_test_16;
u8 data_test_8;
u8 Data_osc[320]; //波形數據
u8 Data_osc_full=0;
u8 Data_set[10];
//延遲函數
void Delay(u16 speed)
{
u16 i;
while(speed!=0)
{
speed--;
for(i=0;i<400;i++);
}
}
//設置水平掃描速度
void shuiping(u8 sp)
{
if(sp >= 12)
sp=12;
if(sp <= 1)
sp=1;
//設置不同采樣速率
switch(sp)
{
case 1:TIM1->PSC=0; break;
case 2:TIM1->PSC=1; break;
case 3:TIM1->PSC=3; break;
case 4:TIM1->PSC=9; break;
case 5:TIM1->PSC=19; break;
case 6:TIM1->PSC=39; break;
case 7:TIM1->PSC=99; break;
case 8:TIM1->PSC=199; break;
case 9:TIM1->PSC=399; break;
case 10:TIM1->PSC=999; break;
case 11:TIM1->PSC=1999; break;
case 12:TIM1->PSC=3999; break;
default :break;
}
}
//設置水平靈敏度
void SetAGC(u16 pulse)
{
if(pulse >= 3)
pulse=3;
if(pulse <= 1)
pulse=1;
//設置不同的增益
switch(pulse)
{
case 1: TIM4->CCR1=255;break;
case 2: TIM4->CCR1=195;break;
case 3: TIM4->CCR1=153;break;
}
}
int main(void)
{
u16 i_osc=0;
u16 i_start=0;
ChipHalInit(); //片內硬件初始化
ChipOutHalInit(); //片外硬件初始化
SetLevel(128); //初始化垂直基線
SetAGC(2); //初始化垂直靈敏度
shuiping(6); //初始化水平靈敏度
while(1)
{
if(Data_osc_full==1)
{
Data_osc_full=0;
while(!(Data_osc[i_start]<=160&& Data_osc[i_start+1]>=160))
{
i_start++;
if(i_start>=150)
break;
}
if(i_start < 150)
{
for( i_osc=0; i_osc<160; i_osc++)
{
USART2_Putc(Data_osc[i_osc + i_start]);
}
}
Delay(500); //延時,等待Android系統處理完畢數據
TIM1->CR1 |= 0x0001; //開啟定時器TIM1
}
}
}
附錄 C Android藍牙服務程序設計源碼
package com.test.BTClient;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
public class DeviceListActivity extends Activity {
// 調試用
private static final String TAG = "DeviceListActivity";
private static final boolean D = true;
// 返回時數據標簽
public static String EXTRA_DEVICE_ADDRESS = "設備地址";
// 成員域
private BluetoothAdapter mBtAdapter;
private ArrayAdapter mPairedDevicesArrayAdapter;
private ArrayAdapter mNewDevicesArrayAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 創建并顯示窗口,并設置窗口顯示模式為窗口方式
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.device_list);
// 設定默認返回值為取消
setResult(Activity.RESULT_CANCELED);
// 設定掃描按鍵響應
Button scanButton = (Button) findViewById(R.id.button_scan);
scanButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
doDiscovery();
v.setVisibility(View.GONE);
}
});
// 初使化設備存儲數組
mPairedDevicesArrayAdapter = new ArrayAdapter(this,
R.layout.device_name);
mNewDevicesArrayAdapter = new ArrayAdapter(this,
R.layout.device_name);
// 設置已配隊設備列表
ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
pairedListView.setAdapter(mPairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener(mDeviceClickListener);
// 設置新查找設備列表
ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
newDevicesListView.setOnItemClickListener(mDeviceClickListener);
// 注冊接收查找到設備action接收器
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
// 注冊查找結束action接收器
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
// 得到本地藍牙句柄
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
}
@Override
protected void onDestroy() {
super.onDestroy();
// 關閉服務查找
if (mBtAdapter != null) {
mBtAdapter.cancelDiscovery();
}
// 注銷action接收器
this.unregisterReceiver(mReceiver);
}
public void OnCancel(View v){
finish();
}
//開始服務和設備查找
private void doDiscovery() {
if (D) Log.d(TAG, "doDiscovery()");
// 在窗口顯示查找中信息
setProgressBarIndeterminateVisibility(true);
setTitle("查找設備中...");
// 顯示其它設備(未配對設備)列表
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
// 關閉再進行的服務查找
if (mBtAdapter.isDiscovering()) {
mBtAdapter.cancelDiscovery();
}
//并重新開始
mBtAdapter.startDiscovery();
}
// 選擇設備響應函數
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
public void onItemClick(AdapterView av, View v, int arg2, long arg3) {
// 準備連接設備,關閉服務查找
mBtAdapter.cancelDiscovery();
// 得到mac地址
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
// 設置返回數據
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
// 設置返回值并結束程序
setResult(Activity.RESULT_OK, intent);
finish();
}
};
// 查找到設備和搜索完成action監聽器
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// 查找到設備action
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// 得到藍牙設備
BluetoothDevice device =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 如果是已配對的則略過,其余的在添加到列表中進行顯示
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mNewDevicesArrayAdapter.add(device.getName() + "" +
device.getAddress());
}else{ //添加到已配對設備列表
mPairedDevicesArrayAdapter.add(device.getName() + "" +
device.getAddress());
}
// 搜索完成action
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
setProgressBarIndeterminateVisibility(false);
setTitle("選擇要連接的設備");
if (mNewDevicesArrayAdapter.getCount() == 0) {
String noDevices = "沒有找到新設備";
mNewDevicesArrayAdapter.add(noDevices);
}
}
}
};
}