Chinaunix首页 | 论坛 | 博客
  • 博客访问: 695183
  • 博文数量: 90
  • 博客积分: 3225
  • 博客等级: 少校
  • 技术积分: 1200
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-20 11:04
个人简介

菩提本无树,明镜变非台 本来无一物,何处惹尘埃

文章分类

全部博文(90)

文章存档

2015年(1)

2014年(12)

2013年(15)

2012年(31)

2011年(8)

2010年(23)

分类: LINUX

2010-12-20 17:23:21

1 串口简介

串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。常用的串口是 RS-232-C 接口(又称 EIA RS-232-C)它是在 1970 年由美国电子工业协会(EIA)联合贝尔系统、 调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换 接口技术标准"该标准规定采用一个 25 个脚的 DB25 连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。传输距离在码元畸变小于 4% 的情况下,传输电缆长度应为 50 英尺。

Linux 操作系统从一开始就对串行口提供了很好的支持,本文就 Linux 下的串行口通讯编程进行简单的介绍,如果要非常深入了解,建议看看本文所参考的

2 计算机串口的引脚说明

序号

信号名称

符号

流向

功能

2

发送数据

TXD

DTE→DCE

DTE发送串行数据

3

接收数据

RXD

DTE←DCE

DTE 接收串行数据

4

请求发送

RTS

DTE→DCE

DTE 请求 DCE 将线路切换到发送方式

5

允许发送

CTS

DTE←DCE

DCE 告诉 DTE 线路已接通可以发送数据

6

数据设备准备好

DSR

DTE←DCE

DCE 准备好

7

信号地

 

 

   信号公共地

8

载波检测

DCD

DTE←DCE

表示 DCE 接收到远程载波

20

数据终端准备好

DTR

DTE→DCE

DTE 准备好

22

振铃指示

RI

DTE←DCE

表示 DCE 与线路接通,出现振铃

3 串口操作

相关头文件

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h> /*file control*/
  7. #include <termios.h> /*PPSIX terminal control*/
  8. #include <errno.h> /*error number*/

3.1 打开串口

Linux 下串口文件是位于 /dev 下的串口一 为 /dev/ttyS0;串口二 为 /dev/ttyS1。

通过使用系统打开函数打开串口:

  1. int fd;
  2. fd = open("/dev/ttyS0", O_RDWR); //open serial in r/w way
  3. if( fd < 0 ){
  4.   perror("open serial failed\n");
  5. }

3.2 设置串口

最基本的设置串口包括波特率设置,效验位和停止位设置。串口的设置主要是设置 struct termios 结构体的各成员值。

  1. struct termios
  2. {
  3.   unsigned short c_iflag;  /* input mode flags */
  4.   unsigned short c_oflag;  /* output mode flags */
  5.   unsigned short c_cflag;  /* control mode flags */
  6.   unsigned short c_lflag;  /* local mode flags */
  7.   unsigned char c_line     /* line discipline */
  8.   unsigned char c_cc[NCC]; /* control characters */
  9. };

设置这个结构体很复杂,我这里就只说说常见的一些设置:

3.2.1波特率设置接口

  1. struct termios Opt;
  2. tcgetattr(fd, &Opt);
  3. cfsetispeed(&Opt,B19200); /*set 19200Bps*/
  4. cfsetospeed(&Opt,B19200);
  5. tcsetattr(fd,TCANOW,&Opt);
示例:
  1. /**
  2. *@brief 设置串口通信速率
  3. *@param fd int
  4. *@param speed int
  5. *@return void
  6. */
  7. int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,
  8.           B38400, B19200, B9600, B4800, B2400, B1200, B300, };
  9. int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400,
  10.           19200, 9600, 4800, 2400, 1200, 300, };
  11. void set_speed(int fd, int speed){
  12.   int i;
  13.   int status;
  14.   struct termios Opt;
  15.   tcgetattr(fd, &Opt);
  16.   for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {
  17.     if (speed == name_arr[i]) {
  18.       tcflush(fd, TCIOFLUSH);
  19.       cfsetispeed(&Opt, speed_arr[i]);
  20.       cfsetospeed(&Opt, speed_arr[i]);
  21.       status = tcsetattr(fd1, TCSANOW, &Opt);
  22.       if (status != 0) {
  23.         perror("tcsetattr fd1");
  24.         return;
  25.       }
  26.       tcflush(fd,TCIOFLUSH);
  27.     }
  28.   }
  29. }

3.2.2效验位和停止位的设置

无效验

8

Option.c_cflag &= ~PARENB;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag |= ~CS8;

奇效验(Odd)

7

Option.c_cflag |= ~PARENB;
Option.c_cflag &= ~PARODD;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag |= ~CS7;

偶效验(Even)

7

Option.c_cflag &= ~PARENB;
Option.c_cflag |= ~PARODD;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag |= ~CS7;

Space效验

7

Option.c_cflag &= ~PARENB;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= &~CSIZE;
Option.c_cflag |= CS8;

示例

  1. /**
  2. *@brief 设置串口数据位,停止位和效验位
  3. *@param fd int
  4. *@param databits int 数据位取7或8
  5. *@param stopbits int 停止位取1或2
  6. *@param parity   int 校验类型取N,E,O,S
  7. */
  8. int set_Parity(int fd,int databits,int stopbits,int parity)
  9. {
  10.         struct termios options;
  11.         if ( tcgetattr( fd,&options) != 0) {
  12.                perror("SetupSerial 1");
  13.                return(FALSE);
  14.         }
  15.         options.c_cflag &= ~CSIZE;
  16.         switch (databits) /*设置数据位*/
  17.         {
  18.         case 7:
  19.                options.c_cflag |= CS7;
  20.                break;
  21.         case 8:
  22.                options.c_cflag |= CS8;
  23.                break;
  24.         default:
  25.                fprintf(stderr,"Unsupported data size\n"); return (FALSE);
  26.         }
  27.         switch (parity) /* 设置校验类型 */
  28.         {
  29.          case 'n':
  30.          case 'N':
  31.          options.c_cflag &= ~PARENB; /* Clear parity enable */
  32.          options.c_iflag &= ~INPCK; /* Enable parity checking */
  33.          break;
  34.          case 'o':
  35.          case 'O':
  36.          options.c_cflag |= (PARODD | PARENB); /* */
  37.          options.c_iflag |= INPCK; /* Disnable parity checking */
  38.          break;
  39.          case 'e':
  40.          case 'E':
  41.          options.c_cflag |= PARENB; /* Enable parity */
  42.          options.c_cflag &= ~PARODD; /* */
  43.          options.c_iflag |= INPCK; /* Disnable parity checking */
  44.          break;
  45.          case 'S':
  46.          case 's': /*as no parity*/
  47.          options.c_cflag &= ~PARENB;
  48.          options.c_cflag &= ~CSTOPB;break;
  49.          default:
  50.          fprintf(stderr,"Unsupported parity\n");
  51.          return (FALSE);
  52.         }
  53.        
  54.         switch (stopbits)  /* 设置停止位 */
  55.         {
  56.          case 1:
  57.          options.c_cflag &= ~CSTOPB;
  58.          break;
  59.          case 2:
  60.          options.c_cflag |= CSTOPB;
  61.          break;
  62.          default:
  63.          fprintf(stderr,"Unsupported stop bits\n");
  64.          return (FALSE);
  65.         }
  66.         /* Set input parity option */
  67.         if (parity != 'n')
  68.          options.c_iflag |= INPCK;
  69.         tcflush(fd,TCIFLUSH);
  70.         options.c_cc[VTIME] = 150; /* 15 seconds*/
  71.         options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
  72.         if (tcsetattr(fd,TCSANOW,&options) != 0)
  73.         {
  74.          perror("SetupSerial 3");
  75.          return (FALSE);
  76.         }
  77.         return (TRUE);
  78. } 

需要注意的是:

如果不是开发终端之类的,只是串口传输数据,而不需要串口来处理,那么使用原始模式(Raw Mode)方式来通讯,设置方式如下:

  1. options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
  2. options.c_oflag &= ~OPOST; /*Output*/

3.3 读写串口

设置好串口之后,读写串口就很容易了,把串口当作文件读写就是。

3.3.1发送数据

  1. char buffer[1024];
  2. int Length;
  3. int nByte;
  4. nByte = write(fd, buffer ,Length)

3.3.2读取串口数据

使用read函数读取,如果设置为原始模式(Raw Mode)传输数据,那么read函数返回的字符数是实际串口收到的字符数。

可以使用fcntl,或者select函数来实现异步读取

  1. char buff[1024];
  2. int Len;
  3. int readByte = read(fd,buff,Len);

3.4 关闭串口

  1. close(fd);


下面是一个简单的读取串口数据的例子,使用了上面定义的一些函数和头文件

  1. /**
  2.  * describe: use serial2 for testing.
  3.  * sending character data
  4.  */
  5. #define FALSE -1
  6. #define TRUE 0
  7. /*********************************************************************/
  8. int OpenDev(char *Dev)
  9. {
  10.         int fd = open( Dev, O_RDWR ); //| O_NOCTTY | O_NDELAY
  11.         if (-1 == fd)
  12.         {
  13.                perror("Can't Open Serial Port");
  14.                return -1;
  15.         }
  16.         else
  17.                return fd;
  18. }
  19. int main(int argc, char **argv){
  20.         int fd;
  21.         int nread;
  22.         char buff[512];
  23.         char *dev = "/dev/ttyS1"; //
  24.         fd = OpenDev(dev);
  25.         set_speed(fd,19200);
  26.         if (set_Parity(fd,8,1,'N') == FALSE) {
  27.                printf("Set Parity Error\n");
  28.                exit (0);
  29.         }
  30.         while (1) //
  31.         {
  32.          while((nread = read(fd, buff, 512))>0)
  33.          {
  34.          printf("\nLen %d\n",nread);
  35.          buff[nread+1] = '\0';
  36.          printf( "\n%s", buff);
  37.          }
  38.         }
  39.         close(fd);
  40.         exit (0);
  41. }


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