我所使用的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文件大致解释完毕,本人水平有限,有错误的地方希望指出,谢谢。