周立功教授新书《面向AMetal框架与接口的编程(上)》,对AMetal框架进行了详细介绍,通过阅读这本书,你可以学到高度复用的软件设计原则和面向接口编程的开发思想,聚焦自己的“核心域”,改变自己的编程思维,实现企业和个人的共同进步。
第八章为深入理解AMetal,本文内容为8.3 蜂鸣器接口和8.4 温度采集接口。
8.3 蜂鸣器接口
>>>8.3.1 定义接口
1. 接口命名
由于操作的对象是蜂鸣器(buzzer),因此,接口命名以“am_buzzer_”作为前缀。对于蜂鸣器,基本的操作是打开和关闭蜂鸣器,可定义相应的两个接口名为:
am_buzzer_on
am_buzzer_off
特别地,在一些应用场合,还需要类似蜂鸣器“嘀一声”这样的操作,即鸣叫一定的时间后自动停止。可以定义其接口名为:
am_buzzer_beep
am_buzzer_beep_async
这里定义了两个接口,都是用于蜂鸣器鸣叫指定的时间,二者的区别在于函数返回的时机不同。am_buzzer_beep 会等待鸣叫结束后返回,am_buzzer_beep_async 不会等待,函数立即返回,蜂鸣器鸣叫指定时间后自动停止。
显然,对于am_buzzer_beep_async 接口,在最开始的蜂鸣器接口设计中,很可能是不会想到的,该接口是在大量实际应用中得出的,由于在一些特殊的应用场景,不希望程序被阻塞,因此,需要提供am_buzzer_beep_async 这样的异步接口。
2. 接口参数
在LED 通用接口的设计中,由于在一个系统中,可能存在多个LED,这就必须使用某种方法区分不同的LED,如使用了唯一ID 号led_id 表示来区分系统中的多个LED。按照这种逻辑,是否也需要一个buzzer_id 来区分不同的蜂鸣器呢?
蜂鸣器的功能单一,是一种发声器件,在一个具体应用中,发声器件往往只有一个,没有必要使用多个蜂鸣器。因此,蜂鸣器可以看做系统的一个单实例设备,基于此,也就无需使用类似于buzzer_id 这样的参数来区分多个蜂鸣器了,对于打开和关闭蜂鸣器的接口,则无需任何参数,即:
am_buzzer_on(void);
am_buzzer_off(void);
特别地,对于am_buzzer_beep 和am_buzzer_beep_async 接口,虽无需参数来区分多个蜂鸣器,但由于其功能是鸣叫一定的时间,因此,还需要一个用于指定鸣叫时长的参数。
am_buzzer_beep(uint32_t ms);
am_buzzer_beep_async (uint32_t ms);
其中,ms 用于指定鸣叫时长,单位为毫秒。
3. 返回值
接口无特殊说明,直接将所有接口的返回值定义为int 类型的标准错误号。基于此,蜂鸣器控制接口的完整定义详见表8.5。
表8.5 蜂鸣器通用接口(am_buzzer.h)
其对应的类图详见图8.8。
图8.8 蜂鸣器接口类图
>>>8.3.2 实现接口
1. 抽象的蜂鸣器设备类
蜂鸣器共计4 个通用接口,其中,am_buzzer_beep()和am_buzzer_beep_async()接口可以直接基于am_buzzer_on()和am_buzzer_off()接口实现,am_buzzer_beep()的实现详见程序清单8.24。
程序清单8.24 am_buzzer_beep()的实现
程序中,首先使用am_buzzer_on()打开蜂鸣器,若打开蜂鸣器失败(返回值为负数),则直接返回相应的错误号,若打开成功,则使用am_mdelay()延时指定的时间,最后关闭蜂鸣器。对于am_buzzer_beep_async()接口,其需要立即返回,不能在函数内部直接使用延时函数,可以基于软件定时器实现,范例程序详见程序清单8.25。
程序清单8.25 am_buzzer_beep_async()的范例程序
程序中,首先使用am_buzzer_on()打开蜂鸣器,若打开蜂鸣器失败(返回值为负数),则直接返回相应的错误号,若打开成功,则启动软件定时器,定时时间为指定的鸣叫时间,启动定时器后,函数立即返回。软件定时器定时时间到后,需要调用自定义回调函数__beep_timer_callback(),在回调函数中,关闭了软件定时器和蜂鸣器,鸣叫结束。
显然,软件定时器在使用前,需要初始化,以将__beep_timer_callback()函数作为其定时时间到后的回调函数,如:
初始化语句放在哪里呢?这里仅仅展示了使用软件定时器实现am_buzzer_beep_async()函数的范例,后文再介绍初始化软件定时器的合适时机。
由于am_buzzer_beep()和am_buzzer_beep_async()接口可以直接基于am_buzzer_