前言


最近在自学 Zigbee,每天的主要是任务是:看博客,看 CC2530 的 datasheet 和实践,熟悉片上的 SFR 以及控制板子。

学和做内容包括:IO、外部中断、Timer1/3/4、串口实验、ADC温度的转换、看门狗、Sleep Timer 和 DMA。

之后做了一个综合的小实验,基于 CC2530 的温度监测系统,关于协议栈的部分还在学习,所以这个实验没有使用到协议栈。

实验目的


检验学习成果,熟悉 sfr 的配置和片上资源的使用。

实验工具


硬件;CC2530、CCDebug、串口线

软件:IAR Embedded Workbench、串口调试助手

要实现的功能


1. 系统每 2s 统计一次温度,由定时器1 来精确定时;

2. 温度需要通过多次采样减少误差;

3. 得到温度后通过串口发送给上位机;

4. 有看门狗复位的功能;

5. 采集温度和发送数据时都有指示灯。

编码设计


主要分 3 个文件:includes.h、init.h 和 main.c

[ includes.h ]

 /*  includes.h  */
/*
* 1.ioCC2530.h的包含
* 2.全局变量的定义
* 3.所有函数的声明
*
*/ #ifndef INCLUDES_H
#define INCLUDES_H #include <ioCC2530.h> #define YLED P1_0
#define BLED P1_1 #define LEDON 1
#define LEDOFF 0 unsigned char output[] = {}; // 温度格式:"12.34\0"
unsigned char receive_char; // void xtal_init(void); void io_init(void); void timer1_init(void); void WDT_init(void); void FeetDog(void); void uart0_init(void); void setTempSensor(void); float adc_start(void); void get_temperature(unsigned char *output); void Uart_Send_String(unsigned char *Data); void Delay(unsigned int n); #endif

[ init.h ]

 /*  init.h  */
/*
* 硬件的初始化和函数定义
*
*/ #ifndef INIT_H
#define INIT_H #include "includes.h" extern unsigned char output[];
extern unsigned char receive_char; // 系统时钟初始化
void xtal_init(void)
{
CLKCONCMD &= ~0x40; // 选择系统时钟源为 32MHz 晶振
while(CLKCONSTA & 0x40); // 等待晶振稳定
CLKCONCMD &= ~0x47; // 设置系统主频为 32MHz
} // 设置电源模式,这个函数没有用到
// mode = 0, 1, 2, 3
void setPowerMode(unsigned char mode)
{
if(mode < )
{
CLKCONCMD &= 0xfc; // CLKCONCMD.mode = 0
CLKCONCMD |= mode; // 设置电源模式
PCON |= 0x01; // 启动设置的PM
}
} // P0口初始化
void io_init(void)
{
P1SEL = 0x00; // 通用数字IO
P1DIR |= 0x03; // P1_0和P1_1为输出
YLED = LEDOFF; // 灭灯
BLED = LEDOFF;
} // 串口0初始化
// 这些函数不通用,而且比宏定义耗资源
void uart0_init()
{
PERCFG = 0x00; // 位置1 P0口
P0SEL = 0x3c; // P0 用作串口
P2DIR &= ~0xc0; // P0 优先作为 UART0 U0CSR |= 0x80; // uart mode
U0GCR = ;
U0BAUD = ; // UTX0IF = ; // UART0 TX 中断标志置位
U0CSR |= 0X40; // 允许接收
IEN0 |= 0x84; // IEN0.URX0IE = 1
} // 串口接收中断
// 这里还没有实现控制 2530 的功能
#pragma vector = URX0_VECTOR
__interrupt void UART0_ISP(void)
{
EA = ;
URX0IF = ;
receive_char = U0DBUF; // y:start n:stop
Uart_Send_String(&receive_char);
Uart_Send_String("\r\n");
EA = ;
} // 连接 ADC 和温感器
void setTempSensor(void)
{
TR0 = 0x01; // 连接起来
ATEST = 0x01; // 启动温感
} // 启动 AD 转换
float adc_start()
{
unsigned int value;
ADCCON3 = 0x3e; // 选择 1.25V 为参考电压;14 位分辨率;片内采样
ADCCON1 |= 0x30; // 选择 ADC 的启动模式为手动
ADCCON1 |= 0x40; // 启动 AD 转换
while(!(ADCCON1 & 0x80)); // 等待转换结束 value = ADCL >> ; // 低 2 位数字无效
value |= (((unsigned int)ADCH) << ); return ((value>>) - );
} void get_temperature(unsigned char *output)
{
unsigned int i;
float AvgTemp = ;
for(i = ; i < ; i++) // 多次采样
{
AvgTemp += adc_start();
AvgTemp = AvgTemp/; //每次累加后除 2
}
AvgTemp /= ; output[] = (unsigned char)(AvgTemp) / + ; //十位
output[] = (unsigned char)(AvgTemp) % + ; //个位
output[] = '.'; //小数点
output[] = (unsigned char)(AvgTemp*) % + ; //十分位
output[] = (unsigned char)(AvgTemp*) % + ; //百分位
output[] = '\0'; //字符串结束符
} // 从串口发送字符串
void Uart_Send_String(unsigned char *Data)
{
BLED = LEDON; // 发送时蓝灯亮
while(*Data != '\0')
{
U0DBUF = *Data++;
while(UTX0IF == ); // 等待发送结束
UTX0IF = ; // 清除发送中断标志
}
BLED = LEDOFF; // 发送结束了
} // 定时器1初始化
/* 组合模式:
* 2s 62500 0xf424
* 1s 31250 0x7a12
* 0.5s 15625 0x3d09
*/
void timer1_init()
{
setTempSensor(); // 随带配置温感
EA = ; // 开启系统总中断
T1IE = ; // 开启定时器1中断
TIMIF |= 0x40; // Timer 1 overflow interrupt mask CLKCONCMD &= (~0x38);
CLKCONCMD |= 0x18; // 设置定时器1的频率为 4MHz T1CCTL0 |= 0x44; // 通道0 比较模式 T1CTL = 0x0e; // 128分频,模模式
T1STAT |=0x021; // 通道0,中断有效 T1CC0L = 0x2a;
T1CC0H = 0xf4; // 计数 2s T1IF = ; // 清除定时器1的中断标志
T1STAT = 0x00; // 清除通道0的中断标志
} // 定时器1溢出中断
// 采集温度并通过串口发送到上位机
#pragma vector = T1_VECTOR
__interrupt void T1_ISR(void)
{
YLED = LEDON; // 采集温度时黄灯亮
EA = ;
T1IF = ; // 清除 T1 中断标志 get_temperature(output); // 获取温度,存在全局变量 output 中
Uart_Send_String(output); // 串口送出
Uart_Send_String("℃\r\n"); // 输出符号和换行 YLED = LEDOFF; // 黄灯熄灭
EA = ;
} // 看门狗模式,1s复位
void WDT_init(void)
{
WDCTL = 0x00; // INT(10) = 00 1s
// mode(2) = 0 WDT mode
WDCTL |= 0x08; // EN(3) = 1
} // 喂狗
void FeetDog(void)
{
WDCTL = 0xa0;
WDCTL = 0x50;
} // 这个函数没有使用
void Delay(unsigned int n)
{
unsigned int i;
for(i=;i<n;i++);
for(i=;i<n;i++);
for(i=;i<n;i++);
for(i=;i<n;i++);
for(i=;i<n;i++);
} #endif

[ main.c ]

 #include <ioCC2530.h>
#include "includes.h"
#include "init.h" int main( void )
{
// 片上资源初始化
xtal_init();
io_init();
uart0_init();
timer1_init();
WDT_init(); // 定时器溢出 -> 采集温度数据 -> 串口输出
// 串口收到字符进入中断... EA = ; while(){
FeetDog();
}
return ;
}

实验结果


实验中遇到的主要问题


1)定时器T1 的准确定时

系统默认主频是 16MHz,如果使用 128 分频和自由运行模式,计算下来溢出时间是:

128/16000000*65536 = 0.524288,这个值 ≈ 0.5s,但是不够精确。

所以我采用了模模式,系统主频 32MHz,定时器 4MHz,128 分频,计数值从 0x0000 到 0xf424

2)自己的粗心

定时器1 采用模模式,使用方法有些许异于自由运行模式,看下面这段我从网上摘来的话:

模模式需要开启通道0的输出比较模式,否则计数器只有到了0XFF时才会产生溢出中断(相应的产生溢出标志),

也就是如果没有设置通道0的输出比较模式,计数器的值到达T1CC0后,不会产生溢出中断(相应的溢出标志不会置1),这点需要特别注意。

难怪我一直不能溢出啊,于是我在 timer_init(void) 定时器1初始化函数中添加了下面的两句:

T1CCTL0 |= 0x40; // 通道0 比较模式

T1STAT  |=0x021; // 通道0,中断有效

为什么还是不能溢出呢,我明明“写对”了啊!?后来经过多次尝试和阅读别人的代码,我回去看了手册:

我把 T1CCTL0.IM 置了位,也就是通道0 的中断屏蔽位,但是却粗心地把 mode 给遗忘了,我对不起你啊mode:

T1CCTL0 |= 0x44; // 通道0 比较模式

3)温度的确定,见代码

应该改进的地方


在看TI官方的例程的时候,发现人家关于硬件初始化的代码中,使用到了很多的宏,而且可以通用,不像我的代码,泪流满面,惨不忍睹。应该珍惜有限的资源。

最重要的体悟


多去阅读手册和实践,这是多么痛的领悟啊。

基于 CC2530 的温度采集系统(未定稿)的更多相关文章

  1. 基于CC2530/CC2430 的温度采集系统--DS18B20

    DS18B20是常用的温度传感器.CC2530 采集DS18B20 可以实现温度采集系统等等. 模块链接:https://item.taobao.com/item.htm?id=54130861732 ...

  2. 基于CC2530/CC2430 的光强采集系统--ADC实验

    使用光敏电阻,程序通用所有模拟量传感器 参见论坛中实例视频讲解http://bphero.com.cn/forum.php?mod=viewthread&tid=15&extra=pa ...

  3. 基于CC2530/CC2430 的温湿度采集系统--DHT11

    采用常用的温湿度传感器DHT11 参见论坛中实例视频讲解http://bphero.com.cn/forum.php?mod=viewthread&tid=15&extra=page% ...

  4. 基于ARM-LINUX的温度传感器驱动-DS18B20

    转载:http://blog.csdn.net/ayangke/article/details/6883244 作者:冯建,华清远见嵌入式学院讲师. DS18B20数字温度传感器接线方便,封装成后可应 ...

  5. 基于ARM-LINUX的温度传感器驱动(DS18B20) .

    DS18B20数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有LTM8877,LTM8874等等.主要根据应用场合的不同而改变其外观.封装 ...

  6. 基于CC2530的ZigBee转以太网网关的设计与实现

    *已刊登至:<无线电>8月刊 物联网技术的实现中,无线技术是必不可少的部分. 近年无线技术的发展,将ZigBee推入人们的视线中.那么ZigBee是如何的一种技术呢?带着疑问.我查询了它的 ...

  7. 基于Qt的图像采集系统

    硬件 Point Gray Camera 型号:FL3-U3-13S2C-CS 参数 Sony IMX035 CMOS, 1/3", 3.63 µm Rolling Shutter 1328 ...

  8. 基于CC2530的ZigBee最小系统

    http://www.cirmall.com/circuit/1946/%E5%9F%BA%E4%BA%8ECC2530%E7%9A%84ZigBee%E6%9C%80%E5%B0%8F%E7%B3% ...

  9. MCP3421使用详解

    0 摘要 因某项目需要,需要采集微弱的电压信号,且对电压精度要求较高,于是选中MCP3421这款18 bit 高精度IIC AD转换芯片.本文将结合MCP3421的手册,对该芯片的使用进行详细解释,并 ...

随机推荐

  1. linux - redis基础

    目录 linux - redis基础 redis 源码编译安装 redis 数据结构 1. strings类型 2. list 类型 3. sets集合类型 有序集合 5. 哈希数据结构 centos ...

  2. python json结构

    =====================================================json==============================import reques ...

  3. Xen、OpenVZ、KVM、Hyper-V、VMWare虚拟化技术介绍

    一.Xen 官网:http://xen.org/ Xen 由剑桥大学开发,它是基于硬件的完全分割,物理上有多少的资源就只能分配多少资源,因此很难超售.可分为Xen-PV(半虚拟化),和Xen-HVM( ...

  4. SCU Travel

    Travel The country frog lives in has n towns which are conveniently numbered by 1,2,…,n . Among n(n− ...

  5. (38)Spring Boot分布式Session状态保存Redis【从零开始学Spring Boot】

    [本文章是否对你有用以及是否有好的建议,请留言] 在使用spring boot做负载均衡的时候,多个app之间的session要保持一致,这样负载到不同的app时候,在一个app登录之后,而访问到另外 ...

  6. 联赛前集训日记Day2

    考试 倒数第二,我已经废了= = T1 那么水的点转区间都看不出来 T2 裸的线段树生打了个啥都不是的分块 T3 枚举想骗spj的部分分,结果啥都没有 GG 刷题 改题改的也是心累,现在蒙的要死 生活 ...

  7. .net performance optimize your C# app 读书笔记

    目录 序 作者简介 推荐人简介 感谢 本书简介 第一章  性能指标 第二章  性能测量 第三章  内部类型 第四章  垃圾回收机制 第五章  集合和泛型 第六章  并发和并行性 第七章  网络.I / ...

  8. nginx启动访问

    修改配置文件后,查看配置是否ok 以下是有错误的 以下是ok的 nginx/sbin/nginx -t 启动查询: /usr/local/nginx/sbin/nginx -c /usr/local/ ...

  9. 编程算法 - 和为s的连续正整数序列 代码(C)

    和为s的连续正整数序列 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 输入一个正数s, 打印出全部和为s的连续正数序列(至少含有两个数). 起 ...

  10. VC UI界面库大集合

    Guitoolkit http://www.beyondata.com/pwc.html The Ultimate Toolbox http://www.codeproject.com/KB/MFC/ ...