单片机学习(四)蜂鸣器和独立按键的使用

蜂鸣器

两种蜂鸣器的介绍

有源蜂鸣器一般是输入一个电流或电压即可直接驱动工作,而无源蜂鸣器则需要输入脉冲信号才可以进行工作。在51单片机开发板上的即为无源蜂鸣器。

蜂鸣器相关电路图

在这里插入图片描述
在这里插入图片描述
可以看出,信号是通过P15传递到ULN2003D芯片后进而传递到芯片的OUT5(即BEEP端口)再传递到蜂鸣器中的,其中ULN2003D芯片起着电流放大的作用。

控制代码

首先我们先获得控制蜂鸣器的引脚,从电路图可以看出是P15,所以:

sbit BEEP= P1^5;

因为这是无源蜂鸣器,所以我们需要给它提供脉冲信号输入才能使它工作。而当BEEP为0时有电流,BEEP为1时无电流,所以我们需要循环改变BEEP的值,主函数代码如下所示:

int main() {
    while (1)
    {
        BEEP = ~BEEP;
        deley(10);
    }
}

如果我们希望改变蜂鸣器的音调,只需要改变脉冲信号的频率即可,也就是while循环中deley()的参数。

我们也可以不断改变deley()中填入的参数来使蜂鸣器发出奇怪的声音🤣:

int main() {
    u16 time = 10; 
    u8 cnts = 50;
    u8 i;
    for(time=10;time<200;time++) {
        for(i=0;i<cnts;i++) {
            BEEP = ~BEEP;
            deley(time);
        }
    }
}

独立按键

独立按键电路图

在这里插入图片描述
可以看到,这4个独立按键都是一端和单片机的引脚(P3[0…3])相连,而另一端直接接地的。

这些按键的效果是,当按键没有按下时,它们对应的端口的输出是高电平,而当按键按下之后,这些端口的输出则变为低电平了。

因此我们可以使用轮询的方式查看这些端口的电平情况来检测按钮是否被按下,如果按下,则我们可以进行计数等控制其他元件的操作。

按键控制一个LED的点亮和熄灭

我们希望当点击按键时,第一个LED点亮,而在此单击时则熄灭。

按照之前的思路,我们很容易就能写出对应的控制代码:

sbit OneLED = P2^0; // 使用OneLED来控制对应的引脚的输出
sbit k1 = P3^1;

void keypros() {
    if (k1 == 0) {
        deley(1000); // 消抖
        if (k1 == 0) {
            OneLED = ~OneLED;
        }
        while (!k1);
    }
}

int main() {
    while (1) {
        keypros();           
    }
}

重要的是keypros()函数中的内容,当我们点击第一个按钮时,k1的值会变为0,因此我们进行轮询的时候就会进入到keypros()函数的第一个if中。然后进行deley(1000);是为了进行消抖处理。然后再次查看k1是否为0,若不为0则说明此次按动是非法的(即可能是抖动产生的),而如果为0则进入切换LED状态的代码。然后使用while (!k1);来等待抬手,若没有这句话,则此次函数调用结束后我们的手还没有抬起来又再次进入函数了,会导致灯光不断亮灭变换,和我们希望的不符,所以使用这个循环语句进行等待抬手再次轮询。

运行效果:
在这里插入图片描述

设置控制框架

可以看出,我们的按键控制其他硬件的框架已经搭好了,以后我们需要控制其他元件时就只需要将keypros()函数中的OneLED = ~OneLED;这个部分切换为其他的控制代码即可。但是直接切换又会显得非常的麻烦,因此我们使用C语言的一个好用的东西函数指针来完成这项功能。

其实回调函数这种东西是非常常见的,特别是在JavaScript这个语言中被大量地使用,在JavaScript中函数是一等公民,可以随便作为参数进行传递,而在C语言可以通过函数指针将一个函数作为另一个函数的参数进行传递,例如:

typedef void (*CallBack)();

int getRunTime(CallBack function) {
    clock_t startTime = clock();
    function();
    clock_t endTime = clock();
    return endTime - startTime;
}

这里定义了一个回调函数指针类型CallBack,其指向的函数无参数无返回值。然后我们可以将一个函数指针作为参数传递到getRunTime()函数中,这样运行结束后我们即可获得传递进去的函数的运行时间是多少了,例如:

void countFunc() {
    for (int i = 0; i < 10000000; ++i) {}
}

int main() {
    int runTime = getRunTime(countFunc); <--将函数指针传递进去,相当于回调函数
    cout << "runTime: " << runTime << "ms" << endl;
}

参考博客:https://www.jianshu.com/p/2862d05f64e8

所以我们使keypros()函数接收一个函数指针,然后将OneLED = ~OneLED;替换为传入的函数:

typedef void (*CallBack)(void);

void keypros(CallBack function) {
    if (k1 == 0) {
        deley(1000);
        if (k1 == 0) {
            function();
        }
        while (!k1);
    }
}

这样,我们写一个切换LED状态的函数:

void switchLED() { 
	OneLED = ~OneLED; 
}

然后我们在主函数中将它传递到keypros()函数中:

int main() {
    while (1) {
        keypros(switchLED);
    }
}

即我们希望在单击按钮后发生什么事件,就将这个事件的函数传递到keypros()中即可,这样按钮控制事件的框架就搭好了。

按钮点击计数器

既然框架已经搭好,我们继续编写事件函数即可。

此时事件为计数器+1并显示出来。

u8 code smgduan[16] = {
	0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,
	0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71
};

u8 addOneDigitCnt = 1;
void addOneDigit() {
    P0 = smgduan[addOneDigitCnt];
    addOneDigitCnt++;
    if (addOneDigitCnt == 16) {
        addOneDigitCnt = 0;
    }
}

int main() {
    P0 = smgduan[0];
    while (1) {
        keypros(addOneDigit);
    }
}

运行效果:
在这里插入图片描述

按钮点击流水灯

我们点击按钮是LED灯向前传递一格。

代码:

void LEDMove() {
    LED <<= 1;
    if (LED != 0xfe) {
        LED += 1;
    }
}

int main() {
    LED = 0xfe;
    while (1) {
        keypros(LEDMove);
    }
}

运行效果:
在这里插入图片描述

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
51单片机开机后,我们可以使用单击key1键来触发带有蜂鸣器的操作。 首先,在51单片机的开机初始化代码中,我们需要将key1键配置为输入引脚,并且使能其中断功能。这样当我们单击key1键时,会触发外部中断。 接下来,在主程序中,我们可以编写一个函数来控制蜂鸣器工作。在函数内部,我们可以通过设置相关的IO口,使蜂鸣器发出声音。为了产生连续的声音,我们可以使用一个循环来控制蜂鸣器的开关状态,从而实现发出连续的"beep"声。 在主函数中,我们可以通过检测key1键的状态来判断用户是否进行了单击操作。当检测到key1键被按下时,我们可以调用上述的蜂鸣器函数,以便产生"beep"声。同时,我们也需要为了避免持续检测key1键状态而引入的抖动,可以增加一个延时函数来进行适当的延时,从而稳定读取key1键的状态。 最后,为了使代码正常运行,我们需要在51单片机上进行一些硬件连接。需要将蜂鸣器连接到相应的IO口上,并将key1键通过一个上拉电阻连接到地。这样在键未被按下时,IO口会被拉高,而当键被按下时,IO口被拉低,从而产生触发中断的信号。 总之,通过以上的步骤,我们可以实现51单片机开机后,当单击key1键时,带有蜂鸣器的"beep"声会被触发。注意,以上只是简单示意,具体的实现可能会因硬件连接和编程工具的不同而有所差异。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值