採用結構體方式
在上節課我們只採用了GPIOC,但是有的型號引腳比較多,可以分成A、B、C、D…G組。那麼根據下圖的寫法我們要重複寫好幾次。大家有發現除了A、B、C、D…G不一樣之外,別的基本一樣。也就是說GPIOA有7個寄存器控制,GPIOB也是有7個寄存器控制,由此聯想到採用結構體。舉個例子,一個小區裏有A幢樓、B幢樓、、、但是每幢樓的結構層數都一樣。
定義:
typedef unsigned int uint32_t;
typedef struct
{
uint32_t CRL;
uint32_t CRH;
uint32_t IDR;
uint32_t ODR;
uint32_t BSRR;
uint32_t BRR;
uint32_t LCKR;
}GPIO_TypeDef;
也就是說把32位的寄存器CRL、CRH、、LCKR組成一個整體,名字叫做 GPIO_TypeDef,在內存中是連續排列的,假設CRL的地址爲0x00,那麼CRH的地址爲0x04,依次排列下去。
再定義:
#define GPIOC ((GPIO_TypeDef*)GPIOC_BASE)
看下(GPIO_TypeDef*)GPIOC_BASE 這條語句,意思是將GPIOC_BASE轉換成GPIO_TypeDef類型的地址。上節課中可知GPIOC_BASE的值爲0x4001 1000。那麼以該地址爲基礎(0x4001 0C00),CRL的地址爲0x4001 0C00,CRH地址爲0x4001 1004…依次下去。完全跟我們以前的方式符合!
下圖中的“GPIO_CRH”的地址即爲0x40011004,那麼怎麼用結構體表示呢?
再回到這條語句
#define GPIOC ((GPIO_TypeDef*)GPIOC_BASE)
可以用GPIOC->CRH的方式來表示GPIOC_CRH。由於程序小,看不出來優勢在哪,以後慢慢體會。那麼在main函數中都可以用這種方式來代替。時鐘也類似!
寫法跟配置GPIO一樣,可以寫相應的結構體!
typedef struct
{
uint32_t CR;
uint32_t CFGR;
uint32_t CIR;
uint32_t APB2RSTR;
uint32_t APB1RSTR;
uint32_t AHBENR;
uint32_t APB2ENR;
uint32_t APB1ENR;
uint32_t BDCR;
uint32_t CSR;
}RCC_TypeDef;
綜上所述,在頭文件中進行相應的程序修改,如下:
#define PERIPH_BASE ((unsigned int)0x40000000)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
/* AHB總線基地址 */
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
/*GPIOC外設基地址*/
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
/*RCC外設基地址*/
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
typedef unsigned int uint32_t;
typedef struct
{
uint32_t CRL;
uint32_t CRH;
uint32_t IDR;
uint32_t ODR;
uint32_t BSRR;
uint32_t BRR;
uint32_t LCKR;
}GPIO_TypeDef;
typedef struct
{
uint32_t CR;
uint32_t CFGR;
uint32_t CIR;
uint32_t APB2RSTR;
uint32_t APB1RSTR;
uint32_t AHBENR;
uint32_t APB2ENR;
uint32_t APB1ENR;
uint32_t BDCR;
uint32_t CSR;
}RCC_TypeDef;
#define GPIOC ((GPIO_TypeDef*)GPIOC_BASE)
#define RCC ((RCC_TypeDef*)RCC_BASE)
在main函數中,進行如下修改:
#include "stm32f10x.h"
int main(void)
{
RCC->APB2ENR |= 1<<4;
GPIOC->CRH &=~(0x0F<<(4*5));
GPIOC->CRH |=(1<<(4*5));
GPIOC->ODR &=~(1<<13);
while(1);
}
void SystemInit()
{
}
經測試完全沒有問題!