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

STM32--MPU6050与I2C外设

文章目录

  • 前言
  • MPU6050
    • 参数
    • 电路
    • MPU6050框图
  • IIC外设
    • 框图
  • IIC的基本结构
  • 软件IIC实现MPU6050
  • 硬件IIC实现MPU6050

前言

在51单片机专栏中,用过I2C通信来进行实现AT24C02的数据存储;
里面介绍的是利用程序的编程来实现I2C的时序,进而实现AT24C02与单片机之间的关系连接;
本章将介绍使用I2C的硬件外设来实现I2C通信,和介绍MPU6050,利用I2C通信实现STM32对MPU6050的控制.

I2C通信软件实现程序链接入口

MPU6050

MPU6050是一种集成三轴陀螺仪和三轴加速度计的六轴运动处理组件。
可以用来感知物体的旋转和加速度运动,并提供相应的测量数据

在这里插入图片描述

MPU6050采用微机电系统(MEMS)技术,通过测量微小的力和振动来检测物体的运动。其内置的三轴陀螺仪可以测量绕X、Y、Z轴的角速度,而三轴加速度计可以测量物体在X、Y、Z轴上的加速度。通过结合两者的数据,可以获得更准确的运动信息。

MPU6050还具有一个可扩展的数字运动处理器(DMP),可以实现更复杂的运动处理功能。DMP可以通过主要的I2C或SPI端口输出完整的九轴运动融合数据,当连接到三轴磁强计时,可以获得更全面的运动信息。

MPU6050广泛应用于飞行器、机器人、游戏控制器等领域,可以提供准确的姿态感知和运动跟踪功能。它的集成设计减少了封装空间和组合陀螺仪与加速度计时间轴不匹配的问题,使其在各种应用中具有较高的可靠性和性能。

参数

角速度全格感测范围:±250、±500、±1000、±2000°/sec(dps)
可追踪快速和慢速动作

加速度全格感测范围:±2g、±4g、±8g、±16g

产品传输可透过最高至400kHz的IIC

16位ADC采集传感器的模拟信号,量化范围:-32768~32767

I2C从机地址:
1101000(AD0=0) 0x68
1101001(AD0=1)0x69

这里的地址是没有融入读写地址位的,如果融入读写地址位,那么将通过左移的方式,变成11010000,0xD0;11010001,0xD1。

电路

在这里插入图片描述
最右边的是MPU6050的芯片,左下角是8针的排针,左上角是一个低压差线性稳压器。

芯片包括时钟、IIC通信引脚、供电、帧同步等,本章有很多是用不到的。

左下角VCC和GND是引脚供电;SCL和SDA是IIC通信的引脚,在芯片处,SCL和SDA已经内置了两个4.7k的上拉电阻,在接线时,可以直接连接到GPIO口。
XCL和XDA是主机的IIC引脚,目的是为了拓展芯片功能,可拓展磁力计等功能。
AD0是从机地址的最低位,接低电平时,7位从机地址为1101000,接高电平时,7位从机地址就是1101001.这里默认连接上了弱下拉到低电平,引脚悬空时,即为低电平。倘若想变为高电平,可以直接连接VCC,强上拉为高电平。
INT是中断输出引脚,可配置芯片内部一些事件,来触发中断引脚的输出。

左上角LD0是供电的逻辑,MPU6050芯片的VCC供电为2.375~3.46V,属于3.3V的供电设备,为了扩大供电范围,设计者在电路中加入3.3V的稳压器,输入端电压VCC_5V可以在3.3V到5V之间,经过稳压器后即可输出3.3V的电压,一旦3.3V端有电压,指示灯就会亮起。

MPU6050框图

在这里插入图片描述
该图即为芯片的内部结构。

左上角是时钟系统,有时钟输入脚和时钟输出脚。

灰色部分就是芯片的传感器,分别是XYZ轴的加速度计,XYZ轴的陀螺仪。且还内置一个温度传感器,本质上传感器就是可变电阻,所以通过ADC模数转换,就可以产生数据放在数据寄存器中。我们只需要读取寄存器中的数据即可得到测量值。

最左边是用来验证芯片的好坏的,当启动自测后,芯片内部会模拟一个外力施加在传感器上,该数据一般给的比平时大一些。可以用使能自测,读取数据,再使能自测,读取数据,最后数据差称为数据响应,只要数据响应在规定范围内,则表明芯片没问题。

ChargePump为电荷泵,这是一种升压电路,会连接一个电容。
电荷泵与电容并联时,可为电容充电,串联时,那么电荷泵和电容一起为芯片供电,提供比原来大的电压。

右边是通信接口和一些寄存器。
中断状态寄存器,可以控制内部的某些事件到中断引脚的输出;
FIFO是先入先出寄存器,可以对数据流进行缓冲;
配置寄存器,可以对内部电路进行配置。
传感器寄存器,也就是数据寄存器,存储各传感器的数据。
工厂校准,内部的传感器都进行了校准;
数字运动处理器(DMP),这是芯片内部自带的一个姿态解算的硬件算法。

然后就是IIC通信的接口,链接着STM32,下面还有一些是主机的IIC通信接口。通过(SIBM)寄存器选择。

IIC外设

STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担

支持多主机模型

支持7位/10位地址模式

支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz)

支持DMA

兼容SMBus协议

STM32F103C8T6 硬件I2C资源:I2C1、I2C2

框图

在这里插入图片描述
SDA接收数据和发送数据;
对于要发送的数据,会从数据寄存器转移到数据移位寄存器中,数据移位寄存器再通过引脚串行发送数据位;
对于要接收的数据,也会先放到数据移位寄存器中,数据寄存器再从移位寄存器中取数据,这样做的目的是为了更好的缓存数据,防止有些数据会丢失。
数据寄存器可以通过写入控制寄存器对应位进行操作。

比较器和地址寄存器是从机模式使用的,STM32的IIC是基于可变多主机模型设计的,当STM32不通信时,可作为从机,可被别人召唤,这时就需要一个地址。
PEC是一个数据校验模块,当发送一个多数据帧时,硬件可以自动执行CRC校验计算,CRC是一种校验算法,会根据前面这些数据,进行各种数据运算,会得到一个字节的校验位,加在数据帧后面;STM32也可以自动对数据帧进行判断,如果数据在传输过程中出错,CRC算法通不过,硬件就会置校验错误标志位。

SCL连接着时钟控制。
SMBALEART是用于SMBus模式的,不使用该模式接口不能使用。

IIC的基本结构

在这里插入图片描述
数据控制器,控制对数据的发送和接收;
时钟控制器,控制对时钟的流动;
再接上GPIO口,最后把开关控制启用,就能实现IIC通信。

软件IIC实现MPU6050

OLED代码链接入口

连接方式:
在这里插入图片描述

利用OLED屏幕显示MPU6050陀螺仪和加速度各轴数据;

IIC.h

#ifndef __I2C_H__
#define __I2C_H__void I2C_INIT();
void I2C_Start();
void I2C_Stop();
void I2C_SendByte(uint8_t Byte);
uint8_t I2C_ReceiveByte();
void I2C_SendAck(uint8_t AckBit);
uint8_t I2C_ReceiveAck();#endif

IIC.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"void I2C_W_SCL(uint8_t BitValue)
{GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);Delay_us(10); //延迟是让函数有时间反应
}void I2C_W_SDA(uint8_t BitValue)
{GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);Delay_us(10); //延迟是让函数有时间反应
}uint8_t I2C_R_SDA()
{uint8_t BitValue;BitValue=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);Delay_us(10);return BitValue;
}void I2C_INIT()
{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);
}void I2C_Start()
{I2C_W_SDA(1);I2C_W_SCL(1);I2C_W_SDA(0);I2C_W_SCL(0);
}void I2C_Stop()
{I2C_W_SDA(0);I2C_W_SCL(1);I2C_W_SDA(1);
}void I2C_SendByte(uint8_t Byte)
{uint8_t i;for(i=0;i<8;i++){I2C_W_SDA(Byte&(0x80>>i));//高电平锁存,从机读取I2C_W_SCL(1);I2C_W_SCL(0);}
}uint8_t I2C_ReceiveByte()
{uint8_t i,Byte=0x00;I2C_W_SDA(1); //主机释放SDAfor(i=0;i<8;i++){I2C_W_SCL(1); //SCL高电平期间主机读取从机发送的数据if(I2C_R_SDA()==1){Byte|=(0x80>>i);}I2C_W_SCL(0);}return Byte;
}void I2C_SendAck(uint8_t AckBit)
{I2C_W_SDA(AckBit);//高电平锁存,从机读取I2C_W_SCL(1);I2C_W_SCL(0);
}uint8_t I2C_ReceiveAck()
{uint8_t AckBit;I2C_W_SDA(1); //主机释放SDAI2C_W_SCL(1); //SCL高电平期间主机读取从机发送的数据AckBit=I2C_R_SDA(); I2C_W_SCL(0);return AckBit;
}

这部分实现的是IIC的六个主要部分的代码,与51单片机上的时序基本一致;在STM32上,是利用GPIO口来实现高低电平的输入输出。

输出模式用开漏输出,当输出低电平时,电路会强下拉,变为低电平;
当输出为高电平时,为弱上拉,一旦有下拉电平输入,就会变成低电平。

该模式不止可以实现输出,也可以实现对IIC的接收,当输入为1时,在SCL高电平时STM32会读取;当输入为0时,在SCL高电平STM32会读取.

MPU6050_tag.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

MPU6050.h

#ifndef __MPU6050_H__
#define __MPU6050_H__void MPU6050_Init();
uint8_t MPU6050_GetID();
void MPU6050_GetData(int16_t* AccX,int16_t* AccY,int16_t* AccZ,int16_t* GyroX,int16_t* GyroY,int16_t* GyroZ);#endif

MPU6050.c

#include "stm32f10x.h"                  // Device header
#include "I2C.h"
#include "MPU6050_rag.h"#define MPU6050_ADDRESS 0xD0void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)
{I2C_Start();I2C_SendByte(MPU6050_ADDRESS);I2C_ReceiveAck();I2C_SendByte(RegAddress);I2C_ReceiveAck();I2C_SendByte(Data);I2C_ReceiveAck();I2C_Stop();}uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data;I2C_Start();I2C_SendByte(MPU6050_ADDRESS);I2C_ReceiveAck();I2C_SendByte(RegAddress);I2C_ReceiveAck();I2C_Start();I2C_SendByte(MPU6050_ADDRESS|0x01);I2C_ReceiveAck();Data=I2C_ReceiveByte();I2C_SendAck(1); //主机不应答,主机收回主动权,让从机停止发送数据字节I2C_Stop();return Data;}void MPU6050_Init()
{I2C_INIT();MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01); //解除睡眠,选择陀螺仪时钟MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x00); //6个轴均不待机MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09); //采样分频为10MPU6050_WriteReg(MPU6050_CONFIG, 0x06);  //滤波参数给最大MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18); //最大陀螺仪量程MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18); //最大加速度量程}uint8_t MPU6050_GetID()
{return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}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);DataL=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);*AccX=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);DataL=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);*AccY=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);DataL=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);*AccZ=(DataH<<8)|DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);*GyroX = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);*GyroY = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);*GyroZ = (DataH << 8) | DataL;}

第一个代码块是对MPU6050一些寄存器地址的宏定义,主要有采样分频寄存器、陀螺仪配置寄存器、加速度配置寄存器、加速度数据寄存器、陀螺仪数据寄存器、状态寄存器1/2、地址寄存器。

对于MPU6050的读写,采用了IIC通信时序实现
写时序:在这里插入图片描述
读时序:
在这里插入图片描述
数据存储器为16位存储;

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"uint8_t ID;
int16_t AX,AY,AZ,GX,GY,GZ;int main()
{OLED_Init();MPU6050_Init();OLED_ShowString(1,1,"ID:");ID=MPU6050_GetID();OLED_ShowHexNum(1,4,ID,2);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);}
}

硬件IIC实现MPU6050

连接方式与软件的保持一致。由于是硬件外设,需要注意引脚有没有支持该IIC功能。
在这里插入图片描述
对于硬件外设,我们只需要对软件实现部分的IIC通信进行修改。
MPU6050.c

#include "stm32f10x.h"                  // Device header
#include "MPU6050_rag.h"#define MPU6050_ADDRESS 0xD0void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{uint32_t Timeout;Timeout = 10000;while (I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS){Timeout --;if (Timeout == 0){break;}}
}void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)
{I2C_GenerateSTART(I2C2,ENABLE); //SMPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //EV5I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //EV6I2C_SendData(I2C2,RegAddress);MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING); //EV8I2C_SendData(I2C2,Data);MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED); //EV8_2I2C_GenerateSTOP(I2C2,ENABLE);
}uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data;I2C_GenerateSTART(I2C2,ENABLE); //SMPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //EV5I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter); MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //EV6I2C_SendData(I2C2,RegAddress); MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);I2C_GenerateSTART(I2C2,ENABLE); //SMPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //EV5I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver);MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED); //EV6//EV7_1I2C_AcknowledgeConfig(I2C2,DISABLE);//应答位禁用    I2C_GenerateSTOP(I2C2,ENABLE); //PMPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED); //EV7Data=I2C_ReceiveData(I2C2);I2C_AcknowledgeConfig(I2C2,ENABLE); //应答位启用return Data;}void MPU6050_Init()
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_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);I2C_InitTypeDef I2C_InitStructure;I2C_InitStructure.I2C_Ack=I2C_Ack_Enable; //启用应答位I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit; //确认地址模式I2C_InitStructure.I2C_ClockSpeed=50000; //时钟频率I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2; //占空比I2C_InitStructure.I2C_Mode=I2C_Mode_I2C; //模式选择I2C_InitStructure.I2C_OwnAddress1=0x00;I2C_Init(I2C2,&I2C_InitStructure);I2C_Cmd(I2C2,ENABLE);MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01); //解除睡眠,选择陀螺仪时钟MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x00); //6个轴均不待机MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09); //采样分频为10MPU6050_WriteReg(MPU6050_CONFIG, 0x06);  //滤波参数给最大MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18); //最大陀螺仪量程MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18); //最大加速度量程}uint8_t MPU6050_GetID()
{return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}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);DataL=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);*AccX=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);DataL=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);*AccY=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);DataL=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);*AccZ=(DataH<<8)|DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);*GyroX = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);*GyroY = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);*GyroZ = (DataH << 8) | DataL;}

这里的初始化,GPIO引脚需要用到复用模式,因为IIC外设是片上外设;
接收数据和发送数据要根据STM32的要求,
在这里插入图片描述
根据响应事件来确定事件的产生效果,所以会在每条条件后执行响应事件。
对于所给的库函数,有些事件(EVX)没有提供,一些可以省略,一些需要对程序进行一定的整改。
如上面的EV8_1,确保数据寄存器和移位寄存器为空,在我们一开始调用时,就为空,所以可以对它进行忽略。
在这里插入图片描述
接收数据的EV7_1,描述到,设置应答位为无应答,和Stop请求;对于连续接收的数据,需要在最后一个数据之前进行EV7_1响应,在进行EV7_1响应时,因为最后一个数据会先放到移位寄存器中,最后第二个会在数据寄存器中。需要提前STOP请求,表示,接收结束。
而在程序中,我们只是对一个数据进行接收,并没有连续接收数据,但道理一样,需要提前STOP请求。而在库函数中刚好没有对应的函数,需要自己禁用ACK和STOP请求。

上软下硬:
在这里插入图片描述

这时软件和硬件的波形对比,会发现,在应答位硬件会更快应答,只要到到SCL下降沿和SDA上升沿,就会产生应答。这就是硬件的优势;

在软件中,由于是同步时序,对于时间没有严格要求,只要在对应时间完成对应的电平操作即可,所以IIC通信才可以实现软件编程。而软件编程相对来说,也比较容易理解。

相关文章:

STM32--MPU6050与I2C外设

文章目录 前言MPU6050参数电路MPU6050框图 IIC外设框图 IIC的基本结构软件IIC实现MPU6050硬件IIC实现MPU6050 前言 在51单片机专栏中&#xff0c;用过I2C通信来进行实现AT24C02的数据存储&#xff1b; 里面介绍的是利用程序的编程来实现I2C的时序&#xff0c;进而实现AT24C02与…...

项目管理实战笔记1:项目管理常识

序 看了下极客时间的《项目管理实战》&#xff0c;觉得跟之前学习PMP的标准资料还是有所侧重。重新整理下&#xff0c;相比书上繁杂的知识&#xff0c;这个更通俗易懂。 1 角色转换&#xff1a;三大误区 误区1&#xff1a;事必躬亲 自己做事情是可控的&#xff0c;做项目依赖…...

时序分解 | MATLAB实现基于SVMD逐次变分模态分解的信号分解分量可视化

时序分解 | MATLAB实现基于SVMD逐次变分模态分解的信号分解分量可视化 目录 时序分解 | MATLAB实现基于SVMD逐次变分模态分解的信号分解分量可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 SVMD分解算法&#xff0c;分解结果可视化&#xff0c;MATLAB程序&#xff…...

阿里云访问端口被限制解决方法记录

阿里云服务器&#xff0c;80端口可以访问&#xff0c;但是加入了安全组端口8080 通过公网访问改端口策略&#xff0c;发现不能被访问 问题出在防火墙&#xff0c;需要重置一下 解决方法&#xff1a; 在运行的服务器上执行如下命令&#xff1a; # iptables -A INPUT -j ACCEP…...

antd5源码调试环境启动(MacOS)

将源码下载至本地 这里antd5 版本是5.8.3 $ git clone gitgithub.com:ant-design/ant-design.git $ cd ant-design $ npm install $ npm start前提&#xff1a;安装python3、node版本18.14.0(这是本人当前下载的版本&#xff09; python3安装教程可参考&#xff1a;https://…...

单片机使用基于时间片轮询系统的-状态机-[1]

目的&#xff1a;【1】用C实现一个超轻量化任务管理系统 【2】具有任务suspend, resume, runonce ,auto loop ,task_delay功能 【3】易于移植&#xff0c;不涉及硬件底层。 示例例码&#xff1a; 利用switch case结构实现了单一层的 task_delay功能。弊端就是switch..case不…...

前端开发怎么解决性能优化的问题? - 易智编译EaseEditing

前端性能优化是确保网站或应用在加载速度、响应性和用户体验等方面达到最佳状态的关键任务。以下是一些解决前端性能优化问题的方法&#xff1a; 压缩和合并代码&#xff1a; 压缩和合并CSS、JavaScript和HTML文件可以减少文件大小&#xff0c;加快加载速度。使用压缩工具&am…...

共享球拍小程序:打破拥有束缚,尽享运动乐趣

市场前景&#xff1a; 随着健身和运动的流行趋势&#xff0c;越来越多的人加入了各种体育项目。然而&#xff0c;拥有球拍作为体育装备的成本较高&#xff0c;对于想要尝试不同运动的人来说&#xff0c;这可能是个阻碍。共享球拍小程序迎合了这一需求&#xff0c;提供了一个经济…...

uniapp 微信小程序 绘制海报,长按图片分享,保存海报

uView UI 2.0 dcloud 插件市场地址 弹窗海报源码 <template><!-- 推荐商品弹窗 --><u-popup :show"haibaoShow" mode"center" round26rpx z-index10076 bgColortransparent safeAreaInsetTop close"goodsclose"><image …...

爬虫异常捕获与处理方法详解

Hey&#xff01;作为一名专业的爬虫代理供应商&#xff0c;我今天要和大家分享一些关于爬虫异常捕获与处理的方法。在进行爬虫操作时&#xff0c;我们经常会遇到各种异常情况&#xff0c;例如网络连接错误、请求超时、数据解析错误等等。这些异常情况可能会导致程序崩溃或数据丢…...

制作网络课堂学习平台(标签嵌套,后代选择器)

网络课堂学习平台 课程 1 这是课程 1 的描述。 模块 1 这是模块 1 的描述。 查看详情 模块 2 这是模块 2 的描述。 查看详情 课程 2 这是课程 2 的描述。 模块 1 这是块 2 的描述。 查看详情...

基于医疗领域数据微调LLaMA——ChatDoctor模型

文章目录 ChatDoctor简介微调实战下载仓库并进入目录创建conda环境并配置环境&#xff08;安装相关依赖&#xff09;下载模型文件微调数据微调过程全量微调基于LoRA的微调基于微调后的模型推理 ChatDoctor简介 CHatDoctor论文&#xff1a; ChatDoctor: A Medical Chat Model F…...

UDP TCP 报文内容

1.UDP 2.TCP 源/目的端口号:表示数据是从哪个进程来,到哪个进程去; 32位序号/32位确认号:后面详细讲;4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节);所以TCP头部最大长度是15*460 6位标志位: o URG:紧急指针是否有效 ——urgent 紧急的 o ACK:确认号是否有…...

Boost开发指南-4.8operators

operators C提供了强大且自由的操作符重载能力&#xff0c;可以把大多数操作符重新定义为函数&#xff0c;使操作更加简单直观。这方面很好的例子就是标准库中的string和 complex&#xff0c;可以像操作内置类型int、double那样对它们进行算术运算和比较运算&#xff0c;非常方…...

c# 泛型约束

在C#中&#xff0c;泛型约束用于指定泛型类型参数的限制条件&#xff0c;以确保类型参数满足特定的条件。以下是C#中常见的泛型约束&#xff1a; where T : struct&#xff1a; 这个约束要求类型参数必须是一个值类型&#xff08;如int、float等&#xff09;。 where T : cla…...

android frida

Frida 是一个用于动态分析、调试和修改 Android 应用程序的强大工具。它的主要作用包括&#xff1a; 代码注入和Hooking&#xff1a; Frida 允许您在运行时修改和监视应用程序的行为。您可以通过Frida注入JavaScript代码到目标应用程序中&#xff0c;然后使用该代码来Hook&…...

Linux下的Shell编程——正则表达式入门(四)

前言&#xff1a; 正则表达式使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。在很多文本编辑器里&#xff0c;正则表达式通常被用来检索、替换那些符合某个模式的文本。 在Linux 中&#xff0c;grep&#xff0c;sed&#xff0c;awk 等文本处理工具都支持…...

使用VisualStudio制作上位机(一)

文章目录 使用VisualStudio制作上位机(一)写在前面第一部分:创建应用程序第二部分:GUI主界面设计使用VisualStudio制作上位机(一) Author:YAL 写在前面 1.达到什么目的呢 本文主要讲怎么通过Visual Studio 制作上位机,全文会以制作过程来介绍怎么做,不会去讲解具体…...

【前端从0开始】JavaSript——自定义函数

函数 函数是一个可重用的代码块&#xff0c;用来完成某个特定功能。每当需要反复执行一段代码时&#xff0c;可以利用函数来避免重复书写相同代码。函数包含着的代码只能在函数被调用时才会执行&#xff0c;就可以避免页面载入时执行该脚本在JavaScript中&#xff0c;可以使用…...

如何在Windows、Mac和Linux操作系统上安装Protocol Buffers(protobuf)编译器

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…...

简单介绍 CPU 的工作原理

内部架构 CPU 的根本任务就是执行指令&#xff0c;对计算机来说最终都是一串由 0 和 1 组成的序列。CPU 从逻辑上可以划分成 3 个模块&#xff0c;分别是控制单元、运算单元和存储单元 。其内部架构如下&#xff1a; 【1】控制单元 控制单元是整个CPU的指挥控制中心&#xff…...

UE4/5数字人MetaHuman的控制绑定资产使用

目录 开始操作 找到控制绑定资产 放入控制绑定资产 ​编辑 生成动画资产 开始操作 首先我们创建一个关卡序列&#xff1a; 打开后将我们的数字人放进去【右键&#xff0c;第一个添加进去】&#xff1a; 我们会自动进入动画模式&#xff0c;没有的话&#xff0c;就自己…...

二、11.系统交互

fork 函数原型是 pid_t fork(void&#xff09;&#xff0c;返回值是数字&#xff0c;该数字有可能是子进程的 pid &#xff0c;有可能是 0&#xff0c;也有可能是-1 。 1个函数有 3 种返回值&#xff0c;这是为什么呢&#xff1f;可能的原因是 Linux 中没有获取子进程 pid 的方…...

敏捷管理工具/国内软件敏捷开发工具

​Scrum中非常强调公开、透明、直接有效的沟通&#xff0c;这也是“可视化的管理工具”在敏捷开发中如此重要的原因之一。通过“可视化的管理工具”让所有人直观的看到需求&#xff0c;故事&#xff0c;任务之间的流转状态&#xff0c;可以使团队成员更加快速适应敏捷开发流程。…...

Selenium环境+元素定位大法

selenium 与 webdriver Selenium 是一个用于 Web 测试的工具&#xff0c;测试运行在浏览器中&#xff0c;就像真正的用户在手工操作一样。支持所有主流浏览器 WebDriver 就是对浏览器提供的原生API进行封装&#xff0c;使其成为一套更加面向对象的Selenium WebDriver API。 使…...

Vue3 用父子组件通信实现页面页签功能

一、大概流程 二、用到的Vue3知识 1、组件通信 &#xff08;1&#xff09;父给子 在vue3中父组件给子组件传值用到绑定和props 因为页签的数组要放在父页面中&#xff0c; data(){return {tabs: []}}, 所以顶部栏需要向父页面获取页签数组 先在页签页面中定义props用来接…...

HCIP STP协议

STP协议 STP协议概念生成树为什么要用STP STP名词解释根网桥根端口指定端口非指定端口 STP的版本802.1DPVSTPVST 快速生成树 STP协议概念 IEEE 802.1d STP&#xff08;生成树协议&#xff0c;Spanning-Tree Protocol&#xff09;协议&#xff1a; ①使冗余端口置于“阻塞状态”…...

链表的顶级理解

目录 1.链表的概念及结构 2.链表的分类 单向或者双向 带头或者不带头 循环或者非循环 3.无头单向非循环链表的实现 3.1创建单链表 3.2遍历链表 3.3得到单链表的长度 3.4查找是否包含关键字 3.5头插法 3.6尾插法 3.7任意位置插入 3.8删除第一次出现关键字为key的节点 …...

探索贪心算法:理解与实现JAVA语言

探索贪心算法&#xff1a;理解与实现 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种基于每一步的最优选择来达到整体最优的算法思想。尽管贪心算法并不适用于所有问题&#xff0c;但它在很多情况下都能够提供高效、近似的解决方案。本文将深入探讨贪心算法的基本概…...

数字孪生技术对旅游行业能起到什么作用?

随着疫情对我们生活影响的淡化&#xff0c;旅游行业迎来了新的春天&#xff0c;暑期更是旅游行业的小高潮&#xff0c;那么作为一个钻研数字孪生行业的小白&#xff0c;本文就着旅游的话题以及对旅游的渴望带大家一起探讨一下数字孪生对智慧旅游发展的作用~ 数字孪生作为一种虚…...

邯郸市城乡住房建设局网站/网站模板搭建

F#的class赋予了F#面向对象的编程能力&#xff0c;也是F#连接.net中其它面向对象语言的桥梁。其基本形式如下&#xff1a; // Class definition:type [access-modifier] type-name [type-params]( parameter-list ) [ as identifier ] [ class ] [ inherit base-…...

wordpress无法打开 404/网店运营推广方案

QT Creator是轻量级集成开发环境&#xff0c;在Ubuntu系统操作中&#xff0c;使用QT时无法输入中文&#xff0c;遇到这种情况要如何处理呢&#xff1f;下面小编就给大家介绍下Ubuntu如何解决QT无法输入中文问题。1 安装搜狗输入法&#xff0c;(如果你想用ubuntu自带的输入法也没…...

网站建设联盟/线下广告投放渠道都有哪些

这里为了弄清楚JobIntentService&#xff0c;这边我将androidx的JobIntentService源码&#xff0c;doc都进行了翻译并拆分了2个类&#xff0c;分别为BelowOJobIntentService(android8.0以下版本)&#xff0c;和JobIntentXService&#xff08;8.0和以上版本&#xff09;。以便充…...

网页显示网站正在建设中怎么做/东莞互联网推广

多线程程序常考虑三种性质&#xff1a;原子性、可见性、有序性。定义如下&#xff1a; 1. 原子性&#xff1a;一个或多个操作的执行&#xff0c;只有两种情况&#xff1a;&#xff08;1&#xff09;全部执行并且执行过程中不会被打断&#xff1b;&#xff08;2&#xff09;不执…...

城乡建设学校官方网站/站外推广渠道

卓老师&#xff0c;我有一个信号与系统的问题想请教。按照时域采样定理&#xff0c;采样频率≥2倍的信号频率&#xff0c;才能得到信号全部信息。而以智能车中的编码器测速为例。我们知道测速周期在可接受范围内越小越利于控速&#xff0c;比如2ms。但2ms采样一次速度&#xff…...

站长工具最近查询/广东企业网站seo哪里好

2019独角兽企业重金招聘Python工程师标准>>> Logback日志使用说明 项目跑了几个月了、测试服务器一直报空间不足、公司很小也没有运维。登上去查看以后发现log日志文件上百G并且很多都是没用的。所以下午简单查看了一下日志文件的配置。 没有优化后的logback.xml配置…...