当前位置: 首页 > news >正文

基于STM32的阿里云智能农业大棚

目录

前言:

项目效果演示:

一、简介

二、硬件需求准备

三、硬件框图

四、CubeMX配置

4.1、按键、蜂鸣器GPIO口配置

4.2、ADC输入配置

4.3、IIC——驱动OLED

4.4、DHT11温湿度读取

4.5、PWM配置——光照灯、水泵、风扇

4.6、串口——esp8266模块

4.7、定时器配置——按键消抖所需

五、部分代码实现思路

5.1、菜单实现思路

5.2、OLED驱动

5.3、按键消抖

5.4、DHT11温湿度驱动

5.5、光照强度、土壤湿度ADC转换

5.6、esp8266连接阿里云

六、功能拓展


前言:

注意事项:本项目使用的是u8g2库进行显示驱动OLED,需要学会移植或者直接使用我的模板,具体可以看我的这个博文:手把手移植基于STM移植U8g2图形库教程——0.96寸OLED(附送整理资料)

买来的esp8266模可能不支持连接阿里云,需要烧写MQTT固件,具体操作可以看看我的这个博文:手把手连接阿里云教程

里面都会有所需的固件和工具和教程!

项目效果演示:

智能农业大棚

一、简介

这可以作为一个简单的课设或者用来水毕设的一个小项目,总体来说挺简单的,我做完后就打算开源出来大家一起学习一下,具体功能如下:

1、按键:

      按键一:切换菜单

      按键二:切换选项

      按键三:+-或调节风扇 | 水泵 | 灯光

      按键四:确认 | 连接阿里云平台

2、液晶屏幕显示:

     菜单1:主界面显示空气温湿度,土壤湿度,光照强度,检测是否超过或低于临界值

     菜单2:临界值调节

     菜单3:风扇手动开关

     菜单4:灯光手动开关

     菜单5:水泵手动开关

     菜单6:阿里云连接菜单界面

3、土壤湿度、空气温湿度、光照强度高于或低于临界值,蜂鸣器就会响

4、土壤湿度过低自动打开水泵

5、光照强度过低自动打开照明灯

6、空气温度过高会自动打开风扇

7、连接阿里云平台,可以在电脑上面查看各个数据

二、硬件需求准备

1、STM32F103最小核心开发板

2、0.96寸OLED屏幕

3、按键X4

4、TB6612FNG点击驱动模块

5、水泵

6、电机(带小风扇)

7、DHT11温湿度模块

8、esp8266模块

9、蜂鸣器

10、土壤湿度传感器

11、光照强度传感器

12、照明灯模块

三、硬件框图

四、CubeMX配置

这里只演示配置使用的外设配置过程!

4.1、按键、蜂鸣器GPIO口配置

按键配置为上拉模式、蜂鸣器低电平输出有效

  4.2、ADC输入配置

ADC为读取土壤湿度和光照强度的ADC数值,这里开启两个ADC分别读取

ADC1——读取土壤湿度:

ADC2——读取光照强度:

4.3、IIC——驱动OLED

4.4、DHT11温湿度读取

这个使用过程中会对弈随意变动上下拉模式,所以这里就不配置了,使用的GPIO口为PB8

4.5、PWM配置——光照灯、水泵、风扇

4.6、串口——esp8266模块

开启中断:

4.7、定时器配置——按键消抖所需

开启中断:

最后生成工程即可。

五、部分代码实现思路

5.1、菜单实现思路

最常用的就是菜单索引法还有链表法,我这里菜单结构非常简单,所以我就使用索引法了,这里简单说一下,就是每一个菜单都对应一个结构体((这个项目没有二级界面,所以用不到进入索引和返回索引)):

typedef struct
{int current_index;//当前索引int last_index;   //下一索引int enter_index;  //进入索引int back_index;   //返回索引void(*current)(u8g2_t u8g2);}Menu;

结构体成员包括以上的几个。

这个小项目有5个菜单页面:所以定义5个结构体(这个项目没有二级界面,所以用不到进入索引和返回索引):

Menu Menu_Table[30] = 
{
// 当 下 进 返{0, 1, 0, 0,(*Home_Menu)}, //主页显示界面{1, 2, 0, 0,(*Set_Menu)},  //设置临界值界面{2, 3, 0, 0,(*Fan_Menu)},  //风扇控制界面{3, 4, 0, 0,(*Light_Menu)},//灯光控制界面{4, 5, 0, 0,(*Water_Menu)},//水泵控制界面{5, 0, 0, 0,(*Wifi_Menu)},//连接阿里云控制界面};

然后定义一个当前显示菜单的索引值和当前菜单显示绘制函数:

int Current_Menu_index = 0;//当前菜单索引
void(*Current)(u8g2_t u8g2);//当前菜单索引执行绘制函数

然后初始化好按键,按下后执行跳转:

切换下一菜单使用例子(如果是其他的可以八next换成其他的结构体成员):

Current_Menu_index = Menu_Table[Current_Menu_index].last_index;//变换索引值Current = Menu_Table[Current_Menu_index].current;//函数复制
(*Current)(u8g2);//执行绘制函数

在举一个例子帮助大家理解一下,比如,我们当前程序处在索引号为2(临界值界面),就会执行Set_Menu函数。此时,如果按下next按键,程序当前索引号就会变为3,并且执行索引号为3时候的Fan_Menu函数。以此类推!

5.2、OLED驱动

这里我是使用开源的u8g2库进行开发,这个库显示效果很好,而且也很好移植!具体可以参考我的这个博文:移植u8g2库,移植成功后使用也可以看看我的另外要给博文:u8g2库函数使用

5.3、按键消抖

我这里使用的是中断消抖:

unsigned char Key_PIN_Read()
{unsigned char Temp=0;if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET)   Temp = 1;if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13) == GPIO_PIN_RESET)   Temp = 2;if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_RESET)   Temp = 3;if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_15) == GPIO_PIN_RESET)   Temp = 4;return Temp;} void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)              //中断回调函数
{Key_Slow++;if(Key_Slow == 10)  Key_Slow = 0;//按键消抖
}void Key_Pro()
{if(Key_Slow) return;//按键减速Key_Slow=1;Key_Val=Key_PIN_Read();Key_Down=Key_Val & (Key_Val ^ Key_Old);//捕捉下降沿Key_Up = ~Key_Val & (Key_Old ^ Key_Val);//捕捉按键上降沿Key_Old=Key_Val;switch(Key_Up){case 1:break;case 2:break;case 3:break;case 4:break;}}

5.4、DHT11温湿度驱动

手动配置GPIO模式:

#define DHT_HIGHT HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET)
#define DHT_LOW HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET)
#define DHT_VALUE HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8)uint8_t datas[5];//空气温湿度数据void delay_us(uint16_t cnt)
{uint8_t i;while(cnt){for (i = 0; i < 10; i++){}	cnt--;}
}void DHT_GPIO_Init(uint32_t Mode)
{GPIO_InitTypeDef GPIO_InitStruct = {0};__HAL_RCC_GPIOB_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_8;GPIO_InitStruct.Mode = Mode;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}void DHT11_Start(void)
{DHT_GPIO_Init(GPIO_MODE_OUTPUT_PP);DHT_HIGHT;DHT_LOW;HAL_Delay(30);DHT_HIGHT;DHT_GPIO_Init(GPIO_MODE_INPUT);while(DHT_VALUE);while(!DHT_VALUE);while(DHT_VALUE);
}void Read_Data_From_DHT()
{int i;//轮int j;//每一轮读多少次char tmp;char flag;DHT11_Start();DHT_GPIO_Init(GPIO_MODE_INPUT);for(i= 0;i < 5;i++){for(j=0;j<8;j++){while(!DHT_VALUE);//等待卡g点delay_us(40);if(DHT_VALUE == 1){flag = 1;while(DHT_VALUE);}else{flag = 0;}tmp = tmp << 1;tmp |= flag;}datas[i] = tmp;}
}

数据显示以及文字显示:

void Printf_DHT11(u8g2_t u8g2,u8g2_uint_t x, u8g2_uint_t y, const uint8_t *font)
{char var_buf[100];char var_buf1[100];Read_Data_From_DHT();//读取温湿度数据u8g2_DrawXBMP(&u8g2, x, y, 16, 16, kong);u8g2_DrawXBMP(&u8g2, x+16, y, 16, 16, qi);u8g2_DrawXBMP(&u8g2, x+32, y, 16, 16, wen);u8g2_DrawXBMP(&u8g2, x+48, y, 16, 16, du);u8g2_DrawXBMP(&u8g2, x, y+16, 16, 16, kong);u8g2_DrawXBMP(&u8g2, x+16, y+16, 16, 16, qi);u8g2_DrawXBMP(&u8g2, x+32, y+16, 16, 16, wen);u8g2_DrawXBMP(&u8g2, x+48, y+16, 16, 16, du);sprintf(var_buf , ": %d.%d C",datas[2],datas[3]);sprintf(var_buf1, ": %d.%d",datas[0],datas[1]);u8g2_SetFont(&u8g2, font);u8g2_DrawStr(&u8g2, x+64, y+16, var_buf);u8g2_DrawStr(&u8g2, x+64, y+32, var_buf1);
}

5.5、光照强度、土壤湿度ADC转换

int Printf_Soil(u8g2_t u8g2,u8g2_uint_t x, u8g2_uint_t y, const uint8_t *font)
{char var[100];int value;HAL_ADC_Start(&hadc1); //启动ADC单次转换HAL_ADC_PollForConversion(&hadc1, 50); //等待ADC转换完成value = HAL_ADC_GetValue(&hadc1); //读取ADC转换数据value = 100 - value * 100 / 4096;
//	Soil  = value;u8g2_DrawXBMP(&u8g2, x, y, 16, 16, tu);u8g2_DrawXBMP(&u8g2, x+16, y, 16, 16, rang);u8g2_DrawXBMP(&u8g2, x+32, y, 16, 16, shi);u8g2_DrawXBMP(&u8g2, x+48, y, 16, 16, du);sprintf(var , ": %d %%", value);u8g2_SetFont(&u8g2, font);u8g2_DrawStr(&u8g2, x+64, y+16, var);return value;}int Printf_Light(u8g2_t u8g2,u8g2_uint_t x, u8g2_uint_t y, const uint8_t *font)
{char var[100];int value;HAL_ADC_Start(&hadc2); //启动ADC单次转换HAL_ADC_PollForConversion(&hadc2, 50); //等待ADC转换完成value = HAL_ADC_GetValue(&hadc2); //读取ADC转换数据value = 100 - value * 100 / 4096;
//	Light = value;u8g2_DrawXBMP(&u8g2, x, y, 16, 16, guang);u8g2_DrawXBMP(&u8g2, x+16, y, 16, 16, zhao);u8g2_DrawXBMP(&u8g2, x+32, y, 16, 16, qiang);u8g2_DrawXBMP(&u8g2, x+48, y, 16, 16, du);sprintf(var , ": %d %%", value);u8g2_SetFont(&u8g2, font);u8g2_DrawStr(&u8g2, x+64, y+16, var);return value;}

5.6、esp8266连接阿里云

这里我为了保险起见就是用了很多的延迟时间(连接时间过长),你们可以自己调节时间!

#define USERNAME   "test&k28qfTAtkBg" //用户名
//                 "test&k28qfTAtkBg"
#define PASSWORD   "d7c3b27a5d8ca954487de1e1946a4a08439a2c2508242268e9d90ce178178f39" //密码
//                 "d7c3b27a5d8ca954487de1e1946a4a08439a2c2508242268e9d90ce178178f39"
#define CLIENTID   "k28qfTAtkBg.test|securemode=2\\,signmethod=hmacsha256\\,timestamp=1736673123047|" //设备名称
//                 "k28qfTAtkBg.test|securemode=2\\,signmethod=hmacsha256\\,timestamp=1736673123047|"
#define PRODUCTID  "k28qfTAtkBg" //产品ID
//                 "k28qfTAtkBg"
#define DOMAINNAME "iot-06z00fj5kcoes6j.mqtt.iothub.aliyuncs.com" //域名
//                 "iot-06z00fj5kcoes6j.mqtt.iothub.aliyuncs.com"
#define DEVICENAME "test"//WiFi连接函数
void Wifi_Connect()
{printf("AT\r\n");//避免报错HAL_Delay(500);printf("AT+RESTORE\r\n");//恢复出厂HAL_Delay(5000);//	printf("AT+RST\r\n");//复位
//	HAL_Delay(5000);printf("ATE0\r\n");//关闭回显HAL_Delay(5000);printf("AT+CWMODE=3\r\n");//设置双模式HAL_Delay(5000);printf("AT+CWJAP=\"USER_E191B0\",\"98599714\"\r\n");//设置WIFI密码和账号HAL_Delay(5000);printf("AT+MQTTUSERCFG=0,1,\"NULL\",\"%s\",\"%s\",0,0,\"\"\r\n",USERNAME,PASSWORD);//设置MQTT的username和passwordHAL_Delay(5000);printf("AT+MQTTCLIENTID=0,\"%s\"\r\n",CLIENTID);	//设置CLIENTIDHAL_Delay(5000);printf("AT+MQTTCONN=0,\"%s\",1883,1\r\n",DOMAINNAME);//设置域名HAL_Delay(5000);printf("AT+MQTTSUB=0,\"/%s/%s/user/get\",1\r\n",PRODUCTID,DEVICENAME);//订阅}

六、功能拓展

后续拓展:

1、电脑阿里云平台控制单片机

2、添加语音模块

。。。。。。。。。。。。其他

后续打了PCB板子后有空会实现给大家,觉得有帮助的可以点点关注!

相关文章:

基于STM32的阿里云智能农业大棚

目录 前言&#xff1a; 项目效果演示&#xff1a; 一、简介 二、硬件需求准备 三、硬件框图 四、CubeMX配置 4.1、按键、蜂鸣器GPIO口配置 4.2、ADC输入配置 4.3、IIC——驱动OLED 4.4、DHT11温湿度读取 4.5、PWM配置——光照灯、水泵、风扇 4.6、串口——esp8266模…...

80,【4】BUUCTF WEB [SUCTF 2018]MultiSQL

53&#xff0c;【3】BUUCTF WEB october 2019 Twice SQLinjection-CSDN博客 上面这个链接是我第一次接触二次注入 这道题也涉及了 对二次注入不熟悉的可以看看 BUUCTF出了点问题&#xff0c;打不开&#xff0c;以下面这两篇wp作为学习对象 [SUCTF 2018]MultiSQL-CSDN博客 …...

深入探索imi框架:PHP Swoole的高性能协程应用实践

摘要 本文将介绍 imi 框架&#xff0c;这是一个基于 PHP Swoole 的高性能协程应用开发框架。imi 支持 HttpApi、WebSocket、TCP 和 UDP 等多种服务类型&#xff0c;利用 Swoole 的优化技术&#xff0c;使得在处理请求时响应速度远超传统的 php-fpm 方式。通过丰富的代码示例&a…...

【算法篇·更新中】C++秒入门(附练习用题目)

一.二分 1.二分查找 我们来看这样一道题&#xff1a; 有一个保证有序的数组a&#xff0c;它的长度为n。现在我们需要知道这个序列是否含有x。 数据范围&#xff1a;保证n<1e9 我们看到这道题之后&#xff0c;第一时间想到的就是暴力枚举了&#xff0c;可是我们发现直接枚举…...

对神经网络基础的理解

目录 一、《python神经网络编程》 二、一些粗浅的认识 1&#xff09; 神经网络也是一种拟合 2&#xff09;神经网络不是真的大脑 3&#xff09;网络构建需要反复迭代 三、数字图像识别的实现思路 1&#xff09;建立一个神经网络类 2&#xff09;权重更新的具体实现 3&am…...

存储基础 -- SCSI命令格式与使用场景

SCSI命令格式与使用场景 1. SCSI命令描述符块&#xff08;CDB&#xff09; 1.1 CDB基本概念 SCSI命令通过**命令描述符块&#xff08;CDB, Command Descriptor Block&#xff09;**表示。 CDB长度&#xff1a;SCSI命令根据使用场景有不同长度的CDB&#xff0c;常见的有6字节…...

从崩溃难题看 C 标准库与 Rust:线程安全问题引发的深度思考

在软件开发的世界里&#xff0c;每一次技术的变革和尝试都伴随着未知的挑战。EdgeDB 团队在将部分网络 I/O 代码从 Python 迁移到 Rust 的过程中&#xff0c;就遭遇了一场棘手的问题&#xff0c;这个问题不仅暴露了 C 标准库的线程安全隐患&#xff0c;也让我们对 Rust 的 “安…...

【CSS入门学习】Flex布局设置div水平、垂直分布与居中

水平平均分布 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>…...

9. 神经网络(一.神经元模型)

首先&#xff0c;先看一个简化的生物神经元结构&#xff1a; 生物神经元有多种类型&#xff0c;内部也有复杂的结构&#xff0c;但是可以把单个神经元简化为3部分组成&#xff1a; 树突&#xff1a;一个神经元往往有多个树突&#xff0c;用于接收传入的信息。轴突&#xff1a;…...

R 语言 | future 包,非阻塞的执行耗时脚本

目的&#xff1a;有一段代码&#xff0c;后面暂时用不到&#xff0c;但是又很耗时&#xff0c;占了当前R session&#xff0c;难道只能等半个小时&#xff0c;等到它结束才能画图&#xff1f; 可以使用R多线程&#xff0c;在支线进程中执行耗时任务&#xff0c;同时不阻塞当前…...

UE学习日志#12 Niagara特效大致了解(水文,主要是花时间读了读文档和文章)

1 核心组件&#xff08;官方文档阅读&#xff09; 一些介绍主要来自官方文档Niagara概述 1.1 Systems 官方文档中的描述&#xff1a; Niagara系统是一种容器&#xff0c;可以放入你要构建该效果的所有内容。在这个系统中&#xff0c;你可以搭建不同的构建块来实现总体效果。…...

【数据结构】_链表经典算法OJ:合并两个有序数组

目录 1. 题目描述及链接 2. 解题思路 3. 程序 3.1 第一版 3.2 第二版 1. 题目描述及链接 题目链接&#xff1a;21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。 新链表是通过拼接给…...

Mongodb副本集群为什么选择3个节点不选择4个节点

一、容错能力的定义 在副本集中&#xff0c;容错能力是指系统能够容忍多少个节点故障而仍然能够保持服务可用性的能力。这通常与选举机制中的多数投票原则密切相关。 二、三节点副本集的容错能力 在三节点的副本集中&#xff0c;通常有一个主节点和两个从节点。当主节点故障…...

基于 WEB 开发的手机销售管理系统设计与实现内容

标题:基于 WEB 开发的手机销售管理系统设计与实现 内容:1.摘要 摘要&#xff1a;随着智能手机的普及和电子商务的快速发展&#xff0c;手机销售行业面临着越来越多的挑战和机遇。为了提高销售效率和管理水平&#xff0c;本文设计并实现了一个基于 WEB 的手机销售管理系统。该系…...

LeetCode - Google 大模型校招10题 第1天 Attention 汇总 (3题)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/145368666 GroupQueryAttention(分组查询注意力机制) 和 KVCache(键值缓存) 是大语言模型中的常见架构&#xff0c;GroupQueryAttention 是注意力…...

Vue3 provide/inject用法总结

1. 基本概念 provide/inject 是 Vue3 中实现跨层级组件通信的方案&#xff0c;类似于 React 的 Context。它允许父组件向其所有子孙组件注入依赖&#xff0c;无论层级有多深。 1.1 基本语法 // 提供方&#xff08;父组件&#xff09; const value ref(hello) provide(key, …...

Linux——网络基础(1)

文章目录 目录 文章目录 前言 一、文件传输协议 应用层 传输层 网络层 数据链路层 数据接收与解封装 主机与网卡 数据传输过程示意 二、IP和MAC地址 定义与性质 地址格式 分配方式 作用范围 可见性与可获取性 生活例子 定义 用途 特点 联系 四、TCP和UDP协…...

【记录】日常|从零散记录到博客之星Top300的成长之路

文章目录 shandianchengzi 2024 年度盘点概述写作风格简介2024年的创作内容总结 shandianchengzi 2024 年度盘点 概述 2024年及2025年至今我创作了786即84篇文章&#xff0c;加上这篇就是85篇。 很荣幸这次居然能够入选博客之星Top300&#xff0c;这个排名在我之前的所有年份…...

【二分查找】力扣373. 查找和最小的 K 对数字

给定两个以 非递减顺序排列 的整数数组 nums1 和 nums2 , 以及一个整数 k 。 定义一对值 (u,v)&#xff0c;其中第一个元素来自 nums1&#xff0c;第二个元素来自 nums2 。 请找到和最小的 k 个数对 (u1,v1), (u2,v2) … (uk,vk) 。 示例 1: 输入: nums1 [1,7,11], nums2 …...

池化层Pooling Layer

1. 定义 池化是对特征图进行的一种压缩操作&#xff0c;通过在一个小的局部区域内进行汇总统计&#xff0c;用一个值来代表这个区域的特征信息&#xff0c;常用于卷积神经网络&#xff08;CNN&#xff09;中。 2. 作用 提取代表性信息的同时降低特征维度&#xff0c;具有平移…...

力扣算法题——11.盛最多水的容器

目录 &#x1f495;1.题目 &#x1f495;2.解析思路 本题思路总览 借助双指针探索规律 从规律到代码实现的转化 双指针的具体实现 代码整体流程 &#x1f495;3.代码实现 &#x1f495;4.完结 二十七步也能走完逆流河吗 &#x1f495;1.题目 &#x1f495;2.解析思路…...

自由学习记录(32)

文件里找到切换颜色空间 fgui中的 颜色空间是一种总体使用前的设定 颜色空间&#xff0c;和半透明混合产生的效果有差异&#xff0c;这种问题一般可以产生联系 动效就是在fgui里可以编辑好&#xff0c;然后在unity中也准备了对应的调用手段&#xff0c;可以详细的使用每一个具…...

VScode+Latex (Recipe terminated with fatal error: spawn xelatex ENOENT)

使用VSCode编辑出现Recipe terminated with fatal error: spawn xelatex ENOENT问题咋办&#xff1f; 很好解决&#xff0c;大概率的原因是因为latex没有添加到系统环境变量中&#xff0c;所有设置的编译工具没有办法找到才出现的这种情况。 解决方法&#xff1a; winR 然后输…...

「蓝桥杯题解」蜗牛(Java)

题目链接 这道题我感觉状态定义不太好想&#xff0c;需要一定的经验 import java.util.*; /*** 蜗牛* 状态定义&#xff1a;* dp[i][0]:到达(x[i],0)最小时间* dp[i][1]:到达 xi 上方的传送门最小时间*/public class Main {static Scanner in new Scanner(System.in);static f…...

PHP EOF (Heredoc) 详解

PHP EOF (Heredoc) 详解 PHP 中的 EOF(End Of File)是一种非常有用的语法特性,允许开发者创建多行字符串。它特别适合于创建格式化文本,如配置文件、HTML 模板等。本文将详细讲解 PHP EOF 的用法、优势以及注意事项。 什么是 EOF? EOF 是一种特殊的字符串定义方式,它允…...

pyautogui操控Acrobat DC pro万能PDF转Word,不丢任何PDF格式样式

为了将PDF转换脚本改为多进程异步处理&#xff0c;我们需要确保每个进程独立操作不同的Acrobat窗口。以下是实现步骤&#xff1a; 实现代码 import os import pyautogui import time import subprocess import pygetwindow as gw from multiprocessing import Pooldef conver…...

Day32:字符串的复制

在 Python 中&#xff0c;字符串的复制是指创建一个新的字符串&#xff0c;它的内容与原字符串相同。字符串是不可变的对象&#xff0c;这意味着你不能直接修改字符串的内容&#xff0c;但是可以通过复制来创建新的字符串进行操作。字符串的复制在一些情况下非常有用&#xff0…...

基于Mybatis继承AbstractRoutingDataSource使用自定义注解实现动态数据源

一&#xff1a;实现 方式一&#xff1a;继承AbstractRoutingDataSource使用自定义注解实现 环境&#xff1a;springboot3 MyBatis3 mysql-connector8 DataSourceKeyEnum枚举类 有几个数据源就配置几个枚举类&#xff0c;和数据源数量一一对应 class DataSourceKeyEnum{D…...

ZooKeeper 数据模型

ZooKeeper 数据模型 ZooKeeper 拥有层次化的命名空间&#xff0c;类似分布式文件系统&#xff0c;但每个节点不仅能有子节点&#xff0c;还可关联数据。节点路径为规范的绝对路径&#xff0c;用斜杠分隔&#xff0c;无相对引用。路径命名有如下约束&#xff1a; 路径名不能包…...

【VUE】Vue2中Vue.extend方法

在 Vue.js 2.x 版本中&#xff0c;Vue.extend() 方法被用于创建一个新的 Vue 子类&#xff0c;可以在该子类上扩展一些属性、指令和组件选项等&#xff0c;然后进行实例化。 比如&#xff0c;可以在创建一些类似 loading 式的函数式插件时&#xff0c;使用&#xff1a; 在 Vue…...