android 蓝牙 单片机 显示波形
更新时间:2023-08-20 12:02:01 阅读量: 高等教育 文档下载
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
(希望可以上传成功)
写在前面:
最近一个月,自己尝试了开发一款手机应用,通过单片机的串口
连接蓝牙模块发送数据,然后在手机端通过手机蓝牙收取数据,
并将数据显示出来,其实这就是一个串口通信要做的事情,但是
我要做的除此之外,还要将数据通过图像画出来。即是要求单片
机通过AD采集模拟信号把转换出来的数字量通过蓝牙发送,在
手机端将采集到的波形画出来。此文主要涉及蓝牙操作,画图,
等。也给爱好单片机的一份参考。关于单片机连接的蓝牙是一个
淘宝上买的模块,推荐个网址:
我是在这里买的,其中店家会给资料说明。
By ways (没有抄袭任何人的原作,只是查找资料,看别人程序,
自己开发,很大一部分来自androidsdk/doc/index.xml,因为自己
深感网上资料冗杂,在此整理,借助百度文库的话,让每个人能
有平等提升自己的机会,希望像我的android启蒙老师mars一样
提供给大家免费的资料,讨厌那些需要积分的网站,比如程序员
联合开发网,比如CSDN,因为没有积分,好几个看上的资源都
不能下载。个人微博:/u/2698171342)
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
程序目前问题:我承认自己现阶段的程序存在bug,但已经基本
完成,关于最后的退出处理,会抛出异常,这个我还没解决,不
过貌似应该是没有结束线程出现的问题;还有关于程序我几乎全
部使用全局变量,因为比较简单,便于操作,所以,呵呵,但是
我知道这样肯定不好;另外我本想用几个不同的activity和
service但是在其中的通信中用到广播,消息队列等,但我一直没
有收到数据,所以最后不得已全部在一个activity中实现,这个
表示初学也有很大困难,本例为我后者程序,也就是版本二吧。
我会改善这些问题,因为我希望自己可以追求完美。
先展示结果:
图一是最后的图,图二只是演示可以画出正弦波,其中按钮开启
蓝牙是直接默认连接一个设备,按钮sin是开始接受蓝牙数据并
画图,图示中由于没有开蓝牙,故一直接收数据一直为0 所以
是画出的一条直线,关于清除,是因为在画布下方还有一个
TextView空间使用来显示接受到的数据的。
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
图一 图二
关于程序:
其中的注释我已经写的很清楚
在manifest中,添加蓝牙权限:
</application>
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN" />
</manifest>
在main.xml:
<?xml version="1.0" encoding="utf-8"?>
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
xmlns:android="/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"> <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"
android:text="@string/button" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/sin"
android:text="@string/sin" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/clear"
android:text="@string/clear" />
</LinearLayout>
<SurfaceView
android:id="@+id/show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/myview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/myview" />
/>
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
在strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, OscilloscopeActivity!</string>
<string name="app_name">Oscilloscope</string>
<string name="button">开启蓝牙</string>
<string name="myview">参数显示:</string>
<string name="sin">sin</string>
<string name="buttonstart">搜索</string>
<string name="buttonselect">选择设备</string>
<string name="buttonsend">发送</string>
<string name="input">please input</string>
<string name="clear">清除</string>
</resources>
在Oscilloscope.java
package com.ways;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Set;
import java.util.Timer;
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
import java.util.TimerTask;
import java.util.UUID;
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.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
import android.widget.Button;
import android.widget.TextView;
public class Oscilloscope extends Activity {
/** Called when the activity is first created. */
final int HEIGHT=320; //设置画图范围高度
final int WIDTH=450; //画图范围宽度
final int X_OFFSET = 5; //x轴(原点)起始位置偏移画图范围一点
private int cx = X_OFFSET; //实时x的坐标
int centerY = HEIGHT /2; //y轴的位置
TextView myview = null; //画布下方显示获取数据的地方
final UUID uuid =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
//uuid 此为单片机蓝牙模块用
//还有其他的uuid,这个可以再百度查到,暂不清楚其中的差别
final BluetoothAdapter mBluetoothAdapter =
BluetoothAdapter.getDefaultAdapter();
//获取本手机的蓝牙适配器
static int REQUEST_ENABLE_BT = 1; // 一个常量而已,开启蓝牙时使用
BluetoothSocket socket = null; //用于数据传输的socket
int READ = 1; //一个常量,用于传输数据消息队列的
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
识别字
public ConnectedThread thread = null; //连接蓝牙设备线程
static int temp = 0; //临时变量用于保存接收到的数据
private SurfaceHolder holder = null; //画图使用,可以控制一个
SurfaceView
private Paint paint = null; //画笔
SurfaceView surface = null; //
Timer timer = new Timer(); //一个时间控制的对象,用于控制实时的
x的坐标,
//使其递增,类似于示波器从前到后扫描
TimerTask task = null; //时间控制对象的一个任务
/* 关于画图类的几点说明
* SurfaceView 是View的继承类,这个视图里
* 内嵌了一个专门用于绘制的Surface。可以控制这个Surface的格式和尺
寸。
* SurfaceView控制这个Surface的绘制位置。
*
* 实现过程:继承SurfaceView并实现SurfaceHolder.Callback接口------>
* SurfaceView.getHolder()获得SurfaceHolder对象
----->SurfaceHolder.addCallback(callback)
* 添加回调函数----->surfaceHolder.lockCanvas()获得Canvas对象并锁
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
定画布------>
* Canvas绘画------->SurfaceHolder.unlockCanvasAndPost(Canvas
canvas)结束锁定画图,
* 并提交改变,将图形显示。
*
* 这里用到了一个类SurfaceHolder,可以把它当成surface的控制器,
* 用来操纵surface。处理它的Canvas上画的效果和动画,控制表面,大
小,像素等
*
* 其中有几个常用的方法,锁定画布,结束锁定画布
* */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(yout.main);
myview = (TextView)findViewById(R.id.myview); //获取控件对象
Button bluetooth =(Button)findViewById(R.id.button);
Button sin =(Button)findViewById(R.id.sin);
Button clear =(Button)findViewById(R.id.clear);
surface = (SurfaceView)findViewById(R.id.show);
//初始化SurfaceHolder对象
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
holder = surface.getHolder();
holder.setFixedSize(WIDTH+50, HEIGHT+100); //设置画布大小,要
比实际的绘图位置大一点
paint = new Paint();
paint.setColor(Color.GREEN); //画波形的颜色是绿色的,区别于坐标
轴黑色
paint.setStrokeWidth(3);
bluetooth.setOnClickListener(new MyButtonListener());
//添加按钮监听器 开启蓝牙 开启连接通信线程
clear.setOnClickListener(new MyButtonClearListener());
//添加按钮监听器 清除TextView内容
holder.addCallback(new Callback() { //按照上面注释,添加回调函数
public void surfaceChanged(SurfaceHolder holder,int format,int
width,int height){
drawBack(holder);
//如果没有这句话,会使得在开始运行程序,整个屏幕没有白
色的画布出现
//直到按下按键,因为在按键中有对drawBack(SurfaceHolder
holder)的调用
}
public void surfaceCreated(SurfaceHolder holder) {
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
// TODO Auto-generated method stub
}
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
});
//添加按钮监听器 开启画图线程
sin.setOnClickListener(new OnClickListener(){
public void onClick(View v) { } // TODO Auto-generated method stub new DrawThread().start(); //线程启动
});
}
public void onClick(View v) { class MyButtonListener implements OnClickListener{
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
// TODO Auto-generated method stub //如果没有打开蓝牙,此时打开蓝牙 if (!mBluetoothAdapter.isEnabled()) { enableBtIntent = new Intent
Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent,
REQUEST_ENABLE_BT);
} //此处我已经知道我对应的蓝牙模块的地址,所以省去扫描,配对的
过程,
//如果从头开始的话,需要添加很多内容。 /* * 这是获得在手机中已经存储的已经配对过的蓝牙信息 * Set<BluetoothDevice>devices =
mBluetoothAdapter.getBondedDevices();
iterator.next();
System.out.println(bluetoothdevice.getAddress()); myview.append( "\n"+bluetoothdevice.getAddress()); //这里就是获取地址 当然这里又不止一个信息,所有配对的信息if(devices.size()>0){ for(Iterator iterator = devices.iterator();iterator.hasNext();){ BluetoothDevice bluetoothdevice = (BluetoothDevice)
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
都有,
* 你要选择蓝牙模块的地址,其实地址只是一个说法,它实际
上是一个虚拟通道,
}*/
BluetoothDevice device = * 我也不太清楚,就称之为地址了 }
mBluetoothAdapter.getRemoteDevice("20:13:03:18:10:09");
try { socket = device.createRfcommSocketToServiceRecord(uuid);
//建立连接
BluetoothAdapter.getDefaultAdapter().cancelDiscovery(); //取消搜索蓝牙设备,不写也罢,因为我压根没搜索 socket.connect(); //建立连接,如果连接成功,此时蓝牙模块中的显示当前连接状
态的指示灯就不会闪烁了,
//此时意味着连接成功了 } catch (IOException e) { } thread = new ConnectedThread(socket); //开启通信的线程 thread.start(); e.printStackTrace();
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
}
}
} class MyButtonClearListener implements OnClickListener{ public void onClick(View v) { } // TODO Auto-generated method stub myview.setText(""); Handler handler = new Handler() { //这是处理消息队列的Handler对象 @Override public void handleMessage(Message msg) { //处理消息 if (msg.what==READ) { String str = (String)msg.obj; //类型转化 myview.append(" "+str); //显示在画布下方的TextView中
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
}; /* } } super.handleMessage(msg); * 关于此类,因为我的手机端只需要从蓝牙读取数据,不需要发送,所以
就不必实现输出流
* 其实相比起来,输出流更简单 * */ private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
//构造函数
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream(); //获取输入流
tmpOut = socket.getOutputStream(); //获取输出流
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer); //bytes数组返回值,为
buffer数组的长度
// Send the obtained bytes to the UI activity
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
String str = new String(buffer);
temp = byteToInt(buffer); //用一个函数实现类型转化,
从byte到int
handler.obtainMessage(READ, bytes, -1, str)
.sendToTarget(); //压入消息队列
} catch (Exception e) {
System.out.print("read error");
break;
}
}
}
}
public void run() { // TODO Auto-generated method stub drawBack(holder); //画出背景和坐标轴 //绘图线程,实时获取temp 数值即是y值 public class DrawThread extends Thread {
if(task != null){
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
task.cancel();
}
task = new TimerTask() { //新建任务
@Override
public void run() {
//获取每一次实时的y坐标值
//如果不注释,则是画出正弦波
//int cy = centerY -(int)(100 * Math.sin((cx -5) *2 *
Math.PI/150));
int cy = centerY + temp; //实时获取的temp数值,因为对于
画布来说
//最左上角是原点,所以我要到y值,需要从画布中间开始
计数
Canvas
Rect(cx,cy-2,cx+2,cy+2));
//锁定画布,只对其中Rect(cx,cy-2,cx+2,cy+2)这块区域
做改变,减小工程量
canvas.drawPoint(cx, cy, paint); //打点 canvas = holder.lockCanvas(new
cx++; //cx 自增, 就类似于随时间轴的图形 holder.unlockCanvasAndPost(canvas); //解锁画布
if(cx >=WIDTH){
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
cx=5; //如果画满则从头开始画 drawBack(holder); //画满之后,清除原来的图像,从新开始
}
}
};
timer.schedule(task, 0,1); //隔1ms被执行一次该循环任务画出图形
//简单一点就是1ms画出一个点,然后依次下去
} }
//设置画布背景色,设置XY轴的位置
private void drawBack(SurfaceHolder holder){
Canvas canvas = holder.lockCanvas(); //锁定画布
//绘制白色背景
canvas.drawColor(Color.WHITE);
Paint p = new Paint();
p.setColor(Color.BLACK);
p.setStrokeWidth(2);
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
//绘制坐标轴
canvas.drawLine(X_OFFSET, centerY, WIDTH, centerY, p); //绘制X轴 前四个参数是起始坐标
canvas.drawLine(X_OFFSET, 20, X_OFFSET, HEIGHT, p); //绘制Y轴 前四个参数是起始坐标
holder.unlockCanvasAndPost(canvas); //结束锁定 显示在屏幕上 holder.lockCanvas(new Rect(0,0,0,0)); //锁定局部区域,其余地方不做改变
holder.unlockCanvasAndPost(canvas);
}
//数据转化,从byte到int
/*
* 其中 1byte=8bit,int = 4 byte,
* 一般单片机比如c51 8位的 MSP430 16位 所以我只需要用到后两个byte就ok
* */
public static int byteToInt(byte[] b){
} return (((int)b[0])+((int)b[1])*256);
通过单片机连接的蓝牙模块发送数据,手机也是通过蓝牙接收,并在屏幕上完成绘画。
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub menu.add(0,1, 1, "exit");// 添加menu菜单一个item //第一个参数是菜单所在组的名字,组的id,第二个是item的id ,第三个是item
}
//当按下菜单时,选择其中一个item会调用下函数 //最后一个是item显示的内容。 return super.onCreateOptionsMenu(menu);
@Override public boolean onMenuItemSelected(int featureId, MenuItem item) { } // TODO Auto-generated method stub finish(); return super.onMenuItemSelected(featureId, item);
@Override
protected void onStop() { // TODO Auto-generated method stub super.onStop();
正在阅读:
android 蓝牙 单片机 显示波形08-20
2022年整合十三五规划思路的试题与答案讲解名师精品资料04-19
生活上的自我评价【优秀3篇】03-28
关于节日的作文600字_初二作文03-23
人教版八年级上册语文教学计划10-26
相位噪声11-30
学期自我评价范文4篇_自我评价07-30
173湿空气参数计算方法的分析研究06-04
日语二级词汇练习192407-01
2011年中考专题八 - 阅读理解06-29
- 2012诗歌鉴赏讲座 师大附中张海波
- 2012-2013学年江苏省苏州市五市三区高三(上)期中数学模拟试卷(一)
- 市政基础设施工程竣工验收资料
- 小方坯连铸机专用超越离合器(引锭杆存放用)
- 荀子的学术性质之我见
- 氩弧焊管轧纹生产线操作说明
- 小学科学六年级上册教案
- (商务)英语专业大全
- 外汇储备的快速增长对我国经济发展的影响
- 幼儿园中班优秀语言教案《小猴的出租车》
- 第七章 仪表与显示系统
- 身份证号码前6位行政区划与籍贯对应表
- 单位(子单位)工程验收通知书
- 浅谈地铁工程施工的项目成本管理
- 沉积学知识点整理
- 前期物业管理中物业服务企业的法律地位
- 2014微量养分营养试卷
- 地质专业校内实习报告范文(通用版)
- 内部审计视角下我国高校教育经费支出绩效审计研究
- 高次插值龙格现象并作图数值分析实验1
- 蓝牙
- 波形
- 单片机
- android
- 显示
- 在全县秋季植树造林暨经济林综合管理工作动员大会上的讲话
- 中外设计史复习资料修改版
- 小学语文知识大全-对联谜语
- 良好行为习惯养成教育
- 中级职称个人专业技术工作总结 Microsoft Word 文档
- 科学谋划 夯实提升 赢在高效
- 小学生篮球学习计划及教案
- 2013-2014学年七年级英语上册 Unit 7 Days and Months单元综合检测试题 (新版)冀教版
- 康拓安防科技有限公司运营计划书
- 停车场管理系统报告
- 实验八 感受态细胞的制备与转化
- mooc课程 java 期末考试试卷
- 聚能装药爆破
- 2015年中南大学文学硕士复试分数线是345分
- IP-guard可信赖的内网安全专家
- 人物摄影欣赏
- QT-DFDQ02 单机设备控制柜(箱)出厂检验规范
- IPAD展销系统(珠宝行业)
- 中班美术《神奇的刷子》
- 第九章货币需求 (教材第七章123节)