STM32_IIC

1、IIC簡介

? ? ? ? I2C,即Inter IC Bus。是由Philips公司開發的一種串行通用數據總線,主要用于近距離、低速的芯片之間的通信;有兩根通信線:SCL(Serial Clock)用于通信雙方時鐘的同步、SDA(Serial Data)用于收發數據;具有同步,半雙工,帶數據應答,支持總線掛載多設備(一主多從、多主多從)等特點。

? ? ? ? IIC總線是一種多主機總線,連接在IIC總線上的器件分為主機和從機,主機有權發起和結束一次通信,而從機只能被主機呼叫;當總線上有多個主機同時啟用總線時,IIC也具備沖突檢測和仲裁的功能來防止錯誤產生;每個連接到IIC總線上的器件都有一個唯一的地址(一般是7bit),且每個器件都可以作為主機也可以作為從機(同一時刻只能有一個主機),總線上的器件增加和刪除不影響其它器件正常工作;IIC總線在通信時,總線上發送數據的器件為發送器,接收數據的器件為接收器。

? ? ? ? 所有I2C設備的SCL連在一起,SDA連在一起;設備的SCL和SDA均要配置成開漏輸出模式;SCL和SDA各添加一個上拉電阻,阻值一般為4.7KΩ左右。

? ? ? ? 在STM32內部集成了硬件I2C收發電路,可以由硬件自動執行時鐘生成、起始終止條件生成、應答位收發、數據收發等功能,減輕CPU的負擔;支持多主機模型;支持7位/10位地址模式;支持不同的通訊速度,標準速度(高達100 kHz),快速(高達400 kHz);支持DMA;兼容SMBus協議。

????????STM32F103C8T6 硬件I2C資源:I2C1、I2C2

? ? ? ? 對于串口這樣的異步時序來說,軟件實現非常麻煩,硬件實現非常簡單,所以串口的實現基本全都倒向硬件了;而對IIC這樣的同步時序來說,軟件實現反而簡單靈活,硬件實現,相比之下,不能完全讓人省心,所以IIC的實現,軟件模擬的情況還是比較多的。

? ? ? ? 考慮到硬件IIC也有很多獨有的優勢,比如執行效率比較高,可以節省軟件資源,功能比較強大,可以實現完整的多主機通信模型,時序波形規整,通信速率快等,所以硬件IIC也是有相應的應用場景的。

2、IIC結構圖

????????以下結構圖基于STM32F103xxx

?????????這里的數據收發的核心部分是數據寄存器和數據移位寄存器,當我們需要發送數據時,可以把一個字節的數據寫到數據寄存器DR,當移位寄存器沒有數據移位時,這個數據寄存器的值就是進一步轉到移位寄存器這里,在移位的過程中,我們就可以直接把下一個數據放在數據寄存器里等著了,一旦數據發送完成,下一個數據就可以無縫連接,繼續發送。當數據由數據寄存器轉到移位寄存器時,就會置狀態寄存器的值TXE位為1,表示發送寄存器為空。

? ? ? ? 在接收時,也是這一路,輸入的數據,一位一位的從引腳移入到移位寄存器里,當一個字節的數據收齊之后,數據就整體從移位寄存器轉到數據寄存器,同時置標志位RXNE,表示接收寄存器非空,這時就可以把數據從數據寄存器讀出來了。

? ? ? ? 基本框圖

3、IIC時序

3.1?IIC時序基本單元

????????起始條件:SCL高電平期間,SDA從高電平切換到低電平

????????終止條件:SCL高電平期間,SDA從低電平切換到高電平

? ? ? ? 發送一個字節:SCL低電平期間,主機將數據位依次放到SDA線上(高位先行),然后釋放SCL,從機將在SCL高電平期間讀取數據位,所以SCL高電平期間SDA不允許有數據變化,依次循環上述過程8次,即可發送一個字節?。

? ? ? ? 接收一個字節:SCL低電平期間,從機將數據位依次放到SDA線上(高位先行),然后釋放SCL,主機將在SCL高電平期間讀取數據位,所以SCL高電平期間SDA不允許有數據變化,依次循環上述過程8次,即可接收一個字節(主機在接收之前,需要釋放SDA)?

????????發送應答:主機在接收完一個字節之后,在下一個時鐘發送一位數據,數據0表示應答,數據1表示非應答

????????接收應答:主機在發送完一個字節之后,在下一個時鐘接收一位數據,判斷從機是否應答,數據0表示應答,數據1表示非應答(主機在接收之前,需要釋放SDA)?

3.2?IIC時序

3.2.1?指定地址寫

? ? ? ? 對于指定設備(Slave Address),在指定地址(Reg Address)下,寫入指定數據(Data)

? ? ? ? 這里這個指定設備,通過從機地址來確定,這里這個指定地址就是某個設備內部的寄存器地址。

3.2.2? 當前地址讀

? ? ? ? 對于指定設備(Slave Address),在當前地址指針指示的地址下,讀取從機數據(Data)

? ? ? ? 在這個時序圖中,主機發送第一個字節,指定讀之后,第2個字節讀寫的方向就要反過來了,控制權交給從機,由從機來發送數據,這時主機無法去指定是由從機哪個寄存器發出的數據,那么這里這個當前地址指針指示的地址就很重要了。在從機中,所有的寄存器都被分配到了一個線性區域中,并且會有一個單獨的指針變量指示著其中一個寄存器,這個指針上電一般默認0地址,并且每寫入和讀出一個字節后,這個指針就會自動自增一次,移動到下一個位置,那么在調用當前地址讀的時序時,主機沒有指定要讀哪個地址,從機就會返回當前指針指向的寄存器的值。

3.2.3?指定地址讀

? ? ? ? 對于指定設備(Slave Address),在指定地址(Reg Address)下,讀取從機數據(Data)

? ? ? ? 這里先指定從機地址是1101000,讀寫標志位是0,代表我要進行寫的操作。經常從機應答之后,再發送一個字節,第二個字節用來指定地址,這個數據就寫入到了從機的地址指針中了,也就是從機接受到這個數據之后,他的寄存器指針就指向了0x19這個位置,之后再重復一個起始條件,因為指定讀寫標志位只能是跟著起始條件的第一個字節,如果想要切換讀寫方向,只能再來個起始條件,然后起始條件后,重新尋址并且指定讀寫標志位,此時讀寫標志位是1,代表我要開始讀了,這時候接收到的就是0x19下的數據。

? ? ? ? 寫入的地址會存在地址指針里面,所以這個地址并不會因為時序的停止而消失。

4、操作流程

4.1?主機發送

? ? ? ? 指定地址寫:首先初始化之后,總線默認空閑狀態,STM32默認是從模式,為了產生一個起始條件,STM32需要寫入控制寄存器(這個要看一下手冊的寄存器描述),之后STM32由從模式轉為主模式,控制完硬件電路之后,要檢查標志位,來看看硬件有沒有達到我們想要的狀態,在這里起始條件之后會發生EV5事件,這個EV5事件就可以把它當成標志位(這里使用EV幾事件,而不寫具體標志位,是因為有的事件會產生多個標志位,這里的EV幾事件就是包含了多個標志位的大標志位,在庫函數中也會有對應),檢查到起始條件已發送的情況下就可以發送一個字節的從機地址了,從機地址需要寫到數據寄存器DR中,寫入DR后,硬件電路會把這個字節發送到移位寄存器中,再把這一個字節發送到IIC總線上,之后硬件會自動接收應答并判斷,如果沒有應答,硬件會置應答失敗的標志位,然后這個標志位可以申請中斷來提醒我們,在尋址完成之后,會發生EV6事件(代表主模式下地址發送結束),EV6事件結束之后是EV8_1事件(TXE標志位=1,移位寄存器空,數據寄存器空),這時需要我們寫入數據寄存器DR進行數據發送了,一旦寫入數據寄存器之后,因為移位寄存器也是空,所以DR會立刻轉到移位寄存器進行發送,這時就是EV8事件(移位寄存器非空,數據寄存器空),這時就是移位寄存器正在發數據的狀態,所以流程這里,數據1的時序就發生了,之后應該是寫入了下一個數據,數據2此刻應該被寫入到數據寄存器里等著了,然后接收應答位之后,數據2就轉入移位寄存器進行發送,此時的狀態是移位寄存器非空,數據寄存器空,所以這是EV8事件又發生了,之后重復該過程,一旦我們檢測要EEV8事件,就可以寫入下一個數據了,最后當我們想要發送的數據寫完之后,這時就沒有新的數據寫入數據寄存器了,當移位寄存器當前的數據移位完成時,此時就是移位寄存器空,數據寄存器也空的狀態,這個事件就是這里的EV8_2事件,當檢測到EV8_2時,就可以產生終止條件了,產生終止條件在控制寄存器中有相應的位可以控制,到這里,一個完整的時序就發送完成了。

4.2?主機接收?

? ? ? ? 從七位主接收來看,起始,從機地址+讀,接收應答,然后就是,接收數據,發送應答,最后一個數據給非應答,之后終止。從這個時序看,這是當前地址讀的一個時序。

5、示例代碼

5.1?軟件讀寫IIC

#include "stm32f10x.h"                  // Device header
#include "Delay.h"     //#define SCL_PORT		GPIOB
//#define SCL_PIN		GPIO_Pin_10//對端口和引腳的封裝,方便后續修改和移植
void MyI2C_W_SCL(uint8_t BitValue)
{GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);//I2C時序可以稍微慢一點,但是如果快了,那就要看一下手冊對時序時間的要求Delay_us(10);}void MyI2C_W_SDA(uint8_t BitValue)
{GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);//I2C時序可以稍微慢一點,但是如果快了,那就要看一下手冊對時序時間的要求Delay_us(10);}uint8_t MyI2C_R_SDA(void)
{uint8_t BitValue;BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);Delay_us(10);return BitValue;
}void MyI2C_Init(void)
{//軟件讀取I2C只要gpio的庫函數就可以了,I2C的庫函數就不用看了//任務一,將SCL和SDA都初始化為開漏輸出模式//任務二,將SCL和SDA都置高電平RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//配置端口//先定義一個結構體變量GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;	//開漏輸出,開漏輸出模式仍然可以輸入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//速度50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);//釋放總線,SCL和SDA處于高電平,此時I2C總線處于空閑狀態GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);}void MyI2C_Start(void)
{//根據I2C時序要求,這里兼顧了開始時序和Sr期間時序MyI2C_W_SCL(1);MyI2C_W_SDA(1);MyI2C_W_SDA(0);MyI2C_W_SCL(0);
}	void MyI2C_Stop(void)
{MyI2C_W_SDA(0);MyI2C_W_SCL(1);MyI2C_W_SDA(1);
}void MyI2C_SendByte(uint8_t Byte)
{
//	MyI2C_W_SDA(Byte & 0x80);	//取出數據的最高位,SDA是高位先行
//	//釋放SCL,讀走放在SDA的數據
//	MyI2C_W_SCL(1);
//	//再拉低SCL,就可以放下一位數據了
//	MyI2C_W_SCL(0);uint8_t i;for (i = 0; i < 8; i ++){MyI2C_W_SDA(Byte & (0x80 >> i));	//0x80 >> i,表示0x80右移i位MyI2C_W_SCL(1);MyI2C_W_SCL(0);}
}uint8_t MyI2C_ReceiveByte(void)
{uint8_t i, Byte = 0x00;//主機釋放SDA,從機把數據放到SDAMyI2C_W_SDA(1);for (i = 0; i < 8; i ++){//主機釋放SCL,SCL高電平,主機就能讀取數據了MyI2C_W_SCL(1);if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}//再次拉低SCL,這時從機就會把數據放在SDA上MyI2C_W_SCL(0);}return Byte;}void MyI2C_SendAck(uint8_t AckBit)
{//函數進來時,SCL低電平,主機把AckBit放到SDA上MyI2C_W_SDA(AckBit);	//SCL高電平,從機讀取應答MyI2C_W_SCL(1);//SCL低電平,進入下一個時序單元MyI2C_W_SCL(0);
}uint8_t MyI2C_ReceiveAck(void)
{uint8_t AckBit;//函數進來時,SCl低電平//主機釋放SDA,防止從機干擾,同時從機應答位放到SDAMyI2C_W_SDA(1);//SCL高電平,主機讀取應答位MyI2C_W_SCL(1);AckBit = MyI2C_R_SDA();//SCL低電平,進入下一個時序單元MyI2C_W_SCL(0);return AckBit;}

5.2?硬件讀寫IIC

//MyI2C_Init();//用硬件來配置I2C外設,對I2C2外設進行初始化,來替換之前用軟件實現的MyI2C_Init();	//第一步,開啟I2C外設和對應GPIO口的時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//第二步,把I2C外設對應的GPIO口初始化為復用開漏模式GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;	//復用開漏輸出,開漏是I2C硬件要求,復用就是GPIO的控制權要交給硬件外設GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//速度50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);//第三步,使用結構體,對整個I2C進行配置I2C_InitTypeDef I2C_InitStructure;I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;	//I2C的模式,這里選擇是I2CI2C_InitStructure.I2C_ClockSpeed = 50000;	//配置SCL的時鐘頻率,數值越大,SCL頻率越高,數據傳輸就越快,這里寫的是50kHzI2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;	//時鐘占空比,只有在時鐘頻率大于100kHz,也就是進入到快速狀態時才有用,在小雨100kHz的標準速度下,占空比是標準的1:1I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;	//應答位配置,這里給enable,默認是給應答的I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;	//這里是指定STM32作為從機,可以響應幾位的地址,這里選擇7位地址I2C_InitStructure.I2C_OwnAddress1 = 0x00;	//自身地址1,這個也是stm32作為從機使用的,用于指定stm32的自身地址,方便別的主機呼叫它,這里暫時不需要做從機被別人使喚,隨便給一個,只要不和總線上其它設備的地址重復就可以了I2C_Init(I2C2, &I2C_InitStructure);//第四步,I2C_Cmd,使能I2CI2C_Cmd(I2C2, ENABLE);
//封裝指定地址寫和指定地址讀的時序
//指定地址寫寄存器
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
//	MyI2C_Start();
//	MyI2C_SendByte(MPU6050_ADDRESS);	//從機地址+讀寫位
//	MyI2C_ReceiveAck();
//	//發送指定寄存器地址
//	MyI2C_SendByte(RegAddress);
//	MyI2C_ReceiveAck();
//	//發送指定要寫入指定寄存器地址下的數據
//	MyI2C_SendByte(Data);
//	MyI2C_ReceiveAck();
//	//終止時序
//	MyI2C_Stop();uint32_t Timeout;//控制外設電路,實現指定地址寫的時序,來替換上面的WriteRegI2C_GenerateSTART(I2C2, ENABLE);	//生成起始條件//對于非阻塞的程序,在函數結束之后,都要等待相應的標志位,來確保這個函數的操作執行到位了//對照PPT流程圖,等待EV5的到來,stm32默認為從機,發送起始條件后變為主機Timeout = 10000;while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)	//監測EV5事件是否發生了//在程序中如果while死循環等待用多了,一旦總線出問題了,就很容易造成整個程序卡死,還要設計一個超時退出的機制{Timeout --;if (Timeout == 0){break;	//使用break跳出這個循環,使用return跳出整個函數//在實際項目中,如果想讓代碼更加完善,這里不能只是簡單的break了//這里還應該做一些相應的錯誤處理操作,比如說打印錯誤日志、進行系統復位//或者說,如果項目設計危險的機械結構,就要評估一下,是不是應該進行緊急停機的操作}}
//	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);	//這一句就等同與上面的等待事件和超時退出的結合I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);	//發送從機地址,第三個參數是方向,也就是從機地址的最低位,讀寫位//在這個庫函數中,發送數據都自帶了接收應答的過程,同樣,接收數據也自帶了發送應答的過程,如果應答錯誤,硬件會通過中斷和標志位來提示我們,所以這里發送地址后,應答位就不需要處理了//等待EV6事件while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);//寫入DR,發送數據I2C_SendData(I2C2, RegAddress);//等待EV8事件while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);//發送數據I2C_SendData(I2C2, Data);//等待事件,這里這個是最后一個字節,要等待EV8_2事件while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);I2C_GenerateSTOP(I2C2, ENABLE);
}//指定地址讀
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data;
//	MyI2C_Start();
//	MyI2C_SendByte(MPU6050_ADDRESS);	//從機地址+讀寫位
//	MyI2C_ReceiveAck();
//	//發送指定寄存器地址
//	MyI2C_SendByte(RegAddress);
//	MyI2C_ReceiveAck();
//	
//	//轉入讀的時序,就必須重新指定讀寫位,就必須重新起始
//	MyI2C_Start();
//	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);		//原從機地址,讀寫位為1
//	MyI2C_ReceiveAck();		//接收應答后,總線控制權就正式交給從機了
//	Data = MyI2C_ReceiveByte();
//	//主機接收后,要給從機發送一個應答
//	//參數給0,就是給從機應答,給1,就是不給從機應答;想繼續讀多個字節,那就要給應答,從機收到應答后就會繼續發送數據
//	MyI2C_SendAck(1);
//	MyI2C_Stop();//控制外設電路,來實現指定地址讀的時序,來替換上面的ReadRegI2C_GenerateSTART(I2C2, ENABLE);	//生成起始條件while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);	//監測EV5事件是否發生了//在程序中如果while死循環等待用多了,一旦總線出問題了,就很容易造成整個程序卡死,還要設計一個超時退出的機制I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);	//發送從機地址,第三個參數是方向,也就是從機地址的最低位,讀寫位while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);//寫入DR,發送數據I2C_SendData(I2C2, RegAddress);while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);I2C_GenerateSTART(I2C2, ENABLE);	//重復生成起始條件while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);	//監測EV5事件是否發生了I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Receiver);	//第三個參數改為Receiver之后,函數內部就會自動把MPU6050_ADDRESS這個地址的最低位置1了,就不需要手動來改了while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS);	//在接收最后一個字節之前,也就是EV7_1事件那里,需要提前把ACK置0,STOP置1,如果只需要讀取一個字節,那在EV6事件之后就要立刻ACK置0,STOP置1,要是設置晚了,時序上就會多一個字節出來I2C_AcknowledgeConfig(I2C2, DISABLE);I2C_GenerateSTOP(I2C2, ENABLE);//等待EV7事件,等EV7事件產生后,一個字節的數據就已經在DR里面了,我們讀取DR即可拿出這一個字節while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);Data = I2C_ReceiveData(I2C2);//ack再次置1,我們的想法是,默認狀態下ACK就是1,給從機應答,在接收最后一個字節之前,臨時把ACK置0,給非應答。//所以在接收函數的最后,要回復默認的ACk = 1,這個流程是為了方便指定地址收多個字節I2C_AcknowledgeConfig(I2C2, ENABLE);return Data;
}

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

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

相關文章

JVM之【執行引擎】

執行引擎 執行引擎是JVM的核心組件之一&#xff0c;它負責將Java字節碼文件轉換為機器指令并執行。這一過程涉及多個組成部分&#xff0c;各部分協同工作來完成字節碼到機器指令的轉換和執行。以下是執行引擎的主要組成部分及其作用&#xff1a; 1. 解釋器&#xff08;Interp…

vue.js框架快速入門

Vue.js是一個漸進式JavaScript框架&#xff0c;用于構建用戶界面和單頁應用程序。以下是Vue.js快速入門的基本步驟和概念&#xff1a; 1. 環境準備 確保你的計算機上安裝了Node.js&#xff0c;它包括npm&#xff08;Node Package Manager&#xff09;&#xff0c;用于管理項目…

友善RK3399v2平臺利用rkmpp實現硬件編解碼加速

測試VPU 編譯mpp sudo apt update sudo apt install gcc g cmake make cd ~ git clone https://github.com/rockchip-linux/mpp.git cd mpp/build/linux/aarch64/ sed -i s/aarch64-linux-gnu-gcc/gcc/g ./arm.linux.cross.cmake sed -i s/aarch64-linux-gnu-g/g/g ./arm.lin…

如何學習ai agent?

如何學習Agent&#xff0c;推薦閱讀《動手做AI Agent》這本書。 推薦理由&#xff1a; 1&#xff1a;一本書能夠全方位了解并探索Agent的奧秘&#xff01; &#xff08;1&#xff09;Agent的發展進程。 &#xff08;2&#xff09;可以幫我們做哪些事&#xff1a;自動辦公&am…

TypeScript 中的迭代器和生成器

1. 迭代器 迭代器是一種對象&#xff0c;它提供了一種統一的方式來訪問集合中的元素&#xff0c;而不暴露集合的內部結構。在 TypeScript 中&#xff0c;迭代器通過實現 Iterator 接口來定義。 interface Iterator<T> {next(): IteratorResult<T>; }interface It…

Liunx登錄時相關bash配置文件(登錄腳本)

profile類的文件&#xff1a;設定環境變量&#xff0c;運行命令或腳本 bashrc類的文件&#xff1a;定義命令別名 全局配置&#xff1a; /etc/profile /etc/profile.d/*.sh /etc/bashrc 個人配置文件: ~/.bash_profile ~/.bashrc 用戶登錄時加載bash配置文件的過程&#xff0c;…

碼隨想錄算法訓練營第二十四天| 77. 組合

77. 組合 - 力扣&#xff08;LeetCode&#xff09; class Solution {ArrayList<Integer> path new ArrayList<>();ArrayList<List<Integer>> result new ArrayList<>();public List<List<Integer>> combine(int n, int k) {if(n &…

升級Jenkins從2.263.3到2.440.2

升級Jenkins從2.263.3到2.440.2 ###任何一次升級前&#xff0c;先做整體備份&#xff0c;同時最好對plugins目錄和config.xml單獨備份。 ###對于任何一次插件安裝&#xff0c;務必安裝前先備份當前的plugins目錄&#xff0c;這是血的教訓。升級過程 1、 升級2.263.3到2.263.4…

15-通過JS代碼處理窗口滾動條

selenium并不是萬能的&#xff0c;頁面上有些操作無法實現時&#xff0c;就需要借助JS代碼來完成了。selenium提供了一個方法&#xff1a;execute_script()&#xff0c;可以執行JS腳本代碼。 比如&#xff1a;當頁面上的元素超過一屏后&#xff0c;想操作屏幕下方的元素&#x…

MyBatis查詢功能

MyBatis的各種查詢功能 1、若查詢出的數據只有一條 &#xff08;1)可以通過實體類對象或者集合接收 (2)可以通過List集合接收 (3&#xff09;可以通過map集合接收 結果&#xff1a;{password123456, sex女, id8, age22, email1234qq.com, usernameadmin4} 2、若查詢出來的數據有…

[leetcode hot 150]第一百零八題,將有序數組轉換為二叉搜索樹

題目&#xff1a;給你一個整數數組 nums &#xff0c;其中元素已經按 升序 排列&#xff0c;請你將其轉換為一棵 平衡二叉搜索樹。 給定一個有序的整數數組,我們需要構建一棵平衡的二叉搜索樹。平衡二叉樹是指任意一個節點的左右子樹的高度差不超過1。 由于給定的數組是有序的…

阿里云計算學習筆記(一)

運維管理 運維管理&#xff08;Operation and Maintenance Management, 簡稱O&M管理&#xff09;是指通過科學的管理方法和技術手段&#xff0c;對IT系統和基礎設施進行監控、維護、優化和保障&#xff0c;以確保系統的高可用性、穩定性、安全性和性能。運維管理涵蓋了硬件…

Prime1 - 提權的另一種解法,徹底搞懂OpenSSL解密滲透提權,超強思路版。

提權枚舉 現在我們直接從低權限用戶開始&#xff1b;我們先按照提權步驟&#xff0c;簡單的系統枚舉 雖然我們知道可以利用系統版本低進行內核提權&#xff0c;內核提權雖然比較快比較方便&#xff0c;但也比較暴力&#xff0c;缺點非常明顯&#xff1b;很容易導致系統服務中…

【云原生】Kubernetes----POD控制器

目錄 引言 一、Pod控制器概述 二、Pod控制器的種類 &#xff08;一&#xff09;ReplicaSet &#xff08;二&#xff09;Deployment &#xff08;三&#xff09;StatefulSet &#xff08;四&#xff09;DaemonSet &#xff08;五&#xff09;Job 三、使用POD控制器 &a…

【Seafile】Seafile容器版文件刪除后存儲空間不釋放問題解決

Seafile是一款非常優秀的網盤系統&#xff0c;我們可以根據官方文檔&#xff0c;在本地虛擬機研究Seafile免費版的安裝和使用&#xff0c;安裝建議采用使用docker容器的方式。 不過在使用過程中&#xff0c;剛接觸的小伙伴可能會遇到這樣的問題&#xff1a; 刪除網盤里面的文…

數據賦能(106)——方法論:描述模式與AI——批量處理

在一系列相似的主題內容進行編寫時&#xff0c;可以采用批處理的方式。主要步驟如下&#xff1a; 1、確定主題內容模式。如&#xff1a;各個主題的概述中&#xff0c;包括如下內容模式項目&#xff1a;工作主要目的、工作重要性、工作核心內容、工作本質 2、確定模式的各項內…

C++設計模式-狀態模式

文章目錄 28. 狀態模式 運行在VS2022&#xff0c;x86&#xff0c;Debug下。 28. 狀態模式 狀態模式讓一個對象的行為隨著內部狀態的改變而改變&#xff0c;而該對象也像換了類一樣。應用&#xff1a;如在游戲開發中&#xff0c;游戲有不同場景&#xff0c;如主菜單、開始、戰斗…

在leafet上畫圓、多邊形、線、矩形

在leaflet上畫圓、多邊形、線、矩形 <template><div id"map" class"map"></div> </template><script> import L from leaflet; export default {data () {return {myGroup: ,};},mounted () {this.initMaps()this.huizhiro…

Houdini的PythonScript基本使用

前言 Houdini內置了Python腳本和相應的編輯器, 很多時候想靈活的制作各種Houdini工具, 基本是必須用到 Python。Houdini官方的python提供了非常完善的接口, 比如可以創建各種節點&#xff0c;連接各種節點&#xff0c;遍歷節點各種數據&#xff0c;遍歷節點參數等等。 Houdin…

Spring中Bean的生命周期詳解

目錄 Bean的定義和作用Bean的生命周期概述Bean實例化階段依賴注入階段初始化階段Bean的使用銷毀階段完整的Bean生命周期流程示例代碼總結 Bean的定義和作用 在Spring框架中&#xff0c;Bean是指由Spring IoC容器管理的Java對象。Bean是構建Spring應用程序的基本單元&#xf…