Linux驱动(中断、异步通知):红外对射,并在Qt StatusBus使用指示灯进行显示

本文工作:

1、Linux驱动与应用程序编写:使用了设备树、中断、异步通知知识点,实现了红外对射状态的异步信息提醒

2、QT程序编写:自定义了一个“文本指示灯”类,并放置在QMainWidget的StatusBus中。

3、C与C++混合编程与调试:将Linux C下的面向过程转化为QT C++的面向对象。但是Linux C下signal函数需要使用static函数作为传入参数,但是C++中static的用法与C语言不一样,因此在C++中对抽象出的类进行了适配与修改

参考资料

1、《正点原子:I.MX6U嵌入式Linux驱动开发指南V1.6》

2、C/C++ static关键字详解(最全解析,static是什么,static如何使用,static的常考面试题)-CSDN博客

3、【创龙AM4379 Cortex-A9试用体验】之I/O中断异步通知驱动程序+QT捕获Linux系统信号+测试信号通知 - ARM技术论坛 - 电子技术论坛 - 广受欢迎的专业电子论坛! (elecfans.com)

4、Qt 封装一个简单的LED(指示灯)控件_qt 指示灯-CSDN博客

本文不对基础知识进行讲解,因此阅读本文需要一定的驱动/QT基础。

开发板:IMX6ULL

内核版本:4.1.15

QT版本:5.12

一、项目需求与效果

1、项目需求:

项目中的一个简单传感器:使用红外对射,检查物品是否放入了盒子中,并在QT界面的statusBus中,使用指示灯的形式进行显示与说明。

2、代码效果

红外对射-Linux驱动-QT

代码效果:屏幕左下角文本指示灯的变化

二、Linux驱动与应用程序编写

1、使用引脚说明

本次所使用的引脚为GPIO2_2,查看了I.MX6ULL核心板对GPIO的描述,该引脚可复用到GPIO1_IO02引脚上,因此我们需要先修改下设备树的文件。

2、修改设备树文件

在根节点目录下先添加节点:

gpio_infrared {
		compatible = "csx-gpio-infrared";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_infrared>;
		infrared-gpio = <&gpio1 2 GPIO_ACTIVE_LOW>;
		interrupts = < IRQ_TYPE_EDGE_BOTH>;
		status = "okay";
	};

项目中,我们需要极度关注是否有物体存入,进拿进取出都需要通知用户,因此需要中断类型使用IRQ_TYPE_EDGE_BOTH。

其中的pinctrl_infrared为:

pinctrl_infrared: infraredgrp {
		fsl,pins = <
		MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0x10B0
		>;
		};	

修改完之后,执行make dtbs,更换开发板的设备树之后,我们使用 ls /proc/device-tree查看是否有我们增加的设备树节点。

如上图,设备树修改成功,接下来就是编写驱动文件。

3、驱动文件编写

(1)结构体编写

/* 设备中断结构体 */
struct irq_gpio_infrared{
	int gpio;				/* gpio */
	int irqnum;				/* 中断号 */
	unsigned char value;	/* 读取的值 */
	char name[10];			/* 名字 */
	irqreturn_t (*handler)(int,void *); /* 中断服务函数 */
	
};

/* gpioinfrared设备结构体 */
struct gpio_infrared_dev{
	dev_t devid;			/* 设备号 	 */
	struct cdev cdev;		/* cdev 	*/
	struct class *class;	/* 类 		*/
	struct device *device;	/* 设备 	 */
	int major;				/* 主设备号	  */
	int minor;				/* 次设备号   */
	struct device_node	*nd; /* 设备节点 */
	struct irq_gpio_infrared irqgpioinfrared;	/* 中断结构体 */
	struct fasync_struct *async_queue; /* 异步相关结构体 */
};


struct gpio_infrared_dev gpioinfrared;	/* infrared设备 */

代码中我们需要注意的是,使用了中断结构体,用于红外对射,检测到物体时通知用户,在各种通知方法中,使用异步通知是最可行的,其他方法需要占据大量的cpu资源,不适合本次的应用场景,因此,中断服务其实就是使用异步通知对用户进行通知,因此,我们还需要使用异步通知的结构体。

(2)获取设备树节点的信息【设备树API、GPIO子系统API】

	/* 1、获取设备节点:gpioinfrared */
	gpioinfrared.nd = of_find_node_by_path("/gpio_infrared");
	if(gpioinfrared.nd == NULL) {
		printk("gpioinfrared node not find!\r\n");
		return -EINVAL;
	} else {
		printk("gpioinfrared node find!\r\n");
	}

	/* 2、 获取设备树中的gpio属性,得到GPIO所使用的编号 */
	gpioinfrared.irqgpioinfrared.gpio = of_get_named_gpio(gpioinfrared.nd, "infrared-gpio", 0);
	if(gpioinfrared.irqgpioinfrared.gpio < 0) {
		printk("can't get infrared-gpio");
		return -EINVAL;
	}else{
		printk("infrared-gpio num = %d\r\n", gpioinfrared.irqgpioinfrared.gpio);
	}
	
	/* 3、初始化使用的gpio */
	memset(gpioinfrared.irqgpioinfrared.name,0,sizeof(gpioinfrared.irqgpioinfrared.name));
	sprintf(gpioinfrared.irqgpioinfrared.name,"gpioinfrared%d",i);
	ret = gpio_direction_input(gpioinfrared.irqgpioinfrared.gpio);
	if(ret < 0) {
		printk("can't set gpio!\r\n");
	}

(3)中断申请

	/* 4、设置中断模式,返回中断号 */
	gpioinfrared.irqgpioinfrared.irqnum = gpio_to_irq(gpioinfrared.irqgpioinfrared.gpio);
	printk("gpio:%d,irq:%d",gpioinfrared.irqgpioinfrared.gpio,gpioinfrared.irqgpioinfrared.irqnum);
	/* 申请中断 */
	gpioinfrared.irqgpioinfrared.handler = goio_infrared_handler;
	ret = request_irq(gpioinfrared.irqgpioinfrared.irqnum, 
					  gpioinfrared.irqgpioinfrared.handler, 
		              IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
					  gpioinfrared.irqgpioinfrared.name, 
					  &gpioinfrared);
	if(ret < 0){
		printk("irq %d request fail infrared!\r\n", gpioinfrared.irqgpioinfrared.irqnum);
		printk("irq_name: %s\r\n",gpioinfrared.irqgpioinfrared.name);
		return -EFAULT;
	}
	if (ret==-EBUSY){
		printk("irq already apply\r\n");
	}

(4)编写红外对射的中断函数

/*
	GPIO红外中断服务函数,用于发送异步信息
*/
static irqreturn_t goio_infrared_handler(int irq,void *dev_id)
{
	struct gpio_infrared_dev *dev = (struct gpio_infrared_dev *)dev_id;

	printk("irq happend!\r\n");
	kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
	return IRQ_RETVAL(IRQ_HANDLED);
}

如上述所说,就是用于发送异步通信的!在这里还使用内核进行打印输出,方便检测。

(5)编写异步通信函数

static int imx6uirq_fasync(int fd, struct file *filp, int on)
{
	struct gpio_infrared_dev *dev = (struct gpio_infrared_dev *)filp->private_data;
	return fasync_helper(fd, filp, on, &dev->async_queue);
}

static int imx6uirq_release(struct inode *inode, struct file *filp)
{
	return imx6uirq_fasync(-1, filp, 0);
}

(6)编写用户层数据接口

/*
 * @description		: 从设备读取数据 
 * @param - filp 	: 要打开的设备文件(文件描述符)
 * @param - buf 	: 返回给用户空间的数据缓冲区
 * @param - cnt 	: 要读取的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 读取的字节数,如果为负值,表示读取失败
 */
static ssize_t infrared_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
	int ret = 0;
	unsigned char value=-1;
	struct gpio_infrared_dev *dev = (struct gpio_infrared_dev *)filp->private_data;
	value = gpio_get_value(dev->irqgpioinfrared.gpio);
	printk("gpioinfrared read:%d!\r\n",value);
	ret = copy_to_user(buf, &value, sizeof(value));
	return ret;
}

重点的内容都介绍完了,接下来就是检查下是否正确驱动编写是否正确了!make生成.ko文件后,传到开发板,使用insmod命令,会有如下输入:

此时,我们将红外进行对射后,就会有如下输出:

即驱动编写正确。接下来,我们先编写应用程序的代码,接收异步通知的提醒。

4、Linux C应用程序代码编写

应用程序接收异步通知需要以下三个步骤:

(1)使用signal函数设置(驱动程序所使用的)信号处理函数;

(2)将当前应用程序的内核号告知内核

(3)开启异步通知

signal(SIGIO, sigio_signal_func);   /* 设置信号SIGIO的处理函数     */
fcntl(fd, F_SETOWN, getpid());		/* 设置当前进程接收SIGIO信号   */
flags = fcntl(fd, F_GETFL);			/* 获取当前的进程状态 		  */
fcntl(fd, F_SETFL, flags | FASYNC);	/* 设置进程启用异步通知功能 	  */	
在此处的异步处理函数就很简单了,使用GPIO子系统的API获取当前的引脚数值,但是值得一提的是, signal函数的传入函数必须是使用static进行修饰的,在后面与C++代码对接时,就是因为static增加了不少的限制
/*
 * SIGIO信号处理函数
 * @param - signum 	: 信号值
 * @return 			: 无
 */
static void sigio_signal_func(int signum)
{
	int err = 0;
	unsigned int infrared_value = 0;
	err = read(fd, &infrared_value, sizeof(infrared_value));
	if(err < 0) {
		/* 读取错误 */
		printf("read error!\r\n");
	} else {
		printf("sigio signal:%d!\r\n",infrared_value);
	
	}
	
}

接下来,我们在进行交叉编译之后

arm-linux-gnueabihf-gcc infrared_asy.c -o infrared_asy

进行测试一下。

上图所示,测试成功!

三、C++ Qt程序编写

1、自定义LedWithText

 先根据自己的需要,对参考资料第四点对自封装的LED控件进行了简化,类名为QSimpleLed

QSimpleLed.cpp文件

#include "qsimpleled.h"

#include <QGradient>
#include <QPainter>
#include <QDebug>
#include <QColor>


QSimpleLed::QSimpleLed(QWidget *parent, QColor color,int radius)
    : QLabel(parent)
    , mColor(color)
{
    setMinimumSize(radius, radius);
    setMaximumSize(radius,radius);
}

void QSimpleLed::setStates(QSimpleLed::LEDSTATES states)
{
    switch (states) {
    case ON:
        resetStatus();

        mStates = ON;
        break;

    case OFF:
        resetStatus();
        break;

    case BLINK:
        resetStatus();

        if (!mBlinkTimer) {
            mBlinkTimer = new QTimer(this);
            connect(mBlinkTimer, &QTimer::timeout, this, &QSimpleLed::onBlinkTimerTimeout);
        }
        mBlinkTimer->setInterval(mInterval);
        mBlinkTimer->start();
        mStates = BLINK;
        break;

    default:
        qDebug() << "LED - unknown states!!!";
    }

    update();
}

void QSimpleLed::setColor(QColor color)
{
    mColor = color;
}



void QSimpleLed::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    qreal realSize = qMin(width(), height());
    QPainter painter(this);

    painter.setRenderHint(QPainter::Antialiasing);      // 反锯齿
    painter.translate(width()/2, height()/2);           // 绘点移到控件中心处


    if(blinkState)
        painter.setBrush(QBrush(QColor(111,111,111)));
    else
        painter.setBrush(QBrush(mColor));

    painter.drawEllipse(QPointF(0, 0), realSize/2, realSize/2);

}

void QSimpleLed::resizeEvent(QResizeEvent *event)
{
    Q_UNUSED(event);
    update();
}



void QSimpleLed::onBlinkTimerTimeout()
{
    blinkState = !blinkState;
    update();
}

void QSimpleLed::resetStatus()
{
    if (mBlinkTimer && mBlinkTimer->isActive()) {
        mBlinkTimer->stop();
    }
    mStates = OFF;
}

QSimpleLed.h文件

#ifndef QSIMPLELED_H
#define QSIMPLELED_H

#include <QLabel>
#include <QTimer>
#include <QColor>

class QSimpleLed : public QLabel
{
    Q_OBJECT


public:

    enum LEDSTATES {
        ON       = 0,
        OFF      = 1,
        BLINK    = 2,
    };


    QSimpleLed(QWidget *parent = nullptr, QColor color = Qt::green,int radius=16);

    void setStates(LEDSTATES states);
    void setInterval(int msec) { mInterval = msec; }
    void setColor(QColor color);

protected:
    virtual void paintEvent(QPaintEvent *event) override;
    virtual void resizeEvent(QResizeEvent *event) override;

private slots:
    void onBlinkTimerTimeout();

private:
    void resetStatus();

    LEDSTATES mStates = OFF;
    QColor mColor;
    QTimer *mBlinkTimer = nullptr;
    int mInterval = 500;
    bool blinkState = false;

};



#endif // QSIMPLELED_H

再根据自己的需求,自定义一个widget,用于存放led(左)与text(右),我们在外部只需要传入led的状态、颜色、文本的内容即可,该类的名称为LedWithText。

LedWithText.cpp

#include "ledwithtext.h"
#include <QFont>
#include <QDebug>

ledWithText::ledWithText(QWidget *parent, QColor color, const QString &text)
    :QWidget(parent)
{


    ledLabel = new QSimpleLed(this);
    ledLabel->setColor(color);
//    ledLabel->setStyleSheet("border-width: 1px;border-style: solid;border-color: rgb(255, 170, 0);");

    textLabel = new QLabel(text,this);
    textLabel->adjustSize();
    textLabel->setAlignment(Qt::AlignVCenter);
    textLabel->setMinimumHeight(ledLabel->height()+5);
    textLabel->setVisible(!text.isEmpty());

    QFont ft;
    ft.setPointSize(14);
    textLabel->setFont(ft);

    layout = new QHBoxLayout(this);
    layout->addWidget(ledLabel);
    layout->addWidget(textLabel);
    layout->setSpacing(5);
    setLayout(layout);

    int adjustWith = ledLabel->width()+textLabel->width()+25;
    int adjustHeight = textLabel->height()+10;
//    qDebug()<<adjustHeight<<adjustWith;
    setGeometry(0,0,adjustWith,adjustHeight);
}

ledWithText::~ledWithText()
{
    delete  ledLabel;
    delete  textLabel;
}

void ledWithText::setLedColor(QColor color)
{
    ledLabel->setColor(color);
}

void ledWithText::setLedState(QSimpleLed::LEDSTATES states)
{
    ledLabel->setStates(states);
}



void ledWithText::setText(const QString &text)
{
    textLabel->setText(text);
    textLabel->adjustSize();
    textLabel->setVisible(!text.isEmpty());
    int adjustWith = ledLabel->width()+textLabel->width()+25;
    int adjustHeight = textLabel->height()+10;
    setGeometry(0,0,adjustWith,adjustHeight);
}

void ledWithText::setTextFontSize(int size)
{
    QFont ft;
    ft.setPointSize(size);
    textLabel->setFont(ft);
    textLabel->adjustSize();
    int adjustWith = ledLabel->width()+textLabel->width()+25;
    int adjustHeight = textLabel->height()+10;
    setGeometry(0,0,adjustWith,adjustHeight);
}

LedWithText.h

#ifndef LEDWITHTEXT_H
#define LEDWITHTEXT_H
#include <QLabel>
#include <ui_optimize/qsimpleled.h>
#include <QWidget>
#include <QHBoxLayout>

class ledWithText:public QWidget
{
    Q_OBJECT
public:
    ledWithText(QWidget *parent = nullptr, QColor color = Qt::green, const QString &text = "");
    ~ledWithText();
    void setLedColor(QColor color);
    void setLedState(QSimpleLed::LEDSTATES states);
    void setText(const QString &text);
    void setTextFontSize(int size);


private:
    QSimpleLed *ledLabel;
    QLabel *textLabel;
    QHBoxLayout *layout;
};

#endif // LEDWITHTEXT_H

2、使用MainWidget的StatusBus存放文本指示灯

我们要把这些控件放置在状态栏中,不管切换到什么界面都可以看到,就不需要一直重复写代码了,因此,我们需要使用MainWidget的StatusBus,Widget类没有StatusBus!不要用错

void MainWindow::state_bus_init()
{
    device_connect_label = new ledWithText(this,Qt::green,"设备正在连接");
    device_connect_label->setLedColor(Qt::blue);
    device_connect_label->setLedState(QSimpleLed::BLINK);
    device_connect_label->setTextFontSize(10);

    ui->statusbar->addWidget(device_connect_label);
    device_place_label = new ledWithText(this,Qt::green,"设备未放置");
    device_place_label->setTextFontSize(10);
    ui->statusbar->addWidget(device_place_label);
}

 就可以看到如下效果了。我们自定义的LedWithText类的效果就显示在左下角了。

3、Qt接受异步通知,并根据结果改变文本指示灯

按道理,最简单的做法,这一步只需要将应用层的代码搬过来就可以,但是在上文我们提到,在Linux C的应用程序中,signal函数需要传入static修饰的函数,但是Qt使用C++语言,想要将其转化为类(而不是面向过程),就需要解决static在C语言和C++的差异。

#include "infrareddev.h"


InfraredDev::InfraredDev(QObject *parent) : QObject(parent)
{
    fd = open(DEVNAME, O_RDWR);
    if (fd < 0) {
        qDebug()<<"Can't open file :"<<DEVNAME;

    }else{
        register_infrared_asy();
        qDebug()<<"infrared:init succeed!";
    }

}

InfraredDev::~InfraredDev()
{
    if(fd){
        close(fd);
    }
}

void InfraredDev::set_dev_name(char *name)
{
    dev_name = name;
}

char *InfraredDev::get_dev_name()
{
    return dev_name;
}

void InfraredDev::setLedWithText(ledWithText *obj)
{
    infrared_ledWithText = obj;
}

void InfraredDev::sigio_signal_func(int signum)
{
    int err = 0;
    unsigned int infrared_value = 0;
    err = read(fd, &infrared_value, sizeof(infrared_value));
    if(err < 0) {
//        InfraredDev instance; // 创建对象实例
//        emit instance.infraredSignal(infrared_value);
        /* 读取错误 */
        infrared_ledWithText->setLedColor(Qt::red);
        infrared_ledWithText->setLedState(QSimpleLed::BLINK);
        infrared_ledWithText->setText("获取设备失败");
        qDebug()<<"infrared:read error!";
    } else {
        if(infrared_value==0){
            infrared_ledWithText->setLedColor(Qt::green);
            infrared_ledWithText->setText("设备已放置");
        }else if(infrared_value==1){
            infrared_ledWithText->setLedColor(Qt::red);
            infrared_ledWithText->setLedState(QSimpleLed::BLINK);
            infrared_ledWithText->setText("设备未放置");
        }

        qDebug()<<"infrared:sigio signal!"<<infrared_value;

    }

}

void InfraredDev::register_infrared_asy()
{
    int flags = 0;
    /* 设置信号SIGIO的处理函数 */
    signal(SIGIO, &InfraredDev::sigio_signal_func);

    fcntl(fd, F_SETOWN, getpid());		/* 设置当前进程接收SIGIO信号 	*/
    flags = fcntl(fd, F_GETFL);			/* 获取当前的进程状态 			*/
    fcntl(fd, F_SETFL, flags | FASYNC);	/* 设置进程启用异步通知功能 	*/
}



int InfraredDev::fd = -1; // 初始化为无效的文件描述符
ledWithText *InfraredDev::infrared_ledWithText = nullptr;
#ifndef INFRAREDDEV_H
#define INFRAREDDEV_H


#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include "poll.h"
#include "sys/select.h"
#include "sys/time.h"
#include "linux/ioctl.h"
#include "signal.h"

#include <QObject>
#include <QDebug>
#include <QFile>
#include <QTextStream>
#include <QString>


#include "ui_optimize/ledwithtext.h"

#define DEVNAME "/dev/gpio_infrared"



class InfraredDev : public QObject
{
    Q_OBJECT
public:
    explicit InfraredDev(QObject *parent = nullptr);
    ~InfraredDev();
    void set_dev_name(char *name);
    char * get_dev_name();
    static ledWithText *infrared_ledWithText;
    static void setLedWithText(ledWithText *obj);


private:
    static int fd;	/* 文件描述符 */
    static QFile file;
    char *dev_name;
    static void sigio_signal_func(int signum);
    void register_infrared_asy(void);

};

#endif // INFRAREDDEV_H

因为static修饰的成员变量、成员函数并没有this指针,因此无法读取其他非static成员只允许读取static变量,因此我们需要将fd也需要使用static函数进行修饰,并且函数内不能包含其他no-static的变量。

因此在signal函数,我们就需要根据C++访问静态函数的规则,对参数进行传入了修改,使用通过(类名::静态成员)的方式来访问。

signal(SIGIO, &InfraredDev::sigio_signal_func);

 然后,我们需要让QMainwindow类知道,接收到异步通信了,需要刷新UI了。

(1)信号机制方法

我一开始是照常使用信号机制,定义了信号函数,使用emit函数进行发送,但是因为异步通知处理函数是static类的,无法直接调用其他non-static的成员,无法发送信号,因此我想是实例化一个类,发送类的实例,进而发送信号:

InfraredDev instance; // 创建对象实例
emit instance.infraredSignal(infrared_value);

代码没报错,但是执行过程出错了,在开发板上只能读取第一次的数值,发送后,就无法进行读取,由于是在开发板上进行运行的,无法进行debug,不知道是什么原因,如果有大神知道,还请不吝赐教!

(2)指针传入做法

之后,我看到了参考资料的3的做法,就想直接传入界面的指针,在异步通知里面,直接读取指针,进行界面的修改。因此我就根据,non-static成员函数可以访问static成员变量的特性,对该做法进行了改进。定义了一个设置控件的函数,外部传入一个控件指针,函数内部设置为static类型,因此完美解决了该问题。

void InfraredDev::setLedWithText(ledWithText *obj)
{
    infrared_ledWithText = obj;
}


// 在static函数就可以使用这个static指针进行设置了
void InfraredDev::sigio_signal_func(int signum){
   ......
   infrared_ledWithText->setLedColor(Qt::red);
   infrared_ledWithText->setLedState(QSimpleLed::BLINK);
   infrared_ledWithText->setText("设备未放置");

}

在infrared_dev.h中,存在该声明,为static成员变量

 static ledWithText *infrared_ledWithText;

那么,我们在外部只需要传入该控件的指针即可

device_connect_label = new ledWithText(this,Qt::green,"设备正在连接");

......
infrared_dev = new InfraredDev();
infrared_dev->setLedWithText(device_place_label);

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++:函数重载

1.函数重载概念 函数重载就是用同一个函数名定义的不同函数&#xff0c;当函数名和不同的参数搭配时函数的功能和含义不同。 2.实现函数重载的条件 同一个作用域&#xff0c;参数个数不同或者参数类型不同或者参数顺序不同(满足一个即可) void func(){} void func(int x){} v…

55 代码审计-JAVA项目注入上传搜索或插件挖掘

目录 必备知识点演示案例:简易Demo段SQL注入及预编译IDEA审计插件FindBugs安装使用Fortify_SCA代码自动审计神器使用Ofcms后台SQL注入-全局搜索关键字Ofcms后台任意文件上传-功能点测试 涉及资源&#xff1a; 我们一般针对java项目&#xff0c;进行漏洞分析的话&#xff0c;主要…

SolidWorks二次开发 C#-读取基于Excel的BOM表信息

SolidWorks二次开发 C#-读取基于Excel的BOM表信息 问题点来源解决方案及思路相关引用链接 问题点来源 这是一位粉丝问的一个问题&#xff0c;他说到: 老师&#xff0c;请问Solidworks二次开发工程图中"基于Excel的材料明细表"怎么读取里面的数据&#xff1f; Ps:这…

风速预测(五)基于Pytorch的EMD-CNN-LSTM模型

目录 前言 1 风速数据EMD分解与可视化 1.1 导入数据 1.2 EMD分解 2 数据集制作与预处理 2.1 先划分数据集&#xff0c;按照8&#xff1a;2划分训练集和测试集 2.2 设置滑动窗口大小为96&#xff0c;制作数据集 3 基于Pytorch的EMD-CNN-LSTM模型预测 3.1 数据加载&…

「Verilog学习笔记」流水线乘法器

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 timescale 1ns/1nsmodule multi_pipe#(parameter size 4 )(input clk , input rst_n ,input [size-1:0] mul_a ,input [size-1:0] mul_b ,output …

DHCP—动态主机配置协议

动态主机配置协议DHCP&#xff08;Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议&#xff09;是RFC 1541&#xff08;已被RFC 2131取代&#xff09;定义的标准协议&#xff0c;该协议允许服务器向客户端动态分配IP地址和配置信息。 DHCP协议支持C/S&#x…

【数据分享】2019-2023年我国地级市逐月新房房价数据(Excel/Shp格式)

房价是一个城市发展程度的重要体现&#xff0c;一个城市的房价越高通常代表这个城市越发达&#xff0c;对于人口的吸引力越大&#xff01;因此&#xff0c;房价数据是我们在各项城市研究中都非常常用的数据&#xff01;之前我们分享过2015-2023年我国区县逐月新房房价数据&…

倚力未来:人工智能智能辅助医疗的前景与挑战

导言 人工智能在医疗领域的应用正迅速发展&#xff0c;为医疗行业带来了新的可能性。本文将深入探讨人工智能在医疗中的智能辅助应用&#xff0c;以及这一趋势面临的前景和挑战。智慧医疗是指通过先进的信息技术&#xff0c;如人工智能、物联网、大数据等&#xff0c;实现医疗数…

Javaweb考前复习冲刺(不断更新版)

Javaweb考前复习冲刺 第一章&#xff1a; JavaWeb 入门 JavaWeb是指&#xff1a;以Java作为后台语言的项目工程。 javaweb项目创建的过程&#xff1a; 首先集成Tomcat服务器环境新建dynamic web project部署工程运行 路由含义&#xff1a; ​ http://localhost:8080/工程…

[NCTF2019]Fake XML cookbook1

提示 xml注入 一般遇到像登录页之类的就因该想到sql注入、弱口令或者xml等 随便输入抓包 这里明显就是xml注入 这里我们来简单了解一下xml注入 这里是普通的xml注入 xml注入其实和sql注入类似&#xff0c;利用了xml的解析机制如果系统没有将‘<’‘>’进行转义&#xff0…

Autosar CAN报文周期抖动可能的原因分析+解决方法(总结)

一、背景 在Autosar项目中我们经常会遇到各种CAN报文在CANOE上抓取的图形周期抖动,因此需要通过一些可能的原因分析解决报文周期不准的问题。 那么下面就我根据实际项目中遇到的一些可能的原因做一些总结(后续持续完善)。 二、可能的原因及解决方案 1、可能原因:CPU idl…

《ThreadLocal使用与学习总结:2023-12-15》由浅入深全面解析ThreadLocal

由浅入深全面解析ThreadLocal 目录 由浅入深全面解析ThreadLocal简介基本使用ThreadLocal与synchronized的区别ThreadLocal现在的设计&#xff08;JDK1.8&#xff09;ThreadLocal核心方法源码分析ThreadLocalMap源码分析弱引用与内存泄露&#xff08;内存泄漏和弱引用没有直接关…

python排序算法 直接插入排序法和折半插入排序法

最近需要使用到一些排序算法&#xff0c;今天主要使针对直接插入排序和折半插入排序进行讲解。 首先是直接插入排序&#xff0c;其排序过程主要是&#xff0c;针对A[a1,a2,a3,a4,a5....an]&#xff0c;从排序的序列头部起始位置开始&#xff0c;将其也就是a1视为只有一个元素的…

Android编译优化之Jetifier优化

本文字数&#xff1a;9048字 预计阅读时间&#xff1a;40分钟 在狐友项目的编译优化中&#xff0c;我们发现在 BuildAnalyzer 中有明确的 Warnings 提示&#xff0c;告知项目可以进行 Jetifier 优化。 Jetifier 是之前项目进行 AndroidX 迁移时引入的插件&#xff0c;它能辅助迁…

Azure Machine Learning - 提示工程简介

OpenAI的GPT-3、GPT-3.5和GPT-4模型基于用户输入的文本提示工作。有效的提示构造是使用这些模型的关键技能&#xff0c;涉及到配置模型权重以执行特定任务。这不仅是技术操作&#xff0c;更像是一种艺术&#xff0c;需要经验和直觉。本文旨在介绍适用于所有GPT模型的提示概念和…

diffuser为pipeline设置不用的scheduler

查看默认的schedulers&#xff1a; 使用默认的schedulers生成数据 查看默认scheduler的默认配置&#xff0c;定义了采样器中的相关参数&#xff0c;网上关于DDPM和DDIM的文章较多&#xff0c;可以先去看看这两种schedulers&#xff1a; 修改scheduler&#xff0c;可以用于…

13.二进制枚举练习题

文章目录 二进制枚举练习题[78. 子集](https://leetcode.cn/problems/subsets/)[77. 组合](https://leetcode.cn/problems/combinations/)[1286. 字母组合迭代器](https://leetcode.cn/problems/iterator-for-combination/)[2397. 被列覆盖的最多行数](https://leetcode.cn/pro…

CSS3 2D变形 过渡 动画

​​​​​ transform(2D变形)概述translate()平移scale()缩放skew()倾斜rotate()旋转transform-origin中心原点 CSS3 2D变形 3D变形 过渡 动画 在CSS3中&#xff0c;动画效果包括4个部分&#xff1a;变形&#xff08;transform&#xff09;、3D变形、过渡&#xff08;transit…

【Linux】cp问题,生产者消费者问题代码实现

文章目录 前言一、 BlockQueue.hpp&#xff08;阻塞队列&#xff09;二、main.cpp 前言 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯&#xff0c;而通过阻塞队列来进行通讯&#xff0c;所以生产者生产完数据之后不用…

计算机网络:网络层(无分类编址CIDR、计算题讲解)

带你快速通关期末 文章目录 前言一、无分类编址CIDR简介二、构成超网三、最长前缀匹配总结 前言 我们在前面知道了分类地址&#xff0c;但是分类地址又有很多缺陷&#xff1a; B类地址很快将分配完毕!路由表中的项目急剧增长! 一、无分类编址CIDR简介 无分类域间路由选择CI…