- 嵌入式技術與應用開發項目教程(STM32版)
- 郭志勇
- 3863字
- 2020-01-16 14:07:18
1.2 任務2 點亮一個LED
任務要求
使用STM32F103R6芯片,其PB8引腳接LED的陰極,通過C語言程序控制,從PB8引腳輸出低電平,使LED點亮。
1.2.1 用Proteus設計第一個STM32的LED控制電路
1. Proteus仿真軟件簡介
本書使用的Proteus 8.6 Professional是英國Lab Center Electronics公司最新推出的一款EDA工具(仿真軟件),支持STM32 Cortex-M3系列的仿真,是目前世界上唯一將電路仿真軟件、PCB(印制電路板)設計軟件和虛擬模型仿真軟件三合一的設計平臺。它實現了在計算機上,從原理圖與電路設計、電路分析與仿真、單片機代碼級調試與仿真、系統測試與功能驗證,到形成PCB的完整的電子設計研發過程,真正實現了從概念到產品的完整設計。
2. STM32的LED控制電路設計分析與實現
Proteus 8.6 Professional仿真軟件只支持STM32 Cortex-M3系列6種型號的芯片,本任務選擇STM32F103R6芯片,該芯片是由ST公司生產的。
LED加正向電壓發光,反之,不發光。LED電路設計一般采用的方法是:陽極接高電平,陰極接輸出控制引腳。當該引腳輸出低電平時,LED點亮;該引腳輸出高電平時,LED不亮。這樣我們只須編程控制該引腳,就可以控制LED亮或滅。
按照任務要求,點亮一個LED電路可由STM32F103R6和LED電路構成。LED陽極通過100Ω限流電阻后連接高電平(電源),電阻在這里起到了限流分壓的作用。STM32F103R6芯片的PB8引腳連接LED陰極,PB8引腳輸出低電平時,LED點亮,輸出高電平時,LED熄滅。STM32的LED控制電路設計如圖1-24所示。

圖1-24 STM32的LED控制電路
3. 用Proteus設計STM32的LED控制電路
這里介紹兩種運行Proteus仿真軟件的方法。第一種是雙擊桌面上的Proteus 8 Professional圖標;第二種是單擊屏幕左下方的“開始”→“程序”→“Proteus 8 Professional”→“Proteus 8 Professional”應用程序,進入Proteus 8 Professional主頁,如圖1-25所示。

圖1-25 Proteus 8 Professional主頁
(1)新建Proteus工程
在設計原理圖之前,必須先新建一個Proteus工程。由于本書沒有涉及PCB繪制,所以這里新建一個帶有原理圖和無PCB的Proteus工程。
在圖1-25中,單擊Proteus 8 Professional主頁頂部的New Project按鈕,彈出New Project Wizard:Start對話框,在Name欄中輸入新建工程名“LED點亮控制”,并選擇新建工程保存路徑,如圖1-26所示。

圖1-26 New Project Wizard:Start對話框
單擊Next按鈕,彈出New Project Wizard:Schematic Design對話框,如果不需要繪制原理圖,可直接選擇Do not create a schematic。本任務是從模板創建原理圖的,先選擇Create a Schematic from the selected template,然后選擇默認DEFAULT模板,如圖1-27所示。

圖1-27 New Project Wizard:Schematic Design對話框
單擊Next按鈕,彈出New Project Wizard:PCB Layout對話框,因為不需要進行PCB設計,直接選擇Do not create a PCB Layout,如圖1-28所示。

圖1-28 New Project Wizard: PCB Layout對話框
單擊Next按鈕,彈出New Project Wizard: Firmware對話框,若需要仿真,在仿真頁面選擇Create Firmware Project,并設置Family(系列)為Cortex-M3,Controller(控制器)為STM32F103R6,Compiler(編譯器)為GCC for Arm(not configured),也就是在此設計外部代碼編譯器,如圖1-29(a)所示。若不需要仿真,則可直接選擇No Firmware Project,如圖1-29(b)所示。

圖1-29 New Project Wizard: Firmware對話框
單擊Next按鈕,彈出New Project Wizard: Summary對話框,如圖1-30所示。

圖1-30 New Project Wizard: Summary對話框
如果單擊圖1-30(a)的Finish按鈕,就完成帶有Schematic Capture(電路圖繪制)和Source Code(源代碼)選項卡的新建工程,如圖1-31所示。

圖1-31 Schematic Capture和Source Code選項卡
Proteus 8.0或以上版本都自帶源代碼編輯器、編譯器,不再需要外部文本編輯器。研發人員只要在源代碼編輯器中,把自己所寫的源代碼添加進去就可以了,如圖1-31(b)所示。由于這部分內容不是本書重點,這里只是簡單介紹一下。
單擊圖1-30(b)的Finish按鈕,只完成帶有Schematic Capture(電路圖繪制)選項卡的新建工程,如圖1-32所示。

圖1-32 Schematic Capture選項卡
(2)設置圖紙尺寸
單擊System→Set Sheet Sizes,在彈出的Sheet Size Configuration對話框中選擇A4圖紙尺寸或自定義尺寸后單擊OK按鈕。
(3)設置網格
單擊View→Toggle Grid,顯示網格(再次單擊,隱藏網格)。單擊Toggle Grid→Snap ××th(或Snap ×.×in),可改變網格單位,默認為“Snap 0.1in”。
(4)添加元器件
單擊模式選擇工具欄中的Component Mode按鈕,單擊“器件選擇”按鈕
,在彈出的Pick Devices(選取元器件)對話框的Keywords欄中輸入元器件名稱“STM32F103R6”,與關鍵字匹配的STM32F103R6元器件顯示在元器件列表中,如圖1-33所示。

圖1-33 Pick Devices對話框
然后雙擊選中的元器件STM32F103R6,便將所選元器件STM32F103R6加入到對象選擇器窗口,單擊“確定”按鈕完成元器件選取。
用同樣的方法可以添加其他元器件。在本任務中,需要添加STM32F103R6、RES(電阻)、LED-YELLOW(黃色發光二極管)等元器件。
注意
? Proteus 8.6 Professional仿真軟件只支持STM32 Cortex-M3系列的6種型號芯片,本書選擇STM32F103R6芯片;
? 任何一款Cortex-M3芯片,其內核結構都是一樣的,不影響其他Cortex-M3芯片的學習。
(5)放置元器件
單擊對象選擇器窗口的元器件STM32F103R6,元器件名STM32F103R6變為藍底白字,預覽窗口顯示STM32F103R6元器件。
單擊方向工具欄的按鈕可以實現元器件的左旋、右旋、水平和垂直翻轉,以調整元器件的擺放方向。
將鼠標指針移到編輯區某一位置,單擊一次就可放置元器件STM32F103R6。
然后,參考上述放置STM32F103R6的步驟,依照圖1-24放置其他元器件。
(6)調整元器件位置
在要移動的元器件上單擊鼠標左鍵,元器件變為紅色(表明被選中),在被選中的元器件外單擊,即可撤銷選中。
按住鼠標左鍵拖動被選中的元器件,移到編輯區某一位置后松開,即完成元器件的移動;在被選中的元器件上單擊鼠標右鍵,利用彈出的快捷菜單可實現元器件的旋轉和翻轉,以及刪除元器件。
按照上述方法,依照圖1-24所示的元器件位置,可以對已放置的元器件進行位置調整。
(7)放置終端
單擊模式選擇工具欄中的Terminals Mode按鈕,再單擊對象選擇器窗口的電源終端POWER,該終端名背景變為藍色,預覽窗口也將顯示該終端;單擊方向工具欄中的“左旋轉”按鈕
,電源終端逆時針旋轉90°;將鼠標指針移到編輯區某一位置,單擊一次就可放置一個終端。以后,可以用同樣的方法放置接地終端GROUND。
(8)連線
當鼠標指針接近元器件的引腳端時,該處會自動出現一個小紅方塊,表明可以自動連接到該點。依照圖1-24所示,單擊要連線的元器件起點和終點,完成連線。
(9)屬性設置
在電阻R1上單擊鼠標右鍵,彈出快捷菜單,單擊Edit Propertise(編輯屬性)選項,彈出Edit Component(編輯元件)對話框,如圖1-34所示。

圖1-34 “編輯元件”對話框
將電阻值改為100,單擊OK按鈕完成電阻R1屬性的編輯設置。用同樣的方法設置其他元器件的屬性。
到此,STM32的LED控制電路就設計完成了。在以后的任務中,設計Proteus仿真電路時再涉及以上步驟,就不作詳細說明了。
1.2.2 開發第一個基于工程模板的Keil μVision4工程
前面的任務已經建立了基于固件庫的Keil μVision4工程模板,我們如何利用工程模板來開發第一個“點亮一個LED”工程呢?
1. 移植工程模板
(1)在建立“點亮一個LED”工程之前,先建立一個“任務2點亮一個LED”工程目錄,然后把STM32_Project工程模板直接復制到該目錄下。
(2)在“任務2點亮一個LED”工程目錄下,將工程模板目錄名STM32_Project修改為“點亮一個LED”。
(3)在USER子目錄下,把STM32_Project.uvproj工程名修改為leddl.uvproj。
2. 編寫第一個基于庫函數的“點亮一個LED”的控制代碼
在USER文件夾下面新建一個文件,并保存為leddl.c,在該文件中輸入如下代碼:
#include "stm32f10x.h" int main(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB時鐘 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //PB8引腳配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 配置PB8 為推挽輸出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIOB 速度為50 MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB8 GPIO_SetBits(GPIOB,GPIO_Pin_8); //PB8輸出高電平,LED熄滅 while(1) { GPIO_ResetBits(GPIOB,GPIO_Pin_8); //PB8輸出低電平,LED點亮 } }
代碼說明:
(1)“GPIO_InitTypeDef GPIO_InitStructure;”語句聲明一個結構體GPIO_InitStructure,結構體原型由GPIO_InitTypeDef確定。設置完GPIO_InitStructure里面的內容后,就可以執行“GPIO_Init(GPIOB,&GPIO_InitStructure);”語句,對PB端口進行初始化。
(2)GPIO_ResetBits()和GPIO_SetBits()是庫函數,可以對多個I/O口同時置1或置0。
(3)Keil μVision4支持C++風格的注釋,可以用“//”進行注釋,也可以用“/*……*/”進行注釋。“//”注釋只對本行有效,書寫比較方便。所以在只需要一行注釋的時候,往往采用這種格式。“//”注釋的內容可以單獨寫在一行上,也可以寫在一個語句之后。
3. 添加主文件leddl.c到工程與編譯
完成leddl.c主文件編寫后,打開leddl.uvproj工程;先把工程模板里原來的main.c主文件移出工程;然后把leddl.c主文件添加到工程里面;再按圖1-13所示的Components Environment and Books對話框,把Project Targets欄下的STM32_Project名修改為Leddl,即可完成“點亮一個LED”工程建立。
最后,單擊Rebuild按鈕對工程進行編譯,生成“leddl.hex”目標代碼文件。若編譯發生錯誤,要進行分析檢查,直到編譯正確,修改之后再次編譯,只要單擊工具欄的Build
按鈕即可,如圖1-35所示。

圖1-35 完成工程編譯
4. Keil μVision4和Proteus聯合調試
打開Proteus“LED點亮控制”電路,雙擊STM32F103R6芯片,在彈出的Edit Component對話框中單擊Program File后的打開按鈕,在彈出的Select File Name對話框中選中前面編譯生成的“leddl.hex”文件,然后單擊“打開”按鈕,完成“leddl.hex”加載HEX文件的選擇,如圖1-36所示。

圖1-36 加載目標代碼文件
單擊仿真工具欄的“運行”按鈕,STM32F103R6芯片全速運行程序。觀察LED是否點亮,若LED點亮,則說明LED點亮控制是好的,如圖1-37所示。

圖1-37 “LED點亮控制”Proteus仿真運行
1.2.3 位操作
位操作就是對基本類型變量在位級別上進行的操作。C語言支持如表1-1所示的6種位操作。
表1-1 C語言支持的位操作

下面我們圍繞表1-1中的6種位操作,著重介紹在STM32程序開發中使用位操作的相關關鍵技術。
1. 在不改變其他位的狀況下,對某幾個位賦值
針對這種情況,應該怎么做才能實現對某幾個位賦值呢?我們可以把“&”和“|”兩個位操作結合起來使用,步驟如下。
(1)先對需要設置的位用“&”操作符進行清零操作。
(2)再用“|”操作符賦值。
例如,在初始化時,若配置PD8引腳為推挽輸出、速度為50 MHz,需將GPIOD->CRH的0~3位設置為3(即二進制0011B),這時可先對寄存器的0~3位進行“&”清零操作。
GPIOD->CRH&=0Xfffffff0; //清掉原來的設置,同時不影響其他位設置
然后再與需要設置的值進行“|”運算:
GPIOD->CRH|=0X00000003; //設置0~3 位的值為3,不改變其他位的值
2. 使用移位操作,提高代碼的可讀性
移位操作在STM32程序開發中也非常重要。比如在初始化時,若需要使能GPIOD口的時鐘,就可使用移位操作來實現,使能PORTD時鐘的語句是:
RCC->APB2ENR|=1<<5;
使能GPIOD和GPIOE口時鐘的語句是:
RCC->APB2ENR|=3<<5;
這個左移位操作,就是將RCC->APB2ENR寄存器的第5位設置為1,使能PORTD時鐘。為什么要通過左移而不是直接設置一個固定的值來對寄存器進行操作呢?其實,這樣做是為了提高代碼的可讀性以及可重用性。讀者可以很直觀明了地看到,這行代碼是將第5位設置為1。如果寫成:
RCC->APB2ENR =0x00000020;
這樣的代碼既不好看也不好重用。類似這樣的代碼很多,如:
GPIOD->ODR|=1<<8; //PD8 輸出高電平,不改變其他位
這樣非常一目了然,8告訴讀者這是第8位,也就是PD8,1告訴讀者設置為1。
3. 取反位操作的應用
SR寄存器的每一位都代表一個狀態。在某個時刻,我們希望設置某一位為0,同時其他位都保留為1,簡單的做法是直接給寄存器設置一個值。
TIMx->SR=0xF7FF;
上述代碼設置第11位為0,但代碼可讀性很差。你可以這樣寫:
#define TIM_FLAG_Update ((uint16_t)0x0001) TIMx->SR &=~(TIM_FLAG_Update <<11);
從上面的代碼中,讀者可以從第一條語句看出,宏定義了TIM_FLAG_Update第0位是1,其他位是0;第二條語句讓TIM_FLAG_Update左移11位取反,第11位就為0,其他位都為1;最后通過按位與操作,使第11位為0,其他位保持不變。這樣,讀者就能很容易地看明白代碼,所以代碼的可讀性也就非常強。