軟件I2C

軟件I2C

在這里插入圖片描述
注意:
SDA(串行數據線)和SCL(串行時鐘線)都是雙向I/O線,接口電路為開漏輸出。需通過上拉電阻接電源VCC。

軟件I2C說明

說明,有的單片機沒有硬件I2C的功能,或者因為電路設計失誤不得不使用軟件I2C。
軟件I2C雖然引腳設定靈活,但效果自然是比不上硬件I2C的……
本人按照STM32的硬件I2C風格編寫了軟件I2C,這樣便于移植更換

具體來說:
雖然軟件I2C(也稱為Bit-banging I2C)提供了極大的靈活性,允許開發者在任意GPIO引腳上實現I2C通信,但它也有幾個明顯的缺點:

  1. CPU占用率高:由于所有的I2C協議處理(如時序控制、信號的高低電平轉換等)都由CPU直接管理,而不是專用硬件模塊完成,因此會占用大量的CPU資源。這意味著,在進行I2C通信時,CPU不能執行其他任務,除非通過中斷或DMA等方式來部分緩解這個問題。

  2. 速度受限:由于需要依靠CPU指令來精確地控制時序,軟件I2C的速度通常比硬件I2C慢得多。特別是在高速模式下(例如I2C Fast-mode Plus,速度可達1MHz),準確地生成和檢測信號變得更加困難,可能無法達到標準要求的速度。

  3. 時序精度問題:不同CPU架構和運行頻率下的指令周期時間不同,這使得編寫可移植性好的軟件I2C代碼變得復雜。此外,中斷或其他系統活動可能會干擾軟件I2C的時序,導致通信失敗。

  4. 可靠性較低:與硬件I2C相比,軟件I2C更容易受到電磁干擾(EMI)和其他電氣噪聲的影響,因為其不具備硬件級別的過濾和錯誤糾正能力。同時,軟件實現難以完全保證嚴格的I2C協議時序要求,尤其是在復雜的系統環境中。

  5. 不支持高級特性:許多現代微控制器的硬件I2C接口支持諸如多主控、時鐘擴展(clock stretching)、中斷驅動傳輸、DMA支持等高級特性。而這些特性通常很難或者不可能通過軟件I2C來實現。

  6. 開發和維護成本:雖然對于簡單的應用來說,軟件I2C可以快速實現,但對于更復雜的應用場景,如需要支持多種速率、處理各種異常情況等,則需要更多的開發工作,并且調試起來也更加困難。

綜上所述,盡管軟件I2C在某些特定情況下(比如當硬件I2C引腳已被占用,或者需要在多個不同的GPIO引腳上實現I2C通信)非常有用,但考慮到性能、穩定性和功能完整性等方面,硬件I2C通常是更好的選擇。如果條件允許,使用硬件I2C可以減少開發時間和提高系統的整體性能。

軟件I2C代碼

注意,根據自己使用的單片機修改IO口輸入輸出的相關實現!
SDA(串行數據線)和SCL(串行時鐘線)都是雙向I/O線,接口電路為開漏輸出。需通過上拉電阻接電源VCC。
實現軟件微秒級延時的代碼

微秒級延時頭文件

#pragma once#ifdef __cplusplus
extern "C" {
#endif#include <stdint.h>//移植時請根據自身單片機修改/*** @brief 軟件微秒級延時* * @param us 微秒數* * @note 需要根據系統頻率簡單修改* @note 不怎么準,但一般不需要很準* @note 準確的延時需要借助硬件定時器等*/
void softDelayMicro(uint8_t us);#ifdef __cplusplus
}
#endif

微秒級延時源文件

#include "soft_delay.h"// 定義每微秒需要執行的大約循環次數
// 注意:這個值可能需要根據實際情況進行調整
// 例如我的stm32f405頻率168MHz
#define DELAY_MICROSECOND_LOOP_COUNT (168 / 4)#pragma GCC push_options    //禁止編譯器優化這段代碼
#pragma GCC optimize ("O0")void softDelayMicro(uint8_t us)
{while (us--) {volatile uint32_t counter = DELAY_MICROSECOND_LOOP_COUNT;while (counter--);}
}#pragma GCC pop_options

軟件I2C頭文件

/*** @file soft_I2C.h* @author your name (you@domain.com)* @brief 軟件I2C* @version 0.1* @date 2025-05-12* * @copyright Copyright (c) 2025* * @note //根據你的單片機修改IO口的輸入輸出的相關內容!* @note SDA(串行數據線)和SCL(串行時鐘線)都是雙向I/O線,接口電路為開漏輸出。*/#pragma once#ifdef __cplusplusextern "C" {#endif#include <stdbool.h>#include "gpio.h"//根據你的單片機修改IO口的輸入輸出的相關內容!#include "soft_delay.h"/*** @brief 保存某個I2C總線使用的端口引腳信息* * @note SDA(串行數據線)和SCL(串行時鐘線)都是雙向I/O線,接口電路為開漏輸出。*/typedef struct{GPIO_TypeDef* SCL_Port; //時鐘線端口uint32_t SCL_Pin;       //時鐘線引腳GPIO_TypeDef* SDA_Port; //數據線端口uint32_t SDA_Pin;       //數據線引腳}Soft_I2C_Handle;/*** @brief 設置軟件I2c使用的端口和引腳* * @param si2c 指向Soft_I2C_Handle結構體的指針,該結構體包含指定軟件I2C的配置信息。* @param scl_port 時鐘線端口* @param scl_pin 時鐘線引腳* @param sda_port 數據線端口* @param sda_pin 數據線引腳* * @note 請先完成對應端口的初始化配置,然后再使用這個函數* @note SDA(串行數據線)和SCL(串行時鐘線)都是雙向I/O線,接口電路為開漏輸出。*/void Soft_I2C_Config(Soft_I2C_Handle* si2c, GPIO_TypeDef* scl_port, uint32_t scl_pin, GPIO_TypeDef* sda_port, uint32_t sda_pin);/*** @brief 軟件I2C以主模式發送一定數量的數據。** @param si2c 指向Soft_I2C_Handle結構體的指針,該結構體包含指定軟件I2C的配置信息。* @param DevAddress 目標設備地址:在調用接口之前,必須將數據表中的設備7位地址值左移1位* @param pData 指向數據緩沖區的指針* @param Size 要發送的數據量* @return true 成功* @return false 失敗*/bool Soft_I2C_Master_Transmit(Soft_I2C_Handle* si2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);/*** @brief 軟件I2C以主模式接收一定數量的數據。* * @param si2c 指向Soft_I2C_Handle結構體的指針,該結構體包含指定軟件I2C的配置信息。* @param DevAddress 目標設備地址:在調用接口之前,必須將數據表中的設備7位地址值左移1位* @param pData 指向數據緩沖區的指針* @param Size 要接收的數據量* @return true 成功* @return false 失敗*/bool Soft_I2C_Master_Receive(Soft_I2C_Handle* si2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);/** @defgroup I2C_Memory_Address_Size I2C Memory Address Size* @{*/#define SOFT_I2C_MEMADD_SIZE_8BIT            0x00000001U#define SOFT_I2C_MEMADD_SIZE_16BIT           0x00000010U/*** @brief 軟件I2C以阻塞方式從特定內存地址讀取一定數量的數據* * @param si2c 指向Soft_I2C_Handle結構體的指針,該結構體包含指定軟件I2C的配置信息。* @param DevAddress 目標設備地址:在調用接口之前,必須將數據表中的設備7位地址值左移1位* @param MemAddress 目標設備內部存儲器地址* @param MemAddSize 目標設備內部存儲器地址的大小,只能是SOFT_I2C_MEMADD_SIZE_8BIT或者SOFT_I2C_MEMADD_SIZE_16BIT* @param pData 指向數據緩沖區的指針* @param Size 要接收的數據量* @return true 成功* @return false 失敗* */bool Soft_I2C_Mem_Read(Soft_I2C_Handle *si2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);/*** @brief 軟件I2C以阻塞方式將一定數量的數據寫入特定的內存地址* * @param si2c 指向Soft_I2C_Handle結構體的指針,該結構體包含指定軟件I2C的配置信息。 * @param DevAddress 目標設備地址:在調用接口之前,必須將數據表中的設備7位地址值左移1位* @param MemAddress 目標設備內部存儲器地址* @param MemAddSize 目標設備內部存儲器地址的大小,只能是SOFT_I2C_MEMADD_SIZE_8BIT或者SOFT_I2C_MEMADD_SIZE_16BIT* @param pData 指向數據緩沖區的指針* @param Size 要發送的數據量* @return true 成功* @return false 失敗* */bool Soft_I2C_Mem_Write(Soft_I2C_Handle *si2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);#ifdef __cplusplus}#endif

軟件I2C源文件

/*** @file soft_I2C.c* @author your name (you@domain.com)* @brief 軟件I2C* @version 0.1* @date 2025-05-12* * @copyright Copyright (c) 2025* */#include "soft_I2C.h"/****************************** 1. 配置函數 *****************************************///移植時請根據自身單片機修改void Soft_I2C_Config(Soft_I2C_Handle* si2c, GPIO_TypeDef* scl_port, uint32_t scl_pin, GPIO_TypeDef* sda_port, uint32_t sda_pin)
{si2c->SCL_Port = scl_port;si2c->SCL_Pin = scl_pin;si2c->SDA_Port = sda_port;si2c->SDA_Pin = sda_pin;
}/****************************** 2. 輔助宏/函數定義 *****************************************/#define I2C_PIN_HIGH GPIO_PIN_SET
#define I2C_PIN_LOW  GPIO_PIN_RESET//移植時請根據自身單片機修改static inline void SCL_Low(Soft_I2C_Handle* si2c) {HAL_GPIO_WritePin(si2c->SCL_Port, si2c->SCL_Pin, GPIO_PIN_RESET);
}static inline void SCL_High(Soft_I2C_Handle* si2c) {HAL_GPIO_WritePin(si2c->SCL_Port, si2c->SCL_Pin, GPIO_PIN_SET);
}static inline void SDA_Low(Soft_I2C_Handle* si2c) {HAL_GPIO_WritePin(si2c->SDA_Port, si2c->SDA_Pin, GPIO_PIN_RESET);
}static inline void SDA_High(Soft_I2C_Handle* si2c) {HAL_GPIO_WritePin(si2c->SDA_Port, si2c->SDA_Pin, GPIO_PIN_SET);
}static inline GPIO_PinState SDA_Read(Soft_I2C_Handle* si2c) {return HAL_GPIO_ReadPin(si2c->SDA_Port, si2c->SDA_Pin);
}/*** @brief 設置SDA引腳為輸入* * @param si2c */
static void SDA_SetInput(Soft_I2C_Handle* si2c)
{GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = si2c->SDA_Pin;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(si2c->SDA_Port, &GPIO_InitStruct);
}/*** @brief 設置SDA引腳為輸出* * @param si2c */
static void SDA_SetOutput(Soft_I2C_Handle* si2c)
{GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = si2c->SDA_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(si2c->SDA_Port, &GPIO_InitStruct);
}/****************************** 3. I2C 協議輔助函數 *****************************************/
/******************** 為了內部實現I2C功能而創造,通常不需要直接調用 ******************************//*** @brief 產生IIC起始信號** @param si2c* * @note SCL為高電平時,SDA由高變低表示起始信號;*/
void I2C_Start(Soft_I2C_Handle *si2c);/*** @brief 產生IIC停止信號* * @param si2c * * @note SCL為高電平時,SDA由低變高表示停止信號;*/
void I2C_Stop(Soft_I2C_Handle *si2c);/*** @brief 發送一字節數據* * @param si2c * @param byte * * @note 先傳送最高位,后傳送低位*/
void I2C_SendByte(Soft_I2C_Handle *si2c, uint8_t byte);/*** @brief 等待應答信號到來* * @param si2c * @return true 接收應答成功* @return false 接收應答失敗* * @note 在SCL為高電平期間,若檢測到SDA引腳為低電平,則接收設備響應正常* @note 發送器發送完一個字節數據后接收器必須發送1位應答位來回應發送器* */
bool I2C_Wait_Ack(Soft_I2C_Handle *si2c);/*** @brief 接收1字節數據* * @param si2c * @return uint8_t */
uint8_t I2C_ReceiveByte(Soft_I2C_Handle *si2c);/*** @brief 產生ACK應答* * @param si2c * * @note 在SCL為高電平期間,SDA引腳輸出為低電平,產生應答信號*/
void I2C_Ack(Soft_I2C_Handle *si2c);/*** @brief 不產生ACK應答* * @param si2c * * @note 在SCL為高電平期間,若SDA引腳為高電平,產生非應答信號*/
void I2C_Nack(Soft_I2C_Handle *si2c);/*** @brief 發送一字節數據,并等待應答* * @param si2c * @param byte * @return true 應答* @return false 無應答*/
bool I2C_TransmitByte(Soft_I2C_Handle* si2c, uint8_t byte);/*** @brief 向目標設備發送內存地址* * @param si2c 指向Soft_I2C_Handle結構體的指針* @param MemAddress 目標設備地址:在調用接口之前,必須將數據表中的設備7位地址值左移1位* @param MemAddSize 目標設備內部存儲器地址的大小* * @note 根據 MemAddSize 決定發送長度 只能是SOFT_I2C_MEMADD_SIZE_8BIT或者SOFT_I2C_MEMADD_SIZE_16BIT*/
bool I2C_TransmitMemoryAddress(Soft_I2C_Handle* si2c, uint16_t MemAddress, uint16_t MemAddSize);void I2C_Start(Soft_I2C_Handle* si2c) {SDA_SetOutput(si2c);  SDA_High(si2c);SCL_High(si2c);softDelayMicro(10);SDA_Low(si2c);softDelayMicro(10);SCL_Low(si2c);//鉗住I2C總線,準備發送或接收數據
}void I2C_Stop(Soft_I2C_Handle* si2c) {SDA_SetOutput(si2c);SCL_Low(si2c);SDA_Low(si2c);softDelayMicro(10);SCL_High(si2c);SDA_High(si2c);//發送I2C總線結束信號softDelayMicro(10);
}void I2C_SendByte(Soft_I2C_Handle* si2c, uint8_t byte) {SDA_SetOutput(si2c);for (int i = 0; i < 8; i++) {if (byte & 0x80)SDA_High(si2c);elseSDA_Low(si2c);softDelayMicro(10);SCL_High(si2c);softDelayMicro(10);SCL_Low(si2c);softDelayMicro(10);byte <<= 1;//左移準備發下一位}
}bool I2C_Wait_Ack(Soft_I2C_Handle* si2c) {SDA_High(si2c);SDA_SetInput(si2c);softDelayMicro(10);SCL_High(si2c);softDelayMicro(10);uint8_t cycleTimes = 0;while(SDA_Read(si2c) != I2C_PIN_LOW)// 從機拉低表示 ACK{if(cycleTimes > 5){// I2C_Stop(si2c);SCL_Low(si2c);softDelayMicro(10);return false;}cycleTimes++;softDelayMicro(10);}SCL_Low(si2c);softDelayMicro(10);return true;
}bool I2C_TransmitByte(Soft_I2C_Handle* si2c, uint8_t byte)
{I2C_SendByte(si2c, byte);return I2C_Wait_Ack(si2c);
}uint8_t I2C_ReceiveByte(Soft_I2C_Handle* si2c) {uint8_t byte = 0;SDA_SetInput(si2c);for (int i = 0; i < 8; i++) {SCL_Low(si2c);softDelayMicro(10);SCL_High(si2c);byte <<= 1;if (SDA_Read(si2c) == I2C_PIN_HIGH)byte |= 0x01;softDelayMicro(10);}return byte;
}void I2C_Ack(Soft_I2C_Handle* si2c) {SDA_SetOutput(si2c);SCL_Low(si2c);softDelayMicro(10);    SDA_Low(si2c);softDelayMicro(10);SCL_High(si2c);softDelayMicro(10);SCL_Low(si2c);// SCL輸出低時,SDA應立即拉高,釋放總線SDA_High(si2c);softDelayMicro(10);
}void I2C_Nack(Soft_I2C_Handle* si2c) {SDA_SetOutput(si2c);SCL_Low(si2c);softDelayMicro(10);SDA_High(si2c);softDelayMicro(10);SCL_High(si2c);softDelayMicro(10);SCL_Low(si2c);softDelayMicro(10);
}bool I2C_TransmitMemoryAddress(Soft_I2C_Handle* si2c, uint16_t MemAddress, uint16_t MemAddSize) 
{if (MemAddSize == SOFT_I2C_MEMADD_SIZE_8BIT){if(!I2C_TransmitByte(si2c, (uint8_t)(MemAddress & 0xFF))) return false;}else if (MemAddSize == SOFT_I2C_MEMADD_SIZE_16BIT){if(!I2C_TransmitByte( si2c, (uint8_t)((MemAddress >> 8) & 0xFF) ) ) return false;if(!I2C_TransmitByte( si2c, (uint8_t)(MemAddress & 0xFF) ) ) return false;}return true;
}/****************** 4. 軟件I2C讀寫函數實現 ***************/bool Soft_I2C_Master_Transmit(Soft_I2C_Handle* si2c, uint16_t DevAddress, uint8_t* pData, uint16_t Size) {I2C_Start(si2c);// 啟動IIC通信if(!I2C_TransmitByte(si2c, DevAddress | 0x00)) return false;//發送寫數據指令for (uint16_t i = 0; i < Size; i++) {if(!I2C_TransmitByte(si2c, pData[i])) return false;}I2C_Stop(si2c);return true;
}bool Soft_I2C_Master_Receive(Soft_I2C_Handle* si2c, uint16_t DevAddress, uint8_t* pData, uint16_t Size) {I2C_Start(si2c);if(!I2C_TransmitByte(si2c, DevAddress | 0x01)) return false;//發送讀數據指令for (uint16_t i = 0; i < Size; i++) {pData[i] = I2C_ReceiveByte(si2c);if (i < Size - 1)I2C_Ack(si2c);elseI2C_Nack(si2c);}I2C_Stop(si2c);return true;
}bool Soft_I2C_Mem_Read(Soft_I2C_Handle* si2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size)
{// 第一階段:發送設備地址 + 內存地址I2C_Start(si2c); // 假設啟動信號總是成功I2C_SendByte(si2c, DevAddress | 0x00); // 寫模式if (!I2C_Wait_Ack(si2c)) return false;//向目標設備發送內存地址if( !I2C_TransmitMemoryAddress(si2c, MemAddress, MemAddSize) ) return false;// 第二階段:重復啟動,切換為讀模式I2C_Stop(si2c); // 停止信號I2C_Start(si2c); // 重新啟動if(!I2C_TransmitByte( si2c, DevAddress | 0x01 ) ) return false;// 讀模式// 第三階段:接收數據for (uint16_t i = 0; i < Size; i++) {pData[i] = I2C_ReceiveByte(si2c);if (i < Size - 1)I2C_Ack(si2c);elseI2C_Nack(si2c);}I2C_Stop(si2c);return true;
}bool Soft_I2C_Mem_Write(Soft_I2C_Handle *si2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size)
{I2C_Start(si2c); // 假設啟動信號總是成功if(!I2C_TransmitByte( si2c, DevAddress | 0x00 ) ) return false;// 寫模式//向目標設備發送內存地址if( !I2C_TransmitMemoryAddress(si2c, MemAddress, MemAddSize) ) return false;// 發送數據for (uint16_t i = 0; i < Size; i++) {if(!I2C_TransmitByte( si2c, pData[i] ) ) return false;}I2C_Stop(si2c);return true;
}

代碼使用說明

1、根據自己的單片機修改相關內容
2、創造句柄并配置引腳(和硬件I2C類似)
3、進行讀寫操作(和硬件I2C類似)

以溫濕度傳感器AHT20為例
aht20.h

#ifndef __DHT20_H__
#define __DHT20_H__#ifdef __cplusplus
extern "C" {
#endif#include "main.h"
#include "soft_I2C.h"// 初始化AHT20
void AHT20_Init();// 獲取溫度和濕度
void AHT20_Read(float *Temperature, float *Humidity);#ifdef __cplusplus
}
#endif#endif

aht20.c

#include "aht20.h"#define AHT20_ADDRESS 0x70uint8_t readBuffer[6] = {0};Soft_I2C_Handle AHT20_I2C;/*** @brief  初始化AHT20*/
void AHT20_Init()
{Soft_I2C_Config(&AHT20_I2C, AHT20_SCL_GPIO_Port, AHT20_SCL_Pin, AHT20_SDA_GPIO_Port, AHT20_SDA_Pin);uint8_t readBuffer;HAL_Delay(40);Soft_I2C_Master_Receive(&AHT20_I2C, AHT20_ADDRESS, &readBuffer, 1);if ((readBuffer & 0x08) == 0x00){uint8_t sendBuffer[3] = {0xBE, 0x08, 0x00};Soft_I2C_Master_Transmit(&AHT20_I2C, AHT20_ADDRESS, sendBuffer, 3);}
}/*** @brief  獲取溫度和濕度* @param  Temperature: 存儲獲取到的溫度* @param  Humidity: 存儲獲取到的濕度*/
void AHT20_Read(float *Temperature, float *Humidity)
{uint8_t sendBuffer[3] = {0xAC, 0x33, 0x00};uint8_t readBuffer[6] = {0};Soft_I2C_Master_Transmit(&AHT20_I2C, AHT20_ADDRESS, sendBuffer, 3);HAL_Delay(75);Soft_I2C_Master_Receive(&AHT20_I2C, AHT20_ADDRESS, readBuffer, 6);if ((readBuffer[0] & 0x80) == 0x00){uint32_t data = 0;data = ((uint32_t)readBuffer[3] >> 4) + ((uint32_t)readBuffer[2] << 4) + ((uint32_t)readBuffer[1] << 12);*Humidity = data * 100.0f / (1 << 20);data = (((uint32_t)readBuffer[3] & 0x0F) << 16) + ((uint32_t)readBuffer[4] << 8) + (uint32_t)readBuffer[5];*Temperature = data * 200.0f / (1 << 20) - 50;}
}

參考資料

https://blog.csdn.net/zhangduang_KHKW/article/details/121953275
https://baike.baidu.com/item/I2C%E6%80%BB%E7%BA%BF/918424

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/81612.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/81612.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/81612.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++性能測試工具——Vtune的使用

一、Intel Vtune的安裝 在前面初步認識了一下幾個性能的測試工具&#xff0c;本篇重點介紹一下Intel VTune Profiler&#xff0c;VTune是一個強大的性能分析工具&#xff0c;它屬于Intel oneAPI工具包中工具的一種。VTune的安裝只介紹在Linux平臺下的場景&#xff08;Windows安…

互聯網大廠Java求職面試:優惠券服務架構設計與AI增強實踐-6

互聯網大廠Java求職面試&#xff1a;優惠券服務架構設計與AI增強實踐-6 場景設定&#xff1a;技術總監張總坐在會議室里&#xff0c;鄭薪苦帶著自信的微笑走了進來。今天他們要圍繞優惠券服務的架構設計及如何結合AI進行增強展開討論。 第一輪面試&#xff1a;基礎架構設計 …

nginx模塊使用、過濾器模塊以及handler模塊

一、如何使用nginx的模塊 1.ngx_code.c: #include "ngx_config.h" #include "ngx_conf_file.h" #include "nginx.h" #include "ngx_core.h" #include "ngx_string.h" #include "ngx_palloc.h" #include "n…

【Odoo】Pycharm導入運行Odoo15

【Odoo】Pycharm導入運行Odoo15 前置準備1. Odoo-15項目下載解壓2. PsrtgreSQL數據庫 項目導入運行1. 項目導入2. 設置項目內虛擬環境3. 下載項目中依賴4. 修改配置文件odoo.conf 運行Pycharm快捷運行 前置準備 1. Odoo-15項目下載解壓 將下載好的項目解壓到開發目錄下 2. …

網絡安全-等級保護(等保) 2-5 GB/T 25070—2019《信息安全技術 網絡安全等級保護安全設計技術要求》-2019-05-10發布【現行】

################################################################################ GB/T 22239-2019 《信息安全技術 網絡安全等級保護基礎要求》包含安全物理環境、安全通信網絡、安全區域邊界、安全計算環境、安全管理中心、安全管理制度、安全管理機構、安全管理人員、安…

【SpringBoot】??整合飛書群機器人發送消息

&#x1f4a5;&#x1f4a5;????歡迎閱讀本文章????&#x1f4a5;&#x1f4a5; &#x1f3c6;本篇文章閱讀大約耗時3分鐘。 ??motto&#xff1a;不積跬步、無以千里 &#x1f4cb;&#x1f4cb;&#x1f4cb;本文目錄如下&#xff1a;&#x1f381;&#x1f381;&am…

我的多條件查詢

背景&#xff1a;2個表&#xff0c;是一對多的關系&#xff0c;一個實時視頻幀可以出現多個檢測結果 要求&#xff0c;可以根據&#xff0c;ids&#xff0c;起始時間&#xff0c;識別出的鳥的種類&#xff0c;來進行刪除。 出現的問題&#xff0c; 一致性沒有實現&#xff1a…

關于網站提交搜索引擎

發布于Eucalyptus-blog 一、前言 將網站提交給搜索引擎是為了讓搜索引擎更早地了解、索引和顯示您的網站內容。以下是一些提交網站給搜索引擎的理由&#xff1a; 提高可見性&#xff1a;通過將您的網站提交給搜索引擎&#xff0c;可以提高您的網站在搜索結果中出現的機會。當用…

【Oracle專欄】擴容導致數據文件 dbf 丟失,實操

Oracle相關文檔,希望互相學習,共同進步 風123456789~-CSDN博客 1.背景 同事檢查擴容情況,發現客戶擴容后數據盤后,盤中原有文件丟失,再檢查發現數據庫沒有啟動。通過檢查發現數據盤中丟失的是oracle的 dbf 表空間文件。數據庫無法啟動。 檢查情況:1)沒有rman備份 …

負載均衡—會話保持技術詳解

一、會話保持的定義 會話保持&#xff08;Session Persistence&#xff09;是一種負載均衡策略&#xff0c;其核心機制是確保來自同一客戶端的連續請求&#xff0c;在特定周期內被定向到同一臺后端服務器進行處理。這種機制通過記錄和識別客戶端的特定標識信息&#xff0c;打破…

CSRF攻擊 + 觀測iframe加載時間利用時間響應差異側信道攻擊 -- reelfreaks DefCamp 2024

參考: https://0x90r00t.com/2024/09/30/3708/ 題目信息 有些事情最好還是保持低調。當然&#xff0c;除非你是個真正的怪胎。 注意&#xff1a;該網站通過HTTPS提供服務 標志格式&#xff1a;DCTF&#xff5b;&#xff5d;題目實現了一個類似視頻網站的東西 在其提供的數據庫中…

JS逆向-某易云音樂下載器

文章目錄 介紹下載鏈接Robots文件搜索功能JS逆向**函數a&#xff1a;生成隨機字符串****函數b&#xff1a;AES-CBC加密****函數c&#xff1a;RSA公鑰加密** 歌曲下載總結 介紹 在某易云音樂中&#xff0c;很多歌曲聽是免費的&#xff0c;但下載需要VIP&#xff0c;此程序旨在“…

黑馬k8s(十)

1.Pod生命周期-鉤子函數 2.Pod生命周期-容器探測 因為沒有hello.txt文件 查看詳情&#xff1a; 修改為查看命令&#xff1a; 查看一下詳情&#xff1a; 因為只有一個80端口&#xff0c;沒有8080&#xff0c;所以會重啟 查看詳情&#xff1a; 修改成80&#xff1a; 因為沒有…

每日算法刷題Day9 5.17:leetcode定長滑動窗口3道題,用時1h

9. 1652.拆炸彈(簡單&#xff0c;學習) 1652. 拆炸彈 - 力扣&#xff08;LeetCode&#xff09; 思想 為了獲得正確的密碼&#xff0c;你需要替換掉每一個數字。所有數字會 同時 被替換。 如果 k > 0 &#xff0c;將第 i 個數字用 接下來 k 個數字之和替換。如果 k < 0…

Java IO及Netty框架學習小結

Netty netty官網: Netty 什么是Netty&#xff1f; Netty 是 一個異步事件驅動的網絡應用程序框架&#xff0c;用于快速開發可維護的高性能協議服務器和客戶端。Netty 是一個 NIO 客戶端服務器框架&#xff0c;可以快速輕松地開發網絡應用程序&#xff08;例如協議服務器和客…

計算機網絡筆記(二十七)——4.9多協議標簽交換MPLS

4.9.1MPLS的工作原理 一、MPLS基本工作原理 MPLS&#xff08;Multiprotocol Label Switching&#xff09;是一種介于數據鏈路層和網絡層之間的轉發技術&#xff0c;通過固定長度的標簽進行高速數據轉發。其核心特點是通過預建立的標簽交換路徑&#xff08;Label Switching Pa…

AI 賦能 Copula 建模:大語言模型驅動的相關性分析革新

技術點目錄 R及Python語言及相關性研究初步二元Copula理論與實踐&#xff08;一&#xff09;二元Copula理論與實踐&#xff08;二&#xff09;【R語言為主】Copula函數的統計檢驗與選擇【R語言為主】高維數據與Vine Copula 【R語言】正則Vine Copula&#xff08;一&#xff09;…

【洛谷P3386】二分圖最大匹配之Kuhn算法/匈牙利算法:直觀理解

題目&#xff1a;洛谷P3386 【模板】二分圖最大匹配 &#x1f955; 匈牙利算法本來是針對帶權圖最大匹配的&#xff0c;這里由于題目只是求最大匹配的邊數&#xff0c;所以我們也只考慮無權的情況。 &#x1f680; 本文旨在服務于看了別的關于匈牙利算法的文章但不甚理解的童…

【數據結構】二分查找(返回插入點)5.14

二分查找基礎版 package 二分查找; public class BinarySearch { public static void main(String[] args) { // TODO Auto-generated method stub } public static int binarySearchBasic(int[] a,int target) { int i0,ja.length-1; //設置指針初值 while…

Ubuntu 命令

Ubuntu 命令速查表? ?分類??命令??功能描述??示例/常用選項????文件與目錄?ls列出目錄內容ls -a&#xff08;顯示隱藏文件&#xff09;; ls -lh&#xff08;詳細列表易讀大小&#xff09; cd切換目錄cd ~&#xff08;主目錄&#xff09;; cd ..&#xff08;上級…