首页 > 解决方案 > 将数组数据从处理发送到 Arduino

问题描述

我成功地设法将一个整数从处理发送到 Arduino,但现在我想发送一个由三个整数组成的数组,但我无法让它工作。我想用 Arduino 创建一个蜂鸣器反馈,该处理将控制激活哪个蜂鸣器。例如,从处理发送的数据应该是 [1,0,1] 意味着传感器 1 和 3 应该开始工作。如果[1,1,1]通过,蜂鸣器应该能够同时激活。

这是我到目前为止的代码:我试图了解哪些数据被发送回 Arduino 以了解如何使用它,并且我不断得到空值或随机整数。

我正在尝试学习如何做到这一点,如果代码不好,我深表歉意。

阿杜诺

void setup(){
  Serial.begin(9600); // Start serial communication at 9600 bps
}

void loop(){
  if (Serial.available()){ 
     const char data = Serial.read();
     char noteBuzzer[] = {data}; 
  for (int i = 0 ; i < sizeof(noteBuzzer); i++) {
  }
   Serial.print(noteBuzzer[1]);
  }
 }

加工

import processing.serial.*;
String notes[];
String tempo[];
Serial myPort;  
String val;

void setup(){
  size(200,200); 
  String portName = Serial.list()[0]; 
  myPort = new Serial(this, portName, 9600);
  notes = loadStrings("data/notes.txt");
 tempo = loadStrings("data/tempo.txt");
}

 void draw() {
    if (keyPressed == true) 
     {                          
      if (key == '1') {
         println("Start"); 
        readNotes();
      } 
    }
 }

 void readNotes(){
   for (int i = 0 ; i < notes.length; i++) {
   println(notes[i]);
   //println(tempo[i]);
   myPort.write(notes[i]);
   delay(int(tempo[i])); //this will be the tempo? 
    if ( myPort.available() > 0) 
     {  
      val = myPort.readStringUntil('\n');         
       println("Arduino",val); 
     } 
 }

}

标签: arduinoprocessingserial-communication

解决方案


如果您的数据是一个始终包含 3 个项目的数组,并且每个项目始终为 1 或 0(位),则您可以将整个数据存储在一个字节中(并且还有 5 个多位可用)。使用 Arduino 发送和接收字节非常简单。

这是一个基本草图,向您展示如何在单个字节中翻转 3 位:

// the state as a byte
byte buzzerState = 0B000;

void setup(){
  textFont(createFont("Courier New",18),18);
}

void draw(){
  background(0);
  text("DEC: " + buzzerState + 
     "\nBIN:" + binary(buzzerState,3),10,40);
}

void keyPressed(){
  if(key == '1'){
    buzzerState = flipBit(buzzerState,0);
  }
  if(key == '2'){
    buzzerState = flipBit(buzzerState,1);
  }
  if(key == '3'){
    buzzerState = flipBit(buzzerState,2);
  }
}

// flips a bit at a given index within a byte and returns updated byte
byte flipBit(byte state,int index){
  int bit = getBitAt(state,index);
  int bitFlipped = 1 - bit;
  return setBitAt(state,index,bitFlipped);
}
// returns the integer value of a bit within a byte at the desired index
int getBitAt(byte b,int index){
  index = constrain(index,0,7);
  return b >> index & 1;
}
// sets an individual bit at a desired index on or off (value) and returns the updated byte
byte setBitAt(byte b,int index, int value){
  index = constrain(index,0,7);
  value = constrain(value,0,1);

  if(value == 1) b |= (1 << (index));
  else           b &= ~(1 << (index));

  return b;
}

使用键“1”、“2”和“3”翻转位。

请注意,在按键中,我们总是更新相同的字节。文本将首先显示十进制值,然后显示二进制值。

处理位设置演示:以二进制和十进制显示一个字节的前 3 位

这是发送数据的最有效方式,也是最简单的串行通信方式。在 Arduino 方面,您可以简单地使用bitRead()Serial.read(). 有关二进制/位/字节的更多信息,请务必阅读BitMath Arduino 教程。二进制一开始可能看起来很吓人,但是一旦你练习了一下,它真的没那么糟糕,而且完全值得了解。

这是上面代码的更新版本,它在第一个可用的串行端口上将字节发送到 Arduino(确保更改Serial.list()[0]对您的设置有意义的内容,然后按“s”将更新发送到 Arduino:

import processing.serial.*;

// the state as a byte
byte buzzerState = 0B000;

Serial port;

void setup(){
  textFont(createFont("Courier New",18),18);

  try{
    port = new Serial(this,Serial.list()[0],9600);
  }catch(Exception e){
    e.printStackTrace();
  }
}

void draw(){
  background(0);
  text("DEC: " + buzzerState + 
     "\nBIN:" + binary(buzzerState,3),10,40);
}

void keyPressed(){
  if(key == '1'){
    buzzerState = flipBit(buzzerState,0);
  }
  if(key == '2'){
    buzzerState = flipBit(buzzerState,1);
  }
  if(key == '3'){
    buzzerState = flipBit(buzzerState,2);
  }
  if(key == 's'){
    if(port != null){
      port.write(buzzerState);
    }else{
      println("serial port is not open: check port name and cable connection");
    }
  }
}

// flips a bit at a given index within a byte and returns updated byte
byte flipBit(byte state,int index){
  int bit = getBitAt(state,index);
  int bitFlipped = 1 - bit;
  return setBitAt(state,index,bitFlipped);
}
// returns the integer value of a bit within a byte at the desired index
int getBitAt(byte b,int index){
  index = constrain(index,0,7);
  return b >> index & 1;
}
// sets an individual bit at a desired index on or off (value) and returns the updated byte
byte setBitAt(byte b,int index, int value){
  index = constrain(index,0,7);
  value = constrain(value,0,1);

  if(value == 1) b |= (1 << (index));
  else           b &= ~(1 << (index));

  return b;
}

这是一个超级基本的 Arduino 草图:

byte buzzerState;

void setup() {
  Serial.begin(9600);

  //test LEDs setup
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(12,OUTPUT);
}

void loop() {
  if(Serial.available() > 0){
    buzzerState = Serial.read();

    bool bit0   = bitRead(buzzerState,0);
    bool bit1   = bitRead(buzzerState,1);
    bool bit2   = bitRead(buzzerState,2);

    //test LEDs update
    digitalWrite(10,bit0);
    digitalWrite(11,bit1);
    digitalWrite(12,bit2);

  }  
}

如果您将 3 个 LED 连接到引脚 10、11、12,您应该在按“1”、“2”、“3”键时切换它们,然后在“处理”中按“s”键

在处理中解决二进制的一种方法可能是使用数据的字符串表示形式(例如"00000101"for [1,0,1]unbinary()并将该字符串转换为可以写入串行的整数值,但是在索引处获取和设置字符会有点烦人(并可能将该字符解析为它的整数值并返回)

当您需要发送超过一个字节时,事情会变得有点复杂,因为您需要处理数据损坏/中断等。在这些情况下,最好根据您的需要设置/设计一个通信协议,这并不容易,如果您才刚刚开始使用 Arduino,但也并非不可能。个例子,网上还有很多。

您可以尝试的一件快速而肮脏的事情是将该数据作为由换行符 ( \n) 终止的字符串发送,您可以将其缓冲到 Arduino 中,然后一次读取 4 个字节,丢弃\n解析时的内容:

例如,从处理中发送“101\n”,表示 [1,0,1],然后在 Arduino 端使用和访问该字符串中的每个整数Serial.readStringUntil('\n')的组合。charAt()toInt()

这是一个示例处理草图:

import processing.serial.*;

// the state as a byte
String buzzerState = "010\n";

Serial port;

void setup(){
  textFont(createFont("Courier New",18),18);

  try{
    port = new Serial(this,Serial.list()[0],9600);
  }catch(Exception e){
    e.printStackTrace();
  }

}

void draw(){
  background(0);
  text(buzzerState,30,50);
}

void keyPressed(){
  if(key == '1'){
    buzzerState = flipBit(buzzerState,0);
  }
  if(key == '2'){
    buzzerState = flipBit(buzzerState,1);
  }
  if(key == '3'){
    buzzerState = flipBit(buzzerState,2);
  }
  if(key == 's'){
    if(port != null){
      port.write(buzzerState);

    }else{
      println("serial port is not open: check port name and cable connection");
    }
  }
}

String flipBit(String state,int index){
  index = constrain(index,0,2);
  // parse integer from string
  int bitAtIndex = Integer.parseInt(state.substring(index,index+1));
  // return new string concatenating the prefix (if any), the flipped bit (1 - bit) and the suffix
  return state = (index > 0 ? state.substring(0,index) : "") + (1 - bitAtIndex) + state.substring(index+1);
}

还有一个基于Arduino > File > Examples > 04.Communication > SerialEvent的 Arduino :

/*
  Serial Event example

 When new serial data arrives, this sketch adds it to a String.
 When a newline is received, the loop prints the string and
 clears it.

 A good test for this is to try it with a GPS receiver
 that sends out NMEA 0183 sentences.

 Created 9 May 2011
 by Tom Igoe

 This example code is in the public domain.

 http://www.arduino.cc/en/Tutorial/SerialEvent

 */

String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);

  // test LEDs setup
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(12,OUTPUT);
}

void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
    Serial.println(inputString);
    // process string
    bool bit0   = inputString.charAt(2) == '1';
    bool bit1   = inputString.charAt(1) == '1';
    bool bit2   = inputString.charAt(0) == '1';

    //test LEDs update
    digitalWrite(10,bit0);
    digitalWrite(11,bit1);
    digitalWrite(12,bit2);


    // clear the string:
    inputString = "";
    stringComplete = false;
  }
}

/*
  SerialEvent occurs whenever a new data comes in the
 hardware serial RX.  This routine is run between each
 time loop() runs, so using delay inside loop can delay
 response.  Multiple bytes of data may be available.
 */
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

请注意,这更容易出错,并且使用的数据量是单字节选项的 4 倍。


推荐阅读