原创 串口编程.Linux串口编程

2010-8-27 15:48 1987 8 8 分类: MCU/ 嵌入式
串口编程.Linux串口编程
http://leiweni1972.blog.163.com/blog/static/16897128220107270328884/
    在第一次调试Linux串口驱动的时候,一定要保证与Linux串口通信的器件是没有问题可以使用的,然后我们再进行串口操作的学习,否则也许可能碰到问题的时候不知如何处理了。
  
    好了,在保证硬件已经没有问题的情况下,我们开始学习串口驱动模块的使用。
  
    PC上的串口不比嵌入式,你可以在了解了寄存器之后操作寄存器就可以实现串口的功能了。
  
    PC都是基于操作系统的,操作系统在用户模式是不能随便操作硬件,只有用户将内核模块加载,让内核模块去操作硬件,在Linux下就是使用这样的方式操作模块的。
  
    在Linux下目录/dev/ 下就是一些硬件的驱动模块,对应串口的是名称为ttyS(数字)的模块,比如ttyS0就是串口1(COM1),ttyS1就是串口2,以此类推。
  
    Linux下对硬件的操作就像是对文件的操作一样,唯一的区别就是文件不是流操作,可以在文件内部来回移动,串口以及其他硬件都是流操作,读取过了的数据是没有办法恢复的。
  
    在了解了这些之后,我们开始学习串口的访问函数。
  
    首先我们从头文件开始:
  
    #include <stdio.h> //标准输入输出定义
  
    #include <string.h> //字符串功能定义
  
    #include <unistd.h> //UNIX标准函数定义
  
    #include <fctl.h> //文件控制定义
  
    #include <errno.h> //错误码定义
  
    #include <termios.h> //POSIX终端控制定义
  
    #include <stdlib.h> //exit函数
  
    #include <sys/time.h> //时间函数
  
    #include <sys/types.h> //pid_t 多线程
  
    #include <sys/ioctl.h> //ioctl
  
    以上就是我们串口调试所用到的所有头文件,当然很多头文件应该用不上,但是我们一次性包含进来,用的时候就不用那样的找了。
  
    下面是串口的打开操作:
  
    串口打开用 open 函数,具体为:
  
    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
  
    这个函数返回-1就表示打开错误,有可能是被占用。后门的标志位O_RDWR 表示读写,O_NOCTTY表示改程序不会成为此程序的控制终端,与O_NDELAY,表示不等的DCD信号,一直处于等待数据接收状态。
  
    在打开成功后,在最后添加函数 fcntl(fd, F_SETFL, 0);表示执行read命令的时候,如果没有数据会阻塞进程。
  
    串口关闭操作,
  
    串口关闭使用close函数,
  
    close(fd); 即可关闭,没有返回值。
  
    串口写数据使用write函数
  
    write(fd,W_buf,n)
  
    串口读操作使用read函数
  
    len=read(fd,W_buf,n)
  
    如果串口设置fcntl(fd,F_SETFL,FNDELAY);
  
    read函数将不会阻塞,如果没有数据将会直接返回0
  
    在我们知道如何操作串口之后,我们只能操作一个适合我们使用的串口,
  
    串口属性的设置就是我们首先要解决的问题了。
  
    1 波特率
  
    2400 B2400
  
    4800 B4800
  
    9600 B9600
  
    19200 B19200
  
    38400 B38400
  
    57600 B57600
  
    115200 B115200
  
    其中9600是默认波特率,用的比较多,ARM芯片使用的波特率比较高,是115200。
  
    设置波特率使用函数cfsetispped和cfsetospeed设置输入波特率和输出波特率,一般情况下我们使用的输入和输出都是同一个波特率。
  
    2 设置控制模式
  
    设置流控制:
  
    不使用流控制:termios_new.c_cflag &= ~CRTSCTS
  
    使用硬件流控:termios_new.c_cflag |= CRTSCTS
  
    使用软件流控:termios_new.c_iflag |= IXON | IXOFF | IXANY
  
    设置字符大小:
  
    termios_new.c_cflag &= ~CSIZE;
  
    termios_new.c_cflag |= CS8;
  
    termios_new.c_cflag |= CS7;
  
    termios_new.c_cflag |= CS6;
  
    termios_new.c_cflag |= C5;
  
    设置奇偶校验:
  
    无校验:termios_new.c_cflag &= ~PARENB;
  
    奇校验:termios_new.c_cflag |= PARENB;
  
    termios_new.c_cflag &= ~PARODD;
  
    偶校验:termios_new.c_cflag |= PARENB;
  
    termios_new.c_cflag |= PARODD;
  
    以上就是串口通信的一些基础知识。
  
    下面开始看程序:
  
    MyCom.h
  
    typedef struct
  
    {
  
    char prompt; //prompt agter reciving data
  
    int baudrate; //baudrate
  
    char databit; //data bits, 5 6 7 8
  
    char debug; //debug mode ,0:none,1:debug
  
    char echo; //echo mode ,0:none,1:echo
  
    char fctl; //flow control,0:none,1:hardware,2:software
  
    char tty; //tty:0,1,2,3,4,5,6,7
  
    char parity; //parity 0:none,1:odd,2:even
  
    char stopbit; //stop bits,1,2
  
    const int reserved;
  
    }portinfo_t;
  
    typedef portinfo_t *pportinfo_t;
  
    int PortOpen(pportinfo_t pportinfo);
  
    int PortSet(int fdcom,const pportinfo_t pportinfo);
  
    void PortClose(int fdcom);
  
    int PortSend(int fdcom, char *data, int datalen);
  
    int PortRecv(int fdcom, char *data, int datalen, int baudrate);
  
    MyCom.c
  
    /*
  
    MyCom.c
  
    */
  
    #include <stdio.h>
  
    #include <fcntl.h>
  
    #include <string.h>
  
    #include <stdlib.h>
  
    #include <sys/times.h>
  
    #include <sys/types.h>
  
    #include <termios.h>
  
    #include <unistd.h>
  
    #include <sys/ioctl.h>
  
    #include "MyCom.h"
  
    #define TTY_DEV "/dev/ttyS"
  
    #define TIMEOUT_SEC(buflen,baud) (buflen*20/baud+2)
  
    #define TIMEOUT_USEC 0
  
    char *get_ptty(pportinfo_t pportinfo)
  
    {
  
    char *ptty;
  
    switch(pportinfo->tty)
  
    {
  
    case '0':
  
    {
  
    ptty=TTY_DEV"0";
  
    }break;
  
    case '1':
  
    {
  
    ptty=TTY_DEV"1";
  
    }break;
  
    case '2':
  
    {
  
    ptty=TTY_DEV"2";
  
    }break;
  
    }
  
    return ptty;
  
    }
  
    int convbaud(unsigned long int baudrate)
  
    {
  
    switch(baudrate)
  
    {
  
    case 2400:
  
    return B2400;
  
    case 4800:
  
    return B4800;
  
    case 9600:
  
    return B9600;
  
    case 19200:
  
    return B19200;
  
    case 38400:
  
    return B38400;
  
    case 57600:
  
    return B57600;
  
    case 115200:
  
    return B115200;
  
    default:
  
    return B9600;
  
    }
  
    }
  
    int PortSet(int fdcom, const pportinfo_t pportinfo)
  
    {
  
    struct termios termios_old, termios_new;
  
    int baudrate,tmp;
  
    char databit, stopbit, parity, fctl;
  
    bzero(&termios_old,sizeof(termios_old));
  
    bzero(&termios_new,sizeof(termios_new));
  
    cfmakeraw(&termios_new);
  
    tcgetattr(fdcom, &termios_old);
  
    baudrate = convbaud(pportinfo->baudrate);
  
    cfsetispeed(&termios_new,baudrate);
  
    cfsetispeed(&termios_new,baudrate);
  
    termios_new.c_cflag |= CLOCAL;
  
    termios_new.c_cflag |= CREAD;
  
    fctl = pportinfo->fctl;
  
    switch(fctl)
  
    {
  
    case '0':
  
    termios_new.c_cflag &= ~CRTSCTS;
  
    break;
  
    case '1':
  
    termios_new.c_cflag |= CRTSCTS;
  
    break;
  
    case '2':
  
    termios_new.c_iflag |= IXON | IXOFF | IXANY;
  
    break;
  
    }
  
    termios_new.c_cflag &= ~CSIZE;
  
    databit = pportinfo->databit;
  
    switch(databit)
  
    {
  
    case '5':
  
    termios_new.c_cflag |= CS5;
  
    break;
  
    case '6':
  
    termios_new.c_cflag |= CS6;
  
    break;
  
    case '7':
  
    termios_new.c_cflag |= CS7;
  
    break;
  
    default:
  
    termios_new.c_cflag |= CS8;
  
    break;
  
    }
  
    parity = pportinfo->parity;
  
    switch(parity)
  
    {
  
    case '0':
  
    termios_new.c_cflag &= ~PARENB;
  
    break;
  
    case '1':
  
    termios_new.c_cflag |= PARENB;
  
    termios_new.c_cflag &= ~PARODD;
  
    break;
  
    case '2':
  
    termios_new.c_cflag |= PARENB;
  
    termios_new.c_cflag |= PARODD;
  
    break;
  
    }
  
    stopbit = pportinfo->stopbit;
  
    if(stopbit == '2')
  
    {
  
    termios_new.c_cflag |= CSTOPB;
  
    }
  
    else
  
    {
  
    termios_new.c_cflag &= ~CSTOPB;
  
    }
  
    termios_new.c_oflag &= ~OPOST;
  
    termios_new.c_cc[VMIN] = 1;
  
    termios_new.c_cc[VTIME] = 1;
  
    tcflush(fdcom, TCIFLUSH);
  
    tmp = tcsetattr(fdcom, TCSANOW, &termios_new);
  
    tcgetattr(fdcom, &termios_old);
  
    return tmp;
  
    }
  
    int PortOpen(pportinfo_t pportinfo)
  
    {
  
    int fdcom;
  
    char *ptty;
  
    ptty = get_ptty(pportinfo);
  
    //fdcom = open(ptty,O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
  
    fdcom = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK);
  
    return fdcom;
  
    }
  
    void PortClose(int fdcom)
  
    {
  
    close(fdcom);
  
    }
  
    int PortSend(int fdcom, char *data, int datalen)
  
    {
  
    int len=0;
  
    len = write(fdcom, data, datalen);
  
    if(len == datalen)
  
    {
  
    return len;
  
    }
  
    else
  
    {
  
    tcflush(fdcom, TCOFLUSH);
  
    return -1;
  
    }
  
    }
  
    int PortRecv(int fdcom, char *data, int datalen, int baudrate)
  
    {
  
    int readlen, fs_sel;
  
    fd_set fs_read;
  
    struct timeval tv_timeout;
  
    FD_ZERO(&fs_read);
  
    FD_SET(fdcom, &fs_read);
  
    tv_timeout.tv_sec = TIMEOUT_SEC(datalen, baudrate);
  
    tv_timeout.tv_usec = TIMEOUT_USEC;
  
    fs_sel = select(fdcom+1, &fs_read, NULL, NULL, &tv_timeout);
  
    if(fs_sel)
  
    {
  
    readlen = read(fdcom, data, datalen);
  
    return readlen;
  
    }
  
    else
  
    {
  
    return 1;
  
    }
  
    }
  
    主函数:
  
    int main(int argc, char *argv[])
  
    {
  
    int fdcom, i, SendLen, RecvLen;
  
    struct termios termios_cur;
  
    char RecvBuf[11];
  
    RecvBuf[10]=0;
  
    char *str = "1234567890";
  
    portinfo_t portinfo =
  
    {
  
    '0',
  
    115200,
  
    '8',
  
    '0',
  
    '0',
  
    '2',
  
    '0',
  
    '0',
  
    '1',
  
    0
  
    };
  
    if(argc != 2)
  
    {
  
    printf("Usage:<type 0 -- send 1 -- receive>\n");
  
    printf(" eg:");
  
    printf(" MyPort0");
  
    exit(-1);
  
    }
  
    fdcom = PortOpen(&portinfo);
  
    if(fdcom<0)
  
    {
  
    printf("Error\n");
  
    exit(1);
  
    }
  
    PortSet(fdcom, &portinfo);
  
    if(atoi(argv[1])==0)
  
    {
  
    for(i=0;i<100;i++)
  
    {
  
    SendLen = PortSend(fdcom,str+i%10,1);
  
    if(SendLen>0)
  
    {
  
    printf("No %d send %d data %c.\n",i,SendLen,str[i%10]);
  
    }
  
    else
  
    {
  
    printf("ERROR:Send failed.\n");
  
    }
  
    sleep(1);
  
    }
  
    PortClose(fdcom);
  
    }
  
    else
  
    {
  
    for(;;)
  
    {
  
    RecvLen = PortRecv(fdcom, RecvBuf, 10, portinfo.baudrate);
  
    if(RecvLen>0)
  
    {
  
    //for(i=0;i<RecvLen;i++)
  
    //{
  
    // printf("Receive data No %d is %x:%c.\n",i,RecvBuf,RecvBuf);
  
    //}
  
    printf("%s\nTotal frame length is %d.\n",RecvBuf,RecvLen);
  
    }
  
    else
  
    {
  
    printf("Error:receive error.\n");
  
    }
  
    sleep(2);
  
    }
  
    }
  
    return 0;
  
    }

文章评论0条评论)

登录后参与讨论
我要评论
0
8
关闭 站长推荐上一条 /2 下一条