首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 其他相关 >

ZigBee研究之旅(4)-CC2530的时钟模块

2013-10-08 
ZigBee研究之旅(四)---CC2530的时钟模块CC2530的时钟模块(cc2530_datasheet节选翻译如下)****************

ZigBee研究之旅(四)---CC2530的时钟模块

CC2530的时钟模块

(cc2530_datasheet节选翻译如下)

******************************************************************

* 作        者:fulinux

* 转载声明:点击链接
******************************************************************

    振荡器和时钟
    CC2530设备有一个内部系统时钟,或者主时钟。系统时钟源可以是从16MHz RC振荡器或一个32M晶体振荡器中的一个提供。系统时钟源是由CLKCONCMD SRF控制寄存器。
    还有一个32KHz的时钟源,来源可以是从RC 振荡器或者32KHz的晶体振荡器中过来,同样是由CLKCONCMD寄存器控制。
    CLKCONSTA寄存器是一个制度寄存器,用来获得当前系统时钟的状态。
    时钟源可以在一个精度高的晶体振荡器和一个功耗低的RC振荡器中交替选择使用。注意一点:RF的收发操作是要以32MHz的晶体振荡器为时钟源才行。

    振荡器
    ZigBee研究之旅(4)-CC2530的时钟模块
    图中给出了时钟系统中可用的时钟源的一个全貌图。
    设备中存在的两个高频振荡器:
    * 32MHz晶体振荡器
    * 16MHz的RC振荡器
    32MHz的晶体振荡器启动时间对于某些应用来说可能太长了;因此设备可以先运行在16MHz的RC振荡器中运行直到晶体振荡器稳定后在使用32MHz晶体振荡器。16MHz的RC振
    荡器功耗低但是不是很准,所以不能为RF模块提供服务,只能用32MHz的晶体振荡器。
    设备中存在的两个低频振荡器:
    * 32 KHz晶体振荡器
    * 32 KHz RC振荡器
    32KHz的XOSC被设计的工作频率频率是32.768KHz并且可以为一些要求时钟准确子系统提供一个稳定的时钟信号。32KHz的RCOSC当校准后可以运行在32.753KHz频率下。校准
    只能发生在当32MHz XOSC使能的情况下,可以通过使能SLEEPCMD.OSC32K_CALDIS位来关闭校准。32KHz RC振荡器相对于32KHz  XOSC晶体振荡器功耗低,应该用在可以降
    低成本情况下。两个振荡器不能同时工作。

    系统时钟
    系统时钟是由32MHz XOSC或者16MHz RCOSC两个时钟源驱动的。CLKCONCMD.OSC位用来选择系统时钟源。注意:使用RF模块时,32MHz晶体振荡器必须被选上并且运行稳定。
    注意:改变CLKCONCMD.OSC位并不能立即导致系统时钟源的改变。当CLKCONSTA.OSC = CLKCONCMD.OSC时时钟源的改变才会发挥作用。这是因为设备在实际改变时钟源之前
    需要稳定的时钟。还有就是注意CLKCONCMD.CLKSPD位反应着系统时钟频率,因此是CLKACONCMD.OSC位的镜子。一旦32MHz的XOSC被选中和稳定,例如,当CLKCONSTA.OSC
    位从1切换到0时。
    注意:从16MHz到32MHz时钟源的改变符合CLKCONCMD.TICKSPD设置。CLKCONCMD.TICKSPD设置的缓慢一些的话,当CLKCONCMD.OSC改变的话会导致实际的时钟源起作用的
    时间会很长。当CLKCONCMD.TICKSPD等于000时会获得最快的切换速度。

    32KHz的振荡器
    默认的或者复位后32KHz RCOSC使能并且被设置作为32KHz的时钟源。其功耗低,但是相对于32KHz晶体振荡器而言精度不高,32KHz时钟源用来驱动睡眠定时器,产生看门狗的滴答值
    和作为timer 2计算睡眠定时器的一个闸门。32KHz时钟源被寄存器CLKCONCMD.OSC32K位用来作为选择振荡器。CLKCONCMD.OSC32K寄存器可以在任意时间写入,但是在16MHz RC
    振荡器是活跃的系统时钟源之前是不会起作用的。当系统时钟从16MHz改变为32MHz的晶体振荡器(CLKCONCMD.OSC从1到0)一旦32KHz RC振荡器被选中了它的的校验就启动了并且被执行。在校准期间,32MHz晶体振荡器的一个分频量会被使用。32KHzRCOSC振荡器校准后的结果是它会工作在32.753kHz上。32kHz RC振荡器校准时间可能要2ms时间来完成。可以设置SLEEPCMD.OSC32K_CALDIS位设置为1的话,会关闭校准。在校准结束时,会在32KHz时钟源上产生一个额外的脉冲,会导致睡眠定时器增加1。
    注意:当切换到32KHz晶体振荡器后和从32KHz晶体振荡器被设置的PM3模式唤醒时,振荡器稳定到准确频率的时间在500 ms以上。睡眠定时器、看门狗定时器和时钟损失探测器在32KHz
    晶体振荡器稳定之前不能使用。

    振荡器和时钟寄存器
    下面是振荡器和时钟寄存器的描述,所有寄存器的位会在进入PM2和PM3时保持不变,除非有异常情况发生。
    ZigBee研究之旅(4)-CC2530的时钟模块
    ZigBee研究之旅(4)-CC2530的时钟模块
    定时器滴答值产生器
    CLKCONCMD.TICKSPD寄存器控制timer1、timer3和timer4的全局预分频。预分频的值设置范围在0.25MHz和32MHz之间。
    需要注意的是如果CLKCONCMD.TICKSPD显示的频率高于系统时钟,则在CLKCONSTA.TICKSPD中的实际的预分频值表明是和系统时钟的值是一样的。

    数据滞留
    在PM2和PM3电源模式中,绝大多数的内部电路关闭了,然而,SRAM中任保留它的内容,内部寄存器的值也会保留。
    保留数据的寄存器是CPU的寄存器、外部寄存器和RF寄存器,除非另一些位域值设置的比较特殊。切换到PM2和PM3模式的现象对于软件而已是透明的。
    注意在PM3模式下睡眠定时器的值不会保存。

******************************************************************

* 作        者:fulinux

* 转载声明:点击链接,如有不对之处,请指正
******************************************************************


/*********************************************************************************************************** 文 件 名:iic.C* 功    能:实验二 GPIO控制实验*            该实验采用CC2530的I/O口(P1.0和P1.1)模拟IIC总线的SCL和SDA,然后通过IIC总线形式控制GPIO扩展芯片*            PCA9554,最后通过扩展的IO来控制LED的亮灭。** 硬件连接:将OURS的CC2530RF模块插入到普通电池板或智能电池板上。**           P1.0 ------ SCL*           P1.1 ------ SDA*           * 版    本:V1.0* 作    者:WUXIANHAI* 日    期:2011.1.18* 奥尔斯电子主页:www.ourselec.com**************************************************************************************************************/#include "ioCC2530.h" #include "hal_mcu.h"#define SCL          P1_0       //IIC时钟线#define SDA          P1_1       //IIC数据线//定义IO方向控制函数#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)#define OSC_32KHZ  0x00                //使用外部32K晶体振荡器//时钟设置函数#define HAL_BOARD_INIT()                                         \{                                                                \  uint16 i;                                                      \                                                                 \  SLEEPCMD &= ~OSC_PD;                       /* 开启 16MHz RC 和32MHz XOSC */         \  while (!(SLEEPSTA & XOSC_STB));            /* 等待 32MHz XOSC 稳定 */               \  asm("NOP");                                                                         \  for (i=0; i<504; i++) asm("NOP");          /* 延时63us*/                            \  CLKCONCMD = (CLKCONCMD_32MHZ | OSC_32KHZ); /* 设置 32MHz XOSC 和 32K 时钟 */        \  while (CLKCONSTA != (CLKCONCMD_32MHZ | OSC_32KHZ)); /* 等待时钟生效*/               \  SLEEPCMD |= OSC_PD;                        /* 关闭 16MHz RC */                      \}#define IO_IN   0           //输入#define IO_OUT  1           //输出uint8 ack;            //应答标志位uint8 PCA9554ledstate = 0;  //所有LED当前状态/****************************************************************************** * 函数名称:QWait * * 功能描述:1us的延时 * * 参    数:无 * * 返 回 值:无 *****************************************************************************/ void QWait()     {    asm("NOP");asm("NOP");    asm("NOP");asm("NOP");    asm("NOP");asm("NOP");    asm("NOP");asm("NOP");    asm("NOP");asm("NOP");    asm("NOP");}/****************************************************************************** * 函数名称:Wait * * 功能描述:ms的延时 * * 参    数:ms - 延时时间 * * 返 回 值:无 *****************************************************************************/ void Wait(unsigned int ms){                       unsigned char g,k;   while(ms)   {        for(g=0;g<=167;g++)   {     for(k=0;k<=48;k++);   }      ms--;                               }} /****************************************************************************** * 函数名称:Start_I2c * * 功能描述:启动I2C总线,即发送I2C起始条件. * * 参    数:无 * * 返 回 值:无 *****************************************************************************/ void Start_I2c(){  IO_DIR_PORT_PIN(1, 0, IO_OUT);    //设置P1.0为输出  IO_DIR_PORT_PIN(1, 1, IO_OUT);    //设置P1.1为输出    SDA=1;                   /*发送起始条件的数据信号*/  asm("NOP");  SCL=1;  QWait();                /*起始条件建立时间大于4.7us,延时*/  QWait();  QWait();  QWait();  QWait();      SDA=0;                   /*发送起始信号*/  QWait();                 /* 起始条件锁定时间大于4μs*/  QWait();  QWait();  QWait();  QWait();         SCL=0;                   /*钳住I2C总线,准备发送或接收数据 */  asm("NOP");  asm("NOP");}/****************************************************************************** * 函数名称:Stop_I2c * * 功能描述:结束I2C总线,即发送I2C结束条件. * * 参    数:无 * * 返 回 值:无 *****************************************************************************/ void Stop_I2c(){  IO_DIR_PORT_PIN(1, 0, IO_OUT);    //设置P1.0为输出  IO_DIR_PORT_PIN(1, 1, IO_OUT);    //设置P1.1为输出  SDA=0;                            /*发送结束条件的数据信号*/  asm("NOP");                       /*发送结束条件的时钟信号*/  SCL=1;                            /*结束条件建立时间大于4μs*/  QWait();  QWait();  QWait();  QWait();  QWait();  SDA=1;                           /*发送I2C总线结束信号*/  QWait();  QWait();  QWait();  QWait();}/****************************************************************************** * 函数名称:SendByte * * 功能描述:将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对 *           此状态位进行操作.(不应答或非应答都使ack=0 假)      *           发送数据正常,ack=1; ack=0表示被控器无应答或损坏。 * * 参    数:c - 需发送的数据 * * 返 回 值:无 *****************************************************************************/ void  SendByte(uint8 c){ uint8 BitCnt; IO_DIR_PORT_PIN(1, 0, IO_OUT);    //设置P1.0为输出 IO_DIR_PORT_PIN(1, 1, IO_OUT);    //设置P1.1为输出 for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/    {     if((c<<BitCnt)&0x80)SDA=1;   /*判断发送位*/       else  SDA=0;                      asm("NOP");     SCL=1;                       /*置时钟线为高,通知被控器开始接收数据位*/      QWait();       QWait();                    /*保证时钟高电平周期大于4μs*/      QWait();      QWait();      QWait();              SCL=0;     }        QWait();    QWait();    QWait();    SDA=1;                        /*8位发送完后释放数据线,准备接收应答位*/    asm("NOP");    IO_DIR_PORT_PIN(1, 1, IO_IN);      SCL=1;    QWait();    QWait();    QWait();    QWait();    if(SDA==1)ack=0;         else ack=1;                   /*判断是否接收到应答信号*/    SCL=0;       QWait();    QWait();    IO_DIR_PORT_PIN(1, 1, IO_OUT);}/****************************************************************************** * 函数名称:RcvByte * * 功能描述:用来接收从器件传来的数据,并判断总线错误(不发应答信号), *           发完后请用应答函数。 * * 参    数:无 * * 返 回 值:retc - 从器件传来的数据 *****************************************************************************/ uint8  RcvByte(){  uint8 retc;  uint8 BitCnt;  IO_DIR_PORT_PIN(1, 0, IO_OUT);    //设置P1.0为输出  IO_DIR_PORT_PIN(1, 1, IO_OUT);    //设置P1.1为输出  retc=0;   SDA=1;                            /*置数据线为输入方式*/  IO_DIR_PORT_PIN(1, 1, IO_IN);  for(BitCnt=0;BitCnt<8;BitCnt++)      {        asm("NOP");                  SCL=0;                     /*置时钟线为低,准备接收数据位*/        QWait();        QWait();                   /*时钟低电平周期大于4.7μs*/        QWait();        QWait();        QWait();        SCL=1;                    /*置时钟线为高使数据线上数据有效*/        QWait();        QWait();        retc=retc<<1;        if(SDA==1)retc=retc+1;   /*读数据位,接收的数据位放入retc中 */        QWait();        QWait();       }  SCL=0;      QWait();  QWait();  IO_DIR_PORT_PIN(1, 1, IO_OUT);  return(retc);}/****************************************************************************** * 函数名称:Ack_I2c * * 功能描述:主控器进行应答信号,(可以是应答或非应答信号) *            * * 参    数:无 * * 返 回 值:无 *****************************************************************************/ void Ack_I2c(uint8 a){  IO_DIR_PORT_PIN(1, 0, IO_OUT);    //设置P1.0为输出  IO_DIR_PORT_PIN(1, 1, IO_OUT);    //设置P1.1为输出  if(a==0)SDA=0;                   /*在此发出应答或非应答信号 */  else SDA=1;  QWait();  //QWait();  //QWait();        SCL=1;  QWait();  QWait();                         /*时钟低电平周期大于4μs*/  QWait();  QWait();  QWait();    SCL=0;                           /*清时钟线,钳住I2C总线以便继续接收*/  QWait();  //QWait();    }/****************************************************************************** * 函数名称:ISendByte * * 功能描述:从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla. *           如果返回1表示操作成功,否则操作有误。 *            * * 参    数:sla - 从器件地址 *           c - 需发送的数据 * * 返 回 值:0 -- 失败 *           1 -- 成功 *****************************************************************************/ uint8 ISendByte(uint8 sla,uint8 c){   Start_I2c();               /*启动总线*/   SendByte(sla);             /*发送器件地址*/     if(ack==0)return(0);   SendByte(c);               /*发送数据*/     if(ack==0)return(0);  Stop_I2c();                 /*结束总线*/   return(1);}/****************************************************************************** * 函数名称:ISendStr * * 功能描述:从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件 *            地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。 *           如果返回1表示操作成功,否则操作有误。 *            * * 参    数:sla - 从器件地址 *           suba - 从器件子地址 *           *s - 数据 *           no - 数据字节数目 * * 返 回 值:0 -- 失败 *           1 -- 成功 * * 注    意:使用前必须已结束总线。 *****************************************************************************/ uint8 ISendStr(uint8 sla,uint8 suba,uint8 *s,uint8 no){   uint8 i;   Start_I2c();               /*启动总线*/   SendByte(sla);             /*发送器件地址*/     if(ack==0)return(0);   SendByte(suba);            /*发送器件子地址*/     if(ack==0)return(0);   for(i=0;i<no;i++)    {        SendByte(*s);            /*发送数据*/       if(ack==0)return(0);     s++;    }  Stop_I2c();                  /*结束总线*/   return(1);}/****************************************************************************** * 函数名称:IRcvByte * * 功能描述:从启动总线到发送地址,读数据,结束总线的全过程,从器件地 *          址sla,返回值在c. 如果返回1表示操作成功,否则操作有误。 *            * * 参    数:sla - 从器件地址 *           *c - 需发送的数据 * * 返 回 值:0 -- 失败 *           1 -- 成功 * *注    意:使用前必须已结束总线。 *****************************************************************************/ uint8 IRcvByte(uint8 sla,uint8 *c){   Start_I2c();                /*启动总线*/   SendByte(sla+1);            /*发送器件地址*/   //SendByte(sla);    if(ack==0)return(0);   *c=RcvByte();               /*读取数据*/   Ack_I2c(1);                 /*发送非就答位*/   Stop_I2c();                 /*结束总线*/    return(1);}/****************************************************************************** * 函数名称:IRcvStr * * 功能描述:从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件 *          地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。 *         如果返回1表示操作成功,否则操作有误。 *            * * 参    数:sla - 从器件地址 *           suba - 从器件子地址 *           *s - 数据 *           no - 数据字节数目 * * 返 回 值:0 -- 失败 *           1 -- 成功 * * 注    意:使用前必须已结束总线。 *****************************************************************************/ uint8 IRcvStr(uint8 sla,uint8 suba,uint8 *s,uint8 no){   Start_I2c();               /*启动总线*/   SendByte(sla);             /*发送器件地址*/   if(ack==0)return(0);   SendByte(suba);            /*发送器件子地址*/  // if(ack==0)return(0);  // SendByte(sla+1);   if(ack==0)return(0);   while(no > 0)    {    *s++ = RcvByte();     if(no > 1)  Ack_I2c(0);   /*发送就答位*/      else Ack_I2c(1);          /*发送非应位*/     no--;   }   Stop_I2c();                 /*结束总线*/    return(1);}/****************************************************************************** * 函数名称:ctrPCA9554LED * * 功能描述:通过IIC总线控制PCA9554的输出,进而控制相应的LED。 *                     * * 参    数:LED - 所控制的LED *           operation - 开或关操作 * * 返 回 值:无 *            * * 注    意:PCA9554的地址为:0x40 *****************************************************************************/ void ctrPCA9554LED(uint8 led,uint8 operation){  uint8 output = 0x00;  uint8 *data = 0;  if(ISendStr(0x40,0x03,&output,1))  //配置PCA9554寄存器  {    switch(led)    {      case 0:                        //LED0控制        if (operation)        {          output = PCA9554ledstate & 0xfe;        }        else        {          output = PCA9554ledstate | 0x01;        }      break;       case 1:                      //LED1控制        if (operation)        {          output = PCA9554ledstate & 0xfd;        }        else        {          output = PCA9554ledstate | 0x02;        }      break;       case 2:                     //LED2控制        if (operation)        {          output = PCA9554ledstate & 0xf7;        }        else        {          output = PCA9554ledstate | 0x08;        }      break;       case 3:                     //LED3控制        if (operation)        {          output = PCA9554ledstate & 0xfb;        }        else        {          output = PCA9554ledstate | 0x04;        }      break;       case 4:                    //LED4控制        if (operation)        {          output = PCA9554ledstate & 0xdf;        }        else        {          output = PCA9554ledstate | 0x20;        }      break;       case 5:                   //LED5控制        if (operation)        {          output = PCA9554ledstate & 0xef;        }        else        {          output = PCA9554ledstate | 0x10;        }      break;     default:break;    }    if(ISendStr(0x40,0x01,&output,1)) //写PCA9554输出寄存器    {      if(IRcvByte(0x40,data))         //读PCA9554输出寄存器      {        PCA9554ledstate = *data;      }    }  }}/****************************************************************************** * 函数名称:PCA9554ledInit * * 功能描述:初始化6个LED,即关闭所有的LED *                     * 参    数:无           * * 返 回 值:无 *            *****************************************************************************/ void PCA9554ledInit(){  uint8 output = 0x00;  uint8 *data = 0;  if(ISendStr(0x40,0x03,&output,1))  //配置PCA9554寄存器  {    output = 0xbf;    if(ISendStr(0x40,0x01,&output,1)) //写输出寄存器    {      if(IRcvByte(0x40,data))         //读输出寄存器      {        PCA9554ledstate = *data;      }    }  }}





热点排行