STM32F1单片机-GPIO

一、C语言部分

  • 数据类型和关键字

  stdint关键字使用了新名称来定义数据类型,ST是老版本的数据类型名(例:int8_t有符号8位,uint8_t无符号8位)

在这里插入图片描述

  • 宏定义

  #define:用一个字符串去代替一个数字。例#define ABC 12345
  typedef:将一个比较长的变量类型名换个名字(针对变量类型)。例typedef unsigned char uint_8,即unsigned char a等效于uint_8 a

  • 结构体:数据打包,不同变量类型的集合

  定义结构体变量(struct {数据类型} 结构体名)
  struct {char x;int y;float z;} StructName

  因为结构体变量类型较长,一般用typedef更改变量类型
  例:typedef struct{char x;int y;float z;} StructName_t
  则可以写成StructName_t StructName;
  引用结构体成员:StryctName.x = ‘A’

  • 枚举变量:定义一个取值受限制的整数变量,用于限制变量的取值范围

  定义枚举变量(enum{} 枚举名)
  enum {FALSE = 0,TRUE = 1} EnumName;
  因为枚举变量类型较长,所以一般用typedef更改变量类型
  例:typedef enum{MON = 1,TUE,WED} week_t
  则可以写成week_t week
  引用枚举成员:week = MON即week=1

二、GPIO(通用输入输出口)

  • GPIO总共可以配置成8种输入输出模式

  • 输入模式浮空输入(电平不确定)、上拉输入IPU(上拉电阻,默认高电平)、下拉输入IPD(下拉电阻,默认低电平)、模拟输入(GPIO无效,引脚直接接入内部ADC)

  • 输出模式推挽输出PP(输出高低电平都可以)、开漏输出OD(输出低电平有效)、复用推挽输出AF_PP(电平由片上外设控制)、复用开漏输出AF_OD(电平由片上外设控制)、关闭(都无效)

  开漏输出模式下,当引脚输出低电平时,内部开关导通,引脚接地,低电平有驱动能力,当配置成高电平时,内部开关断开,引脚处于高阻态模式,不驱动任何电平,如果需要驱动高电平,则需要外接上拉电阻
  STM32单片机的GPIO口内部接了一个弱上、下拉电阻,但开漏输出模式下会禁用内部上下拉电阻,但可以在外部(外设)接上拉电阻,从而实现在高阻态下由上拉电阻拉高GPIO口,从而在开漏输出模式下输出高电平

  • 输出模式下可以控制端口输出高低电平,用以驱动LED、蜂鸣器、模拟通信协议输出时序
  • 输入模式下单片机可以读取端口的高低电平或者电压,用以读取按键输入、外接模块电平信号输入、ADC电压采集、模块通信协议接收数据等
  • GPIO引脚电平可以配置成0-3.3V,部分引脚可以容忍到5V,即输出最大3.3V,这是由于单片机供电的3.3V,有些端口输入电压(FT)可以到5V
  • GPIO速度:F1系列最高50MHz

  下图为GPIO的基本结构图

  开漏模式:输出寄存器的0激活N-MOS,输出寄存器的1将端口置于高阻态模式(P-MOS从不被激活),读输入寄存器同样也可以得到GPIO状态(外部信号),即同样可以输入(依赖外部上拉电阻提供的电压来确定输入状态),高阻态模式下允许外置的上拉电阻可以拉高电平,从而可以准确读取到外部输入信号
  推挽模式:输出寄存器的0激活N-MOS,输出寄存器的1激活P-MOS,推挽模式下,必须重新初始化GPIO配置成输入模式才可以输入(读取)外部的信号(由于较强主动地驱动高低电平,会影响外部引脚的对电平的控制),但是可以读取当前引脚输出的电平

  有的GPIO可以容忍5V电压是因为保护二极管不一致

在这里插入图片描述

  下图为GPIO的基本框架
  GPIO是挂载在APB2外设总线上的,每个GPIO有16个引脚

在这里插入图片描述

三、LED&蜂鸣器&按键

  LED、按键蜂鸣器见51系列

  下图是按键部分的电路原理图
  左边表示K1悬空接到单片机PA0口,低电平有效,所以在配置GPIO输入模式时,需要配置上拉输入模式,使得空闲为高电平;
  右边接了一个上拉电阻,空闲时默认高电平,所以配置GPIO输入模式时,可以选择浮空输入模式或者上拉输入模式

在这里插入图片描述

四、传感器模块

  • 传感器模块包括:光敏电阻、热敏电阻、红外接收管等
  • 传感器的电阻会随着外界因素的变化而变化,通过与定值电阻分压得到模拟电压输出,再通过电压比较器进行二值化即可得到数字电压输出(0或1)

  如下图是通用的传感器模块电路图
  从左到右,依次为电压比较器阈值电路分压电路(N1就是光敏电阻or热敏电阻等等)、电源指示灯DO输出电平指示灯电路(低电平点亮)
  AO模拟电压输出(接收光照、热量强度),DO是数字电压输出(0和1),数字输出就是对AO二值化的结果,是由电压比较器来完成的;电压比较器中IN+接到AO,IN-接到阈值电路(电位器),调节阈值,两个电压进行比较最终输出DO,接到引脚输出端;

在这里插入图片描述
  下图为传感器模块的接线原理图

Alt

五、功能实现(标准库)

5.1 GPIO输出

5.1.1 寄存器配置方式点亮LED

  寄存器配置点亮PC13的LED,PC13口是挂载在APB2总线上的,先配置APB2外设时钟使能寄存器(RCC_APB2ENR),然后配置PC13口的模式,找到端口配置高寄存器(x=8-15),最后配置端口输出数据寄存器

	RCC->APB2ENR = 0x00000010;		//STM32的寄存器为32位,GPIOPC13使能给1
	GPIOC->CRH = 0x00300000;		//配置端口模式-通用推挽输出
	GPIOC->ODR = 0x00000000;		//配置端口输出数据寄存器

  配置寄存器方式去操作STM32系列单片机较为繁琐,位数较多

5.1.2 LED闪烁

  使用库函数去实现LED闪烁,在使用外设时,需要先配置RCC的时钟,LED负极接在PA0口,GPIOA挂载在APB2总线上,所以第一步需要开启RCC_APB2PeriphClockCmd时钟第二步需要初始化GPIO_Init(配置模式、Pin口和速度)最后一步给定GPIO口高低电平

#include "stm32f10x.h"
#include "Delay.h"


//涉及外设:GPIO
int main(void)
{
	//开启RCC时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//初始化GPIO	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;			//Pin0
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//速度
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	while(1)
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_0);				//给PA0低电平
		Delay_ms(100);
		GPIO_SetBits(GPIOA,GPIO_Pin_0);					//给PA0高电平
		Delay_ms(100);
	}
}

5.1.3 LED流水灯

  多个LED接在不同的GPIO口,配置GPIOA时需要同时配置不同的Pin,可以|上需要的Pin或者直接给GPIO_Pin = GPIO_Pin_ALL

#include "stm32f10x.h"
#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_All;		//GPIO_Pin_0|GPIO_Pin_1...
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	while(1)
	{
		GPIO_Write(GPIOA,~(0x0001));		//0000 0000 0000 0001,PA0点亮
		Delay_ms(500);
		GPIO_Write(GPIOA,~(0x0002));		//PA1点亮
		Delay_ms(500);
		GPIO_Write(GPIOA,~(0x0004));		//PA2点亮
		Delay_ms(500);
	} 
}

5.1.4 蜂鸣器

  使用有源蜂鸣器,只要给蜂鸣器端口低电平,蜂鸣器就会响

#include "stm32f10x.h"
#include "Delay.h"

int main(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);		//开启APB2时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;		
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;			//推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;					//PA12
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	while(1)
	{
		GPIO_ResetBits(GPIOB, GPIO_Pin_12);			//响
		Delay_ms(100);
		GPIO_SetBits(GPIOB, GPIO_Pin_12);			//不响
		Delay_ms(100);
		GPIO_ResetBits(GPIOB, GPIO_Pin_12);
		Delay_ms(100);
		GPIO_SetBits(GPIOB, GPIO_Pin_12);
		Delay_ms(700);
	} 
}

5.2 GPIO输入

5.2.1 按键控制LED亮灭

  按键端口配置成上拉输入模式
  按键控制需要按键消抖
  下面给出Key.c

#include "stm32f10x.h"
#include "Delay.h"
/*
@brief:GPIOB初始化
*/
void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_Initstructure;
	GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IPU;			//上拉输入
	GPIO_Initstructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_11;
	GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_Initstructure);
}
/*
@brief:获取按键键码值
@retval:按键键码值:PB1按下返回1,PB11按下返回2
*/
uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;
	if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0)
	{
		Delay_ms(20);
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0);
		Delay_ms(20);
		KeyNum = 1;
	}
	if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0)
	{
		Delay_ms(20);
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==0);
		Delay_ms(20);
		KeyNum = 2;
	}
	return KeyNum;
}

  下面给出LED.c

#include "stm32f10x.h"

/*
@brief:GPIOA初始化
*/
void LED_Init(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_1 | GPIO_Pin_2;
	GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_Initstructure);
	GPIO_SetBits(GPIOA,GPIO_Pin_1 | GPIO_Pin_2);			//初始为高电平
}
/*
@brief:LED1-PA1电平翻转
*/
void LED1_Turn(void)
{
	if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1) == 0)		//读取GPIOA_Pin_1为低
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_1);						//给GPIOA_Pin_1高
	}
	else
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_1);					//给GPIOA_Pin_1低
	}
}
/*
@brief:LED2-PA2电平翻转
*/
void LED2_Turn(void)
{
	if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_2) == 0)		//读取GPIOA_Pin_2为低
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_2);						//给GPIOA_Pin_2高
	}
	else
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_2);					//给GPIOA_Pin_2低
	}
}
/*
@brief:点亮LED1
*/
void LED1_ON(void)
{
	GPIO_ResetBits(GPIOA,GPIO_Pin_1);
}
/*
@brief:熄灭LED1
*/
void LED1_OFF(void)
{
	GPIO_SetBits(GPIOA,GPIO_Pin_1);
}
/*
@brief:点亮LED2
*/
void LED2_ON(void)
{
	GPIO_ResetBits(GPIOA,GPIO_Pin_2);
}
/*
@brief:熄灭LED2
*/
void LED2_OFF(void)
{
	GPIO_SetBits(GPIOA,GPIO_Pin_2);
}

5.2.2 光敏电阻电阻控制蜂鸣器

  光敏电阻模块采用上拉输入模式,较暗环境输入1,较亮环境输入0
  传感器DO数字量(01)通过GPIO输入,单片机读GPIO口
  下面为Buzzer.c

#include "stm32f10x.h"
/*
@brief:蜂鸣器初始化
*/
void Buzzer_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure; 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		//推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}
/*
@brief:开启蜂鸣器
*/
void Buzzer_ON()
{
	GPIO_ResetBits(GPIOB,GPIO_Pin_12);
}
/*
@brief:蜂鸣器关闭
*/
void Buzzer_OFF()
{
	GPIO_SetBits(GPIOB,GPIO_Pin_12);
}
/*
@brief:蜂鸣器状态翻转
*/
void Buzzer_Turn()
{
	if(GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_12) == 0)
	{
		GPIO_SetBits(GPIOB,GPIO_Pin_12);
	}
	else
	{
		GPIO_ResetBits(GPIOB,GPIO_Pin_12);
	}
}

  下面为LightSensor.c

#include "stm32f10x.h"
/*
@brief:光敏电阻初始化
*/
void LightSensor_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;			//上拉输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}
/*
@brief:返回光敏电阻数字量(01),较暗环境输入1,较亮环境输入0
@retval:光敏传感器数字量
*/
uint8_t LightSensor_Get()
{
	return GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13);
}

六、功能实现(HAL库)

  通用外设驱动模型(四步法)

  • 初始化时钟设置参数设置IO设置中断设置(开中断、设NVIC)-可选
  • 读函数(可选):从外设读取数据
  • 写函数(可选):往外设写入数据
  • 中断服务函数(可选):根据中断标志,处理外设各种中断事务

  GPIO配置步骤

  • 使能时钟:stm32f1xx_hal_rcc.h中__HAL_RCC_GPIOx_CLK_ENABLE()
  • GPIO初始化:stm32f1xx_hal_gpio.h中HAL_GPIO_Init()
  • 写/翻转GPIO:stm32f1xx_hal_gpio.h中HAL_GPIO_WritePin()和HAL_GPIO_TogglePin()
  • 读取GPIO:stm32f1xx_hal_gpio.h中GPIO_PinState HAL_GPIO_ReadPin()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值