STM32学习记录-02-GPIO通用输入输出口

news2024/11/24 15:35:10

mm

1 GPIO简介

GPIO(General Purpose Input Output)通用输入输出口

可配置为8种输入输出模式

引脚电平:0V~3.3V,部分引脚可容忍5V

输出模式下可控制端口输出高低电平,用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等

输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等

2 GPIO基本结构

左边为APB2外设总线,每个GPIO外设总共有16个引脚。每个模块内包括了寄存器和驱动器,寄存器就是特殊的存储器,内核通过APB2总线对寄存器进行读写,寄存器每一位对应一个引脚。因为STM32都是32位的,而GPIO只有16位,所以只能表示低十六位。驱动器增加信号驱动能力,寄存器只负责存储数据

3 GPIO位结构

左边三个寄存器,中间为驱动器,右边为某一个IO引脚,上面输入下面输出

输入部分:右边的IO引脚接两个保护二极管对输入电压进行限幅,产生的电流直接流入VDD/流出VSS而不会流入内部电路,避免过高电压。若电压在0-3.3V之间则两个二极管不会导通。然后连接了上拉和下拉电阻,可以通过程序配置,避免输入数据不确定。上拉默认高电平,下拉默认低电平,阻值较大,为弱上拉/下拉,尽量不影响正常的输入操作。

施密特触发器对输入电压进行整形(如果输入电压大于某一阈值则输出为高电平,小于则输出低电平),整形后直接写入输入数据寄存器。模拟输入连接到ADC,接在触发器前;复用功能输入连接到其他需要读取端口的外设上,接收数字量

输出部分:输出数据寄存器和片上外设的复用功能输出通过数据选择器接到输出控制部分。如果选择输出数据寄存器,就是IO口输出。位设置/清除寄存器用来单独操作输出数据寄存器的某一位。输出控制后接到两个MOS管,是一种电子开关,有三种输出方式(推挽、开漏、关闭)(推挽模式P_MOS、N_MOS均有效,高低电平有较强驱动能力;开漏输出P_MOS无效,只有低电平有驱动能力;关闭则两个MOS都无效,引脚配置为输入模式)

4 GPIO模式

4.1 浮空/上拉/下拉输入

都可以读取端口高低电平,而浮空不固定。浮空模式时一定要接上连续驱动源不能悬空。

输入时输出寄存器开关断开,输入寄存器可选上拉下拉或悬空,通过施密特触发器就能输入

4.2 模拟输入

输出断开,施密特触发器关闭无效,从引脚直接接上片上外设,ADC常用

4.3 开漏/推挽输出

开漏输出为高阻态没有驱动能力,推挽输出高低电平都有驱动能力。

输出由输出数据寄存器控制,P-MOS无效为开漏输出,P-MOS和N-MOS都有效为推挽输出。输出模式下输入模式也有效

4.4 复用开漏/推挽输出

复用输出由片上外设控制,引脚控制权转移到片上外设。输入部分外设可以读取引脚电平,普通输入也有效

5 操作GPIO三步骤

(1)使用RCC开启GPIO时钟

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

(2)使用GPIO_Init函数初始化GPIO

        与初始化GPIO有关库函数:

        GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO类型

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //工作模式

                GPIO_Mode_AIN 模拟输入,GPIO_Mode_IN_FLOATING 浮空输入,

                GPIO_Mode_IPD 下拉输入,GPIO_Mode_IPU 上拉输入,

                GPIO_Mode_Out_OD 开漏输出,GPIO_Mode_Out_PP 推挽输出,

                GPIO_Mode_AF_OD 复用开漏,GPIO_Mode_AF_PP 复用推挽

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //选择引脚

        GPIO_InitStructure.GPIO_Speed = //输出速度

        GPIO_Init(GPIOA, &GPIO_InitStructure);

(3)使用输出或输入的函数控制GPIO口

        与GPIO有关库函数:

        void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //把指定端口设为高电平

        void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //把指定端口设为低电平

        void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal); //根据第三个参数的值设置指定端口

        void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal); //PortVal可以同时对16个端口进行写入

        void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//锁定GPIO配置

6 GPIO读取

与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);//读取整个输出数据寄存器

二极管/蜂鸣器硬件电路

二极管:上方低电平驱动,下方高电平驱动

蜂鸣器:三极管驱动减少STM32负担。上方为PNP三极管,左边为基极,带箭头为发射极,剩下的是集电极,基极给低电平三极管导通,给蜂鸣器提供电流。下方为NPN三极管,左边为基极,带箭头为发射极,剩下的是集电极,基极给高电平导通低电平断开。最好不要隔开基极和发射极,两边之间需要开启电压。

传感器模块介绍

传感器模块:传感器元件(光敏电阻/热敏电阻/红外接收管等)的电阻会随外界模拟量的变化而变化,通过与定值电阻分压即可得到模拟电压输出,再通过电压比较器进行二值化即可得到数字电压输出

图三:N1代表传感器元件所代表的可变电阻,R1是和N1进行分压的定值电阻,C2为滤波电容,给中间的电压输出进行滤波,滤出干扰保证电路稳定。N1阻值变小时下拉作用增强,AO端电压拉低,极端情况下N1阻值为0,AO输出完全下拉输出0V。当N1变大下拉作用减弱,中间引脚由于R1上拉作用电压升高,极端情况下N1阻值无穷大相当于断路,AO输出完全拉高输出VCC。

图一:LM393为电压比较器芯片,可用作数字输出,对AO二值化。电容为电路的滤波电容

图二:电阻为电位器

图四:LED1为电源指示灯,LED2为DO输出指示灯,低电平点亮,R5上拉电阻默认输出高电平

常用上面两种接法

图一:按键按下时PA0直接下拉到GND,PA0口电压为低电平。松手时PA0悬空,引脚电压不稳定,此时必须要求PA0是上拉输入模式(此时引脚悬空则为高电平)

图二:按键松手时自动接高电平,按下为低电平,此时不会产生按键悬空

图三:PA0需配置成下拉输入

图四:PA0需要配置成下拉输入模式或浮空输入模式

图五:传感器模块电路,DO数字输出接引脚,AO模拟输出

程序源码

LED.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引脚为低电平
	}
}
Delay.c
#include "stm32f10x.h"

/**
  * @brief  微秒级延时
  * @param  xus 延时时长,范围:0~233015
  * @retval 无
  */
void Delay_us(uint32_t xus)
{
	SysTick->LOAD = 72 * xus;				//设置定时器重装值
	SysTick->VAL = 0x00;					//清空当前计数值
	SysTick->CTRL = 0x00000005;				//设置时钟源为HCLK,启动定时器
	while(!(SysTick->CTRL & 0x00010000));	//等待计数到0
	SysTick->CTRL = 0x00000004;				//关闭定时器
}

/**
  * @brief  毫秒级延时
  * @param  xms 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_ms(uint32_t xms)
{
	while(xms--)
	{
		Delay_us(1000);
	}
}
 
/**
  * @brief  秒级延时
  * @param  xs 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_s(uint32_t xs)
{
	while(xs--)
	{
		Delay_ms(1000);
	}
} 
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
}
main.c 
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"

uint8_t KeyNum;		//定义用于接收按键键码的变量

int main(void)
{
	/*模块初始化*/
	LED_Init();		//LED初始化
	Key_Init();		//按键初始化
	
	while (1)
	{
		KeyNum = Key_GetNum();		//获取按键键码
		
		if (KeyNum == 1)			//按键1按下
		{
			LED1_Turn();			//LED1翻转
		}
		
		if (KeyNum == 2)			//按键2按下
		{
			LED2_Turn();			//LED2翻转
		}
	}
}

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

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

相关文章

揭秘GPT-5,探索未来人工智能的无限可能

引言 在过去的几年里,人工智能领域的快速发展引发了全球范围内的广泛关注和讨论。作为这一浪潮的先锋,OpenAI 推出的 GPT 系列模型已经成为了生成式人工智能的代名词。随着 GPT-4 的发布,它在各种任务中表现出的强大能力进一步巩固了其在行业…

精通推荐算法27:行为序列建模之BST— 代码实现

1 引言 上文 精通推荐算法26:行为序列建模之BST— Transformer建模用户行为序列-CSDN博客 讲解了BST的背景和模型结构,本文给出其代码实现,供大家参考。 2 BST核心代码 Transformer已经成为了算法工程师的必备技能,因此这一节给…

文档在线翻译软件推荐哪些?亲测好用的文档翻译器分享

处暑已至,秋风送爽,正是学习交流的好时节。想象一下,在翻阅外文文献或是与国际友人交流时,如果能有一款便捷的文档翻译软件免费版在手,是不是能让学习之路更加畅通无阻呢? 为了方便大家能够有更高效的学习…

UltraISO刻录Ubuntu镜像制作安装U盘

使用UltraISO 软件来刻录Ubuntu镜像启动盘: 首先下载UltraISO软件,然后点击试用,使用RAW的方式刻录就行!!!

【java】RuoYi-Vue前后端分离版本-登陆请求流程解析

【java】RuoYiBootstrap多模块版本-登陆请求流程解析 这里它用到了一个安全管理框架Spring Security 你可以通过这篇文章《Spring Security 详解》 去了解它,怎么使用 登陆请求流程逻辑图 Created with Raphal 2.3.0 (1)开始 (2&a…

基于yolov5猫狗检测

项目简介 该项目使用YOLOv5深度学习框架来检测图像或视频中的猫和狗。YOLOv5(You Only Look Once v5)是一种高效的物体检测模型,能够快速准确地识别出图像中的目标。本项目具有以下特点: 图像检测:用户可以通过上传图…

Nginx-企业高性能web服务器 超长完整版!只有你想不到 没有你学不到的满满干货!!

Web服务基础介绍 Web 服务器访问流程 按下回车时浏览器根据输入的 URL 地址发送请求报文给服务器。服务器接收到请求报文,会对请求报文进行处理。服务器将处理完的结果通过响应报文返回给浏览器。浏览器解析服务器返回的结果,将结果显示出来。 1. 输入…

苹果手机视频误删怎么恢复?看完拍手叫好的4个方法

试想一下,当你在翻看苹果手机相册的视频,正沉浸在过往的美好回忆中时,手指一不小心触碰到了屏幕上的删除按钮,手机上的视频就这样消失了……面对这样的意外情况,苹果手机视频误删怎么恢复呢?别急&#xff0…

Nuxt学习_基础知识(一)

文章学习来源,nuxt中文网 1. 安装nuxt 指令 npx create-nuxt-app t_nuxt或yarn create nuxt-app f_nuxt 执行指令后按需选择添加自己所需要的相关依赖,若安装出现报错等问题 清除npm、yarn缓存 npm cache clean --force yarn cache clean切换安装命令切…

NSIS - 创建桌面应用程序(Client-Side, CS 或者称为本地应用程序)的安装包

B站视频 C# winform Costura.Fody将多个dll打包生成一个可执行的exe文件中_哔哩哔哩_bilibili 博客 NSIS打包教程 Wnform程序打包-罗分明网络博客 补充:(以下面代码为例) ; 该脚本使用 HM VNISEdit 脚本编辑器向导产生; 安装程序初始定义常量 !define PRODUCT_NAME "sql…

9个超强查找下载化学学科文献的数据库 建议收藏

一、CAS(美国化学文摘社)数据库 CAS SciFinder Discovery Platform 是由全球科学信息引领者CAS(美国化学文摘社)出品的新一代的权威科学研究工具,是化学及相关学科智能研究平台,提供全球全面、可靠的化学及…

图片转PDF?小case!这几步操作,让你秒变职场小旋风

嘿,大家在忙碌的工作里,经常得处理一堆文件和照片,尤其是当你想把一堆照片弄成一个PDF文件时,这事儿就显得特别重要。不管是为了做报告、提项目建议还是整理日常工作资料,把照片转成PDF格式,都能让我们工作…

知识付费小程序引领线上直播

亲爱的朋友们,欢迎来到“探索未知领域,知识付费小程序引领知识新探索”线上直播课程! 在这个信息爆炸的时代,知识的获取从未如此便捷,但高质量、有深度的知识却仍需我们精心筛选。本次直播课程,将聚焦于知识…

conda切换32位运行环境,解决无法在64位系统中安装32位py

当前系统大部分都64位的,我的conda也是64位的,但是如果需要创建32位的py环境,会发现 conda create -n DouyinLive32 python3.7 --force创建的仍然是32位的,为此我们可以使用切换命令切换。 按一下Windows键,输入Prom…

大数据-94 Spark 集群 SQL DataFrame DataSet RDD 创建与相互转换 SparkSQL

点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…

数据资产入表,全流程实施指南!

数据成为生产要素已是社会共识,但不是所有数据都有资产价值。数据资源当中被重复使用的那部分才会资产化,具有流通中的定价,有些数据资产被专业开发变成数据产品,具有商品价值。从数据原始资源到数据产品,再到数据资产…

华为LTC流程体系的内涵(附PPT分享)

往期回顾: 企业4A架构:数字化转型的底层方法论(附TOGAF资料下载) PPT分享:数据治理的方法论、设计思路与方案(干货) 浅谈数字化转型方法论 110页PPT:xx业务流程优化(BPR&#xff…

Linux压缩和解压

目录 压缩和解压类 gzip/gunzip指令 zip/unzip指令 tar指令 压缩和解压类 gzip/gunzip指令 gzip用于压缩文件,gunzip用于解压缩文件。 解压后去掉了gz的后缀。 zip/unzip指令 ​​​​​​​ 将文件压缩后发给别人,别人再解压。 将整个文件压…

Python | Leetcode Python题解之第354题俄罗斯套娃信封问题

题目: 题解: class Solution:def maxEnvelopes(self, envelopes: List[List[int]]) -> int:if not envelopes:return 0n len(envelopes)envelopes.sort(keylambda x: (x[0], -x[1]))f [1] * nfor i in range(n):for j in range(i):if envelopes[j]…

利用srs进行视频流转发

框图如下 docker-compose.yaml如下 rtmp2rtc.conf的配置如下 就增加了 #配置如下 forward {enabled on;#开启转发backend http://192.168.0.131:6789/api/v1/forward; #有视频流数据后会调用这个接口} #回调的参数如下 Received payload: {actionon_forward, server_idvid-k2…