前言
最近在自学 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 ]
1 /* includes.h */ 2 /* 3 * 1.ioCC2530.h的包含 4 * 2.全局变量的定义 5 * 3.所有函数的声明 6 * 7 */ 8 9 #ifndef INCLUDES_H 10 #define INCLUDES_H 11 12 13 #include <ioCC2530.h> 14 15 16 #define YLED P1_0 17 #define BLED P1_1 18 19 #define LEDON 1 20 #define LEDOFF 0 21 22 23 unsigned char output[6] = {0}; // 温度格式:"12.34 " 24 unsigned char receive_char; // 25 26 27 void xtal_init(void); 28 29 void io_init(void); 30 31 void timer1_init(void); 32 33 void WDT_init(void); 34 35 void FeetDog(void); 36 37 void uart0_init(void); 38 39 void setTempSensor(void); 40 41 float adc_start(void); 42 43 void get_temperature(unsigned char *output); 44 45 void Uart_Send_String(unsigned char *Data); 46 47 void Delay(unsigned int n); 48 49 #endif
[ init.h ]
1 /* init.h */ 2 /* 3 * 硬件的初始化和函数定义 4 * 5 */ 6 7 #ifndef INIT_H 8 #define INIT_H 9 10 11 #include "includes.h" 12 13 extern unsigned char output[6]; 14 extern unsigned char receive_char; 15 16 17 // 系统时钟初始化 18 void xtal_init(void) 19 { 20 CLKCONCMD &= ~0x40; // 选择系统时钟源为 32MHz 晶振 21 while(CLKCONSTA & 0x40); // 等待晶振稳定 22 CLKCONCMD &= ~0x47; // 设置系统主频为 32MHz 23 } 24 25 // 设置电源模式,这个函数没有用到 26 // mode = 0, 1, 2, 3 27 void setPowerMode(unsigned char mode) 28 { 29 if(mode < 4) 30 { 31 CLKCONCMD &= 0xfc; // CLKCONCMD.mode = 0 32 CLKCONCMD |= mode; // 设置电源模式 33 PCON |= 0x01; // 启动设置的PM 34 } 35 } 36 37 // P0口初始化 38 void io_init(void) 39 { 40 P1SEL = 0x00; // 通用数字IO 41 P1DIR |= 0x03; // P1_0和P1_1为输出 42 YLED = LEDOFF; // 灭灯 43 BLED = LEDOFF; 44 } 45 46 // 串口0初始化 47 // 这些函数不通用,而且比宏定义耗资源 48 void uart0_init() 49 { 50 PERCFG = 0x00; // 位置1 P0口 51 P0SEL = 0x3c; // P0 用作串口 52 P2DIR &= ~0xc0; // P0 优先作为 UART0 53 54 U0CSR |= 0x80; // uart mode 55 U0GCR = 11; 56 U0BAUD = 216; // 115200 57 58 UTX0IF = 1; // UART0 TX 中断标志置位 59 U0CSR |= 0X40; // 允许接收 60 IEN0 |= 0x84; // IEN0.URX0IE = 1 61 } 62 63 // 串口接收中断 64 // 这里还没有实现控制 2530 的功能 65 #pragma vector = URX0_VECTOR 66 __interrupt void UART0_ISP(void) 67 { 68 EA = 0; 69 URX0IF = 0; 70 receive_char = U0DBUF; // y:start n:stop 71 Uart_Send_String(&receive_char); 72 Uart_Send_String(" "); 73 EA = 1; 74 } 75 76 // 连接 ADC 和温感器 77 void setTempSensor(void) 78 { 79 TR0 = 0x01; // 连接起来 80 ATEST = 0x01; // 启动温感 81 } 82 83 // 启动 AD 转换 84 float adc_start() 85 { 86 unsigned int value; 87 ADCCON3 = 0x3e; // 选择 1.25V 为参考电压;14 位分辨率;片内采样 88 ADCCON1 |= 0x30; // 选择 ADC 的启动模式为手动 89 ADCCON1 |= 0x40; // 启动 AD 转换 90 while(!(ADCCON1 & 0x80)); // 等待转换结束 91 92 value = ADCL >> 2; // 低 2 位数字无效 93 value |= (((unsigned int)ADCH) << 6); 94 95 return ((value>>4) - 315); 96 } 97 98 void get_temperature(unsigned char *output) 99 { 100 unsigned int i; 101 float AvgTemp = 0; 102 for(i = 0 ; i < 64 ; i++) // 多次采样 103 { 104 AvgTemp += adc_start(); 105 AvgTemp = AvgTemp/2; //每次累加后除 2 106 } 107 AvgTemp /= 2; 108 109 output[0] = (unsigned char)(AvgTemp) / 10 + 48; //十位 110 output[1] = (unsigned char)(AvgTemp) % 10 + 48; //个位 111 output[2] = '.'; //小数点 112 output[3] = (unsigned char)(AvgTemp*10) % 10 + 48; //十分位 113 output[4] = (unsigned char)(AvgTemp*100) % 10 + 48; //百分位 114 output[5] = '