應部分網友要求,最新加入固件庫以及開發環境使用入門視訊教程,同時提供例程模闆,個人錄制,歡迎指正。下載下傳位址:
<a href="http://115.com/file/e78l0xlo#%20emouse-STM32%E7%B3%BB%E5%88%97%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B.rar">http://115.com/file/e78l0xlo# emouse-STM32系列視訊教程.rar</a>
歡迎大家針對本部落格文章提出寶貴意見。
關于使用固件庫建立工程請參考
關于固件庫的學習請參考
在上一小節中已經詳細介紹了使用Keil MDK和标準外設庫建立一個工程的過程,下面将介紹基于這個工程來編寫一個小程式,通過這個程式我們可以初步了解:
STM32标準外設庫的簡單使用過程
STM32外設的使用方法和大緻流程
程式的編譯、連結、下載下傳步驟
利用Keil MDK的線上仿真功能進行軟體仿真的簡要步驟
1. 程式的編寫
(1)程式實作的功能
為了友善各位讀者的入門和了解,這個小程式的功能非常簡單,作為本書功能實踐的第一個程式,其功能當然也是最為經典的“Hello World!”了,隻不過不是簡單的螢幕輸出,而是利用硬體的序列槽進行輸出,同時作為單片機類的第一個程式自然少不了LED閃爍的功能,這就是這個小程式的兩個主要的功能:
l 利用序列槽1輸出“Hello World!”字元。
l 控制兩個LED閃爍。
(2)程式的實作
在基于标準外設庫進行程式開發時一定要充分利用标準外設庫下面的幫助檔案stm32f10x_stdperiph_lib_um.chm以及庫中自帶的工程執行個體,同時結合STM32F10x系列的晶片手冊來完成程式的開發,stm32f10x_stdperiph_lib_um.chm幫助檔案如圖 5‑25所示。此檔案中已經包含了标準外設庫的全部内容,并根據根據内容結構進行了重新的編排和整理,更加友善程式的閱讀和了解。
STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples檔案夾下包括了衆多外設的使用例程,這裡的例程多是針對官方的開發闆而編寫,然而這些例程卻非常全面的展示了相關外設的各種使用方法,對我們做基于标準外設庫的開發有着非常重要的意義。

我們的第一個程式就通過這些參考來完成,首先來看序列槽部分。序列槽部分的詳細資訊可以參考本書第8章,這兒隻進行簡單的說明和介紹簡便的開發方法,首先先找一個與我們使用的功能最近的一個例程,STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\USART檔案夾下給出了多達12中的USART例程,這裡選擇較為相近的Interrupt檔案夾下得例程,打開檔案夾下面的mian.c檔案,通過簡單的浏覽可以找到如下一段程式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<code>/* USARTy and USARTz configuration ------------------------------------------------------*/</code>
<code>/* USARTy and USARTz configured as follow:</code>
<code>- BaudRate = 9600 baud</code>
<code>- Word Length = 8 Bits</code>
<code>- One Stop Bit</code>
<code>- No parity</code>
<code>- Hardware flow control disabled (RTS and CTS signals)</code>
<code>- Receive and transmit enabled</code>
<code>*/</code>
<code>USART_InitStructure.USART_BaudRate = 9600;</code>
<code>USART_InitStructure.USART_WordLength = USART_WordLength_8b;</code>
<code>USART_InitStructure.USART_StopBits = USART_StopBits_1;</code>
<code>USART_InitStructure.USART_Parity = USART_Parity_No;</code>
<code>USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;</code>
<code>USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;</code>
<code>/* Configure USARTy */</code>
<code>USART_Init(USARTy, &USART_InitStructure);</code>
<code>/* Configure USARTz */</code>
<code>USART_Init(USARTz, &USART_InitStructure);</code>
<code>/* Enable USARTy Receive and Transmit interrupts */</code>
<code>USART_ITConfig(USARTy, USART_IT_RXNE, ENABLE);</code>
<code>USART_ITConfig(USARTy, USART_IT_TXE, ENABLE);</code>
<code>/* Enable USARTz Receive and Transmit interrupts */</code>
<code>USART_ITConfig(USARTz, USART_IT_RXNE, ENABLE);</code>
<code>USART_ITConfig(USARTz, USART_IT_TXE, ENABLE);</code>
<code>/* Enable the USARTy */</code>
<code>USART_Cmd(USARTy, ENABLE);</code>
<code>/* Enable the USARTz */</code>
<code>USART_Cmd(USARTz, ENABLE);</code>
上面的這段的程式配合注釋可以很容易了解,USART_InitTypeDef定義了一個包括USART主要參數的結構體,是以首先對USART的相關參數進行配置,使用标準外設庫進行配置的優勢就展現出來了,通過程式可以很容易讀出這個序列槽的配置:
l 波特率9600Kbps
l 資料長度8
l 停止位1
l 奇偶校驗:無
l 硬體流控制:無
l 工作模式:收、發
然後利用USART_Init函數進行初始化,這段程式中設定了兩個序列槽,使用同樣的配置,然後配置相應的中斷。最後通過USART_Cmd函數使能相應的序列槽,前面有過介紹,這些例程裡的程式是針對官方的開發套件的,是以程式中并沒有指名具體的端口,而是使用了宏定義USARTy、USARTz。通過這段程式就可以很友善的更改相關的參數得到我們需要的配置程式。
這兒隻是完成了USART的配置,下面來看一下對應的I/O設定,仍然在這個檔案中可以找到GPIO_Configuration(void)這個函數,程式如下:
<code>void</code> <code>GPIO_Configuration(</code><code>void</code><code>)</code>
<code>{</code>
<code>GPIO_InitTypeDef GPIO_InitStructure;</code>
<code>#ifdef USE_STM3210C_EVAL</code>
<code>/* Enable the USART3 Pins Software Remapping */</code>
<code>GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, ENABLE);</code>
<code>/* Enable the USART2 Pins Software Remapping */</code>
<code>GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);</code>
<code>#elif defined USE_STM3210B_EVAL || defined USE_STM32100B_EVAL</code>
<code>#endif</code>
<code>/* Configure USARTy Rx as input floating */</code>
<code>GPIO_InitStructure.GPIO_Pin = USARTy_RxPin;</code>
<code>GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;</code>
<code>GPIO_Init(USARTy_GPIO, &GPIO_InitStructure);</code>
<code>/* Configure USARTz Rx as input floating */</code>
<code>GPIO_InitStructure.GPIO_Pin = USARTz_RxPin;</code>
<code>GPIO_Init(USARTz_GPIO, &GPIO_InitStructure);</code>
<code>/* Configure USARTy Tx as alternate function push-pull */</code>
<code>GPIO_InitStructure.GPIO_Pin = USARTy_TxPin;</code>
<code>GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;</code>
<code>GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;</code>
<code>/* Configure USARTz Tx as alternate function push-pull */</code>
<code>GPIO_InitStructure.GPIO_Pin = USARTz_TxPin;</code>
<code>}</code>
這段函數完成了相關的I/O配置,首先通過宏定義判斷是官方的哪一款開發套件,然後進行相應的端口映射(端口映射請參加官方的資料手冊),然後進行相應的端口配置,同序列槽配置一樣,這段程式中德端口用的也是宏定義USARTy_RxPin替代的,改為我們使用的實際I/O,端口時鐘設定為50MHz,序列槽所使用到的端口設定為複用(GPIO_Mode_AF_PP)完成端口初始化。
另外仍然通過觀察這個例程可以很容易發現,在使用一個外設時還需要首先打開對應的外設時鐘,這部分程式如下:
<code>void</code> <code>RCC_Configuration(</code><code>void</code><code>)</code>
<code>/* Enable GPIO clock */</code>
<code>RCC_APB2PeriphClockCmd(USARTy_GPIO_CLK | USARTz_GPIO_CLK | RCC_APB2Periph_AFIO, ENABLE);</code>
<code>#ifndef USE_STM3210C_EVAL</code>
<code>/* Enable USARTy Clock */</code>
<code>RCC_APB2PeriphClockCmd(USARTy_CLK, ENABLE);</code>
<code>#else</code>
<code>RCC_APB1PeriphClockCmd(USARTy_CLK, ENABLE);</code>
<code>/* Enable USARTz Clock */</code>
<code>RCC_APB1PeriphClockCmd(USARTz_CLK, ENABLE);</code>
這段程式中需要注意兩點,首先,GPIO、USART等都是連在APB1、APB2兩條總線上的,各外設具體的總線連接配接情況參見圖 5‑2,是以首先應該确定外設對應的總線,例如USART1是APB2總線,而USART2是APB1總線。其次使能相應的時鐘時不光要使能對應的I/O端口,還要使能總線的複用端口,這點也容易忽略。
最後根據庫中的例程,借鑒庫中例程的編寫風格,就可以得出我們需要的程式,程式在工程的mian.c中編寫,函數如下:
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
<code>#include "stm32f10x.h"</code>
<code>void</code> <code>USART_Configuration(</code><code>void</code><code>);</code>
<code>void</code> <code>GPIO_Configuration(</code><code>void</code><code>);</code>
<code>void</code> <code>Delay(__IO uint32_t nCount);</code>
<code>void</code> <code>USART1_Puts(</code><code>char</code> <code>* str);</code>
<code>int</code> <code>main(</code><code>void</code><code>)</code>
<code>USART_Configuration();</code>
<code>GPIO_Configuration();</code>
<code>USART1_Puts(</code><code>"Hello Wrold!\n"</code><code>);</code>
<code>while</code> <code>(1)</code>
<code>GPIOF->BSRR = 0x000000C0;</code>
<code>Delay(0xAFFFF);</code>
<code>GPIOF->BRR = 0x000000C0;</code>
<code>void</code> <code>USART_Configuration(</code><code>void</code><code>)</code>
<code>USART_InitTypeDef USART_InitStructure;</code>
<code>//使能序列槽、序列槽所用的I/O口以及端口複用時鐘</code>
<code>RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO, ENABLE);</code>
<code>/* A9 USART1_Tx */</code>
<code>GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;</code>
<code>GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; </code><code>//推挽輸出-TX</code>
<code>GPIO_Init(GPIOA,&GPIO_InitStructure);</code>
<code>/* A10 USART1_Rx */</code>
<code>GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;</code>
<code>GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;</code><code>//浮空輸入-RX</code>
<code>GPIO_Init(GPIOA, &GPIO_InitStructure);</code>
<code>USART_Init(USART1, &USART_InitStructure);</code>
<code>/* Enable the USARTx */</code>
<code>USART_Cmd(USART1, ENABLE);</code>
<code>RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);</code>
<code>/* 設定LED對應的引腳 */</code>
<code>GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;</code>
<code>GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;</code>
<code>GPIO_Init(GPIOF, &GPIO_InitStructure);</code>
<code>void</code> <code>Delay(__IO uint32_t nCount)</code>
<code>for</code><code>(; nCount != 0; nCount--);</code>
<code>void</code> <code>USART1_Puts(</code><code>char</code> <code>* str)</code>
<code>while</code><code>(*str)</code>
<code>USART_SendData(USART1, *str++);</code>
<code>/* Loop until the end of transmission */</code>
<code>while</code><code>(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);</code>
至此完成了主函數的編寫。接下來還需要到stm32f10x_conf.h檔案中選擇相應的頭檔案,這兒去掉需要使用的頭檔案之前的注釋,去掉注釋的頭檔案如下:
l #include "stm32f10x_gpio.h"
l #include "stm32f10x_usart.h"
這樣,我們的程式編寫就完成了,下面可以進行我們的編譯與調試了。
2. 程式的編譯
第一次生成工程成功以後,如果修改了相應的檔案再次點選生成工程時隻會對有改動的檔案進行重新編譯、生成,而重新生成全部工程會重新生成工程中的所有檔案。
3. 程式的調試
在實際開發時,可以首先利用軟體進行仿真,利用軟體進行仿真檢視具體的寄存器配置,外設的工作情況等,同時通過斷點的配合可以查找出程式中絕大多數的錯誤。軟體仿真完成後可以下載下傳到硬體平台去運作,如果程式仍然沒有達到需要的效果,在硬體檢查完成後可以使用線上仿真的方式,在硬體平台上直接運作程式,進一步查找問題。
首先,先看一下這個小程式的軟體仿真,首先在工程設定Debug選項中選擇使用軟體模拟,如圖 5‑28所示。
在程式行号的左側直接輕按兩下可以非常友善的添加或者取消斷點,如圖 5‑30所示。
在菜單Peripherals中可以打開需要檢視的外設,這裡點選Peripherals-USART1彈出USART1的相關觀察視窗,點選運作後,視窗如圖 5‑31所示,就會顯示運作的程式對USART1所完成的相關配置。從中可以清晰的看出,程式對USART1的相關寄存器配置,從地面Settings一欄中則可以直覺的看出USART1目前的工作狀态,從這兒就可以檢查我們的相關參數設定正确與否,對應時鐘有無開啟等。需要說明的是這裡寄存器在進行仿真的時候是可以進行改寫的,也就是說允許我們在程式運作的時候直接進行相關的操作來觀察運作結果。但是此時程式本身也是可以對寄存器進行操作的,是以直接更改相應的寄存器觀察時還要注意你的操作是否和程式沖突。例如在本程式的運作過程中如果将寄存器中發送使能TE的勾給去掉,則序列槽就不會在輸出資料。
接下來繼續檢視I/O的配置,本程式中使用的是F端口,則點選菜單Peripherals-General-Purpose I/O,選擇GPIOF,出現GPIOF的配置視窗,程式運作後可以通過視窗檢視GPIOF的相關配置,如圖 5‑32所示。在這個視窗中可以檢視引腳的配置情況,當程式運作時就能看到對應引腳的勾在閃爍。
至此,已經利用Keil MDK的軟體仿真功能完成了程式的調試,看到了設計的效果。通過這個例子也能夠讓我們深刻的體會到Keil MDK線上調試功能的強大之處。接下來我們将編寫好的程式下載下傳到開發闆中運作,看看運作效果。
4. 程式的下載下傳
編寫好的程式工程生成完成後下載下傳到硬體平台的方法有很多種,一是直接利用Flash燒寫工具燒寫相應的hex檔案,在工程配置時需要設定才能生成hex檔案,具體設定參加圖 5‑16,生成hex檔案之後就可以利用燒寫工具燒寫到硬體平台,常用的仿真器都帶有相應的軟體工具,如筆者使用的JLink-V8,可以使用自帶的J-Flash工具,使用J-Flash工具如圖 5‑35所示,在工程管理中選擇所使用的硬體平台,點選Target-Connect後就可以連接配接上硬體平台,在圖中左側顯示了仿真器以及對應的硬體平台資訊。然後選擇所生産的hex檔案,就可以講編譯的程式下載下傳到硬體平台中。
程式下載下傳到硬體平台後通過實際的序列槽來檢視程式運作情況了,将硬體平台的序列槽1連接配接至PC,筆記本等電腦上沒有實體序列槽的可以使用USB轉序列槽裝置,注意在裝置管理器中檢視實際所配置設定的序列槽号,本機配置設定的序列槽号為COM4,如圖 5‑36所示,序列槽号也可以在進階選項中進行更改。
這裡使用本章所介紹的TKStudio中的序列槽調試助手工具來進行檢視,設定序列槽的相應參數與程式一緻,序列槽設定于運作結果如圖 5‑37所示,從圖中可以看出序列槽接資料正确,開發闆上的兩個LED也在不停閃爍。
至此,我們完成了一個簡單的程式開發過程。本小節通過實作序列槽輸出與LED閃爍的功能系統的介紹了怎樣基于标準外設庫進行程式的開發與調試,這兒隻是列舉了一個非常簡單的小例子,更多的聯系讀者可以參考标準外設庫中的例程自行完成。
本文轉自emouse部落格園部落格,原文連結:http://www.cnblogs.com/emouse/archive/2012/03/09/2388253.html,如需轉載請自行聯系原作者