在程序的世界里,一个蜂鸣器的驱动策略是如此简单:高电平让三极管开启,让蜂鸣器振荡声响起;低电平则让三极管关闭,使得蜂鸣器沉默无声。这一原理被我最初编程时所遵循。项目中的原理图清晰展示了这一点:
如果不能保证输入/输出(I/O)端口的性能,可以根据需要添加上拉或下拉电阻以增强稳定性。
在程序中,这个蜂鸣器的驱动方式依旧是高低电平控制。高电平使得三极管导通,蜂鸣器发出了声音,而低电平则导致三极管断开,蜂鸣器静音。这确实非常直接,但为了提升效率,我最初尝试采用以下方法:
当单片机没有足够强大的I/O跳变功能时,也可以通过修改代码来实现:
这里有一些解释:
函数功能:这是一个用来驱动蜂鸣器发声的函数,它接收一个参数,即要发出的次数。
传入的次数cnt需要在函数内部翻倍。这是因为传入的是希望连续发出几次声音,但是由于每一次都需要关闭一次才能再次响起,所以实际上会得到连续响一声而非多次。如果不加处理,就无法达到预期效果。
在while循环结束后,还需要加上关闭蜂鸼的声音操作。
假设我们传入参数为2,以便让它发出两声。当执行这个函数时:
第1次while(4),打开并减少到3
第2次while(3),关闭并减少到2
第3次while(2),打开并减少到1
第4次while(1),关闭并减少到0
最后第5次while(0)跳出循环
可以看出,在最后一次循环结束后,蜂鸼已经处于关闭状态。但为了保险起见,我们确保函数调用完毕后,蜂鸼始终处于关闭状态,这对于使用I/O跳变功能更为重要,因为仅能看到跳变过程,不知道其后的状态。
至此,我们就温习了这简单但实用的电子学和编程知识,现在准备进入核心内容。在编写程序时,我们经常追求效率,比如这个简单而又明显影响效率的地方——延迟操作。不过,上述讨论也指出,不进行延迟同样不可行。为了提高效率,我尝试了一种新的方法来驱动该模块。
代码如下:
简化来说,这个新方法包含三个步骤:
提供用于配置和初始化I/O端口与定时器资源。
配置定时器以产生固定的时间间隔(比如每隔50毫秒)。
实现中断处理逻辑,该逻辑将检查是否应该触发对应事件,并相应地更新相关变量。
选择使用项目中最基础且容易管理的一个定时器,它配备有每秒钟溢出一次(即每毫秒发生1000个溢出)的计数能力。我通常用它作为系统运行时间Systick_ms的一部分,但本项目并不要求精确计数,因此我决定利用其提供给我的资源进行其他任务,如我们的实验目的所需。此外,由于Systick_ms不会直接涉及本节实验之中,因此可以完全利用它作为调度工具去优化我们的应用流程。
具体做法如下:
调用该驱动函数仍然保持接口相同,只不过现在增加了两个全局变量BELL_CNT和FLAG_BELL,其中BELL_CNT保存当前应该播放多少遍声音,而FLAG_BELL标记是否正在播放声音。
定义了一个名为Bell_Tog() 的内嵌函数,用以切换蜂鳴聲開關狀態,以及设置 Timer 中斷處理函數 (ISR) 的時間為50ms,這樣我們就能模擬軟件延遲來實現更好的控制與準確性,並且避免因硬件限制導致無法達到的情況發生。
3 在Timer ISR 中,一旦達成50ms時間片,便會檢查 FLAG_BELL 狀態,如果為真則啟動 Bell_Tog() 函數並將 BELL_CNT 減 1,如果減至 0 則設 FLAG_BELL 為假,並進入下一個時間片等待新指令執行
以上就是改进后的代码示例。