目 录
1 绪论 1
1.1 示波器概述 1
1.2 数字示波器的特点及原理 1
1.3 数字示波器国内外研究状况 2
1.4 Android概述 3
1.5 题目研究背景及意义 4
2 数字示波器原理分析与技术指标 5
2.1 数字示波器的组成原理 5
2.2 数字示波器与模拟示波器相比较 5
2.3 数字示波器技术指标 7
2.3.1 最大采样速率 7
2.3.2 存储宽度 7
2.3.3 分辨率 8
2.3.4 记录长度 8
2.3.5 存储带宽 9
2.3.6 垂直灵敏度及误差 9
2.3.7 扫描速度及误差 10
2.4 采样原理分析 10
2.4.1 实时采样方式的原理 10
2.4.2 等效取样方式的原理 12
3 系统方案论证 13
3.1 系统总体方案设计 13
3.2 数据采集系统 14
3.2.1 波形整形电路方案选择 14
3.2.2 程控放大电路方案选择 15
3.3 数据处理系统 15
3.3.1 触发方案选择 15
3.3.2 峰值测量方案选择 16
3.3.3 测量频率方案选择 16
3.3.4 采样方案选择 17
4 系统硬件电路设计 19
4.1 微控制器电路 19
4.2 电源电路设计 19
4.3 信号采集电路设计 20
4.3.1 A/D转换及FIFO缓存器 20
4.3.2 程控放大电路 21
4.3.3 电平移位电路设计 22
4.3.4 频率测量电路 23
4.4 无线数据传输 24
5 系统软件设计 26
5.1 单片机软件开发环境 26
5.2 主程序设计及流程图 26
5.3 数据处理子程序 27
5.3.1 同步触发的软件实现 27
5.3.2 频率计算原理及流程图 28
5.3.3 测量信号峰峰值 29
6 Android显示平台 31
6.1 Android应用开发环境 31
6.1.1 Android简介 31
6.1.2 开发所需的软件包 31
6.1.3 搭建Android开发环境 31
6.1.4 测试所配的开发环境 32
6.2 Android蓝牙通信设计 33
6.2.1 Android设备中蓝牙模块的使用 34
6.2.2 蓝牙数据通信 35
6.3 Android上绘制波形 36
6.3.1 SurfaceView的使用 36
6.3.2 绘制波形子程序 37
结论 39
参考文献 40
致谢 42
附录 A 实物图 43
附录 B 系统主程序设计源码 44
附录 C Android蓝牙服务程序设计源码 48
3 系统方案论证
3.1 系统总体方案设计
数字示波器很大的一个特点,就是能对采集到的波形数据进行处理,通过特定的算法即可测量出信号的频率、幅值和相位等电气参数。并且示波器能将运算处理后的数据直接显示在LCD液晶屏上,通过调整合适的扫描速度就能方便的观察到信号的细节。由于示波器需要处理的数据量比较大,且对于高频信号需要很高的采样率和刷新速度,因此一般的微处理器难于满足[19]。目前高性能的数字示波器都采用FPGA来控制数据的采集和处理数据。由于FPGA的灵活性极高,采用FPGA的系统能高效的处理数据及显示波形。但是由于FPGA的成本较高,并不适用于低端便携式产品上。
本文的设计理念是便携式、低成本,因此需要寻找一款性能高、价格低的微处理器。考虑到成本和实际应用,本文选择了意法半导体公司的STM32微处理器作为主控制器。STM32系列是基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex-M3内核,能完全满足本设计对成本和性能的要求。
本文的另外一个亮点就是使用了Android作为波形显示平台。在这个基本上是人手一部Android手机的时代,怎样充分挖掘Android软硬件的使用价值就显得尤为重要。本设计用到Android的屏幕来显示波形,而且还使用了触摸屏来对示波器进行控制,这样将大大缩小硬件的体积和降低系统成本。同时示波器硬件电路和Android之间通过蓝牙实现无线数据传输,这使得系统的应用将是非常的方便。
数字示波器的结构框图如图3.1所示。
本论文设计的数字示波器的工作方式是,被测信号经STM32控制的采样电路进行采样并对数据进行处理,然后通过蓝牙把处理过后的波形数据发送到Android端,最后通过Android端的应用程序把波形显示出来。在Android端的应用程序上可以操作示波器的所有功能,比如调节垂直灵敏度、水平扫描速度、触发电平、垂直基线等。同时本设计非常小巧,且使用锂电池进行供电,非常方便携带。本设计的理念是,只要你拥有一台Android手机或者平板电脑,你就可以拥有一个低成本的、便于携带的数字示波器。

图3.1 结构框图
模拟信号处理是示波器的重要组成部分,也是信号采集系统中的一个核心部分。图3.1清晰的介绍了数字示波器的结构框图,从图中可以看出,模拟通道的输入信号被分成两路,一路送至程控放大器,用来实现垂直灵敏度的调节;另一路送至触发电路,用于测量被测信号的频率。其中程控放大器是示波器模拟部分设计的关键,也是示波器带宽最重要的限制因素。
3.2 数据采集系统
3.2.1 波形整形电路方案选择
波形整形电路的选择主要是选择合适的比较器芯片,为了防止波形在过零点出现抖动,比较电路最好是接成滞回比较结构,以免影响比较器的输出波形。
方案一:采用Maxim公司的高速比较芯片Max912构成滞回比较器。Max912的最高转换速度可达ns级别,对频率很高的信号都能进行有效的整形。但缺点是Max912的成本太高。
方案二:采用比较器LM311构成滞回比较器。在对5M以下的信号进行整形时,能收到比较好的效果。最主要的还是其价格相对比较低,能满足本设计对成本的控制。但当信号频率高于5M时,本文转载自http://www.biyezuopin.vip/onews.asp?id=14838由于收到LM311转换速度的限制,其整形效果比较差。
基于本设计对测试范围的要求以及成本的控制,本设计选择方案二。
3.2.2 程控放大电路方案选择
由于A/D转换器的输入范围一般都比较小(低于2Vpp),不可能直接测量几十伏甚至是几百伏的信号。而且由于A/D转换器的分辨率有限,对于幅值很低的信号测量误差将会很大甚至是无法测量。所以在输入级必须要设计一个程控放大电路,以现实对信号进行不失真的处理,而后再送至A/D数模转换器,以达到A/D数模转换器的输入要求。通常情况下所说的“示波器的模拟带宽”就是输入级的模拟信号放大电路的带宽。而数字示波器的带宽主要是用采样率来定义,主要受数模转换器的最高采样率以及控制器的处理速度的限制。
方案一:利用高速运放LM6172构成放大电路,并设置多种不同放大倍数的反馈电阻网络,然后通过控制继电器选择不同的反馈电阻,从而实现不同放大倍数的切换。其优点是电路和控制都比较简单,放大倍数稳定。但缺点是继电器的工作电流大,且需要多个继电器配合才能实现多种不同的放大倍数,很明显不符合本设计便携小巧的宗旨。同时继电器在开和关的瞬间都会产生很大的电磁干扰,有可能会影响到系统的正常运行。
方案二:使用模拟开关HCF4051BE代替继电器,来实现不同放大倍数的切换。优点是克服了继电器工作电流大、体积大等缺点,且电路结构简单,成本低廉。但缺点是模拟开关无法实现零阻抗,且其带宽有限,通过高频信号将会产生失真。
方案三:使用专用PGA芯片AD603,可以通过MCU来控制AD603的基准,进而实现不同放大倍数的调节。该电路优点是控制比较简单,且增益调节范围大,外围电路简单。缺点是成本稍微偏高。
基于本设计便携小巧的宗旨,和电路复杂度的考虑,本设计选择方案三。

package com.test.BTClient;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import com.test.BTClient.R;
import com.test.BTClient.DeviceListActivity;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;public class BTClient extends Activity {private final static int REQUEST_CONNECT_DEVICE = 1;    //宏定义查询设备句柄private final static String MY_UUID = "00001101-0000-1000-8000-00805F9B34FB";   //SPP服务UUID号private InputStream is;    //输入流,用来接收蓝牙数据private TextView Title;    //提示栏解句柄private TextView TextX;private TextView TextY;Button X1,X2,Y1,Y2;//绘图部分定义SurfaceView sfv;SurfaceHolder sfh;//蓝牙接收数据缓存int sdflag=1;//开始先发送初始数据int sent_num=0;int num = 0;int data_num=0;int data_byte;byte[] buffer = new byte[1024];byte[] buffer_new = new byte[1024];int[] data_osc = new int[1024];int flag_draw=0;int Y_axis[],//保存正弦波的Y 轴上的点centerY,//中心线oldX,oldY,//上一个XY 点currentX;//当前绘制到的X 轴上的点int rateX=5;int rateY=5;int baseY=255;public String filename=""; //用来保存存储的文件名BluetoothDevice _device = null;     //蓝牙设备BluetoothSocket _socket = null;      //蓝牙通信socketboolean _discoveryFinished = false;    boolean bRun = true;boolean bThread = false;private OutputStream outStream = null;private BluetoothAdapter _bluetooth = BluetoothAdapter.getDefaultAdapter();    //获取本地蓝牙适配器,即蓝牙设备 @Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);   //设置画面为主画面 main.xml/* 获得TextView对象    标题 “数字示波器” */Title = (TextView) findViewById(R.id.Text0);/* 设置文本的颜色 */Title.setTextColor(Color.RED);/* 设置字体大小 */Title.setTextSize(35);/* 设置文本框大小 *///Title.setWidth(150);/* 设置文字背景 */Title.setBackgroundColor(Color.TRANSPARENT);TextX =   (TextView) findViewById(R.id.TextX);      //得到数据显示句柄/* 设置文本的颜色 */TextX.setTextColor(Color.CYAN);/* 设置字体大小 */TextX.setTextSize(20);/* 设置文本框大小 *///Title.setWidth(150);/* 设置文字背景 */TextX.setBackgroundColor(Color.TRANSPARENT);TextY =   (TextView) findViewById(R.id.TextY);      //得到数据显示句柄/* 设置文本的颜色 */TextY.setTextColor(Color.CYAN);/* 设置字体大小 */TextY.setTextSize(20);/* 设置文本框大小 *///Title.setWidth(150);/* 设置文字背景 */TextY.setBackgroundColor(Color.TRANSPARENT);X1 = (Button) this.findViewById(R.id.X1);//X-/* 设置字体大小 */X1.setTextSize(25);X2 = (Button) this.findViewById(R.id.X2);//X+/* 设置字体大小 */X2.setTextSize(25);Y1 = (Button) this.findViewById(R.id.Y1);//Y-/* 设置字体大小 */Y1.setTextSize(25);Y2 = (Button) this.findViewById(R.id.Y2);//Y+/* 设置字体大小 */Y2.setTextSize(25);sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);sfh = sfv.getHolder();// 初始化y 轴数据centerY = (getWindowManager().getDefaultDisplay().getHeight()-sfv.getTop()) / 2;Y_axis = new int[getWindowManager().getDefaultDisplay().getWidth()];//for (int i = 1; i < 170; i++) {// 计算正弦波//   data_osc[i -1] = 128- (int) (100 * Math.sin(i * 2 * Math.PI / 180));//}//如果打开本地蓝牙设备不成功,提示信息,结束程序if (_bluetooth == null){Toast.makeText(this, "无法打开手机蓝牙,请确认手机是否有蓝牙功能!", Toast.LENGTH_LONG).show();finish();return;}     // 设置设备可以被搜索  new Thread(){public void run(){if(_bluetooth.isEnabled()==false){_bluetooth.enable();}}        }.start();      }//发送设置数据
void SentData(){//数据头sentying(222);sentying(0);sentying(88);sentying(111);//sentying(255-baseY/2);//垂直基线sentying(rateX);//水平灵敏度sentying(rateY);    sentying(88);sentying(250);sentying(55);switch(rateX){case 1: TextX.setText("10uS/div");break;case 2: TextX.setText("20uS/div");break;case 3: TextX.setText("40uS/div");break;case 4: TextX.setText("100uS/div");break;case 5: TextX.setText("200uS/div");break;case 6: TextX.setText("400uS/div");break;case 7: TextX.setText("1mS/div");break;case 8: TextX.setText("2mS/div");break;case 9: TextX.setText("4mS/div");break;case 10: TextX.setText("10mS/div");break;case 11: TextX.setText("20mS/div");break;case 12: TextX.setText("40mS/div");break;default: break;}switch(rateY){case 1: TextY.setText("200mV/div");break;case 2: TextY.setText("500mV/div");break;case 3: TextY.setText("1V/div");break;default: break;}
}/** 绘制指定区域*/void SimpleDraw(int length) {Canvas canvas = sfh.lockCanvas(new Rect(0, 0, 480,511));// 关键:获取画布canvas.drawColor(Color.BLACK);//清除画布int x=0,y=0;//画网格8*8Paint mPaint = new Paint();mPaint.setColor(Color.GRAY);// 网格为黄色mPaint.setStrokeWidth(1);// 设置画笔粗细oldY=0;for (int i = 0; i <= 8; i++) {// 绘画横线canvas.drawLine(0, oldY, 511, oldY, mPaint);oldY = oldY+64;}oldX=0;for (int i = 0; i <= 8; i++) {// 绘画纵线canvas.drawLine(oldX, 0, oldX, 511, mPaint);oldX = oldX+60;}//画Y轴基线mPaint.setColor(Color.RED);mPaint.setStrokeWidth(3);// 设置画笔粗细// 绘画横线canvas.drawLine(0, baseY, 479, baseY, mPaint);if( length != 500){//画波形mPaint.setColor(Color.YELLOW);// 画笔为绿色mPaint.setStrokeWidth(3);// 设置画笔粗细oldX = 0;oldY = (255-data_osc[0])*2;for (int i = 0; i < length; i++) {y = (255 - data_osc[i])*2;//Y轴32点/格x=i*3;//X轴20点/格canvas.drawLine(oldX, oldY, x, y, mPaint);   oldX = x;oldY = y;}}//oldX = 0;sfh.unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像}  /* 触笔事件   触摸屏幕动态设置波形图基线  */public boolean onTouchEvent(MotionEvent event){int iAction = event.getAction();if (iAction == MotionEvent.ACTION_CANCEL || iAction == MotionEvent.ACTION_DOWN || iAction == MotionEvent.ACTION_MOVE) {return false;}//得到触笔点击的位置int y = (int) event.getY();if((y >= sfv.getTop()) && (y <= sfv.getTop() + 511))baseY = y - sfv.getTop();else if(y < sfv.getTop())   baseY = 0;else if(y > sfv.getTop() + 511)baseY = 511;SimpleDraw(500);SentData();//发送设置数据return super.onTouchEvent(event);}//水平灵敏度 - public void onClickedX1(View v){if(rateX > 1)rateX --;elserateX = 1;SentData();//发送设置数据}//水平灵敏度 + public void onClickedX2(View v){if(rateX < 12)rateX ++;elserateX = 12;SentData();//发送设置数据}//垂直灵敏度 - public void onClickedY1(View v){if(rateY > 1)rateY --;elserateY = 1;SentData();//发送设置数据}//垂直灵敏度 + public void onClickedY2(View v){if(rateY < 3)rateY ++;elserateY = 3;     //SimpleDraw(160);//直接绘制正弦波SentData();//发送设置数据}//蓝牙发送一位数据public void sentying(int ying){try { outStream = _socket.getOutputStream();} catch (IOException e1) {}try {          outStream.write(ying);} catch (IOException e1) {}           }       //接收活动结果,响应startActivityForResult()public void onActivityResult(int requestCode, int resultCode, Intent data) {switch(requestCode){case REQUEST_CONNECT_DEVICE:     //连接结果,由DeviceListActivity设置返回// 响应返回结果if (resultCode == Activity.RESULT_OK) {   //连接成功,由DeviceListActivity设置返回// MAC地址,由DeviceListActivity设置返回String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);// 得到蓝牙设备句柄      _device = _bluetooth.getRemoteDevice(address);// 用服务号得到sockettry{_socket = _device.createRfcommSocketToServiceRecord(UUID.fromString(MY_UUID));}catch(IOException e){Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();}//连接socketButton btn = (Button) findViewById(R.id.Button03);try{_socket.connect();Toast.makeText(this, "连接"+_device.getName()+"成功!", Toast.LENGTH_SHORT).show();btn.setText("断开");}catch(IOException e){try{Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();_socket.close();_socket = null;}catch(IOException ee){Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();}return;}//打开接收线程try{is = _socket.getInputStream();   //得到蓝牙数据输入流}catch(IOException e){Toast.makeText(this, "接收数据失败!", Toast.LENGTH_SHORT).show();return;}if(bThread==false){ReadThread.start();bThread=true;}else{bRun = true;}}break;default:break;}}//接收数据线程Thread ReadThread=new Thread(){public void run(){int i;//bRun = true;//接收线程while(true){try{  while(true){num = is.read(buffer);         //读入数据for(i=0;i<num;i++){if(buffer[i] < 0)data_osc[data_num+i]=buffer[i] + 255;elsedata_osc[data_num+i]=buffer[i];}data_num = data_num + num;if(data_num>=159){data_num=0;//SimpleDraw(160);//直接绘制正弦波//发送显示消息,进行显示刷新//handler.sendMessage(handler.obtainMessage()); }      if(is.available()==0)break;  //短时间没有数据才跳出进行显示}}catch(IOException e){}}}};//消息处理队列Handler handler= new Handler(){public void handleMessage(Message msg){super.handleMessage(msg);//SentData();//发送设置数据}};//关闭程序掉用处理部分public void onDestroy(){super.onDestroy();if(_socket!=null)  //关闭连接sockettry{_socket.close();}catch(IOException e){}//  _bluetooth.disable();  //关闭蓝牙服务}//连接按键响应函数public void onConnectButtonClicked(View v){ if(_bluetooth.isEnabled()==false){  //如果蓝牙服务不可用则提示Toast.makeText(this, " 打开蓝牙中...", Toast.LENGTH_LONG).show();return;}//如未连接设备则打开DeviceListActivity进行设备搜索Button btn = (Button) findViewById(R.id.Button03);if(_socket==null){Intent serverIntent = new Intent(this, DeviceListActivity.class); //跳转程序设置startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);  //设置返回宏定义}else{//关闭连接sockettry{is.close();_socket.close();_socket = null;bRun = false;btn.setText("连接");}catch(IOException e){}   }return;}//退出按键响应函数public void onQuitButtonClicked(View v){finish();}}














基于STM32单片机和Android的便携式数字示波器设计相关推荐

  1. stm32 带通滤波器_带通滤波 - 基于STM32芯片和TFT-LCD的便携式心电图仪设计

    相关推荐 3月10日,纽约州州长安德鲁-库默(Andrew Cuomo)曾在上月宣布,纽约大都市圈的公共交通系... 发表于 2018-04-16 08:50 • 88次阅读 LCD驱动我们只需要写硬 ...

  2. 基于STM32单片机温湿度一氧化碳(CO)浓度仿真设计

    毕设帮助.开题指导.技术解答(有偿)见文末. 目录 一.功能 二.电脑开发环境 三.Protues仿真 四.程序 五.原理图 六.资料包括 一.功能 1.STM32单片机可以通过传感器获取环境中的温湿 ...

  3. 基于stm32单片机的Grayhill编码器/开关软件设计

    1.初识编码器,像示波器的旋转按钮,可左旋右旋,还可以按下,我们使用的是Grayhill编码器,如下图所示: 从图中可以看出,该编码器一共有6个IO,从1-6分别为GND,GND,C,B,A,VCC, ...

  4. 基于STM32单片机的水质监测系统(Proteus仿真+程序)

    编号:14 基于STM32单片机的水质监测系统 功能描述: 14.基于STM32单片机的水质监测系统 本设计由STM32F103单片机最小系统+AMPIRE12864液晶显示模块+两路A/D转换模块组 ...

  5. 基于STM32单片机的智能家居测量系统设计

    当今的家庭生活面临着各种环境和健康问题,周围的生活参数存在潜在的隐患,包括室温.气体中有害物质的浓度等.在新时代,人们越来越关注健康及其相关因素.随着微电子技术的应用,电器的普及,以及单片机和传感器性 ...

  6. 基于STM32单片机的电子钟(Proteus仿真+程序)

    编号:12 基于STM32单片机的电子钟 功能描述: 本设计由STM32单片机+液晶1602+按键+RTC时钟组成. 1.采用STM32F103最小系统板. 2.利用STM32内部自带RTC时钟提供时 ...

  7. 最简单DIY基于STM32单片机的蓝牙智能小车设计方案

    STM32库函数开发系列文章目录 第一篇:STM32F103ZET6单片机双串口互发程序设计与实现 第二篇:最简单DIY基于STM32单片机的蓝牙智能小车设计方案 文章目录 STM32库函数开发系列文 ...

  8. B40 - 基于STM32单片机的电热蚊香蓝牙控制系统

    任务 本项目进行智能电热蚊香器系统的设计与开发,将STM32开发板作为一个微控制器,结合蓝牙技术,通过手机APP软件对电热蚊香器进行灵活的控制,使电热蚊香器的功能更加人性化,更加符合当代人们对家用电器 ...

  9. 基于STM32单片机的智能书桌设计与实现

    研究结果表明,学生的读写姿势不正确率高达70%甚至85%以上[1].不良的读写姿势.不合适的光照条件会令学生不停地调整眼睛的睫状肌,容易降低睫状肌调节能力,进而导致近视[2].从长远看,不良的读写姿势 ...

最新文章

  1. 多项式模2运算及求逆元
  2. Linux中pthread源码在哪,pthread - 源码下载|系统编程|Linux/Unix编程|源代码 - 源码中国...
  3. 大数据WEB阶段Mybatis(一)
  4. 一种基于邻域的聚类算法
  5. vue.js 使用axios实现下载功能
  6. echarts line
  7. centos mysql php tomcat_CentOS 6.x使用yum快速安装Apache+PHP+Tomcat(JSP)+MySQL
  8. 属于自己的MES(二)必备的主数据
  9. 24.事务控制和锁定语句
  10. HTTP Header 详解 Requests 与 Responses 头信息
  11. C语言中使输入的字符串反序输出,C语言: 写一函数,使输入的一个字符串按反序存放,在主函数中输入和输出字符串。...
  12. vue中的浏览量_vue项目中使用百度统计
  13. 转:: 刺鸟:用python来开发webgame服务端(1)
  14. 机械臂速成小指南(二):机械臂的应用
  15. java 定义16进制_java数据类型(大小等),变量定义,各进制书写方法
  16. C语言错误类型中英文对照表
  17. linux驱动-设备驱动模型
  18. 职场001 什么时候跳槽
  19. 计算机的防呆接口,电脑上有哪些“防呆设计”
  20. K8s——kubernetes集群中ceph集群使用【下】

热门文章

  1. Java核心类库之(网络编程:网络编程入门、UDP通信程序、TCP通信程序)
  2. RAMDISK 内存盘工具推荐
  3. 当”众云购”遇上众测平台(ALLtesting),友谊的小船从此不翻
  4. 业务架构的定义、特性和方法
  5. Visual Studio(VS) 编程推荐字体和主题设置
  6. 【论文简述】Multiview Stereo with Cascaded Epipolar RAFT(ECCV 2022)
  7. taskkill /im test.exe /f
  8. uni-app学习笔记(完)
  9. VisionPro学习笔记:用IEEE1394相机抓取图像
  10. postman和JMeter并发测试对比