【RK3568 平臺I2C協議與AGS10驅動開發】

RK3568 平臺I2C協議與AGS10驅動開發

  • 一、I2C 總線協議基礎
  • 二、I2C 通信過程詳解
  • 三、AGS10 傳感器概述
  • 四、AGS10驅動開發
    • 1. 硬件連接
    • 2. 設備樹(DTS)配置
    • 3. 內核驅動開發
  • 五、調試與驗證
  • 六、總結

引言

在嵌入式系統開發中,傳感器數據采集是常見需求。本文將詳細介紹如何在 RK3568 平臺上開發 AGS10 空氣質量傳感器的 Linux 驅動,同時深入解析 I2C 總線協議的工作原理。通過本文,你將掌握 I2C 通信的核心概念,并學會如何為特定傳感器開發 Linux 內核驅動。

一、I2C 總線協議基礎

I2C(Inter-Integrated Circuit)是由飛利浦公司開發的一種串行通信協議,廣泛應用于短距離、低速的設備間通信。它具有以下特點:

  1. 雙線制:僅需兩根信號線
    SDA(Serial Data Line):數據傳輸線
    SCL(Serial Clock Line):時鐘線
  2. 主從架構:
    主設備(Master):控制總線,發起通信
    從設備(Slave):被動響應主設備請求
  3. 尋址機制:
    每個從設備有唯一的 7 位或 10 位地址
    地址在通信開始時由主設備發送
  4. 傳輸速率:
    標準模式:100kHz
    快速模式:400kHz
    高速模式:3.4MHz
  5. 信號特征:
    開漏輸出,需外接上拉電阻
    邏輯 0:低電平;邏輯 1:高阻態(由上拉電阻拉至高電平)

二、I2C 通信過程詳解

I2C 通信的基本流程如下:

  1. 起始條件(Start):
    主設備在 SCL 為高電平時,將 SDA 從高電平拉至低電平
    標志一次通信的開始
  2. 地址幀:
    主設備發送從設備地址(7 位或 10 位)
    第 8 位為 R/W 位(0 表示寫,1 表示讀)
  3. 應答位(ACK/NACK):
    每傳輸 8 位數據后,接收方需發送一個 ACK(低電平)或 NACK(高電平)
    表示是否成功接收數據
  4. 數據傳輸:
    根據 R/W 位決定數據方向
    寫操作:主設備→從設備
    讀操作:從設備→主設備
  5. 停止條件(Stop):
    主設備在 SCL 為高電平時,將 SDA 從低電平拉至高電平
    標志一次通信的結束
  6. 重復起始條件(Repeated Start):
    在不發送 Stop 條件的情況下,再次發送 Start 條件
    用于連續傳輸不同地址的數據

三、AGS10 傳感器概述

AGS10 是奧松電子推出的一款高精度空氣質量傳感器,用于檢測空氣中的揮發性有機化合物(VOCs)。其主要特性包括:
在這里插入圖片描述
傳感器采用標準I2C通信協議,適應多種設備。I2C的物理接口包含串行數據信號(SDA)與串行
時鐘信號(SCL)兩個接口。兩個接口需通過1kΩ~10kΩ電阻上拉至VDD。SDA用于讀、寫傳感器數
據。SCL上電必須保持高電平直到進行I2C通信開始,否則會引起I2C通訊不良。當I2C通信時SCL用于主機與傳感器之間的通訊同步。多個I2C設備可以共享總線,但是只能允許一個主機設備出現在總線上。傳感器I2C器件地址為0x1A(7-bit),寫指令為0x34,讀指令為0x35。通訊速率不高于15kHz。
在這里插入圖片描述
在這里插入圖片描述
命令集合:
在這里插入圖片描述

四、AGS10驅動開發

1. 硬件連接

AGS10 SCL ---> RK3568 I2C3_SCL_MO
AGS10 SDA ---> RK3568 I2C3_SDA_MO
AGS10 GND ---> RK3568 GND
AGS10 VCC ---> RK3568 VCC3V3_SYS

在這里插入圖片描述

2. 設備樹(DTS)配置

在 RK3568 的設備樹文件kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi中添加 ags10節點:
在這里插入圖片描述

&i2c3 {  clock-frequency = <15000>;status = "okay";ags10: ags10@1a {compatible = "aosong,ags10";reg = <0x1A>;status = "okay";};
};

i2c3定義如下:
kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi
在這里插入圖片描述
i2c3引腳復用如下:
kernel/arch/arm64/boot/dts/rockchip/rk3568-pinctrl.dtsi
在這里插入圖片描述

3. 內核驅動開發

i2c函數介紹:

函數原型

int i2c_master_send(struct i2c_client *client, const char *buf, int count);

功能

  • 向指定 I2C 從設備發送數據,適用于簡單的寫操作(如配置寄存器)。

參數

  • client:指向目標 I2C 設備的客戶端結構體指針
  • buf:指向要發送的數據緩沖區
  • count:要發送的字節數

返回值

  • 成功:返回實際發送的字節數(通常等于count
  • 失敗:返回負值錯誤碼(如-ENODEV-EIO等)

函數原型

int i2c_master_recv(struct i2c_client *client, char *buf, int count);

功能

  • 從指定 I2C 從設備接收數據,適用于簡單的讀操作(如讀取傳感器數據)。

參數

  • client:指向目標 I2C 設備的客戶端結構體指針
  • buf:指向接收數據的緩沖區
  • count:期望接收的字節數

返回值

  • 成功:返回實際發送的字節數(通常等于count
  • 失敗:返回負值錯誤碼(如-ENODEV-EIO等)

函數原型

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);

功能

  • 發送一個或多個 I2C 消息(struct i2c_msg數組),支持復雜的通信序列(如帶重復 START 的復合操作)。

參數

  • adap:指向 I2C 適配器的指針
  • msgs:指向struct i2c_msg數組的指針
  • num:消息數組的長度(即消息數量)

返回值

  • 成功:返回實際成功傳輸的消息數(等于num
  • 失敗:返回負值錯誤碼,或已成功傳輸的消息數(小于num

struct i2c_msg結構

struct i2c_msg {__u16 addr;     /* 從設備地址 */__u16 flags;    /* 標志位(如I2C_M_RD表示讀操作) */__u16 len;      /* 消息長度 */__u8 *buf;      /* 數據緩沖區 */
};
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/fs.h>       
#include <linux/miscdevice.h> // 包含miscdevice相關定義
#include <linux/uaccess.h>/* 寄存器命令 */
#define AGS10_CMD_READ_TVOC    0x00    // 讀取TVOC值
#define AGS10_CMD_CALIBRATE    0x01    // 校準命令
#define AGS10_CMD_READ_VERSION 0x11    // 讀取固件版本
#define AGS10_CMD_RESISTANCE  0x20    // 讀取阻值#define AGS10_IOC_MAGIC  'a'/* 定義命令 */
#define AGS10_CMD_GET_TVOC    _IOR(AGS10_IOC_MAGIC, 1, u16)  // 讀取TVOC值
#define AGS10_CMD_CALIBRATE   _IO(AGS10_IOC_MAGIC, 2)         // 觸發校準struct ags10_data {struct i2c_client *client;struct mutex lock;struct miscdevice miscdev;u8 firmware_version;bool initialized;
};static int ags10_i2c_write(struct i2c_client *client, u8 cmd, u8 *data, int len)
{int ret;u8 buf[len + 1];memcpy(buf + 1, data, len);/* 發送命令 */buf[0] = cmd;ret = i2c_master_send(client, buf, len + 1);if (ret != 1) {dev_err(&client->dev, "Failed to send command: %d\n", ret);return ret;}return 0;
}/* 發送命令并讀取響應 */
static int ags10_send_command(struct i2c_client *client, u8 cmd, u8 *data, int len)
{int ret;u8 buf[16];u8 addr = client->addr;/* 發送命令 */struct i2c_msg msgs[] = {[0] = {.addr = addr,.flags = 0,.len = sizeof(u8),.buf = &addr,},[1] = {.addr = addr,.flags = 0,.len = sizeof(u8),.buf = &cmd,},};ret = i2c_transfer(client->adapter, msgs, 2);printk(KERN_INFO "ags10_send_command ret = %d, addr = %x, cmd = %x", ret, addr, cmd);/*buf[0] = cmd;ret = i2c_master_send(client, buf, 1);if (ret != 1) {dev_err(&client->dev, "Failed to send command: %d\n", ret);return ret;}*//* 等待傳感器響應 */msleep(10);/* 讀取響應 */if (data && len > 0) {ret = i2c_master_recv(client, data, len);if (ret != len) {dev_err(&client->dev, "Failed to read response: %d\n", ret);return ret;}}return 0;
}/* 計算CRC校驗 */
static u8 ags10_calculate_crc(u8 *data, int len)
{u8 crc = 0xFF;int i, j;for (i = 0; i < len; i++) {crc ^= data[i];for (j = 0; j < 8; j++) {if (crc & 0x80) {crc = (crc << 1) ^ 0x31;} else {crc <<= 1;}}}return crc;
}/* 讀取TVOC值 (單位: ppb) */
static int ags10_read_tvoc(struct ags10_data *data, u16 *tvoc)
{int ret;u8 buf[5];  // 5字節緩沖區: [STATUS][DATA_H][DATA_M][DATA_L][CRC]u32 raw_value;mutex_lock(&data->lock);/* 發送讀取TVOC命令并接收4字節數據 */ret = ags10_send_command(data->client, AGS10_CMD_READ_TVOC, buf, 5);if (ret) {mutex_unlock(&data->lock);return ret;}int i;for(i = 0; i < 5; i++){printk(KERN_INFO "ags10_read_tvoc[%d] = 0x%x", i, buf[i]);}/* 驗證CRC (校驗前3個數據字節) */if (buf[4] != ags10_calculate_crc(&buf[0], 4)) {dev_err(&data->client->dev, "TVOC CRC check failed: 0x%02X vs 0x%02X\n",buf[4], ags10_calculate_crc(&buf[0], 4));mutex_unlock(&data->lock);return -EIO;}/* 計算TVOC值 (24位原始值轉換為ppb) */raw_value = ((u32)buf[1] << 16) | ((u32)buf[2] << 8) | buf[3];printk(KERN_INFO "ags10_read_tvoc raw_value = 0x%x", raw_value);*tvoc = (raw_value);mutex_unlock(&data->lock);return 0;
}//零點恢復校準
static int ags10_reset_calibration(struct ags10_data *data)
{	int ret;u8 buf[5] = {0x00, 0x0C, 0xFF, 0xFF, 0x81};mutex_lock(&data->lock);ret = ags10_i2c_write(data->client, AGS10_CMD_CALIBRATE, buf, 5);if (ret) {dev_err(&data->client->dev, "ags10_reset_calibration failed\n");return ret;}mutex_unlock(&data->lock);msleep(30);  // 校準需要約30msreturn 0;}/*以當前阻值為零點校準*/
static int ags10_current_resistance_calibration(struct ags10_data *data)
{	int ret;u8 buf[5] = {0x00, 0x0C, 0x00, 0x00, 0xAC};mutex_lock(&data->lock);ret = ags10_i2c_write(data->client, AGS10_CMD_CALIBRATE, buf, 5);if (ret) {dev_err(&data->client->dev, "ags10_current_resistance_calibration failed\n");return ret;}mutex_unlock(&data->lock);msleep(30);  // 校準需要約30msreturn 0;}/*以raw為零點校準*/
static int ags10_calibration(struct ags10_data *data, uint16_t raw)
{	int ret;u8 buf[5] = {0x00, 0x0C, (raw >> 8) & 0xFF, (raw >> 0) & 0xFF, };buf[4] = ags10_calculate_crc(buf, 4);mutex_lock(&data->lock);ret = ags10_i2c_write(data->client, AGS10_CMD_CALIBRATE, buf, 5);if (ret) {dev_err(&data->client->dev, "ags10_calibration failed\n");return ret;}mutex_unlock(&data->lock);msleep(30);  // 校準需要約30msreturn 0;}/* 讀取固件版本 */
static int ags10_read_version(struct ags10_data *data)
{int ret;u8 buf[5]; //0-2:[Reserved][Version][CRC]mutex_lock(&data->lock);/* 發送讀取版本命令 */ret = ags10_send_command(data->client, AGS10_CMD_READ_VERSION, buf, 5);if (ret) {mutex_unlock(&data->lock);return ret;}int i;for(i = 0; i < 5; i++){printk(KERN_INFO "ags10_read_version[%d] = 0x%x", i, buf[i]);}/* 驗證CRC */if (buf[4] != ags10_calculate_crc(&buf[0], 4)) {dev_err(&data->client->dev, "CRC check failed\n");mutex_unlock(&data->lock);return -EIO;}data->firmware_version = buf[3];dev_info(&data->client->dev, "Firmware version: %d\n", data->firmware_version);mutex_unlock(&data->lock);return 0;
}/* 文件操作: 讀取 */
static ssize_t ags10_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{struct ags10_data *data = filp->private_data;u16 tvoc;int ret;size_t len;if (count < 4)return -EINVAL;/* 讀取TVOC值 */ret = ags10_read_tvoc(data, &tvoc);if (ret)return ret;/* 復制到用戶空間 */if (copy_to_user(buf, &tvoc, sizeof(u16)))return -EFAULT;return len;
}/* 文件操作: ioctl */
static long ags10_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{struct ags10_data *data = filp->private_data;int ret;u16 tvoc;switch (cmd) {case AGS10_CMD_READ_TVOC:/* 讀取TVOC值 */ret = ags10_read_tvoc(data, &tvoc);if (ret)return ret;/* 復制到用戶空間 */if (copy_to_user((u16*)arg, &tvoc, sizeof(u16)))return -EFAULT;return 0;case AGS10_CMD_CALIBRATE:/* 發送校準命令 */ret = ags10_send_command(data->client, AGS10_CMD_CALIBRATE, NULL, 0);if (ret)return ret;return 0;default:return -ENOTTY;}
}/* 文件操作表 */
static const struct file_operations ags10_fops = {.read = ags10_read,.unlocked_ioctl = ags10_ioctl,.llseek = no_llseek,
};/* 探測函數 */
static int ags10_probe(struct i2c_client *client, const struct i2c_device_id *id)
{struct ags10_data *data;int ret;/* 檢查設備是否支持 */if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {dev_err(&client->dev, "I2C functionality not supported\n");return -ENODEV;}dev_err(&client->dev, "ags10 I2C functionality supported\n");/* 分配并初始化驅動數據結構 */data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);if (!data) {dev_err(&client->dev, "Failed to allocate memory\n");return -ENOMEM;}data->client = client;mutex_init(&data->lock);i2c_set_clientdata(client, data);/* 初始化misc設備 */data->miscdev.minor = MISC_DYNAMIC_MINOR;data->miscdev.name = "ags10";data->miscdev.fops = &ags10_fops;data->miscdev.parent = &client->dev;ret = misc_register(&data->miscdev);if (ret) {dev_err(&client->dev, "Failed to register misc device\n");return ret;}/* 讀取固件版本 */ret = ags10_read_version(data);if (ret) {dev_err(&client->dev, "Failed to read firmware version\n");misc_deregister(&data->miscdev);return ret;}u16 tvoc;ags10_read_tvoc(data, &tvoc);printk(KERN_INFO "ags10_read_tvoc tvoc = %d", tvoc);data->initialized = true;dev_info(&client->dev, "AGS10 TVOC sensor initialized\n");return 0;
}/* 移除函數 */
static int ags10_remove(struct i2c_client *client)
{printk(KERN_INFO "AGS10 TVOC sensor remove");struct ags10_data *data = i2c_get_clientdata(client);if (data->initialized) {misc_deregister(&data->miscdev);data->initialized = false;}return 0;
}/* 設備ID表 */
static const struct i2c_device_id ags10_id_table[] = {{ "ags10", 0 },{},
};
MODULE_DEVICE_TABLE(i2c, ags10_id_table);/* OF匹配表 */
static const struct of_device_id ags10_of_match[] = {{ .compatible = "aosong,ags10" },{},
};
MODULE_DEVICE_TABLE(of, ags10_of_match);/* I2C驅動結構體 */
static struct i2c_driver ags10_driver = {.driver = {.name = "ags10",.owner = THIS_MODULE,.of_match_table = ags10_of_match,},.probe = ags10_probe,.remove = ags10_remove,.id_table = ags10_id_table,
};module_i2c_driver(ags10_driver);MODULE_LICENSE("GPL");
MODULE_AUTHOR("cmy");
MODULE_DESCRIPTION("AGS10 TVOC Sensor Driver");
MODULE_VERSION("1.0");

五、調試與驗證

將編譯好的驅動文件拷貝到開發板進行測試:
在這里插入圖片描述
也可以通過i2cdetect 、i2cget、i2cset等命令進行調試。

六、總結

本文詳細介紹了 I2C 總線協議的工作原理,并展示了如何在 RK3568 平臺上開發 AGS10 空氣質量傳感器的 Linux 驅動。通過深入理解 I2C 協議和 Linux 內核 I2C 子系統,我們實現了一個完整的驅動程序,包括設備初始化、數據讀取和用戶接口。

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

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

相關文章

arm版本的ubuntu安裝git或者vim等方法

看起來你在基于 ARM 的 Ubuntu 系統上安裝 Vim 時遇到了問題&#xff0c;錯誤提示為“E: 無法定位軟件包 vim”。這通常是因為系統的軟件包列表未更新&#xff0c;或者該軟件包在你檢查的標準軟件源中不可用。以下是通常可以解決這個問題的方法&#xff1a;1. 更新軟件包列表“…

MFC擴展庫BCGControlBar Pro v36.2新版亮點:可視化設計器升級

BCGControlBar庫擁有500多個經過全面設計、測試和充分記錄的MFC擴展類。 我們的組件可以輕松地集成到您的應用程序中&#xff0c;并為您節省數百個開發和調試時間。 BCGControlBar專業版 v36.2已全新發布了&#xff0c;在這個版本中添加了一個新的擴展器控件、改進了網格和報表…

小杰學C(eleven day)——莫道浮云終蔽日,總有云開霧散時。

1.結構體&#xff08;1&#xff09;內容定義&#xff1a;1.用戶自定義的數據類型2.可以包含若干不同數據類型&#xff08;可相同&#xff09;的成員變量3.這些數據項組合起來反應某一信息格式&#xff1a;struct 結構體名 (用戶自定義的數據類型){數據類型 成員變量1;數據類型 …

海豚遠程控制APP:隨時隨地,輕松掌控手機

在快節奏的現代生活中&#xff0c;我們常常需要在不同設備之間切換&#xff0c;管理手機也變得越來越重要。無論是遠程辦公、遠程學習還是日常生活中對手機的管理&#xff0c;一款高效、便捷的遠程控制軟件都能極大地提升我們的效率。海豚遠程控制APP正是這樣一款功能強大的手機…

Linux/Ubuntu安裝go

Linux/Ubuntu安裝go1. 首先移除舊版本&#xff08;如有&#xff09;&#xff1a;2. 下載Go 1.23.9安裝包&#xff1a;3. 解壓到系統目錄&#xff1a;4. 設置環境變量&#xff08;添加到~/.profile或~/.bashrc文件末尾&#xff09;&#xff1a;5.使環境變量生效&#xff1a;6. 驗…

教程:如何快速查詢 A 股實時 K線和5檔盤口

實時行情數據是量化交易策略、看板系統和交易決策系統的重要輸入。本文將以 Infoway API 提供的 WebSocket API 為例&#xff0c;教你如何使用 Python 快速接入并獲取 A 股的實時 K線數據 和 盤口數據。一、準備工作安裝 WebSocket 庫&#xff1a;pip install websockets二、查…

施易德門店管理系統應用案例分析:零售女裝品牌伊芙麗的全球化布局

在零售品牌的全球化進程中&#xff0c;如何應對不同市場的合規要求、實現本地化精細化運營&#xff0c;是企業面臨的重要課題。施易德&#xff08;Cegid&#xff09;門店管理系統憑借40年的全球零售數字化服務經驗&#xff0c;為多個品牌的海外拓展提供了支持。其中&#xff0c…

安全初級作業2

一、作業要求 1、xss-labs 1~8關 2、python實現自動化sql布爾育注代碼優化(二分查找) 二、操作過程 &#xff08;一&#xff09;xss-labs 1~8關 1、前期準備 &#xff08;1&#xff09;打開小皮面板&#xff0c;并啟動Apache和MySQL &#xff08;2&#xff09;將 xss-labs…

多模態大語言模型arxiv論文略讀(157)

Automatic Evaluation for Text-to-image Generation: Task-decomposed Framework, Distilled Training, and Meta-evaluation Benchmark ?? 論文標題&#xff1a;Automatic Evaluation for Text-to-image Generation: Task-decomposed Framework, Distilled Training, and M…

面試150——數組字符串

88. 合并兩個有序數組 給你兩個按 非遞減順序 排列的整數數組 nums1 和 nums2&#xff0c;另有兩個整數 m 和 n &#xff0c;分別表示 nums1 和 nums2 中的元素數目。請你 合并 nums2 到 nums1 中&#xff0c;使合并后的數組同樣按 非遞減順序 排列。倒序比較&#xff0c;避免覆…

深入理解設計模式:命令模式詳解

在軟件開發中&#xff0c;我們經常遇到需要將"請求"或"操作"封裝成對象的情況。比如&#xff0c;GUI中的按鈕點擊、遙控器控制家電、事務系統中的操作回滾等場景。命令模式&#xff08;Command Pattern&#xff09;正是為解決這類問題而生的設計模式。本文…

自己寫的 MyHttpServlet 和直接繼承 HttpServlet 的區別

繼承你自己寫的 MyHttpServlet 和直接繼承 HttpServlet 的區別如下&#xff1a;1. 繼承 HttpServlet&#xff08;官方推薦用法&#xff09;HttpServlet 是 Java EE 官方提供的 Servlet 基類&#xff0c;已經實現了 Servlet 接口的大部分方法。它內部已經實現了 service() 方法&…

python庫 maya 庫的各種案例的使用詳解(人性化的日期時間處理)

文章目錄 一、Maya庫概述 1.1 maya介紹 1.2 安裝 maya 1.3 注意事項 二、基本使用 2.1 創建 MayaDT 對象 2.2 格式化輸出 2.3 時間運算 三、高級使用 3.1 時區處理 3.2 時間間隔 3.3 網絡時間獲取 四、實際應用示例 4.1 日志時間處理 4.2 會議時間提醒 4.3 國際化時間顯示 5. M…

企業選擇大帶寬服務器租用的原因有哪些?

大帶寬服務器作為各個行業使用較多的服務器類型&#xff0c;可以為企業提供更高的數據傳輸速率&#xff0c;極大縮短文件上傳與下載時間&#xff0c;對于大型文件&#xff0c;大帶寬服務器能夠將時間大幅縮減至數分鐘或數小時&#xff0c;提高企業整體的工作效率。大帶寬服務器…

使用canal同步分庫分表數據,到 Elasticsearch

作者&#xff1a;小凱 沉淀、分享、成長&#xff0c;讓自己和他人都能有所收獲&#xff01; 本文的宗旨在于通過簡單干凈實踐的方式教會讀者&#xff0c;配置出一套 Canal 工具服務&#xff0c;來同步分庫分表的數據到 Elasticsearch 文件夾系統中。同時在 SpringBoot 工程中&a…

氣候為何愈演愈“炙” — 未來五年高溫趨勢與 AI 氣象大模型的突破性價值

早、更準 代表性模型 主要特征 應用進展 GraphCast(DeepMind) 10 天全球預報;0.25 分辨率;< 1 min 推理 90 % 指標超 ECMWF HRES,已用于極端風暴提前鎖定Google DeepMind MetNet-3(Google Research) 1–4 km 分辨率;2 min 時序;24 h 區域精細預報 美東、歐洲已在 G…

LVS四種模式及部署NAT、DR模式集群

1、lvs簡介LVS:Linux Virtual Server&#xff0c;負載調度器&#xff0c;內核集成&#xff0c;章文嵩&#xff0c;阿里四層SLB(ServerLoadBalance)是基于LVSkeepalived實現LVS 官網: http://www.linuxvirtualserver.org/LVS 相關術語VS: Virtual Server&#xff0c;負責調度RS:…

【Linux】Ubuntu22.04安裝zabbix

官方文檔&#xff1a;zabbix安裝文檔 環境如下 環境版本nginx1.26.3zabbix7.0.16mysql8.0.41 安裝nginx和mysql 一鍵部署腳本 部署zabbix #!/bin/bash wget https://repo.zabbix.com/zabbix/7.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest_7.0ubuntu22.04_…

C++ - 仿 RabbitMQ 實現消息隊列--sqlite與gtest快速上手

目錄 SQLite 什么是 SQLite 為什么要用 SQLite SQLite3 C/C API 介紹 SQLite3 C/C API 使用 GTest GTest 是什么 GTest 使用 TEST 宏 斷言 事件機制 全局事件 TestSuite 事件 SQLite 什么是 SQLite SQLite 是一個進程內的輕量級數據庫&#xff0c;它實現了自給自足…

Web3.0 學習方案

Web3.0 學習方案 一、學習方案 &#xff08;一&#xff09;入門階段 1. 了解 Web3.0 基礎概念 學習內容&#xff1a; Web3.0 的起源、愿景、與 Web2.0 的區別區塊鏈的基本概念&#xff1a;分布式賬本、哈希、公鑰/私鑰、共識機制&#xff08;PoW、PoS、DPoS、PBFT 等&#xff0…