【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》(翻译为《POSIX操作系统的串口编程指南》)
计算机串口的引脚说明
串口操作
串口操作需要的头文件
#include <stdio.h> /*标准输入输出定义*/
#include <stdlib.h> /*标准函数库定义*/
#include <unistd.h> /*Unix 标准函数定义*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> /*文件控制定义*/
#include <termios.h> /*PPSIX 终端控制定义*/
#include <errno.h> /*错误号定义*/
打开串口
在 Linux 下串口文件是位于 /dev 下的
串口一 为 /dev/ttyS0
串口二 为 /dev/ttyS1
打开串口是通过使用标准的文件打开函数操作:
int fd;
/*以读写方式打开串口*/
fd = open( "/dev/ttyS0", O_RDWR);
if (-1 == fd){
/* 不能打开串口一*/
perror(" 提示错误!");
}
设置串口
最基本的设置串口包括波特率设置,效验位和停止位设置。
串口的设置主要是设置 struct termios 结构体的各成员值。
struct termio
{ unsigned short c_iflag; /* 输入模式标志 */ unsigned short c_oflag; /* 输出模式标志 */ unsigned short c_cflag; /* 控制模式标志*/ unsigned short c_lflag; /* local mode flags */ unsigned char c_line; /* line discipline */ unsigned char c_cc[NCC]; /* control characters */
};
设置这个结构体很复杂,我这里就只说说常见的一些设置:
波特率设置
下面是修改波特率的代码:
struct termios Opt;
tcgetattr(fd, &Opt);
cfsetispeed(&Opt,B19200); /*设置为19200Bps*/
cfsetospeed(&Opt,B19200);
tcsetattr(fd,TCANOW,&Opt);
设置波特率的例子函数:
/**
*@brief 设置串口通信速率
*@param fd 类型 int 打开串口的文件句柄
*@param speed 类型 int 串口速度
*@return void
*/
int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, };
void set_speed(int fd, int speed){int i; int status; struct termios Opt;tcgetattr(fd, &Opt); for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) { if (speed == name_arr[i]) { tcflush(fd, TCIOFLUSH); cfsetispeed(&Opt, speed_arr[i]); cfsetospeed(&Opt, speed_arr[i]); status = tcsetattr(fd1, TCSANOW, &Opt); if (status != 0) { perror("tcsetattr fd1"); return; } tcflush(fd,TCIOFLUSH); } }
}
效验位和停止位的设置:
设置效验的函数:
/**
*@brief 设置串口数据位,停止位和效验位
*@param fd 类型 int 打开的串口文件句柄
*@param databits 类型 int 数据位 取值 为 7 或者8
*@param stopbits 类型 int 停止位 取值为 1 或者2
*@param parity 类型 int 效验类型 取值为N,E,O,,S
*/
int set_Parity(int fd,int databits,int stopbits,int parity)
{ struct termios options; if ( tcgetattr( fd,&options) != 0) { perror("SetupSerial 1"); return(FALSE); }options.c_cflag &= ~CSIZE; switch (databits) /*设置数据位数*/{ case 7: options.c_cflag |= CS7; break;case 8: options.c_cflag |= CS8;break; default: fprintf(stderr,"Unsupported data size\n"); return (FALSE); }
switch (parity)
{ case 'n':case 'N': options.c_cflag &= ~PARENB; /* Clear parity enable */options.c_iflag &= ~INPCK; /* Enable parity checking */ break; case 'o': case 'O': options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'e': case 'E': options.c_cflag |= PARENB; /* Enable parity */ options.c_cflag &= ~PARODD; /* 转换为偶效验*/ options.c_iflag |= INPCK; /* Disnable parity checking */break;case 'S': case 's': /*as no parity*/ options.c_cflag &= ~PARENB;options.c_cflag &= ~CSTOPB;break; default: fprintf(stderr,"Unsupported parity\n"); return (FALSE); }
/* 设置停止位*/
switch (stopbits)
{ case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break;default: fprintf(stderr,"Unsupported stop bits\n"); return (FALSE);
}
/* Set input parity option */
if (parity != 'n') options.c_iflag |= INPCK;
tcflush(fd,TCIFLUSH);
options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/
options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
if (tcsetattr(fd,TCSANOW,&options) != 0)
{ perror("SetupSerial 3"); return (FALSE);
}
return (TRUE);
}
需要注意的是:
如果不是开发终端之类的,只是串口传输数据,而不需要串口来处理,那么使用原始模式(Raw Mode)方式来通讯,设置方式如下:
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
options.c_oflag &= ~OPOST; /*Output*/
读写串口
设置好串口之后,读写串口就很容易了,把串口当作文件读写就是。
- 发送数据
char buffer[1024];int Length;int nByte;nByte = write(fd, buffer ,Length)
- 读取串口数据
使用文件操作read函数读取,如果设置为原始模式(Raw Mode)传输数据,那么read函数返回的字符数是实际串口收到的字符数。
可以使用操作文件的函数来实现异步读取,如fcntl,或者select等来操作。
char buff[1024];int Len;int readByte = read(fd,buff,Len);
关闭串口
关闭串口就是关闭文件。
close(fd);
例子
下面是一个简单的读取串口数据的例子,使用了上面定义的一些函数和头文件
/**********************************************************************
代码说明:使用串口二测试的,发送的数据是字符,
但是没有发送字符串结束符号,所以接收到后,后面加上了结束符号。
我测试使用的是单片机发送数据到第二个串口,测试通过。
**********************************************************************/
#define FALSE -1
#define TRUE 0
/*********************************************************************/
int OpenDev(char *Dev)
{int fd = open( Dev, O_RDWR ); //| O_NOCTTY | O_NDELAY if (-1 == fd) { perror("Can't Open Serial Port");return -1; } else return fd;
}
int main(int argc, char **argv){int fd;int nread;char buff[512];char *dev = "/dev/ttyS1"; //串口二fd = OpenDev(dev);set_speed(fd,19200);if (set_Parity(fd,8,1,'N') == FALSE) {printf("Set Parity Error\n");exit (0);}
while (1) //循环读取数据
{ while((nread = read(fd, buff, 512))>0){ printf("\nLen %d\n",nread); buff[nread+1] = '\0'; printf( "\n%s", buff); }
}//close(fd); // exit (0);
}
相关主题
- Serial Programming Guide for POSIX Operating Systems
- Linux 的源代码
- 代码下载: 代码
#include <stdio.h> /*标准输入输出定义*/
#include <stdlib.h> /*标准函数库定义*/
#include <unistd.h> /*Unix标准函数定义*/
#include <sys/types.h> /**/
#include <sys/stat.h> /**/
#include <fcntl.h> /*文件控制定义*/
#include <termios.h> /*PPSIX终端控制定义*/
#include <errno.h> /*错误号定义*//***@brief 设置串口通信速率
*@param fd 类型 int 打开串口的文件句柄
*@param speed 类型 int 串口速度
*@return void*/int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300,38400, 19200, 9600, 4800, 2400, 1200, 300, };
void set_speed(int fd, int speed)
{int i;int status;struct termios Opt;tcgetattr(fd, &Opt);for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++){if (speed == name_arr[i]){tcflush(fd, TCIOFLUSH);cfsetispeed(&Opt, speed_arr[i]);cfsetospeed(&Opt, speed_arr[i]);status = tcsetattr(fd, TCSANOW, &Opt);if (status != 0)perror("tcsetattr fd1");return;}tcflush(fd,TCIOFLUSH);}
}
/**
*@brief 设置串口数据位,停止位和效验位
*@param fd 类型 int 打开的串口文件句柄*
*@param databits 类型 int 数据位 取值 为 7 或者8*
*@param stopbits 类型 int 停止位 取值为 1 或者2*
*@param parity 类型 int 效验类型 取值为N,E,O,,S
*/
int set_Parity(int fd,int databits,int stopbits,int parity)
{struct termios options;if ( tcgetattr( fd,&options) != 0){perror("SetupSerial 1");return(FALSE);}options.c_cflag &= ~CSIZE;switch (databits) /*设置数据位数*/{case 7:options.c_cflag |= CS7;break;case 8:options.c_cflag |= CS8;break;default:fprintf(stderr,"Unsupported data size\n");return (FALSE);}switch (parity){case 'n':case 'N':options.c_cflag &= ~PARENB; /* Clear parity enable */options.c_iflag &= ~INPCK; /* Enable parity checking */break;case 'o':case 'O':options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/ options.c_iflag |= INPCK; /* Disnable parity checking */break;case 'e':case 'E':options.c_cflag |= PARENB; /* Enable parity */options.c_cflag &= ~PARODD; /* 转换为偶效验*/ options.c_iflag |= INPCK; /* Disnable parity checking */break;case 'S':case 's': /*as no parity*/options.c_cflag &= ~PARENB;options.c_cflag &= ~CSTOPB;break;default:fprintf(stderr,"Unsupported parity\n");return (FALSE);}/* 设置停止位*/ switch (stopbits){case 1:options.c_cflag &= ~CSTOPB;break;case 2:options.c_cflag |= CSTOPB;break;default:fprintf(stderr,"Unsupported stop bits\n");return (FALSE);}/* Set input parity option */if (parity != 'n')options.c_iflag |= INPCK;options.c_cc[VTIME] = 150; // 15 secondsoptions.c_cc[VMIN] = 0;tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */if (tcsetattr(fd,TCSANOW,&options) != 0){perror("SetupSerial 3");return (FALSE);}return (TRUE);}
/**
*@breif 打开串口
*/
int OpenDev(char *Dev)
{
int fd = open( Dev, O_RDWR ); //| O_NOCTTY | O_NDELAYif (-1 == fd){ /*设置数据位数*/perror("Can't Open Serial Port");return -1;}elsereturn fd;}
/**
*@breif main()
*/
int main(int argc, char **argv)
{int fd;int nread;char buff[512];char *dev ="/dev/ttyS1";fd = OpenDev(dev);if (fd>0)set_speed(fd,19200);else{printf("Can't Open Serial Port!\n");exit(0);}if (set_Parity(fd,8,1,'N')== FALSE){printf("Set Parity Error\n");exit(1);}while(1){while((nread = read(fd,buff,512))>0){printf("\nLen %d\n",nread);buff[nread+1]='\0';printf("\n%s",buff);}}//close(fd);//exit(0);
}
本文转自:https://www.ibm.com/developerworks/cn/linux/l-serials/
类似文章:https://www.cnblogs.com/jason-lu/articles/3173988.html
【Linux】Linux 下串口编程入门相关推荐
- Linux下串口编程入门
1. 串口简介 串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用.常用的串口是 RS-232-C 接口(又称 EIA RS-232-C)它是在 1970 年由美国电子工业协会(EI ...
- Linux 下串口编程(C++ 程序设计)
串口通信是最简单的通信方式.即使在USB 非常流行的今天,依然保留了串行通信的方式.网络上已经有大量关于Linux下 C++ 串口编程的文章,但是我依然要写这篇博文.因为网络上的资料不是内容太多,就是 ...
- Linux下串口编程(C语言版本)
Linux 系统下串口编程 1.准备工具 案例选择在Ubuntu下创建虚拟串口,作为收发使用,需要用到socat命令. 首先进行安装,本人已经安装好了,使用安装命令后,所以下面会提示一些信息,记得连网 ...
- linux实验串行端口程序设计,Linux下串口编程心得(转)
最近一段时间,需要完成项目中关于Linux下使用串口的一个部分,现在开帖记录过程点滴. 项目的要求是这样的,Qt应用程序主要完成数据采集和发送功能,一开始在google中海搜关键字"Qt串口 ...
- Linux下串口编程
文章目录 串口 驱动 安装 设备文件 测试代码 编译运行 引用 串口 电平之类的就不说了,串口使用的一般包括rs232全双工,rs422四线全双工,rs485两线半双工,rs485四线全双工几种模式, ...
- c linux下并行编程指南,Linux环境下C编程指南(第2版)
摘要: <Linux环境下C编程指南(第2版)>系统地介绍在Linux平台下用C语言进行程序开发的过程,通过列举大量的程序实例,使读者能够很快掌握在Linux平台下进行C程序开发的方法和技 ...
- 【转】MT7688学习笔记(6)——OpenWrt下串口编程
一.头文件 操作串口需要包含的头文件: #include <stdio.h> /*标准输入输出定义*/ #include <errno.h> /*错误号定义*/ #includ ...
- Linux下串口编程基础
串口知识 串行接口 (SerialInterface) 是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用 ...
- 串口设置波特率linux函数接口,Linux下串口编程之一:基础设置函数
1,串口操作需要的头文件 #include /* 标准输入输出定义 */ #include /* 标准函数库定义 */ #include /* Unix 标准函数定义 */ #include #inc ...
最新文章
- 没想到这家老牌AI公司越来越不“纯粹”了
- JVM-Java程序性能监控-初级篇
- 这是一名既能打比赛,又会发论文JD AI实验室的算法工程师,CSDN博客专家
- 小店怎么做内容营销?这个家居店铺有诀窍
- java 子类重定义变量_java子类对象和成员变量的隐写方法重写
- LeetCode 464. 我能赢吗(状态压缩+记忆化递归 / 博弈)
- 为什么Mac source ~/.bash_profile只生效一次(macOS Catalina)
- ANSI C:+++
- 《剑指 Offer I》刷题笔记 20 ~ 30 题
- 【数据科学系统学习】机器学习算法 # 西瓜书学习记录 [8] 支持向量机(二)...
- 如何阅读MySQL源码
- web第三课html课堂笔记
- Scratch(五):Scratch小游戏之超级玛丽
- 周受资从小米跳槽字节跳动任CFO、拜腾创始人戴雷将加盟恒大汽车 | 高管变动2021年3月22日-28日...
- 百度网盘上传文件时提示超过4G限制如何解决?
- [Python] 年终奖税后计算器
- “云脉文档管理”微信小程序提供高效的办公体验
- 小程序源码:游戏助手王者战力查询扫码登录多功能微信小程序
- Jmeter察看结果树的响应数据中的中文显示乱码问题处理
- 最新计算机cpu简介,计算机cpu的类型是什么?计算机CPU分类简介
热门文章
- CC2541解析广播数据及扫描响应
- 华山全敏还是全劲_楚留香:最全的华山攻略,一个老华山的毕身所学!
- VS Code(windows) mingw64
- 《见与不见》——仓央嘉措
- 港大计算机专业世界排名,香港大学优势专业及优势专业排名(QS世界排名)
- mysql自带的邮件发送功能_Python实现的查询mysql数据库并通过邮件发送信息功能...
- Java封装详解,很简单
- vue报错:Non-nested routes must include a leading slash character. Fix the following routes
- [转]DirectShow应用——视频捕捉WDM Vs VFW
- STM32F030C8T6芯片参数和内部资源