stc32g利用硬件I2C配合中断实现高效率异步无阻塞读写方法

I2C读写巨慢, 即使在400kbit/s下, 读写一个字节数据也要花费20多us, 这太慢了, 每读写一次设备的寄存器数据, 还要设备地址和寄存器地址, 又加了两个字节数据, 我就读了个传感器的两个字节数据而已, 动辄还要花费100us的阻塞时间, 这太浪费资源了
针对这个问题, 我利用硬件I2C及中断配合, 实现了这个全程没有任何阻塞MCU来读写I2C设备的方法, 效率大大提升
单片机采用stc32g8k64, 主频为40Mhz, 读写LDC1612电感涡流传感器为例来测试异步读写I2C数据

/*** stc32g8k64 硬件i2c 实现 无阻塞异步执行* ldc1612 i2c异步读写测试*/
#include <STC32G.h>
#include <stdio.h>
#define FOSC 40000000UL // 主频40Mvoid Delay1ms(void) //@40.000MHz
{unsigned char data i, j;i = 39;j = 230;do{while (--j);} while (--i);
}
void delay(uint16 ms)
{while (ms--){Delay1ms();}
}// ---------------------- uart1打印测试用 开始----------------------------
bit busy;
char wptr;
char rptr;
char buffer[16];void Uart1_Isr(void) interrupt 4
{if (TI){TI = 0;busy = 0;}if (RI){RI = 0;buffer[wptr++] = SBUF;wptr &= 0x0f;}
}
void Uart1_Init(void) // 1000000bps@40.000MHz
{SCON = 0x50;  // 8位数据,可变波特率AUXR |= 0x40; // 定时器时钟1T模式AUXR &= 0xFE; // 串口1选择定时器1为波特率发生器TMOD &= 0x0F; // 设置定时器模式TL1 = 0xF6;   // 设置定时初始值TH1 = 0xFF;   // 设置定时初始值ET1 = 0;      // 禁止定时器中断TR1 = 1;      // 定时器1开始计时ES = 1;       // 使能串口1中断
}
void UartSend(char dat)
{while (busy);busy = 1;SBUF = dat;
}
void UartSendStr(char *p)
{while (*p){UartSend(*p++);}
}char sendNumberCharArr[20];
// 实现一个uint32转char的方法
void numberToChar(uint32 number, char *buffer)
{char temp[12]; // Maximum digits for uint32 + null terminatorint i = 0;int j = 0;// Handle zero caseif (number == 0){buffer[0] = '0';buffer[1] = '\0';return;}// Extract digits in reverse orderwhile (number > 0){temp[i++] = (number % 10) + '0';number /= 10;}// Reverse the string to correct orderwhile (i > 0){buffer[j++] = temp[--i];}buffer[j] = '\0'; // Null terminate
}
// ---------------------- uart1打印测试用 结束----------------------------//------------------------------- I2C异步执行栈 开始 -----------------------------
sbit ET4 = IE2 ^ 6;
typedef void (*AsyncFunc)(void);
AsyncFunc AsyncFuncNext_callback = NULL;
// 延时执行下一个任务
void AsyncFuncNext(AsyncFunc callback, uint16 usDelay)
{uint16 totalTime = 0xffff - usDelay;T4T3M &= ~0x80;ET4 = 0;T4L = totalTime & 0xff; // 设置定时初始值T4H = totalTime >> 8;   // 设置定时初始值AsyncFuncNext_callback = callback;T4T3M |= 0x80; // 定时器4开始计时ET4 = 1;       // 使能中断
}
// 定时器用于异步执行
void Timer4_Init(void) //@40.000MHz
{// 1us计时一个数字TM4PS = 0x27;   // 设置定时器时钟预分频T4T3M |= 0x20;  // 定时器时钟1T模式T4L = 0x00;     // 设置定时初始值T4H = 0x00;     // 设置定时初始值T4T3M &= ~0x80; // 定时器4停止计时ET4 = 0;
}
// 定时器4用作异步执行定时器, 延时触发下一步的执行函数
void Timer4_async_next_isr() interrupt 20
{T4T3M &= ~0x80;ET4 = 0;if (AsyncFuncNext_callback != NULL){AsyncFuncNext_callback();}
}
AsyncFunc I2C_Isr_callback = NULL; // I2C中断回调函数
void I2C_Isr() interrupt 24        // I2C中断
{if (I2CMSST & 0x40){I2CMSST &= ~0x40; // 清中断标志if (I2C_Isr_callback != NULL){I2C_Isr_callback();}}
}
//------------------------------- 异步执行栈 结束 -----------------------------//------------------------------- I2C寄存器操作 开始 --------------------------
void Wait_I2C()
{while (!(I2CMSST & 0x40));I2CMSST &= ~0x40;
}uint8 i2c_readRegister16Async_addr = 0;               // readRegister16Async 地址参数
uint8 i2c_readRegister16Async_reg = 0;                // readRegister16Async 寄存器参数
uint8 i2c_readRegister16Async_step = 0;               // readRegister16Async 异步执行步骤
uint16 i2c_readRegister16Async_value = 0;             // readRegister16Async 读取数据返回值
AsyncFunc i2c_readRegister16Async_endCallback = NULL; // readRegister16Async 读取数据完成回调
void i2c_readRegister16Async_timeout()
{i2c_readRegister16Async_value = 0;i2c_readRegister16Async_step = 0;I2C_Isr_callback = NULL;I2CMSST = 0x00;if (i2c_readRegister16Async_endCallback != NULL){i2c_readRegister16Async_endCallback();}
}
// I2C异步读取, 16位寄存器
void i2c_readRegister16Async()
{if (i2c_readRegister16Async_step == 1){I2CTXD = i2c_readRegister16Async_addr << 1; // 发送i2c地址I2CMSCR = 0x89;                             // 中断使能, 发送起始信号+设备地址+写信号i2c_readRegister16Async_step++;AsyncFuncNext(i2c_readRegister16Async_timeout, 200);return;}if (i2c_readRegister16Async_step == 2){I2CTXD = i2c_readRegister16Async_reg; // 发送读取寄存器地址I2CMSCR = 0x8A;                       // 中断使能,  发送数据命令+接收ACK命令i2c_readRegister16Async_step++;AsyncFuncNext(i2c_readRegister16Async_timeout, 200);return;}if (i2c_readRegister16Async_step == 3){I2CTXD = i2c_readRegister16Async_addr << 1 | 0x01; // 发送i2c地址+读取数据I2CMSCR = 0x89;                                    // 中断使能,  发送起始信号+设备地址+写信号i2c_readRegister16Async_step++;AsyncFuncNext(i2c_readRegister16Async_timeout, 200);return;}if (i2c_readRegister16Async_step == 4){I2CMSST = 0x00; // 设置 ACK 信号I2CMSCR = 0x8B; // 中断使能, 接收数据命令+发送ACK(0)命令i2c_readRegister16Async_step++;AsyncFuncNext(i2c_readRegister16Async_timeout, 200);return;}if (i2c_readRegister16Async_step == 5){i2c_readRegister16Async_value = I2CRXD;i2c_readRegister16Async_value <<= 8;I2CMSST = 0x01; // 设置 NAK 信号I2CMSCR = 0x8C; // 中断使能, 接收数据命令+发送NAK(1)命令i2c_readRegister16Async_step++;AsyncFuncNext(i2c_readRegister16Async_timeout, 200);return;}if (i2c_readRegister16Async_step == 6){i2c_readRegister16Async_value |= I2CRXD;i2c_readRegister16Async_step++;I2CMSCR = 0x86; // 中断使能, 发送 STOP 命令AsyncFuncNext(i2c_readRegister16Async_timeout, 200);return;}if (i2c_readRegister16Async_step == 7){I2C_Isr_callback = NULL;i2c_readRegister16Async_step = 0;AsyncFuncNext(i2c_readRegister16Async_endCallback, 20);return;}
}
// 使用异步来读取i2c数据
void i2c_readRegister16Async_start(uint8 addr, uint8 reg, AsyncFunc readEndCallback)
{i2c_readRegister16Async_addr = addr;i2c_readRegister16Async_reg = reg;i2c_readRegister16Async_value = 0;i2c_readRegister16Async_step = 1;I2C_Isr_callback = i2c_readRegister16Async;i2c_readRegister16Async_endCallback = readEndCallback;i2c_readRegister16Async();
}
// I2C同步读取, 16位寄存器
uint16 i2c_readRegister16(uint8 addr, uint8 reg)
{uint16 readDataValue = 0;I2CTXD = addr << 1; // 写数据到数据缓冲区I2CMSCR = 0x09;     // 发送起始信号+设备地址+写信号Wait_I2C();I2CTXD = reg;   // 写数据到数据缓冲区I2CMSCR = 0x0A; // 发送数据命令+接收ACK命令Wait_I2C();I2CTXD = addr << 1 | 0x01; // 发送i2c地址+读取数据I2CMSCR = 0x09;            // 发送起始信号+设备地址+写信号Wait_I2C();I2CMSST = 0x00; // 设置 ACK 信号I2CMSCR = 0x0B; // 接收数据命令+发送ACK(0)命令Wait_I2C();readDataValue = I2CRXD;readDataValue <<= 8;I2CMSST = 0x01; // 设置 NAK 信号I2CMSCR = 0x0C; // 接收数据命令+发送NAK(1)命令Wait_I2C();readDataValue |= I2CRXD;I2CMSCR = 0x06; // 发送 STOP 命令Wait_I2C();return readDataValue;
}uint8 i2c_writeRegister16Async_addr = 0;               // writeRegister16Async 地址参数
uint8 i2c_writeRegister16Async_reg = 0;                // writeRegister16Async 寄存器参数
uint8 i2c_writeRegister16Async_step = 0;               // writeRegister16Async 异步执行步骤
uint16 i2c_writeRegister16Async_value = 0;             // writeRegister16Async 写入数据
AsyncFunc i2c_writeRegister16Async_endCallback = NULL; // writeRegister16Async 读取数据完成回调
// 异步写16位寄存器超时
void i2c_writeRegister16Async_timeout()
{i2c_writeRegister16Async_value = 0;i2c_writeRegister16Async_step = 0;I2C_Isr_callback = NULL;I2CMSST = 0x00;if (i2c_writeRegister16Async_endCallback != NULL){i2c_writeRegister16Async_endCallback();}
}
// 异步写16位寄存器
void i2c_writeRegister16Async()
{if (i2c_writeRegister16Async_step == 1){I2CTXD = i2c_writeRegister16Async_addr << 1; // 写数据到数据缓冲区I2CMSCR = 0x89;                              // 发送起始信号+设备地址+写信号i2c_writeRegister16Async_step++;AsyncFuncNext(i2c_writeRegister16Async_timeout, 200);return;}if (i2c_writeRegister16Async_step == 2){I2CTXD = i2c_writeRegister16Async_reg; // 写数据到数据缓冲区I2CMSCR = 0x8A;                        // 发送数据命令+接收ACK命令i2c_writeRegister16Async_step++;AsyncFuncNext(i2c_writeRegister16Async_timeout, 200);return;}if (i2c_writeRegister16Async_step == 3){I2CTXD = (i2c_writeRegister16Async_value >> 8) & 0xFF; // 写数据到数据缓冲区I2CMSCR = 0x8A;                                        // 发送数据命令+接收ACK命令i2c_writeRegister16Async_step++;AsyncFuncNext(i2c_writeRegister16Async_timeout, 200);return;}if (i2c_writeRegister16Async_step == 4){I2CTXD = i2c_writeRegister16Async_value & 0xFF; // 写数据到数据缓冲区I2CMSCR = 0x8A;                                 // 发送数据命令+接收ACK命令i2c_writeRegister16Async_step++;AsyncFuncNext(i2c_writeRegister16Async_timeout, 200);return;}if (i2c_writeRegister16Async_step == 5){I2CMSCR = 0x86; // 发送 STOP 命令i2c_writeRegister16Async_step++;AsyncFuncNext(i2c_writeRegister16Async_timeout, 200);return;}if (i2c_writeRegister16Async_step == 6){I2C_Isr_callback = NULL;i2c_writeRegister16Async_step = 0;AsyncFuncNext(i2c_writeRegister16Async_endCallback, 20);return;}
}
// 使用异步来写入i2c数据
void i2c_writeRegister16Async_start(uint8 addr, uint8 reg, uint16 value, AsyncFunc writeEndCallback)
{i2c_writeRegister16Async_addr = addr;i2c_writeRegister16Async_reg = reg;i2c_writeRegister16Async_value = value;I2C_Isr_callback = i2c_writeRegister16Async;i2c_writeRegister16Async_endCallback = writeEndCallback;i2c_writeRegister16Async_step = 1;i2c_writeRegister16Async();
}
// 同步写16位寄存器
void i2c_writeRegister16(uint8 addr, uint8 reg, uint16 value)
{I2CTXD = addr << 1; // 写数据到数据缓冲区I2CMSCR = 0x09;     // 发送起始信号+设备地址+写信号Wait_I2C();I2CTXD = reg;   // 写数据到数据缓冲区I2CMSCR = 0x0A; // 发送数据命令+接收ACK命令Wait_I2C();I2CTXD = (value >> 8) & 0xFF; // 写数据到数据缓冲区I2CMSCR = 0x0A;               // 发送数据命令+接收ACK命令Wait_I2C();I2CTXD = value & 0xFF; // 写数据到数据缓冲区I2CMSCR = 0x0A;        // 发送数据命令+接收ACK命令Wait_I2C();I2CMSCR = 0x06; // 发送 STOP 命令Wait_I2C();
}
//------------------------------- I2C寄存器操作 结束 --------------------------//------------------------------- LDC1612操作 开始 ----------------------------
#define SD_PIN P1_6    // SD引脚
#define INTB_PIN P1_7  // 数据就绪中断
#define CLKIN_PIN P1_3 // 外部时钟引脚// LDC1612 寄存器地址
#define LDC1612_ADDR 0x2A           // I2C地址 (ADDR接地时)
#define REG_DATA_MSB_CH0 0x00       // 通道0数据高16位
#define REG_DATA_LSB_CH0 0x01       // 通道0数据低16位
#define REG_DATA_MSB_CH1 0x02       // 通道1数据高16位
#define REG_DATA_LSB_CH1 0x03       // 通道1数据低16位
#define REG_RCOUNT_CH0 0x08         // 通道0转换计数
#define REG_RCOUNT_CH1 0x09         // 通道1转换计数
#define REG_SETTLE_CNT_CH0 0x10     // 通道0稳定计数
#define REG_SETTLE_CNT_CH1 0x11     // 通道1稳定计数
#define REG_CLOCK_DIVIDERS_CH0 0x14 // 通道0时钟分频
#define REG_CLOCK_DIVIDERS_CH1 0x15 // 通道1时钟分频
#define REG_STATUS 0x18             // 状态寄存器
#define REG_ERROR_CONFIG 0x19       // 错误配置
#define REG_CONFIG 0x1A             // 配置寄存器
#define REG_MUX_CONFIG 0x1B         // 多路复用配置
#define REG_RESET_DEV 0x1C          // 设备复位
#define REG_DRIVE_CURRENT_CH0 0x1E  // 通道0驱动电流
#define REG_DRIVE_CURRENT_CH1 0x1F  // 通道1驱动电流// 配置常量
#define CONVERSION_TIME 0x0850 // 转换时间设置
#define SETTLE_TIME 0x0400     // 稳定时间设置
#define CLOCK_DIVIDER 0x1001   // 时钟分频设置
#define DRIVE_CURRENT 0x1C00   // 驱动电流设置 (最大电流)
// 全局变量
uint32 ch0_value = 0;
uint32 ch1_value = 0;
uint8 LDC1612_read_ready = 0;
uint8 LDC1612_data_ready = 0;uint16 LDC1612_readDataAsync_msb = 0;
uint16 LDC1612_readDataAsync_lsb = 0;
uint16 LDC1612_readDataAsync_step = 0;
uint8 LDC1612_readDataAsync_isStart = 0;
// 异步读取传感器数据
void LDC1612_readDataAsync()
{if (LDC1612_readDataAsync_step == 1){LDC1612_readDataAsync_step++;AsyncFuncNext(LDC1612_readDataAsync, 100);i2c_readRegister16Async_start(LDC1612_ADDR, REG_STATUS, LDC1612_readDataAsync);return;}if (LDC1612_readDataAsync_step == 2){LDC1612_readDataAsync_step++;i2c_readRegister16Async_start(LDC1612_ADDR, REG_DATA_MSB_CH0, LDC1612_readDataAsync);return;}if (LDC1612_readDataAsync_step == 3){LDC1612_readDataAsync_step++;LDC1612_readDataAsync_msb = i2c_readRegister16Async_value;i2c_readRegister16Async_start(LDC1612_ADDR, REG_DATA_LSB_CH0, LDC1612_readDataAsync);return;}if (LDC1612_readDataAsync_step == 4){LDC1612_readDataAsync_step = 0;LDC1612_readDataAsync_lsb = i2c_readRegister16Async_value;ch0_value = ((uint32)LDC1612_readDataAsync_msb << 16) | LDC1612_readDataAsync_lsb;ch0_value &= 0x0FFFFFFF; // 保留28位有效数据ch0_value >>= 12;        // 转为16位数据LDC1612_data_ready = 1;  // 读取数据完成return;}
}
// 同步读取传感器数据
void LDC1612_readData()
{uint16 msb = 0;uint16 lsb = 0;// 读取状态寄存器uint16 status = i2c_readRegister16(LDC1612_ADDR, REG_STATUS);// 检查错误标志if (status & 0x0008){// Serial.println("Error: Amplitude too low!");}if (status & 0x0010){// Serial.println("Error: Timeout occurred!");}// 读取通道0数据msb = i2c_readRegister16(LDC1612_ADDR, REG_DATA_MSB_CH0);lsb = i2c_readRegister16(LDC1612_ADDR, REG_DATA_LSB_CH0);ch0_value = ((uint32)msb << 16) | lsb;ch0_value &= 0x0FFFFFFF; // 保留28位有效数据ch0_value >>= 12;LDC1612_data_ready = 1; // 读取数据完成
}uint8 LDC1612_writeInitReg_step = 0;
// 异步方法写入寄存器值
void LDC1612_writeInitRegAsync()
{// 配置通道0if (LDC1612_writeInitReg_step == 1){LDC1612_writeInitReg_step++;i2c_writeRegister16Async_start(LDC1612_ADDR, REG_RCOUNT_CH0, CONVERSION_TIME, LDC1612_writeInitRegAsync);return;}if (LDC1612_writeInitReg_step == 2){LDC1612_writeInitReg_step++;i2c_writeRegister16Async_start(LDC1612_ADDR, REG_SETTLE_CNT_CH0, SETTLE_TIME, LDC1612_writeInitRegAsync);return;}if (LDC1612_writeInitReg_step == 3){LDC1612_writeInitReg_step++;i2c_writeRegister16Async_start(LDC1612_ADDR, REG_CLOCK_DIVIDERS_CH0, CLOCK_DIVIDER, LDC1612_writeInitRegAsync);return;}if (LDC1612_writeInitReg_step == 4){LDC1612_writeInitReg_step++;i2c_writeRegister16Async_start(LDC1612_ADDR, REG_DRIVE_CURRENT_CH0, DRIVE_CURRENT, LDC1612_writeInitRegAsync);return;}// 配置错误检测if (LDC1612_writeInitReg_step == 5){LDC1612_writeInitReg_step++;// 启用数据输出错误检测i2c_writeRegister16Async_start(LDC1612_ADDR, REG_ERROR_CONFIG, 0x0001, LDC1612_writeInitRegAsync);return;}// 配置多路复用器 - 只启用通道0if (LDC1612_writeInitReg_step == 6){LDC1612_writeInitReg_step++;// 只扫描通道0,去抖动计数=1i2c_writeRegister16Async_start(LDC1612_ADDR, REG_MUX_CONFIG, 0x0208, LDC1612_writeInitRegAsync);return;}// 配置主配置寄存器if (LDC1612_writeInitReg_step == 7){LDC1612_writeInitReg_step++;// 启用传感器,单通道模式i2c_writeRegister16Async_start(LDC1612_ADDR, REG_CONFIG, 0x1401, LDC1612_writeInitRegAsync);return;}// 初始化完成if (LDC1612_writeInitReg_step == 8){LDC1612_writeInitReg_step = 0;return;}
}
// 同步方法写入寄存器值
void LDC1612_writeInitReg()
{// 配置通道0i2c_writeRegister16(LDC1612_ADDR, REG_RCOUNT_CH0, CONVERSION_TIME);i2c_writeRegister16(LDC1612_ADDR, REG_SETTLE_CNT_CH0, SETTLE_TIME);i2c_writeRegister16(LDC1612_ADDR, REG_CLOCK_DIVIDERS_CH0, CLOCK_DIVIDER);i2c_writeRegister16(LDC1612_ADDR, REG_DRIVE_CURRENT_CH0, DRIVE_CURRENT);// 配置错误检测i2c_writeRegister16(LDC1612_ADDR, REG_ERROR_CONFIG, 0x0001); // 启用数据输出错误检测// 配置多路复用器 - 只启用通道0i2c_writeRegister16(LDC1612_ADDR, REG_MUX_CONFIG, 0x0208); // 只扫描通道0,去抖动计数=1// 配置主配置寄存器i2c_writeRegister16(LDC1612_ADDR, REG_CONFIG, 0x1401); // 启用传感器,单通道模式
}// LDC1612 中断服务程序 (数据就绪)
void LDC1612_ready_isr() interrupt 38
{unsigned char intf;intf = P1INTF;if (intf){P1INTF = 0x00;// P1.7 口中断if (intf & 0x80){LDC1612_read_ready = 1;}}
}void initI2C()
{P_SW2 = 0x80; // 使能访问XFRP1PU |= 0x30; // P1.4和P1.5使能4K上拉电阻P1M1 |= 0x10;P1M0 |= 0x10; // P1.4(SDA)开漏输出P1M1 |= 0x20;P1M0 |= 0x20; // P1.5(SCL)开漏输出// I2C总线速度计算: SYSCLK / 2 / (MSSPEED * 2 + 4)// 对于400KHz: MSSPEED = (40M / 400K / 2 - 4) / 2 = 23 (0x17)I2CCFG = 0x80 | 0x40 | 0x17; // 使能I2C + 主机模式 + 400KHz速度I2CMSST = 0x00;              // 清除状态寄存器IP2H |= 0x40;                // 设置I2c中断的优先级为高IP2 |= 0x40;                 // 设置I2c中断的优先级为高
}// LDC1612初始化
void initLDC1612()
{// p1.6 SDP1M1 &= ~0x40;P1M0 |= 0x40; // 推挽输出// p1.3 CLKIN_PINP1M1 &= ~0x08;P1M0 |= 0x08; // 推挽输出// p1.7 INTB 数据准备好中断P1M1 |= 0x80;P1M0 &= ~0x80; // 高阻输入SD_PIN = 0;    // 低电平使能ldc1612CLKIN_PIN = 0; // 禁用外部时钟引脚P1IM0 = 0x00;  // 下降沿中断P1IM1 = 0x00;P1INTE = 0x80; // 使能 p1.7 口中断Timer4_Init();initI2C();delay(50);// 同步方法写入寄存器// LDC1612_writeInitReg();// 异步方式写入寄存器LDC1612_writeInitReg_step = 1;LDC1612_writeInitRegAsync();
}
//------------------------------- LDC1612操作 结束 ----------------------------void main(void)
{P_SW2 = 0x80; // 使能访问XFRWTST = 0;     // 设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快CKCON = 0;    // 提高访问XRAM速度Uart1_Init(); // 初始化串口 1M波特率EA = 1;       // 允许总中断initLDC1612();UartSendStr("setup\n");while (1){if (LDC1612_read_ready == 1){LDC1612_read_ready = 0;// 同步读取传感器数据// LDC1612_readData();// i2c无阻塞异步读取传感器数据LDC1612_readDataAsync_step = 1;LDC1612_readDataAsync();}if (LDC1612_data_ready == 1){LDC1612_data_ready = 0;UartSendStr("LDC1612 data:");numberToChar(ch0_value, sendNumberCharArr);UartSendStr(sendNumberCharArr);UartSendStr("\n");}}
}

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

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

相关文章

生成式 AI 重塑自动驾驶仿真:4D 场景生成技术的突破与实践

近年来&#xff0c;伴随自动驾驶技术的快速发展&#xff0c;行业对于仿真测试平台的精度、覆盖率和可扩展性提出了更高要求。尤其在数据闭环迭代、长尾场景验证及安全冗余验证等关键环节中&#xff0c;高保真、高复杂度的场景生成能力正在成为测试体系的核心支撑。 传统场景生…

Java 启动命令的完整解析

以下为您提供的 Java 启动命令的完整解析和优化建议: nohup java -server \ -XX:+PrintGCDateStamps \ -XX:+PrintGCTimeStamps \ -Xlogger:/home/logs/gc_`date +%Y%m%d_%H%M`.log \ -jar ytr.jar > /dev/null & 一、命令逐行解析 命令部分 功能说明 技术原理 nohup …

JVM中的垃圾回收暂停是什么,为什么会出现暂停,不同的垃圾回收机制暂停对比

JVM中的垃圾回收暂停是什么&#xff1f; 在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;垃圾回收暂停&#xff08;Garbage Collection Pause&#xff09;&#xff0c;也称为“Stop-The-World”事件&#xff0c;是指当垃圾收集器执行特定阶段时&#xff0c;所有应用程序…

Spearman 相关系数与 Pearson 相关系数的区别

核心区别对比表特征Pearson 相关系数Spearman 相关系数相关性类型线性相关单调相关计算基础原始数据值数据排名&#xff08;秩&#xff09;公式数据要求连续变量&#xff0c;近似正态分布有序数据或连续变量异常值敏感性高度敏感不敏感取值范围[-1, 1][-1, 1]单调关系检测仅检测…

sqli-labs靶场less36-less40

less361.我们打开靶场之后打开来看一下&#xff0c;输入的内容会被转义&#xff0c;依旧是宽字节注入2.使用以下宽字节注入&#xff0c;使用的是%df?id-1%df%27%20union%20select%201,database(),3--3.剩余内容与前面关卡基本一样&#xff0c;只要使用上面的方法合成宽字节即可…

企业级 TinyMCE Vue 编辑器解决方案 – 配置优化与性能提升指南、自定义插件

## 简介TinyMCE Vue 是官方提供的 TinyMCE 富文本编辑器的 Vue 组件封装&#xff0c;支持 Vue 2 和 Vue 3。它让你可以在 Vue 项目中快速集成强大的富文本编辑能力&#xff0c;支持多种插件、主题和自定义扩展&#xff0c;适用于博客、内容管理、后台系统等多种场景。主要特性&…

【模电笔记】—— 直流稳压电源——稳压电路

Tips&#xff1a;本章节笔记建议读者综合学习&#xff0c;内容较多&#xff0c;可谓是模电相当重要的部分&#xff0c;因此部分知识点没有做到详细解释。 1.稳压电路的性能指标 &#xff08;同上节直流稳压电源的主要技术指标【模电笔记】—— 直流稳压电源——整流、滤波电路…

C++——设计模式

文章目录一、面向对象的优点和缺点1.1 回答重点1.2 扩展知识二、面向对象的三大特点2.1 回答重点2.2 扩展知识三、设计模式的六大原则3.1 回答重点3.1.1 单一职责原则&#xff08;Single Responsibility Principle, SRP&#xff09;3.1.2 开放 - 封闭原则&#xff08;Open-Clos…

Android PDFBox 的使用指南

Android PDFBox 使用指南 概述 PDFBox是一个强大的PDF处理库&#xff0c;在Android平台上也有对应的实现。本指南将介绍如何在Android项目中使用PDFBox进行PDF文件的加载、读取、修改等操作。 依赖配置 在 app/build.gradle 中添加PDFBox依赖&#xff1a; dependencies {i…

TFTP: Linux 系统安装 TFTP,文件系统启动后TFTP使用

安装 TFTP 服务器 sudo apt update sudo apt install tftpd-hpa配置 TFTP 服务器 编辑配置文件 /etc/default/tftpd-hpa&#xff1a; sudo nano /etc/default/tftpd-hpa 修改内容如下&#xff1a; TFTP_USERNAME"tftp" TFTP_DIRECTORY"/srv/tftp" TFTP_ADD…

昇思+昇腾开发板+DeepSeek模型LoRA微调

昇思昇腾开发板DeepSeek模型LoRA微调 LoRA微调原理核心思想&#xff1a;冻结预训练模型权重&#xff0c;仅训练橙色的低秩适配矩阵&#xff08;A/B矩阵&#xff09;优势&#xff1a; 训练参数量减少至全量微调的0.5%显存占用降低50%以上适配器权重仅需保存3MB&#xff08;原模型…

计算机网络:详解网络地址的计算步骤

网络地址计算是网络规划与配置的基础,核心是通过IP地址和子网掩码确定网络标识、广播地址、可用主机范围等关键信息。以下是详细的计算步骤,配合实例说明(以IPv4为例): 一、明确基础概念 在计算前,需先明确3个核心概念: IP地址:标识网络中主机的32位二进制数,通常以…

Spring AI 系列之三十五 - Spring AI Alibaba-Graph框架之MCP

之前做个几个大模型的应用&#xff0c;都是使用Python语言&#xff0c;后来有一个项目使用了Java&#xff0c;并使用了Spring AI框架。随着Spring AI不断地完善&#xff0c;最近它发布了1.0正式版&#xff0c;意味着它已经能很好的作为企业级生产环境的使用。对于Java开发者来说…

FastAPI后端工程化项目记录

以下是一个使用fastapi上传视频的接口&#xff0c;记录一下工程化后端程序的业务逻辑 重点是代码如何抽离 项目结构优化 project/ ├── .env # 环境变量配置 ├── app/ │ ├── __init__.py │ ├── main.py # 主应用入口 │ …

令牌桶限流算法

你提供的 Java 代码实现的是令牌桶限流算法&#xff08;Token Bucket Algorithm&#xff09;&#xff0c;这是目前最常用、最灵活的限流算法之一。它允许一定程度的“突发流量”&#xff0c;同时又能控制平均速率。下面我将&#xff1a;逐行详细解释 TokenBucketLimiter 类的每…

基于springboot的宠物商城设计与实现

管理员&#xff1a;登录&#xff0c;个人中心&#xff0c;用户管埋&#xff0c;宠物分类管理&#xff0c;宠物信息管理&#xff0c;留言反馈&#xff0c;宠物论坛&#xff0c;系统管理&#xff0c;订单管理用户&#xff1a;宠物信息&#xff0c;宠物论坛&#xff0c;公告信息&a…

Python day36

浙大疏锦行 Python day36. 复习日 本周内容&#xff1a; 如何导入模块以及库项目的规范拆分和写法官方文档的阅读MLP神经网络的训练在GPU上训练模型可视化以及推理

【gaussian-splatting】用自己的数据复现高斯泼溅(一)

1.环境准备1.1.下载diff-gaussian-rasterization这里本来没啥说的&#xff0c;直接从github上下载就行了&#xff0c;但是我踩坑了&#xff0c;下的版本不对&#xff0c;后续运行报错参数个数对不上&#xff0c;特在此给大家避坑&#xff0c;注意一定要下带3dgs版本的diff-gaus…

中国移动h10g-01_S905L处理器安卓7.1当贝纯净版线刷机包带root权限_融合终端网关

下载固件之前请先将主板上的屏蔽罩取下&#xff0c;查看处理器型号 是否为S905L型号&#xff0c;然后再下载固件进行刷机&#xff1b; 本页面的固件是采用双公头数据线进行刷机的哈&#xff1b; 安卓4.4.2版本固件下载地址&#xff1a;点此进行下载 安卓7.1版本固件下载地址…

夜天之书 #110 涓滴开源:Cronexpr 的故事

在年初的一篇关于商业开源的博文当中&#xff0c;我介绍了在开发商业软件的过程中&#xff0c;衍生出开源公共软件库的模式。在那篇博文里面&#xff0c;我只是简单罗列了相关开源库的名字及一句话总结。近期&#xff0c;我会结合商业开源实践的最新进展&#xff0c;对其中一些…