编程背景:板子是linux 2.6.39系统,人机交互接口是板子上的一个串口。输入命令时,当长度大于8时,发现read读取到的数据是分多次得到的(串口用非阻塞模式读取数据),比如输入的字符长度为25(循环读取,下面贴代码):第一次读取8个,并发生串口中断(发生中断后中间会有一小会读不到数据,实测),然后又读取8个、8个、1个(‘\0’不占位),查了下原因,好多网友也遇到了这个问题,看了几个帖子都没直接说出解决办法。原来这个和串口设备的缓冲有关,常见的缓冲大小是8bytes,既然能收到数据,那就自己撸代码来一次一次的接收,然后放到缓存里面去,直到接收满足预定的为止
编程目的:串口接收输入任意长度的字符串(有上限),放入缓存字符数组中
#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 <string.h> #include <limits.h> #include <asm/ioctls.h> #include <time.h> #include <pthread.h> #include "GPRS.h" #define DATA_LEN 0xFF #define BUFSIZE 512 char read_buf[256] = {'\0'}; char read_nBytes[10] = {0}; int openSerial_GPRS(char *cSerialName, unsigned int Baud) { int iFd; struct termios opt; iFd = open(cSerialName, O_RDWR|O_NOCTTY|O_NONBLOCK|O_NDELAY);//|O_NONBLOCK 特别注意这里的串口打开属性设置 if(iFd < 0) { perror(cSerialName); return -1; } tcgetattr(iFd, &opt); switch(Baud) { case 115200: cfsetispeed(&opt, B115200);cfsetospeed(&opt, B115200);break; case 57600: cfsetispeed(&opt, B57600);cfsetospeed(&opt, B57600);break; case 38400: cfsetispeed(&opt, B38400);cfsetospeed(&opt, B38400);break; case 19200: cfsetispeed(&opt, B19200);cfsetospeed(&opt, B19200);break; case 9600: cfsetispeed(&opt, B9600) ;cfsetospeed(&opt, B9600);break; case 4800: cfsetispeed(&opt, B4800) ;cfsetospeed(&opt, B4800);break; case 2400: cfsetispeed(&opt, B2400) ;cfsetospeed(&opt, B2400);break; default: break; } /* * raw mode */ opt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); opt.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); opt.c_oflag &= ~(OPOST); opt.c_cflag &= ~(CSIZE | PARENB); opt.c_cflag |= CS8; /* * 'DATA_LEN' bytes can be read by serial */ opt.c_cc[VMIN] = DATA_LEN; opt.c_cc[VTIME] = 150; if (tcsetattr(iFd, TCSANOW, &opt)<0) { return -1; } return iFd; } void gprs_send_test(int fd) { char tmp[1024]; int len; int i; for(i = 0; i < 16; i++) tmp[i] = i%0xFF; len = write(fd, tmp, 16); printf("len = %d\n", len); } //粘连的字符串最后保存在*p指向的地址所在的内存中 static int mystrcat(char *p,char *q) { int ret = -1; char *pp = p; ret = (p != NULL) && (q != NULL); if(ret) { while(*pp != '\0') { pp++; } while(*q != '\0') { *(pp++) = *(q++); } *(pp) = '\0'; } return ret; } void gprs_recieve_test1(int fd) { int i = 0; static int len = 0; int readnum = 0; //bzero(read_buf,sizeof(read_buf)); bzero(read_nBytes,sizeof(read_nBytes)); while((readnum = read(fd,read_nBytes,8))>0) { len += readnum; if(readnum == 8) { read_nBytes[readnum] = '\0'; mystrcat(read_buf,read_nBytes); } if(readnum > 0 && readnum < 8) { read_nBytes[readnum] = '\0'; mystrcat(read_buf,read_nBytes); printf("read_buf:%d\n", len); printf("read_buf:%s\n", read_buf); len = 0; //bzero(read_buf,sizeof(read_buf)); bzero(read_buf,sizeof(read_buf)); } } }
void *thread_func(void *arg)
{
/* 这里定义了一个指向argument类型结构体的指针arg_thread1 */
//struct argument *arg_thread1;
//arg_thread1=(struct argument *)arg;
while(1)
{
gprs_recieve_test1(fd);
usleep(200);
}
return (void *)123;
}
此处发送的回车换行符也存储在字符数组中,所以发送的字符比接收到字符少两个
串口设置部分这里就不啰嗦了 网上很全
下面是运行效果图: