• 【genius_platform软件平台开发】第八十讲:终端 I/O 函数-用于控制异步通信端口的通用终端接口


    • 终端 I/O 函数
    • 终端 I/O 接口处理用于控制异步通信端口的通用终端接口

    1. 终端 I/O 接口

    接口名称目的
    tcgetattr(3C), tcsetattr(3C)获取并设置终端属性
    tcsendbreak(3C), tcdrain(3C), tcflush(3C), tcflow(3C)执行行控制接口
    cfgetospeed(3C), cfgetispeed(3C)cfsetispeed(3C), cfsetospeed(3C)获取并设置波特率
    tcsetpgrp(3C)获取并设置终端前台进程组 ID
    tcgetsid(3C)获取终端会话 ID

    以下示例说明服务器如何从其处于非 DEBUG 操作模式下的调用方的控制终端分离出来。

    2. tcflush函数

    • tcflush函数清空输入缓存区(终端驱动已经接收到数据,但用户尚未读)或输出缓存(用户已经写,但尚未发送).
      int tcflush(int filedes,int quene)
      quene数该当是下列三个常数之一:
        *TCIFLUSH  刷清输入队列
        *TCOFLUSH  刷清输出队列
        *TCIOFLUSH 刷清输入、输出队列
    
    • 1
    • 2
    • 3
    • 4
    • 5

    例如:

    tcflush(fd,TCIFLUSH);
    
    • 1
    • 在打开串口后,串口其实已经可以开始读取数据了 ,这段时间用户如果没有读取,将保存在缓冲区里,如果用户不想要开始的一段数据,或者发现缓冲区数据有误,可以使用这个函数清空缓冲
    tcflush(fdcom, TCIFLUSH);
    sleep(2);
    RecvLen = PortRecv(fdcom, RecvBuf, 10, portinfo.baudrate);
    
    • 1
    • 2
    • 3
    • 这样,在sleep之前发的数据都被清空了。

    2.1 缓冲区

    • 又称为缓存,是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲出入或输出的数据,这部分预留的空间就叫做缓冲区。
      缓冲区根据其对应的输入设备还和输出设备,分为输入缓冲区和输出缓冲区

    2.2 缓冲区的作用

    • 缓冲区的作用是为了解决速度不匹配的问题,高速的cpu与内存,内存与硬盘,cpu与io等速度不匹配的问题,而引人缓冲区,比如我们从磁盘里读取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中读取数据,等缓冲区的数据读取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。
      缓冲区就是一块内存区,它用在输入输出设备和CPU之间,用来缓存数据。它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU。解放出CPU,使其能够高效率工作。

    2.3 缓冲区的类型

    • 缓冲区分为三种类型:全缓冲、行缓冲和不带缓冲。

    2.3.1 全缓冲

    • 在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。

    2.3.2 行缓冲

    • 在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是键盘输入数据。

    2.3.3 不带缓冲

    • 不带缓冲也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。

    3. tcdrain函数

    • 等待所有输出都被传递

    4. tcflow函数

    • 对输入和输出流通过action参数进行控制
    TCOOFF:输出被挂起(暂停输出)
    TCOON:重新启动以前被挂起(暂停)的输出
    TCIOFF:系统发送一个STOP字符。这将使终端设备暂停发送数据。
    TCION:系统发送一个START字符。这将使终端恢复发送数据。
    
    • 1
    • 2
    • 3
    • 4

    5. tcsendbreak函数:

    • 如果终端使用异步串行数据传输,tcsendbreak() 会在特定持续时间内传输零值位的连续流。 如果持续时间为零,则它传输零值位至少 0.25 秒,不超过 0.5 秒。 如果持续时间不为零,则传递时间依赖于实现
      如果终端未使用异步串行数据传输,则 tcsendbreak() 不执行任何操作返回。

    6.例子

    rs485Service.h

    #ifndef __RS485_SERVER_H__
    #define __RS485_SERVER_H__
    
    #include "dataType.h"
    
    typedef enum
    {
        OPEN_485_SUCCESS = 0,
        OPEN_485_FAIL,  
    }Open485State;
    
    class Rs485Service
    {
        
    private:
        Rs485Service();
        ~Rs485Service();
        
    public:
        static Rs485Service& Get();
        
    public:
        int Rs485Read(ubyte *buf, uint32 size);
        int Rs485Write(const ubyte *data, uint32 len);
        int InitRs485Dev(uint32 bound);
        void UninitRs485Dev();
        
    private:
        int m_devFd;
        int m_bound;
        int32_t m_485WriteState; //true 485处于写状态
    };
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    rs485Service.cpp

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "rs485Service.h"
    
    #define RS485COM "/dev/???"
    
    Rs485Service::Rs485Service()
    {
        m_devFd = -1;
    }
    
    Rs485Service::~Rs485Service()
    {
    }
    
    Rs485Service& Rs485Service::Get()
    {
        static Rs485Service Rs485server;
        return Rs485server;
    }
    
    int Rs485Service::InitRs485Dev(uint32 bound)
    {
        /*
        * Hi3536 GPIO的读写操作,有两种方法:
        * 1、重新编写GPIO的驱动程序,在通过访问设备进行GPIO的读写
        。
        * 2、根据海思提供的工具himm,进行寄存器值的读写
        *   sprintf(buffer, "himm 0x%x r", data_addr);
        *   system(buffer);
        *   sprintf(buffer, "himm 0x%x 0x%x", data_addr, (value << (pin)) );
        *   system(buffer);
        */
        system("himm 0x11111111 1");
        system("himm 0x2222222 1");
        
        system("himm 0x33333333 0");
        system("echo ???> /sys/class/gpio/export");
        system("echo out > /sys/class/gpio/gpio???/direction");
        system("echo 0 > /sys/class/gpio/gpio???/value");
        
        m_devFd = open(RS485COM, O_RDWR | O_NOCTTY); //加上O_NDELAY,就变为了非阻塞
        if (m_devFd != -1)
        {
            struct termios cfg;
            
            memset(&cfg, 0, sizeof(cfg));
            tcgetattr(0, &cfg);
            switch(bound)
            {
                case 19200:
                    cfsetispeed(&cfg, B19200);
                    cfsetispeed(&cfg, B19200);
                    m_bound = 19200;
                    break;
                case 9600:
                    cfsetispeed(&cfg, B9600);
                    cfsetispeed(&cfg, B9600);
                    m_bound = 9600;
                    break;
                default:
                    cfsetispeed(&cfg, B19200);
                    cfsetispeed(&cfg, B19200);
                    m_bound = 19200;
                    break;
            }
            cfg.c_oflag &= ~(ONLCR);
            cfg.c_oflag &= (OCRNL);
            cfg.c_iflag &= (INLCR);
            
            cfg.c_cflag |= CLOCAL | CREAD; //使能串口输入
            //cfg.c_lflag |= ICANON; //标准模式
            cfg.c_lflag &= ~ICANON;//原始模式
            cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
        
            //8bit数据
            cfg.c_cflag &= ~CSIZE;
            cfg.c_cflag |= CS8;
            //1bit停止位
            cfg.c_cflag &= ~CSTOPB;
            //无校验
            cfg.c_cflag &= ~PARENB;
            //禁用硬件流控制:
            cfg.c_cflag &= ~CRTSCTS;
            
          //  cfg.c_cc[VTIME] = 1; //设置超时时间,如果采用非阻塞模式则不设置
            cfg.c_cc[VMIN] = 1;     //设置最小接收的数据长度
    
            //清楚输入输出缓冲区
            tcflush(m_devFd, TCIOFLUSH);
            tcsetattr(m_devFd, TCSANOW, &cfg);
            return OPEN_485_SUCCESS;
        }
        else
        {
            printf("open dev err.\n");
            return OPEN_485_FAIL;
        }
    }
    
    void Rs485Service::UninitRs485Dev()
    {
        if (m_devFd != -1)
        {
            struct termios cfg;
            memset(&cfg, 0, sizeof(cfg));
            tcgetattr(0, &cfg);
            cfg.c_cc[VTIME] = 1;
            tcflush(m_devFd, TCIOFLUSH);
            tcsetattr(m_devFd, TCSANOW, &cfg);
            close(m_devFd);
        }
    }
    
    int Rs485Service::Rs485Read(ubyte* buf, uint32 size)
    {
        int rlen = -1;
        if (m_devFd != -1)
        {
            rlen = read(m_devFd, buf, size);
            tcflush(m_devFd, TCIOFLUSH);
        }
        return rlen;
    }
    
    int Rs485Service::Rs485Write(const ubyte* data, uint32 len)
    {
        int wlen = -1;
    
        //485是半双工,置为发送状态
        system("echo 1 > /sys/class/gpio/gpio42/value");   
        if (m_devFd != -1)
        {     
            wlen = write(m_devFd, data, len);
        }
    
       //等待数据输出完毕
        tcdrain(m_devFd);
        //清空输入输出缓冲区
        tcflush(m_devFd, TCIOFLUSH);
        //485是半双工,置为接收状态
        system("echo 0 > /sys/class/gpio/gpio42/value");
        
        return wlen;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
  • 相关阅读:
    跨域及cors解决跨域
    OceanBase 数据文件缩容实践
    vqvae简单实战,利用vqvae来提升模型向量表达
    福建师范大学2022年8月课程考试《文采风流:近现代闽籍文人与作家》作业考核试题【标准答案】
    Linux环境变量
    Unity & PS Linear Workflow - Unity 和 PS 的线性工作流实践 - 简单配置示例(后续补上渲染差异图)
    神经网络在飞行疲劳检测中的应用综述
    vm.$set函数的个人总结
    深度学习系列46:人脸图像超分GFP-GAN
    RabbitMQ、Kafka和RocketMQ比较
  • 原文地址:https://blog.csdn.net/Windgs_YF/article/details/127880901