GPIO 端口配置
GPIO 的pin,速度,模式,都由GPIO 的端口配置寄存器来控制,其中IO0~IO7 由端口配置低寄存器CRL 控制,IO8~IO15 由端口配置高寄存器CRH 配置。固件库把端口配置的pin,速度和模式封装成一个结构体:
typedef struct { uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; } GPIO_InitTypeDef; pin 可以是GPIO_Pin_0~GPIO_Pin_15 或者是GPIO_Pin_All,这些都是库预先定义好的宏。speed 也被封装成一个结构体:
typedef enum { GPIO_Speed_10MHz = 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz } GPIOSpeed_TypeDef; 速度可以是10M,2M 或者50M,这个由端口配置寄存器的MODE 位控制,速度是针对IO 口输出的时候而言,在输入的时候可以不用设置。mode 也被封装成一个结构体:
typedef enum { GPIO_Mode_AIN = 0x0, // 模拟输入 GPIO_Mode_IN_FLOATING = 0x04, // 浮空输入(复位后的状态) GPIO_Mode_IPD = 0x28, // 下拉输入 GPIO_Mode_IPU = 0x48, // 上拉输入 GPIO_Mode_Out_OD = 0x14, // 通用开漏输出 GPIO_Mode_Out_PP = 0x10, // 通用推挽输出 GPIO_Mode_AF_OD = 0x1C, // 复用开漏输出 GPIO_Mode_AF_PP = 0x18 // 复用推挽输出 } GPIOMode_TypeDef; IO 口的模式有8 种,输入输出各4 种,由端口配置寄存器的CNF 配置。平时用的最多的就是通用推挽输出,可以输出高低电平,驱动能力大,一般用于接数字器件。至于剩下的七种模式的用法和电路原理,我们在后面的GPIO 章节再详细讲解。
最终用固件库实现就变成这样:
// 定义一个GPIO_InitTypeDef 类型的结构体 GPIO_InitTypeDef GPIO_InitStructure; // 选择要控制的IO 口 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 设置引脚为推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 设置引脚速率为50MHz GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; /*调用库函数,初始化GPIOB0*/ GPIO_Init(GPIOB, &GPIO_InitStructure); 倘若同一端口下不同引脚有不同的模式配置,每次对每个引脚配置完成后都要调用GPIO初始化函数,代码如下:
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO 输出控制
GPIO 输出控制,可以通过端口数据输出寄存器ODR、端口位设置/清除寄存器BSRR和端口位清除寄存器BRR 这三个来控制。端口输出寄存器ODR 是一个32 位的寄存器,低16 位有效,对应着IO0~IO15,只能以字的形式操作,一般使用寄存器操作。
// PB0 输出高电平,点亮LED GPIOB->ODR = 1<<0; 端口位清除寄存器BRR 是一个32 位的寄存器,低十六位有效,对应着IO0~IO15,只能以字的形式操作,可以单独对某一个位操作,写1 清0。
// PB0 输出低电平,点亮LED GPIO_ResetBits(GPIOB, GPIO_Pin_0); BSRR 是一个32 位的寄存器,低16 位用于置位,写1 有效,高16 位用于复位,写1有效,相当于BRR 寄存器。高16 位我们一般不用,而是操作BRR 这个寄存器,所以BSRR 这个寄存器一般用来置位操作。
// PB0 输出高电平,熄灭LED GPIO_SetBits(GPIOB, GPIO_Pin_0); 综上:固件库LED GPIO 初始化函数
void LED_GPIO_Config(void) { // 定义一个GPIO_InitTypeDef 类型的结构体 GPIO_InitTypeDef GPIO_InitStructure; // 开启GPIOB 的时钟 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); // 选择要控制的IO 口 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 设置引脚为推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 设置引脚速率为50MHz GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化GPIOB0*/ GPIO_Init(GPIOB, &GPIO_InitStructure); // 关闭LED GPIO_SetBits(GPIOB, GPIO_Pin_0); } 主函数
#include "stm32f10x.h" void SOFT_Delay(__IO uint32_t nCount); void LED_GPIO_Config(void); int main(void) { // 程序来到main 函数之前,启动文件:statup_stm32f10x_hd.s 已经调用 // SystemInit()函数把系统时钟初始化成72MHZ // SystemInit()在system_stm32f10x.c 中定义 // 如果用户想修改系统时钟,可自行编写程序修改 LED_GPIO_Config(); while ( 1 ) { // 点亮LED GPIO_ResetBits(GPIOB, GPIO_Pin_0); Time_Delay(0x0FFFFF); // 熄灭LED GPIO_SetBits(GPIOB, GPIO_Pin_0); Time_Delay(0x0FFFFF); } } // 简陋的软件延时函数 void Time_Delay(volatile uint32_t Count) { for (; Count != 0; Count--); } 注意void Time_Delay(volatile uint32_t Count)
只是一个简陋的软件延时函数,如果小伙伴们有兴趣可以看一看MultiTimer,它是一个软件定时器扩展模块,可无限扩展所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。
GPIO 端口配置
GPIO 的pin,速度,模式,都由GPIO 的端口配置寄存器来控制,其中IO0~IO7 由端口配置低寄存器CRL 控制,IO8~IO15 由端口配置高寄存器CRH 配置。固件库把端口配置的pin,速度和模式封装成一个结构体:
typedef struct { uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; } GPIO_InitTypeDef; pin 可以是GPIO_Pin_0~GPIO_Pin_15 或者是GPIO_Pin_All,这些都是库预先定义好的宏。speed 也被封装成一个结构体:
typedef enum { GPIO_Speed_10MHz = 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz } GPIOSpeed_TypeDef; 速度可以是10M,2M 或者50M,这个由端口配置寄存器的MODE 位控制,速度是针对IO 口输出的时候而言,在输入的时候可以不用设置。mode 也被封装成一个结构体:
typedef enum { GPIO_Mode_AIN = 0x0, // 模拟输入 GPIO_Mode_IN_FLOATING = 0x04, // 浮空输入(复位后的状态) GPIO_Mode_IPD = 0x28, // 下拉输入 GPIO_Mode_IPU = 0x48, // 上拉输入 GPIO_Mode_Out_OD = 0x14, // 通用开漏输出 GPIO_Mode_Out_PP = 0x10, // 通用推挽输出 GPIO_Mode_AF_OD = 0x1C, // 复用开漏输出 GPIO_Mode_AF_PP = 0x18 // 复用推挽输出 } GPIOMode_TypeDef; IO 口的模式有8 种,输入输出各4 种,由端口配置寄存器的CNF 配置。平时用的最多的就是通用推挽输出,可以输出高低电平,驱动能力大,一般用于接数字器件。至于剩下的七种模式的用法和电路原理,我们在后面的GPIO 章节再详细讲解。
最终用固件库实现就变成这样:
// 定义一个GPIO_InitTypeDef 类型的结构体 GPIO_InitTypeDef GPIO_InitStructure; // 选择要控制的IO 口 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 设置引脚为推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 设置引脚速率为50MHz GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; /*调用库函数,初始化GPIOB0*/ GPIO_Init(GPIOB, &GPIO_InitStructure); 倘若同一端口下不同引脚有不同的模式配置,每次对每个引脚配置完成后都要调用GPIO初始化函数,代码如下:
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO 输出控制
GPIO 输出控制,可以通过端口数据输出寄存器ODR、端口位设置/清除寄存器BSRR和端口位清除寄存器BRR 这三个来控制。端口输出寄存器ODR 是一个32 位的寄存器,低16 位有效,对应着IO0~IO15,只能以字的形式操作,一般使用寄存器操作。
// PB0 输出高电平,点亮LED GPIOB->ODR = 1<<0; 端口位清除寄存器BRR 是一个32 位的寄存器,低十六位有效,对应着IO0~IO15,只能以字的形式操作,可以单独对某一个位操作,写1 清0。
// PB0 输出低电平,点亮LED GPIO_ResetBits(GPIOB, GPIO_Pin_0); BSRR 是一个32 位的寄存器,低16 位用于置位,写1 有效,高16 位用于复位,写1有效,相当于BRR 寄存器。高16 位我们一般不用,而是操作BRR 这个寄存器,所以BSRR 这个寄存器一般用来置位操作。
// PB0 输出高电平,熄灭LED GPIO_SetBits(GPIOB, GPIO_Pin_0); 综上:固件库LED GPIO 初始化函数
void LED_GPIO_Config(void) { // 定义一个GPIO_InitTypeDef 类型的结构体 GPIO_InitTypeDef GPIO_InitStructure; // 开启GPIOB 的时钟 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); // 选择要控制的IO 口 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 设置引脚为推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 设置引脚速率为50MHz GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化GPIOB0*/ GPIO_Init(GPIOB, &GPIO_InitStructure); // 关闭LED GPIO_SetBits(GPIOB, GPIO_Pin_0); } 主函数
#include "stm32f10x.h" void SOFT_Delay(__IO uint32_t nCount); void LED_GPIO_Config(void); int main(void) { // 程序来到main 函数之前,启动文件:statup_stm32f10x_hd.s 已经调用 // SystemInit()函数把系统时钟初始化成72MHZ // SystemInit()在system_stm32f10x.c 中定义 // 如果用户想修改系统时钟,可自行编写程序修改 LED_GPIO_Config(); while ( 1 ) { // 点亮LED GPIO_ResetBits(GPIOB, GPIO_Pin_0); Time_Delay(0x0FFFFF); // 熄灭LED GPIO_SetBits(GPIOB, GPIO_Pin_0); Time_Delay(0x0FFFFF); } } // 简陋的软件延时函数 void Time_Delay(volatile uint32_t Count) { for (; Count != 0; Count--); } 注意void Time_Delay(volatile uint32_t Count)
只是一个简陋的软件延时函数,如果小伙伴们有兴趣可以看一看MultiTimer,它是一个软件定时器扩展模块,可无限扩展所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。
举报