Linux I2C 驱动实验
目录
一、Linux I2C 驱动简介
1、I2C 总线驱动
2、I2C 设备驱动
1、 i2c_client 结构体
2、 i2c_driver 结构体
二、硬件分析
三、设备树编写
1、pinctrl_i2c1
2、在 i2c1 节点追加 ap3216c 子节点
3、验证
四、 代码编写
1、makefile
2、ap3216c.h
3、ap3216c.c
①、头文件
②、驱动出入口
③、 i2c驱动结构体
④、匹配函数
⑤、probe 函数
⑥、remove 函数
⑦、函数入口出口添加注册i2c_drive
⑧、读取AP3216C的N个寄存器
⑨、向AP3216C的N个寄存器写数据
⑩、读、写AP3216C一个寄存器
⑩①、读取AP3216C的数据
⑩②完善ap3216c_open、read函数
代码如下
4、ap3216c.c
一、Linux I2C 驱动简介
在IMX6ULL开发篇中"IIC实验"写了四个文件: bsp_i2c.c、bsp_i2c.h、 bsp_ap3216c.c 和 bsp_ap3216c.h。其中前两个是 I.MX6U 的 IIC 接口驱动,后两个文件是 AP3216C 这个 I2C 设备驱动文件。相当于有两部分驱动:
①、 I2C 主机驱动。
②、 I2C 设备驱动。
对于 I2C 主机驱动,一旦编写完成就不需要再做修改,其他的 I2C 设备直接调用主机驱动提供的 API 函数完成读写操作即可。这个正好符合 Linux 的驱动分离与分层的思想,因此 Linux内核也将 I2C 驱动分为两部分:
①、 I2C 总线驱动, I2C 总线驱动就是 SOC 的 I2C 控制器驱动,也叫做 I2C 适配器驱动。
②、 I2C 设备驱动, I2C 设备驱动就是针对具体的 I2C 设备而编写的驱动
1、I2C 总线驱动
在”platform驱动实验"的时候就说过, platform 是虚拟出来的一条总线,目的是为了实现总线、设备、驱动框架。对于 I2C 而言,不需要虚拟出一条总线,直接使用 I2C总线即可。 I2C 总线驱动重点是 I2C 适配器(也就是 SOC 的 I2C 接口控制器)驱动,Linux 内核将 SOC 的 I2C 适配器(控制器)抽象成 i2c_adapter, i2c_adapter 结构体定义在 include/linux/i2c.h 文件中,i2c_algorithm 类型的指针变量 algo,对于一个 I2C 适配器,肯定要对外提供读写 API 函数,设备驱动程序可以使用这些 API 函数来完成读写操作。 i2c_algorithm 就是 I2C 适配器与 IIC 设备进行通信的方法;i2c_algorithm 结构体定义在 include/linux/i2c.h 文件中,其中的master_xfer 就是 I2C 适配器的传输函数,可以通过此函数来完成与 IIC 设备之间的通信,smbus_xfer 是 SMBUS 总线的传输函数
一般 SOC 的 I2C 总线驱动都是由半导体厂商编写的,比如 I.MX6U 的 I2C 适配器驱动 NXP 已经编写好了,这个不需要用户去编写。因此 I2C 总线驱动对我们这些 SOC 使用者来说是被屏蔽掉的,我们只要专注于 I2C 设备驱动即可。
2、I2C 设备驱动
I2C 设备驱动重点关注两个数据结构: i2c_client 和 i2c_driver,i2c_client 就是描述设备信息的, i2c_driver 描述驱动内容,类似于 platform_driver
1、 i2c_client 结构体
i2c_client 结构体定义在 include/linux/i2c.h 文件中,内容如下:
struct i2c_client {unsigned short flags; /* 标志 */unsigned short addr; /* 芯片地址, 7 位,存在低 7 位*/
......char name[I2C_NAME_SIZE]; /* 名字 */struct i2c_adapter *adapter; /* 对应的 I2C 适配器 */struct device dev; /* 设备结构体 */int irq; /* 中断 */struct list_head detected;
......};
一个设备对应一个 i2c_client,每检测到一个 I2C 设备就会给这个 I2C 设备分配一个i2c_client
2、 i2c_driver 结构体
i2c_driver 类似 platform_driver,i2c_driver 结构体定义在 include/linux/i2c.h 文件中,部分如下
struct i2c_driver {........./* Standard driver model interfaces */
1 int (*probe)(struct i2c_client *, const struct i2c_device_id *);......
2 struct device_driver driver;
3 const struct i2c_device_id *id_table;..........}
第 1 行,当 I2C 设备和驱动匹配成功以后 probe 函数就会执行,和 platform 驱动一样。
第 2行, device_driver 驱动结构体,如果使用设备树的话,需要设置 device_driver
of_match_table 成员变量,也就是驱动的兼容(compatible)属性。
第3行, id_table 是传统的、未使用设备树的设备匹配 ID 表
重点工作就是构建 i2c_driver,构建完成以后需要向Linux 内核注册这个 i2c_driver
二、硬件分析
这部分在在IMX6ULL开发篇中"IIC实验"有详细介绍,下面就简单介绍
打开AP3216C原理图,这是一个IIC接口的器件,是一个环境光传感器


I2C1_SCL: 使用的是UART4_TXD这个IO;I2C1_SDA: 使用的是UART4_RXD这个IO
打开ap3216数据手册

地址为0x1e
三、设备树编写
1、pinctrl_i2c1
打开设备树,找到i2c1,pinctrl_i2c1 就是 I2C1 的 IO 节点
这里将 UART4_TXD 和 UART4_RXD 这两个 IO 分别复用为 I2C1_SCL 和 I2C1_SDA,电气属性都设置为 0x4001b8b0
2、在 i2c1 节点追加 ap3216c 子节点
AP3216C 是连接到 I2C1 上的,因此需要在 i2c1 节点下添加 ap3216c 的设备子节点,默认内容如下

305-316行,NXP 官方的 EVK 开发板上接了 mag3110和fxls8471,这里使用的开发板并没有这这两个器件,所以删掉,并添加上我们使用的

300行,clock-frequency 属性为 I2C 频率,这里设置为 100KHz
302行,inctrl-0 属性指定 I2C 所使用的 IO 为上面的pinctrl_i2c1
305行,ap3216c 子节点, @后面的“1e”是 ap3216c 的器件地址
306行,设置 compatible 值为“my,ap3216c”
307行,reg 属性也是设置 ap3216c 器件地址的,因此 reg 设置为 0x1e
3、验证
改完成以后使用“make dtbs”重新编译一下,然后使用新的设备树启动 Linux 内核
/sys/bus/i2c/devices 目录下存放着所有 I2C 设备,如果设备树修改正确的话,会在/sys/bus/i2c/devices 目录下看到一个名为“0-001e”的子目录,如下
“0-001e”就是 ap3216c 的设备目录,“1e”就是 ap3216c 器件地址。进入0-001e 目录,可以看到“name”文件, name 问价就保存着此设备名字,在这里就是“ap3216c”,如下

四、 代码编写
1、makefile
需要的文件如下图左,修改makefile

2、ap3216c.h
定义器件及其寄存器地址

3、ap3216c.c
①、头文件

②、驱动出入口

③、 i2c驱动结构体

46行,当 I2C 设备和驱动匹配成功以后 probe 函数就会执行,和 platform 驱动一样
47行,当关闭 驱动的时候remove 函数就会执行,和 platform 驱动一样
49行,name是在无设备树时用于和设备进行匹配,也就是上面写的实验,也作为驱动名字;
使用设备树就设置of_match_table变量,也就是驱动的兼容(compatible)属性
53行,id_table 是传统的、未使用设备树的设备匹配 ID 表
④、匹配函数
i2c驱动结构体 里对应的函数

236行,无设备树的时候匹配 ID 表
241行,设备树所使用的匹配表
⑤、probe 函数
在这里面实现基本的字符设备
#define AP3216C_CNT 1
#define AP3216C_NAME "ap3216c"struct ap3216c_dev{int devid;int major;int minor;struct cdev cedv;struct class *class;struct device *device;void *private_data;/*私有数据*/unsigned short ir, als, ps; /* 三个光传感器数据 */
};
static struct ap3216c_dev ap3216cdev;
static int ap3216c_open(struct inode *inode, struct file *filp)
{return 0;
}static int ap3216c_release(struct inode *inode, struct file *filp)
{printk("ap3216c_release\r\n");return 0;
}
static ssize_t ap3216c_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{return 0;
}static struct file_operations ap3216c_fops = {.owner = THIS_MODULE,.open = ap3216c_open,.read = ap3216c_read,.release = ap3216c_release,
};static int ap3216c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{int ret =0;/*搭建字符设备驱动框架*//*1、创建字符设备*/ap3216cdev.major=0;if(ap3216cdev.major){ap3216cdev.devid = MKDEV(ap3216cdev.major,0);ret = register_chrdev_region(ap3216cdev.devid,AP3216C_CNT,AP3216C_NAME);}else{ret = alloc_chrdev_region(&ap3216cdev.devid,0,AP3216C_CNT,AP3216C_NAME);ap3216cdev.major = MAJOR(ap3216cdev.devid);ap3216cdev.minor = MINOR(ap3216cdev.devid);}if(ret < 0){printk("ap3216cdev_chrdev_region error!\r\n");goto fail_devid;}printk("ap3216cde major: %d minor: %d\r\n",ap3216cdev.major,ap3216cdev.minor);/*2、注册字符设备*/ap3216cdev.cedv.owner = THIS_MODULE;cdev_init(&ap3216cdev.cedv,&ap3216c_fops);ret = cdev_add(&ap3216cdev.cedv,ap3216cdev.devid,AP3216C_CNT);if(ret < 0){printk("cdev_add error!\r\n");goto fail_cdev;}/*3、自动创建设备节点*/ap3216cdev.class = class_create(THIS_MODULE,AP3216C_NAME);if(IS_ERR(ap3216cdev.class)){ret = PTR_ERR(ap3216cdev.class);goto fail_class;}ap3216cdev.device = device_create(ap3216cdev.class, NULL,ap3216cdev.devid, NULL,AP3216C_NAME);if(IS_ERR(ap3216cdev.device)){ret = PTR_ERR(ap3216cdev.device);goto fail_device;}printk("ap3216c_probe\r\n");ap3216cdev.private_data = client;return 0;
fail_device:class_destroy(ap3216cdev.class);
fail_class:cdev_del(&ap3216cdev.cedv);
fail_cdev:unregister_chrdev_region(ap3216cdev.devid,AP3216C_CNT);
fail_devid:return ret;
}
" return 0 "前一行,将此函数的第一 个参数 client 传递给 ap3216cdev 的 private_data 成员变量
当设备和驱动匹配成功后,probe函数执行,传递的第一个参数就是i2c_client ,i2c_client 每检测到一个 I2C 设备就会给这个 I2C 设备分配一个i2c_client,这里用 ap3216cdev结构体中的private_data 成员接收
⑥、remove 函数

⑦、函数入口出口添加注册i2c_drive

50行,调用 i2c_add_driver 来向 Linux 内 核注册 i2c_driver,也就是 ap3216c_driver
i2c_add_driver 是一个宏,定义如下:
#define i2c_add_driver(driver) \
i2c_register_driver(THIS_MODULE, driver)
i2c_add_driver 就是对 i2c_register_driver 做了一个简单的封装,只有一个参数,就是要注册的 i2c_driver。
66行,调用 i2c_del_driver 来注销掉前面 注册的 ap3216c_driver,函数原型如下:
void i2c_del_driver(struct i2c_driver *driver)
driver:要注销的 i2c_driver。返回值: 无。
⑧、读取AP3216C的N个寄存器

这里先看61行,一般需要在 probe 函数里面初始化 I2C 设备,要初始化 I2C 设备就必须能够对 I2C 设备寄存器进行读写操作,这里就要用到 i2c_transfer 函数了,i2c_transfer 函数最终会调用 I2C 适配器中 i2c_algorithm 里面的 master_xfer 函数,对于 I.MX6U 而言就是i2c_imx_xfer 这个函数。 i2c_transfer 函数原型如下:
int i2c_transfer(struct i2c_adapter *adap,
struct i2c_msg *msgs,
int num)
adap: 所使用的 I2C 适配器, i2c_client 会保存其对应的 i2c_adapter。
msgs: I2C 要发送的一个或多个消息。
num: 消息数量,也就是 msgs 的数量。
返回值: 负值,失败,其他非负值,发送的 msgs 数量
从上面介绍i2c_client结构体就能看到有adapter成员,在probe函数里面已经获取到ap3216cdev设备的private_data成员中
48行,就是把private_data成员中把私有数据提出来,就在61行第一个参数中使用i2c_client中的adapter成员
继续看 i2c_transfer 函数msgs 这个参数,这是一个 i2c_msg 类型的指针参数, I2C 进行数据收发
说白了就是消息的传递, Linux 内核使用 i2c_msg 结构体来描述一个消息。 i2c_msg 结构体定义
在 include/uapi/linux/i2c.h 文件中

69行,从机地址
70行,标志
72行,read data,读数据
79行,要发送消息(本 msg)长度
80行,发送消息的数据
47行,定义结构体数组,按照I2C读时序把操作分为两部分

前面两段作为一部分,就是50-54行;后面两段作另一部分,就是56-59行
50-54行,发送器件寄存器地址。从i2c_client中获取从机地址,标志为0,表示发送数据,要发送的数据,也就是器件寄存器地址,寄存器地址长度为1个字节
56-59行,读取数据。从i2c_client中获取从机地址,标志表示读数据,读出来的数据保存在val,最后为读取的长度
再回到61行,第二个参数就是结构体数组msg,第三个参数就是2,结构体数组msg的长度
⑨、向AP3216C的N个寄存器写数据

76行,这里根据I2C写时序,寄存器地址和数据一次可以发完,所以只需要一个msg即可

79行,寄存器地址保存在b[0],先发寄存器地址
80行,把要发送的数据拷贝到b数组里面
⑩、读、写AP3216C一个寄存器

就是调用函数
⑩①、读取AP3216C的数据

⑩②完善ap3216c_open、read函数


代码如下
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/atomic.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include "ap3216c.h"#define AP3216C_CNT 1
#define AP3216C_NAME "ap3216c"struct ap3216c_dev{int devid;/* 设备号 */int major;int minor;struct cdev cedv;/* cdev */struct class *class;/* 类 */struct device *device;/* 设备 */void *private_data;/*私有数据*/unsigned short ir, als, ps; /* 三个光传感器数据 */
};static struct ap3216c_dev ap3216cdev;/*读取AP3216C的N个寄存器*/
static int ap3216c_read_regs(struct ap3216c_dev *dev,u8 reg,void *val, int len)
{int ret;struct i2c_msg msg[2];struct i2c_client *client = (struct i2c_client *)dev->private_data;/*msg[0]发送要读取的寄存器首地址*/msg[0].addr = client->addr;/*从机地址,也就是ap3216c*/msg[0].flags = 0;/* 标记为发送数据 */msg[0].buf = ®/*要发送的数据,也就是寄存器地址*/msg[0].len = 1;/*要发送的寄存器地址长度为1*//*msg[1]读取数据*/msg[1].addr = client->addr;/*从机地址,也就是ap3216c*/msg[1].flags = I2C_M_RD;/*表示读数据*/msg[1].buf = val;/*接收到的从机地址*/msg[1].len = len;/*要读取的寄存器数据长度*/ret = i2c_transfer(client->adapter,msg,2);if(ret == 2){ret = 0;}else{printk("i2c rd failed=%d reg=%06x len=%d\n",ret, reg, len);ret = -EREMOTEIO;}return ret;
}/*向AP3216C的N个寄存器写数据*/
static int ap3216c_write_regs(struct ap3216c_dev *dev,u8 reg,u8 *buf , u8 len)
{u8 b[256];struct i2c_msg msg;struct i2c_client *client = (struct i2c_client *)dev->private_data;/*构建要发送的数据,也就是寄存器首地址+实际的数据*/b[0] = reg;/*msg[0]发送要读取的寄存器首地址*/memcpy(&b[1], buf, len);msg.addr = client->addr;/*从机地址,也就是ap3216c*/msg.flags = 0;/*表示为要发送的数据*/msg.buf = b;/*要发送的数据,寄存器首地址+实际的数据*/msg.len = len +1;/*要发送的数据长度:寄存器首地址+实际的数据*/return i2c_transfer(client->adapter,&msg,1);
}
/*读取AP3216C一个寄存器*/
static unsigned char ap3216c_read_reg(struct ap3216c_dev *dev,u8 reg)
{u8 data=0;ap3216c_read_regs(dev,reg,&data,1);return data;
}
/*向AP3216C一个寄存器写数据*/
static void ap3216c_write_reg(struct ap3216c_dev *dev, u8 reg , u8 data)
{u8 buf = data;ap3216c_write_regs(dev,reg,&buf,1);
}void ap3216c_readdata(struct ap3216c_dev *dev)
{unsigned char i =0;unsigned char buf[6];/* 循环读取所有传感器数据 */for(i = 0; i < 6; i++) {buf[i] = ap3216c_read_reg(dev, AP3216C_IRDATALOW + i); }if(buf[0] & 0X80) /* IR_OF位为1,则数据无效 */dev->ir = 0; else /* 读取IR传感器的数据 */dev->ir = ((unsigned short)buf[1] << 2) | (buf[0] & 0X03); dev->als = ((unsigned short)buf[3] << 8) | buf[2]; /* 读取ALS传感器的数据 */ if(buf[4] & 0x40) /* IR_OF位为1,则数据无效 */dev->ps = 0; else /* 读取PS传感器的数据 */dev->ps = ((unsigned short)(buf[5] & 0X3F) << 4) | (buf[4] & 0X0F);
}static int ap3216c_open(struct inode *inode, struct file *filp)
{unsigned char value = 0;filp->private_data = &ap3216cdev;printk("ap3216c_open\r\n");/*初始化ap3216c*/ap3216c_write_reg(&ap3216cdev,AP3216C_SYSTEMCONG,0x4);/*复位*/mdelay(50);/*50ms*/ap3216c_write_reg(&ap3216cdev,AP3216C_SYSTEMCONG,0x3);/*复位*/value = ap3216c_read_reg(&ap3216cdev,AP3216C_SYSTEMCONG);printk("AP3216C_SYSTEMCONG = %#x\r\n",value);return 0;
}static int ap3216c_release(struct inode *inode, struct file *filp)
{printk("ap3216c_release\r\n");return 0;
}
static ssize_t ap3216c_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{long err=0;short data[3];struct ap3216c_dev *dev = (struct ap3216c_dev *)filp->private_data;/*向应用返回AP3216C的原始数据*/ap3216c_readdata(dev);data[0] =dev->ir;data[1] =dev->als;data[2] =dev->ps;err = copy_to_user(buf, data,sizeof(data));return 0;
}static struct file_operations ap3216c_fops = {.owner = THIS_MODULE,.open = ap3216c_open,.read = ap3216c_read,.release = ap3216c_release,
};static int ap3216c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{int ret =0;/*搭建字符设备驱动框架*//*1、创建字符设备*/ap3216cdev.major=0;if(ap3216cdev.major){ap3216cdev.devid = MKDEV(ap3216cdev.major,0);ret = register_chrdev_region(ap3216cdev.devid,AP3216C_CNT,AP3216C_NAME);}else{ret = alloc_chrdev_region(&ap3216cdev.devid,0,AP3216C_CNT,AP3216C_NAME);ap3216cdev.major = MAJOR(ap3216cdev.devid);ap3216cdev.minor = MINOR(ap3216cdev.devid);}if(ret < 0){printk("ap3216cdev_chrdev_region error!\r\n");goto fail_devid;}printk("ap3216cde major: %d minor: %d\r\n",ap3216cdev.major,ap3216cdev.minor);/*2、注册字符设备*/ap3216cdev.cedv.owner = THIS_MODULE;cdev_init(&ap3216cdev.cedv,&ap3216c_fops);ret = cdev_add(&ap3216cdev.cedv,ap3216cdev.devid,AP3216C_CNT);if(ret < 0){printk("cdev_add error!\r\n");goto fail_cdev;}/*3、自动创建设备节点*/ap3216cdev.class = class_create(THIS_MODULE,AP3216C_NAME);if(IS_ERR(ap3216cdev.class)){ret = PTR_ERR(ap3216cdev.class);goto fail_class;}ap3216cdev.device = device_create(ap3216cdev.class, NULL,ap3216cdev.devid, NULL,AP3216C_NAME);if(IS_ERR(ap3216cdev.device)){ret = PTR_ERR(ap3216cdev.device);goto fail_device;}printk("ap3216c_probe\r\n");ap3216cdev.private_data = client;return 0;
fail_device:class_destroy(ap3216cdev.class);
fail_class:cdev_del(&ap3216cdev.cedv);
fail_cdev:unregister_chrdev_region(ap3216cdev.devid,AP3216C_CNT);
fail_devid:return ret;
}
static int ap3216c_remove(struct i2c_client *client)
{cdev_del(&ap3216cdev.cedv);unregister_chrdev_region(ap3216cdev.devid,AP3216C_CNT);device_destroy(ap3216cdev.class, ap3216cdev.devid);class_destroy(ap3216cdev.class);printk("ap3216c_remove\r\n");return 0;
}
/*传统匹配表*/
static struct i2c_device_id ap3216c_id[] = {{"my,ap3216c",0},{}
};
/*设备树匹配*/
static struct of_device_id ap3216c_of_match[] = {{.compatible = "my,ap3216c"},{}
};
/*i2c_driver*/
static struct i2c_driver ap3216c_driver= {.probe = ap3216c_probe,.remove = ap3216c_remove,.driver = {.name = "ap3216c",.owner = THIS_MODULE,.of_match_table = of_match_ptr(ap3216c_of_match),},.id_table = ap3216c_id,
};
/*驱动入口*/
static int __init ap3216c_init(void)
{int ret = 0;/*添加*/ret = i2c_add_driver(&ap3216c_driver);return ret;
}
/*驱动出口*/
static void __exit ap3216c_exit(void)
{i2c_del_driver(&ap3216c_driver);
}module_init(ap3216c_init);
module_exit(ap3216c_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ba che kai qi lai");
4、ap3216c.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/input.h>/*argc:应用程序参数个数(argv数组元素个数)argv:具体参数,也可以写作char **argv./ap3216cAPP <filename> ./ap3216cAPP /dev/ap3216c
*/int main(int argc, char *argv[])
{int fd,err;char *filename;unsigned short ir, als, ps, data[3];/*判断命令行输入参数是否正确*/if(argc != 2){printf("error usage!\r\n");return -1;}/*用指针指向文件*/filename = argv[1];/*打开文件*/fd = open(filename , O_RDWR);if(fd < 0){printf("file open failed\r\n",filename);return -1;}while(1){err =read(fd,&data,sizeof(data));if(err == 0){ir=data[0];als=data[1];ps=data[2] ;printf("ap3216c ir = %d,als = %d,ps = %d\r\n",ir,als,ps);}usleep(200000);/*200ms*/}/*关闭文件*/close(fd);return 0;
}
用APP测试驱动

用手接近和用灯照ap3216c传感器,数值都会发生变化
相关文章:
Linux I2C 驱动实验
目录 一、Linux I2C 驱动简介 1、I2C 总线驱动 2、I2C 设备驱动 1、 i2c_client 结构体 2、 i2c_driver 结构体 二、硬件分析 三、设备树编写 1、pinctrl_i2c1 2、在 i2c1 节点追加 ap3216c 子节点 3、验证 四、 代码编写 1、makefile 2、ap3216c.h 3、ap3216c.c …...
DC-DC模块电源隔离直流升压高压稳压输出5v12v24v转60v100v110v150v220v250v300v400v500v
特点效率高达80%以上1*1英寸标准封装单电压输出稳压输出工作温度: -40℃~85℃阻燃封装,满足UL94-V0 要求温度特性好可直接焊在PCB 上应用HRB 0.2~10W 系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为:4.5~9V、9~18V、及18~36VDC标准&#…...
EF有几种模式,EF的三种模式分别是什么?
EF有几种模式,EF的三种模式分别是什么? 第一种:DataBase First DataBase First传统的表驱动方式创建EDM,然后通过EDM生成模型和数据层代码。除生成实体模型和自跟踪实现模型,还支持生成轻型DbContext。 解释…...
数据可视化展示:打工人常见职业病,颈腰椎病占比最高达66.51%
身体健康才是一切的根本。只有身体健健康康才能更好的去享受世间的美好,无论是谁都应当注重身体健康,而不是无度的挥霍它! 良好的身体,释放给工作,健壮的体魄,享受美好生活,良好的心态ÿ…...
【食品图像识别】Large Scale Visual Food Recognition
1 引言 视觉智能部与中科院计算所于2020-2021年度展开了《细粒度菜品图像识别和检索》科研课题合作,本文系双方联合在IEEE T-PAMI2023发布论文《Large Scale Visual Food Recognition》 (Weiqing Min, Zhiling Wang, Yuxin Liu, Mengjiang Luo, Liping Kang, Xiaom…...
RAN-in-the-Cloud:为 5G RAN 提供云经济性
RAN-in-the-Cloud:为 5G RAN 提供云经济性 5G 部署在全球范围内一直在加速。 许多电信运营商已经推出了5G服务并正在快速扩张。 除了电信运营商之外,企业也对使用 5G 建立私有网络产生了浓厚的兴趣,这些私有网络利用了更高的带宽、更低的延迟…...
vector、list、queue
引用:windows程序员面试指南 vector vector 类似于C语言中的数组 vector 支持随机访问,访问某个元素的时间复杂度 O(1) vector 插入和删除元素效率较低,时间复杂度O(n) vector 是连续存储,没有内存碎片,空间利用率高…...
操作系统面经
进程与线程区别 1.进程是资源分配的最小单位,线程是程序执行的最小单位(资源调度的最小单位) 2.进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数…...
一天约了4个面试,复盘一下面试题和薪资福利
除了最新的面经分享,还有字节大佬的求职面试答疑,告诉你关键问题是什么?少走弯路。**另外本文也汇总了6份大厂面试题:字节、腾讯、小米、腾讯云、滴滴、小米游戏。**希望对大家有帮助。 前言 昨天我的交流群里,有位宝…...
详解单链表(内有精美图示哦)
全文目录引言链表链表的定义与结构链表的分类单链表的实现及对数据的操作单链表的创建与销毁创建销毁单链表的打印单链表的头插与头删头插头删单链表的尾插与尾删尾插尾删单链表的查找单链表在pos位置后插入/删除插入删除单链表在pos位置插入/删除插入删除总结引言 在上一篇文…...
csdn文章导航
这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…...
【Spring】掌握 Spring Validation 数据校验
个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ Spring Validation 数据校验一、什么是 Spring…...
定语 从句
回顾能作定语的成分 形容词:She is a responsible girl.她是一个负责任的姑娘。(前置定语) The girl responsible was expelled.对此负责的姑娘被开除了。(后置定语) 代词:Whose f…...
【数据可视化工具】浅谈 DataEase 和 FineBI 支持的数据源
前言最近对市面上比较火热的数据可视化工具 DataEase 和 FineBI 进行了调研,在支持的数据源方面感觉不太一样,所以就有了这篇文章,话不多说,我们一起来看一下吧!以下的内容,大多来自两个工具的官方文档&…...
100种思维模型之上帝视角思维模型-025
惊奇、愤怒、郁闷,我们觉得生活不精彩,事情乱作一团,但这仅仅是视角问题而已。 换个视角,可以看到不同的世界。 “上帝视角思维模型”,即以一个更高、更客观、更理性的角度来看问题,从而做出理性的决策。 …...
从这5个方面,总结我当PM的第一年
以下5个方面(学习、思考、沟通、执行、产品)的分享,都是我站在巨人的肩膀上,结合自己所学所做总结而来;同时,我也继续学习,不断完善这些知识。如有不当,欢迎大家指正~一、学习&#…...
ChatGPT可以作为一个翻译器吗?
论文地址:https://arxiv.org/abs/2301.08745.pdf 背景 自从OpenAI2022年11月30日发布ChatGPT以来,基本上把NLP所有任务大统一了,那么在机器翻译的表现到底如何呢?腾讯AI Lab在翻译Prompt、多语言翻译以及翻译鲁棒性三方面做了一…...
详述java的设计模式(三)
1.装饰者模式 装饰者模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 使用场景: 在不影响其他对象的情况下ÿ…...
Linux命令·pwd
Linux中用 pwd 命令来查看”当前工作目录“的完整路径。 简单得说,每当你在终端进行操作时,你都会有一个当前工作目录。 在不太确定当前位置时,就会使用pwd来判定当前目录在文件系统内的确切位置。1.命令格式:pwd [选项…...
以图搜图服务快速搭建
以图搜图服务快速搭建 电商公司,管理的商品少则几千,多则上百万。如何帮助用户从多如牛毛的商品中找到类似的商品就成了问题。 以图搜图就可以很好的帮助解决这个问题,通过 Towhee(resnet50 模型) Milvus 如何实现本…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
2.3 物理层设备
在这个视频中,我们要学习工作在物理层的两种网络设备,分别是中继器和集线器。首先来看中继器。在计算机网络中两个节点之间,需要通过物理传输媒体或者说物理传输介质进行连接。像同轴电缆、双绞线就是典型的传输介质,假设A节点要给…...
