2013-02-05 3 views
2

시리얼을 통해 내 arduino와 이야기하기 위해 C++ 코드를 작성했습니다. 사인과 코사인을 사용하여 두 개의 서보 모터에서 진동을 만들려고 시도하지만 데이터는 건너 뜁니다. 왜 이런 일이 일어나고 있는지 모르겠습니다. serialios에 termios.h를 사용하고 있습니다. C + +에서 출력은 "V180H90"즉, 수직 180, 수평 90과 같습니다. fstream과 usleep()을 사용하여 이전에 데이터를 전송했지만 작동 중이었지만 임의의 수만큼 지연하는 것보다 나은 방법을 사용하고 싶습니다. .데이터를 보낼 때 직렬 포트가 데이터를 건너 뛰는 이유는 무엇입니까?

도움이나 도움을 주셔서 감사합니다.

내 아두 이노 코드

#include <Servo.h> 
typedef enum { NONE, GOT_V, GOT_H } states; 
states state = NONE; 
Servo pan; 
Servo tilt; 
int laser = 11; 
unsigned int currentValue; 

int v_pan = 0; 
int v_tilt = 0; 

void setup() 
{ 
    pan.attach(10); 
    tilt.attach(9); 

    Serial.begin(9600); 
    state = NONE; 
} 

void processVertical(const unsigned int value) 
{ 
    Serial.print("Vertical = "); 
    Serial.println(value); 
    int result = 1300 + (value - 90) * 2; 
    //Serial.println(result); 
    tilt.writeMicroseconds(result); 
} 

void processHorizontal(const unsigned int value) 
{ 
    Serial.print("Horizontal = "); 
    Serial.println(value); 
    int result = 1500 + (value - 180) * 1; 
    //Serial.println(result); 
    pan.writeMicroseconds(result); 
} 

void handlePreviousState() 
{ 
    switch(state) 
    { 
    case GOT_V: 
     processVertical(currentValue); 
     break; 
    case GOT_H: 
     processHorizontal(currentValue); 
     break; 
    } 
    currentValue = 0; 
} 

void processIncomingByte (const byte c) 
{ 
    if (isdigit(c)) 
    { 
    currentValue *=10; 
    currentValue += c - '0'; 
    } 
    else 
    { 
    handlePreviousState(); 

    switch (c) 
    { 
     case 'V': 
     state = GOT_V; 
     break; 
     case 'H': 
     state = GOT_H; 
     break; 
     default: 
     state = NONE; 
     break; 
    } 
    } 
} 

void loop() 
{ 
    if(Serial.available() > 0) 
    { 
    processIncomingByte(Serial.read()); 
    } 
    digitalWrite(laser, HIGH); 
} 

//check out writeMicroseconds 

내 C++ 코드 당신은 빨리 당신이 그것을 다시 읽을 수있는 것보다 데이터를 침되어있는 시리얼 장치와 그 장치 자체에 너무 빨리 데이터를 작성하는

// Program for sending data to serial 

#include <iostream> 
#include <sstream> 
#include <string> 
#include <termios.h> 
#include <fcntl.h> 
#include <math.h> 

using namespace std; 

//open serial port 
int openPort(string path) 
{ 
    int fd; //file descriptor for port 
    fd = open(path.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); 
    if (fd == -1) 
    cerr << "Cannot open port" << endl; 
    else 
    fcntl(fd, F_SETFL, 0); 
    return (fd); 
} 

//set options for an open serial port 
void setOptions(int fd) 
{ 
    struct termios options; 
    tcgetattr(fd, &options); 
    cfsetispeed(&options, B9600); 
    cfsetospeed(&options, B9600); 

    //No parity 8N1 
    options.c_cflag &= ~PARENB; 
    options.c_cflag &= ~CSTOPB; 
    options.c_cflag &= ~CSIZE; 
    options.c_cflag |= CS8; 

    //No flow control 
    options.c_cflag &= ~CRTSCTS; 

    //Turn off s/w flow control 
    options.c_iflag &= ~(IXON | IXOFF | IXANY); 

    //Turn on read and ignore ctrl lines 
    options.c_cflag |= (CLOCAL | CREAD); 

    if(tcsetattr(fd, TCSANOW, &options) < 0) { 
    cerr << "Could not set attributes" << endl; 
    } 
} 

//write to serial port 
void writePort(int fd, string data) 
{ 
    int n = write(fd, data.c_str(), 9); 
    if (n < 0) 
    cerr << "Cannot write to port" << endl; 
} 

int main() { 
    string path = "/dev/tty.usbmodemfd131"; 
    //string path = "/dev/tty.usbmodemfa141"; 
    int fd = openPort(path); 
    setOptions(fd); 

    stringstream ss; 
    string output; 
    unsigned short vertical = 0; 
    unsigned short horizontal = 0; 
    unsigned short freq = 10; 

    for(int i = 0; i < 360; i++) { 
    vertical = ((cos(i * freq * ((M_PI)/180))) + 1) * 90; 
    horizontal = ((sin(i * freq * ((M_PI)/180))) + 1) * 90; 
    ss << "V" << vertical << "H" << horizontal << endl; 
    output = ss.str(); 
    ss.str(""); 
    writePort(fd, output); 
// cout << output; //DEBUG 
    } 

    close(fd); 
    return 0; 
} 
+1

나쁜 농담처럼 들리는 군 ... * 직렬 포트가 데이터를 건너 뛴 이유는 무엇입니까? * – thang

+1

EOP (종결 자) 추가를 시도한 적이 있습니까? – KMC

+1

같은 컴퓨터의 터미널 프로그램에 "C++ 코드"(Linux라고 가정합니다)를 연결하면 어떻게됩니까? 그것을 확인하는 것으로 시작하십시오. 그런 다음 보낸 사람 또는받는 사람이 범인인지 여부를 결정할 수 있습니다. – Lundin

답변

2

새 모드를받은 직후에 이전 상태 (handlePreviousState)를 처리 할 때 장치 내부의 "processIncomingByte"루프가 속도 문제를 겪을 수 있습니다.

직렬을 수행하면 문제가 발생할 수 있습니다.값 데이터 바이트가 PC에서 계속해서 수신되는 동안 해당 기능으로 인쇄하십시오. 직렬 인쇄는 마이크로 컨트롤러 로직에서 비교적 느린 프로세스입니다.

저는 Arduino 하드웨어에 익숙하지 않지만 일부 저가형 마이크로 컨트롤러 보드는 비트 밴잉 방법을 사용하여 소프트웨어 직렬 인터페이스를 수행하므로 전송할 때 수신이 완전히 중지됩니다. 이것을 확인하기 위해 Serial.print를 언급하여 도움이되는지 확인할 수 있습니다.

어쨌든 FIFO 버퍼가 많은 장치에 하드웨어 직렬 인터페이스가 없다면 들어오는 데이터 스트림 중간에 오랜 처리를하는 것이 문제가됩니다.

이 문제의 적절한 방법은 전체 메시지를 버퍼 내에 먼저받은 다음 메시지 끝 표시를 수신 한 경우에만 처리하는 것입니다. 예를 들어 [V180H90]과 같이 [] 쌍 안에 메시지를 삽입하십시오. 버퍼를 "["로 재설정하고 "]"을받은 후에 버퍼를 처리하십시오. 버퍼로 바이트를 수집 할 때 버퍼 오버 플로우도 확인하십시오.

+0

이 도움을 주셔서 감사합니다. 더 나은 흐름 제어를 구현하려고합니다. Serial.print를 제거하고 모든 것이 제대로 작동했습니다. 데이터 건너 뛰기 없음. 왜 내 논리에 결함이 있는지 알 수 있습니다. 이것을 올바르게 구현하고 양방향 통신으로 재생할 수있는 간단한 프로그램을 만들겠습니다. 다시 한번 감사드립니다. – mightcouldb1

0

장치의 다른쪽에.

이 문제를 해결하는 올바른 방법은 직렬 장치에 쓰기 속도를 제한하여 데이터가 넘치지 않도록하는 것입니다.

1

포트의 목구멍에 데이터를 저장하면 화재가 발생하지 않도록 최선을 다하지만 초과 데이터는 전송되지 않습니다. 결국 포트는 유한 속도로 작동하며 매우 제한적이고 덤프 장치입니다.

포트에 문자를 보내기 전에 포트의 상태를 확인하여 실제로 다른 데이터 문자를 받아 들일 준비가되었는지 확인해야합니다. 일부 직렬 포트는 불필요한 상태 폴링을 피할 수 있도록 더 많은 데이터를 사용할 수있을 때 인터럽트를 생성 할 수도 있습니다.

두 장치의 직렬 포트 2 개를 비 데이터 신호 (RTSCTS) 쌍으로 연결하여 수신 측에서 더 많은 데이터를 수신 할 준비가되었는지 여부를 나타낼 수도 있습니다. 연결된 장치가 있고 장치가 준비 상태를 나타 내기 위해 장치를 사용하는 경우 프로그램은 장치의 CTS 상태도 고려해야합니다.

+0

CTS/RTS를 확인해야하는지 궁금하거나 termios.h에서 플래그를 설정하여 활성화 할 수 있습니다. – mightcouldb1

1

분명히 장치가 직렬 포트를 통해 데이터를 보내는 것보다 느리게 데이터를 읽고 처리합니다. 여기에 가능한 해결책이 몇 가지 있습니다.

1) 흐름 제어를 구현하고 직렬 포트를 통해 차단 모드로 데이터를 보냅니다. 전송 한 후에도 기다려야하지만 기기에서 데이터를 읽고 처리하는 데 필요한만큼만 기다려야합니다.

2) 양방향 통신을 구현하여 기기가 데이터를 수락 할 준비가되었음을 나타내는 확인 메시지 (즉, 단일 ASCII 기호)를 보냅니다.

3) 코드를 두 개의 병렬 부분으로 나눕니다. 즉, 주 루프 (또는 ISR)는 직렬 포트에서 데이터를 읽고 ring buffer에 저장하며 다른 루프는 링 버퍼를 폴링하고 곧바로 데이터를 처리합니다 사용할 수있는 데이터가 있으므로 이것은 두 개의 개별 스레드 (또는 스레드와 ISR)가 필요하고 동시 액세스에서 링 버퍼를 보호 할뿐만 아니라 가장 강력하고 유연한 세 가지 솔루션 중 가장 어려운 솔루션입니다.

+0

답장을 보내 주셔서 감사합니다. 나는 확실히 흐름 제어를 구현할 것이다. 양방향 의사 소통은 내가 손을 잡고 싶습니다. 지금은 간단한 예입니다. 링 버퍼에 관한 정보는 매우 유용하며 앞으로의 프로젝트를 위해 확실히 조사 할 것입니다. – mightcouldb1