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

stm32入门学习10-I2C和陀螺仪模块

(一)I2C通信

(1)通信方式

I2C是一种同步半双工的通信方式,同步指的是通信双方时钟为一个时钟,半双工指的是在同一时间只能进行接收数据或发送数据,其有一条时钟线(SCL)和一条数据线(SDA),使用I2C通信要遵守一定的规定

其收发数据有几种模式

(1)开启传输:在时钟线(SCL)为1时将数据线(SDA)由1转为0;

(2)结束传输:在时钟线(SCL)为1时将数据线(SDA)由0转为1;

(3)传输数据:在时钟线(SCL)为0时在数据线(SDA)中写入数据,将时钟线(SCL)由0变为1发送;

(4)接收数据:先释放数据线(SDA置1),后将时钟线(SCL)由0变为1后读取数据线(SDA);

(5)接收响应:I2C在主机传输8位数据时会给主机响应,为1则接收失败,为0则接收成功,主机需要接收响应,接收方式和接收数据相同;

(6)发送响应:I2C在主机接收8位数据时要给从机响应,给1则从机停止继续向主机发送,给0则继续向主机发送数据

这里可以注意到,I2C通信中只有开始和结束时在时钟线(SCL)为1时操作的数据线(SDA),其余都是在时钟线为0时操作数据线;

通信过程中其有一定的协议

(1)发送数据:(1)开启传输;(2)写入外设地址写模式;(3)接收从机响应;(4)写入外设寄存器的地址;(5)接收响应;(6)写入数据;(7)接收响应;(8)结束传输

(2)接收数据:(1)开启传输;(2)写入外设地址写模式;(3)接收从机响应;(4)写入外设寄存器的地址;(5)接收响应;(6)重新开启传输;(7)写入外设地址读模式;(8)接收响应;(9)读取数据;(10)发送响应;(11)结束传输

(2)软件模拟

这样我们就可以用代码来模拟I2C通信,我们选择时钟线(SCL)接在PA0口上,数据线(SDA)接在PA1口上

#define SCL GPIO_Pin_0
#define SDA GPIO_Pin_1

(1)时钟打开和初始化

这里要注意的是I2C是采用开漏输出的,即默认为高电平,我们这里端口输出模式也要选择开漏输出

void i2c_init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef gpio_init;gpio_init.GPIO_Mode = GPIO_Mode_Out_OD;gpio_init.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;gpio_init.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpio_init);GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1);
}

(2)置高低电平和读取数据

为了方便给SCL和SDA高电平或低电平,封装几个函数方便后面调用,分别为置某个端口高电平、置某个端口低电平、读取某个端口的值

void set(uint16_t io)
{GPIO_SetBits(GPIOA, io);Delay_us(10);
}void reset(uint16_t io)
{GPIO_ResetBits(GPIOA, io);Delay_us(10);
}unsigned char read(uint16_t io)
{unsigned char result;result = GPIO_ReadInputDataBit(GPIOA, io);return result;
}

(3)开启传输

和前面讲的一样,我们要在SCL高电平的情况下把SDA由高电平拉到低电平,然后拉低SCL,为后面的传输数据做准备

void i2c_start()
{set(SDA);set(SCL);reset(SDA);reset(SCL);
}

由于我们不知道在开始前数据线和时钟线是否一定为高电平,因此我们先把两者置高电平后再拉低

(4)结束传输

我们要在SCL为高电平的情况下把SDA由低电平上拉为高电平

void i2c_end()
{reset(SDA);set(SCL);set(SDA);
}

我们不知道在要结束的时候SDA是否为低电平,因此我们先拉低SDA,为后面的上拉做准备,至于我们的时钟线SCL,我们确保其在除了结束传输这一步外每一步结束时都为低电平,可以注意一下其他步骤的代码

(5)传输一个字节

我们在时钟线SCL为低电平的时候把数据放在数据线SDA上,然后把SCL拉高为高电平即完成传输,循环8次,传输一个字节

void i2c_send_byte(unsigned char message)
{unsigned char i;for(i = 0; i < 8; i++){if ((message & (0x80>>i)) == 0)reset(SDA);elseset(SDA);set(SCL);reset(SCL);}
}

这里的数据传输为高位先行,先传输高位,我们使用“与”的方法依次提取从高位到低位的八位bit,将数据message和1000 0000 的右移i位相与;

(6)接收一个字节

先释放数据线SDA(将其置1),后在SCL置1后读取SDA,循环八次,读取一个字节

unsigned char i2c_receive_byte()
{unsigned char i;unsigned char message = 0x00;set(SDA);for (i = 0; i < 8; i++){set(SCL);if (read(SDA) == 1)message |= (0x80>>i);reset(SCL);}return message;
}

这里使用“或”的方式来接收数据,如果接收到i位数据为1,则将message与1000 0000 右移i位相或,第i位置1,其余位保持不变;

(7)发送应答

发送应答和发送单个bit做法相同,需要在SCL低电平期间将应答置于SDA中,再SCL上拉发送

void i2c_send_ack(unsigned char ack)
{if (ack == 0)reset(SDA);else set(SDA);set(SCL);reset(SCL);
}

(8)接收应答

接收应答和接收单个bit做法相同,需要先释放数据线SDA(置1),在SCL置高电平时读取数据线的值

unsigned char i2c_receive_ack()
{unsigned char ack;set(SDA);set(SCL);ack = read(SDA);reset(SCL);return ack;
}

(3)封装

这样I2C的几种基本通信方式就写好了,我们只需要把其封装,再按照发送接收的规定,就可以读取改写外设寄存器,最后.c和.h文件可以这样

#include "stm32f10x.h"                  // Device header
#include "Delay.h"#define SCL GPIO_Pin_0
#define SDA GPIO_Pin_1void i2c_init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef gpio_init;gpio_init.GPIO_Mode = GPIO_Mode_Out_OD;gpio_init.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;gpio_init.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpio_init);GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1);
}void set(uint16_t io)
{GPIO_SetBits(GPIOA, io);Delay_us(10);
}void reset(uint16_t io)
{GPIO_ResetBits(GPIOA, io);Delay_us(10);
}unsigned char read(uint16_t io)
{unsigned char result;result = GPIO_ReadInputDataBit(GPIOA, io);return result;
}void i2c_start()
{set(SDA);set(SCL);reset(SDA);reset(SCL);
}void i2c_end()
{reset(SDA);set(SCL);set(SDA);
}void i2c_send_byte(unsigned char message)
{unsigned char i;for(i = 0; i < 8; i++){if ((message & (0x80>>i)) == 0)reset(SDA);elseset(SDA);set(SCL);reset(SCL);}
}unsigned char i2c_receive_byte()
{unsigned char i;unsigned char message = 0x00;set(SDA);for (i = 0; i < 8; i++){set(SCL);if (read(SDA) == 1)message |= (0x80>>i);reset(SCL);}return message;
}void i2c_send_ack(unsigned char ack)
{if (ack == 0)reset(SDA);else set(SDA);set(SCL);reset(SCL);
}unsigned char i2c_receive_ack()
{unsigned char ack;set(SDA);set(SCL);ack = read(SDA);reset(SCL);return ack;
}
#ifndef __I2C_H__
#define __I2C_H__void i2c_init(void);
void i2c_start(void);
void i2c_end(void);
void i2c_send_byte(unsigned char message);
unsigned char i2c_receive_byte(void);
void i2c_send_ack(unsigned char ack);
unsigned char i2c_receive_ack(void);#endif

(二)MPU-6050

MPU-6050是一个可以测量加速度和角速度的陀螺仪加速度计,其外设写地址为0xD0,外设的读地址为0xD1,其测量的加速度和角速度存在其内部寄存器中,我们通过I2C访问其内部寄存器来读取测量值

经过我们前面的程序,我们已经有了这几个函数:(1)开启传输函数;(2)结束传输函数;(3)发送一个字节函数;(4)接收一个字节函数;(5)发送应答函数;(6)接收应答函数;通过这些函数我们就可以操作寄存器了

(1)写某个位置的一个字节

按照我们之前的说法,我们要写某个寄存器,我们先要开启传输,发送外设写地址,接收应答,发送寄存器地址,接收应答,写入数据,接收应答,结束传输,对应下面的每一行代码

void mpu_write(unsigned char address, unsigned char message)
{i2c_start();i2c_send_byte(mpu6050_address);ack = i2c_receive_ack();i2c_send_byte(address);ack = i2c_receive_ack();i2c_send_byte(message);ack = i2c_receive_ack();i2c_end();Delay_us(10);
}

(2)读某个位置的一个字节

和前面说的一样,要读取某个外设的寄存器,我们需要开启传输,发送外设写地址,接收应答,发送寄存器地址,接收应答,重新开启传输,发送外设读地址,接收应答,读取数据,发送应答,结束传输,对应代码为

uint8_t mpu_read(unsigned char address)
{uint8_t message = 0x00;i2c_start();i2c_send_byte(mpu6050_address);ack = i2c_receive_ack();i2c_send_byte(address);ack = i2c_receive_ack();i2c_start();i2c_send_byte(mpu6050_address | 0x01);ack = i2c_receive_ack();message = i2c_receive_byte();i2c_send_ack(1);i2c_end();return message;
}

(3)初始化MPU-6050

MPU-6050默认为睡眠模式,如果不初始化不会进行数据转换,这里直接操作寄存器转换如下,主要为停止睡眠模式、选择时钟等,顺便把I2C也在此初始化

void mpu_init()
{i2c_init();mpu_write(0x6B, 0x01);	//PWR_MGMT_1 -> 0000 0001mpu_write(0x6C, 0x00);	//PWR_MGMT_2 -> 0000 0000mpu_write(0x19, 0x09);	//SMPLRT_DIV -> 0000 1001mpu_write(0x1A, 0x06);	//CONFIG -> 0000 0110mpu_write(0x1B, 0x18);	//GYRO_CONFIG -> 0001 1000mpu_write(0x1C, 0x18);	//ACCEL_CONFIG -> 0001 1000
}

(4)传输数据

MPU-6050中有六个数据,分别为x、y、z轴加速度,x、y、z轴的角速度,我们需要一次返回六个变量,可以用数组,但这里用一个结构体来返回六个变量

typedef struct inf
{int x_acceleration;int y_acceleration;int z_acceleration;int x_angular_velocity;int y_angular_velocity;int z_angular_velocity;
} information;

这六个变量都是16位数据,其高八位和低八位存在不同的寄存器中

我们可以通过把高位左移8位“或”低位的方式来读取其16位寄存器

这里记录下常见的错误:如果你在读取某些有符号数据时其逼近但不超过最大值,但是却从来没有为负数,这可能是因为在位数小的数据强行转换为位数大的数据中出现的错误,其会在位数小数据的前面自动补0,而众所周知我们负数的补码是要在前面补1的,比如8位有符号数据1111 1101为-3,若将其强行转化为16位有符号数据则默认为0000 0000 1111 1101,这就是一个很大的正数了,我们要的16位-3应该为1111 1111 1111 1101

information mpu_get_inf()
{uint8_t inf_L;uint8_t inf_H;information infor;inf_H = mpu_read(0x3B);inf_L = mpu_read(0x3C);infor.x_acceleration = (inf_H<<8) | inf_L;inf_H = mpu_read(0x3D);inf_L = mpu_read(0x3E);infor.y_acceleration = (inf_H<<8) | inf_L;inf_H = mpu_read(0x3F);inf_L = mpu_read(0x40);infor.z_acceleration = (inf_H<<8) | inf_L;inf_H = mpu_read(0x43);inf_L = mpu_read(0x44);infor.x_angular_velocity = (inf_H<<8) | inf_L;inf_H = mpu_read(0x45);               inf_L = mpu_read(0x46);               infor.y_angular_velocity = (inf_H<<8) | inf_L;inf_H = mpu_read(0x47);               inf_L = mpu_read(0x48);               infor.z_angular_velocity = (inf_H<<8) | inf_L;if (infor.x_acceleration & 0x8000){infor.x_acceleration |= 0xFFFF0000;}if (infor.y_acceleration & 0x8000){infor.y_acceleration |= 0xFFFF0000;}if (infor.z_acceleration & 0x8000){infor.z_acceleration |= 0xFFFF0000;}if (infor.x_angular_velocity & 0x8000){infor.x_angular_velocity |= 0xFFFF0000;}if (infor.y_angular_velocity & 0x8000){infor.y_angular_velocity |= 0xFFFF0000;}if (infor.z_angular_velocity & 0x8000){infor.z_angular_velocity |= 0xFFFF0000;}return infor;
}

最后的一连串if就是来解决类型转化间的错误的

这样我们就成功读到了寄存器内的数据并返回一个包含所有数据的结构体

(5)封装与声明

最后的.c 和 .h代码如下

#include "stm32f10x.h"                  // Device header
#include "i2c.h"
#include "Delay.h"#define mpu6050_address 0xD0
unsigned char ack;void mpu_write(unsigned char address, unsigned char message)
{i2c_start();i2c_send_byte(mpu6050_address);ack = i2c_receive_ack();i2c_send_byte(address);ack = i2c_receive_ack();i2c_send_byte(message);ack = i2c_receive_ack();i2c_end();Delay_us(10);
}uint8_t mpu_read(unsigned char address)
{uint8_t message = 0x00;i2c_start();i2c_send_byte(mpu6050_address);ack = i2c_receive_ack();i2c_send_byte(address);ack = i2c_receive_ack();i2c_start();i2c_send_byte(mpu6050_address | 0x01);ack = i2c_receive_ack();message = i2c_receive_byte();i2c_send_ack(1);i2c_end();return message;
}void mpu_init()
{i2c_init();mpu_write(0x6B, 0x01);	//PWR_MGMT_1 -> 0000 0001mpu_write(0x6C, 0x00);	//PWR_MGMT_2 -> 0000 0000mpu_write(0x19, 0x09);	//SMPLRT_DIV -> 0000 1001mpu_write(0x1A, 0x06);	//CONFIG -> 0000 0110mpu_write(0x1B, 0x18);	//GYRO_CONFIG -> 0001 1000mpu_write(0x1C, 0x18);	//ACCEL_CONFIG -> 0001 1000
}typedef struct inf
{int x_acceleration;int y_acceleration;int z_acceleration;int x_angular_velocity;int y_angular_velocity;int z_angular_velocity;
} information;information mpu_get_inf()
{uint8_t inf_L;uint8_t inf_H;information infor;inf_H = mpu_read(0x3B);inf_L = mpu_read(0x3C);infor.x_acceleration = (inf_H<<8) | inf_L;inf_H = mpu_read(0x3D);inf_L = mpu_read(0x3E);infor.y_acceleration = (inf_H<<8) | inf_L;inf_H = mpu_read(0x3F);inf_L = mpu_read(0x40);infor.z_acceleration = (inf_H<<8) | inf_L;inf_H = mpu_read(0x43);inf_L = mpu_read(0x44);infor.x_angular_velocity = (inf_H<<8) | inf_L;inf_H = mpu_read(0x45);               inf_L = mpu_read(0x46);               infor.y_angular_velocity = (inf_H<<8) | inf_L;inf_H = mpu_read(0x47);               inf_L = mpu_read(0x48);               infor.z_angular_velocity = (inf_H<<8) | inf_L;if (infor.x_acceleration & 0x8000){infor.x_acceleration |= 0xFFFF0000;}if (infor.y_acceleration & 0x8000){infor.y_acceleration |= 0xFFFF0000;}if (infor.z_acceleration & 0x8000){infor.z_acceleration |= 0xFFFF0000;}if (infor.x_angular_velocity & 0x8000){infor.x_angular_velocity |= 0xFFFF0000;}if (infor.y_angular_velocity & 0x8000){infor.y_angular_velocity |= 0xFFFF0000;}if (infor.z_angular_velocity & 0x8000){infor.z_angular_velocity |= 0xFFFF0000;}return infor;
}
#ifndef __MPU_H__
#define __MPU_H__typedef struct inf
{int x_acceleration;int y_acceleration;int z_acceleration;int x_angular_velocity;int y_angular_velocity;int z_angular_velocity;
} information;//extern struct information;
void mpu_init(void);
information mpu_get_inf(void);#endif

(三)主函数调用

由于我们的MPU-6050初始化中已经包含了I2C的初始化,我们只要引用MPU头文件即可,我们在第1列显示加速度,在第9列显示角速度

#include "stm32f10x.h"                  // Device header
#include "mpu6050.h"
#include "OLED.h"
#include "Delay.h"int main()
{information num;mpu_init();OLED_Init();while(1){num = mpu_get_inf();OLED_ShowSignedNum(1, 1, num.x_acceleration, 5);OLED_ShowSignedNum(2, 1, num.y_acceleration, 5);OLED_ShowSignedNum(3, 1, num.z_acceleration, 5);OLED_ShowSignedNum(1, 9, num.x_angular_velocity, 5);OLED_ShowSignedNum(2, 9, num.y_angular_velocity, 5);OLED_ShowSignedNum(3, 9, num.z_angular_velocity, 5);Delay_ms(500);}return 0;
}

(三)总结

通过读取加速度和角速度,我们通过I2C通信协议读写MPU-6050,了解了I2C的工作原理和手动模拟I2C的工作流程,解决了一些遇到的错误,积累了错误处理的经验

相关文章:

stm32入门学习10-I2C和陀螺仪模块

&#xff08;一&#xff09;I2C通信 &#xff08;1&#xff09;通信方式 I2C是一种同步半双工的通信方式&#xff0c;同步指的是通信双方时钟为一个时钟&#xff0c;半双工指的是在同一时间只能进行接收数据或发送数据&#xff0c;其有一条时钟线&#xff08;SCL&#xff09;…...

GDB常用指令

GDB调试&#xff1a;GDB调试的是可执行文件&#xff0c;在gcc编译时加入-g参数&#xff0c;告诉gcc在编译时加入调试信息&#xff0c;这样gdb才能调试这个被编译的文件。此外还会加上-Wall参数尽量显示所有警告信息。 GDB命令格式&#xff1a; 1、start&#xff1a;程序在第一…...

Nginx 高级 扩容与高效

Nginx高级 第一部分&#xff1a;扩容 通过扩容提升整体吞吐量 1.单机垂直扩容&#xff1a;硬件资源增加 云服务资源增加 整机&#xff1a;IBM、浪潮、DELL、HP等 CPU/主板&#xff1a;更新到主流 网卡&#xff1a;10G/40G网卡 磁盘&#xff1a;SAS(SCSI) HDD&#xff08;机械…...

pythonflaskMYSQL自驾游搜索系统32127-计算机毕业设计项目选题推荐(附源码)

目 录 摘要 1 绪论 1.1研究背景 1.2爬虫技术 1.3flask框架介绍 2 1.4论文结构与章节安排 3 2 自驾游搜索系统分析 4 2.1 可行性分析 4 2.2 系统流程分析 4 2.2.1数据增加流程 5 2.3.2数据修改流程 5 2.3.3数据删除流程 5 2.3 系统功能分析 5 2.3.1 功能性分析 6 2.3.2 非功…...

C++ vector的基本使用(待补全)

std::vector 是C标准模板库(STL)中的一个非常重要的容器类&#xff0c;它提供了一种动态数组的功能。能够存储相同类型的元素序列&#xff0c;并且可以自动管理存储空间的大小&#xff0c;以适应序列大小变化&#xff0c;处理元素集合的时候很灵活 1. vector的定义 构造函数声…...

Java 属性拷贝 三种实现方式

第一种 List<OrederPayCustomer> orederPayCustomerList this.list(queryWrapper); List<CustomerResp>customerRespListnew ArrayList<>();for (OrederPayCustomer orederPayCustomer : orederPayCustomerList) {CustomerResp customerResp new Custome…...

Java-变量,运算符,输入与输出

目录 一&#xff0c;语法基础 1.基本Java程序 2.语法基础 2.1 变量 2.2 常量限制(fiinal)类比C中的const 2.3 类型转化 2.4 运算符 2.5 表达式 2.5 输入与输出 2.5.1 输入 2.5.2 输出 一&#xff0c;语法基础 1.基本Java程序 public class Main{public static void…...

五、一个quad同时支持pcie和sfp两种高速接口的ref时钟配置

项目描述 上位机将截图数据通过 XDMA 写入到 FPGA 侧的 DDR 内存区域 1 中通过 axi_lite 接口给 axi_read_start 信号&#xff0c;通知 AXI_read 模块启动读取数据&#xff0c;然后通过 GTP TX 模块发送出去。经过光纤回环&#xff0c;GTP RX 端接收到数据&#xff0c;送给 AX…...

AI辅助教育:九章大模型的数学辅导功能解析

1.简介 九章大模型是学而思为学习研发的模型&#xff0c;该模型对于数学做了很多专门的训练&#xff0c;在题目推荐方面做得比较好。 同时&#xff0c;这个模型也能支持上传图片&#xff0c;对图片内容进行分析&#xff0c;然后针对内容进行校对&#xff0c;推荐相识题目。 支…...

力扣刷题之3128.直角三角形

题干描述 给你一个二维 boolean 矩阵 grid 。 请你返回使用 grid 中的 3 个元素可以构建的 直角三角形 数目&#xff0c;且满足 3 个元素值 都 为 1 。 注意&#xff1a; 如果 grid 中 3 个元素满足&#xff1a;一个元素与另一个元素在 同一行&#xff0c;同时与第三个元素…...

OD C卷 - 机场航班调度

机场航班调度&#xff08;100&#xff09; 航班组成&#xff1a;前两个大写字母代表航空公司缩写&#xff0c;后面4个数字代表航班信息&#xff1b;对输入的航班排序 首先按照航空公司缩写升序排序&#xff1b;同一航空公司的按照航班信息升序排序&#xff1b; 输入描述&…...

uni-app中使用支付宝扫码插件并且在真机调试时使用(详细教程)

前言&#xff1a;uni-app自带的扫码api 识别不灵敏&#xff0c;每次都得扫很长时间且不断调整才能扫出来码&#xff0c;所以决定使用支付宝扫码插件&#xff0c;官方插件地址&#xff1a;https://ext.dcloud.net.cn/plugin?id2636#detail 使用步骤: 1、下载插件到项目中 2、…...

每日学术速递8.5—1

1.SV4D: Dynamic 3D Content Generation with Multi-Frame and Multi-View Consistency 标题&#xff1a; SV4D&#xff1a;具有多帧和多视图一致性的动态 3D 内容生成 作者&#xff1a;Yiming Xie, Chun-Han Yao, Vikram Voleti, Huaizu Jiang, Varun Jampani 文章链接&…...

1、操作系统相关概念

1、操作系统是计算机上的第一层软件&#xff0c;用于管理计算机硬件设备&#xff0c;提高他们的利用率和通吐量&#xff0c;并为用户和应用程序提供一个接口。不同操作系统目标不同&#xff0c;查询设备的操作系统&#xff0c;侧重人机交互性&#xff1b;武器控制操作系统&…...

【ModelSim】仿真问题记录

1、波形出不全&#xff1a; 1、甚至连clk波形都出不来 2、个别波形只有到仿真结束的时候才出现 解决办法&#xff1a; 1、添加波形需要是实例中的net 2、排查是否存在声明与示例的位宽不一致的信号 3、观察是否存在未初始化的变量寄存器 4、缩短整个仿真的步长 2、Instance列…...

如何提高深度学习中数据运行的稳定性

在深度学习中&#xff0c;模型的训练通常会受到随机性因素的影响&#xff0c;如参数初始化、数据加载顺序等。这会导致每次训练得到的结果有所不同。要减少这种不稳定性&#xff0c;可以采取以下措施&#xff1a; 1.固定随机种子 通过设置随机种子&#xff0c;可以使得每次训…...

【连续数组】python刷题记录

R3-前缀和专题 绝对要用字典记录 ben神&#xff0c;前缀和字典 class Solution:def findMaxLength(self, nums: List[int]) -> int:#前缀和字典,key为差值&#xff0c;value为坐标dict{0:-1}#当前1和0的差值counter0ret0for i,num in enumerate(nums):#多1&#xff0b;1if…...

JavaScript青少年简明教程:DOM和CSS简介

JavaScript青少年简明教程&#xff1a;DOM和CSS简介 DOM简介 DOM&#xff08;Document Object Model&#xff09;将文档表示为一个树形结构&#xff0c;其中每个节点都是一个对象&#xff0c;每个对象都有其自身的属性和方法。 通过对DOM的操作&#xff0c;开发者可以使用编…...

架构师知识梳理(一):计算机硬件

目录 计算机硬件组成 CPU CPU的组成 CPU的功能 校验码 奇偶校验 CRC CRC计算案例 指令 指令指行过程 指令系统 指令系统分类 指令流水线技术 流水线技术相关计算公式 存储 计算机存储系统设计 高速缓存Cache 缓存的局部性原理 地址映射 替换算法 关于命中…...

从根儿上学习spring 四 之run方法启动第一段

图1 由上图我们可以看到&#xff0c;我把run方法分成了5个小段&#xff0c;每小段使用红框圈了起来&#xff0c;这一篇我们先开始讲第一段。大家需要关注下行号&#xff0c;我讲的时候可能会使用行号对应具体某行代码。 图1-289-290行&#xff1a; 没啥好说的定义了两个变量&…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...