STM32初学——GPIO

GPIO  (General Purpose Input Output)通用输入输出口

可配置8种输入输出模式(8种工作模式)

部分引脚FT(five tolerate)可以输入5v的电压,但对于输出来讲最高只能是3.3v,引脚电平0---3.3v

 每个GPIO外设,共有16个引脚,编号是从0-15

每个GPIO的模块内,主要包含了寄存器和驱动器

  • 寄存器:特殊存储器,只负责存储数据,内核可通过APB2总线对寄存器进行读写rw(输出、读取电平的功能)
  • STM32是32位的单片机,所以其内部寄存器都是32位的。由于端口(引脚)只有16位,所以只用到了低16位,高16位没有用到
  • 驱动器:增强信号的驱动能力 

 上、下拉电阻

  • 为了避免引脚悬空(漂浮在外太空,极易受到干扰)导致的输入数据不确定——上拉、下拉电阻(阻值较大、弱上拉、弱下拉)——尽量不影响正常的输入操作
  • 上拉输入——默认为高电平的输入模式
  • 下拉输入——默认位低电平的输入模式

施密特触发器——对输入电压进行整形

  • 执行逻辑:若输入电压大于某一阈值,输出瞬间升为高电平;若输入电压小于某一阈值,输出瞬间降为低电平。只有高于上限或低于下限,输出才会变化。在上限阈值与下限阈值的波动范围之间,维持不变。
  • advantage:有效避免因信号波动造成的输出抖动现象

输出数据寄存器:同时控制16个端口,且其只能整体rw,若想单独控制其中一个端口而不影响其他端口——特殊方式

  • 特殊方式1——读出此寄存器,利用按位与&=、按位或|=,最后再将更改后的数据写入
  •         fault:麻烦、效率差
  • 特殊方式2——通过设置位设置和位清除寄存器
  • 特殊方式3——rwSTM32的“位带”区域(与51单片机的位寻址相似)(暂时用不到)

库函数使用的是——rw位设置和位清除寄存器的方法

mos管——电子开关      三种输出方式:推挽、开漏、关闭

1.推挽输出方式——高低电平均有较强的驱动能力——强推输出模式

        STM32对IO口具有绝对的控制权

2.开漏模式——数据寄存器为1,高阻模式;为0,NMOS接入。即只有低电平具有驱动能力

  •         主要用途:作为通信协议的驱动方式,例如I2C通信的引脚
  •                            输出5v的电平信号,用于兼容一些5v电平的设备

3.关闭状态——当引脚配置为输入模式,PMOS、NMOS均无效,即输出关闭,端口电平信号由外部信号控制

8种工作方式:

输入模式下:输出无效

        原因:一个端口只能有一个输出,但可以有多个输入,所以当配置成输出模式下,内部输入也是无影响的

GPIO配置寄存器

每一个端口的模式由4位进行配置,16个端口需要64位,所以这里的配置寄存器需要2个——端口配置低寄存器、端口配置高寄存器

 对多个端口同时进行位设置和位清除,保证位设置和位清除的同步性

LED两种驱动方式如何选择?

取决于IO口高低电平的驱动能力

之前介绍到:推挽输出方式——高低电平均有较强的驱动能力——强推输出模式

我们倾向于使用低电平驱动——很多单片机、芯片都使用了高电平弱驱动、低电平强驱动的规则。

蜂鸣器:

三极管驱动

操作STM32的GPIO的三个步骤:

1、使用RCC开启使能GPIO的时钟

2、使用GPIO_Init函数初始化GPIO

3、使用输出或输入函数控制GPIO口

 

 GPIO的八种工作模式:

AIN Analog IN  模拟输入

IN FlOATING  浮空输入

IPD  in pull down 下拉输入

IPU  in pull up    上拉输入

Out_OD  Out Open Drain   开漏输出

Out_PP  out push pull  推挽输出

AF_OD   Atl Open Drain  复用开漏

AF_PP

//把指定端口设置成高电平

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

 void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

 啊啊啊,因为红光太强,所以我一直以为我的灯没有亮,别因为别人的光芒太耀眼,而看不到自己的光芒。

在PA0口不太行,我在PA2口实验成功,不知道是不是因为拓展坞的原因,明明是采用推挽输出,但是导致灯特别暗。

#include "stm32f10x.h"                  // Device header

int main(void)
{
	RCC_AHBPeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//RCC里面的外设时钟控制函数,开启时钟
	//---------------GPIO初始化--------------------------
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //点灯使用的是推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;  //0号引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//-----------------GPIO初始化完成---------------------------------
	//GPIO_ResetBits(GPIOA, GPIO_Pin_2);
	//GPIO_SetBits(GPIOA, GPIO_Pin_2);
	GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_SET);
	while(1)
	{
	
	}
}

哟吼,PA0口也行了。实际没行。

什么鬼啊,为什么我的程序不行,我拿up主的程序灯就会亮,运行up主的程序前,要先修改

我把up主的程序复制也可以,就是我自己程序的问题,不行了,我要去吃饭了

下图对高低电平进行操作

		GPIO_WriteBit(GPIOA, GPIO_Pin_0, 0);
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, 1);
		Delay_ms(500);

产生两个错误:枚举类型中混入其他类型的变量

solution:强制类型转换

GPIO_WriteBit(GPIOA, GPIO_Pin_0,(BitAction)0);

 我的代码:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
int main(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//RCC里面的外设时钟控制函数,开启时钟
	//---------------GPIO初始化--------------------------
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //点灯使用的是推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;  //0号引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//-----------------GPIO初始化完成---------------------------------
	//GPIO_ResetBits(GPIOA, GPIO_Pin_2);
	//GPIO_SetBits(GPIOA, GPIO_Pin_2);

	while(1)
	{	GPIO_ResetBits(GPIOA, GPIO_Pin_0);
		Delay_ms(500);
		GPIO_SetBits(GPIOA, GPIO_Pin_0);
		Delay_ms(500);
		
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
		Delay_ms(500);
		
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);
		Delay_ms(500);

	}
}

 up代码:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	while (1)
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_0);
		Delay_ms(500);
		GPIO_SetBits(GPIOA, GPIO_Pin_0);
		Delay_ms(500);
		
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
		Delay_ms(500);
		
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);
		Delay_ms(500);
	}
}

啊啊啊,整个人又傻了

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // Out Open Drain   开漏输出

 开漏模式——数据寄存器为1,高阻模式;为0,NMOS接入。即只有低电平具有驱动能力

我们把LED的负极接在面包板的负极上,把LED正极接在PA0口,(对应的是LED的高电平驱动)可以看到在此情形下,LED是没有闪烁的。

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //点灯使用的是推挽输出

在推挽输出的情况下,无论LED是高电平驱动还是低电平驱动都是闪烁的

而我又犯了错误,在LED是低电平驱动的条件下,使用开漏输出模式,结果是编译、下载,LED仍闪烁,我还又责怪不知道哪里出了问题,但是我也验证了在开漏模式下,只有低电平驱动具有驱动能力

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值