1 GPIO功能模式
GPIO有八种工作模式
1、输入浮空 -该模式可以用于按键检测等场景。
2、输入上拉 -上拉电阻导通,施密特触发器打开,输出被禁止。使用内部电阻(内部电阻较大)为“弱上拉”不适合做电流型驱动空闲时,IO呈现高电平
3、输入下拉 -下拉电阻导通,施密特触发器打开,输出被禁止。使用内部电阻(内部电阻较大)为“弱下拉”不适合做电流型驱动空闲时,IO呈现低电平
4、模拟功能 -上下拉电阻断开,施密特触发器关闭,双 MOS管也关闭。上下拉电阻断开,施密特触发器关闭,双 MOS管也关闭。
特点:专门用于模拟信号输入或输出,如:ADC和DAC
5、开漏输出 -STM32的开漏输出模式是数字电路输出的一种,从结果上看它只能输出低电平 Vss或者高阻态,常用于 IIC通讯(IIC_SDA)或其它需要进行电平转换的场景。
特点:不能输出高电平, 必须有外部(或内部)上拉才能输出高电平(F1)
6、推挽输出 -STM32的开漏输出模式是数字电路输出的一种,从结果上看它只能输出低电平 Vss或者高阻态,常用于 IIC通讯(IIC_SDA)或其它需要进行电平转换的场景。
特点:可输出高低电平, 驱动能力强
7、开漏式复用功能 -STM32的开漏输出模式是数字电路输出的一种,从结果上看它只能输出低电平 Vss或者高阻态,常用于 IIC通讯(IIC_SDA)或其它需要进行电平转换的场景。特点:
1、不能输出高电平,必须有外部(或内部)上拉才能输出高电平
2、由其他外设控制输出
8、推挽式复用功能 -复用功能介绍请查看开漏式复用功能,结构分析请参考推挽输出模式(SPI的SCK)
特点:
1、可输出高低电平, 驱动能力强
2、由其他外设控制输出
图13.1.2.1详细查STM32F103开发指南
1,STM32工作电压范围?
2
V ≤ VDD ≤ 3.6 V
2,GPIO识别电压范围?
COMS端口:-0.3V ≤ VIL ≤
1.164V
1.833V ≤ VIH ≤ 3.6V
3,GPIO输出电流?
单个IO,最大25mA
TTL触发器(整型为方波)
P-MOS&N-MOS管
G:栅极:G=1,N-MOS导通;G=0,P-MOS导通
D:漏极
P:Vgs<0,导通
N:Vgs>0,导通
总结:F4/F7/H7系列和F1系列的GPIO差异点?
1,F1在输出模式,禁止使用内部上下拉,F4/F7/H7在输出模式,可以使用内部上下拉;
2,不同系列IO翻转速度可能不同;
2.GPIO寄存器介绍
(F1系列)GPIO通用寄存器GPIOX_yyy |
CRL |
CRH |
IDR |
ODR |
BSRR |
BRR |
LCKR |
配置工作模式,输出速度
|
输入数据 |
输出数据 |
设置ODR寄存器的值 |
F4之后没有这个寄存器,考虑代码兼容性的话不建议使用 |
配置锁定,用得不多 |
(F4/F7/H7系列)GPIO通用寄存器GPIOX_yyy |
MODER
|
OTYPER |
OSPEEDR |
PUPDR |
IDR |
ODR |
BSRR |
LCKR |
设置模式
|
设置输出
类型
|
设置输出
速度
|
设置上下拉电阻 |
输入数据 |
输出数据 |
设置ODR寄存器值 |
配置锁定,用得不多
|
命名注:(F1系列)GPIO通用寄存器GPIOX_yyy A端口类
(F4/F7/H7系列)GPIO通用寄存器GPIOX_yyy B端口类
A端口配置寄存器(GPIOx_CRL 和 GPIO_x_CRH)
这两个寄存器都是 GPIO口配置寄存器,不过 CRL控制端口的低八位(Px0-Px7的IO口),CRH控制端口的
高八位(Px8-Px15的IO口)。
A8种工作模式对应的配置
2个配置寄存器就是用来配置 GPIO的相关工作模式和工作速度,它们通过不同的配置组合方法,就决定我们所说的 8种工作模式。
输入上拉/下拉电阻通过ODR寄存器来设置
A端口输出入数据寄存器(IDR)
用于判断IO引脚的电平
A端口输出数据寄存器(ODR)
该寄存器用于控制 GPIOx的输出高电平或者低电平,寄存器描述如图 13.1.3.3所示。
用于设置IO引脚输出的电平
A端口置位/复位寄存器(BSRR)
该寄存器也用于控制 GPIOx的输出高电平或者低电平,寄存器描述如图 13.1.3.4所示
用于设置ODR寄存器
B端口模式寄存器(MODER)
用于设置模式
B端口输出类型寄存器(OTYPER)
用于设置输出类型
B端口输出速度寄存器(OSPEEDR)
用于设置IO的输出速度
B端口上拉/下拉寄存器(PUPDR)
用于设置上拉/下拉电阻
B8种工作模式对应的配置
用于读取IO引脚的电平
B端口输出数据寄存器(ODR)
用于设置IO引脚输出的电平
B端口置位/复位寄存器(BSRR)
用于设置ODR寄存器
思考
ODR和BSRR寄存器控制输出有什么区别?
GPIOB->ODR|= 1 << 3; /* PB3= 1 */
GPIOB->BSRR= 0x00000008; /* PB3 = 1 */
ODR修改:读à改à写
BSRR修改: 写
ST官方给的答案:使用ODR,在读和修改访问之间产生中断时,可能会发生风险;BSRR则无风险
总的来说,建议大家使用BSRR寄存器控制输出!
通用外设驱动模型(四步法)(掌握)
初始化 |
时钟设置,参数设置,OI设置,中断设置(开中断,设NVIC) |
读函数(可选) |
从外设读取数据 |
写函数(可选) |
往外设写入数据 |
中断服务函数(可选) |
根据中断标志,处理外设各种中断事务(可选) |
-
时钟设置 __HAL_RCC_GPIOx_CLK_ENABLE()
-
设置工作模式 HAL_GPIO_Init()
-
设置输出状态(可选) HAL_GPIO_WritePin HAL_GPIO_TogglePin()
-
读取输入状态(可选) HAL_GPIO_ReadPin()
HAL库驱动函数 |
主要寄存器 |
功能 |
__HAL_RCC_GPIOx_CLK_ENABLE()
|
F1:RCC_APB2ENR
F4:RCC_AHB1ENR
F7:RCC_AHB1ENR
H7:RCC_AHB4ENR
|
开启GPIO时钟 |
HAL_GPIO_Init(...) |
F1:CRL、CRH、ODR
F4/F7/H7:MODER、OTYPER、
OSPEEDR、PUPDR
|
初始化GPIO |
HAL_GPIO_WritePin(...) |
BSRR |
控制IO输出高/低电平 |
HAL_GPIO_TogglePin(...) |
BSRR |
每次调用IO输出电平翻转一次 |
HAL_GPIO_ReadPin(...) |
IDR |
读取IO电平 |
3.点亮一个LED灯
0805贴片发光二极管参考:
红色:压降范围1.82~1.88V
电流范围5~8mA
绿色:压降范围1.75~1.82V
电流范围3~5mA
蓝色:压降范围1.8~2.2V
电流范围8~10mA
不算LED内阻,电流I=(VCC-压降)/R电阻=(3.3-1.82)/510 =2.9mA
电流微低影响的是亮度
点亮LED灯代码模块
/*----------点亮LED灯代码模块(led.c)--------*/
/*----------------------------------------*/
#include "./BSP/LED/led.h"
void led_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
__HAL_RCC_GPIOB_CLK_ENABLE();
gpio_init_struct.Pin = GPIO_PIN_5;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &gpio_init_struct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
}
/*----------点亮LED灯代码模块(led.h)--------*/
/******************************************/
#ifndef __LED_H
#define __LED_H
#include "./SYSTEM/sys/sys.h"
void led_init(void);
#endif
/*----------点亮LED灯代码模块(main.c)--------*/
/*******************************************/
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
led_init(); /* LED初始化 */
while(1)
{
/******************方法一*******************/
// HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET); /* PB5置1 */
// delay_ms(200);
// HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET); /* PB5置0 */
// delay_ms(200);
/******************方法二*******************/
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);//每次调用IO输出电平翻转一次
delay_ms(200);
}
}
按键控制LED灯模块
/*----------按键控制LED灯代码模块(main.c)--------*/
/********************************** *********/
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LED/key.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
led_init(); /* LED初始化 */
key_init(); /* KEY初始化 */
while(1)
{
delay_ms(200); //消抖
if(key_scan())
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
}
else
{
delay_ms(10);
}
}
}
/*----------按键控制LED灯代码模块(key.c)--------*/
/**********************************************/
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
void key_init(void)//按键初始化函数
{
GPIO_InitTypeDef gpio_init_struct; //
__HAL_RCC_GPIOE_CLK_ENABLE();
gpio_init_struct.Pin = GPIO_PIN_2;
gpio_init_struct.Mode = GPIO_MODE_INPUT;
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOE, &gpio_init_struct);
}
uint8_t key_scan(void)//按键扫描函数
{
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5)==0) //读取按键电平
{
delay_ms(10); //消抖
while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5)==0)//等待按键松开
{
return 1; //返回值1
}
}
return 0; //返回值0
}
/*----------按键控制LED灯代码模块(key.h)--------*/
/**********************************************/
#ifndef __KEY_H
#define __KEY_H
#include "./SYSTEM/sys/sys.h"
void key_init(void);
uint8_t key_scan(void);
#endif
按键的LED初始化同“点亮一个LED灯”!!!
//初始化PB1为输出.并使能时钟
//LED IO初始化
/*下面主函数是使用HAL库函数实现控制IO口输出*/
#include "led.h"
int main(void)
{
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M
delay_init(72); //初始化延时函数
LED_Init(); //初始化LED
while(1)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET); //LED0对应引脚PB5拉低,亮,等同于LED0(0)
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET); //LED1对应引脚PE5拉高,灭,等同于LED1(1)
delay_ms(500); //延时500ms
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET); //LED0对应引脚PB5拉高,灭,等同于LED0(1)
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_RESET); //LED1对应引脚PE5拉低,亮,等同于LED1(0)
delay_ms(500); //延时500ms
}
}
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
/*下面主函数是使用HAL库函数实现控制IO口输出*/
int main(void)
{
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M
delay_init(72); //初始化延时函数
LED_Init(); //初始化LED
while(1)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET); //LED0对应引脚PB5拉低,亮,等同于LED0(0)
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET); //LED1对应引脚PE5拉高,灭,等同于LED1(1)
delay_ms(500); //延时500ms
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET); //LED0对应引脚PB5拉高,灭,等同于LED0(1)
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_RESET); //LED1对应引脚PE5拉低,亮,等同于LED1(0)
delay_ms(500); //延时500ms
}
}