GPIO口的使用:
1.GPIO和AFIO全系列支持
GPIO寄存器
(1)两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH);
(2)两个32位数据寄存器(GPIOx_IDR,GPIOx_ODR);
(3)一个32位置为/复位寄存器(GPIOx_BSRR);
(4)一个16位复位寄存器(GPIOx_BRR);
(5)一个32位锁存器(GPIOx_LCKR);
输入配置
当I/O端口配置为输入时:
●输出缓冲器被禁止
●施密特触发输入被激活
●根据输入配置(上拉,下拉或浮动)的不同,弱上拉和下拉电阻被连接
●出现在I/O脚上的数据在每个APB2时钟被采样到输入数据寄存器
●对输入数据寄存器的读访问可得到I/O状态
输出配置
当I/O端口被配置为输出时:
●输出缓冲器被激活
─开漏模式:输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将端口置于高阻状态(PMOS从不被激活)。
─推挽模式:输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将激活P-MOS。
●施密特触发输入被激活
●弱上拉和下拉电阻被禁止
●出现在I/O脚上的数据在每个APB2时钟被采样到输入数据寄存器
●在开漏模式时,对输入数据寄存器的读访问可得到I/O状态
●在推挽式模式时,对输出数据寄存器的读访问得到最后一次写的值。
STM32中的配置寄存器在固件函数库中早已生成,因此无需再对寄存器的每个设定写定义,而是直接调用关键字。这样我们可以不再关心寄存器的具体配置(因为那已经在固件配置好了);因此直观的从配置函数中去看,更能有效的提高。
GPIO相关的库函数如下,位于在“stm32f10x_gpio.h”
GPIO相关函数如下:
voidGPIO_DeInit(GPIO_TypeDef*GPIOx);
voidGPIO_AFIODeInit(void);
voidGPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct);
voidGPIO_StructInit(GPIO_InitTypeDef*GPIO_InitStruct);
uint8_tGPIO_ReadInputDataBit(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);
uint16_tGPIO_ReadInputData(GPIO_TypeDef*GPIOx);
uint8_tGPIO_ReadOutputDataBit(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);
uint16_tGPIO_ReadOutputData(GPIO_TypeDef*GPIOx);
voidGPIO_SetBits(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);
voidGPIO_ResetBits(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);
voidGPIO_WriteBit(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin,BitActionBitVal);
voidGPIO_Write(GPIO_TypeDef*GPIOx,uint16_tPortVal);
voidGPIO_PinLockConfig(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);
voidGPIO_EventOutputConfig(uint8_tGPIO_PortSource,uint8_tGPIO_PinSource);
voidGPIO_EventOutputCmd(FunctionalStateNewState);
voidGPIO_PinRemapConfig(uint32_tGPIO_Remap,FunctionalStateNewState);
voidGPIO_EXTILineConfig(uint8_tGPIO_PortSource,uint8_tGPIO_PinSource);
voidGPIO_ETH_MediaInterfaceConfig(uint32_tGPIO_ETH_MediaInterface);
以下将逐个说明函数功能及注释说明:
·voidGPIO_DeInit(GPIO_TypeDef*GPIOx);
该函数原型在"stm32f10x_gpio.C"当中,类似C++的注释说明如下:
*@briefDeinitializestheGPIOxperipheralregisterstotheirdefaultresetvalues.
*@paramGPIOx:wherexcanbe(A..G)toselecttheGPIOperipheral.
*@retvalNone
其中是为不同组的IO口进行寄存器值的初始化。
初始化语句如下:
“RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA,DISABLE);”
再追根溯源到这个函数,位于“stm32f10x_rcc.C”当中
"voidRCC_APB2PeriphResetCmd(uint32_tRCC_APB2Periph,FunctionalStateNewState)"
{
assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if(NewState!=DISABLE)
{
RCC->APB2RSTR|=RCC_APB2Periph;
}
else
{
RCC->APB2RSTR&=~RCC_APB2Periph;
}
}
函数注释如下:
一目了然,即配置IO口时钟状态为使能或者失效。
当然在其中此函数作为一个初学实例还是值得深究的:
assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
assert_param(IS_FUNCTIONAL_STATE(NewState));
此处两句即类似于C++中的断言函数,作为函数运行的先决条件。这里将断言函数直接说明,在后续的实例中,仍旧会有使用到的地方。
#defineassert_param(expr)((expr)?(void)0:assert_failed((uint8_t*)__FILE__,__LINE__))
voidassert_failed(uint8_t*file,uint32_tline);
#else
#defineassert_param(expr)((void)0)
#endif
#endif
若满足断言值为"1"的条件,否则判定失败输出文件名和所在行。不为"0"返回0.
再返回“assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));”此句中。“IS_RCC_APB2_PERIPH”如下定义:
·#defineIS_RCC_APB2_PERIPH(PERIPH)((((PERIPH)&0xFFC00002)==0x00)&&((PERIPH)!=0x00))
此处使用到的是AP2进入该函数还可以看到AP2、AP1、AP三个高速时钟族的各项定义。姑且在这里认为是判定开启对应时钟前的时钟功能验证。
·#defineIS_FUNCTIONAL_STATE(STATE)(((STATE)==DISABLE)||((STATE)==ENABLE))
只为考虑还是的形参是否是“DISABLE”or“ENABLE”两个状态。
“if(NewState!=DISABLE)
{
RCC->APB2RSTR|=RCC_APB2Periph;
}
else
{
RCC->APB2RSTR&=~RCC_APB2Periph;
}
”
而APB2RSTR则即将牵扯到RCC的设置问题,我们下一节再讲。
·voidGPIO_AFIODeInit(void);功能复用,重新映射事件控制。
同样调用“RCC_APB2PeriphResetCmd”。也是串口初始化判断
·voidGPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct);
寄存器手册中记为:根据GPIO_InitStruct中指定参数初始化外设GPIOx寄存器
不想在此处在赘述此函数,主要通过写寄存器的值来配置GPI0x,GPIO_pin,GPIO_Mode,GPIO_speed,以及写GPIOCRL/CRH寄存器。
·voidGPIO_StructInit(GPIO_InitTypeDef*GPIO_InitStruct);被上一结构体调用
GPIO_Speed描述
GPIO_Speed_10MHz最高输出速率10MHz
GPIO_Speed_2MHz最高输出速率2MHz
GPIO_Speed_50MHz最高输出速率50MHz
GPIO_Mode_AIN模拟输入
GPIO_Mode_IN_FLOATING浮空输入
GPIO_Mode_IPD下拉输入
GPIO_Mode_IPU上拉输入
GPIO_Mode_Out_OD开漏输出
GPIO_Mode_Out_PP推挽输出
GPIO_Mode_AF_OD复用开漏输出
GPIO_Mode_AF_PP复用推挽输出
·
uint8_tGPIO_ReadInputDataBit(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);
uint16_tGPIO_ReadInputData(GPIO_TypeDef*GPIOx);,
uint8_tGPIO_ReadOutputDataBit(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);
uint16_tGPIO_ReadOutputData(GPIO_TypeDef*GPIOx);
读取指定管脚输入/输出,读取管脚输入/输出数据值。一个读取的是管脚的状态,而一个读取的输入or输出数据寄存器的值。这一点要分清
·
voidGPIO_SetBits(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);
voidGPIO_ResetBits(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);
voidGPIO_WriteBit(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin,BitActionBitVal);
"bitvalmustbeBit_RESETorBit_SET“
voidGPIO_Write(GPIO_TypeDef*GPIOx,uint16_tPortVal);
“Portval为将写入数据寄存器的值”
设定/清除指定的数据位
·voidGPIO_PinLockConfig(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);
锁存管脚寄存器,锁存指定GPIO组指定引脚。
·voidGPIO_EventOutputConfig(uint8_tGPIO_PortSource,uint8_tGPIO_PinSource);
voidGPIO_EventOutputCmd(FunctionalStateNewState);
配置GPIO为事件输出,其后我们来解决这个疑问。
·voidGPIO_PinRemapConfig(uint32_tGPIO_Remap,FunctionalStateNewState);
此函数决定了IO口的重新映射,实际是IO复用功能的实现,GPIO_Remap选择输入引脚,NewState的配置值如下:GPIO_Remap_SPI1SPI1复用功能映射
GPIO_Remap_I2C1I2C1复用功能映射
GPIO_Remap_USART1USART1复用功能映射
GPIO_PartialRemap_USART3USART2复用功能映射
GPIO_FullRemap_USART3USART3复用功能完全映射
GPIO_PartialRemap_TIM1USART3复用功能部分映射
GPIO_FullRemap_TIM1TIM1复用功能完全映射
GPIO_PartialRemap1_TIM2TIM2复用功能部分映射1
GPIO_PartialRemap2_TIM2TIM2复用功能部分映射2
GPIO_FullRemap_TIM2TIM2复用功能完全映射
GPIO_PartialRemap_TIM3TIM3复用功能部分映射
GPIO_FullRemap_TIM3TIM3复用功能完全映射
GPIO_Remap_TIM4TIM4复用功能映射
GPIO_Remap1_CANCAN复用功能映射1
GPIO_Remap2_CANCAN复用功能映射2
GPIO_Remap_PD01PD01复用功能映射
GPIO_Remap_SWJ_NoJTRST除JTRST外SWJ完全使能(JTAG+SW-DP)
GPIO_Remap_SWJ_JTAGDisableJTAG-DP失能+SW-DP使能
GPIO_Remap_SWJ_DisableSWJ完全失能(JTAG+SW-DP)
每个功能在后面小节的应用中体现。
·voidGPIO_EXTILineConfig(u8GPIO_PortSource,u8GPIO_PinSource)
GPIO配置为外部中断,两个值分别为端口值和引脚。
·voidGPIO_ETH_MediaInterfaceConfig(uint32_tGPIO_ETH_MediaInterface)
最后一个配置