Linux第69步_依据“旧字符设备的一般模板”编写LED驱动

在编写LED驱动之前,先要了解和硬件有关的一些知识。

1、了解“MMU内存管理单元”以及相关函数

MMU是Memory Manage Unit的缩写,意思是“内存管理单元”。

老版本的Linux内核要求处理器必须有“MMU内存管理单元”,而现在的Linux内核已经支持无“MMU内存管理单元”的处理器了。

“MMU内存管理单元”的功能:

1)、完成“虚拟空间”到“物理空间”的映射。

2)、内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性。

地址映射:

虚拟地址(VA.Virtual Address)

物理地址(PA,PhyscicalAddress)。

对于 32位的处理器来说,虚拟地址范围是 2^32=4GB,开发板的DDR3只有1GB,这就是“物理内存”,经过MMU可以将“物理内存”映射到整个4GB的虚拟空间。

ioremap()函数

它用于获取与“指定的物理地址空间”对应的“虚拟地址空间”,ioremap()函数定义在arch/arm/include/asm/io.h文件中。

void __iomem *ioremap(resource_size_t res_cookie, size_t size);

res_cookie:要映射的“物理内存”的起始地址;

size:要映射的“物理内存”的空间大小;

返回值:__iomem类型的指针,它是指向“映射后的虚拟空间”的首地址;

iounmap()函数

当我们需要卸载驱动时,可以用iounmap()函数释放掉ioremap()函数所做的映射;

void iounmap (volatile void __iomem *addr);

举例:

#define GPIOI_MODER (0X5000A000)         //定义寄存器物理地址

static void __iomem* GPIO_MODER_PI;      //声明映射后的“虚拟空间地址”

GPIO_MODER_PI = ioremap(GPIOI_MODER, 4);

//获取与“物理地址0X5000A000”对应的“虚拟地址空间”,共计4个字节;

iounmap(GPIO_MODER_PI);

//释放“物理地址0X5000A000”对应的“虚拟地址空间”

2、IO内存访问函数

读操作函数:

u8 readb(const volatile void __iomem *addr)

u16 readw(const volatile void __iomem *addr)

u32 readl(const volatile void __iomem *addr)

写操作函数:

void writeb(u8 value, volatile void __iomem *addr)

void writew(u16 value, volatile void __iomem *addr)

void writel(u32 value, volatile void __iomem *addr)

3、创建LED目录

输入“cd /home/zgq/linux/Linux_Drivers/回车

切换到“/home/zgq/linux/Linux_Drivers/

输入“ls回车”,查看“/home/zgq/linux/Linux_Drivers/

输入“makdir LED回车”,创建“LED”目录

输入“cd CharDeviceXXX_1/回车

切换到“/home/zgq/linux/Linux_Drivers/CharDeviceXXX_1/

输入“ls回车”,查看“/home/zgq/linux/Linux_Drivers/CharDeviceXXX_1/

输入“cp *  /home/zgq/linux/Linux_Drivers/LED回车

将“/home/zgq/linux/Linux_Drivers/CharDeviceXXX_1/”目录下的所有文件拷贝到“/home/zgq/linux/Linux_Drivers/LED/

输入“cd ../回车”,返回到“/home/zgq/linux/Linux_Drivers/

输入“ls回车

查看“/home/zgq/linux/Linux_Drivers/”目录下的文件和文件夹

输入“cd LED/回车”,切换到“/home/zgq/linux/Linux_Drivers/LED/”目录

输入“ls回车”查看“/home/zgq/linux/Linux_Drivers/LED/”目录

输入“mv CharDeviceXXX.c LED.c回车”,将“CharDeviceXXX.c”更名为“LED.c”

输入“mv CharDeviceXXX_APP.c LED_APP.c回车”,将“CharDeviceXXX_APP.c”更名为“LED_APP.c

输入“ls回车”查看“/home/zgq/linux/Linux_Drivers/LED/”目录

4、创建“c_cpp_properties.json” 的文件

打开虚拟机上“VSCode”,点击“文件”,点击“打开文件夹”,点击“zgq”,点击“linux”,点击“Linux_Drivers”,点击“LED”,按下“Ctrl+Shift+P”,打开VSCode控制台,然后输入“C/C++:Edit Configurations(JSON)”,打开以后会自动在“.vscode ”目录下生成一个名为“c_cpp_properties.json” 的文件,修改c_cpp_properties.json内容如下所示:

{

    "configurations": [

        {

            "name": "Linux",

            "includePath": [

                "${workspaceFolder}/**",

               "/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31",

                "/home/zgq/linux/Linux_Drivers/LED",

"/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31/arch/arm/include", 

 "/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31/include",

"/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31/arch/arm/include/generated"

            ],

            "defines": [],

            "compilerPath": "/usr/bin/gcc",

            "cStandard": "gnu11",

            "cppStandard": "gnu++14",

            "intelliSenseMode": "gcc-x64"

        }

    ],

    "version": 4

}

5、修改Makefile文件如下:

KERNELDIR := /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31

#使用“:=”将其后面的字符串赋值给KERNELDIR

CURRENT_PATH := $(shell pwd)

#采用“shell pwd”获取当前打开的路径

#使用“$(变量名)”引用“变量的值”

MyDriver := LED

MyAPP := LED_APP

CC := arm-none-linux-gnueabihf-gcc

obj-m := $(MyDriver).o

#生成“obj-m”需要依赖“LED.o”,指定要编译成内核模块的文件

all: drv app

#生成“all”需要依赖“drv和app”

    @echo $(KERNELDIR)

#输出KERNELDIR的值为“/home/zgq/linux/atk-mp1/linux/linux-5.4.31”

    @echo $(CURRENT_PATH)

#输出CURRENT_PATH的值为/home/zgq/linux/Linux_Drivers/LED”

    @echo $(MAKE)

#输出MAKE的值为make

    @echo $(CC)

#输出CC的值为arm-none-linux-gnueabihf-gcc

drv:

    $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules

#后面的"modules"表示编译成模块

#“KERNELDIR”上面定义为“/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31”,即“指定的工作目录”

#“CURRENT_PATH”上面定义为“当前的工作目录”

#“-C $(KERNELDIR) M=$(CURRENT_PATH) ”表示将“当前的工作目录”切换到“指定的目录”中

#即切换到“/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31”。

#M表示模块源码目录

#在“make和modules”之间加入“M=$(CURRENT_PATH)”,表示切换到由“CURRENT_PATH”指定的目录中读取源码,同时将其编>译为.ko 文件

app:

    $(CC)  $(MyAPP).c  -o $(MyAPP)

clean: clean_drv clean_app

#生成“clean”需要依赖“clean_DRV和clean_APP”

clean_drv:

    $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

#“KERNELDIR”上面定义为“/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31”,即“指定的工作目录”

#“CURRENT_PATH”上面定义为“当前的工作目录

clean_app:

    rm $(MyAPP)

install:

    sudo cp *.ko $(MyAPP) /home/zgq/linux/nfs/rootfs/lib/modules/5.4.31/ -f

6、LED灯驱动程序框架:

修改led.c文件如下:

#include <linux/types.h>

//数据类型重命名

//使能bool,u8,u16,u32,u64, uint8_t, uint16_t, uint32_t, uint64_t

//使能s8,s16,s32,s64,int8_t,int16_t,int32_t,int64_t

#include <linux/kernel.h>

#include <linux/delay.h>

#include <linux/ide.h>

#include <linux/init.h>

#include <linux/module.h>

#include <linux/string.h>

#include <linux/errno.h>

#define led_MAJOR   200

//定义主设备号

//静态分配设备号:在串口输入“cat/proc/devices”查询当前已用的主设备号

//然后使用一个“没有被使用的设备号”作为该设备的的主设备号

#define led_NAME   "ledName//定义设备的名字

/* 打开设备 */

static int led_open(struct inode *inode, struct file *filp)

{

  int ret = 0;

  //printk("led_open!\r\n");

  return ret;

}

/* 向设备写数据,将数据块首地址为buf的数据,长度为cnt个字节,发送给用户 */

//file结构指针变量flip表示要打开的设备文件

//buf表示用户数据块的首地址

//cnt表示用户数据的长度,单位为字节

//loff_t结构指针变量offt表示“相对于文件首地址的偏移”

static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)

{

  int ret = 0;

  return ret;

}

/* 关闭/释放设备 */

static int led_release(struct inode *inode, struct file *filp)

{

  int ret=0;

  printk("led_release!\r\n");

  return ret;

}

/*声明file_operations结构变量MyCharDevice_fops*/

/*它是指向设备的操作函数集合变量*/

const struct file_operations led_fops = {

  .owner = THIS_MODULE,

  .open = led_open,

  .write = led_write,

  .release = led_release,

};

/*驱动模块的入口函数 */

static int  __init led_init(void)

{

  int ret=0;

  printk("led_init!\r\n");

  ret = register_chrdev(led_MAJOR, led_NAME, &led_fops);

  //注册字符设备

  //led_MAJOR为主设备号,采用宏led_NAME定义设备名字

  //led_fops是设备的操作函数集合,它是file_operations结构变量

  if (ret < 0)

  {

printk("CharDeviceDriver register failed!!!\r\n");

goto faile_register;

  }

  return 0;//注册字符设备正确

faile_register:

return -EIO;//注册字符设备失败

}

/*驱动模块的出口函数 */

static void __exit led_exit(void)

{

  printk("led_exit!\r\n");

  unregister_chrdev(led_MAJOR, led_NAME);

  //注销字符设备

  //led_MAJOR为主设备号,采用宏led_NAME定义设备名字

}

module_init(led_init);

//加载“驱动模块”:指定led_init()为驱动入口函数

module_exit(led_exit);

//卸载“驱动模块”:指定led_exit()为驱动出口函数

MODULE_AUTHOR("Zhanggong");//添加作者名字

MODULE_LICENSE("GPL");//LICENSE采用“GPL协议”

MODULE_INFO(intree,"Y");

//去除显示“loading out-of-tree module taints kernel.”

7、LED灯驱动程序:

led.c文件如下:

#include <linux/types.h>

/*

数据类型重命名

使能bool,u8,u16,u32,u64, uint8_t, uint16_t, uint32_t, uint64_t

使能s8,s16,s32,s64,int8_t,int16_t,int32_t,int64_t

*/

#include <linux/kernel.h>

#include <linux/delay.h>

#include <linux/ide.h>

#include <linux/init.h>

#include <linux/module.h>

#include <linux/string.h>

#include <linux/errno.h>

#include <linux/gpio.h>

#define led_MAJOR   200

/*

定义主设备号

静态分配设备号:在串口输入“cat/proc/devices”查询当前已用的主设备号

然后使用一个“没有被使用的设备号”作为该设备的的主设备号

*/

#define led_NAME   "ledName"  //定义设备的名字

#define LEDOFF    0             /* 关灯 */

#define LEDON     1             /* 开灯 */

/* 寄存器物理地址 */

#define PERIPH_BASE            (0x40000000)

#define MPU_AHB4_PERIPH_BASE   (PERIPH_BASE + 0x10000000)

#define RCC_BASE               (MPU_AHB4_PERIPH_BASE + 0x0000)

#define RCC_MP_AHB4ENSETR       (RCC_BASE + 0XA28)

#define GPIOI_BASE              (MPU_AHB4_PERIPH_BASE + 0xA000)

#define GPIOI_MODER             (GPIOI_BASE + 0x0000)   

#define GPIOI_OTYPER            (GPIOI_BASE + 0x0004)   

#define GPIOI_OSPEEDR           (GPIOI_BASE + 0x0008)   

#define GPIOI_PUPDR             (GPIOI_BASE + 0x000C)   

#define GPIOI_BSRR              (GPIOI_BASE + 0x0018)

/* 映射后的寄存器虚拟地址指针 */

static void __iomem *MPU_AHB4_PERIPH_RCC_PI;

/*RCC_MP_AHB4ENSETR寄存器*/

static void __iomem *GPIOI_MODER_PI; /*GPIOx_MODER寄存器,x=A to K, Z*/

static void __iomem *GPIOI_OTYPER_PI;/*GPIOx_OTYPER,x=A to K,Z*/

static void __iomem *GPIOI_OSPEEDR_PI;/*GPIOx_OSPEEDR,x=A to K, Z*/

static void __iomem *GPIOI_PUPDR_PI; /*GPIOx_PUPDR,x=A to K, Z*/

static void __iomem *GPIOI_BSRR_PI;/*GPIOx_BSRR,x=A to K, Z*/

/* 寄存器地址映射 */

static void led_ioremap(void)

{

    MPU_AHB4_PERIPH_RCC_PI = ioremap(RCC_MP_AHB4ENSETR, 4);

    GPIOI_MODER_PI = ioremap(GPIOI_MODER, 4);

    GPIOI_OTYPER_PI = ioremap(GPIOI_OTYPER, 4);

    GPIOI_OSPEEDR_PI = ioremap(GPIOI_OSPEEDR, 4);

    GPIOI_PUPDR_PI = ioremap(GPIOI_PUPDR, 4);

    GPIOI_BSRR_PI = ioremap(GPIOI_BSRR, 4);

}

/*取消“寄存器地址映射”*/

static void led_iounmap(void)

{

    iounmap(MPU_AHB4_PERIPH_RCC_PI);

    iounmap(GPIOI_MODER_PI);

    iounmap(GPIOI_OTYPER_PI);

    iounmap(GPIOI_OSPEEDR_PI);

    iounmap(GPIOI_PUPDR_PI);

    iounmap(GPIOI_BSRR_PI);

}

void led_switch(u8 sta)

{

    u32 val = 0;

    if(sta == LEDON) {

    val = readl(GPIOI_BSRR_PI);/*读GPIOI_BSRR寄存器*/

val &= ~(0X1 << 16); /* bit16 清零*/

    val |= (0x1 << 16);  /*bit16 设置为1,令PI0输出低电平*/

    writel(val, GPIOI_BSRR_PI);

/* 将val的值写入GPIOI_BSRR寄存器 */

    }

else if(sta == LEDOFF) {

    val = readl(GPIOI_BSRR_PI);/*读GPIOI_BSRR寄存器*/

val &= ~(0X1 << 0); /* bit0 清零*/

    val |= (0x1 << 0);/*bit0 设置为1,令PI0输出高电平*/   

    writel(val, GPIOI_BSRR_PI);

/* 将val的值写入GPIOI_BSRR寄存器 */

    }  

}

/* 打开设备 */

static int led_open(struct inode *inode, struct file *filp)

{

  int ret = 0;

  //printk("led_open!\r\n");

  return ret;

}

/* 向设备写数据,将数据块首地址为buf的数据,长度为cnt个字节,发送给用户 */

//file结构指针变量flip表示要打开的设备文件

//buf表示用户数据块的首地址

//cnt表示用户数据的长度,单位为字节

//loff_t结构指针变量offt表示“相对于文件首地址的偏移”

static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)

{

  int ret = 0;

unsigned char databuf[1];

unsigned char ledstat;

ret = copy_from_user(databuf, buf, cnt);

if(ret <0){

printk("kernel write failed!\r\n");

ret = -EFAULT;

}

ledstat = databuf[0];/*获取到应用传递进来的开关灯状态*/

led_switch(ledstat);/*执行开灯或执行关灯*/

  return ret;

}

/* 关闭/释放设备 */

static int led_release(struct inode *inode, struct file *filp)

{

  int ret=0;

  printk("led_release!\r\n");

  return ret;

}

/*声明file_operations结构变量MyCharDevice_fops*/

/*它是指向设备的操作函数集合变量*/

const struct file_operations led_fops = {

  .owner = THIS_MODULE,

  .open = led_open,

  .write = led_write,

  .release = led_release,

};

/*驱动模块的入口函数 */

static int  __init led_init(void)

{

  int ret=0;

  u32 val = 0;

/* 1、寄存器地址映射 */

  led_ioremap();

/* 2、使能RCC时钟 */

val = readl(MPU_AHB4_PERIPH_RCC_PI);/* 读RCC_MP_AHB4ENSETR寄存器 */

val &= ~(0X1 << 8);/* 清除以前的bit8设置 */

val |= (0X1 << 8); /* 设置新的bit8值 */

writel(val, MPU_AHB4_PERIPH_RCC_PI);

/* 将val的值写入RCC_MP_AHB4ENSETR寄存器 */

/* 3、将PI0输出引脚。*/

    val = readl(GPIOI_MODER_PI);/*读GPIOI_MODER寄存器*/

    val &= ~(0X3 << 0);  /* bit0:1清零 */

    val |= (0X1 << 0);   /* bit0:1设置01,配置为输出模式 */

    writel(val, GPIOI_MODER_PI);

/* 将val的值写入GPIOI_MODER寄存器 */

/* 4、设置PI0为推挽模式 */

    val = readl(GPIOI_OTYPER_PI);/*读GPIOI_OTYPER寄存器*/

    val &= ~(0X1 << 0);  /* bit0清零,设置为上拉*/

    writel(val, GPIOI_OTYPER_PI);

/* 将val的值写入GPIOI_OTYPER寄存器 */

/* 5、设置PI0为高速 */

    val = readl(GPIOI_OSPEEDR_PI);/*读GPIOI_OSPEEDR寄存器*/

    val &= ~(0X3 << 0); /* bit0:1 清零 */

    val |= (0x3 << 0); /* bit0:1 设置为11,极高速*/

    writel(val, GPIOI_OSPEEDR_PI);

/* 将val的值写入GPIOI_OSPEEDR寄存器 */

/* 6、设置PI0为上拉。*/

    val = readl(GPIOI_PUPDR_PI);/*读GPIOI_PUPDR寄存器*/

    val &= ~(0X3 << 0); /* bit0:1 清零*/

    val |= (0x1 << 0); /*bit0:1 设置为01,配置为上拉*/

    writel(val,GPIOI_PUPDR_PI);

/* 将val的值写入GPIOI_PUPDR寄存器 */

/* 6、默认打开LED,PI0=0 */

    val = readl(GPIOI_BSRR_PI);/*读GPIOI_BSRR寄存器*/

val &= ~(0X1 << 16); /* bit16 清零*/

    val |= (0x1 << 16);  /*bit16 设置为1,令PI0输出低电平*/

    writel(val, GPIOI_BSRR_PI);

/* 将val的值写入GPIOI_BSRR寄存器 */

/* 6、默认关闭LED,PI0=1 */

    val = readl(GPIOI_BSRR_PI);/*读GPIOI_BSRR寄存器*/

val &= ~(0X1 << 0); /* bit0 清零*/

    val |= (0x1 << 0);/*bit0 设置为1,令PI0输出高电平*/   

    writel(val, GPIOI_BSRR_PI);

/* 将val的值写入GPIOI_BSRR寄存器 */

  printk("led_init!\r\n");

  ret = register_chrdev(led_MAJOR, led_NAME, &led_fops);

  //注册字符设备

  //led_MAJOR为主设备号,采用宏led_NAME定义设备名字

  //led_fops是设备的操作函数集合,它是file_operations结构变量

  if (ret < 0)

  {

printk("CharDeviceDriver register failed!!!\r\n");

goto faile_register;

  }

  return 0;

faile_register:

  return -EIO;

}

/*驱动模块的出口函数 */

static void __exit led_exit(void)

{

/* 1、取消寄存器地址映射 */

  led_iounmap();

  printk("led_exit!\r\n");

  unregister_chrdev(led_MAJOR, led_NAME);

  //注销字符设备

  //led_MAJOR为主设备号,采用宏led_NAME定义设备名字

}

module_init(led_init);

//加载“驱动模块”:指定led_init()为驱动入口函数

module_exit(led_exit);

//卸载“驱动模块”:指定led_exit()为驱动出口函数

MODULE_AUTHOR("Zhanggong");//添加作者名字

MODULE_LICENSE("GPL");//LICENSE采用“GPL协议”

MODULE_INFO(intree,"Y");

//去除显示“loading out-of-tree module taints kernel.”

8、LED_APP.c程序如下:

#include "stdio.h"

#include "unistd.h"

#include "sys/types.h"

#include "sys/stat.h"

#include "fcntl.h"

#include "stdlib.h"

#include "string.h"

//APP运行命令:./LED_APP filename <1>|<0>如果是1表示打开LED,如果是0表示关闭LED

#define LEDOFF    0             /* 关灯 */

#define LEDON     1             /* 开灯 */

/*

参数argc: argv[]数组元素个数

参数argv[]:是一个指针数组

返回值: 0 成功;其他 失败

*/

int main(int argc, char *argv[])

{

  int fd, retvalue;

  char *filename;

  unsigned char databuf[1];

  if(argc != 3)

  {

    printf("Error Usage!\r\n");

    return -1;

  }

  //argv[]是指向输入参数“./LED_App” “/dev/LED” “1”

  filename = argv[1];

  //argv[1]指向字符串“/dev/LED”

  fd = open(filename, O_RDWR);

  //如果打开“/dev/LED”文件成功,则fd为“文件描述符”

  //fd=0表示标准输入流; fd=1表示标准输出流;fd=2表示错误输出流;

  if(fd < 0)

  {

    printf("Can't open file %s\r\n", filename);

    return -1;

  }

  databuf[0]= atoi(argv[2]); /* 写入的数据,是数字的,表示打开或关闭 */

  retvalue = write(fd, databuf, 1);

  //将databuf[]中前1个字节发送给用户

  //返回值大于0表示写入的字节数;

  //返回值等于0表示没有写入任何数据;

  //返回值小于0表示写入失败

  if(retvalue < 0)

  {

    printf("write file %s failed!\r\n", filename);

    close(fd);

    //fd表示要关闭的“文件描述符”

    //返回值等于0表示关闭成功

    //返回值小于0表示关闭失败

    return -1;

  }

  /* 关闭设备 */

  retvalue = close(fd);

  //fd表示要关闭的“文件描述符”

  //返回值等于0表示关闭成功

  //返回值小于0表示关闭失败

  if(retvalue < 0)

  {

    printf("Can't close file %s\r\n", filename);

    return -1;

  }

  return 0;

}

6、使用Makefile编译

输入“make drv回车”,编译生成LED.ko

输入“make app回车”,编译生成LED_APP

输入“make clean_drv回车”,清除LED.*

输入“make clean_app回车”,清除LED_APP

输入“make all回车”,编译生成LED.ko和LED_APP

输入“make clean回车”,清除“LED.*”和“LED_APP”

输入“make all回车”,编译生成LED.ko和LED_APP

输入“make install回车”,执行文件拷贝

7、测试

启动开发板,从网络下载程序

输入“root

输入“cd /lib/modules/5.4.31/回车

切换到“/lib/modules/5.4.31/”目录

注意:“lib/modules/5.4.31/在虚拟机中是位于“/home/zgq/linux/nfs/rootfs/”目录下,但在开发板中,却是位于根目录中

输入“ls -l”查看“LED.ko和LED_APP”是否存在

输入“depmod”,驱动在第一次执行时,需要运行“depmod”

输入“modprobe LED.ko”,加载“LED.ko”模块

输入“lsmod”查看有哪些驱动在工作

输入“mknod /dev/LED c 200 0回车

//mknod”是创建节点命令

///dev/LED”表示节点文件

//c”表示LED是个字符设备

//200”表示设备的主设备号

//0”表示设备的次设备号

输入“ls /dev/LED  -l回车”,发现节点文件“/dev/LED

输入“./LED_APP /dev/LED 1回车”执行写1开灯

输入“./LED_APP /dev/LED 0回车”执行写0关灯

操作完成,则执行卸载模块:

输入“rmmod LED.ko”,卸载“LED.ko”模块

注意:输入“rmmod LED”也可以卸载“LED.ko”模块

输入“lsmod”查看有哪些驱动在工作。

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

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

相关文章

车牌定位识别企业版

车牌定位识别企业版&#xff0c;只需要OPENCV&#xff0c;采用YOLOV8NANO检测车牌区域&#xff0c;然后使用PADDLE OCR检测车牌&#xff0c;能识别各国车牌&#xff0c;支持C,PYTHON开发 车牌定位识别企业版&#xff0c;只需要OPENCV&#xff0c;支持C,python

什么是云游戏?云游戏平台可以运行3A游戏吗?

对于不熟悉游戏行业的人来说&#xff0c;面对云游戏可能会有一个疑问——除了单机游戏&#xff0c;现在所有游戏不都是联网玩吗&#xff1f;云游戏和网络游戏有什么区别&#xff1f; 实际上&#xff0c;云游戏和传统网络游戏有着本质的不同。 传统网络游戏需要玩家先下载并在本…

【HTML】HTML基础7.1(无序列表)

目录 标签 属性 效果 注意 标签 <ul> <li>列表里要装的东西</li> <li>列表里要装的东西</li> <li>列表里要装的东西</li> </ul> 属性 type&#xff1a; circle空心圆disc实心圆square方框 效果 circle空心圆效果…

Positional Encoding 位置编码

Positional Encoding 位置编码 flyfish Transformer模型没有使用循环神经网络&#xff0c;无法从序列中学习到位置信息&#xff0c;并且它是并行结构&#xff0c;不是按位置来处理序列的&#xff0c;所以为输入序列加入了位置编码&#xff0c;将每个词的位置加入到了词向量中…

【hugggingface】批量加速下载HuggingFace上的模型

镜像网站及说明&#xff1a;https://hf-mirror.com/ 其他教程&#xff1a;如何快速下载huggingface模型——全方法总结 一、huggingface-cli方法下载 1.1安装依赖 pip install -U huggingface_hub1.2 设置环境变量 linux export HF_ENDPOINThttps://hf-mirror.comwindows …

如何挑选好的游泳耳机?游泳耳机的六大避坑指南!

游泳耳机是现代科技与运动健康完美结合的产物&#xff0c;对于热爱水上运动的朋友来说&#xff0c;一款好的游泳耳机不仅能让你在水中畅游时享受到音乐带来的乐趣&#xff0c;还能保护你的听力。然而&#xff0c;市场上琳琅满目的游泳耳机品牌和型号让人眼花缭乱&#xff0c;如…

08、MongoDB -- MongoDB 的 集合关联($lookup 和 DBRef 实现集合关联)

目录 MongoDB 的 集合关联演示前提&#xff1a;登录单机模式的 mongodb 服务器命令登录【test】数据库的 mongodb 客户端命令登录【admin】数据库的 mongodb 客户端命令 SQL 术语 与 Mongodb 的对应关系使用 $lookup 实现集合关联语法格式添加测试数据1、查询出订单数量大于6&a…

混沌工程-经典案例分享

目录 前言 案例 1、强弱依赖不合理 2、预案不生效 3、异常数据不兼容 4、监控体系缺陷 5、系统缺整体架构设计 总结 前言 我们公司从启动混沌工程到现在已经几乎覆盖了线上的所有核心业务&#xff0c;先后进行过2000次演练共挖掘出120个漏洞。这些漏洞有些得了及时修复…

C if...else 语句

一个 if 语句 后可跟一个可选的 else 语句&#xff0c;else 语句在布尔表达式为 false 时执行。 语法 C 语言中 if…else 语句的语法&#xff1a; if(boolean_expression) {/* 如果布尔表达式为真将执行的语句 */ } else {/* 如果布尔表达式为假将执行的语句 */ }如果布尔表…

Java Day2 面向对象

这里写目录标题 1、static总结1.1 代码块1.1.1 静态代码块1.1.2 实例代码块1.1.3 小例子 2、继承2.1 权限修饰符2.2 方法重写2.3 子类访问成员特点2.4子类构造器的特点 3、多态4、final、常量4.1 final4.2 常量 5 抽象类5.1 概念5.2 模板设计方法 6、接口6.1 接口新方法6.2 接口…

openEuler学习——部署MGR集群

本文介绍如何利用GreatSQL 8.0.25构建一个三节点的MGR集群。 1.安装准备 IP端口角色192.168.20.1103306mgr1192.168.20.1113306mgr2192.168.20.1123306mgr3 配置hosts解析 [rootMGR1 ~]# cat >> /etc/hosts << EOF > 192.168.20.110 MGR1 > 192.168.20.1…

Qt QtCreator打开pro项目时出现假死现象

在Windows系统下&#xff0c;QtCreator打开pro项目时出现假死现象&#xff0c;左侧项目树形图无法展开&#xff0c;项目根节点一直在转圈。尝试关掉所有QtCreator进程&#xff0c;重新打开pro也是无济于事。 解决方案&#xff1a; 打开“运行”窗口&#xff08;快捷键&#x…

overleaf latex 笔记

overleaf: www.overleaf.com 导入.tex文件 1.代码空一行&#xff0c;代表文字另起一段 2. 1 2 3 排序 \begin{enumerate} \item \item \item \end{enumerate} 3.插入图片 上传图片并命名 \usepackage{float}导包\begin{figure}[H]&#xff1a;表示将图…

鸿蒙开发报错解决方案: cannot be smaller than version 10 declared in library [:library]

由于报错信息不详&#xff0c;即使给hvigor.js 提供--stacktrace 级别的日志也无法定位具体模块。 解决方案&#xff1a;修改编译源码js。 1、定位具体js&#xff1a;我的定位是&#xff1a;/Users/xdg/.hvigor/project_caches/489b334bc29a5a8428674c766cdae532/workspace…

智能边缘计算网关实现工业自动化与数据处理的融合-天拓四方

随着物联网&#xff08;IoT&#xff09;技术的迅速发展和普及&#xff0c;越来越多的设备被连接到互联网上&#xff0c;产生了海量的数据。如何有效地处理和分析这些数据&#xff0c;同时确保数据的安全性和实时性&#xff0c;成为了摆在企业面前的一大挑战。智能边缘计算网关作…

图像处理与视觉感知---期末复习重点(1)

文章目录 一、概述二、图像处理基础2.1 视觉感知要素2.2 像素间的一些基本关系2.2.1 相邻像素2.2.2 连通性2.2.3 距离度量 2.3 基本坐标变换2.4 空间变换与灰度值 一、概述 1. 图像的概念及分类。  图像是用各种观测系统以不同形式和手段观测客观世界而获得的、可以直接或间接…

百度AI已经实现盈利,普通人如何通过AI短视频直播拿到结果?

从百度最新的财报数据来看&#xff0c;百度AI为广告业务、智能云业务带来了增长动力。除了直接带来商业收入&#xff0c;AI还为百度带来了新增长。2023年&#xff0c;百度用户总数、用户时长及用户粘性、付费率等都有所增加。数据显示&#xff0c;2023年12月&#xff0c;百度Ap…

刚刚,OpenAI官方发文驳斥马斯克,自曝8年间邮件往来截图

文章开篇表示&#xff1a;「OpenAI 的使命是确保 AGI 惠及全人类&#xff0c;这意味着既要构建安全、有益的 AGI&#xff0c;又要帮助创造广泛的利益。我们正在分享我们在实现使命方面所学到的知识&#xff0c;以及有关我们与马斯克关系的一些事实。我们打算驳回马斯克的所有主…

Spring事务管理与模板对象

1.事务管理 1.事务回顾 事务指数据库中多个操作合并在一起形成的操作序列 事务的作用 当数据库操作序列中个别操作失败时&#xff0c;提供一种方式使数据库状态恢复到正常状态&#xff08;A&#xff09;&#xff0c;保障数据库即使在异常状态下仍能保持数据一致性&#xff…

Netty权威指南——基础篇5 IO基础 备份

1 什么是I/O 在UNIX世界里一切皆是文件&#xff0c;而文件是什么&#xff1f;文件就是一串二进制流而已&#xff0c;其实不管是Socket&#xff0c;还是FIFO&#xff08;先进先出队列&#xff09;、管道、终端。对计算机来说&#xff0c;一切都是文件&#xff0c;一切都是流。在…