周立功教授新書《面向AMetal框架與接口的編程(上)》,對AMetal框架進行了詳細介紹,通過閱讀這本書,你可以學到高度復用的軟件設計原則和面向接口編程的開發思想,聚焦自己的“核心域”,改變自己的編程思維,實現企業和個人的共同進步。經周立功教授授權,即日起,致遠電子公眾號將對該書內容進行連載,愿共勉之。
第七章為面向通用接口的編程,本文內容為7.1 LED 控制接口、7.2 HC595 接口、7.3 蜂鳴器控制接口。
本章導讀
雖然面向接口的編程簡單易懂,但無法做到最大程度上地重用應用程序,這是導致軟件開發成本居高不下的原因之一。而面向通用接口的編程就是基于AMetal 框架的應用程序設計,其核心是制定統一的接口規范,使程序員脫離非核心域的束縛聚焦于核心競爭力。
7.1 LED 控制接口
>>> 7.1.1 LED 通用接口
為了實現跨平臺開發應用軟件,AMetal 提供了操作LED 的通用接口,詳見表7.1。
表7.1 LED 通用接口(am_led.h)
1. 設置LED 的狀態
設置LED 狀態的函數原型為:
其中,led_id 為LED 編號,AM824-Core 開發板共有兩個LED:LED0 和LED1,其編號分別為0 和1。如果LED 的狀態state 值為AM_TRUE,則點亮LED;反之state 值為AM_FALSE,則熄滅LED,其相應的范例程序詳見程序清單7.1。
程序清單7.1 am_led_set()范例程序
2. 點亮LED
點亮LED 的函數原型為:
其中,led_id 為LED 編號,其相應的范例程序詳見程序清單7.2。
程序清單7.2 am_led_on()范例程序
3. 熄滅LED
熄滅LED 的函數原型為:
其中,led_id 為LED 編號,其相應的范例程序詳見程序清單7.3。
程序清單7.3 am_led_off()范例程序
4. 翻轉LED 的狀態
翻轉LED 的狀態就是使LED 由點亮狀態轉變為熄滅狀態或由熄滅狀態轉變為點亮狀態。
其函數原型為:
其中,led_id 為LED 編號,其相應的范例程序詳見程序清單7.4。
程序清單7.4 am_led_toggle()范例程序
通過LED 通用接口控制AM824-Core 板載的兩個LED,使兩燈交替點亮(2 個LED 的流水燈效果),其相應的范例詳見程序清單7.5。
程序清單7.5 兩個LED 燈交替點亮(LED 流水燈)
>>> 7.1.2 LED 驅動
顯然,如果要想使用通用接口操作LED,則必須為具體的LED 設備提供相應的驅動。基于此,AMetal 提供了相應的驅動初始化函數。當使用該函數初始化一個LED 實例后,即可使用通用LED 接口操作LED。其函數原型為:
-
p_dev 為指向am_led_gpio_dev_t 類型實例的指針;
-
p_info 為指向am_led_gpio_info_t 類型實例信息的指針。
1. 實例
定義am_led_gpio_dev_t 類型(am_led_gpio.h)實例如下:
其中,g_led_gpio 為用戶自定義的實例,其地址作為p_dev 的實參傳遞。
2. 實例信息
實例信息主要描述了LED 的相關信息,比如,使用的GPIO 引腳號,LED 為低電平點亮與相應的LED 編號等信息。其類型am_led_gpio_info_t 的定義(am_key_gpio.h)如下:
(1)serv_inf0
serv_info 包含LED 編號信息,其類型am_led_servinfo_t 定義如下:
一個LED 設備可能包含多個LED,start_id 為LED 的起始編號,end_id 為LED 的結束編號,LED數目為end_id–start_id+1。由于AM824-Core 開發板僅有LED0和LED1兩個LED,因此其起始編號為0,結束編號為1。
(2)p_pins
p_pins 指向存放各個LED 相應引腳號的數組,比如,AM824-Core 開發板的LED0 通過J9 與MCU 的PIO0_20 相連,LED1 通過J10 與MCU 的PIO0_21 相連。基于此,定義一個存放引腳號的數組。比如:
該數組的地址為p_pins 的值。
當引腳輸出低電平時,則點亮LED,因此active_low 的值為AM_TRUE。實例信息定義如下:
基于實例和實例信息,即可完成LED 的初始化。比如:
當完成初始化后,即可調用通用LED 接口操作LED0 和LED1。為了便于配置LED(修改實例信息),基于模塊化編程思想,將初始化相關的實例和實例信息等定義存放在LED 配置文件中,通過頭文件引出實例初始化函數接口,源文件和頭文件的程序范例分別詳見程序清單7.6 和程序清單7.7。
程序清單7.6 LED 實例初始化函數實現(am_hwconf_led_gpio.c)
程序清單7.7 LED 實例初始化函數聲明(am_hwconf_led_gpio.h)
后續只需要使用無參數的實例初始化函數,即可完成LED 實例的初始化:
AM824-Core 的LED0 和LED1 作為一種板載資源,在系統啟動時默認進行了初始化操作,因此應用程序無需再調用實例初始化函數,即可直接使用LED0 和LED1。
如果用戶不需要使用LED,為了節省內存空間,可以將工程配置文件(am_prj_config.h)中的AM_CFG_LED_ENABLE 宏值修改為0,裁掉LED 程序,該宏本質上控制了板級初始化函數中的一段程序,詳見程序清單7.8。
程序清單7.8 在板級初始化中裁剪LED 的原理
>>> 7.1.3 MiniPort-LED
MiniPort-LED 模塊由8 個LED 組成的, 當MiniPort-LED 與AM824-Core 的PIO0_8~PIO0_15 相連時,如果GPIO 輸出低電平,則點亮LED。由于MiniPort-LED 也是GPIO 驅動型LED,因此可以使用與板載LED 相同的LED 驅動。其實例定義如下:
為了避免與板載LED 編號沖突,Miniport-LED 應該使用與板載LED 不同的編號,比如,將編號定義為2~9。如果系統不使用板載LED0 和LED1(已將工程配置文件中的AM_CFG_LED_ENABLE 宏值修改為0),僅使用MiniPort-LED,則編號定義為 0~7。其實例信息定義如下:
基于實例和實例信息,即可完成Miniport-LED 的初始化。比如:
當完成初始化后,即可調用通用LED 接口操作LED2~LED9。為了便于配置(修改實例信息)Miniport-LED,基于模塊化編程思想,將初始化相關的實例和實例信息等定義存放在Miniport-LED 的配置文件中,通過頭文件引出實例初始化函數接口,源文件和頭文件的程序范例分別詳見程序清單7.9 和程序清單7.10。
程序清單7.9 Miniport-LED 實例初始化函數實現(am_hwconf_miniport_led.c)
程序清單7.10 MiniPort-LED 實例初始化函數聲明(am_hwconf_miniport_led.h)
后續只需要使用無參數的實例初始化函數,即可完成Miniport-LED 實例的初始化:
當完成初始化后,即可使用通用LED 接口操作LED2~LED9。在AM824-Core 中,MiniPort-LED 作為可選的配板資源,在系統啟動時沒有像板載LED0 和LED1 那樣默認執行初始化操作。如果要使用MiniPort-LED,則必須調用MiniPort-LED 實例初始化函數。
7.2 HC595 接口
>>> 7.2.1 HC595 通用接口
AMetal 提供了一套操作HC595 的通用接口,詳見表7.2。
表7.2 HC595 通用接口(am_hc595.h)
1. HC595 輸出
使能HC595 輸出的函數原型為:
其中,handle 為HC595 的實例句柄,可通過具體的HC595 驅動初始化函數獲得。其類型am_hc595_handle_t(am_hc595.h)定義如下:
未使能時,HC595 的輸出處于高阻狀態,使能后才能正常輸出0 或1,范例程序詳見程序清單7.11。
程序清單7.11 am_hc595_enable()范例程序
其中,hc595_handle 可以通過具體的HC595 驅動獲得,若HC595 使用SPI 驅動,則可以通過如下語句獲得:
該實例初始化函數am_miniport_595_inst_init()會在后面詳細介紹。
2. 禁能HC595 輸出
禁能后HC595 輸出處于高阻狀態,其函數原型為:
其中,handle 為HC595 的實例句柄,范例程序詳見程序清單7.12。
程序清單7.12 am_hc595_disable()范例程序
3. 輸出數據
輸出數據的函數原型為:
其中,handle 為HC595 的實例句柄,p_data 為指向待輸出數據的緩沖區,nbytes 指定了輸出數據的字節數。對于單個HC595,其只能并行輸出8 位數據,即只能輸出單字節數據,其范例程序詳見程序清單7.13。
程序清單7.13 輸出單字節數據的范例程序
當需要并行輸出超過8 位數據時,可以使用多個HC595 級聯,此時即可輸出多字節數據,范例程序詳見程序清單7.14。
程序清單7.14 輸出多字節數據的范例程序
對于MiniPort-HC595,僅包含一個HC595,因此每次只能輸出1 字節數據。
>>> 7.2.2 HC595 驅動
AMetal 已經提供基于SPI 的HC595 的驅動,該驅動提供了一個初始化函數,使用該函數初始化一個HC595 實例后,即可得到一個通用的HC595 實例句柄。其函數原型為:
-
p_dev 為指向am_hc595_spi_dev_t 類型實例的指針;
-
p_info 為指向am_hc595_spi_info_t 類型實例信息的指針。
1. 實例
定義am_hc595_spi_dev_t 類型(am_hc595_spi.h)實例如下:
其中,g_miniport_595 為用戶自定義的實例,其地址作為p_dev 的實參傳遞。
2. 實例信息
實例信息主要描述了HC595 的相關信息,比如,鎖存引腳、輸出使能引腳以及SPI 速率等,其類型am_hc595_spi_info_t 的定義(am_hc595_spi.h)如下:
其中,pin_lock 指定了HC595 的鎖存引腳,即STR 引腳,該引腳與LPC824 連接的引腳為PIO0_14,因此pin_lock 的值應設置為PIO0_14。
pin_oe 指定了HC595 的輸出使能引腳,該引腳未與LPC824 連接,固定為低電平,因此pin_oe 的值應設置為-1。
clk_speed 指定了SPI 的速率,可根據實際需要設定,若HC595 的輸出用于驅動LED 或數碼管等設備,則對速率要求并不高,可設置為 300000(300KHz)。
lsb_first 決定了一個8 位數據在輸出時,輸出位的順序,若該值為AM_TRUE,則表明最低位先輸出,最高位后輸出,若該值為AM_FALSE,則表明最低位后輸出,最高位先輸出,最先輸出的位決定了HC595 輸出端Q7 的電平,最后輸出的位決定了HC595 輸出端Q0的電平。如設置為AM_TRUE,當后續發現輸出順序與期望輸出的順序相反時,可再將該值修改為AM_FALSE。基于以上信息,實例信息可以定義如下:
3. SPI 句柄handle
若使用LPC824 的SPI0 驅動HC595 輸出,則通過LPC82x 的SPI0 實例初始化函數am_lpc82x_spi0_inst_init()獲得SPI 句柄。即:
SPI 句柄即可直接作為handle 的實參傳遞。
3. 實例句柄
HC595 初始化函數am_hc595_spi_init ()的返回值即為HC595 實例的句柄,其作為HC595通用接口第一個參數(handle)的實參。其類型am_hc595_handle_t(am_hc595.h)定義如下:
若返回值為NULL,說明初始化失敗;若返回值不為NULL,說明返回了有效的handle。
基于模塊化編程思想,將初始化相關的實例和實例信息等定義存放在對應的配置文件中,通過頭文件引出實例初始化函數接口,源文件和頭文件的程序范例分別詳見程序清單7.15和程序清單7.16。
程序清單7.15 實例初始化函數范例程序(am_hwconf_miniport_595.c)
程序清單7.16 實例初始化函數接口(am_hwconf_miniport_595.h)
后續只需要使用無參數的實例初始化函數,即可獲取到HC595 的實例句柄:
當直接使用AM824-Core 與MiniPort-LED連接時,使用8 個GPIO 控制8 個LED,得益于MiniPort 接口的靈活性。當GPIO 資源不足時,可以在AM824-Core 與MiniPort-LED 之間增加MiniPort-595,使用595 的輸出控制LED,達到節省引腳的目的。
當將MiniPort-595 和MiniPort-LED 連接后,等效的原理圖詳見圖7.1。
圖7.1 MiniPort-595+MiniPort-LED
通過控制HC595的輸出,可以達到控制LED 點亮和熄滅的效果,范例詳見程序清單7.17。
程序清單7.17 74HC595 驅動LED 的范例程序
由此可見,通用接口的好處就是屏蔽了底層的差異性,使得無論底層硬件怎么變化,應用程序都可以使用同一套接口操作LED。顯然,無論是使用GPIO 直接驅動MiniPort-LED還是使用HC595 驅動MiniPort-LED,對于用戶來說,都可以使用標準接口訪問。AMeatl 提供了使用HC595 控制LED 的驅動,使用初始化函數完成相應實例的初始化后,即可使用通用接口操作LED。
>>> 7.2.3 使用HC595 驅動LED
AMetal 已經提供了使用HC595 控制LED 的驅動,該驅動提供了一個初始化函數,使用該函數初始化一個LED 實例后,即可使用通用LED 接口操作LED。其函數原型為:
-
p_dev 為指向am_led_hc595_dev_t 類型實例的指針;
-
p_info 為指向am_led_hc595_info_t 類型實例信息的指針。
1. 實例
定義am_led_hc595_dev_t 類型(am_led_hc595.h)實例如下:
其中,g_miniport_led_595 為用戶自定義的實例,其地址作為p_dev 的實參傳遞。
2. 實例信息
實例信息主要描述了HC595 驅動LED 的相關信息,比如,LED 是否低電平點亮,對應的LED 編號等信息。其類型am_led_hc595_info_t 的定義(am_led_hc595.h)如下:
(1)serv_info
serv_info 包含了通用接口訪問LED 的編號信息,當使用HC595 驅動時,編號信息可以保持不變,同樣為2~9。
(2)hc595_num
hc595_num 表示HC595 的個數,顯然一個HC595 只能輸出8 位數據,因此最多控制8個LED。當需要控制的LED 數目超過8 個時,則需要使用多個HC595 級聯。對于MiniPort-LED,其僅僅只有8 個LED,恰好使用一個HC595 控制8 個LED,因此hc595_num的值應設置為1。
(3)p_buf
p_buf 是指向一個大小為hc595_num 的緩沖區的指針,用于緩存各個595 當前的輸出值。由于hc595_num 的值設置為1,因此緩存的大小也為1,緩存定義如下:
其中,g_miniport_led_595_buf 為緩存首地址,即可作為p_buf 的值。
基于以上信息,實例信息定義如下:
3. HC595 句柄handle
若使用Miniport-595 的輸出控制MiniPort-LED,則應通過MiniPort-595 的實例初始化函數am_miniport_595_inst_init()獲得HC595 的句柄。即:
HC595 句柄即可直接作為handle 的實參傳遞,基于實例、實例信息和HC595 句柄,即可完成LED 實例的初始化:
由于HC595 是LED 的另一種驅動方式,因此將其新增到am_hwconf_miniport_led.c 文件中。為了便于使用,將實例初始化函數的聲明新增到am_hwconf_miniport_led.h 文件中,詳見程序清單7.18 和程序清單7.19。
程序清單7.18 實例初始化函數范例程序(am_hwconf_miniport_led.c)
程序清單7.19 am_hwconf_miniport_led.h 文件更新
后續只需要使用無參數的實例初始化函數,即可完成Miniport-LED 實例的初始化:
當完成初始化后,即可調用通用LED 接口操作LED~LED9。MiniPort-LED 有兩種驅動方式:GPIO 驅動和HC595 驅動,當使用MiniPort-LED 時,應該根據實際情況選擇對應的實例初始化函數。但無論何種驅動方式,在完成初始化后,對于應用程序來說都是調用通用LED 接口操作LED2~LED9。
7.3 蜂鳴器控制接口
>>> 7.3.1 蜂鳴器通用接口
為了實現跨平臺開發應用軟件,AMetal 提供了操作蜂鳴器的通用接口,詳見表7.3。
表7.3 蜂鳴器通用接口(am_buzzer.h)
1. 打開蜂鳴器
打開蜂鳴器的函數原型為:
打開蜂鳴器,使蜂鳴器開始鳴叫的范例程序詳見程序清單7.20。
程序清單7.20 am_buzzer_on()范例程序
2. 關閉蜂鳴器
關閉蜂鳴器的函數原型為:
關閉蜂鳴器,使蜂鳴器停止鳴叫的范例程序詳見程序清單7.21。
程序清單7.21 am_buzzer_off()范例程序
3. 蜂鳴器鳴叫指定時間(同步)
該函數用于打開蜂鳴器,使蜂鳴器鳴叫指定時間后自動關閉,該函數會一直等到蜂鳴器鳴叫結束后返回。其函數原型為:
使蜂鳴器鳴叫50 毫秒(“嘀”一聲)的范例程序詳見程序清單7.22。
程序清單7.22 am_buzzer_beep()范例程序
注意,由于該函數會一直等到蜂鳴器鳴叫結束后才會返回,因此主程序調用該函數后,會阻塞50ms。
4. 蜂鳴器鳴叫指定時間(異步)
該函數用于打開蜂鳴器,使蜂鳴器鳴叫指定時間后自動關閉,與am_buzzer_beep()函數不同的是,該函數會立即返回,不會等待蜂鳴器鳴叫結束。其函數原型為:
使蜂鳴器鳴叫50 毫秒(“嘀”一聲)的范例程序詳見程序清單7.23。
程序清單7.23 am_buzzer_beep_async()范例程序
注意,由于該函數不會等待蜂鳴器鳴叫結束,因此,主程序調用該函數后,會立即返回,不會被阻塞。顯然,要使應用程序可以使用通用接口操作蜂鳴器,就需要為具體的蜂鳴器設備提供相應的驅動。
>>> 7.3.2 無源蜂鳴器驅動
無源蜂鳴器內部沒有震蕩源,需要外部使用一定頻率的方波信號驅動才能發聲。AMetal已經提供了無源蜂鳴器的驅動,直接輸出PWM 驅動無源蜂鳴器發聲。其函數原型為:
其中,pwm_handle 為標準的PWM 服務句柄,chan 為PWM 通道號,duty_ns 為和period_ns分別指定了輸出PWM 波形的脈寬和周期,決定了蜂鳴器鳴叫的響度和頻率。AM824-Core板載了一個無源蜂鳴器。只要短接J7_1 與J7_2,則蜂鳴器接入PIO0_24。
LPC82x 能夠提供PWM 輸出功能的外設是SCT(State Configurable Timer),AMetal 提供了對應的實例初始化函數,其原型為:
若需使用SCT 輸出PWM,只需調用其對應的實例初始化函數即可獲取標準的PWM 服務句柄:
獲取的PWM 服務句柄即可作為am_buzzer_pwm_init()函數pwm_handle 的實參傳遞,當SCT 用作PWM 功能時,支持6 個通道,即可同時輸出6 路PWM,各通道對應的I/O 口詳見表7.4。
表7.4 各通道對應的IO 口
由于無源蜂鳴器使用的引腳為PIO0_24,其對應的通道為1,因此,chan 參數的值應設置為1。duty_ns 為和period_ns 分別指定了輸出PWM波形的脈寬和周期,若頻率設置為2500Hz,則對應的周期時間為:400000ns(1000000000 / 2500),占空比通常為50%(脈寬時間為周期時間的一半),即脈寬時間為:200000ns。實際中,可以根據實際發聲效果修改脈寬時間和周期時間。
基于對各個參數的分析,即可調用am_buzzer_pwm_init()完成無源蜂鳴器的初始化:
無源蜂鳴器作為一種板載資源,在系統啟動時已經默認進行了初始化操作,因此應用程序無需再手動調用無源蜂鳴器初始化函數,就可以直接使用通用接口操作蜂鳴器。
若用戶不需要使用蜂鳴器,為了節省內存空間,可以將工程配置文件(am_prj_config.h)中的AM_CFG_BUZZER_ENABLE 宏值修改為0,以裁剪掉蜂鳴器,該宏本質上控制了板級初始化函數中的一段程序,詳見程序清單7.24。
程序清單7.24 在板級初始化中裁剪蜂鳴器的原理
注:板級初始化函數在系統啟動時自動調用,初始化完畢后才會進入應用程序入口,即am_main()。
-
周立功
+關注
關注
38文章
130瀏覽量
37656 -
無源蜂鳴器
+關注
關注
0文章
41瀏覽量
11154
原文標題:周立功:面向通用接口的編程——LED 控制接口、HC595 接口、蜂鳴器控制接口
文章出處:【微信號:ZLG_zhiyuan,微信公眾號:ZLG致遠電子】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論