RK3566(泰山派):GP7101背光驱动

RK3566(泰山派):GP7101背光驱动


文章目录

  • RK3566(泰山派):GP7101背光驱动
  • GP7101背光驱动电路
  • 配置i2c1设备树
  • 创建驱动
  • 编写Makefile
  • gp7101_bl.c驱动
    • 触摸I2C驱动框架。
    • 驱动中的结构体
    • probe函数
    • devm_backlight_device_register函数
  • gp7101_backlight_set函数
    • i2c_write
    • 注释backlight
  • GP7101背光完整驱动代码
  • 编译生效


GP7101背光驱动电路

调试屏幕我们一般会先把背光点亮如果使用的是泰山派的背光电路那直接使用代码里面默认的背光PWM驱动就行,但为了保护屏幕背光我们选择的是扩展板上的板载背光电路给3.1寸屏幕背光供电,扩展板板载背光电路PWM脚是通过GP7101 i2C转PWM芯片实现。所以我们需要编写一个GP7101驱动。
背光选择电路

背光选择电路
GP7101 I2C转PWM电路

硬件3.1寸mipi屏幕背光电路

配置i2c1设备树

从原理图中可知GP7101和触摸共同挂在道I2C下,从数据手册中我们可以得知GP7101的I2C地址是10110000,即0XB0,0xB0是包含了读写位的所以我们实际填写中还需要右移一位最终地址为01011000,即0X58。
在这里插入图片描述


tspi-rk3566-dsi-v10.dtsi中添加GP7101相关设备树驱动,首先引用I2C1并往设备树I2C1节点中添加GP7101子节点并指定I2C地址、最大背光,默认背光等。

/home/paranoid/tspi/android/kernel/arch/arm64/boot/dts/rockchip/tspi-rk3566-dsi-v10.dtsi
&i2c1 {              // 引用名为i2c1的节点  status = "okay"; // 状态为"okay",表示此节点是可用和配置正确的  GP7101@58 {      // 定义一个子节点,名字为GP7101,地址为58  compatible = "gp7101-backlight";   // 该节点与"gp7101-backlight"兼容,  reg = <0x58>;                      // GP7101地址0x58  max-brightness-levels = <255>;     // 背光亮度的最大级别是255  default-brightness-level = <100>;  // 默认的背光亮度级别是100  };  
};

在这里插入图片描述

创建驱动

一般背光驱动都放在/kernel/drivers/video/backlight目录下,所以我们在此路径下创建一个my_gp7101_bl目录用来存放Makefile和gp7101_bl.c文件。

cd kernel/drivers/video/backlight
mkdir my_gp7101_bl
cd my_gp7101_bl/
touch Makefile
touch gp7101_bl.c

在这里插入图片描述

编写Makefile

my_gp7101_bl/Makefile中把gp7101_bl.c编译到内核中,当然也可以选择obj-m编译成模块。

/home/paranoid/tspi/android/kernel/drivers/video/backlight/my_gp7101_bl/Makefile
obj-y   += gp7101_bl.o

在这里插入图片描述

要想
my_gp7101_bl下的Makefile生效还需要在上一层目录的Makefile中添加my_gp7101_bl目录,所以我们需要在backlight目录下Makefile中加入:

/home/paranoid/tspi/android/kernel/drivers/video/backlight/Makefile
obj-y += my_gp7101_bl/

在这里插入图片描述

gp7101_bl.c驱动

I2C驱动框架

触摸I2C驱动框架。

#include "linux/stddef.h"
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/input/mt.h>
#include <linux/random.h>#if 1
#define MY_DEBUG(fmt,arg...)  printk("gp7101_bl:%s %d "fmt"",__FUNCTION__,__LINE__,##arg);
#else
#define MY_DEBUG(fmt,arg...)
#endif#define BACKLIGHT_NAMEstatic int gp7101_bl_probe(struct i2c_client *client,const struct i2c_device_id *id)
{MY_DEBUG("locat");return 0;
}static int gp7101_bl_remove(struct i2c_client *client)
{MY_DEBUG("locat");return 0;
}static const struct of_device_id gp7101_bl_of_match[] = {{ .compatible = BACKLIGHT_NAME, },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, gp7101_bl_of_match);static struct i2c_driver gp7101_bl_driver = {.probe      = gp7101_bl_probe,.remove     = gp7101_bl_remove,.driver = {.name     = BACKLIGHT_NAME,.of_match_table = of_match_ptr(gp7101_bl_of_match),},
};static int __init my_init(void)
{MY_DEBUG("locat");return i2c_add_driver(&gp7101_bl_driver);
}static void __exit my_exit(void)
{MY_DEBUG("locat");i2c_del_driver(&gp7101_bl_driver);
}module_init(my_init);
module_exit(my_exit);MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("My touch driver");
MODULE_AUTHOR("KuLiT");

驱动中的结构体

因为驱动过程中会有很多参数,我们不可能创建全局变量去保存他们,在linux驱动中一般都是通过创建一个结构体来保存驱动相关的参数,所以这里我创建一个gp7101_backlight_data结构体。

/* 背光控制器设备数据结构 */
struct gp7101_backlight_data {/* 指向一个i2c_client结构体的指针*/struct i2c_client *client;/*......其他成员后面有用到再添加........*/
};

probe函数

当驱动中of_match_table = of_match_ptr(gp7101_bl_of_match)和设备树匹配成功以后会执行探针函数,探针函数中我们会去初始化驱动。

// gp7101_bl_probe - 探测函数,当I2C总线上的设备与驱动匹配时会被调用
static int gp7101_bl_probe(struct i2c_client *client,const struct i2c_device_id *id)
{struct backlight_device *bl; // backlight_device结构用于表示背光设备struct gp7101_backlight_data *data; // 自定义的背光数据结构struct backlight_properties props; // 背光设备的属性struct device_node *np = client->dev.of_node; // 设备树中的节点MY_DEBUG("locat"); // 打印调试信息// 为背光数据结构动态分配内存data = devm_kzalloc(&client->dev, sizeof(struct gp7101_backlight_data), GFP_KERNEL);if (data == NULL){dev_err(&client->dev, "Alloc GFP_KERNEL memory failed."); // 内存分配失败,打印错误信息return -ENOMEM; // 返回内存分配错误码} // 初始化背光属性结构memset(&props, 0, sizeof(props));props.type = BACKLIGHT_RAW; // 设置背光类型为原始类型props.max_brightness = 255; // 设置最大亮度为255// 从设备树中读取最大亮度级别of_property_read_u32(np, "max-brightness-levels", &props.max_brightness);// 从设备树中读取默认亮度级别of_property_read_u32(np, "default-brightness-level", &props.brightness);// 确保亮度值在有效范围内if(props.max_brightness>255 || props.max_brightness<0){props.max_brightness = 255;}if(props.brightness>props.max_brightness || props.brightness<0){props.brightness = props.max_brightness;}// 注册背光设备bl = devm_backlight_device_register(&client->dev, "backlight", &client->dev, data, &gp7101_backlight_ops,&props);if (IS_ERR(bl)) {dev_err(&client->dev, "failed to register backlight device\n"); // 注册失败,打印错误信息return PTR_ERR(bl); // 返回错误码}data->client = client; // 保存i2c_client指针i2c_set_clientdata(client, data); // 设置i2c_client的客户端数据MY_DEBUG("max_brightness:%d brightness:%d",props.max_brightness, props.brightness); // 打印最大亮度和当前亮度backlight_update_status(bl); // 更新背光设备的状态return 0; // 返回成功
}

devm_backlight_device_register函数

devm_backlight_device_register这个函数非常重要,他是 Linux 内核中用于动态注册背光设备的一个函数。前缀带devm的一般都会在设备被销毁时自动释放相关资源,无需手动调用 backlight_device_unregister。这个函数的主要作用是创建并注册一个 backlight_device 实例,这个实例代表了系统中的一个背光设备。背光设备通常用于控制显示屏的亮度。函数原型如下:

struct backlight_device *devm_backlight_device_register(struct device *dev, const char *name, struct device *parent,void *devdata, const struct backlight_ops *ops,const struct backlight_properties *props);

参数说明:

  • dev:指向父设备的指针,通常是一个 struct i2c_client 或 struct platform_device。
  • name:背光设备的名称。
  • parent:背光设备的父设备,通常与 dev 参数相同。
  • devdata:私有数据,会被传递给背光操作函数。
  • ops:指向 backlight_ops 结构的指针,这个结构定义了背光设备的行为,包括设置亮度、获取亮度等操作。
  • props:指向 backlight_properties 结构的指针,这个结构包含了背光设备的属性,如最大亮度、当前亮度等。
    gp7101_backlight_ops结构体ops参数非常重要,因为我们就是通过这个参数指向的结构成员中的函数去实现获取背光更新背光的。函数的原型如下:
struct backlight_ops {unsigned int options;#define BL_CORE_SUSPENDRESUME   (1 << 0)/* Notify the backlight driver some property has changed */int (*update_status)(struct backlight_device *);/* Return the current backlight brightness (accounting for power,fb_blank etc.) */int (*get_brightness)(struct backlight_device *);/* Check if given framebuffer device is the one bound to this backlight;return 0 if not, !=0 if it is. If NULL, backlight always matches the fb. */int (*check_fb)(struct backlight_device *, struct fb_info *);
};

通过backlight_ops定义了一个名为gp7101_backlight_ops的backlight_ops结构体实例,并且只初始化了.update_status成员,它指向了一个名为
gp7101_backlight_set的函数,这个函数负责更新背光设备的亮度状态。

static struct backlight_ops gp7101_backlight_ops = {.update_status = gp7101_backlight_set,
};

gp7101_backlight_set函数

这就是我们更新背光的核心函数了,每次背光被改动的时候系统都会回调这个函数,在函数中我们通过I2C1去写GP7101实现修改背光。GP7101两种操作方法第一种是8位PWM,第二种是16位数PWM,刚好我们背光是从0~255所以,我们就选择8位PWM,八位PWM模式需要写寄存器0x03。
在这里插入图片描述

/* I2C 背光控制器寄存器定义 */
#define BACKLIGHT_REG_CTRL_8  0x03  
#define BACKLIGHT_REG_CTRL_16 0x02
/* 设置背光亮度 */
static int gp7101_backlight_set(struct backlight_device *bl)
{struct gp7101_backlight_data *data = bl_get_data(bl);  // 获取背光数据结构指针struct i2c_client *client = data->client;  // 获取I2C设备指针u8 addr[1] = {BACKLIGHT_REG_CTRL_8};  // 定义I2C地址数组u8 buf[1] = {bl->props.brightness};  // 定义数据缓冲区,用于存储背光亮度值MY_DEBUG("pwm:%d", bl->props.brightness);  // 输出背光亮度值// 将背光亮度值写入设备i2c_write(client, addr, sizeof(addr), buf, sizeof(buf));return 0;  // 返回成功
}

i2c_write

触摸驱动I2C写函数。

s32 i2c_write(struct i2c_client *client, u8 *addr, u8 addr_len, u8 *buf, s32 len)
{struct i2c_msg msg; // 定义i2c消息结构,用于传输数据s32 ret = -1; // 初始化返回值为-1,表示失败u8 *temp_buf; // 定义临时缓冲区指针msg.flags = !I2C_M_RD; // 标志位,表示写操作msg.addr = client->addr; // 设备地址msg.len = len + addr_len; // 写入数据的总长度(地址长度+数据长度)// 分配临时缓冲区temp_buf = kzalloc(msg.len, GFP_KERNEL);if (!temp_buf) {goto error; // 如果分配失败,跳转到错误处理}// 装填地址到临时缓冲区memcpy(temp_buf, addr, addr_len);// 装填数据到临时缓冲区(紧随地址之后)memcpy(temp_buf + addr_len, buf, len);msg.buf = temp_buf; // 设置消息的缓冲区为临时缓冲区// 发送消息并写入数据ret = i2c_transfer(client->adapter, &msg, 1);if (ret == 1) {kfree(temp_buf); // 释放临时缓冲区return 0; // 如果消息成功传输,返回0表示成功}error:// 如果写入失败,打印错误信息if (addr_len == 2) {MY_DEBUG("I2C Write: 0x%04X, %d bytes failed, errcode: %d! Process reset.", (((u16)(addr[0] << 8)) | addr[1]), len, ret);} else {MY_DEBUG("I2C Write: 0x%02X, %d bytes failed, errcode: %d! Process reset.", addr[0], len, ret);}if (temp_buf) {kfree(temp_buf); // 释放临时缓冲区}return -1; // 返回-1表示失败
}

注释backlight

因为我们之前的背光驱动也是用的"backlight"节点,为了不去修改上层我们自己写的驱动也是用的"backlight"节点所以两个节点会冲突,所以我们在tspi-rk3566-dsi-v10.dtsi中把之前的屏蔽掉留下我们自己写的驱动。屏蔽原有背光设备树节点。

/ {/*backlight: backlight {compatible = "pwm-backlight";pwms = <&pwm5 0 25000 0>;brightness-levels = <0  20  20  21  21  22  22  2323  24  24  25  25  26  26  2727  28  28  29  29  30  30  3131  32  32  33  33  34  34  3535  36  36  37  37  38  38  3940  41  42  43  44  45  46  4748  49  50  51  52  53  54  5556  57  58  59  60  61  62  6364  65  66  67  68  69  70  7172  73  74  75  76  77  78  7980  81  82  83  84  85  86  8788  89  90  91  92  93  94  9596  97  98  99 100 101 102 103104 105 106 107 108 109 110 111112 113 114 115 116 117 118 119120 121 122 123 124 125 126 127128 129 130 131 132 133 134 135136 137 138 139 140 141 142 143144 145 146 147 148 149 150 151152 153 154 155 156 157 158 159160 161 162 163 164 165 166 167168 169 170 171 172 173 174 175176 177 178 179 180 181 182 183184 185 186 187 188 189 190 191192 193 194 195 196 197 198 199200 201 202 203 204 205 206 207208 209 210 211 212 213 214 215216 217 218 219 220 221 222 223224 225 226 227 228 229 230 231232 233 234 235 236 237 238 239240 241 242 243 244 245 246 247248 249 250 251 252 253 254 255>;default-brightness-level = <255>;};*/
};

在这里插入图片描述

在dsi1中也需要屏蔽掉否则找不到引用节点编译时候会报错。

&dsi1 {status = "okay";rockchip,lane-rate = <1000>;dsi1_panel: panel@0 {/*省略*/// backlight = <&backlight>;/*省略*/}}

在这里插入图片描述

GP7101背光完整驱动代码

#include "linux/stddef.h"
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/input/mt.h>
#include <linux/random.h>
#include <linux/backlight.h>#if 1
#define MY_DEBUG(fmt,arg...)  printk("gp7101_bl:%s %d "fmt"",__FUNCTION__,__LINE__,##arg);
#else
#define MY_DEBUG(fmt,arg...)
#endif#define BACKLIGHT_NAME "gp7101-backlight"/* I2C 背光控制器寄存器定义 */
#define BACKLIGHT_REG_CTRL_8  0x03  
#define BACKLIGHT_REG_CTRL_16 0x02/* 背光控制器设备数据结构 */
struct gp7101_backlight_data {struct i2c_client *client;};s32 i2c_read(struct i2c_client *client,u8 *addr,u8 addr_len, u8 *buf, s32 len)
{struct i2c_msg msgs[2];s32 ret=-1;msgs[0].flags = !I2C_M_RD;msgs[0].addr  = client->addr;msgs[0].len   = addr_len;msgs[0].buf   = &addr[0];msgs[1].flags = I2C_M_RD;msgs[1].addr  = client->addr;msgs[1].len   = len;msgs[1].buf   = &buf[0];ret = i2c_transfer(client->adapter, msgs, 2);if(ret == 2)return 0;if(addr_len == 2){MY_DEBUG("I2C Read: 0x%04X, %d bytes failed, errcode: %d! Process reset.", (((u16)(addr[0] << 8)) | addr[1]), len, ret);}else {MY_DEBUG("I2C Read: 0x%02X, %d bytes failed, errcode: %d! Process reset.", addr[0], len, ret);}return -1;
}s32 i2c_write(struct i2c_client *client, u8 *addr, u8 addr_len, u8 *buf,s32 len)
{struct i2c_msg msg;s32 ret = -1;u8 *temp_buf;msg.flags = !I2C_M_RD;msg.addr  = client->addr;msg.len   = len+addr_len;temp_buf= kzalloc(msg.len, GFP_KERNEL);if (!temp_buf){goto error;}// 装填地址memcpy(temp_buf, addr, addr_len);// 装填数据memcpy(temp_buf + addr_len, buf, len);msg.buf = temp_buf;ret = i2c_transfer(client->adapter, &msg, 1);if (ret == 1) {kfree(temp_buf);return 0;}error:if(addr_len == 2){MY_DEBUG("I2C Read: 0x%04X, %d bytes failed, errcode: %d! Process reset.", (((u16)(addr[0] << 8)) | addr[1]), len, ret);}else {MY_DEBUG("I2C Read: 0x%02X, %d bytes failed, errcode: %d! Process reset.", addr[0], len, ret);}if (temp_buf)kfree(temp_buf);return -1;
}/* 设置背光亮度 */
static int gp7101_backlight_set(struct backlight_device *bl)
{struct gp7101_backlight_data *data = bl_get_data(bl);struct i2c_client *client = data->client;u8 addr[1] = {BACKLIGHT_REG_CTRL_8};u8 buf[1] = {bl->props.brightness}; MY_DEBUG("pwm:%d", bl->props.brightness);i2c_write(client, addr, sizeof(addr), buf, sizeof(buf));return 0;
}/* 背光设备操作函数 */
static struct backlight_ops gp7101_backlight_ops = {.update_status = gp7101_backlight_set,
};static int gp7101_bl_probe(struct i2c_client *client,const struct i2c_device_id *id)
{struct backlight_device *bl;struct gp7101_backlight_data *data;struct backlight_properties props;struct device_node *np = client->dev.of_node;MY_DEBUG("locat");data = devm_kzalloc(&client->dev, sizeof(struct gp7101_backlight_data), GFP_KERNEL);if (data == NULL){dev_err(&client->dev, "Alloc GFP_KERNEL memory failed.");return -ENOMEM;} memset(&props, 0, sizeof(props));props.type = BACKLIGHT_RAW;props.max_brightness = 255; of_property_read_u32(np, "max-brightness-levels",&props.max_brightness);of_property_read_u32(np, "default-brightness-level", &props.brightness);if(props.max_brightness>255 || props.max_brightness<0){props.max_brightness = 255;}if(props.brightness>props.max_brightness || props.brightness<0){props.brightness = props.max_brightness;}/* 初始化背光设备 */bl = devm_backlight_device_register(&client->dev, "backlight", &client->dev, data, &gp7101_backlight_ops,&props);if (IS_ERR(bl)) {dev_err(&client->dev, "failed to register backlight device\n");return PTR_ERR(bl);}data->client = client;i2c_set_clientdata(client, data);MY_DEBUG("max_brightness:%d brightness:%d",props.max_brightness, props.brightness);backlight_update_status(bl);return 0;
}static int gp7101_bl_remove(struct i2c_client *client)
{MY_DEBUG("locat");return 0;
}static const struct of_device_id gp7101_bl_of_match[] = {{ .compatible = BACKLIGHT_NAME, },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, gp7101_bl_of_match);static struct i2c_driver gp7101_bl_driver = {.probe      = gp7101_bl_probe,.remove     = gp7101_bl_remove,.driver = {.name     = BACKLIGHT_NAME,.of_match_table = of_match_ptr(gp7101_bl_of_match),},
};static int __init my_init(void)
{MY_DEBUG("locat");return i2c_add_driver(&gp7101_bl_driver);
}static void __exit my_exit(void)
{MY_DEBUG("locat");i2c_del_driver(&gp7101_bl_driver);
}module_init(my_init);
module_exit(my_exit);MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("My touch driver");
MODULE_AUTHOR("KuLiT");

编译生效

cd u-boot && ./make.sh rk3566 && cd ../kernel && make distclean && make ARCH=arm64 tspi_defconfig rk356x_evb.config android-11.config && make ARCH=arm64 tspi-rk3566-user-v10.img -j16 && cd .. && source build/envsetup.sh && lunch rk3566_tspi-userdebug && make installclean -j16 && make -j16 && ./mkimage.sh

在这里插入图片描述

./build.sh -u

在这里插入图片描述

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

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

相关文章

过滤器Filter和拦截器Interceptor实现登录校验

一.过滤器 Filter过滤器可以把对资源的请求拦截下来&#xff0c;从而实现一些登录验证的功能 1.Filter的快速入门 1.定义Filter:定义一个类&#xff0c;实现Filter接口&#xff0c;并重写其所有方法。2.配置 public class dofilter implements Filter {Override //初始化只…

【JAVA】数组的定义与使用

前一篇我们讲述了方法的使用和递归&#xff0c;这一讲 我们来叙述一下数组相关知识点。最近更新较快&#xff0c;大家紧跟步伐哦~~ 1. 数组的基本概念 1.1 为什么要使用数组 假设现在要存5个学生的javaSE考试成绩&#xff0c;并对其进行输出&#xff0c;按照之前掌握的知识点&…

obsidian 外观设置解毒

前言 一入obsidian深似海&#xff0c;外观设置也是五花八门&#xff0c;仿佛回到读书时期折腾桌面一样。 我对比了AnuPpuccin、minimal和其他的一些外观主题&#xff0c;设置都太复杂了&#xff0c;尤其是需要调整CSS文件&#xff0c;最后发现一款&#xff0c;非常好用&#…

数据传送指令

数据传送&#xff1a;负责把数据、地址或立即数传送到寄存器或存储单元中 数据传送指令可以分为四个类型&#xff1a;通用数据传送指令、地址传送指令、标志位传送指令、专用累加器传送指令(输入、输出指令) 一、通用数据传送指令 &#xff08;一&#xff09;传送字或字节指…

前端框架-echarts

Echarts 项目中要使用到echarts框架&#xff0c;从零开始在csdn上记笔记。 这是一个基础的代码&#xff0c;小白入门看一下 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" co…

刷题之找到字符串所有字母异位词

找到字符串所有字母异位词 滑动窗口。滑动窗口大小为待比较数组的大小。 class Solution { public:vector<int> findAnagrams(string s, string p) {//滑动窗口vector<int>result;if(s.size()<p.size())return result;vector<int>pnum(26,0);//记录p的字…

链表----带环链表快慢指针进阶版

1.带环链表及其拓展 &#xff08;1&#xff09;这个题目组要就是进行判断这个链表是否带环&#xff0c;使用的是布尔类型作为返回值&#xff1b; &#xff08;2&#xff09;我们这里的思路是使用的快慢指针&#xff0c;快指针一次走2步&#xff0c;慢指针一次走1步&#xff0c…

iOS Xcode 升级Xcode15报错: SDK does not contain ‘libarclite

一 iOS Xcode 升级Xcode15报错: SDK does not contain libarclite 1.1 报错信息 SDK does not contain libarclite at the path /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/ lib/arc/libarclite_iphonesimulator.a; try increasin…

Sass(Syntactically Awesome Stylesheets)是一种强大的CSS预处理器

Sass&#xff08;Syntactically Awesome Stylesheets&#xff09;是一种强大的CSS预处理器&#xff0c;它旨在简化CSS的编写&#xff0c;并增强其功能。它让开发者能够使用变量、嵌套规则、混入&#xff08;mixins&#xff09;、继承等高级功能&#xff0c;从而编写更加结构化和…

Linux基础知识面试题

1. 请描述Linux操作系统的安装过程&#xff0c;并说明其中的关键步骤。 Linux操作系统的安装过程通常涉及以下几个关键步骤&#xff1a; 准备安装介质&#xff1a;需要从官网或者其他可靠来源下载Linux发行版的ISO镜像文件&#xff0c;并制作一个启动U盘或者烧录到DVD中。现在…

基于 LlaMA 3 + LangGraph 在windows本地部署大模型 (九)

LlaMA 3 系列博客 基于 LlaMA 3 + LangGraph 在windows本地部署大模型 (一) 基于 LlaMA 3 + LangGraph 在windows本地部署大模型 (二) 基于 LlaMA 3 + LangGraph 在windows本地部署大模型 (三) 基于 LlaMA 3 + LangGraph 在windows本地部署大模型 (四) 基于 LlaMA…

Java面向对象——多态

即同一个方法可以根据发送对象的不同而采用多种不同的行为方式。 一个对象的实际类型是确定的&#xff0c;但可以指向对象的引用的类型有很多&#xff08;父类&#xff0c;有关系的类&#xff09;。 多态存在的条件&#xff1a; 1. 有继承关系&#xff1b; 2. 子类重写父类…

linux 卸载Nginx

在Linux中卸载Nginx&#xff0c;通常涉及几个关键步骤&#xff0c;包括停止Nginx服务、卸载依赖库、删除文件和清理安装包。具体的命令可能因Linux发行版的不同而略有差异。以下是一个通用的卸载流程&#xff1a; 1、停止Nginx服务 在卸载Nginx之前&#xff0c;需要先停止Ngi…

思维导图软件哪个好?5个软件教你自己快速制作思维导图

思维导图软件哪个好&#xff1f;5个软件教你自己快速制作思维导图 思维导图软件在现代生活和工作中扮演着重要的角色&#xff0c;它们可以帮助人们整理思维、规划项目、记录笔记等。以下是五款值得推荐的思维导图软件&#xff0c;它们各有特色&#xff0c;可以帮助您快速制作思…

嵌入式Linux:编译和使用Protobuf库

目录 1、开发环境和工具 2、安装和编译Protobuf、Protobuf-C库 3、编写和编译proto文件 4、修改makefile文件 5、测试示例 6、参考资料 Protobuf&#xff08;Protocol Buffers&#xff09;是由 Google 开发的一种轻量级、高效的结构化数据序列化方式&#xff0c;用于在不同应用…

Java红黑树详解及示例

红黑树&#xff08;Red-Black Tree&#xff09;是一种自平衡的二叉查找树&#xff08;Binary Search Tree&#xff09;&#xff0c;它确保了在最坏情况下基本操作&#xff08;比如插入、删除、查找&#xff09;都能在O(log n)时间内完成。红黑树的关键在于它在每个节点上存储了…

Charger之三动态电源路径管理(DPPM)

-----本文简介----- 主要内容包括&#xff1a; 领资料&#xff1a;点下方↓名片关注回复&#xff1a;粉丝群 硬件之路学习笔记公众号 Charger的动态电源路径管理&#xff08;DPPM&#xff09; 前篇内容&#xff1a;①电池管理IC&#xff08;Charger&#xff09;了解一下&…

python中几种推导式简单样例

目录 一、python中几种推导式 1.1 列表推导式&#xff1a; 1.2 字典推导式 1.3 生成器表达式&#xff1a; 1.4 条件表达式&#xff1a; 二、简化对多个列表的并行迭代函数&#xff1a; 一、python中几种推导式 1.1 列表推导式&#xff1a; 使用列表推导式可以简化对列表…

基于java 自定义注解Annotation设计简单ORM框架——进阶篇

目录 引言实例新建两个注解标注实体类拼接sql语句 总结 引言 一般Java规范编程&#xff08;只是一种习惯&#xff0c;而不是强制&#xff09;中&#xff0c;变量的命名方式一般采用驼峰式命名。比如userName&#xff0c;userImage。但是在数据库中一般不会采用驼峰式&#xff…

AIGC、LLM 加持下的地图特征笔记内容生产系统架构设计

文章目录 背景构建自动化内容生产平台系统架构设计架构详细设计流程介绍笔记来源笔记抓取干预 笔记 AIGC 赋能笔记 Rule 改写笔记特征库构建 附录Bash Cron 定时任务Golang 与 Pyhon AIGC 实践 小结 背景 在大模型的浪潮下&#xff0c;ChatGPT、Sora、Gemini、文言一心 等新技…