Linux驅動開發筆記(九)IIC子系統及其驅動

文章目錄

  • 前言
  • 一、IIC驅動框架
  • 二、總線驅動
    • 2.1 iic總線的運行機制
    • 2.2 重要數據結構
      • 2.2.1 i2c_driver結構體
      • 2.2.2 i2c總線結構體
    • 2.3 匹配規則
  • 三、設備樹的修改
  • 四、設備驅動的編寫
    • 4.1 相關API函數
      • 4.1.1 i2c_add_adapter( )
      • 4.1.2 i2c_register_driver( )
      • 4.1.3 i2c_transfer( )
      • 4.1.4 i2c_master_send( )
      • 4.1.5 i2c_master_recv( )
      • 4.1.6 i2c_transfer_buffer_flags( )
      • 4.1.7 i2c_del_driver( )
      • 4.1.8 i2c_set_clientdata
    • 4.2 MPU6050
      • 4.2.1 基本介紹
      • 4.2.2 主要特點
      • 4.2.3 引腳對應表
    • 4.3 驅動編寫
      • 4.3.1 IIC驅動的設計框架
      • 4.3.2 .probe函數
      • 4.3.3 .remove函數
      • 4.3.4 mpu6050初始化函數
      • 4.3.5 write/read函數
      • 4.3.6 report函數


前言

??IIC我們已經學習過很多次了,在應用部分我們已經介紹過其應用層的開發,這章我們將繼續驅動部分的開發。本次實驗采用MPU6050,使用了input子系統及IIC子系統構成。

一、IIC驅動框架

??i2c總線包括i2c設備(i2c_client)和i2c驅動(i2c_driver),當我們向linux中注冊設備或驅動的時候,按照i2c總線匹配規則進行配對,這也意味著我們不再需要手動創建,而是使用設備樹機制引入,設備樹節點是與paltform總線相配合使用,在匹配成功之后自動進入.probe函數。
在這里插入圖片描述
?I2C core框架
??提供了核心數據結構的定義和相關接口函數,用來實現I2C適配器驅動和設備驅動的注冊、注銷管理,以及I2C通信方法上層的、與具體適配器無關的代碼,為系統中每個I2C總線增加相應的讀寫方法。
?I2C總線驅動
??定義描述具體I2C總線適配器的i2c_adapter數據結構、實現在具體I2C適配器上的I2C總線通信方法,并由i2c_algorithm數據結構進行描述。 經過I2C總線驅動的的代碼,可以為我們控制I2C產生開始位、停止位、讀寫周期以及從設備的讀寫、產生ACK等。
?I2C 設備驅動
??I2C 設備驅動通過I2C適配器與CPU通信,其中主要包含i2c_driver和i2c_client數據結構,i2c_driver結構對應一套具體的驅動方法。i2c_client數據結構由內核根據具體的設備注冊信息自動生成,設備驅動根據硬件具體情況填充。

二、總線驅動

??一個完整的iic驅動函數包括兩部分,即iic總線驅動和設備驅動,而總線部分的驅動通常情況下在外設出廠時就由廠商提供,這里我們便簡單了解即可。

2.1 iic總線的運行機制

  1. 注冊i2C總線
  2. 將i2C驅動添加到i2C總線的驅動鏈表中
  3. 遍歷i2C總線上的設備鏈表,根據i2c_device_match函數進行匹配,如果匹配調用i2c_device_probe函數
  4. i2c_device_probe函數會調用I2C驅動的probe函數

2.2 重要數據結構

??在應用層的學習中我們已經介紹過i2c_algorithm,i2c_client和i2c_adapter結構體,感興趣可以回顧下。

2.2.1 i2c_driver結構體

struct i2c_driver {unsigned int class;int (*probe)(struct i2c_client *, const struct i2c_device_id *);int (*remove)(struct i2c_client *);struct device_driver driver;const struct i2c_device_id *id_table;int (*detect)(struct i2c_client *, struct i2c_board_info *);const unsigned short *address_list;struct list_head clients;...};
  • probe: i2c設備和i2c驅動匹配后,回調該函數指針。
  • id_table: struct i2c_device_id 要匹配的從設備信息。
  • address_list: 設備地址
  • clients: 設備鏈表
  • detect: 設備探測函數

2.2.2 i2c總線結構體

//定義總線,維護著兩個鏈表(I2C驅動、I2C設備),管理I2C設備和I2C驅動的匹配和刪除等
struct bus_type i2c_bus_type = {.name           = "i2c",.match          = i2c_device_match,.probe          = i2c_device_probe,.remove         = i2c_device_remove,.shutdown       = i2c_device_shutdown,};

2.3 匹配規則

??一般來說,i2c的匹配方式有三種,包括設備樹,ACPI和字符匹配,這部分的對比前章已經介紹過了。現在我們習慣性采用設備樹的匹配方式:

static int i2c_device_match(struct device *dev, struct device_driver *drv)
{struct i2c_client       *client = i2c_verify_client(dev);struct i2c_driver       *driver;//設備樹匹配方式,比較 I2C 設備節點的 compatible 屬性和 of_device_id 中的 compatible 屬性if (i2c_of_match_device(drv->of_match_table, client))return 1;//ACPI 匹配方式if (acpi_driver_match_device(dev, drv))return 1;driver = to_i2c_driver(drv);//i2c總線傳統匹配方式,比較 I2C設備名字和 i2c驅動的id_table->name 字段是否相等if (i2c_match_id(driver->id_table, client))return 1;return 0;
}

三、設備樹的修改

??下面是瑞芯微官方給出的ic3控制器的設備樹代碼:

//存放于“rk3568.dtsi”
i2c2: i2c@fe5b0000 {//驅動名稱compatible = "rockchip,rk3399-i2c";//寄存器reg = <0x0 0xfe5b0000 0x0 0x1000>;//時鐘源clocks = <&cru CLK_I2C2>, <&cru PCLK_I2C2>;clock-names = "i2c", "pclk";//中斷源interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;pinctrl-names = "default";pinctrl-0 = <&i2c2m0_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";//存放于“rk3568-pinctrl.dtsi”
i2c2 {/omit-if-no-ref/i2c2m0_xfer: i2c2m0-xfer {rockchip,pins =/* i2c2_sclm0 */<0 RK_PB5 1 &pcfg_pull_none_smt>,/* i2c2_sdam0 */<0 RK_PB6 1 &pcfg_pull_none_smt>;};/omit-if-no-ref/i2c2m1_xfer: i2c2m1-xfer {rockchip,pins =/* i2c2_sclm1 */<4 RK_PB5 1 &pcfg_pull_none_smt>,/* i2c2_sdam1 */<4 RK_PB4 1 &pcfg_pull_none_smt>;};};

??接下來就是我們要編寫的內容,這部分編寫方式和以前一樣即可。

&i2c2 {status = "okay";pinctrl-names = "default";pinctrl-0 = <&i2c2m0_xfer>;     #address-cells = <1>;#size-cells = <0>;/*添加你的I2C設備參考*/myi2c: myi2c@68 {compatible = "company,myi2c";reg = <0x68>;status = "okay";};

四、設備驅動的編寫

4.1 相關API函數

4.1.1 i2c_add_adapter( )

??使用這個函數時,不需要提前指定適配器編號,內核會負責管理和分配編號,適合于大多數情況下的使用。

//自動分配 I2C 適配器編號
int i2c_add_adapter(struct i2c_adapter *adapter);

??適配器編號(adapter->nr)在注冊過程中由系統自動設置,具體的步驟如下:

  • 適配器初始化:調用這個函數之前,需要先初始化 i2c_adapter 結構體,填充相關字段。
  • 自動分配編號:內核會自動選擇一個可用的編號,并將其分配給 adapter->nr。
  • 注冊適配器:將適配器注冊到 I2C子系統中,使其可以被使用。

注:相似地還還存在int i2c_add_numbered_adapter(struct i2c_adapter *adapter)函數,這個函數用于手動設置 I2C 適配器編號。調用這個函數之前,需要先初始化 i2c_adapter 結構體,并填充 adapter->nr 字段和其他相關字段。
i2c_register_driver 函數用于在 Linux 內核中注冊一個 I2C 驅動。這個函數是 I2C 子系統的一部分,用于將一個 I2C 驅動程序注冊到 I2C 驅動程序模型中,以便內核能夠識別并管理該驅動程序。

4.1.2 i2c_register_driver( )

??這個函數是 I2C 子系統的一部分,用于將一個 I2C 驅動程序注冊到 I2C 驅動程序模型中,以便內核能夠識別并管理該驅動程序。

//在 Linux 內核中注冊一個 I2C 驅動
int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
  • 參數:
    • owner:通常使用 THIS_MODULE 宏來指定當前模塊
    • driver:指向一個 i2c_driver 結構體,該結構體包含了驅動程序的相關信息和操作函數
  • 返回值:
    • 0:成功注冊
    • 負數:注冊失敗

注:#define i2c_add_driver(driver)宏定義是對i2c_register_driver函數的調用,也可以直接使用這個宏定義進行注冊

4.1.3 i2c_transfer( )

??i2c_transfer 是一個底層函數,它可以執行多條消息的讀寫操作。

//在 I2C 總線上進行數據傳輸
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
  • 參數
    • adap:指向 i2c_adapter 結構體的指針,表示 I2C 適配器。
    • msgs:指向 i2c_msg 結構體數組的指針,每個 i2c_msg 結構體表示一條 I2C 消息。
    • num:消息數量。
  • 返回值
    • 正值:表示成功傳輸的消息數量。
    • 負值:表示傳輸失敗,返回一個負的錯誤代碼。

注:i2c_msg結構體之前在應用開發實驗時已經介紹過了, 這里簡單回憶一下:

//描述一個iic消息
struct i2c_msg {__u16 addr;     //iic設備地址__u16 flags;	//消息傳輸方向和特性。I2C_M_RD:表示讀取消息;0:表示發送消息__u16 len;      //消息數據的長度__u8 *buf;      //字符數組存放消息,作為消息的緩沖區... 
};

4.1.4 i2c_master_send( )

??i2c_master_send 是一個便捷函數,用于向 I2C 設備發送數據。

復制代碼
int i2c_master_send(const struct i2c_client *client, const char *buf, int count);
  • 參數
    • client:指向 i2c_client 結構體的指針,表示目標 I2C 設備。
    • buf:指向數據緩沖區的指針。
    • count:要發送的數據長度。
  • 返回值
    • 正值:表示成功發送的字節數。
    • 負值:表示發送失敗,返回一個負的錯誤代碼。

4.1.5 i2c_master_recv( )

??i2c_master_recv 是一個便捷函數,用于從 I2C 設備接收數據。

int i2c_master_recv(const struct i2c_client *client, char *buf, int count);
  • 參數
    • client:指向 i2c_client 結構體的指針,表示目標 I2C 設備。
    • buf:指向接收緩沖區的指針。
    • count:要接收的數據長度。
  • 返回值
    • 正值:表示成功接收的字節數。
    • 負值:表示接收失敗,返回一個負的錯誤代碼。

4.1.6 i2c_transfer_buffer_flags( )

//用于在 I2C 總線上進行帶有特定標志的數據傳輸
int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf, int count, u16 flags);
  • 參數
    • client:指向 i2c_client 結構體的指針,表示目標 I2C 設備。
    • buf:指向數據緩沖區的指針。
    • count:要傳輸的數據長度。
    • flags:傳輸標志。
  • 返回值
    • 正值:表示成功傳輸的字節數。
    • 負值:表示傳輸失敗,返回一個負的錯誤代碼。

4.1.7 i2c_del_driver( )

??這個函數與 i2c_register_driver 相對應,i2c_register_driver 用于注冊一個 I2C 驅動程序,而 i2c_del_driver 用于注銷它。

//從I2C 子系統中注銷一個 I2C 驅動程序
void i2c_del_driver(struct i2c_driver *driver);
  • 參數
    • driver:指向一個 i2c_driver 結構體,該結構體表示要注銷的 I2C 驅動程序

4.1.8 i2c_set_clientdata

??這個函數用于在I2C驅動的probe函數中設置私有數據指針。這個私有數據通常是指向設備結構體或者其他相關數據結構的指針,它允許驅動在后續的操作中能夠方便地訪問這些數據。

void i2c_set_clientdata(struct i2c_client *client, void *data);
  • 參數
    • client:指向I2C設備客戶端結構體的指針。
    • data:要設置的私有數據指針,通常指向一個自定義的設備結構體或其他相關數據。

4.2 MPU6050

4.2.1 基本介紹

??MPU6050是全球首例整合性6軸(3軸陀螺儀+3軸加速度計)運動處理組件,也可以通過擴展實現9軸運動處理(在連接三軸磁傳感器后)。它集成了三軸MEMS陀螺儀和三軸MEMS加速度計,以及一個可擴展的數字運動處理器DMP(Digital Motion Processor)。MPU6050通過I2C接口與微控制器通信,廣泛應用于需要精確姿態測量的場合,如無人機、機器人和智能穿戴設備等。

4.2.2 主要特點

  1. 整合性:MPU6050免除了組合陀螺儀與加速器時間軸之差的問題,減少了大量的封裝空間。
  2. 靈活性:MPU6050的角速度全格感測范圍為±250、±500、±1000與±2000°/sec(dps),可準確追蹤快速與慢速動作;用戶可程式控制的加速器全格感測范圍為±2g、±4g、±8g與±16g,滿足各種應用需求。
  3. 接口:MPU6050支持最高至400kHz的I2C接口,對于需要高速傳輸的應用,也可使用SPI接口(但請注意,SPI接口僅在MPU-6000上可用)。
  4. 穩定性:MPU6050具有內建的溫度感測器和在工作環境下僅有±1%變動的振蕩器,保證了測量數據的穩定性。
  5. 尺寸與封裝:MPU6050采用QFN封裝(無引線方形封裝),尺寸為4x4x0.9mm,可承受最大10000g的沖擊。
  6. 電源:VDD供電電壓為2.5V±5%、3.0V±5%、3.3V±5%;VDDIO為1.8V±5%或VDD。
  7. 功耗:陀螺儀運作電流5mA,待命電流5μA;加速器運作電流350μA,省電模式電流20μA@10Hz。
  8. 性能:陀螺儀敏感度131 LSBs/°/sec,加速度計范圍±2g至±16g。

4.2.3 引腳對應表

MPU6050引腳說明泰山派引腳
SCLSCL引腳GPIO0_B5
SDASDA引腳GPIO0_B6
XDA沒有使用
XCL沒有使用
AD0接地GND
INT(Interrupt)懸空或者接地
GNDGNDGND
VCC電源3.3V

4.3 驅動編寫

4.3.1 IIC驅動的設計框架

??本次實驗大致采用input子系統和IIC子系統,這里著重講一下這部分的設計思路:

  1. 本實驗采用設備樹匹配的方式進行匹配,故而需要設置i2c_driver結構體。
//定義ID匹配表
static const struct i2c_device_id gtp_device_id[] = {{"company,myi2c", 0},{}
};
//定義設備樹匹配表
static const struct of_device_id mpu6050_of_match_table[] = {{.compatible = "company,myi2c"},{}
};
//定義i2c設備結構體
struct i2c_driver mpu6050_driver = {.probe = mpu6050_probe,.remove = mpu6050_remove,.id_table = gtp_device_id,.driver = {.owner = THIS_MODULE,.name = "company,myi2c",.of_match_table = mpu6050_of_match_table,},
};
  1. 出入口函數的編寫,通常情況下這里需要編寫module_init和module_exti,并且在其中分別使用i2c_register_driver( )函數和i2c_del_driver( )函數進行 i2c 驅動的注冊和注銷。但是這里引入一個module_i2c_driver(driver) 宏定義,這個宏定義可以自動進行iic總線的注冊和注銷,故而不需要前兩個函數的編寫。
  2. probe函數的編寫,這部分內容我們需要的進行內存申請,之后便可以進行選擇利用字符設備的方式還是input子系統,筆者這里選擇趁熱打鐵使用input設備,這里流程不太熟悉的可以回顧上章內容。之后利用i2c_set_clientdata將數據和設備鏈接起來。
  3. remove函數的編寫,這部分與probe函數對應即可,如果選擇字符設備的方式,則依次進行device_destroy(設備刪除)、class_destroy(清除類)、cdev_del(清除設備號)、unregister_chrdev_region(注銷字符設備);若采用input的子系統,則僅需要使用input_unregister_device(注銷input設備即可)。
  4. 具體外設的初始化、讀、寫函數的編寫,這部分內容根據廠商提供的寄存器、時序圖操作即可。
  5. 若使用字符設備的話,這里還需要編寫operations結構體相關函數,包括open、write、read、release,并利用cdev_init()函數與設備進行綁定。

4.3.2 .probe函數

static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id){struct mpu6050_data *data;int ret = 0;printk(KERN_EMERG "mpu6050_probe enter!\n");data = devm_kzalloc(&client->dev, sizeof(struct mpu6050_data), GFP_KERNEL);if (!data){printk(KERN_EMERG "devm_kzalloc err!\n");return -ENOMEM;}data->client = client;ret = mpu6050_init_device(client);if(ret < 0){printk(KERN_EMERG "mpu6050_init_device err!\n");return ret;}data->input_dev = devm_input_allocate_device(&client->dev);if (!data->input_dev){printk(KERN_EMERG "devm_input_allocate_device err!\n");return -ENOMEM;}data->input_dev->name = "mpu6050";data->input_dev->id.bustype = BUS_I2C;input_set_abs_params(data->input_dev, ABS_X, -32768, 32767, 0, 0);input_set_abs_params(data->input_dev, ABS_Y, -32768, 32767, 0, 0);input_set_abs_params(data->input_dev, ABS_Z, -32768, 32767, 0, 0);input_set_abs_params(data->input_dev, ABS_RX, -32768, 32767, 0, 0);input_set_abs_params(data->input_dev, ABS_RY, -32768, 32767, 0, 0);input_set_abs_params(data->input_dev, ABS_RZ, -32768, 32767, 0, 0);ret = input_register_device(data->input_dev);if (ret < 0){printk("input_register_device err!\n");return ret;}i2c_set_clientdata(client, data);INIT_DELAYED_WORK(&data->work, mpu6050_report_data);schedule_delayed_work(&data->work, msecs_to_jiffies(100));return 0;
}

4.3.3 .remove函數

static int mpu6050_remove(struct i2c_client *client){struct mpu6050_data *data = i2c_get_clientdata(client);printk(KERN_EMERG "mpu6050_remove enter!\n");cancel_delayed_work_sync(&data->work);input_unregister_device(data->input_dev);return 0;
}

4.3.4 mpu6050初始化函數

static int mpu6050_init_device(struct i2c_client *client)
{int error = 0;error += i2c_write_mpu6050(client, PWR_MGMT_1, 0x00);error += i2c_write_mpu6050(client, SMPLRT_DIV, 0x07);error += i2c_write_mpu6050(client, CONFIG, 0x06);error += i2c_write_mpu6050(client, ACCEL_CONFIG, 0x01);if (error < 0) {printk(KERN_DEBUG "mpu6050_init_device error\n");return error;}return 0;
}

4.3.5 write/read函數

static int i2c_write_mpu6050(struct i2c_client *mpu6050_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;send_msg.addr = mpu6050_client->addr;send_msg.flags = 0;send_msg.buf = write_data;send_msg.len = 2;error = i2c_transfer(mpu6050_client->adapter, &send_msg, 1);if (error != 1) {printk(KERN_DEBUG "i2c_write_mpu6050 error\n");return -EIO;}return 0;
}static int i2c_read_mpu6050(struct i2c_client *mpu6050_client, u8 address, void *data, u32 length){int error = 0;u8 address_data = address;struct i2c_msg mpu6050_msg[2];mpu6050_msg[0].addr = mpu6050_client->addr;mpu6050_msg[0].flags = 0;mpu6050_msg[0].buf = &address_data;mpu6050_msg[0].len = 1;mpu6050_msg[1].addr = mpu6050_client->addr;mpu6050_msg[1].flags = I2C_M_RD;mpu6050_msg[1].buf = data;mpu6050_msg[1].len = length;error = i2c_transfer(mpu6050_client->adapter, mpu6050_msg, 2);if (error != 2) {printk(KERN_DEBUG "i2c_read_mpu6050 error\n");return -EIO;}return 0;
}

4.3.6 report函數

static void mpu6050_report_data(struct work_struct *work)
{struct mpu6050_data *data = container_of(work, struct mpu6050_data, work.work);struct i2c_client *client = data->client;s16 accel_data[3];s16 gyro_data[3];u8 buffer[14];int ret;ret = i2c_read_mpu6050(client, ACCEL_XOUT_H, buffer, 14);if (ret < 0) {dev_err(&client->dev, "Failed to read data: %d\n", ret);return;}accel_data[0] = (buffer[0] << 8) | buffer[1];accel_data[1] = (buffer[2] << 8) | buffer[3];accel_data[2] = (buffer[4] << 8) | buffer[5];gyro_data[0] = (buffer[8] << 8) | buffer[9];gyro_data[1] = (buffer[10] << 8) | buffer[11];gyro_data[2] = (buffer[12] << 8) | buffer[13];//用于報告絕對坐標事件input_report_abs(data->input_dev, ABS_X, accel_data[0]);input_report_abs(data->input_dev, ABS_Y, accel_data[1]);input_report_abs(data->input_dev, ABS_Z, accel_data[2]);input_report_abs(data->input_dev, ABS_RX, gyro_data[0]);input_report_abs(data->input_dev, ABS_RY, gyro_data[1]);input_report_abs(data->input_dev, ABS_RZ, gyro_data[2]);input_sync(data->input_dev);schedule_delayed_work(&data->work, msecs_to_jiffies(100));
}

免責聲明:本內容部分參考野火科技及其他相關公開資料,若有侵權或者勘誤請聯系作者。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/36637.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/36637.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/36637.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring+SpringMVC+MyBatis整合

目錄 1.SSM介紹1.1 什么是SSM&#xff1f;1.2 SSM框架1.2.1 Spring1.2.2 SpringMVC1.2.3 MyBatis 2.SSM框架整合2.1 建庫建表2.2 創建工程2.3 pom.xml2.4 log4j.properties2.5 db.properties2.6 applicationContext-dao.xml2.7.applicationContext-tx.xml2.8 applicationContex…

Redis-在springboot環境下執行lua腳本

文章目錄 1、什么lua2、創建SpringBoot工程3、引入相關依賴4、創建LUA腳本5、創建配置類6、創建啟動類7、創建測試類 1、什么lua “Lua”的英文全稱是“Lightweight Userdata Abstraction Layer”&#xff0c;意思是“輕量級用戶數據抽象層”。 2、創建SpringBoot工程 3、引入相…

新能源汽車CAN總線故障定位與干擾排除的幾個方法

CAN總線是目前最受歡迎的現場總線之一,在新能源車中有廣泛應用。新能源車的CAN總線故障和隱患將影響駕駛體驗甚至行車安全,如何進行CAN總線故障定位及干擾排除呢? 目前,國內機動車保有量已經突破三億大關。由于大量的燃油車帶來嚴峻的環境問題,因此全面禁售燃油車的日程在…

汽車租賃系統

摘 要 隨著汽車租賃市場的快速發展&#xff0c;為了提高汽車租賃服務的效率和用戶體驗&#xff0c;本論文設計與實現了一款基于Java的汽車租賃系統。 該系統采用B/S架構&#xff0c;利用JavaWeb技術和MySQL數據庫實現了車輛信息管理、在線車輛租賃、門店出車模塊、租賃訂單信息…

1. Tensorrt-llm 基礎

1.Tensorrt-llm安裝 os: ubuntu 22.04 1.1搭建docker 環境 切換到 root 用戶 sodu passwd root 更新apt sudo apt-get update --fix-missing 更新docker sudo apt-get upgrade docker-ce 安裝nvidia 容器運行時&#xff0c;避免如下錯誤 Error response from daemon…

Android Kotlin 中的閉包函數

閉包函數是現代編程語言中一個重要的概念&#xff0c;Kotlin 作為一種現代的 JVM 語言&#xff0c;自然也支持閉包函數。本文將詳細介紹閉包函數的概念、在Kotlin 中的使用方法&#xff0c;以及一些常見的應用場景。 什么是閉包函數&#xff1f; 閉包函數&#xff0c;也稱為閉…

每天一個項目管理概念之WBS

項目管理中的工作分解結構&#xff08;Work Breakdown Structure&#xff0c;簡稱WBS&#xff09;是規劃和管理項目的核心工具之一&#xff0c;它通過將復雜的項目任務細分為更小、更易管理的部分來提高項目執行的效率與效果。WBS不僅有助于明確項目范圍&#xff0c;還為時間管…

[RPI] istoreos安裝esphome

esphome可以提供了一個集成的編譯環境,同時他又可以通過無線方式更新firmware,這無疑方便了我們的開發工作。 istoreos商店沒有提供esphome,所以我們需要自己用‘類似’命令行的方式來安裝, 1. 拉取esphome鏡像 依次點擊左側邊欄Docker -> 鏡像,輸入esphome/esphome…

【LeetCode面試經典150題】117. 填充每個節點的下一個右側節點指針 II

一、題目 117. 填充每個節點的下一個右側節點指針 II - 力扣&#xff08;LeetCode&#xff09; 給定一個二叉樹&#xff1a; struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每個 next 指針&#xff0c;讓這個指針指向其下一個右側節點。如果找不到下一個…

React@16.x(42)路由v5.x(7)常見應用場景(4)- 路由切換動畫

目錄 1&#xff0c;實現路由切換基礎樣式 2&#xff0c;使用 CSSTransition 添加動畫1&#xff0c;自定義動畫組件 *TransitionRoute.jsx*2&#xff0c;*App.jsx*3&#xff0c;樣式改動 3&#xff0c;注意點 通過一個例子來說明如何實現。 1&#xff0c;實現路由切換 基礎樣式…

[DDD] 領域驅動設計簡介

領域驅動設計 Domain Driven Design 1 DDD簡介 領域驅動設計&#xff08;Domain-Driven Design&#xff0c;簡稱DDD&#xff09;是一種軟件開發方法論&#xff0c;它強調軟件設計應緊密圍繞業務領域模型進行。DDD的核心思想是將實現與業務邏輯分離&#xff0c;通過深入理解和…

億發進銷存管理系統+:多終端無縫協同,實現經營銷售場景全覆蓋

億發軟件憑借產品、市場、業務的深入理解&#xff0c;在進銷存基礎上進行了延伸&#xff0c;推出多終端、一體化的“進銷存管理系統”多元產品矩陣。對企業經營中進貨、出貨、銷售、付款等進行全程跟蹤管理。有效輔助企業解決業務管理、銷售管理、庫存管理、財務管理等一系列問…

Java路徑操縱漏洞示例與解決賞析之一

示例代碼 public static List<File> findClassesInPackage(String codePath,String packageName, boolean recursive) {List<File> classFiles = new ArrayList<>();String packagePath = packageName.replace(., /);File directory = new File(codePath + &…

【大數據】—量化交易實戰案例雙均線策略(移動平均線)

聲明&#xff1a;股市有風險&#xff0c;投資需謹慎&#xff01;本人沒有系統學過金融知識&#xff0c;對股票有敬畏之心沒有踏入其大門&#xff0c;今天用另外一種方法模擬炒股&#xff0c;后面的模擬的實戰全部用同樣的數據&#xff0c;最后比較哪種方法賺的錢多。 量化交易…

【項目實訓】各種反爬策略及爬蟲困難點總結

在這里&#xff0c;我總結了本次項目的數據收集過程中遇到的反爬蟲策略以及一些爬蟲過程中容易出現問題的地方。 user-agent 簡單的設置user-agent頭部為瀏覽器即可&#xff1a; 爬取標簽中帶href屬性的網頁 對于顯示崗位列表的頁面&#xff0c;通常檢查其源代碼就會發現&…

深入理解鏈表:基礎概念、操作及應用

前言 鏈表&#xff08;Linked List&#xff09;是一種重要的數據結構&#xff0c;廣泛應用于各種算法和系統設計中。本文將詳細介紹鏈表的基本概念、類型、基本操作及其在實際編程中的應用&#xff0c;并使用C語言代碼示例進行說明。 鏈表的基本概念 鏈表是一種線性數據結構…

【數據結構】(C語言):動態數組

動態數組&#xff1a; 內存區域連續&#xff0c;即每個元素的內存地址連續。可用索引查看元素&#xff0c;數組[索引號]。指定位置刪除元素&#xff0c;該位置之后的元素全部往前移動一位。指定位置添加元素&#xff0c;從最后到該位置的元素全部往后移動一位。物理大小&#…

【保姆級講解ECMAScript和JavaScript之間的區別】

&#x1f3a5;博主&#xff1a;程序員不想YY啊 &#x1f4ab;CSDN優質創作者&#xff0c;CSDN實力新星&#xff0c;CSDN博客專家 &#x1f917;點贊&#x1f388;收藏?再看&#x1f4ab;養成習慣 ?希望本文對您有所裨益&#xff0c;如有不足之處&#xff0c;歡迎在評論區提出…

mysql 升級到8.0

MySQL :: MySQL 8.0 Reference Manual :: 3.7 Upgrading MySQL Binary or Package-based Installations on Unix/Linux 2種升級方式&#xff1a; In-Place Upgrade &#xff1a; data目錄替換 Logical Upgrade&#xff1a; 通過 mysqldump 導出為sql文本后&#xff0c;導入…

全面國產化信創適配改造方案說明

一、概敘 系統的全面國產化適配改造需要從多個方面進行考慮&#xff0c;改造前需要進行充分的論證&#xff0c;在滿足具體業務場景的前提下&#xff0c;以確保系統的穩定性和安全性&#xff0c;同時還要考慮技術的發展&#xff0c;不斷優化和更新。因此全面國產化適配改造也面臨…