STM32标准库学习笔记-11.I2C通信

news2024/11/13 19:36:49

参考教程:【STM32入门教程-2023版 细致讲解 中文字幕】

I2C通信
  • I2C(Inter IC Bus)是由Philips公司八十年代推出的一种通用数据总线
  • 两根通信线:SCL(Serial Clock)、SDA(Serial Data) 同步,半双工 带数据应答
  • 支持总线挂载多设备(一主多从、多主多从)

硬件电路
  • 所有I2C设备的SCL连在一起,SDA连在一起
  • 设备的SCL和SDA均要配置成开漏输出模式
  • SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右

I2C时序基本单元
  • 起始条件:SCL高电平期间,SDA从高电平切换到低电平

  • 终止条件:SCL高电平期间,SDA从低电平切换到高电平

  • 发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

  • 接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)

  • 发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答

  • 接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

I2C时序
  • 指定地址写
  • 对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)

  • 当前地址读
  • 对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)

  • 指定地址读
  • 对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)

        Sr为重复起始

代码实现软件I2C通信
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

//标准库I2C函数以I2C开头,这里自己实现用IIC作为前缀

#define IIC_PORT GPIOB
#define IIC_SCL GPIO_Pin_10
#define IIC_SDA GPIO_Pin_11

void IIC_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Pin = IIC_SCL | IIC_SDA;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStructure);
    
    //默认状态给高电平
    GPIO_SetBits(IIC_PORT,IIC_SCL | IIC_SDA);
}

void IIC_W_SCL(uint8_t BitVal)
{
    GPIO_WriteBit(IIC_PORT,IIC_SCL,(BitAction)BitVal);
    Delay_us(10);
}

void IIC_W_SDA(uint8_t BitVal)
{
    GPIO_WriteBit(IIC_PORT,IIC_SDA,(BitAction)BitVal);
    Delay_us(10);
}

uint8_t IIC_R_SDA(void)
{
    uint8_t Bitval = GPIO_ReadInputDataBit(IIC_PORT,IIC_SDA);
    Delay_us(10);
    return Bitval;
}

void IIC_Start(void)
{
    IIC_W_SDA(1);
    IIC_W_SCL(1);
    IIC_W_SDA(0);
    IIC_W_SCL(0);
}

void IIC_End(void)
{
    //其余的函数保证了SCL结束操作时是0
    IIC_W_SDA(0);
    IIC_W_SCL(1);
    IIC_W_SDA(1);
}

void IIC_SendByte(uint8_t Byte)
{
    uint8_t i;
    for(i = 0;i < 8;i++)
    {
        //00000001
        IIC_W_SDA(Byte & (0x80 >> i));
        IIC_W_SCL(1);
        IIC_W_SCL(0);
    }
}

void IIC_SendAck(BitAction Ack)
{
    IIC_W_SDA(Ack);
    IIC_W_SCL(1);
    IIC_W_SCL(0);
}

uint8_t IIC_ReceiveByte(void)
{
    uint8_t i;
    uint8_t Byte = 0x00;
    IIC_W_SDA(1);
    for(i = 0;i < 8;i++)
    {
        IIC_W_SCL(1);
        if(IIC_R_SDA())
        {
            Byte |= (0x80 >> i);
        }
        IIC_W_SCL(0);
    }
    return Byte;
}

uint8_t IIC_ReceiveAck(void)
{
    uint8_t Ack;
    IIC_W_SDA(1);   //主机释放SDA,以接受从机Ack
    IIC_W_SCL(1);
    Ack = IIC_R_SDA();
    IIC_W_SCL(0);
    return Ack;
}
MPU6050使用软件I2C通信
#include "stm32f10x.h"                  // Device header
#include "IIC_SOFTWARE.h"
#include "MPU6050.h"
#include "MPU6050_Regs.h"


void MPU6050_WriteRegData(uint8_t RegAddr,uint8_t Data)
{
    IIC_Start();
    IIC_SendByte(MPU6050_DEVICE_ADDRESS);
    IIC_ReceiveAck();
    IIC_SendByte(RegAddr);
    IIC_ReceiveAck();
    IIC_SendByte(Data);
    IIC_ReceiveAck();
    IIC_End();
}

uint8_t MPU6050_ReadRegData(uint8_t RegAddr)
{
    uint8_t RegData;
    
    IIC_Start();
    IIC_SendByte(MPU6050_DEVICE_ADDRESS);
    IIC_ReceiveAck();
    IIC_SendByte(RegAddr);
    IIC_ReceiveAck();
    
    IIC_Start();
    IIC_SendByte(MPU6050_DEVICE_ADDRESS | 0x01);
    IIC_ReceiveAck();
    RegData = IIC_ReceiveByte();
    IIC_SendAck(1);
    IIC_End();
    return RegData;
}

uint8_t MPU6050_ReadID(void)
{
    return MPU6050_ReadRegData(MPU6050_WHO_AM_I);
}

void MPU6050_GetData(MPU6050_GYRO_TypeDef *MPU6050_GYRO_Structure,MPU6050_ACCEL_TypeDef *MPU6050_ACCEL_Structure)
{
    uint16_t Reg_H,Reg_L;
    
    //MPU6050_GYRO_OUT
    Reg_H = MPU6050_ReadRegData(MPU6050_GYRO_XOUT_H);
    Reg_L = MPU6050_ReadRegData(MPU6050_GYRO_XOUT_L);
    MPU6050_GYRO_Structure->GYRO_XOUT = (Reg_H << 8) | Reg_L;
    
    Reg_H = MPU6050_ReadRegData(MPU6050_GYRO_YOUT_H);
    Reg_L = MPU6050_ReadRegData(MPU6050_GYRO_YOUT_L);
    MPU6050_GYRO_Structure->GYRO_YOUT = (Reg_H << 8) | Reg_L;
    
    Reg_H = MPU6050_ReadRegData(MPU6050_GYRO_ZOUT_H);
    Reg_L = MPU6050_ReadRegData(MPU6050_GYRO_ZOUT_L);
    MPU6050_GYRO_Structure->GYRO_ZOUT = (Reg_H << 8) | Reg_L;
    
    //MPU6050_ACCEL_OUT
    Reg_H = MPU6050_ReadRegData(MPU6050_ACCEL_XOUT_H);
    Reg_L = MPU6050_ReadRegData(MPU6050_ACCEL_XOUT_H);
    MPU6050_ACCEL_Structure->ACCEL_XOUT = (Reg_H << 8) | Reg_L;
    
    Reg_H = MPU6050_ReadRegData(MPU6050_ACCEL_YOUT_H);
    Reg_L = MPU6050_ReadRegData(MPU6050_ACCEL_YOUT_H);
    MPU6050_ACCEL_Structure->ACCEL_YOUT = (Reg_H << 8) | Reg_L;
    
    Reg_H = MPU6050_ReadRegData(MPU6050_ACCEL_ZOUT_H);
    Reg_L = MPU6050_ReadRegData(MPU6050_ACCEL_ZOUT_H);
    MPU6050_ACCEL_Structure->ACCEL_ZOUT = (Reg_H << 8) | Reg_L;
}
void MPU6050_MeasureData(MPU6050_GYRO_TypeDef *MPU6050_GYRO_Structure,MPU6050_ACCEL_TypeDef *MPU6050_ACCEL_Structure,MPU6050_Measure_TypeDef *MPU6050_Measure_Structure)
{
    MPU6050_Measure_Structure->Gx = ((float)MPU6050_GYRO_Structure->GYRO_XOUT)/32768.0*2000.0;
    MPU6050_Measure_Structure->Gy = ((float)MPU6050_GYRO_Structure->GYRO_YOUT)/32768.0*2000.0;
    MPU6050_Measure_Structure->Gz = ((float)MPU6050_GYRO_Structure->GYRO_ZOUT)/32768.0*2000.0;
    
    MPU6050_Measure_Structure->Ax = ((float)MPU6050_ACCEL_Structure->ACCEL_XOUT)/32768.0*16.0;
    MPU6050_Measure_Structure->Ay = ((float)MPU6050_ACCEL_Structure->ACCEL_YOUT)/32768.0*16.0;
    MPU6050_Measure_Structure->Az = ((float)MPU6050_ACCEL_Structure->ACCEL_ZOUT)/32768.0*16.0;
}

void MPU6050_Init(void)
{
    IIC_Init();
    MPU6050_WriteRegData(MPU6050_PWR_MGMT_1,0x00);
    
    MPU6050_WriteRegData(MPU6050_PWR_MGMT_2,0x00);
    MPU6050_WriteRegData(MPU6050_SMPRT_DIV,0x00);
    MPU6050_WriteRegData(MPU6050_CONFIG,0x06);
    MPU6050_WriteRegData(MPU6050_GYRO_CONFIG,0x18);
    MPU6050_WriteRegData(MPU6050_ACCEL_CONFIG,0x18);
}

float MPU6050_Abs(float num)
{
    return num < 0 ? -num:num;
}
I2C外设简介
  • STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担
  • 支持多主机模型
  • 支持7位/10位地址模式
  • 支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz)
  • 支持DMA
  • 兼容SMBus协议
  • STM32F103C8T6 硬件I2C资源:I2C1、I2C2

I2C外设基本结构

I2C主机发送数据

I2C主机接收数据

MPU6050使用I2C外设通信
#include "stm32f10x.h"                  // Device header
#include "MPU6050.h"
#include "MPU6050_Regs.h"

#define IIC_PORT GPIOB
#define IIC_SCL GPIO_Pin_10
#define IIC_SDA GPIO_Pin_11

void MPU6050_WriteRegData(uint8_t RegAddr,uint8_t Data)
{
//    IIC_Start();
//    IIC_SendByte(MPU6050_DEVICE_ADDRESS);
//    IIC_ReceiveAck();
//    IIC_SendByte(RegAddr);
//    IIC_ReceiveAck();
//    IIC_SendByte(Data);
//    IIC_ReceiveAck();
//    IIC_End();
    
    I2C_GenerateSTART(I2C2,ENABLE);
    while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
    
    I2C_Send7bitAddress(I2C2,MPU6050_DEVICE_ADDRESS,I2C_Direction_Transmitter);
    while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);
    
    I2C_SendData(I2C2,RegAddr);
    while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);
    
    I2C_SendData(I2C2,Data);
    while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);
    
    I2C_GenerateSTOP(I2C2,ENABLE);
}

uint8_t MPU6050_ReadRegData(uint8_t RegAddr)
{
    uint8_t RegData;
    
//    IIC_Start();
//    IIC_SendByte(MPU6050_DEVICE_ADDRESS);
//    IIC_ReceiveAck();
//    IIC_SendByte(RegAddr);
//    IIC_ReceiveAck();
//    
//    IIC_Start();
//    IIC_SendByte(MPU6050_DEVICE_ADDRESS | 0x01);
//    IIC_ReceiveAck();
//    RegData = IIC_ReceiveByte();
//    IIC_SendAck(1);
//    IIC_End();
    
    I2C_GenerateSTART(I2C2,ENABLE);
    while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
    
    I2C_Send7bitAddress(I2C2,MPU6050_DEVICE_ADDRESS,I2C_Direction_Transmitter);
    while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);
    
    I2C_SendData(I2C2,RegAddr);
    while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);
    
    I2C_GenerateSTART(I2C2,ENABLE);
    while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
    
    I2C_Send7bitAddress(I2C2,MPU6050_DEVICE_ADDRESS,I2C_Direction_Receiver);
    while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS);
    
    I2C_AcknowledgeConfig(I2C2,DISABLE);
    I2C_GenerateSTOP(I2C2,ENABLE);
    
    while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);
    RegData = I2C_ReceiveData(I2C2);

    I2C_AcknowledgeConfig(I2C2,ENABLE);
    return RegData;
}

uint8_t MPU6050_ReadID(void)
{
    return MPU6050_ReadRegData(MPU6050_WHO_AM_I);
}

void MPU6050_GetData(MPU6050_GYRO_TypeDef *MPU6050_GYRO_Structure,MPU6050_ACCEL_TypeDef *MPU6050_ACCEL_Structure)
{
    uint16_t Reg_H,Reg_L;
    
    //MPU6050_GYRO_OUT
    Reg_H = MPU6050_ReadRegData(MPU6050_GYRO_XOUT_H);
    Reg_L = MPU6050_ReadRegData(MPU6050_GYRO_XOUT_L);
    MPU6050_GYRO_Structure->GYRO_XOUT = (Reg_H << 8) | Reg_L;
    
    Reg_H = MPU6050_ReadRegData(MPU6050_GYRO_YOUT_H);
    Reg_L = MPU6050_ReadRegData(MPU6050_GYRO_YOUT_L);
    MPU6050_GYRO_Structure->GYRO_YOUT = (Reg_H << 8) | Reg_L;
    
    Reg_H = MPU6050_ReadRegData(MPU6050_GYRO_ZOUT_H);
    Reg_L = MPU6050_ReadRegData(MPU6050_GYRO_ZOUT_L);
    MPU6050_GYRO_Structure->GYRO_ZOUT = (Reg_H << 8) | Reg_L;
    
    //MPU6050_ACCEL_OUT
    Reg_H = MPU6050_ReadRegData(MPU6050_ACCEL_XOUT_H);
    Reg_L = MPU6050_ReadRegData(MPU6050_ACCEL_XOUT_H);
    MPU6050_ACCEL_Structure->ACCEL_XOUT = (Reg_H << 8) | Reg_L;
    
    Reg_H = MPU6050_ReadRegData(MPU6050_ACCEL_YOUT_H);
    Reg_L = MPU6050_ReadRegData(MPU6050_ACCEL_YOUT_H);
    MPU6050_ACCEL_Structure->ACCEL_YOUT = (Reg_H << 8) | Reg_L;
    
    Reg_H = MPU6050_ReadRegData(MPU6050_ACCEL_ZOUT_H);
    Reg_L = MPU6050_ReadRegData(MPU6050_ACCEL_ZOUT_H);
    MPU6050_ACCEL_Structure->ACCEL_ZOUT = (Reg_H << 8) | Reg_L;
}
void MPU6050_MeasureData(MPU6050_GYRO_TypeDef *MPU6050_GYRO_Structure,MPU6050_ACCEL_TypeDef *MPU6050_ACCEL_Structure,MPU6050_Measure_TypeDef *MPU6050_Measure_Structure)
{
    MPU6050_Measure_Structure->Gx = ((float)MPU6050_GYRO_Structure->GYRO_XOUT)/32768.0*2000.0;
    MPU6050_Measure_Structure->Gy = ((float)MPU6050_GYRO_Structure->GYRO_YOUT)/32768.0*2000.0;
    MPU6050_Measure_Structure->Gz = ((float)MPU6050_GYRO_Structure->GYRO_ZOUT)/32768.0*2000.0;
    
    MPU6050_Measure_Structure->Ax = ((float)MPU6050_ACCEL_Structure->ACCEL_XOUT)/32768.0*16.0;
    MPU6050_Measure_Structure->Ay = ((float)MPU6050_ACCEL_Structure->ACCEL_YOUT)/32768.0*16.0;
    MPU6050_Measure_Structure->Az = ((float)MPU6050_ACCEL_Structure->ACCEL_ZOUT)/32768.0*16.0;
}

void MPU6050_Init(void)
{
//    IIC_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 = IIC_SCL | IIC_SDA;
    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_WriteRegData(MPU6050_PWR_MGMT_1,0x00);
    MPU6050_WriteRegData(MPU6050_PWR_MGMT_2,0x00);
    MPU6050_WriteRegData(MPU6050_SMPRT_DIV,0x00);
    MPU6050_WriteRegData(MPU6050_CONFIG,0x06);
    MPU6050_WriteRegData(MPU6050_GYRO_CONFIG,0x18);
    MPU6050_WriteRegData(MPU6050_ACCEL_CONFIG,0x18);
}

float MPU6050_Abs(float num)
{
    return num < 0 ? -num:num;
}

I2C通信只需要SDA和SCL两根通信线,节省IO口,一般常用软件实现。

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

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

相关文章

适用于所有Android手机的5个最佳Android手机解锁工具

在当今互联互通的世界中&#xff0c;我们移动设备的安全至关重要。但是&#xff0c;由于忘记密码、屏幕破裂或其他不可预见的问题&#xff0c;用户可能会发现自己被锁定在 Android 设备之外。为了满足这一需求&#xff0c;出现了各种 Android 解锁工具&#xff0c;提供创新的解…

CMake编译不同文件目录下的C++文件

由于我们构建一个项目的时候&#xff0c;通常不会将所有的源文件放在一个文件目录下&#xff0c;这样既不方便开发&#xff0c;也不方便源码阅读&#xff0c;我们通常会对项目文件进行分层&#xff0c;比如分为include、src、res、lib这些目录&#xff0c;src下又分为model、co…

解决怎样在使用Signal Tap进行在线调试时,单独编译工程没有报错,而在Signal tap添加了信号之后进行时编译报错。

问题 如下图所示&#xff0c;我们在Signal Tap中添加完相应的信号之后对于工程进行重新编译时&#xff0c;显示报错信息&#xff1a; 报错原因 这里错误显示的时我们使用的设备只有30个 类型为M9K的RAM位置。然而&#xff0c;当前设计需要超过30个位置才能成功适配。意思就是…

<Linux> 进程控制

目录 一、进程创建 1. fork函数 2. fork函数返回值 3. 写时拷贝 4. fork常规用法 5. fork调用失败原因 6. 如何创建多个子进程&#xff1f; 二、进程终止 1. 进程退出场景 2. 进程退出码 3. errno 4. 进程异常退出 5. 进程常见退出方法 5.1 return退出 5.2 exit退出 5.3 _ex…

JavaFX入门01 制作简易计算器

目录 利用JavaFX Scene Builder 2.0制作图形界面将fxml文件导入IDEA中&#xff0c;并添加JavaFX相关依赖定义启动类&#xff0c;呈现界面定义控制类&#xff0c;实现具体逻辑运行代码&#xff0c;进行测试 利用JavaFX Scene Builder 2.0制作图形界面 制作完成后&#xff0c;将其…

C语言之“ 数组 ”

&#x1f339;个人主页&#x1f339;&#xff1a;喜欢草莓熊的bear &#x1f339;专栏&#x1f339;&#xff1a;C语言基础 目录 前言 一、数组 二、一维数组 2.1 一维数组的创建和初始化 数组创建 数组初始化 数组类型 2.2 一维数组的使用 数组下标 数组打印 数组输…

Spring由于后端逻辑,前端无法展示数据

1.Spring由于后端逻辑&#xff0c;前端无法展示数据 1.代码详情 后端逻辑&#xff1a;在ctroller层&#xff0c;调用getList方法返回的是List列表 使用枚举类来定义了状态码&#xff1a; 状态码SUCCESS返回result类 前端代码&#xff0c;if条件里面是根据自定义的状态码来进…

RM集团在造船中应用虚拟现实辅助工程技术

船舶内饰中的虚拟现实辅助工程 设计船舶内饰是一项资源密集型任务&#xff0c;全球范围内有数百名工程师参与到大型造船项目中。如今&#xff0c;作为船舶内饰设计领域的专家&#xff0c;R&M集团正在利用虚拟现实辅助工程(VAE)技术&#xff0c;优化开发流程。 从游轮上的餐…

浅谈如何克服编程学习中的挫折感

目录 1.概述 2.心态调整 3.学习方法 3.1. 基础知识的打牢 3.2. 分解问题 3.3. 理论与实践相结合 3.4. 利用在线资源和社区 3.5. 教学 3.6. 定期复习与总结 3.7. 持续学习和适应新技术 3.8. 解决实际问题 4.成功经验 5.总结 1.概述 在编程学习的过程中&#xff0c…

【流媒体】RTMPDump—RTMP_ConnectStream(创建流连接)

目录 1. RTMP_ConnectStream函数1.1 读取packet&#xff08;RTMP_ReadPacket&#xff09;1.2 解析packet&#xff08;RTMP_ClientPacket&#xff09;1.2.1 设置Chunk Size&#xff08;HandleChangeChunkSize&#xff09;1.2.2 用户控制信息&#xff08;HandleCtrl&#xff09;1…

灵创空间:打造健康与创意融合的全新文化体验

近日&#xff0c;备受瞩目的灵创空间品牌正式亮相&#xff0c;致力于为顾客提供健康、舒适且富有文化氛围的环境。灵创空间专注于研发中高端健康饮品&#xff0c;精选国内外优质健康原料&#xff0c;推出符合现代人需求的平价高品质饮品。在满足消费者健康需求的同时&#xff0…

【Word多级标题完整设置】设置各级标题样式将多级列表链接到各级标题样式中

Word多级标题完整设置 一、设置各级标题样式主标题样式设置中英文字体、字形以及字号设置段落设置&#xff08;缩进、间距和行距&#xff09; 一级标题样式设置中英文字体、字形以及字号设置段落设置&#xff08;缩进、间距和行距&#xff09; 二级标题样式设置中英文字体、字形…

OurTV v3.1.1 — 完全免费,播放流畅的电视直播软件

OurTV是一款专业的魔改大屏版开源电视直播软件&#xff0c;与“我的电视”类似&#xff0c;内含丰富的电视频道&#xff0c;完全免费且无广告&#xff0c;画质清晰&#xff0c;播放流畅&#xff0c;提供良好的观影体验。此外&#xff0c;该软件还提供手机版。 链接&#xff1a…

AM32开源代码之代码分析 - DSHOT/BDSHOT

AM32开源代码之代码分析 - DSHOT/BDSHOT 1. 源由2. 协议设计2.1 位格式2.2 帧结构2.3 CRC计算2.4 帧格式&#xff08;eRPM&#xff09;2.4.1 DSHOT2.4.2 BDSHOT 2.5 EDT编码策略2.5 eRPM传输 3. 框架设计3.1 初始化3.2 动态过程3.2.1 飞控触发3.2.2 定时触发 3.3 协议检测3.3.1…

JS day0820

ok了家人们今天学习Dom对象&#xff0c;和一个综合案例&#xff0c;一起去看看吧。 一.BOM对象 Browser Object Model 浏览器对象模型。 JavaScript 将浏览器的各 个组成部分封装为对象 Window &#xff1a;浏览器窗口对象。 对象表示浏览器中打开的窗口Navigator&#xff1…

(含华为案例) 企业数字化转型规划方案313页PDF限免下载!

一、前言 数字化转型势在必行&#xff0c;这已成为所有企业CIO的共识。但在现实中&#xff0c;很多数字化转型计划还是陷入重重困难&#xff0c;其原因大多在于企业内部对数字化转型的认知还不够透彻。尤其是对于那些业务正处于发展和上升期的公司&#xff0c;各个部门的负责人…

算法学习017 不同的二叉搜索树 c++算法学习 中小学算法思维学习 比赛算法题解 信奥算法解析

目录 C不同的二叉搜索树 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、运行结果 五、考点分析 六、推荐资料 C不同的二叉搜索树 一、题目要求 1、编程实现 给定一个整数n&#xff0c;求以1、2、3、......、n为节点组成的二叉搜索树有多少种…

网络瘫痪幕后黑手:如何应对TCP/IP端口消耗?

TCP/IP 协议是互联网通信的基础&#xff0c;它的稳定性和可靠性使我们使用互联网的十分重要的一点。在网络运行过程中&#xff0c; TCP/IP 的连接问题中&#xff0c; TCP/IP 端口耗尽故障是较为常见的一种。我们要及时有效地排除这些故障来保障网络的正常运行并确保业务顺利开展…

Windows下如何将mmdetection训练好的模型导出为onnx格式?

写在前面 注意:第一部分是踩坑记录,第二部分才是正确的导出步骤!!!! 踩坑方法记录 这一部分的方法看样子好像没啥问题,但是一步步繁琐的操作下来你会发现,你已经入坑了!!! 提醒大家,如果你正在按照这个方法导出模型,劝你尽快放弃,行不通【原因在于后续的pyth…

Linux网络配置的基本原理、常用命令以及实战操作

&#x1f600;前言 本篇博文是关于Linux网络配置的基本原理、常用命令以及实战操作&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您…