2015-6-10
声明:
因为我这几个月项目相当紧急,在搞嵌入式的方案,不再负责单片机的方案了。
单片机NRF51822的方案在当时的考察中,发现不合适,已经不再继续往下做了。早已替换了方案。
这篇博文我也没有时间再去写了,爱莫能助。
建议正在搞NRF51822的童鞋们,找一份已经演示通的代码,例如心率计的这套代码。
把这套代码搞通搞透,不懂的函数、变量和宏定义,可以去查NRF官方提供的手册。也可以自己做假设,然后做实验做验证。
NRF51822项目实战
2014-12-23
首先,需要查到蓝牙发送数据的API接口,可能是类似于网络sock的recv()和send()
拿到用户手册,看到可以参考的第一份代码是心率计,ble_app_hrs这个例程。
之前不知道这个例程的功能,一通乱找都没找到,照着用户手册试了下这个例程,很快就知道突破口了,去找那个按键触发的后续代码,
首先是按键初始化buttons_init(),找到了它有个类似的注册函数button_event_handler,接着进去,找到m_cur_heart_rate这个量,那就接着去找这个变量相关的操作,最后找到
接下来围绕这个API解析外层代码。
后续所有要讲的都是围绕这个API来解析外层代码,搞清楚了相关的流程和函数,就知道怎么改成自己需要的代码了。
2014-12-24
心率计的功能演示:
按开发板上KEY1,手机端会看到心率参数增加
按开发板上KEY2,手机端会看到心率参数减少
代码先从上层往底层解析。
先看main函数
int main(void)
{
uint32_t err_code;
timers_init();
gpiote_init();
buttons_init();
ble_stack_init();
bond_manager_init();
// Initialize Bluetooth Stack parameters
gap_params_init();
advertising_init();
services_init();
conn_params_init();
sec_params_init();
// Start advertising
advertising_start();
// Enter main loop
for (;;)
{
// Switch to a low power state until an event is available for the application
err_code = sd_app_evt_wait();
APP_ERROR_CHECK(err_code);
}
}
上面5个函数都是初始化,首先是定时器的初始化,先就不进去看了。然后是gpiote的初始化,不知道是不是KEY那两IO的初始化,先进去看看
static void gpiote_init(void)
{
// Configure the GPIOTE Task to toggle the LED state.
nrf_gpiote_task_config(GPIOTE_CHAN_FOR_LED_TASK,
ADVERTISING_LED_PIN_NO,
NRF_GPIOTE_POLARITY_TOGGLE,
NRF_GPIOTE_INITIAL_VALUE_LOW);
}
然来是初始化那几个LED的。
退出接着看buttons_init,进入
/**@brief Function for initializing the button module.
*/
static void buttons_init(void)
{
// Configure HR_INC_BUTTON_PIN_NO and HR_DEC_BUTTON_PIN_NO as wake up buttons and also configure
// for 'pull up' because the eval board does not have external pull up resistors connected to
// the buttons.
static app_button_cfg_t buttons[] =
{
{HR_INC_BUTTON_PIN_NO, false, BUTTON_PULL, button_event_handler},
{HR_DEC_BUTTON_PIN_NO, false, BUTTON_PULL, button_event_handler} // Note: This pin is also BONDMNGR_DELETE_BUTTON_PIN_NO
};
APP_BUTTON_INIT(buttons, sizeof(buttons) / sizeof(buttons[0]), BUTTON_DETECTION_DELAY, false);
}
功能是初始化按键模块
HR_INC_BUTTON_PIN_NO和HR_DEC_BUTTON_PIN_NO分别对应KEY1和KEY2,false在这里的逻辑意义不知道,先不管。
BUTTON_PULL明显是表示该IO用内部上拉方式,button_event_handler这个,应该是回调函数,在发生按键外部中断是,被调用到的,类似于注册方式。
进入这个函数看看
/**@brief Function for handling button events.
*
* @param[in] pin_no The pin number of the button pressed.
*/
static void button_event_handler(uint8_t pin_no, uint8_t button_action)
{
if (button_action == APP_BUTTON_PUSH)
{
switch (pin_no)
{
case HR_INC_BUTTON_PIN_NO:
// Increase Heart Rate measurement
m_cur_heart_rate += HEART_RATE_CHANGE;
if (m_cur_heart_rate > MAX_HEART_RATE)
{
m_cur_heart_rate = MIN_HEART_RATE; // Loop back
}
break;
case HR_DEC_BUTTON_PIN_NO:
// Decrease Heart Rate measurement
m_cur_heart_rate -= HEART_RATE_CHANGE;
if (m_cur_heart_rate < MIN_HEART_RATE)
{
m_cur_heart_rate = MAX_HEART_RATE; // Loop back
}
break;
default:
APP_ERROR_HANDLER(pin_no);
break;
}
}
}
非常清晰,就是在发生外部中断时,检测是哪个IO被拉低了,对应的增加或减少m_cur_heart_rate这个参数。
这里特别注意m_cur_heart_rate这个参数,后续蓝牙发送数据,一定会和它有关联,顺着它我才找到sd_ble_gatts_hvx这个发送的函数。
回退到上层,APP_BUTTON_INIT()应该就是类似于注册函数了,不深入去看了。
接着ble_stack_init(),蓝牙协议栈初始化,进入:
static void ble_stack_init(void)
{
uint32_t err_code;
// Initialize the SoftDevice handler module.
SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false);
// Register with the SoftDevice handler module for BLE events.
err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
APP_ERROR_CHECK(err_code);
// Register with the SoftDevice handler module for BLE events.
err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
APP_ERROR_CHECK(err_code);
}
这里面就3个函数,都已经有注释,就不再解释了,其实我也没看明白。没事,先接着往下走,后面看完了再回头来理清楚。
退出看bond_manager_init
/**@brief Function for the Bond Manager initialization.
*/
static void bond_manager_init(void)
{
uint32_t err_code;
ble_bondmngr_init_t bond_init_data;
bool bonds_delete;
// Initialize persistent storage module.
err_code = pstorage_init();
APP_ERROR_CHECK(err_code);
// Clear all bonded centrals if the Bonds Delete button is pushed
err_code = app_button_is_pushed(BONDMNGR_DELETE_BUTTON_PIN_NO, &bonds_delete);
APP_ERROR_CHECK(err_code);
// Initialize the Bond Manager
bond_init_data.evt_handler = NULL;
bond_init_data.error_handler = bond_manager_error_handler;
bond_init_data.bonds_delete = bonds_delete;
err_code = ble_bondmngr_init(&bond_init_data);
APP_ERROR_CHECK(err_code);
}
虽然有注释,不过还是看不懂,接着往下走。
回到main函数
// Initialize Bluetooth Stack parameters
gap_params_init();
advertising_init();
services_init();
conn_params_init();
sec_params_init();
初始化蓝牙协议栈的参数,很关键。
首先是