中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Qt怎么寫通信協議

發布時間:2021-12-15 13:56:10 來源:億速云 閱讀:130 作者:iii 欄目:互聯網科技

這篇文章主要講解了“Qt怎么寫通信協議”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Qt怎么寫通信協議”吧!

一、前言

通信協議解析是整個系統的核心靈魂,絕大部分人做軟硬件通信開發,第一步估計就是寫demo將協議解析好,然后再慢慢寫整個界面和操作流程等,在工業控制領域,modbus協議應用還是非常廣泛的,這個系統用的也是modbus協議,采用此協議可以方便的用一些第三方的組態軟件接入,兼容性更強,modbus只是個協議規約標準,至于使用串口還是網絡還是其他,都由廠家自行具體實現,一般正常來說,使用modbus協議的系統支持255個設備在同一個網絡上進行通信,而且大部分都會采用485半雙工的機制,挨個輪詢設備狀態,每次通信鏈路上要么在發送數據,要么在接收數據,不能同時進行,這樣有個好處就是可以傳輸的距離一般可以到1200米,而如果是串口全雙工的話,基本上在100米就歇菜,具體還要看波特率,當然如果可以用中轉設備進行轉發那除外。

本項目即支持串口設備也支持網絡設備,在端口管理中添加好對應的通信端口即可,modbus通信協議的解析庫,有個第三方開源的libmodbus,跨平臺的,Qt從Qt5.8以來新增了總線serialbus庫,其中就包括了QModbusClient和QModbusServer來做modbus協議的解析,本人兩種都用過,大同小異,使用方法都差不多,總體上libmodbus要優于Qt自帶的modbus。但是為了更大的靈活性,這個項目采用的自己程序解析協議數據來實現,這樣不用去糾結封裝的接口中每次發送幾個字節那些接口對應的含義等,而且自己解析也很方便,我寫過的所有的modbus通信項目,都是采用的自己做協議解析。

二、功能特點

  1. 采集數據端口,支持串口端口+網絡端口,串口支持自由設置串口號+波特率,網絡支持自由設置IP地址+通訊端口,每個端口支持采集周期,默認1秒鐘一個地址,支持設置通訊超時次數,默認3次,支持最大重連時間,用于重新讀取離線的設備。

  2. 控制器信息,能夠添加控制器名稱,選擇控制器地址+控制器型號,設置該控制器下面的探測器數量。

  3. 探測器信息,能夠添加位號,可自由選擇探測器型號,氣體種類,氣體符號,高報值,低報值,緩沖值,清零值,是否啟用,報警聲音,背景地圖,存儲周期,數值換算小數點位數,報警延時時間,報警的類型(HH,LL,HL)等。

  4. 控制器型號+探測器型號+氣體種類+氣體符號,均可自由配置。

  5. 地圖支持導入和刪除,所有的探測器對應地圖位置可自由拖動保存。

  6. 端口信息+控制器信息+探測器信息,支持導入導出+導出到excel+打印。

  7. 運行記錄+報警記錄+用戶記錄,支持多條件組合查詢,比如時間段+控制器+探測器等,所有記錄支持導出到excel+打印。

  8. 導出到excel的記錄支持所有excel+wps等表格文件版本,不依賴excel等軟件。

  9. 可刪除指定時間范圍內的數據,支持自動清理早期數據,設置最大保存記錄數。

  10. 支持報警短信轉發,支持多個接收手機號碼,可設定發送間隔,比如即時發送或者6個小時發送一次所有的報警信息,短信內容過長,自動拆分多條短信。

  11. 支持報警郵件轉發,支持多個接收郵箱,可設定發送間隔,比如即時發送或者6個小時發送一次所有的報警信息,支持附件發送。

  12. 高報顏色+低報顏色+正常顏色+0值顏色+曲線背景+曲線顏色等,都可以自由選擇。

  13. 軟件的中文標題+英文標題+logo路徑+版權所有都可以自由設置。

  14. 提供開關設置開機運行+報警聲音+自動登錄+記住密碼等。

  15. 報警聲音可設置播放次數,界面提供17種皮膚文件選擇。

  16. 支持云端數據同步,可設置云端數據庫的信息,比如數據庫名稱,用戶名+密碼等。

  17. 支持網絡轉發和網絡接收,網絡接收開啟后,軟件從udp接收數據進行解析。網絡轉發支持多個目標IP,這樣就實現了本地采集的軟件,自由將數據轉到客戶端,隨時查看探測器數據。

  18. 自動記住用戶最后停留的界面+其他信息,重啟后自動應用。

  19. 報警自動切換到對應的地圖,探測器按鈕閃爍。

  20. 雙擊探測器圖標,可以進行回控。

  21. 支持用戶權限管理,管理員+操作員兩大類,用戶登錄+用戶退出,可以記住密碼和自動登錄,超過三次報錯提示并關閉程序。

  22. 支持四種監控模式,設備面板監控+地圖監控+表格數據監控+曲線數據監控,可自由切換,四種同步應用。

  23. 支持報警繼電器聯動,一個位號可以跨串口聯動多個模塊和繼電器號,支持多對多。

  24. 本地數據存儲支持sqlite+mysql,支持遠程數據同步到云端數據庫。自動重連。

  25. 本地設備采集到的數據實時上傳到云端,以便手機APP或者web等其他方式提取。

  26. 支持兩種數據源,一種是串口和網絡通過協議采集設備數據,一種是數據庫采集。數據庫采集模式可以作為通用的系統使用。

  27. 自帶設備模擬工具,支持16個設備數據模擬,同時還帶數據庫數據模擬,以便在沒有設備的時候測試數據。

  28. 默認通信協議采用modbus協議,后期增加mqtt等物聯網協議的支持,做成通用系統。

  29. 支持所有windows操作系統+linux操作系統和其他操作系統。

三、效果圖

Qt怎么寫通信協議

四、核心代碼

void DeviceClient::checkValue()
{
    if (!isOk) {
        return;
    }

    QMutexLocker locker(&mutex);
    readData();

    //至少要多少個字節,保證下面取數據不出錯
    int size = buffer.size();
    if (size < 5) {
        return;
    }

    //01 03 08 00 00 00 00 00 00 00 00 95 D7
    //01 03 08 00 14 03 12 00 00 00 00 79 E6

    //取出首字節,判斷是否為當前地址集合中的地址
    quint8 addr = buffer.at(0);
    quint8 cmd = buffer.at(1);
    quint8 len = buffer.at(2);

    //如果是錯誤碼則直接解析錯誤信息
    QList<quint8> cmds;
    cmds << 0x03 << 0x04 << 0x06;
    if (!cmds.contains(cmd)) {
        emit receiveError(portName, addr, QString("數據出錯: %1").arg(QUIHelper::byteArrayToHexStr(buffer)));
        buffer.clear();
        return;
    }

    //如果數據過長則丟棄當前數據包,不然一旦產生了錯誤的數據會一直累積
    if (size > 517) {
        emit receiveError(portName, addr, QString("數據出錯: %1").arg(QUIHelper::byteArrayToHexStr(buffer)));
        buffer.clear();
        return;
    }

    //后面的數據長度必須大于等于長度數據位表示的長度
    if ((cmd == 0x03 || cmd == 0x04 || cmd == 0x06) && size < len + 5) {
        emit receiveError(portName, addr, QString("數據不全,等待完整數據再解析: %1").arg(QUIHelper::byteArrayToHexStr(buffer)));
        return;
    }

    //放在這里發出去數據是準確的完整的
    emit receiveData(portName, addr, buffer);

    //過濾不存在的地址,防止索引越界
    int index = addrs.indexOf(addr);
    if (index < 0) {
        emit receiveError(portName, addr, "地址出錯: 當前地址不在設定的地址集合中");
        buffer.clear();
        return;
    }

    //來過消息的設備,立馬更新最后的消息時間,以及判斷設備上線
    times[index] = QDateTime::currentDateTime();
    if (!onlines.at(index)) {
        onlines[index] = true;
        emit receiveOnline(portName, addr, true);
        emit receiveInfo(portName, addr, "設備上線");
    }

    //根據不同的cmd+不同的命令類型 取出對應的數據內容
    if (cmd == 0x03) {
        QString info;
        if (currentType == "查詢濃度值") {
            QList<quint16> values;
            for (int i = 3; i < size - 2; i = i + 2) {
                values << (float)QUIHelper::byteToUShort(buffer.mid(i, 2));
            }

            QStringList list;
            foreach (quint16 value, values) {
                list << QString::number(value);
            }

            info = QString("%1返回: %2").arg(currentType).arg(list.join(" "));
            emit receiveValue(portName, addr, values);
        } else if (currentType == "查詢4路AD值") {
            //01 03 08 02 07 08 0C 00 00 00 00 73 87
            QList<quint16> values;
            for (int i = 3; i < size - 2; i = i + 2) {
                values << (float)QUIHelper::byteToUShort(buffer.mid(i, 2));
            }

            QStringList list;
            foreach (quint16 value, values) {
                list << QString::number(value);
            }

            info = QString("%1返回: %2").arg(currentType).arg(list.join(" "));
            emit receiveValueAD4(portName, addr, values);
        } else if (currentType == "查詢報警標志") {
            //01 03 08 00 00 00 12 07 13 00 12 5D 68

        } else if (currentType == "查詢標定日期") {
            //01 03 04 00 12 07 13 19 CB
            int year = QString("20%1").arg(QString::number(buffer.at(4), todate)).toInt();
            int month = QString::number(buffer.at(5), todate).toInt();
            int day = QString::number(buffer.at(6), todate).toInt();
            info = QString("%1返回: %2年%3月%4日").arg(currentType).arg(year).arg(month).arg(day);
            emit receiveDate(portName, addr, year, month, day);
        } else if (currentType == "查詢出廠日期") {
            //01 03 04 00 12 07 13 19 CB
            int year = QString("20%1").arg(QString::number(buffer.at(4), todate)).toInt();
            int month = QString::number(buffer.at(5), todate).toInt();
            int day = QString::number(buffer.at(6), todate).toInt();
            info = QString("%1返回: %2年%3月%4日").arg(currentType).arg(year).arg(month).arg(day);
            emit receiveDateInit(portName, addr, year, month, day);
        }

        //發送對應的文字解析
        if (!info.isEmpty()) {
            emit receiveInfo(portName, addr, info);
        }
    } else if (cmd == 0x04) {

    } else if (cmd == 0x06) {

    }

    //重新賦值
    buffer.clear();
}

感謝各位的閱讀,以上就是“Qt怎么寫通信協議”的內容了,經過本文的學習后,相信大家對Qt怎么寫通信協議這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

qt
AI

澎湖县| 湟源县| 石林| 大方县| 密云县| 五大连池市| 明光市| 新宾| 日土县| 藁城市| 绵竹市| 无锡市| 大竹县| 中超| 通许县| 建始县| 申扎县| 启东市| 吉安市| 吉木乃县| 溧阳市| 奉化市| 远安县| 郯城县| 新郑市| 永春县| 扎兰屯市| 瑞安市| 朝阳县| 峨山| 东乡县| 张家口市| 报价| 宁强县| 禹城市| 榆中县| 鄂温| 富阳市| 汉寿县| 荃湾区| 包头市|