应用界面编写(十四)

news2024/12/26 15:06:23

一. 介绍QT

接下来我们会在Qt Creater来进行界面的编写,并且在荔枝派中运行。那么我们有必要了解一下Qt到底是什么呢?它又为什么可以在荔枝派中运行呢?

QT是一个跨平台的应用程序和用户界面框架,用于开发具有图形界面的软件。而QT的跨平台原理则是基于“一次编码,处处编译”的策略。这意味着开发者可以使用相同的源代码在不同的平台上编译,以生产适应各个平台的应用程序。QT框架通过封装底层操作系统的差异,为开发者提供了统一的API接口,从而实现跨平台开发。

而QT可以对不同平台的编译器和环境进行区分,例如,QT使用宏定义来区分不同的操作系统和编译器环境,如Linux、MSVC、MINGW等,从而在编译时选择合适的实现。

二. QT移植和编译执行文件

全志D1-H,官方SDK Tina2.0 移植 QT5.15 | 全志在线开发者论坛 (aw-ol.com)

2.1 下载源码

点击下载QT5.15.4

wget https://mirrors.tuna.tsinghua.edu.cn/qt/official_releases/qt/5.15/5.15.4/single/qt-everywhere-opensource-src-5.15.4.tar.xz

tar zxvf qt-everywhere-opensource-src-5.15.4.tar.xz
cd qt-everywhere-opensource-src-5.15.4

2.2 环境配置

添加交叉编译配置文件qt-everywhere-src-5.15.4/qtbase/mkspecs/linux-riscv64-gnu-g++/qmake.conf,内容如下:

# qmake configuration for building with riscv64-unknown-linux-gnu-g++no
MAKEFILE_GENERATOR      = UNIX
CONFIG                 += incremental
QMAKE_INCREMENTAL_STYLE = sublib

include(../common/linux.conf)
include(../common/gcc-base-unix.conf)
include(../common/g++-unix.conf)

# modifications to g++.conf
QMAKE_CC                = riscv64-unknown-linux-gnu-gcc   # 需要使用的交叉编译工具链的名称
QMAKE_CXX               = riscv64-unknown-linux-gnu-g++
QMAKE_LINK              = riscv64-unknown-linux-gnu-g++ 
QMAKE_LINK_SHLIB        = riscv64-unknown-linux-gnu-g++
QMAKE_LIBS              = -latomic

# modifications to linux.conf
QMAKE_AR                = riscv64-unknown-linux-gnu-ar cqs
QMAKE_OBJCOPY           = riscv64-unknown-linux-gnu-objcopy
QMAKE_NM                = riscv64-unknown-linux-gnu-nm -P
QMAKE_STRIP             = riscv64-unknown-linux-gnu-strip
load(qt_config)

 添加编译配置文件qt-everywhere-src-5.15.4/qtbase/mkspecs/linux-riscv64-gnu-g++/qplatformdefs.h,内容如下:

/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the qmake spec of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "../linux-g++/qplatformdefs.h"

修改源码中一个缺失的头文件包含,位于 qt-everywhere-src-5.15.4/qtdeclarative/src/qmldebug/qqmlprofilerevent_p.h :52行,添加如下内容:

#include <limits>

在QT源码根目录创建 configure 自动配置文件

vi autoConfigure.sh
./configure \
    -prefix ./riscv-qt \
    -opensource \
    -confirm-license \
    -release \
    -strip \
    -shared \
    -xplatform linux-riscv64-gnu-g++ \
    -optimized-qmake \
    -c++std c++11 \
    --rpath=no \
    -pch \
    -skip qt3d \
    -skip qtactiveqt \
    -skip qtandroidextras \
    -skip qtcanvas3d \
    -skip qtconnectivity \
    -skip qtdatavis3d \
    -skip qtdoc \
    -skip qtgamepad \
    -skip qtlocation \
    -skip qtmacextras \
    -skip qtnetworkauth \
    -skip qtpurchasing \
    -skip qtremoteobjects \
    -skip qtscript \
    -skip qtscxml \
    -skip qtsensors \
    -skip qtspeech \
    -skip qtsvg \
    -skip qttools \
    -skip qttranslations \
    -skip qtwayland \
    -skip qtwebengine \
    -skip qtwebview \
    -skip qtwinextras \
    -skip qtx11extras \
    -skip qtxmlpatterns \
    -make libs \
    -make examples \
    -nomake tools \
    -nomake tests \
    -gui \
    -widgets \
    -dbus-runtime \
    --glib=no \
    --iconv=no \
    --pcre=qt \
    --zlib=qt \
    -no-openssl \
    --freetype=qt \
    --harfbuzz=qt \
    -no-opengl \
    -linuxfb \
    --xcb=no \
    -tslib \
    --libpng=qt \
    --libjpeg=qt \
    --sqlite=qt \
    -plugin-sql-sqlite \
    -I/home/allwinner/LicherPI/tina-d1-h/tina_d1_open_v2/out/d1-h-nezha/staging_dir/target/usr/include/ \
    -I/home/allwinner/LicherPI/tina-d1-h/tina_d1_open_v2/out/d1-h-nezha/staging_dir/target/usr/include/allwinner/ \
    -I/home/allwinner/LicherPI/tina-d1-h/tina_d1_open_v2/out/d1-h-nezha/staging_dir/target/usr/include/allwinner/include/ \
    -L/home/allwinner/LicherPI/tina-d1-h/tina_d1_open_v2/out/d1-h-nezha/staging_dir/target/usr/lib/ \
    -recheck-all

使用简化配置

试图使用最简化的配置选项来排除参数问题。例如:

复制代码

./configure -prefix /path/to/install/qt -opensource -confirm-license -release

如果这成功了,逐步添加其他参数以找出引发问题的参数。

2.3 交叉编译QT5文件

进入QT源码根目录,运行刚刚配置的环境。

source ./autoConfigure.sh

若配置成功会显示以下信息

image-20220529224209489

开始编译,具体核心数按照自己的配置指定,预留 8G 空间已足够使用。

make -j2

我按照以上配置一次编译成功,没有遇见错误。

编译成功后执行

make install

安装目录在qt-everywhere-src-5.15.4/qtbase/bin/riscv-qt

riscv-qt 就是刚刚配置文件中-prefix ./riscv-qt指定的目录。

2.4 移植

将该目录移动到DockRV开发板上,具体方法可以 tar 打包后通过 adb push 或者SFTP发送。

创建环境配置文件 qt-path

echo begin
export QT_HOME=/root/riscv-qt

export QT_QPA_PLATFORM=linuxfb:tty=/dev/fb0
export QT_QPA_FB_DRM=1
export QT_QPA_GENERIC_PLUGINS=evdevkeyboard
export QT_QPA_EVDEV_KEYBOARD_PARAMETERS=/dev/input/event0

#export QT_QPA_GENERIC_PLUGINS=evdevmouse
#export QT_QPA_EVDEV_MOUSE_PARAMETERS=/dev/input/event1

export QT_QPA_GENERIC_PLUGINS=evdevtouch
export QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS=/dev/input/event2

export QT_PLUGIN_PATH=$QT_HOME/plugins
export LD_LIBRARY_PATH=/lib:/usr/lib:$QT_HOME/lib

2.5 问题解决

2.5.1 链接断开

报错链接断开了,所有.so文件都断开了?

while loading shared libraries: /lib64/libgcc_s.so.1: file too short_error while loading shared libraries file too shor-CSDN博客

就改回蓝色了。 

2.5.2 报错缺少链接文件

root@TinaLinux:~/bin/riscv-qt/examples/gui/analogclock# ./analogclock
./analogclock: error while loading shared libraries: libatomic.so.1: cannot open shared object file: No such file or directory

检查 qt-path 的 LIB 配置, 或者是少了这些链接文件

libatomic.so,libatomic.so.1,libatomic.so.1.2.0

QT时钟程序报不能加载.so库 | 全志在线开发者论坛 (aw-ol.com)

添加如下链接文件,并且建立链接 

2.5.3 GCC版本报错 

CentOS 安装QT SDK qt-everywhere-src-5.15.0.tar.xz时报错-CSDN博客

GCC版本为4.8.5,需要升级GCC

2.5.4 qmake编译.pro文件

qtbase目录下,执行命令

$(QMAKE) -o Makefile 目录/.pro

QMAKE         = /home/allwinner/LicherPI/tina-d1-h/QT/qt-everywhere-src-5.15.4/qtbase/bin/qmake

/home/allwinner/LicherPI/tina-d1-h/QT/qt-everywhere-src-5.15.4/qtbase/bin/qmake -o Makefile apply_1/apply_1.pro

 .pro文件添加如下:

QMAKE_PROJECT_NAME = apply_1

# install

target.path = $$[QT_INSTALL_EXAMPLES]/apply_1/apply_1

INSTALLS += target

三. GPIO

bool GPIO::initialize()
{
    if (m_initialized) {
        return true; // Already initialized
    }

    // Export GPIO pin
    if (!exportPin()) {
        return false;
    }

    m_initialized = true;
    return true;
}

bool GPIO::exportPin()
{
    QFile file("/sys/class/gpio/export");
    if (file.open(QIODevice::WriteOnly))
    {
        QTextStream stream(&file);
        stream << m_pin;
        file.flush();
        file.close();
        return true;
    }
    qWarning() << "Failed to export GPIO pin:" << m_pin;
    return false;
}

bool GPIO::unexportPin()
{
    QFile file("/sys/class/gpio/unexport");
    if (file.open(QIODevice::WriteOnly))
    {
        QTextStream stream(&file);
        stream << m_pin;
        file.close();
        return true;
    }
    qWarning() << "Failed to unexport GPIO pin:" << m_pin;
    return false;
}

bool GPIO::setDirection(const QString &direction)
{
    QFile file(m_path + "direction");
    if (file.open(QIODevice::WriteOnly))
    {
        QTextStream stream(&file);
        stream << direction;
        file.close();
        return true;
    }
    qWarning() << "Failed to set direction for GPIO pin:" << m_pin;
    return false;
}

bool GPIO::setValue(int value)
{
    QFile file(m_path + "value");
    if (file.open(QIODevice::WriteOnly))
    {
        QTextStream stream(&file);
        stream << value;
        file.close();
        return true;
    }
    qWarning() << "Failed to set value for GPIO pin:" << m_pin;
    return false;
}

int GPIO::getValue()
{
    QFile file(m_path + "value");
    if (file.open(QIODevice::ReadOnly))
    {
        QTextStream stream(&file);
        int value;
        stream >> value;
        file.close();
        return value;
    }
    qWarning() << "Failed to get value for GPIO pin:" << m_pin;
    return -1;
}
PG15(207)GPIO输出控制继电器,控制风机,高电平吸合
PD20(116)GPIO输出控制485读写模式
PD9(105)GPIO输入,外部上拉读上限位
PD10(106)GPIO输入,外部上拉读下限位
PD12(108)GPIO输入,外部上拉读水位
PD13(109)GPIO输出控制继电器,来控制压缩机,高电平吸合
PD15(111)GPIO输出控制继电器,来控制水泵,高电平吸合
PD6(102)GPIO输入,外部上拉中间限位
PD11(107)GPIO输出控制继电器,底盘上升,高电平吸合
PD16(112)GPIO输出控制继电器,底盘下降,高电平吸合
PD17(113)GPIO输出控制固态继电器,来控制水加热(已接220v),低电平吸合

3.1 GPIO输出

实际上有些需要注意的地方,我们在改变 LED 的状态时,需要先去读取 LED 的状态,

PG15(207)GPIO输出控制继电器,控制风机,高电平吸合
PD15(111)GPIO输出控制继电器,来控制水泵,高电平吸合
PD17(113)GPIO输出控制固态继电器,来控制水加热(已接220v),低电平吸合
PD13(109)GPIO输出控制继电器,来控制压缩机,高电平吸合
PD11(107)GPIO输出控制继电器,底盘上升,高电平吸合
PD16(112)GPIO输出控制继电器,底盘下降,高电平吸合

 3.2 GPIO输入

PD9(105)GPIO输入,外部上拉读上限位
PD10(106)GPIO输入,外部上拉读下限位
PD12(108)GPIO输入,外部上拉读水位

通过sysfs方式控制GPIO,先访问/sys/class/gpio目录,向export文件写入GPIO编号,使得该 GPIO 的操作接口从内核空间暴露到用户空间,GPIO 的操作接口包括 direction 和 value 等,direction 控制 GPIO 方向,而 value 可控制 GPIO 输出或获得 GPIO 输入。文件 IO 方式操作 GPIO,使用到了4个函数 open、close、read、write。

首先,看看系统中有没有“/sys/class/gpio”这个文件夹。如果没有请在编译内核的时候加入:

Device Drivers -> 
        GPIO Support ->
                /sys/class/gpio/… (sysfs interface)。

/sys/class/gpio 的使用说明

如果是在已经适配好的 Linux 内核上,那么相信已经有了完成的 gpiochip,可以在用户空间 /sys/class/gpio 目录下看到如下文件:

嵌入式Linux:Qt5+触摸屏+点灯(使用sysfs控制gpio)_qt gpio-CSDN博客

# cd /sys/class/gpio
# ls
export     gpiochip0  unexport

#define BEEP_PATH        "/sys/class/gpio/gpio36"

/* QButtonGroup */
bgbeep = new QButtonGroup(this);

connect(bgbeep, SIGNAL(buttonClicked(int)), this, SLOT(execCmd(int)));
    
void MainWindow::execCmd(int id)
{
    QString path = BEEP_PATH;
   /* 由于system函数只能用char类型,所以进行了转换 */
    /* export */
    QString cmd_export = "echo 36 > /sys/class/gpio/export";
    QByteArray cmdby_export = cmd_export.toLatin1();
    char* charCmd_export = cmdby_export.data();
    /* config */
    QString cmd_dir = "echo out >"+ path +"/direction";
    QByteArray cmdby_dir = cmd_dir.toLatin1();
    char* charCmd_dir = cmdby_dir.data();
    /* 关 */
    QString cmd_off = "echo 0 >"+ path +"/value";
    QByteArray cmdby_off = cmd_off.toLatin1();
    char* charCmd_off = cmdby_off.data();
    /* 开 */
    QString cmd_on = "echo 1 >"+ path +"/value";
    QByteArray cmdby_on = cmd_on.toLatin1();
    char* charCmd_on = cmdby_on.data();
	/* 导出GPIO */
    system(charCmd_export);
	/* 设置GPIO的输入输出状态 */
    system(charCmd_dir);

    switch (id) {
    case 0:
        system(charCmd_off);
        break;
    case 1:
        system(charCmd_on);
        break;
    }
}

四. 摄像头

V4L2是视频设备的驱动框架,为上层访问底层的视频视频设备,提供统一的接口,dev目录产生,USB摄像头常用,FFMPEG,使用V4L2库、完成对图片的捕捉,并且保存为一张图片,依照Tina SDK开发框架,我们代码床啊金在,

USB摄像头拍照Demo - D1-H (aw-ol.com)

https://blog.csdn.net/qq_41873311/article/details/125209866

V4L2编程之USB摄像头采集jpeg图像

首先是打开摄像头设备;
查询设备的属性或功能;
设置设备的参数,譬如像素格式、 帧大小、 帧率;
申请帧缓冲、 内存映射;
帧缓冲入队;
开启视频采集;
帧缓冲出队、对采集的数据进行处理;
处理完后,再次将帧缓冲入队,往复;
结束采集。

五. UART

//CO2模块
void Serial::serial_Open()
{
             CO2_Data.resize(6);

            // 删除旧的串口对象(如果存在)
            if (serial) {
                delete serial;
            }

            serial = new QSerialPort();
            serial->setPortName("/dev/ttyS1"); // 你的串口名称
            serial->setBaudRate(QSerialPort::Baud9600);
            serial->setDataBits(QSerialPort::Data8);
            serial->setParity(QSerialPort::NoParity);
            serial->setStopBits(QSerialPort::OneStop);
            serial->setFlowControl(QSerialPort::NoFlowControl);

            // 打开串口,只允许读
            if (serial->open(QIODevice::ReadOnly)) {
                qDebug() << "UART_1 opened successfully.";
            } else {
                qDebug() << "Failed to open UART_1";
            }

            // 连接信号和槽
        connect(serial, &QSerialPort::readyRead, this, &Serial::handleReadyRead);
}

void Serial::handleReadyRead()
{
    QByteArray data = serial->readAll();
    qDebug() << "Received data:" << data;

    // 处理接收到的数据
    for (char byte : data) {
        if (index < CO2_Data.size()) {
            CO2_Data[index++] = byte; // 使用 QByteArray 的赋值方法
        }

        if (index >= CO2_Data.size()) {
            // 校验数据的正确性
            if (CO2_Data[0] == 0x2C &&
                CO2_Data[5] == (uint8_t)(CO2_Data[0] + CO2_Data[1] + CO2_Data[2] + CO2_Data[3] + CO2_Data[4]))
            {
                // 更新UI,确保在主线程中更新 UI
                QMetaObject::invokeMethod(ui->co2, "setText", Qt::QueuedConnection,
                                          Q_ARG(QString, QString::number(CO2_Data[1] * 256 + CO2_Data[2])));

                // 打印调试信息
                qDebug() << CO2_Data[0] << " " << CO2_Data[1] << " " << CO2_Data[2] << " "
                         << CO2_Data[3] << " " << CO2_Data[4] << " " << CO2_Data[5];
            }

            // 重置索引
            index = 0;
        }
    }
}

二氧化碳模块--波特率:9600;模块型号:JW01-CO2-V2.2;

TXD是5V,但如果我们用3.3V供电,但我们D1-H只能承受3.3V,因此我们只能供电3.3V

数据位8位,停止位1位,无校验

一秒钟检测一次CO2,自带了数据检测。

下图可知,一共是六个字节,一个是固定的2C,通过这个来使得获取的数据位对齐

第二个和第三个字节可以通过公式来得到检测到的CO2浓度

然后第三个和第五个也是固定的,0x03和0xFF

最后一个字节是校验位,也就是前五个字节加起来,要转位8位的数据格式,例如uint8_t,等于第六个字节的时候,我们得到的数据才是正确的

JW01虽然是需要5V供电,但是3.3V也可以带动,不过预热速度会比5V稍慢一些

我们只需要接收JW01的信息而不需要给他发送数据,因为JW01固定发送的是6字节的数据,因此我们使用容量为6个uint8_t的数组来存放数据。在接收中断函数里面,按照接收的顺序把收到的数据放入到数组里,但是要多一个判断,只有当我们准备存放在数值的第一位并且此时接收的数据为0x2C的时候(参考前文的数据包格式),JW01的发送速率是一秒发一次。也就是说正常情况下我们数组里的数据是一秒更新一次。接收之后我们显示检测的数据,CO2的浓度为数组第二个元素乘上256再加上数值第三个元素,单位为ppm。并且之前也说了,六个字节的最后一个字节是校验位,前五个字节加起来要等于第六个字节,需要注意的是在比较的时候需要将比较结果转换为8个bit的数据,这样才能正确比较。

【STM32F103】JW01-CO2-V2.2二氧化碳检测模块(USART)_jw01二氧化碳传感器-CSDN博客

六. RS485

//RS485
void Serial::serial_485_Open()
{
    // 删除旧的串口对象(如果存在)
    if (serial_485) {
        delete serial_485;
    }

    serial_485 = new QSerialPort(this);
    serial_485->setPortName("/dev/ttyS4"); // 你的串口名称
    serial_485->setBaudRate(QSerialPort::Baud9600);
    serial_485->setDataBits(QSerialPort::Data8);
    serial_485->setParity(QSerialPort::NoParity);
    serial_485->setStopBits(QSerialPort::OneStop);
    serial_485->setFlowControl(QSerialPort::NoFlowControl);

    // 打开串口
    if (serial_485->open(QIODevice::ReadWrite)) {
        qDebug() << "UART_4 opened successfully.";
        sendRequest();
    } else {
        qDebug() << "Failed to open UART_4";
    }

    connect(serial_485, &QSerialPort::readyRead, this, &Serial::handleReadyRead_485);
}
void Serial::sendRequest()
{
    QByteArray request;
    request.append(static_cast<char>(0x01));  // 从站地址
    request.append(static_cast<char>(0x03));  // 功能码
    request.append(static_cast<char>(0x00));  // 起始地址高字节
    request.append(static_cast<char>(0x02));  // 起始地址低字节
    request.append(static_cast<char>(0x00));  // 寄存器数量高字节
    request.append(static_cast<char>(0x02));  // 寄存器数量低字节

    // 计算 CRC
    uint crc = CRC16(request);
    request.append(static_cast<char>(crc & 0xFF));     // CRC 低位
    request.append(static_cast<char>((crc >> 8) & 0xFF));  // CRC 高位

    serial_485->write(request);
    if (serial_485->waitForBytesWritten(1000)) {
        qDebug() << "Request sent successfully.";
    } else {
        qDebug() << "Failed to send request.";
    }
}

void Serial::handleReadyRead_485()
{
    QByteArray response = serial_485->readAll();
    processResponse(response);
}
void Serial::processResponse(const QByteArray &response)
{
    if (response.size() != 9)// 长度应为9
    {
        qDebug() << "Invalid response length.";
        return;
    }

     // 提取数据
    unsigned char temperatureH = response[3];
    unsigned char temperatureL = response[4];
    unsigned char humidityH = response[5];
    unsigned char humidityL = response[6];
    unsigned char crcL = response[7];
    unsigned char crcH = response[8];

    // 计算 CRC
    QByteArray data = response.left(7);  // 取前7个字节进行CRC校验(不包括 CRC 字节)
    uint calculatedCRC = CRC16(data);

    // 校验 CRC
    if (calculatedCRC == ((crcH << 8) | crcL)) {
        qDebug() << "CRC valid!";
        qDebug() << "Temperature:" << ((temperatureH << 8) | temperatureL);
        qDebug() << "Humidity:" << ((humidityH << 8) | humidityL);
    } else {
        qDebug() << "CRC invalid!";
    }
}
uint Serial::CRC16(const QByteArray &data)
{
    unsigned char uchCRCHi = 0xFF;  // 高CRC字节初始化
           unsigned char uchCRCLo = 0xFF;  // 低CRC字节初始化
           uint uIndex;

           static const unsigned char auchCRCHi[] = {
               // CRC 查找表的高字节部分
               0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
               0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
               0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
               0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
               0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
               0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
               0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
               0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
               0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1,
               0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
               0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
               0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
               0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1,
               0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
               0x00, 0xC1, 0x81, 0x40
           };

           static const unsigned char auchCRCLo[] = {
               // CRC 查找表的低字节部分
               0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
               0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
               0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
               0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
               0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
               0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
               0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
               0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
               0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
               0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
               0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
               0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
               0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
               0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
               0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
               0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
               0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D,
               0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A,
               0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
               0x41, 0x81, 0x80, 0x40
           };

           for (int i = 0; i < data.size(); ++i)
           {
               uIndex = uchCRCHi ^ static_cast<unsigned char>(data[i]);  // 计算CRC
               uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
               uchCRCLo = auchCRCLo[uIndex];
           }

           return (uchCRCHi << 8) | uchCRCLo;
}

void Serial::sendAddressChangeRequest()
{
    QByteArray request;

    // 构造请求数据
    request.append(static_cast<char>(0x00));  // 地址(主机地址)
    request.append(static_cast<char>(0x10));  // 功能码(写寄存器)
    request.append(static_cast<char>(0x00));  // 写入位置高位
    request.append(static_cast<char>(0x00));  // 写入位置低位
    request.append(static_cast<char>(0x00));  // 操作数高位(这里假设为0)
    request.append(static_cast<char>(0x01));  // 操作数低位(当前地址为0x01)
    request.append(static_cast<char>(0x02));  // 字节长度(修改地址需要2字节)
    request.append(static_cast<char>(0x00));  // 写入内容高位(新地址高位)
    request.append(static_cast<char>(0x02));  // 写入内容低位(新地址低位)

    // 计算CRC
    uint crc = CRC16(request);
    request.append(static_cast<char>(crc & 0xFF));     // CRC 低位
    request.append(static_cast<char>((crc >> 8) & 0xFF));  // CRC 高位

    serial_485->write(request);
    if (serial_485->waitForBytesWritten(1000)) {  // 等待最多3000毫秒
        qDebug() << "Address change request sent successfully.";
    } else {
        qDebug() << "Failed to send address change request.";
    }
}

步骤

  • 设置 RS485 通信:配置串口。
  • 发送请求:发送读取数据的命令。
  • 接收响应:读取并解析变送器返回的数据。
  • 校验数据:使用 CRC16 校验响应数据的有效性。
PD20(116)GPIO输出控制485读写模式

;半双工,半双工可以进行一主多从的通信;

逻辑1:以两线间的电压差为+(2~6)V来表示

逻辑0:以两线间的电压差为-(2~6)V来表示

B-RS-L30  光照传感器模块

1). 串行接口:波特率 9600, 数据位 8 位,停止位 1 位,无校验位;

2). 设备地址:默认地址模式 0x01;(“0x**”表示十六进制数)

THM-V6 温湿度模块

在RS485网络中使用MODBUS协议进行通信,MODBUS是一种用于工业自动化的串行通信协议,可以在RS485或RS232物理层上运行。

发送请求:发送的报文是'01 03 00 02 00 02 65 CB',其中'01'是从设备地址,'03'是功能码,'00 0 2'是起始地址,'00 0 2'是读取的寄存器数量,'65 CB'是CRC校验码。

接收数据并处理:发送器返回数据格式为'01 03 04 温度H 温度H 湿度L 湿度L CRC_L CRC_H',你需要读取这些字节并进行CRC校验。

CRC函数计算方法

预置一个16位的寄存器为十六进制FFFF,

把第一个8位二进制数据与16位的CRC寄存器的低8位相异或,

七. WIFI

void Serial::wifi_Connect(int *flag_t, const QString &command) {
//    if (flag == nullptr) {
//        qCritical() << "[Error] Flag pointer is null! Cannot proceed with WiFi connection.";
//        return;
//    }

    *flag_t = this->flag;
      qDebug() << "this->flag;" << this->flag;
    // 如果进程还在运行,等待其结束
    if (process && process->state() != QProcess::NotRunning) {
        qWarning() << "[Warning] Previous process is still running! Waiting for it to finish. Command: " << command;
        process->waitForFinished();  // 等待之前的进程结束
    }

    // 创建一个新的 QProcess 对象
    process = QSharedPointer<QProcess>::create(this);
    qDebug() << "[Info] Created a new QProcess for command: " << command;
    // 启动外部命令
    process->start(command);

    // 检查进程是否成功启动
    if (!process->waitForStarted()) {
        qCritical() << "[Error] Failed to start process for command: " << command;
      //  *flag = 0;
        return; // 退出函数,防止进一步操作
    } else {
        qDebug() << "[Info] Process started successfully. Command: " << command;
    }

    // 连接信号和槽
    connect(process.data(), SIGNAL(readyReadStandardOutput()), this, SLOT(handleStandardOutput()));
    connect(process.data(), SIGNAL(readyReadStandardError()), this, SLOT(handleStandardError()));
   // connect(process.data(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onProcessFinished(int, QProcess::ExitStatus)));

    // 等待进程完成
    if (!process->waitForFinished()) {
        qWarning() << "Process did not finish correctly";
        process->deleteLater(); // 使用 deleteLater 释放内存
        return;
    }

}

void Serial::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) {
    qDebug() << "[Info] Process finished. Exit code:" << exitCode << ", Exit status:" << exitStatus;

    if (exitCode == 0) {
        qDebug() << "[Success] Process completed successfully.";
    } else {
        qWarning() << "[Failure] Process failed. Exit code: " << exitCode << ", Exit status: " << exitStatus;
    }

    // 检查 process 是否有效
    if (!process) {
        qCritical() << "[Error] Process object is null. It might have been destroyed elsewhere!";
        return;
    }

    // 在释放之前,检查进程状态
    if (process->state() != QProcess::NotRunning) {
        qWarning() << "[Warning] Process is still running! Waiting for it to finish.";
        if (!process->waitForFinished(5000)) {  // 等待进程结束(最多 5 秒)
            qCritical() << "[Critical] Process did not finish in time!";
        }
    }

    // 断开所有信号连接,确保不会访问被销毁的对象
    disconnect(process.data(), SIGNAL(readyReadStandardOutput()), this, SLOT(handleStandardOutput()));
    disconnect(process.data(), SIGNAL(readyReadStandardError()), this, SLOT(handleStandardError()));
    disconnect(process.data(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onProcessFinished(int, QProcess::ExitStatus)));

    // 使用延时机制释放 QProcess 对象,避免在销毁时出现竞争条件
    QTimer::singleShot(10, this, SLOT(resetProcess()));
}

void Serial::resetProcess() {
    if (process && process->state() == QProcess::NotRunning) {
        qDebug() << "[Info] Process has been reset.";
        process.reset();
    } else {
        qWarning() << "[Warning] Process is still running or already null!";
    }
}


void Serial::handleStandardOutput() {
    if (process) {
        QString output = process->readAllStandardOutput();
        qDebug() << "[Info] Standard Output received from process:" << output;


        if (output.contains("Wifi connect ap : Success!")) {
            qDebug() << "[Success] WiFi connected to the specified network.";
            this->flag = 1;  // WiFi连接成功
            qDebug() <<"wifi_yesorno:"<<this->flag;
        }
//        else {
//            qWarning() << "[Warning] WiFi did not connect. Full output log: " << output;

//            this->flag = 0;  // WiFi连接失败
//        }

    } else {
        qCritical() << "[Error] Process object is null! Cannot read standard output.";
    }
}

void Serial::handleStandardError() {
    if (process) {
        QString error = process->readAllStandardError();
        qCritical() << "[Error] Standard Error received from process: " << error;
    } else {
        qCritical() << "[Error] Process object is null! Cannot read standard error.";
    }
}

Tina Linux SDK中已经内置了XR829的驱动并且以及启用,但是其默认适配的是全志官方的哪吒D1-H开发板,并不一定能直接在我们的开发板上使用。

Tina提供了一套简易方便的WI-FI STA 测试套件:wifi_connect_ap_test,使用这个命令可以设置连接的AP的SSID和密码,

在f1c100s上跑MySQL5.1.73 移植记录 / 全志 SOC / WhyCan Forum(哇酷开发者社区)

荔枝派Zero V3s开发板入坑记录 (TF/SD卡启动)(主线Linux,主线u-boot) / 全志 SOC / WhyCan Forum(哇酷开发者社区)

关于arm开发板远程访问mysql数据库 / 全志 SOC / WhyCan Forum(哇酷开发者社区)

【EVB-335X-II试用体验】之QT远程访问MySql数据库(交叉编译MySql QT客户端驱动程序及功能测试) - 盈鹏飞嵌入式 - 电子技术论坛 - 广受欢迎的专业电子论坛! (elecfans.com)

八. PWM0/PD16

#include "pwm.h"
#include <QFile>
#include <QTextStream>
#include <QDebug>
PWM::PWM()
{
}

void PWM::PWMController(int pwmChip, int pwmChannel) {
    pwmChipPath = QString("/sys/class/pwm/pwmchip%1/export").arg(pwmChip);
    pwmPath = QString("/sys/class/pwm/pwmchip%1/pwm%2/").arg(pwmChip).arg(pwmChannel);
}

bool PWM::exportPWM()
{
    QFile file(pwmChipPath);
    if (!file.open(QIODevice::WriteOnly)) {
        qWarning() << "Failed to open file for writing:" << pwmChipPath;
        return false;
    }

    QTextStream stream(&file);
    stream << 2;
    file.close();

    // Verify if the PWM channel is exported by checking the existence of the directory
    QFile pwmDir(pwmPath);
    if (!pwmDir.exists()) {
        qWarning() << "Failed to export PWM channel. Directory does not exist:" << pwmPath;
        return false;
    }

    return true;
}

bool PWM::setPeriod(int period) {
    QFile file(pwmPath + "period");
    if (file.open(QIODevice::WriteOnly)) {
        QTextStream stream(&file);
        stream << period;
        file.close();
        return true;
    }
    qWarning() << "Failed to set PWM period";
    return false;
}

bool PWM::setDutyCycle(int dutyCycle) {
    QFile file(pwmPath + "duty_cycle");
    if (file.open(QIODevice::WriteOnly)) {
        QTextStream stream(&file);
        stream << dutyCycle;
        file.close();
        return true;
    }
    qWarning() << "Failed to set PWM duty cycle";
    return false;
}

bool PWM::enable() {
    QFile file(pwmPath + "enable");
    if (file.open(QIODevice::WriteOnly)) {
        QTextStream stream(&file);
        stream << 1;  // 1 表示启用
        file.close();
        return true;
    }
    qWarning() << "Failed to enable PWM";
    return false;
}

bool PWM::disable() {
    QFile file(pwmPath + "enable");
    if (file.open(QIODevice::WriteOnly)) {
        QTextStream stream(&file);
        stream << 0;  // 0 表示禁用
        file.close();
        return true;
    }
    qWarning() << "Failed to disable PWM";
    return false;
}

九. 参考链接 

在Ubuntu中交叉编译Opencv 4.5.1 运行于Tina Linux中(整合帖) | 全志在线开发者论坛 (aw-ol.com)

全志D1-H,官方SDK Tina2.0 移植 QT5.15 | 全志在线开发者论坛

通过buildroot解决需要移植QT库的问题!!!!步骤详细,需要的拿走_buildroot 如何编译eglfs的库-CSDN博客

全志D1-H,官方SDK Tina2.0 移植 QT5.15 / 全志 SOC / WhyCan Forum(哇酷开发者社区)

给Buildroot(全志D1)移植RTL8723DS驱动 | 全志在线开发者论坛 (aw-ol.com)

【Sipeed D1 Dock Pro】QT初体验 | 全志在线开发者论坛 (aw-ol.com)

https://doc.embedfire.com/linux/imx6/base/zh/latest/submission/buildroot2017-1.html?highlight=buildroot

git clone出现 fatal: unable to access 'https://github.com/...'的解决办法(亲测有效)-CSDN博客

通过buildroot解决需要移植QT库的问题!!!!步骤详细,需要的拿走_buildroot 如何编译eglfs的库-CSDN博客

使用D1-H驱动树莓派DSI屏幕 | 全志在线开发者论坛 (aw-ol.com)

【极简操作】使用builroot 2021一键编译生成D1 nezha 系统镜像! | 全志在线开发者论坛 (aw-ol.com)

10【正点原子】I.MX6U_Buildroot构建Qt根文件系统V1.0.pdf

感谢全志官方友情赠送的 D1 RISC-V 开发板, 坐等release sdk / 全志 SOC / WhyCan Forum(哇酷开发者社区)

使用builroot 2021一键编译生成D1 nezha 系统镜像

使用D1-H驱动树莓派DSI屏幕 | 全志在线开发者论坛 (aw-ol.com)

【极简操作】使用builroot 2021一键编译生成D1 nezha 系统镜像! | 全志在线开发者论坛 (aw-ol.com)

Qt——Ubuntu下安装Qt Creator的方法步骤总结及其界面功能与基本设置简介(Qt简介、Qt Creator版本选择、软件入门、常用设置)_qtcreator-CSDN博客

【极简操作】使用builroot 2021一键编译生成D1 nezha 系统镜像! | 全志在线开发者论坛 (aw-ol.com)

Buildroot--如何配置安装带Qt5的文件系统_buildroot qt5-CSDN博客

能不能弄个qt交叉编译的教程,谢谢! / 全志 SOC / WhyCan Forum(哇酷开发者社区)

能不能弄个qt交叉编译的教程,谢谢! / 全志 SOC / WhyCan Forum(哇酷开发者社区)

一步一步分享在Windows QtCreator/Mingw平台编译运行调试LittleVGL / 计算机图形/GUI/RTOS/FileSystem/OpenGL/DirectX/SDL2 / WhyCan Forum(哇酷开发者社区)

Ubuntu 14.04 下安装Qt5 并配置开发环境_ubuntu14.04安装qt-CSDN博客

Ubuntu 14.04 下安装Qt5 并配置开发环境_ubuntu14.04安装qt-CSDN博客

QTCreator出现提示无法覆盖文件 /home/xxx/.config/QtProject/Qtcreator/qtversion.xml : Permission denied的错误 - 不明白就去明白 - 博客园 (cnblogs.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2196672.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【最新版】Stable Diffusion4.9(AI绘画)下载及安装教程(附软件安装包)!

随着技术的迭代&#xff0c;目前 Stable Diffusion 已经能够生成非常艺术化的图片了&#xff0c;完全有赶超人类的架势&#xff0c;已经有不少工作被这类服务替代&#xff0c;比如制作一个 logo 图片&#xff0c;画一张虚拟老婆照片&#xff0c;画质堪比相机。 最新 Stable Di…

日常物品实例分割系统源码&数据集分享

日常物品实例分割系统源码&#xff06;数据集分享 [yolov8-seg-dyhead-DCNV3&#xff06;yolov8-seg-SPPF-LSKA等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Globa…

Maven - 依赖管理

依赖配置 在pom.xml的project标签内添加dependencies标签&#xff0c;之后添加依赖配置。 <dependencies><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.4.5</version>…

Acwing 记忆化搜索

Acwing 901.滑雪 输入样例&#xff1a; 5 5 1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9 输出样例&#xff1a; 25 实现思路&#xff1a; 状态表示f[i][j]&#xff0c;表示从点(i,j)出发的最长路径长度集合划分可分为四种情况&#xff1a;从点(i,j)出…

Mybatis框架梳理——更新中

Mybatis框架梳理 前言1.ORM2.模块划分2.1 ORM的实现2.2 SQL的映射2.3 插件机制2.4 缓存机制2.5 其他2.5.1 用到的设计模式 3. 愿景 前言 如果让我聊一聊mybatis&#xff0c;我该怎么说呢&#xff1f;开发中时时刻刻都在用它&#xff0c;此时此刻&#xff0c;脑海中却只浮现ORM框…

揭秘:ARM 工业计算机缘何替代树莓派

工业自动化、物联网以及嵌入式系统等领域对高性能、稳定可靠的计算设备的需求日益增长。国产 ARMxy工业计算机的出现&#xff0c;为这些领域带来了新的机遇和选择。特别是那些采用国产芯片如全志、瑞芯微等&#xff0c;并支持 Ubuntu 系统的工业计算机&#xff0c;展现出了令人…

微信公众号菜单栏----第⑦篇

如果你是新手小白&#xff0c;请从微信公众号开发第一篇看起&#xff1a;微信公众号开发-接口配置信息&#xff08;第①篇&#xff09;_微信公众号 接口配置信息怎么设置-CSDN博客 代码&#xff1a; <?php// 获取菜单配置数据$menuConfig array(button > array(array(…

认知战认知作战:激发认知战战术分享热情的秘诀

认知战认知作战&#xff1a;激发认知战战术分享热情的秘诀 认知战认知作战&#xff1a;激发认知战战术分享热情的秘诀 关键词&#xff1a;认知战, 认知作战, 创造独特体验, 融入社交元素, 情感共鸣策略, 分享激励机制, 战略形象塑造, 个性化内容推荐,认知作战,新质生产力,人类…

Observability:使用 OpenTelemetry 自动检测 Go 应用程序

作者&#xff1a;来自 Elastic Damien Mathieu 使用 OpenTelemetry 检测 Go 应用程序可以深入了解应用程序的性能、依赖项和错误。我们将向你展示如何使用 Docker 自动检测 Go 应用程序&#xff0c;而无需更改应用程序代码。 在快节奏的软件开发领域&#xff0c;尤其是在云原生…

网络资源模板--Android Studio 通讯录App

目录 一、项目演示 二、项目测试环境 三、项目详情​编辑 四、完整的项目源码 一、项目演示 网络资源模板--通讯录App 二、项目测试环境 三、项目详情 首页 package com.example.addressbook.activity;import androidx.appcompat.app.AppCompatActivity; import androidx.c…

Qwen变体新成员加一,英伟达训练 NVLM-D-72B 视觉大模型

今天&#xff08;2024 年 9 月 17 日&#xff09;&#xff0c;我们推出了前沿级多模态大语言模型&#xff08;LLM&#xff09;系列 NVLM 1.0&#xff0c;它在视觉语言任务上取得了最先进的结果&#xff0c;可与领先的专有模型&#xff08;如 GPT-4o&#xff09;和开放存取模型&…

2024高校网络安全管理运维赛 wp

0x00 前言 本文是关于“2024高校网络安全管理运维赛”的详细题解&#xff0c;主要针对Web、Pwn、Re、Misc以及Algorithm等多方向题目的解题过程&#xff0c;包含但不限于钓鱼邮件识别、流量分析、SQLite文件解析、ssrf、xxe等等。如有错误&#xff0c;欢迎指正。 0x01 Misc 签到…

纯干货!一个白帽子挖漏洞经验细致分享_白帽子找漏洞一天能多少

不知道是不是很多人和我一样&#xff0c;每天刷着漏洞&#xff0c;看着自己的排名一位一位的往上提升&#xff0c;但是&#xff0c;但是。总感觉怪怪的&#xff0c;为什么别人刷的漏洞都是现金&#xff0c;而自己刷的漏洞都是给库币。别人一天为什么提交那么多漏洞&#xff0c;…

winform appconfig

文章目录 添加一个appconfig配置文件的结构读取写入 这是wiform自带的配置文件&#xff0c;格式为xml 其位置在程序根目录下 添加一个appconfig 首先默认情况下&#xff0c;winform会自动创建一个名叫appconfig的配置文件&#xff0c;位于程序根目录下 如果需要手动创建更多…

【路径规划】基于球面向量的粒子群优化算法(SPSO)

摘要 本文提出了一种基于球面向量的粒子群优化算法&#xff08;Spherical Vector-based Particle Swarm Optimization, SPSO&#xff09;用于解决路径规划问题。该算法通过球面坐标系表示粒子的位置更新&#xff0c;增强了搜索空间的探索能力和全局优化性能。通过与遗传算法&a…

浅析基于双碳目标的光储充一体化电站状态评估技术

摘要&#xff1a;全国碳市场拉开了我国能源结构加速转型的大幕&#xff0c;催生了光伏、储能和新能源汽车等一批绿色产业的兴起&#xff0c;同时随着利好政策扶植和消费者的青睐&#xff0c;光伏、储能和新能源汽车市场均加快发展。但传统的充电桩和光伏电站都是分开建设&#…

基于SSM的家庭理财系统的设计与实现

文未可获取一份本项目的java源码和数据库参考。 选题目的: 随着社会的进步&#xff0c;我国经济的快速发展&#xff0c;人们的生活水平提高了&#xff0c;现在人们已经不仅仅满足于能够吃得饱穿得好&#xff0c;现在的人们在想着如何丰富自己的精神世界&#xff0c;想着如何去…

Win11环境下 DELPHI 12.2 安装全过程

背景描述 DELPHI作为曾经的Windows原生开发的王者&#xff0c;DELPHI12.2可以实现Windows、Android、IOS、macOS、Linux的应用开发&#xff0c;现在还有少数企业使用&#xff0c;大多数用户是从传统D3/4/5/6/7坚持下来的爱好者&#xff0c;2ccc.com里有相关内容&#xff0c;但…

基于方块编码的图像压缩matlab仿真,带GUI界面

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 编码单元的表示 4.2编码单元的编码 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 下图是随着方块大小的变化&#xff0c;图像的压缩率以及对应的图像质量指标PSN…

QT使用websocket实现语音对讲

简介&#xff1a; 本文所描述的功能和代码&#xff0c;是基于QT的开发环境。在QT上使用websocket&#xff0c;接受和发送pcm音频&#xff0c;实现了语音对讲功能。经自测&#xff0c;该功能可以正常使用&#xff0c;以下是相关代码的分享。 void MainWindow::on_pushButton_Ope…