在Linux环境下,采用C编程,为了使用串口接收完整包。采用超时接收的方法。
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/timerfd.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#define bzero(buffer, size) memset(buffer, 0, size)
#define ARRAY_LEN(array) (sizeof(array) / sizeof(*array))
fd_set mRd;
struct timeval mTimeout;
static speed_t getBaudrate(int baudrate)
{
switch (baudrate)
{
case 0:
return B0;
case 50:
return B50;
case 75:
return B75;
case 110:
return B110;
case 134:
return B134;
case 150:
return B150;
case 200:
return B200;
case 300:
return B300;
case 600:
return B600;
case 1200:
return B1200;
case 1800:
return B1800;
case 2400:
return B2400;
case 4800:
return B4800;
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
case 230400:
return B230400;
case 460800:
return B460800;
case 500000:
return B500000;
case 576000:
return B576000;
case 921600:
return B921600;
case 1000000:
return B1000000;
case 1152000:
return B1152000;
case 1500000:
return B1500000;
case 2000000:
return B2000000;
case 2500000:
return B2500000;
case 3000000:
return B3000000;
case 3500000:
return B3500000;
case 4000000:
return B4000000;
default:
return -1;
}
}
int uart_open(char *devname)
{
int fd = 0;
fd = open(devname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
if (fd > 0)
{
/*恢复串口为阻塞状态*/
if (fcntl(fd, F_SETFL, 0) < 0)
printf("fcntl failed!\n");
else
printf("fcntl=%d\n", fcntl(fd, F_SETFL, 0));
}
else
{
printf("Can't open %s fd:%d\n", devname, fd);
fd = -1;
// exit(1);
}
return fd;
}
static void xraw(int fd, const char *name, speed_t speed,
struct termios *original)
{
struct termios t;
if (tcgetattr(fd, &t))
printf("tcgetattr %s", name);
*original = t;
cfmakeraw(&t);
if (speed)
{
cfsetspeed(&t, speed);
cfsetospeed(&t, speed);
}
if (tcsetattr(fd, TCSAFLUSH, &t))
printf("tcsetattr %s", name);
}
/********************************************************************************************************
【函数名】UART::cfg
【功 能】配置UART工作参数
【参 数】fd : 串口描述符
inSpeed :串口波特率
inBits :数据位
inEvent :奇偶校验位
inStop :停止位
inReadLen: 阻塞方式一次读取字节最大长度
inTimeout:阻塞超时等待时长,单位:inTimeout*100ms
【返回值】返回0表示配置成功;否则表示配置失败
********************************************************************************************************/
int uart_cfg(int fd, int inSpeed, int inBits, int inEvent, int inStop)
{
struct termios newtio, oldtio;
if (tcgetattr(fd, &oldtio) != 0)
{
perror("Setup Serial");
return -1;
}
bzero(&newtio, sizeof(newtio));
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
switch (inBits)
{
// 设置数据位
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
}
// 设置奇偶校验位
switch (inEvent)
{
case 'O':
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'E':
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
break;
case 'N':
newtio.c_cflag &= ~PARENB;
break;
}
// 设置波特率
cfsetispeed(&newtio, getBaudrate(inSpeed));
cfsetospeed(&newtio, getBaudrate(inSpeed));
// 停止位设置
if (inStop == 1)
{
newtio.c_cflag &= ~CSTOPB;
}
else if (inStop == 2)
{
newtio.c_cflag |= CSTOPB;
}
/*设置等待时间和最小接收字符*/
/* 阻塞读取字节设置:
每读取到inReadLen个字节后read函数返回,
或者是在接收到不够inReadLen字节时,
等待时长超过inTimeout*100ms时函数返回
*/
#if 0
newtio.c_cc[VTIME] = inTimeout; //以十分之一秒为单位。
newtio.c_cc[VMIN] = inReadLen;
tcflush(fd,TCIFLUSH);
#endif
if ((tcsetattr(fd, TCSANOW, &newtio)) != 0)
{
perror("Set uart error");
return -1;
}
return 0;
}
int uart_send(int fd, unsigned char *pcnBuf, int inLen)
{
int count = 0;
while (count < inLen)
{
int i = write(fd, count + pcnBuf, inLen - count);
if (i < 1)
return i;
count += i;
}
return count;
}
int check_timeout(struct timeval end, struct timeval start, int timeoutMs)
{
int tv_sec = end.tv_sec - start.tv_sec;
int tv_usec = end.tv_usec - start.tv_usec;
return (tv_sec * 1000 + tv_usec / 1000) < timeoutMs ? 1 : 0;
}
int uart_recv(int fd, char *pcnBuf, int timeOutMs)
{
int count = 0;
time_t old, new;
double diff;
struct timeval tv_old;
struct timeval tv_new;
gettimeofday(&tv_new, NULL);
tv_old = tv_new;
while (check_timeout(tv_new, tv_old, timeOutMs))
{
int i = read(fd, pcnBuf + count, 1);
gettimeofday(&tv_new, NULL);
new = time(NULL);
if (!i)
break;
else if (i < 0)
{
return i;
}
else
{
count += i;
tv_old = tv_new;
}
}
return count;
}
int uart_mselect(int fd, int inTimeoutMs)
{
int retval;
FD_ZERO(&mRd);
FD_SET(fd, &mRd);
mTimeout.tv_sec = inTimeoutMs / 1000;
mTimeout.tv_usec = (inTimeoutMs % 1000) * 1000;
retval = select(fd + 1, &mRd, NULL, NULL, &mTimeout);
return (retval);
}
int uart_mflush(int fd)
{
return tcflush(fd, TCIFLUSH);
}
int uart_close(int fd)
{
close(fd);
return 0;
}
int main()
{
char *devname = "/dev/ttyUSB0";
int speed = 115200;
int uartfd;
int retval;
char buf[512] = {};
if ((access(devname, F_OK)) != -1)
{
uartfd = uart_open(devname);
if (uartfd <= 0)
{
printf("%s open error:", devname);
return -1;
}
}
else
{
printf("wait %s device ... mount\n", devname);
// sleep(2); // 等待ttyUSB0设备挂载
return -2;
}
retval = uart_cfg(uartfd, speed, 8, 'N', 1); //
if (retval < 0)
{
retval = -3;
return retval;
}
while (1)
{
int mret = uart_recv(uartfd, buf, 5);
if (mret > 0)
{
uart_mflush(uartfd);
printf("recvLen:%d,recvData:%s\n", mret, buf);
memset(buf, 0, 512);
}
// sleep(1);
// printf("test sleep 1\n");
usleep(1000);
// sleep(1);
}
}