用STM32的GPIO來點亮跑馬燈
步驟:
1.新建工程:復(fù)制模板中的一切文件夾,注意刪除USER中模板Template產(chǎn)生的三個文件以及OBJ中的文件(OBJ中產(chǎn)生的是編譯過程中產(chǎn)生的文件)。
2.打開keil,對工程中的各縣設(shè)置進行修改(包括:右鍵Manage Project Items里面的各個組及頭文件;魔術(shù)棒中的Output選項卡中HEX文件和Folder的修改;C/C++選項卡中Define和頭文件路徑的修改)
3.build工程,查看設(shè)置是否正確,注意此時各個文件前面有可能沒有小加號,解決辦法是Translate一下,要是還不行就關(guān)了重開。
至此新建工程完成
新建工程需注意的事項:
(1)在不完全手冊中有著詳細的新建步驟,要仔細的按照步驟來,
(2)Define:STM32F10X_HD,USE_STDPERIPH_DRIVER,
(3)FIWLIB添加文件的時候添加的是src中的文件,但在添加路徑的時候是inc文件夾,并且注意一定要相應(yīng)的添加,
(4)Translate和build的區(qū)別:Translate的時候只是檢查語法的錯誤,并不產(chǎn)生HEX文件,
(5)出現(xiàn)無法gotodefinition的情況的時候是沒有build工程,build一下就可以了,
想要對外設(shè)進行驅(qū)動就要相應(yīng)的編寫函數(shù),我們在這里只將具體要做什么事(如亮多久滅多久,一起亮還是輪流亮)放于main文件中,每個外設(shè)的初始化函數(shù)我們都放在HARDWARE文件夾下面相應(yīng)的.c和.h文件中(初始化函數(shù)是要根據(jù)外設(shè)連接到了哪個端口來編寫的,內(nèi)容包括用了哪個端口,處于什么工作模式下等),在這里使用到了這兩個文件,不要忘記添加頭文件和相應(yīng)的路徑。
1.對.h文件的編寫
(1).h文件一般用于存放函數(shù)的聲明和宏定義等
(2)使用到的函數(shù):ifndef,define,endif
#ifndef __XXXX_H
#define __XXXX_H
A
#else
B
#endif
這是一個宏定義,防止重復(fù)定義:如果沒有定義(if not define,ifndef)過xxxx.h,那么定義(define)xxxx.h并執(zhí)行A,如果定義過了就執(zhí)行B,通常我們在用的時候不會用到else,那么也就直接跳過了這段代碼(endif),其中的這些下劃線和H是c語言的書寫規(guī)范,并且都是用大寫來寫,如led.h就會寫成_LED_H。
關(guān)于這個函數(shù)的用法和重復(fù)定義的問題可以參考:http://blog.sina.com.cn/s/blog_aef927a50102wg9u.html
(3)舉例:
#ifndef __LED_H//if not define led.h
#define __LED_H//define led.h,并執(zhí)行下面的程序
void LED_Init(void);
#endif
注意:LED_Init是空函數(shù),在末尾要加上分號,沒有分號會報錯。
說明:這里看到一個解釋,說.h頭文件并不是直接對應(yīng)執(zhí)行的,而是給編譯器看的,在.h文件中的代碼在實際編譯的時候會直接替換掉.c中的#include "xxx.h"。如果沒有這段代碼,那么遇到main.c中包含了許多頭文件,而這些頭文件中又不止一次包含了這個xxx.h,在編譯的時候就會出現(xiàn)重復(fù)定義的報錯,也會浪費時間,而有了這段代碼就可以保證了它只被定義一遍,因為不符合not define,所以直接跳過。
2.對.c文件的編寫
在本實驗中,.c文件里面存放了led的初始化函數(shù)LED_Init,
LED_Init包括:
(1)include相應(yīng)的.h文件
(2)對GPIO時鐘的初始化:GPIO用的是時鐘2,函數(shù)為:RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx,ENABLE);
(3)對GPIO端口的初始化:
GPIO_InitTypeDefGPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=
GPIO_InitStructure.GPIO_Pin=
GPIO_InitStructure.GPIO_Speed=
GPIO_Init(GPIOx,&GPIO_InitStructure);
GPIO_SetBits(GPIOx,GPIO_Pin_x);
注意這里一定是要先設(shè)置初始值再進行函數(shù)的調(diào)用。
下面來解釋一下這些語句:
1.GPIO_Init(GPIOx,&GPIO_InitStructure);
這條語句為初始化語句,輸入GPIO_Init后,可以goto去查看它的definition,可以看到是這個樣子的:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct),也就是說我們在.c文件中調(diào)用的是這個函數(shù)。通過查看這個函數(shù)我們就可以知道這個函數(shù)的格式和需要設(shè)置的參數(shù)都有哪些,可以看出,想要調(diào)用這個函數(shù),需要傳遞過來兩個參數(shù),一個是具體哪個管腳,一個是要被初始化的變量們組成的結(jié)構(gòu)體。具體是哪個管腳,取決于硬件電路的連接。
這兩句話可以類比于
hanshu(a,&b);//調(diào)用函數(shù)hanshu
void hanshu(int *p,char *q);//定義一個名叫hanshu的函數(shù),有兩個指針型變量,分別指向int和char型變量
GPIO_TypeDef* GPIOx:這句話表示一個結(jié)構(gòu)體變量的地址,GPIO_TypeDef是類型,相當于int,float之類的,*GPIOx的意思是定義一個指針名叫GPIOx,整體這句話的意思就是定義一個名叫GPIOx的指針,這個指針指向GPIO_TypeDef類型的東西
在這里,要講一下指針的問題:
指針是能夠存放一個地址的一組存儲單元(通常為2個或4個字節(jié)),這就像機器的一個字節(jié)可以存放一個char類型的數(shù)據(jù),四個字節(jié)就可以存放一個long型的數(shù)據(jù),當然了,四個字節(jié)我們就可以叫它單元了,存放著地址的存儲單元,我們叫它指針,它也是一個變量,只是其他變量表示的是一個數(shù)或者字母或者其他什么東西,而它表示的是地址,表示的是它所指向的東西的所在地址。這樣就可以理解指針到底是個什么東西了。
如果在A處存放了一個char類型的數(shù)據(jù)c(當然也可以是別的,但char只是一個字節(jié)的,用來舉例比較好理解),若p是指向c的指針,那么,p中存放的就是這個c所在的地址,也就是A,根據(jù)學過的微機接口課程的內(nèi)容我們可以知道,這個A實際上應(yīng)該是一個類似于0xFFH之類的十六進制的東西,我們在這里也沒有必要知道具體是什么,因為這個地址A是CPU自己分配的,我們想要進行操作,那么就直接操作指針p就可以了,因為p中存放的就是A呀?,F(xiàn)在這個A是我這里用來理解而加入的字母,在程序中是不存在這個A的,我們想要將一個東西指向另一個東西,要怎么寫呢?需要啷個運算符,一個是地址運算符&,一個是間接尋址或間接引用運算符*。
p=&c,這樣p就指向c了。&可以取出內(nèi)存中的對象的地址,即變量或數(shù)組元素的地址(也就是說在這樣用的時候這個c只能夠代表變量或者數(shù)組元素,如果這個c是一個常量或者是一個表達式就不行了),&c就表示c所在的地址,也就是我之前假設(shè)的A,這個A也就相當于&c。
*運算符用于指針的定義和尋找指針指向的東西,&運算符用于對變量的取址。
舉一個例子用來理解*和&
int x=1,y=2,z[10];
int *p;//定義一個指向int類型的東西的指針,它的名字叫p
p=&x;//現(xiàn)在指針p指向x,p指向x也就是p表示x所在的位置,現(xiàn)在p中應(yīng)該是一個地址
y=*p;//現(xiàn)在,y=1。*p表示取p中的內(nèi)容所代表的地址中的內(nèi)容,也就是去找p指向的東西,也就是x。
*p=0;//現(xiàn)在x=0,可以看出,指針是能夠改變它本來的東西的值的,與值的傳遞有差別,這一點稍后詳細解釋
p=&z[0];//現(xiàn)在指針p又轉(zhuǎn)而指向z[0]
這里簡要說一下為什么要用這個指針,在這個例子中當然看不出它的優(yōu)勢,但是一旦出現(xiàn)對一個數(shù)組的每一個元素依次進行計算或者是x中存放的內(nèi)容將會進行改變的情況,指針的方便就顯現(xiàn)出來了。還有需要依次存儲的時候,可以用數(shù)組下標來完成,也可以每次給地址+1,也就是用指針(這兩者的區(qū)別是用指針的時候程序執(zhí)行的速度更快,具體原理就不深入探究了,應(yīng)該就是微機接口那一套東西,指令時間指令長度之類的)。還有一種情況必須要用指針就是你想要對一個數(shù)組進行計算,但需要調(diào)用子函數(shù)計算,因此就需要將這個數(shù)組傳給調(diào)用函數(shù),在傳遞的時候,c語言語法規(guī)定的是數(shù)組的名字代表這個數(shù)組第一個元素的地址,因此在調(diào)用子函數(shù)的時候傳遞的是這個數(shù)組的第一個元素的地址(參見c語言程序設(shè)計84頁),這個時候你在編寫子函數(shù)的時候,局部變量的變量類型必須設(shè)置成指針,因為存放的是地址(參見85-86頁的例子)。其實到底什么時候用指針這個問題本人體會并不是非常深刻,所以就先寫到這里,如果以后遇到再添加進來。指針給我的感覺就像是打包裝箱一樣,這樣可以不用考慮長度啊,類型啊之類的問題,用起來還是比較方便的,當然前提是能用明白。。。
看書的時候還有一種感覺,正常將一個變量的值賦給另一個變量,就像將本地磁盤E中的文件復(fù)制粘貼到桌面上,無論我怎么對桌面上這個新文件進行操作,存在E盤中的那個原文件都不會被改變,但指針不一樣,指針就像是將E盤中的這個文件創(chuàng)建了桌面的快捷方式,你能夠看到它的路徑是E盤而不是c盤的桌面,在進行修改的時候也會直接影響到E盤中的那個原文件。忽然明白為什么說用指針會降低程序的可讀性了,因為你要是想要用這個指針,你就要追根溯源的去找它到底指向的是個什么東西而不是像變量那樣可以直接根據(jù)名字或者所賦的值來知道這個變量是個什么東西,而且也容易找著找著就蒙了。個人認為,當我們看到一個變量在使用的時候前面帶*,那么它應(yīng)該就是一個指針,我們就要去找這個指針指向的東西,找的時候如果看見這個指針=&一個什么東西,那它應(yīng)該就是指向這個東西了。
GPIO_InitTypeDef* GPIO_InitStruct:定義一個名叫GPIO_InitStruc的指針,指向GPIO_InitTypeDef型的數(shù)據(jù)。
整體來看這句話,就是我要調(diào)用這個初始化函數(shù)GPIO_Init(GPIOx,&GPIO_InitStructure);它要求我傳過去兩個參數(shù),一個是到底是哪個端口,是GPIOA還是B還是C還是什么,另一個是我要初始化的東西,由于初始化的參量比較多,于是就放在一個結(jié)構(gòu)體里面了關(guān)于結(jié)構(gòu)體,繼續(xù)看下文吧。
2.GPIO_InitTypeDefGPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=
GPIO_InitStructure.GPIO_Pin=
GPIO_InitStructure.GPIO_Speed=
這幾句話的意思:定義一個GPIO_InitTypeDef類型的結(jié)構(gòu),名字叫做GPIO_InitStructure(當然可以叫別的名字)這個結(jié)構(gòu)的成員(結(jié)構(gòu)中定義的變量叫做成員)包括三個:GPIO_Mode,GPIO_Pin和GPIO_Speed并進行了初始化。至于為什么是這三個,稍后會進行解釋。
在這里我們只是定義了一個結(jié)構(gòu),并沒有對里面的成員進行定義(里面的都是默認值,需要設(shè)置哪個再單獨去改),下面三行語句是引用了成員并對其進行了修改。
這里對結(jié)構(gòu)進行一下說明:
結(jié)構(gòu)是一個或者多個變量的集合,之前我們在用MSP430編程的時候,就體會過傳遞參數(shù)的時候一下子傳過去好多個,要加好多注釋,在matlab編程的時候也出現(xiàn)過這種狀況,在這里,采用了結(jié)構(gòu)(當然其他語言也采用了,之前沒用過結(jié)構(gòu)體也是因為我不會用,哦呵呵)。對于結(jié)構(gòu)成員的引用的格式有兩個:
(1)結(jié)構(gòu)名.成員,也就是后三行的引用方式。
(2)p->結(jié)構(gòu)成員,這個要求左邊的這個結(jié)構(gòu)必須為指針。若p是一個指向結(jié)構(gòu)的指針,那么可以用這種方式來引用相應(yīng)的結(jié)構(gòu)成員,在庫函數(shù)頭文件中采用的就是這種方式(當我們gotodefinition的時候就可以發(fā)現(xiàn)),但是在我們的.c文件中不可以這么寫,因為這里我們在進行定義的時候定義的是一個結(jié)構(gòu),是一個實體。
詳細內(nèi)容可以參照:http://www.cnblogs.com/winifred-tang94/p/5843440.html
(3)關(guān)于.和->的用法,有這樣一個規(guī)律:點.要求左邊的這個結(jié)構(gòu)必須為實體,箭頭->要求左邊的這個結(jié)構(gòu)必須為指針。
如果想要對一個結(jié)構(gòu)進行操作,有三種方法:一是分別傳遞各個成員,二是傳遞整個結(jié)構(gòu),三是傳遞指向結(jié)構(gòu)的指針。在這里就要再次提起剛剛討論過的那個初始化函數(shù)了,它的第二個變量傳遞的就是結(jié)構(gòu)體,并且采用的是第三種傳遞指針的方式。在結(jié)構(gòu)中使用指針的使用方法和普通變量的指針類似。
這里引用正點原子不完全手冊中的一個例子來解釋一下結(jié)構(gòu)體的優(yōu)勢:
在我們單片機程序開發(fā)過程中,經(jīng)常會遇到要初始化一個外設(shè)比如串口,它的初始化狀態(tài)是由幾個屬性來決定的,比如串口號,波特率,極性,以及模式。對于這種情況,在我們沒有 學習結(jié)構(gòu)體的時候,我們一般的方法是:
void USART_Init(u8 usartx,u32 u32 BaudRate,u8 parity,u8 mode);
這種方式是有效的,同時在一定場合是可取的。但是試想,如果有一天,我們希望往這個函數(shù)里 面再傳入一個參數(shù),那么勢必我們需要修改這個函數(shù)的定義,重新加入字長這個入口參數(shù)。于是我們的定義被修改為:
void USART_Init (u8 usartx,u32 BaudRate, u8 parity,u8 mode,u8 wordlength );
但是如果我們這個函數(shù)的入口參數(shù)是隨著開發(fā)不斷的增多,那么是不是我們就要不斷的修改函 數(shù)的定義呢?這是不是給我們開發(fā)帶來很多的麻煩?那又怎樣解決這種情況呢? 這樣如果我們使用到結(jié)構(gòu)體就能解決這個問題了。我們可以在不改變?nèi)肟趨?shù)的情況下, 只需要改變結(jié)構(gòu)體的成員變量,就可以達到上面改變?nèi)肟趨?shù)的目的。
結(jié)構(gòu)體就是將多個變量組合為一個有機的整體。上面的函數(shù),BaudRate,wordlength, Parity,mode,wordlength 這些參數(shù),他們對于串口而言,是一個有機整體,都是來設(shè)置串口參 數(shù)的,所以我們可以將他們通過定義一個結(jié)構(gòu)體來組合在一個。MDK 中是這樣定義的:
typedef struct
{
uint32_t USART_BaudRate;
uint16_t USART_WordLength;
uint16_t USART_StopBits;
uint16_t USART_Parity;
uint16_t USART_Mode;
uint16_t USART_HardwareFlowControl;
} USART_InitTypeDef;
于是,我們在初始化串口的時候入口參數(shù)就可以是 USART_InitTypeDef 類型的變量或者指針變 量了,MDK 中是這樣做的:
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
這樣,任何時候,我們只需要修改結(jié)構(gòu)體成員變量,往結(jié)構(gòu)體中間加入新的成員變量,而不需 要修改函數(shù)定義就可以達到修改入口參數(shù)同樣的目的了。這樣的好處是不用修改任何函數(shù)定義 就可以達到增加變量的目的。
在這里要說一下typedef函數(shù),這是一個類型定義函數(shù),可以用來建立新的數(shù)據(jù)類型名。用法為:
typedef舊的類型名新的類型名;
實際上這個函數(shù)并沒有新出現(xiàn)一個什么新的東西,只是在原來的基礎(chǔ)上命了新名字,作用類似于#define,但比define的功能更加強大,可以定義更多的東西。
舉個例子,我們看這段程序的第一句話,也就是定義了一個GPIO_InitTypeDef類型的結(jié)構(gòu),我們這里并不知道這個GPIO_InitTypeDef類型是個什么類型,那么我們?nèi)otodefinition,這樣就可以看到,在stm32f10x_gpio.h文件中存在著typedef定義的一個結(jié)構(gòu),里面包含了三個成員,GPIO_Mode,GPIO_Pin和GPIO_Speed,這也就解釋了為什么我們要對這幾個進行賦值,對于其中的一個成員GPIO_Pin,我們可以看到,是一個uint16_t類型的數(shù)據(jù),到這里我們?nèi)匀徊恢肋@到底是個什么類型的數(shù)據(jù),因為c語言中就只有int,char之類的類型,那么我們就再繼續(xù)gotodefinition,就可以在stdint.h文件中看到這樣一行語句:typedef unsigned shortint uint16_t;這句話我們可以類比typedef unsigned char uchar來看,用uchar代替unsigned char,這種方式在我們編寫msp430的時候經(jīng)常會用,只不過那時候用的是define。這樣我們就明白了,GPIO_Pin是一個無符號短整型的數(shù)據(jù),這和我們對430編程的時候的int x=0x00;中的x是一樣的。
到這里我們已經(jīng)剖開這個函數(shù)的層層外殼看到了最原始的定義,這也就和我們當時編寫c51,msp430的時候自己定義的那些東西差不多了,而對于stm32來說,它的復(fù)雜程度已經(jīng)遠遠超過了那兩個單片機,所以stm公司自己在出廠的時候就把許多函數(shù)打包好了,經(jīng)過層層包裝來到我們面前的這個函數(shù)庫,忽然覺得好震撼,這是一個多么龐大的工程啊,我們簡直是站在巨人的肩膀上。(咳咳,跑題了。。。)
就舉這一個例子,我實際操作又去看了一些其他的函數(shù),發(fā)現(xiàn)后面帶著TypeDef的東西都可以在gotodefinition的時候發(fā)現(xiàn)下一層函數(shù),剛才舉例的那個GPIO_Pin是屬于包裝層數(shù)少的了。
現(xiàn)在我們再回頭來看這四行代碼,疑問就可以解答了,整理如下:
為什么要定義一個結(jié)構(gòu)呢?
GPIO_Init函數(shù)要求我們傳遞過去一個結(jié)構(gòu)的地址,因此我們要在外面定義一個結(jié)構(gòu)。
為什么是GPIO_Pin,GPIO_Speed和GPIO_Mode這三個變量呢?
因為在我們?nèi)サ紾PIO_Init函數(shù)里面的時候,看到它的第二個參量GPIO_InitTypeDef*GPIO_StructInit,這里定義了傳過來的這個結(jié)構(gòu)的類型,就是GPIO_InitTypeDef,我們再goto去看GPIO_InitTypeDef是什么類型的時候會發(fā)現(xiàn)它被定義成一個包含這三個成員的結(jié)構(gòu)體,因此,我們在賦值的時候就要賦給這三個變量。
如果不賦值會怎樣?
如果不賦值,那么這個結(jié)構(gòu)體就默認為stm公司設(shè)置的初值,這個初值也可以看到,在GPIO_Init函數(shù)里面,查看它的第二個參量GPIO_InitTypeDef*GPIO_StructInit的GPIO_StructInit,可以看到它的初始值,pin_all,2MHz和IN_FLOTING。
那么究竟要給這三個成員賦怎樣的初值呢?
這個的確定,我們需要用到一個工具,那就是技術(shù)手冊或是什么別的手冊,上面在講到GPIO都會仔細的說明每種工作方式,工作速度的區(qū)別我們要用哪個模式和速度,是由我們具體要做什么東西來確定的,而具體使用哪個引腳則需要通過查找硬件電路圖來確定。
選好想要的模式之后,具體的程序要怎么寫呢,有什么格式的要求嗎?
這就是對結(jié)構(gòu)體成員的賦值問題了。這個我們可以參照剛剛看到的stm給的初值的形式,但要注意使用點(.)而不是箭頭(->)。舉個例子,如Speed,在我們回答第二個問題的時候,我們可以看到stm定義的結(jié)構(gòu)體中的GPIO_Speed的類型為GPIOSpeed_TypeDef,當然我們不知道這是一個什么類型,我們gotodefinition去看一下,可以看到stm用typedef定義了一個enum(枚舉類型)的東西,這里面包括三個:GPIO_Speed_10MHz, GPIO_Speed_2MHz,GPIO_Speed_50MHz,因此我們可以知道,這個speed只有這三個值可以賦,并且不能夠?qū)懗?0,50之類的任意格式,而必須是GPIO_Speed_10MHz,GPIO_Speed_2MHz,GPIO_Speed_50MHz其中的一個,假設(shè)說我們選擇的是50MHz的速度,那么就要寫成‘結(jié)構(gòu)體名.GPIO_Speed_50MHz’的形式。對于工作模式的設(shè)置也是一樣,goto之后就可以看到它也是一個枚舉類型,里面包含八個成員。
解釋到這里,這四句的意思大概已經(jīng)清楚了。
還有一點要說的,c語言中規(guī)定所有的變量、結(jié)構(gòu)體的聲明(定義)都必須在代碼段之前,就像我們之前define都要寫在最上面一樣,因此第一句的結(jié)構(gòu)定義放在了最前面。
3.GPIO_SetBits(GPIOx,GPIO_Pin_x);
這句話比較好理解,設(shè)置LED默認不點亮,置1是不點亮,至于為什么,看電路圖就明白了,LED的正連的高電平,負連的管腳。
對于程序的解析到此為止。
附加說明一個問題,我們是如何知道要用這些函數(shù)呢,比如GPIO_SetBits這個函數(shù)。其實和GPIO有關(guān)的函數(shù)有一個匯總,就在stm32f10x_gpio.h文件的最下面,有許多的函數(shù),我們大致看一眼就可以知道那個函數(shù)是做什么用的,因為已經(jīng)經(jīng)過層層包裝,名字已經(jīng)很好辨認了,就像SetBits函數(shù),很明顯是置位用的。(這里總覺得不太對勁,應(yīng)該還有什么別的方式來查找函數(shù)的)在這里我們也可以基本看到這個函數(shù)的格式,需要哪些參數(shù),例如void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);可以看出來我們需要給它兩個參數(shù),一個是GPIOx,一個是pinx,如PA8就是GPIOA,GPIO_Pin_8。這里要說明的是,我們在使用原子家的mini板的時候,往往不會自己親自動手從頭再去編寫初始化什么的東西,而是可以參考他給的例程,進行加工和修改。
我們剛剛編寫.c和.h文件,性質(zhì)上和stm32的開發(fā)者一樣,都是在給程序打包裝箱,只不過stm32給出的函數(shù)庫更加的通用,而我們寫的這兩個文件比較有針對性。
3.main.c的編寫
(1)include各個需要的文件
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
(2)編寫main主函數(shù):
一般情況下,main中包含兩部分:
用到的各個部分的初始化,在本實驗中包括led的初始化(也就是剛剛在led.c里面寫的那個初始化函數(shù)),delay(延時)函數(shù)的初始化
delay_init();
led_Init();
while函數(shù),基本上我們需要的函數(shù)都會放在while(1){ }里面,因為我們要讓它一直執(zhí)行,而不是執(zhí)行一次就完事了,但是對于比較復(fù)雜的函數(shù),往往不是這個樣子的,會有許多的判斷條件。
while(1)
{
GPIO_SetBits(GPIOA,GPIO_Pin_8);//設(shè)置LED默認不點亮
delay_ms(500);
GPIO_ResetBits(GPIOA,GPIO_Pin_8);//設(shè)置LED默認不點亮
delay_ms(500);
}
說明:本實驗中,main函數(shù)的返回值類型是int型的,而不是void型的,void是空,是不提供返回值的意思
這里要寫成int main (void){}
這里需要說明一下:c語言規(guī)定不接收任何參數(shù)也不返回任何信息的函數(shù)原型為“void foo(void);”。可能正是因為這個,所以很多人都誤認為如果不需要程序返回值時可以把main函數(shù)定義成void main(void) 。然而這是錯誤的!c語言規(guī)定main 函數(shù)的返回值應(yīng)該定義為 int 類型。雖然在一些編譯器中,void main 可以通過編譯(如我們用IAR寫msp430的時候),但并非所有編譯器都支持 void main(如我們現(xiàn)在用的keil),因為標準中從來沒有定義過 void main 。
main 函數(shù)的返回值類型必須是 int ,這樣返回值才能傳遞給程序的激活者(如操作系統(tǒng)),如果 main 函數(shù)的最后沒有寫 return 語句的話,C99 規(guī)定編譯器要自動在生成的目標文件中(如 exe 文件)加入return 0; 。main函數(shù)的返回值用于說明程序的退出狀態(tài)。如果返回0,則代表程序正常退出。返回其它數(shù)字的含義則由系統(tǒng)決定。通常,返回非零代表程序異常退出。
更加詳細的解釋可以參考:http://blog.csdn.net/piaojun_pj/article/details/5986516
PS:
1.go to Definition 的時候會出現(xiàn)以下這種情況,解決辦法:在name下面任意雙擊其中一個就可以跳過去,但具體我們要找的是哪一個,需要自己去判斷。