本章节要实现的功能是开发板的LED灯轮流点亮。
开发板的LED灯连接到GPIO的P2口的P20~P27:
LED采用共阳极接法。这种接法的好处是点亮LED不需要I/O口输出很大功率电流;GPIO在输出低电平时LED亮。
为方便后面操作,定义一个types.h用来定义变量类型,位置放在 includes/ 目录下:
#ifndef __TYPES_H__
#define __TYPES_H__
// 定义无符号8位整型数据类型
typedef unsigned char u8;
// 定义无符号16位整型数据类型
typedef unsigned int u16;
#endif
设置引用路径:
这里简单给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);
}
}
下面代码控制移位关键是 ~(0x01< 操作。
0x01 << i
:这是一个位运算操作,表示将十六进制数 0x01
(二进制为 00000001
)左移 i
位。左移操作将在二进制数的右端补零。因此,0x01 << i
的结果是在二进制数 00000001
的基础上向左移动 i
位,即将 1
逐位左移 i
位。
~(0x01 << i)
:这是一个按位取反的操作,用于翻转 0x01 << i
的每一位,即将 0x01 << i
中的每一位 0
变为 1
,每一位 1
变为 0
。
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);
}
}
这里要使用系统intrins.h库。下面的循环流水灯使用变量 direction 来表示方法,只占用一个bit即可。
crol 与 <<
最大区别是,左移后溢出部分自动补到最右侧,其函数定义为:
unsigned char _crol_(unsigned char value, unsigned char 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值也带进去了,会产生类似跳跃的效果。
蜂鸣器是一种常见的声音发生器,它通过振动产生声音。通常情况下,蜂鸣器被设计成小型的电子器件,可广泛应用于各种电子设备中。
主要分类:
蜂鸣器需要30mA左右电流进行驱动,51的I/O口驱动能力比较弱,一般不会直接使用I/O口来驱动蜂鸣器,需要使用放大电路。
开发板使用了ULN2003D来驱动蜂鸣器,原理图如下:
蜂鸣器接在ULN2003D的12脚,通过单片机的P25来进行控制。
需要注意的是,beep 连的引脚,同时也是LED6的引脚。
ULN2003是高耐压、大电流复合晶体管阵列,由七个硅NPN 复合晶体管组成。一般采用DIP—16 或SOP—16 塑料封装。
ULN2003灌电流可达500mA,并且能够在关态时承受50V 的电压,输出还可以在高负载电流并行运行。它可以直接驱动继电器等负载;输入5VTTL电平,输出可达500mA/50V。
ULN2003D 常用于驱动大功率负载,如步进电机、继电器、蜂鸣器等。
注意3.3V的高电平也可以直接驱动输入端I/O口。
#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
#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);
}
}
#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);
}
}
本文代码开源地址:
https://gitee.com/xundh/learn51