智能穿戴——nRF51822开发总结

工作的要求,最近断断续续的做了一些关于Nordic公司的 51822芯片的应用开发,这篇博客主要是总结下在工作中遇到的问题和一些解决思路

1、简介

简介我摘取 Nordic 官方规格书的说明如下:

nRF51822 is an ultra-low power 2.4GHz wireless System-on-Chip(SoC) integrating the nRF51 series 2.4GHz transceiver, a 32 bit ARM Cortex-M0 CPU, flash memory, and analog and digital periherals. nRF51822 can support Bluetooth low wnergy and a range of proprietary 2.4GHz protocols, such as Gazell from Nordic Semiconductor.

Fully qualified Bluetooth low energy stacks fir nRF51822 arm implemented in the S100 series SoftDevices. The S100 series of SoftDevices are available for free and can be downloaded and installed on nRF51822 independent of your own application code.

大概讲的意思是,51822是一款这样的芯片,低功耗、支持2.4G、32位ARM、cortex-M0架构、是一款蓝牙芯片


2、接下来,我们看看蓝牙的协议栈究竟是怎样的一种关系。蓝牙低功耗协议栈架构图如下所示:

智能穿戴——nRF51822开发总结_第1张图片

协议栈详细有7层,由下而上包括:物理层、链路层、逻辑链路控制、安全协议、属性协议、访问配置、属性配置、应用程序配置和服务,其实这么多的层析,在实际的开发中我们正真需要关心的只有最上面的应用程序配置和服务层,其余的几层,芯片出厂时就已经封装好,所以接下来的开发就明显简单的多了……


3、到 Nordic 官网上下载最新的SDK,安装好之后,会在如下目录产生相应的文件,

C:\Keil\ARM\Device\Nordic\nrf51822,这些SDK源码包,能够使我们更快的了解51822这款芯片,使用这些程序,日后开发就显得简单多了……

下面简单的总结下,经常用到的一些函数和这些函数的功能介绍

串口操作:51822有一个串口,通过配置可以使用不同引脚作为串口的输入输出脚,同时支持串口中断

// 串口发送 1 byte
void simple_uart_put(uint8_t cr)

//与上面发送对应的,串口接受 1byte
uint8_t simple_uart_get(void)
//串口的配置
void simple_uart_config(  uint8_t rts_pin_number,
                          uint8_t txd_pin_number,
                          uint8_t cts_pin_number,
                          uint8_t rxd_pin_number,
                          bool    hwfc)

//串口初始化和中断使能
static void uart_init(void)
{
    /**@snippet [UART Initialization] */
    simple_uart_config(RTS_PIN_NUMBER, TX_PIN_NUMBER, CTS_PIN_NUMBER, RX_PIN_NUMBER, HWFC);
    
    NRF_UART0->INTENSET = UART_INTENSET_RXDRDY_Enabled << UART_INTENSET_RXDRDY_Pos;
    
    NVIC_SetPriority(UART0_IRQn, APP_IRQ_PRIORITY_LOW);
    NVIC_EnableIRQ(UART0_IRQn);
    /**@snippet [UART Initialization] */
}

//串口中断处理句柄函数
void UART0_IRQHandler(void)
GPIO管脚操作:GPIO管脚操作的函数比较多,介绍几个常用的,函数比较简单,不做详细分析;其中51822最大支持4个GPIO中断

//往一个管脚写
static __INLINE void nrf_gpio_pin_write(uint32_t pin_number, uint32_t value)
//读取一个管脚的值
static __INLINE uint32_t nrf_gpio_pin_read(uint32_t pin_number)
//读取一组管脚的值
static __INLINE uint8_t nrf_gpio_port_read(nrf_gpio_port_select_t port)
//写一组管脚的值
static __INLINE void nrf_gpio_port_write(nrf_gpio_port_select_t port, uint8_t value)
//设置一组管脚的值
static __INLINE void nrf_gpio_port_set(nrf_gpio_port_select_t port, uint8_t set_mask)

//将一组管脚 清零
static __INLINE void nrf_gpio_port_clear(nrf_gpio_port_select_t port, uint8_t clr_mask)
//设置单个管脚值
static __INLINE void nrf_gpio_pin_set(uint32_t pin_number)
//对单个管脚清零
static __INLINE void nrf_gpio_pin_clear(uint32_t pin_number)
//配置管脚为输出
static __INLINE void nrf_gpio_cfg_output(uint32_t pin_number)

//配置管脚为出入
static __INLINE void nrf_gpio_cfg_input(uint32_t pin_number, nrf_gpio_pin_pull_t pull_config)

//GPIO管脚中断配置
NVIC_EnableIRQ(GPIOTE_IRQn);
    NRF_GPIOTE->CONFIG[0] =  (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos)
                           | (0 << GPIOTE_CONFIG_PSEL_Pos)  
                           | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
    NRF_GPIOTE->INTENSET  = GPIOTE_INTENSET_IN0_Set << GPIOTE_INTENSET_IN0_Pos;
//GPIO中断处理句柄函数
void GPIOTE_IRQHandler(void)

定时器操作:51822总的有3个定时器,可以用来中断使用,下面介绍几个函数和函数的功能

//定时器 0 初始化函数
static void timer0_init(void)

//定时器 0 处理句柄函数
void TIMER0_IRQHandler(void)
其余的两个定时器 timer1 和timer2 可以模仿 timer0做出相应的配置之后,便可以使用
//定时器中断使能
    NVIC_EnableIRQ(TIMER0_IRQn); 
    __enable_irq();
实时时钟:与上面提到的定时器相关的实时时钟,51822中有一个实时时钟,相关函数如下

//实时时钟初始化
static void rtc1_init(uint32_t prescaler)

//实时时钟使能
static void rtc1_start(void)
//实时时钟中断操作
 NVIC_ClearPendingIRQ(RTC1_IRQn);
    NVIC_EnableIRQ(RTC1_IRQn);

//实时时钟处理句柄函数
void RTC1_IRQHandler(void)
更多的始终操作函数在 C:\Keil\ARM\Device\Nordic\nrf51822\Board\nrf6310\ble\ble_app_gzll\ble_gzll_app_timer.c文件中,这里就不再详细的说明


4、简单的介绍51822的蓝牙开发,下面介绍只是一个的抛砖引玉的,其他的开发可以类似,OK,有了上面的一些函数简单的介绍之后,后面的用到就容易多了,51822所有的蓝牙应用开发的,程序架构都是一样的,Nordic的SDK已经做了相当详细的说明,下面我们看看主函数

int main(void)
{
    // Initialize.
    leds_init();
    buttons_init();
    ble_stack_init();
    bond_manager_init();
    timers_init();
    gap_params_init();
    advertising_init();
    services_init();
    sensor_sim_init();
    conn_params_init();
    sec_params_init();

    // Start execution.
    application_timers_start();
    advertising_start();

    // Enter main loop.
    for (;;)
    {
        power_manage();
    }
}
主函数调用的函数有十几个,但正真需要我们去关心的也就三四个,首先需要我们去关心的

static void services_init(void)
这里我们主要是添加一些自己使用到的seervices
还有就是在下面的蓝牙功能函数中

static void on_ble_evt(ble_evt_t * p_ble_evt)
在  case BLE_GAP_EVT_CONNECTED: 之后添加自己在蓝牙连接上之后,需要的工作
到目前为止,其余大函数不需要做太多的修改,一个简单的蓝牙应用程序OK了,编译下载之后,你会神奇的发现,自己的手机上能够找到该蓝牙设备(说明51822是基于蓝牙4.0的,所以比4.0低的版本的系统是不能找到该蓝牙设备)


5、工作中遇到的问题

下面说说我在弄51822时遇到的问题,遇到的问题有那么些,挑个自己认为比较重要的说下吧!

公司接了个项目,主要是做一个通过蓝牙发送命令,然后接受客户端返回来的命令,比较命令做相应的处理……我一开始通过使用ble_uart,蓝牙串口的例子,板子通过接受串口获得的数据产生中断,然后将串口获得的数据,存储在一个static的静态数组中,追后通过了蓝牙发送出去,到客户端……用串口处理,完全没有问题,但是产品最终不提供外设接口,也就不能用串口来控制了,用按键控制,通过按键产生中断,在中断处理句柄函数中去发送蓝牙命令包,好的,有这样的思想,那就去做呗,可以当我添加了按键中断之后,能正确的出发中断。可是一个奇葩的问题产生了,一旦按键按下,程序就会卡死……

单片机的调试实在是让人感觉头疼,不能很爽的看printk 或printf打印,只能看一些LED的反应判断程序跑到了哪里,程序在什么地方挂掉……

就是这样的一个问题,我活活的折腾了两天的时间,后来终于解决了,按键中断的优先级 与 uart 中断的优先级的级别不相同,这样会导致按键产生的中断使程序挂掉。

详细的更正如下

 NVIC_ClearPendingIRQ(GPIOTE_IRQn);
 NVIC_SetPriority(GPIOTE_IRQn, NRF_APP_PRIORITY_LOW); //优先级的设置,设置成和uart的优先级一样,就OK了
 NVIC_EnableIRQ(GPIOTE_IRQn);





你可能感兴趣的:(单片机)