一、模块概述
LED模块封装了LED灯、蜂鸣器、电机、继电器的控制功能。这些设备虽然功能不同,但都通过74HC138译码器进行片选控制。
文件位置
-
driver/led.c- 实现文件 -
driver/led.h- 头文件
包含功能
| 函数 | 功能 | 控制引脚 |
|---|---|---|
Led_Disp() |
LED显示控制 | Y4 (0x80) |
Led_Off() |
关闭所有LED | Y4 (0x80) |
Beep() |
蜂鸣器控制 | Y5 (0xA0) |
Motor() |
电机控制 | Y5 (0xA0) |
Relay() |
继电器控制 | Y5 (0xA0) |
二、硬件原理
LED电路(共阳极)
VCC ────┬────┬────┬────┬────┬────┬────┬────
│ │ │ │ │ │ │ │
LED1 LED2 LED3 LED4 LED5 LED6 LED7 LED8
│ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
┌───────────────────────────────────────────┐
│ 74HC573 锁存器 │
│ D0 D1 D2 D3 D4 D5 D6 D7 │
└───────────────────────────────────────────┘
│ │ │ │ │ │ │ │
P0.0 P0.1 P0.2 P0.3 P0.4 P0.5 P0.6 P0.7
锁存使能 ← Y4 (74HC138)
关键点:
-
共阳极:LED阳极接VCC,阴极接P0
-
P0=0 → LED亮,P0=1 → LED灭
-
需要取反操作:
P0 = ~led_data
蜂鸣器/电机/继电器电路
VCC
│
┌───────┴───────┐
│ 驱动电路 │
│ (ULN2003) │
└───────┬───────┘
│
┌─────────────┼─────────────┐
│ │ │
继电器 蜂鸣器 电机
(bit4) (bit6) (bit5)
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────┐
│ 74HC573 锁存器 │
│ D4 D5 D6 │
└─────────────────────────────────────────┘
│ │ │
P0.4 P0.5 P0.6
锁存使能 ← Y5 (74HC138)
关键点:
-
高电平有效:P0=1 → 设备启动
-
继电器:bit4 (0x10)
-
电机:bit5 (0x20)
-
蜂鸣器:bit6 (0x40)
三、代码详解
全局变量
// LED状态变量
idata unsigned char temp_1 = 0x00; // 当前LED状态
idata unsigned char temp_1_old = 0xff; // 上次LED状态(用于状态变化检测)
// 蜂鸣器/电机/继电器状态变量
idata unsigned char temp_2 = 0x00; // 当前状态
idata unsigned char temp_2_old = 0xff; // 上次状态
LED显示函数
/**
* @brief LED显示函数
* @param ucLed 指向8元素数组的指针,每个元素0或1
* ucLed[0]对应LED1,ucLed[7]对应LED8
*/
void Led_Disp(unsigned char *ucLed)
{
unsigned char temp;
// 1. 将8个数组元素合并成一个字节
temp_1 = 0x00;
temp_1 = (ucLed[0] << 0) | (ucLed[1] << 1) | (ucLed[2] << 2) | (ucLed[3] << 3) |
(ucLed[4] << 4) | (ucLed[5] << 5) | (ucLed[6] << 6) | (ucLed[7] << 7);
// 2. 状态变化检测:只有状态改变才更新硬件
if (temp_1 != temp_1_old)
{
// 3. 写入硬件(取反,因为共阳极)
P0 = ~temp_1;
// 4. 选中LED锁存器(Y4) BCD码100对应4
temp = P2 & 0x1f;//清零高三位0001 0000
temp = temp | 0x80;//对应Y4 1000 0000
P2 = temp;
// 5. 取消选择,锁存数据
temp = P2 & 0x1f;
P2 = temp;
// 6. 更新状态缓存
temp_1_old = temp_1;
}
}
LED关闭函数
/**
* @brief 关闭所有LED
*/
void Led_Off()
{
unsigned char temp;
// 共阳极,P0=0xFF全部熄灭
P0 = 0xff;
// 选中并锁存
temp = P2 & 0x1f;
temp = temp | 0x80;
P2 = temp;
temp = P2 & 0x1f;
P2 = temp;
// 重置状态缓存
temp_1_old = 0x00;
}
蜂鸣器控制函数
/**
* @brief 控制蜂鸣器
* @param enable 1=响,0=停
*/
void Beep(bit enable)
{
unsigned char temp;
// 蜂鸣器在bit6位置 (0x40 = 0100 0000b)
if (enable)
temp_2 |= 0x40; // 置位:开启
else
temp_2 &= (~0x40); // 清位:关闭
// 状态变化检测
if (temp_2 != temp_2_old)
{
// 直接写入(高电平有效,不需取反)
P0 = temp_2;
// 选中Y5锁存器
temp = P2 & 0x1f;
temp = temp | 0xa0;
P2 = temp;
temp = P2 & 0x1f;
P2 = temp;
temp_2_old = temp_2;
}
}
电机控制函数
/**
* @brief 控制电机
* @param enable 1=转动,0=停止
*/
void Motor(bit enable)
{
unsigned char temp;
// 电机在bit5位置 (0x20 = 0010 0000b)
if (enable)
temp_2 |= 0x20;
else
temp_2 &= (~0x20);
if (temp_2 != temp_2_old)
{
P0 = temp_2;
temp = P2 & 0x1f;
temp = temp | 0xa0;
P2 = temp;
temp = P2 & 0x1f;
P2 = temp;
temp_2_old = temp_2;
}
}
继电器控制函数
/**
* @brief 控制继电器
* @param enable 1=吸合,0=断开
*/
void Relay(bit enable)
{
unsigned char temp;
// 继电器在bit4位置 (0x10 = 0001 0000b)
if (enable)
temp_2 |= 0x10;
else
temp_2 &= (~0x10);
if (temp_2 != temp_2_old)
{
P0 = temp_2;
temp = P2 & 0x1f;
temp = temp | 0xa0;
P2 = temp;
temp = P2 & 0x1f;
P2 = temp;
temp_2_old = temp_2;
}
}
四、位操作技巧
设备控制位对照
| 设备 | 位置 | 掩码 | 开启操作 | 关闭操作 |
|---|---|---|---|---|
| 继电器 | bit4 | 0x10 | temp_2 |= 0x10 |
temp_2 &= ~0x10 |
| 电机 | bit5 | 0x20 | temp_2 |= 0x20 |
temp_2 &= ~0x20 |
| 蜂鸣器 | bit6 | 0x40 | temp_2 |= 0x40 |
temp_2 &= ~0x40 |
位操作图解
开启蜂鸣器(保持其他设备状态不变):
temp_2: 0b00100000 (电机开)
0x40: 0b01000000
OR结果: 0b01100000 (电机开 + 蜂鸣器开)
关闭蜂鸣器(保持其他设备状态不变):
temp_2: 0b01100000 (电机开 + 蜂鸣器开)
~0x40: 0b10111111
AND结果: 0b00100000 (电机开)
五、使用方法
在main.c中定义LED数组
pdata unsigned char ucLed[8] = {0, 0, 0, 0, 0, 0, 0, 0};
LED处理任务
void Led_Proc()
{
// 方式1:直接设置单个LED
ucLed[0] = 1; // LED1亮
ucLed[1] = 0; // LED2灭
// 方式2:根据条件控制
if (Temperature > 30)
ucLed[2] = 1; // 温度过高,LED3报警
else
ucLed[2] = 0;
// 方式3:流水灯效果
static unsigned char flow = 0;
for (i = 0; i < 8; i++)
ucLed[i] = (i == flow) ? 1 : 0;
flow = (flow + 1) % 8;
}
在定时器中断中调用
void Timer1_Isr(void) interrupt 3
{
// PWM调光方式
pwm_period = (++pwm_period) % 10;
if (pwm_period < pwm_compare)
Led_Disp(ucLed); // 亮
else
Led_Off(); // 灭
}
蜂鸣器/电机/继电器使用
// 开启蜂鸣器
Beep(1);
// 关闭蜂鸣器
Beep(0);
// 开启电机
Motor(1);
// 开启继电器
Relay(1);