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做个环境变…