在这里插入图片描述

一、流水灯

本章节要实现的功能是开发板的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

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

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

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

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

  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<<i) 为按位取反的操作,实现LED流水灯的效果
        LED_PORT = ~(0x01<<i);  
        i++;                
        if(i>7) i=0;        
		// 延时一段时间,控制LED的流动速度
        delay_10us(50000);  
    }
}


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

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

unsigned char _crol_(unsigned char value, unsigned char count);

参数说明:

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

这里延时计算把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 <reg52.h>
#include "types.h"

/**
 * 蜂鸣器端口
*/
sbit BEEP_PORT = P2^5;
/**
 * 蜂鸣器发声一段时间
*/
void beep(u16 high, u16 low, u16 times);

#endif

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

main

#include <reg52.h>
#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);
	}
}


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

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐