基于linux的串口编程,包括一些串口配置,自己学习当作笔记记录。参考Linux程序设计
myserial.h
#ifndef __SERIAL_H__
#define __SERIAL_H__
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/select.h>
#include <termios.h>
#include <errno.h>
#include <fcntl.h>
/*
* 波特率
*/
enum MYBAUDRATE
{
B_115200 = 115200,
B_57600 = 57600,
B_9600 = 9600
};
class MySerial
{
public:
/*
* 函数介绍: 构造函数
*
* 输入参数: 串口名称
*
* 输出参数: 无
*
* 返回值 : 成功返回0,失败返回-1
*/
MySerial(const char* name = "");
MySerial(const MySerial& s);
const MySerial& operator=(const MySerial& s);
~MySerial();
/*
* 函数介绍: 打开串口
*
* 输入参数: 无
*
* 输出参数: 无
*
* 返回值 : 成功返回0,失败返回-1
*/
int openSerial();
/*
* 函数介绍: 关闭串口
*
* 输入参数: 无
*
* 输出参数: 无
*
* 返回值 : 成功返回0,失败返回-1
*/
int closeSerial();
/*
* 函数介绍: 设置波特率
*
* 输入参数: 波特率,MYBAUDRATE
*
* 输出参数: 无
*
* 返回值 : 成功返回0,失败返回-1
*/
int setSpeed(int speed);
/*
* 函数介绍: 设置串口属性
*
* 输入参数: databit,数据位,stopbit停止位,checkbit校验方式,
* checkbit: 0为无,1为奇校验,2为偶校验
*
* 输出参数:
*
* 返回值 : 成功返回0,失败返回-1
*/
virtual int setProperty(int databit, int stopbit, int checkbit);
/*
* 函数介绍: 读串口
*
* 输入参数: datalen一次最大读长度
*
* 输出参数: data读出的数据
*
* 返回值 : 读到的数据长度,失败返回-1
*/
int readSerial(char *data, const int datalen);
/*
* 函数介绍: 写串口
*
* 输入参数: data要写的数据内容,datalen要写的长度
*
* 输出参数: 无
*
* 返回值 : 写入的数据长度,失败返回-1
*/
int writeSerial(const char* data, const int datalen);
/*
* 函数介绍: 获取串口当前状态
*
* 输入参数: 无
*
* 输出参数: 无
*
* 返回值 : 串口状态值
*/
int getStatu() { return m_is_open;}
/*
* 函数介绍: 获取串口名字
*
* 输入参数: 无
*
* 输出参数: 串口名字
*
* 返回值 : 无
*/
void getSerialName(char *name) { strcpy(name, m_name);}
private:
int m_fd; //! 设备描述符
int m_is_open; //! 开启状态,0开启,-1关闭
char* m_name; //! 串口名称
};
#endif
myserial.cpp
#include <stdio.h>
#include "myserial.h"
MySerial::MySerial(const char* name) : m_name(new char[strlen(name)+1]), m_fd(-1),
m_is_open(-1)
{
strcpy(m_name, name);
}
MySerial::MySerial(const MySerial& s) : m_name(new char[strlen(s.m_name)+1]), m_fd(s.m_fd),
m_is_open(s.m_is_open)
{
strcpy(m_name,s.m_name);
}
const MySerial& MySerial::operator=(const MySerial& s)
{
if(&s != this)
{
delete [] m_name;
m_name = new char[strlen(s.m_name)+1];
strcpy(m_name, s.m_name);
m_fd = s.m_fd;
m_is_open = s.m_is_open;
}
return *this;
}
MySerial::~MySerial()
{
delete [] m_name;
}
int MySerial::openSerial()
{
m_fd = open(m_name, O_RDWR | O_NOCTTY | O_NDELAY); //! 非阻塞可读可写打开
if(m_fd == -1)
{
#ifdef _SERIAL_DEBUG_
perror("openSerial:");
#endif
return -1;
}
m_is_open = 0;
return 0;
}
int MySerial::closeSerial()
{
if(close(m_fd) == -1)
{
#ifdef _SERIAL_DEBUG_
perror("closeSerial:");
#endif
return -1;
}
m_is_open = -1;
return 0;
}
int MySerial::setSpeed(int speed)
{
struct termios opt;
if(tcgetattr(m_fd, &opt) != 0) //! 获取当前串口属性
{
#ifdef _SERIAL_DEBUG_
perror("tcgetattr:");
#endif
return -1;
}
tcflush(m_fd, TCIOFLUSH);
switch(speed) //! 配置波特率
{
case B_115200:
cfsetispeed(&opt, B115200);
cfsetospeed(&opt, B115200);
break;
case B_57600:
cfsetispeed(&opt, B57600);
cfsetospeed(&opt, B57600);
break;
case B_9600:
cfsetispeed(&opt, B9600);
cfsetospeed(&opt, B9600);
break;
default:
cfsetispeed(&opt, B9600);
cfsetospeed(&opt, B9600);
break;
}
if(tcsetattr(m_fd, TCSANOW, &opt) != 0) //! 设置波特率
{
#ifdef _SERIAL_DEBUG_
perror("SetSpeed:");
#endif
return -1;
}
tcflush(m_fd, TCIOFLUSH);
return 0;
}
int MySerial::setProperty(int databit, int stopbit, int checkbit)
{
struct termios options;
if(tcgetattr(m_fd, &options) != 0) //! 获取当前串口属性
{
#ifdef _SERIAL_DEBUG_
perror("tcgetattr:");
#endif
return -1;
}
options.c_cflag |= (CLOCAL | CREAD); //! 忽略modem控制线,使能读
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //! 配置原始模式
options.c_cflag &= ~CSIZE; //! 屏蔽字符掩码
switch(databit) //! 配置字符掩码
{
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
#ifdef _SERIAL_DEBUG_
fprintf(stderr, "databit is error\n");
#endif
return -1;
}
switch(stopbit) //! 配置停止位
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
#ifdef _SERIAL_DEBUG_
fprintf(stderr, "stop bit is error\n");
#endif
return -1;
}
switch(checkbit) //! 配置校验方式
{
case 0:
options.c_cflag &= ~PARENB;
break;
case 1:
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
break;
case 2:
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
break;
default:
#ifdef _SERIAL_DEBUG_
fprintf(stderr, "set check bit is error\n");
#endif
return -1;
}
if(tcsetattr(m_fd, TCSANOW, &options) != 0) //! 设置串口属性
{
#ifdef _SERIAL_DEBUG_
perror("tcsetattr:");
#endif
return -1;
}
return 0;
}
int MySerial::readSerial(char *data, const int datalen)
{
int ret = -1;
fd_set my_set;
FD_ZERO(&my_set);
FD_SET(m_fd, &my_set);
struct timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 0;
int retval = select(m_fd+1, &my_set, NULL, NULL, &tv); //! 等待串口可读,阻塞3s
if(retval == 0)
{
#ifdef _SERIAL_DEBUG_
printf("select is timeout\n");
#endif
ret = 0;
}
if(retval > 0)
{
ret = read(m_fd, data, datalen);
if(ret < 0)
{
#ifdef _SERIAL_DEBUG_
perror("read:->");
#endif
}
}
if(retval == -1)
{
#ifdef _SERIAL_DEBUG_
perror("select->");
#endif
}
return ret;
}
int MySerial::writeSerial(const char* data, const int datalen)
{
int ret = -1;
tcflush(m_fd, TCIFLUSH);
if((ret = write(m_fd, data, datalen)) < 0)
{
#ifdef _SERIAL_DEBUG_
perror("write:->");
#endif
}
return ret;
}
main.cpp
#include <stdio.h>
#include <string.h>
#include "myserial.h"
int main(int argc, char *argv[])
{
if(argc < 3)
{
printf("argc is not right\n");
exit(-1);
}
char *ptr = argv[2];
char *dev = argv[1];
MySerial *serial = new MySerial(dev);
if(serial->openSerial() < 0)
{
delete serial;
exit(-1);
}
printf("m_fd is -------------->%d\n", serial->getStatu());
char name[30] = "0";
serial->getSerialName(name);
printf("dev name is --------> %s\n",name);
if(serial->setSpeed(B_115200) < 0)
{
delete serial;
exit(-1);
}
if(serial->setProperty(8,1,0) < 0)
{
delete serial;
exit(-1);
}
if(serial->writeSerial(ptr,strlen(ptr)) < 0)
{
delete serial;
exit(-1);
}
int temp = 0;
char buffer[24];
while(1)
{
int num = 0;
memset(buffer,0,sizeof(buffer));
if((num = serial->readSerial(buffer, 1024)) <= 0 )
{
continue;
}
else
{ temp++;
printf("buffer num is %d is %s\n",num,buffer);
if(temp > 10)
{
break;
}
}
}
serial->closeSerial();
return 0;
}
简单实现自收自发,如有错误请提出,共同进步!!!