记录某大二菜入门电子之路~
包括以下几个部分
- 功能叙述
- 深度理解IO口的输入输出机制
- 寄存器详解
- 库函数分析
- 库函数代码示例
功能叙述
每个GPIO有8种模式:
─ 输入浮空
─ 输入上拉
─ 输入下拉
─ 模拟输入
─ 开漏输出:不能输出高电平
─ 推挽式输出
─ 推挽式复用功能
─ 开漏复用功能
这里有一点要提的是:
复用输入和输入共线,所以复用输入没有独立的GPIO模式,只要在Input模式下使能复用外设的重映射即可,在复用接收数据的时候IDR依然在接受数据。
而复用输出和输出是有路线选择器(structure图上可见)的,故复用输出和输出是两个独立的模式。需要切换线路来选取其中一个。
我们可以大致了解到,除用于模拟量输入以外,施密特在所有模式下均激活,故可知Input模式应该是始终激活的,其他模式其实只是在Input模式依然存在的情况下开启其他模式。所以IDR应该是始终可以读取的。
深度理解IO口的输入输出机制
首先是IO输入输出双用问题,一开始是做1—Wire的一个时序编程的时候突发奇想到GPIO的双向输出输入问题。因为源程序中IO口在频繁的用Init函数更改模式来起到输出和检测输入的作用。
首先我认为,IO口只要时钟使能变进入工作,Init设置为推挽模式输出高电平后并不影响输入,当IO被拉低时依然可以在IDR检测到0。但是Init设为输入输入却会关闭电流?
在1—Wire遇到一种情况:需要将端口拉高释放,然后由另一从机开漏输入,再由端口进行输入检测。很简单是不是?一开始我的步骤是:先推挽输出拉高,再
寄存器详解
寄存器:
GPIOx_CLR/GPIOx_CHR:CNF位和MODE位,设置模式和速度。
GPIOx_IDR\ODR:输入和输出寄存器,输出寄存器可以按端口写入。
GPIOx_BSR\BSRR:位重置和位重置/挂起寄存器,给对应的位写1可以重置/挂起某个位,即不影响其他位,也可以通过ODR的&=和|=操作做到。
GPIOx_LCKR:不作多解释,通过时序操作激活位锁定。
库函数分析
步骤:
启动APB2时钟
Init初始化
IDR读取ODR输出
调用库函数如图所示
/**
* @brief Initializes the GPIOx peripheral according to the specified
* parameters in the GPIO_InitStruct.
* @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
* @param GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that
* contains the configuration information for the specified GPIO peripheral.
* @retval None
*/
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
需要注意的是:
这个初始化函数,GPIO_InitStruct -> GPIO_Pin是初始化这个引脚,不是赋值!!!初始化后其值依然为复位值0。
库函数代码示例
GPIOConfig.h
#ifndef __GPIO_CONFIG_H
#define __GPIO_CONFIG_H
#include "stm32f10x.h"
void GPIO_InitConfig( GPIO_TypeDef* GPIOx , uint16_t GPIO_Pin , GPIOSpeed_TypeDef GPIO_Speed , GPIOMode_TypeDef GPIO_Mode );
GPIOConfig.c
#include "GPIOConfig.h"
void GPIO_InitConfig( GPIO_TypeDef* GPIOx , uint16_t GPIO_Pin , GPIOSpeed_TypeDef GPIO_Speed , GPIOMode_TypeDef GPIO_Mode )
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed;
GPIO_Init( GPIOx , &GPIO_InitStruct );
}
main.c
#include "GPIOConfig.h"
#include "stm32f10x.h"
int main()
{
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA , ENABLE );
GPIO_InitConfig( GPIOA , GPIO_Pin_0 , GPIO_Speed_50MHz , GPIO_Mode_IN_FLOATING );
}
//此处以A0 50MHZ 悬挂输入 作例子,这样的代码易于维护,避免重复使能,虽然繁琐一些,但是比较好维护
欢迎交流指正~~