功能:

  1. 调试建议按ASCII字符格式进行收发;
  2. 点击”Receive”按钮之后,等待接收到的字符数据,如果接收到字符数据则显示;
  3. 简单了解如何使用 termios 结构体和相关函数完成串口的初始化等操作;
  4. 关于 termios 结构体更多内容,可以参考:
    https://www.softool.cn/blog-159.html
    https://www.softool.cn/blog-158.html
    https://www.softool.cn/blog-157.html

效果:

源码:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <gtk/gtk.h>

int serial_fd;
int init_serial();

void closeApp (GtkWidget *window, gpointer data) {
    gtk_main_quit();
}

void send_button_clicked (GtkWidget *button, gpointer data) {
    char buf[512];
    const char *send_text = gtk_entry_get_text(GTK_ENTRY((GtkWidget *) data));
    memset(buf, '\0', sizeof(buf)/sizeof(buf));
    strcpy(buf,send_text);
    int len = strlen(buf);
    int send_number = write (serial_fd, buf, len);
}

void receive_button_clicked (GtkWidget *button, gpointer data) {
    char buffer[512];
    int read_number;

    memset(buffer,'\0',sizeof(buffer)/sizeof(char));

    //如果从串口读取到数据,最大一次性读取512B:
    if  ( (read_number = read(serial_fd, buffer, 512))>0 ) {
        gtk_entry_set_text(GTK_ENTRY((GtkWidget *)data), buffer);
        memset(buffer,'\0',sizeof(buffer)/sizeof(char));
    }
}

int main (int argc, char *argv[]) {

    init_serial();

    gtk_init(&argc, &argv);
    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "www.softool.cn - 串口收发");
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
    gtk_signal_connect ( GTK_OBJECT (window), "destroy",
                          GTK_SIGNAL_FUNC ( closeApp), NULL);
    GtkWidget *send_label = gtk_label_new("send:");
    GtkWidget *receive_label = gtk_label_new("receive:");
    GtkWidget *send_entry = gtk_entry_new();
    GtkWidget *receive_entry = gtk_entry_new();
    GtkWidget *send_button = gtk_button_new_with_label("Send");
    GtkWidget *receive_button = gtk_button_new_with_label("Receive");
    gtk_signal_connect (GTK_OBJECT (send_button), "clicked",
                         GTK_SIGNAL_FUNC(send_button_clicked), send_entry);
    gtk_signal_connect (GTK_OBJECT (receive_button), "clicked",
                         GTK_SIGNAL_FUNC(receive_button_clicked),
                            receive_entry
                            );
    GtkWidget *hbox1 = gtk_hbox_new ( TRUE, 5 );
    GtkWidget *hbox2 = gtk_hbox_new ( TRUE, 5 );
    GtkWidget *hbox3 = gtk_hbox_new ( TRUE, 5 );
    GtkWidget *vbox = gtk_vbox_new ( FALSE, 10);
    gtk_box_pack_start(GTK_BOX(hbox1), send_label, TRUE, FALSE, 5);
    gtk_box_pack_start(GTK_BOX(hbox1), send_entry, TRUE, FALSE, 5);
    gtk_box_pack_start(GTK_BOX(hbox2), receive_label, TRUE, FALSE, 5);
    gtk_box_pack_start(GTK_BOX(hbox2), receive_entry, TRUE, FALSE, 5);
    gtk_box_pack_start(GTK_BOX(hbox3), send_button, TRUE, FALSE, 5);
    gtk_box_pack_start(GTK_BOX(hbox3), receive_button, TRUE, FALSE, 5);
    gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 5);
    gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 5);
    gtk_box_pack_start(GTK_BOX(vbox), hbox3, FALSE, FALSE, 5);
    gtk_container_add(GTK_CONTAINER(window), vbox);
    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}

int OpenDev(char *Dev) {

    int fd = open( Dev, O_RDWR );
    //如果打开失败:
    if (-1 == fd) {
        perror("Can't Open Serial Port");
        return -1;
    }
    else
    {
        return fd;
    }
}

void set_speed(int fd, int speed);
int init_serial() {
    int nread;
    //此处需要根据自己的串口设备修改,我的是串口2,所以 ttyS1。
    char *dev  = "/dev/ttyS1";
    serial_fd = OpenDev(dev);
    //设置波特率为 9600
    set_speed(serial_fd,9600);
    //设置8位数据位、1位停止位、无校验
    if (set_Parity(serial_fd, 8, 1, 'N') == FALSE) {
        printf("Set Parity Error\n");
        exit (0);
    }
    return 0;
}

int speed_arr[] = {
    B38400, B19200, B9600, B4800, B2400, B1200, B300,
    B38400, B19200, B9600, B4800, B2400, B1200, B300,
};
int name_arr[] = {
    38400,  19200, 9600,  4800,  2400,  1200,  300, 38400,
    19200,  9600, 4800, 2400, 1200,  300,
};
void set_speed(int fd, int speed) {
    int   i;
    int   status;
    struct termios   Opt;

    tcgetattr(fd, &Opt);

    for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++) {
        if  (speed == name_arr[i]) {
            tcflush(fd, TCIOFLUSH);
            cfsetispeed(&Opt, speed_arr[i]);
            cfsetospeed(&Opt, speed_arr[i]);
            status = tcsetattr(fd, TCSANOW, &Opt);
            if  (status != 0) {
                perror("tcsetattr fd");
                return;
            }
            tcflush(fd,TCIOFLUSH);
        }
    }
}
int set_Parity(int fd, int databits,int stopbits,int parity) {
    struct termios options;
    if  ( tcgetattr( fd,&options)  !=  0) {
        perror("SetupSerial 1");
        return(FALSE);
    }
    options.c_cflag &= ~CSIZE;
    switch (databits) {
        case 7:
            options.c_cflag |= CS7;
        break;
        case 8:
            options.c_cflag |= CS8;
        break;
        default:
            fprintf(stderr,"Unsupported data size\n");
        return (FALSE);
    }
    switch (parity) {
        //无校验
        case 'n':
        case 'N':
            options.c_cflag &= ~PARENB;
            options.c_iflag &= ~INPCK;
        break;
        //奇校验 (odd parity)
        case 'o':  
        case 'O':
            //PARODD 奇校验
            options.c_cflag |= (PARODD | PARENB);
            options.c_iflag |= INPCK;
        break;
        //偶校验 (even parity)
        case 'e':
        case 'E':
            options.c_cflag |= PARENB;
            options.c_cflag &= ~PARODD;
            options.c_iflag |= INPCK;
        break;
        case 's':
        case 'S':
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~CSTOPB;
        break;
        default:  
               fprintf(stderr,"Unsupported parity\n");
        return (FALSE);
    }
    if (parity != 'n')  
        options.c_iflag |= INPCK;

    switch (stopbits) {
        case 1:
            options.c_cflag &= ~CSTOPB;
        break;
        case 2:
            //CSTOPB: 每个字符使用两停止位
            options.c_cflag |= CSTOPB;
        break;
        default:
            fprintf(stderr,"Unsupported stop bits\n");
        return (FALSE);
    }

    tcflush(fd,TCIFLUSH);

    options.c_cc[VTIME] = 100;
    options.c_cc[VMIN] = 0;

    //SofTool.CN Note:
    //    如果在测试中发现:点击 Receive 按钮之后,没有响应。可以尝试把下面一行注释打开。
    //    因为我调试的发现通过另外一端串口发送的时候,发送数据后自动接收了,所以考虑可能是开了回显等功能。
    //options.c_lflag = 0;

    if (tcsetattr(fd, TCSANOW, &options) != 0) {
        perror("SetupSerial 3");
        return (FALSE);
    }
    return (TRUE);
}

作者:蟲蟲
http://blog.sina.com.cn/s/blog_6f1e688e0100mgkc.html