CC2540-BLE4.0 學歷筆記1之串口體驗


  PS:這篇文章記錄筆者TI ble協議棧的學習串口的筆記。歡迎各位評論討論,也希望有大牛解答文末的問題。

  前些日子CC2540模塊沒到,就搗鼓CC2530。深深的感受到,ZigBee就是個坑啊。然后果斷玩BLE了。BLE,TI的棧給的文檔,project這回看起來好點,然后找了其他一些資料。這里介紹《藍牙4.0BLE開發完全手冊-物聯網開發技術實戰》。看起來還行吧。不過我照着他的串口例子做,沒看到效果(可能是協議棧版本問題)。於是,一怒之下,自己啃。

  最后再說一下,CC2530和CC2540除了RF不同外,51內核是一樣的。因為棧中使用的HAL是一樣的。

  說下自己的裝備。如下圖。手焊跳線o(∩_∩)o。主要可以用的IO有串口0,定時器1的通道0~3,定時器的IO映射到了位置2。和兩個按鍵。

  先來看看HAL都給了啥。我個人認為key、led、lcd就是多余的。這個硬件相關性實在是太強了。所以先從串口開始看起,我想各位看官的串口也都在位置1吧。

HAL里面默認串口使用的DMA。這個就不管它了。我建議先簡單的看下APP Group下面的幾個c文件。和OSAL.C中的osal_init_system和osal_run_system兩個函數,其它最好也瀏覽一下。在開始寫我們自己的串口函數前先看看項目的配置情況。請注意下,函數中用很多預編譯,看的時候仔細點。

左上角,選擇CC2540,關掉POWER_SAVING,在defined symbols中的POWER_SAVING前面加個x就可以了。關於POWER_SAVING,在函數osal_run_system中可以看到,這里我們x掉,不然編譯會出現一個警告,說什么串口和key的中斷被重復的啥啥啥的。至於LCD,因為我的板是沒用LCD的干脆也x了。

  現在開始來看看怎么來串口打印出信息來。找到SimpleBLEPeripheral.c中的SimpleBLEPeripheral_Init函數,添加如下代碼,注意{}中才是我添加的。另外要添加hal_uart.h這個頭文件。

 1 void SimpleBLEPeripheral_Init( uint8 task_id )
 2 {
 3   simpleBLEPeripheral_TaskID = task_id;
 4 
 5     {    //add
 6         halUARTCfg_t halUARTCfg;
 7         halUARTCfg.configured            =    TRUE;
 8         halUARTCfg.baudRate                = HAL_UART_BR_115200;
 9         halUARTCfg.flowControl        =    HAL_UART_FLOW_OFF;
10         
11         HalUARTOpen(HAL_UART_PORT_0, &halUARTCfg);
12         HalUARTWrite(HAL_UART_PORT_0, "Hello CC2540!\n", 14);
13     }
添加串口

來看看串口配置這個結構體。注意到,這個結構體是沒有關於配置停止位,校驗位的。也就是全是默認。其他沒用到的先不理會是用來干嘛的。

 1 typedef struct
 2 {
 3   bool                configured;
 4   uint8               baudRate;
 5   bool                flowControl;
 6   uint16              flowControlThreshold;
 7   uint8               idleTimeout;
 8   halUARTBufControl_t rx;
 9   halUARTBufControl_t tx;
10   bool                intEnable;
11   uint32              rxChRvdTime;
12   halUARTCBack_t      callBackFunc;    //回調函數
13 }halUARTCfg_t;
halUARTCfg_t

順便吐槽一下,TI給的HAL api文檔里面關於串口的宏定義有錯,所以還是看源碼靠譜點。

到這里,編譯燒錄,應該就可以看到串口出來的信息了。附圖,注意一下右邊的配置情況。


華麗的分割線


   上面講了一下,如何使用Hal給的API來調用串口。也實現了串口信息打印功能。但這並不具有實際意義。在OSAL中,會對系統中的各種事件進行掃描,若事件發生,則會回調相應的函數去執行對應的功能。比如串口接收到信息。筆者嘗試着halUARTCfg_t結構體中的callBackFunc成員賦予回調函數。並使用HAL的串口API來實現這個函數——發送串口接收到的內容。

 1 //類似於這樣子
 2 
 3 halUARTCfg_t a
 4 
 5 a.callBackFunc = funcA
 6 
 7 
 8 static void funcA (uint8 port, uint8 event)
 9 {
10     HalUARTRead(, , );
11     HalUARTWrite(, ,);
12 }

上面是省略了的形式,但有個很怪的問題。就是串口接收一次數據后,這個回調函數就一直被調用,一直打印數據出來。經過各種嘗試之后也沒找出個所以然。可能是對整個協議棧的了解太少了。折騰了一個下午后,使用了npi.c提供的API函數。npi是Network Processor Interface的簡稱。

  來看看npi里面到底都是些什么

 1 //初始化串口配置
 2 void NPI_InitTransport( npiCBack_t npiCBack )
 3 {
 4   halUARTCfg_t uartConfig;
 5 
 6   // configure UART
 7   uartConfig.configured           = TRUE;
 8   uartConfig.baudRate             = NPI_UART_BR;
 9   uartConfig.flowControl          = NPI_UART_FC;
10   uartConfig.flowControlThreshold = NPI_UART_FC_THRESHOLD;
11   uartConfig.rx.maxBufSize        = NPI_UART_RX_BUF_SIZE;
12   uartConfig.tx.maxBufSize        = NPI_UART_TX_BUF_SIZE;
13   uartConfig.idleTimeout          = NPI_UART_IDLE_TIMEOUT;
14   uartConfig.intEnable            = NPI_UART_INT_ENABLE;
15   uartConfig.callBackFunc         = (halUARTCBack_t)npiCBack;
16 
17   // start UART
18   // Note: Assumes no issue opening UART port.
19   (void)HalUARTOpen( NPI_UART_PORT, &uartConfig );
20 
21   return;
22 }
23 
24 //讀數據
25 uint16 NPI_ReadTransport( uint8 *buf, uint16 len )
26 {
27   return( HalUARTRead( NPI_UART_PORT, buf, len ) );
28 }
29 
30 //寫數據
31 uint16 NPI_WriteTransport( uint8 *buf, uint16 len )
32 {
33   return( HalUARTWrite( NPI_UART_PORT, buf, len ) );
34 }
35 
36 //長度R
37 uint16 NPI_RxBufLen( void )
38 {
39   return( Hal_UART_RxBufLen( NPI_UART_PORT ) );
40 }
41 
42 //R緩沖區大小
43 uint16 NPI_GetMaxRxBufSize( void )
44 {
45   return( NPI_UART_RX_BUF_SIZE );
46 }
47 
48 //T緩沖區大小
49 uint16 NPI_GetMaxTxBufSize( void )
50 {
51   return( NPI_UART_TX_BUF_SIZE );
52 }
 1 #ifndef NPI_H
 2 #define NPI_H
 3 
 4 #ifdef __cplusplus
 5 extern "C"
 6 {
 7 #endif
 8 
 9 /*******************************************************************************
10  * INCLUDES
11  */
12 
13 #include "hal_types.h"
14 #include "hal_board.h"
15 #include "hal_uart.h"
16 
17 /*******************************************************************************
18  * MACROS
19  */
20 
21 /*******************************************************************************
22  * CONSTANTS
23  */
24 
25 /* UART port */
26 #if !defined NPI_UART_PORT
27 #if ((defined HAL_UART_SPI) && (HAL_UART_SPI != 0))
28 #define NPI_UART_PORT                  HAL_UART_PORT_1
29 #else
30 #define NPI_UART_PORT                  HAL_UART_PORT_0
31 #endif
32 #endif
33 
34 #if !defined( NPI_UART_FC )
35 #define NPI_UART_FC                    FALSE    //add ->true
36 #endif // !NPI_UART_FC
37 
38 #define NPI_UART_FC_THRESHOLD          48
39 #define NPI_UART_RX_BUF_SIZE           128
40 #define NPI_UART_TX_BUF_SIZE           128
41 #define NPI_UART_IDLE_TIMEOUT          6
42 #define NPI_UART_INT_ENABLE            TRUE
43 
44 #if !defined( NPI_UART_BR )
45 #define NPI_UART_BR                    HAL_UART_BR_115200
46 #endif // !NPI_UART_BR
47 
48 /*******************************************************************************
49  * TYPEDEFS
50  */
51 
52 typedef void (*npiCBack_t) ( uint8 port, uint8 event );
53 
54 //
55 // Network Processor Interface APIs
56 //
57 
58 extern void   NPI_InitTransport( npiCBack_t npiCBack );
59 extern uint16 NPI_ReadTransport( uint8 *buf, uint16 len );
60 extern uint16 NPI_WriteTransport( uint8 *, uint16 );
61 extern uint16 NPI_RxBufLen( void );
62 extern uint16 NPI_GetMaxRxBufSize( void );
63 extern uint16 NPI_GetMaxTxBufSize( void );
64 
65 /*******************************************************************************
66 */
67 
68 #ifdef __cplusplus
69 }
70 #endif
71 
72 #endif /* NPI_H */

可以看出來,npi就是對Hal中的串口API做了一層封裝。

之后SimpleBLEPeripheral_Init函數

1 void SimpleBLEPeripheral_Init( uint8 task_id )
2 {
3   simpleBLEPeripheral_TaskID = task_id;
4 
5     {    //add
6         NPI_InitTransport(UartEventChange);    //Network Processor Interface 初始化
7     }
8 ………… //省略
9

添加UartEventChange回調函數

 1 static void UartEventChange(uint8 port, uint8 event)    //add
 2 {
 3     VOID    port;
 4     uint8 temp;
 5 
 6     if(event & HAL_UART_RX_TIMEOUT)    //接收完成事件
 7     {
 8         temp = NPI_RxBufLen();
 9         if(temp)
10         {
11             NPI_ReadTransport(uartbuf, temp);
12             NPI_WriteTransport(uartbuf, temp);
13             osal_memset(uartbuf, 0, sizeof(uartbuf));
14         }
15     }
16 }

對SimpleBLEPeripheral.c文件做上面的修改,然后編譯、燒錄,就可以看到想要的現象了。CC2540在接收完串口信息后,返回接收到的內容。僅返回一次。而不像使用Hal的串口API那樣,接收到之后就一直發送不停。

  注意要關閉串口的流控制和power saving

  盡管通過npi實現了串口的收發。但還是有些問題沒搞懂。

 1 /*
 2  *
 3  *1、為何使用Hal中的串口api就無法產生上述效果。是我那些地方沒有注意
 4  *到了嗎??
 5  *
 6  *2、系統是如何知道串口接收完畢的。在調試過程中發現,串口事件有是有
 7  *定時器的。真的嗎?
 8  *
 9  *3、默認使用了DMA,那這個緩沖區在那里,文件中並沒有聲明出來這個數
10  *組,只聲明了DMA的大小。東西到底存哪里去了。
11  *
12  *4、系統的事件到底是怎么運作的?
13  *
14  *……
15  *
16  */

先記錄下這些問題。等熟悉了BLE棧之后在慢慢找答案。一開始就糾結這些問題的話,可能到頭來就啥都沒搞懂了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM