STM32 I2C

目录

I2C通信

 软件I2C读写MPU6050

I2C通信外设

硬件I2C读写MPU6050


I2C通信

R/W:0写1读

十轴:3轴加速度,3轴角速度,3轴磁场强度和一个气压强度

 软件I2C读写MPU6050

MyI2C.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"/*** @brief  为I2C的SCL线写入数据* @param  BitValue:要写入的数据* @retval 无*/
void MyI2C_W_SCL(uint8_t BitValue)
{GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);Delay_us(10);//防止引脚反转速度过快,外设跟不上
}/*** @brief  为I2C的SDA线写入数据* @param  BitValue:要写入的数据* @retval 无*/
void MyI2C_W_SDA(uint8_t BitValue)
{GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);Delay_us(10);//防止引脚反转速度过快,外设跟不上
}/*** @brief  读取I2C的SDA线中的数据* @param  无* @retval SDA中的数据*/
uint8_t MyI2C_R_SDA(void)
{uint8_t BitValue;BitValue = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);Delay_us(10);return BitValue;
}/*** @brief  初始化GPIO引脚* @param  无* @retval 无*/
void MyI2C_Init(void)
{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;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_10 |  GPIO_Pin_11);//将SCL与SDA初始置为高电平(空闲)}/*** @brief  开启I2C通信* @param  无* @retval 无*/
void MyI2C_Start(void)
{MyI2C_W_SDA(1);MyI2C_W_SCL(1);//将两根线都置为高电平,准备开始时序MyI2C_W_SDA(0);MyI2C_W_SCL(0);//先将SDA拉低,再将SCL拉低形成起始条件
}/*** @brief  终止I2C通信* @param  无* @retval 无*/
void MyI2C_Stop(void)
{MyI2C_W_SDA(0);//确保SDA能产生上升沿,先进行拉低MyI2C_W_SCL(1);MyI2C_W_SDA(1);//在SCL处于高电平时,SDA产生上升沿形成终止条件
}/*** @brief  使用I2C发送一个字节* @param  Byte:发送的字节数据* @retval 无*/
void MyI2C_SendByte(uint8_t Byte)
{uint8_t i;for(i = 0;i<8;i++){MyI2C_W_SDA(Byte & (0x80 >> i));//取出最高位//即使进行运算后结果为0x80,写入的还是只有1MyI2C_W_SCL(1);//释放SCL进行发送MyI2C_W_SCL(0);//结束一次发送}
}/*** @brief  使用I2C接收一个字节* @param  无* @retval 接收到的字节数据*/
uint8_t MyI2C_ReceiveByte(void)
{uint8_t i,Byte = 0x00;MyI2C_W_SDA(1);//接收前需要先释放SDAfor(i = 0;i < 8;i ++){MyI2C_W_SCL(1);//SCL为高电平主机进行读取SDA上的数据if(MyI2C_R_SDA() == 1)//此时接收为1{Byte |= (0x80 >> i);//读到数据存入Byte}MyI2C_W_SCL(0);//拉低SCL完成一次读取}return Byte;
}/*** @brief  主机接收完一个字节后发送应答* @param  AckBit:应答位,0为应答,1为不应答* @retval 无*/
void MyI2C_SendAck(uint8_t AckBit)
{//接收完成时SCL为低电平MyI2C_W_SDA(AckBit);MyI2C_W_SCL(1);//释放SCL进行发送MyI2C_W_SCL(0);//结束一次发送
}/*** @brief  从机发送完一个字节后接收主机应答* @param  无* @retval 从机的应答值*/
uint8_t MyI2C_ReceiveAck(void)
{//发送完成时SCL为低电平uint8_t AckBit;MyI2C_W_SDA(1);//接收前先释放SDA//这里主机输出1,并不是强制SDA为高电平,而是释放SDA//进行通信时,主机释放SDA,从机会暂时获得控制权MyI2C_W_SCL(1);//释放SCL进行接收AckBit = MyI2C_R_SDA();//进行读取SDAMyI2C_W_SCL(0);//结束一次接收return AckBit;
}

MPU6050.c

#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "MPU6050_Reg.h"#define MPU6050_ADDRESS     0xD0/*** @brief  MPU6050指定地址写数据进寄存器* @param  RegAddress:写入寄存器位置* @param  Data:写入寄存器数据* @retval 无*/
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)//指定地址写寄存器
{MyI2C_Start();//开启I2C时序MyI2C_SendByte(MPU6050_ADDRESS);//从机地址加R(1)/W(0)MyI2C_ReceiveAck();//接收应答MyI2C_SendByte(RegAddress);//这个字节会存在MPU6050的当前地址指针中MyI2C_ReceiveAck();//接收应答MyI2C_SendByte(Data);//发送数据MyI2C_ReceiveAck();//接收应答MyI2C_Stop();//结束I2C时序
}/*** @brief  MPU6050指定地址读寄存器数据* @param  RegAddress:寄存器位置* @retval 寄存器中存的数据*/
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data;//写的时序MyI2C_Start();//开启I2C时序MyI2C_SendByte(MPU6050_ADDRESS);//从机地址加R(1)/W(0)MyI2C_ReceiveAck();//接收应答MyI2C_SendByte(RegAddress);//这个字节会存在MPU6050的当前地址指针中MyI2C_ReceiveAck();//接收应答//读的时序MyI2C_Start();//再次开启I2C时序MyI2C_SendByte(MPU6050_ADDRESS | 0x01);//从机地址+读MyI2C_ReceiveAck();//接收应答//此时控制权由从机控制(主机接收一个字节数据)Data = MyI2C_ReceiveByte();//主机接收一个字节数据MyI2C_SendAck(1);//发送应答(如果需要接收多个字节应答就给0,结束则给1)//主机收回总线控制权MyI2C_Stop();return Data;
}/*** @brief  初始化MPU6050* @param  无* @retval 无*/
void MPU6050_Init(void)
{MyI2C_Init();MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);//配置电源管理寄存器1//解除睡眠模式,并选择使用X轴陀螺仪时钟MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);//配置电源管理寄存器2//六个轴均不待机MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);//配置分频寄存器(值越小越快)//十分频MPU6050_WriteReg(MPU6050_CONFIG,0x06);//配置寄存器,(外部同步+数字低通滤波器)MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);//陀螺仪配置寄存器(自测使能+满量程选择)MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);//加速度计配置寄存器(自测+满量程配置+高通滤波器)
}/*** @brief  获得芯片ID号* @param  无* @retval 芯片ID*/
uint8_t MPU6050_GetID(void)
{return MPU6050_ReadReg(MPU6050_WHO_AM_I);//读取芯片ID号
}/*** @brief  读取加速度以及角速度数据* @param  AccX:X轴方向加速度* @param  AccY:Y轴方向加速度* @param  AccZ:Z轴方向加速度* @param  GyroX:X轴方向角速度* @param  GyroY:Y轴方向角速度* @param  GyroZ:Z轴方向角速度* @retval 无*/
void MPU6050_GetData(int16_t *AccX,int16_t *AccY,int16_t *AccZ,int16_t *GyroX,int16_t *GyroY,int16_t *GyroZ)
{uint8_t DataH,DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);//加速度X轴高八位DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);//低八位*AccX = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);//加速度Y轴高八位DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);//低八位*AccY = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);//加速度Z轴高八位DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);//低八位*AccZ = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);//加速度Z轴高八位DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);//低八位*GyroX = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);//加速度Z轴高八位DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);//低八位*GyroY = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);//加速度Z轴高八位DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);//低八位*GyroZ = (DataH << 8) | DataL;
}

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 header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"uint8_t KeyNum;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(),3);while(1){MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);OLED_ShowSignedNum(2,1,AX,5);OLED_ShowSignedNum(3,1,AY,5);OLED_ShowSignedNum(4,1,AZ,5);OLED_ShowSignedNum(2,8,GX,5);OLED_ShowSignedNum(3,8,GY,5);OLED_ShowSignedNum(4,8,GZ,5);}}

I2C通信外设

GPIO口需要配置为复用开漏输出模式。复用:就是GPIO的状态是交由片上外设来控制的,开漏输出,是I2C所规定的。

硬件I2C读写MPU6050

MPU6050.c

#include "stm32f10x.h"                  // Device header
#include "MPU6050_Reg.h"#define MPU6050_ADDRESS     0xD0/*** @brief  监控事件完成并延时退出* @param  I2Cx:选择的I2C资源* @param  I2C_EVENT:等待I2C完成的事件* @retval 无*/
void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{uint32_t TimeOut;TimeOut = 10000;while(I2C_CheckEvent(I2C2,I2C_EVENT) != SUCCESS)//等待Ev5事件完成{TimeOut -- ;if(TimeOut == 0){break;}}
}/*** @brief  MPU6050指定地址写数据进寄存器* @param  RegAddress:写入寄存器位置* @param  Data:写入寄存器数据* @retval 无*/
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)//指定地址写寄存器
{I2C_GenerateSTART(I2C2,ENABLE);//生成起始条件(非阻塞式,需要标志位判断)MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待Ev5事件完成I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);//发送从机地址(自带接收应答)MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待发送Ev6事件完成I2C_SendData(I2C2,RegAddress);//发送写入地址MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING);//等待Ev8事件完成I2C_SendData(I2C2,Data);//发送数据(只有一个字节,发完紧接结束)MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待Ev8_2事件完成I2C_GenerateSTOP(I2C2,ENABLE);
}/*** @brief  MPU6050指定地址读寄存器数据* @param  RegAddress:寄存器位置* @retval 寄存器中存的数据*/
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data;//写的时序I2C_GenerateSTART(I2C2,ENABLE);//生成起始条件(非阻塞式,需要标志位判断)MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待Ev5事件完成I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);//发送从机地址(自带接收应答)MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待发送Ev6事件完成(发送)I2C_SendData(I2C2,RegAddress);//发送写入地址MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待Ev8事件完成//读的时序I2C_GenerateSTART(I2C2,ENABLE);//生成重复起始条件MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待发送Ev5事件完成I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver);//发送从机地址并改为接收方向(自带接收应答)MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//等待发送Ev6事件完成(接收)//清除响应和停止条件的产生位(在最后一个数据之前就要将Ack置零以及设置Stop终止条件)I2C_AcknowledgeConfig(I2C2,DISABLE);//设置Ack = 0,不给应答I2C_GenerateSTOP(I2C2,ENABLE);//配置停止位MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED);//等待发送Ev7事件完成//此时一个字节的数据以及存在DR中//读取DR即可获得字节Data = I2C_ReceiveData(I2C2);I2C_AcknowledgeConfig(I2C2,ENABLE);//方便接收多个字节return Data;
}/*** @brief  初始化MPU6050* @param  无* @retval 无*/
void MPU6050_Init(void)
{//开启对应时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);//配置GPIOGPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//复用开漏GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);//配置I2CI2C_InitTypeDef I2CInitStructure;I2CInitStructure.I2C_Mode = I2C_Mode_I2C;//I2C模式I2CInitStructure.I2C_ClockSpeed = 50000;//时钟速度(标准100 kHz,快速400 kHz)I2CInitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//时钟占空比(>100kHz才有用)I2CInitStructure.I2C_Ack = I2C_Ack_Enable;//配置Ack位I2CInitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//Stm32作为从机能响应几位地址I2CInitStructure.I2C_OwnAddress1 = 0x00;//指定stm32自身地址I2C_Init(I2C2,&I2CInitStructure);I2C_Cmd(I2C2,ENABLE);MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);//配置电源管理寄存器1//解除睡眠模式,并选择使用X轴陀螺仪时钟MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);//配置电源管理寄存器2//六个轴均不待机MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);//配置分频寄存器(值越小越快)//十分频MPU6050_WriteReg(MPU6050_CONFIG,0x06);//配置寄存器,(外部同步+数字低通滤波器)MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);//陀螺仪配置寄存器(自测使能+满量程选择)MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);//加速度计配置寄存器(自测+满量程配置+高通滤波器)
}/*** @brief  获得芯片ID号* @param  无* @retval 芯片ID*/
uint8_t MPU6050_GetID(void)
{return MPU6050_ReadReg(MPU6050_WHO_AM_I);//读取芯片ID号
}/*** @brief  读取加速度以及角速度数据* @param  AccX:X轴方向加速度* @param  AccY:Y轴方向加速度* @param  AccZ:Z轴方向加速度* @param  GyroX:X轴方向角速度* @param  GyroY:Y轴方向角速度* @param  GyroZ:Z轴方向角速度* @retval 无*/
void MPU6050_GetData(int16_t *AccX,int16_t *AccY,int16_t *AccZ,int16_t *GyroX,int16_t *GyroY,int16_t *GyroZ)
{uint8_t DataH,DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);//加速度X轴高八位DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);//低八位*AccX = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);//加速度Y轴高八位DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);//低八位*AccY = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);//加速度Z轴高八位DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);//低八位*AccZ = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);//加速度Z轴高八位DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);//低八位*GyroX = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);//加速度Z轴高八位DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);//低八位*GyroY = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);//加速度Z轴高八位DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);//低八位*GyroZ = (DataH << 8) | DataL;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/470202.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue2学习第一天

Vue2 学习第一天 1. 什么是 vue? Vue 是一套用于构建用户界面的渐进式框架。 2. vue 历史 vue 是在 2013 年创建的&#xff0c;vue3 是 2020 出现的&#xff0c;现在主要是用 vue2&#xff0c;创新公司用的是 vue3 vue 的作者是尤雨溪&#xff0c;vue 的搜索热度比 react…

基于HTML5实现动态烟花秀效果(含音效和文字)实战

目录 前言 一、烟花秀效果功能分解 1、功能分解 2、界面分解 二、HTML功能实现 1、html界面设计 2、背景音乐和燃放触发 3、燃放控制 4、对联展示 5、脚本引用即文本展示 三、脚本调用及实现 1、烟花燃放 2、燃放响应 3、烟花canvas创建 4、燃放声音控制 5、实际…

鸿蒙开发系列教程(十八)--页面内动画(1)

页面内的动画 显示动画 语法&#xff1a;animateTo(value: AnimateParam, event: () > void): void 第一个参数指定动画参数 第二个参数为动画的闭包函数。 如&#xff1a;animateTo({ duration: 1000, curve: Curve.EaseInOut }, () > {动画代码}&#xff09; dura…

Excel导入预览与下载

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Excel导入预览与下载 preview Controller PostMapping("preview")ApiOperation("上传拒付预警预览")public Result<List<ResChargebackWa…

Linux系统编程(四)进程

一、进程的产生&#xff08;fork&#xff09; fork(2) 系统调用会复制调用进程来创建一个子进程&#xff0c;在父进程中 fork 返回子进程的 pid&#xff0c;在子进程中返回 0。 #include <sys/types.h> #include <unistd.h>pid_t fork(void); fork 后子进程不继…

【MySQL】高度为2和3时B+树能够存储的记录数量的计算过程

文章目录 题目答案高度为2时的B树高度为3时的B树总结 GPT4 对话过程 题目 InnoDB主键索引的Btree在高度分别为 2 和 3 时&#xff0c;可以存储多少条记录&#xff1f; 答案 高度为2时的B树 计算过程&#xff1a; 使用公式 ( n 8 ( n 1 ) 6 16 1024 ) (n \times 8 …

一文搞懂“什么是双亲委派”

文章目录 双亲委派介绍类加载器介绍类加载流程验证自定义类加载器为什么要设计这种机制 提前声明&#xff1a;以下介绍都是基于jdk9之前版本的双亲委派机制&#xff0c;jdk9及之后版本双亲委派会有变化&#xff0c;不在本篇介绍。 双亲委派介绍 双亲委派机制&#xff08;Pare…

[Vue warn]: Duplicate keys detected: ‘1‘. This may cause an update error.

[Vue warn]: Duplicate keys detected: ‘1‘. This may cause an update error.——> Vue报错&#xff0c;key关键字不唯一&#xff1a; 解决办法&#xff1a;修改一下重复的id值&#xff01;&#xff01;&#xff01;

并发CPU伪共享及优化

目录 伪共享 解决 伪共享 缓存系统中是以缓存行&#xff08;cache line&#xff09;为单位存储的。缓存行是2的整数幂个连续字节&#xff0c;一般为32-256个字节。最常见的缓存行大小是64个字节。当多线程修改互相独立的变量时&#xff0c;如果这些变量共享同一个缓存行&am…

459. Repeated Substring Pattern( 重复的子字符串)

问题描述 给定一个非空的字符串 s &#xff0c;检查是否可以通过由它的一个子串重复多次构成。 问题分析 如果一个字符串s能够由其子字符串重复多次构成&#xff0c;那么这个子字符串的长度 l l l一定是字符串s长度 L L L的因子&#xff0c;即 L / l z ( z ∈ 整数 ) L/lz …

【Linux学习】线程池

目录 23.线程池 23.1 什么是线程池 23.2 为什么需要线程池 23.3 线程池的应用场景 23.4 实现一个简单的线程池 23.4.1 RAII风格信号锁 23.4.2 线程的封装 23.4.3 日志打印 22.4.4 定义队列中存放Task类任务 23.4.5 线程池的实现(懒汉模式) 为什么线程池中需要有互斥锁和条件变…

云备份项目:在云端保护您的数据【二、开发】

☘️过度的信息对一个过着充实生活的人来说&#xff0c;是一种不必要的负担☘️ 文章目录 前言工具类实现文件实用工具类代码实现 Json实用工具类代码实现 服务端单例配置类系统配置信息单例配置类 数据管理类数据信息数据管理 热点管理类业务处理类 客户端数据管理类文件备份类…