久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3177|回復: 1
打印 上一主題 下一主題
收起左側

解析STM32的庫函數-學習筆記分享

[復制鏈接]
跳轉到指定樓層
樓主
ID:386207 發表于 2018-8-16 03:21 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
解析STM32的庫函數

  意法半導體在推出 STM32 微控制器之初,也同時提供了一套完整細致的固件開發包, 里面包含了在 STM32 開發過程中所涉及到的所有底層操作。通過在程序開發中引入這樣的 固件開發包,可以使開發人員從復雜冗余的底層寄存器操作中解放出來,將精力專注應用程 序的開發上,這便是 ST 推出這樣一個開發包的初衷。

但這對于許多從 51/AVR 這類單片機的開發轉到 STM32 平臺的開發人員來說,勢必有一 個不適應的過程。因為程序開發不再是從寄存器層次起始,而要首先去熟悉 STM32 所提供 的固件庫。那是否一定要使用固件庫呢?當然不是。但 STM32 微控制器的寄存器規模可不 是常見的 8 位單片機可以比擬,若自己細細琢磨各個寄存器的意義,必然會消耗相當的時間, 并且對于程序后續的維護,升級來說也會增加資源的消耗。對于當前“時間就是金錢”的行 業競爭環境,無疑使用庫函數進行 STM32 的產品開發是更好的選擇。本文將通過一個簡單 的例子對 STM32 的庫函數做一個簡單的剖析。

以最常用的 GPIO 設備的初始化函數為例,如下程序段一:
GPIO_InitTypeDef GPIO_InitStructure;              ○1
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;              ○2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;              ○3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;              ○4
GPIO_Init(GPIOA , &GPIO_InitStructure);              ○5


這是一個在 STM32 的程序開發中經常使用到的 GPIO 初始化程序段,其功能是將 GPIOA.4 口 初始化為推挽輸出狀態,并最大翻轉速率為50MHz。

下面逐一分解:
              首先是○1 ,該語句顯然定義了一個 GPIO_InitTypeDef 類型的變量,名為 GPIO_InitStructure, 則找出 GPIO_InitTypeDef 的原型位于“stm32f10x_gpio.h”文件,原型如下:
typedef struct
{
u16 GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;
由此可知 GPIO_InitTypeDef 是一個結構體類型同義字,其功能是定義一個結構體,該結 構體有三個成員分別是 u16 類型的 GPIO_Pin、GPIOSpeed_TypeDef類型的 GPIO_Speed 和 GPIOMode_TypeDef  類 型 的 GPIO_Mode 。 繼 續 探 查 GPIOSpeed_TypeDef  和 GPIOMode_TypeDef 類型,在“stm32f10x_gpio.h”文件中找到對 GPIOSpeed_TypeDef 的 定義:
typedef enum
{
GPIO_Speed_10MHz = 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
則可知 GPIOSpeed_TypeDef 枚舉類型同一只,其功能是定義一個枚舉類型變量,該變量 可表示 GPIO_Speed_10MHz、GPIO_Speed_2MHz 和GPIO_Speed_50MHz 三個含義(其中 GPIO_Speed_10MHz 已經定義為 1,讀者必須知道 GPIO_Speed_2MHz 則依次被編譯器賦 予 2,而 GPIO_Speed_50MHz為 3)。
同樣也在“stm32f10x_gpio.h”文件中找到對 GPIOMode_TypeDef 的定義:


typedef enum
{
GPIO_Mode_AIN = 0x0, GPIO_Mode_IN_FLOATING = 0x04, GPIO_Mode_IPD = 0x28, GPIO_Mode_IPU =0x48, GPIO_Mode_Out_OD = 0x14, GPIO_Mode_Out_PP = 0x10, GPIO_Mode_AF_OD = 0x1C,GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;
這同樣是一個枚舉類型同義字,其成員有 GPIO_Mode_AIN、GPIO_Mode_AF_OD 等(也 可以輕易判斷出這表示 GPIO 設備的工作模式)。

至此對程序段一的○1 解析可以做一個總結:
該行定義一個結構體類型的變量 GPIO_InitStructure,并且該結構體有 3 個成員,分別為 GPIO_Pin、GPIO_Speed 和 GPIO_Mode,并且 GPIO_Pin 表示 GPIO 設備引腳 GPIO_Speed 表示 GPIO 設備速率和 GPIO_Mode 表示 GPIO 設備工作模式。

              接下來是○2 ,此句是一個賦值語句,把 GPIO_Pin_4 賦給 GPIO_InitStructure 結構體中的 成員 GPIO_Pin,可以在“stm32f10x_gpio.h”文件中找到對GPIO_Pin_4 做的宏定義:
#define GPIO_Pin_4                ((u16)0x0010)
因此○2 的本質是將 16 位數 0x0010 賦給 GPIO_InitStructure 結構體中的成員 GPIO_Pin。

              ○3  語 句和 ○2  相似將 GPIO_Speed_50MHz 賦給 GPIO_InitStructure 結 構體中的成員
GPIO_Speed,但注意到此處 GPIO_Speed_50MHz 只是一個枚舉變量,并非具體的某個值。

              ○4 語句亦和○2 語句類似,把 GPIO_Mode_Out_PP 賦給 GPIO_InitStructure 結構體中的成 員 GPIO_Mode,從上文可知 GPIO_Mode_Out_PP 的值為0x10。

              ○5 是一個函數調用,即調用 GPIO_Init 函數,并提供給該函數 2 個參數,分別為 GPIOA 和&GPIO_InitStructure,其中&GPIO_InitStructure 表示結構體變量 GPIO_InitStructure 的 地址,而 GPIOA 則在“stm32f10x_map.h”文件中找到定義:
#ifdef _GPIOA
#define GPIOA              ((GPIO_TypeDef *) GPIOA_BASE)
#endif
此三行代碼是一個預編譯結構 , 首先判斷是否定義了宏_GPIOA 。 可以在 “stm32f10x_conf.h”中發現對_GPIOA 的定義為:
#define _GPIOA


這表示編譯器會將代碼中出現的 GPIOA 全部替換為((GPIO_TypeDef *) GPIOA_BASE)。從 該句的 C 語言語法可以判斷出((GPIO_TypeDef *) GPIOA_BASE)的功能為將 GPIOA_BASE 強制類型轉換為指向 GPIO_TypeDef 類型的結構體變量。如此則需要找出 GPIOA_BASE 的含義,依次在“stm32f10x_map.h”文件中找到:
#define GPIOA_BASE                         (APB2PERIPH_BASE + 0x0800)
和:
#define APB2PERIPH_BASE              (PERIPH_BASE + 0x10000)
還有:
#define PERIPH_BASE                       ((u32)0x40000000)
明顯 GPIOA_BASE 表示一個地址,通過將以上 3 個宏展開可以得到:


GPIOA_BASE = 0x40000000 + 0x10000 + 0x0800
此處的關鍵便在于 0x40000000、0x10000 和 0x0800 這三個數值的來歷。讀者應該通過 宏名猜到了,這就是 STM32 微控制器的 GPIOA 的設備地址。通過查閱STM32 微控制器 開發手冊可以得知,STM32 的外設起始基地址為 0x40000000,而 APB2 總線設備起始地 址相對于外設基地址的偏移量為 0x10000,GPIOA設備相對于 APB2 總線設備起始地址 偏移量為 0x0800。
對○5 句代碼進行一個總結:調用 GPIO_Init 函數,并將 STM32 微控制器的 GPIOA 設備地 址和所定義的結構體變量 GPIO_InitStructure 的地址傳入。
以上是對 GPIOA 初始化庫函數的剖析,現繼續轉移到函數內部分析,GPIO_Init 函數原 型如程序段二:

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
u32 currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
u32 tmpreg = 0x00, pinmask = 0x00;

/* 檢查參數是否正確 */ assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));

/* 將工作模式暫存至 currentmode 變量中 */
currentmode = ((u32)GPIO_InitStruct->GPIO_Mode) & ((u32)0x0F);
/* 如果欲設置為任意一種輸出模式,則再檢查”翻轉速率“參數是否正確 */
if ((((u32)GPIO_InitStruct->GPIO_Mode) & ((u32)0x10)) != 0x00)
{
assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
currentmode |= (u32)GPIO_InitStruct->GPIO_Speed;
}


/* 設置低八位引腳(即 pin0 ~ pin7) */
if (((u32)GPIO_InitStruct->GPIO_Pin & ((u32)0x00FF)) != 0x00)
{
/* 讀出當前配置字 */
tmpreg = GPIOx->CRL;
for (pinpos = 0x00; pinpos < 0x08; pinpos++)
{
/* 獲取將要配置的引腳號 */
pos = ((u32)0x01) << pinpos;
currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
if (currentpin == pos)
{
/* 先清除對應引腳的配置字 */
pos = pinpos << 2;
pinmask = ((u32)0x0F) << pos;


tmpreg &= ~pinmask;
/* 寫入新的配置字 */
tmpreg |= (currentmode << pos);
/* 若欲配置為上拉 / 下拉輸入,則需要配置 BRR 和 BSRR 寄存器 */
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
{

}
else
{
GPIOx->BRR = (((u32)0x01) << pinpos);


if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
{


GPIOx->BSRR = (((u32)0x01) << pinpos);
}
}
}
}
/* 寫入低八位引腳配置字 */ GPIOx->CRL = tmpreg;
}


/* 設置高八位引腳(即 pin8 ~ pin15),流程和第八位引腳配置流程一致,不再作解析 */
if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
{
tmpreg = GPIOx->CRH;
for (pinpos = 0x00; pinpos < 0x08; pinpos++)
{
pos = (((u32)0x01) << (pinpos + 0x08));
currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
if (currentpin == pos)
{
pos = pinpos << 2;
pinmask = ((u32)0x0F) << pos;
tmpreg &= ~pinmask;
tmpreg |= (currentmode << pos);
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
{
GPIOx->BRR = (((u32)0x01) << (pinpos + 0x08));
}
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
{
GPIOx->BSRR = (((u32)0x01) << (pinpos + 0x08));
}
}


}
GPIOx->CRH = tmpreg;
}
}
這段程序的流程是:首先檢查由結構體變量 GPIO_InitStructure 所傳入的參數是否正確, 然后對 GPIO 寄存器進行“保存——修改——寫入”的操作,完成對 GPIO 設備的設置工作。 顯然,結構體變量 GPIO_InitStructure 所傳入參數的目的是設置對應 GPIO 設備的寄存器。而 STM32 的參考手冊對關于 GPIO 設備的設置寄存器的描述如下圖 1 和表 1(僅列出低八位引 腳寄存器描述,高八位引腳類同):
圖 1              GPIO 設備控制寄存器 GPIOx_CRL

位 31:30
27:26
23:22
19:18
15:14
11:10
7:6
3:2
在輸入模式(MODE[1:0]=00):
00:模擬輸入模式
01:浮空輸入模式(復位后的狀態)
10:上拉/下拉輸入模式
11:保留

在輸出模式(MODE[1:0]>00):
00:通用推挽輸出模式
01:通用開漏輸出模式
10:復用功能推挽輸出模式
11:復用功能開漏輸出模式
位 29:28
25:24
21:20
17:16
13:12
9:8
5:4
1:0

MODEy[1:0] :端口 x 的模式位(y = 0„7) (Port x mode bits)
軟件通過這些位配置相應的 I/O 端口,請參考表 17 端口位配置表。
00:輸入模式(復位后的狀態)
01:輸出模式,最大速度 10MHz
10:輸出模式,最大速度 2MHz
11:輸出模式,最大速度 50MHz
表 1  GPIO 設備控制寄存器 GPIOx_CRL 描述
該寄存器為 32 位,其中分為 8 份,每份 4 位,對應低八位引腳的設置。每一個引腳的 設置字分為兩部分,分別為 CNF 和 MODE,各占兩位空間。當MODE 的設置字為 0 時,表 示將對應引腳配置為輸入模式,反之設置為輸出模式,并有最大翻轉速率限制。而當引腳配 置為輸出模式時,CNF 配置字則決定引腳以哪種輸出方式工作(通用推挽輸出、通用開漏輸 出等)。通過對程序的閱讀和分析不難發現,本文最初程序段中 GPIO_InitStructure 所傳入參 數的對寄存器的作用如下:

              GPIO_Pin_4 被宏替換為 0x0010,對應圖 1 可看出為用于選擇配置 GPIOx_CRL 的[19:16]


位,分別為 CNF4[1:0]、MODE4[1:0]。

             GPIO_Speed_50MHz 為枚舉類型,包含值 0x03,被用于將 GPIOx_CRL 位中的 MODE4[1:0]
配置為 b11(此處 b 意指二進制)。

            GPIO_Mode 亦為枚舉類型,包含值 0x10,被用于將 GPIOx_CRL 位中的 MODE4[1:0]配置 為 b00。事實上 GPIO_Mode 的值直接影響寄存器的只有低四位,而高四位的作用可以 從程序段二中看出,是用于判斷此參數是否用于 GPIO 引腳輸出模式的配置。 至此應不難知道 STM32 的固件庫最后是怎樣影響最底層的寄存器的。總結起來就是:
固件庫首先將各個設備所有寄存器的配置字進行預先定義,然后封裝在結構或枚舉變量中, 待用戶調用對應的固件庫函數時,會根據用戶傳入的參數從這些封裝好的結構或枚舉變量中 取出對應的配置字,最后寫入寄存器中,完成對底層寄存器的配置。
可以看到,STM32 的固件庫函數對于程序開發人員來說是十分便利的存在,只需要填 寫言簡意賅的參數就可以在完全不關心底層寄存器的前提下完成相關寄存器的配置,具有相 當不錯的通用性和易用性,也采取了一定措施保證庫函數的安全性(主要引入了參數檢查函
數 assert_param)。但同時也應該知道,通用性、易用性和安全性的代價是加大了代碼量, 同時增加了一些邏輯判斷代碼造成了一定的時間消耗,在對時間要求比較苛刻的應用場合需 要評估使用固件庫函數對程序運行時間所帶來的影響。讀者在使用 STM32 的固件庫函數進 行程序開發時,應該意識到這些問題。


完整的pdf格式文檔51黑下載地址:
STM32學習筆記.pdf (310.69 KB, 下載次數: 29)


評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:1 發表于 2018-8-16 03:37 | 只看該作者
好資料,51黑有你更精彩!!!
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 一级黄色绿像片 | 久久一久久 | av免费网站在线 | 成人久久18免费网站麻豆 | 欧美成人精品在线观看 | 亚洲高清久久 | 午夜三级网站 | 久久九 | 成人影院在线视频 | 久久久久久国产 | 日韩综合一区 | 国产精品久久久久久久久久尿 | 成人午夜 | 日韩精品一区在线观看 | 欧美黄色一区 | 国产一区二区小视频 | 亚洲精品日韩一区二区电影 | 欧洲av在线 | 在线成人免费视频 | a级大片免费观看 | 亚洲www | 久久伊人精品一区二区三区 | 午夜午夜精品一区二区三区文 | 亚洲一区二区三区免费在线 | 国产乱码精品一区二区三区五月婷 | 日日干夜夜操 | 久久精品亚洲精品国产欧美 | 国产高清精品在线 | 91网视频 | 精品久久久久久久 | 五月网婷婷| 啪啪免费| 国产不卡在线播放 | 亚洲欧美一区二区三区在线 | 91精品国产一区二区三区 | 中文在线一区二区 | 亚洲第一在线 | 午夜影院视频在线观看 | 国产国产精品久久久久 | 欧美二级 | 国产在线高清 |