stm32入门——GPIO输入输出(1)基础理解

news2024/9/27 9:07:20

          最近比较想上进,又不知道要干什么,就来水几篇博客欺骗一下自己。

        GPIO全称是:General Purpose Input / Output ,是stm32用于控制输入和输出信号的通用接口。我们用的MCU都有这玩意,比如STM32F103C8T6上有 GPIOA,GPIOB,GPIOC,这些ABC等,把GPIO分成了不同的组,每组端口为0~15,一般不同的芯片,分组也不一样。              

        这里我们主要学习GPIO的输入,输出,还有有些时候的引脚复用,因而对不同芯片的引脚排布不做过多的讨论。我们将通过几个例程来学习IO口的输入,输出,最后做出一个超级简单的小项目。

        在介绍GPIO的输入输出之前,我想我有必要去再介绍一下GPIO的8种工作模式。这八种工作模式分为输入和输出,其中输入的模式有4种,分别是:上拉输入,下拉输入,浮空输入,模拟输入。对应的,我们同样有4种输出模式,分别叫: 推挽输出,开漏输出,和复用推挽输出和复用开漏输出。其中具体的结构,我在我的另一篇博客:      stm32——详解GPIO的8种模式,不会你打我_学习stm32的gpio口控制-CSDN博客

中写的很详细,在这里不在过多描述,我这里只告诉你这玩意在标准库里的英文是什么,怎么在简单的项目中去玩,然后一般我们怎么去用,更深的理解需要你在日后的工作和学习中去积累。

其实说句实话,使用一个GPIO的模式,其实就是配置这条路上的各种寄存器,按道理来说配置寄存器应该是很麻烦的,你要翻着手册一页一页去看,一位一位的去写寄存器。但是我们用的是库函数啊,这玩意已经把配置每个寄存器的过程写好了,我们这里要做的不是去纠结为什么要这样配置,我们要学会的是如何运用这些函数。至于底层的东西,也需要你以后去理解。

下面我们开始介绍GPIO相关的函数。 

首先,有关GPIO的文件,在stm32的标准库里,在“stm32f10x_gpio.c”和“stm32f10x_gpio.h”里。

那么我们在标准库里,是如何去定义配置GPIO的? 

其实就是用的一个函数,这个函数是

GPIO_Init(GPIO_TypeDef *  GPIOx   ,  GPIO_InitTypeDef * GPIO_InitStruct) 

这个函数有两个参数,第一个是需要初始化的GPIO组,我们可以选择GPIOA,GPIOB,GPIOC,等,说白了就是你要用的引脚属于的那个GPIO的组,比如我要用GPIOA的第2个引脚,那么就要初始化GPIOA。第二个参数是一个结构体指针,结构体的类型是 GPIO_InitTypeDef,他会用这个结构体里的参数去配置GPIO。其实说了这么多就一句话——就是第一个参数选择GPIO,第二个参数配置GPIO。下面我们来看这个结构体里的东西是什么我们可以找到这个结构体的定义,如图:

 其实结构体里就三个成员,GPIO_Pin ,GPIO_Mode, GPIO_Speed

下面我们一个一个来说:

GPIO_Pin 就是选择引脚,你用哪个引脚就选择哪个:

其实就是从这一大堆里去选择。 

这个GPIO_Mode,就是上边我说的GPIO的8种工作模式。这里需要你根据你做的工程去选择这个模式。 就是从这个枚举里去选择一个。

GPIO_Speed指的是输出频率,这个玩意我们一般没有特别要求,我们一般用50MHZ 

其实说到这里, GPIO_Init(GPIO_TypeDef *  GPIOx   ,  GPIO_InitTypeDef * GPIO_InitStruct) 这个函数就讲完了,具体怎么写呢,我们可以在Keil里去看看

#include "stm32f10x.h"                  // 这个是stm32的头文件

首先我们要写头文件 

然后我们可以定义一个结构体

GPIO_InitTypeDef GPIO_InitStructure; //这里定义这个结构体为GPIO_InitStructure

在c语言里我们可以用‘.’引出结构体成员 

       

我们配置这个结构体,假定我用的GPIOA的第一个引脚,输入方式为上拉输入,频率给一个50MHz,此时我们应该进行对应的配置:

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //配置为上拉输入;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //配置选择端口
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置频率

当我们结构体配置好以后,就要去调用GPIO_Init()函数对IO口进行配置: 

GPIO_Init(GPIOA,&GPIO_InitStructure);//调用GPIO_Init函数

        到这里,我们的GPIO在理论上就初始化完成了,但是我们这里忽略了一步很重要的东西,就是开启时钟。这是因为STM32的外设和模块需要时钟信号才能正常工作。STM32的内部资源是由时钟控制的,默认情况下,为了节约能量,很多外设的时钟是关闭的。如果时钟没有开启,相应的外设将不会接收到时钟信号,无法进行初始化和工作。那我们开启时钟的又要用到一个函数,是 

RCC_APB2PeriphResetCmd(),这玩意就是开启我们GPIOA时钟的,由于这个函数涉及到另一个部分RCC,在这里不多说,如果需要了解这玩意,可以去看看这俩玩意

我这里就直接说明如何去开启时钟:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使用RCC开启GPIOA的时钟

那么我们把它综合起来,就得到了一个GPIOA初始化的代码

#include "stm32f10x.h"       // Device header

int main(void)
{	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使用RCC开启GPIOA的时钟
	GPIO_InitTypeDef GPIO_InitStructure; //这里定义这个结构体为GPIO_InitStructure
	/*用.可以引出结构体的成员*/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //配置为上拉输入;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //配置选择端口
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置频率
	
	GPIO_Init(GPIOA,&GPIO_InitStructure);//调用GPIO_Init函数
}

 下面我们就可以进行GPIO的读和写的操作,stm32中完成GPIO的读和写的函数有好几个,这里为了减少篇幅,我只提供一个读和写的,其余的可以去文件里看,或者去看stm32公司提供的固件库

我们通过两个小实验去完成,第一个就是 GPIO输出,我们用蜂鸣器去完成,现在要满足一个小项目,输出一个高电平,让蜂鸣器响

接线图大概能看懂哈 

下边给出函数GPIO _SetBits

GPIO_SetBits(GPIOA,GPIO_Pin_1);//将GPIOA的PA1设置为高电平

这样我们把整个代码给出来

#include "stm32f10x.h"                  // Device header

int main(void)
{	
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使用RCC开启GPIOA的时钟
	GPIO_InitTypeDef GPIO_InitStructure; //这里定义这个结构体为GPIO_InitStructure
	/*用.可以引出结构体的成员*/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //配置为上拉输入;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //配置选择端口
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置频率
	
	GPIO_Init(GPIOA,&GPIO_InitStructure);//调用GPIO_Init函数
	
	while(1)
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_1);//将GPIOA的PA1设置为高电平 
	}
}

while(1)这个循环,目的就是让其中的命令持续执行。·这里我的蜂鸣器是高电平响 ,编译下载后确实蜂鸣器响了 。而且实现很简单,就是我们初始化好GPIO后,直接让这个引脚输出高电平。

其实IO口输入也是同样的操作,不过就是换个函数罢了。很简单,把写的函数换成读的函数就行了,聪明的你肯定知道要怎么去改,其实就是把GPIO_SetBits(GPIOA,GPIO_Pin_1);换成一个

GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1);就可以了,这些就你自己发挥一下聪明才智就行了。

然后我们在这里提一嘴GPIO的复用 

stm32是不是引脚不是很多,但是作用很多,看这个图就可以知道为什么要复用哈,让有限数量的引脚实现更多的外设和功能。stm32的每个IO口都对应很多功能,一般情况下我们都将其作为IO口进行输入输出(其实只做输入输出用在项目中不常用)。但是有时候我会遇到引脚用的很满,或者要用某个引脚的特殊功能,如定时器,串口等,都要引脚复用,今天这里就不多说了,有感觉直接去看手册。

        今天就到这里吧,下一篇博客就水一个单纯用GPIO输入和输出做的一个简易的烟雾报警器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2169530.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法葫芦书(笔试面试)

一、特征工程 1.特征归一化:所有特征统一到一个区间内 线性函数归一化(0到1区间)、零均值归一化(均值0,标准差1) 2.类比型特征->数值性特征 序号编码、独热编码、二进制编码(010&#xf…

prd文档编写(to b)

如何编写产品需求文档(PRD) | 人人都是产品经理 (woshipm.com) 一.prd文档编写得目的 PRD文档最为重要的目的就是:协调各个相关角色 PRD就是提高效率的,把各个角色的共识全部写出来,大家都已PRD为最终的工作指导文档…

2:数据结构:列表与元组

目录 2.1 列表的创建与操作 2.1.1 列表的创建 2.1.2 列表的常用操作 2.1.3 列表切片操作 2.2 元组的特点与用法 2.2.1 元组的创建 2.2.2 元组与列表的区别 2.2.3 元组的常用操作 2.3 示例代码与练习 2.3.1 示例代码:列表与元组的基本操作 2.3.2 练习题 文…

ICM20948 DMP代码详解(46)

接前一篇文章:ICM20948 DMP代码详解(45) 上一回讲到了inv_icm20948_setup_compass_akm函数中的以下代码片段: /* Set compass in power down through I2C SLV for compass */result inv_icm20948_execute_write_secondary(s, COM…

网口为什么叫RJ45接口,名字的由来?

大家有没有注意到很多地方“网口”都被称作“RJ45”接口。但是,您是否曾经好奇过,这个小小的插孔为何被称为“RJ-45”?这个名字背后又有着怎样的故事呢? RJ-45的全称与定义 首先,我们需要了解“RJ-45”的全称是“Regi…

jetlinks物联网平台学习3:mqtt协议及物模型

mqtt协议及物模型 1、创建产品2、配备设备接入方式3、上传消息协议4、填写网关信息5、配置mqtt认证信息6、配置物模型7、创建设备8、使用MQTT X模拟设备接入9、mqttx实现设备->平台 平台->设备 消息发送9.1、属性上报9.2、获取最新属性值(读取属性&#xff09…

EEPROM手册笔记

目录 一、特征描述二、功能描述三、总线特性四、设备寻址五、写入操作1.字节写入2.页写入 六、读取操作1.当前地址读取2.随机读取3.顺序读取 一、特征描述 1.Microchip Technology Inc. 24AA04/24LC04B (24XX04*) 是一款 4 Kbit 电气可擦除 PROM。该器件…

ChatDev:基于对话的多智能体协同软件开发框架

相关代码资源见文末 论文地址:ChatDev: Communicative Agents for Software Development - ACL Anthologyhttps://aclanthology.org/2024.acl-long.810/ 1. 概述 1.1. 当前的挑战 软件开发是一个复杂且多层次的过程,要求具备不同技能的团队成员之间密切合作。例如,架构师…

老人跌倒扶不扶?涪城三职工给出响亮答案

一、关键时刻的选择 于绵阳市三江湖湿地公园,平凡午后,三名环卫人员刘后刚、严荣礼及杨树坤正紧张作业。突闻呼救声,一位老人在石阶上跌倒需援手。在紧急关头,他们果断抛却工具,疾速赶至老人身边。此举不仅展现了他们…

了解网络的相关信息

文章目录 前言了解网络的相关信息1. ip是什么?1.1. 公网IP:1.2. 私有IP:1.2.1. 示例 2. 子网掩码3. 子网掩码的划分网段是什么4. 特殊的回路IP网段(127.0.0.1)5. 端口 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊&#x…

学习C++的第七天!

1.虚函数是在基类中用 virtual 关键字声明的函数,可以在派生类中被重写。纯虚函数是在虚函数的基础上,在基类中被初始化为 0 的函数,含有纯虚函数的类是抽象类,不能被实例化。 2.如果基类的析构函数不是虚函数,当通过…

(done TODO:从频谱到时域要考虑负频波和余弦波?) 傅里叶变换知识补充

参考:https://www.bilibili.com/video/BV1rC4y1E7FD/?vd_source7a1a0bc74158c6993c7355c5490fc600 sinx 和 sin2x sin3x 等整数倍频率的正弦波都是正交的 cosx 和 cos2x cos3x 等整数倍频率的余弦波都是正交的 这成为三角函数系的正交性 up主从分解出来的波恢复成…

buuctf [ACTF2020 新生赛]Include

学习笔记。 开启靶机。 进入靶场: 我们跟进 tips瞅瞅: 额,纯小白,能想到的就是先F12看看,在CTRLu、以及抓包。 得,不会了,看wp呗,不会死磕没脑子0,0? 参考:…

解决 Adobe 盗版弹窗

在这个文件夹下删除 Adobe CCXProcess 然后重装。 Adobe Premiere Pro 2024 (v24.6.1) Multilingual :: Варез от m0nkrusa [Warez by m0nkrus] (monkrus.ws) Adobe Photoshop 2024 (v25.12) Multilingual :: Варез от m0nkrusa [Warez by m0nkrus] (monkrus.…

FastAPI 第五课 -- 基本路由

目录 一. 前言 二. 根路径路由 三. 路径参数 四. 启动应用和测试路由 一. 前言 在 FastAPI 中,基本路由是定义 API 端点的关键。每个路由都映射到应用程序中的一个函数,用于处理特定的 HTTP 请求,并返回相应的响应。 二. 根路径路由 创…

矩阵求逆的几种方法

1. 定义 对于矩阵的运算中定义了加减法、乘法(包含数乘)但未定义矩阵除法,可以简单认为矩阵的逆即为矩阵除法。矩阵求逆是线性代数中的一个重要概念,在很多应用领域都有广泛的应用。对于一个给定的方阵 ( A ),如果存在…

全志A133开发板安卓系统调试串口复用成普通串口方法-触觉智能EVB1309

本文介绍了在开发板/主板串口接口不够的情况下,可将调试串口改为普通串口使用,下面为大家分享修改方法。基于触觉智能EVB1309开发板演示,搭载全志A133芯片,具有高性能超低功耗优势,待机功耗低至15mW。 1、内核配置 源…

FortiGate 无线组网

无线管理与配置 FortiAP 连接 internal 接口之后自动获得 ip 地址:192.168.1.xxx/24在 FortiGate 中创建 SSIDFortiGate 自动发现 FortiAP,将 FortiAP 添加到 FortiGate将 SSID 和 FortiAP 关联创建防火墙策略 下面我们就来一起看看在 FortiGate 中该如…

【HTTP 和 HTTPS详解】3

HTTP 状态代码 HTTP 状态代码是服务器发送给客户端的三位数字,用于指示客户端请求的结果。它们分为五类:信息性(100-199)、成功(200-299)、重定向(300-399)、客户端错误&#xff08…

【java笔记】 5 接口使用举例

// 导入Swing库中的消息对话框组件 import javax.swing.*; // 定义一个Circle类,该类实现了ShapeInterface接口 public class Circle implements ShapeInterface { // 定义一个私有变量radius来保存圆的半径 private double radius; // 默认构造函数,初…