Processing에서 마이크로 컴퓨터에서 전송 된 데이터를 실시간으로 표시

동작 확인일 2019/06/26

개발 환경:
· Processing3.5.3
· M5STACK GRAY + Arduino IDE

목적:
마이크로 컴퓨터의 데이터를 시리얼 통신으로 수신하여 동작을 확인할 때, 일단 그래프를 그릴 때까지 귀찮게합니다.
→ 손쉽게 데이터의 움직임만 볼 수 있는 프로그램을 만들자!


움직이는 그림

Processing에서 구조체를 받는 방법을 모르기 때문에 시리얼 통신을 2Byte 읽고 int형을 만드는 recv_int 함수와 4Byte 읽어 long형을 만드는 recv_long 함수를 각각 구현했습니다.
마이크로컴퓨터로 읽는 시간은 ms라든지가 많기 때문에 long형, 마이크로컴퓨터에서 읽는 데이터로서는 AD값을 상정해 int형을 각각 받는 샘플 브로그램이 아래가 됩니다. 덧붙여서 Processing에서는 int형이 4Byte 취급할 수 있었을 것이므로 recv_long 함수는 이름입니다만 int형으로 받고 있습니다. (Arduino측이 long형으로 보내고 있었기 때문에 이런 이름을 붙였을 것)

serial_graph.pde
import processing.serial.*;

Serial port;

IntList time_list;
IntList data_list;

int GRAPH_HEIGHT = 400;
int GRAPH_WIDTH = 1000;
int GRAPH_OFFSETX = 40;
int GRAPH_OFFSETY = 50;

void setup () {
    size (1200, 600);
    port = new Serial (this, Serial.list ()[1], 115200);   

    time_list = new IntList();
    data_list = new IntList();
}

void draw_graph(){
  strokeWeight(4); 
  stroke(255, 89, 23);

  for(int i=1; i< time_list.size(); i++){
    PVector v1 = new PVector(GRAPH_OFFSETX + time_list.get(i-1) - time_list.min(), (height - GRAPH_OFFSETY) - data_list.get(i-1));
    PVector v2 = new PVector(GRAPH_OFFSETX + time_list.get(i) - time_list.min(), (height - GRAPH_OFFSETY) - data_list.get(i));

    line( v1.x, v1.y, v2.x, v2.y);
  }
}

void draw_graph_outline(){
  strokeWeight(5); 
  stroke(240, 240, 240);

  PVector v1 = new PVector(GRAPH_OFFSETX, (height - GRAPH_OFFSETY));
  PVector v2 = new PVector(GRAPH_OFFSETX, (height - GRAPH_OFFSETY) - GRAPH_HEIGHT);
  PVector v3 = new PVector(GRAPH_OFFSETX + GRAPH_WIDTH, (height - GRAPH_OFFSETY));

  line( v1.x, v1.y, v2.x, v2.y);
  line( v1.x, v1.y, v3.x, v3.y);
}

void draw () {
  background(45, 45, 45);
  draw_graph_outline();
  draw_graph();
}

int recv_int(Serial port){
  int data1 = port.read();
  int data2 = port.read();  
  int recv_data = data1 << 8 | data2 << 0 ;

  return recv_data;
}

int recv_long(Serial port){
  int data1 = port.read();
  int data2 = port.read();
  int data3 = port.read();
  int data4 = port.read();
  int recv_data = data1 << 24 | data2 << 16 | data3 << 8 | data4 << 0 ;

  return recv_data;
}

void serialEvent (Serial port) {
  if ( port.available() >= 7 ) {
    if(port.read() == 'H'){
      int recv_time = recv_long(port);
      int recv_data = recv_int(port);

      int time = (int)(recv_time / 10);
      int data = (int)map(recv_data, 0, 4095, 0, GRAPH_HEIGHT);

      time_list.append(time);
      data_list.append(data);

      if(time - time_list.min() > GRAPH_WIDTH){
        time_list.remove(0);
        data_list.remove(0);
      }

      print(recv_time);
      print(",");
      println(recv_data);
    }
  }
}

Processing의 동작 확인용으로 이번에는 M5STACK을 사용해, 텍토에 정현파를 시리얼 통신에 흘러넘치는 프로그램을 구축했습니다.
M5STACK측은 구조체로 보낼 수 있는 것 같은 생각도 합니다만, 머리를 사용하고 싶지 않았으므로 Processing과 같이 write_int함수인 write_long함수인 구현해 포치포치 송신하고 있습니다.

test_serial.ino
#include<M5Stack.h>

int timer_begin = 0;
float pi = 3.14159265;
int counter = 0;

void setup() {
  M5.begin();

  Serial.begin(115200);

  timer_begin = millis();
}

void write_long(long val, uint8_t d[4]){
  uint32_t _data = val;
  d[0] = (uint8_t)((_data >> 24) & 0xFF);
  d[1] = (uint8_t)((_data >> 16) & 0xFF);
  d[2] = (uint8_t)((_data >>  8) & 0xFF);
  d[3] = (uint8_t)((_data >>  0) & 0xFF);

  Serial.write(d[0]);
  Serial.write(d[1]);
  Serial.write(d[2]);
  Serial.write(d[3]);

}

void write_int(int val, uint8_t d[2]){
  uint32_t _data = val;
  d[0] = (uint8_t)((_data >> 8) & 0xFF);
  d[1] = (uint8_t)((_data >> 0) & 0xFF);

  Serial.write(d[0]);
  Serial.write(d[1]);

}

void loop() {
  int send_data = 500 * sin(pi * counter / 100) + 2000;
  counter++;
  long timer = millis();
  Serial.write('H');

  byte data1[4];  
  byte data2[2];

  write_long(timer-timer_begin, data1);
  write_int(send_data, data2);

  //uint8_t data0[6] = {data2[0], data2[1], data1[0], data1[1], data1[2], data1[3]};
  //Serial.write(data0,6);
  delay(10);
}

좋은 웹페이지 즐겨찾기