晓麦教你定制自己的蓝牙控制器(入门)-Arduino中文社区 - Powered by Discuz! Archiver

xmile 发表于 2017-1-5 23:15

晓麦教你定制自己的蓝牙控制器(入门)

本帖最后由 xmile 于 2017-1-8 20:28 编辑

现在蓝牙控制已经越来越普遍,市面上蓝牙控制器app也非常多,但是并都不能满足大家的控制需要
所以在这里教大家如何用processing定制自己的蓝牙控制器
首先要搭建起processing的开发环境 https://processing.org/download/
下载processing ide,解压就可以用
打开之后界面有一种让人非常熟悉的感觉

没错,他跟arduino ide的界面是差不多的
右上角有一个可以点开选择开发的模式
默认是java模式,没有我们所需要的Android模式,但是我们点击右下角的update进入管理页面
下载我们需要的Android模式即可
之后再重新打开processing ide转换成Android模式,并且还要连接Android sdk。
这是Android sdk链接:http://pan.baidu.com/s/1kUOY9UZ 密码:ujmv
接下来,我将结合实例来讲解processing制作蓝牙控制器的过程不过在那之前我们需要点东西

我们还需要下载ketai库,里面有可以让我们调用手机设备的函数
另外,还要保证你的电脑已经安装了你手机的usb驱动,如果已经安装的可以在这里看到你手机的名字

如果没看到也没关系,你装个手机管家(例如360手机管家)然后按照提示一步步连接你的手机就可以装上了。
那么接下来就开始上代码
import android.content.Intent;
import android.os.Bundle;
import ketai.net.bluetooth.*;
import ketai.ui.*;
import ketai.net.*;
KetaiBluetooth bt;//KetaiBluetooth
KetaiList klist; //KetaiList
boolean isConfiguring;
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bt = new KetaiBluetooth(this);
}
void onActivityResult(int requestCode, int resultCode, Intent data) {
bt.onActivityResult(requestCode, resultCode, data);
}
void setup() {
isConfiguring = true;
bt.start();
}

void draw() {
    if (isConfiguring){
      ArrayList names;
      klist = new KetaiList(this, bt.getPairedDeviceNames());
      isConfiguring = false;
   }
   else{}
}

void onKetaiListSelection(KetaiList klist) {
String selection = klist.getSelection();
bt.connectToDeviceByName(selection);
//dispose of list for now
klist = null;
}
void onBluetoothDataEvent(String who, byte[] data) {
if (isConfiguring)
return;
val_read=data;
}

以上这个就是一个基本的具有蓝牙串口功能的app框架,编译出来是没有画面的,但是会提示你是否允许打开蓝牙
最上面的import 就是导入我们所需要的库文件,processing编程的写法其实更接近java,有学过java的童鞋应该能感受到
其中KetaiBluetooth这个库就是我们需要调用的蓝牙库文件,他里面封装能实现蓝牙发送和接收功能的函数
而KetaiList则是调出我们手机里面曾经匹配过的蓝牙设备的清单,毕竟我们还要选择到底是跟哪个蓝牙设备进行信息传输
void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   bt = new KetaiBluetooth(this);
}
这个函数是安卓的app启动的时候执行的,不懂java的可以忽略不用管

void onActivityResult(int requestCode, int resultCode, Intent data) {
bt.onActivityResult(requestCode, resultCode, data);
}

这个函数则是将app的数据传递给蓝牙,也是不用管
void setup()
void draw()
这两个函数其实就跟arduino里的setup和loop差不多
setup()我就不多说了,程序刚开始的执行,并且只执行一次
draw()这个函数则是重复执行

void onKetaiListSelection(KetaiList klist) {
String selection = klist.getSelection();
bt.connectToDeviceByName(selection);
//dispose of list for now
klist = null;
}

这个函数就实现我们前面提到的,把跟手机匹配过的蓝牙设配列出来供我们选择
void onBluetoothDataEvent(String who, byte[] data) {
if (isConfiguring)
return;
val_read=data;
}

这个函数则是把蓝牙读取到的数据传给val__read这个变量
以上是固定的蓝牙传感器要用到的库和函数
接下来就是processing的编程
processing其实最开始是作为艺术绘图编程软件而闻名,对于数学较好的人来说,用processing可以画出他们想要的动态图形
为什么说是动态呢?因为前面说到draw()函数是重复执行的,他每次根据语句调用的先后顺序画出图形,越是靠后执行的语句,越是覆盖在最前面
而draw()函数每次执行完之后就会清空屏幕,再重新画上去,所以说,如果我们使用可控变量来调整函数的参数的话就可以控制图形的位置或大小,动态的效果。
所以我们接下来上要做的就是画出一个动态的界面
首先要做好画布
size(720,1280);这个函数就是设置画布的函数,里面的参数是画布的长度,最好填上的是手机屏幕的分辨率,但调小一点也没关系
然后是画布的坐标系,是以左上角为原点,向右为x轴的正方向,向下为y轴的正方向
接下来是ellipseMode(RADIUS);这个函数是声明画圆时候的模式,这个用这个半径(RADIUS)模式就好
smooth();这个函数式样线条更圆滑
text(s,x,y);这个函数是用来显示文字的,s参数是文字,x参数是文字在背景中的
textSize(50);是调用text()这个函数时显示字体的大小
strokeWeight(5);这个是显示图形边框的宽度

background(70);这个函数是决定画布的颜色,也就是背景的颜色,0为黑色,255为白色,0-255之间是不同深度的灰色
line()这个函数是画直线,line(x1,y1,x2,y2);这样就能画出一条直线
ellipse()这个函数是画圆的,ellipse(x,y,半径1,,半径2);如果半径1和半径2不相等则是画出椭圆
fill()这个函数是填充字体和图形的颜色,有两种写法fill(s)和fill(r,g,b)第一种是只有黑白灰,0为黑色,255为灰色,第二种是彩色,三个参数分别是红色,绿色,蓝色
fill()要放在画图形之前
要注意的是线条不是图形,所以fill()对线条是不起作用的
还有三个重要的变量,mouseX,mouseY,mousePressed
这三个是系统预先定义好的,当我们的手指点在手机屏幕上的时候,mousePressed就会为true,否则为false
在我们手指点在手机屏幕的同时,mouseX这个变量的值就会等于我们手指点在屏幕上的X轴坐标
同理mouseY这个变量的值就会等于我们手指点在屏幕上的Y轴坐标
好了铺垫了这么多,那么就开始写代码了
首先这次我要做的是一个可以调整LED灯闪烁时间的app,arduino端的工作流程就是接收蓝牙发过去的时间,然后用来作为delay的参数
而手机端则是要有一个调整时间的界面,当然不是通过文本输入这样发出,也不是设定好那个按钮是发多少时间这样,而是最方便的滑动调整时间
为此,我预想一个最朴素的界面,一条直线,在直线上有一个圆形的滑块,通过左右移动这个滑块的位置,可以让蓝牙发出不同的时间给arduino
接下来在代码上我们这样编写
在setup()里面设定好画面的配置
size(720,1280);//第一步设定好画布大小,一般设为手机的分辨率
smooth();//线条要圆滑
ellipseMode(RADIUS);//画圆是采用半径模式
textSize(50);//设定好字体大小
strokeWeight(5);//设定好边界线粗细

bt.start();//启动蓝牙
ArrayList names;
klist = new KetaiList(this, bt.getPairedDeviceNames());//获取跟蓝牙匹配过的设备列表

获取蓝牙设备列表之后,需要我们选择跟哪个设备进行信息传输


在draw()函数里面
background(70);//设定好画布的颜色
line(360,280,360,1000);//在屏幕中央画一条直线,这条线将作为滑块滑动的轨道,轨道是一条垂直x轴,并且是从y坐标280到1000的的直线
fill(255,255,0);//要填充的是红色+绿色
ellipse(360,y,50,50);画一个圆,x坐标和直线是一样的,y坐标为变量我会在后面的语句里根据mouseY的位置来改变y的值,y是一个int类型的变量,这个圆就作为我调整时间的滑块
s1=byte((y-280)*100/(1000-280));//我用一个byte类型的变量s1存储我要发出去的时间,它的值则是根据y变量的值而改变,也就是说我们可以通过mouseY的值来改变s1,为什么要用byte类型呢?因为arduino端接收蓝牙的数据是通过Serial.read()这个函数来读取的,众所周知,Serial每次只能读取一个字节的数据,也就是一个byte的数据,所以我们要用byte类型的变量s1来发送时间
text(s1,200,y);//显示s1的值,他要跟我画的圆,也就是跟我们的滑块保持在一同水平线上,因此y轴坐标也是变量y,因为要放在左边,所以x坐标是200比圆形的x坐标360要小
下面这个判断是整个程序的关键
if(mousePressed){//先判断手指有没有放在屏幕上
    if(abs(mouseX-360)<=50&&abs(mouseY-y)<=50&&mouseY>=280&&mouseY<=1000){//然后判断手指的x坐标和我们一开始画的线(也就是轨道)的差的绝对值是否小于50(滑块圆的半径),并且手指的y坐标是否与滑块的y坐标的差值的绝对值是否小于50,并且y坐标要在(280,1000)之间
以上是数学描述,如果转换成逻辑描述的就是,手指要放在圆(滑块)内,并且手指还要同时在轨道上才会执行下面的语句
      y=mouseY;//把手指触碰屏幕是的y轴坐标赋给变量y,那么跟y相关的滑块圆,文字,以及要发出去的时间s1都会发生相应的变化
    }
}
到这里画出来的界面就是这样

最后把s1交给蓝牙发出去就行
执行bt.broadcast(s1);就行
但因为我们发给arduino端的数据是时间,arduino要把它放进delay里面,他每获取一个参数都需要暂停,如果他获取太多的话就,我在app的操作效果就不明显,所以我们要限制一下蓝牙发出去数据的频率
如果是像发出去的数据是直接用来调输出pwm的(例如像Led灯的亮度),或者角度的(舵机的角度)这种就不需要限制蓝牙发出的频率
因为虽然Serial.read()每次只读取一个byte,但是arduino的缓存会把发送过去的数据都存储,然后再让Serial去读取,所以说调整暂停时间这种就不能发送太多数据过去,不然arduino的delay都还没执行完,你又发送的数据过去,那你看到永远都是之前发过去的时间而不是你当前发送过去的时间。
我们新建两个int类型的变量new_time 和 old_time,还有一个byte类型变量 old_s
new_time= millis();//把程序当前的时间赋给new_time
if((new_time-old_time)>100){//判断new_time old_time是否相差100毫秒以上
if(s1!=old_s){//判断s1是否有改变,有就执行下面的语句
    val_write = s1;//这里用一个byte数组类型的变量来代替s1,为什么要用数组,因为虽然我们现在只是发送一个数据时间,但是如果我们日后要发送多个数据(时间,电压什么的)就要用到数组来发送才行
    bt.broadcast(val_write);//然后把时间发送出去
    old_s = s1;}//把s1的值赋给old_s,用作下一次判断
    old_time=new_time;把new_time赋给old_time,用作下一次判断

以上的程序描述比较难懂,其实他实现的效果就是每过100毫秒判断s1的值是否发生变化,如果发生变化就把s1发送出去
下面贴上完整的程序

import android.content.Intent;
import android.os.Bundle;
import ketai.net.bluetooth.*;
import ketai.ui.*;
import ketai.net.*;
KetaiBluetooth bt;//KetaiBluetooth
KetaiList klist; //KetaiList
boolean isConfiguring;
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bt = new KetaiBluetooth(this);
}
void onActivityResult(int requestCode, int resultCode, Intent data) {
bt.onActivityResult(requestCode, resultCode, data);
}
byte[] val_read=new byte;
byte[] val_write =new byte;
int y=640;
byte s1;
int new_time;
int old_time=0;
byte old_s=0;
void setup() {
size(720,1280);
smooth();
ellipseMode(RADIUS);
textSize(50);
strokeWeight(5);
bt.start();
ArrayList names;
klist = new KetaiList(this, bt.getPairedDeviceNames());
}

void draw() {
background(70);
fill(255);
line(360,280,360,1000);
fill(255,255,0);
ellipse(360,y,50,50);
s1=byte((y-280)*100/(1000-280));
text(s1,200,y);
if(mousePressed){
    if(abs(mouseX-360)<=50&&abs(mouseY-y)<=50&&mouseY>=280&&mouseY<=1000){
      y=mouseY;
    }
}
new_time= millis();
if((new_time-old_time)>100){
if(s1!=old_s){
    val_write = s1;
    bt.broadcast(val_write);
    old_s = s1;}
    old_time=new_time;
}
}

void onKetaiListSelection(KetaiList klist) {
String selection = klist.getSelection();
bt.connectToDeviceByName(selection);
//dispose of list for now
klist = null;
}
void onBluetoothDataEvent(String who, byte[] data) {
if (isConfiguring)
return;
val_read=data;
}

程序编写完毕后不要忘记给app添加权限,如图找到跟蓝牙相关的权限,打上勾就行


这个权限必须勾上,不然你的app打开的时候会直接闪退
最后点这个按钮安装到你的手机上就行
接下来arduino端的程序
int s=50;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(3,OUTPUT);//连接蓝牙端EN
pinMode(13,OUTPUT);
digitalWrite(3,HIGH);
}

void loop() {
// put your main code here, to run repeatedly:
if(Serial.available()){
s = Serial.read();
Serial.println(s);
}

digitalWrite(13,HIGH);
delay(s*10);
digitalWrite(13,LOW);
delay(s*10);
}

我的蓝牙TX和RX分别接arduino的RX和TX,所以我就直接用Serial.read()来读取蓝牙的数据
基本的编程思路就是如果Serial读取到数据那就将读取到的值赋给s,如果没读到就保持现状,s是led灯闪烁的延时时间
http://www.tudou.com/programs/view/CAJ5oMwoPrk/

刺客佳 发表于 2017-1-6 00:19

支持一下

wdh666 发表于 2017-1-6 01:43

深度好文呀一定 要好好学习 新手上路 看不懂也要看

mostblack 发表于 2017-1-6 07:41

wdh666 发表于 2017-1-6 01:43 static/image/common/back.gif
深度好文呀一定 要好好学习 新手上路 看不懂也要看

恕我直言,没什么用,文中除了说是做蓝牙的以外,什么内容都没有,营养度为零

markmarkmark 发表于 2017-1-6 07:55

等待更新。。。

xzlhw 发表于 2017-1-6 08:23

等待更新http://www.arduino.cn//mobcent//app/data/phiz/default/03.png

xmile 发表于 2017-1-6 08:29

mostblack 发表于 2017-1-6 07:41
恕我直言,没什么用,文中除了说是做蓝牙的以外,什么内容都没有,营养度为零
...

不先搭建好环境,我后面说再多也没用

mostblack 发表于 2017-1-6 09:27

xmile 发表于 2017-1-6 08:29
不先搭建好环境,我后面说再多也没用

恩恩。。建议整合一下,更新在这个帖子里,每篇都分开的话一个是比较分散,第二个是容易沉掉不好一篇一篇的找出来,连贯性会差一些。。

mostblack 发表于 2017-1-6 09:27

xmile 发表于 2017-1-6 08:29
不先搭建好环境,我后面说再多也没用

恩恩。。建议整合一下,更新在这个帖子里,每篇都分开的话一个是比较分散,第二个是容易沉掉不好一篇一篇的找出来,连贯性会差一些。。

jackten 发表于 2017-1-6 09:44

谢谢分享                           
页: [1] 2
查看完整版本: 晓麦教你定制自己的蓝牙控制器(入门)