蓝桥杯单片机进阶教程——蜂鸣器继电器
前言
上一讲我们介绍了该开发板上面的LED灯的状态显示,这一节我们继续往下看我们的蜂鸣器和继电器,该模块与上一讲相差不大,在比赛中常做状态展示,接下来我们来看我们这一部分
继电器
在该开发板中,继电器很显眼
这里我们截了上一讲中的一部分图片,在单片机的右侧,我们可以看到一个大的方块,这个就是我们的继电器,在继电器的右侧(或者旁边),我们可以看到一个LED灯,这个LED灯就可以判断我们的继电器的开合状态,继电器闭合时,此处的LED就会点亮,如果断开,则LED处于熄灭状态。
来看我们的原理图
上面就是我们继电器的一个模组,下面是我们继电器的部分,上面是我们继电器外接的LED灯。
我们顺着原理图来看,这里和之前的LED模组一样,通过一个74HC138译码器选中相应的端口,这里我们来看对应的是Y5C,我们还是通过74HC138选择到Y5端口然后通过一个或非门,Y5片选被选中,WR进行写使能,Y5C输出1,然后对我们的继电器和蜂鸣器进行操作
74HC573
接下来我们要用到74HC573锁存器,74HC573是一款非常常见和通用的数字集成电路,属于八路透明D型锁存器。它在数字系统中扮演着 “数据暂存与缓冲” 的关键角色。
接下来我们对应我们的原理图来介绍我们各个引脚的作用
D1 - D8 (数据输入)
这是需要被锁存的8位数据输入端口。它们通常直接连接到微处理器或系统总线的数据总线上
Q1 - Q8 (锁存输出):
这是锁存器锁存后的8位数据输出端口。一旦数据被锁存,无论输入端D的数据如何变化,输出端Q都将保持锁存的值不变,直到下一次锁存操作。
LE (锁存使能):
这是最关键的控制引脚。
当 LE为高电平(1) 时,锁存器处于 “透明”模式:输出端Q的状态会实时跟随输入端D的状态变化。
当 LE从高电平跳变为低电平(0) 时,锁存器会 “锁存” 当前D输入端的数据,并在Q端保持住这个数据,即使之后D端的数据改变了,Q端也保持不变。
OE (输出使能):
这个引脚控制输出端的状态。
当 OE为低电平(0) 时,锁存器的输出Q正常工作(高电平或低电平)。
当 OE为高电平(1) 时,锁存器的输出Q变为高阻抗状态,相当于与外部电路“断开连接”。这个功能在将多个器件连接到同一总线上时至关重要,可以防止总线冲突。
我们对它的工作模式做一个总结,如下图所示
至此,我们电路部分中的各个模块都介绍差不多了,至于ULN2003,这个对我们的代码不会产生影响,他是一个驱动放大器,我们直接视他为一一对应的导线即可。
下面对照我们的原理图来看我们的代码
代码
在我学习的时候看大佬的代码,大概是这样的
// 蜂鸣器控制函数
// 参数flag: 1-打开蜂鸣器, 0-关闭蜂鸣器
void Beep(unsigned char flag)
{static unsigned char temp = 0x00;// 静态变量,用于保存当前P0端口的状态(保持其他位不变)static unsigned char temp_old = 0xff;// 静态变量,用于保存上一次的状态,避免重复写入相同数据if(flag)// 根据flag参数设置或清除temp的第6位(0x40 = 0100 0000)temp |= 0x40;// 置位第6位,打开蜂鸣器elsetemp &= ~0x40;// 清除第6位,关闭蜂鸣器if(temp != temp_old)// 只有当状态发生变化时才更新硬件,避免不必要的IO操作{P0 = temp; // 将新的状态值写入P0端口P2 = P2 & 0x1f | 0xa0;// 操作P2端口的高三位来选择锁存器(可能是74HC573)// 0x1f = 0001 1111,与操作保留低5位// 0xa0 = 1010 0000,或操作设置高三位为101// 这行代码选择特定的锁存器来锁存P0数据P2 &= 0x1f;// 取消锁存器选择,恢复P2端口状态// 0x1f = 0001 1111,与操作清除高三位temp_old = temp; }
}// 继电器控制函数
// 参数flag: 1-打开继电器, 0-关闭继电器
void Relay(unsigned char flag)
{static unsigned char temp = 0x00;// 静态变量,用于保存当前P0端口的状态(保持其他位不变)static unsigned char temp_old = 0xff;// 静态变量,用于保存上一次的状态,避免重复写入相同数据if(flag)// 根据flag参数设置或清除temp的第4位(0x10 = 0001 0000)temp |= 0x10;// 置位第4位,打开继电器elsetemp &= ~0x10;// 清除第4位,关闭继电器if(temp != temp_old)// 只有当状态发生变化时才更新硬件,避免不必要的IO操作{P0 = temp;// 将新的状态值写入P0端口P2 = P2 & 0x1f | 0xa0;// 操作P2端口的高三位来选择锁存器// 0x1f = 0001 1111,与操作保留低5位// 0xa0 = 1010 0000,或操作设置高三位为101// 这行代码选择特定的锁存器来锁存P0数据P2 &= 0x1f;// 取消锁存器选择,恢复P2端口状态// 0x1f = 0001 1111,与操作清除高三位temp_old = temp; // 更新旧状态值}
}
这个代码很全面,也很方便使用,但是大家也发现了,这个代码的代码量比较大,对于打字较慢的同学不太友好,并且代码量大在比赛同分排名中,排名会靠后,这一个模组只有两个外设,每个外设只有两个状态,我们通过排列组合一共只有四种状态,分别是(全开,全关,一开一关*2),这里我对这个代码做了一个改动,通过一个函数对其状态进行不同的选取即可,代码如下
void Relay_Init(unsigned char enable)
{// 选择锁存器P2 = P2 & 0X1F | 0XA0;// 设置输出状态switch(enable){case 0: P0 = 0x00; break; // 全关case 1: P0 = 0X10; break; // 仅继电器开case 2: P0 = 0X40; break; // 仅蜂鸣器开case 3: P0 = 0X50; break; // 全开}// 取消锁存器选择P2 &= 0x1F;
}
这样通过一个switch的选择,我们就可以做到对两个外设不同状态的控制
练习
下面给大家搞一个4T测评上面的小题
答案放到下一节
代码如上,本节大概就介绍完了,大家有问题可以在评论区讨论,或者进入群聊大家一起讨论相关内容,需要源程序的同学可以通过主页方式获取