我所使用的Contiki系统是contiki-sensinode。理解该文需要有cc2530里uart的相关知识,具体寄存器的用法不做介绍。

先放上所有代码,然后再仔细分析。

 #include <stdlib.h>
#include <string.h> #include "cc253x.h"
#include "sfr-bits.h"
#include "dev/uart0.h" #if UART0_ENABLE
/*---------------------------------------------------------------------------*/
void
uart0_init()
{
#if UART0_CONF_HIGH_SPEED
UART_SET_SPEED(, UART_460_M, UART_460_E);
#else
UART_SET_SPEED(, UART_115_M, UART_115_E);
#endif #ifdef UART0_ALTERNATIVE_2
PERCFG |= PERCFG_U0CFG; / *alternative port = P1.- */
#ifdef UART0_RTSCTS
P1SEL |= 0x3C; /* peripheral select for TX and RX, RTS, CTS */
#else
P1SEL |= 0x30; /* peripheral select for TX and RX */
P1 &= ~0x08; /* RTS down */
#endif
P1DIR |= 0x28; /* RTS, TX out */
P1DIR &= ~0x14; /* CTS & RX in */
#else
PERCFG &= ~PERCFG_U0CFG; /* alternative port 1 = P0.5-2 */
#ifdef UART0_RTSCTS
P0SEL |= 0x20 | 0x10; /* peripheral select for TX and RX */
#else
P0SEL |= 0x0C; /* peripheral select for TX and RX */
P0 &= ~0x20; /* RTS down */
#endif
P0DIR |= 0x28; /* RTS, TX out */
P0DIR &= ~0x14; /* CTS, RX in */
#endif #ifdef UART0_RTSCTS
U0UCR = 0x42; /*defaults: 8N1, RTS/CTS, high stop bit*/
#else
U0UCR = 0x02; /*defaults: 8N1, no flow control, high stop bit*/
#endif U0CSR = UCSR_MODE; /* UART mode */
U0UCR |= 0x80; /* Flush */
UART0_RX_EN(); UART0_RX_INT();
}
/*---------------------------------------------------------------------------*/
/* Write one byte over the UART. */
void
uart0_writeb(uint8_t byte)
{
UTX0IF = ;
U0DBUF = byte;
while(!UTX0IF); /* Wait until byte has been transmitted. */
UTX0IF = ;
}
#endif
  • 首先是包含的头文件,就不多说了。
  • 然后是一个宏定义,#if UART0_ENABLE,若该宏未被定义,则uart0_init()不会被编译,节省内存空间。查看头文件:
 /* UART0 Enable - Disable */
#ifdef UART0_CONF_ENABLE
#define UART0_ENABLE UART0_CONF_ENABLE
#else
#define UART0_ENABLE 0
#endif

发现UART0_CONF_ENABLE为真时,UART0_ENABLE也为真;否则UART0_ENABLE为0。再往上就没有找到UART0_CONF_ENABLE的定义了,可能需要自己定义。

  • 之后就是uart0_init()函数了,
 #if UART0_CONF_HIGH_SPEED
UART_SET_SPEED(, UART_460_M, UART_460_E);
#else
UART_SET_SPEED(, UART_115_M, UART_115_E);
#endif

这是为了设置波特率,若定义的UART0_CONF_HIGH_SPEED为真,则设置的波特率大一些。查看宏定义:

#define UART_SET_SPEED(N, M, E) do{ U##N##BAUD = M; U##N##GCR = E; } while(0)

以上面第二行为例:变换结果为(“##”为连接符,把两边的字符相连)

 do{
U0BUAD = UART_460_M;
U0GCR = UART_460_E;
}while();

继续跟踪宏定义:

 /* 2000000 - cc2430 theoretical MAX when using the 32MHz clock */
#define UART_2K_M 0
#define UART_2K_E 16
/* 1000000 - cc2430 theoretical MAX when using the 16MHz clock */
#define UART_1K_M 0
#define UART_1K_E 15
/* 921600 */
#define UART_921_M 216
#define UART_921_E 14
/* 460800 Higher values lead to problems when the node needs to RX */
#define UART_460_M 216
#define UART_460_E 13
/* 115200 */
#define UART_115_M 216
#define UART_115_E 11
/* 38400 */
#define UART_38_M 59
#define UART_38_E 10
/* 9600 */
#define UART_9_M 59
#define UART_9_E 8

最终的替换结果为,波特率查表为460800。

 do{
U0BUAD = ;
U0GCR = ;
}while();
  • 继续往下看:
 #ifdef UART0_ALTERNATIVE_2
PERCFG |= PERCFG_U0CFG; / *alternative port = P1.- */
#ifdef UART0_RTSCTS
P1SEL |= 0x3C; /* peripheral select for TX and RX, RTS, CTS */
#else
P1SEL |= 0x30; /* peripheral select for TX and RX */
P1 &= ~0x08; /* RTS down */
#endif
P1DIR |= 0x28; /* RTS, TX out */
P1DIR &= ~0x14; /* CTS & RX in */

这个宏的条件是使用uart0的可变端口2,看下面的PERCFG |= 0x01(宏展开的值),uart0用备用位置2,根据后面信息知道端口为TX:P1_5,RX: P1_4。

至于注释里面的RTS和CTS我了解的不多,就管它。但是相应的uart0的TX和RX是知道了的。

假设上面那个宏条件失败,于是就到了这里:

 #else
PERCFG &= ~PERCFG_U0CFG; /* alternative port 1 = P0.5-2 */
#ifdef UART0_RTSCTS
P0SEL |= 0x20 | 0x10; /* peripheral select for TX and RX */
#else
P0SEL |= 0x0C; /* peripheral select for TX and RX */
P0 &= ~0x20; /* RTS down */
#endif
P0DIR |= 0x28; /* RTS, TX out */
P0DIR &= ~0x14; /* CTS, RX in */
#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。

  • 继续往下:
 #ifdef UART0_RTSCTS
U0UCR = 0x42; /*defaults: 8N1, RTS/CTS, high stop bit*/
#else
U0UCR = 0x02; /*defaults: 8N1, no flow control, high stop bit*/
#endif

假设宏条件失败,其实这个条件在上面也出现过,若它为假,则初始化内容就是我们熟悉的cc2530里uart0的初始化。

U0UCR = 0x02;禁止硬件流,8位传输,无奇偶校验,1停止位,停止位高电平,起始位低电平。

  • 继续
   U0CSR = UCSR_MODE; /* UART mode */
U0UCR |= 0x80; /* Flush */
UART0_RX_EN(); UART0_RX_INT();

展开宏为

  U0CSR = 0x80; /* UART mode */
U0UCR |= 0x80; /* Flush */
do { U0CSR |= UCSR_RE; } while(); do { URX0IE = ; } while();

继续展开

  U0CSR = 0x80; /* UART mode */
U0UCR |= 0x80; /* Flush */
do { U0CSR |= 0x40; } while(); do { URX0IE = ; } while();

UART模式,接收器使能。设置FLASH为1,UART0读中断使能。

uart0_init()总算介绍完了,把各种不要的宏,以及宏展开就是如下结果:

     U0BUAD = ;
U0GCR = ;
PERCFG &= ~0x01;
P0SEL |= 0x0C;
P0DIR |= 0x28;
P0DIR &= ~0x14;
U0UCR = 0x02;
U0CSR = 0x80;
U0UCR |= 0x80;
U0CSR |= 0x40;
URX0IE = ;

怎么样,是不是感觉很熟悉。

  • 后面还有一个uart0_writeb()写字节传输
void
uart0_writeb(uint8_t byte)
{
UTX0IF = ;
U0DBUF = byte;
while(!UTX0IF); /* Wait until byte has been transmitted. */
UTX0IF = ;
}

这个就是cc2530里通过中断方式串口发送字节,就不解释了。

至此,uart0.c文件大致解释完毕,本人水平有限,有错误的地方希望指出,谢谢。

Contiki源码分析--CPU为cc253x里的uart0.c的更多相关文章

  1. 鸿蒙内核源码分析(CPU篇) | 整个内核就是一个死循环 | 祝新的一年牛气冲天 ! | v32.02

    百篇博客系列篇.本篇为: v32.xx 鸿蒙内核源码分析(CPU篇) | 整个内核就是一个死循环 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...

  2. spring源码分析-core.io包里面的类

    前些日子看<深入理解javaweb开发>时,看到第一章java的io流,发觉自己对io流真的不是很熟悉.然后看了下JDK1.7中io包的一点点代码,又看了org.springframewo ...

  3. 鸿蒙内核源码分析(线程概念篇) | 是谁在不停的折腾CPU? | 百篇博客分析OpenHarmony源码 | v21.06

    百篇博客系列篇.本篇为: v21.xx 鸿蒙内核源码分析(线程概念篇) | 是谁在不断的折腾CPU | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调 ...

  4. 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅 | 百篇博客分析OpenHarmony源码 | v37.03

    百篇博客系列篇.本篇为: v37.xx 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁 ...

  5. 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 百篇博客分析OpenHarmony源码 | v25.01

    百篇博客系列篇.本篇为: v25.xx 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...

  6. 鸿蒙内核源码分析(调度机制篇) | 任务是如何被调度执行的 | 百篇博客分析OpenHarmony源码 | v7.07

    百篇博客系列篇.本篇为: v07.xx 鸿蒙内核源码分析(调度机制篇) | 任务是如何被调度执行的 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调 ...

  7. 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 百篇博客分析OpenHarmony源码 | v6.05

    百篇博客系列篇.本篇为: v06.xx 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...

  8. 鸿蒙内核源码分析(任务管理篇) | 任务池是如何管理的 | 百篇博客分析OpenHarmony源码 | v5.05

    百篇博客系列篇.本篇为: v05.xx 鸿蒙内核源码分析(任务管理篇) | 任务池是如何管理的 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁 ...

  9. 鸿蒙内核源码分析(任务调度篇) | 任务是内核调度的单元 | 百篇博客分析OpenHarmony源码 | v4.05

    百篇博客系列篇.本篇为: v04.xx 鸿蒙内核源码分析(任务调度篇) | 任务是内核调度的单元 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...

随机推荐

  1. MySQL 其它基本操作

    索引 所谓索引,就是类似于书的目录,目的也类似,都是为了提高检索速度.ALTER TABLE <表名> ADD INDEX <索引名(列名)>;或者CREATE INDEX & ...

  2. UBUNTU 16.04 + CUDA8.0 + CUDNN6.0 + OPENCV3.2 + MKL +CAFFE + tensorflow

    首先说一下自己机子的配置 CPU:Intel(R) Core(TM) i5-5600 CUP @3.20GHz *4 GPU : GTX 1060 OS : 64bit Ubuntu16.04LTS ...

  3. ASP.NET Core Linux 发布

    这篇博客参考了以下文章: 1.http://www.cnblogs.com/ants/p/5732337.html 2.http://www.linuxidc.com/Linux/2016-11/13 ...

  4. Delphi中动态调用TXMLDocument的经历

    var  vXMLDocument: TXMLDocument;begin  vXMLDocument := TXMLDocument.Create('c:/temp/temp.xml');  Cap ...

  5. centos 部署 asp.net core Error -99 EADDRNOTAVAIL address not available解决

    centos7.3上部署 asp.net core 错误如下: Hosting environment: Production Content root path: /home/netcore Now ...

  6. Bitmap的读写和几个小儿科的滤镜效果~

    闲来玩玩图像处理,拿破仑说过:“不想自己实现滤镜的美工不是好程序员~~#@!*^...#&!@......”  因为在学校做过很多美工的工作,而且从小就喜欢画画所以对图像相关的东西都还比较感兴 ...

  7. 对新数据库使用 Code First

    如果使用的是 Visual Studio 2010,还需要安装 Nuget 1.创建应用程序 简单起见,我们将构建一个使用 Code First 执行数据访问的基本控制台应用程序. 打开 Visual ...

  8. 由TreeView 如何触发OnSelectedNodeChanged事件想到的与做到的

    前提是每层的结点上设置了NavigateUrl OnSelectedNodeChanged事件好像失去了作用. 另外TreeView是没有AutoPostBack的!!!! 那么要如何触发OnSele ...

  9. spring boot自定义配置文件

    把一些可能会经常变动的东西写在配置文件中,可以增加程序的灵活性,避免多次改版发版. 在sping boot中除了自带的默认配置文件application.properties之外,我们还可以在reso ...

  10. Spark之权威指南经典案例

    hadoop权威指南上有一个求历史最高温度的经典案例,源数据如下: -- sample.txt0067011990999991950051507004+68750+023550FM-12+038299 ...