【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 刷清输入、输出队列

例如:

tcflush(fd,TCIFLUSH);
  • 在打开串口后,串口其实已经可以开始读取数据了 ,这段时间用户如果没有读取,将保存在缓冲区里,如果用户不想要开始的一段数据,或者发现缓冲区数据有误,可以使用这个函数清空缓冲
tcflush(fdcom, TCIFLUSH);
sleep(2);
RecvLen = PortRecv(fdcom, RecvBuf, 10, portinfo.baudrate);
  • 这样,在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字符。这将使终端恢复发送数据。

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

rs485Service.cpp

#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <netinet/in.h>
#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;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隨意的風

如果你觉得有帮助,期待你的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值