Linux 串口编程
来源:互联网 发布:怎么把照片导入mac 编辑:程序博客网 时间:2024/06/05 09:17
在linux中,所有的设备文件一般位于"/dev"目录下,其中串口对应的名称为"/dev/ttySx",(因驱动不同,该设备名也会有所不同),可也查看在"/dev"下的文件以确认。在linux下对设备的操作方法与对文件操作方法一样,因此,对串口的读写就可以使用简单的read,write等函数来完成,所不同的只是需要对串口的其他参数另做配置。
串口的设置主要是设置structtermios结构体中的成员,如下所示.
struct termios
{
tcflag_t c_iflag; //输入模式标志
tcflag_t c_oflag; //输出模式标志
tcflag_t c_cflag; //控制模式标志
tcflag_t c_lflag; //本地模式标志
cc_t c_line; //线路规则
cc_t c_cc[NCC]; //控制特性
}
C_iflag支持的常量名称如下表所示,其用于控制端口接收端的字符输入处理。
键 值
说 明
IGNBRK
忽略BREAK键输入
BRKINT
如果设置了IGNBRK,BREAK键的输入将被忽略,如果设置了BRKINT ,将产生SIGINT中断
IGNPAR
忽略奇偶校验错误
PARMRK
标识奇偶校验错误
INPCK
允许输入奇偶校验
ISTRIP
去除字符的第8个比特
INLCR
将输入的NL(换行)转换成CR(回车)
IGNCR
忽略输入的回车
ICRNL
将输入的回车转化成换行(如果IGNCR未设置的情况下)
IUCLC
将输入的大写字符转换成小写字符(非POSIX)
IXON
允许输入时对XON/XOFF流进行控制
IXANY
输入任何字符将重启停止的输出
IXOFF
允许输入时对XON/XOFF流进行控制
IMAXBEL
当输入队列满的时候开始响铃,Linux在使用该参数而是认为该参数总是已经设置
C_oflag支持的常量名称如下表所示,其用于控制终端端口发送出去的字符处理。
键 值
说 明
OPOST
处理后输出
OLCUC
将输入的小写字符转换成大写字符(非POSIX)
ONLCR
将输入的NL(换行)转换成CR(回车)及NL(换行)
OCRNL
将输入的CR(回车)转换成NL(换行)
ONOCR
第一行不输出回车符
ONLRET
不输出回车符
OFILL
发送填充字符以延迟终端输出
OFDEL
以ASCII码的DEL作为填充字符,如果未设置该参数,填充字符将是NUL(‘\0’)(非POSIX)
NLDLY
换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)
CRDLY
回车延迟,取值范围为:CR0、CR1、CR2和 CR3
TABDLY
水平制表符输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3
BSDLY
空格输出延迟,可以取BS0或BS1
VTDLY
垂直制表符输出延迟,可以取VT0或VT1
FFDLY
换页延迟,可以取FF0或FF1
C_cflag支持的常量名称如下表所示,其是结构中最重要的一个,通过对他的赋值,用户可以设置波特率,字符大小,数据位,停止位,奇偶校验位和硬件流控等。但是c_cflag中的成员不能直接对其初始化,需要将其通过“或”、“与”操作使用其中的某些选项。
键 值
说 明
CBAUD
波特率(4+1位)(非POSIX)
CBAUDEX
附加波特率(1位)(非POSIX)
CSIZE
字符长度,取值范围为CS5、CS6、CS7或CS8
CSTOPB
设置两个停止位
CREAD
使用接收器
PARENB
使用奇偶校验
PARODD
对输入使用奇偶校验,对输出使用偶校验
HUPCL
关闭设备时挂起
CLOCAL
忽略调制解调器线路状态
CRTSCTS
使用RTS/CTS流控制
C_lflag支持的常量名称如下表所示,其用于控制终端的本地数据处理和工作模式。
键 值
说 明
ISIG
当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
ICANON
使用标准输入模式
XCASE
在ICANON和XCASE同时设置的情况下,终端只使用大写。如果只设置了XCASE,则输入字符将被转换为小写字符,除非字符使用了转义字符(非POSIX,且Linux不支持该参数)
ECHO
显示输入字符
ECHOE
如果ICANON同时设置,ERASE将删除输入的字符,WERASE将删除输入的单词
ECHOK
如果ICANON同时设置,KILL将删除当前行
ECHONL
如果ICANON同时设置,即使ECHO没有设置依然显示换行符
ECHOPRT
如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)
TOSTOP
向后台输出发送SIGTTOU信号
C_cc[nccs]支持的常量名称如下表所示
宏
说 明
宏
说 明
VINTR
Interrupt字符 ,对应键 “ctrl+c”
VEOL
附加的End-of-file字符
VQUIT
Quit字符 ,”ctrl+z”
VTIME
非规范模式读取时的超时时间
VERASE
Erase字符 , “backspace”
VSTOP
Stop字符
VKILL
Kill字符 ,”ctrl+u”
VSTART
Start字符
VEOF
End-of-file字符 ,”ctrl+d”
VSUSP
Suspend字符
VMIN
非规范模式读取时的最小字符数
操作串口的控制函数
函数名
说明
Tcgetattr
获取属性(termios结构)
Tcsetattr
设置属性(termios结构)
Tcsendbreak
发送break字符
Tcdrain
等待所有输出都被传输(使程序阻塞,直到输出缓冲区中的数据全部发送完毕)
tcflow
挂起传输或接收(用于暂停或重新开始输出)
Tcflush
用于清空输入/输出缓冲区
cfmakeraw
设置串口模式为原始模式
Cfgetispeed
获取输入波特率
Cfgetospeed
获取输出波特率
Cfsetispeed
设置输入波特率
Cfsetospeed
设置输出波特率
cfsetspeed
设置波特率
Linux串口实现-uart.c
/************************************************************************************************************* * 文件名: uart.c * 功能: Linux串口操作函数 * 作者: oxp_edward@163.com * 创建时间: 2014年12月31日 * 最后修改时间:2014年12月31日 * 详细: 无*************************************************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h>#include <sys/stat.h>#include <fcntl.h> #include <termios.h> #include <errno.h> #include <strings.h>static int SerialPortFd = 0; //保存串口的文件描述符/**************************************************************************************************************************函数 :int SerialIsValid(void)*功能 : 检查串口文件描述符的有效性*参数 : 无*返回 : 0:有效 -1:无效*依赖 : 无*作者 : edward*时间 : 20141231*最后修改时间: 20141231*说明 : 无*************************************************************************************************************************/static int SerialIsValid(void){//SerialPortFd 安全检查if(0 == SerialPortFd){perror("SerialPortFd is invalid");return -1;}return 0;}/**************************************************************************************************************************函数 :int SerialIsValid(void)*功能 : 检查串口文件描述符的有效性*参数 : 无*返回 : 0:有效 -1:无效*依赖 : 无*作者 : edward*时间 : 20141231*最后修改时间: 20141231*说明 : 无*************************************************************************************************************************/int SerialOpen(const char *devicePath){SerialPortFd = open(devicePath,O_RDWR | O_NOCTTY | O_NDELAY);if(SerialPortFd < 0){perror(devicePath);printf("%s open failed\n",devicePath);return -1;}return 0;}/**************************************************************************************************************************函数 :int SerialConfig(int nSpeed,int nBits,char nEvent,int nStop)*功能 : 串口参数设置*参数 : nSpeed:波特率 nBits :数据位 nEvent:奇偶校验位 nStop :停止位*返回 : 0:设置成功 -1:设置失败*依赖 : 无*作者 : edward*时间 : 20141231*最后修改时间: 20141231*说明 : 无*************************************************************************************************************************/int SerialConfig(int nSpeed,int nBits,char nEvent,int nStop){int rtn = 0;int speed = 0;struct termios NewConfig,OldConfig;//SerialPortFd 安全检查if(SerialIsValid())return -1;//1、保存原串口配置/*tcgetattr(serialPortFd,&options)得到与SerialFd指向对象的相关参数,并将它们保存于oldtio,该函数,还可以测试配置是否正确,该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1.*/rtn = tcgetattr(SerialPortFd,&OldConfig);if(0 != rtn){perror("Error on tcgetattr");return -1;}bzero(&NewConfig,sizeof(NewConfig));//2、激活选项//CLOCAL:修改控制模式,保证程序不会占用串口//CREAD:修改控制模式,接收使能,使得能够从串口中读取输入数据NewConfig.c_cflag |= CLOCAL | CREAD;//3、设置数据位//在设置数据位时,需要先使用CSIZE位清空数据位设置,然后再设置相应的数据位NewConfig.c_cflag &= ~CSIZE;switch(nBits){case 8: NewConfig.c_cflag |= CS8;break;case 7: NewConfig.c_cflag |= CS7;break;case 6: NewConfig.c_cflag |= CS6;break;case 5: NewConfig.c_cflag |= CS5;break;default:printf("Error on nBits\n");return -1;}//4、设置奇偶校验位//设置奇偶校验需要使用到termiso中的两个成员:c_cflag和c_iflag,//首先激活c_cflag中的校验位使能标志PARENB,这样会对输出数据产生校验位,//而输入数据进行校验检测。同时还要激活c_iflag中的对于输入数据的奇偶校验使能INPCK//c_cflag中的PARODD为1时使用奇校验,为0时使用偶校验switch(nEvent){case 'o':case 'O': //设置为奇校验NewConfig.c_cflag |=(PARODD|PARENB);NewConfig.c_iflag |= INPCK;break;case 'e':case 'E': //设置为偶校验NewConfig.c_cflag |=PARENB;NewConfig.c_cflag &= ~PARODD;NewConfig.c_iflag |= INPCK;break;case 's':case 'S':/*as no parity*/NewConfig.c_cflag &=~PARENB;NewConfig.c_cflag &= ~CSTOPB;break;case 'n':case 'N': //设置无奇偶校验位NewConfig.c_cflag &= ~PARENB;NewConfig.c_iflag &= ~INPCK;break;default:printf("Error on nEvent\n");return -1;}//5、设置波特率switch(nSpeed){case 2400: speed = B2400; break;case 4800: speed = B4800; break;case 9600: speed = B9600; break;case 19200: speed = B19200; break;case 38400: speed = B38400; break;case 115200: speed = B115200; break;default:printf("Error on nSpeed\n");return -1;}cfsetispeed(&NewConfig,speed);cfsetospeed(&NewConfig,speed);//6、设置停止位//设置停止位是通过激活c_cflag中的CSTOPB而实现的。若停止位为1个,这清除CSTOPB,若停止位为2个,则激活CSTOPBswitch(nStop){case 1: NewConfig.c_cflag &= ~CSTOPB;break;case 2: NewConfig.c_cflag |= CSTOPB;break;default:printf("Error on nStop\n");return;}//7、设置等待时间和最小接收字符NewConfig.c_cc[VTIME] = 0;//读取一个字符等待1*(1/10)sNewConfig.c_cc[VMIN] = 0;//读取字符的最少个数//8、清除串口缓冲//在串口重新设置后,需要对当前的串口设备进行适当的处理,//这时可以调用tcdrain,tcflow,tcflush等函数来处理目前串口缓冲区中的数据//tcdrain 函数使程序阻塞,直到输出缓冲区中的数据全部发送完毕//tcflow 函数用于暂停或重新开始输出//tcflush 函数用于清空输入/输出缓冲区//如果发生数据溢出,接收数据,但是不再读取tcflush(SerialPortFd,TCIFLUSH);//9、激活配置//在串口配置完成后,需要使用tcsetattr函数激活配置。rtn = tcsetattr(SerialPortFd,TCSANOW,&NewConfig);if(0 != rtn){perror("Error on tcsetattr");return -1;}printf("Serial Set Done\n");return 0;}/**************************************************************************************************************************函数 :int SerialReceive(unsigned char *buf,int size)*功能 : 串口接收数据*参数 : buf: 接收缓冲区 size:缓冲区大小*返回 :错误-1,返回接收数据的大小*依赖 : 无*作者 : edward*时间 : 20141231*最后修改时间: 20141231*说明 : 无*************************************************************************************************************************/int SerialReceive(unsigned char *buf,int size){int rtn ;//SerialPortFd 安全检查if(SerialIsValid())return -1;rtn = read(SerialPortFd,buf,size);//printf("ReadLength = %d\n",rtn);return rtn;}/**************************************************************************************************************************函数 : int SerialSend(unsigned char *buf,int DataLength)*功能 : 串口发送数据*参数 : buf:发送缓冲区 DataLength:需要发送的字节数*返回 : rtn:成功发送的字节数 -1:发送失败*依赖 : 无*作者 : edward*时间 : 20141231*最后修改时间: 20141231*说明 : 无*************************************************************************************************************************/int SerialSend(unsigned char *buf,int DataLength){int rtn ;//SerialPortFd 安全检查if(SerialIsValid())return -1;#if 0int remain = DataLength;int offset = 0;int sub = 0;while(remain > 0 ){sub = (remain >= 8? 8:remain);write(SerialPortFd,buf+offset,sub);tcflush(SerialPortFd,TCOFLUSH);remain -= 8;offset += 8;}#elsertn = write(SerialPortFd,buf,DataLength);#endifreturn rtn;}/**************************************************************************************************************************函数 : int SerialIsValid(void)*功能 : 关闭串口*参数 : 无*返回 : 0:关闭成功*依赖 : 无*作者 : edward*时间 : 20141231*最后修改时间: 20141231*说明 : 无*************************************************************************************************************************/int SerialClose(void){//SerialPortFd 安全检查if(SerialIsValid())return -1;close(SerialPortFd);return 0;}
uart.h头文件
#ifndef __UART_H__#define __UART_H__int SerialOpen(const char *devicePath);int SerialConfig(int nSpeed,int nBits,char nEvent,int nStop);int SerialReceive(unsigned char *buf,int size);int SerialSend(unsigned char *buf,int DataLength);int SerialClose(void);#endif
uart-test测试文件,固定发送字符,并接收,硬件上将串口的RX与TX相连接
#include <stdio.h>#include <string.h>#include "uart.h"int main(int argc,char**argv){int rtn;int Count = 0;unsigned char *send = "Hello Uart";unsigned char buf[1024] ={0};if(2 > argc){printf("Input error\n");printf("Usage: %s <Device>\n",argv[0]);printf("Eample: %s /dev/ttyS0\n",argv[0]);return -1;}//打开串口rtn = SerialOpen(argv[1]);if(0 > rtn)return -1;//配置串口rtn = SerialConfig(115200,8,'n',1);if(0 > rtn)return -1;//循环发送与接收while(1){//发送数据rtn = SerialSend(send,strlen(send));if(0 < rtn){printf("[Send]: %s\n",send);}sleep(1);//接收数据rtn = SerialReceive(buf,sizeof(buf));if(0 < rtn){printf("[Recv]: %s\n",buf);}}}
- Linux 串口编程
- Linux下串口编程
- Linux串口编程分析
- Linux串口编程
- Linux串口编程
- Linux串口编程
- Linux串口编程
- Linux 下串口编程
- Linux串口编程
- Linux串口编程
- linux串口通信编程
- linux串口编程
- linux 串口编程
- linux串口编程
- linux串口编程
- linux 串口编程
- Linux串口编程分析
- linux 串口编程
- 【linux学习日记】Windows_grub引导的修复
- Kafka的Producer和Consumer源码学习
- LeetCode - Palindrome Partitioning II 题解
- patch文件的格式(ns2的)
- MoreWindows博客目录(微软最有价值专家博客,原创技术文章152篇,访问量164万)
- Linux 串口编程
- spring+hibernate 关联映射
- 工作日志
- 101个MySQL的调节和优化的提示
- 数组中只出现一次的数
- python学习:继承
- va_list 简介
- 【转】在单板上通过串口调试内核
- 使用setAction()方法来启动目标Activity