zoukankan      html  css  js  c++  java
  • C++ 串口应用——自定义串口类

    记录:  

      ARM板子串口的使用算是最基本的操作,经过3、4天的努力终于完成了可以应用在ARM板子上的串口类。代码多是参考网上,所以本博客开源分享

    说明:

    1、串口类使用静态函数,使其他文件可以引用。

    2、特别适合Linux系统,调用设备文件(使用不同的串口,只需要更改初始化的配置即可)。

    3、原理上还是调用C头文件,使用open、write、read函数完成打开读写关键操作;使用select,FD_ISSET对设备文件监听。

    代码:

    bsp_CSerial.h

    #ifndef __BSP_CSERIAL_H
    #define __BSP_CSERIAL_H
    
    /* 获取 波特率 */
    typedef struct port_info
    {
        int  fd;
        int  baudrate;
        char databits;
        char stopbits;
        char parity;
        char flowctrl;
    }*pport_info;
    class CSerial
    {
    public:
        CSerial();
        ~CSerial();
    
    
        static int  UART_Init(pport_info p_info);
        static void UART_Close(int fd);
        static int  UART_Send(int fd,void *buf,int len);
        static int  UART_Recv(int fd,void *buf,int len);
    };
    
    
    #endif //#ifndef __BSP_USART_H

    bsp_CSerial.cpp

    /* Local Include */
    
    #include "bsp_CSerial.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <string.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/un.h>
    #include <sys/time.h>
    #include <sys/ioctl.h>
    #include <pthread.h>
    #include <termios.h>
    #include <QIODevice>
    #include <QDebug>
    
    CSerial::CSerial()
    {
    
    }
    
    CSerial::~CSerial()
    {
    
    }
    
    int CSerial::UART_Init(pport_info p_info)
    {
        struct termios new_opt;
        int baud_rate;
        int status;
    
        //get the current config -> new_opt
        tcgetattr(p_info->fd,&new_opt);
        bzero( &new_opt, sizeof(new_opt));
    
        //convert baud rate -> baud_flag
        switch(p_info->baudrate)
        {
            case 0:
                baud_rate = B0;
                break;
            case 50:
                baud_rate = B50;
            break;
            case 75:
                baud_rate = B75;
            break;
            case 110:
                baud_rate = B110;
            break;
            case 134:
                baud_rate = B134;
            break;
            case 150:
                baud_rate = B150;
            break;
            case 200:
                baud_rate = B200;
            break;
            case 300:
                baud_rate = B300;
            break;
            case 600:
                baud_rate = B600;
            break;
            case 1200:
                baud_rate = B1200;
            break;
            case 1800:
                baud_rate = B1800;
            break;
            case 2400:
                baud_rate = B2400;
            break;
            case 4800:
                baud_rate = B4800;
            break;
            case 9600:
                baud_rate = B9600;
            break;
            case 19200:
                baud_rate = B19200;
            break;
            case 38400:
                baud_rate = B38400;
            break;
            case 57600:
                baud_rate = B57600;
            break;
            case 115200:
                baud_rate = B115200;
            break;
            case 230400:
                baud_rate = B230400;
            break;
            default:break;
        }
    
        tcflush(p_info->fd, TCIOFLUSH);
        //setup input/output baudrate
        cfsetispeed(&new_opt,baud_rate);
        //printf("cfsetispeed::c_cflag = %x
    ", new_opt.c_cflag);
        cfsetospeed(&new_opt,baud_rate);
        //printf("cfsetospeed::c_cflag = %x
    ", new_opt.c_cflag);
        status = tcsetattr(p_info->fd, TCSANOW, &new_opt);
        if (status != 0)
        {
            qCritical("tcsetattr::set baud rate failed
    ");
            return -1;
        }
    
        //修改控制模式,保证程序不会占用串口?
        new_opt.c_cflag |= CLOCAL;
        //printf("c_cflag |= CLOCAL => %x
    ", new_opt.c_cflag);
    
        //修改控制模式,使得能够从串口读取输入数据
        new_opt.c_cflag |= CREAD;
        //printf("c_cflag |= CREAD => %x
    ", new_opt.c_cflag);
    
        new_opt.c_cflag |= HUPCL;
        //setup control flow
        switch(p_info->flowctrl)
        {
        case '0':
            //no control-flow
            new_opt.c_cflag &=~CRTSCTS;
            break;
        case '1':
            //hardware control-flow
            new_opt.c_cflag |=CRTSCTS;
            break;
        case '2':
            new_opt.c_iflag |= IXON | IXOFF | IXANY;
            break;
        }
        //printf("c_cflag(no ctl-flow) = %x
    ", new_opt.c_cflag);
    
        //setup bit size
        new_opt.c_cflag &=~CSIZE;
        switch(p_info->databits)
        {
        case '5':
            new_opt.c_cflag |=CS5;
            break;
        case '6':
            new_opt.c_cflag |=CS6;
            break;
        case '7':
            new_opt.c_cflag |=CS7;
            break;
        case '8':
            new_opt.c_cflag |=CS8;
            break;
        default:
            new_opt.c_cflag |=CS8;
        }
        qDebug("c_cflag |= CS8 => %x
    ", new_opt.c_cflag);
    
        //setup parity
        switch(p_info->parity)
        {
        case 'n':
        case 'N':
            new_opt.c_cflag &= ~PARENB;   /* Clear parity enable */
            new_opt.c_iflag &= ~INPCK;     /* Enable parity checking */
            break;
    
        case 'o':
        case 'O':
            new_opt.c_cflag |= (PARODD | PARENB);    /* 设置为奇效验*/
            new_opt.c_iflag |= INPCK;                /* Disable parity checking */
            break;
    
        case 'e':
        case 'E':
            new_opt.c_cflag |= PARENB;        /* Enable parity */
            new_opt.c_cflag &= ~PARODD;        /* 转换为偶效验*/
            new_opt.c_iflag |= INPCK;       /* Disable parity checking */
            break;
    
        case 'S':
        case 's':  /*as no parity*/
            new_opt.c_cflag &= ~PARENB;
            new_opt.c_cflag &= ~CSTOPB;
            break;
    
        default:
            qDebug("Unsupported parity
    ");
            return -1;
        }
        //printf("c_cflag &=~PARENB => %x
    ", new_opt.c_cflag);
    
    
        //setup stop-bit
        if(p_info->stopbits=='2')
        {
            new_opt.c_cflag |=CSTOPB;
        }
        else
        {
            new_opt.c_cflag &=~CSTOPB;
        }
        //printf("c_cflag &=~CSTOPB => %x
    ", new_opt.c_cflag);
    
        /* Set input parity option */
        if ((p_info->parity != 'n') || (p_info->parity != 'N'))
        {
            new_opt.c_iflag |= INPCK;
        }
    
        //修改输出模式:原始数据输出(raw 模式)
        new_opt.c_lflag &= ~(ICANON | ECHO | ISIG);                /*Input*/
        new_opt.c_oflag &= ~OPOST;                                /*Output*/
    
        //修改控制字符:读取字符的最少个数为1 ???
        new_opt.c_cc[VMIN]=1;
    
        //修改控制字符:读取第一个字符的超时时间为1×100ms
        new_opt.c_cc[VTIME]=1;
    
        //试图去掉在接收时必须收到'
    '才返回的问题
        //忽略输入的回车
        //new_opt.c_iflag |= IGNCR;
        //new_opt.c_iflag &= ~(IXON|IXOFF|IXANY);
    
        //如果发生数据溢出,接收数据,但是不再读取
        tcflush(p_info->fd,TCIFLUSH);
    
        status = tcsetattr(p_info->fd,TCSANOW,&new_opt);
        if(status != 0)
        {
            qCritical("Cannot set the serial port parameters");
            return -1;
        }
    
        return status;
    }
    
    void CSerial::UART_Close(int fd)
    {
        close(fd);
    }
    
    int CSerial::UART_Send(int fd, void *buf, int len)
    {
        int  sendlen=0;
    
        sendlen=write(fd, buf, len);
    
        if(sendlen==len)
        {
            return sendlen;
        }
        else
        {
            //如果出现溢出情况
            tcflush( fd,TCOFLUSH);
            return -1;
        }
    }
    
    int CSerial::UART_Recv(int fd, void *buf, int len)
    {
        //定义读事件集合
        fd_set fdRead;
        int ret;
        struct timeval    aTime;
    
        FD_ZERO(&fdRead);
        FD_SET(fd,&fdRead);
    
        aTime.tv_sec = 0;
        aTime.tv_usec = 300000; //300ms
    
        ret = select( fd+1,&fdRead,NULL,NULL,&aTime );
        //printf( "select ret = %d
    ", ret);
    
        if (ret < 0 )
        {
            //关闭串口
            UART_Close(fd);
        }else if (ret > 0)
        {
            //判断是否读事件
            if (FD_ISSET(fd,&fdRead))
            {
                //data available, so get it!
                ret = read( fd, buf, len );
                // 对接收的数据进行处理,这里为简单的数据回发
            }
        }
        return ret;
    }

    使用串口的线程:

    thread_sericalport.cpp

    1、初始化

    Thread_SerialPort::Thread_SerialPort(char *PortName, int baudrate, char databits, char stopbits, char parity, DeviceType_m type)
    {
        int fd;
        QMutexLocker locker(&mutex);
        isStop = false;
        this->type = type;
        if( (fd=open(PortName,O_RDWR | O_NOCTTY | O_NONBLOCK)) == -1 )
        {
            qCritical()<<"打开端口"<<PortName<<"失败";
        }
        info.fd       = fd;
        info.baudrate = baudrate;
        info.databits = databits;
        info.stopbits = stopbits;
        info.parity   = parity;//奇偶校验
        info.flowctrl = '0';
    
    
        if( CSerial::UART_Init( &info ) < 0)//创建了接收线程
        {
            qCritical()<<"端口"<<PortName<<"初始化设置失败";
        }
    
    }

    2、run() 包括读写

    void Thread_SerialPort::run()
    {
        uint8_t         receiveBuffer[128];
        int             receiveLength;
        while(1)
        {
            //----------判断全局变量中Carrier命令是否为空----------//
            if( type == DeviceType_WaterDepth)
            {
    
            }else if( type == DeviceType_Ins )
            {
    
            }else if( type == DeviceType_Carrier )
            {
                globeData->cmd_RS232_Carrier.mutex.lock();
                while( !globeData->cmd_RS232_Carrier.queue.isEmpty()  )
                {
                    Device_Cmd_t packageToSend = globeData->cmd_RS232_Carrier.queue.dequeue();//获取全局变量中运载器命令
                    //发送数据
                    if( CSerial::UART_Send(info.fd,packageToSend.dataBuff,packageToSend.length) != packageToSend.length )
                    {
                        qDebug()<<"Thread_SerialPort.cpp--->发送命令错误,请进行检查!!";
                    }else
                    {
                        qDebug("RS232_Carrier 命令发送成功! ");
                    }
                }
                globeData->cmd_RS232_Carrier.mutex.unlock();
            }else if( type == DeviceType_UnderwaterAcoustic )
            {
    
            }else
            {
                qDebug()<<"Thread_SerialPort.cpp--->命令类型错误,请进行检查!!";
            }
            //----------接收数据----------//
            receiveLength = 0;
            while( CSerial::UART_Recv(info.fd,&receiveBuffer[receiveLength],1) > 0 )
            {
                receiveLength++;
            }
            if(receiveLength > 0)
            {
                uint8_t   str[receiveLength];//原str[receiveLength]
                Device_Buff_t packageToReceive;
                int i=0;
                for(i=0;i<receiveLength;i++)
                {
                    str[i] = receiveBuffer[i];
                    qDebug("str=%x",str[i]);
                }
                //str[i] = '';
                //qDebug("命令=%x",str);
                packageToReceive.deviceType = type;
                packageToReceive.length     = receiveLength;//算上
                memcpy(packageToReceive.dataBuff,receiveBuffer,receiveLength);
                globeData->data_Agreement.mutex.lock();
                globeData->data_Agreement.queue.append(packageToReceive);//接收到的协议入队
                globeData->data_Agreement.mutex.unlock();
    
            }
    
    
            {
                QMutexLocker locker(&mutex);
                if(true == isStop)
                    break;
            }
        }
    }
  • 相关阅读:
    历史书单
    《Tornado介绍》—— 读后总结
    基于TensorFlow的深度学习系列教程 2——常量Constant
    深度学习Tensorflow生产环境部署(下·模型部署篇)
    深度学习Tensorflow生产环境部署(上·环境准备篇)
    Crontab和sudo中无法使用TensorFlow ImportError libcublas.so.9.0
    基于TensorFlow的深度学习系列教程 1——Hello World!
    想要接触人工智能吗?先要学会如何阅读论文
    《数据挖掘与数据化运营实战 思路、方法、技巧与应用》—— 读书笔记
    《新参者》—— 读后总结
  • 原文地址:https://www.cnblogs.com/shuoguoleilei/p/11446689.html
Copyright © 2011-2022 走看看