1. 我使用GPIO的不同就是,GPIO 操作是直接动用了STM32内部的寄存器的.虽说库好用,但对于某些IO 操作,很多人都会嫌库的效率底下(包括我自己在内),总得对STM32 的寄存器看两眼的吧,不然还不敢叫STM32 达人!
2. 当然了,即使直接操作寄存器了,但一些方便的宏定义还是用库里面的好,反正宏定义本身并不影响效率.这里要说一下MDK 的一个重要技巧,就是把工程编译完以后,在变量或函数体上按下F12 键,就会自动跳转到这个变量或函数的定义处.要研究库代码,这个技巧必不可少,不然在大堆C文件里找一个定义是相当累人的.
大家看看ST 官方库里面对各个寄存器的定义,是使用结构体的,可谓相当有技巧,首先要定义几个基础地址:
//定义片内外设基础地址
#define PERIPH_BASE ((uint32_t)0x40000000)
//定义APB2地址,APB2地址在片内外设的0x10000偏移处.
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
//这个定义了GPIOA首地址:,在APB2 的0x800偏移处
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
//定义GPIOA的结构体
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
GPIO_TypeDef结构体的原型:
typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
__IO uint32_t IDR;
__IO uint32_t ODR;
__IO uint32_t BSRR;
__IO uint32_t BRR;
__IO uint32_t LCKR;
} GPIO_TypeDef;
那个__IO 的东西也是库定义的类型,还有__I 和__O 呢,主要方便表达这个寄存器是读写,还是只读,只写:
#define __I volatile const /*!< defines 'read only' permissions */
#define __O volatile /*!< defines 'write only' permissions */
#define __IO volatile /*!< defines 'read / write' permissions */
好了,说了这么多,其实每组GPIO 就7 个寄存器:
CRL,CRH,IDR,ODR,BSSR,BRR,LCKR.
库函数之所以用如此繁琐的定义,也是为了代码结构的一致和更系统的使用库调用,当然你看库会觉得这样很麻烦,但相对的是,我们使用起来就很简单.例如要操作GPIOA 的CRL寄存器,那么就是:
GPIOA->CRL=0x00;就可以了.
这些GPIO 寄存器STM32F10xxx_CH_Rev7V3 中文用户手册.pdf 中的P75 里有详细介绍.
另外,IO 还有一些重映射和事件寄存器等的,将在以后讨论.
3. 例程中IO 的输入输出控制都是直接操作的寄存器,例如:
#define LED1_ON GPIOA->BRR = GPIO_Pin_8
#define GET_LEFT() (!(GPIOD->IDR&GPIO_Pin_3))
这个GPIO_Pin_8,其实就是(1<<8), GPIO_Pin_3,就是(1<<3).
这些操作都要比调用库函数快不少的.对于实际项目中需要快速IO操作的,建议像这样直接操作寄存器.
另外在GPIO.C 文件里的GPIO_Configuration()函数中,配置按键的输入,也采用了直接操作寄存器的方式,这里只是简单地介绍一下使用寄存器配置GPIO 的方法,实际使用中,还是建议用库函数配置,毕竟,配置硬件这类操作一般不会十分频繁地调用,而是在系统上电的时候调用一次的,所以这些情况下都不会在乎执行效率.而且,直接操作寄存器,出低级错误的几率挺大~