Chinaunix首页 | 论坛 | 博客
  • 博客访问: 435531
  • 博文数量: 117
  • 博客积分: 3003
  • 博客等级: 中校
  • 技术积分: 1221
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-16 14:11
文章分类

全部博文(117)

文章存档

2011年(7)

2010年(110)

我的朋友

分类: LINUX

2010-08-31 13:11:13

Linux串口测试程序

冷胜魁(Seaquester)
lengshengkui@gmail.com
2009-11-18

这 是以前在做一个基于ARM的项目的时候,写的一个简单串口测试程序,同样也适用于X86平台16C550串口。程序很简单,运行是通过参数指定程序是发送 端还是接收端。接收端运行之后就简单的读取串口数据,打印到stdout。发送端则接受键盘输入,通过串口发送出去。如果直接回车则表示发送完毕,通知接 收端退出。

/******************************************************************************
 *
 * FILENAME:
 * testcom.c
 *
 * DESCRIPTION:
 * A utility to read/write serial port
 * Usage: testcom
 * databits: 5, 6, 7, 8
 * parity: 0(None), 1(Odd), 2(Even)
 * stopbits: 1, 2
 * read_or_write: 0(read), 1(write)
 * Example: testcom /dev/ttyS0 9600 8 0 1 0
 *
 * REVISION(MM/DD/YYYY):
 * 03/12/2008 Shengkui Leng (shengkui.leng@advantech.com.cn)
 * - Initial version
 *
 ******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <termio.h>
#include <time.h>


#define MAX_BUF_SIZE 2048
char buf[MAX_BUF_SIZE+2];

#define MY_END_CHAR 0x13


int setup_port(int fd, int baud, int databits, int parity, int stopbits);
int reset_port(int fd);
int read_data(int fd, void *buf, int len);
int write_data(int fd, void *buf, int len);
void print_usage(char *program_name);


int main(int argc, char *argv[])
{
    int fd;
    int baud;
    int len;
    int count;
    int i;
    int databits;
    int stopbits;
    int parity;
    int read_or_write;


    if (argc != 7) {
        print_usage(argv[0]);
        return 1;
    }

    baud = atoi(argv[2]);
    if ((baud < 0) || (baud > 921600)) {
        fprintf(stderr, "Invalid baudrate!\n");
        return 1;
    }

    databits = atoi(argv[3]);
    if ((databits < 5) || (databits > 8)) {
        fprintf(stderr, "Invalid databits!\n");
        return 1;
    }

    parity = atoi(argv[4]);
    if ((parity < 0) || (parity > 2)) {
        fprintf(stderr, "Invalid parity!\n");
        return 1;
    }

    stopbits = atoi(argv[5]);
    if ((stopbits < 1) || (stopbits > 2)) {
        fprintf(stderr, "Invalid stopbits!\n");
        return 1;
    }

    read_or_write = atoi(argv[6]);

    fd = open(argv[1], O_RDWR, 0);
    if (fd < 0) {
        fprintf(stderr, "open <%s> error %s\n", argv[1], strerror(errno));
        return 1;
    }

    if (setup_port(fd, baud, databits, parity, stopbits)) {
        fprintf(stderr, "setup_port error %s\n", strerror(errno));
        close(fd);
        return 1;
    }

    count = 0;

    if (read_or_write) {
        fprintf(stderr, "Begin to send:\n");

        while ( (len = read(0, buf, MAX_BUF_SIZE)) > 0 ) {
            if (len == 1) {
                buf[0] = MY_END_CHAR;
                buf[1] = 0;
                write_data(fd, buf, len);
                break;
            }

            /* send a pack */
            i = write_data(fd, buf, len);
            if (i == 0) {
                fprintf(stderr, "Send data error!\n");
                break;
            }

            //count += len;

            //fprintf(stderr, "Send %d bytes\n", len);

        }

    } else {

        fprintf(stderr, "Begin to recv:\n");

        len = MAX_BUF_SIZE;

        while (1) {
            /* read a pack */
            i = read_data(fd, buf, len);
            if (i > 0) {
                //count += i;

                //fprintf(stderr, "Recv %d byte\n", i);

                printf("%s", buf);
                if (buf[i-1] == MY_END_CHAR) {
                    break;
                }
            }
        }
    }

    reset_port(fd);
    close(fd);

    return 0;
}


static int baudflag_arr[] = {
    B921600, B460800, B230400, B115200, B57600, B38400,
    B19200, B9600, B4800, B2400, B1800, B1200,
    B600, B300, B150, B110, B75, B50
};
static int speed_arr[] = {
    921600, 460800, 230400, 115200, 57600, 38400,
    19200, 9600, 4800, 2400, 1800, 1200,
    600, 300, 150, 110, 75, 50
};


/******************************************************************************
 * NAME:
 * speed_to_flag
 *
 * DESCRIPTION:
 * Translate baudrate into flag
 *
 * PARAMETERS:
 * speed - The baudrate to convert
 *
 * RETURN:
 * The flag
 ******************************************************************************/

int speed_to_flag(int speed)
{
    int i;

    for (i = 0; i < sizeof(speed_arr)/sizeof(int); i++) {
        if (speed == speed_arr[i]) {
            return baudflag_arr[i];
        }
    }

    fprintf(stderr, "Unsupported baudrate, use 9600 instead!\n");
    return B9600;
}


static struct termio oterm_attr;

/******************************************************************************
 * NAME:
 * stup_port
 *
 * DESCRIPTION:
 * Set serial port (include baudrate, line control)
 *
 * PARAMETERS:
 * fd - The fd of serial port to setup
 * baud - Baudrate: 9600, ...
 * databits - Databits: 5, 6, 7, 8
 * parity - Parity: 0(None), 1(Odd), 2(Even)
 * stopbits - Stopbits: 1, 2
 *
 * RETURN:
 * 0 for OK; Others for ERROR
 ******************************************************************************/

int setup_port(int fd, int baud, int databits, int parity, int stopbits)
{
    struct termio term_attr;

    /* Get current setting */
    if (ioctl(fd, TCGETA, &term_attr) < 0) {
        return -1;
    }

    /* Backup old setting */
    memcpy(&oterm_attr, &term_attr, sizeof(struct termio));

    term_attr.c_iflag &= ~(INLCR | IGNCR | ICRNL | ISTRIP);
    term_attr.c_oflag &= ~(OPOST | ONLCR | OCRNL);
    term_attr.c_lflag &= ~(ISIG | ECHO | ICANON | NOFLSH);
    term_attr.c_cflag &= ~CBAUD;
    term_attr.c_cflag |= CREAD | speed_to_flag(baud);

    /* Set databits */
    term_attr.c_cflag &= ~(CSIZE);
    switch (databits) {
        case 5:
            term_attr.c_cflag |= CS5;
            break;

        case 6:
            term_attr.c_cflag |= CS6;
            break;

        case 7:
            term_attr.c_cflag |= CS7;
            break;

        case 8:
        default:
            term_attr.c_cflag |= CS8;
            break;
    }

    /* Set parity */
    switch (parity) {
        case 1: /* Odd parity */
            term_attr.c_cflag |= (PARENB | PARODD);
            break;

        case 2: /* Even parity */
            term_attr.c_cflag |= PARENB;
            term_attr.c_cflag &= ~(PARODD);
            break;

        case 0: /* None parity */
        default:
            term_attr.c_cflag &= ~(PARENB);
            break;
    }


    /* Set stopbits */
    switch (stopbits) {
        case 2: /* 2 stopbits */
            term_attr.c_cflag |= CSTOPB;
            break;

        case 1: /* 1 stopbits */
        default:
            term_attr.c_cflag &= ~CSTOPB;
            break;
    }

    term_attr.c_cc[VMIN] = 1;
    term_attr.c_cc[VTIME] = 0;

    if (ioctl(fd, TCSETAW, &term_attr) < 0) {
        return -1;
    }

    if (ioctl(fd, TCFLSH, 2) < 0) {
        return -1;
    }

    return 0;
}


/******************************************************************************
 * NAME:
 * read_data
 *
 * DESCRIPTION:
 * Read data from serial port
 *
 *
 * PARAMETERS:
 * fd - The fd of serial port to read
 * buf - The buffer to keep readed data
 * len - The max count to read
 *
 * RETURN:
 * Count of readed data
 ******************************************************************************/

int read_data(int fd, void *buf, int len)
{
    int count;
    int ret;

    ret = 0;
    count = 0;

    //while (len > 0) {


    ret = read(fd, (char*)buf + count, len);
    if (ret < 1) {
        fprintf(stderr, "Read error %s\n", strerror(errno));
        //break;

    }

    count += ret;
    len = len - ret;

    //}


    *((char*)buf + count) = 0;
    return count;
}


/******************************************************************************
 * NAME:
 * write_data
 *
 * DESCRIPTION:
 * Write data to serial port
 *
 *
 * PARAMETERS:
 * fd - The fd of serial port to write
 * buf - The buffer to keep data
 * len - The count of data
 *
 * RETURN:
 * Count of data wrote
 ******************************************************************************/

int write_data(int fd, void *buf, int len)
{
    int count;
    int ret;

    ret = 0;
    count = 0;

    while (len > 0) {

        ret = write(fd, (char*)buf + count, len);
        if (ret < 1) {
            fprintf(stderr, "Write error %s\n", strerror(errno));
            break;
        }

        count += ret;
        len = len - ret;
    }

    return count;
}


/******************************************************************************
 * NAME:
 * print_usage
 *
 * DESCRIPTION:
 * print usage info
 *
 * PARAMETERS:
 * program_name - The name of the program
 *
 * RETURN:
 * None
 ******************************************************************************/

void print_usage(char *program_name)
{
    fprintf(stderr,
            "*************************************\n"
            " A Simple Serial Port Test Utility\n"
            "*************************************\n\n"
            "Usage:\n %s \n"
            " databits: 5, 6, 7, 8\n"
            " parity: 0(None), 1(Odd), 2(Even)\n"
            " stopbits: 1, 2\n"
            " read_or_write: 0(read), 1(write)\n"
            "Example:\n %s /dev/ttyS0 9600 8 0 1 0\n\n",
            program_name, program_name
           );
}


/******************************************************************************
 * NAME:
 * reset_port
 *
 * DESCRIPTION:
 * Restore original setting of serial port
 *
 * PARAMETERS:
 * fd - The fd of the serial port
 *
 * RETURN:
 * 0 for OK; Others for ERROR
 ******************************************************************************/

int reset_port(int fd)
{
    if (ioctl(fd, TCSETAW, &oterm_attr) < 0) {
        return -1;
    }

    return 0;
}

阅读(2536) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

yypotato19852012-03-02 21:13:57

嗯,很不错
你好,我想请教下
我写了个linux串口收发程序,在宿主机上,linux与windows之间都可以互相进行收发。但是把程序交叉编译到了ARM开发板上,就不对了。。。首先不能收,ARM开发板发送数据到宿主机,也是错误数据,这个是为什么啊?