当前位置: 首页 > article >正文

GPIO输入及两个应用案例

GPIO输入及两个应用案例

文章目录

  • GPIO输入及两个应用案例
    • 1.关键字与c语言的差异
    • 2.常用的四个GPIO库函数
    • 3.按键控制LED
      • 3.1接线图
      • 3.2分类存放(硬件代码)
      • 3.4代码实现
        • 3.4.1主函数(main的实现)
        • 3.4.2LED函数实现(开/关,状态转换)
          • 函数的定义(LED.c)
          • 函数的声明(LED.h)
        • 3.4.3开关函数实现(检测按键状态)
          • 开关函数的定义(key.c)
          • 开关函数声明(key.h)
        • 3.4.4头文件的拓展部分
    • 4.光敏传感器控制蜂鸣器
      • 4.1接线图
      • 4.2代码实现
        • 4.2.1主函数的实现(main.c)
        • 4.2.2蜂鸣器模块的定义(Buzzer.c)
        • 4.2.3蜂鸣器的声明(Buzzer.h)
        • 4.2.4光敏传感器的定义(LightSensor.c)
        • 4.2.5光敏传感器部分的声明(LightSensor.h)
    • 5.总结GPIO的使用方法

1.关键字与c语言的差异

关键字位数表示范围stdint****关键字ST****关键字
char8-128 ~ 127int8_ts8
unsigned char80 ~ 255uint8_tu8
short16-32768 ~ 32767int16_ts16
unsigned short160 ~ 65535uint16_tu16
int32-2147483648 ~ 2147483647int32_ts32
unsigned int320 ~ 4294967295uint32_tu32
long32-2147483648 ~ 2147483647
unsigned long320 ~ 4294967295
long long64-(2^64)/2 ~ (2^64)/2-1int64_t
unsigned long long640 ~ (2^64)-1uint64_t
float32-3.4e38 ~ 3.4e38
double64-1.7e308 ~ 1.7e308

关键字部分表示C语言时的名称,stdint表示现在库函数里面的名称,st关键字表示以前库函数的名称都是一个意思。

现在的库函数依然支持以前库函数的写法,因为内部有重新声明(为了兼容老版本)

2.常用的四个GPIO库函数

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
  1. uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);用来读取输入数据寄存器某一个端口的输入值。他的参数是GPIOxGPIO_Pin,用来指定某一个端口,返回值是uint8_t指的是高低电平。
  2. uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);比上一个函数少了个bit,是用来读取整个输入数据寄存器的,参数只有一个GPIOx来指定外设,返回值是一个uint16_t,是一个16位的数据,每一位代表一个端口值。
  3. uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);用来读取输出数据寄存器的某一个位。所以原则上说,它不是用来读取端口的输入数据的,一般用于输出模式下,用来看自己到底输出了什么。
  4. uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);比上一个函数少了个bit,是用来读取整个输出寄存器

3.按键控制LED

本实验任务:实现,按键PB1控PA1的亮灭,按键PB11控制PA2的亮灭

3.1接线图

3.1接线图

3.2分类存放(硬件代码)

这里我们开始分层管理所以新建一个Hardware用来存放硬件

新建硬件库

在hardware处新建c文件

.c的文件中插入stm32的头文件

.h的头文件中加入下列代码以防止重复定义

#ifndef __LED_H//判断是否重复定义if not define
#define __LED_H//如果没有重复就定义


#endif//结束,对应开头的判断

3.4代码实现

3.4.1主函数(main的实现)
#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){
			//LED1_on();
			LED1_turn();
		}
		if(KeyNum == 2){
			//LED1_off();
			LED2_turn();
		}
		
	}
}

3.4.2LED函数实现(开/关,状态转换)
函数的定义(LED.c)
#include "stm32f10x.h"                  // Device header

//该.c文件用于定义函数
//定义LED初始化函数
void LED_Init(void){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//定义一个结构体
	GPIO_InitTypeDef GPIO_Structure;
	GPIO_Structure.GPIO_Mode = GPIO_Mode_Out_PP;
	//打开0口和1口
	GPIO_Structure.GPIO_Pin = GPIO_Pin_1 |GPIO_Pin_2;
	GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_Structure);
	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);
}
//LED1取反操作
void LED1_turn(void){
	//读取当前LED的输出状态
	if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1)==0){
		GPIO_SetBits(GPIOA,GPIO_Pin_1);
	}else{
		GPIO_ResetBits(GPIOA,GPIO_Pin_1);
	}
}
//LED2取反操作
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.h)
#ifndef __LED_H
#define __LED_H
//该.h文件用于函数的声明

void LED_Init(void);
void LED1_on(void);
void LED1_off(void);
void LED2_on(void);
void LED2_off(void);
void LED1_turn(void);
void LED2_turn(void);
#endif

3.4.3开关函数实现(检测按键状态)
开关函数的定义(key.c)
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

//初始化按键
void Key_Init(void){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	GPIO_InitTypeDef GPIO_Structure;
	//这里需要读取按键所以使用GPIO_Pin_IPU(上拉输入)
	GPIO_Structure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Structure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	//输入模式下这个参数其实是没用的
	GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_Structure);
}

//获取按键的信息(按键的检测)
uint8_t Key_getNum(void){
	uint8_t KeyNum = 0;
	//读取到0则表示按键按下
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0){
		//延时消除抖动
		Delay_ms(20);
		//按键一般是松手之后才会有动作的,等于0就表示一直按着
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0){
			Delay_ms(20);
			KeyNum = 1;
		}
	}
	//判断Pin11的状态
		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

3.4.4头文件的拓展部分

#ifndef __KEY_H,#define __KEY_H,#endif宏保护的解释

  • #ifndef __KEY_H:这是一个预处理器指令,用于检查是否尚未定义宏 __KEY_Hifndef 是 “if not defined” 的缩写。如果 __KEY_H 尚未被定义,那么预处理器将继续处理后续的代码。
  • #define __KEY_H:如果 __KEY_H 尚未被定义,那么这条指令将定义 __KEY_H 宏。这样做的目的是防止头文件被重复包含。如果没有这种保护机制,可能会导致重复定义错误。
  • #endif:结束 #ifndef 条件判断。
  • 上述用于防止头文件的重复包含,而 __KEY_H 的具体名称可以根据自己的项目需要进行修改,但要保证唯一性和遵循一定的命名规则

4.光敏传感器控制蜂鸣器

光敏传感器:遮住光线输出指示灯灭,代表输出高电平松手时输出指示灯亮,代表输出低电平(光敏传感器的电位器可以调节高低电平的判断阈值,可以自行调节)

本实验任务:遮住光敏传感器,蜂鸣器鸣叫;未遮住光敏传感器,蜂鸣器不鸣叫。

4.1接线图

传感器控制蜂鸣器接线图

4.2代码实现

4.2.1主函数的实现(main.c)
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Buzzer.h"
#include "LightSensor.h"


int main(void){
	//初始化蜂鸣器
	Buzzer_Init();
	//初始化传感器
	LightSensor_Init();
	
	while(1){
		//光线不好蜂鸣器叫
		if(LightSensor_Get()==1){
			Buzzer_on();
		}else{
			Buzzer_off();
		}
		
		//测试蜂鸣器模块
		/*Buzzer_on();
		Delay_ms(500);
		Buzzer_off();
		Delay_ms(500);
		Buzzer_turn();
		Delay_ms(500);
		Buzzer_turn();
		Delay_ms(500);*/
	}
}

4.2.2蜂鸣器模块的定义(Buzzer.c)
#include "stm32f10x.h"                  // Device header

//初始化蜂鸣器
void Buzzer_Init(void){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	//定义一个结构体
	GPIO_InitTypeDef GPIO_Structure;
	GPIO_Structure.GPIO_Mode = GPIO_Mode_Out_PP;
	//打开0口和1口
	GPIO_Structure.GPIO_Pin = GPIO_Pin_12;
	GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_Structure);
	GPIO_SetBits(GPIOB,GPIO_Pin_12);
}
//蜂鸣
void Buzzer_on(void){
	GPIO_ResetBits(GPIOB,GPIO_Pin_12);
}
//蜂不鸣
void Buzzer_off(void){
	GPIO_SetBits(GPIOB,GPIO_Pin_12);
}

//对换蜂鸣器状态
void Buzzer_turn(void){
	
	if(GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_12)==0){
		GPIO_SetBits(GPIOB,GPIO_Pin_12);
	}else{
		GPIO_ResetBits(GPIOA,GPIO_Pin_12);
	}
}

4.2.3蜂鸣器的声明(Buzzer.h)
#ifndef __BUZZER_H
#define __BUZZER_H

//蜂鸣器初始化
void Buzzer_Init(void);
//蜂鸣器低电平
void Buzzer_on(void);
//蜂鸣器高电平
void Buzzer_off(void);

//蜂鸣器取反操作
void Buzzer_turn(void);
#endif

4.2.4光敏传感器的定义(LightSensor.c)
#include "stm32f10x.h"                  // Device header

void LightSensor_Init(void){
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	//定义一个结构体
	GPIO_InitTypeDef GPIO_Structure;
	//可以选择上拉输入,也可以选择浮空输入(如果始终接在端口上),只要保证引脚不会悬空即可
	GPIO_Structure.GPIO_Mode = GPIO_Mode_IPU;
	//打开0口和1口
	GPIO_Structure.GPIO_Pin = GPIO_Pin_13;
	GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_Structure);
	GPIO_SetBits(GPIOB,GPIO_Pin_13);
}

uint8_t	LightSensor_Get(void){
	//直接获取传感器的输入数据
	return GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13);
}

4.2.5光敏传感器部分的声明(LightSensor.h)
#ifndef __LIGHT_SENSOR_H
#define __LIGHT_SENSOR_H

//传感器初始化
void LightSensor_Init(void);
//传感器输入的返回数据(高/低电平)
uint8_t	LightSensor_Get(void);

#endif

5.总结GPIO的使用方法

  1. 首先,初始化时钟,定义结构体,赋值结构体(mode(模式有8种),Pin(可通过逻辑或”|“来多选),Speed要求不高(50MHz就好)),最后使用GPIO_Init来初始化GPIO外设.

  2. 读取输入输出主要使用前面讲过的(GPIO输入和GPIO输出笔记)8个输入输出函数来实现

  3. **模块化设计。**外围硬件较多就要把每个硬件的驱动函数分别分装起来(.c和.h)用于简化主函数的逻辑


http://www.kler.cn/a/473041.html

相关文章:

  • 网络安全-web渗透环境搭建-BWAPP(基础篇)
  • 【vue3封装element-plus的反馈组件el-drawer、el-dialog】
  • flutter 独立开发之笔记
  • 腾讯云AI代码助手编程挑战赛——智能音乐推荐系统
  • vue2日历组件
  • 二、模型训练与优化(1):构建并训练模型
  • 『SQLite』解释执行(Explain)
  • benchANT 性能榜单技术解读 Part 1:写入吞吐
  • 金融租赁系统助力行业转型与升级的创新之路
  • 生成模型:变分自编码器-VAE
  • 产品经理-商业模式构建 - AxureMost
  • SparkStreaming集群调优
  • H2数据库在单元测试中的应用
  • 实时数仓:Apache Iceberg 的表管理与实时数仓架构设计
  • [读书日志]从零开始学习Chisel 第八篇:Scala的集合(敏捷硬件开发语言Chisel与数字系统设计)
  • MySQL error [Warning] InnoDB: Table mysql/innodb_index_stats has length
  • win32汇编环境,怎么进行乘法运算的
  • (一)使用 WebGL 绘制一个简单的点和原理解析
  • 《计算机视觉解锁图像理解密码:编程实现图片场景文字描述生成》
  • Ungoogled Chromium127 编译指南 MacOS篇(七)- 安装依赖包
  • 【郑大主办、ACM出版、EI稳定检索】第四届密码学、网络安全与通信技术国际会议 (CNSCT 2025)
  • 瑞芯微rk3568平台 openwrt系统适配ffmpeg硬件解码(rkmpp)
  • spring cloud alibaba-dubbo3 rpc运行原理
  • 最新版Edge浏览器加载ActiveX控件之Adobe PDF阅读器控件
  • 【MySQL高可用】什么时候分库、分表?怎样进行分库分表?
  • 网络安全 | 网络安全的未来趋势