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而言,在硬件电路上采用了开漏输出+上拉电阻的形式

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

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

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

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

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

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

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

相关文章

Java Web|day6.MyBatis-Plus

MyBatisPlus 定义 mybatis-plus是一款Mybatis增强工具&#xff0c;用于简化开发&#xff0c;提高效率。 核心功能 注解 TableName 注解在类上&#xff0c;指定类和数据库表的映射关系。实体类的类名&#xff08;转成小写后&#xff09;和数据库表名相同时&#xff0c;可以不…

网络协议九 应用层 HTTPS

一 什么是 HTTPS 前面我们看到HTTP 有很多安全问题&#xff0c;因此引出了 对称加密 和 不对称加密。 那么这个对称加密和不对称加密&#xff0c;我们怎么和HTTP结合起来呢&#xff1f;HTTPS 就是弄好的 HTTP 和 加密结合的协议。 通过HTTP加密后的数据&#xff0c;整个传输过…

Fly Catcher:通过监测恶意信号来检测飞机欺骗

Fly Catcher 的开发者 Angelina Tsuboi 是一名飞行员、网络安全研究员和发明家。 她决定着手一个将这三个不同兴趣结合起来的项目&#xff0c;以解决航空雷达系统的一个重大问题。 ADS-B 系统最初用于基本的飞机定位和跟踪&#xff0c;Tsuboi 对该系统的网络安全方面进行了深…

Java语言程序设计——篇十四(1)

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

日撸Java三百行(day25:栈实现二叉树深度遍历之中序遍历)

目录 一、栈实现二叉树遍历的可行性 二、由递归推出栈如何实现中序遍历 1.左子树入栈 2.根结点出栈 3.右子树入栈 4.实例说明 三、代码实现 总结 一、栈实现二叉树遍历的可行性 在日撸Java三百行&#xff08;day16&#xff1a;递归&#xff09;中&#xff0c;我们讲过…

【C++11】入门基础

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;C从入门至进阶 这里将会不定期更新有关C/C的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目录…

minikube 实践练习4 - 滚动更新

1. 应用版本更新 #查看image kubectl describe pods#设置应用的image为新版本 v1 -> v2 kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcampdocker.io/jocatalin/kubernetes-bootcamp:v2#验证更新结果 export NODE_PORT"$(kubectl get services/…

糟糕界面集锦-控件篇11

GUI 的一个设计基本准则是&#xff1a;如果控件被禁用&#xff0c;那么就应该表现出来。这样不管是菜单项、命令按钮、列表框、下拉列表&#xff0c;我们只要一瞥就可以知道是否可用。奇怪的是为什么微软在按钮被禁用时不把它显示出来&#xff1f;这幅图片来自Office95 系列中的…

Redis操作--RedisTemplate(二)StringRedisTemplate

一、介绍 1、简介 由于存储在 Redis 中的 key 和 value 通常是很常见的 String 类型&#xff0c;Redis模块提供了 RedisConnection 和 RedisTemplate 的扩展&#xff0c;分是 StringRedisConnection 和 StringRedisTemplate&#xff0c;作为字符串操作的解决方案。 通过源码…

【区块链+金融服务】第一创业证券开发银行间报价 Dapp | FISCO BCOS应用案例

在银行间市场现券交易的过程中&#xff0c;通过银保监会发牌的代理机构进行报价交易&#xff0c;已解决无代理阶段存在的许多问题。 但是由于业务需要&#xff0c;使用以前模式进行报价交易的仍占有一定比例。 针对这一现状&#xff0c;第一创业证券基于 FISCO BCOS 区块链底层…

多种办公功能的WORD VBA程序

word的VBA办公助手 源代码 Option Explicit 需要引用 excel 16.0 库 所有内容仅供个人学习使用&#xff0c;严禁传播。1-公共变量-表格属性------------------------------------------------------------------------- Dim Hg% hg:行高 Const K1 0.1 Dim Flg_bh As Boolean …

专业技能——Redis常用命令和持久化策略,内存回收策略+主从模式,哨兵模式,集群模式+缓存穿透击穿雪崩

Redis 是一个开源&#xff08;BSD许可&#xff09;的&#xff0c;内存中的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构&#xff0c;如 字符串&#xff08;strings&#xff09;&#xff0c;散列&#xff08;hashes&#xff09;…

Kali Linux-设置系统24小时时间制

文章目录 设置系统24小时时间制 设置系统24小时时间制 在Kali Linux中&#xff0c;如果系统时间不是以24小时制显示&#xff0c;你可以通过修改系统时间格式配置文件来调整为24小时制。以下是具体的操作步骤&#xff1a; 1.编辑/etc/locale.conf配置文件。 vim /etc/locale.c…

微信云开发云存储 下载全部文件

一、安装 首先按照这个按照好依赖&#xff0c;打开cmd 安装 | 云开发 CloudBase - 一站式后端云服务 npm i -g cloudbase/cli 安装可能遇到的问题 ‘tcb‘ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。-CSDN博客 二、登录 在cmd输入 tcb login 三、…

VirtualBox安装Oracle Linux 7.9全流程

1.准备工作 1.1 VirtualBox下载 下载地址1&#xff1a; Downloads – Oracle VM VirtualBoxhttps://www.virtualbox.org/wiki/Downloads 下载地址2&#xff1a; https://www.oracle.com/virtualization/virtualbox/ 选择以上的任意一个地址都可下载到。 1.2 Oracle Linux 操作…

JavaScript初级——基础知识

一、JS的HelloWord 1、JS的代码需要编写到script标签中 2、JS的执行是根据语句从上到下一次执行的。 二、JS的编写位置 1、可以将js代码编写到标签的onclick属性中&#xff0c;当我们点击按钮时&#xff0c;js代码才会执行。 2、可以将js代码写在超链接的href属性中&#xff0…

HDFS的透明加密

一、HDFS透明加密原理 Hadoop的透明加密(HDFS Transparent Data Encryption) - TDE 1.HDFS中的数据明文存储 HDFS中的数据会以block的形式保存在各台数据节点的本地磁盘中,但这些block都是明文的。 通过Web UI页面找到Block的ID和副本位于的机器信息 如果在操作系统中直接访…

csrf漏洞(二)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 前言&#xff1a; 本文依靠phpstudy以及dvwa靶场进行操作&#xff0c;具体搭建流程参考&#xff1a;xss漏洞&#xff08;二&#xff0c;xss靶场搭建以及简单利用&#xff09; 前篇…

docker 部署 遇到的一些问题

1. nacos 部署问题 1.1 问题 springboot 服务器启动失败 AnnotationNacosPropertySourceBuilder - There is no content for NacosPropertySource from dataId[rsa.yaml] , groupId[DEFAULT_GROUP] , properties[{accessKey${nacos.access-key:}, clusterName${nacos.cluster…

leetcode387. 字符串中的第一个唯一字符,哈希表

leetcode387. 字符串中的第一个唯一字符 给定一个字符串 s &#xff0c;找到 它的第一个不重复的字符&#xff0c;并返回它的索引 。如果不存在&#xff0c;则返回 -1 。 示例 1&#xff1a; 输入: s “leetcode” 输出: 0 示例 2: 输入: s “loveleetcode” 输出: 2 示例…