通过蓝牙串口从Arduino发送数据

4
我目前正在尝试设计一个控制器,通过蓝牙与安卓手机(Galaxy Nexus)通信。我面临一些挑战,而且我没有太多的实际编程经验。
在控制器的核心部分是一块Arduino微控制器,它扫描8个数字引脚和6个模拟引脚(10位),并通过串行发送数据到HC-05蓝牙芯片。然后,安卓手机应读取通过蓝牙发送的串行信息,并将数据包传输到另一部手机,这需要我花费一些时间来实现,因为我对互联网的了解很少,或者分析和解释信息以采取进一步的行动。
我请求的是关于如何最好地完成此任务的见解。那么什么是最好的方式?我希望它是实时的,所以当我按下一个按钮或多个按钮的组合时,安卓手机可以快速地采取行动,人类无法感知延迟。
然后,我希望能够将手机读取的串行缓冲区中的信息与相应的按钮或模拟引脚相关联。以防出现错误或避免它们失去同步。
以下是我目前已有的内容,我还没有测试过这段代码,部分原因是因为我仍在学习如何编写这个项目的安卓部分,另一部分原因是我想得到一些反馈, 以确定是否存在更好的方案。
//Initialization
/*

This Program has three functions:
1) Scan 8 digital pins and compile their state in a single byte ( 8 bits)
2) Scans 6 Analogue inputs corresponding to the joysticks and triggers 
3) Send this info as packets through seril --> Bluetooth 

*/
#include <SoftwareSerial.h>// import the serial software library

#define A = 2
#define B = 3
#define X = 4
#define Y = 5
#define LB = 6
#define RB = 7
#define LJ = 8
#define RJ = 9
#define RX = 10
#define TX = 11
//Pin 12 and 13 are unused for now
SoftwareSerial Bluetooth(RX,TX); //Setup software serial using the defined constants
// declare other variables
byte state = B00000000

void setup() {
  //Setup code here, to run once:
  //Setup all digital pin inputs
  pinMode(A,INPUT);
  pinMode(B,INPUT);
  pinMode(X,INPUT);
  pinMode(Y,INPUT);
  pinMode(LB,INPUT);
  pinMode(RB,INPUT);
  pinMode(LJ,INPUT);
  pinMode(RJ,INPUT);
  //Setup all analogue pin inputs
  //setup serial bus and send validation message
  Bluetooth.begin(9600);
  Bluetooth.println("The controller has successfuly connected to the phone")
}

void loop() {
  //Main code here, to run repeatedly: 
  //Loop to sum digital inputs in a byte, left shift the byte every time by 1 and add that if the pin is high
  for(byte pin = 2, b = B00000001;  pin < 10; pin++, b = b << 1){ if (digitalRead(pin)== HIGH) state += b; }
  //Send digital state byte to serial
  Bluetooth.write(state);
  //Loop to read analgue pin 0 to 5 and send it to serial
  for( int pin = 0, testByte = 0x8000; pin < 6 ; pin++, testByte = testByte >> 1) { Bluetooth.write(analogRead(pin)+testByte); }
}

//Adding some validation would be wise. How would I go about doing that?
// Could add a binary value of 1000_0000_0000_0000,  0100_0000_0000_0000,  0010_0000_0000_0000 ... so on and then use a simple AND statement at the other end to veryfy what analogue reading the info came from
// so say the value for analgue is 1023 and came from analgue pin 1 I would have 0100_0011_1111_1111 now using an bitwise && I could check it against 0100_0000_0000_0000 if the result is 0100_0000_0000_0000 then I know this is the analogu reading from pin 1
//could easily implement a test loop with a shiting bit on the android side

我这样做位移是否毫无意义?最终,如果我没有弄错,所有的数据都会以字节(8位数据包)的形式发送,所以Bluetooth.write(analogRead(pin)+testByte)是否实际上会发送两个字节,还是会截断int数据?它将如何被分解,我怎样才能在android端恢复它呢?

你会如何实现这个功能?有什么见解或建议吗?

3个回答

3

很高兴你正在学习这个!以下是一些建议:

如果你添加新行,特别是留有空白,你的代码将更容易被阅读、理解和维护...

void loop() {
  //Main code here, to run repeatedly: 
  //Loop to sum digital inputs in a byte, 
  //left shift the byte every time by 1 and add that  if the pin is high
  for( byte pin = 2, b = B00000001;  pin < 10; pin++, b = b << 1) {
    if (digitalRead(pin)== HIGH)
      state += b;
  }
  //Send digital state byte to serial
  Bluetooth.write(state);
  //Loop to read analgue pin 0 to 5 and send it to serial
  for( int pin = 0, testByte = 0x8000; pin < 6 ; pin++, testByte = testByte >> 1) {
    Bluetooth.write(analogRead(pin)+testByte); 
  }
}

此外,您可以将移位运算符与除1以外的其他值一起使用。因此,您不需要保留移位掩码然后再添加,而只需使用一个简单的变量即可。更经典的方法是在第一个循环中表达的内容可以像这样实现:

#define PIN_OFFSET 2
  for ( int i=0; i < 8; i++) {
    if (digitalRead( i+PIN_OFFSET)== HIGH)
      state += (1 << i);
  }

第二个循环可以类似地完成:
  for( int pin = 0; pin < 6; pin++) {
    short testByte = 0x8000 >> pin;
    short result =  analogRead(pin) + testByte;
    Bluetooth.write( result >> 8); 
    Bluetooth.write( result & 0xFF); 
  }

请注意,Bluetooth.write()调用会发送一个字节,因此此代码先发送最高有效字节,然后再发送最低有效字节。
最后,您可能希望在loop()的开始处将状态变量清零——否则,一旦设置位,它就永远不会被清除。
您可能需要考虑一下要发送到手机的内容。它将是二进制数据,这可能很难处理——您如何知道起始和结束位置,经常会将一个值误解为控制字符而导致严重问题。考虑将其更改为格式化的、人类可读的字符串,并在结尾处添加换行符。
希望这有所帮助。

感谢您的建议和鼓励,@bobwki!我一定会记住的。好的,您建议我发送更多“格式化的人类可读字符串”。那么计算速度仍然足够快以实时处理吗?这真的是我的唯一问题,也是我试图尽可能高效地发送和处理数据的原因。 - Ethienne
不确定效率问题 -- 另一种方法是对结果进行编码,以至少使其成为可打印字符,以避免控制代码问题。此外,请注意,您不能假定蓝牙能够像您发送它们一样快地接收字符。它将缓存字符并尽力发送它们。根据接口的工作方式(我还没有看过),它可能会丢弃无法发送的字符,或者进行某种类型的 "流控制" -- 这两种方法都可能不适合您想要做的事情。 - bobwki

1
这个Arduino端点足够快,可以完成你想要的操作,当你处理如此少量数据时,无需担心最小化从微控制器发送到手机的字节数。我不太清楚你要发送什么到手机; 当按下按钮时,您是否希望每个按钮有一个不同的值,以便发送出类似以下内容的内容:
按钮已按下,按钮编号(两个字节)
如果是模拟值:
读取模拟值,模拟值MSB,模拟值LSB(假设模拟值大于8位)
我不知道你正在使用的Arduino代码,但我怀疑是这行代码:

Bluetooth.write(analogRead(pin)+testByte)

发送一个字节,该字节是模拟值和testByte相加的结果。

您能否提供此API的文档链接?

如果所有这些都有延迟,那么电话端会受到影响。请不要过于关心在Arduino端尝试节省一两个字节!(我目前正在进行一个项目,使用Cortex M3通过蓝牙模块将数据发送到Android手机,我们需要传输几千字节的数据。我知道从这方面来看,2到20个字节之间的差异无关紧要。)


好的,谢谢,很高兴知道我不必担心速度问题!如果我先发送“按钮按下”信号,那么我就不需要测试字节了。该API可以在Arduino网站上找到。http://www.arduino.cc/en/Reference/HomePage#.UxLULfldVjQ - Ethienne

0

谢谢建议。我已经下载了一个终端来测试我的蓝牙模块是否工作正常。话虽如此,终端应用程序是无意义的,因为它们只显示通过终端发送的数据。如果我想处理这些数据,我需要修改他们的代码或从头编写一个应用程序。在这两种情况下,我都需要学习Android方面的知识。我完全可以接受!这个项目的整个目的就是给我一个好的借口去付出必要的努力去学习一些东西。=) - Ethienne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接