版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、STM32 開(kāi)發(fā)基礎(chǔ)知識(shí)開(kāi)發(fā)基礎(chǔ)知識(shí)MDK 下下 C 語(yǔ)言基礎(chǔ)復(fù)習(xí)語(yǔ)言基礎(chǔ)復(fù)習(xí) STM32 系統(tǒng)架構(gòu)系統(tǒng)架構(gòu) STM32 時(shí)鐘系統(tǒng)時(shí)鐘系統(tǒng) 端口復(fù)用和重映射端口復(fù)用和重映射 STM32 NVIC 中斷管理中斷管理 MDK 中寄存器地址名稱映射分析中寄存器地址名稱映射分析 MDK 固件庫(kù)快速開(kāi)發(fā)技巧固件庫(kù)快速開(kāi)發(fā)技巧MDK 下下 C 語(yǔ)言基礎(chǔ)復(fù)習(xí)語(yǔ)言基礎(chǔ)復(fù)習(xí)位操作位操作位操作在單片機(jī)開(kāi)發(fā)中的一些實(shí)用技巧位操作在單片機(jī)開(kāi)發(fā)中的一些實(shí)用技巧不改變其他位的值的狀況下,對(duì)某幾個(gè)位進(jìn)行設(shè)值。不改變其他位的值的狀況下,對(duì)某幾個(gè)位進(jìn)行設(shè)值。 這個(gè)場(chǎng)景單片機(jī)開(kāi)發(fā)中經(jīng)常使用,方法就是先對(duì)需要設(shè)置的位用這個(gè)場(chǎng)景單片
2、機(jī)開(kāi)發(fā)中經(jīng)常使用,方法就是先對(duì)需要設(shè)置的位用&操作符進(jìn)行清零操作,然后用操作符進(jìn)行清零操作,然后用| 操作符設(shè)值。比如我要改變操作符設(shè)值。比如我要改變 GPIOA 的狀態(tài)的狀態(tài), 可以先對(duì)寄存器的值進(jìn)行可以先對(duì)寄存器的值進(jìn)行&清零操作清零操作GPIOA-CRL&=0XFFFFFF0F; /將第將第 4-7 位清位清 0然后再與需要設(shè)置的值進(jìn)行然后再與需要設(shè)置的值進(jìn)行| 或運(yùn)算或運(yùn)算GPIOA-CRL|=0X00000040; /設(shè)置相應(yīng)位的值,不改變其他位的值設(shè)置相應(yīng)位的值,不改變其他位的值移位操作提高代碼的可讀性移位操作提高代碼的可讀性移位操作在單片機(jī)開(kāi)發(fā)中也非常重要,下面讓我們看看固件庫(kù)移
3、位操作在單片機(jī)開(kāi)發(fā)中也非常重要,下面讓我們看看固件庫(kù)的的 GPIO 初始化的函數(shù)里面的一行代碼初始化的函數(shù)里面的一行代碼GPIOx-BSRR = (uint32_t)0 x01) BSRR =0 x0030;這樣的代碼就不好看也不好重用了。這樣的代碼就不好看也不好重用了。類似這樣的代碼很多類似這樣的代碼很多:GPIOA-ODR|=15; /PA.5 輸出高輸出高,不改變其他位不改變其他位這樣我們一目了然,這樣我們一目了然, 5 告訴我們是第告訴我們是第 5 位也就是第位也就是第 6 個(gè)端口,個(gè)端口, 1 告訴我們是設(shè)置為告訴我們是設(shè)置為 1 了。了。uint8_t / uint16_t / u
4、int32_t /uint64_t 是什么數(shù)據(jù)類型是什么數(shù)據(jù)類型這些數(shù)據(jù)類型是這些數(shù)據(jù)類型是 C99 中定義的,具體定義在:中定義的,具體定義在:/usr/include/stdint.h ISO C99: 7.18 Integer types 取反操作使用技巧取反操作使用技巧SR 寄存器的每一位都代表一個(gè)狀態(tài),某個(gè)時(shí)刻我們希望去設(shè)置寄存器的每一位都代表一個(gè)狀態(tài),某個(gè)時(shí)刻我們希望去設(shè)置某一位的值為某一位的值為 0,同時(shí)其他位都保留為,同時(shí)其他位都保留為 1,簡(jiǎn)單的作法是直接給,簡(jiǎn)單的作法是直接給寄存器設(shè)置一個(gè)值:寄存器設(shè)置一個(gè)值:TIMx-SR=0 xFFF7;這樣的作法設(shè)置第這樣的作法設(shè)置第
5、 3 位為位為 0,但是這樣的作法同樣不好看,并且,但是這樣的作法同樣不好看,并且可讀性很差??纯磶?kù)函數(shù)代碼中怎樣使用的:可讀性很差。看看庫(kù)函數(shù)代碼中怎樣使用的:TIMx-SR = (uint16_t)TIM_FLAG;而而 TIM_FLAG 是通過(guò)宏定義定義的值:是通過(guò)宏定義定義的值:#define TIM_FLAG_Update (uint16_t)0 x0001)#define TIM_FLAG_CC1 (uint16_t)0 x0002)看這個(gè)應(yīng)該很容易明白,可以直接從宏定義中看出看這個(gè)應(yīng)該很容易明白,可以直接從宏定義中看出 TIM_FLAG_Update 就是設(shè)置的第就是設(shè)置的第 0
6、 位了,可讀性非常強(qiáng)。位了,可讀性非常強(qiáng)。define 宏定義宏定義define 是是 C 語(yǔ)言中的預(yù)處理命令,它用于宏定義,可以提高源語(yǔ)言中的預(yù)處理命令,它用于宏定義,可以提高源代碼的可讀性,為編程提供方便。常見(jiàn)的格式:代碼的可讀性,為編程提供方便。常見(jiàn)的格式:#define 標(biāo)識(shí)符標(biāo)識(shí)符 字符串字符串“標(biāo)識(shí)符標(biāo)識(shí)符”為所定義的宏名。為所定義的宏名?!白址址笨梢允浅?shù)、表達(dá)式、可以是常數(shù)、表達(dá)式、格式串等。例如:格式串等。例如:#define SYSCLK_FREQ_72MHz 72000000定義標(biāo)識(shí)符定義標(biāo)識(shí)符 SYSCLK_FREQ_72MHz 的值為的值為 72000000。
7、ifdef條件編譯條件編譯單片機(jī)程序開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)遇到一種情況,單片機(jī)程序開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)遇到一種情況, 當(dāng)滿足某條件當(dāng)滿足某條件時(shí)對(duì)一組語(yǔ)句進(jìn)行編譯,而時(shí)對(duì)一組語(yǔ)句進(jìn)行編譯,而當(dāng)條件不滿足時(shí)則編譯另一組語(yǔ)句。當(dāng)條件不滿足時(shí)則編譯另一組語(yǔ)句。 條件編譯命令最常見(jiàn)的形條件編譯命令最常見(jiàn)的形式為:式為:#ifdef 標(biāo)識(shí)符標(biāo)識(shí)符程序段程序段 1#else程序段程序段 2#endif它的作用是:當(dāng)標(biāo)識(shí)符已經(jīng)被定義過(guò)它的作用是:當(dāng)標(biāo)識(shí)符已經(jīng)被定義過(guò)(一般是用一般是用#define 命令命令定義定義) ,則對(duì)程序段,則對(duì)程序段 1 進(jìn)行編譯,進(jìn)行編譯,否則編譯程序段否則編譯程序段 2。 其中其中#
8、else 部分也可以沒(méi)有,即:部分也可以沒(méi)有,即:#ifdef程序段程序段 1#endif這個(gè)條件編譯在這個(gè)條件編譯在 MDK 里面是用得很多的,在里面是用得很多的,在 stm32f10 x.h 這個(gè)頭文件中經(jīng)常會(huì)看到這樣的語(yǔ)句:這個(gè)頭文件中經(jīng)常會(huì)看到這樣的語(yǔ)句:#ifdef STM32F10X_HD大容量芯片需要的一些變量定義大容量芯片需要的一些變量定義#end而而 STM32F10X_HD 則是我們通過(guò)則是我們通過(guò)#define 來(lái)定義的。來(lái)定義的。extern 變量申明變量申明C 語(yǔ)言中語(yǔ)言中 extern 可以置于變量或者函數(shù)前,以表示變量或者函數(shù)可以置于變量或者函數(shù)前,以表示變量或者
9、函數(shù)的定義在別的文件中,提示編譯器遇到此變量和函數(shù)時(shí)在其他模的定義在別的文件中,提示編譯器遇到此變量和函數(shù)時(shí)在其他模塊中尋找其定義。塊中尋找其定義。 這里面要注意,對(duì)于這里面要注意,對(duì)于 extern 申明變量可以多申明變量可以多次,但定義只有一次。在我們的代碼中你會(huì)看到看到這樣的語(yǔ)句:次,但定義只有一次。在我們的代碼中你會(huì)看到看到這樣的語(yǔ)句:extern u16 USART_RX_STA;這個(gè)語(yǔ)句是申明這個(gè)語(yǔ)句是申明 USART_RX_STA 變量在其他文件中已經(jīng)定義了,變量在其他文件中已經(jīng)定義了,在這里要使用到。所以,你肯定可以找到在某個(gè)地方有變量定義在這里要使用到。所以,你肯定可以找到在
10、某個(gè)地方有變量定義的語(yǔ)句:的語(yǔ)句:u16 USART_RX_STA;的出現(xiàn)。下面通過(guò)一個(gè)例子說(shuō)明一下使用方法。的出現(xiàn)。下面通過(guò)一個(gè)例子說(shuō)明一下使用方法。引出引出IO口口在在 Main.c 定義的全局變量定義的全局變量 id, id 的初始化都是在的初始化都是在 Main.c 里面里面進(jìn)行的。進(jìn)行的。Main.c 文件文件u8 id;/定義只允許一次定義只允許一次main()id=1;printf(d%,id);/id=1test();printf(d%,id);/id=2但是我們希望在但是我們希望在 test.c 的的 changeId(void) 函數(shù)中使用變量函數(shù)中使用變量 id, 這這個(gè)
11、時(shí)候我們就需要在個(gè)時(shí)候我們就需要在 test.c里面去申明變量里面去申明變量 id 是外部定義的了,是外部定義的了,因?yàn)槿绻簧昝?,變量因?yàn)槿绻簧昝?,變?id 的作用域是到不了的作用域是到不了 test.c 文件中。文件中??聪旅婵聪旅?test.c 中的代碼:中的代碼:extern u8 id;/申明變量申明變量 id 是在外部定義的,申明可以在是在外部定義的,申明可以在很很 多個(gè)文件中進(jìn)行多個(gè)文件中進(jìn)行void test(void) id=2;在在 test.c 中申明變量中申明變量 id 在外部定義,然后在在外部定義,然后在 test.c 中就可中就可以使用變量以使用變量 id 了。
12、了。對(duì)于對(duì)于 extern 申明函數(shù)在外部定義的應(yīng)用,這里我們就不多申明函數(shù)在外部定義的應(yīng)用,這里我們就不多講解了。講解了。typedef類型別名類型別名typedef 用于為現(xiàn)有類型創(chuàng)建一個(gè)新的名字,或稱為類型別名,用來(lái)用于為現(xiàn)有類型創(chuàng)建一個(gè)新的名字,或稱為類型別名,用來(lái)簡(jiǎn)化變量的定義。簡(jiǎn)化變量的定義。typedef 在在 MDK 用得最多的就是定義結(jié)構(gòu)體的類型別名和枚舉類型用得最多的就是定義結(jié)構(gòu)體的類型別名和枚舉類型了。了。struct _GPIO_IO uint32_t CRL;_IO uint32_t CRH;定義了一個(gè)結(jié)構(gòu)體定義了一個(gè)結(jié)構(gòu)體 GPIO,這樣我們定義變量的方式為:,這樣
13、我們定義變量的方式為:struct _GPIO GPIOA; /定義結(jié)構(gòu)體變量定義結(jié)構(gòu)體變量 GPIOA但是這樣很繁瑣,但是這樣很繁瑣, MDK 中有很多這樣的結(jié)構(gòu)體變量需要定義。這里中有很多這樣的結(jié)構(gòu)體變量需要定義。這里我們可以為結(jié)體定義一個(gè)別名我們可以為結(jié)體定義一個(gè)別名 GPIO_TypeDef,這樣我們就可以在其,這樣我們就可以在其他地方通過(guò)別名他地方通過(guò)別名 GPIO_TypeDef 來(lái)定義結(jié)構(gòu)體變量了。來(lái)定義結(jié)構(gòu)體變量了。方法如下:方法如下:typedef struct_IO uint32_t CRL;_IO uint32_t CRH; GPIO_TypeDef;Typedef 為結(jié)
14、構(gòu)體定義一個(gè)別名為結(jié)構(gòu)體定義一個(gè)別名 GPIO_TypeDef,這樣我們可,這樣我們可以通過(guò)以通過(guò) GPIO_TypeDef 來(lái)定義結(jié)構(gòu)體來(lái)定義結(jié)構(gòu)體變量:變量:GPIO_TypeDef _GPIOA,_GPIOB;這里的這里的 GPIO_TypeDef 就跟就跟 struct _GPIO 是等同的作用了。是等同的作用了。 這樣是不是方便很多?這樣是不是方便很多?結(jié)構(gòu)體結(jié)構(gòu)體經(jīng)常很多用戶提到,他們對(duì)結(jié)構(gòu)體使用不是很熟悉,但是經(jīng)常很多用戶提到,他們對(duì)結(jié)構(gòu)體使用不是很熟悉,但是 MDK 中太多地方使用結(jié)構(gòu)體以及結(jié)構(gòu)體指針,這讓他們一下中太多地方使用結(jié)構(gòu)體以及結(jié)構(gòu)體指針,這讓他們一下子摸不著頭腦,學(xué)
15、習(xí)子摸不著頭腦,學(xué)習(xí) STM32 的積極性大大降低,其實(shí)結(jié)構(gòu)體的積極性大大降低,其實(shí)結(jié)構(gòu)體并不是那么復(fù)雜,這里我們稍微提一下結(jié)構(gòu)體的一些知識(shí),并不是那么復(fù)雜,這里我們稍微提一下結(jié)構(gòu)體的一些知識(shí),還有一些知識(shí)我們會(huì)在下一節(jié)的還有一些知識(shí)我們會(huì)在下一節(jié)的“寄存器地址名稱映射分析寄存器地址名稱映射分析”中講到一些。中講到一些。聲明結(jié)構(gòu)體類型:聲明結(jié)構(gòu)體類型:Struct 結(jié)構(gòu)體名結(jié)構(gòu)體名 成員列表成員列表;變量名列表;變量名列表;例如:例如:Struct U_TYPE Int BaudRate Int WordLength;usart1,usart2;在結(jié)構(gòu)體申明的時(shí)候可以定義變量,也可以申明之后定
16、義,方在結(jié)構(gòu)體申明的時(shí)候可以定義變量,也可以申明之后定義,方法是:法是:Struct 結(jié)構(gòu)體名字結(jié)構(gòu)體名字 結(jié)構(gòu)體變量列表結(jié)構(gòu)體變量列表 ;例如:例如: struct U_TYPE usart1, usart2;結(jié)構(gòu)體成員變量的引用方法是:結(jié)構(gòu)體成員變量的引用方法是:結(jié)構(gòu)體變量名字結(jié)構(gòu)體變量名字.成員名成員名比如要引用比如要引用 usart1 的成員的成員 BaudRate,方法是:,方法是: usart1.BaudRate;結(jié)構(gòu)體指針變量定義也是一樣的,跟其他變量沒(méi)有啥區(qū)別。結(jié)構(gòu)體指針變量定義也是一樣的,跟其他變量沒(méi)有啥區(qū)別。例如:例如: struct U_TYPE *usart3; /定義
17、結(jié)構(gòu)體指針變量定義結(jié)構(gòu)體指針變量 usart1;結(jié)構(gòu)體指針成員變量引用方法是通過(guò)結(jié)構(gòu)體指針成員變量引用方法是通過(guò)“-”符號(hào)實(shí)現(xiàn),比如要符號(hào)實(shí)現(xiàn),比如要訪問(wèn)訪問(wèn) usart3 結(jié)構(gòu)體指針指向的結(jié)結(jié)構(gòu)體指針指向的結(jié)構(gòu)體的成員變量構(gòu)體的成員變量 BaudRate, 方法是:方法是:Usart3-BaudRate;上面講解了結(jié)構(gòu)體和結(jié)構(gòu)體指針的一些知識(shí),其他的什么初上面講解了結(jié)構(gòu)體和結(jié)構(gòu)體指針的一些知識(shí),其他的什么初始化這里就不多講解了。始化這里就不多講解了。 講到這里,有人會(huì)問(wèn),結(jié)構(gòu)體到底講到這里,有人會(huì)問(wèn),結(jié)構(gòu)體到底有什么作用呢?為什么要使用結(jié)構(gòu)體呢?下面我們將簡(jiǎn)單的有什么作用呢?為什么要使用結(jié)構(gòu)
18、體呢?下面我們將簡(jiǎn)單的通過(guò)一個(gè)實(shí)例回答一下這個(gè)問(wèn)題。通過(guò)一個(gè)實(shí)例回答一下這個(gè)問(wèn)題。在我們單片機(jī)程序開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)遇到要初始化一個(gè)外設(shè)在我們單片機(jī)程序開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)遇到要初始化一個(gè)外設(shè)比如串口,它的初始化狀態(tài)是由幾個(gè)屬性來(lái)決定的,比如串口比如串口,它的初始化狀態(tài)是由幾個(gè)屬性來(lái)決定的,比如串口號(hào),波特率,極性,以及模式。對(duì)于這種情況,在我們沒(méi)有學(xué)號(hào),波特率,極性,以及模式。對(duì)于這種情況,在我們沒(méi)有學(xué)習(xí)結(jié)構(gòu)體的時(shí)候,我們一般的方法是:習(xí)結(jié)構(gòu)體的時(shí)候,我們一般的方法是:void USART_Init(u8 usartx,u32 u32 BaudRate,u8 parity,u8 mode);這
19、種方式是有效的同時(shí)在一定場(chǎng)合是可取的。但是試想,如果這種方式是有效的同時(shí)在一定場(chǎng)合是可取的。但是試想,如果有一天,我們希望往這個(gè)函數(shù)里面再傳入一個(gè)參數(shù),那么勢(shì)必有一天,我們希望往這個(gè)函數(shù)里面再傳入一個(gè)參數(shù),那么勢(shì)必我們需要修改這個(gè)函數(shù)的定義,重新加入字長(zhǎng)這個(gè)入口參數(shù)。我們需要修改這個(gè)函數(shù)的定義,重新加入字長(zhǎng)這個(gè)入口參數(shù)。于是我們的定義被修改為:于是我們的定義被修改為:void USART_Init (u8 usartx,u32 BaudRate, u8 parity,u8 mode,u8 wordlength );但是如果我們這個(gè)函數(shù)的入口參數(shù)是隨著開(kāi)發(fā)不斷的增多,那但是如果我們這個(gè)函數(shù)的入口
20、參數(shù)是隨著開(kāi)發(fā)不斷的增多,那么是不是我們就要不斷的修改函數(shù)的定義呢?這是不是給我們么是不是我們就要不斷的修改函數(shù)的定義呢?這是不是給我們開(kāi)發(fā)帶來(lái)很多的麻煩?那又怎樣解決這種情況呢?開(kāi)發(fā)帶來(lái)很多的麻煩?那又怎樣解決這種情況呢?這樣如果我們使用到結(jié)構(gòu)體就能解決這個(gè)問(wèn)題了。我們可以這樣如果我們使用到結(jié)構(gòu)體就能解決這個(gè)問(wèn)題了。我們可以在不改變?nèi)肟趨?shù)的情況下,只需要改變結(jié)構(gòu)體的成員變量,在不改變?nèi)肟趨?shù)的情況下,只需要改變結(jié)構(gòu)體的成員變量,就可以達(dá)到上面改變?nèi)肟趨?shù)的目的。結(jié)構(gòu)體就是將多個(gè)變就可以達(dá)到上面改變?nèi)肟趨?shù)的目的。結(jié)構(gòu)體就是將多個(gè)變量組合為一個(gè)有機(jī)的整體。上面的函數(shù)量組合為一個(gè)有機(jī)的整體。上
21、面的函數(shù), BaudRate, wordlength, Parity, mode, wordlength 這些參數(shù),他們對(duì)于串這些參數(shù),他們對(duì)于串口而言,是一個(gè)有機(jī)整體,都是來(lái)設(shè)置串口參數(shù)的,所以我口而言,是一個(gè)有機(jī)整體,都是來(lái)設(shè)置串口參數(shù)的,所以我們可以將他們通過(guò)定義一個(gè)結(jié)構(gòu)體來(lái)組合在一個(gè)。們可以將他們通過(guò)定義一個(gè)結(jié)構(gòu)體來(lái)組合在一個(gè)。 MDK 中中是這樣定義的:是這樣定義的:typedef structuint32_t USART_BaudRate;uint16_t USART_WordLength;uint16_t USART_StopBits;uint16_t USART_Parity;
22、uint16_t USART_Mode;uint16_t USART_HardwareFlowControl; USART_InitTypeDef;于是,我們?cè)诔跏蓟诘臅r(shí)候入口參數(shù)就可以是于是,我們?cè)诔跏蓟诘臅r(shí)候入口參數(shù)就可以是 USART_InitTypeDef 類型的變量或者指針變量了,類型的變量或者指針變量了, MDK 中是中是這樣做的:這樣做的:void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);這樣,任何時(shí)候,我們只需要修改結(jié)構(gòu)體成員變量,往這樣,任何時(shí)候,我們只需要修改結(jié)構(gòu)體
23、成員變量,往結(jié)構(gòu)體中間加入新的成員變量,而不需要修改函數(shù)定義就可以結(jié)構(gòu)體中間加入新的成員變量,而不需要修改函數(shù)定義就可以達(dá)到修改入口參數(shù)同樣的目的了。達(dá)到修改入口參數(shù)同樣的目的了。 這樣的好處是不用修改任何這樣的好處是不用修改任何函數(shù)定義就可以達(dá)到增加變量的目的。函數(shù)定義就可以達(dá)到增加變量的目的。在以后的開(kāi)發(fā)過(guò)程中,如果你的變量定義過(guò)多,如果某在以后的開(kāi)發(fā)過(guò)程中,如果你的變量定義過(guò)多,如果某幾個(gè)變量是用來(lái)描述某一個(gè)對(duì)象,你可以考慮將這些變量定義幾個(gè)變量是用來(lái)描述某一個(gè)對(duì)象,你可以考慮將這些變量定義在結(jié)構(gòu)體中,這樣也許可以提高你的代碼的可讀性。使用結(jié)構(gòu)在結(jié)構(gòu)體中,這樣也許可以提高你的代碼的可讀性
24、。使用結(jié)構(gòu)體組合參數(shù),可以提高代碼的可讀性,不會(huì)覺(jué)得變量定義混亂。體組合參數(shù),可以提高代碼的可讀性,不會(huì)覺(jué)得變量定義混亂。STM32 系統(tǒng)架構(gòu)系統(tǒng)架構(gòu)STM32 主系統(tǒng)主要由四個(gè)驅(qū)動(dòng)單元和四個(gè)被動(dòng)單元構(gòu)成。主系統(tǒng)主要由四個(gè)驅(qū)動(dòng)單元和四個(gè)被動(dòng)單元構(gòu)成。四個(gè)驅(qū)動(dòng)單元是:四個(gè)驅(qū)動(dòng)單元是:內(nèi)核內(nèi)核 DCode 總線總線;系統(tǒng)總線系統(tǒng)總線;通用通用 DMA1;通用通用 DMA2;四被動(dòng)單元是:四被動(dòng)單元是:AHB 到到 APB 的橋:連接所有的的橋:連接所有的 APB 設(shè)備;設(shè)備;內(nèi)部?jī)?nèi)部 FlASH 閃存;閃存;內(nèi)部?jī)?nèi)部 SRAM;FSMC; ICode 總線:該總線將總線:該總線將 M3 內(nèi)核指令總
25、線和閃存指令接口相內(nèi)核指令總線和閃存指令接口相連,指令的預(yù)取在該總線上面完成。連,指令的預(yù)取在該總線上面完成。 DCode 總線:該總線將總線:該總線將 M3 內(nèi)核的內(nèi)核的 DCode 總線與閃存存儲(chǔ)總線與閃存存儲(chǔ)器的數(shù)據(jù)接口相連接,常量加載和調(diào)試訪問(wèn)在該總線上面完成。器的數(shù)據(jù)接口相連接,常量加載和調(diào)試訪問(wèn)在該總線上面完成。 系統(tǒng)總線:該總線連接系統(tǒng)總線:該總線連接 M3 內(nèi)核的系統(tǒng)總線到總線矩陣,總內(nèi)核的系統(tǒng)總線到總線矩陣,總線矩陣協(xié)調(diào)內(nèi)核和線矩陣協(xié)調(diào)內(nèi)核和 DMA 間訪問(wèn)。間訪問(wèn)。 DMA 總線:該總線將總線:該總線將 DMA 的的 AHB 主控接口與總線矩陣相主控接口與總線矩陣相連,總線
26、矩陣協(xié)調(diào)連,總線矩陣協(xié)調(diào) CPU 的的DCode 和和 DMA 到到 SRAM,閃存和外閃存和外設(shè)的訪問(wèn)。設(shè)的訪問(wèn)。 總線矩陣:總線矩陣協(xié)調(diào)內(nèi)核系統(tǒng)總線和總線矩陣:總線矩陣協(xié)調(diào)內(nèi)核系統(tǒng)總線和 DMA 主控總線之主控總線之間的訪問(wèn)仲裁,仲裁利用輪換算法。間的訪問(wèn)仲裁,仲裁利用輪換算法。 AHB/APB 橋橋:這兩個(gè)橋在這兩個(gè)橋在 AHB 和和 2 個(gè)個(gè) APB 總線間提供同總線間提供同步連接,步連接, APB1 操作速度限于操作速度限于36MHz, APB2 操作速度全速。操作速度全速。STM32 時(shí)鐘系統(tǒng)時(shí)鐘系統(tǒng)眾所周知,時(shí)鐘系統(tǒng)是眾所周知,時(shí)鐘系統(tǒng)是 CPU 的脈搏,就像人的心跳一樣。所以的
27、脈搏,就像人的心跳一樣。所以時(shí)鐘系統(tǒng)的重要性就不言而喻了。時(shí)鐘系統(tǒng)的重要性就不言而喻了。 STM32 的時(shí)鐘系統(tǒng)比較復(fù)雜,的時(shí)鐘系統(tǒng)比較復(fù)雜,不像簡(jiǎn)單的不像簡(jiǎn)單的 51 單片機(jī)一個(gè)系統(tǒng)時(shí)鐘就可以解決一切。于是有人單片機(jī)一個(gè)系統(tǒng)時(shí)鐘就可以解決一切。于是有人要問(wèn),采用一個(gè)系統(tǒng)時(shí)鐘不是很簡(jiǎn)單嗎?為什么要問(wèn),采用一個(gè)系統(tǒng)時(shí)鐘不是很簡(jiǎn)單嗎?為什么 STM32 要有多要有多個(gè)時(shí)鐘源呢?因?yàn)槭紫葌€(gè)時(shí)鐘源呢?因?yàn)槭紫萐TM32 本身非常復(fù)雜,外設(shè)非常的多,本身非常復(fù)雜,外設(shè)非常的多,但是并不是所有外設(shè)都需要系統(tǒng)時(shí)鐘這么高的頻率,比如看門(mén)但是并不是所有外設(shè)都需要系統(tǒng)時(shí)鐘這么高的頻率,比如看門(mén)狗以及狗以及 RTC
28、 只需要幾十只需要幾十 k 的時(shí)鐘即可。同一個(gè)電路,時(shí)鐘越快的時(shí)鐘即可。同一個(gè)電路,時(shí)鐘越快功耗越大,同時(shí)抗電磁干擾能力也會(huì)越弱,所以對(duì)于較為復(fù)雜功耗越大,同時(shí)抗電磁干擾能力也會(huì)越弱,所以對(duì)于較為復(fù)雜的的 MCU 一般都是采取多時(shí)鐘源的方法來(lái)解決這些問(wèn)題。一般都是采取多時(shí)鐘源的方法來(lái)解決這些問(wèn)題。在在 STM32 中,有五個(gè)時(shí)鐘源,為中,有五個(gè)時(shí)鐘源,為 HSI、 HSE、 LSI、 LSE、 PLL。從時(shí)鐘頻率來(lái)分可以分為高速時(shí)鐘源和低速時(shí)鐘源,在。從時(shí)鐘頻率來(lái)分可以分為高速時(shí)鐘源和低速時(shí)鐘源,在這這 5 個(gè)中個(gè)中 HIS, HSE 以及以及 PLL 是高速時(shí)鐘,是高速時(shí)鐘, LSI 和和
29、LSE 是低是低速時(shí)鐘。從來(lái)源可分為外部時(shí)鐘源和內(nèi)部時(shí)鐘源,外部時(shí)鐘源速時(shí)鐘。從來(lái)源可分為外部時(shí)鐘源和內(nèi)部時(shí)鐘源,外部時(shí)鐘源就是從外部通過(guò)接晶振的方式獲取時(shí)鐘源,其中就是從外部通過(guò)接晶振的方式獲取時(shí)鐘源,其中 HSE 和和 LSE 是外部時(shí)鐘源。是外部時(shí)鐘源。、 HSI 是高速內(nèi)部時(shí)鐘,是高速內(nèi)部時(shí)鐘, RC 振蕩器,振蕩器, 頻率為頻率為 8MHz。、 HSE 是高速外部時(shí)鐘,可接石英是高速外部時(shí)鐘,可接石英 /陶瓷諧振器,或者接外部陶瓷諧振器,或者接外部時(shí)鐘源,頻率范圍為時(shí)鐘源,頻率范圍為4MHz16MHz。 我們的開(kāi)發(fā)板接的是我們的開(kāi)發(fā)板接的是 8M 的晶振。的晶振。、 LSI 是低速內(nèi)
30、部時(shí)鐘,是低速內(nèi)部時(shí)鐘, RC 振蕩器,頻率為振蕩器,頻率為 40kHz。 獨(dú)立獨(dú)立看門(mén)狗的時(shí)鐘源只能是看門(mén)狗的時(shí)鐘源只能是 LSI,同時(shí),同時(shí) LSI 還可以作為還可以作為 RTC 的時(shí)鐘的時(shí)鐘源。源。、 LSE 是低速外部時(shí)鐘,接頻率為是低速外部時(shí)鐘,接頻率為 32.768kHz 的石英晶體。的石英晶體。 這個(gè)主要是這個(gè)主要是 RTC 的時(shí)鐘源。的時(shí)鐘源。、 PLL 為鎖相環(huán)倍頻輸出,其時(shí)鐘輸入源可選擇為為鎖相環(huán)倍頻輸出,其時(shí)鐘輸入源可選擇為 HSI/2、 HSE 或者或者 HSE/2。倍頻可選擇為。倍頻可選擇為216 倍,但是其輸出頻率最大倍,但是其輸出頻率最大不得超過(guò)不得超過(guò) 72MH
31、z。那么這那么這 5 個(gè)時(shí)鐘源是怎么給各個(gè)外設(shè)以及系統(tǒng)提供時(shí)鐘的呢?個(gè)時(shí)鐘源是怎么給各個(gè)外設(shè)以及系統(tǒng)提供時(shí)鐘的呢?A. MCO 是是 STM32 的一個(gè)時(shí)鐘輸出的一個(gè)時(shí)鐘輸出 IO(PA8),它可以選擇一個(gè),它可以選擇一個(gè)時(shí)鐘信號(hào)輸出,時(shí)鐘信號(hào)輸出, 可以選擇為可以選擇為 PLL 輸出的輸出的 2 分頻、分頻、 HSI、 HSE、或者系統(tǒng)時(shí)鐘。這個(gè)時(shí)鐘可以用來(lái)給外部其他系統(tǒng)提供時(shí)鐘源?;蛘呦到y(tǒng)時(shí)鐘。這個(gè)時(shí)鐘可以用來(lái)給外部其他系統(tǒng)提供時(shí)鐘源。B. 這里是這里是 RTC 時(shí)鐘源,從圖上可以看出,時(shí)鐘源,從圖上可以看出, RTC 的時(shí)鐘源可以的時(shí)鐘源可以選擇選擇 LSI, LSE,以及,以及HSE
32、的的 128 分頻。分頻。C. 從圖中可以看出從圖中可以看出 C 處處 USB 的時(shí)鐘是來(lái)自的時(shí)鐘是來(lái)自 PLL 時(shí)鐘源時(shí)鐘源.STM32 中有一個(gè)全速功能的中有一個(gè)全速功能的 USB 模塊,其串行接口引擎需要一個(gè)頻率模塊,其串行接口引擎需要一個(gè)頻率為為 48MHz 的時(shí)鐘源。該時(shí)鐘源只能從的時(shí)鐘源。該時(shí)鐘源只能從 PLL 輸出端獲取,可以選輸出端獲取,可以選擇為擇為 1.5 分頻或者分頻或者 1 分頻,也就是,當(dāng)需要使用分頻,也就是,當(dāng)需要使用 USB模塊時(shí),模塊時(shí),PLL 必須使能,并且時(shí)鐘頻率配置為必須使能,并且時(shí)鐘頻率配置為 48MHz 或或 72MHz。D. 處就是處就是 STM32
33、 的系統(tǒng)時(shí)鐘的系統(tǒng)時(shí)鐘 SYSCLK,它是供,它是供 STM32 中絕大中絕大部分部件工作的時(shí)鐘源。部分部件工作的時(shí)鐘源。 系統(tǒng)時(shí)鐘可選擇為系統(tǒng)時(shí)鐘可選擇為 PLL 輸出、輸出、 HSI 或或者者 HSE。系統(tǒng)時(shí)鐘最大頻率為。系統(tǒng)時(shí)鐘最大頻率為 72MHz. 這里的這里的 E 處是指其他所有外設(shè)了。從時(shí)鐘圖上可以看出,其處是指其他所有外設(shè)了。從時(shí)鐘圖上可以看出,其他所有外設(shè)的時(shí)鐘最終來(lái)源都是他所有外設(shè)的時(shí)鐘最終來(lái)源都是 SYSCLK。 SYSCLK 通過(guò)通過(guò) AHB 分頻器分頻后送給各模塊使用。這些模塊包括:分頻器分頻后送給各模塊使用。這些模塊包括:、 AHB 總線、內(nèi)核、內(nèi)存和總線、內(nèi)核、內(nèi)
34、存和 DMA 使用的使用的 HCLK 時(shí)鐘。時(shí)鐘。、通過(guò)、通過(guò) 8 分頻后送給分頻后送給 Cortex 的系統(tǒng)定時(shí)器時(shí)鐘,也就是的系統(tǒng)定時(shí)器時(shí)鐘,也就是 systick 、直接送給、直接送給 Cortex 的空閑運(yùn)行時(shí)鐘的空閑運(yùn)行時(shí)鐘 FCLK。、送給、送給 APB1 分頻器。分頻器。 APB1 分頻器輸出一路供分頻器輸出一路供 APB1 外設(shè)使外設(shè)使用用(PCLK1,最大頻率,最大頻率 36MHz),另一路送給定時(shí)器,另一路送給定時(shí)器(Timer)2、 3、 4 倍頻器使用。倍頻器使用。、送給、送給 APB2 分頻器。分頻器。 APB2 分頻器分頻輸出一路供分頻器分頻輸出一路供 APB2 外
35、外設(shè)使用設(shè)使用(PCLK2,最大頻率,最大頻率 72MHz),另一路送給定時(shí)器,另一路送給定時(shí)器(Timer)1 倍頻器使用。倍頻器使用。 其中需要理解的是其中需要理解的是 APB1 和和 APB2 的區(qū)別,的區(qū)別, APB1 上面連接上面連接的是低速外設(shè),包括電源接口、備份接口、的是低速外設(shè),包括電源接口、備份接口、 CAN、 USB、 I2C1、 I2C2、 UART2、 UART3 等等,等等, APB2 上面連接的是高速外設(shè)包上面連接的是高速外設(shè)包括括 UART1、 SPI1、 Timer1、 ADC1、 ADC2、所有普通、所有普通 IO 口口(PAPE)、第二功能、第二功能 IO
36、口等??诘?。在以上的時(shí)鐘輸出中,有很多是帶使能控制的,例如在以上的時(shí)鐘輸出中,有很多是帶使能控制的,例如AHB 總線總線時(shí)鐘、內(nèi)核時(shí)鐘、各種時(shí)鐘、內(nèi)核時(shí)鐘、各種 APB1外設(shè)、外設(shè)、 APB2 外設(shè)等等。當(dāng)需要外設(shè)等等。當(dāng)需要使用某模塊時(shí),記得一定要先使能對(duì)應(yīng)的時(shí)鐘。使用某模塊時(shí),記得一定要先使能對(duì)應(yīng)的時(shí)鐘。 后面我們講解后面我們講解實(shí)例的時(shí)候會(huì)講解到時(shí)鐘使能的方法。實(shí)例的時(shí)候會(huì)講解到時(shí)鐘使能的方法。STM32 時(shí)鐘系統(tǒng)的配置除了初始化的時(shí)候在時(shí)鐘系統(tǒng)的配置除了初始化的時(shí)候在 system_stm32f10 x.c 中的中的 SystemInit()函數(shù)中外,其他的配置主函數(shù)中外,其他的配置主
37、要在要在 stm32f10 x_rcc.c 文件中,里面有很多時(shí)鐘設(shè)置函數(shù),大家文件中,里面有很多時(shí)鐘設(shè)置函數(shù),大家可以打開(kāi)這個(gè)文件瀏覽一下,基本上看看函數(shù)的名稱就知道這可以打開(kāi)這個(gè)文件瀏覽一下,基本上看看函數(shù)的名稱就知道這個(gè)函數(shù)的作用。這里需要指明一下,對(duì)于系統(tǒng)時(shí)鐘,默認(rèn)情況個(gè)函數(shù)的作用。這里需要指明一下,對(duì)于系統(tǒng)時(shí)鐘,默認(rèn)情況下是在下是在 SystemInit 函數(shù)的函數(shù)的 SetSysClock()函數(shù)中間判斷的,而設(shè)函數(shù)中間判斷的,而設(shè)置是通過(guò)宏定義設(shè)置的。我們可以看看置是通過(guò)宏定義設(shè)置的。我們可以看看 SetSysClock()函數(shù)體:函數(shù)體:static void SetSysCl
38、ock(void)#ifdef SYSCLK_FREQ_HSESetSysClockToHSE();#elif defined SYSCLK_FREQ_24MHzSetSysClockTo24();#elif defined SYSCLK_FREQ_36MHzSetSysClockTo36();#elif defined SYSCLK_FREQ_48MHzSetSysClockTo48();#elif defined SYSCLK_FREQ_56MHzSetSysClockTo56();#elif defined SYSCLK_FREQ_72MHzSetSysClockTo72();#endi
39、f這段代碼非常簡(jiǎn)單,就是判斷系統(tǒng)宏定義的時(shí)鐘是多少,這段代碼非常簡(jiǎn)單,就是判斷系統(tǒng)宏定義的時(shí)鐘是多少,然后設(shè)置相應(yīng)值。我們系統(tǒng)默認(rèn)宏定義是然后設(shè)置相應(yīng)值。我們系統(tǒng)默認(rèn)宏定義是 72MHz:#define SYSCLK_FREQ_72MHz 72000000如果你要設(shè)置為如果你要設(shè)置為 36MHz,只需要注釋掉上面代碼,然后,只需要注釋掉上面代碼,然后加入下面代碼即可:加入下面代碼即可:#define SYSCLK_FREQ_36MHz 36000000同時(shí)還要注意的是,當(dāng)我們?cè)O(shè)置好系統(tǒng)時(shí)鐘后,可以通過(guò)變量同時(shí)還要注意的是,當(dāng)我們?cè)O(shè)置好系統(tǒng)時(shí)鐘后,可以通過(guò)變量 SystemCoreClock 獲
40、取系統(tǒng)時(shí)鐘值,如果系統(tǒng)是獲取系統(tǒng)時(shí)鐘值,如果系統(tǒng)是 72M 時(shí)鐘,時(shí)鐘,那么那么 SystemCoreClock=72000000。這是在。這是在 system_stm32f10 x.c 文件中設(shè)置的:文件中設(shè)置的:#ifdef SYSCLK_FREQ_HSEuint32_t SystemCoreClock = SYSCLK_FREQ_HSE;#elif defined SYSCLK_FREQ_36MHzuint32_t SystemCoreClock = SYSCLK_FREQ_36MHz;#elif defined SYSCLK_FREQ_48MHzuint32_t SystemCoreC
41、lock = SYSCLK_FREQ_48MHz;#elif defined SYSCLK_FREQ_56MHzuint32_t SystemCoreClock = SYSCLK_FREQ_56MHz;#elif defined SYSCLK_FREQ_72MHzuint32_t SystemCoreClock = SYSCLK_FREQ_72MHz;#elseuint32_t SystemCoreClock = HSI_VALUE;#endif這里總結(jié)一下這里總結(jié)一下 SystemInit()函數(shù)中設(shè)置的系統(tǒng)時(shí)鐘大小:函數(shù)中設(shè)置的系統(tǒng)時(shí)鐘大?。篠YSCLK(系統(tǒng)時(shí)鐘)(系統(tǒng)時(shí)鐘) =72MH
42、zAHB 總線時(shí)鐘總線時(shí)鐘(使用使用 SYSCLK) =72MHzAPB1 總線時(shí)鐘總線時(shí)鐘(PCLK1) =36MHzAPB2 總線時(shí)鐘總線時(shí)鐘(PCLK2) =72MHzPLL 時(shí)鐘時(shí)鐘 =72MHz端口復(fù)用和重映射端口復(fù)用和重映射端口復(fù)用功能端口復(fù)用功能STM32 有很多的內(nèi)置外設(shè),這些外設(shè)的外部引腳都是有很多的內(nèi)置外設(shè),這些外設(shè)的外部引腳都是與與 GPIO 復(fù)用的。也就是說(shuō),一個(gè)復(fù)用的。也就是說(shuō),一個(gè) GPIO如果可以復(fù)用為內(nèi)置如果可以復(fù)用為內(nèi)置外設(shè)的功能引腳,那么當(dāng)這個(gè)外設(shè)的功能引腳,那么當(dāng)這個(gè) GPIO 作為內(nèi)置外設(shè)使用的時(shí)作為內(nèi)置外設(shè)使用的時(shí)候,就叫做復(fù)用。候,就叫做復(fù)用。大家都
43、知道,大家都知道, MCU 都有串口,都有串口, STM32 有好幾個(gè)串口。有好幾個(gè)串口。比如說(shuō)比如說(shuō) STM32F103ZET6 有有 5 個(gè)串口,我們可以查手冊(cè)知道,個(gè)串口,我們可以查手冊(cè)知道,串口串口 1 的引腳對(duì)應(yīng)的的引腳對(duì)應(yīng)的 IO 為為 PA9,PA10。 PA9,PA10 默認(rèn)功能是默認(rèn)功能是GPIO, 所以當(dāng)所以當(dāng)PA9,PA10 引腳作為串口引腳作為串口 1 的的 TX,RX 引腳使用引腳使用的時(shí)候,那就是端口復(fù)用。的時(shí)候,那就是端口復(fù)用。復(fù)用端口初始化有幾個(gè)步驟:復(fù)用端口初始化有幾個(gè)步驟:1) GPIO 端口時(shí)鐘使能。要使用到端口復(fù)用,當(dāng)然要使端口時(shí)鐘使能。要使用到端口復(fù)用
44、,當(dāng)然要使能端口的時(shí)鐘了。能端口的時(shí)鐘了。RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);2) 復(fù)用的外設(shè)時(shí)鐘使能。比如你要將端口復(fù)用的外設(shè)時(shí)鐘使能。比如你要將端口 PA9,PA10 復(fù)復(fù)用為串口,所以要使能串口時(shí)鐘。用為串口,所以要使能串口時(shí)鐘。RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);3) 端口模式配置。端口模式配置。 在在 IO 復(fù)用位內(nèi)置外設(shè)功能引腳的時(shí)復(fù)用位內(nèi)置外設(shè)功能引腳的時(shí)候,必須設(shè)置候,必須設(shè)置 GPIO 端口的模式,至于在復(fù)用功能下端口的模式,至于在復(fù)用
45、功能下 GPIO 的模式是怎么對(duì)應(yīng)的,這個(gè)可以查看手冊(cè)的模式是怎么對(duì)應(yīng)的,這個(gè)可以查看手冊(cè) 。這里。這里我們拿我們拿 Usart1 舉例:舉例:從表格中可以看出,我們要配置全雙工的串口從表格中可以看出,我們要配置全雙工的串口 1,那么,那么 TX 管管腳需要配置為推挽復(fù)用輸出,腳需要配置為推挽復(fù)用輸出,RX 管腳配置為浮空輸入或者帶管腳配置為浮空輸入或者帶上拉輸入。上拉輸入。我們?cè)谑褂脧?fù)用功能的是時(shí)候,最少要使能我們?cè)谑褂脧?fù)用功能的是時(shí)候,最少要使能 2 個(gè)時(shí)鐘:個(gè)時(shí)鐘:1) GPIO 時(shí)鐘使能時(shí)鐘使能2) 復(fù)用的外設(shè)時(shí)鐘使能復(fù)用的外設(shè)時(shí)鐘使能同時(shí)要初始化同時(shí)要初始化 GPIO 以及復(fù)用外設(shè)功
46、能以及復(fù)用外設(shè)功能/USART1_TX PA.9 復(fù)用推挽輸出復(fù)用推挽輸出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; /PA.9GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; /復(fù)用推挽輸復(fù)用推挽輸出出GPIO_Init(GPIOA, &GPIO_InitStructure);/USART1_RX PA.10 浮空輸入浮空輸入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;/
47、PA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;/浮空輸入浮空輸入GPIO_Init(GPIOA, &GPIO_InitStructure);端口重映射端口重映射為了使不同器件封裝的外設(shè)為了使不同器件封裝的外設(shè) IO 功能數(shù)量達(dá)到最優(yōu),可功能數(shù)量達(dá)到最優(yōu),可以把一些復(fù)用功能重新映射到其他一些引腳上。以把一些復(fù)用功能重新映射到其他一些引腳上。 STM32 中有中有很多內(nèi)置外設(shè)的輸入輸出引腳都具有重映射很多內(nèi)置外設(shè)的輸入輸出引腳都具有重映射(remap) 的功能。的功能。 我們知道每個(gè)內(nèi)置外設(shè)都有若干個(gè)輸入輸出引腳,一般這些引我們知
48、道每個(gè)內(nèi)置外設(shè)都有若干個(gè)輸入輸出引腳,一般這些引腳的輸出端口都是固定不變的,為了讓設(shè)計(jì)工程師可以更好地腳的輸出端口都是固定不變的,為了讓設(shè)計(jì)工程師可以更好地安排引腳的走向和功能,在安排引腳的走向和功能,在 STM32 中引入了外設(shè)引腳重映射中引入了外設(shè)引腳重映射的概念,即一個(gè)外設(shè)的引腳除了具有默認(rèn)的端口外,還可以通的概念,即一個(gè)外設(shè)的引腳除了具有默認(rèn)的端口外,還可以通過(guò)設(shè)置重映射寄存器的方式,把這個(gè)外設(shè)的引腳映射到其它的過(guò)設(shè)置重映射寄存器的方式,把這個(gè)外設(shè)的引腳映射到其它的端口。簡(jiǎn)單的講就是把管腳的外設(shè)功能映射到另一個(gè)管腳,但端口。簡(jiǎn)單的講就是把管腳的外設(shè)功能映射到另一個(gè)管腳,但不是可以隨便映
49、射的不是可以隨便映射的.上圖是截取的中文參考手冊(cè)中的重映射表,從表中可以上圖是截取的中文參考手冊(cè)中的重映射表,從表中可以看出,默認(rèn)情況下,串口看出,默認(rèn)情況下,串口 1 復(fù)用的時(shí)候的引腳位復(fù)用的時(shí)候的引腳位 PA9,PA10,同,同時(shí)我們可以將時(shí)我們可以將 TX 和和 RX 重新映射到管腳重新映射到管腳 PB6 和和 PB7 上面去。上面去。所以重映射我們同樣要使能復(fù)用功能的時(shí)候講解的所以重映射我們同樣要使能復(fù)用功能的時(shí)候講解的 2 個(gè)時(shí)鐘外,個(gè)時(shí)鐘外,還要使能還要使能 AFIO 功能時(shí)鐘,然后要調(diào)用重映射函數(shù)。功能時(shí)鐘,然后要調(diào)用重映射函數(shù)。 1) 使能使能 GPIOB 時(shí)鐘:時(shí)鐘:RCC_
50、APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);2) 使能串口使能串口 1 時(shí)鐘:時(shí)鐘:RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);3) 使能使能 AFIO 時(shí)鐘:時(shí)鐘:RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);4) 開(kāi)啟重映射:開(kāi)啟重映射:GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);這樣就將串口的這樣就將串口的 TX 和和 RX 重映射到管腳重映射到管腳 PB6 和和
51、PB7 上面了。上面了。有哪些功能可以重映射,大家除了查看中文參考手冊(cè)之有哪些功能可以重映射,大家除了查看中文參考手冊(cè)之外,還可以從外,還可以從 GPIO_PinRemapConfig 函數(shù)入手查看第一個(gè)入函數(shù)入手查看第一個(gè)入口參數(shù)的取值范圍可以得知。在口參數(shù)的取值范圍可以得知。在 stm32f10 x_gpio.h 文件中定義文件中定義了取值范圍為下面宏定義的標(biāo)識(shí)符,這里我們貼一小部分:了取值范圍為下面宏定義的標(biāo)識(shí)符,這里我們貼一小部分:#define GPIO_Remap_SPI1 (uint32_t)0 x00000001)#define GPIO_Remap_I2C1 (uint32_
52、t)0 x00000002)#define GPIO_Remap_USART1 (uint32_t)0 x00000004)#define GPIO_Remap_USART2 (uint32_t)0 x00000008)#define GPIO_PartialRemap_USART3 (uint32_t)0 x00140010)#define GPIO_FullRemap_USART3 (uint32_t)0 x00140030)從上面可以看出,從上面可以看出, USART1 只有一種重映射,而對(duì)于只有一種重映射,而對(duì)于 USART3, 存在部分重映射和完全重映射。存在部分重映射和完全重映射。
53、 所謂部分重映射就是所謂部分重映射就是部分管腳和默認(rèn)的是一樣的,而部分管腳是重新映射到其他管部分管腳和默認(rèn)的是一樣的,而部分管腳是重新映射到其他管腳。腳。 而完全重映射就是所有管腳都重新映射到其他管腳。而完全重映射就是所有管腳都重新映射到其他管腳。部分重映射就是部分重映射就是 PB10, PB11,PB12 重映射到重映射到 PC10,PC11,PC12 上。而上。而 PB13 和和 PB14 和沒(méi)有重映射情況是一樣和沒(méi)有重映射情況是一樣的,都是的,都是USART3_CTS 和和 USART3_RTS 對(duì)應(yīng)管腳。對(duì)應(yīng)管腳。 完全重映完全重映射就是將這兩個(gè)腳重新映射到射就是將這兩個(gè)腳重新映射到
54、PD11 和和 PD12 上去。上去。 我們要使用我們要使用 USART3 的部分重映射,我們調(diào)用函數(shù)方法為:的部分重映射,我們調(diào)用函數(shù)方法為:GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, ENABLE);STM32 NVIC 中斷優(yōu)先級(jí)管理中斷優(yōu)先級(jí)管理CM3 內(nèi)核支持內(nèi)核支持 256 個(gè)中斷,其中包含了個(gè)中斷,其中包含了 16 個(gè)內(nèi)核中斷個(gè)內(nèi)核中斷和和 240 個(gè)外部中斷,并且具有個(gè)外部中斷,并且具有 256級(jí)的可編程中斷設(shè)置。但級(jí)的可編程中斷設(shè)置。但 STM32 并沒(méi)有使用并沒(méi)有使用 CM3 內(nèi)核的全部東西,而是只用了它的一內(nèi)核的全部東西,而
55、是只用了它的一部分。部分。STM32 有有 84 個(gè)中斷,包括個(gè)中斷,包括 16 個(gè)內(nèi)核中斷和個(gè)內(nèi)核中斷和 68 個(gè)可屏個(gè)可屏蔽中斷,具有蔽中斷,具有 16 級(jí)可編程的中斷優(yōu)先級(jí)。而我們常用的就是這級(jí)可編程的中斷優(yōu)先級(jí)。而我們常用的就是這 68 個(gè)可屏蔽中斷,但是個(gè)可屏蔽中斷,但是 STM32 的的 68 個(gè)可屏蔽中斷,在個(gè)可屏蔽中斷,在 STM32F103 系列上面,又只有系列上面,又只有 60 個(gè)(在個(gè)(在 107 系列才有系列才有 68 個(gè))。個(gè))。所以我們就只針對(duì)所以我們就只針對(duì) STM32F103 系列這系列這 60 個(gè)可屏蔽中斷進(jìn)行介個(gè)可屏蔽中斷進(jìn)行介紹。紹。在在 MDK 內(nèi),與內(nèi)
56、,與 NVIC 相關(guān)的寄存器,相關(guān)的寄存器, MDK 為其定義為其定義了如下的結(jié)構(gòu)體:了如下的結(jié)構(gòu)體:typedef structvu32 ISER2;u32 RESERVED030;vu32 ICER2;u32 RSERVED130;vu32 ISPR2;u32 RESERVED230;vu32 ICPR2;u32 RESERVED330;vu32 IABR2;u32 RESERVED462;vu32 IPR15; NVIC_TypeDef;STM32 的中斷在這些寄存器的控制下有序的執(zhí)行的。只的中斷在這些寄存器的控制下有序的執(zhí)行的。只有了解這些中斷寄存器,才能了解有了解這些中斷寄存器,才能
57、了解STM32 的中斷。下面簡(jiǎn)要介的中斷。下面簡(jiǎn)要介紹這幾個(gè)寄存器:紹這幾個(gè)寄存器:ISER2: ISER 全稱是:全稱是: Interrupt Set-Enable Registers,這,這是一個(gè)中斷使能寄存器組。上面說(shuō)了是一個(gè)中斷使能寄存器組。上面說(shuō)了 STM32F103 的可屏蔽中的可屏蔽中斷只有斷只有 60 個(gè),這里用了個(gè),這里用了 2 個(gè)個(gè) 32 位的寄存器,總共可以表示位的寄存器,總共可以表示 64 個(gè)中斷。而個(gè)中斷。而 STM32F103 只用了其中的前只用了其中的前 60 位。位。 ISER0的的 bit0bit31 分別對(duì)應(yīng)中斷分別對(duì)應(yīng)中斷 031。 ISER1的的 bit
58、027 對(duì)應(yīng)中斷對(duì)應(yīng)中斷 3259;這樣總共;這樣總共 60 個(gè)中斷就分別對(duì)應(yīng)上了。你要使能某個(gè)中個(gè)中斷就分別對(duì)應(yīng)上了。你要使能某個(gè)中斷,必須設(shè)置相應(yīng)的斷,必須設(shè)置相應(yīng)的 ISER 位為位為 1,使該中斷被使能,使該中斷被使能(這里僅僅這里僅僅是使能,還要配合中斷分組、屏蔽、是使能,還要配合中斷分組、屏蔽、 IO 口映射等設(shè)置才算是口映射等設(shè)置才算是一個(gè)完整的中斷設(shè)置一個(gè)完整的中斷設(shè)置)。ICER2:全稱是:全稱是: Interrupt Clear-Enable Registers,是一個(gè)中斷除能,是一個(gè)中斷除能寄存器組。該寄存器組與寄存器組。該寄存器組與 ISER 的作用恰好相反,是用來(lái)清除
59、某個(gè)中斷的作用恰好相反,是用來(lái)清除某個(gè)中斷的使能的。其對(duì)應(yīng)位的功能,也和的使能的。其對(duì)應(yīng)位的功能,也和 ICER 一樣。這里要專門(mén)設(shè)置一個(gè)一樣。這里要專門(mén)設(shè)置一個(gè) ICER 來(lái)清除中斷位,而不是向來(lái)清除中斷位,而不是向 ISER 寫(xiě)寫(xiě) 0 來(lái)清除,是因?yàn)閬?lái)清除,是因?yàn)?NVIC 的這的這些寄存器都是寫(xiě)些寄存器都是寫(xiě) 1 有效的,寫(xiě)有效的,寫(xiě) 0 是無(wú)效的。是無(wú)效的。ISPR2:全稱是:全稱是: Interrupt Set-Pending Registers,是一個(gè)中斷掛起,是一個(gè)中斷掛起控制寄存器組。每個(gè)位對(duì)應(yīng)的中斷和控制寄存器組。每個(gè)位對(duì)應(yīng)的中斷和 ISER 是一樣的。通過(guò)置是一樣的。通過(guò)置
60、 1,可以,可以將正在進(jìn)行的中斷掛起,而執(zhí)行同級(jí)或更高級(jí)別的中斷。寫(xiě)將正在進(jìn)行的中斷掛起,而執(zhí)行同級(jí)或更高級(jí)別的中斷。寫(xiě) 0 是無(wú)效的是無(wú)效的.ICPR2:全稱是:全稱是: Interrupt Clear-Pending Registers,是一個(gè)中斷解,是一個(gè)中斷解掛控制寄存器組。其作用與掛控制寄存器組。其作用與 ISPR 相反,對(duì)應(yīng)位也和相反,對(duì)應(yīng)位也和 ISER 是一樣的。是一樣的。通過(guò)設(shè)置通過(guò)設(shè)置 1,可以將掛起的中斷接掛。寫(xiě),可以將掛起的中斷接掛。寫(xiě) 0 無(wú)效。無(wú)效。IABR2:全稱是:全稱是: Interrupt Active Bit Registers,是一個(gè)中斷激活標(biāo),是一個(gè)中
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026四川雅安市老干部活動(dòng)中心招聘1人筆試備考題庫(kù)及答案解析
- 2026浙江金華市武義縣城鄉(xiāng)環(huán)境服務(wù)有限公司招聘1人筆試備考題庫(kù)及答案解析
- 2026湖南永州市廉潔征兵筆試參考題庫(kù)及答案解析
- 2025年多媒體應(yīng)用設(shè)計(jì)師筆試及答案
- 2025年大學(xué)高校財(cái)務(wù)管理崗筆試及答案
- 2025年boss心理測(cè)試筆試及答案
- 2025年達(dá)州鋼鐵集團(tuán)筆試及答案
- 2025年建筑集團(tuán)招聘筆試題庫(kù)及答案
- 2025年內(nèi)蒙古教招英語(yǔ)筆試及答案
- 2025年醫(yī)院會(huì)計(jì)事業(yè)編考試真題及答案
- 【二下數(shù)學(xué)】計(jì)算每日一練60天(口算豎式脫式應(yīng)用題)
- 殘疾人服務(wù)與權(quán)益保護(hù)手冊(cè)(標(biāo)準(zhǔn)版)
- 車(chē)隊(duì)春節(jié)前安全培訓(xùn)內(nèi)容課件
- 2025年溫州肯恩三位一體筆試英語(yǔ)真題及答案
- 云南師大附中2026屆高三高考適應(yīng)性月考卷(六)歷史試卷(含答案及解析)
- PCR技術(shù)在食品中的應(yīng)用
- 輸液滲漏處理課件
- 教育培訓(xùn)行業(yè)發(fā)展趨勢(shì)與機(jī)遇分析
- 物業(yè)與商戶裝修協(xié)議書(shū)
- 湖南鐵道職業(yè)技術(shù)學(xué)院2025年單招職業(yè)技能測(cè)試題
評(píng)論
0/150
提交評(píng)論