天天看點

Keil MDK介紹

轉自:http://www.eefocus.com/book/08-11/575071276059422.html

STM32微處理器基于ARM核,是以很多基于ARM嵌入式開發環境都可用于STM32開發平台。開發工具都可用于STM32開發。選擇合适的開發環境可以加快開發進度,節省開發成本。本章将先對STM32常用的開發工具Keil MDK和IAR EWARM進行簡單介紹,然後結合STM32_SK仿真評估闆和STM32F103C的開發闆講解STM32片上資源使用,最後給出一個基于STM32的資料采集器的應用執行個體。

5.1 Keil MDK介紹

Keil是德國知名軟體公司Keil(現已并入ARM 公司)開發的微控制器軟體開發平台,是目前ARM核心單片機開發的主流工具。Keil提供了包括C編譯器、宏彙編、連接配接器、庫管理和一個功能強大的仿真調試器在内的完整開發方案,通過一個內建開發環境(uVision)将這些功能組合在一起。uVision目前最高版本是uVision3,它的界面和常用的微軟VC++的界面相似,界面友好,易學易用,在調試程式,軟體仿真方面也有很強大的功能。是以很多開發ARM應用的工程師,都對它十分喜歡。

5.1.1 開發過程及內建開發環境簡介

1. Keil的軟體開發周期

使用Keil來開發嵌入式軟體,開發周期和其他的平台軟體開發周期是差不多的,大緻有以下幾個步驟:

1. 建立一個工程,選擇一塊目标晶片,并且做一些必要的工程配置。

2. 編寫C或者彙編源檔案。

3. 編譯應用程式。

4. 修改源程式中的錯誤。

5. 聯機調試。

下面這種結構圖完整描述了Keil開發軟體的整個過程。

Keil MDK介紹

2. uVision3 內建開發環境

uVision3 IDE是一款集編輯,編譯和項目管理于一身的基于視窗的軟體開發環境。uVision3內建了C語言編譯器,宏編譯,連結/定位,以及HEX檔案産生器。uVision3具有如下特性:

 功能齊全的源代碼編輯器,

 用于配置開發工具的裝置庫,

 用于建立工程和維護工程的項目管理器,

 所有的工具配置都采用對話框進行,

 內建了源碼級的仿真調試器,包括高速CPU和外設模拟器,

 用于往Flash ROM下載下傳應用程式的Flash程式設計工具,

 完備的開發工具幫助文檔,裝置資料表和使用者使用向導。

uVision3具有良好的界面風格,下圖是一個典型的調試時的視窗。

Keil MDK介紹

 工程區:用于通路檔案組和檔案,調試是可以檢視CPU寄存器。

 輸出視窗:顯示編譯結果,以便快速查找錯誤的地方,同時還是調試指令輸入輸出視窗,也可以用于顯示查找結果。

 記憶體視窗:顯示指定位址内村裡的内容。

 檢視和調用棧視窗:用于檢視和修改變量的值,并且現實目前函數調用樹。

 代碼視窗:用于檢視和編輯源檔案。

 外設對話框:檢查微控制的片上外設的狀态。

3. ULINK USB-JTAG接口擴充卡

ULINK USB-JTAG是一個用于連接配接PC USB口和開發闆JTAG口的小硬體擴充卡。通過ULINK你可以在真實的目标闆上建立,下載下傳和測試嵌入式應用。ULINK支援如下操作:

 下載下傳目标程式。

 檢查記憶體和寄存器。

 單步運作程式。

 插入多個斷點。

 實時運作程式

 燒寫FLASH存儲器

Keil MDK介紹

5.1.2 工程管理

在項目開發中,并不是僅有一個源程式就行了,還要為這個項目選擇CPU(Keil支援數百種CPU,而這些CPU的特性并不完全相同),确定編譯、彙編、連接配接的參數,指定調試的方式,有一些項目還會有多個檔案組成等,為管理和使用友善,Keil使用工程(Project)這一概念,将這些參數設定和所需的所有檔案都加到一個工程中,隻對工程而不是對單一的源程式進行編譯(彙編)和連接配接等操作。下面我們就以一個簡單的例子HelloWorld來講解如何建立工程和配置工程。在這個例子裡,我們将實作開發闆上的LED1閃爍,本例使用STM32F103C開發闆為目标闆。

5.1.2.1 建立工程

點選菜單“Project”,選擇“New uVision Project”,這是将會出現一個對話框,要求給将要建立的工程起一個名字。

選擇你要儲存的路徑,輸入工程檔案的名字,這裡我們就叫HelloWorld,uVision3工程檔案的字尾為“.uv2”,然後點選“Save”。 這時會彈出一個對話框要求你選擇目标裝置的型号。

Keil MDK介紹

你可以根據你使用的處理器來選擇,如果您所使用的處理器型号在清單中找不到,也可以找一款與您使用的相相容的型号來代替。這裡我們選擇STM32F103C8,如圖所示,右邊一欄是對這個晶片的基本的說明,然後點選“OK”。

Keil MDK介紹

有些晶片會提供啟動代碼,我們這個時候點選“Yes”,到此一個工程就建立好了。

5.1.2.2 配置工程

工程建立好了之後,還要對工程進行進一步的設定,以滿足要求。

首先用滑鼠右鍵(注意用右鍵)點選左邊工程視窗的“Target 1”,會出現一個菜單,選擇“Options for Target 'Target 1'”(也可以通過點選工程視窗的Target 1”,然後使用菜單“Project”->“Options for Target 'Target 1'”),即出現工程配置的對話框,如下圖所示:

Keil MDK介紹

這個對話框很複雜,而且根所選擇的晶片有關,這裡共有10個頁面,絕大多數選擇預設配置即可,下面将對一些需要注意的配置簡單介紹一下。

1. Output标簽頁的設定

Keil MDK介紹

Select Folder for Objects:選擇編譯之後的目标檔案存儲在哪個目錄裡,預設位置為工程檔案的目錄裡。

Name of Executable:生成的目标檔案的名字,預設是工程的名字。

Create Executable:生成OMF以及HEX檔案。OMF檔案名同工程檔案名但沒有帶擴充名。

Debug Information:用于Debug版本,生成調試資訊,否則的話無法進行單步調試。

Create Batch File:生成用于實作整個編譯過程的批處理檔案,使用這個檔案可以脫離IDE對省程式進行編譯。

Create Hex File:這個選項預設情況下未被選中,如果要寫片做硬體實驗就必須選中該項。這一點是初學者易疏忽的,在此特别提醒注意一定要要選中,否則編譯之不生成Hex檔案。

Big Endian:編碼格式,與CPU相關,如果CPU采用的是Big Endian編碼則勾選上。

Browse Information:産生用于在源檔案快速定位的資訊。

Create Library:生成lib庫檔案,預設不選。

在我們剛剛建立的HelloWorld工程中,更改了三個地方,在工程目錄下建立了一個Output目錄儲存目标檔案,以避免和源檔案混在一起。另外選中了Create Hex File和Browse Information,如上圖所示。

2. C/C++标簽頁的設定

Keil MDK介紹

Include Paths:指定頭檔案的查找路徑,可以添加多個。

這裡我們所有的選擇保持預設選擇就可以了。

3. Debug标簽頁的設定

Keil MDK介紹

左邊是對應uVision3的模拟環境,右邊是針對仿真器,這裡選擇右邊的ULINK Cortex Debugger仿真器為例進行說明。

如果已經将ULINK仿真器連接配接到你的電腦,點選“Settings”你将進入ARM Target Driver Setup 界面。

Keil MDK介紹

ULINK - JTAG/SWD Adapter:

Serial No:列出了目前連接配接到主機的所有ULINK擴充卡的串号,你可以通過清單選擇要使用的ULINK擴充卡。

ULINK Version,Device Family以及Firmware Version分别列出了目前選擇的ULINK擴充卡的版本,裝置家族和固件版本。

SWJ,Port:根據和開發闆接口的類型選擇端口,有JTAG和SW兩種,勾選SWJ表示支援兩種方式。

Max Clock:指定和開發闆的最高通信時鐘。

JTAG Device Chain:顯示目前通過擴充卡連接配接上的開發闆。

Automatic Detection:自動監測,選擇系統将自動檢測連接配接上的開發闆,建議使用。

Manual Configuration:手動配置,通過手動設定ID CODE,Device Name和IR len等屬性來查找裝置。

Debug:

Cache Options:

 Cache Code:通知調試器已經下載下傳的程式代碼不會改變,選中的話uVision将不會從目标系統讀取程式代碼。

 Cache Memory:決定調試程式期間程式停止運作的時候,是否更新存儲器顯示。

Download Options:

 Verify Code Download:比較目标存儲器和調試器上的應用程式的内容。

 Download to Flash:将代碼下載下傳到所有的存儲器區域,如果不選中,調試器不會把代碼下載下傳到Flash Download Setup中制定的存儲器位址範圍。

Misc Options:

 Use Reset at Startup:選中的時候,調試器在開始調試的時候會發起一次CPU複位。 

Load Application at Startup:将Output标簽中指定的可執行檔案導入到調試器的起始位址。

Run to Main:開始調試時執行到Main函數入口暫停執行。

Initialization File:指定一個包含一組調試指令的檔案,這組指令是調試器開始工作或者調試函數在調試期間要使用的。

Restore Debug Session Settings:使用上一次調試過程對Breakpoints,Watchpoints,Memory Display和Toolbox(如果這些項被選中的話)。

Driver DLL – Parameter:由Device Database設定的目标驅動DLL,不要修改。

Dialog DLL – Parameter:由Device Database設定的對話框DLL,不要修改。

這裡我們修改了兩個地方,選中了Use ULINK和Run to Main,對ULINK的設定進行了一些調整,具體的設定圖5.11所示。

4. Utilities标簽頁的設定

Keil MDK介紹

Configure Flash Menu Command

 Use Target Driver for Flash Programming:清單選擇和調試接口一緻的驅動。Init File的設定也和前面調試設定一緻。點選Settings将進入Flash Download Setup界面。

Keil MDK介紹

Download Function:定義了Flash燒寫的時候進行的操作。

 Erase Full Chip:前面三項要選一,燒寫程式之前擦除整個Flash存儲器。

 Erase Sectors:燒寫程式之前擦除程式要使用的扇區。

 Do not Erase:不進行擦除操作

 Program:使用目前uVision工程的程式燒寫ROM。

 Verify:驗證Flash ROM的内容和目前工程中的程式一緻。

 Reset and Run:在燒寫和驗證完成之後複位開發闆并且運作程式。

RAM for Algorithm:指定用于燒寫程式的RAM區域,通常是微控制器上的一段片上空間。

 Start:起始位址。

 Size:大小。

可以通過點選Add添加,點選Add你将看到如下的選擇清單,可以根據你選用的晶片選擇合适的,也可以自己手動添加。

Keil MDK介紹

 Use External Tool for Flash Programming:使用第三方的工具進行Flash下載下傳。

 Command:要使用的Flash燒寫工具的指令檔案(通常是一個.exe檔案)。

 Arguments:傳遞給Flash燒寫工具的參數。

 Run Independent:當選中的時候,uVision不等待Flash燒寫完成。不選中的時候uVision要等待Flash燒寫完成并且在輸出視窗顯示燒寫結果。

在HelloWorld裡面修改了Flash Download Setup,具體的設定如上圖所示。到此工程設定就結束了。

5.1.2.3 打開工程

通過菜單“Project”->“Open Project”來打開一個現有工程,這時将彈出一個打開檔案對話框讓我們選擇要打開的工程檔案。

選擇你要打開的工程的路徑,然後點選“Open”打開工程。我們還可以和打開其他檔案一樣,找到一個字尾為“uv2”的uVision3工程檔案,直接輕按兩下,Windows會自動調用uVision3打開這個檔案,前提是你電腦已經安裝了uVision3并且和“uv2”檔案建立了關聯。

5.1.3 編寫源程式

選擇菜單“File”->“New”或者點選工具欄的建立檔案按鈕,即可在項目視窗的右側打開一個新的文本編輯視窗,在該視窗可以輸入程式代碼。

需要說明的是,源檔案就是一般的文本檔案,不一定使用Keil軟體編寫,可以使用任意文本編輯器編寫,而且Keil的編輯器對漢字的支援不好,建議使用UltraEdit之類的編輯軟體進行源程式的輸入。

每一個程式至少有一個原型為int main(void)的主函數,這是程式的入口位址,程式将從這裡開始運作。此外,我們還需要對開發闆做一些時鐘和中斷方面的初始化工作,這些工作将在函數RCC_Configuration和NVIC_Configuration中完成。源檔案的代碼清單如下所示。

#include "stm32f10x_lib.h"

GPIO_InitTypeDef GPIO_InitStructure;

void Delay (vu32 nCount);

int main (void)

{

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ GPIOB, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init (GPIOB, &GPIO_InitStructure);

while (1)

{

GPIO_WriteBit (GPIOB, GPIO_Pin_9,

(BitAction)(1-GPIO_ReadOutputDataBit (GPIOB, GPIO_Pin_9)));

Delay (1000000);

}

}

void Delay (vu32 nCount)

{

for (; nCount != 0; nCount--);

}

代碼編輯完成之後,我們可以儲存源檔案,選擇菜單“File”->“Save”或者點選工具欄的儲存檔案按鈕,可以用來儲存源檔案。

這時會出現一個儲存檔案的檔案對話框,選擇你要儲存的路徑,輸入檔案名HelloWorld.c。注意一定要輸入擴充名,如果是c程式檔案擴充名為.c,如果是彙編檔案擴充名為.s,習慣.asm的也可以存儲為.asm。注解說明檔案可以儲存為.txt的擴充名。

源檔案編輯完成之後我們還需要将源檔案加入到工程中,工程建好之後,在工程視窗的檔案頁中,将會出現“Target 1”,前面有個“+”号,點選“+”号展開,可以看到下一層的“Source Group 1”,我們需要向這個裡面加入源檔案,點選“Source Group 1”使其反白顯示,然後,點選滑鼠右鍵,出現一個下拉菜單,如下圖如示。

Keil MDK介紹

選中其中的“Add file to Group ‘Source Group 1’”,出現一個對話框,要求尋找源檔案,如下圖所示。

Keil MDK介紹

注意,該對話框下面的“檔案類型”預設為C source file(*.c),我們可以通過調整這個來選擇過濾我們想要格式的檔案,進而幫助我們快速查找檔案。如果是彙編檔案,就選擇“asm source file”;如果是目标檔案,選擇“Object file”;如果是庫檔案,選擇“Library file”。最後點選“Add”,也可以輕按兩下要添加的檔案進行加入。注意:點選“Add”之後,視窗不會消失,如果要添加多個檔案,可以不斷添加,添加完畢此時再點選“Close”關閉該視窗。初學者時常誤認為操作沒有成功而再次輕按兩下同一檔案或者再次點選“Add”,這時會出現如下的對話框。

Keil MDK介紹

在這裡我們把剛建立的HelloWorld.c添加進去,檔案添加進去之後,我們點選“Source Group 1”前面的“+”号,就會發現我們剛剛添加的檔案HelloWrold.c已在其中了,輕按兩下檔案名,即在代碼區打開該源程式檔案。

除了添加檔案,我們還可以添加新的Group,操作和添加檔案類似,出現下拉菜單之後我們選擇“New Group”,這時就會在工程視窗看到新加的Group。對Group和添加檔案的操作我們還可以通過點選工具欄上的彩色品字按鈕進入“Components,Environment and Books”視窗,如下圖所示。

Keil MDK介紹

輕按兩下清單中的項可以對該項進行重命名操作,點選空白處可以添加新的項,虛方框按鈕也可以添加新的項,紅叉表示删除選中的項,上下箭頭用于調整目前選中項在清單中的位置,“Add Files”可以添加新的源檔案,操作過程和前面添加檔案的操作是一樣的。

5.1.4 編譯程式

程式代碼寫好之後就進入編譯程式階段,可以通過菜單,工具欄和浮動菜單多種方式來發起編譯過程,也可以通過批處理檔案進行,關于這個批處理檔案在Output标簽頁的設定中提到過。

Keil MDK介紹

紅線圈起來的區域就是對應的菜單編譯指令和工具欄編譯指令。各指令的含義如下:

 Clean target:清除編譯結果。

 Build target:編譯被修改的檔案并且編譯應用程式。

 Rebuild all target files:重新編譯所有的源檔案并且編譯應用程式。

 Batch Build:通過前面輸出的批處理檔案進行編譯。

 Translate **.*:編譯某個源檔案,**.*代表要編譯的源檔案。

 Stop build:隻有編譯進行過程中這一項才有效。

通過在工程視窗“Target 1”上點選右鍵,也可以彈出相應的編譯菜單,各指令含義和上面一緻。

Keil MDK介紹

現在就讓我們來編譯我們的“HelloWorld”,如下圖所示,編譯的結果會在輸出視窗顯示。

Keil MDK介紹

很遺憾,有不少錯誤,也許你早就發現我們的代碼中使用了很多我們沒有定義的而且也不屬于标準C的一些函數,沒錯這就是ST固件庫給我們提供的函數,我們要做的就是把固件庫添加到我們的工程中,和其他的開發環境一下,我們可以直接添加強件庫的源檔案和工程一起編譯,也可以通過添加已經編譯好的靜态連接配接庫(*.lib)檔案。這裡我們以後者為例,這些庫在我們安裝好Keil開發環境的時候已經提供了,路徑一般在你安裝目錄下的ARMRV31LIB中,例如我這裡的路徑是D:KeilARMRV31LIBST。這裡我們将添加一個新的Group,取名為FWLIB。然後将庫檔案添加到這個Group中,具體的操作過程可以參照編寫源程式章節。添加庫之後我們再次編譯。

Keil MDK介紹

問題解決了,當出現“0 Error(s), 0 Warning(s)”的時候也就意味着我們的程式已經通過了文法檢查,有時候一些Warning也不影響程式執行,但是我們要慎重對待,仔細分析每一個Warning。如果是源程式中有文法錯誤或者警告,我們可以通過輕按兩下輸出視窗的該行,快速定位到出錯的位置。

5.1.5 調試程式

編譯通過隻是說明我們的代碼沒有文法錯誤,至于源程式中存在的其他錯誤,必須通過調試才能發現并解決,事實上,除了極簡單的程式以外,絕大部分的程式都要通過反複調試才能得到正确的結果,是以,調試是軟體開發接下來我們需要運作我們的程式來驗證是否達到了預期的目的。也就是程式調試,程式調試往往是程式開發過程中最難的階段,尤其是對一些比較大型的程式。下面我們就來看看uVision3對調試的支援。

5.1.5.1 常用的調試指令

在對工程成功進行彙編、連接配接之後,按Ctrl+F5或者使用菜單Debug->Start/Stop Debug Session即可進入調試狀态。進入調試狀态後,界面與編輯狀态相比有明顯的變化,Debug才單項中原來不能用的指令現在已經可以使用了,工具欄會多出一個用于運作和調試的工具欄,如下圖所示,Debug菜單上的大部分指令可以在此找到對應的快捷按鈕。

Keil MDK介紹

常用的Debug菜單指令如下所示:

 Start/Stop Debug Session:開始或者停止調試。

 Run:一直執行下一個活動的斷點。

 Step:單步執行。

 Step Over:過程單步執行,即将一個函數作為一個語句來執行。

 Step out of current Function:跳出目前的函數。

 Run to Cursor line:執行到光标所在的行。

 Stop Running:停止運作。

 Breakpoints:打開斷點對話框。

 Insert/Remove Breakpoint:在目前行插入/删除一個斷點。

 Enable/Disable Breakpoint:激活目前行的斷點或者使斷點無效。

 Disable All Breakpoints:使程式中所有的斷點都無效。

 Kill all Breakpoints:删除程式中所有的斷點。

Keil MDK介紹

學習程式調試,必須明确兩個重要的概念,即單步執行與全速執行。全速執行是指一行程式執行完了以後緊接着執行下一行程式,中間不停止,這樣程式執行的速度就很快,并可以看到該段程式執行的總體效果,即最終結果正确還是錯誤,但如果程式有錯,則難以确認錯誤出現在哪些程式行。單步執行是每次執行一行程式,執行完該行程式執行完以後即停止,等待指令執行下一行程式,此時我們可以觀察該行程式執行完以後得到的結果,是否與我們寫程式行所想要得的結果相同,借此可以找到程式中問題所在。程式調試中,這兩種運作方式都要用到,要靈活應用,可以大大提高調試效率。

在調試視窗中,我們可以看到一個黃色的調試箭頭,指向了目前執行到的程式行。

5.1.5.2 斷點設定

程式調試時,有些程式行往往很難确認什麼時候能夠執行到,這類問題就不适合單步調試,這是我們需要使用程式調試中另一種非常重要的方法——斷點設定。斷點設定的方法有多種,常用的是在某一程式行設定斷點,設定好斷點之後可以全速運作程式,一旦執行到該程式行即停止,可在此觀察有關的變量值,以确定問題所在。設定斷點的指令請參考上一節常用調試指令介紹。一旦某一行被設定了斷點,我們可以在程式行的左端看到一個紅色方框(如圖5.24調試視窗圖所示),如果該斷點被禁用,方框将會變為白色。

除了在某程式行設定斷點這一基本方法以外,uVision3還提供了多種設定斷點的方法,按Debug->Breakpoints,即出現一個對話框,該對話框用于對斷點進行詳細的設定,如下圖所示。

Keil MDK介紹

圖5.26中的Expression後的編輯框用于輸入表達式,該表達式用于确定程式停止運作的條件,功能強大,涉及到uVision3内置的一套調試算法,這裡不做詳細說明,請查閱相關幫助文檔。

5.1.5.3 調試視窗

前面講了調試的一些方法,裡面多次提到檢查程式的執行狀态。調試視窗就是用于檢視程式執行狀态的。uVision3提供了多種調試視窗,如寄存器視窗,存儲器視窗,反彙編視窗,外設視窗等,下面将會一一作介紹。

Keil MDK介紹

1. 寄存器視窗

圖5.26是工程視窗寄存器頁的内容,寄存器頁包含了目前所有的工作寄存器和系統寄存器,每當程式中執行到對某個寄存器的操作時,該寄存器會反色顯示,用滑鼠單擊然後按F2(滑鼠連續單擊兩次),即可修改該值。

2. 存儲器視窗

存儲器視窗可以顯示系統中各種記憶體中的值,通過在Address後的編輯框中輸入“字母:數字”即可顯示相應記憶體值,其中字母C、D、I、X,分别代表代碼存儲空間、直接尋址的片記憶體儲空間、間接尋址的片記憶體儲空間、擴充的外部RAM單元值、鍵入C:0即可顯示從0開始的ROM單元中的值,即檢視程式的二進制代碼。該視窗的顯示值可以以各種形式顯示,如十進制、十六進制、字元型等。改變顯示方式的方法是點滑鼠右鍵,在彈出的快捷菜單中選擇。除了顯示,還可以修改記憶體中的值,如下圖所示。

Keil MDK介紹

3. 檢視和調用棧視窗

這個視窗可以幫助我們檢視目前調用樹的情況,我們還可以通過這個視窗檢視和修改一些變量的值。滑鼠停留在某個變量的時候點右鍵,在彈出的浮動菜單中選擇Add ***to Watch window,Local 視窗顯示目前一些局部變量的值,變量值的現實方式可以在十六進制和十進制之間切換,方式是在檢視視窗點右鍵,在某個變量的Value欄用滑鼠單擊然後按F2(滑鼠連續單擊兩次),即可修改該值。如下圖所示。

Keil MDK介紹

4. 反彙編視窗

點選View->Dissambly Window可以打開反彙編視窗,該視窗可以顯示反彙編後的代碼、源代碼和相應反彙編代碼的混合代碼,可以在該視窗進行線上彙編、利用該視窗跟蹤已找行的代碼、在該視窗按彙編代碼的方式單步執行。點選滑鼠右鍵,出現快捷菜單,如圖5.29所示,其中Mixed Mode是以混合方式顯示,Assembly Mode是以傳回編碼方式顯示。

Keil MDK介紹

5. 外設視窗

為了能夠比較直覺地了解單片機中各種外設的使用情況,uVison3提供了一個外圍接口對話框。通過Peripherals菜單,下拉菜單中的内容和你選擇的晶片有關,會列出你所選擇的晶片上所有的外設。選擇一項你可以進入檢視或修改該外設的一些狀态。例如在這裡我們是通過GPIO中的PB9來控制LED閃爍,我們可以打開GPIOB的狀态對換框,如圖5.30所示。

Keil MDK介紹

現在我們可以調試我們的HelloWorld了。程式運作時,你将看到開發闆上的L1不停閃爍。