[nRF52832] 外設篇 | 實驗一 LED 燈 及 BUTTON 按鍵
SDK:nRF5_SDK_12.2.0
1. 概述
實驗一用於講解 nRF52832 SDK v12.2.0 關於 LED 燈及 BUTTON 按鍵的板級支援函式及使用方法。利用板級支援函式可以控制在硬體上設定 LED 燈的有效狀態(高電平亮還是低電平亮),在軟體上配置 LED 的管腳和數量則可以方便地讀取並設定 LED 的狀態,達到快速開發的目的,BUTTON 按鍵與 LED 燈實現原理類似。
1.1 工程目錄
- 進入官方 SDK 外設工程目錄的 blinky 例程,該例程提供 LED 閃爍的模板;
..\nRF5_SDK_12.2.0_f012efa\examples\peripheral\blinky\ - 依次進入 pca10040 板型,s132 版本協議棧,arm5(MDK5) 開發環境目錄 ,開啟 Keil 工程檔案。
…\blinky\pca10040\s132\arm5_no_pack\blinky_pca10040_s132.uvprojx
1.2 工程講解
官方例程程式碼入口 MDK5 Project:Application\main.c 中,如下文程式碼所示,在主函式 main() 中呼叫 bsp_board_leds_init() 函式初始化 LED 裝置,while 迴圈任務中每隔 500ms 反轉一次所有的 LED 燈(共 LEDS_NUMBER 個 LED 燈)的亮滅。
int main(void)
{
/* Configure board. */
bsp_board_leds_init();
/* Toggle LEDs. */
while (true)
{
for (int i = 0; i < LEDS_NUMBER; i++)
{
bsp_board_led_invert(i);
nrf_delay_ms(500);
}
}
}
2. 定義與宣告
上文例程的 bsp 字首函式位於在 MDK5 Project:Board Definition\boards.c
2.1 巨集定義
在 board.c 跟 board.h 檔案中引用了一些 LED 字首的巨集定義,這些巨集定義被定義在 pca10040.h(選擇哪塊板就是哪個板級配置標頭檔案) 中,如下所示:
// LEDs definitions for PCA10040
#define LEDS_NUMBER 4 /*!< 定義 LED 的個數 */
#define LED_START 17 /*!< 定義第一個 LED 的控制管腳號 */
#define LED_1 17 /*!< 定義 LED_1 的管腳號 */
#define LED_2 18 /*!< 定義 LED_2 的管腳號 */
#define LED_3 19 /*!< 定義 LED_3 的管腳號 */
#define LED_4 20 /*!< 定義 LED_4 的管腳號 */
#define LED_STOP 20 /*!< 定義最後一個 LED 控制管腳號 */
#define LEDS_ACTIVE_STATE 0 /*!< 定義 LED 有效狀態:0-低電平,1-高電平 */
#define LEDS_LIST { LED_1, LED_2, LED_3, LED_4 } /*!< LED 列表,上面定義的 LED 應填入列表 */
2.1 LED 陣列緩衝區
在 board.c 聲明瞭一個靜態常量全域性陣列 m_board_led_list,用於存放 LED 列表,空間大小為 LEDS_NUMBER,內容為上文巨集定義中的 LEDS_LIST ,由此我們可知當 led_idx = 0 時,m_board_led_list[led_idx] 為 LED_1,其他 LED 依次類推。
static const uint8_t m_board_led_list[LEDS_NUMBER] = LEDS_LIST;
3. 函式介面
● void bsp_board_leds_init(void)
用途:初始化所有的 LED 燈裝置
引數:無
返回:無
● bool bsp_board_led_state_get(uint32_t led_idx)
用途:獲取 led_idx 的 LED 的當前狀態
引數:- led_idx:LED列表序號,最大等於LEDS_NUMBER-1
返回:- true(1):LED 亮
- flase(0):LED 滅
這裡值得注意的是:在硬體上板級 LED 統一使用同一種有效狀態,即 LEDS_ACTIVE_STATE 配置高電平亮(有效)或者低電平亮(有效),預設為0-低電平亮(有效),呼叫該函式對高低電平亮做了相容,使用者在軟體上只需關注 true 跟 flase 就可以。
● void bsp_board_led_on(uint32_t led_idx)
用途:設定 led_idx 的 LED 亮
引數:- led_idx:LED列表序號,最大等於LEDS_NUMBER-1
返回:無
● void bsp_board_led_off(uint32_t led_idx)
用途:設定 led_idx 的 LED 滅
引數:- led_idx:LED列表序號,最大等於LEDS_NUMBER-1
返回:無
● void bsp_board_led_invert(uint32_t led_idx)
用途:反轉 led_idx 的 LED 狀態
引數:- led_idx:LED列表序號,最大等於LEDS_NUMBER-1
返回:無
● void bsp_board_leds_off(void)
用途:關閉所有的 LED 燈
引數:無
返回:無
● void bsp_board_leds_on(void)
用途:開啟所有的 LED 燈
引數:無
返回:無
● uint32_t bsp_board_pin_to_led_idx(uint32_t pin_number)
用途:將 LED 的管腳序號轉化成 LED 的燈序號
引數:- pin_number :GPIO管腳序號
返回:- 0xFFFFFFFF 無效管腳序號
- 其他值: LED 的燈序號
● uint32_t bsp_board_led_idx_to_pin(uint32_t led_idx)
用途:將 LED 的燈序號轉化成 LED 的管腳序號
引數:- led_idx:LED列表序號,最大等於LEDS_NUMBER-1
返回:- GPIO管腳序號
具體函式實現方式在board.c,相對比較簡單,可自行通過閱讀程式碼學習,該檔案還包含 BUTTON 的板級支援函式,原理類似於 LED ,此處不再講解。)
3. 實驗
接下通過一個實驗演示上文函式,讓 LED_0 1s 閃爍一次,LED_1 狀態跟隨 LED_0, LED2 狀態與 LED_0 相反。
int main(void)
{
/* 初始化所有的 LED 燈裝置 */
bsp_board_leds_init();
while(true)
{
/* 反轉 LED_0 狀態 */
bsp_board_led_invert(0);
/* 讀取 LED_0 狀態 */
if(true == bsp_board_led_state_get(0))
{
/* 若 LED_0 亮,則點亮 LED_1, 熄滅 LED_2 */
bsp_board_led_on(1);
bsp_board_led_off(2);
}
else
{
/* 若 LED_0 滅,則熄滅 LED_1, 點亮 LED_2 */
bsp_board_led_off(1);
bsp_board_led_on(2);
}
/* 延時軟體1s */
nrf_delay_ms(1000);
}
}
4. 拓展
官方 SDK 外設工程目錄下還有基於 FreeRTOS 的 blinky_freertos 例程可供學習。此外上文提到的nrf_delay_ms() 毫秒級延時函式是利用軟體機器週期延時,外設工程目錄下有一個 blinky_systick 例程利用滴答定時器準確延時(在nRF52832中,預設不使用 systick,似乎為了節省功耗?)