QT 使用 WinIO 读取工控主板 GPIO

系统环境

软件环境

Win10 64位 + Qt5.13.2

硬件环境

主板

型号为 C6950Z-C6 工控主板一个,带有 4 4 4 路 DI 和 4 4 4 路 DO。
在这里插入图片描述

GPIO 地址

这部分资料是主板供应商提供的。每个主板会有一些差异。

DI

DI1 0xA00 bit0
DI2 0xA01 bit3
DI3 0xA07 bit0
DI4 0xA07 bit1
我的主板 DI 需要接入低电平才会变化,这个部分说明书上竟然没有写,也搞了好久。

DO

DO1 0xA02 bit6
DO2 0xA02 bit7
DO3 0xA04 bit1
DO4 0xA04 bit2

需要特殊功能组件

在 Win10 下要获取电脑主板的数据,只能通过驱动层,但是我又不想自己写驱动程序,借用了 WinIO 这个库来实现。

WinIO 特别说明

为了这个目的,摸索了挺久的。一个是网络上 WinIO 资料比较上,第二是大部分资料都是针对 Win7 系统或者实在太老。

WinIO 下载

Github 搜索 WinIO 就有。WinIO 已经编译好的库在网络上可以直接下载的。如下图所示。
在这里插入图片描述
64 64 64 位驱动文件 WinIo64.sys 和 32 32 32 位驱动文件 WinIo32.sys。

安装数字签名

找到 WinIo64.sys,鼠标右键属性。
在这里插入图片描述
在弹出对话框中,选择数字签名。如下
在这里插入图片描述
选择详细信息,出现如下界面。
在这里插入图片描述
选择查看证书,出现如下界面。
在这里插入图片描述
选择安装证书。
在这里插入图片描述
我是选择了本地计算机。然后点击下一步。会跳出一个对话框,选择是。出现下面界面。
在这里插入图片描述
选择 将所有的证书都放在下列存储,然后点 浏览。出现下面界面
在这里插入图片描述
选择 受信任的根证书发布机构,点击确定。出现如下界面。
在这里插入图片描述
点击 下一页。出现如下界面。
在这里插入图片描述
点击 完成。这样就完成了证书的安装。

开启测试模式

1、管理员模式运行CMD。
2、输入以下命令

bcdedit.exe /set TESTSIGNING ON

该命令成功后,在 Win10 的右下角会多出如图所示的东西。
在这里插入图片描述
3、重启 Win10 系统。

QT测试程序

用管理员权限运行 QtCreator

注意本步骤特别重要,一定要使用管理员权限运行 QtCreator,因为 WinIO 需要使用特权模式。这里我卡了几天。
在这里插入图片描述

创建一个 Qt Widgets Application

本步骤忽略。

将 WinIO 拷贝到对应的目录

在这里插入图片描述
如上图红框所示,需要拷贝这些文件。

pro 文件增加支持

加上以下两行,增加对 DLL 的支持。

DEFINES += WINIO_DLL
unix|win32: LIBS += -L$$PWD/./ -lWinIo64

修改 MainWindow.ui

在这里插入图片描述
如上图所示,增加了两个 QLineEdit,两个 PushButton。

增加头文件

在 MainWindow.cpp 中加入头文件。

#include "WinIo.h"

MainWindow.h 和 MainWindow.cpp

Read DI 功能函数

根据指定地址,读取 DI。

DWORD MainWindow::HTKReadDI(WORD pbPhysAddr, int index)
{
    //1 param: 要读出的IO内存地址 ;2 param: 读出的值,单位为字;3 param:1 byte 2 WORD  3 DWORD
    //dwPortVal指向双字变量的指针,接收从端口得到的数据。
    DWORD val = 0x0 ;
    GetPortVal((WORD)pbPhysAddr, &val, 1);
    qDebug() << QString::number(val, 16)<< " " << QString::number(val, 2);
    return val;
}

Write DO 功能函数

根据指定的地址,写 DO。

DWORD MainWindow::HTKWriteDo(WORD pbPhysAddr, int bitIndex)
{
    1 param: 写入的IO内存地址 ;2 param: 写入的值,单位为字;3 param:1 byte 2 WORD  3 DWORD
    //若写入成功,则返回0
    int flag = 0;
    WORD Data;
    DWORD dwPortVal2 = 0x0;
    DWORD temp = 1;

    temp = temp<<bitIndex;//将1左移bitIndex位,从而得到要与的值
    GetPortVal((WORD)pbPhysAddr,&dwPortVal2,1);
    QString str2 = "Previous write data:"+QString::number(dwPortVal2, 10);
    QMessageBox::information(NULL, "dwPortVal2", str2);
    DWORD flag2 = dwPortVal2&temp;

    if(flag2)//若为真,则第bitIndex位为1,灯是灭的,那么就要将其点亮
    {
        dwPortVal2 = ~dwPortVal2;
        Data = dwPortVal2 | temp;//取反->与->取反
        Data = ~Data;
    }
    else
    {
        Data = dwPortVal2 | temp;
    }

    QString str3 = "Write data:"+QString::number(Data, 10);
    QMessageBox::information(NULL, "Data", str3);

    SetPortVal((WORD)pbPhysAddr,(DWORD)Data,1);//进行设置
    dwPortVal2 = 0x0;//再初始化一次然后再获取
    GetPortVal((WORD)pbPhysAddr,&dwPortVal2,1);
    return dwPortVal2;//把那个地址获得的数据往上传
}

载入 WinIO

在 MainWindow 的构造函数中增加。

#if 0
HINSTANCE hDLL; // Handle to DLL
typedef bool (*fun)();
typedef bool (*gff)(WORD, PDWORD, BYTE);
    QLibrary qlib("WinIo64");
    if(qlib.load())
        {
            qDebug() << "\r\n";
            qDebug() << "qlib.load() success!" ;
            fun initWinIo=(fun)qlib.resolve("InitializeWinIo");
            if (initWinIo==nullptr)
            {
                qDebug() << "qlib.load() initWinIo fail";
            }
            bool bRet = initWinIo();
            if (!bRet) {
                qDebug()<<"Error In InitializeWinIo!";
            }
            gff fGetVal=(gff)qlib.resolve("GetPortVal");
            if (fGetVal==nullptr)
            {
                qDebug() << "qlib.load() GetPortVal fail";
            }

            WORD pbPhysAddr=0xA00;
            DWORD val = 0x0;
            bRet = fGetVal(pbPhysAddr,&val,(BYTE)1);
            qDebug() << QString::number(val, 16)<< " " << QString::number(val, 2);

            fGetVal(pbPhysAddr,&val,1);
            qDebug() << QString::number(val, 16)<< " " << QString::number(val, 2);

            qlib.unload();
    }
#else
    int retValue = 0;//非0代表的是失败,所以先暂时赋值为0
    retValue = InitializeWinIo();
    if (!retValue)
    {
        QMessageBox::critical(this, tr("Error"), tr("Can not load InitializeWinIo"));
    }
#endif

备注:
上面代码用了两周模式打开 DLL,两个模式都测试通过了。

增加 获取数据 信号槽

void MainWindow::on_pbGetValue_clicked()
{
    QString str = ui->leAddr->text();
    QByteArray array;
    array.append(str);
    WORD addr = array.toUShort(Q_NULLPTR,16);
    DWORD val = HTKReadDI(addr, 1);
    ui->leValue->setText(QString::number(val, 2));
}

运行效果

我用 DI1 做实验。根据上面的描述,DI1 对应的地址位 0xA00 的 bit0。

DI1 没有接入低电平

在这里插入图片描述
如上图所示,对应的 0xA00 数据位 0xFF,也就是 0b11111111,也就是对应的 DI1 为 1。

DI1 接入低电平

在这里插入图片描述
如上图所示,对应的 0xA00 数据位 0xFE,也就是 0b11111110,也就是对应的 DI1 为 0。

总结

这样,我们就完成了 Qt 通过 WinIO 读取计算机主板的 GPIO。

代码下载

对应的代码已经放到了 Github 上,https://github.com/ZHOUYI-UM/WinIO-Test-with-Qt5.13.2.git

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

努力的老周

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值