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

STM32通过I2C硬件读写MPU6050

目录

STM32通过I2C硬件读写MPU6050

1. STM32的I2C外设简介

2. STM32的I2C基本框图

3. STIM32硬件I2C主机发送流程

10位地址与7位地址的区别

7位主机发送的时序流程

7位主机接收的时序流程

4. STM32硬件与软件的波形对比

5. STM32配置硬件I2C外设流程

6. STM32的I2C.h标准库函数介绍

1.I2C配置和使用函数

2.I2C状态监控功能

7. STM32编写代码实现I2C硬件读写MPU6050

7.1编写时需要注意的点

7.2程序文件简要说明:

MPU650.c

MPU650.h

main.c

8.[扩展]为什么STM32硬件I2C为什么在速度快时会调节占空比;为什么有最大速度限制


I2C通信介绍部分可以看这一篇博客:STM32软件I2C通信详解-CSDN博客

STM32软件读取MPU6050可以看这一篇博客:STM32通过I2C硬件读写MPU6050-CSDN博客

STM32通过I2C硬件读写MPU6050

1. STM32的I2C外设简介

硬件I2C具有高速传输、低占用率和稳定性高的优点,适用于对传输速度和稳定性要求较高的场景; 而软件I2C具有灵活性高和可移植性强的特点,适用于没有硬件I2C支持或需要扩展硬件I2C功能的场景

  • STM32内部集成了硬件12C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担
  • 支持多主机模型
  • 支持7位/10位地址模式
  • 支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz)
  • 支持DMA
  • 兼容SMBus协议(System Management Bus 系统管理总线) 基于I2C改进而来的,主要用于电源管理系统
  • STM32F103C8T6 硬件I2C资源:12C1、12C2

2. STM32的I2C基本框图

3. STIM32硬件I2C主机发送流程

10位地址与7位地址的区别

  • 7位地址
    • 起始条件后的第一个字节是寻址(地址+读写位)
  • 10位地址
    • 起始条件后的两个字节都是寻址(11110+2位地址+读写位+8位地址)

7位主机发送的时序流程

  • 起始、从机地址+读写位、应答、数据1、应答、数据2、应答、….数据N、应答、停止
  1. 起始 STM32默认为从模式,所以需要下在START寄存器下写1就产生起始条件,由硬件自动清除。之后STM32由从模式转为主模式

  2. 发生EV5事件 可以把他当做大标志位。因为有的状态会产生多个标志位。所以EVx事件就是组合了很多标志位的一个大标志位 EV5事件,就是SB标志为1 。SB是状态寄存器的一个位。表示了硬件的状态(在状态寄存器SR1中可以找到这一位,置1代表起始条件已发送。由硬件自动清除)

  3. 发送一个字节 需要写入DR寄存器。硬件电路会自动把DR寄存器的值转入移位寄存器。再把这一个字节发送到I2C总线上。

  4. 应答 电路会自动判断。如果没有应答,则会置应答失败标志位。这个标志位可以申请中断。在寻址完成之后

  5. 会发生EV6事件,也就是ADDR为1。手册中查看到的意思是: 在主模式下,代表地址发送结束

  6. 发生EV8_1事件 此时 TXE = 1,移位寄存器为空、数据寄存器为空 这时需要我们写入数据寄存器DR进行数据发送了。

  7. 发生EV8事件 DR在填写数据之后,会立刻把数据转移到移位寄存器进行发送。 (也就是填写了数据1) 这时就是EV8事件:移位寄存器非空、数据寄存器空。

  8. 此时再写入DR 把数据放到数据寄存器中。同时因写入DR,导致EV8事件清除。 (也就是说已经写入了下一个数据:数据2)(在没有应答之前写入)

  9. 接收应答位 当从机接收到应答位之后,数据2就转入移位寄存器进行发送。

  10. 发送后又产生了EV8事件 移位寄存器非空、数据寄存器空。

  11. 此时再写入DR……等待应答….转入移位寄存器发送…产生EV8事件….写入…. (在没有应答之前写入)

  12. 直到数据发完,触发EV8_2 当移位寄存器空、数据寄存器也空时。就会触发EV8_2 EV8_2 是 EXT = 1 (数据寄存器为空 )、 BTF = 1(字节发送结束标志位 )(也就是移位寄存器移位完成后找数据寄存器要下一个数据时发现数据寄存器没数据时的标志位)

  13. 停止 (控制寄存器CR1中) STOP、这一位写1的时候,就会在当前字节或在起始条件产生停止条件

7位主机接收的时序流程

7位地址主机接收流程:

  • 起始、从机地址+读、接收、接收数据、发送应答、接收数据、发送应答…接收数据、非应答、停止

10位地址主机接收流程

  • 起始、发送帧头(11110 + 两位地址 + 0(写))、发送第二个字节的8位地址、重复起始条件、发送枕头(11110 + 两位地址 + 1(写))、直接接收数据、发送应答、接收…发送…接收、非应答、停止(没有发送第二次的字节)

7位详解:

  1. 写入控制位的Start位、产生起始条件
  2. 等待EV5事件 表示已发送
  3. 发送地址(地址+读)
  4. 接收应答(ACK,写1 在接受一个字节后就返回一个应答)
  5. 产生EV6事件, 代表寻址已完成
  6. 产生EV6_1时间, 没有对应的标志事件。
  7. 接收数据1 代表数据正在通过移位寄存器输入
  8. 发送应答 硬件自动执行,需要配置是否应答。CR1寄存器中,ACK写1 应答, 否则不应答
  9. 产生EV7事件 因为此时就代表已经接收到数据了。 数据会通过移位寄存器转移到数据寄存器。 产生RxNE标志位,表示数据寄存器非空 (读DR寄存器来清除这个Ev7事件)
  10. 接收数据2 在我们正在读DR寄存器是 数据2就已经移位到移位寄存器中。等待移位到DR数据寄存器中。
  11. 发送应答
  12. 这事数据又被传入DR数据寄存器。EV7事件又来了。需要我们读取、
  13. 如此循环……直到停止 也就是需要设置ACK = 0 不应答, 和STOP请求。

其实同上,这里是在发送一个字节之后,在对面没有应答前,就填充好了下一次要发送的数据。产生的标志位也是一样的。

4. STM32硬件与软件的波形对比

5. STM32配置硬件I2C外设流程

  1. 开启外设和对应GPIO口的时钟
  2. 把I2C外设对应的GPIO口配置为复用开漏模式
  3. 使用结构体,对I2C进行配置
  4. 使能I2C

6. STM32的I2C.h标准库函数介绍

1.I2C配置和使用函数

void I2C_DeInit(I2C_TypeDef* I2Cx);

  • 恢复缺省配置

void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);

  • 初始化I2C

void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct);

  • 初始化结构体

void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);

  • 使能I2C

void I2C_DMACmd(I2C_TypeDef* I2Cx, FunctionalState NewState);

  • I2C MDA使能
  • void I2C_DMALastTransferCmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
    • 用于控制 I2C 传输中的最后一次传输的相关操作。

void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState);

  • 调用,生成起始条件

void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);

  • 调用,生成终止条件

void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState);

  • 配置 I2C 的应答机制。1为应答
  • void I2C_OwnAddress2Config(I2C_TypeDef* I2Cx, uint8_t Address);
    • 设置 I2C 设备自身的地址。
  • void I2C_DualAddressCmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
    • 启用或禁用双地址模式,以适应特定的通信需求。
  • void I2C_GeneralCallCmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
    • 控制是否响应通用呼叫。
  • void I2C_ITConfig(I2C_TypeDef* I2Cx, uint16_t I2C_IT, FunctionalState NewState);
    • 配置 I2C 的中断功能,根据不同的中断类型进行使能或禁用。

void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);

  • 发送一个字节的数据。

uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);

  • 接收一个字节的数据。

void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);

  • 发送 7 位地址并指定通信方向(读或写)。
  • uint16_t I2C_ReadRegister(I2C_TypeDef* I2Cx, uint8_t I2C_Register);
    • 读取 I2C 设备的特定寄存器的值。
  • void I2C_SoftwareResetCmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
    • 通过软件方式对 I2C 进行复位操作。
  • void I2C_NACKPositionConfig(I2C_TypeDef* I2Cx, uint16_t I2C_NACKPosition);
    • 配置非应答信号(NACK)的位置。
  • void I2C_SMBusAlertConfig(I2C_TypeDef* I2Cx, uint16_t I2C_SMBusAlert);
    • 针对 SMBus 警报进行相关配置。
  • void I2C_TransmitPEC(I2C_TypeDef* I2Cx, FunctionalState NewState);
    • 控制是否传输 PEC(Packet Error Checking,数据包错误检查)信息。
  • void I2C_PECPositionConfig(I2C_TypeDef* I2Cx, uint16_t I2C_PECPosition);
    • 配置 PEC 的位置。
  • void I2C_CalculatePEC(I2C_TypeDef* I2Cx, FunctionalState NewState);
    • 决定是否计算 PEC 值。
  • uint8_t I2C_GetPEC(I2C_TypeDef* I2Cx);
    • 获取计算得到的 PEC 值。
  • void I2C_ARPCmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
    • 控制自动重传功能的启用或禁用。
  • void I2C_StretchClockCmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
    • 配置时钟拉伸功能。
  • void I2C_FastModeDutyCycleConfig(I2C_TypeDef* I2Cx, uint16_t I2C_DutyCycle);
    • 设置快速模式下的占空比,以优化通信性能。
  • FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);
    • 读取标志位
  • void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);
    • 清除标志位
  • ITStatus I2C_GetITStatus(I2C_TypeDef* I2Cx, uint32_t I2C_IT);
    • 读取中断标志位
  • void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, uint32_t I2C_IT);
    • 清除中断标志位

2.I2C状态监控功能

I2C的标志位,往往是由多个标志位组合起来的一个大标志位。

一个个去判断往往比较麻烦。

所以I2C的库在.h头文件的最后,

为我们提供了两种检测方案

  1. 基础状态监测
    • 使用 I2C_CheckEvent()函数 可以同时检测多个标志位来进行比较。 一般使用这个。

  1. 高级状态监测
    • 使用I2C_GetLastEvent()函数 (实际上是把SR1和SR2两个状态寄存器拼接成一个16位的数据扔给你,随便你处理。所以一般不用)

  1. 基于标志位的状态监控
    • 使用I2C_GetFlagStatus()函数 可以判断某一个标志位是否置一

7. STM32编写代码实现I2C硬件读写MPU6050

7.1编写时需要注意的点

  • 发送字节时

    • 对于发送一个字节,发送地址和读写的一个字节之后,在移位寄存器还未发送完成时,就要填充下一次要发送的字节到DR数据寄存器中。否则将发生EV8_2标志(移位寄存器空,数据寄存器空)。导致读写停止。 正常应为EV8事件发生(字节正在发送,移位寄存器非空,数据寄存器空)
    • 对于发送多个字节,只需要重复发送、等待EV8事件即可。不发送时给予不应答、停止即可。
  • 接收字节时,

    • 对于接收一个字节,在指定完地址,重复起始之后,接收第第一个字节中时,就要提前配置Ack非应答和停止条件。之后等数据全部移位到数据寄存器中,才能保证只接收了一个字节。读取DR寄存器即可。
    • 对于接收多个字节,可以重复应答、然后等待EV7事件到来,读取寄存器。直到不想接收时,在数据进行移位时(还未到达DR寄存器时)提前设置非应答与停止操作。

7.2程序文件简要说明:

  • MPU6050.c:初始化MPU6050的寄存器。使用STM32 自带的I2C外设,编写对指定地址发送指定值、读取指定地址的函数。以及等待标志位且超时退出的函数
  • MPU6050.h:函数声明、数据结构体声明
  • main.c:测试I2C通信结果。

MPU650.c

#include "stm32f10x.h"                  // Device header
#include "MPU6050.h"
#include "MPU6050_Reg.h"#define MPU6050ADDRESS      0xD0/*** 函    数:超时退出、检测标志位* 参    数:I2C_TypeDef* I2Cx,    定时器xuint32_t I2C_EVENT    标志位名称* 返 回 值:无* 注意事项:无*/
void 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;  }}
}/*** 函    数:指定地址写一个字节* 参    数:RegAddress   指定的寄存器地址Data         指定写入的数据* 返 回 值:无*/
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,MPU6050ADDRESS,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);
}/*** 函    数:指定地址读一个字节* 参    数:RegAddress   指定要读的寄存器地址* 返 回 值:无*/
uint8_t MPU6050_ReadeReg(uint8_t RegAddress)
{uint8_t Data = 0x00;I2C_GenerateSTART(I2C2,ENABLE);//起始位MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待EV5事件发生I2C_Send7bitAddress(I2C2,MPU6050ADDRESS,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);//等待发送EVEV8_2事件发生(字节发送完毕)I2C_GenerateSTART(I2C2,ENABLE);//重复起始MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待EV5事件发生I2C_Send7bitAddress(I2C2,MPU6050ADDRESS,I2C_Direction_Receiver);//发送地址和读写操作(也能用发送一个字节来完成)(自动应答)MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//等待发送EV6事件发生I2C_AcknowledgeConfig(I2C2,DISABLE);//在字节来之前,设置非应答。I2C_GenerateSTOP(I2C2,ENABLE);//直接停止。但是会接收字节完毕之后才停MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED);//等待EV7事件到达。代表一个数据的字节已经在DR里了Data = I2C_ReceiveData(I2C2);I2C_AcknowledgeConfig(I2C2,ENABLE);//恢复默认状态,给从机应答return Data;//返回读取到的值
}/*** 函    数:初始化MPU6050* 参    数:无* 返 回 值:无*/
void MPU6050_Init(void)
{/*初始化I2C*/
//    MyI2C_Init();RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启GPIO和I2C外设时钟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);   //初始化PB10、11为复用开漏/*初始化I2C外设*/I2C_InitTypeDef I2C_InitStructure;I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//确定是否应答I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//指定STM32作为从机。可以响应几位的地址I2C_InitStructure.I2C_ClockSpeed = 50000;//最大400KHZ(快速)、标准为(100KHZ)(MPU6050最快也是400KHZ)I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//配置占空比。进入快速模式后才有用(>100KHZ后) (默认为1:1)I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//I2C模式I2C_InitStructure.I2C_OwnAddress1 = 0x00;//指定STM32作为从机。STM本身的地址I2C_Init(I2C2,&I2C_InitStructure);/*使能I2C外设*/I2C_Cmd(I2C2,ENABLE);/*初始化MPU6050*/MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);  //电源管理1:不复位、解除睡眠、不循环、温度传感器不失能、选择X轴陀螺仪时钟MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);  //电源管理2:不需要循环模式唤醒频率、每个轴都不需要待机MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);  //采样率分频:数据输出的快慢,越小输出越快.这里给10分频MPU6050_WriteReg(MPU6050_CONFIG,0x06);  //配置寄存器:外部同步不需要、数字低通滤波器设置为110MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);   //陀螺仪配置寄存器:不自测、满量程选择:11最大量程MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);    //加速度计配置寄存器:不自测、满量程选择:11最大量程、不用高通滤波器
}/*** 函    数:得到六轴传感器中的数据* 参    数:Str   MPU6050_Data的地址* 返 回 值:无*/
SensorData MPU6050_Data;
void MPU6050_GetData(SensorData *Str)//存放这种结构体类型的地址
{Str->AccX = ( MPU6050_ReadeReg(MPU6050_ACCEL_XOUT_H) <<8|MPU6050_ReadeReg(MPU6050_ACCEL_XOUT_L));Str->AccY = ( MPU6050_ReadeReg(MPU6050_ACCEL_YOUT_H) <<8|MPU6050_ReadeReg(MPU6050_ACCEL_YOUT_L));Str->AccZ = ( MPU6050_ReadeReg(MPU6050_ACCEL_ZOUT_H) <<8|MPU6050_ReadeReg(MPU6050_ACCEL_ZOUT_L));Str->Temp = ( MPU6050_ReadeReg(MPU6050_TEMP_OUT_H)   <<8|MPU6050_ReadeReg(MPU6050_TEMP_OUT_L));Str->GyroX = ( MPU6050_ReadeReg(MPU6050_GYRO_XOUT_H) <<8 |MPU6050_ReadeReg(MPU6050_GYRO_XOUT_L));Str->GyroY = ( MPU6050_ReadeReg(MPU6050_GYRO_YOUT_H) <<8 |MPU6050_ReadeReg(MPU6050_GYRO_YOUT_L));Str->GyroZ = ( MPU6050_ReadeReg(MPU6050_GYRO_ZOUT_H) <<8 |MPU6050_ReadeReg(MPU6050_GYRO_ZOUT_L));
}
//MPU6050_ACCEL_XOUT_H    0x3B
//MPU6050_ACCEL_XOUT_L    0x3C
//MPU6050_ACCEL_YOUT_H    0x3D
//MPU6050_ACCEL_YOUT_L    0x3E
//MPU6050_ACCEL_ZOUT_H    0x3F
//MPU6050_ACCEL_ZOUT_L    0x40
//MPU6050_TEMP_OUT_H      0x41
//MPU6050_TEMP_OUT_L      0x42
//MPU6050_GYRO_XOUT_H     0x43
//MPU6050_GYRO_XOUT_L     0x44
//MPU6050_GYRO_YOUT_H     0x45
//MPU6050_GYRO_YOUT_L     0x46
//MPU6050_GYRO_ZOUT_H     0x47
//MPU6050_GYRO_ZOUT_L     0x48

MPU650.h

#ifndef __MPU6050_H
#define __MPU6050_H/*** 函    数:初始化MPU6050* 参    数:无* 返 回 值:无*/
void MPU6050_Init(void);/*** 函    数:指定地址写一个字节* 参    数:RegAddress   指定的寄存器地址Data         指定写入的数据* 返 回 值:无*/
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data);
/*** 函    数:指定地址读一个字节* 参    数:RegAddress   指定要读的寄存器地址* 返 回 值:无*/
uint8_t MPU6050_ReadeReg(uint8_t RegAddress);//传感器数据
typedef struct Data 
{int16_t AccX;int16_t AccY;int16_t AccZ;int16_t Temp;int16_t GyroX;int16_t GyroY;int16_t GyroZ;
}SensorData;extern SensorData MPU6050_Data;/*** 函    数:得到六轴传感器中的数据* 参    数:Str   MPU6050_Data的地址* 返 回 值:无*/
void MPU6050_GetData(SensorData *Str);#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "oled.h"
#include "Delay.h"
#include "key.h"
#include "MPU6050.h"
/*硬件读写I2C
*/int main()
{OLED_Init();//初始化OLED;MPU6050_Init();//初始化MPU6050while(1)    {MPU6050_GetData(&MPU6050_Data);//显示加速度OLED_ShowSignedNum(1,1,(int16_t)MPU6050_Data.AccX,5);OLED_ShowSignedNum(2,1,(int16_t)MPU6050_Data.AccY,5);OLED_ShowSignedNum(3,1,(int16_t)MPU6050_Data.AccZ,5);//显示陀螺仪OLED_ShowSignedNum(1,8,MPU6050_Data.GyroX,5);OLED_ShowSignedNum(2,8,MPU6050_Data.GyroY,5);OLED_ShowSignedNum(3,8,MPU6050_Data.GyroZ,5);//显示温度OLED_ShowSignedNum(4,4,MPU6050_Data.Temp,5);}}

8.[扩展]为什么STM32硬件I2C为什么在速度快时会调节占空比;为什么有最大速度限制

由之前的知识我们可以了解到。

对于I2C而言,在硬件电路上采用了开漏输出+上拉电阻的形式

这就导致了下拉时为强下拉,上拉时为弱上拉。

这就导致了信号在由高电平往低电平时是十分迅速的,而从低电平回到高电平时是需要一定时间的。

在波形上的体现就是:通信速率越快,上升沿呈现出圆弧形越强。而下降沿几乎没有太大影响。

所以,在速度最快时,需要使得低电平的时间更长一些。

在图片中的反馈就是这样子的

相关文章:

STM32通过I2C硬件读写MPU6050

目录 STM32通过I2C硬件读写MPU6050 1. STM32的I2C外设简介 2. STM32的I2C基本框图 3. STIM32硬件I2C主机发送流程 10位地址与7位地址的区别 7位主机发送的时序流程 7位主机接收的时序流程 4. STM32硬件与软件的波形对比 5. STM32配置硬件I2C外设流程 6. STM32的I2C.h…...

ubuntu2204-中文输入法-pycharm-python-django开发环境搭建

文章目录 1.系统常用设置1.1.安装中文输入法1.2.配置输入法1.3.卸载输入法1.4.配置镜像源2.java安装3.pycharm安装与启动4.卸载ubuntu2204默认版本5.安装Anaconda5.1.安装软件依赖包5.2.安装命令5.3.激活安装5.4.常用命令5.5.修改默认启动源6.安装mysql6.1.离线安装mysql6.2.在…...

【学习笔记】Matlab和python双语言的学习(一元线性回归)

文章目录 前言一、一元线性回归回归分析的一般步骤一元线性回归的基本形式回归方程参数的最小二乘法估计对回归方程的各种检验估计标准误差的计算回归直线的拟合优度判定系数显著性检验 二、示例三、代码实现----Matlab四、代码实现----python回归系数的置信区间公式残差的置信…...

LeetCode //C - 316. Remove Duplicate Letters

316. Remove Duplicate Letters Given a string s, remove duplicate letters so that every letter appears once and only once. You must make sure your result is the smallest in lexicographical order among all possible results. Example 1: Input: s “bcabc”…...

【ARM+Codesys 客户案例 】RK3568/A40i/STM32+CODESYS在工厂自动化中的应用:PCB板焊接机

现代化生产中&#xff0c;电子元件通常会使用自动化设备来进行生产&#xff0c;例如像PCB&#xff08;印刷电路板&#xff09;的组装。但是生产过程中也会面临一些问题&#xff0c;类似于如何解决在PCB板上牢固、精准地安装各种组件呢&#xff1f;IBL Lttechnik GmbH公司的CM80…...

【二分查找】--- 初阶题目赏析

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; 算法Joureny 上篇我们讲解了关于二分的朴素模板和边界模板&#xff0c;本篇博客我们试着运用这些模板。 &#x1f3e0; 搜索插入位置 &#x1f4cc; 题目…...

【PostgreSQL003】PostgreSQL数据表空间膨胀,磁盘爆满,应用宕机(经验总结,已更新)

1.一直以来想写下基于PostgreSQL的系列文章&#xff0c;作为较火的数据ETL工具&#xff0c;也是日常项目开发中常用的一款工具&#xff0c;最近刚好挤时间梳理、总结下这块儿的知识体系。 2.熟悉、梳理、总结下PostgreSQL数据库相关知识体系。空间膨胀&#xff08;主键、外键、…...

C语言第20天笔记

文件操作 概述 什么是 文件 文件时保存在外存储器上&#xff08;一般代指磁盘&#xff0c;也可以是U盘、移动硬盘等&#xff09;的数据的集合。 文件操作体现在哪几个方面 1. 文件内容的读取 2. 文件内容的写入 数据的读取和写入可被视为针对文件进行输入和输出的操作&a…...

为什么穷大方

为什么有些人明明很穷&#xff0c;却非常的大方呢&#xff1f; 因为他们认知太低&#xff0c;根本不懂钱的重要性&#xff0c;总是想着及时享乐&#xff0c;所以一年到头也存不了什么钱。等到家人孩子需要用钱的时候&#xff0c;什么也拿不出来&#xff0c;还到处去求人。 而真…...

HiveSQL实战——大数据开发面试高频SQL题

查询每个区域的男女用户数 0 问题描述 每个区域内男生、女生分别有多少个 1 数据准备 use wxthive; create table t1_stu_table (id int,name string,class string,sex string ); insert overwrite table t1_stu_table values(4,张文华,二区,男),(3,李思雨,一区,女),(1…...

RabbitMQ集群 - 普通集群搭建、宕机情况

文章目录 RabbitMQ 普通集群概述集群搭建数据准备启动容器宕机情况 RabbitMQ 普通集群 概述 1&#xff09;普通模式中所有节点没有主从之分&#xff0c;所有节点的元数据&#xff08;交换机、队列、绑定等&#xff09;都是一致的. 例如只要有任意一个节点上面 新增交换机&…...

xssDOM型练习

文章目录 例1要求 例2代码解析方法 例3例4例5例6例7例8 例1 本题通过get接收并传递参数&#xff0c;所有参数不经过过滤直接放入h2标签里面。 要求 1.需要页面弹出1337 2.不能与用户交互 官方认为innerHTML中script标签不安全&#xff0c;所以将其禁用&#xff0c;但只禁用了…...

python中的gradio使用麦克风时报错

python中的gradio使用麦克风时报错 当运行至 import gradio as gr with gr.Blocks() as demo:with gr.Tab("microphone transcriber"):gr.Audio(source"microphone", type"numpy", streamingTrue)demo.queue()##访问链接 https://ip:1235/demo…...

Oracle(63)什么是临时表(Temporary Table)?

临时表&#xff08;Temporary Table&#xff09;是一种特殊类型的表&#xff0c;用于存储临时数据&#xff0c;这些数据在会话期间或事务期间是短暂的。临时表在不同的数据库系统中都有实现&#xff0c;但功能和特性可能有所不同。临时表通常用于存储中间计算结果、临时数据处理…...

《Techporters架构搭建》-Day06 国际化

什么是国际化&#xff1f; 国际化&#xff0c;也叫i18n&#xff0c;为什么叫i18n呢&#xff1f; "i18n"是国际化&#xff08;internationalization&#xff09;的缩写&#xff0c;数字18代表了国际化这个单词中间的字母数量。类似这样的缩写还有k8s&#xff08;kube…...

Linux ACL 访问控制

今天给伙伴们分享一下Linux ACL 访问控制&#xff0c;希望看了有所收获。 我是公众号「想吃西红柿」「云原生运维实战派」作者&#xff0c;对云原生运维感兴趣&#xff0c;也保持时刻学习&#xff0c;后续会分享工作中用到的运维技术&#xff0c;在运维的路上得到支持和共同进步…...

hg transformers pipeline使用

什么是hg transformers pipeline? 在Hugging Face的transformers库中&#xff0c;pipeline是一个高级API&#xff0c;它提供了一种简便的方式来使用预训练模型进行各种NLP任务&#xff0c;比如情感分析、文本生成、翻译、问答等。通过pipeline&#xff0c;你可以在几行代码内…...

高性能内存对象缓存

Memcached概述 一套开源的高性能分布式内存对象缓存系统 所有的数据都存储在内存中 支持任意存储类型的数据 提高网站的访问速度 数据存储方式与数据过期方式 数据存储方式:Slab Allocation 按组分配内存&#xff0c;每次先分配一个Slab&#xff0c;相当于一个大小为1M的页&…...

文件上传-CMS文件上传分析

黑盒思路&#xff1a; 上传点抓包测试 个人用户中心是否存在文件上传功能后台管理系统是否存在文件上传功能字典目录扫描探针文件&#xff08;eg&#xff1a;upload.php&#xff09;构造地址字典目录扫描探针编辑器目录构造地址&#xff08;编辑器目录一般是默认的&#xff09…...

云原生日志Loki

1. Loki简介 1.1 Loki介绍 Loki是 Grafana Labs 团队最新的开源项目&#xff0c;是一个水平可扩展&#xff0c;高可用性&#xff0c;多租户的日志聚合系统。它的设计非常经济高效且易于操作&#xff0c;因为它不会为日志内容编制索引&#xff0c;而是为每个日志流编制一组标签…...

初阶数据结构之直接选择排序和快速排序

直接选择排序 1.在元素集合 array[i]–array[n-1] 中选择关键码最⼤(⼩)的数据元素 2.若它不是这组元素中的最后⼀个(第⼀个)元素&#xff0c;则将它与这组元素中的最后⼀个&#xff08;第⼀个&#xff09;元素 交换 3.在剩余的 array[i]–array[n-2]&#xff08;array[i1]–…...

Java语言程序设计——篇十三(4)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 欢迎大家&#xff1a;这里是我的学习笔记、总结知识的地方&#xff0c;喜欢的话请三连&#xff0c;有问题可以私信&#x1f333;&#x1f333;&…...

低代码: 组件库测试之渲染和元素获取,触发事件,更新表单,验证事件以及异步请求

组件库测试步骤 渲染组件(怎样将一个组件渲染到测试用例里面) mount 和 shallowMount传递属性元素是否成功的显示 查找元素的不同写法get, getAllfind, findAllfindComponent 和 getComponent触发事件(是click也好,是input也好,让它触发对应的事件) trigger 方法观察测试界面…...

银河麒麟服务器操作系统Kylin-Server-V10-SP3-2403-Release-20240426-x86_64安装步骤

银河麒麟服务器操作系统 Kylin-Server-V10-SP3-2403-Release-20240426-x86_64安装步骤 一、准备工作1. 下载ISO镜像2. 制作安装介质3. 设置BIOS 二、安装过程1. 启动系统2. 选择安装语言3. 选择安装配置4. 配置root密码与创建用户5. 开始安装6. 重启系统7. 同意许可协议 三、系…...

2024年电赛H题全开源

当题目出来的的那一刻&#xff0c;看到了M0芯片&#xff0c;我们实验室只有一块板子&#xff0c;并且我没有接触过M0&#xff0c;电赛只准备了TI的MSP430f5529。但是我并没有放弃&#xff0c;决然的选择了H题。基本上将四问全做出来&#xff0c;可是测试由于使用了感为科技的寻…...

Docker:宿主机可以ping通外网,docker容器内无法ping通外网之解决方法

问题描述 1、宿主机可以ping外网&#xff0c;docker容器内无法ping外网 ping www.baidu.com 提示&#xff1a;unknown host baidu.com 2、宿主机可以wget下载&#xff0c;docker容器内无法wget下载 wget www.baidu.com 提示&#xff1a;unknown host baidu.com 解决方法 1、…...

bootchart抓Android系统启动各阶段性能数据

最近在做Android系统启动优化&#xff0c;首要任务是找到启动过程中各阶段耗时点&#xff0c;进而有针对性地进行优化。主要用bootchart抓开机数据&#xff0c;本文主要记录下工具的使用方法。 1.抓开机数据 adb root adb shell ‘touch /data/bootchart/enabled’ adb rebo…...

使用 Node.js 和 Express 框架通过网页访问GPIO和嵌入式 Linux 系统中使用 GSM/3G/4G 模块

点击上方"蓝字"关注我们 01、前言 想要快速开发嵌入式 Linux 网络应用,控制硬件 GPIO,从而使得用户能够远程控制和监控系统。 主要目的是向读者展示开发使用文件系统控制 GPIO 的 Node 代码、创建用户有好的界面、以及运行基于 Express 框架使用 AJAX 通客户端进…...

IT 行业的就业情况

当前&#xff0c;IT 行业的就业情况呈现出以下特点&#xff1a; 1. 需求持续增长&#xff1a;随着数字化转型的加速&#xff0c;各个行业对信息技术的依赖程度不断提高&#xff0c;推动了对 IT 人才的持续需求。特别是在云计算、大数据、人工智能、物联网等新兴领域&#xff…...

如何快速获取麒麟操作系统版本信息

如何快速获取麒麟操作系统版本信息 一、桌面版系统1. 使用 /etc/kylin-build 文件2. 使用 /etc/.kyinfo 文件 二、服务器版系统1. 使用 /etc/.productinfo 文件2. 使用 nkvers 命令3. 使用 /etc/kylin-release 文件 三、总结 &#x1f496;The Begin&#x1f496;点点关注&…...

git提交规范检查husky

一、Eslint 尤雨溪推荐的 prettierrc 配置&#xff0c;句尾不带分号 单引号。 尤雨溪推荐配置&#xff1a;vue-next/.prettierrc lint lint 是最著名的 C 语言工具之一&#xff0c;是由贝尔实验室 SteveJohnson 于 1979 在 PCC(PortableC Compiler) 基础上开发的静态代码分…...

LeetCode 919. 完全二叉树插入器

完全二叉树是每一层&#xff08;除最后一层外&#xff09;都是完全填充&#xff08;即&#xff0c;节点数达到最大&#xff09;的&#xff0c;并且所有的节点都尽可能地集中在左侧。 设计一个用完全二叉树初始化的数据结构 CBTInserter&#xff0c;它支持以下几种操作&#xf…...

C++密码管理器

先问一句 最近有几个关注我的原力等级为0或-1&#xff0c;文章全是转载&#xff0c;转载时间基本都在2021年&#xff0c;而且关注了很多人&#xff0c;这些是僵尸粉吗&#xff1f; 文末有投票&#xff0c;麻烦参与一下谢谢 实现功能列表 暂时还没做加密功能 打算用openssl/a…...

算法【Java】 —— 滑动窗口

滑动窗口 在上一篇文章中&#xff0c;我们了解到了双指针算法&#xff0c;在双指针算法中我们知道了前后指针法&#xff0c;这篇文章就要提到前后指针法的一个经典的使用 —— 滑动窗口&#xff0c;在前后指针法中&#xff0c;我们知道一个指针在前&#xff0c;一个指针在后&a…...

Spring Aware接口执行时机

一. 介绍 Spring Aware 接口的执行时机有两处&#xff0c;都在 getBean() 中的 initializeBean() 中&#xff1b; 下面我们分析这两处时机&#xff1b; // ----------------------- AbstractAutowireCapableBeanFactory --------------------- protected Object initializeB…...

android FD_SET_chk问题定位

android FD_SET_chk问题定位 一、FD报错二、问题定位2.1 APM定位2.2 adb定位2.3. 代码获取FD数 三、FD优化 一、FD报错 App在运行中记录报错如下&#xff0c;FD_SET&#xff0c;这个问题大概是文件描述符&#xff08;File Descriptor&#xff0c;简称FD&#xff09;超过了最大…...

Chapter 39 Python多线程编程

欢迎大家订阅【Python从入门到精通】专栏&#xff0c;一起探索Python的无限可能&#xff01; 文章目录 前言一、并行执行二、threading模块 前言 现代操作系统如 macOS、UNIX、Linux 和 Windows 等&#xff0c;均支持多任务处理。本篇文章详细讲解了并行执行的概念以及如何在 …...

STM32(二):GPIO

GPIO(General Purpose Input Output)通用输入输出口 1.可配置为8种输入输出模式&#xff0c;引脚电平:0V~3.3V&#xff0c;部分引脚可容忍5V&#xff0c;输出模式下可控制端口输出高低电平&#xff0c;用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等&#xff0c;输入模式下…...

一文入门mysql 数据库

一、对数据库的操作 1.展示所有的数据库 show databases; 2.创建数据库 create database 数据库名 charset utf8; 3.删除数据库 drop database 数据库名; 4.查看当前使用的数据库 select database(); 5.使用数据库 use 数据库名; 二、对数据表的操作 1.展示所有表…...

通义千问( 四 ) Function Call 函数调用

4.2.function call 函数调用 大模型在面对实时性问题、私域知识型问题或数学计算等问题时可能效果不佳。 您可以使用function call功能&#xff0c;通过调用外部工具来提升模型的输出效果。您可以在调用大模型时&#xff0c;通过tools参数传入工具的名称、描述、入参等信息。…...

设置idea中放缩字体大小

由于idea没默认支持ctrl滚轴对字体调节大小&#xff0c;下面一起设置一下吧&#xff01; 点击 文件 -> 设置 按键映射 -> 编辑器操作 -> 搜索栏输入f 点击减小字体大小 -> 选择增加鼠标快捷键 按着ctrl键&#xff0c;鼠标向下滚动后&#xff0c;点击确定即可 然后…...

frameworks 之getEvent指令

frameworks 之getEvent指令 指令解析源码追溯源码解析1.解析参数2.初始化ufds数组3.添加到poll 并做对应处理 通过 getEvent 可以识别按键基本命令和里面的关键信息 涉及到的类如下 system/core/toolbox/toolbox.csystem/core/toolbox/tools.hsystem/core/toolbox/getevent.c …...

tensorboard显示一片空白解决方案

OK艾瑞巴蒂 不知道看这个视频几个小土堆过来的&#xff0c;今天已经发了一篇博文探讨快速下载tensorboard了 下面用的时候叒出现问题了 from torch.utils.tensorboard import SummaryWriter writer SummaryWriter("logs")# writer.add_image() # Yx for i in range…...

C#编程中,如何实现一个高效的数据排序算法?

在C#编程中&#xff0c;可以使用内置的排序方法来实现高效的数据排序。最常用的方法是使用Array.Sort()和List<T>.Sort()。这些方法内部使用了快速排序算法&#xff08;Quick Sort&#xff09;&#xff0c;它是一种非常高效的排序算法&#xff0c;平均时间复杂度为O(n lo…...

LookupError: Resource averaged_perceptron_tagger not found.解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

Leetcode JAVA刷刷站(39)组合总和

一、题目概述 二、思路方向 为了解决这个问题&#xff0c;我们可以使用回溯算法来找到所有可能的组合&#xff0c;使得组合中的数字之和等于目标数 target。因为数组中的元素可以无限制地重复选择&#xff0c;所以在回溯过程中&#xff0c;我们不需要跳过已经选择的元素&#x…...

Spring中AbstractAutowireCapableBeanFactory

AbstractAutowireCapableBeanFactory 是 Spring 框架中的一个抽象类&#xff0c;位于 org.springframework.beans.factory.support 包中。它实现了 AutowireCapableBeanFactory 接口&#xff0c;提供了一些通用的方法和逻辑&#xff0c;以支持 Spring 中的自动装配功能。 主要…...

PostgreSQL的walwriter和archiver进程区别

PostgreSQL的walwriter和archiver进程区别 在PostgreSQL中&#xff0c;walwriter和archiver进程是两个重要的后台进程&#xff0c;它们负责管理WAL&#xff08;Write-Ahead Logging&#xff0c;预写日志&#xff09;文件&#xff0c;但它们的职责和功能有所区别。理解这两个进…...

前端字体没有授权,字体版权检测(是否为方正字体)

1.截图系统中的首页和登录页面&#xff0c;主要是有字体的地方 2.在线字体版权检测地址&#xff1a;字体版权自动检测-求字体网 3.上传照片&#xff0c;开始对图片进行检测&#xff0c;每个账号有三次免费次数 4.检测完&#xff0c;直接查看检测报告即可&#xff0c; 报告中…...

在 SOCKS 和 HTTP 代理之间如何选择?

在 SOCKS 和 HTTP 代理之间进行选择需要彻底了解每种代理的工作原理以及它们传达的配置。只有这样&#xff0c;您才能轻松地在不同类型的代理之间进行选择。 本文概述了 HTTP 和 SOCKS 代理是什么、它们如何运作以及它们各自带来的好处。此外&#xff0c;我们将比较这两种代理类…...