Linux操作系统从一開始就对串行口提供了非常好的支持,本文就Linux下的串行口通讯编程进行简单的介绍。

  串口简单介绍
串行口是计算机一种经常使用的接口。具有连接线少。通讯简单。得到广泛的使用。

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

  Linux操作系统从一開始就对串行口提供了非常好的支持,本文就Linux下的串行口通讯编程进行简单的介绍。假设要非常深入了解,建议看看本文所參考的《Serial Programming Guide for POSIX Operating Systems》

  串口操作

  串口操作须要的头文件

1 #include     <stdio.h>      /*标准输入输出定义*/
2 #include     <stdlib.h>     /*标准函数库定义*/
3 #include     <unistd.h>     /*Unix 标准函数定义*/
4 #include     <sys/types.h>  
5 #include     <sys/stat.h>   
6 #include     <fcntl.h>      /*文件控制定义*/
7 #include     <termios.h>    /*PPSIX 终端控制定义*/
8 #include     <errno.h>      /*错误号定义*/

打开串口 

在 Linux 下串口文件是位于 /dev 下的。串口一 为 /dev/ttyS0,串口二 为 /dev/ttyS1。打开串口是通过使用标准的文件打开函数操作:

1 int fd;
2 /*以读写方式打开串口*/
3 fd = open( "/dev/ttyS0", O_RDWR);
4 if (-1 == fd){ 
5 /* 不能打开串口一*/ 
6 perror(" 提示错误!");
7 }

设置串口 

最主要的设置串口包含波特率设置。效验位和停止位设置。

串口的设置主要是设置 struct termios 结构体的各成员值。

1 struct termio
2 {    unsigned short  c_iflag;    /* 输入模式标志 */    
3     unsigned short  c_oflag;        /* 输出模式标志 */    
4     unsigned short  c_cflag;        /* 控制模式标志*/    
5     unsigned short  c_lflag;        /* local mode flags */    
6     unsigned char  c_line;            /* line discipline */    
7     unsigned char  c_cc[NCC];    /* control characters */
8 };

设置这个结构体非常复杂。我这里就仅仅说说常见的一些设置: 

波特率设置 以下是改动波特率的代码: 

1 struct  termios Opt;
2 tcgetattr(fd, &Opt);
3 cfsetispeed(&Opt,B19200);     /*设置为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 }

设置效验的函数: 

 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*/

读写串口 

设置好串口之后,读写串口就非常easy了,把串口当作文件读写就是。

 

·发送数据

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

·读取串口数据 
使用文件操作read函数读取,假设设置为原始模式(Raw Mode)数据传输,那么read函数返回的字符数是实际串口收到的字符数。能够使用操作文件的函数来实现异步读取,如fcntl。或者select等来操作。

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

关闭串口 

关闭串口就是关闭文件。

1 close(fd);

样例 

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

 1 /**********************************************************************
 2 代码说明:使用串口二測试的,发送的数据是字符,
 3 可是没有发送字符串结束符号,所以接收到后,后面加上了结束符号。

 4 我測试使用的是单片机发送数据到第二个串口,測试通过。
 5 **********************************************************************/
 6 #define FALSE  -1
 7 #define TRUE   0
 8 /*********************************************************************/
 9 int OpenDev(char *Dev)
10 {
11     int    fd = open( Dev, O_RDWR ); 
12         //| O_NOCTTY | O_NDELAY    
13     if (-1 == fd)    
14     {             
15         perror("Can't Open Serial Port");
16         return -1;        
17     }    
18     else    
19         return fd;
20 }
21 int main(int argc, char **argv){
22     int fd;
23     int nread;
24     char buff[512];
25     char *dev  = "/dev/ttyS1"; //串口二
26     fd = OpenDev(dev);
27     set_speed(fd,19200);
28     if (set_Parity(fd,8,1,'N') == FALSE)  {
29         printf("Set Parity Error\n");
30         exit (0);
31     }
32 while (1) //循环读取数据
33 {   
34     while((nread = read(fd, buff, 512))>0)
35     { 
36         printf("\nLen %d\n",nread); 
37         buff[nread+1] = '\0';   
38         printf( "\n%s", buff);   
39     }
40 }
41     //close(fd);  
42     // exit (0);
43 }

linux下怎样对串口编程的更多相关文章

  1. Linux下的C Socket编程 -- server端的继续研究

    Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...

  2. Linux下的C Socket编程 -- server端的简单示例

    Linux下的C Socket编程(三) server端的简单示例 经过前面的client端的学习,我们已经知道了如何创建socket,所以接下来就是去绑定他到具体的一个端口上面去. 绑定socket ...

  3. Linux下的C Socket编程 -- 获取对方IP地址

    Linux下的C Socket编程(二) 获取域名对应的IP地址 经过上面的讨论,如果我们想要连接到远程的服务器,我们需要知道对方的IP地址,系统函数gethostbyname便能够实现这个目的.它能 ...

  4. Linux下的C Socket编程 -- 简介与client端的处理

    Linux下的C Socket编程(一) 介绍 Socket是进程间通信的方式之一,是进程间的通信.这里说的进程并不一定是在同一台机器上也有可能是通过网络连接的不同机器上.只要他们之间建立起了sock ...

  5. Linux下高并发网络编程

      Linux下高并发网络编程 1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时, 最高的并发数量都要受到系统对用户单一进程同时可打 ...

  6. linux下的qt串口通信

    1.linux下的qt串口通信跟windows唯一的差别就是端口号的名字,windows下面是COM,而linux是ttyUSB0的路径 2.一般情况下linux插上USB转串口线就可以在/dev/目 ...

  7. linux下C语言多线程编程实例

    用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...

  8. 【ARM-Linux开发】linux下Eclipse进行C编程时动态链接库的生成和使用

    linux下Eclipse进行C编程时动态链接库的生成和使用 引用 http://linux.chinaitlab.com/soft/864157.html 欢迎进入Linux社区论坛,与200万技术 ...

  9. Linux下读写UART串口的代码

    Linux下读写UART串口的代码,从IBM Developer network上拿来的东西,操作比較的复杂,就直接跳过了,好在代码能用,记录一下- 两个实用的函数- //////////////// ...

随机推荐

  1. 常用JS整理

    目录 1 事件 a addEventListener--绑定事件b removeEventListener--解绑事件,只能解开addEventListener绑定的事件 2 JS获取节点信息a by ...

  2. 【bzoj4668】冷战 并查集按秩合并+朴素LCA

    题目描述 1946 年 3 月 5 日,英国前首相温斯顿·丘吉尔在美国富尔顿发表“铁幕演说”,正式拉开了冷战序幕. 美国和苏联同为世界上的“超级大国”,为了争夺世界霸权,两国及其盟国展开了数十年的斗争 ...

  3. 【bzoj4127】Abs 树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  4. HDU 1824 Let's go home(2-SAT+Tarjan)

    Let's go home Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  5. Linux系统——常见的系统调用

    本文列出了大部分常见的Linux系统调用,并附有简要中文说明. 以下是Linux系统调用的一个列表,包含了大部分常用系统调用和由系统调用派生出的的函数.这可能是你在互联网上所能看到的唯一一篇中文注释的 ...

  6. python安装matplotlib

    linux安装 方法: 首先matplotlib是需要numpy先行包支持的,这里,我已经安装了numpy,下面安装matplotlib. matplot需要一些其他软件支持 (1)这时需要安装fre ...

  7. SQL索引基础

    原文发布时间为:2011-02-19 -- 来源于本人的百度文章 [由搬家工具导入]   一、深入浅出理解索引结构   实际上,您可以把索引理解为一种特殊的目录。微软的SQL SERVER提供了两种索 ...

  8. LeetCode OJ--Combinations *

    https://oj.leetcode.com/problems/combinations/ 给一个集合,求个数为k的所有子集 递归调用,深搜 class Solution { public: vec ...

  9. L1-8 外星人的一天

    L1-8 外星人的一天(15 point(s)) 地球上的一天是 24 小时.但地球上还有一些精力和勤奋度都远超一般人的大神级人物,他们的“一天”是以 48 小时为周期运转的,这种人被人们尊称为“外星 ...

  10. CCCC L1-039. 古风排版【图形输出/循环控制行列/模拟/细节】

    L1-039. 古风排版 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 中国的古人写文字,是从右向左竖向排版的.本题就请你编写 ...