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
英文地址,請注明出處:http://en.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;對其中一些…