實驗01 - GPIO輸出控制LED 引腳輸出配置:nrf_gpio_cfg_output(LED_1); 引腳輸出置高:nrf_gpio_pin_set(LED_1); 引腳電平轉換:nrf_gpio_pin_toggle(LED_1); 毫秒延時:nrf_delay_ms(100); 實驗02 ...
實驗01 - GPIO輸出控制LED
- 引腳輸出配置:nrf_gpio_cfg_output(LED_1);
- 引腳輸出置高:nrf_gpio_pin_set(LED_1);
- 引腳電平轉換:nrf_gpio_pin_toggle(LED_1);
- 毫秒延時:nrf_delay_ms(100);
1 int main(void) 2 { 3 nrf_gpio_cfg_output(LED_1);//配置P0.21為輸出 4 nrf_gpio_pin_set(LED_1); //指示燈D1初始狀態為熄滅 5 6 while (true) 7 { 8 //指示燈D1以200ms的間隔閃爍 9 nrf_gpio_pin_toggle(LED_1); 10 nrf_delay_ms(100); 11 } 12 }
實驗02 - 跑馬燈(略)
實驗03 - GPIO輸入按鍵檢測
- 多個引腳同時初始化輸出:nrf_gpio_range_cfg_output(LED_START, LED_STOP);
- 多個引腳同時初始化輸入:nrf_gpio_range_cfg_input(BUTTON_START,BUTTON_STOP,NRF_GPIO_PIN_PULLUP);
- 讀取某引腳的電平狀態:nrf_gpio_pin_read(BUTTON_1) == 0
1 int main(void) 2 { 3 nrf_gpio_range_cfg_output(LED_START, LED_STOP);//配置P0.21~P0.24為輸出 4 nrf_gpio_pin_set(LED_1); //LED初始狀態為熄滅 5 nrf_gpio_range_cfg_input(BUTTON_START,BUTTON_STOP,NRF_GPIO_PIN_PULLUP);//配置P0.17~P0.20為輸入 6 7 8 while (true) 9 { 10 //檢測按鍵S1是否按下 11 if(nrf_gpio_pin_read(BUTTON_1) == 0) 12 { 13 nrf_gpio_pin_clear(LED_1); 14 while(nrf_gpio_pin_read(BUTTON_1) == 0);//等待按鍵釋放 15 nrf_gpio_pin_set(LED_1); 16 } 17 } 18 }
實驗04 - GPIO控制蜂鳴器(略)
實驗05 - RGB三色LED(略)
實驗06 - UART數據收發
調用了串口FIFO驅動,是在串口上繼續封裝一層的
-
/**@brief Function for getting a byte from the UART.
*
* @details This function will get the next byte from the RX buffer. If the RX buffer is empty
* an error code will be returned and the app_uart module will generate an event upon
* reception of the first byte which is added to the RX buffer.
*
* @param[out] p_byte Pointer to an address where next byte received on the UART will be copied.
*
* @retval NRF_SUCCESS If a byte has been received and pushed to the pointer provided.
* @retval NRF_ERROR_NOT_FOUND If no byte is available in the RX buffer of the app_uart module.
*/
uint32_t app_uart_get(uint8_t * p_byte); -
/**@brief Function for putting a byte on the UART.
*
* @details This call is non-blocking.
*
* @param[in] byte Byte to be transmitted on the UART.
*
* @retval NRF_SUCCESS If the byte was successfully put on the TX buffer for transmission.
* @retval NRF_ERROR_NO_MEM If no more space is available in the TX buffer.
* NRF_ERROR_NO_MEM may occur if flow control is enabled and CTS signal
* is high for a long period and the buffer fills up.
*/
uint32_t app_uart_put(uint8_t byte);
1 int main(void) 2 { 3 LEDS_CONFIGURE(LEDS_MASK); 4 LEDS_OFF(LEDS_MASK); 5 uint32_t err_code; 6 const app_uart_comm_params_t comm_params = 7 { 8 RX_PIN_NUMBER, 9 TX_PIN_NUMBER, 10 RTS_PIN_NUMBER, 11 CTS_PIN_NUMBER, 12 APP_UART_FLOW_CONTROL_DISABLED, 13 false, 14 UART_BAUDRATE_BAUDRATE_Baud38400 15 }; 16 17 APP_UART_FIFO_INIT(&comm_params, 18 UART_RX_BUF_SIZE, 19 UART_TX_BUF_SIZE, 20 uart_error_handle, 21 APP_IRQ_PRIORITY_LOW, 22 err_code); 23 24 APP_ERROR_CHECK(err_code); 25 26 while (true) 27 { 28 uint8_t cr; 29 while(app_uart_get(&cr) != NRF_SUCCESS); //等待接收串口數據 30 while(app_uart_put(cr) != NRF_SUCCESS); //返回接收到的串口數據 31 32 if (cr == 'q' || cr == 'Q') 33 { 34 printf(" \n\rExit!\n\r"); 35 36 while (true) 37 { 38 // Do nothing. 39 } 40 } 41 } 42 }
實驗07 - UART控制指示燈(略)
實驗08 - 隨機數發生器
Random number generator
利用NRF51822 隨機數發生器生成隨機數,每隔500ms 通過串口輸出一次隨機數數值
/** @brief Function for getting vector of random numbers.
*
* @param[out] p_buff Pointer to unit8_t buffer for storing the bytes.
* @param[in] length Number of bytes to take from pool and place in p_buff.
*
* @retval Number of bytes actually placed in p_buff.
*/
uint8_t random_vector_generate(uint8_t * p_buff, uint8_t size)
{
uint8_t available;
uint32_t err_code;
err_code = nrf_drv_rng_bytes_available(&available);
APP_ERROR_CHECK(err_code);
uint8_t length = (size<available) ? size : available;
err_code = nrf_drv_rng_rand(p_buff,length);
APP_ERROR_CHECK(err_code);
return length;
}
1 int main(void) 2 {
...... 3 while (true) 4 { 5 uint8_t p_buff[RANDOM_BUFF_SIZE]; 6 uint8_t length = random_vector_generate(p_buff,RANDOM_BUFF_SIZE); 7 printf("Random Vector:"); 8 for(uint8_t i = 0; i < length; i++) //串口輸出RNG 9 { 10 printf(" %3d",(int)p_buff[i]); 11 } 12 printf("\r\n"); 13 nrf_delay_ms(500); //延時,方便觀察數據 14 nrf_gpio_pin_toggle(LED_1); //指示燈D1指示程式運行 15 } 16 }
實驗09 - 看門狗
配置NRF51822 的看門狗超時周期為2 秒,CPU 休眠時看門狗保持運行。
- NRF51822 的看門狗定時器是倒計數器,當計數值減少到0 時產生TIMEOUT 事件。
- 通過START task 來啟動看門狗定時器。
- 看門狗定時器啟動時,如沒有其他32.768KHz 時鐘源提供時鐘,看門狗定時器會強制打開32.768KHz RC 振蕩器。
-
預設情況下,看門狗定時器會在CPU 睡眠期間,或是debugger 將CPU 暫停的時候保持運行。但是,可以通過配置看門狗定時器,使其在CPU 睡眠期間,或是debugger 將CPU 暫停的時候自動暫停。
- 看門狗定時器超時周期:超時時間= ( CRV + 1 ) / 32768 秒
1 int main(void) 2 { 3 uint32_t err_code = NRF_SUCCESS; 4 5 //配置開發板上的4個用戶LED指示燈 6 LEDS_CONFIGURE(LEDS_MASK); 7 LEDS_OFF(LEDS_MASK); 8 9 //4個指示燈輪流閃爍一次,指示系統啟動 10 for(uint32_t i = 0; i < LEDS_NUMBER; i++) 11 { nrf_delay_ms(200); 12 LEDS_ON(BSP_LED_0_MASK << i); 13 } 14 15 //BSP configuration for button support: button pushing will feed the dog. 16 err_code = nrf_drv_clock_init(NULL); 17 APP_ERROR_CHECK(err_code);//檢查返回值 18 nrf_drv_clock_lfclk_request(); 19 20 APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);//定時器設置 21 err_code = bsp_init(BSP_INIT_BUTTONS, APP_TIMER_TICKS(100, APP_TIMER_PRESCALER), bsp_event_callback);//按鍵中斷配置 22 APP_ERROR_CHECK(err_code); 23 24 25 //配置WDT. 26 nrf_drv_wdt_config_t config = NRF_DRV_WDT_DEAFULT_CONFIG;//採用預設設置 27 err_code = nrf_drv_wdt_init(&config, wdt_event_handler);//使用預設參數配置看門狗。即CPU睡眠時,看門狗保持運行;看門狗超時周期2秒 28 APP_ERROR_CHECK(err_code); 29 err_code = nrf_drv_wdt_channel_alloc(&m_channel_id);//分配一個通道id 30 APP_ERROR_CHECK(err_code); 31 nrf_drv_wdt_enable();//使能看門狗 32 33 while(1) 34 { 35 __SEV(); //設置事件 36 __WFE(); //進入睡眠,等待事件喚醒 37 __WFE(); 38 } 39 }
- 每按下一次S1 按鍵,進行一次喂狗操作:
1 void bsp_event_callback(bsp_event_t event)
2 {
3 switch(event)
4 {
5 case BSP_EVENT_KEY_0:
6 nrf_drv_wdt_channel_feed(m_channel_id);
7 break;
8 default : //Do nothing. break;
9 }
10 }
- 如果2 秒內,按下按鍵S1 進行喂狗,系統正常運行,4 個指示燈常亮。如果2 秒內,不進行喂狗操作,系統複位:
1 void wdt_event_handler(void)
2 {
3 LEDS_OFF(LEDS_MASK);
4 //NOTE: The max amount of time we can spend in WDT interrupt is two cycles of 32768[Hz] clock - after that, reset occurs
5 }
實驗10 - 定時器
※ 配置NRF51822 的TIMER0 如下:
- 時鐘:16MHz。
- 模式:定時器。
- 位寬:32 位。
- 比較時間:500ms。
※ 計數器開始計數後,當計數器里的值和比較寄存器里的值相等時,產生輸出比較匹配事件,觸發中斷。在中斷服務函數中輪流翻轉開發板上的4 個LED 指示燈D1~D4。
- NRF51822 共有3 個定時器TIMER0,TIMER1,TIMER2。
- NRF51822 的TIMER 有兩種工作模式:定時模式和計數模式。在兩種模式下都是通過START task 啟動TIMER,通過STOP task 停止TIMER。當TIMER 停止時可以通過START task 讓TIMER 恢復運行,恢復運行後,TIMER 從停止時的定時/計數值繼續定時/計數。
-
定時器時鐘:定時器的時鐘由PCLK16M 分頻而來,公式如下:ftimer=16MHz/(2^PRESCALER)
-
1 int main(void) 2 { 3 uint32_t time_ms = 500; //Time(in miliseconds) between consecutive compare events. 4 uint32_t time_ticks; 5 uint32_t err_code = NRF_SUCCESS; 6 7 8 LEDS_CONFIGURE(LEDS_MASK);//配置開發板上驅賭LED的管腳為輸出 9 LEDS_OFF(LEDS_MASK); //熄滅LED D1~D4 10 11 //Configure TIMER_LED for generating simple light effect - leds on board will invert his state one after the other. 12 err_code = nrf_drv_timer_init(&TIMER_LED, NULL, timer_led_event_handler);//初始化 13 APP_ERROR_CHECK(err_code); 14 15 time_ticks = nrf_drv_timer_ms_to_ticks(&TIMER_LED, time_ms); 16 17 nrf_drv_timer_extended_compare(//設置比較寄存器中的值(本實驗設置的值對應於500ms)。計數器開始計數後,當計數器里的值和比較寄存器里的值相等時,產生輸出比較匹配事件,觸發中斷。 18 &TIMER_LED, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true); 19 20 nrf_drv_timer_enable(&TIMER_LED);//啟動 21 22 while(1) 23 { 24 __WFI(); //進入睡眠,等待中斷 25 } 26 }
定時器(TIMER0)啟動後,系統通過“__WFI();”指令進入睡眠等待比較匹配事件觸發中斷喚醒,中斷發生後,在中斷服務函數中輪流翻轉開發板上的4 個LED 指示燈的狀態:
1 /**
2 * @brief Handler for timer events. 輪流翻轉開發板上的4個指示燈D1~D4的狀態
3 */
4 void timer_led_event_handler(nrf_timer_event_t event_type, void *p_context)
5 {
6 static uint32_t i;
7 uint32_t led_to_invert = (1 << leds_list[(i++) % LEDS_NUMBER]);
8
9 switch(event_type)
10 {
11 case NRF_TIMER_EVENT_COMPARE0:
12 LEDS_INVERT(led_to_invert);
13 break;
14
15 default:
16 //Do nothing.
17 break;
18 }
19 }
@beautifulzzzz - 物聯網&普適計算實踐者
e-mail:[email protected]
i-blog:blog.beautifulzzzz.com