Linux驱动基础篇(一)GPIO(上)LED驱动

news2025/1/14 1:10:31

文章目录

    • Linux驱动基础(一)GPIO(上)LED驱动
    • 一、开发环境准备
      • 1.安装交叉编译工具+编译内核
        • (1)安装交叉编译工具
        • (2)修改Makefile指定编译器和架构
        • (3)生成配置文件.config
        • (4)编译内核
      • 2.安装配置vscode
    • 二、第一个驱动程序HelloWorld
      • 1.简单的驱动框架使用
        • 2.重要的几个宏/函数
    • 三、第二个驱动程序点亮LED
      • 1.阅读原理图和芯片手册
        • (1)找到OrangePi PC+的两个LED
        • (2)找到两个LED和CPU连接的引脚
        • (3)在芯片手册找到PL10和PA15
        • (4)找到对应的配置寄存器
        • (5)找到对应的数据寄存器
      • 2.从驱动开始点亮香橙派orangepi plus的LED
    • 四、面向对象设计思想

Linux驱动基础(一)GPIO(上)LED驱动

一、开发环境准备

ubuntu22.04 + Vscode + OrangePi+

1.安装交叉编译工具+编译内核

(1)安装交叉编译工具

📌选择交叉编译工具链

以官网下载页面为例

在这里插入图片描述

在这里插入图片描述

📌下载交叉编译工具

​ 交叉编译工具链官方下载地址(国外)
​ 交叉编译工具链清华开源镜像站下载地址(国内)

📌解压、添加环境变量、测试安装结果

sudo tar -xvf arm-none-linux-gnueabihf-12.3-x86_64-.tar.xz -C /mnt	# 解压到/mnt目录
# 添加环境变量,在原有的双引号前输入:后粘贴复制工具链的路径
# 例如这里是/mnt/arm-none-linux-gnueabihf-12.3-x86_64/bin
# 保存后重新登录或重启生效,输入arm-尝试tab能否补全命令以及arm-none-linux-gnueabihf-gcc -v进行测试
sudo vi /etc/environment
(2)修改Makefile指定编译器和架构
# 在内核源码顶层目录的Makefile,搜索CROSS_COMPILE或ARCH,添加以下内容
# 要配置上面步骤后,CROSS_COMPILE可以这样写;没有的话要写绝对路径
ARCH  := arm
CROSS_COMPILE	:= arm-none-linux-gnueabihf-
(3)生成配置文件.config
# 生成默认的配置文件,也可以make menuconfig进行配置,最后会保存到.config
make defconfig

❓❓❓ 报错1:arch/arm是一个目录 ❓❓❓

解决:ARCH := arm (arm后面多了空格)

❓❓❓ 报错2:/bin/sh: 1: flex: not found ❓❓❓

sudo apt-get install flex

❓❓❓ 报错3:/bin/sh: 1: bison: not found ❓❓❓

sudo apt-get install bison

❓❓❓ 报错4:make menuconfig 打开失败❓❓❓

sudo apt-get install libncurses5-dev


(4)编译内核
# 建议这里可以将所有的CPU核心分配给虚拟机,提高速度
make -j24

❓❓❓ 报错5:scripts/extract-cert.c:21:10: fatal error: openssl/bio.h: 没有那个文件或目录❓❓❓

原因:没有安装libssl-dev或者安装版本过高
解决:(未安装)sudo apt-get install libssl-dev
(版本过高)sudo apt-get install aptitude(安装aptitude软件包管理器)
sudo aptitude install libssl-dev(使用aptitude安装libssl-dev)
选择不保持当前版本,出现提示输出n,确认y后降级


2.安装配置vscode

二、第一个驱动程序HelloWorld

1.简单的驱动框架使用

简单的驱动框架分为三步:①装载驱动、②操作驱动、③卸载驱动。个人认为这样划分容易理解和记忆!
在这里插入图片描述

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/err.h>

#define   DEV_NAME   "hello"

static struct class *hello_cls;
static int ERR;
static struct device *device;

static int hello_open(struct inode *inode, struct file *file){
    printk("%s  %s  %d\n",__FILE__,__FUNCTION__ ,__LINE__);
    return 0;
}
static ssize_t hello_read (struct file *file, char __user *buf, size_t size, loff_t *offset){
    printk("%s  %s  %d\n",__FILE__,__FUNCTION__ ,__LINE__);
    
    return 0;
}

static ssize_t hello_write (struct file *file, const char __user *buf, size_t size, loff_t * offset){
    printk("%s  %s  %d\n",__FILE__,__FUNCTION__ ,__LINE__);
    return 0;
}
static int hello_release(struct inode *inode, struct file *file){
    printk("%s  %s  %d\n",__FILE__,__FUNCTION__ ,__LINE__);
    return 0;
}

static unsigned int major = 0;
static struct file_operations hello_fop = {
        .owner = THIS_MODULE,
        .open = hello_open,
        .read = hello_read,
        .write = hello_write,
        .release = hello_release
};

/**
 * @brief 初始化驱动(注册设备register_chrdev()、创建设备节点device_create())
 * 注册设备需要:设备号、设备名、设备file_operaction
 * 创建设备节点需要:class、devtype-由设备号确定、设备节点名
 **/
static int  __init hello_Driver_Init(void){
    printk("%s  %s  %d\n",__FILE__,__FUNCTION__ ,__LINE__);
    major = register_chrdev(major,DEV_NAME,&hello_fop);
    hello_cls = class_create(THIS_MODULE,DEV_NAME);
    if(IS_ERR(hello_cls)){
        ERR = PTR_ERR(hello_cls);
        pr_err("class create failed.(error code:%d)\n",ERR);
        unregister_chrdev(major,DEV_NAME);
        return ERR;
    }
    device = device_create(hello_cls,NULL, MKDEV(major,0),NULL,"hello");
    if(IS_ERR(device)){
        ERR = PTR_ERR(device);
        pr_err("device create failed.(error code:%d)\n",ERR);
        class_destroy(hello_cls);
        unregister_chrdev(major,DEV_NAME);
        return ERR;
    }
    return 1;
}

/**
 * @brief 卸载驱动(删除设备节点device_destroy()、注销设备unregister_chrdev())
 **/
static void __exit hello_Driver_Exit(void){
    printk("%s  %s  %d\n",__FILE__,__FUNCTION__ ,__LINE__);
    device_destroy(hello_cls, MKDEV(major,0));
    class_destroy(hello_cls);
    unregister_chrdev(major,DEV_NAME);
}

module_init(hello_Driver_Init);
module_exit(hello_Driver_Exit);
MODULE_LICENSE("GPL");
2.重要的几个宏/函数

2.1 错误指针判断IS_ERR( )、PTR_ERR( )和pr_err( )

2.2 用户和内核之间的数据拷贝copy_from_user( )、copy_to_user( )和get_user( )、put_user( )

三、第二个驱动程序点亮LED

1.阅读原理图和芯片手册

(1)找到OrangePi PC+的两个LED

📌在原理图中搜索"LED",找到关于OrangePi+ LED部分的原理图

在这里插入图片描述

  • 从原理图关于LED的部分可以看到,OrangePi PC+有两个LED:PWR-LED(供电时闪烁LED)、STATUS-LED(开机运行时状态LED)。
(2)找到两个LED和CPU连接的引脚

在这里插入图片描述

  • PWR-LED连接到PL10、STATUS_LED连接到PA15
(3)在芯片手册找到PL10和PA15

在这里插入图片描述

(4)找到对应的配置寄存器

在这里插入图片描述

(5)找到对应的数据寄存器

在这里插入图片描述

2.从驱动开始点亮香橙派orangepi plus的LED

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/err.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/uaccess.h>

#define PIO_BASE    0x01c20800

static volatile unsigned int *PA_CFG1_REG;
static volatile unsigned int *PA_DATA_REG;
static unsigned int major = 0;
static struct class *led_class;

static int led_open(struct inode *inode, struct file *file){
    /* output: bit30-28 = 001 */
    *PA_CFG1_REG &= ~(0x01 << 30);
    *PA_CFG1_REG &= ~(0x01 << 29);
    *PA_CFG1_REG |= (0x01 << 28);
    printk("======= led_open():PA_CFG_REG = 0x%x =========\n",*PA_CFG1_REG);
    return 0;
}
static int led_close(struct inode *inode, struct file *file){
    /* default: bit30-28 = 111 */
    *PA_CFG1_REG |= (0x01 << 30);
    *PA_CFG1_REG |= (0x01 << 29);
    *PA_CFG1_REG |= (0x01 << 28);
    printk("======= led_close():PA_CFG_REG = 0x%x =========\n",*PA_CFG1_REG);
    return 0;
}
static ssize_t led_read (struct file *file, char __user *buf, size_t size, loff_t *off){
    return 0;
}
static ssize_t led_write (struct file *file, const char __user *buf, size_t size, loff_t *off){
    char val;   // 0-OFF 1-ON
    int ret = copy_from_user(&val,buf,1);
    ret = 3;
    if(val){
        *PA_DATA_REG |= 0x1<<15; //bit15 = 1
    }else{
        *PA_DATA_REG &= ~(0x1<<15); //bit15 = 0
    }
    return 1;
}
static struct file_operations led_ops = {
    .owner = THIS_MODULE,
    .open = led_open,
    .read = led_read,
    .write = led_write,
    .release = led_close,
};
static int  __init led_driver_init(void){
    printk("======= %s %s %d ========\n",__FILE__,__FUNCTION__ ,__LINE__);
    major = register_chrdev(major,"led_driver",&led_ops);
    led_class = class_create(THIS_MODULE,"led_driver");
    device_create(led_class,NULL, MKDEV(major,0),NULL,"led1");
    PA_CFG1_REG = ioremap(PIO_BASE+0x04,4);
    PA_DATA_REG = ioremap(PIO_BASE+0x10,4);
    *PA_CFG1_REG &= ~(0x1<<30);
    *PA_CFG1_REG &= ~(0x1<<29);
    *PA_CFG1_REG |= 0x1<<28;
    return 0;
}

static void  __exit led_driver_exit(void){
    printk("======= %s %s %d ========\n",__FILE__,__FUNCTION__ ,__LINE__);
    iounmap(PA_CFG1_REG);
    iounmap(PA_DATA_REG);
    device_destroy(led_class, MKDEV(major,0));
    class_destroy(led_class);
    unregister_chrdev(major,"led_driver");

}

module_init(led_driver_init);
module_exit(led_driver_exit);
MODULE_LICENSE("GPL");

这里为了没有写应用层的测试程序,只简单粗暴点个LED,加载驱动后led亮,香橙派OrangePi Plus上是红灯

四、面向对象设计思想

上面所写的LED驱动程序,驱动和硬件操作绑定在一起,更换开发板平台所有的代码就完全不适用,不仅可维护性和可读性差,而且代码难以移植到其他平台,增加了代码冗余和维护的工作量。因此,内核驱动程序中采用面向对象的编程思想,将驱动和硬件操作的代码分离并进行合理的抽象和封装,通常是更好的选择

📌改写LED驱动,实现应用层程序控制两个LED亮灭

【led_test_app.c】

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

/** ./test_led_app /dev/led1 on **/
/** ./test_led_app /dev/led2 off **/

int main(int argc,char **argv){
    char *buf = (char *)malloc(36);
    int nwrite = 0;
    if(argc < 3){
        printf("Usage:%s [dev-led1/led2]  [status-on/off]  \n",argv[0]);
        return -1;
    }
    int fd = open(argv[1],O_RDWR);
    if(fd < 0){
        printf("open device error\n");
        return -1;
    }

    int val_on = 1;
    int val_off = 0;

    if( 0 == strcmp(argv[2],"on")){
        nwrite = write(fd,&val_on,sizeof(val_on));
    }else if( 0 == strcmp(argv[2],"off")){
        nwrite = write(fd,&val_off,sizeof(val_off));
    }else{
        printf("syntax error\n");
    }
    close(fd);
    return 0;
}

【orangepi_plus_leds.h】

#ifndef _ORANGEPI_PLUS_LEDS_H
#define _ORANGEPI_PLUS_LEDS_H

#define MIN(a,b)    (a < b ? a : b)
#define PIN_GROUP(pin)  (pin >> 22)
#define PIN_NUM(pin)    (pin & 0x3FFFFF)

struct GPIOx_PIN {   
    /** bit[21:0] pin_num **/
    /** bit[31:22] pin_group **/
    int pin; 
    int count;
    volatile unsigned int *GPIOx_CFG_REG;        //配置寄存器
    volatile unsigned int *GPIOx_DAT_REG;        //数据寄存器
    int (*gpio_init)(int pin);             //初始化函数
    int (*gpio_control)(int pin,int status);   //控制函数
    struct GPIOx_PIN *next;
};

extern struct GPIOx_PIN *get_GPIOA_PIN15(void);
extern struct GPIOx_PIN *get_GPIOL_PIN10(void);

#endif

【orangepi_plus_led1.c】

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/err.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include "orangepi_plus_leds.h"

#define BASE_ADDR   (0x01c20800)

#define WHICH_CFG(pin_num)  \
	((pin_num >= 0 && pin_num <= 7)   ?  0x00 : \
	 (pin_num >= 8 && pin_num <= 15)  ?  0x04 : \
	 (pin_num >= 15 && pin_num <= 21) ?  0x08 : 0x0c)


int led1_init(int pin);
int led1_control(int pin,int status);

static struct GPIOx_PIN GPIOA_PIN15 = {
	.pin = (0 << 22)|(15),          //第0组第15pin(GPIOA_15)
	.gpio_init = led1_init,
	.gpio_control = led1_control,
	.next = NULL
};

int led1_init(int pin){
	int pin_num = PIN_NUM(pin);
	GPIOA_PIN15.GPIOx_CFG_REG = ioremap(BASE_ADDR + PIN_GROUP(pin)* 0x24 + WHICH_CFG(pin_num),4);
	GPIOA_PIN15.GPIOx_DAT_REG = ioremap(BASE_ADDR + PIN_GROUP(pin)* 0x24 + 0x10,4);
	if(GPIOA_PIN15.GPIOx_CFG_REG == NULL || GPIOA_PIN15.GPIOx_DAT_REG == NULL){	
		pr_err("======== %s:ioremap address error =======\n",__FUNCTION__);
		return -1;
	}
	*(GPIOA_PIN15.GPIOx_CFG_REG) &= ~(0x1<<29);
	*(GPIOA_PIN15.GPIOx_CFG_REG) &= ~(0x1<<30);
	*(GPIOA_PIN15.GPIOx_CFG_REG) |= (0x1<<28);
	return 0;
}

int led1_control(int pin,int status){   //status 0-off 1-on
	switch(status){
		case 0: //off
			*(GPIOA_PIN15.GPIOx_DAT_REG) &= ~(0x1 << PIN_NUM(pin));
			break;
		case 1: //on
			*(GPIOA_PIN15.GPIOx_DAT_REG) |= (0x1 << PIN_NUM(pin));
			break;
		default:
			break;
	}
	return 0;
}

struct GPIOx_PIN *get_GPIOA_PIN15(void){
	return &GPIOA_PIN15;
}

EXPORT_SYMBOL(get_GPIOL_PIN10);
MODULE_LICENSE("GPL");

【orangepi_plus_led2.c】

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/err.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include "orangepi_plus_leds.h"

#define BASE_ADDR   (0x01f02c00)

#define WHICH_CFG(pin_num)  \
        ((pin_num >= 0 && pin_num <= 7)   ?  0x00 : \
         (pin_num >= 8 && pin_num <= 15)  ?  0x04 : \
         (pin_num >= 15 && pin_num <= 21) ?  0x08 : 0x0c)

int led2_init(int pin);
int led2_control(int pin,int status);

static struct GPIOx_PIN GPIOL_PIN10 = {
    .pin = (0 << 22)|(10),         //第0组第10pin(GPIOL_10)
    .gpio_init = led2_init,
    .gpio_control = led2_control,
    .next = NULL
};


int led2_init(int pin){
    int pin_num = PIN_NUM(pin);
    GPIOL_PIN10.GPIOx_CFG_REG = ioremap(BASE_ADDR + PIN_GROUP(pin)*0x24 + WHICH_CFG(pin_num),4);
    GPIOL_PIN10.GPIOx_DAT_REG = ioremap(BASE_ADDR + PIN_GROUP(pin)*0x24 + 0x10,4);
    if(GPIOL_PIN10.GPIOx_CFG_REG == NULL || GPIOL_PIN10.GPIOx_DAT_REG == NULL){
         pr_err("======= %s ioremap address error ========\n",__FUNCTION__);
         return -1;
     }
    *(GPIOL_PIN10.GPIOx_CFG_REG) &= ~(0x1<<29);
    *(GPIOL_PIN10.GPIOx_CFG_REG) &= ~(0x1<<30);
    *(GPIOL_PIN10.GPIOx_CFG_REG) |= (0x1<<28);
    return 0;
}

int led2_control(int pin,int status){   //status 0-off 1-on
    switch(status){
        case 0: //off
            *(GPIOL_PIN10.GPIOx_DAT_REG) &= ~(0x1<<PIN_NUM(pin));
            break;
        case 1: //on
            *(GPIOL_PIN10.GPIOx_DAT_REG) |= (0x1<<PIN_NUM(pin));
            break;
        default:
            break;
    }
    return 0;
}


struct GPIOx_PIN *get_GPIOL_PIN10(void){
    return &GPIOL_PIN10;
}

EXPORT_SYMBOL(get_GPIOL_PIN10);
MODULE_LICENSE("GPL");

【led_driver.c】

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/err.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include "orangepi_plus_leds.h"


static int major = 0;
static int error_check = 0;
static int i = 0;
static struct device *device_check;
static unsigned int minor;
static int kernel_buf = 0;

static volatile int *GPIOx_base_address;
static volatile int *PA_CFGx_REG;
static volatile int *PA_DATA_REG;

static struct GPIOx_PIN *led = NULL;

static int gpio_open(struct inode *inode, struct file *file){
    printk("========== %s  %s  %d ===============\n",__FILE__,__FUNCTION__ ,__LINE__);
    dev_t dev = inode->i_rdev;  //应用层open文件的设备号
    minor = MINOR(dev);  //获取次设备号    0-1 
    switch (minor){
        case 0:
            led = get_GPIOA_PIN15();
            break;
        case 1:
            led = get_GPIOL_PIN10();
        default:
            break;
    }
    led->gpio_init(led->pin);
    return 0;
}

static ssize_t gpio_read (struct file *file, char __user *buf, size_t size, loff_t *offset){
    printk("========== %s  %s  %d =============\n",__FILE__,__FUNCTION__ ,__LINE__);
    return 0;
}

static ssize_t gpio_write (struct file *file, const char __user *buf, size_t size, loff_t * offset){
    printk("========== %s  %s  %d  =============\n",__FILE__,__FUNCTION__ ,__LINE__);
    if(copy_from_user(&kernel_buf,buf,4)){
        pr_err("copy_from_user error.(%s)\n",__FUNCTION__);
        return -1;
    }
    led->gpio_control(led->pin,kernel_buf);
    return 0;
}
static int gpio_close(struct inode *inode, struct file *file){
    printk("========== %s  %s  %d ===============\n",__FILE__,__FUNCTION__ ,__LINE__);
    iounmap(PA_DATA_REG);
    iounmap(PA_CFGx_REG);
    iounmap(GPIOx_base_address);
    return 0;
}


static struct file_operations gpio_ops = {
    .owner = THIS_MODULE,
    .open = gpio_open,
    .release = gpio_close,
    .write = gpio_write,
    .read = gpio_read,
};

static struct class *gpio_cls;
 
static int __init gpio_driver_init(void){
    printk("============= %s  %s  %d ==================\n",__FILE__,__FUNCTION__ ,__LINE__);
    /* 1.注册字符设备 */
    major = register_chrdev(major,"GPIO",&gpio_ops);

    /* 2.创建设备节点 */
    gpio_cls = class_create(THIS_MODULE,"gpio_class");
    if(IS_ERR(gpio_cls)){
        error_check = PTR_ERR(gpio_cls);
        pr_err("class create failed.(error code:%d)\n",error_check);
        unregister_chrdev(major,"GPIO");
        return -1;
    }

    for(i=0;i<2;i++){
        device_check = device_create(gpio_cls,NULL,MKDEV(major,i),NULL,"led%d",i+1);
        if(IS_ERR(device_check)){
            error_check = PTR_ERR(device_check);
            pr_err("device create failed.(error code:%d)\n",error_check);
            class_destroy(gpio_cls);
            unregister_chrdev(major,"GPIO");
            return -1;
        }
    }
    return 0;
}

static void __exit gpio_driver_exit(void){
    printk("============= %s  %s  %d ==================\n",__FILE__,__FUNCTION__ ,__LINE__);
    iounmap(PA_DATA_REG);
    iounmap(PA_CFGx_REG);
    iounmap(GPIOx_base_address);
    device_destroy(gpio_cls, MKDEV(major,0));
    device_destroy(gpio_cls, MKDEV(major,1));
    class_destroy(gpio_cls);
    unregister_chrdev(major,"GPIO");
}

module_init(gpio_driver_init);
module_exit(gpio_driver_exit);
MODULE_LICENSE("GPL");

【Makefile】

# KERNEL_DIR = /usr/src/linux-headers-5.4.65-sunxi/
KERNEL_DIR =/home/socket/Desktop/linux-5.4-orangepi

# CROSS_COMPILE = arm-linux-gnueabihf-
CROSS_COMPILE = arm-none-linux-gnueabihf-


all:
	make -C $(KERNEL_DIR) M=`pwd` modules
	$(CROSS_COMPILE)gcc test_led_app.c -o test_led_app
clean:
	make -C $(KERNEL_DIR) M=`pwd` modules clean
	rm -rf modules.order test_led_app

OrangePiPlus_leds-y	:= led_driver.o orangepi_plus_led1.o orangepi_plus_led2.o
obj-m	+= OrangePiPlus_leds.o

在这里插入图片描述

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

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

相关文章

小知识(7) wangEditor富文本编辑器简单引入(vue3)

wangEditor富文本编辑器 https://github.com/wangeditor-team/wangEditorhttps://www.wangeditor.com/ 一、安装 cnpm install wangeditor/editor --savecnpm install wangeditor/editor-for-vuenext --save二、使用 BaseEditor.vue <template><div style"b…

CSS 基础知识-02

CSS 基础知识-01 1. flex布局 1. flex布局

蓝桥杯每日一题2032.10.24

蓝桥杯大赛历届真题 - C 语言 B 组 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 由于布局为两个字节为一行&#xff0c;那我们输入两个数就为一行&#xff0c;但是这两个数全部得用二进制进行表示使用bitset bitset:将一个数转化为二进制 bitset<8>:将一个数转化为8位…

4种实用的制作URL 文件的方法

很多小伙伴有自己的博客、淘宝或者共享文件网站&#xff0c;想要分享、推广自己的网址做成url文件&#xff0c;让别人点击这个url文件直接访问自己的网站。URL文件其实就一个超级链接&#xff0c;制作的方法很多&#xff0c;这里列举4种。 收藏网站直接拖拽 1.第一种&#xf…

小知识(5) el-table行样式失效问题

一、实现效果 子级呈现不同颜色去区分 二、最初代码 tips: 我这里使用的vue3 elementplus <el-table :row-class-name"tableRowClassName" >... </el-table>function tableRowClassName({ row, rowIndex }) {if (row.children.length 0) {return …

nestJs(一) 创建node项目

开发准备 1、安装 Node 环境. 下载安装后&#xff0c;Node > 10.13.0 即可, 可通过命令行检查 node -v 2.安装 NestJS cli npm i -g nestjs/cli创建 nest-test 项目 // step1 nest new nest-test// step2 Which package manager would you 选择: npm目录结构 src|- app…

QLable 类使用教程

文章目录 1、简介2 、公共类型3、属性4、functions4.1、访问属性相关 function4.2、公共槽4.3、Signal4.4、其他方法 QLabel 内容长度超过控件本身长度时处理1、QLabel 内容长度超过控件本身长度时超出的部分用省略号2、QLabel 内容长度超过控件本身长度时使用定时器滑动显示文…

【T3】畅捷通T3备份账套提示:超时已过期,错误‘53‘文件不存在。

【问题描述】 针对畅捷通T3软件&#xff0c;进行账套备份&#xff08;账套输出&#xff09;的时候&#xff0c; 先是提示”超时已过期“&#xff1b; 点击确定后&#xff0c;再次提示&#xff1a;运行时错误53&#xff0c;文件未找到。 最终导致账套备份/输出失败。 【解决…

Pd虚拟机Parallels Desktop 19.1.0

Parallels Desktop是一款功能强大的虚拟机软件&#xff0c;它允许用户在Mac电脑上同时运行Windows、Linux和其他操作系统。Parallels Desktop提供了直观易用的界面&#xff0c;使用户可以轻松创建、配置和管理虚拟机。 该软件具有快速启动和关闭虚拟机的能力&#xff0c;让用户…

HFSS笔记——优化设计optimetrics

HFSS的优化设计可以分成4步走&#xff1a; 使用参数扫描确定合理区间 → 确定优化变量 → 构造目标函数→ 确定优化算法 1、变量分为两种&#xff0c;一种较工程变量&#xff0c;一种叫设计变量。 在一个project下可以同时存在多个design&#xff0c;在project下设置的变量叫…

云计算技术的新发展:公有云、私有云还是混合云的未来?

在当今数字化时代&#xff0c;云计算技术已经成为企业和组织不可或缺的工具。在众多的云计算服务模式中&#xff0c;公有云、私有云和混合云备受关注。这些服务模式各具特点&#xff0c;分别适用于不同的应用场景和需求&#xff0c;为企业的信息化建设带来了无限的可能性。 一…

Ubuntu18.04如何安装搜狗、网易云音乐、百度网盘、金山WPS、谷歌浏览器、微信、Maven、Pycharm、Anaconda、MySQL8.0等软件

目录 1.搜狗输入法 下载 安装 卸载 2.网易云音乐 下载 安装 3.百度网盘 下载 安装 4.金山WPS 下载 安装 5.谷歌浏览器 下载 安装 6.微信 下载安装 7.Maven 下载 安装 配置镜像源 8.Pycharm 下载 安装 9.Anaconda 下载 安装 卸载 10.MySQL8.0 下载…

Linux下的IMX6ULL——开发板基本操作(二)

目录&#xff1a; 前面我们已经配置好了环境&#xff0c;下载好了软件&#xff0c;下面让我们对我们使用的开发板有给简单的了解吧&#xff0c;IMX6ULL Pro开发板基本操作是必不可少的一大环节&#xff0c;下面让我们从它的硬件资源&#xff0c;软件资源等一系列开发板的基础操…

一键闪测仪的基本概述和应用全面解析

闪测仪是一种采用新型图像影像测量技术的精密测量仪器&#xff0c;主要是为满足用户快速测量的需要而开发的。它能一键测量二维平面尺寸&#xff0c;或配备光学非接触式测量头&#xff0c;实现高度尺寸、平面度等参数的精密快速测量。在工业制造领域&#xff0c;它通过对目标物…

进程 概念和理解 - Linux 是怎么做到 管理进程的?-fork 手动创建进程

前言 上一篇博客当中&#xff0c;对 冯诺依曼体系结构 和 操作系统 进行了简要概述&#xff0c;本篇博客将会从上一篇博客的基础之上进行展开&#xff0c;如果你有些不了解的话&#xff0c;建议先看上一篇博客再看本篇博客&#xff1a; 冯诺依曼体结构 - 为什么要有操作系统-…

ResNet论文精读,代码实现与拓展知识

文章目录 ResNet 论文精读代码实现网络可视化代码 拓展知识 ResNets残差的调参残差链接的渊源残差链接有效性的解释ResNet 深度ResNeXt代码实现 能够提点的技巧「Warmup」「Label-smoothing」「Random image cropping and patching」「Knowledge Distiallation」「Cutout」「Ra…

学习如何在linux服务器上修改默认端口22

学习如何在linux服务器上修改默认端口22 修改默认的22端口号重启ssh服务测试连接 修改默认的22端口号 [rootqipa250 ssh]# vim /etc/ssh/sshd_config 知道Port&#xff0c;改为自己想要的端口号 重启ssh服务 [rootqipa250 ssh]# systemctl restart sshd.service测试连接 阿…

Netty使用和常用组件

简述 netty 版本 <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId<version>4.1.42.Final </version><scope>compile</scope> </dependency>Netty5 已经停止开发了。 netty 优势 API …

SQL注入专项整理(持续更新中)

深入了解SQL注入 什么是SQL注入&#xff1f; SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严&#xff0c;攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句&#xff0c;在管理员不知情的情况下实现非法操作&#xff0c;以此来实现…