架构师_程序员_码农网

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6316|回复: 1

【转】Zigbee之旅(十):综合小实验——基于CC2430的温度监测系统

[复制链接]
发表于 2014-10-30 23:47:44 | 显示全部楼层 |阅读模式
 在3月3日写完“zigbee之旅(九)”后,笔者本打算立即着手“温度监测系统”小实验的编写,以作为对之前一系列零散知识点的总结。然而我又意识到,前面的几个小实验虽然每一篇都讲得较为详细,但是其代码的规范性、结构性,可以说是不堪入目的。既然是小结,就应当在原来的基础上有所进步,而不是机械地把前面的小知识点拼凑起来了事。因此,我暂停了原来的计划,抽出时间去学习了一下嵌入式开发的通用技巧,写下了两篇随笔《嵌入式C51编程规范》和《嵌入式项目代码结构的分层》。本篇日志,既是Zigbee首次旅行的一个阶段性小结,也融入了笔者近几天的学习心得,希望能对Zigbee初学者有所帮助。
  全文按软件开发的基本流程来组织:需求分析、概要设计、详细设计、编码实现、测试。
一、需求分析
  经“客户”与“开发者”共同商讨,确定了如下的系统功能描述:
  …缀用基于CC2430的节点采集当前室温,并可通过PC监测其温度数值
  …CC2430节点本身需具备一定的稳定性,可自动恢复正常状态
  …可通过PC来控制节点的采样间隔与电源管理
二、概要设计
  根据上述需求分析,我们可以把系统分为两大模块:CC2430节点 PC机
2011030915423875.png
  [CC2430节点]  
   …可定时采集外部参数,并发送至PC端
   …尀机时自动复位
   …可接收来自PC机的指令,并作出相应处理:改变采样间隔/电源管理
  [PC机]  
   …倀C机通过串口工具接收数据并显示
   …可通过串口工具向单片机发送指令,控制其采样速度,电源管理
三、详细设计
(1)代码结构
  本系统代码结构的分层,其实已在随笔《嵌入式项目代码结构的分层》中提到了,现copy如下:
  (1)硬件抽象层
      [ioCC2430.h](系统自带)定义了CC2430的所有SFR 、中断向量   
      [hal.h] 包括常用类型定义、常用赋值宏、以及CC2430片上资源的通用配置(I/O、串口通讯、ADC、定时器、电源管理等)
  (2)功能模块层
      [module.h] 定义了片内资源(定时器、I/O)片外扩展模块(LED),以及相关函数的声明
      [module.c] 实现各模块(LED)的初始化
  (3)应用程序层
      [main.c] 引用 hal.h、ioCC2430.h 与 module.h,实现温度采集、与PC互通信、停机复位等具体的应用需求
(2)各模块实现方法
  根据概要设计中所划分的模块包括,本性系统可分为两大模块:CC2430节点PC机
  由于PC机上已有串口通信工具,其功能已能满足要求,所以PC这一部分我们不需要做,没必要对其分析。下面谈一下CC2430节
点的各子功能的实现方法:
  …利用定时器的计数溢出中断,来触发定时采样
  …缀用串口的 UART0 模式将温度数据传送至PC
  …利用CC2430自带的看门狗电路,实现系统的停机自动复位功能
  …利用串口接收中断,来实现对来自PC端的控制指令的捕获与响应
    1) 若接收到 @ 字符,则为采样间隔控制命令,后面紧跟的一个数字表示采样间隔:0——0.5s、1——1s、2——2s
     如:@0,表示每隔0.5秒采样一次。
    2) 若接收到 $  字符,则为睡眠控制命令,后面紧跟的一个数字表示电源模式
     如:$3,表示使系统进入电源模式3。
(3)程序流程图
  • 主程序流程图
  • 定时器1溢出中断程序流程图
  • 串口接收中断程序流程图
2011031221543780.png
2011031221572357.png

2011031222005035.png


四、编码实现
(1)硬件抽象层
  硬件抽象层包括 ioCC2430.h 和 hal.h。由于前者系统自带,就不列出来了。
  下面把 hal.h 的全部内容列出来(由于这个文件太长,看起来不方便,我就分模块展示):
  • 头部
  • I/O口
  • 中断
  • 串口
  • 电源及时钟管理
  • 定时器
  • 看门狗
  • ADC
[url=] copycode.gif [/url]
/***********************************************************
*文件名称:    hal.h
*作    者:    hustlzp
*日    期:    2011/3/8
*版    本:    1.1
*功能说明:    硬件抽象层
*修改记录:
**********************************************************
*/


#ifndef HAL_H
#define HAL_H


#include


/***********************************************************
                       常用类型定义
**********************************************************
*/
typedef unsigned char   BYTE;
typedef unsigned int    WORD;
typedef unsigned long   DWORD;



/***********************************************************
                       常用宏定义
**********************************************************
*/

//高8位
#define HIGH_BYTE(a) ((BYTE) (((WORD)(a)) >> 8))


//低8位
#define LOW_BYTE(a) ((BYTE) ((WORD)(a)))


//赋值
#define SET_WORD(regH,regL,word)  
   do{                           
      (regH)=HIGH_BYTE(word);     
      (regL)=LOW_BYTE(word);      
   }while(0)
[url=][/url]

[url=][/url]
/***********************************************************
                       I/O口
**********************************************************
*/
/*配置I/O口方向
-----------------------------------------
*/
#define IO_DIR_PORT_PIN(port, pin, dir)  
   do {                                 
      if (dir == IO_OUT)                 
         P##port##DIR |= (0x01<<(pin));  
      else                              
         P##port##DIR &= ~(0x01<<(pin));
   }while(0)



//其中参数 dir 的取值为:
#define IO_IN   0
#define IO_OUT  1


/*配置I/O口的输入模式
-----------------------------------------
*/
#define IO_IMODE_PORT_PIN(port, pin, imode)
   do {                                    
      if (imode == IO_IMODE_TRI)            
         P##port##INP |= (0x01<<(pin));     
      else                                 
         P##port##INP &= ~(0x01<<(pin));   
   } while (0)



#define IO_PUD_PORT(port, pud)        
   do {                              
      if (pud == IO_PULLDOWN)         
         P2INP |= (0x01 << (port+5));
      else                           
         P2INP &= ~(0x01 << (port+5));
   } while (0)


//其中参数 pud 的取值为:
#define IO_PULLUP     0   //上拉
#define IO_PULLDOWN   1   //下拉


/*配置I/O口的功能
-----------------------------------------*/

#define IO_FUNC_PORT_PIN(port, pin, func)  
   do {                                    
      if((port == 2) && (pin == 3)){      
         if (func) {                       
            P2SEL |= 0x02;                 
         } else {                          
            P2SEL &= ~0x02;               
         }                                 
      }                                    
      else if((port == 2) && (pin == 4)){  
         if (func) {                       
            P2SEL |= 0x04;                 
         } else {                          
            P2SEL &= ~0x04;               
         }                                 
      }                                    
      else{                                
         if (func) {                       
            P##port##SEL |= (0x01<<(pin));
         } else {                          
            P##port##SEL &= ~(0x01<<(pin));
        }                                 
      }                                    
   } while (0)


//其中参数 func 的取值为:
#define IO_FUNC_GIO     0    // 通用I/O
#define IO_FUNC_PERIPH  1    // 外设I/O


// 配置外设I/O的位置
#define IO_PER_LOC_TIMER1_AT_PORT0_PIN234() do { PERCFG = (PERCFG&~0x40)|0x00; } while (0)
#define IO_PER_LOC_TIMER1_AT_PORT1_PIN012() do { PERCFG = (PERCFG&~0x40)|0x40; } while (0)

#define IO_PER_LOC_TIMER3_AT_PORT1_PIN34()  do { PERCFG = (PERCFG&~0x20)|0x00; } while (0)
#define IO_PER_LOC_TIMER3_AT_PORT1_PIN67()  do { PERCFG = (PERCFG&~0x20)|0x20; } while (0)

#define IO_PER_LOC_TIMER4_AT_PORT1_PIN01()  do { PERCFG = (PERCFG&~0x10)|0x00; } while (0)
#define IO_PER_LOC_TIMER4_AT_PORT2_PIN03()  do { PERCFG = (PERCFG&~0x10)|0x10; } while (0)

#define IO_PER_LOC_SPI1_AT_PORT0_PIN2345()  do { PERCFG = (PERCFG&~0x08)|0x00; } while (0)
#define IO_PER_LOC_SPI1_AT_PORT1_PIN4567()  do { PERCFG = (PERCFG&~0x08)|0x08; } while (0)

#define IO_PER_LOC_SPI0_AT_PORT0_PIN2345()  do { PERCFG = (PERCFG&~0x04)|0x00; } while (0)
#define IO_PER_LOC_SPI0_AT_PORT1_PIN2345()  do { PERCFG = (PERCFG&~0x04)|0x04; } while (0)

#define IO_PER_LOC_UART1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x02)|0x00; } while (0)
#define IO_PER_LOC_UART1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x02)|0x02; } while (0)

#define IO_PER_LOC_UART0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x00; } while (0)
#define IO_PER_LOC_UART0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x01; } while (0)

//其中参数 imode 的取值为:
#define IO_IMODE_PUD  0   // 上拉/下拉
#define IO_IMODE_TRI  1   // 三态[url=][/url]

[url=][/url]
/***********************************************************
                       中断
**********************************************************
*/
// 用于开/关中断
#define INT_ON   1
#define INT_OFF  0


// 用于置位/清除中断标志
#define INT_SET  1
#define INT_CLR  0


// 全局中断设置
#define INT_GLOBAL_ENABLE(on) EA=(!!on)


//定义中断
#define INUM_RFERR 0
#define INUM_ADC   1
#define INUM_URX0  2
#define INUM_URX1  3
#define INUM_ENC   4
#define INUM_ST    5
#define INUM_P2INT 6
#define INUM_UTX0  7
#define INUM_DMA   8
#define INUM_T1    9
#define INUM_T2    10
#define INUM_T3    11
#define INUM_T4    12
#define INUM_P0INT 13
#define INUM_UTX1  14
#define INUM_P1INT 15
#define INUM_RF    16
#define INUM_WDT   17


/*中断允许
-----------------------------------------
*/
#define INT_ENABLE(inum, on)                        
   do {                                             
      if      (inum==INUM_RFERR) { RFERRIE = on; }  
      else if (inum==INUM_ADC)   { ADCIE   = on; }  
      else if (inum==INUM_URX0)  { URX0IE  = on; }  
      else if (inum==INUM_URX1)  { URX1IE  = on; }  
      else if (inum==INUM_ENC)   { ENCIE   = on; }  
      else if (inum==INUM_ST)    { STIE    = on; }  
      else if (inum==INUM_P2INT) { (on) ? (IEN2 |= 0x02) : (IEN2 &= ~0x02); }
      else if (inum==INUM_UTX0)  { (on) ? (IEN2 |= 0x04) : (IEN2 &= ~0x04); }
      else if (inum==INUM_DMA)   { DMAIE   = on; }  
      else if (inum==INUM_T1)    { T1IE    = on; }  
      else if (inum==INUM_T2)    { T2IE    = on; }  
      else if (inum==INUM_T3)    { T3IE    = on; }  
      else if (inum==INUM_T4)    { T4IE    = on; }  
      else if (inum==INUM_P0INT) { P0IE    = on; }  
      else if (inum==INUM_UTX1)  { (on) ? (IEN2 |= 0x08) : (IEN2 &= ~0x08); }
      else if (inum==INUM_P1INT) { (on) ? (IEN2 |= 0x10) : (IEN2 &= ~0x10); }
      else if (inum==INUM_RF)    { (on) ? (IEN2 |= 0x01) : (IEN2 &= ~0x01); }
      else if (inum==INUM_WDT)   { (on) ? (IEN2 |= 0x20) : (IEN2 &= ~0x20); }
   } while (0)


/*设置中断优先级
-----------------------------------------
*/
#define INT_PRIORITY(group, pri)                     
   do {                                               
      if (pri == 0) { IP0 &= ~group; IP1 &= ~group; }
      if (pri == 1) { IP0 |=  group; IP1 &= ~group; }
      if (pri == 2) { IP0 &= ~group; IP1 |=  group; }
      if (pri == 3) { IP0 |=  group; IP1 |=  group; }
   } while (0)

// 其中参数 pri 的取值为:0/1/2/3(最高优先级)


// 其中参数 group 的取值为:
#define RFERR_RF_DMA    0x01 // Group IP0
#define ADC_P2INT_T1    0x02 // Group IP1
#define URX0_UTX0_T2    0x04 // Group IP2
#define URX1_UTX1_T3    0x08 // Group IP3
#define ENC_P1INT_T4    0x10 // Group IP4
#define ST_WDT_P0INT    0x20 // Group IP5


/*获取中断标志
-----------------------------------------
*/
#define INT_GETFLAG(inum) (                       
   (inum==INUM_RFERR)       ? RFERRIF           :
   (inum==INUM_ADC)         ? ADCIF             :
   (inum==INUM_URX0)        ? URX0IF            :
   (inum==INUM_URX1)        ? URX1IF            :
   (inum==INUM_ENC)         ? ENCIF_0           :
   (inum==INUM_ST)          ? STIF              :
   (inum==INUM_P2INT)       ? P2IF              :
   (inum==INUM_UTX0)        ? UTX0IF            :
   (inum==INUM_DMA)         ? DMAIF             :
   (inum==INUM_T1)          ? T1IF              :
   (inum==INUM_T2)          ? T2IF              :
   (inum==INUM_T3)          ? T3IF              :
   (inum==INUM_T4)          ? T4IF              :
   (inum==INUM_P0INT)       ? P0IF              :
   (inum==INUM_UTX1)        ? UTX1IF            :
   (inum==INUM_P1INT)       ? P1IF              :
   (inum==INUM_RF)          ? S1CON &= ~0x03    :
   (inum==INUM_WDT)         ? WDTIF             :
   0                                             
)


/*设置中断标志
-----------------------------------------
*/
#define INT_SETFLAG(inum, f)                     
   do {                                          
      if      (inum==INUM_RFERR) { RFERRIF= f; }
      else if (inum==INUM_ADC)   { ADCIF  = f; }
      else if (inum==INUM_URX0)  { URX0IF = f; }
      else if (inum==INUM_URX1)  { URX1IF = f; }
      else if (inum==INUM_ENC)   { ENCIF_1 = ENCIF_0 = f; }
      else if (inum==INUM_ST)    { STIF  = f;  }
      else if (inum==INUM_P2INT) { P2IF  = f;  }
      else if (inum==INUM_UTX0)  { UTX0IF= f;  }
      else if (inum==INUM_DMA)   { DMAIF = f;  }
      else if (inum==INUM_T1)    { T1IF  = f;  }
      else if (inum==INUM_T2)    { T2IF  = f;  }
      else if (inum==INUM_T3)    { T3IF  = f;  }
      else if (inum==INUM_T4)    { T4IF  = f;  }
      else if (inum==INUM_P0INT) { P0IF  = f;  }
      else if (inum==INUM_UTX1)  { UTX1IF= f;  }
      else if (inum==INUM_P1INT) { P1IF  = f;  }
      else if (inum==INUM_RF)    { (f) ? (S1CON |= 0x03) : (S1CON &= ~0x03); }
      else if (inum==INUM_WDT)   { WDTIF = f;  }
   } while (0)
[url=][/url]

[url=][/url]
/***********************************************************
                       串口
**********************************************************
*/
// 不同波特率对应的BAUD_E的值
#define BAUD_E(baud, clkDivPow) (     
    (baud==2400)   ?  6  +clkDivPow :
    (baud==4800)   ?  7  +clkDivPow :
    (baud==9600)   ?  8  +clkDivPow :
    (baud==14400)  ?  8  +clkDivPow :
    (baud==19200)  ?  9  +clkDivPow :
    (baud==28800)  ?  9  +clkDivPow :
    (baud==38400)  ?  10 +clkDivPow :
    (baud==57600)  ?  10 +clkDivPow :
    (baud==76800)  ?  11 +clkDivPow :
    (baud==115200) ?  11 +clkDivPow :
    (baud==153600) ?  12 +clkDivPow :
    (baud==230400) ?  12 +clkDivPow :
    (baud==307200) ?  13 +clkDivPow :
    0  )


// 不同波特率对应的BAUD_M的值
#define BAUD_M(baud) (      
    (baud==2400)   ?  59  :
    (baud==4800)   ?  59  :
    (baud==9600)   ?  59  :
    (baud==14400)  ?  216 :
    (baud==19200)  ?  59  :
    (baud==28800)  ?  216 :
    (baud==38400)  ?  59  :
    (baud==57600)  ?  216 :
    (baud==76800)  ?  59  :
    (baud==115200) ?  216 :
    (baud==153600) ?  59  :
    (baud==230400) ?  216 :
    (baud==307200) ?  59  :
  0)


/* UART模式下的串口配置
-----------------------------------------
*/
#define UART_SETUP(uart, receiveEnable, baudRate, options)      
   do {                                                         
      if((uart) == 0){                                          
         if(PERCFG & 0x01){                                    
            P1SEL |= 0x30;                                      
         } else {                                               
            P0SEL |= 0x0C;                                      
         }                                                      
      }                                                         
      else {                                                   
         if(PERCFG & 0x02){                                    
            P1SEL |= 0xC0;                                      
         } else {                                               
            P0SEL |= 0x30;                                      
         }                                                      
      }                                                         
                                                               
      U##uart##GCR = BAUD_E((baudRate),CLKSPD);                 
      U##uart##BAUD = BAUD_M(baudRate);                        
                                                               
      U##uart##CSR |= 0x80;                                    
                                                               
      U##uart##CSR |= receiveEnable;                           
                                                               
      U##uart##UCR |= ((options) | 0x80);                       
   } while(0)
     
//其中参数 receiveEnable 的取值:
#define UART_RECEIVE_ENABLE         0x40   //接收允许
#define UART_RECEIVE_DISABLE        0x00   
     
// 其中参数 options 的取值:
#define FLOW_CONTROL_ENABLE         0x40   //流控制
#define FLOW_CONTROL_DISABLE        0x00


#define EVEN_PARITY                 0x20   //偶校验
#define ODD_PARITY                  0x00   //奇校验


#define NINE_BIT_TRANSFER           0x10   //9字节传输
#define EIGHT_BIT_TRANSFER          0x00   //8字节传输


#define PARITY_ENABLE               0x08   //奇偶校验使能
#define PARITY_DISABLE              0x00

#define TWO_STOP_BITS               0x04   //2位停止位
#define ONE_STOP_BITS               0x00   //1位停止位


#define HIGH_STOP                   0x02   //停止位高电平
#define LOW_STOP                    0x00   //停止位低电平
     
#define HIGH_START                  0x01   //起始位电平高
#define LOW_START                   0x00   //起始位电平低


//串口发送字符
#define UART_SEND(uart,data)            
   do{                                 
     while(U##uart##CSR & 0x01);        
       U##uart##DBUF = data;            
   } while (0)
#define UART0_SEND(data) UART_SEND(0,data)
#define UART1_SEND(data) UART_SEND(1,data)


//串口接收字符
#define UART_RECEIVE(uart,data)         
   do{                                 
     while(!(U##uart##CSR&0x04));      
       data=U##uart##DBUF;              
   } while(0)
#define UART0_RECEIVE(data) UART_RECEIVE(0,data)
#define UART1_RECEIVE(data) UART_RECEIVE(1,data)
[url=][/url]

[url=][/url]
/***********************************************************
                       电源及时钟管理
**********************************************************
*/
// 获取时钟分频
#define CLKSPD  (CLKCON & 0x07)


// 设置电源模式
#define SET_POWER_MODE(mode)                  
   do {                                       
      if(mode == 0)        { SLEEP &= ~0x03; }
      else if (mode == 3)  { SLEEP |= 0x03;  }
      else { SLEEP &= ~0x03; SLEEP |= mode;  }
      PCON |= 0x01;                           
      asm("NOP");                              
   }while (0)


// 参数 mode 的取值为:
#define POWER_MODE_0  0x00  
#define POWER_MODE_1  0x01
#define POWER_MODE_2  0x02
#define POWER_MODE_3  0x03


// 用于检测高频RC振荡器的稳定状况
#define HIGH_FREQUENCY_RC_OSC_STABLE    (SLEEP & 0x20)


// 用于检测晶体振荡器的稳定状况
#define XOSC_STABLE (SLEEP & 0x40)


// 获取定时器的tick频率值
#define TICKSPD ((CLKCON & 0x38) >> 3)


// 设置主时钟频率
#define SET_MAIN_CLOCK_SOURCE(source)
   do {                              
      if(source) {                    
        CLKCON |= 0x40;               
        while(!HIGH_FREQUENCY_RC_OSC_STABLE);
        if(TICKSPD == 0){            
          CLKCON |= 0x08;            
        }                             
        SLEEP |= 0x04;               
      }                              
      else {                          
        SLEEP &= ~0x04;               
        while(!XOSC_STABLE);         
        asm("NOP");                  
        CLKCON &= ~0x47;              
        SLEEP |= 0x04;               
      }                              
   }while (0)


// 其中参数 source 的取值为:
#define CRYSTAL 0x00    //晶体振荡器
#define RC      0x01    //RC振荡器
[url=][/url]

[url=][/url]
/***********************************************************
                       定时器1
**********************************************************
*/
//定时器1允许计数溢出中断
#define TIMER1_ENABLE_OVERFLOW_INT(val)
   (TIMIF =  (val) ? TIMIF | 0x40 : TIMIF & ~0x40)


//设置定时器1的溢出中断标志
#define TIMER1_OVERFLOW_INT_SETFLAG(f) (T1CTL= ((T1CTL & (~0x10)) | f))


//定时器1启动
#define TIMER1_RUN(value)      (T1CTL = (value) ? T1CTL|0x02 : T1CTL&~0x03)


//设置定时器的时钟分频
#define SET_TIMER_TICK(value)  do{ CLKCON = ((CLKCON & (~0x38)) | value);} while(0)


//其中value的取值为:
#define TIMER1_TICK_32M    0x00  // 32MHz
#define TIMER1_TICK_16M    0x08  // 16MHz,系统复位默认值
#define TIMER1_TICK_8M     0x10  // 8MHz
#define TIMER1_TICK_4M     0x18  // 4MHz
#define TIMER1_TICK_2M     0x20  // 2MHz
#define TIMER1_TICK_1M     0x28  // 1MHz
#define TIMER1_TICK_500k   0x30  // 500kHz
#define TIMER1_TICK_250k   0x38  // 250kHz

//设置定时器1的TICK分频
#define SET_TIMER1_TICKDIV(value)  
   do{                             
     T1CTL &= ~0x0c;               
     T1CTL |= value;               
   } while (0)
      
//其中 value 的取值为:      
#define TIMER1_TICKDIV_1     0x00   //1分频
#define TIMER1_TICKDIV_8     0x04   //8分频
#define TIMER1_TICKDIV_32    0x08
#define TIMER1_TICKDIV_128   0x0c


//设置定时器溢出周期
#define SET_TIMER1_PERIOD(value)
   do{                           
     T1CC0H = HIGH_BYTE(value);  
     T1CC0L = LOW_BYTE(value);   
   } while (0)
     
//设置定时器1的运行模式
#define SET_TIMER1_MODE(mode)  
   do{                        
     T1CTL = ((T1CTL & (~0x03)) | mode);           
   } while (0)


//其中 mode 的取值为:
#define TIMER1_MODE_STOP    0x00
#define TIMER1_MODE_FREE    0x01
#define TIMER1_MODE_MODULE  0x02
#define TIMER1_MODE_UPDOWN  0x03
[url=][/url]

[url=][/url]
/***********************************************************
                       看门狗
**********************************************************
*/
// 设置看门狗定时器的溢出周期
#define WDT_SET_TIMEOUT_PERIOD(timeout)
   do {  WDCTL &= ~0x03; WDCTL |= timeout; } while (0)


// 其中参数 timeout 的取值为:
#define SEC_1          0x00     // after 1 second
#define M_SEC_250      0x01     // after 250 ms
#define M_SEC_15       0x02     // after 15 ms
#define M_SEC_2        0x03     // after 2 ms


// 喂狗程序
#define WDT_RESET() do {           
   WDCTL = (WDCTL & ~0xF0) | 0xA0;
   WDCTL = (WDCTL & ~0xF0) | 0x50;
} while (0)


// 启动/停止看门狗定时器
#define WDT_ENABLE()   WDCTL |= 0x08
#define WDT_DISABLE()  WDCTL &= ~0x08
[url=][/url]

[url=][/url]
/***********************************************************
                       ADC
**********************************************************
*/
// 配置单次ADC
#define ADC_SINGLE_CONVERSION(settings)
   do{ ADCCON3 = settings; }while(0)

// 其中的参数 setting 由下面的组合构成
// 参考电压
#define ADC_REF_1_25_V      0x00     // 内部 1.25V 参考电压
#define ADC_REF_P0_7        0x40     // AIN7 引脚上的外部参考电压
#define ADC_REF_AVDD        0x80     // AVDD_SOC 引脚
#define ADC_REF_P0_6_P0_7   0xC0     // AIN6-AIN7 差分输入的外部参考电压


// 采样速率
#define ADC_8_BIT           0x00     // 8位
#define ADC_10_BIT          0x10     // 10位
#define ADC_12_BIT          0x20     // 12位
#define ADC_14_BIT          0x30     // 14位


// 输入频道
#define ADC_AIN0            0x00     // P0_0
#define ADC_AIN1            0x01     // P0_1
#define ADC_AIN2            0x02     // P0_2
#define ADC_AIN3            0x03     // P0_3
#define ADC_AIN4            0x04     // P0_4
#define ADC_AIN5            0x05     // P0_5
#define ADC_AIN6            0x06     // P0_6
#define ADC_AIN7            0x07     // P0_7
#define ADC_GND             0x0C     //
#define ADC_TEMP_SENS       0x0E     // 片内温度传感器
#define ADC_VDD_3           0x0F     // vdd/3




// ADC转换完成的标志
#define ADC_SAMPLE_READY()  (ADCCON1 & 0x80)

#endif
//启动ADC转化
#define ADC_START()
  do { ADCCON1 |= 0x40; } while (0)// 选择ADC的触发模式为手动(即ADC_SAMPLE_READY)
#define ADC_STOP()  
  do { ADCCON1 |= 0x30; } while (0)[url=][/url]


(2)功能模块层
  • module.h
  • module.c
[url=][/url]
/***********************************************************
*文件名称:  module.h
*作    者:  hustlzp
*日    期:  2011/3/6
*版    本:  1.0
*功能说明:  功能模块层头文件
*函数列表:  void  led_init()
            void  timer1_init()
            void  uart0_init(void);
            void  Uart0SendString(unsigned char *s);
            float adc_start(void)
            void  get_temperature(unsigned char *output,float temp);
            void  watchdog_init(void);
*修改记录:
**********************************************************
*/

#ifndef MODULE_H
#define MODULE_H


#include "hal.h"


/***********************************************************
                        LED
**********************************************************
*/
//定义LED引脚
#define led1    P1_0         
#define led2    P1_1         
#define led3    P1_2         
#define led4    P1_3   

//led亮与灭
#define LED_OFF  1
#define LED_ON   0

//LED初始化
void led_init(void);




/***********************************************************
                        timer1
**********************************************************
*/
//用于设置定时器的溢出周期值
#define TIMER1_OVF_2SEC     0xF424    // 2s
#define TIMER1_OVF_1SEC     0x7A12    // 1s
#define TIMER1_OVF_dot5SEC  0x3D09    // 0.5s   

//定时器1初始化
void  timer1_init(void);
                  

/***********************************************************
                        UART0
**********************************************************
*/
//UART0初始化
void  uart0_init(void);                    

//串口传送字符串
void  Uart0SendString(unsigned char *s);
   

/***********************************************************
                        ADC-14
**********************************************************
*/
//用于将ADC得到的数据转化为摄氏温度
#define ADC_TO_CELSIUS(temp) (temp * 0.06229 - 311.43)

//启动ADC转换
float adc_start(void);

//转换
void  get_temperature(unsigned char *output,float temp);


/***********************************************************
                        WatchDog
**********************************************************
*/
//看门狗初始化
void  watchdog_init(void);                 

#endif
[url=][/url]

[url=][/url]
/***********************************************************
*文件名称:  module.c
*作    者:  hustlzp
*日    期:  2011/3/11
*版    本:  1.0
*功能说明:  功能模块层源文件
*函数列表:  (略)
*修改记录:
**********************************************************
*/


#include "module.h"


/***********************************************************
*函数名称: led_init
*函数功能: LED初始化
*入口参数: 无    
*出口参数: 无  
**********************************************************
*/
void led_init(void)
{
  //配置P1.0 P1.1 P1.2 P1.3 为通用I/O口
  IO_FUNC_PORT_PIN(1, 0, IO_FUNC_GIO);
  IO_FUNC_PORT_PIN(1, 1, IO_FUNC_GIO);
  IO_FUNC_PORT_PIN(1, 2, IO_FUNC_GIO);
  IO_FUNC_PORT_PIN(1, 3, IO_FUNC_GIO);
  
  //配置P1.0 P1.1 P1.2 P1.3 为输出
  IO_DIR_PORT_PIN(1, 0, IO_OUT);
  IO_DIR_PORT_PIN(1, 1, IO_OUT);
  IO_DIR_PORT_PIN(1, 2, IO_OUT);
  IO_DIR_PORT_PIN(1, 3, IO_OUT);
  
  led1 = LED_ON;
  led2 = LED_OFF;
  led3 = LED_OFF;
  led4 = LED_OFF;
}


/***********************************************************
*函数名称: timer1_init
*函数功能: 定时器1初始化
*入口参数: 无    
*出口参数: 无  
**********************************************************
*/
void timer1_init(void)
{
  INT_GLOBAL_ENABLE(INT_ON);                 //开全局中断
  
  INT_ENABLE(INUM_T1, INT_ON);               //开T1中断

  TIMER1_ENABLE_OVERFLOW_INT(INT_ON);        //开T1计数溢出中断
  
  SET_TIMER_TICK(TIMER1_TICK_4M);            //设置定时器TICK为4MHz
  
  SET_TIMER1_PERIOD(TIMER1_OVF_2SEC);        //设置T1的计数周期为2s
  
  SET_TIMER1_TICKDIV(TIMER1_TICKDIV_128);    //设置T1的时钟分频为128
  
  SET_TIMER1_MODE(TIMER1_MODE_MODULE);       //设置T1的运行模式为module
}


/***********************************************************
*函数名称: uart0_init
*函数功能: 串口UART0初始化
*入口参数: 无    
*出口参数: 无  
**********************************************************
*/
void uart0_init(void)
{
  //选择uart位置
  IO_PER_LOC_UART0_AT_PORT0_PIN2345();
  
  //配置uart:接收允许,115200bps,一位停止位,无奇偶校验
  UART_SETUP(0, UART_RECEIVE_ENABLE, 115200, ONE_STOP_BITS | PARITY_DISABLE);

  //开总中断
  INT_GLOBAL_ENABLE(INT_ON);      

  //开串口0接收中断
  INT_ENABLE(INUM_URX0, INT_ON);   
}


/***********************************************************
*函数名称: Uart0SendString
*函数功能: 定时器1初始化
*入口参数: unsigned char *s
            想要发送的字符串    
*出口参数: 无  
**********************************************************
*/
void Uart0SendString(unsigned char *s)
{
  while(*s != 0)         
    UART0_SEND(*s++);
}


/***********************************************************
*函数名称: adc_start
*函数功能: 启动ADC转换
*入口参数: 无    
*出口参数: float
            片内的摄氏温度值  
**********************************************************
*/
float adc_start(void)
{
  unsigned int temp;
  
  //参考电压选择1.25V,采样精度为14位,转换目标为片内温度传感器
  ADC_SINGLE_CONVERSION(ADC_REF_1_25_V | ADC_14_BIT | ADC_TEMP_SENS);
  
  ADC_STOP();                            //设置ADC转化的触发方式为手动
  
  ADC_START();                           //启动ADC转化
  
  while(!ADC_SAMPLE_READY());            //等待转化完成
  
  temp = ADCL >> 2;                      //将转化结果存入temp中
  temp |= (((unsigned int) ADCH) << 6);
  
  return ADC_TO_CELSIUS(temp);           //返回转换后的实际温度值
}


/***********************************************************
*函数名称: get_temperature
*函数功能: 将温度值处理后存入字符数组中,便于串口输出
*入口参数: unsigned char *output
            用于存储转换后的温度值
            float temp 
            摄氏温度值   
*出口参数: 无  
**********************************************************
*/
void get_temperature(unsigned char *output,float temp)
{
  output[0] = (unsigned char)(temp) / 10 + 48;          //十位
  output[1] = (unsigned char)(temp) % 10 + 48;          //个位
  output[2] = '.';                                      //小数点
  output[3] = (unsigned char)(temp*10) % 10 + 48;       //十分位
  output[4] = (unsigned char)(temp*100) % 10 + 48;      //百分位
  output[5] = '';                                     //字符串结束符
}


/***********************************************************
*函数名称: watchdog_init
*函数功能: 看门狗初始化
*入口参数: 无   
*出口参数: 无  
**********************************************************
*/
void watchdog_init(void)
{
  WDT_SET_TIMEOUT_PERIOD(SEC_1);   //设置超时时间为1s
  WDT_ENABLE();                    //启动看门狗
}
[url=][/url]


(3)应用程序层
  • main.c
[url=][/url]
/*******************************************************************
文件名称:    main.c
作    者:    hustlzp
日    期:    2011/3/11
版    本:    1.0
功能说明:    主程序文件
函数列表:   (略)
修改记录:
******************************************************************
*/


#include




/********************************************************************
                             中断服务程序
********************************************************************/
/* 定时器1溢出中断子程序
-------------------------------------------------------*/
#pragma vector=T1_VECTOR
__interrupt void T1_ISR(void)
{
  EA=0;                                   //关中断
  
  led2 = LED_ON;                          
  
  get_temperature(output,adc_start());    //将温度值转换为待输出的字符数组
   
  Uart0SendString(output);                //输出温度值
  Uart0SendString("℃");  


  led2


/* 串口接收中断子程序
-------------------------------------------------------*/
#pragma vector=URX0_VECTOR
__interrupt void RE_ISR(void)
{
  EA=0;
  
  led3 = LED_ON;

  receive = U0DBUF;   
  
  if(type==1)           // type=1,表示接收到的字符用于设置定时器溢出周期
  {
    type=0;
    switch(receive)
    {
      case '0':   //定时器溢出周期为0.5s
      {
        SET_TIMER1_PERIOD(TIMER1_OVF_dot5SEC);
        break;
      }
      case '1':   //定时器溢出周期为1s
      {
        SET_TIMER1_PERIOD(TIMER1_OVF_1SEC);
        break;
      }
      case '2':   //定时器溢出周期为2s
      {
        SET_TIMER1_PERIOD(TIMER1_OVF_2SEC);
        break;         
      }
    }
  }
  else if(type==2)      // type=2,表示接收到的字符用于睡眠控制
  {
    type=0;
    led1 = LED_OFF;
    led2 = LED_OFF;
    led3 = LED_OFF;
    switch(receive)
    {
      case '1':   //进入电源模式PM1
      {
        SET_POWER_MODE(1);  
        break;
      }
      case '2':   //进入电源模式PM2
      {
        SET_POWER_MODE(2);  
        break;
      }
      case '3':   //进入电源模式PM3
      {
        SET_POWER_MODE(3);  
        break;
      }
    }
  }
  else if(type==0)       // type=0,表示接收到的字符为控制命令的种类:@ 或 $
  {
    if(receive=='@')  
    {
      type=1;     //接收到'@',表示下一个字符用于设置溢出周期
    }
    else if(receive=='$')
    {
      type=2;     //接收到'$',表示下一个字符用于系统睡眠控制
    }
  }
  
  led3 = LED_OFF;
   
  EA=1;
}
=LED_OFF;
  
  TIMER1_OVERFLOW_INT_SETFLAG(INT_CLR);   //清中断标志
  
  EA=1;                                   //开中断  
}
/* 主函数
-------------------------------------------------------*/
void main(void)
{
  SET_MAIN_CLOCK_SOURCE(CRYSTAL);  //设置系统时钟为32MHz晶振
  
  led_init();                      //LED初始化
  
  uart0_init();                    //串口UART0初始化
  
  timer1_init();                   //定时器1初始化
  
  watchdog_init();                 //看门狗初始化
  
  while(1)
  {
    WDT_RESET();                   //不断喂狗
  }
}/********************************************************************
                            主程序   
********************************************************************/
/* 全局变量
-------------------------------------------------------*/
unsigned char output[6]={0};       //存储温度数据以便于串口输出
unsigned char receive;             //存储接收到的字符
unsigned char type=0;              //接收到的字符的类型标志,取值为0/1/2"module.h"[url=][/url]


五、测试
  吁~代码终于贴完了,真是累死了,下面我们来测试一下这个小系统:
(1)定时采样
  打开串口,并启动IAR调试,发现 led1 亮,同时串口工具上不断有温度值产生,采样间隔经测定为2s:
2011031310183932.jpg
(2)采样间隔控制
  在串口工具中输入"@1",然后再测试采样间隔,发现已变为1s;输入"@0",采样间隔已变为0.5s。
2011031310172984.jpg
(3)睡眠控制
  在串口工具中输入"$1",发现 led 全部熄灭,温度采样也已停止:
2011031310170619.jpg
  经测试,本系统工作正常稳定,基本符合要求。
  需要源码的同学点此下载
六、结语
  本文以一个稍具综合性的小实验为例,展示了如何整合CC2430片上资源,编写出一个比较规范的小系统。过几天我会抽时间为 hal.h 编写一个简单的使用手册,方便自己和大家便捷地操控 CC2430。
  接下来,笔者将会结束针对 CC2430 片上资源的研究,全力投入到 TI Z-Stack 协议栈的学习中~
  本系列的博文写作暂时结束了,但Zigbee的旅行仍将继续。前方的风景未知,但相信笔者和大家一起披荆斩棘,遍尝酸甜苦辣,定会有所斩获。
  敬请期待:"登临 TI Z-Stack" 系列博文!















上一篇:【转】Zigbee之旅(九):几个重要的CC2430基础实验——系统睡眠及中断唤醒
下一篇:今天是万圣节啊,大家准备怎么娱乐啊?
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
发表于 2014-10-31 08:04:14 | 显示全部楼层
原谅我的啥也看不懂
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

免责声明:
码农网所发布的一切软件、编程资料或者文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:help@itsvse.com

QQ|手机版|小黑屋|架构师 ( 鲁ICP备14021824号-2 )|网站地图

GMT+8, 2024-5-6 11:53

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表