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);
}
}
}
};
}