我所使用的Contiki系统是contiki-sensinode。理解该文需要有cc2530里uart的相关知识,具体寄存器的用法不做介绍。
先放上所有代码,然后再仔细分析。
1 #include2 #include 3 4 #include "cc253x.h" 5 #include "sfr-bits.h" 6 #include "dev/uart0.h" 7 8 #if UART0_ENABLE 9 /*---------------------------------------------------------------------------*/10 void11 uart0_init()12 {13 #if UART0_CONF_HIGH_SPEED14 UART_SET_SPEED(0, UART_460_M, UART_460_E);15 #else16 UART_SET_SPEED(0, UART_115_M, UART_115_E);17 #endif18 19 #ifdef UART0_ALTERNATIVE_220 PERCFG |= PERCFG_U0CFG; / *alternative port 2 = P1.5-2 */21 #ifdef UART0_RTSCTS22 P1SEL |= 0x3C; /* peripheral select for TX and RX, RTS, CTS */23 #else24 P1SEL |= 0x30; /* peripheral select for TX and RX */25 P1 &= ~0x08; /* RTS down */26 #endif27 P1DIR |= 0x28; /* RTS, TX out */28 P1DIR &= ~0x14; /* CTS & RX in */29 #else30 PERCFG &= ~PERCFG_U0CFG; /* alternative port 1 = P0.5-2 */31 #ifdef UART0_RTSCTS32 P0SEL |= 0x20 | 0x10; /* peripheral select for TX and RX */33 #else34 P0SEL |= 0x0C; /* peripheral select for TX and RX */35 P0 &= ~0x20; /* RTS down */36 #endif37 P0DIR |= 0x28; /* RTS, TX out */38 P0DIR &= ~0x14; /* CTS, RX in */39 #endif40 41 42 #ifdef UART0_RTSCTS43 U0UCR = 0x42; /*defaults: 8N1, RTS/CTS, high stop bit*/44 #else45 U0UCR = 0x02; /*defaults: 8N1, no flow control, high stop bit*/46 #endif47 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 void57 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_ENABLE3 #define UART0_ENABLE UART0_CONF_ENABLE4 #else5 #define UART0_ENABLE 06 #endif
发现UART0_CONF_ENABLE为真时,UART0_ENABLE也为真;否则UART0_ENABLE为0。再往上就没有找到UART0_CONF_ENABLE的定义了,可能需要自己定义。
- 之后就是uart0_init()函数了,
1 #if UART0_CONF_HIGH_SPEED2 UART_SET_SPEED(0, UART_460_M, UART_460_E);3 #else4 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 1410 /* 460800 Higher values lead to problems when the node needs to RX */11 #define UART_460_M 21612 #define UART_460_E 1313 /* 115200 */14 #define UART_115_M 21615 #define UART_115_E 1116 /* 38400 */17 #define UART_38_M 5918 #define UART_38_E 1019 /* 9600 */20 #define UART_9_M 5921 #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_RTSCTS2 U0UCR = 0x42; /*defaults: 8N1, RTS/CTS, high stop bit*/3 #else4 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()写字节传输
voiduart0_writeb(uint8_t byte){ UTX0IF = 0; U0DBUF = byte; while(!UTX0IF); /* Wait until byte has been transmitted. */ UTX0IF = 0;}
这个就是cc2530里通过中断方式串口发送字节,就不解释了。
至此,uart0.c文件大致解释完毕,本人水平有限,有错误的地方希望指出,谢谢。