1.什么是GPIO
GPIO(General Purpose Input Output):通用输入输出口。
输出模式下可用于驱动LED、蜂鸣器、模拟通信协议输出时序等。
输入模式下可读取端口的高低电平和电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等。
GPIO挂载在APB2总线上
2.GPIO模式
推挽输出(PP):STM32端口完全由GPIO控制,寄存器写入高电平端口输出高电平,写入低电平输出低电平
上拉输入(IPU):悬空时默认引脚为高电平
3.GPIO输出
GPIO配置流程:
1.初始化
1.1打开GPIO对应时钟
1.2选择模式,这里选择推挽输出
1.3选择端口号和速度
2.设置端口的输出
1.LED闪烁
1.LED原理图
2.硬件接线图
通过A0口控制LED灯
LED灯引脚较长的一端为正极,另一端为负极
tips:面包板的使用方法
顶部和底部的+-每行的孔洞相当于连接在一起
中间部分每列的孔洞相当于连接在一起
3.源码
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
//使用各个外设前必须开启时钟,否则对外设的操作无效
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //GPIO模式,赋值为推挽输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO引脚,赋值为第0号引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO速度,赋值为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //将赋值后的构体变量传递给GPIO_Init函数
//函数内部会自动根据结构体的参数配置相应寄存器
//实现GPIOA的初始化
/*主循环,循环体内的代码会一直循环执行*/
while (1)
{
/*设置PA0引脚的高低电平,实现LED闪烁,下面展示3种方法*/
/*方法1:GPIO_ResetBits设置低电平,GPIO_SetBits设置高电平*/
GPIO_ResetBits(GPIOA, GPIO_Pin_0); //将PA0引脚设置为低电平
Delay_ms(500); //延时500ms
GPIO_SetBits(GPIOA, GPIO_Pin_0); //将PA0引脚设置为高电平
Delay_ms(500); //延时500ms
/*方法2:GPIO_WriteBit设置低/高电平,由Bit_RESET/Bit_SET指定*/
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); //将PA0引脚设置为低电平
Delay_ms(500); //延时500ms
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); //将PA0引脚设置为高电平
Delay_ms(500); //延时500ms
/*方法3:GPIO_WriteBit设置低/高电平,由数据0/1指定,数据需要强转为BitAction类型*/
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0); //将PA0引脚设置为低电平
Delay_ms(500); //延时500ms
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1); //将PA0引脚设置为高电平
Delay_ms(500); //延时500ms
}
}
4.添加新模块(Delay模块的添加)
1.将要添加的模块复制到工程所在的文件夹,并且添加到工程中
2.在设置中将模块头文件所在的路径包含
3.在main函数中include模块的头文件
4.打开Delay.h文件查看模块定义的函数
2.流水灯
1.硬件接线图
2.关键源码
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
//使用各个外设前必须开启时钟,否则对外设的操作无效
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //GPIO模式,赋值为推挽输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; //GPIO引脚,赋值为所有引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO速度,赋值为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //将赋值后的构体变量传递给GPIO_Init函数
//函数内部会自动根据结构体的参数配置相应寄存器
//实现GPIOA的初始化
/*主循环,循环体内的代码会一直循环执行*/
while (1)
{
/*使用GPIO_Write,同时设置GPIOA所有引脚的高低电平,实现LED流水灯*/
GPIO_Write(GPIOA, ~0x0001); //0000 0000 0000 0001,PA0引脚为低电平,其他引脚均为高电平,注意数据有按位取反
Delay_ms(100); //延时100ms
GPIO_Write(GPIOA, ~0x0002); //0000 0000 0000 0010,PA1引脚为低电平,其他引脚均为高电平
Delay_ms(100); //延时100ms
GPIO_Write(GPIOA, ~0x0004); //0000 0000 0000 0100,PA2引脚为低电平,其他引脚均为高电平
Delay_ms(100); //延时100ms
GPIO_Write(GPIOA, ~0x0008); //0000 0000 0000 1000,PA3引脚为低电平,其他引脚均为高电平
Delay_ms(100); //延时100ms
GPIO_Write(GPIOA, ~0x0010); //0000 0000 0001 0000,PA4引脚为低电平,其他引脚均为高电平
Delay_ms(100); //延时100ms
GPIO_Write(GPIOA, ~0x0020); //0000 0000 0010 0000,PA5引脚为低电平,其他引脚均为高电平
Delay_ms(100); //延时100ms
GPIO_Write(GPIOA, ~0x0040); //0000 0000 0100 0000,PA6引脚为低电平,其他引脚均为高电平
Delay_ms(100); //延时100ms
GPIO_Write(GPIOA, ~0x0080); //0000 0000 1000 0000,PA7引脚为低电平,其他引脚均为高电平
Delay_ms(100); //延时100ms
}
}
要点:
1.如何一次性初始化多个引脚
2.GPIO_Write同时赋值多个引脚
3.蜂鸣器
1.硬件接线图
蜂鸣器为低电平触发
2.关键源码
while (1)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_12); //将PB12引脚设置为低电平,蜂鸣器鸣叫
Delay_ms(100); //延时100ms
GPIO_SetBits(GPIOB, GPIO_Pin_12); //将PB12引脚设置为高电平,蜂鸣器停止
Delay_ms(100); //延时100ms
GPIO_ResetBits(GPIOB, GPIO_Pin_12); //将PB12引脚设置为低电平,蜂鸣器鸣叫
Delay_ms(100); //延时100ms
GPIO_SetBits(GPIOB, GPIO_Pin_12); //将PB12引脚设置为高电平,蜂鸣器停止
Delay_ms(700); //延时700ms
}
4.GPIO输出
1.按键控制LED
1.按键原理图
当按键按下时,PA0输入低电平
按键在按下的时候会出现抖动现象,在刚按下的5-10ms内会抖动,然后进入稳定的低电平,松开开关按键时也会抖动,需要在程序中对该现象进行处理。
2.硬件接线图
3.源码
编程,将LED和按键的功能拆解出来,代码分为对应的模块
按键接入的GPIO采用上拉输入模式(IPU)
Key.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
/**
* 函 数:按键初始化
* 参 数:无
* 返 回 值:无
*/
void Key_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
/*GPIO初始化*/
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); //将PB1和PB11引脚初始化为上拉输入
}
/**
* 函 数:按键获取键码
* 参 数:无
* 返 回 值:按下按键的键码值,范围:0~2,返回0代表没有按键按下
* 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手
*/
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0; //定义变量,默认键码值为0
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) //读PB1输入寄存器的状态,如果为0,则代表按键1按下
{
Delay_ms(20); //延时消抖
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0); //等待按键松手
Delay_ms(20); //延时消抖
KeyNum = 1; //置键码为1
}
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0) //读PB11输入寄存器的状态,如果为0,则代表按键2按下
{
Delay_ms(20); //延时消抖
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0); //等待按键松手
Delay_ms(20); //延时消抖
KeyNum = 2; //置键码为2
}
return KeyNum; //返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0
}
消除抖动思想:首先对GPIO端口的状态进行判断,当检测到端口置0时,表示此时按键被按下,延时20ms,消除按键按下的抖动时间,此时处于按键按下阶段,只要端口一直接收低电平(即按键处于按下状态),程序就一直处于while循环不向下执行,当检测到高电平,表示松手了,再延时20ms,消除松手抖动
4.新建模块
以LED模块为例
1.新建.c文件,包含相关函数
#include "stm32f10x.h" // Device header
/**
* 函 数:LED初始化
* 参 数:无
* 返 回 值:无
*/
void LED_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO初始化*/
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); //将PA1和PA2引脚初始化为推挽输出
/*设置GPIO初始化后的默认电平*/
GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2); //设置PA1和PA2引脚为高电平
}
/**
* 函 数:LED1开启
* 参 数:无
* 返 回 值:无
*/
void LED1_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1); //设置PA1引脚为低电平
}
/**
* 函 数:LED1关闭
* 参 数:无
* 返 回 值:无
*/
void LED1_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1); //设置PA1引脚为高电平
}
/**
* 函 数:LED1状态翻转
* 参 数:无
* 返 回 值:无
*/
void LED1_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0) //获取输出寄存器的状态,如果当前引脚输出低电平
{
GPIO_SetBits(GPIOA, GPIO_Pin_1); //则设置PA1引脚为高电平
}
else //否则,即当前引脚输出高电平
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1); //则设置PA1引脚为低电平
}
}
/**
* 函 数:LED2开启
* 参 数:无
* 返 回 值:无
*/
void LED2_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2); //设置PA2引脚为低电平
}
/**
* 函 数:LED2关闭
* 参 数:无
* 返 回 值:无
*/
void LED2_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2); //设置PA2引脚为高电平
}
/**
* 函 数:LED2状态翻转
* 参 数:无
* 返 回 值:无
*/
void LED2_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0) //获取输出寄存器的状态,如果当前引脚输出低电平
{
GPIO_SetBits(GPIOA, GPIO_Pin_2); //则设置PA2引脚为高电平
}
else //否则,即当前引脚输出高电平
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2); //则设置PA2引脚为低电平
}
}
2.新建h文件
参照这种格式对c文件中的函数进行声明
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
void LED1_ON(void);
void LED1_OFF(void);
void LED1_Turn(void);
void LED2_ON(void);
void LED2_OFF(void);
void LED2_Turn(void);
#endif
3.软件设置中包含头文件
4.main函数中include相应头文件
2.光敏传感器控制蜂鸣器
1.硬件接线图
DO为开关量输出,0/1
AO为模拟量输出
光敏电阻被挡住,输出1,未被挡住输出0
3.源码
LightSensor_Init.c
#include "stm32f10x.h" // Device header
/**
* 函 数:光敏传感器初始化
* 参 数:无
* 返 回 值:无
*/
void LightSensor_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
/*GPIO初始化*/
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); //将PB13引脚初始化为上拉输入
}
/**
* 函 数:获取当前光敏传感器输出的高低电平
* 参 数:无
* 返 回 值:光敏传感器输出的高低电平,范围:0/1
*/
uint8_t LightSensor_Get(void)
{
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13); //返回PB13输入寄存器的状态
}