nrf51822 --- 串口透传 分析

1.目的

     分析蓝牙串口的例子

2.分析

  在实际应用中经常使用串口,下面我们就来分析下串口例子

3.平台:

sofeDevice : s110_nrf51_8.0.0_softdevice.hex

协议栈版本:SDK10.0.0

编译软件:keil 5.12

硬件平台:nrf51822最小系统

例子:SDK 10.0.0\examples\ble_peripheral\ble_app_uart\pca10028\s110\arm4

4.步骤

  

int main(void)
{
    uint32_t err_code;
    bool erase_bonds;
    uint8_t  start_string[] = START_STRING;
    
    // Initialize.
    APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
    uart_init();
    buttons_leds_init(&erase_bonds);
    ble_stack_init();
    gap_params_init();
    services_init();
    advertising_init();
    conn_params_init();
    
    printf("%s",start_string);

    err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
    APP_ERROR_CHECK(err_code);
    
    // Enter main loop.
    for (;;)
    {
        power_manage();
    }
}
a.串口初始化

  uart_init();  

   把APP_UART_FLOW_CONTROL_ENABLED ==》APP_UART_FLOW_CONTROL_DISABLED  不使用流控

   在pca10028.h 中定义串口的管脚,如下:

#define RX_PIN_NUMBER  11
#define TX_PIN_NUMBER  9
#define CTS_PIN_NUMBER 10
#define RTS_PIN_NUMBER 8
#define HWFC           false
   

static void uart_init(void)
{
    uint32_t                     err_code;
    const app_uart_comm_params_t comm_params =
    {
        RX_PIN_NUMBER,
        TX_PIN_NUMBER,
        RTS_PIN_NUMBER,
        CTS_PIN_NUMBER,
        APP_UART_FLOW_CONTROL_DISABLED,// APP_UART_FLOW_CONTROL_ENABLED
        false,
        UART_BAUDRATE_BAUDRATE_Baud38400
    };

    APP_UART_FIFO_INIT( &comm_params,
                       UART_RX_BUF_SIZE,
                       UART_TX_BUF_SIZE,
                       uart_event_handle,
                       APP_IRQ_PRIORITY_LOW,
                       err_code);
    APP_ERROR_CHECK(err_code);
}

b.APP_UART_FIFO_INIT()如下:

   定义了接收和发送缓冲区的大小:

   #define UART_TX_BUF_SIZE                256                                         /**< UART TX buffer size. */
  #define UART_RX_BUF_SIZE                256                                         /**< UART RX buffer size. */

然后初始化哪个串口,串口发送和接收缓冲区,串口回调函数,串口优先级,代码如下

#define APP_UART_FIFO_INIT(P_COMM_PARAMS, RX_BUF_SIZE, TX_BUF_SIZE, EVT_HANDLER, IRQ_PRIO, ERR_CODE) \
    do                                                                                             \
    {                                                                                              \
        app_uart_buffers_t buffers;                                                                \
        static uint8_t     rx_buf[RX_BUF_SIZE];                                                    \
        static uint8_t     tx_buf[TX_BUF_SIZE];                                                    \
                                                                                                   \                                                                                       
        buffers.rx_buf      = rx_buf;                                                              \
        buffers.rx_buf_size = sizeof (rx_buf);                                                     \
        buffers.tx_buf      = tx_buf;                                                              \
        buffers.tx_buf_size = sizeof (tx_buf);                                                     \
        ERR_CODE = app_uart_init(P_COMM_PARAMS, &buffers, EVT_HANDLER, IRQ_PRIO);                  \
    } while (0)
uint32_t app_uart_init(const app_uart_comm_params_t * p_comm_params,
                             app_uart_buffers_t *     p_buffers,
                             app_uart_event_handler_t event_handler,
                             app_irq_priority_t       irq_priority)
{
    uint32_t err_code;

    m_event_handler = event_handler;

    if (p_buffers == NULL)
    {
        return NRF_ERROR_INVALID_PARAM;
    }

    // Configure buffer RX buffer.
    err_code = app_fifo_init(&m_rx_fifo, p_buffers->rx_buf, p_buffers->rx_buf_size);
    if (err_code != NRF_SUCCESS)
    {
        // Propagate error code.
        return err_code;
    }

    // Configure buffer TX buffer.
    err_code = app_fifo_init(&m_tx_fifo, p_buffers->tx_buf, p_buffers->tx_buf_size);
    if (err_code != NRF_SUCCESS)
    {
        // Propagate error code.
        return err_code;
   }

    nrf_drv_uart_config_t config = NRF_DRV_UART_DEFAULT_CONFIG;
    config.baudrate = (nrf_uart_baudrate_t)p_comm_params->baud_rate;
    config.hwfc = (p_comm_params->flow_control == APP_UART_FLOW_CONTROL_DISABLED) ?
            NRF_UART_HWFC_DISABLED : NRF_UART_HWFC_ENABLED;
    config.interrupt_priority = irq_priority;
    config.parity = p_comm_params->use_parity ? NRF_UART_PARITY_INCLUDED : NRF_UART_PARITY_EXCLUDED;
    config.pselcts = p_comm_params->cts_pin_no;
    config.pselrts = p_comm_params->rts_pin_no;
    config.pselrxd = p_comm_params->rx_pin_no;
    config.pseltxd = p_comm_params->tx_pin_no;

    err_code = nrf_drv_uart_init(&config, uart_event_handler);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    nrf_drv_uart_rx_enable();
    return nrf_drv_uart_rx(rx_buffer,1);
}

app_uart_init()

 配置发送 接收缓冲区,配置具体的寄存器,开中断等等。

看nrf_drv_uart_init();

   把 m_cb.handler = event_handler;   m_cb.handler 指向回调函数

ret_code_t nrf_drv_uart_init(nrf_drv_uart_config_t const * p_config,
                             nrf_uart_event_handler_t      event_handler)
{
    if (m_cb.state != NRF_DRV_STATE_UNINITIALIZED)
    {
        return NRF_ERROR_INVALID_STATE;
    }

    if (p_config == NULL)
    {
        p_config = &m_default_config;
    }
#ifdef NRF52
    m_cb.use_easy_dma = p_config->use_easy_dma;
#endif
    apply_config(p_config);

    m_cb.handler = event_handler;
    m_cb.p_context = p_config->p_context;

    if (m_cb.handler)
    {
        interrupts_enable(p_config->interrupt_priority);
    }

    uart_enable();
    m_cb.rx_buffer_length = 0;
    m_cb.tx_buffer_length = 0;
    m_cb.state = NRF_DRV_STATE_INITIALIZED;
    m_cb.rx_enabled = false;
    return NRF_SUCCESS;
}

串口中断函数 因为没有定义UARTE_IN_USE 也没有定义 UART_IN_USE 

所以只有 CODE_FOR_UART定义了

#if (defined(UARTE_IN_USE) && defined(UART_IN_USE))
    // UARTE and UART combined
    #define CODE_FOR_UARTE(code) if (m_cb.use_easy_dma) { code }
    #define CODE_FOR_UART(code)   else { code }
#elif (defined(UARTE_IN_USE) && !defined(UART_IN_USE))
    // UARTE only
    #define CODE_FOR_UARTE(code) { code }
    #define CODE_FOR_UART(code)
#elif (!defined(UARTE_IN_USE) && defined(UART_IN_USE))
    // UART only
    #define CODE_FOR_UARTE(code)
    #define CODE_FOR_UART(code) { code }
#else
    #error "Wrong configuration."
#endif


void UART0_IRQHandler(void)
{
    CODE_FOR_UARTE
    (
        if (nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_ERROR))
        {
            nrf_drv_uart_event_t event;

            nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_ERROR);

            event.type                   = NRF_DRV_UART_EVT_ERROR;
            event.data.error.error_mask  = nrf_uarte_errorsrc_get_and_clear(NRF_UARTE0);
            event.data.error.rxtx.bytes  = nrf_uarte_rx_amount_get(NRF_UARTE0);
            event.data.error.rxtx.p_data = m_cb.p_rx_buffer;

            //abort transfer
            m_cb.rx_buffer_length = 0;

            m_cb.handler(&event,m_cb.p_context);
        }
        else if (nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_ENDRX))
        {
            nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_ENDRX);
            uint8_t amount = nrf_uarte_rx_amount_get(NRF_UARTE0);
            if (amount == m_cb.rx_buffer_length)
            {
   rx_done_event(amount);
            }
        }

        if (nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_RXTO))
        {
            nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_RXTO);
            if (m_cb.rx_buffer_length)
            {
                rx_done_event(nrf_uarte_rx_amount_get(NRF_UARTE0));
            }
        }
        if (nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_ENDTX))
        {
            nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_ENDTX);
            if (m_cb.tx_buffer_length)
            {
                tx_done_event(nrf_uarte_tx_amount_get(NRF_UARTE0));
            }
        }
    )
    CODE_FOR_UART(
        if (nrf_uart_int_enable_check(NRF_UART0, NRF_UART_INT_MASK_ERROR) &&
            nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_ERROR))
        {
            nrf_drv_uart_event_t event;

            nrf_uart_event_clear(NRF_UART0, NRF_UART_EVENT_ERROR);
            nrf_uart_int_disable(NRF_UART0, NRF_UART_INT_MASK_RXDRDY | NRF_UART_INT_MASK_ERROR);
            if (!m_cb.rx_enabled)
            {
                nrf_uart_task_trigger(NRF_UART0, NRF_UART_TASK_STOPRX);
            }
            event.type                   = NRF_DRV_UART_EVT_ERROR;
            event.data.error.error_mask  = nrf_uart_errorsrc_get_and_clear(NRF_UART0);
            event.data.error.rxtx.bytes  = m_cb.rx_buffer_length;
            event.data.error.rxtx.p_data = m_cb.p_rx_buffer;

            //abort transfer
            m_cb.rx_buffer_length = 0;

            m_cb.handler(&event,m_cb.p_context);

        }
        else if (nrf_uart_int_enable_check(NRF_UART0, NRF_UART_INT_MASK_RXDRDY) &&
			
                nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_RXDRDY))
        {
            rx_byte();
            if (m_cb.rx_buffer_length == m_cb.rx_counter)
            {
                if (!m_cb.rx_enabled)
                {
                    nrf_uart_task_trigger(NRF_UART0, NRF_UART_TASK_STOPRX);
                }
                nrf_uart_int_disable(NRF_UART0, NRF_UART_INT_MASK_RXDRDY | NRF_UART_INT_MASK_ERROR);
                rx_done_event(m_cb.rx_counter);
            }
        }
     if (nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_TXDRDY))
        {
            if ((m_cb.tx_buffer_length > m_cb.tx_counter))
            {
                tx_byte();
            }
            else
            {
                nrf_uart_event_clear(NRF_UART0, NRF_UART_EVENT_TXDRDY);
                if (m_cb.tx_buffer_length)
                {
                    tx_done_event(m_cb.tx_buffer_length);
                }
            }
        }
        if (nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_RXTO))
        {
            nrf_uart_event_clear(NRF_UART0, NRF_UART_EVENT_RXTO);

            // RXTO event may be triggered as a result of abort call. In th
            if (m_cb.rx_enabled)
            {
                nrf_uart_task_trigger(NRF_UART0, NRF_UART_TASK_STARTRX);
            }
            if (m_cb.rx_buffer_length)
            {
                rx_done_event(m_cb.rx_counter);
            }
        }
    )
}
 发送数据并且缓冲区没有满的时候就是产生超时事件,

  然后调用  rx_done_event(m_cb.rx_counter);

__STATIC_INLINE void rx_done_event(uint8_t bytes)
{
    nrf_drv_uart_event_t event;

    event.type             = NRF_DRV_UART_EVT_RX_DONE;
    event.data.rxtx.bytes  = bytes;
    event.data.rxtx.p_data = m_cb.p_rx_buffer;

    m_cb.rx_buffer_length = 0;

    m_cb.handler(&event,m_cb.p_context);
}

 在看nrf_drv_uart_init();我们 把 m_cb.handler = event_handler;  

  所以这里会产生uart_event_handle();函数

 看回调函数uart_event_handle();

  当有数据来了并且已“\n” 数据长度大于20,就会通过串口服务发送出去。

  在这里我们添加一天串口打印数据语句,printf("%s",data_array);

 

void uart_event_handle(app_uart_evt_t * p_event)
{
    static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
    static uint8_t index = 0;
    uint32_t       err_code;

    switch (p_event->evt_type)
    {
        case APP_UART_DATA_READY:
            UNUSED_VARIABLE(app_uart_get(&data_array[index]));
            index++;

            if ((data_array[index - 1] == '\n') || (index >= (BLE_NUS_MAX_DATA_LEN)))
            {
                printf("%s",data_array); //添加发送语句
                err_code = ble_nus_string_send(&m_nus, data_array, index);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
                
                index = 0;
            }
            break;
        case APP_UART_COMMUNICATION_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_communication);
            break;

        case APP_UART_FIFO_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_code);
            break;

        default:
            break;
    }
}

实验:download the code  可以看到打印出 Start...  表示发送成功。

nrf51822 --- 串口透传 分析_第1张图片

 串口发送框写“abcdefghijklmnopqrst\n” (注意“\n”结尾并且发送数据的长度要大约等于20,这样程序才会返回,具体看uart_event_handle()函数)点击发送,

可以看到数据显示框里显示 “abcdefghijklmnopqrst”  程序里面发送什么 回复什么。现在发送和回复一致 ,表示正确

nrf51822 --- 串口透传 分析_第2张图片


OK。。。。实验完成。。。。。

你可能感兴趣的:(nrf51822 --- 串口透传 分析)