分类:
2013-01-06 17:04:58
原文地址:Linux 串口读写(二) 作者:sohu2000000
例子
下面是一个简单的读取串口数据的例子,使用了上面定义的一些函数和头文件
/********************************************************************** * 代码说明:使用串口二测试的,发送的数据是字符,但是没有发送字符串结束符号, * 所以接收到后,后面加上了结束符号。我测试使用的是单片机发送数据到第二个串口,测试通过。 **********************************************************************/ #define FALSE -1 #define TRUE 0 /*********************************************************************/ int OpenDev(char *Dev) { //Dev 就是设备,设备就是文件,就是给出该设备文件的路径 int fd = open(Dev, O_RDWR ); //| O_NOCTTY | O_NDELAY if (-1 == fd) { perror("Can't 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); } |
1、虚拟机下使用串口的方法
使用vmwave,默认串口设备是没有添加的,通过vmwave将设备加入即可正常使用串口。虚拟机串口打开后,可能会占用windows下的串口。另外,虚拟机的串口收发比正常的速度的确要慢许多。
2、消除Linux串口收发的一些规则
Linux 串口收发有许多模式,如:
(1) 接收返回模式: 如果串口没有接收到数据,read()函数不返回。
(2) 数据接收\n才返回接收的数据,否则read()函数返回0
(3) 特殊字符解析问题,部分特殊字符接收/发送时,会被屏蔽或者转义。如发送0x
(4) 接收反馈:如串口接收到数据,立即将该数据发送出去。
(上面是我遇到的一些问题,可能表述不很清楚,呵呵。如果用于收发txt文件,一般不大注意。)
3、解决问题的方法是,消除这些默认规则,关键是struct termios 的参数影响。
struct termios {
tcflag_t c_iflag; /**//* 输入模式旗标 */
tcflag_t c_oflag; /**//* 输出模式旗标 */
tcflag_t c_cflag; /**//* 控制模式旗标 */
tcflag_t c_lflag; /**//* 区域模式旗标 */
cc_t c_line; /**//* 行控制 (line discipline) */
cc_t c_cc[NCCS]; /**//* 控制特性 */
};
由于研究不深,如果要消除所有上面的规则,我是如下处理的
struct termios options;
串口打开方式:
open ("dev/ttyS0" , O_RDWR|O_NOCTTY| O_NDELAY );
消除收发模式规则:
options.c_lflag = 0;
options.c_oflag = 0;
options.c_iflag = 0;
消除字符屏蔽规则:
options.c_cc[VINTR] = 0; /**//* Ctrl-c */
options.c_cc[VQUIT] = 0; /**//* Ctrl- */
options.c_cc[VERASE] = 0; /**//* del */
options.c_cc[VKILL] = 0; /**//* @ */
options.c_cc[VEOF] = 0; /**//* Ctrl-d */
options.c_cc[VTIME] = 1; /**//* */
options.c_cc[VMIN] = 0; /**//* */
options.c_cc[VSWTC] = 0; /**//* '' */
options.c_cc[VSTART] = 0; /**//* Ctrl-q */
options.c_cc[VSTOP] = 0; /**//* Ctrl-s */
options.c_cc[VSUSP] = 0; /**//* Ctrl-z */
options.c_cc[VEOL] = 0; /**//* '' */
options.c_cc[VREPRINT] = 0; /**//* Ctrl-r */
options.c_cc[VDISCARD] = 0; /**//* Ctrl-u */
options.c_cc[VWERASE] = 0; /**//* Ctrl-w */
options.c_cc[VLNEXT] = 0; /**//* Ctrl-v */
options.c_cc[VEOL2] = 0; /**//* '' */
以上设置,在其它参数串口设置前执行,如果你需要保留部分参数,请参阅http://blog.chinaunix.net/article.php?articleId=15964&blogId=60
在RedHat Feroda 4 下编译通过
= = = = = = = = = = = 非阻塞read= = = = = = = = = = =
Q:在调用串口read(fd, buff, len);时,如果串口没有数据,会停在read处,请问有没有办法让这个read动作中止?
A:使用非阻塞方式select函数(I/O多工机制)或者open的时候加O_NONBLOCK参数。
int select(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout);关于这个函数的使用我会在下篇blog中整理。
= = = = = = = = = = = 串口收发源码= = = = = = = = = = =
一下代码已经经过我测试,没有问题。开发环境Redhat9,运行环境s
= = = = = = receive.c= = = = = =
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define TRUE 1
//初始化串口选项:
void setTermios(struct termios * pNewtio, int uBaudRate)
{
bzero(pNewtio, sizeof(struct termios)); /* clear struct for new port settings */
//8N1
pNewtio->c_cflag = uBaudRate | CS8 | CREAD | CLOCAL;
pNewtio->c_iflag = IGNPAR;
pNewtio->c_oflag = 0;
pNewtio->c_lflag = 0; //non ICANON
/*
initialize all control characters
default values can be found in /usr/include/termios.h, and
are given in the comments, but we don't need them here
*/
pNewtio->c_cc[VINTR] = 0; /* Ctrl-c */
pNewtio->c_cc[VQUIT] = 0; /* Ctrl-\ */
pNewtio->c_cc[VERASE] = 0; /* del */
pNewtio->c_cc[VKILL] = 0; /* @ */
pNewtio->c_cc[VEOF] = 4; /* Ctrl-d */
pNewtio->c_cc[VTIME] = 5; /* inter-character timer, timeout VTIME*0.1 */
pNewtio->c_cc[VMIN] = 0; /* blocking read until VMIN character arrives */
pNewtio->c_cc[VSWTC] = 0; /* '\0' */
pNewtio->c_cc[VSTART] = 0; /* Ctrl-q */
pNewtio->c_cc[VSTOP] = 0; /* Ctrl-s */
pNewtio->c_cc[VSUSP] = 0; /* Ctrl-z */
pNewtio->c_cc[VEOL] = 0; /* '\0' */
pNewtio->c_cc[VREPRINT] = 0; /* Ctrl-r */
pNewtio->c_cc[VDISCARD] = 0; /* Ctrl-u */
pNewtio->c_cc[VWERASE] = 0; /* Ctrl-w */
pNewtio->c_cc[VLNEXT] = 0; /* Ctrl-v */
pNewtio->c_cc[VEOL2] = 0; /* '\0' */
}
#define BUFSIZE 512
int main(int argc, char **argv)
{
int fd;
int nread;
char buff[BUFSIZE];
struct termios oldtio, newtio;
struct timeval tv;
char *dev ="/dev/ttyS1";
fd_set rfds;
if ((fd = open(dev, O_RDWR | O_NOCTTY))<0)
{
printf("err: can't open serial port!\n");
return -1;
}
tcgetattr(fd, &oldtio); /* save current serial port settings */
setTermios(&newtio, B115200);
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newtio);
tv.tv_sec=30;
tv.tv_usec=0;
while (TRUE)
{
printf("wait...\n");
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
if (select(1+fd, &rfds, NULL, NULL, &tv)>0)
{
if (FD_ISSET(fd, &rfds))
{
nread=read(fd, buff, BUFSIZE);
printf("readlength=%d\n", nread);
buff[nread]='\0';
printf("%s\n", buff);
}
}
}
tcsetattr(fd, TCSANOW, &oldtio);
close(fd);
}
= = = = = send.c= = = = = =
#include
#include
#include
#include
#include
#include
#include
#include
#include
//初始化串口选项:
void setTermios(struct termios * pNewtio, int uBaudRate)
{
bzero(pNewtio, sizeof(struct termios)); /* clear struct for new port settings */
//8N1
pNewtio->c_cflag = uBaudRate | CS8 | CREAD | CLOCAL;
pNewtio->c_iflag = IGNPAR;
pNewtio->c_oflag = 0;
pNewtio->c_lflag = 0; //non ICANON
/*
initialize all control characters
default values can be found in /usr/include/termios.h, and
are given in the comments, but we don't need them here
*/
pNewtio->c_cc[VINTR] = 0; /* Ctrl-c */
pNewtio->c_cc[VQUIT] = 0; /* Ctrl-\ */
pNewtio->c_cc[VERASE] = 0; /* del */
pNewtio->c_cc[VKILL] = 0; /* @ */
pNewtio->c_cc[VEOF] = 4; /* Ctrl-d */
pNewtio->c_cc[VTIME] = 5; /* inter-character timer, timeout VTIME*0.1 */
pNewtio->c_cc[VMIN] = 0; /* blocking read until VMIN character arrives */
pNewtio->c_cc[VSWTC] = 0; /* '\0' */
pNewtio->c_cc[VSTART] = 0; /* Ctrl-q */
pNewtio->c_cc[VSTOP] = 0; /* Ctrl-s */
pNewtio->c_cc[VSUSP] = 0; /* Ctrl-z */
pNewtio->c_cc[VEOL] = 0; /* '\0' */
pNewtio->c_cc[VREPRINT] = 0; /* Ctrl-r */
pNewtio->c_cc[VDISCARD] = 0; /* Ctrl-u */
pNewtio->c_cc[VWERASE] = 0; /* Ctrl-w */
pNewtio->c_cc[VLNEXT] = 0; /* Ctrl-v */
pNewtio->c_cc[VEOL2] = 0; /* '\0' */
}
int main(int argc, char **argv)
{
int fd;
int nCount, nTotal, i;
struct termios oldtio, newtio;
char *dev ="/dev/ttyS1";
if ((argc!=3) || (sscanf(argv[1], "%d", &nTotal) != 1))
{
printf("err: need tow arg!\n");
return -1;
}
if ((fd = open(dev, O_RDWR | O_NOCTTY))<0)
{
printf("err: can't open serial port!\n");
return -1;
}
tcgetattr(fd, &oldtio); /* save current serial port settings */
setTermios(&newtio, B115200);
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newtio);
for (i=0; i
{
nCount=write(fd, argv[2], strlen(argv[2]));
printf("send data\n");
sleep(1);
}
tcsetattr(fd, TCSANOW, &oldtio);
close(fd);
return 0;
}
= = = = = =.makefile= = = = = =
CC = /usr/local/arm/2.95.3/bin/arm-linux-gcc
all:receive send
receive: receive.c
$(CC) receive.c -o receive
send: send.c
$(CC) send.c -o send
clean:
-rm -rf testCOM receive send
到此基本就结束了,可能代码注释比较少些,写的太着急了,等有时间整理一下。最好再看看上一篇blog这样能更好的理解串口。