STM32 I2C

news2024/11/28 4:40:44

目录

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,写入的还是只有1

        MyI2C_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);//接收前需要先释放SDA
   
    for(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();//进行读取SDA
    MyI2C_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);
    
    //配置GPIO
    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
    I2C_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.coloradmin.cn/o/1450616.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【智能家居入门4】(FreeRTOS、MQTT服务器、MQTT协议、微信小程序)

前面已经发了智能家居入门的1、2、3了&#xff0c;在实际开发中一般都会使用到实时操作系统&#xff0c;这里就以FreeRTOS为例子&#xff0c;使用标准库。记录由裸机转到实时操作系统所遇到的问题以及总体流程。相较于裸机&#xff0c;系统实时性强了很多&#xff0c;小程序下发…

[NSSRound#16 Basic]Web

1.RCE但是没有完全RCE 显示md5强比较&#xff0c;然后md5_3随便传 md5_1M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2&md5_2M%C9h%FF%0E%E3%5C%20%95r%D4w…

物流快递管理系统

文章目录 物流快递管理系统一、系统演示二、项目介绍三、13000字论文参考四、系统部分页面展示五、部分代码展示六、底部获取项目源码和万字论文参考&#xff08;9.9&#xffe5;带走&#xff09; 物流快递管理系统 一、系统演示 校园物流快递管理系统 二、项目介绍 主要技术…

用HTML5实现动画

用HTML5实现动画 要在HTML5中实现动画&#xff0c;可以使用以下几种方法&#xff1a;CSS动画、使用<canvas>元素和JavaScript来实现动画、使用JavaScript动画库。重点介绍前两种。 一、CSS动画 CSS3 动画&#xff1a;使用CSS3的动画属性和关键帧&#xff08;keyframes&…

备战蓝桥杯---数据结构之好题分享1

最近几天在刷学校的题单时&#xff0c;发现了几道十分巧妙又有启发性的题&#xff0c;借此来记录分享一下。 看题&#xff1a; 从整体上看似乎没有什么规律&#xff0c;于是我们从小地方入手&#xff0c;下面是图解&#xff1a; 因此&#xff0c;我们用栈的数据结构实现即可&a…

模拟算法总结(Java)

目录 模拟算法概述 练习 练习1&#xff1a;替换所有的问号 练习2&#xff1a;提莫攻击 练习3&#xff1a;Z字形变换 模拟算法概述 模拟&#xff1a;根据题目要求的实现过程进行编程模拟&#xff0c;即题目要求什么就实现什么 解决这类题目&#xff0c;需要&#xff1a; 1…

C 语言 devc++ 使用 winsock 实现 windows UDP 局域网发送消息

U参考来源 U 这里移植到windows 上 &#xff0c;使用 devc 开发。 服务端代码 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <winsock2.h>int main() {WORD sockVersion MAKEWORD(2, 2);WSAD…

【嵌入式移植】6、U-Boot源码分析3—make

U-Boot源码分析3—make all 从【嵌入式移植】4、U-Boot源码分析1—Makefile文章中可知执行make命令的时候&#xff0c;没有指定目标则使用默认目标PHONY&#xff0c;PHONY依赖项为_all all scripts_basic outputmakefile scripts dtbs。 all Makefile中第129行指定默认目标PH…

协调尺度:特征缩放在机器学习中的重要作用

目录 一、介绍 二、背景知识 三、了解功能缩放 四、特征缩放方法 五、特征缩放的重要性 六、实际意义 七、代码 八、结论 一、介绍 特征缩放是机器学习和数据分析预处理阶段的关键步骤&#xff0c;在优化各种算法的性能和效率方面起着至关重要的作用。本文深入探讨了特征缩放的…

蓝桥杯每日一题----单调栈和单调队列

单调栈和单调队列 单调栈 单调栈即栈内的元素是单调递减或者单调递增的&#xff0c;我们通过一个题目来理解。 单调栈模板题 题目描述 给出项数为 n 的整数数列 a 1 … a n a_1…a_n a1​…an​。 定义函数 f ( i ) f(i) f(i)代表数列中第 i 个元素之后第一个大于 a i …

安卓游戏开发框架应用场景以及优劣分析

一、引言 在移动游戏开发领域&#xff0c;选择合适的开发框架是项目成功的关键因素之一。特别是对于安卓平台&#xff0c;由于其开放性和庞大的用户基础&#xff0c;不同的游戏开发框架应运而生&#xff0c;旨在帮助开发者高效地构建游戏应用。以下是一些流行的安卓游戏开发框架…

OpenAI全新发布文生视频模型Sora - 现实,不存在了

OpenAI&#xff0c;发他们的文生视频大模型&#xff0c;Sora了。。。。。 而且&#xff0c;是强到&#xff0c;能震惊我一万年的程度。。。 https://openai.com/sora 如果非要用三个词来总结Sora&#xff0c;那就是“60s超长长度”、“单视频多角度镜头”和“世界模型” &am…

五、DataX源码分析、性能参数优化

DataX源码分析 一、总体流程二、程序入口1.datax.py2.com.alibaba.datax.core.Engine.java3.切分的逻辑并发数的确认 3.调度3.1 确定组数和分组算法3.2 数据传输 三、DataX性能优化1.关键参数2.优化&#xff1a;提升每个 channel 的速度3.优化&#xff1a;提升 DataX Job 内 Ch…

SpringBoot3 + Vue3 由浅入深的交互 基础交互教学

说明&#xff1a;这篇文章是适用于已经学过SpringBoot3和Vue3理论知识&#xff0c;但不会具体如何实操的过程的朋友&#xff0c;那么我将手把手从教大家从后端与前端交互的过程教学。 目录 一、创建一个SpringBoot3项目的和Vue3项目并进行配置 1.1后端配置: 1.1.1applicatio…

php基础学习之作用域和静态变量

作用域 变量&#xff08;常量&#xff09;能够被访问的区域&#xff0c;变量可以在常规代码中定义&#xff0c;也可以在函数内部定义 变量的作用域 在 PHP 中作用域严格来说分为两种&#xff0c;但是 PHP内部还定义一些在严格意义之外的一种&#xff0c;所以总共算三种—— 局部…

紫微斗数双星组合:廉贞天相在子午

文章目录 前言内容总结 前言 紫微斗数双星组合&#xff1a;廉贞天相在子午 内容 紫微斗数双星组合&#xff1a;廉贞天相在子午 性格分析 廉贞星最喜天相星同度来制其恶&#xff0c;因天相星之水可剋制廉贞星之火。廉贞星最喜天相星同度来制其恶&#xff0c;使廉贞星变为较温…

MySQL 基础知识(六)之数据查询(二)

目录 6 数值型函数 7 字符串函数 8 流程控制函数 9 聚合函数 10 分组查询 (group by) 11 分组过滤 (having) 12 限定查询 (limit) 13 多表查询 13.1 连接条件关键词 (on、using) 13.2 连接算法 13.3 交叉连接 (cross join) 13.4 内连接 (inner join) 13.5 外连接 …

【制作100个unity游戏之25】3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱6(附带项目源码)

效果演示 文章目录 效果演示系列目录前言存储加载物品信息源码完结 系列目录 前言 欢迎来到【制作100个Unity游戏】系列&#xff01;本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第25篇中&#xff0c;我们将探索如何用unity制作一个3D背包、库存、制作、快…

【leetcode994】腐烂的橘子(BFS)

文章目录 一、题目二、思路三、代码 一、题目 二、思路 首先将所有烂橘子入队&#xff0c;然后常规BFS遍历&#xff0c;注意while的截止条件除了队列为空&#xff0c;新鲜橘子数量大于0&#xff08;没新鲜橘子也没必要继续遍历&#xff0c;保证时间计算的正确性&#xff09;&a…

Compose自定义动画API指南

很多动画API都可以自定义其参数达到不同的效果&#xff0c;Compose也提供了相应的API供开发者进行自定义动画规范。 AnimationSpec 主要用存储动画规格&#xff0c;可以自定义动画的行为&#xff0c;在animate*AsState和updateTransition函数中&#xff0c;此函数默认参数为s…