linux 下调试 bmp280 气压传感器

供自己备忘;

linux 下有自带的 bmp280 驱动,实际测试数据抖动不理想;

于是自己重写一个 bmp280 驱动,实际测试数据依旧抖动,不理想;

考虑使用 SPL06 来测试看看效果;

1. 参考资料:

BMP280气压传感器详解(STM32)_哔哩哔哩_bilibili

2. 简单调试

计划是每秒读取 100 次,实际是按下图框出的配置配置的;

内核版本为:4.9.84

2.1 阅读手册

通过阅读数据手册,可以获取如下信息:

  • 存在 3 种模式

    • 休眠模式:不进行采样

    • 正常模式:循环采样

    • 强制模式:采样一次后进入休眠模式

  • 上电后,自动进入休眠模式

  • 推荐数据连续读取

  • 使用补偿参数计算实际压力和温度

  • 连续读取时,数据不会错误;非连续读取时数据会有混淆情况(读取的时候更新采样数据)

  • MSB:高字节(高 8 位),表示寄存器地址的前 8 位。

  • LSB:低字节(低 8 位),表示寄存器地址的后 8 位。

  • 可以写的寄存器一共只有三个

    • BMP280_REG_CONFIG 0xF5

    • BMP280_REG_CTRL_MEAS 0xF4

    • BMP280_REG_RESET 0xE0

2.2 dts 配置如下

0x76 是 7 位 i2c 地址,对应芯片 SDO 脚是接地的;

2.3 Makefile 文件如下

内核路径修改为自己的,交叉编译器也是;前提是内核编译过,配置好交叉编译器。

KERN_DIR = /opt/liangtao/sigmastar/js230-IKAYAKI_DLM00V017_SSD222D/kernelall:make -C $(KERN_DIR) M=`pwd` modulesarm-linux-gnueabihf-gcc bmp280_read.c -o bmp280_read -lm#cp i2c_bmp280.ko bmp280_read /opt/liangtao/output/clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm bmp280_readobj-m += i2c_bmp280.o
2.4 驱动代码修改如下

从之前的博客 mpu6050 拷贝而来;

主要的点如下:

  • bmp280_init 初始化 bmp280

    • 复位后延时 2ms

    • 温度 2 倍过采样

    • 气压 16 倍过采样

    • 正常模式

    • STANDBY TIME 为 0.5ms

    • IIR 为 16 倍

    • 读取校验数据

  • 定时器 30ms 触发工作队列进行数据读取

代码如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.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>
#include <linux/workqueue.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>// 宏定义
/* BMP280 specific registers */
#define BMP280_REG_TEMP_XLSB        0xFC
#define BMP280_REG_TEMP_LSB         0xFB
#define BMP280_REG_TEMP_MSB         0xFA
#define BMP280_REG_PRESS_XLSB       0xF9
#define BMP280_REG_PRESS_LSB        0xF8
#define BMP280_REG_PRESS_MSB        0xF7/* Helper mask to truncate excess 4 bits on pressure and temp readings */
#define BMP280_MEAS_TRIM_MASK       GENMASK(24, 4)#define BMP280_REG_CONFIG           0xF5
#define BMP280_REG_CTRL_MEAS        0xF4
#define BMP280_REG_STATUS           0xF3
#define BMP280_REG_RESET            0xE0
#define BMP280_REG_ID               0xD0#define BMP280_REG_COMP_TEMP_START  0x88
#define BMP280_COMP_TEMP_REG_COUNT  6#define BMP280_REG_COMP_PRESS_START 0x8E
#define BMP280_COMP_PRESS_REG_COUNT 18#define BMP280_COMP_H5_MASK     GENMASK(15, 4)#define BMP280_CONTIGUOUS_CALIB_REGS    (BMP280_COMP_TEMP_REG_COUNT + \BMP280_COMP_PRESS_REG_COUNT)#define BMP280_STANDBY_T_MASK       GENMASK(7, 5)
#define BMP280_STANDBY_T_500US      0
#define BMP280_STANDBY_T_62500US    1
#define BMP280_STANDBY_T_125MS      2
#define BMP280_STANDBY_T_250MS      3
#define BMP280_STANDBY_T_500MS      4
#define BMP280_STANDBY_T_1000MS     5
#define BMP280_STANDBY_T_2000MS     6
#define BMP280_STANDBY_T_4000MS     7#define BMP280_FILTER_MASK          GENMASK(4, 2)
#define BMP280_FILTER_OFF           0
#define BMP280_FILTER_2X            1
#define BMP280_FILTER_4X            2
#define BMP280_FILTER_8X            3
#define BMP280_FILTER_16X           4#define BMP280_OSRS_TEMP_MASK       GENMASK(7, 5)
#define BMP280_OSRS_TEMP_SKIP       0
#define BMP280_OSRS_TEMP_1X         1
#define BMP280_OSRS_TEMP_2X         2
#define BMP280_OSRS_TEMP_4X         3
#define BMP280_OSRS_TEMP_8X         4
#define BMP280_OSRS_TEMP_16X        5#define BMP280_OSRS_PRESS_MASK      GENMASK(4, 2)
#define BMP280_OSRS_PRESS_SKIP      0
#define BMP280_OSRS_PRESS_1X        1
#define BMP280_OSRS_PRESS_2X        2
#define BMP280_OSRS_PRESS_4X        3
#define BMP280_OSRS_PRESS_8X        4
#define BMP280_OSRS_PRESS_16X       5#define BMP280_MODE_MASK            GENMASK(1, 0)
#define BMP280_MODE_SLEEP           0
#define BMP280_MODE_FORCED          1
#define BMP280_MODE_NORMAL          3/* BMP280 register skipped special values */
#define BMP280_TEMP_SKIPPED         0x80000
#define BMP280_PRESS_SKIPPED        0x80000#define DEV_NAME "i2c_bmp280"
#define DEV_CNT (1)struct bmp280_calib
{u16 T1;         /* calibration T1 data */s16 T2;         /* calibration T2 data */s16 T3;         /* calibration T3 data */u16 P1;         /* calibration P1 data */s16 P2;         /* calibration P2 data */s16 P3;         /* calibration P3 data */s16 P4;         /* calibration P4 data */s16 P5;         /* calibration P5 data */s16 P6;         /* calibration P6 data */s16 P7;         /* calibration P7 data */s16 P8;         /* calibration P8 data */s16 P9;         /* calibration P9 data */s32 t_fine;     /* calibration t_fine data */
};
static struct bmp280_calib bmp280_calib_data;static dev_t bmp280_devno;                  // 定义字符设备的设备号
static struct cdev bmp280_chr_dev;          // 定义字符设备结构体 chr_dev
struct class *class_bmp280;                 // 保存创建的类
struct device *device_bmp280;               // 保存创建的设备
struct device_node *bmp280_device_node;     // bmp280 的设备树节点结构体
struct i2c_client *bmp280_client = NULL;    // 保存 bmp280 设备对应的 i2c_client 结构体,匹配成功后由 .prob 函数带回。// 定时器,定时读取 bmp280 的数据
static struct timer_list t;
// 用于定时器是否使能
static char is_timer_active;
static unsigned char bmp280_result[8];// 工作队列,用于执行耗时的 i2c 操作
static struct workqueue_struct *bmp280_wq;
static struct work_struct bmp280_work;// 一个互斥锁,对读取数据进行保护
static DEFINE_MUTEX(bmp280_mutex);static u32 __get_unaligned_be24(const u8 *p)
{return p[0] << 16 | p[1] << 8 | p[2];
}static u32 get_unaligned_be24(const void *p)
{return __get_unaligned_be24(p);
}/* 通过 i2c 向 bmp280 写入数据* bmp280_client:bmp280 的 i2c_client 结构体。* address, 数据要写入的地址,* data, 要写入的数据* 返回值,错误,-1。成功,0  */
static int i2c_write_bmp280(struct i2c_client *bmp280_client, u8 address, u8 data)
{int error = 0;u8 write_data[2];struct i2c_msg send_msg; // 要发送的数据结构体/* 设置要发送的数据 */write_data[0] = address;write_data[1] = data;/* 发送 iic 要写入的地址 reg */send_msg.addr = bmp280_client->addr; // bmp280 在 iic 总线上的地址send_msg.flags = 0;                   // 标记为发送数据send_msg.buf = write_data;            // 写入的首地址send_msg.len = 2;                     // reg 长度/* 执行发送 */error = i2c_transfer(bmp280_client->adapter, &send_msg, 1);if (error != 1) {printk("i2c_write_bmp280 error %d\n", error);return -1;}return 0;
}/* 通过 i2c 向 bmp280 写入数据* bmp280_client:bmp280 的 i2c_client 结构体。* address, 要读取的地址,* data,保存读取得到的数据* length,读长度* 返回值,错误,-1。成功,0*/
static int i2c_read_bmp280(struct i2c_client *bmp280_client, u8 address, void *data, u32 length)
{int error = 0;u8 address_data = address;struct i2c_msg bmp280_msg[2];/* 设置读取位置 msg */bmp280_msg[0].addr = bmp280_client->addr;   // bmp280 在 iic 总线上的地址bmp280_msg[0].flags = 0;                    // 标记为发送数据bmp280_msg[0].buf = &address_data;          // 写入的首地址bmp280_msg[0].len = 1;                      // 写入长度/* 设置读取位置 msg */bmp280_msg[1].addr = bmp280_client->addr;   // bmp280 在 iic 总线上的地址bmp280_msg[1].flags = I2C_M_RD;             // 标记为读取数据bmp280_msg[1].buf = data;                   // 读取得到的数据保存位置bmp280_msg[1].len = length;                 // 读取长度error = i2c_transfer(bmp280_client->adapter, bmp280_msg, 2);if (error != 2) {printk("i2c_read_bmp280 error %d\n", error);return -1;}return 0;
}/** Returns temperature in DegC, resolution is 0.01 DegC.  Output value of* "5123" equals 51.23 DegC.  t_fine carries fine temperature as global* value.** Taken from datasheet, Section 3.11.3, "Compensation formula".*/
static s32 bmp280_compensate_temp(s32 adc_temp)
{struct bmp280_calib *calib = &bmp280_calib_data;s32 var1, var2;var1 = (((adc_temp >> 3) - ((s32)calib->T1 << 1)) *((s32)calib->T2)) >> 11;var2 = (((((adc_temp >> 4) - ((s32)calib->T1)) *((adc_temp >> 4) - ((s32)calib->T1))) >> 12) *((s32)calib->T3)) >> 14;calib->t_fine = var1 + var2;return (calib->t_fine * 5 + 128) >> 8;
}/** Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24* integer bits and 8 fractional bits).  Output value of "24674867"* represents 24674867/256 = 96386.2 Pa = 963.862 hPa** Taken from datasheet, Section 3.11.3, "Compensation formula".*/
static u32 bmp280_compensate_press(s32 adc_press)
{struct bmp280_calib *calib = &bmp280_calib_data;s64 var1, var2, p;var1 = ((s64)calib->t_fine) - 128000;var2 = var1 * var1 * (s64)calib->P6;var2 += (var1 * (s64)calib->P5) << 17;var2 += ((s64)calib->P4) << 35;var1 = ((var1 * var1 * (s64)calib->P3) >> 8) +((var1 * (s64)calib->P2) << 12);var1 = ((((s64)1) << 47) + var1) * ((s64)calib->P1) >> 33;if (var1 == 0)return 0;p = ((((s64)1048576 - adc_press) << 31) - var2) * 3125;p = div64_s64(p, var1);var1 = (((s64)calib->P9) * (p >> 13) * (p >> 13)) >> 25;var2 = ((s64)(calib->P8) * p) >> 19;p = ((p + var1 + var2) >> 8) + (((s64)calib->P7) << 4);return (u32)p;
}static void bmp280_work_func(struct work_struct *work)
{u8 buf[6];int ret;s32 adc, comp_temp;u32 comp_press;// 读取原始的气压、温度数据ret = i2c_read_bmp280(bmp280_client, BMP280_REG_PRESS_MSB, buf, sizeof(buf));if (ret < 0) {printk("i2c_read_bmp280 error\n");return;}adc = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&buf[3]));if (adc == BMP280_TEMP_SKIPPED) {/* reading was skipped */printk("reading temperature skipped\n");return;}comp_temp = bmp280_compensate_temp(adc);adc = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&buf[0]));if (adc == BMP280_PRESS_SKIPPED) {/* reading was skipped */printk("reading pressure skipped\n");return;}comp_press = bmp280_compensate_press(adc);mutex_lock(&bmp280_mutex);memcpy(bmp280_result, &comp_temp, sizeof(comp_temp));memcpy(&bmp280_result[4], &comp_press, sizeof(comp_press));mutex_unlock(&bmp280_mutex);//comp_press = comp_press / 256;//printk("temperature = %d, pressure = %d\n", comp_temp, comp_press);
}static void bmp280_timer_func(unsigned long data)
{if (is_timer_active) {mod_timer(&t, jiffies + msecs_to_jiffies(30));}// 只在任务未在队列中时才添加新任务if (!work_pending(&bmp280_work)) {queue_work(bmp280_wq, &bmp280_work);}
}/* 初始化 bmp280* 返回值,成功,返回 0。失败,返回 -1*/
static int bmp280_init(void)
{int err = 0;unsigned char buf[1];/* 配置 bmp280 */// 设置 BMP280_RST_REG 寄存器值为 0xB6,触发复位err += i2c_write_bmp280(bmp280_client, BMP280_REG_RESET, 0xB6);// 等待复位完成msleep(2);// 读取 BMP280_ID_REG 寄存器,判断是否连接成功err += i2c_read_bmp280(bmp280_client, BMP280_REG_ID, &buf[0], 1);if (buf[0] != 0x58) {printk("bmp280_init id error, id 0x%x, err %d\n", buf[0], err);return -1;}// 配置 BMP280_REG_CTRL_MEAS 寄存器; 配置温度过采样,配置气压过采样,配置供电模式buf[0] = FIELD_PREP(BMP280_OSRS_TEMP_MASK, BMP280_OSRS_TEMP_2X) | FIELD_PREP(BMP280_OSRS_PRESS_MASK, BMP280_OSRS_PRESS_16X) | FIELD_PREP(BMP280_MODE_MASK, BMP280_MODE_NORMAL);err += i2c_write_bmp280(bmp280_client, BMP280_REG_CTRL_MEAS, buf[0]);// 配置 IIR 滤波 BMP280_STANDBY_T_MASKbuf[0] = FIELD_PREP(BMP280_STANDBY_T_MASK, BMP280_STANDBY_T_500US) |FIELD_PREP(BMP280_FILTER_MASK, BMP280_FILTER_16X);err += i2c_write_bmp280(bmp280_client, BMP280_REG_CONFIG, buf[0]);/** Some chips have calibration parameters "programmed into the devices'* non-volatile memory during production". Let's read them out at probe* time once. They will not change.*/// 读取校准参数err += i2c_read_bmp280(bmp280_client, BMP280_REG_COMP_TEMP_START, (void *)&bmp280_calib_data, BMP280_CONTIGUOUS_CALIB_REGS);if (err < 0) {printk("bmp280_init error\n");return -1;}return 0;
}static int bmp280_open(struct inode *inode, struct file *filp)
{is_timer_active = 1;mod_timer(&t, jiffies + msecs_to_jiffies(1));return 0;
}static ssize_t bmp280_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{int error;unsigned char buffer[8]; // 保存 bmp280 转换得到的原始数据mutex_lock(&bmp280_mutex);memcpy(buffer, bmp280_result, sizeof(bmp280_result));mutex_unlock(&bmp280_mutex);error = copy_to_user(buf, buffer, sizeof(buffer));if (error != 0) {printk("copy_to_user error!");return -1;}return sizeof(buffer);
}static int bmp280_release(struct inode *inode, struct file *filp)
{is_timer_active = 0;return 0;
}static struct file_operations bmp280_chr_dev_fops =
{.owner = THIS_MODULE,.open = bmp280_open,.read = bmp280_read,.release = bmp280_release,
};static int bmp280_probe(struct i2c_client *client, const struct i2c_device_id *id)
{int ret;printk("bmp280_probe, HZ = %d\n", HZ);bmp280_client = client;/* 初始化 bmp280 */ret = bmp280_init();if (ret < 0) {printk("fail to init bmp280\n");goto alloc_err;}// 采用动态分配的方式,获取设备编号,次设备号为 0,// 设备名称为 i2c_bmp280,可通过命令 cat /proc/devices 查看// DEV_CNT 为 1,当前只申请一个设备编号ret = alloc_chrdev_region(&bmp280_devno, 0, DEV_CNT, DEV_NAME);if (ret < 0) {printk("fail to alloc bmp280_devno\n");goto alloc_err;}// 关联字符设备结构体 cdev 与文件操作结构体 file_operationsbmp280_chr_dev.owner = THIS_MODULE;cdev_init(&bmp280_chr_dev, &bmp280_chr_dev_fops);// 添加设备至 cdev_map 散列表中ret = cdev_add(&bmp280_chr_dev, bmp280_devno, DEV_CNT);if (ret < 0) {printk("fail to add cdev\n");goto add_err;}/* 创建类 */class_bmp280 = class_create(THIS_MODULE, DEV_NAME);/* 创建设备 DEV_NAME 指定设备名 */device_bmp280 = device_create(class_bmp280, NULL, bmp280_devno, NULL, DEV_NAME);/* 初始化工作队列 */bmp280_wq = create_singlethread_workqueue("bmp280_wq");INIT_WORK(&bmp280_work, bmp280_work_func);/* 创建一个定时器,开始以 100hz 的频率来采样 */setup_timer(&t, bmp280_timer_func, 0);return 0;add_err:// 添加设备失败时,需要注销设备号unregister_chrdev_region(bmp280_devno, DEV_CNT);printk("bmp280_probe error! \n");
alloc_err:return -1;
}static int bmp280_remove(struct i2c_client *client)
{device_destroy(class_bmp280, bmp280_devno);         // 清除设备class_destroy(class_bmp280);                        // 清除类cdev_del(&bmp280_chr_dev);                          // 清除设备号unregister_chrdev_region(bmp280_devno, DEV_CNT);    // 取消注册字符设备del_timer_sync(&t);                                 // 删除定时器flush_workqueue(bmp280_wq);                         // 确保所有任务完成destroy_workqueue(bmp280_wq);                       // 销毁工作队列return 0;
}static const struct i2c_device_id bmp280_device_id[] = {{"bosch,bmp280", 0},{/* sentinel */}
};static const struct of_device_id bmp280_of_match_table[] = {{.compatible = "bosch,bmp280"},{/* sentinel */}
};struct i2c_driver bmp280_driver = {.probe = bmp280_probe,.remove = bmp280_remove,.id_table = bmp280_device_id,.driver = {.name = "invensense,bmp280",.owner = THIS_MODULE,.of_match_table = bmp280_of_match_table,},
};static int __init bmp280_driver_init(void)
{int ret;printk("bmp280_driver_init\n");ret = i2c_add_driver(&bmp280_driver);return ret;
}static void __exit bmp280_driver_exit(void)
{printk("bmp280_driver_exit\n");i2c_del_driver(&bmp280_driver);
}module_init(bmp280_driver_init);
module_exit(bmp280_driver_exit);MODULE_LICENSE("GPL");
2.5 应用代码
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <math.h>void print_timestamp() 
{struct timeval tv;gettimeofday(&tv, NULL);printf("[%ld.%06ld] ", tv.tv_sec, tv.tv_usec);
}int main(int argc, char *argv[])
{int error;unsigned char receive_data[8];  //保存收到的 bmp280 转换结果数据,先为温度,后为气压int temp;unsigned int press;float real_temp;float real_press;/*打开文件*/int fd = open("/dev/i2c_bmp280", O_RDWR);if (fd < 0) {printf("open file : %s failed !\n", argv[0]);return -1;}usleep(200000);while (1) {/* 读取数据 */print_timestamp();error = read(fd, receive_data, sizeof(receive_data));if (error != 8) {printf("read file error! \n");close(fd);break;}print_timestamp();/* 打印数据 */memcpy(&temp, receive_data, sizeof(temp));memcpy(&press, &receive_data[4], sizeof(press));real_temp = temp / 100.0;real_press = press / 256.0;printf("temp %f, press %f\n", real_temp, real_press);usleep(10000);}/*关闭文件*/error = close(fd);if (error < 0) {printf("close file error! \n");}return 0;
}

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

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

相关文章

『VUE』26. props实现子组件传递数据给父组件(详细图文注释)

目录 本节内容示例代码总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 本节内容 父组件传子组件–props 子组件传父组件–自定义事件 本节讲子组件传父组件–通过props里的方法传递,就是父亲写了一个函数,给子组件调用,然后…

Linux编辑/etc/fstab文件不当,不使用快照;进入救援模式

目录 红帽镜像9救援模式 现象 解决 第一步&#xff1a;修改启动参数以进入救援模式 第二步&#xff1a;进入救援模式、获取root权限、编辑/etc/fstab文件 第三步&#xff1a;编辑好后在重启 下面是ai给的模板 红帽镜像9救援模式 编辑/etc/fstab不当时 17 /dev/nvme0n3p1…

异地情侣远程玩游戏?GameViewer远程串流轻松实现!

情侣之间偶尔想远程玩游戏增进感情却苦于找不到合适的软件&#xff1f;想要寻找一款低门槛好上手操作便捷的串流软件 &#xff1f; 在这里向你推荐 网易GameViewer远程 &#xff01; GameViewer是专为游戏玩家的设计远程控制软件&#xff0c;可以帮助异地情侣实现这一需求。它让…

1990-2020年中国人工林和天然林空间分布数据集

数据介绍 植树已被认为是减缓气候变化的潜在有效解决方案。自上世纪70年代以来&#xff0c;中国实施了世界上最大的造林和再造林工程&#xff0c;但中国人工林的高分辨率地图仍然无法获得。在这项研究中&#xff0c;我们探索了使用多源遥感图像和众包样本来制作第一张高分辨率…

[Docker#10] network | 架构 | CRUD | 5种常见网络类型 (实验)

目录 1. Docker 为什么需要网络管理 2. Docker 网络架构简介 CNM&#xff08;Container Network Model&#xff09; Libnetwork 驱动 3. ⭕常见网络类型&#xff08;5 种&#xff09; 4. Docker 网络管理命令 一. bridge 网络 1. 操作案例&#xff1a;容器间网络通信 …

Spring Cloud Gateway快速入门Demo

1.什么是Spring Cloud Gateway&#xff1f; Spring Cloud Gateway 是一个基于 Spring Framework 和 Spring Boot 构建的 API 网关服务。它提供了一种简单而有效的方式来路由请求、提供跨领域的关注点&#xff08;如安全、监控/指标和弹性&#xff09;以及其他功能。Spring Clo…

【AI换脸整合包及教程】Rope:AI 换脸工具的功能、原理、应用

在人工智能技术迅猛发展的当下&#xff0c;AI 换脸技术无疑是近年来备受瞩目的焦点之一。其中&#xff0c;Rope 作为一款开源的 AI 换脸工具&#xff0c;因其出色的易用性和强大的功能而广受青睐。本文将对 Rope 的功能、技术原理、应用场景以及所面临的法律和伦理问题进行详细…

Yocto项目 - VIRTUAL-RUNTIME,它有什么用?

Yocto 项目是一个完整的 Linux 分布构建工具集&#xff0c;提供了构建完全自定义小型核心或完整应用的能力。在这样一个构建系统中&#xff0c;VIRTUAL-RUNTIME这个概念是应用构建和选择处理中的重要部分。这篇文章将从概念、优势、应用场景和实战案例几个方面&#xff0c;全面…

BB1-NHS ester被用于将各种生物活性分子与蛋白质或其他生物大分子进行共轭连接,2082771-52-4

CAS号&#xff1a;2082771-52-4 中文名&#xff1a;BB1-琥珀酰亚胺酯&#xff0c;BB1-活性酯 英文名&#xff1a;BB1-NHS ester&#xff0c;或BB1-Succinimidyl Ester 分子式&#xff1a;C32H32N6O4 分子量&#xff1a;564.63 纯度&#xff1a;≥95% 供应商&#xff1a;陕…

初级数据结构——栈

目录 前言一、栈的基本概念二、栈的实现方式三、栈的性能分析四、栈的应用场景五、栈的变体六、出栈入栈的动态图解七、代码模版八、总结结语 前言 数据结构栈&#xff08;Stack&#xff09;是一种线性的数据结构&#xff0c;它只允许在序列的一端&#xff08;称为栈顶&#x…

Jdbc学习笔记(四)--PreparedStatement对象、sql攻击(安全问题)

目录 &#xff08;一&#xff09;使用PreparedStatement对象的原因&#xff1a; 使用Statement对象编写sql语句会遇到的问题 ​编辑 &#xff08;二&#xff09;sql攻击 1.什么是sql攻击 2.演示sql攻击 &#xff08;三&#xff09;防止SQL攻击 1.PreparedStatement是什么 …

前端开发必备!2024年最全工具和框架资源大汇总

在前端开发的过程中&#xff0c;我们会使用各种工具、框架和库来提升开发效率和用户体验。随着技术的不断发展&#xff0c;前端生态系统逐渐丰富&#xff0c;开发者面临着越来越多的选择。本文将分享一些常见的前端资源&#xff0c;帮助开发者根据项目需求选择合适的工具。 1.…

备份可以起到什么作用?

在数字化时代&#xff0c;数据已经成为企业最宝贵的资产。然而&#xff0c;数据丢失和系统故障可能给企业带来巨大的损失。华为云备份服务作为一款全面的数据保护解决方案&#xff0c;致力于帮助企业保障数据安全&#xff0c;确保业务的连续性。九河云来给大家说一下华为云备份…

labview实现导出excel表格

有些项目数据读写在数据库里&#xff0c;有时客户会要求读写出来&#xff0c;这样就用到了labview把数据导出来&#xff0c;一般在测试程序界面&#xff0c;我们会把测试数据放在多列列表框里&#xff0c;这里我们需要对多列列表框进行操作。把多列列表框中的项名拆分出来。 接…

深度解读AI在数字档案馆中的创新应用:高效识别与智能档案管理

一、项目背景介绍 在信息化浪潮推动下&#xff0c;基于OCR技术的纸质档案电子化方案成为解决档案管理难题的有效途径。该方案通过先进的OCR技术&#xff0c;能够统一采集各类档案数据&#xff0c;无论是手写文件、打印文件、复古文档还是照片或扫描的历史资料&#xff0c;都能实…

vue3 vant4 NumberKeyboard 根据焦点输入

说明&#xff1a; 使用该组件时焦点在最后&#xff0c;客户要求可更改前面输错信息 实现逻辑 1.获取输入框焦点位置&#xff0c;此次采用的是ref&#xff0c;也可使用document相关 const inputElement numberKeyboardRef.value;if (inputElement) {cursorPosition.value i…

DHT22温湿度传感器(Espressif驱动)

DHT22&#xff1a; 温度范围&#xff1a;-40-80C温度精度&#xff1a;0.5C湿度范围&#xff1a;0-100%RH湿度精度&#xff1a;2-5%RH分辨率&#xff1a;0.1C / 0.1%RH #define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE#include <stdio.h> #include <freertos/FreeRTOS.h>…

数据结构——排序(续集)

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…

MySQL主从复制

主节点 server id 1. 更改server id 指定二进制日志文件目录 [rootmaster ~]#vim /etc/my.cnf.d/mariadb-server.cnf [mysqld] server-id8 log-bin 2. 新建目录并赋予权限 mkdir -p /data/mysql/logbin/chowm -R mysql.mysql /data/mysql/ 3. 重新启动 systemctl enabl…

酥皮点心,味蕾上的享受

甘肃酥皮点心承载着悠久的历史与深厚的文化底蕴。它起源于古老的丝绸之路&#xff0c;在岁月的长河中&#xff0c;经过一代又一代甘肃人的传承与创新&#xff0c;成为了如今令人陶醉的美食。每一块酥皮点心都仿佛在诉说着过去的故事&#xff0c;见证着甘肃大地的变迁与发展。食…