STM32学习之GPIO输出
·
GPIO简介
- GPIO(General Purpose Input Output)通用输入输出口
- 可配置为8种输入输出模式
- 输出模式下可控制端口输出高低电平,用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等
- 输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等
GPIO位结构
- 输入部分:
1.保护二极管:对输入电压进行限幅。如果输入电压比3.3V高,那么上方二极管导通,输入电流流入VDD而不会流入内部电路,避免过高电压对内部产生伤害;如果输入电压低于0V(相对于VSS存在负电压),那么下方二极管导通,输入电流从VSS流出,不会从内部电路汲取电流。
2.上拉电阻、下拉电阻:如果上面电阻导通,下面电阻断开,上拉输入模式;如果下面电阻导通,上面电阻断开,下拉输入模式;如果两个都断开,浮空输入模式。
作用:给输入提供一个默认的输入电平。上拉默认为高电平,下拉默认为低电平。
3.施密特触发器(图中翻译错误):对输入电压进行整形。如果输入电压大于某一阈值,输出瞬间升为高电平;如果输入电压小于某一阈值,输出瞬间降为低电平。 - 输出部分
1.数字部分可以由输出数据寄存器或片上外设控制。如果选择通过输出数据寄存器控制,就是普通的IO口输出,写输出数据寄存器的某一位就可以操作对应的某个端口。因为输出数据寄存器同时控制16个端口,并且只能整体读写,所以想单独控制其中某一个端口不影响其他端口的话就需要一些特殊的操作方式,第一种方式是先读出然后用按位与和按位或的方式更改某一位,最后将更改后的数据写回去,在C语言中就是&=和|=的操作,效率低,不适合IO口的操作;第二种方式是通过设置位设置/清除寄存器,要实现对某一位进行置1操作,在位设置/清除寄存器对应位置写1即可,剩下不需要操作的位写0,这样的话就会有电路自动的将输出数据寄存器中对应位置1,而剩下其他写0的位保持不变;第三种方式读写SMT32中“位带”区域。
2.P-MOS、N_MOS:MOS管是一种电子开关,信号来控制开关的导通和关闭,开关负责将IO口接到VDD或者VSS。可以选择推挽、开漏和关闭三种输出方式,在推挽输出模式下, P-MOS和N_MOS均有效,数据寄存器为1,则上管导通,下管关闭,输出直接接到VDD,输出高电平,数据寄存器为0,则上管关闭,下管导通,输出直接接到VSS,输出低电平,这种模式下,高低电平均有较强的驱动能力,所以推挽模式又被称为强推输出模式,STM32对IO口具有绝对的控制权,高低电平都是由STM32说了算;在开漏输出模式下,P-MOS是无效的,只有N_MOS在工作,数据寄存器为1,下管关闭,这时输出相当于断开,也就是高阻模式,数据寄存器为0,下管导通,输出直接接到VSS,输出低电平,这种模式下只有低电平由驱动能力,可以作为通信协议的驱动模式,比如I2C通信的引脚,在多机通信的情况下,这种模式可以避免各个设备相互干扰;在关闭模式下, P-MOS和N_MOS均无效,端口的电平由外部信号来控制。GPIO模式

Keil5 MDK新建工程
基于库函数的方式使用ST官方提供封装好的函数,调用函数间接配置寄存器来开发STM32。
- 建立工程文件夹,Keil中新建工程,选择型号
打开keil5软件,Project—New uVision Project—在STM32文件夹里新建项目文件夹—打开项目文件夹—建project项目—保存—选型号–小助手(关掉)–创建完成
STM32命名规则:
- 工程文件夹里建立Start、Library、User等文件夹,复制固件库里面的文件到工程文件

startup_stm32f10x_系列是STM32的启动文件;
stm32f10x.h是STM32的外设寄存器描述文件,用来描述STM32包含的寄存器和对应的地址;
system_stm32f10x文件是用来配置时钟;
core_cm3内核的寄存器描述;
库函数的源文件,misc是内核的库函数,其他的是外设库函数。
stm32f10x_conf(configuration)文件是用来配置库函数头文件包含关系的;
stm32f10x_it(interrupt)文件是用来存放中断函数的; - 工程里对应建立Start、Library、User等同名称的分组,然后将文件夹内的文件添加到工程分组里



- 工程选项,C/C++,Include Paths内声明所有包含头文件的文件夹

- 工程选项,C/C++,Define内定义USE_STDPERIPH_DRIVER

- 工程选项,Debug,下拉列表选择对应调试器,Settings,Flash Download里勾选Reset and Run


LED闪烁
LED:发光二极管,正向通电点亮,反向通电不亮

接线图:

#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_Mode = GPIO_Mode_Out_OD;//开漏输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//GPIOA外设0号引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//GPIO初始化
//GPIO_ResetBits(GPIOA, GPIO_Pin_0); //配置低电平
//GPIO_SetBits(GPIOA, GPIO_Pin_0);//配置高电平
//GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
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);//点亮LED
// Delay_ms(500);
// GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);//熄灭LED
// Delay_ms(500);
}
}
- LED流水灯
接线图:

#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_All;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//GPIO初始化
while(1)
{
GPIO_Write(GPIOA, ~0x0001); //0000 0000 0000 0001
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0002); //0000 0000 0000 0010
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0004); //0000 0000 0000 0100
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0008); //0000 0000 0000 1000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0010); //0000 0000 0001 0000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0020); //0000 0000 0010 0000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0040); //0000 0000 0100 0000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0080); //0000 0000 1000 0000
Delay_ms(500);
}
}
蜂鸣器
有源蜂鸣器:内部自带振荡源,将正负极接上直流电压即可持续发声,频率固定
无源蜂鸣器:内部不带振荡源,需要控制器提供振荡脉冲才可发声,调整提供振荡脉冲的频率,可发出不同频率的声音

接线图:

#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
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);//GPIO初始化
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);
}
}
- 按键
按键按下导通,松手断开,由于按键内部使用的是机械式弹簧片来进行通断的,所以在按下和松手的瞬间会伴随有一连串的抖动,可以设置延时来过滤。 - 传感器
光敏电阻传感器、热敏电阻传感器、对射式红外传感器、反射式红外传感器
传感器元件(光敏电阻/热敏电阻/红外接收管等)的电阻会随外界模拟量的变化而变化,通过与定值电阻分压即可得到模拟电压输出,再通过电压比较器进行二值化即可得到数字电压输出。



按键控制LED
接线图:

//LED.c文件
#include "stm32f10x.h" // Device header
#define LED_1 1
#define LED_2 2
#define LED_ON 1
#define LED_OFF 0
//LED初始化函数
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);
}
//void LED1_ON(void)
//{
// GPIO_ResetBits(GPIOA, GPIO_Pin_1);
//}
//void LED1_OFF(void)
//{
// GPIO_SetBits(GPIOA, GPIO_Pin_1);
//}
//void LED2_ON(void)
//{
// GPIO_ResetBits(GPIOA, GPIO_Pin_2);
//}
//void LED2_OFF(void)
//{
// GPIO_SetBits(GPIOA, GPIO_Pin_2);
//}
/*
LED控制点亮/熄灭函数
led:控制具体的LED灯
state:控制LED的状态
*/
void LED_Control(uint8_t led, uint8_t state)
{
switch (led)
{
case LED_1:
if (state == LED_ON)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
else if (state == LED_OFF)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
break;
case LED_2:
if (state == LED_ON)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}
else if (state == LED_OFF)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2);
}
break;
default:
break;
}
}
//void LED1_Turn(void)
//{
// if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1)==0)
// {
// GPIO_SetBits(GPIOA, GPIO_Pin_1);
// }
// else
// {
// GPIO_ResetBits(GPIOA, GPIO_Pin_1);
// }
//}
//void LED2_Turn(void)
//{
// if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_2)==0)
// {
// GPIO_SetBits(GPIOA, GPIO_Pin_2);
// }
// else
// {
// GPIO_ResetBits(GPIOA, GPIO_Pin_2);
// }
//}
//LED切换函数
void LED_Toggle(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
if (GPIO_ReadOutputDataBit(GPIOx, GPIO_Pin) == 0)
{
GPIO_SetBits(GPIOx, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOx, GPIO_Pin);
}
}
//LED.h文件
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
void LED_Control(uint8_t led, uint8_t state);
void LED_Toggle(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
#endif
//KEY.c文件
#include "stm32f10x.h" // Device header
#include "Delay.h"
//按键初始化函数
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);
}
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;
}
//KEY.h文件
#ifndef __KEY_H
#define __KEY_H
void KEY_Init(void);
uint8_t KEY_GetNum(void);
#endif
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
uint8_t KeyNum;
int main(void)
{
LED_Init();
KEY_Init();
while(1)
{
KeyNum = KEY_GetNum();
if(KeyNum == 1)
{
LED_Toggle(GPIOA, GPIO_Pin_1);
}
else if(KeyNum == 2)
{
LED_Toggle(GPIOA, GPIO_Pin_2);
}
}
}
光敏传感器控制蜂鸣器
接线图:

//LightSensor.c文件
#include "stm32f10x.h" // Device header
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);
}
uint8_t LightSensor_Get(void)
{
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
}
//LightSensor.h文件
#ifndef __LIGHT_SENSOR_H
#define __LIGHT_SENSOR_H
void LightSensor_Init(void);
uint8_t LightSensor_Get(void);
#endif
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "BUzzer.h"
#include "LightSensor.h"
uint8_t KeyNum;
int main(void)
{
BUZZER_Init();
LightSensor_Init();
while(1)
{
if(LightSensor_Get() == 1)
{
BUZZER_Control(1);
}
else
{
BUZZER_Control(0);
}
}
}
「智能机器人开发者大赛」官方平台,致力于为开发者和参赛选手提供赛事技术指导、行业标准解读及团队实战案例解析;聚焦智能机器人开发全栈技术闭环,助力开发者攻克技术瓶颈,促进软硬件集成、场景应用及商业化落地的深度研讨。 加入智能机器人开发者社区iRobot Developer,与全球极客并肩突破技术边界,定义机器人开发的未来范式!
更多推荐



所有评论(0)