【小白51单片机专用教程】protues仿真独立按键控制LED

课程特点

  • 无需开发板
  • 0基础教学
  • 软件硬件双修
  • 辅助入门

本课程面对纯小白,因此会对各个新出现的知识点在实例基础上进行详细讲解,有相关知识的可以直接跳过。课程涉及protues基本操作、原理图设计、数电模电、kell使用、C语言基本内容,所有涉及知识都将建立在实例的基础上放心食用。

食用教程

  • 详细目录,随时跳过已知部分;
  • 全小白按步骤全程跟学;
  • 有开发板的交叉理解开发板的原理图与我们设计的原理图

本次实验内容

设计独立按键控制LED灯;熟悉单片机IO口的输入功能,学会独立按键编程逻辑;加强对C语言的认识。

protues

这篇内容中的硬件设计主要涉及LED灯控制电路的设计以及独立按键电路的设计。

LED灯电路设计

LED设计原理具体去看第一节的内容,在这里我们简单讲一下,LED是二极管,一般额定电压2.2V,额定电流10ma ,正极接上高电平,使得其工作在额定电压电流范围内。因为51单片机的IO口有5V输出电压 ,因此我们直接将LED正极接到单片机IO口上,然后串联一个280欧姆的电阻进行串联分压限流

独立按键电路设计

利用单片机的IO口去读取独立按键的状态,因为单片机IO口大都自带高电平,因此我们可以设计一条电路,按键不按的时候IO口正常高电平,按键按下时电压被拉低。

直接这样设计就行了,不按断路P2.0高电平,按下P2.0接地变低电平。在这里我们不需要担心P2.0直接短路照成的影响是因为其P2.0内部电路的问题,这里我也不过多探讨了。

原理图

keil

通过原理图可以得知,只需要我们读按键所在引脚的高低电平状态即可分辨出按键是否按下。

设计一个程序,读取按键的状态,分别用K1~K4控制D1~D4的亮灭;按下按键则亮,松开按键则灭。程序如下:

cs 复制代码
#include "reg51.h"

/*D1~D4引脚定义*/
sbit LED1=P1^0;
sbit LED2=P1^1;
sbit LED3=P1^2;
sbit LED4=P1^3;

/*K1~K4引脚定义*/
sbit KEY1=P1^4;
sbit KEY2=P1^5;
sbit KEY3=P1^6;
sbit KEY4=P1^7;

/*LED控制函数*/
void LEDdisplay(int L1,int L2,int L3,int L4){
    LED1=L1;
    LED2=L2;
    LED3=L3;
    LED4=L4;
}

void main(){
    LEDdisplay(0,0,0,0);
    
    while(1){

        /*如果KEY1按下,则LED1亮;KEY1没按下,LED1灭*/
        if(KEY1==0){
            LED1=1;
        }else{
            LED1=0;
        }
        /*如果KEY2按下,则LED2亮;KEY2没按下,LED2灭*/
        if(KEY2==0){
            LED2=1;
        }else{
            LED2=0;
        }
        /*如果KEY3按下,则LED3亮;KEY3没按下,LED3灭*/
        if(KEY3==0){
            LED3=1;
        }else{
            LED3=0;
        }
        /*如果KEY3按下,则LED3亮;KEY3没按下,LED3灭*/
        if(KEY4==0){
            LED4=1;
        }else{
            LED4=0;
        }
    }
}
代码讲解

1.引脚定义,protues连接到哪个引脚就定义哪个引脚

cs 复制代码
/*K1~K4引脚定义*/
sbit KEY1=P1^4;
sbit KEY2=P1^5;
sbit KEY3=P1^6;
sbit KEY4=P1^7;

2.控制语句

cs 复制代码
/*如果KEY1按下,则LED1亮;KEY1没按下,LED1灭*/
        if(KEY1==0){
            LED1=1;
        }else{
            LED1=0;
        }
if语句详解

if语句是判断分支语句,其形式是

cs 复制代码
if(条件){
    程序1;
}
else{
    程序2;
}

该语句代表的意思是,如果满足条件即执行程序1,不满足条件则执行程序2.

在我们的程序中表现的就是:如果KEY按下,则LED点亮,否则熄灭。

进阶训练

现在请你设计一个程序,程序内容是:单击KEY1,LED1亮,再次单击LED1灭。需要注意的是,单击表示按下松开的一整个过程(即按下KEY则LED亮;松开再次按下则LED灭)

程序源码
cs 复制代码
#include "reg51.h"  // 包含8051单片机的寄存器定义头文件

// 定义LED和按键对应的端口位
sbit LED1 = P1^0;
sbit LED2 = P1^1;
sbit LED3 = P1^2;
sbit LED4 = P1^3;
sbit KEY1 = P1^4;
sbit KEY2 = P1^5;
sbit KEY3 = P1^6;
sbit KEY4 = P1^7;

// 延时函数,单位为毫秒
void delay_ms(unsigned n) {
    unsigned int i, j;
    for (i = n; i > 0; i--)
        for (j = 1; j > 0; j--);
}

// 显示LED状态的函数
void LEDdisplay(int L1, int L2, int L3, int L4) {
    LED1 = L1;
    LED2 = L2;
    LED3 = L3;
    LED4 = L4;
}

// 获取按键值的函数
unsigned int KeyValue(unsigned int mode) {
    static unsigned int key_up = 1;  // 静态变量,用于记录按键是否释放

    if (mode == 1) key_up = 1;  // 如果模式为1,重置按键状态

    // 检测是否有按键按下
    if (key_up == 1 && (KEY1 == 0 || KEY2 == 0 || KEY3 == 0 || KEY4 == 0)) {
        delay_ms(10);  // 消抖延时
        key_up = 0;  // 标记按键已按下
        // 返回按下的按键编号
        if (KEY1 == 0) return 1;
        else if (KEY2 == 0) return 2;
        else if (KEY3 == 0) return 3;
        else if (KEY4 == 0) return 4;
    }
    // 检测所有按键是否释放
    else if (KEY1 == 1 && KEY2 == 1 && KEY3 == 1 && KEY4 == 1) {
        key_up = 1;  // 标记按键已释放
    }

    return 0;  // 没有按键按下时返回0
}

void main() {
    unsigned int keyval = 0;  // 存储按键值的变量
    LEDdisplay(0, 0, 0, 0);  // 初始化LED状态为关闭

    while (1) {
        keyval = KeyValue(0);  // 获取按键值

        // 根据按键值切换对应LED的状态
        if (keyval > 0) {
            switch (keyval) {
                case 1:
                    LED1 = !LED1; break;
                case 2:
                    LED2 = !LED2; break;
                case 3:
                    LED3 = !LED3; break;
                case 4:
                    LED4 = !LED4; break;
            }
        }
    }
}
C语言知识补充

在正式讲代码之前,有必要为C语言新手补充一点知识

static

静态变量,分配独立内存空间,在函数内部声明的静态变量在整个程序执行期间保持其值。它们不会在每次函数调用时重新初始化。

switch

switch语句用于在多个可能的值之间进行选择,它是一种较为简洁的选择结构。其基本语法如下:

cs 复制代码
switch (表达式) {
    case 常量1:
        // 当表达式的值等于常量1时,执行这部分代码
        break;
    case 常量2:
        // 当表达式的值等于常量2时,执行这部分代码
        break;
    // 可以有多个 case 分支
    default:
        // 如果没有任何 case 匹配,执行这部分代码
}

!

**!是逻辑非运算符(Logical NOT operator)。它用于对一个布尔表达式(0或1这种二进制数)求反。具体来说,LED1为1,则!LED1为0;LED1为0,则!**LED1为1.

按键取值函数详解
cs 复制代码
unsigned int KeyValue(unsigned int mode) {
    static unsigned int key_up = 1;  // 静态变量,用于记录按键是否释放

    if (mode == 1) key_up = 1;  // 如果模式为1,重置按键状态

    // 检测是否有按键按下
    if (key_up == 1 && (KEY1 == 0 || KEY2 == 0 || KEY3 == 0 || KEY4 == 0)) {
        delay_ms(10);  // 消抖延时
        key_up = 0;  // 标记按键已按下
        // 返回按下的按键编号
        if (KEY1 == 0) return 1;
        else if (KEY2 == 0) return 2;
        else if (KEY3 == 0) return 3;
        else if (KEY4 == 0) return 4;
    }
    // 检测所有按键是否释放
    else if (KEY1 == 1 && KEY2 == 1 && KEY3 == 1 && KEY4 == 1) {
        key_up = 1;  // 标记按键已释放
    }

    return 0;  // 没有按键按下时返回0
}

mode: 一个无符号整数,用于控制函数的行为。如果 mode为 1,则重置按键状态。

static unsigned int key_up = 1; 这是一个静态变量,用于记录按键是否已经释放。初始值为 1,表示按键处于释放状态。

功能实现

  1. 重置按键状态:

    • 如果 mode 为 1,则将 key_up 设置为 1,表示重置按键状态,支持按键长按。mode为0,键值按一次读一次,仅仅支持单击。
  2. 检测按键按下:

    • 首先检查 key_up 是否为 1(即按键是否处于释放状态)。
    • 然后检查是否有任意一个按键被按下(即 KEY1, KEY2, KEY3, KEY4 中有一个为低电平)。
    • 如果检测到有按键按下,调用 delay_ms(10) 进行消抖处理,然后设置 key_up 为 0,表示按键已被按下。
    • 根据哪个按键被按下,返回相应的按键编号(1, 2, 3, 或 4)。
  3. 检测按键释放:

    • 如果所有按键都处于高电平(即没有被按下),则将 key_up 设置为 1,表示按键已释放。
  4. 返回值:

    • 如果没有任何按键被按下,函数返回 0。

控制程序详解:

cs 复制代码
        keyval = KeyValue(0);  // 获取按键值

        // 根据按键值切换对应LED的状态
        if (keyval > 0) {
            switch (keyval) {
                case 1:
                    LED1 = !LED1; break;
                case 2:
                    LED2 = !LED2; break;
                case 3:
                    LED3 = !LED3; break;
                case 4:
                    LED4 = !LED4; break;
            }
        }

KeyValue 函数的作用是检测按键的状态并返回按下的按键编号。如果没有按键被按下,则返回 0。返回的按键编号存储在变量 keyval 中。

首先检查 keyval 是否大于 0,即是否有按键被按下。如果 keyval0,则不执行任何操作。

如果 keyval 大于 0,则进入 switch 语句,根据 keyval 的值来切换相应的LED状态。

case 1: 如果 keyval 等于 1,则切换 LED1 的状态。

LED1 = !LED1; 表示将 LED1 的状态取反,即如果 LED1 当前是亮着的,则将其熄灭;如果当前是熄灭的,则将其点亮。

case 2: 如果 keyval 等于 2,则切换 LED2 的状态。

case 3: 如果 keyval 等于 3,则切换 LED3 的状态。

case 4: 如果 keyval 等于 4,则切换 LED4 的状态。

总结

本节课程主要是介绍了一下独立按键的电路原理图,同时重点设计了一个两种模式的键值获取函数,进一步理解C语言的分支语句。读者可以根据现学内容自由发挥,加深对C语言程序的了解。

相关推荐
逼子格18 分钟前
电路中的DGND、GROUND、GROUND_REF的区别,VREF、VCC、VDD、VEE和VSS的区别?
嵌入式硬件·硬件工程·硬件工程师·电源·接地·硬件工程师真题
总结所学21 分钟前
擦除整片flash后,程序下载到单片机,单片机不运行
单片机·嵌入式硬件
2401_888859711 小时前
STM32 ADC模数转换器
stm32·单片机·嵌入式硬件
四夕白告木贞2 小时前
stm32week13
stm32·单片机·嵌入式硬件·学习
本道自然3 小时前
stm32wb55rg (2) 阅读资料手册
stm32·单片机·嵌入式硬件
平凡灵感码头3 小时前
STM32 RTC配置
stm32·单片机·实时音视频
第六个葫芦娃5 小时前
【ESP32】st7735s + LVGL移植
单片机
阿川!5 小时前
嵌入式软件--stm32 DAY 2
stm32·单片机·嵌入式硬件
BW.SU9 小时前
单片机 + 图像处理芯片 + TFT彩屏 触摸滑动条控件
单片机·嵌入式硬件·51单片机·ra8889·ra6809·图形处理芯片·stc8h8k64u
程序员JerrySUN15 小时前
驱动开发硬核特训 · Day 22(下篇): # 深入理解 Power-domain 框架:概念、功能与完整代码剖析
linux·开发语言·驱动开发·嵌入式硬件