主頁 > 作業系統 > STM32(1):點亮LED(上)

STM32(1):點亮LED(上)

2022-01-04 06:05:21 作業系統

本文摘自:
https://blog.csdn.net/xiashiwendao/article/details/122291583

概述

今天我們的開啟了STM32開發的第一站:點亮LED,今天的內容包含了很多基礎的知識,也有一些勸退的意味,不過,如果你能夠扛得住這波攻勢的,我覺得你高嵌入式方面真的是“風骨清奇,可造之材”,

程式總覽

typedef unsigned short     int uint16_t;

typedef unsigned           int uint32_t;
#define     __IO    volatile

#define PERIPH_BASE           ((uint32_t)0x40000000)
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)

#define GPIOC_BASE            (APB2PERIPH_BASE + 0x1000)
#define GPIOC                   (GPIOC_BASE)
#define GPIOC_CRH                           (GPIOC+0x04)
#define GPIOC_ODR                           (GPIOC+0x0C)

#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)
#define RCC_BASE              (AHBPERIPH_BASE + 0x1000)
#define RCC                     (RCC_BASE)
#define RCC_APB2ENR                     (RCC+0x18)
#define RCC_CR                              (RCC+0x00)
#define RCC_CFGR                            (RCC+0x04)

#define FLASH_R_BASE          (AHBPERIPH_BASE + 0x2000)
#define FLASH                   (FLASH_R_BASE)
#define FLASH_ACR             (FLASH+0x00)

void RCC_init(uint16_t PLL)
{
	uint32_t temp=0;  

	*((uint32_t *)RCC_CR) |= 0x00010000; 
	while(!( *((uint32_t *)RCC_CR) >>17));

	*((uint32_t *)RCC_CFGR) = 0X00000400;

	PLL -= 2;
	*((uint32_t *)RCC_CFGR) |= PLL<<18;   

	*((uint32_t *)RCC_CFGR) |= 1<<16;

	*((uint32_t *)FLASH_ACR)|=0x2;
	*((uint32_t *)RCC_CR) |= 0x01000000;
	while(!(*((uint32_t *)RCC_CR) >> 25));

	*((uint32_t *)RCC_CFGR) |= 0x00000002;
	while(temp != 0x02)
	{  
		temp = *((uint32_t *)RCC_CFGR) >> 2;
		temp &= 0x03;
	}   
}

void delay(unsigned int time)
{    
	 unsigned int i=0;  
	 while(time--)
	 {
			i=10000000;
			while(i--) ;    
	 }
}


int main(void)
{
	*((uint32_t *)RCC_APB2ENR)  |= 0x00000010;

	*((uint32_t *)GPIOC_CRH)        |= 0x00300000;
	*((uint32_t *)GPIOC_ODR)        |= 0x00002000;

	while(1)
	{
			*((uint32_t *)GPIOC_ODR)    &= ~(1<<13);
			*((uint32_t *)GPIOC_ODR)    |= 0x00000000;

			delay(3);

			*((unsigned int *)GPIOC_ODR) &= ~(1<<13);
			*((unsigned int *)GPIOC_ODR) |= 0x00002000;

			delay(1);
	}
}

分析代碼套路

不要慌,看到一堆大寫字符,符號,我們梳理一下程式結構,總體來講一般分為三個部分,以后即使我們碰到再復雜的檔案,比如同檔案參考其實也不過是這樣的三個部分:

  1. 型別定義;型別的定義決定了變數的長度;

  2. 定義宏,即定義常量,常量不好理解,通過宏來定義,給予一個有意義的宏定義,程式可理解性會更強;除此之外,如果多個地方使用同一個變數,通過使用宏定義,可以實作只修改一個地方(宏定義)即可實作所有的參考地方做修改;

  3. main函式,程式運行要走的函式;

    // 1.型別定義
    typedef unsigned short int uint16_t;
    ... ...

    // 2. 定義宏

    define __IO volatile

    define PERIPH_BASE ((uint32_t)0x40000000)

    define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)

    ... ...

    // 3. 主函式
    int main(void)
    {
    ... ...
    delay(3);
    ... ...
    }

    // 4.呼叫函式
    void delay(unsigned int time)
    {
    ... ...
    }

任何程式基本都是這三部分的延伸和拓展,
下面我們來看主函式,在研究主函式的時候,上面我們定義的宏自然就明白了;

使能APB2總線

下面是第一行代碼,這一行代碼的含義是向目標記憶體地址暫存器地址中通過與計算0x00000010;至于RCC_APB2ENR是做什么的我們放在后面來講解,首先搞清楚它的計算脈絡;
*((uint32_t *)RCC_APB2ENR) |= 0x00000010;

地址計算

首先搞清楚RCC_APB2ENR是什么東西,首先追溯一下它的define計算程序

#define PERIPH_BASE           ((uint32_t)0x40000000)
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
... ...
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)
#define RCC_BASE              (AHBPERIPH_BASE + 0x1000)
#define RCC                 	(RCC_BASE)
#define RCC_APB2ENR		(RCC+0x18)

PERIPH_BASE是總線基地址,什么是基地址?就是某個組件的起始地址,因為分配各組件的地址是一個范圍,所以有起始地址和結束地址,基地址就是指起始地址,但是并不是所有組件的起始地址都叫做基地址,只有那些組件下面還要掛在其他組件,即其他組件的地址是基于它計算出來的地址才叫做基地址;



0x40000000從哪里來的呢?翻看芯片手冊“3.3 Memory map”章節里面,這里會羅列各個STM32組件的記憶體地址映射,注意,是記憶體地址映射,并不是真正的記憶體地址,為了訪問這些組件需要構造專門為這些組件分配一定的虛擬記憶體地址空間,這些虛擬的記憶體地址并不會真正的和物理記憶體做映射,而是和指定的暫存器做映射;
表格排列的地址順序從高地址到低地址,所以需要拉倒最下面看到基地址,拖拽到表格的最下面就可以看到BUS的起始地址,即總線的基地址是0x4000 000;


file
總線上面其他組件的地址都是這個基地址偏移(offset);所謂的偏移就是指基于某個值再加上指定值;比如我們說基地址是100,某個組件偏移量是60,那么組件的(起始)地址160;
就是我們來看一下下一個APB2的總線地址,是基于總線基址偏移0x10000;

define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)




翻看Memory Map可以看到APB2總線的基址是0x4001 0000;所以我們的宏定義APB2PERIPH_BASE是PERIPH_BASE偏移0x10000就是從這個表格里面來的;


file
后面我們繼續看,AHBPERIPH_BASE,即AHB總線上面基地址,注意AHB總線上面橫跨了幾個地址范圍0x5x,0x4002x,0x4001x;而我們所要獲取的RCC的是0x4002地址段的,所以在計算基地址的時候,就不再是直接看最后一個,因為最后一個是0x4001x地址段;



我們是通過總線基址+0x20000來進行指定的,所以具體的組件的基址的計算也是靈活的,是需要看你要組件所在的地址段來進行偏移計算的;然后是RCC_BASE,也是根據RCC的起始地址0x4002 10000,所以基于AHBPERIPH_BASE(0x4002 0000)基礎上再偏移0x10000,此時得到了RCC的基址:0x4002 10000;

#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)
#define RCC_BASE              (AHBPERIPH_BASE + 0x1000)
#define RCC                   (RCC_BASE)

file

最后一個計算,是RCC的使能位,所謂的使能就是時鐘生效,因為在嵌入式系統里面為了省電,很多組件默認是不作業的,不過這個不作業不是不上電,而是不開啟時鐘,只有開啟時鐘的組件才會作業,沒有時鐘就處于休眠狀態;使能就是開啟時鐘,讓組件處于作業狀態:

#define RCC_APB2ENR		(RCC+0x18)

0x18從哪里來的呢?就是從芯片手冊的章節定義來的,這里的Address就是RCC基地址偏移0x18:
file

關于位計算

然后我們來看一下位運算“|“:

*((uint32_t *)RCC_APB2ENR)	|= 0x00000010;

在C語言里面有七種運算:

// 1.賦值運算,即將具體的值賦給一個變數:
int a = 5;
// 2.算術運算,即+-*÷四則運算:
int c = b + 5;
// 3.邏輯運算,邏輯運算的結果是true/ false,運算包括與運算(“&&”),或運算("||"),取反運算(“!"):
if(a && b){
		... ...
}
int d = c || b;
// 4.關系運算子,包括>,<.<=,>=,!=,==,關系運算的結果也是true/ false
if(a == b){
		... ...
}
// 5.三目運算
int e = a < b ? d : e;
// 6. 位運算,這個重點,也是我們做地址運算普遍采用的運算方式,
// 包括與運算&, 或運算!,異或^,左移<<,右移>>;

// 7.單目運算,++,--,~(取反操作)
for(int i = 0; i<MAX; i++){
		... ...
}

那么這里為什么采用或運算呢?首先搞清楚什么是位運算,位運算和其他運算最大區別在于其他的運算都是以資料型別為單位進行設計規則,而位運算不再是關注資料型別作為一個整體,而是基于每一個bit來設計運算規則;
然再搞清楚什么是或運算,x|y,x和y只要有一個為0(false)就是0,x和y只有都是1(true)才是1(true);


使能PC埠

代碼中要做的事情是使能APB2總線,首先是查找手冊,定位到RCC_APB2ENR;


在芯片手冊的register小節中,將會非常詳細羅列出RCC_APB2ENR這個引腳所對應暫存器的每一位的含義;我們可以把每一個引腳理解為暫存器,一個32bit的暫存器,引腳可以抽象為輸入/輸出介面,用于“存放”輸入/輸出的資料;



這里我們目標是確保設定PC為使能狀態即1,因為采用的或運算,與值為0的位置維持原來的值,而與值為1的位(IOPCEN,第4位)設定為1,于是從32位到0位(注意表示是大端表示方式,從高位到低位),依次是:0000 0000 0000 0000 0000 0000 0000 0000 0001 0000,轉化為16進制就是0x00000010;
file

關于地址型別

最后,為什么前面會有一個呢?在C語言里面變數大體有兩種分類,一種是值,一種是(記憶體)地址,比如整型2009,可以是代表值2009,也可以代表要訪問某個記憶體地址,怎么代表要訪問是這個地址呢?就是在前面添加一個“”;
其實你想沒想過當你定義個變數的時候,所謂的初始化,其實就是為這個變數和一個記憶體地址做了系結,這種系結是記錄在變數定義表的,找到了地址之后,對這個地址進行賦值;
所以,當你看到下面的代碼:

int a = 5;

其實本質是下面的形式,其中a經過初始化,將變數a和地址0x40000230(這個地址是舉例)進行系結:

*0x40000230 = 6;

配置PC13

繼續看配置GPIOC_CRH的代碼:

*((uint32_t *)GPIOC_CRH) |= 0x00300000;

什么是GPIOC_CRH?上手冊,在第9章介紹GPIO和AFIO的GPIO暫存器章節里面可以看到GPIOx_CRH,全稱是Config Register High,即高位配置暫存器,有高位就有地位,看來配置項很多,一個32bit是不夠的,所以有高位和低位兩個暫存器來記錄配置項;


file
繼續手冊下面給了GPIOx_CRH的32bit每個bit的含義,GPIOx中的x是指A,B,C,我們在STM32的板子上面都可以看到PAx,PBx,PCx的字樣(x的取值范圍就是1~16),P代表Port即埠(端子),ABC是分類;CRH描述的是PA/PB/PC的第9引腳到16引腳;我們這里是要設定PC13的相關配置;



其中CNF位配置的是該引腳是作用方向,是輸入還是輸出;MODE位則是配置輸出的最大時鐘頻率(如果是輸出的話基本可以忽略MODE了);注意,每個CNF占兩個bit位,每個MODE也是占兩個bit位;其中rw代表這個bit位是可以通過軟體來進行讀寫,如果碰到了有的位是“r”,則一般是狀態位,有硬體層面設定,軟體層面只能夠讀取:


file

配置PC13高低電平

按照這個思路,我們再來看一下GPIOC_ODR,代碼如下:

*((uint32_t *)GPIOC_ODR) |= 0x00002000;

上手冊:


file


可以看到,ODR全稱是output data register,輸出資料暫存器,暫存器資料分布如下,可以看到其中16~31位是保留位,保留位一般標記都是0:



其中通過與運算為ODR13位賦值是1(其他bit保持不變),這一步操作是一個寫操作,即設定PC13為高電平,


硬體原理圖

代碼的含義我們清楚了,都是根據芯片手冊來的配置的,那么為什么要做這些配置呢?這個就還是需要看一下LED的原理圖,如下圖所示,表示了兩個LED的電路圖,其中我們重點關注LED2(PWR是Power的縮寫,是指電源LED):
file

可以看到LED2兩端一個接著的是VCC,即3.3v,另外一端接的是PC13埠;當PC13是高電平的時候LED2兩端沒有電壓差,所以LED2沒有通電,所以處于關燈狀態;如果PC13是低電平狀態,LED2兩端有電壓差,所以處于通電狀態,此時LED2將會亮燈;


所以可以通過設定PC13的低電平和高電平才讓LED2電量和關閉;設定PC13的高低電平就是設定GPIOC暫存器的ODR的值,1即為高電平,燈滅,0為低電平,燈亮,



上面是LED2的原理圖,我們知道了通過PC13來控制LED2的亮滅;但是PC13并不是直接就可以控制的,在嵌入式開發領域通常為了節能,只有需要某個埠的時候,才需要上電,上時鐘,只有有時鐘輸出才能夠作業;否則埠的時鐘關閉,你設定任何值對于對于埠來說都是無效的;
所以如果我們想要讓對于PC13的控制生效,就需要使能PC的埠使能;要設定使能首先就要明白所有的片內外設都是掛在總線上面,我們需要通過打開總線時鐘來實作對于埠的使能,那么GPIOC掛在哪個總線下面呢?上手冊,打開3.1節:
file
其中,系統架構圖如下,我們看到GPIOC在APB2的總線下面,到此我們知道了剛才在代碼中為什么要使能APB2總線了以及配置GPIOC的CRH來實作使能PC13,
file

呼吸燈實作

代碼最后一部分就是實作了while回圈,通過亮-滅-亮-滅-...從而實作呼吸燈的效果:

while(1)
{
				*((uint32_t *)GPIOC_ODR) &= ~(1<<13);
				*((uint32_t *)GPIOC_ODR) |= 0x00000000;
				delay(3);
				*((unsigned int *)GPIOC_ODR) &= ~(1<<13);
				*((unsigned int *)GPIOC_ODR) |= 0x00002000;

				delay(1);
}

亮燈

首先我們杠一下while里面的第一行,這里面運算比較復雜:

*((uint32_t *)GPIOC_ODR) &= ~(1<<13);

首先我們來拆解一下1左移13位,左移操作屬于我們上面提到的位運算,位運算特點就是和整體數值無關,只是針對每個bit位來盡心運算;1左移13位,就是14位,添加2兩位湊成16位(湊成2的n次方值)即:0010 0000 0000 0000,外面的“~”是代表取反,取反是一個單目運算,即針對運算元本身的操作,取反之后的值:1101 1111 1111 1111;



取反之后的值和GPIOC_ODR的原始值進行與運算(&),與運算的規則就是只有兩個位運算元都是1(true)結果才是1(true),否則結果就是0(false);
和還記得GPIOx_ODR的暫存器定義嗎?



file
所以,GPIOC_ODR和1101 1111 1111 1111做與運算,目的就是如果之前是1的還是1,之前如果是0的還是0;但是對于ODR13而言,無論之前值是什么,此番設定之后就是0了,這里有一點注意,3116為保留位,真正參與位運算的是150位,所以真正與運算的值是0000 0000 0000 0000 1101 1111 1111 1111;



然后GPIOC_ODR再和0x00000000做或運算,運算元和0x00000000或運算實作了原來是1的保持,原來是0的保持0;這一步其實意義并不大,可以是處于對稱的目的做的這一步操作;ODR經過了上述的與運算和或運算之后,將ODR設定為0(清零),從而讓LED產生電壓差,實作了亮燈效果;

滅燈

類似,第6行和第7行代碼如下:

*((unsigned int *)GPIOC_ODR) &= ~(1<<13);
*((unsigned int *)GPIOC_ODR) |= 0x00002000;

第一行代碼含義和上面介紹的完全一致,目的是用于維持其他位不變只是針對第13位ODR13,設定其為0,即“清零”操作;



然后第二行GPIOC_ODR和0x00002000做與運算,前面4個零代表32~16位保留位,可以忽略,重點關注2000,轉換為16進制是0010 0000 0000 0000,即實作設定ODR13的位的值為1;設定ODR13為1的效果,讓LED兩端沒有了電壓差(PC13為1即高電平,高電平即3.3V),于是有了滅燈的效果;


呼吸燈小節

所以設定ODR的狀態一般都是兩個步驟:
第一步是ODR13清零;
第二步是ODR13設定為目標值;不過在設定目標值為0的場景下,這一步似乎沒有什么價值;不過處于對稱的目的,還是會設定一下;于是有了*((unsigned int *)GPIOC_ODR) |= 0x00000000;
基于上述的計算,你會發現,或運算一般用于設定指定位的值(而不影響其他位);與運算用于“清零”(保持指定位不變);

延時函式delay

我們還需要注意在亮滅之間還有一個delay的函式:

void delay(unsigned int time)
{    
	 unsigned int i=0;  
	 while(time--)
	 {
			i=10000000;
			while(i--) ;    
	 }
}

delay這個函式就是一個while回圈,達到指定次數之后就退出,從而實作了延時的效果,類似c/ Java里面的Sleep函式的效果;那么為什么能夠實作這個效果呢?這個是因為任何芯片都有一個時鐘的概念,比如我們說STM32的APB2總線是48MHz,其實講述的就是APB32每秒鐘會經歷481024次時鐘;所以在單位時間內的時鐘/周期次數,就是頻率(也稱之為時鐘頻率)的概念;
再回到上面的例子中,如果我們設定了時鐘是8MHz,那么就意味著每秒鐘將會回圈8
1024次,那么如果回圈次數是8*1024次,就可以認為是1秒鐘;這一個就是為什么while回圈指定次數可以作為定時器來用(后面我們專門有一個原始碼解讀片內外設定時器);


debug時鐘設定

那么我們的時鐘是多少呢?如果你是除錯模式,這個時鐘是通過目標選項(Options For Target)來進行配置,開心就好:
file
如果是直接燒錄到STM32的板子里面,默認使用的是HSI(High Speed Internal,內部高速時鐘),即8MHz;所以為了Debug的效果和燒錄之后的效果保持一致,最好是設定為一致的時鐘頻率,

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/402393.html

標籤:嵌入式

上一篇:Linux之Nginx入門

下一篇:STM32(2):點亮LED(下)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • CA和證書

    1、在 CentOS7 中使用 gpg 創建 RSA 非對稱密鑰對 gpg --gen-key #Centos上生成公鑰/密鑰對(存放在家目錄.gnupg/) 2、將 CentOS7 匯出的公鑰,拷貝到 CentOS8 中,在 CentOS8 中使用 CentOS7 的公鑰加密一個檔案 gpg -a ......

    uj5u.com 2020-09-10 00:09:53 more
  • Kubernetes K8S之資源控制器Job和CronJob詳解

    Kubernetes的資源控制器Job和CronJob詳解與示例 ......

    uj5u.com 2020-09-10 00:10:45 more
  • VMware下安裝CentOS

    VMware下安裝CentOS 一、軟硬體準備 1 Centos鏡像準備 1.1 CentOS鏡像下載地址 下載地址 1.2 CentOS鏡像下載程序 點擊下載地址進入如下圖的網站,選擇需要下載的版本,這里選擇的是Centos8,點擊如圖所示。 決定選擇Centos8后,選擇想要的鏡像源進行下載,此 ......

    uj5u.com 2020-09-10 00:12:10 more
  • 如何使用Grep命令查找多個字串

    如何使用Grep 命令查找多個字串 大家好,我是良許! 今天向大家介紹一個非常有用的技巧,那就是使用 grep 命令查找多個字串。 簡單介紹一下,grep 命令可以理解為是一個功能強大的命令列工具,可以用它在一個或多個輸入檔案中搜索與正則運算式相匹配的文本,然后再將每個匹配的文本用標準輸出的格式 ......

    uj5u.com 2020-09-10 00:12:28 more
  • git配置http代理

    git配置http代理 經常遇到克隆 github 慢的問題,這里記錄一下幾種配置 git 代理的方法,解決 clone github 過慢。 目錄 git配置代理 git單獨配置github代理 git配置全域代理 配置終端環境變數 git配置代理 主要使用 git config 命令 git單獨 ......

    uj5u.com 2020-09-10 00:12:33 more
  • Linux npm install 裝包時提示Error EACCES permission denied解

    npm install 裝包時提示Error EACCES permission denied解決辦法 ......

    uj5u.com 2020-09-10 00:12:53 more
  • Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包

    Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包。 18 (flaskApi) [root@67 flaskDemo]# yum -y install nginx 19 已加載插件:fastestmirror, langpacks 20 Loading ......

    uj5u.com 2020-09-10 00:13:13 more
  • Linux查看服務器暴力破解ssh IP

    在公網的服務器上經常遇到別人爆破你服務器的22埠,用來挖礦或者干其他嘿嘿嘿的事情~ 這種情況下正確的做法是: 修改默認ssh的22埠 使用設定密鑰登錄或者白名單ip登錄 建議服務器密碼為復雜密碼 創建普通用戶登錄服務器(root權限過大) 建立堡壘機,實作統一管理服務器 統計爆破IP [root ......

    uj5u.com 2020-09-10 00:13:17 more
  • CentOS 7系統常見快捷鍵操作方式

    Linux系統中一些常見的快捷方式,可有效提高操作效率,在某些時刻也能避免操作失誤帶來的問題。 ......

    uj5u.com 2020-09-10 00:13:31 more
  • CentOS 7作業系統目錄結構介紹

    作業系統存在著大量的資料檔案資訊,相應檔案資訊會存在于系統相應目錄中,為了更好的管理資料資訊,會將系統進行一些目錄規劃,不同目錄存放不同的資源。 ......

    uj5u.com 2020-09-10 00:13:35 more
最新发布
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:43:21 more
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:42:36 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:26:53 more
  • 設定Windows主機的瀏覽器為wls2的默認瀏覽器

    這里以Chrome為例。 1. 準備作業 wsl是可以使用Windows主機上安裝的exe程式,出于安全考慮,默認情況下改功能是無法使用。要使用的話,終端需要以管理員權限啟動。 我這里以Windows Terminal為例,介紹如何默認使用管理員權限打開終端,具體操作如下圖所示: 2. 操作 wsl ......

    uj5u.com 2023-04-19 09:25:49 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:19:04 more
  • Linux學習筆記

    IP地址和主機名 IP地址 ifconfig可以用來查詢本機的IP地址,如果不能使用,可以通過install net-tools安裝。 Centos系統下ens33表示主網卡;inet后表示IP地址;lo表示本地回環網卡; 127.0.0.1表示代指本機;0.0.0.0可以用于代指本機,同時在放行設 ......

    uj5u.com 2023-04-18 06:52:01 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:50 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:01 more
  • 你是不是暴露了?

    作者:袁首京 原創文章,轉載時請保留此宣告,并給出原文連接。 如果您是計算機相關從業人員,那么應該經歷不止一次網路安全專項檢查了,你肯定是收到過資訊系統技術檢測報告,要求你加強風險監測,確保你提供的系統服務堅實可靠了。 沒檢測到問題還好,檢測到問題的話,有些處理起來還是挺麻煩的,尤其是線上正在運行的 ......

    uj5u.com 2023-04-05 16:52:56 more
  • 細節拉滿,80 張圖帶你一步一步推演 slab 記憶體池的設計與實作

    1. 前文回顧 在之前的幾篇記憶體管理系列文章中,筆者帶大家從宏觀角度完整地梳理了一遍 Linux 記憶體分配的整個鏈路,本文的主題依然是記憶體分配,這一次我們會從微觀的角度來探秘一下 Linux 內核中用于零散小記憶體塊分配的記憶體池 —— slab 分配器。 在本小節中,筆者還是按照以往的風格先帶大家簡單 ......

    uj5u.com 2023-04-05 16:44:11 more