Contiki源码分析--CPU为cc253x里的uart0.c
我所使用的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的更多相关文章
- 鸿蒙内核源码分析(CPU篇) | 整个内核就是一个死循环 | 祝新的一年牛气冲天 ! | v32.02
百篇博客系列篇.本篇为: v32.xx 鸿蒙内核源码分析(CPU篇) | 整个内核就是一个死循环 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...
- spring源码分析-core.io包里面的类
前些日子看<深入理解javaweb开发>时,看到第一章java的io流,发觉自己对io流真的不是很熟悉.然后看了下JDK1.7中io包的一点点代码,又看了org.springframewo ...
- 鸿蒙内核源码分析(线程概念篇) | 是谁在不停的折腾CPU? | 百篇博客分析OpenHarmony源码 | v21.06
百篇博客系列篇.本篇为: v21.xx 鸿蒙内核源码分析(线程概念篇) | 是谁在不断的折腾CPU | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调 ...
- 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅 | 百篇博客分析OpenHarmony源码 | v37.03
百篇博客系列篇.本篇为: v37.xx 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁 ...
- 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 百篇博客分析OpenHarmony源码 | v25.01
百篇博客系列篇.本篇为: v25.xx 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...
- 鸿蒙内核源码分析(调度机制篇) | 任务是如何被调度执行的 | 百篇博客分析OpenHarmony源码 | v7.07
百篇博客系列篇.本篇为: v07.xx 鸿蒙内核源码分析(调度机制篇) | 任务是如何被调度执行的 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调 ...
- 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 百篇博客分析OpenHarmony源码 | v6.05
百篇博客系列篇.本篇为: v06.xx 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...
- 鸿蒙内核源码分析(任务管理篇) | 任务池是如何管理的 | 百篇博客分析OpenHarmony源码 | v5.05
百篇博客系列篇.本篇为: v05.xx 鸿蒙内核源码分析(任务管理篇) | 任务池是如何管理的 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁 ...
- 鸿蒙内核源码分析(任务调度篇) | 任务是内核调度的单元 | 百篇博客分析OpenHarmony源码 | v4.05
百篇博客系列篇.本篇为: v04.xx 鸿蒙内核源码分析(任务调度篇) | 任务是内核调度的单元 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...
随机推荐
- .NET与Java互通AES算法加密解密
/// <summary>AES加密</summary> /// <param name="text">明文</param> /// ...
- 企业级架构 MVVM 模式指南 (WPF 和 Silverlight 实现) 译(1)
前言对于WPF和Silverlight来讲,MVVM是微软设计师和业内专家高度推荐的非常棒的一种设计模式.本书会探讨MVVM设计模式的一些自身缺陷以及为什么MVVM还不能成为行业内的标准设计模式.这会 ...
- 梅林路由器 开启ssh key远程登录
转载自 开启SSH KEY在手机远程登陆路由 http://koolshare.cn/thread-67565-1-1.html (出处: KoolShare) 首先修改路由的登录名和密码 下载put ...
- 怎么看待php 面向对象思想
面向对象的程序设计思路是现代程序设计由面向过程演变面向对象的必然趋势,所以面向对象的而设计思路必然有它不同的时代意义,必然有着不同面向过程的不同历史使命,而php 5以后成功添加面向对象的设计思路其实 ...
- Spark之从hdfs读取数据
/user/hive/warehouse/ycapp.db/appindex") ), e(),e().toInt)) (String, String, String) ,,all_post ...
- sql一关联多查询时否定筛选出现的问题的解决
问题:一方关联多方查询时执行否定筛选,结果包含未通过筛选的项. 我们规定一方为父,多方为子,我们希望子未通过筛选时,结果也不出现对应的父. 查询部门及部门下的所有员工. SELECT * FROM d ...
- .NET开发框架(一)-框架介绍与视频演示
本文主要介绍一套基于.NET CORE的SPA高并发.高可用的开发框架. 我们暂且称它为:(让你懂.NET)开发框架. 以此为主线,陆续编写教程,讲述如何构建高并发.高可用的框架. (欢迎转载与分享) ...
- UI-grid 表格内容可编辑(enableCellEdit可指定列编辑)
在网上搜索了很多关于UI-Grid的问题 很遗憾好少啊啊啊 不过有API还是比较欣慰的 官方API:UI Grid 还有一位大佬的翻译的中文API:angularjs ui-grid中文api 行编辑 ...
- asyncio系列之sleep()实现
先来看个例子,自己实现的模拟耗时操作 例1 import types import select import time import socket import functools class Fu ...
- iOS中 分类(category)与扩展(Extension)的区别?
1.分类(category)的作用 (1).作用:可以在不修改原来类的基础上,为一个类扩展方法.(2).最主要的用法:给系统自带的类扩展方法. 2.分类中能写点啥? (1).分类中只能添加“方法”,不 ...