STM32GPIO输入和输出

news2024/11/22 18:40:59

一、先看IO端口位的结构

上面部分是输入,下面是输出。

1、I/O输入:

首先,从I/O引脚开始,有两个保护二极管,主要作用是对输入电压限幅,保护内部电路。上面二极管接VDD为3.3V,下面二极管接VSS为0V。当输入电压为超过3.3V,则会导通上面的二极管;当输入电压小于0V也就是负电压,则会导通下面的二极管;如果输入电压为0~3.3V,则二极管不会导通,会正常输入。

接着,来到上拉电阻和下拉电阻。上拉电阻接的VDD,下拉电阻接的VSS,开/关是可以通过程序配置的。如果上面导通,下面断开,就是上拉输入模式;如果下面导通,上面断开,就是下拉输入模式;如果上面和下面都断开,则为浮空输入模式上拉和下拉的作用为了给输入提供一个默认的输入电平。如果什么都不接,输入为浮空模式,输入的电平就很容易受到干扰。这里的阻值都是很大的,是一种弱上拉和弱下拉,目的是尽量不影响正常的输入操作。

接着,来到TTL肖特基触发器,实际上这个是施密特触发器,这里翻译错误。这个施密特触发器的作用是对输入电压进行整形的。它的执行逻辑是:如果输入电压大于某一阈值,输出就会瞬间升为高电平;如果输入电压小于某一阈值,输出就会瞬间降为低电平;这样可以有效地避免因信号波动造成的输出抖动现象。如下图,输入的电压不稳定,有两个阈值,高于高阈值或小于高阈值且大于低阈值都为高电平;低于低阈值或大于低阈值且小于高阈值都为低电平。

接着,经过施密特整形的波形就可直接写入数据寄存器中了,就可以直接读取高低电平了。

接着,至片上外设是连接外设的,其中有模拟输入,连接到ADC上的,因为ADC需要接收模拟量,所以是连接到施密特触发电路前面的。另一个是复用功能输入,是连接到其他需要读取端口的外设上,比如串口的输入引脚等,这根线接收的是数字量,所以在施密特触发器后面。

2、I/O输出:

首先,数字部分可以由输出数据寄存器或片上外设控制。如果选择输出数据寄存器进行控制,就是普通的IO口输出,写这个寄存器的某一位就可以操作对应的某个端口;

位设置/清除寄存器可以用来单独操作输出数据寄存器的某一位,而不影响其他位在C语言中就是&=和|=,则在stm32中电路设置好了,只需要配置就行。如果我们要对某一位进行置1的操作(类似于|=),在位设置寄存器的对应位写1即可,剩下不需要操作的位写0,这样它内部就会有电路,自动将输出数据寄存器中对应位置为1,而剩下写0的位则保持不变;如果我们要对某一位进行置0的操作(类似于&=),在位设置寄存器的对应位写0即可,剩下不需要操作的位写1。

接着,通过输出控制,来到两个MOS管,上面为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,也就是输出低电平。作用:可以作为通信协议的驱动方式。另外开漏模式还可以用于输出5V的电平信号,但必须要有上拉电阻的配合,因为本身是不能输出高电平,比如在IIC总线中。

剩下一个状态就是关闭,这个是当引脚配置为输入模式的时候,两个MOS管都无效,也就是输出关闭,端口的电平由外部信号控制。一个端口只有一个输出,但可以由多个输入。

二、GPIO模式

端口可以配置成8个模式,如下:

三、枚举类型

关键字枚举:enum

用途:定义一个取值受限制的整形变量,用于限制变量取值范围;宏定义的集合,里面的值也可以被其他类型引用。其实枚举本质也就是宏定义
定义枚举变量:
enum{FALSE =0,TRUE=1} EnumName;
引用枚举成员:
        EnumName =FALSE;
        EnumName =TRUE;//限制了EnumName;

由于名字过长,一般用typedef进行取个名字。

typedef enum{

FALSE =0,

TRUE=1

}week_t;

然后用week_t定义枚举类型。在32中直接写具体值时必须强转化为枚举类型。
 

四、GPIO输出点亮LED

利用A端0口即PA0,首先配置时钟使能,GPIO初始化。

注意:PA15、PB3、PB4是调试端口,别选,如果当作普通端口,还需要配置。

用到的函数:

    GPIO_InitTypeDef GPIO_InitStruct;                     //写在最前面
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  //使能
	//GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;         //推挽输出
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_OD;     //开漏输出,没有高电平驱动那个能力
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0 ;           //PC13口
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;    //选择50HZ就可以了
	GPIO_Init(GPIOA,&GPIO_InitStruct);              //GPIO初始化

输出函数:

将GPIO某端某口即某一位引脚设置为高电平

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
或
//BitAction BitVal参数为:
// Bit_SET: to set the port pin
GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal)

 将GPIO某端某口即某一位引脚设置为低电平

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
或
//BitAction BitVal参数为:
//Bit_RESET: to clear the port pin
GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal)

 延时函数:

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);
	}
} 

delay.h

#ifndef __DELAY_H   //防止头文件重复包含
#define __DELAY_H

void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);

#endif

main.c

#include  "stm32f10x.h"                  // Device header
#include  "Delay.h"
int main(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  //使能
	//GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;         //推挽输出
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_OD;     //开漏输出,没有高电平驱动那个能力
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0 ;           
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;    //选择50HZ就可以了
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	
	while(1) 
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_0);               //设置为高电平
		Delay_ms(500);
	   GPIO_ResetBits(GPIOA,GPIO_Pin_0);            //设置为低电平
		Delay_ms(500);
		
		GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET); 
		Delay_ms(500);
		GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
		Delay_ms(500);
		
		GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)1);  //也可以直接写数,但必须转为枚举类型BitAction
		Delay_ms(500);
		GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)0);
		Delay_ms(500);
	}
	
}

五、LED流水灯

使用的是GPIOA端0~7引脚作为流水灯的输出引脚。

可以利用如下函数,可直接向GPIO端口写入值,也就是多位数据。

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal)

main.c:

#include  "stm32f10x.h"                  // Device header
#include  "Delay.h"
int main(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;     //推挽输出
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_All;           //PA所有引脚
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;    //选择50HZ就可以了
	GPIO_Init(GPIOA,&GPIO_InitStruct);

	
	while(1) 
	{

		GPIO_Write(GPIOA,~0x0001); //0000 0000 0000 0001,写入值
		Delay_ms(100);
		GPIO_Write(GPIOA,~0x0002); //0000 0000 0000 0010
		Delay_ms(100);
		GPIO_Write(GPIOA,~0x0004); //0000 0000 0000 0100
		Delay_ms(100);
		GPIO_Write(GPIOA,~0x0008); //0000 0000 0000 1000
		Delay_ms(100);
		GPIO_Write(GPIOA,~0x0010); //0000 0000 0001 0000
		Delay_ms(100);
		GPIO_Write(GPIOA,~0x0020); //0000 0000 0010 0000
		Delay_ms(100);
		GPIO_Write(GPIOA,~0x0040); //0000 0000 0100 0000
		Delay_ms(100);
		GPIO_Write(GPIOA,~0x0080); //0000 0000 1000 0000
		Delay_ms(100);
	}
	
}

六、让蜂鸣器响起来

这里蜂鸣器用的有源的,自带振荡源,只需给蜂鸣器一个高电平或低电平即可。我用的蜂鸣器是高电平驱动的。

main.c,代码如下:使用的是B12引脚。

#include  "stm32f10x.h"                  // Device header
#include  "Delay.h"
int main(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;     //推挽输出
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12;          
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;    //选择50HZ就可以了
	GPIO_Init(GPIOB,&GPIO_InitStruct);

	
	while(1) 
	{

		GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_SET); 
		Delay_ms(100);
		GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_RESET); 
		Delay_ms(100);
		GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_SET); 
		Delay_ms(100);
		GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_RESET); 
		Delay_ms(700);
	
	}
	
}

七、光敏传感器控制蜂鸣器

光敏传感器使用的是DO引脚输出,只输出0和1。原理是利用的电阻分压。光暗DO输出1,光强DO输出1。DO与B13引脚相连接。

首先,利用分模块文件进行编写程序,代码便于管理和移植。

蜂鸣器代码:

Buzzer.c"

#include "stm32f10x.h"                  // Device header


void Buzzer_Init(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);	
   
   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);	
    
}

void Buzzer_ON(void)        //响
{
  GPIO_SetBits(GPIOB,GPIO_Pin_12);
}

void Buzzer_OFF(void)       //不响
{
  GPIO_ResetBits(GPIOB,GPIO_Pin_12);
}

Buzzer.h

#ifndef _BUZZER_H
#define _BUZZER_H

void Buzzer_Init(void);

void Buzzer_ON(void);

void Buzzer_OFF(void);


#endif

光敏传感器:

LightSernsor.c:

#include "stm32f10x.h"                  // Device header
#include  "Delay.h"


void LightSensor_Init(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   //RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);	
   
   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_GetNum(void)
{
	uint8_t LightSensorNum=0;
	
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)==0)   //光暗DO输出1,光强DO输出0
	{
		
		LightSensorNum=1; 
	}
	
	return LightSensorNum;
}

LightSernsor.h:

#ifndef _LIGHTSENSOR_H
#define _LIGHTSENSOR_H


void LightSensor_Init(void);

uint8_t LightSensor_GetNum(void);


#endif

main.c:

#include  "stm32f10x.h"                  // Device header
#include  "Delay.h"
#include  "Buzzer.h"
#include  "LightSensor.h"

uint8_t LightSensorNum=0;

int main(void)
{
	
	Buzzer_Init();
	LightSensor_Init();
	while(1) 
	{
		LightSensorNum=LightSensor_GetNum();
		if(LightSensorNum==1)   //光强,使蜂鸣器响
		{
			Buzzer_ON();
		}
	   else
		{
			Buzzer_OFF();
		}
		
		

	}
	
}

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

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

相关文章

认知杂谈71《创业抉择:定制化与标准化的权衡之路》

内容摘要: *嘿,彦祖们!今天来聊聊创业的事,创业选产品类型很关键。定制化产品如魔法,贴合客户需求但成本高且有边际递减风险。要掌握物联网技术,用 3D 建模软件,参考特定书籍,参加展…

在线JSON可视化工具--支持缩放

先前文章提到的超好用的JSON可视化工具,收到反馈,觉得工具好用,唯一不足就是不能缩放视图,其实是支持的,因为滚轮有可能是往下滚动,会与缩放冲突,所以这个工具设计为需要双击视图来触发打开缩放…

C++ 线性表、内存操作、 迭代器,数据与算法分离。

线性表: 线性表是最基本、最简单、也是最常用的一种数据结构。线性表(linear list)是数据结构的 一种,一个线性表是n个具有相同特性的数据元素的有限序列。 线性表中数据元素之间的关系是一对一的关系,即除了第一个和…

Ubuntu2404安装

Ubuntu是一款非常优秀的发行版本,起初她的优势主要在于桌面版,但是随着Centos 从服务版的支持的退出,Ubuntu server也在迅猛的成长,并且不断收获了用户,拥有了一大批忠实的粉丝。好了,废话不多说&#xff0…

基于SSM的出租车租赁管理系统的设计与实现

文未可获取一份本项目的java源码和数据库参考。 1 选题的背景 现代社会,许多个人、家庭,因为生活、工作方式的改变,对汽车不再希望长期拥有,取而代之的是希望汽车能“召之即…

CSS 实现楼梯与小球动画

CSS 实现楼梯与小球动画 效果展示 CSS 知识点 CSS动画使用transform属性使用 页面整体布局 <div class"window"><div class"stair"><span style"--i: 1"></span><span style"--i: 2"></span>…

Flask-3

文章目录 ORMFlask-SQLAlchemySQLAlchemy中的session对象数据库连接设置常用的SQLAlchemy字段类型常用的SQLAlchemy列约束选项 数据库基本操作模型类定义 数据表操作创建和删除表 数据操作基本查询SQLAlchemy常用的查询过滤器SQLAlchemy常用的查询结果方法多条件查询分页器聚合…

Rstudio:强大的R语言集成开发环境(IDE)

Rstudio 应该是 R 语言使用的标配&#xff0c;尽管 Rstudio 的母公司 Posit 推出了新一代的集成开发环境 Positron&#xff0c;但其还处于开发阶段。作为用户不妨让其成熟后再使用&#xff0c;现阶段还是 Rstudio 更稳定。 如果你在生物信息学或统计学领域工作&#xff0c;R语言…

C初阶(六)--- static 来喽

前言&#xff1a;C语言中有许多关键字&#xff08;关键字是预先保留的标识符&#xff0c;具有特殊意义&#xff0c;不能用作变量 名、函数名等普通标识符。&#xff09; 比如&#xff1a;前面在变量与常量那一节提到的extern 就是一个关键字&#xff0c;应该还记得e…

开源项目 - 交通工具检测 yolo v3 物体检测 单车检测 车辆检测 飞机检测 火车检测 船只检测

开源项目 - 交通工具检测 yolo v3 物体检测 单车检测 车辆检测 飞机检测 火车检测 船只检测 开源项目地址&#xff1a;https://gitcode.net/EricLee/yolo_v3 示例&#xff1a;

点云补全 学习笔记

目录 Depth completion with convolutions and vision transformers 依赖项&#xff1a; DCNv2 softpoolnet Depth completion with convolutions and vision transformers Zhang, Y., Guo, X., Poggi, M., Zhu, Z., Huang, G., Mattoccia, S.: Completionformer: Depth co…

JS进阶 3——深入面向对象、原型

JS 进阶3——深入面向对象、原型 1.编程思想 面向过程&#xff1a;分析出解决问题的过程&#xff0c;然后用函数将这些步骤一步步封装起来面向对象&#xff1a;将事物分为一个个对象&#xff0c;然后对象之间分工合作 2.构造函数&#xff1a;封装性、面向对象 构造函数方法存…

Python画笔案例-074 绘制轮子走了

1、绘制轮子走了 通过 python 的turtle 库绘制 轮子走了,如下图: 2、实现代码 绘制轮子走了,以下为实现代码: """轮子走了.py """ import time import turtle def draw_polygon(number,length):

Spark读取MySQL优化方案辩证

0、背景 上篇文章《Spark 任务需要的内存跟哪些因素有关》验证 Spark 任务需要的内存&#xff0c;跟单个 partition 的数据量大小&#xff0c;以及数据计算逻辑复杂度有关。但是之中有个最大的特点&#xff0c;就是把 MySQL 作为数据源的时候&#xff0c;无论数据量多大&#…

【C++】set容器和map容器的基本使用

一、序列式容器和关联式容器 1、STL中的部分容器如&#xff1a;string、vector、list、deque、array、forward_list等&#xff0c;这些容器统称为序列式容器&#xff0c;因为逻辑结构为线性序列的数据结构&#xff0c;两个位置存储的值之间一般没有紧密的关联关系&#xff0c;…

数据结构双向链表和循环链表

目录 一、循环链表二、双向链表三、循环双向链表 一、循环链表 循环链表就是首尾相接的的链表&#xff0c;就是尾节点的指针域指向头节点使整个链表形成一个循环&#xff0c;这就弥补了以前单链表无法在后面某个节点找到前面的节点&#xff0c;可以从任意一个节点找到目标节点…

Leetcode 540. 有序数组中的单一元素

1.题目基本信息 1.1.题目描述 给你一个仅由整数组成的有序数组&#xff0c;其中每个元素都会出现两次&#xff0c;唯有一个数只会出现一次。 请你找出并返回只出现一次的那个数。 你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。 1.2.题目地址 https:…

大语言模型入门(二)——提示词

一、什么是提示词 大语言模型&#xff08;LLM&#xff09;的提示词&#xff08;Prompt&#xff09;是与模型交互的关键&#xff0c;它影响着模型的输出结果。提示词&#xff08;Prompt&#xff09;和提示工程&#xff08;Prompt Engineering&#xff09;密切相关。什么又是提示…

详解代理服务器及Squid

一、 代理服务器简介 &#xff08;1&#xff09;什么是代理服务器 代理服务器英文全称为ProxyServer&#xff0c;其主要功能代理网络用户获取网络信息&#xff0c;起到内网和Internet的桥梁作用。 在TCP/IP网络中&#xff0c;传统的通信过程是这样的&#xff1a;客户端向服务…

ROS2 22.04 Carttographer安装

安装环境&#xff1a; Ubuntu22.04 ros2 humble # 下载源文件 git clone https://github.com/ros2/cartographer.git -b ros2 git clone https://github.com/ros2/cartographer_ros.git -b ros2# 使用小鱼一键配置rosdep wget http://fishros.com/install -O fishros &&am…