本帖最后由 zt1234 于 2018-6-6 10:02 编辑
试用的目的是设计一个DTU,串口通信是基础。看看EVB335X的串口电路图如下:
查看串口 ls -l /dev/tty*
测试串口 在EVB335X上执行#/usr/test/serial /dev/ttyO(大写欧)2 9600 8 0 1,则在测试串口上发送即可收到回送,测试成功。
Linux对所有设备的访问是通过设备文件来进行的,访问串口只需打开系统的/dev下面的设备即可。串口属性定义在结构体structtermios中,详细参见https://blog.csdn.net/yemingzhu163/article/details/5873851, https://blog.csdn.net/u011192270/article/details/48174353 例程如下: #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h>/*Unix 标准函数定义*/ #include <fcntl.h>/*文件控制定义*/ #include <string.h> #include <termio.h> /*PPSIX 终端控制定义*/ #include <time.h> #define MAX_BUF_SIZE 1024 char buf[MAX_BUF_SIZE+2]; int read_data(int fd, void*buf, int len) { int count; int ret; ret = 0; count = 0; ret = read(fd,(char*)buf + count, len); if (ret < 1) {fprintf(stderr, "Read error%s\n", strerror(errno));} count += ret; len = len - ret; *((char*)buf + count) = 0; return count; } int write_data(int fd, void*buf, int len) { int count; int ret; ret = 0; count = 0; while (len > 0) { ret = write(fd,(char*)buf + count, len); if (ret < 1) {fprintf(stderr, "Write error%s\n", strerror(errno));break;} count += ret; len = len - ret; } return count; }
int main(intargc, char *argv[]) { int fd; int len,count,i; struct termio term_attr,oterm_attr; fd= open("/dev/ttyO2", O_RDWR);//ttyS0
if (ioctl(fd, TCGETA, &term_attr) < 0) {return -1;}// Get current setting memcpy(&oterm_attr, &term_attr, sizeof(struct termio));//Backup old setting term_attr.c_iflag &= ~(INLCR | IGNCR | ICRNL |ISTRIP); term_attr.c_oflag &= ~(OPOST | ONLCR | OCRNL); term_attr.c_lflag&= ~(ISIG | ECHO | ICANON | NOFLSH); term_attr.c_cflag &= ~CBAUD; term_attr.c_cflag |= CREAD |B9600; term_attr.c_cflag &= ~(CSIZE); term_attr.c_cflag |= CS8; term_attr.c_cflag &= ~(PARENB);//nono term_attr.c_cflag &= ~CSTOPB;//1 term_attr.c_cc[VMIN] = 1; term_attr.c_cc[VTIME] = 0; if (ioctl(fd, TCSETAW, &term_attr) < 0) {return -1;} if (ioctl(fd, TCFLSH, 2) < 0) {return -1;} count= 0; while ( (len = read(fd, buf, MAX_BUF_SIZE)) > 0 ) { printf("Get data! %s\n",buf);//显示接收的数据 i= write_data(fd, buf, len);//回送接收的数据 if (i == 0) {fprintf(stderr, "Send data error!\n");break;} } if (ioctl(fd, TCSETAW, &oterm_attr) < 0){ return -1;} close(fd); return 0;
} 在ECLIPSE中编辑、编译、拷贝到EVB335X执行成功。
调试单步执行时会停在read()函数上,等待读取数据,此为阻塞函数。
read(intfd,char *p,int nbyte),最后参数nbyte的意义是,如果缓存有大于nbyte个数的数据那么只返回nbyte个数据,剩余的数据下次再去读时才能读到。如果缓存中只有少于nbyte个数据,会等待options.c_cc[VTIME]的时间则返回,并且读取少于nbyte的实际数量的数据。这个等待就是阻塞,在单线程的程序里主线程被阻塞则整个程序被锁死。但非阻塞read函数在没有数据时会返回错误,一直查询返回值会降低效率。这个问题的解决方法一个是多线程,另一个方法就是select函数。 这里先使用select函数先查询串口再读,并且延时到了就返回。int select(nfds, readfds, writefds,exceptfds, timeout) 超时返回0,失败返回-1,成功返回就绪的数目。其中ndfs要监视的句柄数,readfds监视的可读句柄集合,writefds监视的可写文件集合,exceptfds监视的异常文件集合,timeout监视的超时结束时间。该函数在readfds或writefds的文件可读或可写或有异常或超时就返回。struct timeval* timeout可以使select处于三种状态:第一若是NULL即不传入时间,就将select置于阻塞状态,一定等到某个文件发生为止;第二若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管是否有变化都立刻返回,文件无变化返回0,有变化返回一个正值;第三timeout的值大于0这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件就返回了,否则在超时后不管怎样一定返回。使用时涉及到的宏有全部清零的FD_ZERO(&rd),设置某一位的FD_SET(fd,&rd),测试某一位的FD_ISSET(fd,&rd)。测试代码如下
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <termio.h> #include <time.h> #define MAX_BUF_SIZE 1024 char buf[MAX_BUF_SIZE+2];
int main(intargc, char *argv[]) {struct termio term_attr,oterm_attr; int fd; int nread,nwrite,err; struct timeval tv; char buff[]="Hello!\r\n"; fd= open("/dev/ttyO2", O_RDWR);
memcpy(&oterm_attr, &term_attr, sizeof(struct termio));//Backup old setting term_attr.c_iflag &= ~(INLCR | IGNCR |ICRNL |ISTRIP); term_attr.c_oflag &= ~(OPOST | ONLCR |OCRNL); term_attr.c_lflag&= ~(ISIG | ECHO |ICANON | NOFLSH); term_attr.c_cflag &= ~CBAUD; term_attr.c_cflag |= CREAD |B9600; term_attr.c_cflag &= ~(CSIZE); term_attr.c_cflag |= CS8; term_attr.c_cflag &= ~(PARENB);//nono term_attr.c_cflag &= ~CSTOPB;//1 term_attr.c_cc[VMIN] = 1; term_attr.c_cc[VTIME] = 0; if (ioctl(fd, TCSETAW, &term_attr) < 0) {return -1;} if (ioctl(fd, TCFLSH, 2) < 0) {return -1;}
nwrite=write(fd,buff,8); printf("nwrite=%d,%s\n",nwrite,buff); tv.tv_sec = 5; tv.tv_usec = 0; fd_set rd; FD_ZERO(&rd);// FD_SET(fd,&rd); while(FD_ISSET(fd,&rd)) { err= select(fd+1,&rd,NULL,NULL,&tv); if(err == 0){printf("select time out!\n");} //超时 else if(err == -1){ printf("fail to select!\n");} //失败 else { printf("data is available!\n"); while((nread = read(fd,buff,8))>0){printf("nread = %d,%s\n",nread,buff);} }//成功 } close(fd); return 0; }
|