我所使用的Contiki系統是contiki-sensinode。理解該文需要有cc2530裡uart的相關知識,具體暫存器的用法不做介紹。
先放上所有程式碼,然後再仔細分析。
1 #include <stdlib.h> 2 #include <string.h> 3 4 #include "cc253x.h" 5 #include "sfr-bits.h" 6 #include "dev/uart0.h" 7 8 #if UART0_ENABLE 9 /*---------------------------------------------------------------------------*/ 10 void 11 uart0_init() 12 { 13 #if UART0_CONF_HIGH_SPEED 14 UART_SET_SPEED(0, UART_460_M, UART_460_E); 15 #else 16 UART_SET_SPEED(0, UART_115_M, UART_115_E); 17 #endif 18 19 #ifdef UART0_ALTERNATIVE_2 20 PERCFG |= PERCFG_U0CFG; / *alternative port 2 = P1.5-2 */ 21 #ifdef UART0_RTSCTS 22 P1SEL |= 0x3C; /* peripheral select for TX and RX, RTS, CTS */ 23 #else 24 P1SEL |= 0x30; /* peripheral select for TX and RX */ 25 P1 &= ~0x08; /* RTS down */ 26 #endif 27 P1DIR |= 0x28; /* RTS, TX out */ 28 P1DIR &= ~0x14; /* CTS & RX in */ 29 #else 30 PERCFG &= ~PERCFG_U0CFG; /* alternative port 1 = P0.5-2 */ 31 #ifdef UART0_RTSCTS 32 P0SEL |= 0x20 | 0x10; /* peripheral select for TX and RX */ 33 #else 34 P0SEL |= 0x0C; /* peripheral select for TX and RX */ 35 P0 &= ~0x20; /* RTS down */ 36 #endif 37 P0DIR |= 0x28; /* RTS, TX out */ 38 P0DIR &= ~0x14; /* CTS, RX in */ 39 #endif 40 41 42 #ifdef UART0_RTSCTS 43 U0UCR = 0x42; /*defaults: 8N1, RTS/CTS, high stop bit*/ 44 #else 45 U0UCR = 0x02; /*defaults: 8N1, no flow control, high stop bit*/ 46 #endif 47 48 U0CSR = UCSR_MODE; /* UART mode */ 49 U0UCR |= 0x80; /* Flush */ 50 UART0_RX_EN(); 51 52 UART0_RX_INT(1); 53 } 54 /*---------------------------------------------------------------------------*/ 55 /* Write one byte over the UART. */ 56 void 57 uart0_writeb(uint8_t byte) 58 { 59 UTX0IF = 0; 60 U0DBUF = byte; 61 while(!UTX0IF); /* Wait until byte has been transmitted. */ 62 UTX0IF = 0; 63 } 64 #endif
- 首先是包含的標頭檔案,就不多說了。
- 然後是一個巨集定義,#if UART0_ENABLE,若該巨集未被定義,則uart0_init()不會被編譯,節省記憶體空間。檢視標頭檔案:
1 /* UART0 Enable - Disable */ 2 #ifdef UART0_CONF_ENABLE 3 #define UART0_ENABLE UART0_CONF_ENABLE 4 #else 5 #define UART0_ENABLE 0 6 #endif
發現UART0_CONF_ENABLE為真時,UART0_ENABLE也為真;否則UART0_ENABLE為0。再往上就沒有找到UART0_CONF_ENABLE的定義了,可能需要自己定義。
- 之後就是uart0_init()函式了,
1 #if UART0_CONF_HIGH_SPEED 2 UART_SET_SPEED(0, UART_460_M, UART_460_E); 3 #else 4 UART_SET_SPEED(0, UART_115_M, UART_115_E); 5 #endif
這是為了設定波特率,若定義的UART0_CONF_HIGH_SPEED為真,則設定的波特率大一些。檢視巨集定義:
#define UART_SET_SPEED(N, M, E) do{ U##N##BAUD = M; U##N##GCR = E; } while(0)
以上面第二行為例:變換結果為(“##”為連線符,把兩邊的字元相連)
1 do{ 2 U0BUAD = UART_460_M; 3 U0GCR = UART_460_E; 4 }while(0);
繼續跟蹤巨集定義:
1 /* 2000000 - cc2430 theoretical MAX when using the 32MHz clock */ 2 #define UART_2K_M 0 3 #define UART_2K_E 16 4 /* 1000000 - cc2430 theoretical MAX when using the 16MHz clock */ 5 #define UART_1K_M 0 6 #define UART_1K_E 15 7 /* 921600 */ 8 #define UART_921_M 216 9 #define UART_921_E 14 10 /* 460800 Higher values lead to problems when the node needs to RX */ 11 #define UART_460_M 216 12 #define UART_460_E 13 13 /* 115200 */ 14 #define UART_115_M 216 15 #define UART_115_E 11 16 /* 38400 */ 17 #define UART_38_M 59 18 #define UART_38_E 10 19 /* 9600 */ 20 #define UART_9_M 59 21 #define UART_9_E 8
最終的替換結果為,波特率查表為460800。
1 do{ 2 U0BUAD = 216; 3 U0GCR = 13; 4 }while(0);
- 繼續往下看:
1 #ifdef UART0_ALTERNATIVE_2 2 PERCFG |= PERCFG_U0CFG; / *alternative port 2 = P1.5-2 */ 3 #ifdef UART0_RTSCTS 4 P1SEL |= 0x3C; /* peripheral select for TX and RX, RTS, CTS */ 5 #else 6 P1SEL |= 0x30; /* peripheral select for TX and RX */ 7 P1 &= ~0x08; /* RTS down */ 8 #endif 9 P1DIR |= 0x28; /* RTS, TX out */ 10 P1DIR &= ~0x14; /* CTS & RX in */
這個巨集的條件是使用uart0的可變埠2,看下面的PERCFG |= 0x01(巨集展開的值),uart0用備用位置2,根據後面資訊知道埠為TX:P1_5,RX: P1_4。
至於註釋裡面的RTS和CTS我瞭解的不多,就管它。但是相應的uart0的TX和RX是知道了的。
假設上面那個巨集條件失敗,於是就到了這裡:
1 #else 2 PERCFG &= ~PERCFG_U0CFG; /* alternative port 1 = P0.5-2 */ 3 #ifdef UART0_RTSCTS 4 P0SEL |= 0x20 | 0x10; /* peripheral select for TX and RX */ 5 #else 6 P0SEL |= 0x0C; /* peripheral select for TX and RX */ 7 P0 &= ~0x20; /* RTS down */ 8 #endif 9 P0DIR |= 0x28; /* RTS, TX out */ 10 P0DIR &= ~0x14; /* CTS, RX in */ 11 #endif
這就是我們熟悉的cc2530裡uart0的介面P0_2和P0_3。
首先設定PERCFG &= ~0x01; (巨集展開的值),uart0的位置為備用位置1。下面那個巨集UART0_RTSCTS沒有看懂,就先不管它,假設該巨集失敗。
於是為P0SEL |= 0x0C; P0_2和P0_3都被選用了外設功能。 後面的P0 &= ~0x20我沒管它。
之後P0DIR |= 0x28; P0DIR &= ~0x14;得知TX為P0_3,RX為P0_2。
- 繼續往下:
1 #ifdef UART0_RTSCTS 2 U0UCR = 0x42; /*defaults: 8N1, RTS/CTS, high stop bit*/ 3 #else 4 U0UCR = 0x02; /*defaults: 8N1, no flow control, high stop bit*/ 5 #endif
假設巨集條件失敗,其實這個條件在上面也出現過,若它為假,則初始化內容就是我們熟悉的cc2530裡uart0的初始化。
U0UCR = 0x02;禁止硬體流,8位傳輸,無奇偶校驗,1停止位,停止位高電平,起始位低電平。
- 繼續
1 U0CSR = UCSR_MODE; /* UART mode */ 2 U0UCR |= 0x80; /* Flush */ 3 UART0_RX_EN(); 4 5 UART0_RX_INT(1);
展開巨集為
U0CSR = 0x80; /* UART mode */ U0UCR |= 0x80; /* Flush */ do { U0CSR |= UCSR_RE; } while(0); do { URX0IE = 1; } while(0);
繼續展開
U0CSR = 0x80; /* UART mode */ U0UCR |= 0x80; /* Flush */ do { U0CSR |= 0x40; } while(0); do { URX0IE = 1; } while(0);
UART模式,接收器使能。設定FLASH為1,UART0讀中斷使能。
uart0_init()總算介紹完了,把各種不要的巨集,以及巨集展開就是如下結果:
1 U0BUAD = 216; 2 U0GCR = 13; 3 PERCFG &= ~0x01; 4 P0SEL |= 0x0C; 5 P0DIR |= 0x28; 6 P0DIR &= ~0x14; 7 U0UCR = 0x02; 8 U0CSR = 0x80; 9 U0UCR |= 0x80; 10 U0CSR |= 0x40; 11 URX0IE = 1;
怎麼樣,是不是感覺很熟悉。
- 後面還有一個uart0_writeb()寫位元組傳輸
void uart0_writeb(uint8_t byte) { UTX0IF = 0; U0DBUF = byte; while(!UTX0IF); /* Wait until byte has been transmitted. */ UTX0IF = 0; }
這個就是cc2530裡通過中斷方式串列埠傳送位元組,就不解釋了。
至此,uart0.c檔案大致解釋完畢,本人水平有限,有錯誤的地方希望指出,謝謝。