1、准备材料

正点原子stm32f407探索者开发板V2.4

STM32CubeMX软件(Version 6.10.0

野火DAP仿真器

keil µVision5 IDE(MDK-Arm

ST-LINK/V2驱动

XCOM V2.6串口助手

逻辑分析仪nanoDLA

2、实验目标

使用STM32CubeMX软件配置STM32F407开发板的I2C1与MPU6050芯片通信,读取MPU6050的三轴加速度和陀螺仪数据并通过串口打印出来

3、实验流程

3.0、前提知识

本实验重点是理解I2C通信协议,而STM32CubeMX的配置则相对简单,这里不会过于详细全面的介绍I2C通信协议,但是会对所有需要知道的知识做介绍

在我们的开发板上有一颗三轴加速度计和陀螺仪传感器MPU6050,单片机通过I2C1的PB8和PB9两个引脚与MPU6050进行通信,MPU6050还有一个中断引脚,这里为3D_INT引脚,但是本实验仅仅轮询读取加速度计和陀螺仪的数据,并没有用到该引脚中断功能,我们使用的开发板上的MPU6050芯片硬件原理图如下图所示

I2C通信仅需要时钟线SCLK和数据线SDA两根线就可以让主机与挂载在I2C上的从机进行通信和数据交换,一个I2C理论上最多可挂载127个设备(从机地址用7位二进制表示)

为了让主机准确的与众多从机中的一个进行通信,每个从机都会有一个地址,I2C通信时会在通信数据中先发送从机地址,然后对应地址的从机才会响应

而且I2C通信使用的时钟线SCLK和数据线SDA两根线必须要做上拉设置,因为I2C的两个引脚被配置为开漏输出,因此无法输出高电平,I2C总线连线图如下图所示 (注释1)

MPU6050的从机地址由芯片上的AD0引脚确定,当AD0引脚接地时,从机地址为0X68;

当AD0引脚接VCC时,从机地址为0X69;

根据上面MPU6050芯片硬件原理图可知此时MPU6050的从机地址为0X68

根据MPU6050 datasheet 9.3 I2C Communications Protocol 小节可知 (注释2),主机要通过I2C写入/读取MPU6050某一个寄存器一字节的数据,其通信步骤序列应该如下图所示

我们以读取内部寄存器单个字节数据为例做详细介绍,首先确定通信的目的为主机Master从从机Slave内部某个寄存器internal register中读取一个字节数据,以下为详细通信步骤

  1. 主机时钟线SCLK和数据线SDA两根线产生起始信号(当 SCL 线是高电平时 SDA 线从高电平向低电平切换)
  2. 接下来时钟线SCLK的8个时钟节拍中,由数据线SDA发送一字节8位的数据,其中高7位为从机的地址,最后一位为0(1表示读操作,0表示写操作)
  3. 接下来1个时钟节拍,从机应该产生应答信号ACK
  4. 接下来8个时钟节拍,主机发送一字节8位的数据,该数据为要读取的从机内部寄存器地址
  5. 接下来1个时钟节拍,从机应该产生应答信号ACK
  6. 主机重新产生一个起始信号
  7. 接下来8个时钟节拍,重新发送一字节8位的数据,其中高7位为从机的地址,最后一位为1,表示这次要读
  8. 接下来1个时钟节拍,从机应该产生应答信号ACK
  9. 接下来8个时钟节拍,主机读取一字节8位数据
  10. 接下来1个时钟节拍,主机应该产生应答信号NACK
  11. 主机时钟线SCLK和数据线SDA两根线产生停止信号(当 SCL 线是高电平时 SDA 线由低电平向高电平切换)

接下来我们用逻辑分析仪捕获下主机使用I2C1读取MPU6050寄存器WHO_AM_I(0X75)时,时钟线SCLK和数据线SDA的逻辑电平变化,如下图所示,从图上可知I2C读取读取MPU6050内部寄存器的时序与上面我们所描述的一致

用逻辑分析仪捕获主机使用I2C1向MPU6050寄存器PWR_MGMT_1(0X6B)写入一字节0X00数据时,时钟线SCLK和数据线SDA的逻辑电平变化,如下图所示

为什么上图中从机地址从0X68变为0XD0了?

HAL库中的I2C写入函数HAL_I2C_Mem_Write()和读取函数HAL_I2C_Mem_Read()对传入从机地址DevAddress参数做了要求,该地址必须将数据手册中提到的地址左移才可以调用该接口

0X68(0110 1000)向左移动直到遇到1即为0XD0(1101 0000),在I2C通信中使用上述两个API,从机地址传入0XD0表示对从机地址为0X68的从机进行写操作,传入0XD1表示对从机地址为0X68的从机进行读操作

如下图为HAL库HAL_I2C_Mem_Read()函数说明

上面提到,当启用I2C之后,其I2C_SCL和I2C_SDA两个引脚被配置为了复用功能开漏输出,而开漏输出无法输出高电平,因此I2C_SCL和I2C_SDA两个引脚需要外部上拉,一般的开发板都会考虑到这一点,在设计原理图的时候将使用的I2C两根线给外部上拉到3.3V,如果你使用的是自己设计的板子,请务必记住I2C需要上拉

细心的同学可能又发现了,你上面给出的MPU6050硬件原理图I2C两根线并没有外部上拉呀?

虽然MPU6050硬件原理图I2C两根线没有上拉,但是在开发板的其他I2C通信的芯片上进行了外部上拉,如下图所示

3.1、CubeMX相关配置

3.1.0、工程基本配置

打开STM32CubeMX软件,单击ACCESS TO MCU SELECTOR选择开发板MCU(选择你使用开发板的主控MCU型号),选中MCU型号后单击页面右上角Start Project开始工程,具体如下图所示

开始工程之后在配置主页面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具体如下图所示

详细工程建立内容读者可以阅读“STM32CubeMX教程1 工程建立

3.1.1、时钟树配置

系统时钟使用8MHz外部高速时钟HSE,HCLK、PCLK1和PCLK2均设置为STM32F407能达到的最高时钟频率,具体如下图所示

3.1.2、外设参数配置

实验需要通过串口来输出与MPU6050进行I2C通信读取的陀螺仪和加速度计数据,因此外设需要初始化USART1和I2C1

单击Pinout & Configuration页面左边Connectivity/USART1选项,然后按照“STM32CubeMX教程9 USART/UART 异步通信”实验中将USART1配置为异步通信模式,无需开启中断,如下图所示

在Pinout & Configuration页面右边芯片引脚预览Pinout view中找到与开发板上MPU6050芯片连接的I2C的两个通信引脚PB8和PB9,左边单击将其分别配置为I2C1_SCL和I2C1_SDA

然后单击Connectivity/I2C1选项,在其模式中选择I2C,在下方Master Features中将 I2C Speed Mode 根据用户需求选择快速模式(400kkHz)或者标准模式(100kHz),这两种模式仅仅影响通信速率,对于本实验两个模式均可随意选择

其他参数保持默认即可,具体配置如下图所示

3.1.3、外设中断配置

本实验无需启用中断,如果需要启用I2C1的中断,请单击System Core/NVIC,然后根据需求勾选I2C1的事件或错误中断,并选择合适的中断优先级即可,具体配置如下图所示

3.2、生成代码

3.2.0、配置Project Manager页面

单击进入Project Manager页面,在左边Project分栏中修改工程名称、工程目录和工具链,然后在Code Generator中勾选“Gnerate peripheral initialization as a pair of 'c/h' files per peripheral”,最后单击页面右上角GENERATE CODE生成工程,具体如下图所示

详细Project Manager配置内容读者可以阅读“STM32CubeMX教程1 工程建立”实验3.4.3小节

3.2.1、外设初始化调用流程

还是一模一样的流程,与该系列教程所有的外设初始化一致

在生成的工程代码主函数中新增了MX_I2C1_Init()函数,在该函数中实现了对I2C1的模式及参数配置

在MX_I2C1_Init()函数中调用了HAL_I2C_Init()函数使用配置的参数对I2C1进行了初始化

在HAL_I2C_Init()函数中又调用了HAL_I2C_MspInit()函数对I2C1引脚复用设置,I2C1时钟使能,如果开启了中断该函数中还会有中断相关设置及使能

如下图所示为I2C1初始化调用流程

3.2.2、外设中断调用流程

本实验无需中断,因此未启动任何I2C1的中断

3.2.3、添加其他必要代码

需要添加MPU6050的驱动文件,文件中至少应该包括

  1. MPU6050初始化函数
  2. MPU6050获取三轴加速度计原始数据函数
  3. MPU6050获取三轴陀螺仪原始数据函数

注意本实验只使用而不会介绍MPU6050具体驱动文件的原理,具体源代码如下所示 (注释3)

mpu6050.c文件

#include "mpu6050.h"

/**
* @brief MPU6050初始化函数
* @alter 无
* @param 无
* @retval 成功返回0,失败返回1
*/
uint8_t MPU6050_Init(I2C_HandleTypeDef *I2Cx)
{
uint8_t check;
uint8_t Data; // check device ID WHO_AM_I
HAL_I2C_Mem_Read(I2Cx, MPU6050_ADDR, MPU_DEVICE_ID_REG, 1, &check, 1, I2C_TimeOut);
// 0x68 will be returned by the sensor if everything goes well
if (check == 104)
{
// power management register 0X6B we should write all 0's to wake the sensor up
Data = 0;
HAL_I2C_Mem_Write(I2Cx, MPU6050_ADDR, MPU_PWR_MGMT1_REG, 1, &Data, 1, I2C_TimeOut); // Set DATA RATE of 1KHz by writing SMPLRT_DIV register
Data = 0x07;
HAL_I2C_Mem_Write(I2Cx, MPU6050_ADDR, MPU_SAMPLE_RATE_REG, 1, &Data, 1, I2C_TimeOut); // Set accelerometer configuration in ACCEL_CONFIG Register
// XA_ST=0,YA_ST=0,ZA_ST=0, FS_SEL=0 -> 2g
Data = 0x00;
HAL_I2C_Mem_Write(I2Cx, MPU6050_ADDR, MPU_ACCEL_CFG_REG, 1, &Data, 1, I2C_TimeOut); // Set Gyroscopic configuration in GYRO_CONFIG Register
// XG_ST=0,YG_ST=0,ZG_ST=0, FS_SEL=0 -> 250 /s
Data = 0x00;
HAL_I2C_Mem_Write(I2Cx, MPU6050_ADDR, MPU_GYRO_CFG_REG, 1, &Data, 1, I2C_TimeOut);
return 0;
}
return 1;
} /**
* @brief MPU6050温度值获取函数
* @alter 无
* @param 无
* @retval 温度值
*/
float MPU_Get_Temperature(void)
{
uint8_t buf[2];
short raw;
float temp;
HAL_I2C_Mem_Read(&MPU6050_I2C, MPU6050_ADDR, MPU_TEMP_OUTH_REG, 1, buf, 2, I2C_TimeOut);
raw=((int16_t)buf[0]<<8)|buf[1];
temp=36.53+((double)raw)/340;
return temp;;
} /**
* @brief MPU6050陀螺仪值获取函数(三轴原始值)
* @alter 无
* @param gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
* @retval 正常:0,错误:其他
*/
uint8_t MPU_Get_RAW_Gyroscope(int16_t *gx,int16_t *gy,int16_t *gz)
{
uint8_t buf[6],res;
res = HAL_I2C_Mem_Read(&MPU6050_I2C, MPU6050_ADDR, MPU_GYRO_XOUTH_REG, 1, buf, 6, I2C_TimeOut);
if(res==0)
{
*gx=((int16_t)buf[0]<<8)|buf[1];
*gy=((int16_t)buf[2]<<8)|buf[3];
*gz=((int16_t)buf[4]<<8)|buf[5];
}
return res;
} /**
* @brief MPU6050加速度值获取函数(三轴原始值)
* @alter 无
* @param ax,ay,az:加速度计x,y,z轴的原始读数(带符号)
* @retval 正常:0,错误:其他
*/
uint8_t MPU_Get_RAW_Accelerometer(int16_t *ax,int16_t *ay,int16_t *az)
{
uint8_t buf[6],res;
res = HAL_I2C_Mem_Read(&MPU6050_I2C, MPU6050_ADDR, MPU_ACCEL_XOUTH_REG, 1, buf, 6, I2C_TimeOut);
if(res==0)
{
*ax=((int16_t)buf[0]<<8)|buf[1];
*ay=((int16_t)buf[2]<<8)|buf[3];
*az=((int16_t)buf[4]<<8)|buf[5];
}
return res;
}

mpu6050.h文件

#ifndef __MPU6050_H
#define __MPU6050_H
#include "main.h"
#include "i2c.h"
#endif #define MPU6050_I2C hi2c1
#define MPU6050_ADDR 0xD0
#define I2C_TimeOut 100 /*MPU6050内部寄存器地址*/
#define MPU_SAMPLE_RATE_REG 0X19 //采样频率分频器
#define MPU_GYRO_CFG_REG 0X1B //陀螺仪配置寄存器
#define MPU_ACCEL_CFG_REG 0X1C //加速度计配置寄存器
#define MPU_ACCEL_XOUTH_REG 0X3B //加速度值,X轴高8位寄存器
#define MPU_TEMP_OUTH_REG 0X41 //温度值高八位寄存器
#define MPU_GYRO_XOUTH_REG 0X43 //陀螺仪值,X轴高8位寄存器
#define MPU_PWR_MGMT1_REG 0X6B //电源管理寄存器1
#define MPU_DEVICE_ID_REG 0X75 //器件ID寄存器 uint8_t MPU6050_Init(I2C_HandleTypeDef *I2Cx);
float MPU_Get_Temperature(void);
uint8_t MPU_Get_RAW_Gyroscope(int16_t *gx,int16_t *gy,int16_t *gz);
uint8_t MPU_Get_RAW_Accelerometer(int16_t *ax,int16_t *ay,int16_t *az); /*
MPU6050内部所有寄存器地址
#define MPU_SELF_TESTX_REG 0X0D //自检寄存器X
#define MPU_SELF_TESTY_REG 0X0E //自检寄存器Y
#define MPU_SELF_TESTZ_REG 0X0F //自检寄存器Z
#define MPU_SELF_TESTA_REG 0X10 //自检寄存器A
#define MPU_SAMPLE_RATE_REG 0X19 //采样频率分频器
#define MPU_CFG_REG 0X1A //配置寄存器
#define MPU_GYRO_CFG_REG 0X1B //陀螺仪配置寄存器
#define MPU_ACCEL_CFG_REG 0X1C //加速度计配置寄存器
#define MPU_MOTION_DET_REG 0X1F //运动检测阀值设置寄存器
#define MPU_FIFO_EN_REG 0X23 //FIFO使能寄存器
#define MPU_I2CMST_CTRL_REG 0X24 //IIC主机控制寄存器
#define MPU_I2CSLV0_ADDR_REG 0X25 //IIC从机0器件地址寄存器
#define MPU_I2CSLV0_REG 0X26 //IIC从机0数据地址寄存器
#define MPU_I2CSLV0_CTRL_REG 0X27 //IIC从机0控制寄存器
#define MPU_I2CSLV1_ADDR_REG 0X28 //IIC从机1器件地址寄存器
#define MPU_I2CSLV1_REG 0X29 //IIC从机1数据地址寄存器
#define MPU_I2CSLV1_CTRL_REG 0X2A //IIC从机1控制寄存器
#define MPU_I2CSLV2_ADDR_REG 0X2B //IIC从机2器件地址寄存器
#define MPU_I2CSLV2_REG 0X2C //IIC从机2数据地址寄存器
#define MPU_I2CSLV2_CTRL_REG 0X2D //IIC从机2控制寄存器
#define MPU_I2CSLV3_ADDR_REG 0X2E //IIC从机3器件地址寄存器
#define MPU_I2CSLV3_REG 0X2F //IIC从机3数据地址寄存器
#define MPU_I2CSLV3_CTRL_REG 0X30 //IIC从机3控制寄存器
#define MPU_I2CSLV4_ADDR_REG 0X31 //IIC从机4器件地址寄存器
#define MPU_I2CSLV4_REG 0X32 //IIC从机4数据地址寄存器
#define MPU_I2CSLV4_DO_REG 0X33 //IIC从机4写数据寄存器
#define MPU_I2CSLV4_CTRL_REG 0X34 //IIC从机4控制寄存器
#define MPU_I2CSLV4_DI_REG 0X35 //IIC从机4读数据寄存器
#define MPU_I2CMST_STA_REG 0X36 //IIC主机状态寄存器
#define MPU_INTBP_CFG_REG 0X37 //中断/旁路设置寄存器
#define MPU_INT_EN_REG 0X38 //中断使能寄存器
#define MPU_INT_STA_REG 0X3A //中断状态寄存器
#define MPU_ACCEL_XOUTH_REG 0X3B //加速度值,X轴高8位寄存器
#define MPU_ACCEL_XOUTL_REG 0X3C //加速度值,X轴低8位寄存器
#define MPU_ACCEL_YOUTH_REG 0X3D //加速度值,Y轴高8位寄存器
#define MPU_ACCEL_YOUTL_REG 0X3E //加速度值,Y轴低8位寄存器
#define MPU_ACCEL_ZOUTH_REG 0X3F //加速度值,Z轴高8位寄存器
#define MPU_ACCEL_ZOUTL_REG 0X40 //加速度值,Z轴低8位寄存器
#define MPU_TEMP_OUTH_REG 0X41 //温度值高八位寄存器
#define MPU_TEMP_OUTL_REG 0X42 //温度值低8位寄存器
#define MPU_GYRO_XOUTH_REG 0X43 //陀螺仪值,X轴高8位寄存器
#define MPU_GYRO_XOUTL_REG 0X44 //陀螺仪值,X轴低8位寄存器
#define MPU_GYRO_YOUTH_REG 0X45 //陀螺仪值,Y轴高8位寄存器
#define MPU_GYRO_YOUTL_REG 0X46 //陀螺仪值,Y轴低8位寄存器
#define MPU_GYRO_ZOUTH_REG 0X47 //陀螺仪值,Z轴高8位寄存器
#define MPU_GYRO_ZOUTL_REG 0X48 //陀螺仪值,Z轴低8位寄存器
#define MPU_I2CSLV0_DO_REG 0X63 //IIC从机0数据寄存器
#define MPU_I2CSLV1_DO_REG 0X64 //IIC从机1数据寄存器
#define MPU_I2CSLV2_DO_REG 0X65 //IIC从机2数据寄存器
#define MPU_I2CSLV3_DO_REG 0X66 //IIC从机3数据寄存器
#define MPU_I2CMST_DELAY_REG 0X67 //IIC主机延时管理寄存器
#define MPU_SIGPATH_RST_REG 0X68 //信号通道复位寄存器
#define MPU_MDETECT_CTRL_REG 0X69 //运动检测控制寄存器
#define MPU_USER_CTRL_REG 0X6A //用户控制寄存器
#define MPU_PWR_MGMT1_REG 0X6B //电源管理寄存器1
#define MPU_PWR_MGMT2_REG 0X6C //电源管理寄存器2
#define MPU_FIFO_CNTH_REG 0X72 //FIFO计数寄存器高八位
#define MPU_FIFO_CNTL_REG 0X73 //FIFO计数寄存器低八位
#define MPU_FIFO_RW_REG 0X74 //FIFO读写寄存器
#define MPU_DEVICE_ID_REG 0X75 //器件ID寄存器
*/

在keil中添加.c/.h文件步骤如下图所示

然后将源代码复制到新建的.c/.h文件中,最后将.c文件添加到工程即可,如下图所示

在主函数中初始化MPU6050,主循环中获取原始的三轴加速度数据和三轴陀螺仪数据,并通过串口打印信息

源代码如下

/*main.c中定义的变量*/
int16_t ax,ay,az,gx,gy,gz; /*初始化代码*/
while(MPU6050_Init(&hi2c1) != HAL_OK){HAL_Delay(1);} /*主循环中代码*/
MPU_Get_RAW_Gyroscope(&ax,&ay,&az);
MPU_Get_RAW_Accelerometer(&gx,&gy,&gz);
printf("ax:%d,ay:%d,az:%d,",ax,ay,az);
printf("gx:%d,gy:%d,gz:%d\r\n",gx,gy,gz);
HAL_Delay(100);

4、常用函数

/*I2C读函数*/
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) /*I2C写函数*/
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)

5、烧录验证

烧录程序,上电后开启串口,可以看到源源不断的输出当前MPU6050三轴加速度数据和三轴陀螺仪数据,移动开发板会发现数据有规律改变,如下图所示为串口输出的数据

6、注释详解

注释1:图片来源 I2C通信协议介绍 - 知乎

注释2:MPU6050 Datasheet https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf

注释3:MPU6050驱动库参考 https://github.com/leech001/MPU6050

更多内容请浏览 STM32CubeMX+STM32F4系列教程文章汇总贴

STM32CubeMX教程19 I2C - MPU6050驱动的更多相关文章

  1. Linux i2c子系统(一) _动手写一个i2c设备驱动

    i2c总线是一种十分常见的板级总线,本文以linux3.14.0为参考, 讨论Linux中的i2c驱动模型并利用这个模型写一个mpu6050的驱动, 最后在应用层将mpu6050中的原始数据读取出来 ...

  2. I2C子系统驱动框架及应用 (转)

    I2C子系统驱动框架:     应用程序层(app层) ——————————————————————————————————– i2c driver层: 从设备驱动层(TS  Sensor等) 1. ...

  3. i2c总线驱动,总线设备(适配器),从设备,从设备驱动的注册以及匹配

    常用链接 我的随笔 我的评论 我的参与 最新评论 我的标签 随笔分类 ARM裸机(13) C(8) C++(8) GNU-ARM汇编 Linux驱动(24) Linux应用编程(5) Makefile ...

  4. 普冉PY32系列(六) 通过I2C接口驱动PCF8574扩展的1602LCD

    目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 普冉PY32系列(三) P ...

  5. Linux I2C设备驱动编写(三)-实例分析AM3359

    TI-AM3359 I2C适配器实例分析 I2C Spec简述 特性: 兼容飞利浦I2C 2.1版本规格 支持标准模式(100K bits/s)和快速模式(400K bits/s) 多路接收.发送模式 ...

  6. Linux I2C设备驱动编写(二)

    在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_driver.i2c_client.三者的关系也在上一节进行了描述.应该已经算是对Linux I2C子系统有了初步 ...

  7. Linux I2C设备驱动编写(一)

    在Linux驱动中I2C系统中主要包含以下几个成员: I2C adapter 即I2C适配器 I2C driver 某个I2C设备的设备驱动,可以以driver理解. I2C client 某个I2C ...

  8. 【转】Linux I2C设备驱动编写(三)-实例分析AM3359

    原文网址:http://www.cnblogs.com/biglucky/p/4059586.html TI-AM3359 I2C适配器实例分析 I2C Spec简述 特性: 兼容飞利浦I2C 2.1 ...

  9. 【转】Linux I2C设备驱动编写(二)

    原文网址:http://www.cnblogs.com/biglucky/p/4059582.html 在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_drive ...

  10. 【转】Linux I2C设备驱动编写(一)

    原文网址:http://www.cnblogs.com/biglucky/p/4059576.html 在Linux驱动中I2C系统中主要包含以下几个成员: I2C adapter 即I2C适配器 I ...

随机推荐

  1. 如何生成core文件进行项目调试

    由于项目前期的调试错误比较多,或者有某些隐藏危险:例如内存泄漏:偶尔才出现一次,如果没有捕捉错误的手段可能好不容易出现的机会就溜走了,所以生成core文件是必要的,发生段错误会生成相应的core文件, ...

  2. v0.12.0-敏感词/脏词词标签能力进一步增强

    拓展阅读 敏感词工具实现思路 DFA 算法讲解 敏感词库优化流程 java 如何实现开箱即用的敏感词控台服务? 各大平台连敏感词库都没有的吗? v0.10.0-脏词分类标签初步支持 v0.11.0-敏 ...

  3. JS的对象

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  4. MinIO客户端之tree

    MinIO提供了一个命令行程序mc用于协助用户完成日常的维护.管理类工作. 官方资料 mc tree 使用树的形式,输出桶内的目录和文件. ./mc tree --files local1/bkt1 ...

  5. CTFHub XSS DOM反射 WriteUp

    前言:本文需要注册一个xss平台,以接收xss反弹回来的数据,请自己在互联网上寻找合适的xss平台 1. 构造闭合语句 根据题目提示,判断网站存在DOM xss漏洞 查看页面源代码,发现关键位置,其中 ...

  6. 如何在SAP GUI中快速执行新的事务代码

    当我们成功登录SAP的某个连接后,在SAP GUI起始页(SAP轻松访问),我们可以通过点击[收藏夹]或者在界面左上角的输入框输入对应的事务代码,直接进入对应事务的界面.但是下面列举的场景,你是否知道 ...

  7. Provider的八种提供者

    代码 class Example extends StatelessWidget { @override Widget build(BuildContext context) { return Sca ...

  8. java中的数据库连接池

    常见的连接池的优缺点: HikariCP 优点: 性能出色,尤其在高并发负载下表现良好 内存消耗低,占用系统资源较少 具有自动化的连接池维护和统计功能 缺点: 需要 JDK7 或以上版本支持 配置选项 ...

  9. 昇腾实践丨ATC模型转换动态shape问题案例

    本文分享自华为云社区<ATC模型转换动态shape问题案例>,作者:昇腾CANN. ATC(Ascend Tensor Compiler)是异构计算架构CANN体系下的模型转换工具:它可以 ...

  10. 基于DMS的数仓智能运维服务,知多少?

    摘要:GaussDB(DWS)使用DMS来承载数据库的智能运维体系,提供了数据库运维过程中的监控,分析,处理三大核心处理过程. 本文分享自华为云社区<GaussDB(DWS) 数据库智能监控运维 ...