• 51单片机学习笔记5 流水灯实现及蜂鸣器控制


    在这里插入图片描述

    一、流水灯

    本章节要实现的功能是开发板的LED灯轮流点亮。

    1. 硬件电路

    开发板的LED灯连接到GPIO的P2口的P20~P27:

    在这里插入图片描述

    LED采用共阳极接法。这种接法的好处是点亮LED不需要I/O口输出很大功率电流;GPIO在输出低电平时LED亮。
    在这里插入图片描述

    2. 代码实现

    (1)types.h

    为方便后面操作,定义一个types.h用来定义变量类型,位置放在 includes/ 目录下:

    #ifndef __TYPES_H__
    #define __TYPES_H__
    
    // 定义无符号8位整型数据类型
    typedef unsigned char u8;  
    // 定义无符号16位整型数据类型
    typedef unsigned int u16;   
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    设置引用路径:
    在这里插入图片描述

    (2) 点亮一个LED的基本操作

    这里简单给P2口赋值0或1实现GPIO口开关,实际只操作P20端口。由于输出低点平点亮,所以给0x01取反,除了最低位其它位都会变成高电平,效果就是最低位LED亮。

    #include "reg52.h"
    #include "types.h"
    
    #define LED_PORT	P2
    void delay_10us(u16 ten_us){
    	while(ten_us--);
    }
    
    void main(){
    	while(1){
    		LED_PORT=~0x00;
    		delay_10us(50000);
    		LED_PORT=~0x01;
    		delay_10us(50000);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    (3) 使用算术左移实现流水灯

    下面代码控制移位关键是 ~(0x01< 操作。

    1. 0x01 << i:这是一个位运算操作,表示将十六进制数 0x01 (二进制为 00000001)左移 i 位。左移操作将在二进制数的右端补零。因此,0x01 << i 的结果是在二进制数 00000001 的基础上向左移动 i 位,即将 1 逐位左移 i 位。

    2. ~(0x01 << i):这是一个按位取反的操作,用于翻转 0x01 << i 的每一位,即将 0x01 << i 中的每一位 0 变为 1,每一位 1 变为 0

    3. LED_PORT = ~(0x01 << i);:这是将翻转后的结果赋值给 LED_PORT 变量。

      • 例如,如果 i=0,则 0x01 << 0 等于 00000001,经过按位取反操作后,得到 11111110,即只有最右侧的LED亮起。
      • 如果 i=1,则 0x01 << 1 等于 00000010,经过按位取反操作后,得到 11111101,即第二个LED亮起。
      • 以此类推,不断地改变 i 的值,可以控制不同LED的亮灭,从而实现LED的流水灯效果。
    #include "reg52.h"
    #include "types.h"
    
    // 定义LED的端口为P2
    #define LED_PORT P2         
    
    // 延时函数,延时一段时间
    void delay_10us(u16 ten_us){
        while(ten_us--);        
    }
    
    void main(){
        int i=0;    
        while(1){   
    		// 控制LED的亮灭, ~(0x01<
            LED_PORT = ~(0x01<<i);  
            i++;                
            if(i>7) i=0;        
    		// 延时一段时间,控制LED的流动速度
            delay_10us(50000);  
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    (4) 使用库文件左移函数

    这里要使用系统intrins.h库。下面的循环流水灯使用变量 direction 来表示方法,只占用一个bit即可。
    crol<< 最大区别是,左移后溢出部分自动补到最右侧,其函数定义为:

    unsigned char _crol_(unsigned char value, unsigned char count);
    
    
    • 1
    • 2

    参数说明:

    • value:待左移的字节。
    • count:左移的位数。

    例如,如果 value 的二进制表示为 11001010,count 为 3,则经过 crol 函数处理后,结果为 01010110。左移 3 位后,最高位的 1 移出,而原来的最低位 1 移到了最高位,其余位依次向左移动。

    main程序内容:

    #include "reg52.h"
    #include "types.h"
    #include "intrins.h"
    
    // 定义LED的端口为P2
    #define LED_PORT P2         
    
    // 延时函数,延时一段时间
    void delay_10us(u16 ten_us){
        while(ten_us--);        
    }
    
    void main(){
    	int i=0;
    	bit direction=0;
        while(1){
            // 
        	LED_PORT = _crol_(0xFE, i);
    		if(direction==0){
    		 	i++;
    			if(i>=7){
    				direction=1;
    				i=7;
    			}
    		}else{
    			i--;
    			if(i<0){
    				i=1;
    				direction=0;
    			}
    		}
    
            delay_10us(50000*(i+1));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    这里延时计算把i值也带进去了,会产生类似跳跃的效果。

    二、蜂鸣器

    1. 蜂鸣器介绍

    蜂鸣器是一种常见的声音发生器,它通过振动产生声音。通常情况下,蜂鸣器被设计成小型的电子器件,可广泛应用于各种电子设备中。

    主要分类:

    • 压电蜂鸣器:通过施加电压使压电晶体振动来产生声音。它们通常具有较高的效率和较低的功耗。
    • 磁性蜂鸣器:通过电流在电磁铁上产生磁场,从而使得磁性振膜振动,产生声音。这种类型的蜂鸣器通常功耗较大,但可以产生较大的声音。
    • 共振蜂鸣器:利用共振腔体和振膜的共振效应产生声音。这种蜂鸣器体积较小,功耗较低,但声音相对较小。

    2. 硬件电路

    (1)原理图

    蜂鸣器需要30mA左右电流进行驱动,51的I/O口驱动能力比较弱,一般不会直接使用I/O口来驱动蜂鸣器,需要使用放大电路。
    开发板使用了ULN2003D来驱动蜂鸣器,原理图如下:
    在这里插入图片描述

    在这里插入图片描述

    蜂鸣器接在ULN2003D的12脚,通过单片机的P25来进行控制。
    需要注意的是,beep 连的引脚,同时也是LED6的引脚。

    (2)ULN2003介绍

    • ULN2003是高耐压、大电流复合晶体管阵列,由七个硅NPN 复合晶体管组成。一般采用DIP—16 或SOP—16 塑料封装。

    • ULN2003灌电流可达500mA,并且能够在关态时承受50V 的电压,输出还可以在高负载电流并行运行。它可以直接驱动继电器等负载;输入5VTTL电平,输出可达500mA/50V。

    • ULN2003D 常用于驱动大功率负载,如步进电机、继电器、蜂鸣器等。

    注意3.3V的高电平也可以直接驱动输入端I/O口。

    内部结构图:

    在这里插入图片描述

    引脚接线图

    在这里插入图片描述

    3. 代码实现

    beep_utils.h

    #ifndef __BEEP_UTILS_H__
    #define __BEEP_UTILS_H__
    #include 
    #include "types.h"
    
    /**
     * 蜂鸣器端口
    */
    sbit BEEP_PORT = P2^5;
    /**
     * 蜂鸣器发声一段时间
    */
    void beep(u16 high, u16 low, u16 times);
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    beep_utils.c

    #include "beep_utils.h"
    #include "common_utils.h"
    #include "types.h"
    
    /**
     * @brief 打开蜂鸣器
     */
    void beep_on(){
        BEEP_PORT = 1;
    }
    /**
     * @brief 关闭蜂鸣器
     */
    void beep_off(){
        BEEP_PORT = 0;
    }
    /**
     * @brief 蜂鸣器发声
     */
    void beep_once(u16 high, u16 low){
        beep_on();
        delay(high);
        beep_off();
        delay(low);
    }
    /**
     * @brief 蜂鸣器发声一段时间
    */
    void beep(u16 high, u16 low, u16 times){
    	u16 i;
        for(i = 0; i < times; i++){
            beep_once(high, low);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    main

    #include 
    #include "beep_utils.h"
    #include "led_utils.h"
    #include "common_utils.h"
    
    /**
    * @brief 主函数
    */
    main()
    {
    	// 关闭所有led
    	led_all_off();
    	// 打开第1个led
    	led_on(0);
    	led_on(7);
    
    	beep(10, 10, 100);
    	while(1)
    	{
    		delay(10000);
    	}
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    本文代码开源地址:
    https://gitee.com/xundh/learn51

  • 相关阅读:
    高并发系统架构设计之实战篇:消息流设计之拉模式
    shell脚本的编写规范和变量类型
    c++ virtual关键字
    任职超18年,Go团队技术主管Russ Cox官宣卸任!
    U-Net 模型改进和应用场景研究性综述
    GO语言之Goroutine和channel
    Spark 3.0 - 6.ML 自定义 Transformer 踩坑大全
    【故障公告】取代 memcached 的 redis 出现问题造成网站故障
    关于 Nginx 的哪些事
    图问题——深度遍历,广度遍历,并查集
  • 原文地址:https://blog.csdn.net/xundh/article/details/128106835