10天学会嵌入式技术之51单片机-day-3

news2025/4/26 1:25:18

第九章  独立按键

按键的作用相当于一个开关,按下时接通(或断开),松开后断开(或接通)。实物图、原理图、封装

9.2 需求描述

通过 SW1、SW2、SW3、SW4 四个独立按键分别控制 LED1、LED2、LED3、LED4
的亮灭,具体要求是,按一下(按下并松开)SW,LED 点亮,再按一下 SW,LED 熄灭。

9.3 硬件设计


9.3.1 实现思路

为实现上述需求,需要设法令单片机感知到按键被按下,也就是说在按键被按下时,
需要向单片机发送一个信号,当单片机收到该信号后,再执行控制 LED 的逻辑即可。
由于 51 单片机的 GPIO 引脚的默认均为高电平,因此只需将按键的一侧接入单片机的
某个 GPIO 引脚,另一侧接地。这样一来,当按键按下时,引脚直接接地,就相当于向单
片机发送了一个低电平信号。

9.3.2 硬件原理图

9.4 软件设计

9.4.1 初步实现

按照原理图,SW1 按下时,P4.2 引脚会被拉低;SW2 按下时,P4.3 引脚会被拉低;
SW3 被按下时,P3.2 引脚会被拉低;SW4 按下时,P3.3 引脚会被拉低。
因此只需检测上述引脚是否变为低电平即可,若检测到变为低电平,就执行控制 LED
的逻辑。需要注意的是,按键的检测需要持续进行,所以需要不停的检查上述引脚是否变
为低电平。

9.4.2 按键单次触发

当前代码的逻辑是,只要按键处在按下的状态,就触发控制 LED 的逻辑。为实现单次
触发,可以在按键按下后,等待按键抬起,并在抬起的一刻,执行控制 LED 的逻辑。

9.4.3 按键消抖

由于按键的抖动,单片机引脚的信号切换并不像我们想象的那样干脆,实际情况如下
图所示

9.4.4 规范代码

按照前文的编码规范,我们将检测按键的代码单独抽取到 Int 层,具体代码如下。

(1)Int_Key.h
 

#ifndef __INT_KEY_H__
#define __INT_KEY_H__
#include <STC89C5xRC.H>
#include "Util.h"
/**
* @brief 检测 SW1 按键是否按下
*
* @return bit 是或否
*/
bit Int_Key_IsSW1Pressed();
/**
* @brief 检测 SW2 按键是否按下
*
* @return bit 是或否
*/
bit Int_Key_IsSW2Pressed();
/**
* @brief 检测 SW3 按键是否按下
*
* @return bit 是或否
*/
bit Int_Key_IsSW3Pressed();
/**
* @brief 检测 SW4 按键是否按下
*
* @return bit 是或否
*/
bit Int_Key_IsSW4Pressed();
#endif /* __INT_KEY_H__ */

(2)Int_Key.c

#include "Int_Key.h"
#include <STC89C5xRC.H>
#include "Com_Util.h"
#define SW1 P42
#define SW2 P43
#define SW3 P32
#define SW4 P33

bit Int_Key_IsSW1Pressed()
{
    if (SW1 == 0) {
        Com_Util_Delay1ms(10);
        if (SW1 == 0) {
            while (SW1 == 0);
            return 1;
        }
    }
    return 0;
}

bit Int_Key_IsSW2Pressed()
{
    if (SW2 == 0) {
        Com_Util_Delay1ms(10);
        if (SW2 == 0) {
            while (SW2 == 0);
            return 1;
        }
    }
    return 0;
}

bit Int_Key_IsSW3Pressed()
{
    if (SW3 == 0) {
        Com_Util_Delay1ms(10);
        if (SW3 == 0) {
            while (SW3 == 0);
            return 1;
        }
    }
    return 0;
}

bit Int_Key_IsSW4Pressed()
{
    if (SW4 == 0) {
        Com_Util_Delay1ms(10);
        if (SW4 == 0) {
            while (SW4 == 0);
            return 1;
        }
    }
    return 0;
}

(3)Main.c

#include <STC89C5xRC.H>
#include "Int_Key.h"
#define LED1 P00
#define LED2 P01
#define LED3 P02
#define LED4 P03
void main()
{
    while (1) {
        if (Int_Key_IsSW1Pressed()) {
            LED1 = ~LED1;
        }
        if (Int_Key_IsSW2Pressed()) {
            LED2 = ~LED2;
        }
        if (Int_Key_IsSW3Pressed()) {
            LED3 = ~LED3;
        }
        if (Int_Key_IsSW4Pressed()) {
            LED4 = ~LED4;
        }
    }
}

 第 10 章 矩阵按键

按下按键矩阵中的 SW5 到 SW20 按键后,数码管显示对应的按键编号。

10.2 硬件设计

10.2.1 实现思路

由于按键矩阵中共有 4x4=16 个按键,如果每个按键都接入一个 GPIO 引脚,势必会造
成引脚的浪费,为了节省引脚,我们同样可以借用动态扫描的思想,具体逻辑如下。

10.2.2 51 单片机引脚内部结构

在上面的演示中,我们应注意的一个问题是:当高电平引脚和低电平引脚短接时,结
果是高电平引脚被拉低,而不是低电平引脚被拉高。这实际上是由 51 单片机引脚的内部结
构决定的,其简化结构如下图所示。

上图的工作原理是:当端口锁存器为 0 时,mos 管导通,此时引脚直接接地,输出低
电平;当端口锁存器为 1 时,mos 管关闭,引脚靠内部的弱上拉电阻(弱的意思是电流很
微弱,可进一步理解为上拉电阻的阻值很大)拉置高电平。
根据上图,可以得出结论,当引脚输出高电平时,很容易被被外部装置拉低(因为上
拉电阻分压多),而当引脚输出低电平时,却很难被拉高(因为引脚接地)。这就是常说的
弱上拉+强下拉模式。
所以在本节矩阵按键的例子中,当我们按下按键短接高低引脚,最终结果是高电平引
脚被拉低。

10.2.3 硬件原理图

10.3 软件设计

(1)Int_DigitalTube.h 和 Int_DigitalTube.c

数码管项目中的 Int_DigitalTube.h 和 Int_DigitalTube.c 复制到当前项目的 Int 目录。

(2)Int_MatrixKey.h

在项目的 Int 目录下创建 Int_MatrixKey.h,写入以下内容。

#ifndef __INT_KEYMATRIX_H__
#define __INT_KEYMATRIX_H__
#include"Com_Util.h"

u8 Int_KetMatrix_CheckSW();

#endif /* __INT_KEYMATRIX_H__ */

(3)Int_MatrixKey.c

在项目的 Int 目录下创建 Int_MatrixKey.c,写入以下内容。

#include "Int_KeyMatrix.h"
#include<STC89C5xRC.H>

u8 Int_KetMatrix_CheckSW()
{
      u8 i,j;
      u8 lines[4]={0xFE,0xFD,0xFB,0xF7};
      u8 columns[4]={0x10,0x20,0x40,0x80};
  for (i = 0; i < 4; i++)
  {  
       P2=lines[i];
       for ( j = 0; j< 4; j++)
       {
            if((P2 & columns[j])==0)
            {
                Com_Util_Delay1ms(10);
                if((P2 & columns[j])==0)
                {
                  while((P2 & columns[j])==0);
                  return j+5+i*4;
                }
            }
       }
    }
      return 0;
}  

(4)main.c

#include"Int_KeyMatrix.h"
#include"Int_DigitalTube.h"

void main()
{
    u8 key;
    Int_DigitalTube_Init();
    while(1){
        key=Int_KetMatrix_CheckSW();  //检测按键
        if(key){
         Int_DigitalTube_DisplayNum(key);  
        }
        Int_DigitalTube_Refresh();
    }
}

 第 11 章 蜂鸣器

11.1 蜂鸣器简介

蜂鸣器是一种能够发出声音的电子元器件,常用于报警、提示和音频信号输出等场景。
其内部结构如下图所示。
当电流通过线圈时会产生电磁场,电磁场与永磁体相互作用,从而使金属膜产生震动
而发声。为使金属膜持续震动,蜂鸣器需要使用震荡电路进行驱动。有些蜂鸣器元件内部
自带震荡驱动电路,这种蜂鸣器叫做有源蜂鸣器(Active Buzzer,自激式蜂鸣器);而有些
则不带震荡驱动电路,这种蜂鸣器叫做无源蜂鸣器(Passive Buzzer,它激式蜂鸣器)。
更多信息可参考如下内容。

(1)有源蜂鸣器

(2)无源蜂鸣器

11.2 需求描述

为按键矩阵增加按键提示音,要求按键按下后,蜂鸣器响 0.1s。

11.3 硬件设计

11.3.1 硬件原理图

本课程使用的是无源蜂鸣器,所以需要从外部输入一定频率的方波,方波的频率就是
蜂鸣器发声的频率,这里我们使用 500Hz 的方波即可。

11.4 软件设计

(1)Int_DigitalTube.h 和 Int_DigitalTube.c

将数码管项目中的 Int_DigitalTube.h 和 Int_DigitalTube.c 复制到当前项目的 Int 目录。

(2)Int_MatrixKey.h 和 Int_MatrixKey.c

将按键矩阵项目中的 Int_MatrixKey.h 和 Int_MatrixKey.c 复制到当前项目的 Int 目录。

(3)Int_Buzzer.h

在 Int 目录下创建 Int_Buzzer.h,写入以下内容。

#ifndef __INT_BUZZER_H__
#define __INT_BUZZER_H__
#include <STC89C5xRC.H>
#define BUZZ P46
/**
* @brief 蜂鸣器响 0.1s
*
*/
void Int_Buzzer_Buzz();
#endif /* __INT_BUZZER_H__ */

(4)Int_Buzzer.c

在 Int 目录下创建 Int_Buzzer.c,写入以下内容。

#include "Int_Buzzer.h"
#include "Util.h"
void Int_Buzzer_Buzz()
{
    unsigned char counter = 100;
    while (counter) {
        BUZZ = ~BUZZ;
        Delay1ms(1);
        --counter;
    }
}

(5)Main.c

#include "Int_DigitalTube.h"
#include "Int_MatrixKey.h"
#include "Int_Buzzer.h"
int main()
{
    u8 key_pressed = 0;
    Int_DigitalTube_Init();
    Int_DigitalTube_DisplayNum(key_pressed);
    while (1) {
           key_pressed = Int_MatrixKey_CheckKey();
            if (key_pressed) {
                Int_DigitalTube_DisplayNum(key_pressed);
                Int_Buzzer_Buzz(); //按键提示音
             }
        Int_DigitalTube_Refresh();
    }
}

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

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

相关文章

深入解析微软MarkitDown:原理、应用与二次开发指南

一、项目背景与技术定位 微软开源的MarkitDown并非简单的又一个Markdown解析器&#xff0c;而是针对现代文档处理需求设计的工具链核心组件。该项目诞生于微软内部大规模文档系统的开发实践&#xff0c;旨在解决以下技术痛点&#xff1a; 大规模文档处理性能&#xff1a;能够高…

【PVCodeNet】《Palm Vein Recognition Network Combining Transformer and CNN》

[1]吴凯,沈文忠,贾丁丁,等.融合Transformer和CNN的手掌静脉识别网络[J].计算机工程与应用,2023,59(24):98-109. 文章目录 1、Background and Motivation2、Related Work3、Advantages / Contributions4、Method5、Experiments5.1、Datasets and Metrics5.2、Hyper-parameters5.…

x-cmd install | brows - 终端里的 GitHub Releases 浏览器,告别繁琐下载!

目录 核心功能与优势安装适用场景 还在为寻找 GitHub 项目的特定 Release 版本而苦恼吗&#xff1f;还在网页上翻来覆去地查找下载链接吗&#xff1f;现在&#xff0c;有了 brows&#xff0c;一切都将变得简单高效&#xff01; brows 是一款专为终端设计的 GitHub Releases 浏览…

多模态知识图谱:重构大模型RAG效能新边界

当前企业级RAG&#xff08;Retrieval-Augmented Generation&#xff09;系统在非结构化数据处理中面临四大核心问题&#xff1a; 数据孤岛效应&#xff1a;异构数据源&#xff08;文档/表格/图像/视频&#xff09;独立存储&#xff0c;缺乏跨模态语义关联&#xff0c;导致知识检…

实验八 版本控制

实验八 版本控制 一、实验目的 掌握Git基本命令的使用。 二、实验内容 1.理解版本控制工具的意义。 2.安装Windows和Linux下的git工具。 3.利用git bash结合常用Linux命令管理文件和目录。 4.利用git创建本地仓库并进行简单的版本控制实验。 三、主要实验步骤 1.下载并安…

JavaWeb:Web介绍

Web开篇 什么是web? Web网站工作流程 网站开发模式 Web前端开发 初识web Web标准 HtmlCss 什么是Html? 什么是CSS?

教育行业网络安全:守护学校终端安全,筑牢教育行业网络安全防线!

教育行业面临的终端安全问题日益突出&#xff0c;主要源于教育信息化进程的加速、终端设备多样化以及网络环境的开放性。 以下是教育行业终端安全面临的主要挑战&#xff1a; 1、设备类型复杂化 问题&#xff1a;教育机构使用的终端设备包括PC、服务器等&#xff0c;操作系统…

Spring Boot知识点详解

打包部署 <!‐‐ 这个插件&#xff0c;可以将应用打包成一个可执行的jar包&#xff1b;‐‐> <build><plugins> <plugin> <groupId>org.springframework.boot</groupId><artifactId>spring‐boot‐maven‐plugin</artifactId&g…

DNS主从同步及解析

DNS 域名解析原理 域名系统的层次结构 &#xff1a;DNS 采用分层树状结构&#xff0c;顶级域名&#xff08;如.com、.org、.net 等&#xff09;位于顶层&#xff0c;下面是二级域名、三级域名等。例如&#xff0c;在域名 “www.example.com” 中&#xff0c;“com” 是顶级域名…

在Windows11上用wsl配置docker register 镜像地址

一、下载软件 1、下载wsl:安装 WSL | Microsoft Learn,先按照旧版 WSL 的手动安装步骤 | Microsoft Learn的步骤走 注:如果wsl2怎么都安装不下来,可能是Hyper-V没有打开,打开控制面板->程序和功能->启用或关闭Windows功能,勾选Hyper-V 如果Windows功能里面没有Hyp…

【Linux网络】构建UDP服务器与字典翻译系统

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;博客仓库&#xff1a;https://gitee.com/JohnKingW/linux_test/tree/master/lesson &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &…

【PGCCC】Postgres 故障排除:修复重复的主键行

如何从表中删除不需要的重复行。这些重复行之所以“不需要”&#xff0c;是因为同一个值在指定为主键的列中出现多次。自从 glibc 好心地改变了排序方式后&#xff0c;我们发现这个问题有所增加。当用户升级操作系统并修改底层 glibc 库时&#xff0c;这可能会导致无效索引。 唯…

DeepSeek+Cursor+Devbox+Sealos项目实战

黑马程序员DeepSeekCursorDevboxSealos带你零代码搞定实战项目开发部署视频教程&#xff0c;基于AI完成项目的设计、开发、测试、联调、部署全流程 原视频地址视频选的项目非常基础&#xff0c;基本就是过了个web开发流程&#xff0c;但我在实际跟着操作时&#xff0c;ai依然会…

996引擎-拓展变量:物品变量

996引擎-拓展变量:物品变量 测试代码参考资料对于Lua来说,只有能保存数据库的变量才有意义。 至于临时变量,不像TXT那么束手束脚,通常使用Lua变量就能完成。 SELECT * FROM dbo.TBL_ITEM_EX_ABIL WHERE FLD_MAKEINDEX = 28620 <

【踩坑记录】stm32 jlink程序烧录不进去

最近通过Jlink给STM32烧写程序时一直报错&#xff0c;但是换一个其他工程就可以烧录&#xff0c;对比了一下jink配置&#xff0c;发现是速率选太高了“SW Device”&#xff0c;将烧录速率调整到10MHz以下就可以了

‌RISC-V低功耗MCU动态时钟门控技术详解

我来分享一下RISC-V核低功耗MCU的动态时钟门控技术实现&#xff1a; 这款MCU通过硬件级时钟门控电路实现了模块级的功耗管理。当外设&#xff08;如UART、SPI&#xff09;处于闲置状态时&#xff0c;系统会自动切断其时钟信号&#xff0c;减少无效翻转功耗。同时支持多电压域协…

工厂模式:解耦对象创建与使用的设计模式

工厂模式&#xff1a;解耦对象创建与使用的设计模式 一、模式核心&#xff1a;封装对象创建逻辑&#xff0c;客户端无需关心具体实现 在软件开发中&#xff0c;当创建对象的逻辑复杂或频繁变化时&#xff0c;直接在客户端代码中 new 对象会导致耦合度高、难以维护。例如&…

Python爬虫学习:高校数据爬取与可视化

本项目实现了从中国教育在线&#xff08;eol.cn&#xff09;的公开 API 接口爬取高校相关数据&#xff0c;并对数据进行清洗、分析与可视化展示。主要包括以下功能&#xff1a; 爬取高校基础信息及访问量数据数据清洗与格式转换多维度数据分析与可视化&#xff0c;如高校数量分…

触觉智能RK3506核心板,工业应用之RK3506 RT-Linux实时性测试

在工业自动化、机械臂控制等高实时性场景中&#xff0c;系统响应速度与稳定性直接决定设备效能。触觉智能RK3506核心板基于瑞芯微三核Cortex-A7架构深度优化&#xff0c;搭载Linux 6.1内核并支持Linux-RT实时系统&#xff0c;提供实时性能的高性价比解决方案。 RK3506与RT-Linu…

基于SpringBoot的高校体育馆场地预约管理系统-项目分享

基于SpringBoot的高校体育馆场地预约管理系统-项目分享 项目介绍项目摘要目录总体功能图用户实体图赛事实体图项目预览用户个人中心医生信息管理用户管理场地信息管理登录 最后 项目介绍 使用者&#xff1a;管理员 开发技术&#xff1a;MySQLJavaSpringBootVue 项目摘要 随着…