:本篇是我翻譯並加入自己理解的nRF51 SDK中按鈕相關操作的庫和先進先出隊列庫。雖然是nRF51的SDK,但是通過此文你將更多地了解到在BSP(板級支持)上層嵌入式程序或OS的構建方法。
1、按鈕相關操作庫
按鍵管理程序是通過GPIO事務和事件管理程序來檢測一個按鈕是否被按下的。當然,其中也做了消抖的工作——在GPIOTE事件中啟動一個定時器用來延時一段時間,當該定時器失效后如果按鈕仍然處於按下狀態,則會產生一個按鈕事件。如果在延時的過程中又有一個新的GPIOTE,那么這個定時器會重新被啟動。此外,在APP_BUTTON_INIT()參數中,使用USE_SCHEDULER參數來決定是否使用scheduler。(關於GPIOTE和SCHEDULER會在下面詳細講)
app_button模塊會用到app_timer模塊。用戶必須確保app_timer的隊列足夠大來容納app_timer_stop()和app_timer_start()操作(注意:這兩個操作會在每個GPIOTE事件中執行,所以頻度很高!)
ps:即使scheduler沒被用,app_button.h也要包含app_scheduler.h!
2、先進先出隊列
該隊列采用環形緩沖,其大小和緩沖區在初始化的地方配置,如下:
1 // Create a FIFO 2 structureapp_fifo_t my_fifo; 3 4 // Create a buffer for the FIFO 5 uint16_t buffer_size = 8; 6 uint8_t buffer[buffer_size]; 7 8 // Initialize FIFO structure 9 uint32_t err_code = app_fifo_init(&test_fifo, buffer, (uint16_t)sizeof(buffer));
ps:1.通過app_fifo_init函數,test_fifo會被初始化(其結構體如下)。2.buffer的大小應該是2的倍數。3.一定要確保當FIFO在用的時候,app_fifo_t的緩沖內存不被回收了
1 typedef struct{ 2 uint8_t * p_buf; /**< Pointer to FIFO buffer memory. */ 3 uint16_t buf_size_mask; /**< Read/write index mask. Also used for size checking. */ 4 volatile uint32_t read_pos; /**< Next read position in the FIFO buffer. */ 5 volatile uint32_t write_pos; /**< Next write position in the FIFO buffer. */ 6 } app_fifo_t;
這是個環形FIFO隊列,p_buf是調用初始化函數中傳入的數據池地址,read_pos和write_pos是讀地址和寫地址~此外,既然是環形FIFO就要用到mod,即:假設環形fifo數據池大小為n,當前寫入數據為第x個,則應該寫在xmodn位置。這里官方用了個小技巧(如下英語),首先要保證buffer-size是2的倍數,這樣xMODn就等於xAND(n-1)。
>>To simplify the index handling, the FIFO is restricted to require the buffer size <n>
, to be a power of two, as this reduces the modulus operation to become a simple AND operation with
. <n>
- 1
n = 8 = 0b00001000
n - 1 = 7 = 0b00000111
ANDing any number with <n>-1 , is identical to the modulus operation of <n>, when <n> is a power of two, see below:
3 = 11 mod 8 = 11 AND 7 = 0b00001011 & 0b00000111 = 0b00000011 = 3 .
♠ 若n=8,則初始狀態下FIFO為:
♠ 插入一個8位uint8數據則:
1 uint8_t data = 88; 2 // Add an element to the FIFO 3 err_code = app_fifo_put(&my_fifo, data);
上圖為插入4個uint8的效果~
♠ 取出一個8位uint8數據的代碼為:
1 // Consume one element from FIFO 2 uint8_t return_val; 3 err_code = app_fifo_get(&my_fifo, &return_val);
下圖為取出兩個的效果~
♠ Empty Buffer
當read_pos=write_pos時表示buffer是空的。
初始化的時候讀寫位置都置為0、buffer內的內容被取完或者調用app_fifo_flush。
此時再調用讀函數則返回沒數據。
♠ Full Buffer
當write_pos == read_pos + <n>時表示buffer是滿的。
此時再調用寫函數則返回沒內存。
@beautifulzzzz 2016-01-01 continue~