Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1247441
  • 博文数量: 479
  • 博客积分: 12240
  • 博客等级: 上将
  • 技术积分: 4999
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-24 17:12
文章分类

全部博文(479)

文章存档

2014年(1)

2013年(1)

2012年(1)

2011年(95)

2010年(177)

2009年(167)

2008年(16)

2007年(21)

分类: LINUX

2010-01-14 16:24:01


serial.c,串口基本操作的封装:

#include <termios.h> /* tcgetattr, tcsetattr */
#include <stdio.h> /* perror, printf, puts, fprintf, fputs */
#include <unistd.h> /* read, write, close */
#include <fcntl.h> /* open */
#include <sys/signal.h>
#include <sys/types.h>
#include <string.h> /* bzero, memcpy */
#include <limits.h> /* CHAR_MAX */

#include "serial.h"

/*
 * Decription for TIMEOUT_SEC(buflen,baud);
 * baud bits per second, buflen bytes to send.
 * buflen*20 (20 means sending an octect-bit data by use of the maxim bits 20)
 * eg. 9600bps baudrate, buflen=1024B, then TIMEOUT_SEC = 1024*20/9600+1 = 3
 * don't change the two lines below unless you do know what you are doing.
*/

#define TIMEOUT_SEC(buflen,baud) (buflen*20/baud+2)
#define TIMEOUT_USEC 0

#define CH_TO_WAIT 5
#define CH_BITS 11

#define BUFFER_LEN 1024 /* sendfile() */

static INT32 fd; //File descriptor for the port

static struct termios termios_old, termios_new;
static fd_set fs_read, fs_write;
static struct timeval tv_timeout;

static void set_baudrate (INT32);
static INT32 get_baudrate ();
static void set_data_bit (INT32 databit);
static INT32 baudrate2Bxx (INT32 baudrate);
static INT32 Bxx2baudrate (INT32 _baudrate);
static INT32 set_port_attr (
                             INT32 baudrate,         //

                             INT32 databit,
                             const char *stopbit,
                             char parity);
static void set_stopbit (const char *stopbit);
static void set_parity (char parity);

/* Open serial port ComPort at baudrate baud rate. */
INT32 OpenComPort (INT32 ComPort, INT32 baudrate, INT32 databit,
                   const char *stopbit, char parity)
{
    char *pComPort;
    INT32 retval;

    switch (ComPort) {
    case 0:
        pComPort = "/dev/ttyS0";
        break;
    case 1:
        pComPort = "/dev/ttyS1";
        break;
    case 2:
        pComPort = "/dev/ttyS2";
        break;
    case 3:
        pComPort = "/dev/ttyS3";
        break;
    case 4:
        pComPort = "/dev/ttyTX0";
        break;
    case 5:
        pComPort = "/dev/ttyTX1";
        break;
    default:
        pComPort = "/dev/ttyS0";
        break;
    }

    fd = open (pComPort, O_RDWR | O_NOCTTY); // | O_NONBLOCK);

    if (-1 == fd) {
        fprintf (stderr, "cannot open port %s\n", pComPort);
        return (-1);
    }

    printf("comport fd = %d\n", fd);

    tcgetattr (fd, &termios_old); /* save old termios value */
    /* 0 on success, -1 on failure */
    retval = set_port_attr (baudrate, databit, stopbit, parity);
    if (-1 == retval) {
        fprintf (stderr, "\nport %s cannot set baudrate at %d\n", pComPort,
                 baudrate);
    }
    return (retval);
}

/* close serial port by use of file descriptor fd */
void CloseComPort ()
{
    /* flush output data before close and restore old attribute */
    tcsetattr (fd, TCSADRAIN, &termios_old);
    close (fd);
}

int getPortFd(){
    return fd;
}

INT32 ReadComPort (void *data, INT32 datalength)
{
    INT32 retval = 0;
    FD_ZERO (&fs_read);
    FD_SET (fd, &fs_read);
    tv_timeout.tv_sec = TIMEOUT_SEC (datalength, get_baudrate ());
    tv_timeout.tv_usec = TIMEOUT_USEC;
    retval = select (fd + 1, &fs_read, NULL, NULL, &tv_timeout);
    if (retval > 0) {
        retval = read (fd, data, datalength);
        return (retval);
    }
    else {
        if (0 == retval ) {
            return (0);
        }else{
            return (-1);
        }
    }


}

INT32 ReadComPortA (void *data, INT32 datalength)
{
    INT32 retval = 0;
    int bytes_read;
    int readlen;



    /**
     * caculate the time of 5 characters and get the maxim
     * with 3ms and 5 ch's time
    */

    tv_timeout.tv_sec = 0;
    tv_timeout.tv_usec = ( (CH_TO_WAIT * CH_BITS) * (1000000/get_baudrate()));
    //printf("port read timeout:%dus\n",tv_timeout.tv_usec);


    bytes_read = 0;
    while(bytes_read<datalength){
        tv_timeout.tv_sec = 0;
        tv_timeout.tv_usec = ( (CH_TO_WAIT * CH_BITS) * (1000000/get_baudrate()));
        FD_ZERO (&fs_read);
        FD_SET (fd, &fs_read);
        retval = select (fd + 1, &fs_read, NULL, NULL, &tv_timeout);
        if ( retval >0 ) {
            readlen = read (fd, (data+bytes_read), datalength);
            bytes_read += readlen;
        } else
            return (bytes_read==0?-1:bytes_read);
    }

    return -1;

}
/*
 * Write datalength bytes in buffer given by UINT8 *data,
 * return value: bytes written
 * Nonblock mode
*/

INT32 WriteComPort (UINT8 * data, INT32 datalength)
{
    INT32 retval, len = 0, total_len = 0;

    FD_ZERO (&fs_write);
    FD_SET (fd, &fs_write);
    tv_timeout.tv_sec = TIMEOUT_SEC (datalength, get_baudrate ());
    tv_timeout.tv_usec = TIMEOUT_USEC;

    for (total_len = 0, len = 0; total_len < datalength;) {
        retval = select (fd + 1, NULL, &fs_write, NULL, &tv_timeout);
        if (retval) {
            len = write (fd, &data[total_len], datalength - total_len);
            if (len > 0) {
                total_len += len;
            }
        }
        else {
            tcflush (fd, TCOFLUSH); /* flush all output data */
            break;
        }
    }

    return (total_len);
}

/* get serial port baudrate */
static INT32 get_baudrate ()
{
    return (Bxx2baudrate (cfgetospeed (&termios_new)));
}



/* set serial port baudrate by use of file descriptor fd */
static void set_baudrate (INT32 baudrate)
{
    termios_new.c_cflag = baudrate2Bxx (baudrate); /* set baudrate */
}

static void set_data_bit (INT32 databit)
{
    termios_new.c_cflag &= ~CSIZE;
    switch (databit) {
    case 8:
        termios_new.c_cflag |= CS8;
        break;
    case 7:
        termios_new.c_cflag |= CS7;
        break;
    case 6:
        termios_new.c_cflag |= CS6;
        break;
    case 5:
        termios_new.c_cflag |= CS5;
        break;
    default:
        termios_new.c_cflag |= CS8;
        break;
    }
}

static void set_stopbit (const char *stopbit)
{
    if (0 == strcmp (stopbit, "1")) {
        termios_new.c_cflag &= ~CSTOPB; /* 1 stop bit */
    }
    else if (0 == strcmp (stopbit, "1.5")) {
        termios_new.c_cflag &= ~CSTOPB; /* 1.5 stop bits */
    }
    else if (0 == strcmp (stopbit, "2")) {
        termios_new.c_cflag |= CSTOPB; /* 2 stop bits */
    }
    else {
        termios_new.c_cflag &= ~CSTOPB; /* 1 stop bit */
    }
}

static void set_parity (char parity)
{
    switch (parity) {
    case 'N': /* no parity check */
        termios_new.c_cflag &= ~PARENB;
        break;
    case 'E': /* even */
        termios_new.c_cflag |= PARENB;
        termios_new.c_cflag &= ~PARODD;
        break;
    case 'O': /* odd */
        termios_new.c_cflag |= PARENB;
        termios_new.c_cflag |= ~PARODD;
        break;
    default: /* no parity check */
        termios_new.c_cflag &= ~PARENB;
        break;
    }
}

static INT32 set_port_attr (
                          INT32 baudrate, // 1200 2400 4800 9600 .. 115200

                          INT32 databit, // 5, 6, 7, 8

                          const char *stopbit, // "1", "1.5", "2"

                          char parity) // N(o), O(dd), E(ven)

{
    bzero(&termios_new, sizeof (termios_new));
    cfmakeraw (&termios_new);

    set_baudrate (baudrate);
    termios_new.c_cflag |= CLOCAL | CREAD; /* | CRTSCTS */
    set_data_bit (databit);
    set_parity (parity);
    set_stopbit (stopbit);
    termios_new.c_oflag             = 0;
    termios_new.c_lflag             |= 0;
    termios_new.c_oflag             &= ~OPOST;
    termios_new.c_cc[VTIME]     = 1; /* unit: 1/10 second. */
    termios_new.c_cc[VMIN]         = 255; /* minimal characters for reading */
    tcflush (fd, TCIFLUSH);

    return (tcsetattr (fd, TCSANOW, &termios_new));
}




/**
 * baudrate xxx to Bxxx
 *
 * @@param baudrate xxx
 *
 * @@return
 */

static INT32 baudrate2Bxx (INT32 baudrate)
{
    switch (baudrate) {
    case 0:
        return (B0);
    case 50:
        return (B50);
    case 75:
        return (B75);
    case 110:
        return (B110);
    case 134:
        return (B134);
    case 150:
        return (B150);
    case 200:
        return (B200);
    case 300:
        return (B300);
    case 600:
        return (B600);
    case 1200:
        return (B1200);
    case 2400:
        return (B2400);
    case 9600:
        return (B9600);
    case 19200:
        return (B19200);
    case 38400:
        return (B38400);
    case 57600:
        return (B57600);
    case 115200:
        return (B115200);
    default:
        return (B9600);
    }
}

/**
 * get boundrate from Bxxx
 *
 * @@param baudrate Bxxx refers to bound rate
 *
 * @@return
 */

static INT32 Bxx2baudrate (INT32 _baudrate)
{
/* reverse baudrate */
    switch (_baudrate) {
    case B0:
        return (0);
    case B50:
        return (50);
    case B75:
        return (75);
    case B110:
        return (110);
    case B134:
        return (134);
    case B150:
        return (150);
    case B200:
        return (200);
    case B300:
        return (300);
    case B600:
        return (600);
    case B1200:
        return (1200);
    case B2400:
        return (2400);
    case B9600:
        return (9600);
    case B19200:
        return (19200);
    case B38400:
        return (38400);
    case B57600:
        return (57600);
    case B115200:
        return (115200);
    default:
        return (9600);
    }
}


对应的头文件serial.h:

#ifndef _SERIAL_H
#define _SERIAL_H 1

typedef int INT32;
typedef short INT16;
typedef char INT8;
typedef unsigned int UNIT32;
typedef unsigned short UINT16;
typedef unsigned char UINT8;

/* serial.c */
INT32 OpenComPort (INT32 ComPort, INT32 baudrate, INT32 databit,
                                        const char *stopbit, char parity);
void CloseComPort (void);

INT32 ReadComPort (void *data, INT32 datalength);
INT32 WriteComPort (UINT8 * data, INT32 datalength);

/**
 * export serial fd to other program to perform
 * directly read, write to serial.
 *
 * @return serial's file description
 */

int getPortFd();

#endif /* serial.c */


测试程序:

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

#include "serial.h"

//#define ttyS0 0 //
#define ttyS1 1 //OK
#define ttyS2 2
#define ttyS3 3 //OK
#define ttyTX0 4 //OK
#define ttyTX1 5

static int n_com_port = ttyTX0;
int main (int argc, char *argv[])
{
    int ret = -1;
    int len_tty = -1;
    int fd_rs485;
    unsigned char buf_tty[256];

    if (argc > 1) {
        n_com_port = strtol( argv[1], NULL, 10 );
    }

    ret = OpenComPort(n_com_port, 115200, 8, "1", 'N');
    if (ret < 0) {
        fprintf(stderr, "Error: Opening Com Port %d\n", n_com_port);
        return ret;
    }else{
        printf("Open Com Port %d Success, Now going to read port\n", n_com_port);
    }

    while(1){
        bzero(buf_tty, sizeof(buf_tty));
        len_tty = ReadComPort(buf_tty, 255);

        if (len_tty < 0) {
            printf("Error: Read Com Port\n");
            break;
        }

        if (len_tty == 0) {
            write(STDOUT_FILENO, ".", sizeof("."));
            continue;
        }

        printf("Recv: %d bytes, [%s]\n", len_tty, buf_tty);
        
        len_tty = WriteComPort(buf_tty, len_tty);
        WriteComPort(" recved:", sizeof(" recved:"));
        if (len_tty < 0) {
            printf("Error: WriteComPort Error\n");
        }
        // delay 500 ms to let data transfer complete
        // here will cause bugs
        usleep(500 * 1000);
    }

    CloseComPort();
    printf("Program Terminated\n");

    return(0);
}


测试结果和现象:
root@omap3evm:/app/uart# ./test_uart-ttyS0
comport fd = 3
Open Com Port 0 Success, Now going to read port
Recv: 16 bytes, [1234567890abcdef]
Recv: 16 bytes, [1234567890abcdef]
Recv: 16 bytes, [1234567890abcdef]
Recv: 16 bytes, [1234567890abcdef]
...........

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