Linux串口学习

基于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;

}

简单实现自收自发,如有错误请提出,共同进步!!!

猜你喜欢

转载自blog.csdn.net/woyoujiabin_xu/article/details/80663971