STM32 学习笔记_4 GPIO:LED,蜂鸣器,按键,传感器的使用

news2024/11/16 8:50:37

GPIO 通用 IO

General Purpose Input Output.

可配置为8种输入输出模式。通常0~3.3V,部分引脚允许 5V。

image-20230419020637994

上面的虚线方框是输入模块,下面的是输出模块。

推挽输出是1输出高电平,0输出低电平。开漏输出正好相反,因此没有高电平驱动能力。开漏输出通常用于一些通信协议,如 I2C 的引脚,这样各个引脚之间不会互相干扰。

模式名称性质特征
浮空输入数字输入可读取引脚电平,若引脚悬空,则电平不确定
上拉输入数字输入可读取引脚电平,内部连接上拉电阻,悬空时默认高电平
下拉输入数字输入可读取引脚电平,内部连接下拉电阻,悬空时默认低电平
模拟输入模拟输入GPIO无效,引脚直接接入内部ADC
开漏输出数字输出可输出引脚电平,高电平为高阻态,低电平接VSS
推挽输出数字输出可输出引脚电平,高电平接VDD,低电平接VSS
复用开漏输出数字输出由片上外设控制,高电平为高阻态,低电平接VSS
复用推挽输出数字输出由片上外设控制,高电平接VDD,低电平接VSS

三种输入区别就是浮空输入引脚悬空的时候电平不确定(因此尽量接一个连续的驱动源),而上下拉输入就会设置为默认高低电平。

image-20230419144107702

如图,输出部分被断开了。输入部分接上 VDD 开关就是下拉,接上 VSS 就是上拉。

模拟输入用不到图里的任何器件,输入信号直接接入 ADC 模块。

开漏输出和推挽输出就在于高电平是高阻态还是 VDD。

复用输出就是又可以读取,又可以接到外设。

image-20230419145406005

上半部分可见,输入信号经过触发器处理后给两个出口输出了。

代码:驱动LED灯

操纵 GPIO 口驱动点亮LED灯。

首先建好项目模板:

image-20230420024857375

控制gpio需要三个步骤:开启rcc时钟,初始化,输入输出函数控制。根据架构图我们可知,GPIO 在 APB2 总线上。我们看看 RCC 里面有什么函数:

image-20230420025053559

这个是控制 APB2 时钟的,我们看一下其内容:

image-20230420025148413

参数1是要操作的 APB2 口,参数2是启动或禁用。挺简单的。

然后再看一下 GPIO 初始化函数:

image-20230420025345860

第一个参数选口,第二个参数是一个GPIO_InitTypeDef 结构体。我们知道要对其设置三个变量:输入输出模式,pin 脚,速度。

image-20230420040211907

最后一个是输入输出函数控制,这个主要介绍 GPIO 四个函数:SetBits ResetBits WriteBit Write

我们让 GPIOA Pin0 输出高或低电平,LED 另一个脚接在 GND 或 3.3 上。

image-20230420143426678
#include "stm32f10x.h"
int main(void){
    /* 控制gpio需要三个步骤:开启rcc时钟,初始化,输入输出函数控制 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_SetBits(GPIOA,GPIO_Pin_0);
    while(1){}
}

reset 置为0,我们的电路设计是0亮,因此 reset 亮,set 灭。

也可以通过 write 函数写。GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);

进而可以借助江协科技老师提供的 delay 函数做出led灯闪烁的效果:

while(1){
        GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
        Delay_ms(500);
        GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
        Delay_ms(500);
    }

其实 Bit_SET 就是1,RESET 就是0,但是我们不能直接给函数赋值0或1,要加一个类型转化。

while(1){
        GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)1);
        Delay_ms(500);
        GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)0);
        Delay_ms(500);
    }

这里因为我们用的是推挽输出,所以高低电平都有驱动能力。如果改成开漏输出,高电平就没有驱动能力了。开漏输出就不能让 LED 一端接地,一端接输出,因为高电平驱动不了。只能一端接 3.3,一端接 输出。

所以大多数时候推挽输出更方便,开漏输出应用场景不多。

然后我们试一下流水灯。这个就是多个 led 灯接在pin01234567上,while里轮流点亮即可。没啥好说的,就是一个地方:初始化的时候,可以这么写:

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;

同时初始化多个。这么做的原理是这些引脚对应值是 0000 0001, 0000 0010, 0000 0100, 0000 1000……可以或运算。

类似的,我们也可以用 write 函数替代 writebit 函数:

GPIO_WriteBit(GPIOA,~00000010); 只点亮第二位,pin1。

代码:蜂鸣器

这里使用的蜂鸣器比51简单,不用不停反转,给电就响。但是调不了频率。

蜂鸣器上面提示3个引脚,GND,VCC,IO。IO 我们随便挑一个引脚输入(不要挑 JTAG 要用的三个引脚!A15 B3 B4)

GPIO_ResetBits(GPIOB, GPIO_Pin_12);

代码:按键

按键是机械弹簧结构, 按下松开会有 5-10ms 抖动。

按键可以有四种处理方式:接低电平(上拉输入),接高电平(下拉输入,不常见),以及加上上下拉电阻。
image-20230421025011700

这次的项目我们新建一个 HardWare 文件夹,里面添加一些模块化函数。比如这次我们要写的按键用例是两个按键独立控制两个 LED 灯,那么 LED.c 代码:

#include "stm32f10x.h"                  // Device header

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_0 | GPIO_Pin_1;//两个灯泡接在 A0 A1上
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
}

void LED1_On(void){
    GPIO_ResetBits(GPIOA, GPIO_Pin_0);
}

void LED1_Off(void){
    GPIO_SetBits(GPIOA, GPIO_Pin_0);
}

void LED2_On(void){
    GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}

void LED2_Off(void){
    GPIO_SetBits(GPIOA, GPIO_Pin_1);
}

并且补充响应 .h 文件。

当然可以定义一个 LED_Set 函数,传入两个参数决定点亮哪几个灯。

或者其实一个就行了,传入 11 10 01 00 代表灯的状态。

对按键输入的处理:首先初始化 GPIOB 用于读取按键输入,模式设置为上拉输入

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_0 | GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//其实输入模式下这个参数没用
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

对于输入数据如何处理?参考 GPIO.h 里面的文件:

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

后两个是读取输入端口,看看自己输出了什么东西。

我们读取按键输入,就是读取输入模式下的某一位。

简单的按键点亮 LED 只需要第一个函数读取一下即可,记得消抖。

uint8_t Key_GetNum(void){
    uint8_t KeyNum=0;//按下按键时=1
    if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0)==0){
        Delay_ms(20);
        while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0)==0);
        Delay_ms(20);
        KeyNum+=1;
    }
    if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10)==0){
        Delay_ms(20);
        while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10)==0);
        Delay_ms(20);
        KeyNum+=2;
    }
    return KeyNum;
}

这里我用二进制来判断两个按键按下方式。

int main(void){
    LED_Init();
    Key_Init();
    LED1_Off();
    LED2_Off();
    uint8_t KeyNum;
    while(1){
        KeyNum=Key_GetNum();
        if(KeyNum>0){
            if(KeyNum%2==1)LED1_On();
            if(KeyNum>=2)LED2_On();
        }
    }
}

这个只是一个测试代码,跑起来的效果就是按下按键后 LED 永久点亮。

如何让按下按键后 LED 反转状态呢?这时候我们就可以用到输入里介绍的读取当前输出了。我们不再使用 LED_On 和 Off,而是使用 Turn。

void LED1_Turn(void){
	if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0)==1)GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    else GPIO_SetBits(GPIOA, GPIO_Pin_0);
}

void LED2_Turn(void){
    if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1)==1)GPIO_ResetBits(GPIOA, GPIO_Pin_1);
    else GPIO_SetBits(GPIOA, GPIO_Pin_1);
}

代码:传感器

原理:内部有一个受传感因素的值改变而变的电阻,一个定值电阻,根据分压我们可以判断当前阻值。光敏电阻,热敏电阻,红外接收管都类似。

模拟输出 AO:根据传感器电阻的值得到的模拟电压值输出。图中 N1 是传感器电阻。

可能还带有滤波电容,两端接在 VDD GND 上,控制电压稳定(左侧)。

image-20230420205300753

上下拉电阻阻值越小拉力越强。

数字输出 DO:AO 输出的调整,一个电压比较器,同向>反向输出VCC,反之输出 GND。

image-20230421024424317

其中 IN+ 是模拟输入,我们的传感器。IN- 是一个可调节的电位器。

image-20230421024607421

整体电路简化就是这样的:

image-20230421024728192

左边的是一个电源指示灯。

第二个是 DO 指示灯。

第三个是一个确保默认高电平的上拉电阻。

接下来我们写一个用例,光敏传感器控制蜂鸣器。只用 DO 即可。

代码和按键其实非常相似,DO 读取输入,给蜂鸣器输出。

int main(void){
    Buzzer_Init();
    
    while(1){
        if(LightSensor_Get()==1)Buzzer_On();
        else Buzzer_Off();
    }
}
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);
}
void Buzzer_Init(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);
}

void Buzzer_On(void){
    GPIO_ResetBits(GPIOB, GPIO_Pin_12);
}

void Buzzer_Off(void){
    GPIO_SetBits(GPIOB, GPIO_Pin_12);
}

光敏传感器是光线少的时候阻值大,读到的值赋1.可以拧电位器调节水平。

蜂鸣器和LED还都是低电平响/点亮的,所以我把蜂鸣器拔下来换个高电平接 3.3 的LED就实现了小夜灯。

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

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

相关文章

10分钟了解人工智能(最通俗的语言)

最通俗的语言:15分钟了解人工智能;唯一优点,受众完全听懂 无人驾驶、智能家居、远程医疗……如今,人工智能(AI)技术已被广泛应用于金融、交通、医疗、安防、教育等领域,成为经济增长新动能 一 什么是人工智能 人工智能…

动态规划之-不同路径 II-滚动数组_20230421

DP动态规划之-滚动数组 前言 在学习 不同路径II 的动态规划过程中,从介绍资料中了解到 滚动数组可以进一步降低动态规划解空间的复杂度,更高效利用计算机的储存空间。动态规划中的滚动数组究竟能发挥哪些作用,在常规的动态规划中&#xff0…

REDIS02_RDB概述及作用、自动触发、手动触发、优势劣势、触发场景、配置项详解

文章目录 ①. RDB概述及作用②. RDB - 自动触发③. 手动触发 - save、bgsave④. RDB - 优势体现⑤. RDB - 劣势体现⑥. 哪些情况会触发RDB快照⑦. RDB优化配置项详解 ①. RDB概述及作用 ①. RDB概述:在指定的时间间隔,执行数据集的时间点快照 实现类似照片记录效果的方式,就是…

MapReduce高级篇——全局计数器

MapReduce Counter 计数器 概念 在执行MapReduce程序的时候,控制台输出日志中通常下面片段,可以发现输出信息中的核心词是counter,中文叫做计数器 在执行MapReduce城西过程中,许多时候,用户希望了解程序的运行情况,H…

白话文讲计算机视觉-第十讲-灰度阈值分割

灰度阈值是啥意思呢?我们慢慢说。 1.灰度图 我们现在有一张彩色图,我们给它用黑白的方式变现,就形成灰度图,如图所示。 图1 那究竟怎么转换的呢?很简单,我们根据如下公式,把BGR三个通道换成一个…

【算法题解】26. 求串联子串的位置

这是一道 困难 题 来自: https://leetcode.cn/problems/substring-with-concatenation-of-all-words/ 题目 给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的…

REXROTH液压方向阀安装须知

安装规程 阀安装到系统之前,应该对照订货型号比较其型号说明。 确认阀的连接表面和底板无水分,没有油。 - 清洁: ‧ 安装元件时,确认工业阀和周围干净 ‧ 油箱须密闭,以防止外部污染 ‧ 安装之前&…

【youcans的深度学习 D02】PyTorch例程:创建 LeNet 模型进行图像分类

欢迎关注『youcans的深度学习』系列 【youcans的深度学习 D02】PyTorch例程:创建 LeNet 模型进行图像分类 1. PyTorch 深度学习建模的基本步骤2. 加载 CIFAR-10 数据集3. 定义 LeNet-5 模型类3.1 LeNet 网络3.2 LeNet-5 网络3.3 定义 LeNet-5 网络模型类3.4 构建网络…

AI大模型加速RPAxAI时代到来,谁会是RPA领域的杀手级应用?

GPT等AI大模型震撼来袭,基于RPA的超级自动化仍是最佳落地载体 对话弘玑CPO贾岿,深入了解国产RPA厂商对AI大模型的探索与实践 文/王吉伟 关于RPA已死的说法,在中国RPA元年(2019年)投资机构疯狂抢项目之时就已经有了。…

算法训练Day39:62.不同路径 63. 不同路径 II 动态规划

文章目录 不同路径题解(动态规划)数论方法 [不同路径 II](https://leetcode.cn/problems/unique-paths-ii/description/)题解 不同路径 CategoryDifficultyLikesDislikesContestSlugProblemIndexScorealgorithmsMedium (67.70%)17460--0 Tags Companies 一个机器人位于一个 …

Linux基础—网络设置

Linux基础—网络设置 一、查看网络配置1.查看网络接口信息 ifconfig2.查看主机名称 hostname3.查看路由表条目 route4.查看网络连接情况 netstat5.获取socket统计信息 ss 二、测试网络连接1.测试网络连接 ping2.跟踪数据包 traceroute3.域名解析 nslookup 三、使用网络配置命令…

拷贝构造与深浅拷贝

文章目录 一、拷贝构造函数二、拷贝初始化三、深浅拷贝 一、拷贝构造函数 如果一个构造函数的第一个参数是自身类型的引用,而且任何额外参数都有默认值,则此构造函数是拷贝构造函数。 class person { public: person(); //默认构造函数 pe…

54家备案法人信用评级机构名单

2023年4月20日,中国人民银行官网公示备案法人信用评级机构名单,共有54家机构获得了信用评级备案,并进行如下提示: 1.2019年11月26日,人民银行、发展改革委、财政部、证监会联合发布《信用评级业管理暂行办法》&#xf…

C语言之 顺序表(sequence chart)

线性表 线性表是n个具有相同特性的数据元素的有限序列。 常见的有:顺序表、链表、栈、队列、字符串.... 线性表在逻辑上是线性结构的,即一条连续的直线 但在物理结构上不一定是连续的,其在物理存储时,通常以数组和链式结构的形式…

观察者模式解读

目录 问题引进 天气预报项目需求 天气预报设计方案 1-普通方案 传统方式代码实现 观察者模式原理 观察者模式解决天气预报需求 代码实现 观察者模式的好处 问题引进 天气预报项目需求 1) 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式…

idm下载器是免费的吗?有哪些功能

对于PC用户来说,拥有一款好用和快速的下载工具,对我们来说至关重要,可以极大提高我们的工作效率和PC用户体验。IDM可以实现高速下载,其核心原理就是多线程下载,理论上可以达到带宽的峰值速度,深受用户的喜爱…

Python单向链表操作

目录 一、单向链表 单向链表示例图 二、单向链表的操作 1、判断链表是否为空 2,链表长度 3,遍历整个链表 4,在链表头部添加元素 5、链表尾部添加元素 6,在指定位置插入元素 7,修改指定位置的元素 8&#xff…

可视化Echarts中title、tooltip、legend、grid属性的常用设置

title中常用的设置 配置项--tooltip ​编辑 配置项--legend 配置项--grid title中常用的设置 title 标题组件,包含主标题和副标题。 以下是常用的对标题的设置 title:{//设置图表的标题text:"主标题",link:"baidu.com", //设置标题超链接…

详解C语言string.h中常见的14个库函数(三)

本篇博客继续讲解C语言string.h头文件中的库函数。本篇博客计划讲解3个函数,分别是:strstr, strtok, strerror。其中strstr函数我会用一种最简单的方式模拟实现。 strstr char * strstr ( const char * str1, const char * str2 );strstr可以在str1中查…

用yolov5+playwright过滑动验证码

目录 梳理思路 训练模型 编写代码 总结与提高 源码下载 在上一节,我们通过opencv-pythonplaywright成功过掉了QQ空间的滑动验证码。在本节,我们将使用yolov5playwright来实现相同效果。 注:因为yolov5的配置教程网上已经很多了&#xff…