1、前言
? ? ? ?串口驱动是最简单的一种驱动了,在Linux下一切设备都认为是文件,打开设备就像打开文件一样简单,直接上代码
2、RS485.c
//--------------------------------------------------------------------------------------------------
// Include head files
//--------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <fcntl.h> /* File control definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include "RS485.h"
//-------------------------------------------------------------------------------------------------
// Private Definitions
//-------------------------------------------------------------------------------------------------
#define RETRY_TIMES 3
//-------------------------------------------------------------------------------------------------
// Private Members
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
// Private Functions
//-------------------------------------------------------------------------------------------------
static int SetAttributes(int fd, RS485PARA Rs485Para)
{
struct termios newtio, oldtio;
if (tcgetattr(fd, &oldtio) != 0)
{
printf("com error:%s\n", strerror(errno));
return -1;
}
bzero(&newtio, sizeof(newtio));
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
switch (Rs485Para.m_Bits)
{
case SEVEN:
newtio.c_cflag |= CS7;
break;
case EIGHT:
newtio.c_cflag |= CS8;
break;
default:
newtio.c_cflag |= CS8;
}
switch (Rs485Para.m_Parity)
{
case O:
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK);
break;
case E:
newtio.c_iflag |= (INPCK);
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
break;
case N:
newtio.c_cflag &= ~PARENB;
break;
default:
newtio.c_cflag &= ~PARENB;
}
switch (Rs485Para.m_BaudRate)
{
case B_9600:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
case B_19200:
cfsetispeed(&newtio, B19200);
cfsetospeed(&newtio, B19200);
break;
case B_38400:
cfsetispeed(&newtio, B38400);
cfsetospeed(&newtio, B38400);
break;
case B_57600:
cfsetispeed(&newtio, B57600);
cfsetospeed(&newtio, B57600);
break;
case B_115200:
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
break;
default:
cfsetispeed(&newtio, B19200);
cfsetospeed(&newtio, B19200);
}
if (Rs485Para.m_Stop == ONE)
{
newtio.c_cflag &= ~CSTOPB;
}
else if (Rs485Para.m_Stop == TWO)
{
newtio.c_cflag |= CSTOPB;
}
else
{
newtio.c_cflag &= ~CSTOPB;
}
newtio.c_cc[VTIME] = 5;
newtio.c_cc[VMIN] = 0;
tcflush(fd, TCIFLUSH);
if ((tcsetattr(fd, TCSANOW, &newtio)) != 0)
{
printf("com set error:%s\n", strerror(errno));
return -1;
}
return 0;
}
//-------------------------------------------------------------------------------------------------
// Public Functions
//-------------------------------------------------------------------------------------------------
int RS485Open(const char *pDevname, RS485PARA Rs485Para)
{
int ret = 0;
int fd = 0;
if (NULL == pDevname)
{
printf("RS485 device name is null\n");
return -1;
}
fd = open(pDevname, O_RDWR);
if (fd > 0)
{
ret = SetAttributes(fd, Rs485Para);
if (ret != 0)
{
printf("Set RS485 port failed, error=%s\n", strerror(errno));
return -1;
}
}
else
{
printf("Can't open the port %s,error=%s\n", pDevname, strerror(errno));
return -1;
}
return fd;
}
int RS485Read(int fd, void* buf, int size)
{
char *pBuff = buf;
int readLn = 0;
if (fd < 0)
{
printf("RS485 Write Para error, fd = %d\n", fd);
return -1;
}
if (NULL == pBuff)
{
printf("RS485 device read pointer %s is null\n", "buf");
return -1;
}
auto int retry = RETRY_TIMES;
do
{
readLn = read(fd, buf, size);
if ((readLn < 0) && (errno == EINTR))
{
printf("RX has fatal fault, errno = %d!\n", EINTR);
}
else
{
break;
}
retry--;
}while (retry);
return readLn;
}
int RS485Write(int fd, const void *buf, int size)
{
char *pBuff = (char *)buf;
if (NULL == pBuff)
{
printf("RS485 Write Para error\n");
return -1;
}
if (fd < 0)
{
printf("RS485 Write Para error\n");
return -1;
}
auto int willSize = size;
do
{
int rslt = write(fd, buf, willSize);
if (rslt == -1) /EAGAIN
{
printf("write failed:%s\n", strerror(errno));
switch (errno)
{
case EINTR:
case EAGAIN:
break;
default:
return -1;
}
return 0;
}
else
{
pBuff += rslt;
willSize -= rslt;
}
}while (willSize > 0);
return size;
}
int RS485Close(int fd)
{
if (fd > 0)
{
close(fd);
}
else
{
return -1;
}
return 0;
}
3、RS485.h
#ifndef RS485_H
#define RS485_H
//-------------------------------------------------------------------------------------------------
// Public Includes
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
// Public Definitions
//-------------------------------------------------------------------------------------------------
enum BaudRate
{
B_9600 = 0,
B_19200 = 1,
B_38400 = 2,
B_57600 = 3,
B_115200 = 4,
B_40000 = 5,
B_25000 = 6,
};
enum Bits
{
SEVEN = 7,
EIGHT = 8,
};
enum Parity
{
O = 0,
E = 1,
N = 3,
};
enum Stop
{
ONE = 1,
TWO = 2,
};
//-------------------------------------------------------------------------------------------------
// Public Types
//-------------------------------------------------------------------------------------------------
typedef struct tag_RS485PARA
{
unsigned char m_BaudRate;
unsigned char m_Bits;
unsigned char m_Parity;
unsigned char m_Stop;
}RS485PARA;
//-------------------------------------------------------------------------------------------------
// Public Functions
//-------------------------------------------------------------------------------------------------
/**
* Description: open a uart , rturn the fd
*
* @param pDevname [in] uart name with path
* @param Rs485Para [in] uart parater which run correctly
* @return [out] fd value
*/
extern int RS485Open(const char *pDevname, RS485PARA Rs485Para);
/**
* Description: read data to buf from fd
*
* @param fd [in] uart fd
* @param buf [in] store data from uart
* @param size [in] data len from uart
* @return [out] data len to be read
*/
extern int RS485Read(int fd, void* buf, int size);
/**
* Description: read data to buf from fd
*
* @param fd [in] uart fd
* @param buf [in] store data from uart
* @param size [in] data len of buf
* @return [out] data len to be writen
*/
extern int RS485Write(int fd, const void *buf, const int size);
/**
* Description: read data to buf from fd
*
* @param fd [in] uart fd
* @return [out] RET_STATUS_OK if OK
*/
extern int RS485Close(int fd);
#endif
4、总结
注意设置的方式是非阻塞,500毫秒等待时间,在外部程序中使用select/epool等方式去调用read读取数据就可以了
|