dirty 发表于 2024-7-7 11:08

【全能小网关|CH32V208】--6.蓝牙串口服务

本帖最后由 dirty 于 2024-7-7 11:10 编辑

<p>&nbsp; &nbsp; &nbsp; 本篇讲述CH32V208蓝牙串口透传。</p>

<p><strong><span style="color:#0000ff;">一.了解准备</span></strong></p>

<p>&nbsp; &nbsp; &nbsp; 沁恒低功耗蓝牙协议栈以及应用均基于 TMOS(Task Management Operating System),TMOS是一个控制循环,通过 TMOS 可设置事件的执行方式。TMOS 作为调度核心,BLE 协议栈、profile 定义、所有的应用都围绕它来实现。TMOS 不是传统意义上的操作系统,而是一种以实现多任务为核心的系统资源管理机制。TMOS 通过轮询的方式进行调度,系统时钟一般来源于 RTC。<br />
&nbsp; &nbsp; &nbsp; 对于一个任务,独一无二的任务 ID,任务的初始化以及任务下可执行的事件都是不可或缺的。每个Task 用户最多可以自定义 15 个事件,0x8000 为系统预留的SYS_EVENT_MSG<br />
事件,即系统消息传递事件,不可被定义。</p>

<p>&nbsp; &nbsp; &nbsp; 更多关于TMOS及协议栈使用可参考阅读官方文档。</p>

<p><strong><span style="color:#0000ff;">二.代码准备</span></strong></p>

<p>1.蓝牙协议栈初始化。包括协议栈起始地址、大小、时钟、发送功率、MAC、协议栈库初始化等。</p>

<pre>
<code>/*******************************************************************************
* @fn      WCHBLE_Init
*
* <a href="home.php?mod=space&amp;uid=159083" target="_blank">@brief </a> BLE library initialization
*
* @param   None.
*
* <a href="home.php?mod=space&amp;uid=784970" target="_blank">@return </a> None.
*/
void WCHBLE_Init(void)
{
    uint8_t   i;
    bleConfig_t cfg;

    g_LLE_IRQLibHandlerLocation = (uint32_t)LLE_IRQLibHandler;

    if(!tmos_memcmp(VER_LIB, VER_FILE, strlen(VER_FILE)))
    {
      PRINT(&quot;head file error...\n&quot;);
      while(1);
    }

    // 32M crystal capacitance and current
    OSC-&gt;HSE_CAL_CTRL &amp;= ~(0x07&lt;&lt;28);
    OSC-&gt;HSE_CAL_CTRL |= 0x03&lt;&lt;28;
    OSC-&gt;HSE_CAL_CTRL |= 3&lt;&lt;24;

    tmos_memset(&amp;cfg, 0, sizeof(bleConfig_t));
    cfg.MEMAddr = (uint32_t)MEM_BUF;
    cfg.MEMLen = (uint32_t)BLE_MEMHEAP_SIZE;
    cfg.BufMaxLen = (uint32_t)BLE_BUFF_MAX_LEN;
    cfg.BufNumber = (uint32_t)BLE_BUFF_NUM;
    cfg.TxNumEvent = (uint32_t)BLE_TX_NUM_EVENT;
    cfg.TxPower = (uint32_t)BLE_TX_POWER;
#if(defined(BLE_SNV)) &amp;&amp; (BLE_SNV == TRUE)
    cfg.SNVAddr = (uint32_t)BLE_SNV_ADDR;
    cfg.SNVNum = (uint32_t)BLE_SNV_NUM;
    cfg.readFlashCB = Lib_Read_Flash;
    cfg.writeFlashCB = Lib_Write_Flash;
#endif
    cfg.ClockFrequency = CAB_LSIFQ/2;
#if(CLK_OSC32K==0)
    cfg.ClockAccuracy = 50;
#else
    cfg.ClockAccuracy = 1000;
#endif
    cfg.ConnectNumber = (PERIPHERAL_MAX_CONNECTION &amp; 3) | (CENTRAL_MAX_CONNECTION &lt;&lt; 2);
#if(defined TEM_SAMPLE) &amp;&amp; (TEM_SAMPLE == TRUE)
    // Calibrate RF and internal RC according to temperature changes (greater than 7 degrees Celsius)
    cfg.tsCB = HAL_GetInterTempValue;
#if(CLK_OSC32K)
    cfg.rcCB = Lib_Calibration_LSI; // Internal 32K clock calibration
#endif
#endif
#if(defined(HAL_SLEEP)) &amp;&amp; (HAL_SLEEP == TRUE)
    cfg.idleCB = BLE_LowPower; // Enable sleep
#endif
#if(defined(BLE_MAC)) &amp;&amp; (BLE_MAC == TRUE)
    for(i = 0; i &lt; 6; i++)
    {
      cfg.MacAddr = MacAddr;
    }
#else
    {
      uint8_t MacAddr;
      FLASH_GetMACAddress(MacAddr);
      for(i = 0; i &lt; 6; i++)
      {
            cfg.MacAddr = MacAddr; // Use chip mac address
      }
    }
#endif
    if(!cfg.MEMAddr || cfg.MEMLen &lt; 4 * 1024)
    {
      while(1);
    }
    i = BLE_LibInit(&amp;cfg);
    if(i)
    {
      PRINT(&quot;LIB init error code: %x ...\n&quot;, i);
      while(1);
    }
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE );
    NVIC_EnableIRQ( BB_IRQn );
    NVIC_EnableIRQ( LLE_IRQn );
}</code></pre>

<p>2.外设初始化。这里面用到了事件注册函数TMOS_ProcessEventRegister,校准任务函数tmos_start_task</p>

<pre>
<code>void HAL_Init()
{
    halTaskID = TMOS_ProcessEventRegister(HAL_ProcessEvent);
    HAL_TimeInit();
#if(defined HAL_SLEEP) &amp;&amp; (HAL_SLEEP == TRUE)
    HAL_SleepInit();
#endif
#if(defined HAL_LED) &amp;&amp; (HAL_LED == TRUE)
    HAL_LedInit();
#endif
#if(defined HAL_KEY) &amp;&amp; (HAL_KEY == TRUE)
    HAL_KeyInit();
#endif
#if(defined BLE_CALIBRATION_ENABLE) &amp;&amp; (BLE_CALIBRATION_ENABLE == TRUE)
    // Add a calibration task, and a single calibration takes less than 10ms
    tmos_start_task(halTaskID, HAL_REG_INIT_EVENT, MS1_TO_SYSTEM_TIME(BLE_CALIBRATION_PERIOD));
#endif
//    tmos_start_task(halTaskID, HAL_TEST_EVENT, MS1_TO_SYSTEM_TIME(1000));    // Add a test task
}</code></pre>

<p>3.低功耗蓝牙初始化。包含GAP参数设置(广播参数、连接参数、绑定参数等),GATT层服务的注册以及回调函数的注册</p>

<pre>
<code>//扫描回包数据
static uint8_t scanRspData[] = {
    // complete name
    13, // length of this data
    GAP_ADTYPE_LOCAL_NAME_COMPLETE,
    'w', 'c', 'h','_', 'b', 'l', 'e', '_', 'u', 'a', 'r', 't',
    // connection interval range
    0x05, // length of this data
    GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
    LO_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL), // 100ms
    HI_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL),
    LO_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL), // 1s
    HI_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL),

    // Tx power level
    0x02, // length of this data
    GAP_ADTYPE_POWER_LEVEL,
    0 // 0dBm
};

//蓝牙串口服务回调
/*********************************************************************
* @fn      on_bleuartServiceEvt
*
* @brief   ble uart service callback handler
*
* @returnNULL
*/
void on_bleuartServiceEvt(uint16_t connection_handle, ble_uart_evt_t *p_evt)
{
    switch(p_evt-&gt;type)
    {
      case BLE_UART_EVT_TX_NOTI_DISABLED:
            PRINT("%02x:bleuart_EVT_TX_NOTI_DISABLED\r\n", connection_handle);
            break;
      case BLE_UART_EVT_TX_NOTI_ENABLED:
            PRINT("%02x:bleuart_EVT_TX_NOTI_ENABLED\r\n", connection_handle);
            break;
      case BLE_UART_EVT_BLE_DATA_RECIEVED:
            PRINT("BLE RX DATA len:%d\r\n", p_evt-&gt;data.length);

            //for notify back test
            //to ble
            uint16_t to_write_length = p_evt-&gt;data.length;
            app_drv_fifo_write(&amp;app_uart_rx_fifo, (uint8_t *)p_evt-&gt;data.p_data, &amp;to_write_length);
            tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
            //end of nofify back test
            PRINT("\r\n");
                        for(uint16_t i=0;i&lt;to_write_length;i++)
                        {
                                PRINT("%02x ", app_uart_rx_fifo.data);
                        }
                       
                        PRINT("\r\nble to uart\r\n");
            //ble to uart
            app_uart_tx_data((uint8_t *)p_evt-&gt;data.p_data, p_evt-&gt;data.length);

            break;
      default:
            break;
    }
}

void Peripheral_Init()
{
    Peripheral_TaskID = TMOS_ProcessEventRegister(Peripheral_ProcessEvent);

    // Setup the GAP Peripheral Role Profile
    {
      uint8_tinitial_advertising_enable = TRUE;
      uint16_t desired_min_interval = 6;
      uint16_t desired_max_interval = 1000;

      // Set the GAP Role Parameters
      GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &amp;initial_advertising_enable);
      GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), scanRspData);
      GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);
      GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16_t), &amp;desired_min_interval);
      GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16_t), &amp;desired_max_interval);
    }

    // Set advertising interval
    {
      uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL;

      GAP_SetParamValue(TGAP_DISC_ADV_INT_MIN, advInt);
      GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, advInt);
    }

    // Setup the GAP Bond Manager
    {
      uint32_t passkey = 0; // passkey "000000"
      uint8_tpairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
      uint8_tmitm = TRUE;
      uint8_tbonding = TRUE;
      uint8_tioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
      GAPBondMgr_SetParameter(GAPBOND_PERI_DEFAULT_PASSCODE, sizeof(uint32_t), &amp;passkey);
      GAPBondMgr_SetParameter(GAPBOND_PERI_PAIRING_MODE, sizeof(uint8_t), &amp;pairMode);
      GAPBondMgr_SetParameter(GAPBOND_PERI_MITM_PROTECTION, sizeof(uint8_t), &amp;mitm);
      GAPBondMgr_SetParameter(GAPBOND_PERI_IO_CAPABILITIES, sizeof(uint8_t), &amp;ioCap);
      GAPBondMgr_SetParameter(GAPBOND_PERI_BONDING_ENABLED, sizeof(uint8_t), &amp;bonding);
    }

    // Initialize GATT attributes
    GGS_AddService(GATT_ALL_SERVICES);         // GAP
    GATTServApp_AddService(GATT_ALL_SERVICES); // GATT attributes
    DevInfo_AddService();                      // Device Information Service
    ble_uart_add_service(on_bleuartServiceEvt);

    // Set the GAP Characteristics
    GGS_SetParameter(GGS_DEVICE_NAME_ATT, sizeof(attDeviceName), attDeviceName);

    // Init Connection Item
    peripheralInitConnItem(&amp;peripheralConnList);

    // Register receive scan request callback
    GAPRole_BroadcasterSetCB(&amp;Broadcaster_BroadcasterCBs);

    // Setup a delayed profile startup
    tmos_set_event(Peripheral_TaskID, SBP_START_DEVICE_EVT);
}</code></pre>

<p>4.事件处理回调函数。这里面有实现串口接收数据蓝牙notify发送</p>

<pre>
<code>/*********************************************************************
* @fn      Peripheral_ProcessEvent
*
* @brief   Peripheral Application Task event processor.This function
*          is called to process all events for the task.Events
*          include timers, messages and any other user defined events.
*
* @param   task_id - The TMOS assigned task ID.
* @param   events - events to process.This is a bit map and can
*                   contain more than one event.
*
* @returnevents not processed
*/
uint16_t Peripheral_ProcessEvent(uint8_t task_id, uint16_t events)
{
    static attHandleValueNoti_t noti;
    //VOID task_id; // TMOS required parameter that isn't used in this function

    if(events &amp; SYS_EVENT_MSG)
    {
      uint8_t *pMsg;

      if((pMsg = tmos_msg_receive(Peripheral_TaskID)) != NULL)
      {
            Peripheral_ProcessTMOSMsg((tmos_event_hdr_t *)pMsg);
            // Release the TMOS message
            tmos_msg_deallocate(pMsg);
      }
      // return unprocessed events
      return (events ^ SYS_EVENT_MSG);
    }

    if(events &amp; SBP_START_DEVICE_EVT)
    {
      // Start the Device
      GAPRole_PeripheralStartDevice(Peripheral_TaskID, &amp;Peripheral_BondMgrCBs, &amp;Peripheral_PeripheralCBs);
      return (events ^ SBP_START_DEVICE_EVT);
    }
    if(events &amp; SBP_PARAM_UPDATE_EVT)
    {
      // Send connect param update request
      GAPRole_PeripheralConnParamUpdateReq(peripheralConnList.connHandle,
                                             DEFAULT_DESIRED_MIN_CONN_INTERVAL,
                                             DEFAULT_DESIRED_MAX_CONN_INTERVAL,
                                             DEFAULT_DESIRED_SLAVE_LATENCY,
                                             DEFAULT_DESIRED_CONN_TIMEOUT,
                                             Peripheral_TaskID);

      //      GAPRole_PeripheralConnParamUpdateReq( peripheralConnList.connHandle,
      //                                              10,
      //                                              20,
      //                                              0,
      //                                              400,
      //                                              Peripheral_TaskID);

      return (events ^ SBP_PARAM_UPDATE_EVT);
    }

    if(events &amp; UART_TO_BLE_SEND_EVT)
    {
      static uint16_t read_length = 0;
      ;
      uint8_t result = 0xff;
      switch(send_to_ble_state)
      {
            case SEND_TO_BLE_TO_SEND:

                //notify is not enabled
                if(!ble_uart_notify_is_ready(peripheralConnList.connHandle))
                {
                  if(peripheralConnList.connHandle == GAP_CONNHANDLE_INIT)
                  {
                        //connection lost, flush rx fifo here
                        app_drv_fifo_flush(&amp;app_uart_rx_fifo);
                  }
                  break;
                }
                read_length = ATT_GetMTU(peripheralConnList.connHandle) - 3;

                if(app_drv_fifo_length(&amp;app_uart_rx_fifo) &gt;= read_length)
                {
                  PRINT("FIFO_LEN:%d\r\n", app_drv_fifo_length(&amp;app_uart_rx_fifo));
                  result = app_drv_fifo_read(&amp;app_uart_rx_fifo, to_test_buffer, &amp;read_length);
                  uart_to_ble_send_evt_cnt = 0;
                }
                else
                {
                  if(uart_to_ble_send_evt_cnt &gt; 10)
                  {
                        result = app_drv_fifo_read(&amp;app_uart_rx_fifo, to_test_buffer, &amp;read_length);
                        uart_to_ble_send_evt_cnt = 0;
                  }
                  else
                  {
                        tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 4);
                        uart_to_ble_send_evt_cnt++;
                        //PRINT("NO TIME OUT\r\n");
                  }
                }

                if(APP_DRV_FIFO_RESULT_SUCCESS == result)
                {
                  noti.len = read_length;
                  noti.pValue = GATT_bm_alloc(peripheralConnList.connHandle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0);
                  if(noti.pValue != NULL)
                  {
                        tmos_memcpy(noti.pValue, to_test_buffer, noti.len);
                                                PRINT("uart to ble notify\r\n");
                                                for(uint16_t i=0;i&lt;read_length;i++)
                                                {
                                                        PRINT("%02x ",to_test_buffer);
                                                }
                                                PRINT("\r\n");
                        result = ble_uart_notify(peripheralConnList.connHandle, &amp;noti, 0);
                        if(result != SUCCESS)
                        {
                            PRINT("R1:%02x\r\n", result);
                            send_to_ble_state = SEND_TO_BLE_SEND_FAILED;
                            GATT_bm_free((gattMsg_t *)&amp;noti, ATT_HANDLE_VALUE_NOTI);
                            tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
                        }
                        else
                        {
                            send_to_ble_state = SEND_TO_BLE_TO_SEND;
                            //app_fifo_write(&amp;app_uart_tx_fifo,to_test_buffer,&amp;read_length);
                            //app_drv_fifo_write(&amp;app_uart_tx_fifo,to_test_buffer,&amp;read_length);
                            read_length = 0;
                            tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
                        }
                  }
                  else
                  {
                        send_to_ble_state = SEND_TO_BLE_ALLOC_FAILED;
                        tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
                  }
                }
                else
                {
                  //send_to_ble_state = SEND_TO_BLE_FIFO_EMPTY;
                }
                break;
            case SEND_TO_BLE_ALLOC_FAILED:
            case SEND_TO_BLE_SEND_FAILED:

                noti.len = read_length;
                noti.pValue = GATT_bm_alloc(peripheralConnList.connHandle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0);
                if(noti.pValue != NULL)
                {
                  tmos_memcpy(noti.pValue, to_test_buffer, noti.len);
                  result = ble_uart_notify(peripheralConnList.connHandle, &amp;noti, 0);
                  if(result != SUCCESS)
                  {
                        PRINT("R2:%02x\r\n", result);
                        send_to_ble_state = SEND_TO_BLE_SEND_FAILED;
                        GATT_bm_free((gattMsg_t *)&amp;noti, ATT_HANDLE_VALUE_NOTI);
                        tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
                  }
                  else
                  {
                        send_to_ble_state = SEND_TO_BLE_TO_SEND;
                        //app_drv_fifo_write(&amp;app_uart_tx_fifo,to_test_buffer,&amp;read_length);
                        read_length = 0;
                        tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
                  }
                }
                else
                {
                  send_to_ble_state = SEND_TO_BLE_ALLOC_FAILED;
                  tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
                }
                break;
            default:
                break;
      }
      return (events ^ UART_TO_BLE_SEND_EVT);
    }
    // Discard unknown events
    return 0;
}</code></pre>

<p>5.数据收发应用串口初始化。这里使用到UART3.</p>

<pre>
<code>/*********************************************************************
* @fn      app_uart_init
*
* @brief   init uart
*
* @returnNULL
*/
void app_uart_init()
{
    //tx fifo and tx fifo
    //The buffer length should be a power of 2
    app_drv_fifo_init(&amp;app_uart_tx_fifo, app_uart_tx_buffer, APP_UART_TX_BUFFER_LENGTH);
    app_drv_fifo_init(&amp;app_uart_rx_fifo, app_uart_rx_buffer, APP_UART_RX_BUFFER_LENGTH);

    GPIO_InitTypeDefGPIO_InitStructure = {0};
    USART_InitTypeDef USART_InitStructure = {0};
    NVIC_InitTypeDefNVIC_InitStructure = {0};

    //uart3 init
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    /* USART3 TX--&gt;B.10RX--&gt;B.11 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &amp;GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &amp;GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

    USART_Init(USART3, &amp;USART_InitStructure);
    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&amp;NVIC_InitStructure);

    USART_Cmd(USART3, ENABLE);
}
</code></pre>

<p>6.主函数。这里main()的最后循环执行 TMOS_SystemProcess(),保证 TMOS 持续运行。app_uart_process处理串口接收及发送,并将接收到数据蓝牙发送。</p>

<pre>
<code>void app_uart_process(void)
{
    uint8_t data;
    __disable_irq();
    if(uart_rx_flag)
    {
      tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
      uart_rx_flag = false;
    }
    __enable_irq();


    while(app_drv_fifo_length(&amp;app_uart_tx_fifo))
    {
      app_drv_fifo_read_to_same_addr(&amp;app_uart_tx_fifo, (uint8_t *)&amp;data, 1);
      USART_SendData(USART3, data);
      while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET) /* waiting for sending finish */
      {
      }
    }
}

/*******************************************************************************
* Function Name: main
* Description    : Main function
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
int main(void)
{
    SystemCoreClockUpdate();
    Delay_Init();
#ifdef DEBUG
    USART_Printf_Init( 115200 );
#endif
    PRINT("%s\n", VER_LIB);
    WCHBLE_Init();
    HAL_Init();
    GAPRole_PeripheralInit();
    Peripheral_Init();
    app_uart_init();
    while(1)
    {
      TMOS_SystemProcess();
      app_uart_process();
    }
}
</code></pre>

<p>&nbsp;</p>

<p><strong><span style="color:#0000ff;">三.测验</span></strong></p>

<p>&nbsp; &nbsp; &nbsp; 编译烧录后运行。蓝牙广播如下:</p>

<div style="text-align: center;"></div>

<div style="text-align: center;">图1:蓝牙广播</div>

<p>&nbsp; &nbsp; &nbsp; 连接后,蓝牙串口服务如下:</p>

<div style="text-align: center;"></div>

<div style="text-align: center;">图2:蓝牙串口服务</div>

<p>&nbsp; &nbsp; &nbsp; 在nrf connect工具端打开消息通知使能,发送数据,串口端(UART3,图3右侧)将收到数据打印出来。在串口发送数据(UART3),可以看到左侧打印出调试日志并收到蓝牙数据通知如图4.</p>

<div style="text-align: center;"></div>

<div style="text-align: center;">图3:串口日志。左侧调试串口,右侧数据通讯接收发送串口</div>

<div style="text-align: center;">
<div style="text-align: center;"></div>

<div style="text-align: center;">图4:蓝牙串口服务调试</div>

<p>&nbsp;</p>
</div>

<p>&nbsp; &nbsp; &nbsp; 至此,实现WCH蓝牙串口服务功能,熟悉了对沁恒蓝牙功能的使用。</p>

lugl4313820 发表于 2024-7-14 07:04

<p>更多关于TMOS及协议栈使用可参考阅读官方文档。</p>

<p>他有中文文档吗?</p>

dirty 发表于 2024-7-16 13:39

lugl4313820 发表于 2024-7-14 07:04
更多关于TMOS及协议栈使用可参考阅读官方文档。

他有中文文档吗?

<p>有的,SDK路径下,目前是\CH32V20xEVT\EVT\EXAM\BLE\沁恒低功耗蓝牙软件开发参考手册.PDF</p>

回忆的沙漏 发表于 2024-9-2 11:09

<p>蓝牙和freertos能否同时使用?</p>
页: [1]
查看完整版本: 【全能小网关|CH32V208】--6.蓝牙串口服务