【RK3568 RTC 驅動開發詳解】

RK3568 RTC 驅動開發詳解

  • 一、Linux RTC 子系統架構?
  • 二、設備樹配置?
  • 三、驅動
  • 四、時間相關命令

實時時鐘(RTC)是嵌入式系統中不可或缺的硬件模塊,負責在系統斷電后繼續計時,為設備提供穩定的時間基準。本文將以瑞芯微 RK3568 平臺為例,詳細介紹 RTC 驅動的開發過程,包括子系統架構、設備樹配置、驅動實現及測試方法。

一、Linux RTC 子系統架構?

Linux 內核通過 RTC 子系統實現對各類 RTC 硬件的統一管理,其架構采用分層設計:

┌─────────────────────────────────────────┐
│              用戶空間                    │
│  ┌──────────┐  ┌──────────┐  ┌────────┐ │
│  │ hwclock  │  │ date     │  │ 應用程序│ │
│  └──────────┘  └──────────┘  └────────┘ │
└───────────────────┬─────────────────────┘│
┌───────────────────▼─────────────────────┐
│              內核空間                    │
│  ┌───────────────────────────────────┐  │
│  │           RTC核心層                │  │
│  │      (rtc_class_ops .c)           │  │
│  └───────────────────┬───────────────┘  │
│                      │                  │
│  ┌───────────────────▼───────────────┐  │
│  │           RTC驅動層                │  │
│  │     (rtc-rx8010.c 具體實現)        │  │
│  └───────────────────┬───────────────┘  │
└──────────────────────┼──────────────────┘│
┌──────────────────────▼──────────────────┐
│              硬件層                      │
│       RK3568 RTC控制器 + 晶體振蕩器       │
└─────────────────────────────────────────┘
  • 核心層: 提供統一的用戶空間接口(字符設備/dev/rtc0)和驅動框架,定義標準操作集?
  • 驅動層: 實現具體硬件的操作,對接 RTC 核心層的抽象接口?
  • 用戶空間: 通過ioctl、read等系統調用訪問 RTC 功能,或使用hwclock等工具?

核心數據結構:


// RTC操作函數集
struct rtc_class_ops {int (*read_time)(struct device *dev, struct rtc_time *tm);    // 讀時間int (*set_time)(struct device *dev, struct rtc_time *tm);     // 設時間int (*read_alarm)(struct device *dev, struct rtc_wkalrm *alrm); // 讀鬧鐘int (*set_alarm)(struct device *dev, struct rtc_wkalrm *alrm);  // 設鬧鐘int (*proc)(struct device *dev, struct seq_file *seq);        // 調試信息// 其他操作...
};

二、設備樹配置?

RK3568外掛RTC硬件原理圖:
在這里插入圖片描述

定義rtc設備節點:
kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi

在這里插入圖片描述

&i2c5 {status = "okay";rx8010: rx8010@32 {compatible = "epson,rx8010";reg = <0x32>;status = "okay";#clock-cells = <0>;};
};

i2c5設備節點描述如下:
kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi
在這里插入圖片描述

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

三、驅動

在這里插入圖片描述
因為RK809帶有RTC功能,使用外掛RTC時需要先禁用,具體操作如下:
執行make menuconfig

Device Drivers --->[*] Real Time Clock ---><> Rockchip RK805/RK808/RK809/RK816/RK817/RK818 RTC<*> Epson RX8010SJ

取消Rockchip RK805/RK808/RK809/RK816/RK817/RK818 RTC選中
選中Epson RX8010SJ
在這里插入圖片描述

驅動代碼:kernel/drivers/rtc/rtc-rx8010.c

/** Driver for the Epson RTC module RX-8010 SJ** Copyright(C) Timesys Corporation 2015* Copyright(C) General Electric Company 2015** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License version 2 as* published by the Free Software Foundation.**/#include <linux/bcd.h>
#include <linux/bitops.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/rtc.h>#define RX8010_SEC     0x10
#define RX8010_MIN     0x11
#define RX8010_HOUR    0x12
#define RX8010_WDAY    0x13
#define RX8010_MDAY    0x14
#define RX8010_MONTH   0x15
#define RX8010_YEAR    0x16
#define RX8010_RESV17  0x17
#define RX8010_ALMIN   0x18
#define RX8010_ALHOUR  0x19
#define RX8010_ALWDAY  0x1A
#define RX8010_TCOUNT0 0x1B
#define RX8010_TCOUNT1 0x1C
#define RX8010_EXT     0x1D
#define RX8010_FLAG    0x1E
#define RX8010_CTRL    0x1F
/* 0x20 to 0x2F are user registers */
#define RX8010_RESV30  0x30
#define RX8010_RESV31  0x31
#define RX8010_IRQ     0x32#define RX8010_EXT_WADA  BIT(3)#define RX8010_FLAG_VLF  BIT(1)
#define RX8010_FLAG_AF   BIT(3)
#define RX8010_FLAG_TF   BIT(4)
#define RX8010_FLAG_UF   BIT(5)#define RX8010_CTRL_AIE  BIT(3)
#define RX8010_CTRL_UIE  BIT(5)
#define RX8010_CTRL_STOP BIT(6)
#define RX8010_CTRL_TEST BIT(7)#define RX8010_ALARM_AE  BIT(7)static const struct i2c_device_id rx8010_id[] = {{ "rx8010", 0 },{ }
};
MODULE_DEVICE_TABLE(i2c, rx8010_id);static const struct of_device_id rx8010_of_match[] = {{ .compatible = "epson,rx8010" },{ }
};
MODULE_DEVICE_TABLE(of, rx8010_of_match);struct rx8010_data {struct i2c_client *client;struct rtc_device *rtc;u8 ctrlreg;
};static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id)
{struct i2c_client *client = dev_id;struct rx8010_data *rx8010 = i2c_get_clientdata(client);int flagreg;mutex_lock(&rx8010->rtc->ops_lock);flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG);if (flagreg <= 0) {mutex_unlock(&rx8010->rtc->ops_lock);return IRQ_NONE;}if (flagreg & RX8010_FLAG_VLF)dev_warn(&client->dev, "Frequency stop detected\n");if (flagreg & RX8010_FLAG_TF) {flagreg &= ~RX8010_FLAG_TF;rtc_update_irq(rx8010->rtc, 1, RTC_PF | RTC_IRQF);}if (flagreg & RX8010_FLAG_AF) {flagreg &= ~RX8010_FLAG_AF;rtc_update_irq(rx8010->rtc, 1, RTC_AF | RTC_IRQF);}if (flagreg & RX8010_FLAG_UF) {flagreg &= ~RX8010_FLAG_UF;rtc_update_irq(rx8010->rtc, 1, RTC_UF | RTC_IRQF);}i2c_smbus_write_byte_data(client, RX8010_FLAG, flagreg);mutex_unlock(&rx8010->rtc->ops_lock);return IRQ_HANDLED;
}static int rx8010_get_time(struct device *dev, struct rtc_time *dt)
{struct rx8010_data *rx8010 = dev_get_drvdata(dev);u8 date[7];int flagreg;int err;flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG);if (flagreg < 0)return flagreg;if (flagreg & RX8010_FLAG_VLF) {dev_warn(dev, "Frequency stop detected\n");return -EINVAL;}err = i2c_smbus_read_i2c_block_data(rx8010->client, RX8010_SEC,7, date);if (err != 7)return err < 0 ? err : -EIO;dt->tm_sec = bcd2bin(date[RX8010_SEC - RX8010_SEC] & 0x7f);dt->tm_min = bcd2bin(date[RX8010_MIN - RX8010_SEC] & 0x7f);dt->tm_hour = bcd2bin(date[RX8010_HOUR - RX8010_SEC] & 0x3f);dt->tm_mday = bcd2bin(date[RX8010_MDAY - RX8010_SEC] & 0x3f);dt->tm_mon = bcd2bin(date[RX8010_MONTH - RX8010_SEC] & 0x1f) - 1;dt->tm_year = bcd2bin(date[RX8010_YEAR - RX8010_SEC]) + 100;dt->tm_wday = ffs(date[RX8010_WDAY - RX8010_SEC] & 0x7f);return 0;
}static int rx8010_set_time(struct device *dev, struct rtc_time *dt)
{struct rx8010_data *rx8010 = dev_get_drvdata(dev);u8 date[7];int ctrl, flagreg;int ret;if ((dt->tm_year < 100) || (dt->tm_year > 199))return -EINVAL;/* set STOP bit before changing clock/calendar */ctrl = i2c_smbus_read_byte_data(rx8010->client, RX8010_CTRL);if (ctrl < 0)return ctrl;rx8010->ctrlreg = ctrl | RX8010_CTRL_STOP;ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,rx8010->ctrlreg);if (ret < 0)return ret;date[RX8010_SEC - RX8010_SEC] = bin2bcd(dt->tm_sec);date[RX8010_MIN - RX8010_SEC] = bin2bcd(dt->tm_min);date[RX8010_HOUR - RX8010_SEC] = bin2bcd(dt->tm_hour);date[RX8010_MDAY - RX8010_SEC] = bin2bcd(dt->tm_mday);date[RX8010_MONTH - RX8010_SEC] = bin2bcd(dt->tm_mon + 1);date[RX8010_YEAR - RX8010_SEC] = bin2bcd(dt->tm_year - 100);date[RX8010_WDAY - RX8010_SEC] = bin2bcd(1 << dt->tm_wday);ret = i2c_smbus_write_i2c_block_data(rx8010->client,RX8010_SEC, 7, date);if (ret < 0)return ret;/* clear STOP bit after changing clock/calendar */ctrl = i2c_smbus_read_byte_data(rx8010->client, RX8010_CTRL);if (ctrl < 0)return ctrl;rx8010->ctrlreg = ctrl & ~RX8010_CTRL_STOP;ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,rx8010->ctrlreg);if (ret < 0)return ret;flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG);if (flagreg < 0) {return flagreg;}if (flagreg & RX8010_FLAG_VLF)ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG,flagreg & ~RX8010_FLAG_VLF);return 0;
}static int rx8010_init_client(struct i2c_client *client)
{struct rx8010_data *rx8010 = i2c_get_clientdata(client);u8 ctrl[2];int need_clear = 0, err = 0;/* add by lgq 2021-12-17 */u8 flag;flag = i2c_smbus_read_byte_data(client, RX8010_FLAG);if(err < 0)return err;flag &= ~(RX8010_FLAG_VLF);err = i2c_smbus_write_byte_data(client, RX8010_FLAG, flag);
/* end add *//* Initialize reserved registers as specified in datasheet */err = i2c_smbus_write_byte_data(client, RX8010_RESV17, 0xD8);if (err < 0)return err;err = i2c_smbus_write_byte_data(client, RX8010_RESV30, 0x00);if (err < 0)return err;err = i2c_smbus_write_byte_data(client, RX8010_RESV31, 0x08);if (err < 0)return err;err = i2c_smbus_write_byte_data(client, RX8010_IRQ, 0x00);if (err < 0)return err;err = i2c_smbus_read_i2c_block_data(rx8010->client, RX8010_FLAG,2, ctrl);if (err != 2)return err < 0 ? err : -EIO;if (ctrl[0] & RX8010_FLAG_VLF)dev_warn(&client->dev, "Frequency stop was detected\n");if (ctrl[0] & RX8010_FLAG_AF) {dev_warn(&client->dev, "Alarm was detected\n");need_clear = 1;}if (ctrl[0] & RX8010_FLAG_TF)need_clear = 1;if (ctrl[0] & RX8010_FLAG_UF)need_clear = 1;if (need_clear) {ctrl[0] &= ~(RX8010_FLAG_AF | RX8010_FLAG_TF | RX8010_FLAG_UF);err = i2c_smbus_write_byte_data(client, RX8010_FLAG, ctrl[0]);if (err < 0)return err;}rx8010->ctrlreg = (ctrl[1] & ~RX8010_CTRL_TEST);return 0;
}static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t)
{struct rx8010_data *rx8010 = dev_get_drvdata(dev);struct i2c_client *client = rx8010->client;u8 alarmvals[3];int flagreg;int err;err = i2c_smbus_read_i2c_block_data(client, RX8010_ALMIN, 3, alarmvals);if (err != 3)return err < 0 ? err : -EIO;flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG);if (flagreg < 0)return flagreg;t->time.tm_sec = 0;t->time.tm_min = bcd2bin(alarmvals[0] & 0x7f);t->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);if (!(alarmvals[2] & RX8010_ALARM_AE))t->time.tm_mday = bcd2bin(alarmvals[2] & 0x7f);t->enabled = !!(rx8010->ctrlreg & RX8010_CTRL_AIE);t->pending = (flagreg & RX8010_FLAG_AF) && t->enabled;return 0;
}static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{struct i2c_client *client = to_i2c_client(dev);struct rx8010_data *rx8010 = dev_get_drvdata(dev);u8 alarmvals[3];int extreg, flagreg;int err;flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG);if (flagreg < 0) {return flagreg;}if (rx8010->ctrlreg & (RX8010_CTRL_AIE | RX8010_CTRL_UIE)) {rx8010->ctrlreg &= ~(RX8010_CTRL_AIE | RX8010_CTRL_UIE);err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,rx8010->ctrlreg);if (err < 0) {return err;}}flagreg &= ~RX8010_FLAG_AF;err = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, flagreg);if (err < 0)return err;alarmvals[0] = bin2bcd(t->time.tm_min);alarmvals[1] = bin2bcd(t->time.tm_hour);alarmvals[2] = bin2bcd(t->time.tm_mday);err = i2c_smbus_write_i2c_block_data(rx8010->client, RX8010_ALMIN,2, alarmvals);if (err < 0)return err;extreg = i2c_smbus_read_byte_data(client, RX8010_EXT);if (extreg < 0)return extreg;extreg |= RX8010_EXT_WADA;err = i2c_smbus_write_byte_data(rx8010->client, RX8010_EXT, extreg);if (err < 0)return err;if (alarmvals[2] == 0)alarmvals[2] |= RX8010_ALARM_AE;err = i2c_smbus_write_byte_data(rx8010->client, RX8010_ALWDAY,alarmvals[2]);if (err < 0)return err;if (t->enabled) {if (rx8010->rtc->uie_rtctimer.enabled)rx8010->ctrlreg |= RX8010_CTRL_UIE;if (rx8010->rtc->aie_timer.enabled)rx8010->ctrlreg |=(RX8010_CTRL_AIE | RX8010_CTRL_UIE);err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,rx8010->ctrlreg);if (err < 0)return err;}return 0;
}static int rx8010_alarm_irq_enable(struct device *dev,unsigned int enabled)
{struct i2c_client *client = to_i2c_client(dev);struct rx8010_data *rx8010 = dev_get_drvdata(dev);int flagreg;u8 ctrl;int err;ctrl = rx8010->ctrlreg;if (enabled) {if (rx8010->rtc->uie_rtctimer.enabled)ctrl |= RX8010_CTRL_UIE;if (rx8010->rtc->aie_timer.enabled)ctrl |= (RX8010_CTRL_AIE | RX8010_CTRL_UIE);} else {if (!rx8010->rtc->uie_rtctimer.enabled)ctrl &= ~RX8010_CTRL_UIE;if (!rx8010->rtc->aie_timer.enabled)ctrl &= ~RX8010_CTRL_AIE;}flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG);if (flagreg < 0)return flagreg;flagreg &= ~RX8010_FLAG_AF;err = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, flagreg);if (err < 0)return err;if (ctrl != rx8010->ctrlreg) {rx8010->ctrlreg = ctrl;err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,rx8010->ctrlreg);if (err < 0)return err;}return 0;
}static int rx8010_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{struct i2c_client *client = to_i2c_client(dev);struct rx8010_data *rx8010 = dev_get_drvdata(dev);int ret, tmp;int flagreg;switch (cmd) {case RTC_VL_READ:flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG);if (flagreg < 0)return flagreg;tmp = !!(flagreg & RX8010_FLAG_VLF);if (copy_to_user((void __user *)arg, &tmp, sizeof(int)))return -EFAULT;return 0;case RTC_VL_CLR:flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG);if (flagreg < 0) {return flagreg;}flagreg &= ~RX8010_FLAG_VLF;ret = i2c_smbus_write_byte_data(client, RX8010_FLAG, flagreg);if (ret < 0)return ret;return 0;default:return -ENOIOCTLCMD;}
}static const struct rtc_class_ops rx8010_rtc_ops_default = {.read_time = rx8010_get_time,.set_time = rx8010_set_time,.ioctl = rx8010_ioctl,
};static const struct rtc_class_ops rx8010_rtc_ops_alarm = {.read_time = rx8010_get_time,.set_time = rx8010_set_time,.ioctl = rx8010_ioctl,.read_alarm = rx8010_read_alarm,.set_alarm = rx8010_set_alarm,.alarm_irq_enable = rx8010_alarm_irq_enable,
};static int rx8010_probe(struct i2c_client *client,const struct i2c_device_id *id)
{struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);const struct rtc_class_ops *rtc_ops;struct rx8010_data *rx8010;int err = 0;if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA| I2C_FUNC_SMBUS_I2C_BLOCK)) {dev_err(&adapter->dev, "doesn't support required functionality\n");return -EIO;}rx8010 = devm_kzalloc(&client->dev, sizeof(struct rx8010_data),GFP_KERNEL);if (!rx8010)return -ENOMEM;rx8010->client = client;i2c_set_clientdata(client, rx8010);err = rx8010_init_client(client);if (err)return err;if (client->irq > 0) {dev_info(&client->dev, "IRQ %d supplied\n", client->irq);err = devm_request_threaded_irq(&client->dev, client->irq, NULL,rx8010_irq_1_handler,IRQF_TRIGGER_LOW | IRQF_ONESHOT,"rx8010", client);if (err) {dev_err(&client->dev, "unable to request IRQ\n");return err;}rtc_ops = &rx8010_rtc_ops_alarm;} else {rtc_ops = &rx8010_rtc_ops_default;}rx8010->rtc = devm_rtc_device_register(&client->dev, client->name,rtc_ops, THIS_MODULE);if (IS_ERR(rx8010->rtc)) {dev_err(&client->dev, "unable to register the class device\n");return PTR_ERR(rx8010->rtc);}rx8010->rtc->max_user_freq = 1;return err;
}static struct i2c_driver rx8010_driver = {.driver = {.name = "rtc-rx8010",.of_match_table = of_match_ptr(rx8010_of_match),},.probe		= rx8010_probe,.id_table	= rx8010_id,
};module_i2c_driver(rx8010_driver);MODULE_AUTHOR("Akshay Bhat <akshay.bhat@timesys.com>");
MODULE_DESCRIPTION("Epson RX8010SJ RTC driver");
MODULE_LICENSE("GPL v2");

四、時間相關命令

linux有2個時間,一個是系統時間,一個是rtc時間,命令如下:

date #系統時間
date +"%Y:%m:%d" #格式化輸出系統時間
hwclock #rtc時間
hwclock -w #將系統時間同步到硬件
hwclock -s #將硬件時間同步到系統

在這里插入圖片描述

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

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

相關文章

文本編碼檢測庫`chardet` 和 `uchardet`對比使用示例及注意事項

在處理未知編碼的二進制數據時&#xff0c;chardet 和 uchardet 是兩個非常實用的字符編碼自動檢測庫&#xff0c;尤其適用于從衛星通信、文件、網絡流等來源獲取的未標明編碼的文本數據。一、chardet&#xff08;Python版&#xff09; ? 簡介 chardet 是一個用 Python 編寫的…

[Windows]Postman-app官方歷史版本下載方法

Postman-app官方歷史版本下載方法最新版&歷史版本官網地址最新版本下載歷史版本下載禁止自動更新方法Postman最新版安裝后必須要登錄才能使用某些特定功能&#xff0c;多有不便&#xff0c;因此花了點時間整理了一下歷史版本如何下載的方法&#xff0c;鏈接均為官網鏈接&am…

【Spring Boot 快速入門】三、分層解耦

目錄分層解耦案例&#xff1a;將 emp.xml 中的數據解析并響應三層架構分層解耦IOC & DI 入門IOC 詳解DI 詳解分層解耦 案例&#xff1a;將 emp.xml 中的數據解析并響應 emp.xml 內容如下&#xff1a; <emps><emp><name>Tom</name><age>18…

井云科技2D交互數字人:讓智能服務觸手可及的實用方案

在如今的數字化時代&#xff0c;智能交互已成為各行業提升服務質量的重要方向。而井云 2D 交互數字人系統憑借其獨特的技術優勢&#xff0c;正逐漸成為眾多企業實現智能服務升級的優選。它無需復雜的操作和高昂的成本&#xff0c;就能讓數字人在各類線下場景中發揮重要作用&…

本地部署VMware ESXi,并實現無公網IP遠程訪問管理服務器

ESXi&#xff08;VMware ESXi&#xff09;是VMware公司推出的一款企業級虛擬化平臺&#xff0c;基于裸機&#xff08;bare-metal&#xff09;安裝的虛擬化操作系統。它可以在一臺物理服務器上運行多個虛擬機&#xff0c;廣泛應用于數據中心和云計算環境中。很多公司為了方便管理…

讓科技之光,溫暖銀齡歲月——智紳科技“智慧養老進社區”星城國際站溫情紀實

七月的風&#xff0c;帶著夏日的熱情&#xff0c;輕輕拂過邯鄲星城國際社區蔥郁的綠意。2025年7月30日&#xff0c;一個以“幸福晚景&#xff0c;樂享銀齡—智慧養老進社區”為主題的活動&#xff0c;如一股暖流&#xff0c;浸潤了社區的長者們。智紳科技懷揣著“科技賦能養老&…

Java單元測試和設計模式

單元測試 . 測試分類 什么是測試? 測試的目的是盡可能多的發現軟件中存在的BUG,而不是為了隱藏BUG。事實上測試有很多種類,比如:邊界測試,壓力測試,性能測試等 黑盒測試 黑盒測試也叫功能測試,主要關注軟件每個功能是否實現,并不關注軟件代碼是否有錯誤;測試人員…

UOS統信桌面系統解決編譯錯誤:C compiler cc is not found指南

一、系統環境 1.操作系統版本2.編譯環境 PC:~$ gcc --version gcc (Uos 8.3.0.13-deepin1) 8.3.0 Copyright (C) 2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY o…

深入理解 Docker 容器網絡:為什么用 host 網絡模式能解決連通性問題?

Docker 已經成為現代應用部署的標配&#xff0c;大家都知道它的網絡隔離做得很好&#xff0c;既安全又靈活。不過&#xff0c;在實際用 Docker 部署服務的過程中&#xff0c;相信很多人都遇到過這樣的情況&#xff1a;主機上能連通的外部服務&#xff0c;一到容器里卻死活連不上…

Spring Boot 異常處理:從全局捕獲到優化用戶體驗!

全文目錄&#xff1a;開篇語**前言****1. Spring Boot 異常處理的基本概念****2. 使用 ExceptionHandler 局部處理異常****示例&#xff1a;局部異常處理****優化建議&#xff1a;****3. 使用 ControllerAdvice 和 RestControllerAdvice 進行全局異常處理****示例&#xff1a;全…

vue3.0 + TypeScript 中使用 axios 同時進行二次封裝

項目背景是vite搭建的vue3.0 TypeScript 的項目&#xff0c;需要統一處理和統一維護就對axios進行了二次封裝 axios的安裝 npm install axios定義http文件夾然后內部定義index.ts文件&#xff0c;內部開始封裝 import axios, {type AxiosInstance} from "axios";…

ESP32- 項目應用1 音樂播放器之sd的驅動配置 #1

音樂播放器 ESP32- 項目應用1 音樂播放器之sd的驅動配置 #1 文章目錄 音樂播放器 1 sd卡介紹 1.1 SDCARD介紹 1.2 物理結構 1.3 協議說明 1.4 sd 卡模式 1.5 數據模式 1.6 sdio 初始化流程 1.7 SPI 模式下的 SD 卡初始化 2 原理圖 2.1 sd原理圖 2.2 esp32的接口 3 代碼配置 3.…

Vue.js 指令系統完全指南:深入理解 v- 指令

Vue.js 的指令系統是其最強大的特性之一&#xff0c;通過以 v- 開頭的特殊屬性&#xff0c;我們可以在模板中聲明式地綁定底層Vue實例的數據。本文將深入講解Vue中最重要的指令&#xff0c;幫助掌握Vue的核心功能。 文章目錄1. v-model&#xff1a;雙向數據綁定的核心基本用法修…

計算機分類匯總大全

前端部分有 Node.js、ActionScript、Swift、TypeScript、Webpack、JavaScript。需要分別詳細說明它們的定義、特點、應用場景、優缺點等。比如 Node.js&#xff0c;要提到它的運行環境、事件驅動、非阻塞 I/O&#xff0c;適合的應用如 API 服務、實時應用&#xff0c;以及常用框…

模擬鏈路濾波器設計一些細節

目錄 原設計思路剖析 300M帶寬仿真與計算 原設計思路剖析 濾波器設計的一些細節,以下為ADS54J60模擬鏈路的一些問題設計原理圖 實際電路設計如上所示,但是實際bom并未按此設計,根據實際的BOM明細以及ADC使用說明書,可以間接理解原設計者的設計初衷,是將ADC的一部分特性…

CatBoost 完整解析:類別特征友好的梯度提升框架

1?? 什么是 CatBoost&#xff1f;CatBoost&#xff08;Categorial Boosting&#xff09;是由 Yandex&#xff08;俄羅斯搜索引擎公司&#xff09;開源的梯度提升框架&#xff0c;專為類別特征處理優化。核心特點&#xff1a;無需手動 one-hot / LabelEncoding&#xff0c;原生…

NDBmysql-cluster集群部署腳本

NDB(Network Database)是MySQL Cluster的核心存儲引擎,專為高可用性、高吞吐量、分布式數據存儲設計,采用內存計算+磁盤持久化架構,支持跨節點數據分片與自動冗余,適用于對實時性和可靠性要求嚴苛的業務場景(如金融交易、電信計費、實時分析等)。 今天大白鼠就分享構建…

計算機網絡中的socket是什么?編程語言中的socket編程又是什么?python的socket編程又該如何用?

1. 計算機網絡中的 Socket 是什么&#xff1f; 想象一下電話系統&#xff1a; 電話插座 (Socket)&#xff1a; 是墻上的一個物理接口&#xff0c;它本身不是通話&#xff0c;但它是建立通話連接的端點。你需要把電話線插進插座才能打電話。通話 (Connection)&#xff1a; 是兩臺…

【科普】進程與線程的區別

一、定義與概念&#xff1a;進程&#xff1a;進程是執行中的一段程序。一旦程序被載入到內存中并準備執行&#xff0c;就變成了一個進程。進程是表示資源分配的基本概念&#xff0c;又是調度運行的基本單位&#xff0c;是系統中的并發執行的單位。線程&#xff1a;線程是進程中…

Conda創建虛擬環境,解決不同項目的沖突!

隨著需求的增多&#xff0c;又要增加多幾個不同的項目來在本地測試&#xff0c;這個時候往往就會遇到 不同項目的Python版本不同等等一系列問題&#xff0c;只好請出Conda來幫忙。 一、先去下載安裝一下Conda Conda | Anaconda.org 安裝完后&#xff0c;需要給CONDA做個環境變…