【北京迅为】《iTOP-3588开发板系统编程手册》-第14章 GPIO应用编程

news2024/11/18 9:00:19

RK3588是一款低功耗、高性能的处理器,适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用,RK3588支持8K视频编解码,内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP,内置NPU,支持INT4/INT8/INT16/FP16混合运算能力,支持安卓12和、Debian11、Build root、Ubuntu20和22版本登系统。了解更多信息可点击迅为官网   

【粉丝群】824412014

【实验平台】:迅为RK3588开发板

【内容来源】《iTOP-3588开发板系统编程手册》

【全套资料及网盘获取方式】联系淘宝客服加入售后技术支持群内下载

【视频介绍】:【强者之芯】 新一代AIOT高端应用芯片 iTOP -3588人工智能工业AI主板


第14章 GPIO应用编程

由于本章节要使用GPIO的方式来控制LED,所以需要在设备树中注释掉LED节点的相关内容,为了方便起见,已经将修改好的内核设备树放到了“iTOP-3588开发板\03_【iTOP-RK3588开发板】指南教程\03_系统编程配套程序\62”目录下,如下图所示:

将提供的boot.img文件根据07_【北京迅为】itop-3588开发板快速烧写手册.pdf手册中的“单独烧写 Linux 固件”小节进行单独烧写,烧写完成之后就可以进行本章节的学习了。

14.1应用层如何操控GPIO 

与 LED 设备一样,GPIO 同样也是通过 sysfs 方式进行操控的,首先使用以下命令进入到/sys/class/gpio 目录下,如下所示:

可以看到在当前目录下有两个文件 export、unexport 以及 5个 gpiochipX(X 等于 0、32、64、96、128)命名的文件夹。接下来将分别对 gpiochipX、export和unexport进行讲解:

gpiochipX:当前 SoC 所包含的 GPIO 控制器,iTOP-RK3588一共包含了 5 个 GPIO控制器,分别为 RK_GPIO0、RK_GPIO1、RK_GPIO2、RK_GPIO3、RK_GPIO4,在这里分别对应 gpiochip0、gpiochip32、gpiochip64、gpiochip96、gpiochip128 这 5 个文件夹,每一个 gpiochipX 文件夹用来管理一组GPIO。

以gpiochip0文件夹为例,对gpiochipX目录中的内容进行讲解,进入gpiochip0目录下,gpiochip0目录内容如下图所示:

分别为base、device、label、ngpio、power、subsystem、uevent,需要了解的是 base、label、ngpio 这三个属性文件,这三个属性文件均是只读、不可写。

base:与 gpiochipX 中的 X 相同,表示该控制器所管理的这组 GPIO 引脚中最小的编号。每一个 GPIO 引脚都会有一个对应的编号,Linux 下通过这个编号来操控对应的 GPIO 引脚。

使用cat命令对base文件信息进行查看如下图所示:

label:对应该组 GPIO 标签,使用cat命令对label文件进行查看,如下图所示:

ngpio:该控制器所管理的 GPIO 引脚的数量(所以引脚编号范围是:base ~ base+ngpio-1),使用cat命令对ngpio文件进行查看,如下图所示:

iTOP-RK3588有 5 组 GPIO bank:GPIO0~GPIO4,每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分,常用以下公式计算引脚:

GPIO pin脚计算公式:pin = bank * 32 + number     //bank为组号,number为小组编号
GPIO 小组编号计算公式:number = group * 8 + X  

iTOP-RK3588有 5 组 GPIO bank:GPIO0~GPIO4,每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分,常用以下公式计算引脚:

GPIO pin脚计算公式:pin = bank * 32 + number     //bank为组号,number为小组编号
GPIO 小组编号计算公式:number = group * 8 + X  

下面演示gpio座子5号引脚GPIO2_PC4 pin脚计算方法:

bank = 2;       //GPIO0_B7=> 2, bank ∈ [0,4]
group = 2;      //GPIO0_B7 => 2, group ∈ {(A=0), (B=1), (C=2), (D=3)}
X = 4;         //GPIO4_D7 => 4, X ∈ [0,7]
number = group * 8 + X = 2 * 8 + 4 =20
pin = bank*32 + number= 2 * 32 + 20 = 84;

export用于将指定编号的 GPIO 引脚导出。在使用 GPIO 引脚之前,需要将其导出,导出成功之后才能使用它。注意 export 文件是只写文件,不能读取,将一个指定的编号写入到 export 文件中即可将对应的 GPIO 引脚导出,以GPIO2_PC4为例(pin计算值为84)使用export 文件进行导出(如果没有更换本章开始部分的内核设备树镜像,会导出不成功),导出成功如下图所示:

echo 84 > export

 

会发现在/sys/class/gpio 目录下生成了一个名为 gpio84 的文件夹(gpioX,X 表示对应的编号),该文件夹就是导出来的 GPIO 引脚对应的文件夹,用于管理、控制该 GPIO 引脚。

unexport将导出的 GPIO 引脚删除。当使用完 GPIO 引脚之后,需要将导出的引脚删除,同样该文件也是只写文件、不可读,使用unexport 文件进行删除GPIO2_PC4,删除成功如下图所示:

echo 84 > unexport

可以看到之前生成的 gpio84 文件夹就会消失!

需要注意的是,并不是所有 GPIO 引脚都可以成功导出,如果对应的 GPIO 已经被导出或者在内核中被使用了,那便无法成功导出,导出失败如下图所示:

再次使用以下命令导出GPIO2_PC3引脚,导出成功之后进入gpio84文件夹如下图所示:

echo 84 > export

可以看到gpio84文件夹下分别有active_low、device、direction、edge、power、subsystem、uevent、value八个文件,需要关心的文件是 active_low、direction、edge 以及 value 这四个属性文件,接下来分别介绍这四个属性文件的作用:

direction配置 GPIO 引脚为输入或输出模式。该文件可读、可写,读表示查看 GPIO 当前是输入还是输出模式,写表示将 GPIO 配置为输入或输出模式;读取或写入操作可取的值为"out"(输出模式)和"in"(输入模式)。

在“/sys/class/gpio/gpio84”目录下使用cat命令查看direction输入输出模式,如下图所示:

cat direction

 

 默认状态下的输入输出状态为“in”,由于direction为可读可写,可以使用以下命令将模式配置为输出,配置完成如下图所示

echo out > direction

cat direction

active_low用于控制极性得属性文件,可读可写,默认情况下为 0,使用cat命令进行文件内容的查看,如下图所示 :

cat active_low

 

当 active_low 等于 0 时, value 值若为1则引脚输出高电平,value 值若为0则引脚输出低电平。当 active_low 等于 1 时 ,value 值若为0则引脚输出高电平,value 值若为1则引脚输出低电平。

edge控制中断的触发模式,该文件可读可写。在配置 GPIO 引脚的中断触发模式之前,需将其设置为输入模式,四种触发模式的设置如下所示:

非中断引脚:echo "none" > edge

上升沿触发:echo "rising" > edge

下降沿触发:echo "falling" > edge

边沿触发:  echo "both" > edge

至此,关于GPIO的控制相关的知识就讲解完成了,下面将分别进行GPIO的输入和输出实验。

14.2 GPIO输出应用编程 

本小节代码在配套资料“iTOP-3588开发板\03_【iTOP-RK3588开发板】指南教程\03_系统编程配套程序\62”目录下,如下图所示:

实验要求:

通过GPIO输出应用程序控制GPIO口输出高低电平,以此来控制LED灯的亮灭。

14.2.1编写应用程序

实验步骤:

首先进入ubuntu的终端界面输入以下命令来创建 demo62_gpioout.c文件,如下图所示:

vim demo62_gpioout.c

然后向该文件中添加以下内容:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

char gpio_path[100];  // 存放GPIO路径

int gpio_ctrl(char *arg, char *val)  // 控制GPIO输出高低电平
{
    char file_path[100];  // 存放文件路径
    int fd, len, ret;

    sprintf(file_path, "%s/%s", gpio_path, arg);  // 将文件路径拼接起来
    fd = open(file_path, O_WRONLY);  // 以只写方式打开文件
    if (fd < 0) 
    {
        printf("无法打开文件: %s\n", file_path);  // 打开文件失败
        return -1;
    }

    len = strlen(val);
    ret = write(fd, val, len);  // 向文件中写入val内容
    if (ret < 0) 
    {
        printf("无法写入文件: %s\n", file_path);  // 写入文件失败
        close(fd);  // 关闭文件描述符
        return -1;
    }

    close(fd);  // 关闭文件描述符
    return 0;
}

int main(int argc, char *argv[])  // 主函数
{
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]);  // 将GPIO路径存放到gpio_path中

    // 如果 GPIO 没有被导出,则导出 GPIO
    if (access(gpio_path, F_OK))  // 判断是否存在gpio_path指向的路径
    {
        int fd, len, ret;

        fd = open("/sys/class/gpio/export", O_WRONLY);  // 打开export文件
        if (fd < 0) 
        {
            printf("无法打开文件: /sys/class/gpio/export\n");  // 打开文件失败
            return -1;
        }

        len = strlen(argv[1]);
        ret = write(fd, argv[1], len);  // 向文件中写入argv[1]的内容
        if (ret < 0) 
        {
            printf("无法写入文件: /sys/class/gpio/export\n");  // 写入文件失败
            close(fd);  // 关闭文件描述符
            return -1;
        }

        close(fd);  // 关闭文件描述符
    }

    gpio_ctrl("direction", "out");  // 配置GPIO为输出模式
    gpio_ctrl("active_low", "0");  // 设置极性
    gpio_ctrl("value", argv[2]);   // 控制GPIO输出高低电平

    return 0;  // 返回0表示程序正常退出
}

第35行首先会判断相应的gpio文件是否存在,不存在则进行gpio的导出,存在就继续运行,第67-79行为了方便通过gpio_ctrl函数进行属性的配置。

保存退出之后,使用以下命令设置交叉编译器环境,并对demo62_gpioout.c进行交叉编译,编译完成如下图所示:

export PATH=/usr/local/arm64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin:$PATH

aarch64-none-linux-gnu-gcc -o demo62_gpioout demo62_gpioout.c

最后将交叉编译生成的demo62_gpioout文件拷贝到/home/nfs共享目录下即可。

14.2.2开发板测试

Buildroot系统启动之后,首先使用以下命令进行nfs共享目录的挂载(其中192.168.1.7为作者ubuntu的ip地址,需要根据自身ubuntu的ip来设置),如下图所示:

mount -t nfs -o nfsvers=3,nolock 192.168.1.7:/home/nfs /mnt

nfs共享目录挂载到了开发板的/mnt目录下,进入到/mnt目录下,如下图所示:

可以看到/mnt目录下demo62_gpioout文件已经存在了,然后使用以下命令导出LED的GPIO2_PC4 pin脚,并设置为高电平,如下图所示:

./demo62_gpioout 84 1

使用命令之后会发现LED灯会亮起,然后使用以下命令关闭led灯,如下图所示:

./demo62_gpioout 84 0

命令运行成功之后,可以看到LED灯又熄灭了。至此,GPIO输出应用程序在开发板的测试就完成了。

14.3 GPIO输入应用编程

本小节代码在配套资料“iTOP-3588开发板\03_【iTOP-RK3588开发板】指南教程\03_系统编程配套程序\63”目录下,如下图所示:

 

实验要求:

通过GPIO输入应用程序来打印GPIO口当前输入的电平。

14.3.1编写应用程序 

实验步骤:

首先进入到ubuntu的终端界面输入以下命令来创建 demo63_gpioin.c文件,如下图所示:

vim demo63_gpioin.c

然后向该文件中添加以下内容: 

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

char gpio_path[100];  // GPIO文件路径

int gpio_ctrl(char *arg, char *val) 
{
    char file_path[100];    // 文件路径
    int fd, len, ret;       // 文件描述符,写入字节数,返回值

    sprintf(file_path, "%s/%s", gpio_path, arg);  // 将GPIO文件路径和文件名拼接成文件路径
    fd = open(file_path, O_WRONLY);              // 以只写方式打开文件
    if (fd < 0) 
	{
        printf("open error\n");     // 打开文件错误
        return -1;
    }
    len = strlen(val);          // 获取字符串的长度
    ret = write(fd, val, len);  // 向文件中写入数据
    if (ret < 0) 
	{
        printf("write error\n");    // 写入数据错误
        return -1;
    }
    close(fd);          // 关闭文件
    return 0;
}

int main(int argc, char *argv[]) 
{
    char file_path[100], buf[1];    // 文件路径,读取缓冲区
    int fd, len, ret;               // 文件描述符,写入字节数,返回值

    sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]);    // 将GPIO文件路径和GPIO号拼接成GPIO文件路径
    if (access(gpio_path, F_OK))    // 检查GPIO文件是否存在
	{
        fd = open("/sys/class/gpio/export", O_WRONLY);       // 打开export文件
        if (fd < 0) 
		{
            printf("open error\n");     // 打开文件错误
            return -1;
        }
        len = strlen(argv[1]);          // 获取字符串的长度
        ret = write(fd, argv[1], len);  // 向文件中写入GPIO号
        if (ret < 0) 
		{
            printf("write error\n");    // 写入数据错误
            return -1;
        }
        close(fd);          // 关闭文件
    }

    gpio_ctrl("direction", "in");     // 配置为输入模式 
    gpio_ctrl("active_low", "0");     // 极性设置
    gpio_ctrl("edge", "none");        // 设置非中断输入
    sprintf(file_path, "%s/%s", gpio_path, "value"); // 将GPIO文件路径和value文件名拼接成文件路径
    fd = open(file_path, O_RDONLY);                // 以只读方式打开文件
    if (fd < 0) 
	{
        printf("open error\n");     // 打开文件错误
        return -1;
    }
    ret = read(fd, buf, 1);         // 从文件中读取1个字节的数据
    if (ret < 0) 
	{
        printf("write error\n");    // 读取数据错误
        return -1;
    }
    if (!strcmp(buf, "1"))      // 判断读取的数据是否为1
	{
        printf("the value is high\n");  // 数据为1,输出高电平
    } 
	else if (!strcmp(buf, "0")) // 判断读取的数据是否为0
	{
        printf("the value is low\n"); // 数据为0,输出低电平
    }
    close(fd);
    return 0;
}

第41行首先会判断相应的gpio文件是否存在,不存在则进行gpio的导出,存在就继续运行,第59-61行为了方便通过gpio_ctrl函数进行属性的配置。

保存退出之后,使用以下命令设置交叉编译器环境,并对demo63_gpioin.c进行交叉编译,编译完成如下图所示:

export PATH=/usr/local/arm64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin:$PATH

aarch64-none-linux-gnu-gcc -o demo63_gpioin demo63_gpioin.c

最后将交叉编译生成的demo63_gpioin文件拷贝到/home/nfs共享目录下即可。

14.3.2开发板测试

Buildroot系统启动之后,首先使用以下命令进行nfs共享目录的挂载(其中192.168.1.7为作者ubuntu的ip地址,需要根据自身ubuntu的ip来设置),如下图所示:

mount -t nfs -o nfsvers=3,nolock 192.168.1.7:/home/nfs /mnt

nfs共享目录挂载到了开发板的/mnt目录下,进入到/mnt目录下,如下图所示:

可以看到/mnt目录下demo63_gpioin文件已经存在了,然后使用以下命令导出LED的GPIO2_PC4 pin脚,如下图所示:

./demo63_gpioin 84 

可以看到LED的GPIO2_PC4 pin脚打印的high值为高,而此时LED灯为点亮状态,所以gpio的状态打印正确。

为了测试输入底电平的状况,作者使用了杜邦线将GND接到了GPIO2_PC4 pin脚上,然后再次使用以下命令来进行状态的检测,如下图所示:

./demo63_gpioin 84 

可以看到LED的GPIO2_PC4 pin脚打印的low值为低,而此时LED灯为熄灭状态,所以gpio的状态打印正确。

至此GPIO输入应用程序在开发板的测试就完成了。

14.4 GPIO输入中断编程

本小节代码在配套资料“iTOP-3588开发板\03_【iTOP-RK3588开发板】指南教程\03_系统编程配套程序\64”目录下,如下图所示:

实验要求:

通过GPIO的输入中断程序,将中断触发方式设置为边沿触发,每当触发中断会打印“get interrupt”字符串。

14.4.1编写应用程序 

实验步骤:

首先进入到ubuntu的终端界面输入以下命令来创建 demo64_interrupt.c文件,如下图所示:

vim demo64_interrupt.c

 然后向该文件中添加以下内容:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>

char gpio_path[100];

// 控制GPIO的函数
int gpio_ctrl(char *arg, char *val) 
{
    char file_path[100];
    int fd, len, ret;

    // 根据参数和GPIO路径生成要控制的文件路径
    sprintf(file_path, "%s/%s", gpio_path, arg);

    // 打开文件
    fd = open(file_path, O_WRONLY);
    if (fd < 0) 
	{
        printf("open error\n");
        return -1;
    }

    // 计算要写入的值的长度,并将值写入文件
    len = strlen(val);
    ret = write(fd, val, len);
    if (ret < 0) 
	{
        printf("write error\n");
        return -1;
    }

    // 关闭文件并返回成功
    close(fd);
    return 0;
}

int main(int argc, char *argv[]) 
{
    char file_path[100], buff[10];
    int fd, len, ret;
    struct pollfd fds[1];

    // 根据命令行参数生成GPIO路径
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]);

    // 如果该GPIO未导出,则导出该GPIO
    if (access(gpio_path, F_OK)) 
	{
        fd = open("/sys/class/gpio/export", O_WRONLY);
        if (fd < 0) 
		{
            printf("open error\n");
            return -1;
        }
        len = strlen(argv[1]);
        ret = write(fd, argv[1], len);
        if (ret < 0) 
		{
            printf("write error\n");
            return -1;
        }
        close(fd);
    }

    // 配置GPIO为输入模式、极性为正、边沿触发中断
    gpio_ctrl("direction", "in");
    gpio_ctrl("active_low", "0");
    gpio_ctrl("edge", "both");

    // 打开GPIO的值文件并将其文件描述符赋给pollfd结构体
    sprintf(file_path, "%s/%s", gpio_path, "value");
    fd = open(file_path, O_RDONLY);
    if (fd < 0) 
	{
        printf("open error\n");
        return -1;
    }
    fds[0].fd = fd;
    fds[0].events = POLLPRI; // 只关心高优先级数据可读(中断)
    read(fd, buff, 10); // 先读取一次清除状态

    // 进入循环,等待GPIO中断
    while (1) 
	{
        ret = poll(fds, 1, -1); // 等待事件发生
        if (ret == -1) 
		{
            printf("poll fail\n");
        }
        if (fds[0].revents & POLLPRI) 
		{ // 如果高优先级数据可读(中断触发)
            printf("get interrupt\n");
        }
    }

    // 关闭文件并返回成功
    close(fd);
    return 0;
}

第53行首先会判断相应的gpio文件是否存在,不存在则进行gpio的导出,存在就继续运行,第72-74行为了方便通过gpio_ctrl函数进行属性的配置,将中断模式设置为边沿触发,之后使用poll函数进行中断的判断,并打印相应的信息。

保存退出之后,使用以下命令设置交叉编译器环境,并对demo99_gpioin.c进行交叉编译,编译完成如下图所示:

export PATH=/usr/local/arm64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin:$PATH

aarch64-none-linux-gnu-gcc -o demo64_interrupt demo64_interrupt.c

最后将交叉编译生成的demo64_interrupt文件拷贝到/home/nfs共享目录下即可。

14.4.2开发板测试

Buildroot系统启动之后,首先使用以下命令进行nfs共享目录的挂载(其中192.168.1.7为作者ubuntu的ip地址,需要根据自身ubuntu的ip来设置),如下图所示:

mount -t nfs -o nfsvers=3,nolock 192.168.1.7:/home/nfs /mnt

nfs共享目录挂载到了开发板的/mnt目录下,进入到/mnt目录下,如下图所示:

 可以看到/mnt目录demo64_interrupt文件已经存在了,然后使用以下命令导出LED的GPIO2_PC4 pin脚,并设置中断触发模式,如下图所示:

./demo100_interrupt 84 

 

由于中断并没有被触发,所以程序会阻塞,等待中断的进行,然后使用杜邦线将GND接到GPIO2_PC4 pin脚,进行中断的测试,如下图所示:

可以看到中断就被触发了,相应的字符串也被打印了。至此GPIO输入中断应用程序在开发板的测试就完成了。

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

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

相关文章

Vue3: toRefs与toRef的基本使用

一、前言 本文主要介绍toRefs与toRef的基本使用。 二、内容 1、基本概念 作用: toRefs与toRef可以将一个响应式对象中的每一 个属性&#xff0c;转换为ref对象&#xff1b;不同 toRefs与toRef功能一致&#xff0c;但toRefs可以批量转换。 2、toRefs 如果把reactive定义的…

论文解读-ASAP: Fast Mobile Application Switch via Adaptive Prepaging

研究背景&#xff1a; 用户使用移动设备同时打开多个App&#xff0c;很容易造成移动设备的内存紧缺。现有解决方法一般采用杀死守护进程&#xff08;lmkd&#xff09;来释放内存或者基于压缩算法的in-memory swap(ZRAM)方式&#xff0c; 这些方法会面临用户切换回被杀死的进程过…

构建有序链表,有序链表的归并,反转链表

本次将对于构建有序链表&#xff0c;有序链表的归并&#xff0c;反转链表&#xff0c;进行一一介绍和代码分享。 首先是一些链表中的基本的函数&#xff1a; Node* creatList() {Node* headNode (Node*)malloc(sizeof(Node));assert(headNode);headNode->next NULL;retu…

汽车摄像头匿名化处理解决方案,保护信息的安全性和隐私性

随着智能交通和自动驾驶技术的迅猛发展&#xff0c;汽车摄像头已成为现代汽车不可或缺的一部分&#xff0c;摄像头所捕捉的图像信息也引发了日益严峻的信息安全问题。如何在充分利用摄像头功能的同时&#xff0c;保障个人隐私和信息安全&#xff0c;已成为企业亟待解决的问题。…

CPRI协议理解——帧格式中的计数标识

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 CPRI协议理解——帧格式中的计数标识 前言帧格式中的计数标识总结 前言 CPRI协议是一个流式协议&#xff0c;数据不间断的传输&#xff0c;在我们要了解CPRI到底要传输种类繁…

HDMI to TYPE-C芯片|HDMI2.0转TYPE-C转接器方案|CS5802设计方案|ASL CS5802

CS5802输入端可以是1080P、4K30、4K60HZ这三种规格,输出的接口可以是TYPE-C信号接口,或者是TYPE-C信号接口,输入端HDMI由4路信号组成&#xff0c;支持1.62Gbps、2.7Gbps、5.4Gbps链路速率。内置可选SSC功能可降低EMI的干扰状况。 ASL CS5802芯片概述&#xff1a; 符合HDMI规范…

抖去推短视频矩阵系统----源头开发

为什么一直说让企业去做短视频矩阵&#xff1f;而好处就是有更多的流量入口&#xff0c;不同平台或账号之间可以进行资源互换&#xff0c;最终目的就是获客留咨&#xff0c;提单转化。你去看一些做得大的账号&#xff0c;你会发现他们在许多大的平台上&#xff0c;都有自己的账…

基于Python利用zhconv模块进行简繁体字转换

在处理中文文本时&#xff0c;简繁体字之间的转换是一项常见的任务。Python提供了许多库来实现这个目的&#xff0c;其中之一就是zhconv。zhconv是一个Python库&#xff0c;提供了简体字和繁体字之间的转换功能。本教程将向你展示如何使用zhconv模块来实现简繁体字的互转&#…

【MATLAB】App 设计 (入门)

设计APP 主界面 函数方法 定时器 classdef MemoryMonitorAppExample < matlab.apps.AppBase% Properties that correspond to app componentsproperties (Access public)UIFigure matlab.ui.FigureStopButton matlab.ui.control.ButtonStartButton matlab.ui.cont…

用户行为分析模型实践(四)—— 留存分析模型

作者&#xff1a;vivo 互联网大数据团队- Wu Yonggang、Li Xiong 本文是vivo互联网大数据团队《用户行为分析模型实践》系列文章第4篇 -留存分析模型。 本文详细介绍了留存分析模型的概念及基本原理&#xff0c;并阐述了其在产品中具体实现。针对在实际使用过程问题&#xff0…

力扣---从前序与中序遍历序列构造二叉树

给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,15,20,7] 输出: [3,9,20,null,null,15,7]示…

面试Spring框架

什么是Spring框架&#xff1f; Spring框架是一个开源的Java应用程序框架&#xff0c;提供了综合的基础设施支持&#xff0c;用于开发Java企业应用程序。它涵盖了从基本的核心容器到全面的企业服务&#xff0c;可以用于构建任何规模的应用程序。 Spring框架的核心特性是什么&am…

深度解析 Spring 源码:三级缓存机制探究

文章目录 一、 三级缓存的概述二、 三级缓存的实现原理2.1 创建Bean流程图2.2 getBean()2.3 doGetBean()2.4 createBean()2.5 doCreateBean()2.4 getSingleton() 三、 三级缓存的使用场景与注意事项3.1 在实际开发中如何使用三级缓存3.2 三级缓存可能出现的问题及解决方法 一、…

黑马---苍穹外卖总结上

1.功能模块 1.1 管理端功能 员工登录/退出 , 员工信息管理 , 分类管理 , 菜品管理 , 套餐管理 , 菜品口味管理 , 订单管理 &#xff0c;数据统计&#xff0c;来单提醒。 模块描述登录/退出内部员工必须登录后,才可以访问系统管理后台员工管理管理员可以在系统后台对员工信息进…

数据结构学习--环形链表

环形链表 我们在判断一个链表是否是环形的&#xff0c;即首尾相连&#xff0c;我们可以以使用快慢指针&#xff0c;如果快指针能再次追上慢指针&#xff0c;就说明该链表是环形的&#xff0c;这边可以举个操场跑步的例子&#xff0c;当操场是环形的&#xff0c;跑的快的&#…

Ansible组件说明

1.Ansible Inventory 工作当中有不同的业务主机&#xff0c;我们需要在把这些机器信息存放在inventory里面&#xff0c;ansible默认的inventory的文件是/etc/ansible/hosts&#xff0c;也可以通过ANSIBLE_HOSTS环境变量来指定或者运行ansible和ansible-playbook的时候用-i参数临…

泛微E9开发 快速隐藏明细表列

快速隐藏明细表列 1、隐藏列方法&#xff08;不作用&#xff0c;一直隐藏&#xff09; 在实际运用中&#xff0c;用户不需要但是需要间接使用的列&#xff0c;我们可以通过右击该列-【列自定义属性】-在“列自定义属性”菜单中启用“隐藏列”功能。 根据该方法设置的前端页…

纯js图片上传插件

目录标题 一、效果预览二、使用简单三、完整代码&#xff08;一&#xff09;index.html&#xff08;二&#xff09;css&#xff08;三&#xff09;js四、附带后台上传文件代码 一、效果预览 支持多图片上传&#xff0c;删除、预览。 二、使用简单 导入依赖&#xff08;需要…

视觉化数据的艺术:掌握Matplotlib基础绘图

Matplotlib基础绘图 文章目录 Matplotlib基础绘图1.基础流程2.绘图设置3.动态rc参数4.pyplot的基础图表函数 安利 1.基础流程 1.导入模块。绘图之前&#xff0c;需要先导入包含相应函数的模块。 2.创建画布与创建子图。第一部分主要是构建出一张空白的画布&#xff0c;如果需要…

Elastic 网络爬虫:为你的网站添加搜索功能

作者&#xff1a;来自 Elastic Lionel Palacin 为了演示如何使用 Elastic 网络爬虫&#xff0c;我们将以一个具体的网站为例&#xff0c;讲解如何在该网站上添加搜索功能。我们将探讨发现网站的方法&#xff0c;并利用 Elastic 网络爬虫提供的功能&#xff0c;以最佳方式准备待…