当前位置: 首页 > article >正文

rk3576(5)之设备树下GPIO驱动

1、简介rk3576buildroot设备树GPIO驱动编写。个人理解设备树就相当于存在统一规则、统一管理的头文件记录了开发板的设备信息。2、设备树语法2.1、dtsi 头文件设备树也支持头文件设备树的头文件扩展名为.dtsi设备树文件不仅可以应用 C 语言里面的.h 头文件甚至也可以引用.dts 文件。 因此在.dts 设备树文件中可以通过“#include”来引用.h、 .dtsi 和.dts 文件。只是我们在编写设备树头文件的时候最好选择.dtsi 后缀。一般.dtsi 文件用于描述 SOC 的内部外设信息比如 CPU 架构、主频、外设寄存器地址范围比如 UART、 IIC 等等。 比如 rk3576.dtsi 就是描述 RK3576 芯片本身的外设信息 内容一看6000多行不贴了哈哈2.2、设备节点设备树是采用树形结构来描述板子上的设备信息的文件每个设备都是一个节点叫做设备节点每个节点都通过一些属性信息来描述节点信息属性就是键—值对。//rk3576.dtsi i2c2: i2c2ac50000 { compatible rockchip,rk3576-i2c, rockchip,rk3399-i2c; reg 0x0 0x2ac50000 0x0 0x1000; clocks cru CLK_I2C2, cru PCLK_I2C2; clock-names i2c, pclk; interrupts GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH; pinctrl-names default; pinctrl-0 i2c2m0_xfer; resets cru SRST_I2C2, cru SRST_P_I2C2; reset-names i2c, apb; #address-cells 1; #size-cells 0; status disabled; }; //rk3576-custom.dtsi i2c2 { pinctrl-names default; pinctrl-0 i2c2m0_xfer; status okay; gt911_dsi: gt9115d { status okay; compatible goodix,gt911; reg 0x5d; interrupt-parent gpio0; interrupts RK_PD0 IRQ_TYPE_LEVEL_LOW; reset-gpios gpio0 RK_PD1 GPIO_ACTIVE_LOW; irq-gpios gpio0 RK_PD0 GPIO_ACTIVE_HIGH; pinctrl-names default; pinctrl-0 tp0_irq; touchscreen-inverted-x 1; touchscreen-swapped-x-y 1; }; };比如说I2C2表示引用系统中定义好的 I²C 控制器节点通常在 SoC 的 DTSI 文件中定义gt911就是I2C2下的设备节点可以看到节点的命名规则如下node-nameunit-address但是上面还使用了labellabel: node-nameunit-address引入 label 的目的就是为了方便访问节点可以直接通过label 来访问这个节点每个节点都有不同的属性不同的属性又有不同的内容属性是键值对值可以为空或者任意的字节流。2.3、标准属性节点是由一堆的属性组成节点都是具体的设备不同的设备需要的属性不同用户可以自定义属性。除了用户自定义属性有很多属性是标准属性 Linux 下的很多外设驱动都会使用这些标准属性本节我们就来学习一下几个常用的标准属性。2.3.1、compatible 属性compatible 属性也叫做“兼容性”属性这是非常重要的一个属性 compatible 属性的值是一个字符串列表 compatible 属性用于将设备和驱动绑定起来。一般驱动程序文件都会有一个 OF 匹配表此 OF 匹配表保存着一些 compatible 值如果设备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等那么就表示设备可以使用这个驱动。比如上面使用的i2c2的节点属性compatible rockchip,rk3576-i2c, rockchip,rk3399-i2c;表示芯片使用的是rockchip驱动模块是rk3576-i2c可以使用多个属性值后面也有rk3399-i2c。之后使用的时候会在驱动文件里查找对应的属性如果查找到了就会使用这个驱动文件2.3.2、model属性model 属性值也是一个字符串一般 model 属性描述开发板的名字或者设备模块信息但是没有实际用途一般是起个名字2.3.3、status 属性status 属性看名字就知道是和设备状态有关的 status 属性值也是字符串字符串是设备的状态信息比如okay表示已启用disable表示未启用不可操作2.3.4、#address-cells 和#size-cells 属性这两个属性的值都是无符号 32 位整形 #address-cells 和#size-cells 这两个属性可以用在任何拥有子节点的设备中用于描述子节点的地址信息。 #address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32 位) #size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)。 #address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值一般 reg 属性都是和地址有关的内容和地址相关的信息有两种起始地址和地址长度 reg 属性的格式为reg address1 length1 address2 length2 address3 length3……每个“address length”组合表示一个地址范围其中 address 是起始地址 length 是地址长度 #address-cells 表明 address 这个数据所占用的字长 #size-cells 表明 length 这个数据所占用的字长比如:#address-cells 1; #size-cells 0;说明节点 reg 属性中起始地址所占用的字长为 1地址长度所占用的字长为 0。所以当#size-cells 1则表示节点起始地址长度所占用的字长为 1地址长度所占用的字长也为 1。这时reg 0xff4e0000 0x4000;就表示设置了起始地址为 0xff4e0000地址长度为 0x4000。2.3.5、reg属性reg 属性的值一般是(address length)对。 reg 属性一般用于描述设备地址空间资源信息或者设备地址信息比如某个外设的寄存器地址范围信息或者 IIC器件的设备地址等2.3.6、ranges属性ranges属性值可以为空或者按照(child-bus-address,parent-bus-address,length)格式编写的数字矩阵 ranges 是一个地址映射/转换表 ranges 属性每个项目由子地址、父地址和地址空间长度这三部分组成child-bus-address子总线地址空间的物理地址由父节点的#address-cells 确定此物理地址所占用的字长。parent-bus-address 父总线地址空间的物理地址同样由父节点的#address-cells 确定此物理地址所占用的字长。length 子地址空间的长度由父节点的#size-cells 确定此地址长度所占用的字长。如果 ranges 属性值为空值说明子地址空间和父地址空间完全相同不需要进行地址转换2.4、根节点compatible 属性每个节点都有 compatible 属性根节点“/”也不例外比如说rk3576.dtsi中compatible rockchip,rk3576;Linux 内核会通过根节点的 compoatible 属性查看是否支持此设备如果支持的话设备就会启动 Linux 内核。2.5、节点的增改删除比如说前文的I2C2里就存在添加了子节点gt911_dsi注意这里添加不要在rk3576.dtsi文件里添加因为这里添加代表着全部使用rk3576的板子都会添加需要添加在自己的设备树文件添加就跟前面rk3576-custom.dtsi写的一样2.6、特殊节点在根节点“/”中有两个特殊的子节点 aliases 和 chosen我们接下来看一下这两个特殊的子节点aliases 节点的主要功能就是定义别名定义别名的目的就是为了方便访问节点。不过我们一般会在节点命名的时候会加上 label然后通过label 来访问节点。chosen 并不是一个真实的设备 chosen 节点主要是为了 uboot 向 Linux 内核传递数据重点是 bootargs 参数。一般.dts 文件中 chosen 节点通常为空或者内容很少3、设备树常用的OF操作函数设备树描述了设备的详细信息这些信息包括数字类型的、字符串类型的、数组类型的我们在编写驱动的时候需要获取到这些信息。 Linux 内核给我们提供了一系列的函数来获取设备树中的节点或者属性信息这一系列的函数都有一个统一的前缀“of_”所以在很多资料里面也被叫做 OF 函数。这些 OF 函数原型都定义在 include/linux/of.h 文件中3.1、查找节点的 OF 函数of_find_node_by_name 函数of_find_node_by_name 函数通过节点名字查找指定的节点函数原型如下struct device_node *of_find_node_by_name(struct device_node *from,const char *name);from开始查找的节点如果为 NULL 表示从根节点开始查找整个设备树。name要查找的节点名字。返回值 找到的节点如果为 NULL 表示查找失败。of_find_node_by_type 函数struct device_node *of_find_node_by_type(struct device_node *from, const char *type)通过 device_type 属性查找指定的节点of_find_compatible_node 函数struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compat)根据 device_type 和 compatible 这两个属性查找指定的节点of_find_matching_node_and_match 函数struct device_node *of_find_matching_node_and_match(struct device_node *from, const struct of_device_id *matches, const struct of_device_id **match)通过 of_device_id 匹配表来查找指定的节点of_find_node_by_path 函数inline struct device_node *of_find_node_by_path(const char *path)通过路径来查找指定的节点3.2、查找父/子节点的 OF 函数of_get_parent 函数获取指定节点的父节点(如果有父节点的话)struct device_node *of_get_parent(const struct device_node *node)of_get_next_child 函数用迭代的查找子节点struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev)node父节点prev前一个子节点也就是从哪一个子节点开始迭代的查找下一个子节点。可以设置为NULL表示从第一个子节点开始3.3、提取属性值的 OF 函数of_find_property 函数查找指定的属性struct property *of_find_property(const struct device_node *np, const char *name, int *lenp)np设备节点name属性名字lenp属性值的字节数返回值 找到的属性of_property_count_elems_of_size 函数获取属性中元素的数量比如 reg 属性值是一个数组那么使用此函数可以获取到这个数组的大小int of_property_count_elems_of_size(const struct device_node *np, const char *propname, int elem_size)np设备节点proname 需要统计元素数量的属性名字。elem_size元素长度。返回值 得到的属性元素数量of_property_read_u32_index 函数从属性中获取指定标号的 u32 类型数据值(无符号 32位)比如某个属性有多个 u32 类型的值那么就可以使用此函数来获取指定标号的数据值int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value)np设备节点。proname 要读取的属性名字index要读取的值标号。out_value读取到的值返回值 0 读取成功负值读取失败 -EINVAL 表示属性不存在 -ENODATA 表示没有要读取的数据 -EOVERFLOW 表示属性值列表太小。of_property_read_u8/16/32/64_array 函数分别是读取属性中 u8、 u16、 u32 和 u64 类型的数组数据比如大多数的 reg 属性都是数组数据可以使用这 4 个函数一次读取出 reg 属性中的所有数据int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz) int of_property_read_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz) int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz) int of_property_read_u64_array(const struct device_node *np, const char *propname, u64 *out_values, size_t sz)np设备节点proname 要读取的属性名字。out_value读取到的数组值分别为 u8、 u16、 u32 和 u64。sz 要读取的数组元素数量。返回值 0读取成功负值读取失败 -EINVAL 表示属性不存在 -ENODATA 表示没有要读取的数据 -EOVERFLOW 表示属性值列表太小of_property_read_u8/16/32/64函数这四个函数就是用于读取这种只有一个整形值的属性分别用于读取 u8、 u16、 u32 和 u64 类型属性值int of_property_read_u8(const struct device_node *np, const char *propname, u8 *out_value) int of_property_read_u16(const struct device_node *np, const char *propname, u16 *out_value) int of_property_read_u32(const struct device_node *np, const char *propname, u32 *out_value) int of_property_read_u64(const struct device_node *np, const char *propname, u64 *out_value)np设备节点。proname 要读取的属性名字。out_value读取到的数组值。返回值 0读取成功负值读取失败 -EINVAL 表示属性不存在 -ENODATA 表示没有要读取的数据 -EOVERFLOW 表示属性值列表太小。of_property_read_string 函数用于读取属性中字符串值int of_property_read_string(struct device_node *np, const char *propname, const char **out_string)np设备节点。proname 要读取的属性名字。out_string读取到的字符串值。返回值 0读取成功负值读取失败of_n_addr_cells 函数获取#address-cells 属性值int of_n_addr_cells(struct device_node *np)np设备节点。of_n_size_cells 函数获取#size-cells 属性值int of_n_size_cells(struct device_node *np)np设备节点。3.4、其他常用的 OF 函数of_device_is_compatible 函数用于查看节点的 compatible 属性是否有包含 name 指定的字符串也就是检查设备节点的兼容性int of_device_is_compatible(const struct device_node *device,const char *name)函数参数和返回值含义如下device设备节点。name要查看的字符串。返回值 0节点的 compatible 属性中不包含 name 指定的字符串正数节点的 compatible属性中包含 name 指定的字符串。of_get_address 函数用于获取地址相关属性主要是“reg”或者“assigned-addresses”属性值const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags)函数参数和返回值含义如下函数参数和返回值含义如下dev设备节点。index要读取的地址标号。size地址长度。flags参数比如 IORESOURCE_IO、 IORESOURCE_MEM 等返回值 读取到的地址数据首地址为 NULL 的话表示读取失败。of_translate_address 函数负责将从设备树读取到的物理地址转换为虚拟地址u64 of_translate_address(struct device_node *dev,const __be32 *addr)函数参数和返回值含义如下dev设备节点。in_addr要转换的地址。返回值 得到的物理地址如果为 OF_BAD_ADDR 的话表示转换失败。of_address_to_resource 函数提取 reg 属性值然后将其转换为 resource 结构体类型int of_address_to_resource(struct device_node *dev, int index, struct resource *r)函数参数和返回值含义如下dev设备节点。index地址资源标号。r得到的 resource 类型的资源值。返回值 0成功负值失败。of_iomap 函数of_iomap 函数用于直接内存映射以前我们会通过 ioremap 函数来完成物理地址到虚拟地址的映射采用设备树以后就可以直接通过 of_iomap 函数来获取内存地址所对应的虚拟地址不需要使用 ioremap 函数了void __iomem *of_iomap(struct device_node *np,int index)参数和返回值含义如下np设备节点。index reg 属性中要完成内存映射的段如果 reg 属性只有一段的话 index 就设置为 0。返回值 经过内存映射后的虚拟内存首地址如果为 NULL 的话表示内存映射失败。4、设备树驱动4.1、在设备树文件中创建相应的设备节点rk3576_gpio{ #address-cells 1; #size-cells 1; compatible rk3576_gpio_test; reg 0x0 0x2AE40000 0x0 0x00000004 0x0 0x2AE40008 0x0 0x00000004 0x0 0x26044084 0x0 0x00000004 0x0 0x26044140 0x0 0x00000004 0x0 0x26046140 0x0 0x00000004; status okay; };4.2、在驱动文件里使用设备树#include linux/init.h #include linux/module.h #include linux/fs.h #include linux/cdev.h #include linux/uaccess.h #include linux/types.h #include linux/kernel.h #include linux/delay.h #include linux/errno.h #include linux/gpio.h #include linux/of.h #include linux/of_address.h #include linux/of_gpio.h #include asm/io.h #include linux/device.h #include linux/platform_device.h //Pin Name是GPIO4_A4 #define DEV_CNT 1 #define DEV_NAME dtsgpio #define OUTPUT_HIGH 1 #define OUTPUT_LOW 0 static void __iomem *pVCCIO_IOC_GPIO4A_PULL; static void __iomem *pVCCIO_IOC_GPIO4A_DS_H; static void __iomem *pTOP_IOC_GPIO4A_IOMUX_SEL_H; static void __iomem *pGPIO4_DR_L; static void __iomem *pGPIO4_DDR_L; struct dtsgpio_dev{ dev_t devid; /* 设备号 */ struct cdev cdev; /* cdev */ struct class *class; /* 类 */ struct device *device; /* 设备 */ int major; /* 主设备号 */ int minor; /* 次设备号 */ struct device_node *nd;/* 设备节点 */ }; struct dtsgpio_dev dtsgpio; void gpio_switch(u8 sta) { u32 val 0; if(sta OUTPUT_HIGH) { val readl(pGPIO4_DR_L); val ~(0X1 4); /* bit0 清零*/ val | ((0X1 20) | (0X1 4)); writel(val, pGPIO4_DR_L); }else if(sta OUTPUT_LOW) { val readl(pGPIO4_DR_L); val ~(0X1 4); /* bit0 清零*/ val | ((0X1 20) | (0X0 4)); writel(val, pGPIO4_DR_L); } } static ssize_t gpio_chrdev_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { printk(gpio_chrdev_read!\r\n); return 0; } static ssize_t gpio_chrdev_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { int retvalue; unsigned char databuf[1]; unsigned char stat; printk(gpio_chrdev_write!\r\n); retvalue copy_from_user(databuf, buf, cnt); if(retvalue 0) { printk(kernel write failed!\r\n); return -EFAULT; } stat databuf[0]; /* 获取状态值 */ printk(gpio_chrdev_write,stat %d\r\n, stat); if(stat OUTPUT_HIGH) { printk(gpio_chrdev_write,OUTPUT_HIGH\r\n); gpio_switch(OUTPUT_HIGH); } else if(stat OUTPUT_LOW) { printk(gpio_chrdev_write,OUTPUT_LOW\r\n); gpio_switch(OUTPUT_LOW); } return 0; } static int gpio_chrdev_open(struct inode *inode, struct file *filp) { printk(gpio_chrdev_open!\r\n); filp-private_data dtsgpio; /* 设置私有数据 */ return 0; } static int gpio_chrdev_release(struct inode *inode, struct file *filp) { printk(gpio_chrdev_release!\r\n); return 0; } static struct file_operations gpio_chrdev_fops { .owner THIS_MODULE, .open gpio_chrdev_open, .release gpio_chrdev_release, .write gpio_chrdev_write, .read gpio_chrdev_read, }; void gpio_unmap(void) { /* 取消映射 */ iounmap(pVCCIO_IOC_GPIO4A_PULL); iounmap(pVCCIO_IOC_GPIO4A_DS_H); iounmap(pTOP_IOC_GPIO4A_IOMUX_SEL_H); iounmap(pGPIO4_DR_L); iounmap(pGPIO4_DDR_L); } static int __init gpio_dts_init(void) { u32 val 0; int ret; u32 regdata[16]; const char *str; struct property *proper; dtsgpio.nd of_find_node_by_path(/rk3576_gpio); if(dtsgpio.nd NULL) { printk(rk3576_gpio node not find!\r\n); return 1; } else { printk(rk3576_gpio node find!\r\n); } /* 2、获取 compatible 属性内容 */ proper of_find_property(dtsgpio.nd, compatible, NULL); if(proper NULL) { printk(compatible property find failed\r\n); return 1; } else { printk(compatible %s\r\n, (char*)proper-value); } /* 3、获取 status 属性内容 */ ret of_property_read_string(dtsgpio.nd, status, str); if(ret 0){ printk(status read failed!\r\n); return 1; } else { printk(status %s\r\n,str); } /* 4、获取 reg 属性内容 */ ret of_property_read_u32_array(dtsgpio.nd, reg, regdata, 10); if(ret 0) { printk(reg property read failed!\r\n); return 1; } else { u8 i 0; printk(reg data:\r\n); for(i 0; i 10; i) printk(%#X , regdata[i]); printk(\r\n); } pGPIO4_DR_L of_iomap(dtsgpio.nd, 0); pGPIO4_DDR_L of_iomap(dtsgpio.nd, 1); pTOP_IOC_GPIO4A_IOMUX_SEL_H of_iomap(dtsgpio.nd, 2); pVCCIO_IOC_GPIO4A_DS_H of_iomap(dtsgpio.nd, 3); pVCCIO_IOC_GPIO4A_PULL of_iomap(dtsgpio.nd, 4); val readl(pTOP_IOC_GPIO4A_IOMUX_SEL_H); printk(of_iomap 7!\r\n); val ~(0XF 0); val | ((0XF 16) | (0X0 0)); printk(of_iomap 8!\r\n); writel(val, pTOP_IOC_GPIO4A_IOMUX_SEL_H); printk(of_iomap 9!\r\n); /* 设置 GPIO4_A4 驱动能力为 level5 */ val readl(pVCCIO_IOC_GPIO4A_DS_H); printk(of_iomap 10!\r\n); val ~(0X7 0); val | ((0X7 16) | (0X5 0)); writel(val, pVCCIO_IOC_GPIO4A_DS_H); /* 设置上下拉 */ val readl(pVCCIO_IOC_GPIO4A_PULL); val ~(0X3 8); val | ((0X3 24) | (0X1 8)); writel(val, pVCCIO_IOC_GPIO4A_PULL); /* 设置为输出 */ val readl(pGPIO4_DDR_L); val ~(0X1 4); val | ((0X1 20) | (0X1 4)); writel(val, pGPIO4_DDR_L); /* 设置 默认输出低电平 */ val readl(pGPIO4_DR_L); val ~(0X1 4); val | ((0X1 20) | (0X0 4)); writel(val, pGPIO4_DR_L); printk(of_iomap 11!\r\n); ret alloc_chrdev_region(dtsgpio.devid,0,DEV_CNT,DEV_NAME); if(ret 0){ printk(%s alloc_chrdev_region fail,ret %d\r\n, DEV_NAME,ret); return 1; } dtsgpio.major MAJOR(dtsgpio.devid);/* 获取主设备号 */ dtsgpio.minor MINOR(dtsgpio.devid);/* 获取次设备号 */ printk(dtsgpio.devid%d\r\n,dtsgpio.devid); printk(dtsgpio major%d,minor%d\r\n,dtsgpio.major,dtsgpio.minor); cdev_init(dtsgpio.cdev, gpio_chrdev_fops); dtsgpio.cdev.owner THIS_MODULE; ret cdev_add(dtsgpio.cdev, dtsgpio.devid,DEV_CNT); if(ret 0){ printk(%s cdev_add fail,ret %d\r\n, DEV_NAME,ret); return 1; } /* 4、创建类 */ dtsgpio.class class_create(THIS_MODULE, DEV_NAME); if (IS_ERR(dtsgpio.class)) { printk(%s class_create fail\r\n, DEV_NAME); return 1; } /* 5、创建设备 */ dtsgpio.device device_create(dtsgpio.class, NULL, dtsgpio.devid, NULL, DEV_NAME); if (IS_ERR(dtsgpio.device)) { printk(%s device_create fail\r\n, DEV_NAME); return 1; } return 0; } module_init(gpio_dts_init); static void __exit gpio_dts_exit(void) { /* 取消映射 */ gpio_unmap(); /* 注销字符设备驱动 */ cdev_del(dtsgpio.cdev);/* 删除 cdev */ unregister_chrdev_region(dtsgpio.devid, DEV_CNT); device_destroy(dtsgpio.class, dtsgpio.devid); class_destroy(dtsgpio.class); } module_exit(gpio_dts_exit); MODULE_LICENSE(GPL);4.3、应用程序App#include stdio.h #include unistd.h #include fcntl.h #include string.h int main(int argc, char *argv[]) { printf(led_tiny test\n); /*判断输入的命令是否合法*/ if(argc ! 2) { printf( command error ! \n); printf( usage : sudo test_app num [num can be 0 or 1]\n); return -1; } /*打开文件*/ int fd open(/dev/dtsgpio, O_RDWR); if(fd 0) { printf(open file : %s failed !\n, argv[0]); return -1; } unsigned char command atoi(argv[1]); //将受到的命令值转化为数字; /*写入命令*/ int error write(fd,command,sizeof(command)); if(error 0) { printf(write file error! \n); close(fd); /*判断是否关闭成功*/ } /*关闭文件*/ error close(fd); if(error 0) { printf(close file error! \n); } return 0; }

相关文章:

rk3576(5)之设备树下GPIO驱动

1、简介rk3576buildroot设备树GPIO驱动编写。个人理解设备树就相当于存在统一规则、统一管理的头文件,记录了开发板的设备信息。2、设备树语法2.1、dtsi 头文件设备树也支持头文件,设备树的头文件扩展名为.dtsi设备树文件不仅可以应用 C 语言里面的.h 头…...

OpenGL渲染与几何内核那点事-项目实践理论补充(二-1-(1):当你的CAD学会“想象”:图形技术与AI融合的三个层次)

TOC 代码仓库入口: github源码地址。gitee源码地址。 系列文章规划: (OpenGL渲染与几何内核那点事-项目实践理论补充(一-1-(1):从开发的视角看下CAD画出那些好看的图形们))OpenGL渲染与几何内核那点事-项…...

如何通过智慧树自动化学习助手解决网课学习效率问题

如何通过智慧树自动化学习助手解决网课学习效率问题 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 副标题:面向时间紧张学习者的智能网课辅助工具 一、价…...

电机轴承异响?5分钟教你用振动分析仪定位故障(附实测案例)

电机轴承异响诊断实战:振动分析仪操作全流程解析 轴承异响是工业现场最常见的电机故障之一,但很多维护工程师面对"嗡嗡"声或"咔嗒"响往往无从下手。上周某化工厂的水泵电机就因轴承早期磨损未被及时发现,导致整机报废&am…...

美国低值包裹政策收紧后跨境卖家如何重做运营安全底盘

暗流涌动:跨境物流变局下的生存法则清晨,深圳华强北的某个跨境工作室里,键盘敲击声此起彼伏。屏幕上的订单如往常一样跳动,但运营负责人李薇的眉头却紧锁着。她刚刚收到物流服务商的紧急通知:一批通过“低值货物”通道…...

SEO_快速诊断并解决网站SEO问题的常见方法(164 )

快速诊断网站SEO问题的有效方法 在当今数字化时代,网站的SEO(搜索引擎优化)问题不仅关乎网站的流量,更直接影响到业务的发展。对于许多网站来说,SEO问题往往是隐藏在表面现象背后的复杂问题。因此,快速诊断…...

OpenClaw压力测试:千问3.5-9B持续运行24小时稳定性

OpenClaw压力测试:千问3.5-9B持续运行24小时稳定性 1. 为什么需要压力测试? 上周我在本地部署了OpenClaw千问3.5-9B组合,想用它自动处理一些日常文档整理工作。最初几小时运行很顺畅,但第二天早上发现系统卡死了——这让我意识到…...

如何基于OpenAI进行Function Calling调用

基于LLM进行工具调用或技能执行,是近期最热门的话题之一。 目前已经有很多LLM工具调用框架,比如langchain、openclaw、owl等。 然而,工具调用过程一般被封装在框架内,用户一般只能接触到各种配置,窥探不到调用细节。…...

构建编译环境

拉取LLVM并配置这里我保存在D盘#创建文件夹 mkdir D:\LLVM cd D:\LLVM #拉取源码 (只拉取核心仓库,不需要 submodule,现在 LLVM 是 monorepo) #这一步比较大,网络不好请挂梯子 git clone --depth1 https://github.com/llvm/llvm-project.…...

仅用200行代码重构内存管理模块:某AI平台将GPU服务器月成本压至$1,840的独家策略(限时开源)

第一章:Python 智能体内存管理策略Python 的内存管理并非由开发者直接操控,而是由解释器内置的智能体协同完成——包括引用计数、循环垃圾回收器(GC)和内存池机制三者构成动态平衡系统。这一“智能体”在运行时持续感知对象生命周…...

代码分享】“基因集单通路的泛癌GSEA富集分析

【代码分享]基因集单通路的泛癌GSEA富集分析#资料 如图最近在整理TCGA多组学数据时,发现不少小伙伴对通路活性评估有需求。今天分享一个快速实现泛癌GSEA分析的方法,特别适合需要观察某个特定通路在多个癌症类型中激活状态的情况。这个方法不需要复杂的编…...

基于机器学习算法的亚马逊用户评论情感分析研究:深入探讨随机森林与决策树模型的应用及其实验评估

《基于随机森林和决策树的亚马逊用户评论情感分析研究》深入探讨了利用机器学习技术对亚马逊用户评论数据进行情感分析的方法,旨在为电商企业提供更精准的用户反馈处理工具,以辅助产品优化和服务改进 通过采用决策树模型和随机森林模型这两种不同的机器学…...

工业冷水机控制程序西门子1200plc含压缩机,电子膨胀阀控制策略,饱和温度计算公式

工业冷水机控制程序西门子1200plc含压缩机,电子膨胀阀控制策略,饱和温度计算公式凌晨三点钟的冷水机组房,设备轰鸣声中闪烁着PLC运行指示灯。手指划过TP1200触摸屏的瞬间,压缩机启动电流曲线在屏幕上划出漂亮的爬坡轨迹——这就是…...

TI SAR ADC模型(Matlab) 包含各类非理想因素,时钟偏差,增益偏差

TI SAR ADC模型(Matlab) 包含各类非理想因素,时钟偏差,增益偏差,失调偏差 模型参数均可自由设置直接上干货吧,今天聊聊怎么用Matlab折腾带非理想特性的SAR ADC模型。玩过ADC的都知道,现实中的转…...

如何实现 SEO 优化与广告投放的协同效果

如何实现 SEO 优化与广告投放的协同效果 在当今竞争激烈的互联网环境中,实现 SEO 优化与广告投放的协同效果已经成为提升网站流量和销售转化的关键。SEO(搜索引擎优化)和广告投放虽然各自有各自的目标和优势,但它们的结合能够带来…...

飞机喷涂废气治理厂家丨一场看不见的“废气治理战”如何打响?

你有没有注意过,当你透过舷窗望向停机坪时,那些静静停靠的飞机,机身光洁如镜,涂装色彩鲜明?一架飞机交付使用,到每隔数年的定期大修,飞机都需要经历复杂的喷涂过程。这层看似简单的“外衣”&…...

AI 生码:RAG 落地量化实践与体系搭建

一、背景:前端 AI 落地,RAG 成为核心关键 在前端与 AI 融合落地过程中,AI 生成 UI 代码、业务测试用例等核心场景,均依赖知识库能力支撑。当应用进入深水区,RAG(检索增强生成)的选型与优化&…...

Claude Code 源码研究【第二弹】:智能体框架与大模型相互成就

在上一篇“Claude Code 源码研究:一个 while(true) 循环让大模型自己干活”之后,继续我们的研究——01自然语言引导能保证模型每次都听话吗?Claude Code 不靠 if-else 控制模型选哪个工具,而是靠 40 份精心撰写的"工具说明书…...

智能家庭教育:OpenClaw+Phi-3-vision-128k-instruct批改孩子手写作业

智能家庭教育:OpenClawPhi-3-vision-128k-instruct批改孩子手写作业 1. 为什么需要AI作业批改助手 作为一个经常辅导孩子功课的家长,我深刻体会到批改作业的痛点。每天晚上检查数学题时,既要核对答案正确性,又要分析错误原因&am…...

OpenClaw二次开发:基于Qwen3.5-9B定制个性化技能模块

OpenClaw二次开发:基于Qwen3.5-9B定制个性化技能模块 1. 为什么需要自定义技能模块 去年冬天,我发现自己每天早晨都要手动查询天气来决定穿什么衣服。作为一个技术爱好者,我开始思考:能否让OpenClaw自动完成这个任务&#xff1f…...

WarcraftHelper:让魔兽争霸III重获新生的兼容性优化工具

WarcraftHelper:让魔兽争霸III重获新生的兼容性优化工具 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper WarcraftHelper是一款免费开源的魔…...

2026年最新codex 第三方 api 配置指南

真正决定 Codex 能不能顺利进入项目的,通常不是 npm 命令有没有跑完,而是 codex 第三方 api 是否配完整。很多人在 openai/codex 安装结束后马上就碰到 401、请求超时、模型不可用,甚至一直过不了认证,这类问题大多都落在 ~/.code…...

SEO_10个提升网站排名的SEO技巧与实战方法

SEO:10个提升网站排名的SEO技巧与实战方法 在当今数字化时代,网站排名不仅关乎网站的曝光率,更影响到业务的发展。因此,提升网站排名(SEO)成为了每一个网站主的首要任务。有哪些SEO技巧能够帮助提升网站的排名呢&…...

07_Cursor之语言支持与扩展生态

关键字:语言支持, VS Code扩展, 跨平台, Electron, Python开发, 扩展生态 07_Cursor之语言支持与扩展生态 Cursor知识体系 Cursor知识体系(续) | -- 生态支持层 | -- 多语言支持 | | -- 通用LLM支持 | | -- 自动语言检测 | | …...

SEO_ 详解SEO优化中内容与外部链接的建设策略

SEO优化中内容与外部链接的建设策略 在当前互联网营销领域,SEO优化(搜索引擎优化)是提升网站流量和品牌知名度的关键手段。其中,内容与外部链接的建设策略是两大核心要素。本文将详解SEO优化中内容与外部链接的建设策略&#xff…...

OpenClaw家庭相册:Qwen3.5-9B-VL自动识别人物与场景分类

OpenClaw家庭相册:Qwen3.5-9B-VL自动识别人物与场景分类 1. 为什么需要智能相册管理 作为一个摄影爱好者和两个孩子的父亲,我的手机和硬盘里堆积了超过5万张家庭照片。每次想找特定场景(比如"去年夏天在海边的全家福"&#xff09…...

长尾关键词的SEO提交技巧有哪些

长尾关键词的SEO提交技巧有哪些 在当今数字营销的环境中,SEO(搜索引擎优化)是提升网站流量的关键手段之一。而在SEO策略中,长尾关键词(Long-Tail Keywords)的应用尤为重要。长尾关键词通常是由三个或更多的…...

OpenClaw环境隔离方案:Phi-3-vision-128k-instruct多模态任务专用沙箱配置

OpenClaw环境隔离方案:Phi-3-vision-128k-instruct多模态任务专用沙箱配置 1. 为什么需要环境隔离? 去年我在尝试用OpenClaw处理一批包含敏感客户数据的PDF文件时,曾因为一个错误的鼠标操作指令导致系统临时文件被意外删除。那次经历让我意…...

OpenClaw配置文件详解:Qwen3.5-9B高级参数调优手册

OpenClaw配置文件详解:Qwen3.5-9B高级参数调优手册 1. 为什么需要手动调优OpenClaw配置 上周我尝试用OpenClaw自动处理一批技术文档的归档工作,发现同样的任务在不同时段完成速度差异巨大。有时30分钟就能搞定,有时却要卡顿近2小时。这促使…...

Hotkey Detective:定位并解决Windows快捷键冲突的终极方案

Hotkey Detective:定位并解决Windows快捷键冲突的终极方案 【免费下载链接】hotkey-detective A small program for investigating stolen key combinations under Windows 7 and later. 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective 一、…...