天天看點

STM32單片機一

目錄: 一、STM32_命名規則相關 二、STM32_啟動模式配置說明 1、STM32一共有三種啟動模式,相關的配置說明如下 2、啟動模式配置附錄 三、STM32硬體_總線AMBA、AHB、APB 1、AMBA 2、Bus Bridges 3、STM32上的總線結構 四、STM32_NVIC 1、簡述 2、中斷優先級分組 3、舉例說明 五、STM32硬體_TIM1輸出互補波形程式 六、STM32硬體_中斷程式設計過程 1、序列槽中斷程式設計過程 1)應用序列槽中斷時涉及到的一些庫檔案   2)初始化   3)發送資料    4)接收資料   5)main函數    6)在啟動檔案查找中斷函數 2、外中斷程式設計過程式設計過程 1)通用I/O端口連接配接到16個外部中斷/事件線   2)外部中斷服務函數的編寫   3)具體程式編寫 七、STM32硬體_AD用DMA方式時的請注意程式初始化順序 1、DMA初始化 2、STM32關于使用定時器觸發ADC轉換的解決辦法和詳細說明 八、STM32硬體_外設位址設定 九、STM32硬體_時鐘樹 1、在STM32上如果不使用外部晶振,OSC_IN和OSC_OUT的接法 2、STM32時鐘系統 1)簡述      2)時鐘輸出的使能控制     3)使用HSE時鐘,程式設定時鐘參數流程 3、定時器對應的輸出端口 -----------------------------------------------

STM32單片機一

或者使用“STM32CubeMX”工具軟體,介紹STM32CubeMX之F1xx系列實用報告(圖文代碼齊全)下載下傳STM32CubeMX軟體 ----------------------------------------------- ARM單片機一 ARM單片機二 意法半導體   ------------------------------------------------------------------------------------------------------------------- 一、STM32_命名規則相關

STM32單片機一

  從命名規則可得STM32F103VET6Flash大小為512K位元組。 通過資料手冊得到Flash大小,下面以 

STM32F103RBT6為例說明:

STM32單片機一

Page0 – Page127 = 1KB(0000-03FF) * 128Page = 128KB total,該區域位址範圍:0x08000000 – 0x0801FFFF,總大小為128K位元組。該區域主要用途:存放STM32的代碼段(使用者程式)。   ------------------------------------------------------------------------------------------------------------------- 二、STM32_啟動模式配置說明 1、STM32一共有三種啟動模式,相關的配置說明如下

STM32單片機一

所謂啟動,一般來說就是指我們下好程式後,重新開機晶片時,SYSCLK的第4個上升沿,BOOT引腳的值将被鎖存。使用者可以通過設定BOOT1和BOOT0引腳的狀态,來選擇在複位後的啟動模式。

-----------------------

1)Main Flash memory

是STM32内置的Flash,一般我們使用JTAG或者SWD模式下載下傳程式時,就是下載下傳到這個裡面,重新開機後也直接從這啟動程式。正常工作就在這種模式下,STM32的FLASH可以擦出10萬次,是以不用擔心晶片哪天會被擦爆!STM32從Flash存儲的第一條指令開始執行,即執行STM32的啟動代碼stm32f10x_vector.s(或stm32F10x_xxx_xxx.s或startup_xxx.s 根據STM32 Firmware library的不同而不同),執行啟動代碼後會跳到main函數,執行使用者程式。

-----------------------

2)System memory

System memory is used to boot the device in System memory boot mode. The area is reserved for use by STMicroelectronics and contains the boot loader which is used to reprogram the Flash memory using the USART1 serial interface. It is programmed by ST when the device is manufactured, and protected against spurious write/erase operations. For further details please refer to AN2606.

從系統存儲器啟動,這種模式啟動的程式功能是由廠家設定的。一般來說,這種啟動方式用的比較少。

系統存儲器是晶片内部一塊特定的區域,STM32在出廠時,由ST在這個區域内部預置了一段BootLoader,也就是我們常說的ISP程式,這是一塊ROM,出廠後無法修改。

一般來說,我們選用這種啟動模式時,是為了從序列槽下載下傳程式,因為在廠家提供的BootLoader中,提供了序列槽下載下傳程式的固件(比如mcuisp.exe),可以通過這個BootLoader将程式下載下傳到系統的Flash中。但是這個下載下傳方式需要以下步驟:

将BOOT0設定為1,BOOT1設定為0,然後按下複位鍵(或重新開機),這樣才能從系統存儲器啟動BootLoader;

最後在BootLoader的幫助下,通過序列槽下載下傳程式到Flash中;

程式下載下傳完成後,又需要将BOOT0設定為GND(通過電阻連到地),手動複位(或重新開機),這樣STM32才可以從Flash中啟動。

STM32單片機一

關于DB9的針腳定義見“RS232與RS485通訊接口之一、RS-232和RS-485的優缺點及針腳定義之3、DB9針腳定義”

STM32單片機一

-----------------------

3)Embedded SRAM

内置SRAM,既然是SRAM,自然也就沒有程式存儲的能力了,這個模式一般用于程式調試。

(1)故障的局部診斷,寫一段小程式加載到SRAM中診斷闆上的其他電路,或用此方法讀寫闆上的Flash或EEPROM等。

(2)通過這種方法解除内部Flash的讀寫保護,當然解除讀寫保護的同時Flash的内容也被自動清除,以防止惡意的軟體拷貝。

(3)隻修改了代碼中一個小小的地方,然後就需要重新擦除整個Flash,比較的費時,可以考慮從這個模式啟動代碼(也就是STM32的記憶體中),用于快速的程式調試,等程式調試完成後,在将程式下載下傳到FLASH中。

-----------------------------------------------

2、啟動模式配置附錄

先是拿到一塊别人的闆子和程式來修改,後來做了塊闆子,燒錄程式後發現:燒錄後通過燒錄工具的“燒錄後運作”選項可以正常跑起來,但一旦使程式從FLASH開始運作,則跑不了了。後來發現别人闆子上的MCU是燒錄過boot的,而自己做的闆子是沒有燒錄boot的,前者程式從0x8003000開始運作,後者程式實際從0x8000000開始運作,把0x8003000處開始運作的程式燒到0x8000000的闆子上的結果就是:複位向量位址不正确,導緻晶片無法啟動,因為0x8003000的程式把中斷向量表搬到了0x8003000處。 這裡轉載正點原子的分析:

STM32單片機一

  STM32的内部閃存(FLASH)位址起始于0x08000000,一般情況下,程式檔案就從此位址開始寫入。此外STM32是基于Cortex-M3核心的微控制器,其内部通過一張“中斷向量表”來響應中斷,程式啟動後,将首先從“中斷向量表”取出複位中斷向量執行複位中斷程式完成啟動,而這張“中斷向量表”的起始位址是0x08000004(0x8003000的程式中,中斷向量表的位址是0x8003000),當中斷來臨,STM32的内部硬體機制亦會自動将PC指針定位到“中斷向量表”處,并根據中斷源取出對應的中斷向量執行中斷服務程式。 

   在圖53.1.1中,STM32在複位後,先從0X08000004位址取出複位中斷向量的位址,并跳轉到複位中斷服務程式,如圖示号所示;在複位中斷服務程式執行完之後,會跳轉到我們的main函數,如圖示号所示;而我們的main函數一般都是一個死循環,在main函數執行過程中,如果收到中斷請求(發生重中斷),此時STM32強制将PC指針指回中斷向量表處,如圖示号所示;然後,根據中斷源進入相應的中斷服務程式,如圖示号所示;在執行完中斷服務程式以後,程式再次傳回main函數執行,如圖示号所示。

-------------------------------------------------------------------------------------------------------------------

三、STM32硬體_總線AMBA、AHB、APB

1、AMBA

AMBA(Advanced Microprocessor Bus Architecture)是ARM公司提出的一種開放性的SoC總線标準,現在已經廣泛的應用于RISC的核心上了。 

AMBA定義了一種多總線系統(multilevel busing system),包括系統總線和等級稍低的外設總線。 

AMBA支援32位、64位、128位的資料總線,和32位的位址總線,同時支援byte和half-word設計。 

它定義了兩種總線: 

AHB(Advanced High-performance Bus)先進的高性能總線,也叫做ASB(Advanced System Bus)。APB(Advanced peripheral Bus)先進的外設總線 。 AHB和ASB其實是一個東西,是高速總線,主要負責嵌入式處理器、DMA控制器、Memory等等的接口。  APB是低速總線,主要負責外設接口。 AHB和APB之間是通過Bridge(橋接器)連結的。 -----------------------------------------------

2、Bus Bridges

總所周知,一個系統中的各個子產品之間互相通信是通過總線,總線的作用,就是把資料和位址從裝置A搬運到裝置B上。如果說裝置A和裝置B具有一緻性(原文是under discussion,這裡我不知道怎麼翻譯比較好,暫且翻譯為一緻性),那麼裝置A和裝置B可以直接挂在同一個總線上,并直接解讀總線上的資料。 

但是,如果裝置A和裝置B不具有一緻性,那麼裝置A和裝置B就必須挂在兩條不同的總線上,這時候我們就需要一個“翻譯”,把裝置A上的總線上的資料和位址轉換成裝置B可以解析的格式,然後放到裝置B的總線上,這個“翻譯”就是“Bus Bridge”,下面這幅圖就形象的說明了Bus Bridge在AHB和APB之間的作用。

STM32單片機一

AHB連結的裝置的資料傳輸速度是比APB裝置傳輸的速度快很多的,也就是說,這裡的這個Bus Bridge所起的作用就是“緩沖”。這裡可以看到AHB主要是連結在了系統的核心以及存儲管理上面的,APB則主要分布給外設。    下面這張圖,更容易看出AHB和APB的作用:  AHB連結的是系統總線、RAM等; APB連結的是常用的外設:GPIO、UART等,如下: APB1負責DA,USB,SPI,I2C,CAN,序列槽2345,普通TIM APB2負責AD,I/O,進階TIM,序列槽1。

STM32單片機一

-----------------------------------------------

3、STM32上的總線結構

首先看一下F103系列的晶片的總線結構 

STM32單片機一

需要注意的是,這裡有兩個APB,它們連結的外設是不一樣的,是以在STM32的庫檔案中會有關于APB1和APB2的定義:  #define RCC_APB2Periph_AFIO ((uint32_t)0x00000001)  #define RCC_APB2Periph_GPIOA ((uint32_t)0x00000004) #define RCC_APB2Periph_GPIOB ((uint32_t)0x00000008)  #define RCC_APB2Periph_GPIOC ((uint32_t)0x00000010)  #define RCC_APB2Periph_GPIOD ((uint32_t)0x00000020) #define RCC_APB2Periph_GPIOE ((uint32_t)0x00000040)  #define RCC_APB2Periph_GPIOF ((uint32_t)0x00000080)  #define RCC_APB2Periph_GPIOG ((uint32_t)0x00000100)  #define RCC_APB2Periph_ADC1 ((uint32_t)0x00000200)  #define RCC_APB2Periph_ADC2 ((uint32_t)0x00000400)  #define RCC_APB2Periph_TIM1 ((uint32_t)0x00000800)  #define RCC_APB2Periph_SPI1 ((uint32_t)0x00001000)  #define RCC_APB2Periph_TIM8 ((uint32_t)0x00002000)  #define RCC_APB2Periph_USART1 ((uint32_t)0x00004000)  #define RCC_APB2Periph_ADC3 ((uint32_t)0x00008000)  #define RCC_APB2Periph_TIM15 ((uint32_t)0x00010000)  #define RCC_APB2Periph_TIM16 ((uint32_t)0x00020000)  #define RCC_APB2Periph_TIM17 ((uint32_t)0x00040000)  #define RCC_APB2Periph_TIM9 ((uint32_t)0x00080000)  #define RCC_APB2Periph_TIM10 ((uint32_t)0x00100000)  #define RCC_APB2Periph_TIM11 ((uint32_t)0x00200000)  #define IS_RCC_APB2_PERIPH(PERIPH) ((((PERIPH) & 0xFFC00002) == 0x00) && ((PERIPH) != 0x00))    #define RCC_APB1Periph_TIM2 ((uint32_t)0x00000001)  #define RCC_APB1Periph_TIM3 ((uint32_t)0x00000002)  #define RCC_APB1Periph_TIM4 ((uint32_t)0x00000004)  #define RCC_APB1Periph_TIM5 ((uint32_t)0x00000008)  #define RCC_APB1Periph_TIM6 ((uint32_t)0x00000010)  #define RCC_APB1Periph_TIM7 ((uint32_t)0x00000020)  #define RCC_APB1Periph_TIM12 ((uint32_t)0x00000040)  #define RCC_APB1Periph_TIM13 ((uint32_t)0x00000080)  #define RCC_APB1Periph_TIM14 ((uint32_t)0x00000100)  #define RCC_APB1Periph_WWDG ((uint32_t)0x00000800)  #define RCC_APB1Periph_SPI2 ((uint32_t)0x00004000)  #define RCC_APB1Periph_SPI3 ((uint32_t)0x00008000)  #define RCC_APB1Periph_USART2 ((uint32_t)0x00020000)  #define RCC_APB1Periph_USART3 ((uint32_t)0x00040000)  #define RCC_APB1Periph_UART4 ((uint32_t)0x00080000)  #define RCC_APB1Periph_UART5 ((uint32_t)0x00100000)  #define RCC_APB1Periph_I2C1 ((uint32_t)0x00200000)  #define RCC_APB1Periph_I2C2 ((uint32_t)0x00400000)  #define RCC_APB1Periph_USB ((uint32_t)0x00800000)  #define RCC_APB1Periph_CAN1 ((uint32_t)0x02000000)  #define RCC_APB1Periph_CAN2 ((uint32_t)0x04000000)  #define RCC_APB1Periph_BKP ((uint32_t)0x08000000)  #define RCC_APB1Periph_PWR ((uint32_t)0x10000000)  #define RCC_APB1Periph_DAC ((uint32_t)0x20000000)  #define RCC_APB1Periph_CEC ((uint32_t)0x40000000)  #define IS_RCC_APB1_PERIPH(PERIPH) ((((PERIPH) & 0x81013600) == 0x00) && ((PERIPH) != 0x00))   APB的速率見下面說明: APB的速率見下面說明:

APB1限制在了36MHz,APB2也可以達到全速72MHz 

下面是F105和F107的總線構架:

STM32上APB1和APB2的位址映射

STM32單片機一
STM32單片機一

  -------------------------------------------------------------------------------------------------------------------

四、STM32_NVIC

1、簡述

   需要在STM32上移植RTOS,那麼首先必須深入了解它的中斷系統。什麼是NVIC?即嵌套向量中斷控制器(Nested Vectored Interrupt Controller)。STM32的中有一個強大而友善的NVIC,它是屬于Cortex核心的器件,不可屏蔽中斷 (NMI)和外部中斷都由它來處理,而SYSTICK不是由 NVIC來控制的。

特性:

  60個可屏蔽中斷通道(不包含16個Cortex™-M3的中斷線);

  16個可程式設計的優先等級(使用了4位中斷優先級);

  低延遲的異常和中斷處理;

  電源管理控制;

  系統控制寄存器的實作;

-----------------------------------------------

2、中斷優先級分組

STM32(Cortex-M3)中有兩個優先級的概念--搶占式優先級和響應優先級,有人把響應優先級稱作'亞優先級'或'副優先級',每個中斷源都需要被指定這兩種優先級。 

  具有高搶占式優先級的中斷可以在具有低搶占式優先級的中斷處理過程中被響應,即中斷嵌套,或者說高搶占式優先級的中斷可以嵌套在低搶占式優先級的中斷中。

  當兩個中斷源的搶占式優先級相同時,這兩個中斷将沒有嵌套關系,當一個中斷到來後,如果正在處理另一個中斷,這個後到來的中斷就要等到前一個中斷處理完之後才能被處理。如果這兩個中斷同時到達,則中斷控制器根據他們的響應優先級高低來決定先處理哪一個;如果他們的搶占式優先級和響應優先級都相等,則根據他們在中斷表中的排位順序決定先處理哪一個。

    Cortex核心具有強大的異常響應系統,它把能夠打斷目前代碼執行流程的事件分為異常(exception)和中斷(interrupt),并把它們用一個表管理起來,編号為0~15的稱為核心異常,而16以上的則稱為外部中斷,這個表就稱為中斷向量表。

    正是因為每個中斷源都需要被指定這兩種優先級,就需要有相應的寄存器位記錄每個中斷的優先級;在Cortex-M3中定義了8個比特位用于設定中斷源的優先級,這8個比特位可以有8種配置設定方式,如下:

1)所有8位用于指定響應優先級 

2)最高1位用于指定搶占式優先級,最低7位用于指定響應優先級

3)最高2位用于指定搶占式優先級,最低6位用于指定響應優先級

4)最高3位用于指定搶占式優先級,最低5位用于指定響應優先級

5)最高4位用于指定搶占式優先級,最低4位用于指定響應優先級

6)最高5位用于指定搶占式優先級,最低3位用于指定響應優先級

7)最高6位用于指定搶占式優先級,最低2位用于指定響應優先級

8)最高7位用于指定搶占式優先級,最低1位用于指定響應優先級

以上便是優先級分組的概念,但是Cortex-M3允許具有較少中斷源時使用較少的寄存器位指定中斷源的優先級。

    而STM32對這個表重新進行了編排,把編号從-3至6的中斷向量定義為系統異常,編号為負的核心異常不能被設定優先級,如複位(Reset)、不可屏蔽中斷 (NMI)、硬錯誤(Hardfault)。從編号7開始的為外部中斷,這些中斷的優先級都是可以使用者更改的。詳細的 STM32中斷向量号可以在startup_stm32f10x_XX.s中查找。

是以STM32把指定中斷優先級的寄存器位減少到4位,這4個寄存器位的分組方式如下:

第0組:所有4位用于指定響應優先級(16種)

第1組:最高1位用于指定搶占式優先級,最低3位用于指定響應優先級(8種)

第2組:最高2位用于指定搶占式優先級,最低2位用于指定響應優先級(4種)

第3組:最高3位用于指定搶占式優先級,最低1位用于指定響應優先級(2種)

第4組:所有4位用于指定搶占式優先級

這裡便對于于文章最前提到的固件庫裡相關的函數了——NVIC_PriorityGroupConfig(u32 NVIC_PriorityGroup),函數的參數共有5種:

這個函數的參數(NVIC_PriorityGroup值)有下列5種:

NVIC_PriorityGroup_0 => 選擇第0組

NVIC_PriorityGroup_1 => 選擇第1組

NVIC_PriorityGroup_2 => 選擇第2組

NVIC_PriorityGroup_3 => 選擇第3組

NVIC_PriorityGroup_4 => 選擇第4組

     這其實也很好了解,比如選擇NVIC_PriorityGroup_1,那麼搶占式優先級便占一位,也就是說可以有2^1個級别,可以設定為0和1,而響應優先級則占3位,也就是說可以有2^3個選擇,可以設定為0~7;總共來說就可以差別>16種優先級了。

 //NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

 //NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

-----------------------------------------------

3、舉例說明

      假如現在有4個外部中斷,還有一個EXTI9_5中斷,那麼如果選擇優先級分組為第1組,那麼搶占式優先級便隻有兩種,5個中斷就至少有3個在搶占式優先級上是相同的優先級上,其他兩個在令一優先級别。接着設定響應優先級可以有8種選擇;假如現在同時有兩個搶占式優先級别相同的中斷發生,那麼處理的順序是誰的響應優先級高則誰優先進入中斷,另外這點是需要注意的,如果此時進入這個中斷之後又來了一個搶占式優先級相同但是響應優先級更高的中斷,這時也是不會打斷已有的中斷的。

void NVIC_Config(void)

{

 NVIC_InitTypeDef NVIC_InitStructure;

 #ifdef  VECT_TAB_RAM

    //Set the Vector Table base location at 0x20000000 

    NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);

 #else

    //Set the Vector Table base location at 0x08000000 

    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); 

 #endif

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);  //中斷優先級組 :1組(整個系統為同一組)

    // 設定先占優先級0~1,響應優先級0~7

    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; 

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

    // Enable the TIM3 Interrupt

   NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;       // TIM3 全局中斷

   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 先占優先級 1

   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;    // 從優先級 1

   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;       // IRQ通道被使能

   NVIC_Init(&NVIC_InitStructure);

   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占優先級0

   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;      //響應優先級0

   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

   NVIC_Init(&NVIC_InitStructure); 

}

------------------------------------------------------------------------------------------------------------------- 五、STM32硬體_TIM1輸出互補波形程式 使用官方的庫函數的DEMO,如下圖:

STM32單片機一

  #include "stm32f10x.h" TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; uint16_t TimerPeriod = 0; uint16_t Channel1Pulse = 0, Channel2Pulse = 0, Channel3Pulse = 0, Channel4Pulse = 0; void RCC_Configuration(void); void GPIO_Configuration(void);   int main(void) {   RCC_Configuration();   GPIO_Configuration();   TimerPeriod = (SystemCoreClock / 17570 ) - 1;   Channel1Pulse = (uint16_t) (((uint32_t) 5 * (TimerPeriod - 1)) / 10);   Channel2Pulse = (uint16_t) (((uint32_t) 375 * (TimerPeriod - 1)) / 1000);   Channel3Pulse = (uint16_t) (((uint32_t) 25 * (TimerPeriod - 1)) / 100);   Channel4Pulse = (uint16_t) (((uint32_t) 125 * (TimerPeriod- 1)) / 1000); //定時器初始化 函數 見庫函數 P246頁   TIM_TimeBaseStructure.TIM_Prescaler = 0; //設定用來作為TIM 時鐘頻率除數的預分頻值   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //計數器模式   TIM_TimeBaseStructure.TIM_Period = TimerPeriod;   TIM_TimeBaseStructure.TIM_ClockDivision = 0; //時鐘分割   TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; //設定 周期計數值   TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //TIM1 配置 見 庫函數 P294 頁   TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //脈沖寬度調制模式2   TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能輸出比較狀态   TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; //使能 互補 輸出狀态   TIM_OCInitStructure.TIM_Pulse = Channel1Pulse; //脈沖 值   TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //輸出比較極性低   TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;//互補輸出極性高   TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; //MOE=0 設定 TIM1輸出比較空閑狀态   TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;//MOE=0 重置 TIM1輸出比較空閑狀态   TIM_OC1Init(TIM1, &TIM_OCInitStructure); //設定好的參數初始化TIM   TIM_OCInitStructure.TIM_Pulse = Channel2Pulse; //脈寬值   TIM_OC2Init(TIM1, &TIM_OCInitStructure); //設定好的參數初始化TIM   TIM_OCInitStructure.TIM_Pulse = Channel3Pulse; //脈寬值   TIM_OC3Init(TIM1, &TIM_OCInitStructure); //設定好的參數初始化TIM   TIM_OCInitStructure.TIM_Pulse = Channel4Pulse; //脈寬值   TIM_OC4Init(TIM1, &TIM_OCInitStructure);//設定好的參數初始化TIM   TIM_Cmd(TIM1, ENABLE); //使能 TIM1   TIM_CtrlPWMOutputs(TIM1, ENABLE); //使能 TIM1 輸出   while (1)   {} }   void RCC_Configuration(void) {   RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1   RCC_APB2Periph_GPIOA   RCC_APB2Periph_GPIOE   RCC_APB2Periph_GPIOB   RCC_APB2Periph_AFIO, ENABLE); }   void GPIO_Configuration(void) {   GPIO_InitTypeDef GPIO_InitStructure; #ifdef STM32F10X_CL   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9   GPIO_Pin_11   GPIO_Pin_13   GPIO_Pin_14   GPIO_Pin_8   GPIO_Pin_10   GPIO_Pin_12;   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   GPIO_Init(GPIOE, &GPIO_InitStructure);   GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE); #else   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8   GPIO_Pin_9   GPIO_Pin_10   GPIO_Pin_11;   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   GPIO_Init(GPIOA, &GPIO_InitStructure);   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13   GPIO_Pin_14   GPIO_Pin_15;   GPIO_Init(GPIOB, &GPIO_InitStructure); #endif }   #ifdef USE_FULL_ASSERT void assert_failed(uint8_t* file, uint32_t line) {   while (1)   {} } #endif  

-------------------------------------------------------------------------------------------------------------------

六、STM32硬體_中斷程式設計過程

1、序列槽中斷程式設計過程

本文以USART1為例,叙述序列槽中斷的程式設計過程。

1)應用序列槽中斷時涉及到的一些庫檔案

  首先對于STM32外設庫檔案的應用程式設計,misc.c和stm32f10x_rcc.c是肯定要添加到。

  接下來就是我們要用到的相關外設了。毫無疑問,序列槽檔案stm32f10x_usart.c是必須的。序列槽通信是對通用GPIO端口引腳的功能複用,是以還需要stm32f10x_gpio.c檔案。另外,因為有中斷的産生,是以中斷檔案stm32f10x_it.c也是必要的,當然這個檔案一般和main.c放在一個檔案夾下(一般習慣為User檔案夾),因為我們的中斷響應函數是要在裡面自己編寫的。

  當然還有其他的基本必須檔案如系統配置檔案等在這地方就不說了,這個是建立一個工程應該知道的。

-----------------------

2)初始化

對于序列槽通信的初始化,不僅僅隻是對序列槽的初始化(這個地方是比較煩人的,不像别的晶片那樣簡潔明了)。

(1)首先時鐘使能配置。STM32内部的時鐘有很多,感興趣的自己看看參考手冊。此處以USART1為例說明。有USART1時鐘、GPIOA時鐘、GPIO複用(AFIO)時鐘。由于此處USART1和GPIOA、AFIO均在APB2上,是以可以一次配置完成。如下:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO|RCC_APB2Periph_USART1 ,ENABLE);

(2)其次中斷配置。主要有優先級組設定、USART1中斷使能、該中斷的優先級,中斷初始化。程式如下:

void NVIC_Configuration(void)

{

  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//選擇分組方式0

  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

}

(3)然後GPIO複用功能配置。一般情況下我們使用原始的外設和GPIO端口引腳的映射關系,如果要改變其映射的話,請另外檢視參考手冊上關于GPIO重映射部分。對于GPIO的複用,其引腳的輸入與輸出模式都有要求,在參考手冊上有詳細說明。

void GPIO_Configuration(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

  GPIO_Init(USARTy_GPIO, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  GPIO_Init(USARTy_GPIO, &GPIO_InitStructure);

}

(4)序列槽初始化配置。主要有序列槽基本參數配置(如波特率、資料位、工作方式等),序列槽中斷使能,序列槽使能。

基本參數配置

USART_InitTypeDef USART_InitStructure;

USART_InitStructure.USART_BaudRate = 9600;//波特率

USART_InitStructure.USART_WordLength = USART_WordLength_8b;//資料長度

USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位

USART_InitStructure.USART_Parity = USART_Parity_No;//校驗

USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//無硬體流控制

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //發送與接受兩種方式

USART_Init(USART1, &USART_InitStructure);//用配置的參數激活序列槽初始化

 序列槽中斷使能

USART_ITConfig(USARTy, USART_IT_RXNE, ENABLE);//使能接受中斷,在接受移位寄存器中有資料時産生

USART_ITConfig(USARTy, USART_IT_TXE, ENABLE);//使能發送中斷,在發送完資料 後産生。

一般情況下,如果與PC通信的話,我們隻用接受中斷即可。

 序列槽使能

USART_Cmd(USART1, ENABLE); //USART1使能

好了,經過以上步驟之後呢,我們就可以進行資料的收發了。

-----------------------

3)發送資料

//使用函數USART_SendData(USART1, char data),一次隻能發送一個字元。當然我們可以用如下函數發送字元串。

void USART1_Puts(char * str) 

  while(*str)

  USART_SendData(USART1, *str++);  //發送一個字元

while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);  //等待發送完畢

}

//當然我們也可以循環發送字元串數組

for(i = 0; TxBuf1 != '\0'; i++) // TxBuf1為定義好的字元串數組

{

  USART_SendData(USART2 , TxBuf1);

  while(USART_GetFlagStatus(USART2, USART_FLAG_TC)==RESET);

}

-----------------------

4)接收資料

由于我們使用的是接受中斷,是以當有資料需要接收時,會執行相應的中斷函數。此處我們USART1的中斷函數在stm32f10x_it.c檔案中。找到函數void USART1_IRQHandler(void),如果沒有的話就自己加上吧,别忘了頭檔案中需要聲明一下。當然你也可以在其他檔案中寫下該中斷函數。當産生中斷進入該函數之後,我們就可以進行自己的操作了。

void USART1_IRQHandler(void)

{

  if(USART_GetITStatus(USARTy, USART_IT_RXNE) != RESET)//如果寄存器中有資料

  {

    RxBuffer1[RxCounter1++] = USART_ReceiveData(USART1);

  }  

}

别忘了在接受完資料進行别的操作之前為了防止資料被覆寫最好先禁止一下接受中斷

USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); 

USART_ITConfig(USART1, USART_IT_TXE, DISABLE);

-----------------------

5)main函數

int main(void) //這個地方有些特别,我們知道一般main函數是沒有傳回值的,但在STM32 的程式設計中其傳回類型為int。

{

  RCC_Configuration();

  NVIC_Configuration();

  GPIO_Configuration();

  USART_InitStructure.USART_BaudRate = 9600;

  USART_InitStructure.USART_WordLength = USART_WordLength_8b;

  USART_InitStructure.USART_StopBits = USART_StopBits_1;

  USART_InitStructure.USART_Parity = USART_Parity_No;

  USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;

  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

  USART_Init(USART1, &USART_InitStructure);

  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

  //USART_ITConfig(USART1, USART_IT_TXE, ENABLE);

  USART_Cmd(USART1, ENABLE);

  while (1) //等待中斷

  {

  }

}

當然你也可以在main()中添加一些發送指令之類的東西。

----------------------- 6)在啟動檔案查找中斷函數

STM32單片機一

  ------------------------------------------ 2、外中斷程式設計過程式設計過程 1)通用I/O端口連接配接到16個外部中斷/事件線

STM32單片機一

----------------------- 2)外部中斷服務函數的編寫   EXPORT   EXTI0_IRQHandler   EXPORT   EXTI1_IRQHandler   EXPORT   EXTI2_IRQHandler   EXPORT   EXTI3_IRQHandler   EXPORT   EXTI4_IRQHandler   EXPORT   EXTI9_5_IRQHandler   EXPORT   EXTI15_10_IRQHandler 中斷線 0~4 每個中斷線對應一個中斷函數 中斷線 5~9 共用中斷函數 EXTI9_5_IRQHandler 中斷線 10~15 共用中斷函數 EXTI15_10_IRQHandler ----------------------- 3)具體程式編寫 void SurgeProtection_IO_Init(void) {

GPIO_InitTypeDef GPIO_InitStructure; // 使能PortD的外設時鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOD, ENABLE);   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOD, &GPIO_InitStructure);

} void SurgeProtection_IO_EXTI_Init(void) {

EXTI_InitTypeDef EXTI_InitStructure; EXTI_ClearITPendingBit(EXTI_Line8); GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource8); EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿觸發 EXTI_InitStructure.EXTI_Line=EXTI_Line8; EXTI_Init(&EXTI_InitStructure);

} void SurgeProtection_IO_EXTI_Init1(void) {

EXTI_InitTypeDef EXTI_InitStructure; EXTI_ClearITPendingBit(EXTI_Line9); GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource9); EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿觸發 EXTI_InitStructure.EXTI_Line=EXTI_Line9; EXTI_Init(&EXTI_InitStructure);

} void SurgeProtection_NVIC_Init(void) {

NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=6; NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure);

} void SurgeProtectionInit(void)  注:兩個中斷EXIT_Init不能合二為一,不知何故。 {

SurgeProtection_IO_Init(); SurgeProtection_IO_EXTI_Init(); SurgeProtection_IO_EXTI_Init1(); SurgeProtection_NVIC_Init();

} /邊沿觸發中斷服務函數入口/ void EXTI9_5_IRQHandler(void) {

if((EXTI_GetITStatus(EXTI_Line8)!=RESET)||(EXTI_GetITStatus(EXTI_Line9)!=RESET)) {
if(!GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_8)) //PD8=0
{
//使用者服務程式
EXTI_ClearITPendingBit(EXTI_Line8);
}
if(!GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_9)) //PD9=0
{
//使用者服務程式
EXTI_ClearITPendingBit(EXTI_Line9);
}
}

}   ------------------------------------------------------------------------------------------------------------------- 七、STM32硬體_AD用DMA方式時的請注意程式初始化順序 1、DMA初始化 珍情歲月(84848098) 17:19:23

  DMA_DeInit(DMA1_Channel1);

  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //ADC1_DR_Address=(u32)(&ADC1->DR)   DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_Result;

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

  DMA_InitStructure.DMA_BufferSize = 6;

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;;

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

  DMA_InitStructure.DMA_Priority = DMA_Priority_High;

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  DMA_Init(DMA1_Channel1, &DMA_InitStructure);

  //DMA_Cmd(DMA1_Channel1, ENABLE);//以前在這裡啟用DMA,出現通道錯亂

  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

  ADC_InitStructure.ADC_ScanConvMode = ENABLE;

  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  ADC_InitStructure.ADC_NbrOfChannel = 6;

  ADC_Init(ADC1, &ADC_InitStructure);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_55Cycles5);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_55Cycles5);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 6, ADC_SampleTime_55Cycles5);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 5, ADC_SampleTime_55Cycles5);

  ADC_DMACmd(ADC1, ENABLE);

  ADC_Cmd(ADC1, ENABLE);

  ADC_ResetCalibration(ADC1);

  while(ADC_GetResetCalibrationStatus(ADC1));

  ADC_StartCalibration(ADC1);

  while(ADC_GetCalibrationStatus(ADC1));

  DMA_Cmd(DMA1_Channel1, ENABLE);

  ADC_SoftwareStartConvCmd(ADC1, ENABLE);

以上代碼轉自STM32交流群的“情歲月”(84848098) 17:27:48的發言,在此對他表示感謝。

下面的經驗也是“珍情歲月”提供:

用DMA連續采樣多路,自動觸發,如果在初始化AD前使能了DMA就會出現資料錯位現象。 要注意在初始化時将DMA_Cmd(DMA1_Channel1, ENABLE);放置到ADC_SoftwareStartConvCmd(ADC1, ENABLE);前面。 原因是:如果在初始化AD的時候DMA被觸發了一次,但是此時并沒有采樣,但是DMA目的位址已經發生了自加,當你采樣第一路的時候,資料卻填充到了第二路。校準AD的時候會觸發DMA導緻通道錯位,是以校準AD基準前不要啟用DMA。 ----------------------------------------------- 2、STM32關于使用定時器觸發ADC轉換的解決辦法和詳細說明 詳見“AD轉換彙總(去最大最小取平均)”   ------------------------------------------------------------------------------------------------------------------- 八、STM32硬體_外設位址設定   寫過AD采集,DA輸出的人應該知道,經常要在代碼的開始設定外設的位址,那麼這個位址是怎麼來的呢? 檢視《STM32F10XX參考手冊》中的存儲器映像得知:每一個STM32F10XX的外設都有特定的起始位址,如下圖:

STM32單片機一
STM32單片機一

那麼該怎麼用呢?先來看這樣一個例子:用AD1的通道14采集資料,并通過DMA1通道1傳輸資料,顯示在LCD12864上。在DMA外設位址設定中我們就需要知道ADC1_DR_ADDRESS的值了,從上表我們知道ADC1的位址範圍為:0x40012400~0x400127FF

找到10.12.15節:ADC寄存器位址映像表:

STM32單片機一
STM32單片機一

在表的最後一欄ADC_DR,即ADC資料寄存器,我們就可以得知ADC_DR的位址偏移,再加上ADC1的起始位址0x40012400,就可以得到ADC_DR_ADDRESS = 0x4001244C

其他外設的位址也是相同的原理,步驟如下:

 根據表1找到外設的起始位址;

根據外設的存儲器映像表找到具體寄存器的偏移量;

起始位址+偏移位址 = 外設寄存器的實際位址

  ------------------------------------------------------------------------------------------------------------------- 九、STM32硬體_時鐘樹

1、在STM32上如果不使用外部晶振,OSC_IN和OSC_OUT的接法

 如果使用内部RC振蕩器而不使用外部晶振,請按照下面方法處理:

1)對于100腳或144腳的産品,OSC_IN應接地,OSC_OUT應懸空。

2)對于少于100腳的産品,有2種接法:

2.1)OSC_IN和OSC_OUT分别通過10K電阻接地。此方法可提高EMC性能。

2.2)分别重映射OSC_IN和OSC_OUT至PD0和PD1,再配置PD0和PD1為推挽輸出并輸出'0'。此方法可以減小功耗并(相對上面2.1)節省2個外部電阻。

HSI内部8MHz的RC振蕩器的誤差在1%左右,内部RC振蕩器的精度通常比用HSE(外部晶振)要差上十倍以上。STM32的ISP就是用(HSI)内部RC振蕩器。

-----------------------------------------------

2、STM32時鐘系統

1)簡述

在STM32中,有五個時鐘源,為HSI、HSE、LSI、LSE、PLL。

HSI是高速内部時鐘,RC振蕩器,頻率為8MHz。

HSE是高速外部時鐘,可接石英/陶瓷諧振器,或者接外部時鐘源,頻率範圍為4MHz~16MHz。

LSI是低速内部時鐘,RC振蕩器,頻率為40kHz。

LSE是低速外部時鐘,接頻率為32.768kHz的石英晶體。

PLL為鎖相環倍頻輸出,其時鐘輸入源可選擇為HSI/2、HSE或者HSE/2。倍頻可選擇為2~16倍,但是其輸出頻率最大不得超過72MHz。

STM32單片機一

  使用者可通過多個預分頻器配置AHB總線、高速APB2總線和低速APB1總線的頻率。AHB和APB2域的最大頻率是72MHZ。APB1域的最大允許頻率是36MHZ。SDIO接口的時鐘頻率固定為HCLK/2。

  40kHz的LSI供獨立看門狗IWDG使用,另外它還可以被選擇為實時時鐘RTC的時鐘源。另外,實時時鐘RTC的時鐘源還可以選擇LSE,或者是HSE的128分頻。RTC的時鐘源通過RTCSEL[1:0]來選擇。

  STM32中有一個全速功能的USB子產品,其串行接口引擎需要一個頻率為48MHz的時鐘源。該時鐘源隻能從PLL輸出端擷取,可以選擇為1.5分頻或者1分頻,也就是,當需要使用USB子產品時,PLL必須使能,并且時鐘頻率配置為48MHz或72MHz。

  另外,STM32還可以選擇一個PLL輸出的2分頻、HSI、HSE、或者系統時鐘SYSCLK輸出到MCO腳(PA8)上。系統時鐘SYSCLK,是供STM32中絕大部分部件工作的時鐘源,它可選擇為PLL輸出、HSI或者HSE,(一般程式中采用PLL倍頻到72Mhz)在選擇時鐘源前注意要判斷目标時鐘源是否已經穩定振蕩。Max=72MHz,它分為2路,1路送給I2S2、I2S3使用的I2S2CLK,I2S3CLK;另外1路通過AHB分頻器分頻(1/2/4/8/16/64/128/256/512)分頻後送給以下8大子產品使用:

送給SDIO使用的SDIOCLK時鐘。

送給FSMC使用的FSMCCLK時鐘。

送給AHB總線、核心、記憶體和DMA使用的HCLK時鐘。

通過8分頻後送給Cortex的系統定時器時鐘(SysTick)。

直接送給Cortex的空閑運作時鐘FCLK。

送給APB1分頻器。APB1分頻器可選擇1、2、4、8、16分頻,其輸出一路供APB1外設使用(PCLK1,最大頻率36MHz),另一路送給定時器(Timer2-7)2、3、4倍頻器使用。該倍頻器可選擇1或者2倍頻,時鐘輸出供定時器2、3、4、5、6、7使用。

送給APB2分頻器。APB2分頻器可選擇1、2、4、8、16分頻,其輸出一路供APB2外設使用(PCLK2,最大頻率72MHz),另一路送給定時器(Timer1、Timer8)1、2倍頻器使用。該倍頻器可選擇1或者2倍頻,時鐘輸出供定時器1和定時器8使用。另外,APB2分頻器還有一路輸出供ADC分頻器使用,分頻後得到ADCCLK時鐘送給ADC子產品使用。ADC分頻器可選擇為2、4、6、8分頻。

2分頻後送給SDIO AHB接口使用(HCLK/2)。

-----------------------

2)時鐘輸出的使能控制

  在以上的時鐘輸出中有很多是帶使能控制的,如AHB總線時鐘、核心時鐘、各種APB1外設、APB2外設等。

當需要使用某子產品時,必需先使能對應的時鐘。需要注意的是定時器的倍頻器,當APB的分頻為1時,它的倍頻值為1,否則它的倍頻值就為2。

  連接配接在APB1(低速外設)上的裝置有:電源接口、備份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、視窗看門狗、 Timer2、Timer3、Timer4。注意USB子產品雖然需要一個單獨的48MHz時鐘信号,但它應該不是供USB子產品工作的時鐘,而隻是提供給串行接口引擎(SIE)使用的時鐘。USB子產品工作的時鐘應該是由APB1提供的。

  連接配接在APB2(高速外設)上的裝置有:GPIO_A-E、USART1、ADC1、ADC2、ADC3、TIM1、TIM8、SPI1、AFIO

STM32單片機一

-----------------------

3)使用HSE時鐘,程式設定時鐘參數流程

(1)将RCC寄存器重新設定為預設值 RCC_DeInit;

(2)打開外部高速時鐘晶振HSE   RCC_HSEConfig(RCC_HSE_ON);

(3)等待外部高速時鐘晶振工作   HSEStartUpStatus = RCC_WaitForHSEStartUp();

(4)設定AHB時鐘          RCC_HCLKConfig;

(5)設定高速AHB時鐘     RCC_PCLK2Config;

(6)設定低速速AHB時鐘    RCC_PCLK1Config;

(7)設定PLL         RCC_PLLConfig;

(8)打開PLL         RCC_PLLCmd(ENABLE);

(9)等待PLL工作       while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)

(10)設定系統時鐘      RCC_SYSCLKConfig;

(11)判斷是否PLL是系統時鐘  while(RCC_GetSYSCLKSource() != 0x08)

(12)打開要使用的外設時鐘  RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()

下面是STM32軟體固件庫的程式中對RCC的配置函數(使用外部8MHz晶振)

void RCC_Configuration(void)

{

  RCC_DeInit();

  RCC_HSEConfig(RCC_HSE_ON);   //RCC_HSE_ON——HSE晶振打開(ON)

  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if(HSEStartUpStatus == SUCCESS)        //SUCCESS:HSE晶振穩定且就緒

  {   

    RCC_HCLKConfig(RCC_SYSCLK_Div1);  //RCC_SYSCLK_Div1——AHB時鐘 = 系統時鐘

    RCC_PCLK2Config(RCC_HCLK_Div1);   //RCC_HCLK_Div1——APB2時鐘 = HCLK

    RCC_PCLK1Config(RCC_HCLK_Div2);   //RCC_HCLK_Div2——APB1時鐘 = HCLK / 2

    FLASH_SetLatency(FLASH_Latency_2);    //FLASH_Latency_2  2延時周期

    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);       // 預取指緩存使能

    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);    

   // PLL的輸入時鐘 = HSE時鐘頻率;RCC_PLLMul_9——PLL輸入時鐘x 9

    RCC_PLLCmd(ENABLE);

    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) ;    

    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

   //RCC_SYSCLKSource_PLLCLK——選擇PLL作為系統時鐘

    while(RCC_GetSYSCLKSource() != 0x08);        //0x08:PLL作為系統時鐘

  }

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |

  RCC_APB2Periph_GPIOC , ENABLE);

//RCC_APB2Periph_GPIOA    GPIOA時鐘

//RCC_APB2Periph_GPIOB    GPIOB時鐘

//RCC_APB2Periph_GPIOC    GPIOC時鐘

//RCC_APB2Periph_GPIOD    GPIOD時鐘

}

-----------------------------------------------

3、定時器對應的輸出端口

查找其資料手冊找到對應的端口

STM32單片機一

-------------------------------------------------------------------------------------------------------------------

繼續閱讀