1. 程式人生 > >[nRF52832] 外設篇 | 實驗一 LED 燈 及 BUTTON 按鍵

[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

檔案中,該檔案用於存放板級支援函式(如 LED、BUTTON),其標頭檔案為 boards.h

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,似乎為了節省功耗?)