【江协STM32】10-2/3 MPU6050简介、软件I2C读写MPU6050
1. MPU6050简介
- MPU6050是一个6轴姿态传感器,可以测量芯片自身X、Y、Z轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景
- 3轴加速度计(Accelerometer):测量X、Y、Z轴的加速度
- 3轴陀螺仪传感器(Gyroscope):测量X、Y、Z轴的角速度
1.1 主要参数
- 16位ADC采集传感器的模拟信号,量化范围:-32768~32767
- 加速度计满量程选择:±2、±4、±8、±16(g)
- 陀螺仪满量程选择: ±250、±500、±1000、±2000(°/sec)
- 可配置的数字低通滤波器
- 可配置的时钟源
- 可配置的采样分频
I2C从机地址:1101000(AD0=0)、1101001(AD0=1)
如果在程序中用十六进制表示,一般有两种表示方式,以1101000地址为例。第一种,直接把7位二进制数转换为十六进制,110 1000就是0x68,所以可以说MPU6050的从机地址是0x68。在I2C通信时序中,第一个字节的高7位是从机地址,最低位是读写位,所以如果认为0x68是从机地址,在发送第一个字节时,需要先把0x68左移1位,再按位或上读写位。第二种,把0x68左移1位后的数据当做从机地址。0x68左移1位后是0xD0,则MPU6050的从机地址就是0xD0,这时在实际发送第一个字节时,如果需要写,就直接把0xD0当作第一个字节,如果需要读,就或上0x01,即0xD1当作第一个字节。
1.2 硬件电路

XCL、XDA:MPU6050的6轴传感器不够用,需要进行扩展时使用,通常用于外接磁力计或者气压计,MPU6050的主机接口可以直接访问这些扩展芯片的数据,在MPU6050内有DMP单元进行数据融合和姿态解算。
1.3 模块框图
2. 软件I2C读写MPU6050
2.1 接线图
SCL接PB10、SDA接PB11。由于本节代码使用的是软件I2C,即用普通的GPIO口手动翻转电平,不需要STM32内部的外设资源支持,所以这里端口可以任意指定,也可以SCL接PA8,SDA接PA9等。
根据I2C协议的硬件规定,SCL和SDA均应外挂上拉电阻,由于模块内部自带上拉电阻,所以不需要外接。XCL和XDA用于扩展的接口,不使用。AD0引脚修改从机地址的最低位,由于模块内接了下拉电阻,所以引脚悬空相当于接地。INT中断信号输出脚,不使用。
2.2 代码
程序的整体架构:
- 首先,建立I2C通信层的.c和.h模块。在通信层中,写好I2C底层的GPIO初始化和6个时序基本单元(起始、终止、发送一个字节、接收一个字节、发送应答、接收应答)。
- 再建立MPU6050的.c的.h模块。在此层,基于I2C通信模块实现指定地址读、指定地址写,再实现写寄存器对芯片进行配置、读寄存器得到传感器数据。
- 最后在main.c中调用MPU6050模块,初始化,获取数据,显示数据。
由于使用的是软件I2C,所以stm32的I2C库函数就不需要看了,只需要使用GPIO的读写函数。
MyI2C.c(防止和库函数的函数重名)
#include "stm32f10x.h" // Device header
#include "Delay.h"void MyI2C_Init(void)
{// 需要完成2个任务:// ① 把SCL和SDA均初始化为开漏输出模式;// ② 把SCL和SDA置高电平。RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;// 开漏输出(虽然名字是"输出",但开漏输出模式仍然可以输入)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;// SCL是PB10,SDA是PB11GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);// 置SCL和SDA高电平
}// 对操作端口的库函数进行封装
void MyI2C_W_SCL(uint8_t BitValue)// 写SCL。参数给1或0,就可以释放或拉低SCL
{GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);Delay_us(10);// 如果单片机主频较快,可以加延时,防止从机跟不上
}void MyI2C_W_SDA(uint8_t BitValue)// 写SDA。参数给1或0,就可以释放或拉低SDA
{GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);Delay_us(10);
}uint8_t MyI2C_R_SDA(void)// 读SDA
{uint8_t BitValue;BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);Delay_us(10);return BitValue;
}// 接下来完成I2C的6个时序基本单元
//
// 1、起始条件
// 首先确保SCL和SDA释放,然后先拉低SDA,再拉低SCL
void MyI2C_Start(void)
{MyI2C_W_SDA(1);// 释放SDAMyI2C_W_SCL(1);// 释放SCLMyI2C_W_SDA(0);// 先拉低SDAMyI2C_W_SCL(0);// 再拉低SCL
}// 2、终止条件
// SCL高电平期间,SDA从低电平切换到高电平
void MyI2C_Stop(void)
{MyI2C_W_SDA(0);// 先拉低SDA,避免SDA之前为高电平时释放无法产生上升沿MyI2C_W_SCL(1);// 再释放SCLMyI2C_W_SDA(1);// 再释放SDA
}// 3、发送一个字节
// SCL低电平,SDA变换数据;SCL高电平,SDA保持数据稳定。放完1位后,释放SCL,拉低SCL,驱动时钟运转
void MyI2C_SendByte(uint8_t Byte)
{uint8_t i;for(i = 0; i < 8; i++){MyI2C_W_SDA(Byte & (0x80 >> i));// 首先趁SCL低电平,把Byte的最高位放在SDA线上。下一轮就是把次高位放在SDA线上// 取Byte最高位为Byte&0x80,取次高位为Byte&0x40...在循环中,使用右移i位即可实现按位与数值的变换MyI2C_W_SCL(1);// 再释放SCL。释放后从机会立刻把SDA的数据读走MyI2C_W_SCL(0);// 拉低SCL}
}// 4、接收一个字节
// SCL低电平,从机把数据放到SDA上,为了防止主机干扰从机写入数据,主机需要先释放SDA,释放SDA也相当于切换为输入模式
// 然后主机在SCL高电平期间读取SDA,再拉低SCL。这样重复8次,主机就能读到一个字节了。
uint8_t MyI2C_ReceiveByte(void)
{uint8_t i, Byte = 0x00;MyI2C_W_SDA(1);// 主机释放SDAfor(i = 0; i < 8; i++){MyI2C_W_SCL(1);// 主机释放SCLif(MyI2C_R_SDA() == 1)// 主机读取数据{Byte |= (0x80 >> i);// 如果读取到1,就从高到低把Byte对应位置1}MyI2C_W_SCL(0);// 读取1位后拉低SCL,这时从机会把下一位数据放到SDA上}return Byte;
}// 5、发送应答
// 其实就是发送一个字节的简化
void MyI2C_SendAck(uint8_t AckBit)
{MyI2C_W_SDA(AckBit);// 函数进入时,SCL低电平,主机把AckBit放到SDA上MyI2C_W_SCL(1);// 再释放SCL。从机读取应答MyI2C_W_SCL(0);// 拉低SCL,进入下一个时序单元
}// 6、接收应答
// 其实就是接收一个字节的简化
uint8_t MyI2C_ReceiveAck(void)
{uint8_t AckBit;MyI2C_W_SDA(1);// 函数进入时SCL低电平,主机释放SDA防止干扰从机。同时,从机把应答位放在SDA上MyI2C_W_SCL(1);// 主机释放SCL,读取应答位AckBit = MyI2C_R_SDA();MyI2C_W_SCL(0);// 读取后拉低SCL,进入下一个时序单元return AckBit;
}
MyI2C.h
#ifndef __MYI2C_H
#define __MYI2C_Hvoid MyI2C_Init(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);#endif
MPU6050.c
#include "stm32f10x.h" // Device header
#include "MyI2C.h"
#include "MPU6050_Reg.h"#define MPU6050_ADDRESS 0xD0// 指定地址写
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{MyI2C_Start();MyI2C_SendByte(MPU6050_ADDRESS);// 发送从机地址+读写位MyI2C_ReceiveAck();// 接收应答MyI2C_SendByte(RegAddress);// 指定寄存器地址MyI2C_ReceiveAck();MyI2C_SendByte(Data);// 发送写入指定寄存器地址下的数据MyI2C_ReceiveAck();MyI2C_Stop();
}// 指定地址读
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data;MyI2C_Start();MyI2C_SendByte(MPU6050_ADDRESS);// 发送从机地址+读写位MyI2C_ReceiveAck();// 接收应答MyI2C_SendByte(RegAddress);// 指定寄存器地址MyI2C_ReceiveAck();MyI2C_Start();// 重复起始条件MyI2C_SendByte(MPU6050_ADDRESS | 0xD1);// 读写位1,读出数据MyI2C_ReceiveAck();Data = MyI2C_ReceiveByte();// 从机发送数据,主机接收数据MyI2C_SendAck(1);// 这里只想要1个字节,所以不给从机应答MyI2C_Stop();return Data;
}void MPU6050_Init(void)
{MyI2C_Init();MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);// 配置PWR_MGMT_1寄存器,解除睡眠,选择X轴陀螺仪时钟MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);// 采样率分频,决定了数据输出的快慢。10分频MPU6050_WriteReg(MPU6050_CONFIG, 0x06);// 数字低通滤波器给110MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);// 陀螺仪配置,选择最大量程11MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);// 加速度计配置,选择最大量程11}uint8_t MPU6050_GetID(void)
{return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}// 由于需要返回6个变量,使用指针的地址传递
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ,int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{uint8_t Data_H, Data_L;Data_H = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);// 加速度寄存器X轴高8位Data_L = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);*AccX = (Data_H << 8) | Data_L;// 加速度计X轴的16位数据Data_H = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);Data_L = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);*AccY = (Data_H << 8) | Data_L;Data_H = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);Data_L = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);*AccZ = (Data_H << 8) | Data_L;Data_H = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);// 陀螺仪寄存器X轴高8位Data_L = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);*GyroX = (Data_H << 8) | Data_L;// 陀螺仪X轴的16位数据Data_H = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);Data_L = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);*GyroY = (Data_H << 8) | Data_L;Data_H = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);Data_L = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);*GyroZ = (Data_H << 8) | Data_L;
}
MPU6050.h
#ifndef __MPU6050_H
#define __MPU6050_Hvoid MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);void MPU6050_Init(void);
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ,int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);
uint8_t MPU6050_GetID(void);#endif
MPU6050_Reg.h
#ifndef __MPU6050_REG_H
#define __MPU6050_REG_H#define MPU6050_SMPLRT_DIV 0x19
#define MPU6050_CONFIG 0x1A
#define MPU6050_GYRO_CONFIG 0x1B
#define MPU6050_ACCEL_CONFIG 0x1C#define MPU6050_ACCEL_XOUT_H 0x3B
#define MPU6050_ACCEL_XOUT_L 0x3C
#define MPU6050_ACCEL_YOUT_H 0x3D
#define MPU6050_ACCEL_YOUT_L 0x3E
#define MPU6050_ACCEL_ZOUT_H 0x3F
#define MPU6050_ACCEL_ZOUT_L 0x40
#define MPU6050_TEMP_OUT_H 0x41
#define MPU6050_TEMP_OUT_L 0x42
#define MPU6050_GYRO_XOUT_H 0x43
#define MPU6050_GYRO_XOUT_L 0x44
#define MPU6050_GYRO_YOUT_H 0x45
#define MPU6050_GYRO_YOUT_L 0x46
#define MPU6050_GYRO_ZOUT_H 0x47
#define MPU6050_GYRO_ZOUT_L 0x48#define MPU6050_PWR_MGMT_1 0x6B
#define MPU6050_PWR_MGMT_2 0x6C
#define MPU6050_WHO_AM_I 0x75#endif
main.c
#include "stm32f10x.h" // Device
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"int16_t AX, AY, AZ, GX, GY, GZ;int main(void)
{OLED_Init();MPU6050_Init();OLED_ShowString(1, 1, "ID:");OLED_ShowHexNum(1, 4, MPU6050_GetID(), 2);OLED_ShowString(1, 7, "Acc|Gyro");OLED_ShowString(2, 1, "X |");OLED_ShowString(3, 1, "Y |");OLED_ShowString(4, 1, "Z |");while(1){MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);OLED_ShowSignedNum(2, 3, AX, 5);OLED_ShowSignedNum(3, 3, AY, 5);OLED_ShowSignedNum(4, 3, AZ, 5);OLED_ShowSignedNum(2, 10, GX, 5);OLED_ShowSignedNum(3, 10, GY, 5);OLED_ShowSignedNum(4, 10, GZ, 5);}
}
其他引用的头文件和c代码可在此处查阅: OLED.h(【江协STM32】4 OLED调试工具)、Delay.h(【江协STM32】3-2 LED闪烁&LED流水灯&蜂鸣器,第1.3节)
相关文章:

【江协STM32】10-2/3 MPU6050简介、软件I2C读写MPU6050
1. MPU6050简介 MPU6050是一个6轴姿态传感器,可以测量芯片自身X、Y、Z轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景3轴加速度计(Accelerometerÿ…...

仓颉笔记——写一个简易的web服务并用浏览器打开
创建一个web服务端,同时创建一个客户端去读取这个服务端。 也满足浏览器打开web的需求。 直接上代码。 import net.http.* import std.time.* import std.sync.* import std.log.LogLevel// 1. 构建 Server 实例 let server ServerBuilder().addr("127.0.0.1&…...

DolphinScheduler自身容错导致的服务器持续崩溃重大问题的排查与解决
01 问题复现 在DolphinScheduler中有如下一个Shell任务: current_timestamp() { date "%Y-%m-%d %H:%M:%S" }TIMESTAMP$(current_timestamp) echo $TIMESTAMP sleep 60 在DolphinScheduler将工作流执行策略设置为并行: 定时周期调度设置…...
ecmascript 标准+ 严格模式与常规模式 + flat-flatMap 应用
文章目录 ecmascript 历程严格模式与常规模式下的区别及注意事项严格模式下的属性删除Array.prototype.flat()和Array.prototype.flatMap() 实例应用 ecmascript 历程 变量声明要求 常规模式: 在常规模式下,使用var关键字声明变量时会出现变量提升现象。…...

基于ILI9341液晶屏+STM32U5单片的显示试验
试验要求: 1、通过串口,下发两个命令 STR和PIC; 2、STR模式: (1)串口输入什么,屏幕上显示什么 (2)如果屏幕满,自动下滚 (3)输入回车&a…...

最短路径算法
关注:算法思路,时间复杂度,适用情况(单源/多源,负边权/负边权回路) 复习弗雷德算法--基于动态规划--多源--负边权--时间复杂度O(v^3) int的最大值是0x7fffffff #include <iostream> using namesp…...

如何用 ESP32-CAM 做一个实时视频流服务器
文章目录 ESP32-CAM 概述ESP32-S 处理器内存Camera 模块MicroSD 卡槽天线板载 LED 和闪光灯其他数据手册和原理图ESP32-CAM 功耗 ESP32-CAM 引脚参考引脚排列GPIO 引脚哪些 GPIO 可以安全使用?GPIO 0 引脚MicroSD 卡引脚 ESP32-CAM 的烧录方式使用 ESP32-CAM-MB 编程…...
Centos7 解决Maven scope=system依赖jar包没有打包到启动jar包中的问题(OpenCV-4.10)
最近项目中遇到问题,OpenCV的Jar包在程序打包后,找不到相关的类,比如MAT,这个时候怀疑OpenCV_4.10的Jar没有和应用程序一起打包,后面排查到确实是没有打包进去,特此记录,便于日后查阅。 <!-- 加载lib目录下的opencv包 --> <dependency><groupId>org…...
iOS实际开发中使用Alamofire实现多文件上传(以个人相册为例)
引言 在移动应用中,图片上传是一个常见的功能,尤其是在个人中心或社交平台场景中,用户经常需要上传图片到服务器,用以展示个人风采或记录美好瞬间。然而,实现多图片上传的过程中,如何设计高效的上传逻辑并…...
如何将分割的mask转为为分割标签
将分割的mask转换为分割标签通常涉及将每个像素的类别标识(在mask中以不同的灰度值或颜色表示)转换为整数标签。这些标签通常用于机器学习或深度学习模型的训练、验证和测试阶段。 使用方式,控制台或者命令行使用以下命令: pyth…...

【动手学电机驱动】STM32-MBD(5)Simulink 模型开发之 PWM 输出
STM32-MBD(1)安装 Simulink STM32 硬件支持包 STM32-MBD(2)Simulink 模型部署入门 STM32-MBD(3)Simulink 状态机模型的部署 STM32-MBD(4)Simulink 状态机实现按键控制 STM32-MBD&…...

MySQL进阶突击系列(05)突击MVCC核心原理 | 左右护法ReadView视图和undoLog版本链强强联合
2024小结:在写作分享上,这里特别感谢CSDN社区提供平台,支持大家持续学习分享交流,共同进步。社区诚意满满的干货,让大家收获满满。 对我而言,珍惜每一篇投稿分享,每一篇内容字数大概6000字左右&…...

vue2日历组件
这个代码可以直接运行,未防止有组件库没安装,将组件库的代码,转成文字了 vue页面 <template><div class"about"><div style"height: 450px; width: 400px"><div style"height: 100%; overflo…...
【PyQt】多行纯文本框
[toc]qt多行纯文本框 QPlainTextEdit QPlainTextEdit 是可以多行的纯文本编辑框 文本浏览框 内置了一个** QTextDocument **类型的对象 ,存放文档。 1.信号:文本被修改 当文本框中的内容被键盘编辑,被点击就会发出 textChanged 信号&…...
workerman5.0篇〡异步非阻塞协程HTTP客户端
概述 workerman/http-client 是一个异步http客户端组件。所有请求响应异步非阻塞,内置连接池,消息请求和响应符合PSR7规范。 Workerman 5.0 版本中的异步HTTP协程客户端组件是一个基于PHP协程的高性能HTTP客户端,它能够充分利用PHP的异步特…...

JavaScript 延迟加载的方法( 7种 )
JavaScript脚本的延迟加载(也称为懒加载)是指在网页的主要内容已经加载并显示给用户之后,再加载或执行额外的JavaScript代码。这样做可以加快页面的初始加载速度,改善用户体验,并减少服务器的压力。 以下是几种常见的延…...

python+pymysql
python操作mysql 一、python操作数据库 1、下载pymysql 库, 方法一:pip3 install pymysql 或pip install pymysql 方法二:在pycharm中setting下载pymysql 2、打开虚拟机上的数据库 3、pymysql连接 dbpymysql.Connection(host&qu…...
基于 Selenium 实现上海大学校园网自动登录
基于 Selenium 实现上海大学校园网自动登录 一、技术方案 核心工具: Selenium:一个用于自动化测试的工具,能够模拟用户在浏览器上的操作。Edge WebDriver:用于控制 Edge 浏览器的驱动程序。 功能设计: 检测网络状…...

啥!GitHub Copilot也免费使用了
文章目录 前言免费版直接修复代码多文件上下文Agent模式总结 前言 最近,GitHub 给开发者们带来了一个好消息:他们的 AI 编程助手 GitHub Copilot 现在可以免费使用了!以前,每个月要花 10 美元才能享受的服务,现在对所…...
Spring配置文件中:密码明文改为密文处理方式(通用方法)
目录 一、背景 二、思路 A) 普通方式 B) 适合bootstrap.properties方式 三、示例 A) 普通方式(连接Redis集群) A) 普通方式(连接RocketMQ) B) 适合bootstrap.properties方式 四、总结 一、背景 SpringBoot和Sprin…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...