使用Keil MDK運(yùn)行第一個(gè)STM32程序
1.1.1 使用Keil MDK運(yùn)行第一個(gè)STM32F10X程序
在上一小節(jié)中已經(jīng)詳細(xì)介紹了使用Keil MDK和標(biāo)準(zhǔn)外設(shè)庫創(chuàng)建一個(gè)工程的過程,下面將介紹基于這個(gè)工程來編寫一個(gè)小程序,通過這個(gè)程序我們可以初步了解:
STM32標(biāo)準(zhǔn)外設(shè)庫的簡單使用過程
STM32外設(shè)的使用方法和大致流程
程序的編譯、鏈接、下載步驟
利用Keil MDK的在線仿真功能進(jìn)行軟件仿真的簡要步驟
1. 程序的編寫(1)程序?qū)崿F(xiàn)的功能
為了方便各位讀者的入門和理解,這個(gè)小程序的功能非常簡單,作為本書功能實(shí)踐的第一個(gè)程序,其功能當(dāng)然也是最為經(jīng)典的“Hello World!”了,只不過不是簡單的屏幕輸出,而是利用硬件的串口進(jìn)行輸出,同時(shí)作為單片機(jī)類的第一個(gè)程序自然少不了LED閃爍的功能,這就是這個(gè)小程序的兩個(gè)主要的功能:
l 利用串口1輸出“Hello World!”字符。
l 控制兩個(gè)LED閃爍。
(2)程序的實(shí)現(xiàn)
在基于標(biāo)準(zhǔn)外設(shè)庫進(jìn)行程序開發(fā)時(shí)一定要充分利用標(biāo)準(zhǔn)外設(shè)庫下面的幫助文件stm32f10x_stdperiph_lib_um.chm以及庫中自帶的工程實(shí)例,同時(shí)結(jié)合STM32F10x系列的芯片手冊(cè)來完成程序的開發(fā),stm32f10x_stdperiph_lib_um.chm幫助文件如圖 5?25所示。此文件中已經(jīng)包含了標(biāo)準(zhǔn)外設(shè)庫的全部內(nèi)容,并根據(jù)根據(jù)內(nèi)容結(jié)構(gòu)進(jìn)行了重新的編排和整理,更加方便程序的閱讀和理解。
STM32F10x_StdPeriph_Lib_V3.5.0ProjectSTM32F10x_StdPeriph_Examples文件夾下包括了眾多外設(shè)的使用例程,這里的例程多是針對(duì)官方的開發(fā)板而編寫,然而這些例程卻非常全面的展示了相關(guān)外設(shè)的各種使用方法,對(duì)我們做基于標(biāo)準(zhǔn)外設(shè)庫的開發(fā)有著非常重要的意義。
圖 5?25 標(biāo)準(zhǔn)外設(shè)庫的幫助文檔
我們的第一個(gè)程序就通過這些參考來完成,首先來看串口部分。串口部分的詳細(xì)信息可以參考本書第8章,這兒只進(jìn)行簡單的說明和介紹簡便的開發(fā)方法,首先先找一個(gè)與我們使用的功能最近的一個(gè)例程,STM32F10x_StdPeriph_Lib_V3.5.0ProjectSTM32F10x_StdPeriph_ExamplesUSART文件夾下給出了多達(dá)12中的USART例程,這里選擇較為相近的Interrupt文件夾下得例程,打開文件夾下面的mian.c文件,通過簡單的瀏覽可以找到如下一段程序:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657/* USARTy and USARTz configuration ------------------------------------------------------*//* USARTy and USARTz configured as follow:- BaudRate = 9600 baud- Word Length = 8 Bits- One Stop Bit- No parity- Hardware flow control disabled (RTS and CTS signals)- Receive and transmit enabled*/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;/* Configure USARTy */USART_Init(USARTy, &USART_InitStructure);/* Configure USARTz */USART_Init(USARTz, &USART_InitStructure);/* Enable USARTy Receive and Transmit interrupts */USART_ITConfig(USARTy, USART_IT_RXNE, ENABLE);USART_ITConfig(USARTy, USART_IT_TXE, ENABLE);/* Enable USARTz Receive and Transmit interrupts */USART_ITConfig(USARTz, USART_IT_RXNE, ENABLE);USART_ITConfig(USARTz, USART_IT_TXE, ENABLE);/* Enable the USARTy */USART_Cmd(USARTy, ENABLE);/* Enable the USARTz */USART_Cmd(USARTz, ENABLE);上面的這段的程序配合注釋可以很容易理解,USART_InitTypeDef定義了一個(gè)包括USART主要參數(shù)的結(jié)構(gòu)體,因此首先對(duì)USART的相關(guān)參數(shù)進(jìn)行配置,使用標(biāo)準(zhǔn)外設(shè)庫進(jìn)行配置的優(yōu)勢(shì)就體現(xiàn)出來了,通過程序可以很容易讀出這個(gè)串口的配置:
l 波特率9600Kbps
l 數(shù)據(jù)長度8
l 停止位1
l 奇偶校驗(yàn):無
l 硬件流控制:無
l 工作模式:收、發(fā)
然后利用USART_Init函數(shù)進(jìn)行初始化,這段程序中設(shè)置了兩個(gè)串口,使用同樣的配置,然后配置相應(yīng)的中斷。最后通過USART_Cmd函數(shù)使能相應(yīng)的串口,前面有過介紹,這些例程里的程序是針對(duì)官方的開發(fā)套件的,因此程序中并沒有指名具體的端口,而是使用了宏定義USARTy、USARTz。通過這段程序就可以很方便的更改相關(guān)的參數(shù)得到我們需要的配置程序。
這兒只是完成了USART的配置,下面來看一下對(duì)應(yīng)的I/O設(shè)置,仍然在這個(gè)文件中可以找到GPIO_Configuration(void)這個(gè)函數(shù),程序如下:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455voidGPIO_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure;#ifdef USE_STM3210C_EVAL/* Enable the USART3 Pins Software Remapping */GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, ENABLE);/* Enable the USART2 Pins Software Remapping */GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);#elif defined USE_STM3210B_EVAL || defined USE_STM32100B_EVAL/* Enable the USART2 Pins Software Remapping */GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);#endif/* Configure USARTy Rx as input floating */GPIO_InitStructure.GPIO_Pin = USARTy_RxPin;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(USARTy_GPIO, &GPIO_InitStructure);/* Configure USARTz Rx as input floating */GPIO_InitStructure.GPIO_Pin = USARTz_RxPin;GPIO_Init(USARTz_GPIO, &GPIO_InitStructure);/* Configure USARTy Tx as alternate function push-pull */GPIO_InitStructure.GPIO_Pin = USARTy_TxPin;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(USARTy_GPIO, &GPIO_InitStructure);/* Configure USARTz Tx as alternate function push-pull */GPIO_InitStructure.GPIO_Pin = USARTz_TxPin;GPIO_Init(USARTz_GPIO, &GPIO_InitStructure);}
這段函數(shù)完成了相關(guān)的I/O配置,首先通過宏定義判斷是官方的哪一款開發(fā)套件,然后進(jìn)行相應(yīng)的端口映射(端口映射請(qǐng)參加官方的數(shù)據(jù)手冊(cè)),然后進(jìn)行相應(yīng)的端口配置,同串口配置一樣,這段程序中德端口用的也是宏定義USARTy_RxPin替代的,改為我們使用的實(shí)際I/O,端口時(shí)鐘設(shè)置為50MHz,串口所使用到的端口設(shè)置為復(fù)用(GPIO_Mode_AF_PP)完成端口初始化。
另外仍然通過觀察這個(gè)例程可以很容易發(fā)現(xiàn),在使用一個(gè)外設(shè)時(shí)還需要首先打開對(duì)應(yīng)的外設(shè)時(shí)鐘,這部分程序如下:
123456789101112131415161718192021222324252627voidRCC_Configuration(void){/* Enable GPIO clock */RCC_APB2PeriphClockCmd(USARTy_GPIO_CLK | USARTz_GPIO_CLK | RCC_APB2Periph_AFIO, ENABLE);#ifndef USE_STM3210C_EVAL/* Enable USARTy Clock */RCC_APB2PeriphClockCmd(USARTy_CLK, ENABLE);#else/* Enable USARTy Clock */RCC_APB1PeriphClockCmd(USARTy_CLK, ENABLE);#endif/* Enable USARTz Clock */RCC_APB1PeriphClockCmd(USARTz_CLK, ENABLE);}
這段程序中需要注意兩點(diǎn),首先,GPIO、USART等都是連在APB1、APB2兩條總線上的,各外設(shè)具體的總線連接情況參見圖 5?2,因此首先應(yīng)該確定外設(shè)對(duì)應(yīng)的總線,例如USART1是APB2總線,而USART2是APB1總線。其次使能相應(yīng)的時(shí)鐘時(shí)不光要使能對(duì)應(yīng)的I/O端口,還要使能總線的復(fù)用端口,這點(diǎn)也容易忽略。
最后根據(jù)庫中的例程,借鑒庫中例程的編寫風(fēng)格,就可以得出我們需要的程序,程序在工程的mian.c中編寫,函數(shù)如下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133#include "stm32f10x.h"voidUSART_Configuration(void);voidGPIO_Configuration(void);voidDelay(__IO uint32_t nCount);voidUSART1_Puts(char* str);intmain(void){USART_Configuration();GPIO_Configuration();USART1_Puts("Hello Wrold!n");while(1){GPIOF->BSRR = 0x000000C0;Delay(0xAFFFF);GPIOF->BRR = 0x000000C0;Delay(0xAFFFF);USART1_Puts("Hello Wrold!n");}}voidUSART_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;//使能串口、串口所用的I/O口以及端口復(fù)用時(shí)鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO, ENABLE);/* A9 USART1_Tx */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//推挽輸出-TXGPIO_Init(GPIOA,&GPIO_InitStructure);/* A10 USART1_Rx */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入-RXGPIO_Init(GPIOA, &GPIO_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);/* Enable the USARTx */USART_Cmd(USART1