4

Debian マシンに接続されている FTDI と接続したい新しいプロジェクトに取り組んでいます。C++ ではなく、C でコードを書くつもりです。ここに私の問題があります。私が見つけたすべての例は不完全であるか、GCC コンパイラではなく C++ コンパイラ用に作成されています。

目標は、FTDI に接続されているマイクロコントローラーと通信することです。デバッグのために、次のことができる Linux アプリケーションの構築を開始したいと考えています。

  • 起動時に ttyUSB1 でシリアル接続を初期化する
  • 文字列を送る
  • PCが受信した文字列を表示する
  • 通信を .txt ファイルに保存する

これを行うためのサンプルコードまたはチュートリアルはありますか?

成功したら、ここにコードを配置して、新しい視聴者が使用できるようにします。

編集:

私が言ったように、コードがあれば投稿しますが、これが私にとってうまくいきました:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>

#define MODEM "/dev/ttyUSB0"
#define BAUDRATE B115200    

int main(int argc,char** argv)
{   
    struct termios tio;
    struct termios stdio;
    struct termios old_stdio;
    int tty_fd, flags;
    unsigned char c='D';
    tcgetattr(STDOUT_FILENO,&old_stdio);
    printf("Please start with %s /dev/ttyS1 (for example)\n",argv[0]);
    memset(&stdio,0,sizeof(stdio));
    stdio.c_iflag=0;
    stdio.c_oflag=0;
    stdio.c_cflag=0;
    stdio.c_lflag=0;
    stdio.c_cc[VMIN]=1;
    stdio.c_cc[VTIME]=0;
    tcsetattr(STDOUT_FILENO,TCSANOW,&stdio);
    tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio);
    fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);       // make the reads non-blocking
    memset(&tio,0,sizeof(tio));
    tio.c_iflag=0;
    tio.c_oflag=0;
    tio.c_cflag=CS8|CREAD|CLOCAL;           // 8n1, see termios.h for more information
    tio.c_lflag=0;
    tio.c_cc[VMIN]=1;
    tio.c_cc[VTIME]=5;
    if((tty_fd = open(MODEM , O_RDWR | O_NONBLOCK)) == -1){
        printf("Error while opening\n"); // Just if you want user interface error control
        return -1;
    }
    cfsetospeed(&tio,BAUDRATE);    
    cfsetispeed(&tio,BAUDRATE);            // baudrate is declarated above
    tcsetattr(tty_fd,TCSANOW,&tio);
    while (c!='q'){
        if (read(tty_fd,&c,1)>0){
            write(STDOUT_FILENO,&c,1); // if new data is available on the serial port, print it out
            printf("\n");
        }
        if (read(STDIN_FILENO,&c,1)>0){
            write(tty_fd,&c,1);//if new data is available on the console, send it to serial port
            printf("\n");
        }
    }
    close(tty_fd);
    tcsetattr(STDOUT_FILENO,TCSANOW,&old_stdio);
    return EXIT_SUCCESS;
}

ほとんどのコードはhttp://en.wikibooks.org/wiki/Serial_Programming/Serial_Linuxからのものですが、以下に投稿されたコードも少し使用しました。

4

2 に答える 2

3

シリアル ポートの処理 (Linux OS の
場合) : - 通信を開くには、シリアル ポートのハンドルとなる記述子が必要です。
- フラグを設定して、通信方法を制御します。
- このハンドルにコマンドを書き込みます (入力を正しくフォーマットしていることを確認してください)。
- 答えを得る。(必要な量の情報を読んでいることを確認してください)
- ハンドルを閉じます。次のようになります。

int fd; // file descriptor
int flags; // communication flags
int rsl_len; // result size
char message[128]; // message to send, you can even dinamically alocate.
char result[128]; // result to read, same from above, thanks to @Lu

flags = O_RDWR | O_NOCTTY; // Read and write, and make the job control for portability
if ((fd = open("/dev/ttyUSB1", flags)) == -1 ) {
  printf("Error while opening\n"); // Just if you want user interface error control
  return -1;
}
// In this point your communication is already estabilished, lets send out something
strcpy(message, "Hello");
if (rsl_len = write(fd, message, strlen(message)) < 0 ) {
  printf("Error while sending message\n"); // Again just in case
  return -2;
}
if (rsl_len = read(fd, &result, sizeof(result)) < 0 ) {
  printf("Error while reading return\n");
  return -3;
}
close(fd);

何を書くか、何を読むかを気にしなければならないことに注意してください。パリティ制御、ストップビット、ボーレートなどの場合には、さらにいくつかのフラグを使用できます。

于 2013-10-17T14:12:31.647 に答える
0

gcc は C/C++ コンパイラであるため、純粋な C に限定する必要はありません。

ボイラープレート コードをたくさん書くのが好きで、自分が何をしているかを本当に理解しているのであれば、純粋な C に固執することは問題ありません。多くの人が Unix API を間違って使用しており、そこにある多くのサンプル コードは単純すぎます。控えめに言っても、正しい Unix C コードを書くのはやや面倒です。

個人的には、C++ だけでなく、Qt のような高レベルのアプリケーション開発フレームワークも使用することをお勧めします。Qt 5 にはQtSerialPortモジュールがバンドルされており、シリアル ポートの列挙、構成、データの入出力を簡単に行うことができます。Qt は gui モジュールの使用を強制しません。コマンド ライン アプリケーション、または非対話型のサーバー/デーモンを使用できます。

QtSerialPort は Qt 4 からも使用できますが、Qt 4 にはバンドルされていないため、プロジェクトに追加する必要があります。Qt 5 から始めることをお勧めします。C++11 をサポートしているほうが使いやすいです。

Qt を使用したコードは非常に単純で、平易な英語の説明よりも長くはありません。以下は、Qt 5 と C++11 を使用した Qt コンソール アプリケーションです。coreおよびserialportモジュールを使用します。また、シグナルが原因でプロセスが終了する前に出力ファイルがフラッシュされるように、シグナルを処理しSIGINT^Cます。QLocalSocketUnixシグナルハンドラーから通信するために生のUnix APIの代わりに使用していますが、機能は同じです。

内のコードのみmainが厳密に必要です。残りは、 を押したときに適切にまとめるだけです^C

#include <QCoreApplication>
#include <QSerialPort>
#include <QFile>
#include <QTextStream>
#include <QLocalServer>
#include <QLocalSocket>
#include <cstdio>
#include <csignal>

QLocalSocket * xmit;

static void signalHandler(int)
{
    xmit->write(" ");
    xmit->flush();
}

static bool setupSignalHandler()
{
    QLocalServer srv;
    srv.listen("foobarbaz");
    xmit = new QLocalSocket(qApp);
    xmit->connectToServer(srv.serverName(), QIODevice::WriteOnly);
    srv.waitForNewConnection();
    QLocalSocket * receive = srv.nextPendingConnection();
    receive->setParent(qApp);
    qApp->connect(receive, &QLocalSocket::readyRead, &QCoreApplication::quit);
    struct sigaction sig;
    sig.sa_handler = signalHandler;
    sigemptyset(&sig.sa_mask);
    sig.sa_flags = SA_RESTART;
    return ! sigaction(SIGINT, &sig, NULL);
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    setupSignalHandler();

    QSerialPort port("ttyUSB1");
    QFile file("file.txt");
    QTextStream err(stderr, QIODevice::WriteOnly);
    QTextStream out(stdout, QIODevice::WriteOnly);
    if (!file.open(QIODevice::WriteOnly)) {
        err << "Couldn't open the output file" << endl;
        return 1;
    }
    if (!port.open(QIODevice::ReadWrite)) {
        err << "Couldn't open the port" << endl;
        return 2;
    }
    port.setBaudRate(9600);
    QObject::connect(&port, &QSerialPort::readyRead, [&](){
        QByteArray data = port.readAll();
        out << data;
        file.write(data);
    });
    out << "Use ^C to quit" << endl;
    return a.exec();
}
于 2013-10-17T21:29:48.307 に答える