linux串口读写程序

 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
 
#include <getopt.h>             /* getopt_long() */
#include <errno.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
 
/**
 * @}
 */
 
static void errno_exit(const char *s)
{
        fprintf(stderr, "%s error %d, %s\\n", s, errno, strerror(errno));
        exit(EXIT_FAILURE);
}
 
/**
 * \brief 打开串口设备
 *
 * \param[in] p_path:设备路径
 *
 * \retval 成功返回文件描述符,失败返回-1
 */
int uart_open(const char *p_path)
{
    /* O_NOCTTY:阻止操作系统将打开的文件指定为进程的控制终端,如果没有指定这个标
                 志,那么任何一个输入都将会影响用户的进程。 */
    /* O_NONBLOCK:使I/O变成非阻塞模式,调用read如果没有接收到数据则立马返回-1,
            并且设置errno为EAGAIN。*/
    /* O_NDELAY: 与O_NONBLOCK完全相同 */
    return open(p_path, O_RDWR | O_NOCTTY);
}
 
/**
 * \brief 测试函数,打印struct termios各成员值
 */
static void __print_termios(struct termios *p_termios)
{
    printf("c_iflag = %#010x\n", p_termios->c_iflag);
    printf("c_oflag = %#010x\n", p_termios->c_oflag);
    printf("c_cflag = %#010x\n", p_termios->c_cflag);
    printf("c_lflag = %#010x\n\n", p_termios->c_lflag);
}
 
/**
 * \brief 设置串口属性
 *
 * \param[in] fd:打开的串口设备的文件描述符
 * \param[in] baudrate:波特率
 *            #{0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800,
 *              2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400}
 * \param[in] bits:数据位
 *            #{5, 6, 7, 8}
 * \param[in] parity:校验
 *            #'n'/'N':无校验
 *            #'o'/'O':奇校验
 *            #'e','E':偶校验
 * \param[in] stop:停止位
 *            #1:1个停止位
 *            #2:2个停止位
 * \param[in] flow:流控
 *            #'n'/'N':不使用流控
 *            #'h'/'H':使用硬件流控
 *            #'s'/'S':使用软件流控
 *
 * \retval 成功返回0,失败返回-1,并打印失败原因
 *
 * \note 虽然波特率设置支持这么多值,但并不代表输入表中支持的值波特率就
 *       一定能设置成功。
 */
int uart_set(int fd, int baudrate, int bits, char parity, int stop, char flow)
{
    struct termios termios_uart;
    int ret = 0;
    speed_t uart_speed = 0;
 
    /* 获取串口属性 */
    memset(&termios_uart, 0, sizeof(termios_uart));
    ret = tcgetattr(fd, &termios_uart);
    if (ret == -1) {
        printf("tcgetattr failed\n");
        return -1;
    }
 
    //__print_termios(&termios_uart);
 
    /* 设置波特率 */
    switch (baudrate) {
        case 0:      uart_speed = B0;      break;
        case 50:     uart_speed = B50;     break;
        case 75:     uart_speed = B75;     break;
        case 110:    uart_speed = B110;    break;
        case 134:    uart_speed = B134;    break;
        case 150:    uart_speed = B150;    break;
        case 200:    uart_speed = B200;    break;
        case 300:    uart_speed = B300;    break;
        case 600:    uart_speed = B600;    break;
        case 1200:   uart_speed = B1200;   break;
        case 1800:   uart_speed = B1800;   break;
        case 2400:   uart_speed = B2400;   break;
        case 4800:   uart_speed = B4800;   break;
        case 9600:   uart_speed = B9600;   break;
        case 19200:  uart_speed = B19200;  break;
        case 38400:  uart_speed = B38400;  break;
        case 57600:  uart_speed = B57600;  break;
        case 115200: uart_speed = B115200; break;
        case 230400: uart_speed = B230400; break;
        case 460800: uart_speed = B460800; break;
        case 500000: uart_speed = B500000; break;
        case 921600: uart_speed = B921600; break;
        default: printf("Baud rate not supported\n"); return -1;
    }
    cfsetspeed(&termios_uart, uart_speed);
 
    /* 设置数据位 */
    switch (bits) {
        case 5:     /* 数据位5 */
            termios_uart.c_cflag &= ~CSIZE;
            termios_uart.c_cflag |= CS5;
        break;
 
        case 6:     /* 数据位6 */
            termios_uart.c_cflag &= ~CSIZE;
            termios_uart.c_cflag |= CS6;
        break;
 
        case 7:     /* 数据位7 */
            termios_uart.c_cflag &= ~CSIZE;
            termios_uart.c_cflag |= CS7;
        break;
 
        case 8:     /* 数据位8 */
            termios_uart.c_cflag &= ~CSIZE;
            termios_uart.c_cflag |= CS8;
        break;
 
        default:
            printf("Data bits not supported\n");
            return -1;
    }
 
    /* 设置校验位 */
    switch (parity) {
        case 'n':   /* 无校验 */
        case 'N':
            termios_uart.c_cflag &= ~PARENB;
            termios_uart.c_iflag &= ~INPCK;        /* 禁能输入奇偶校验 */
        break;
 
        case 'o':   /* 奇校验 */
        case 'O':
            termios_uart.c_cflag |= PARENB;
            termios_uart.c_cflag |= PARODD;
            termios_uart.c_iflag |= INPCK;        /* 使能输入奇偶校验 */
            termios_uart.c_iflag |= ISTRIP;        /* 除去第八个位(奇偶校验位) */
        break;
 
        case 'e':   /* 偶校验 */
        case 'E':
            termios_uart.c_cflag |= PARENB;
            termios_uart.c_cflag &= ~PARODD;
            termios_uart.c_iflag |= INPCK;        /* 使能输入奇偶校验 */
            termios_uart.c_iflag |= ISTRIP;        /* 除去第八个位(奇偶校验位) */
        break;
 
        default:
            printf("Parity not supported\n");
            return -1;
    }
 
    /* 设置停止位 */
    switch (stop) {
        case 1: termios_uart.c_cflag &= ~CSTOPB; break; /* 1个停止位 */
        case 2: termios_uart.c_cflag |= CSTOPB;  break; /* 2个停止位 */
        default: printf("Stop bits not supported\n");
    }
 
    /* 设置流控 */
    switch (flow) {
        case 'n':
        case 'N':   /* 无流控 */
            termios_uart.c_cflag &= ~CRTSCTS;
            termios_uart.c_iflag &= ~(IXON | IXOFF | IXANY);
        break;
 
        case 'h':
        case 'H':   /* 硬件流控 */
            termios_uart.c_cflag |= CRTSCTS;
            termios_uart.c_iflag &= ~(IXON | IXOFF | IXANY);
        break;
 
        case 's':
        case 'S':   /* 软件流控 */
            termios_uart.c_cflag &= ~CRTSCTS;
            termios_uart.c_iflag |= (IXON | IXOFF | IXANY);
        break;
 
        default:
            printf("Flow control parameter error\n");
            return -1;
    }
 
    /* 其他设置 */
    termios_uart.c_cflag |= CLOCAL;    /* 忽略modem(调制解调器)控制线 */
    termios_uart.c_cflag |= CREAD;    /* 使能接收 */
 
    /* 禁能执行定义(implementation-defined)输出处理,意思就是输出的某些特殊数
       据会作特殊处理,如果禁能的话那么就按原始数据输出 */
    termios_uart.c_oflag &= ~OPOST;
 
    /**
     *  设置本地模式位原始模式
     *  ICANON:规范输入模式,如果设置了那么退格等特殊字符会产生实际动作
     *  ECHO:则将输入字符回送到终端设备
     *  ECHOE:如果ICANON也设置了,那么收到ERASE字符后会从显示字符中擦除一个字符
     *         通俗点理解就是收到退格键后显示内容会往回删一个字符
     *  ISIG:使终端产生的信号起作用。(比如按ctrl+c可以使程序退出)
     */
    termios_uart.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
 
    /**
     * 设置等待时间和最小接收字符
     * 这两个值只有在阻塞模式下有意义,也就是说open的时候不能传入O_NONBLOCK,
     * 如果经过了c_cc[VTIME]这么长时间,缓冲区内有数据,但是还没达到c_cc[VMIN]个
     * 数据,read也会返回。而如果当缓冲区内有了c_cc[VMIN]个数据时,无论等待时间
     * 是否到了c_cc[VTIME],read都会返回,但返回值可能比c_cc[VMIN]还大。如果将
     * c_cc[VMIN]的值设置为0,那么当经过c_cc[VTIME]时间后read也会返回,返回值
     * 为0。如果将c_cc[VTIME]和c_cc[VMIN]都设置为0,那么程序运行的效果与设置
     * O_NONBLOCK类似,不同的是如果设置了O_NONBLOCK,那么在没有数据时read返回-1,
     * 而如果没有设置O_NONBLOCK,那么在没有数据时read返回的是0。
     */
    termios_uart.c_cc[VTIME] = 1;   /* 设置等待时间,单位1/10秒 */
    termios_uart.c_cc[VMIN]  = 1;    /* 最少读取一个字符 */
 
    tcflush(fd, TCIFLUSH);          /* 清空读缓冲区 */
 
    /* 写入配置 */
    ret = tcsetattr(fd, TCSANOW, &termios_uart);
    if (ret == -1) {
        printf("tcsetattr failed\n");
    }
 
    return ret;
}
 
char* dev_name = "/dev/ttyUSB0";
int baudrate = 115200;
int flow_ctrl_flag = 0;
int show_hex_flag = 1;
 
static void usage(FILE *fp, int argc, const char **argv)
{
    fprintf(fp,
             "Usage: %s [options]\n"
             "default device name: /dev/ttyUSB0\n"
             "default baud rate: 115200\n"
             "default show: hex format\n"
             "default flow ctrl: no\n"
             "Options:\n"
             "-d | --device        uart device name [%s]\n"
             "-h | --help          Print this messagen\n"
             "-b | --baudrate      set baudrate %d\n"
             "-s | --string        format string show\n"
             "-f | --flow_ctrl     add hardware flow ctrl\n"
             "",
             argv[0], dev_name, baudrate);
}
 
static const struct option
long_options[] = {
        { "help",      no_argument,           NULL, 'h' },
        { "device",    required_argument,     NULL, 'd' },
        { "baudrate",  required_argument,     NULL, 'b' },
        { "string",    no_argument,           NULL, 's' },
        { "flow_ctrl", no_argument,           NULL, 'f' },
        { 0, 0, 0, 0 }
};
 
static const char short_options[] = "hd:b:sf";
// 参数解析
void option_par(int argc, const char **argv)
{
    for (;;) {
            int idx;
            int c;
 
            c = getopt_long(argc, argv,
                            short_options, long_options, &idx);
 
            if (-1 == c)
                    break;
 
            switch (c) {
            case 0: /* getopt_long() flag */
                    break;
 
            case 'd':
                    dev_name = optarg;
                    break;
 
            case 'h':
                    usage(stdout, argc, argv);
                    exit(EXIT_SUCCESS);
 
            case 's':
                    show_hex_flag = 0;
                    printf("format string\r\n");
                    break;
 
            case 'f':
                    flow_ctrl_flag = 1;
                    printf("add hardware flow ctrl\r\n");
                    break;
 
            case 'b':
                    errno = 0;
                    baudrate = strtol(optarg, NULL, 0);
                    printf("set baud rate is : %d\r\n", baudrate);
                    if (errno)
                            errno_exit(optarg);
                    break;
 
            default:
                    usage(stderr, argc, argv);
                    exit(EXIT_FAILURE);
            }
    }
}
 
/**
 * \test
 * @{
 */
int main(int argc, const char *argv[])
{
    int fd = 0;
    int ret = 0;
    int pid = 0;
    char buf[4096] = { 0 };
    int len = 0;
    int i = 0;
 
    option_par(argc, argv);
 
    /* 打开串口设备 */
    fd = uart_open(dev_name);
    if (fd < 0) {
        printf("open %s failed\n", dev_name);
        return 0;
    }
 
    /**
     * 配置串口:
     * 波特率:baudrate
     * 数据位:8
     * 校验  :无校验
     * 停止位:1
     * 流控  :
     */
    ret = uart_set(fd, baudrate, 8, 'n', 1, flow_ctrl_flag ? 'h' : 'n');
    if (ret == -1) {
        return 0;
    }
	
	printf("%s baudrate=%d, flow_ctrl_flag=%d\n", dev_name, baudrate, flow_ctrl_flag);
 
    pid = fork();
    if (pid > 0) {          /* 读数据 */
        while (1) {
            memset(buf, 0, sizeof(buf));
            len = read(fd, buf, sizeof(buf));
            if (len > 0) {
                printf("len: %d\n", len);
                printf("data: ");
                if (show_hex_flag) {
                    for (i = 0; i < len; i++) {
                        printf("%02x ", buf[i]);
                    }
                    printf("\r\n");
                } else {
                    printf("%s\r\n", buf);
                }
            } else {
       //         printf("len = %d\n", len);
            }
        }
    } else if (pid == 0) {  /* 写数据 */
        printf("please input string\r\n");
        while (1) {
            scanf("%s", buf);
            write(fd, buf, strlen(buf));
        }
    } else {
        printf("fork failed\n");
    }
    return 0;
}
 
/**
 * @}
 */

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值