2013-10-17 44 views
4

我正在一個新的項目,我想與連接到我的debian機器的FTDI連接。我打算用C編寫代碼,而不是C++。這是我的問題。我找到的所有例子都不完整,或者是用C++編譯器代替GCC編譯器。初始化,讀取和寫入linux的串行設備與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但我也來了從下面的代碼中使用了一下。

+1

甚至有一個[很好的howto致力於該主題](http://tldp.org/HOWTO/Serial-Programming-HOWTO/)。 – fvu

+2

你檢查這個問題http://stackoverflow.com/questions/2982552/correct-initialization-sequence-for-linux-serial-port?rq=1 – 999k

+0

這有什麼錯小型機? – KBart

回答

3

使用串口處理(適用於linux操作系統):
- 要打開通信,您需要一個描述符,它將成爲串口的句柄。
- 設置標誌來控制通信的方式。
- 將命令寫入此句柄(確保您正確地格式化輸入)。
- 獲得答案。 (確保你要讀取你想要的信息量)
- 關閉手柄。 它會看起來像這樣:

int fd; // file descriptor 
int flags; // communication flags 
int rsl_len; // result size 
char message; // message to send 
char result; // result to read 

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); 

請注意,你必須關心什麼就寫什麼閱讀。 一些更多的標誌可用於奇偶校驗控制,停止位,波特率等。

+0

當然,這段代碼不處理'E_INTR',不使用'O_CLOEXEC'打開文件句柄,不處理信號...這不是你想要告訴的方式一個新手編寫好的Unix代碼。一旦你得到了這個好的Unix代碼的地方,它會花很長時間,但它有一個問題,它是否值得在純C中進行更長時間而不會失去理智...... –

+0

@KubaOber在在另一方面,人們可以說Qt是如此之大,並且包含了它所做的一切,甚至存在一個值得使用的問題。我已經看到Qt引入了一些項目的依賴關係,這些項目只用於很小的一部分功能(例如:基本的數據結構,這些結構使用STL更加明智地實現),基本上你付出的代價是膨脹的。我認爲以這種方式堅持自己的理智更容易......它從頭開始製造你的車,而不是由製造商擺好替換零件 –

+0

我可能選擇了一個可怕的比喻,因爲沒有特別的資源,汽車你最終會不適合使用。但是,POSIX的挑戰性要小一些,主要是因爲它有很好的文檔記錄。 –

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控制檯應用程序。它使用coreserialport模塊。它也handles the SIGINT signal,以便輸出文件在該過程將由於^C而終止之前被刷新。我使用QLocalSocket代替原始Unix API從Unix信號處理程序進行通信,功能相同。

只有在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(); 
} 
+0

聽起來很有希望,但是如何將Qt庫添加到GCC?我剛剛安裝了QT5,但編譯時仍然出現「gcc -o qtSerial qtSerial.cpp qtSerial.cpp:1:28:致命錯誤:QCoreApplication:沒有這樣的文件或目錄」。 – Embed

+0

那麼,你不能手動去做,不知道發生了什麼。使用QT創建器創建一個項目,將文件添加到項目中,將'serialport'模塊添加到.pro文件('QT + = serialport'),它應該可以工作。 –

+0

我會投你的答案,如果我有15名聲譽 – Embed

相關問題