zigbee zstack ----- zmain_vdd_check();

原文   http://blog.sina.com.cn/s/blog_874d30c90101nzz1.html

下面开始分析main函数中的第三句:

// Make sure supply voltage is high enough to run

  zmain_vdd_check();

看这句的注释是指,确保提供的电压足够运行,那么这个函数应该就是检查电源电压值的。

 

进入函数体,就在Zmain.c文件中

//

//@fn      zmain_vdd_check

//@brief   Check if the Vdd is OK to run the processor.

//@return  Return if Vdd is ok; otherwise, flash LED, then reset

//

static void zmain_vdd_check( void )

{

  uint8 vdd_passed_count 0;

  bool toggle 0;


 

  // Repeat getting the sample until number of failures or successes hits MAX

  // then based on the count value, determine if the device is ready or not

  while vdd_passed_count MAX_VDD_SAMPLES )

  {

    if HalAdcCheckVdd (ZMAIN_VDD_LIMIT) )

    {

      vdd_passed_count++;    // Keep track times Vdd passes in row

      MicroWait (10000);     // Wait 10ms to try again

    }

    else

    {

      vdd_passed_count 0;  // Reset passed counter

      MicroWait (50000);     // Wait 50ms

      MicroWait (50000);     // Wait another 50ms to try again

    }


 

    // toggle LED1 and LED2 

    if (vdd_passed_count == 0)

    {

      if ((toggle !(toggle)))

        HAL_TOGGLE_LED1();

      else

        HAL_TOGGLE_LED2();

    }

  }


 

  // turn off LED1 

  HAL_TURN_OFF_LED1();

  HAL_TURN_OFF_LED2();

}


 

首先定义了两个变量,

uint8 vdd_passed_count 0;

bool toggle 0;

见名之意,第一个变量应该是一个计数器,用于计算电压值超过某一个标志的数量。

          第二个变量就是一个布尔类型的开关值。

 

然后往下看,看到了两行注释:

// Repeat getting the sample until number of failures or successes hits MAX

// then based on the count value, determine if the device is ready or not

意思大体是指,不断的进行采样,直到失败的次数或是成功的次数超过设定好的一个MAX值,然后根据这个次数来判断设备就绪了。

那我们就看是怎么完成这个操作的吧!


 

大条件while vdd_passed_count MAX_VDD_SAMPLES ),这与刚才的注释吻合。

不过我们要关注一下MAX_VDD_SAMPLES的值:

#define MAX_VDD_SAMPLES    也就是说采样的次数就3次。

 

if HalAdcCheckVdd (ZMAIN_VDD_LIMIT) )

    {

      vdd_passed_count++;    // Keep track times Vdd passes in row

      MicroWait (10000);     // Wait 10ms to try again

    }

    else

    {

      vdd_passed_count 0;  // Reset passed counter

      MicroWait (50000);     // Wait 50ms

      MicroWait (50000);     // Wait another 50ms to try again

    }

 

(1)看一下HalAdcCheckVdd:

 //

 //@fn      HalAdcCheckVdd

 //@brief   Check the Vdd and return TRUE if it greater than or equal the limit

 //@param   limit limit that needs to be checked with the Vdd

 //@return  TRUE if Vdd >= limit, FALSE otherwise

 //

 bool HalAdcCheckVdd (uint8 limit)

 {

   uint16 value;

 

   //Clear ADC interrupt flag 

  ADCIF 0;

 

   //Setup the new value for conversion 

  ADCCON3 (HAL_ADC_REF_125V HAL_ADC_DEC_064 HAL_ADC_CHN_VDD3);

 

   //Wait for the conversion to finish 

  while !ADCIF );

 

   //Get the result 

  value ADCL;

  value |= ((uint16) ADCH) << 8;

 

   //Check the limit and return 

  return value >= HalAdcVddLimit[limit] );

}

看样子我们得先分析一下这个函数了……


先看注释,注释说这个函数是用来检查VDD的值是否大于或等于 limit值的,如果大于或等于limit就返回TRUE

#define   ZMAIN_VDD_LIMIT             HAL_ADC_VDD_LIMIT_4

#define   HAL_ADC_VDD_LIMIT_4        0x04

这里的limit值是4

 

那又是怎么判断的呢?


先梳理里面的SFR、宏定义以及一些变量:

SFRBIT( TCON   0x88, URX1IF, _TCON6, ADCIF, _TCON4, URX0IF, IT1, RFERRIF, IT0 )

这里用到了ADCIF:它位于TCON的第5位:

Zigbee学习笔记(四)——zmain_vdd_check();
   也就是ADCIFADC中断标志位,当产生了一个ADC中断时,这一位就被置为了1,然后等待CPU的处理。并且CPU处理后,这一位就会自动清除了。

 

SFR(  ADCCON3    0xB6    //  ADC控制寄存器3

Zigbee学习笔记(四)——zmain_vdd_check();
   SFR(  ADCL       0xBA    // ADC数据低位 

SFR(  ADCH       0xBB    // ADC数据高位

Zigbee学习笔记(四)——zmain_vdd_check();
   #define HAL_ADC_REF_125V    0x00    //Internal 1.25V Reference 

#define HAL_ADC_DEC_064     0x00    //Decimate by 64 8-bit resolution 

#define HAL_ADC_CHN_VDD3   0x0f     //VDD/3 


 

static __code const uint16 HalAdcVddLimit[] =

{

  0x369C,       //  VDD Limit 1.6v 

  0x3A06,       // VDD Limit 1.7v 

  0x3D70,       // VDD Limit 1.8v 

  0x40D9,       // VDD Limit 1.9v 

  0x4443,       // VDD Limit 2.0v 

  0x47AD,       // VDD Limit 2.1v 

  0x4B17,       // VDD Limit 2.2v 

  0x4E81,       // VDD Limit 2.3v 

  0x51EA,       // VDD Limit 2.4v 

};

然后分析这个函数执行的过程,

首先将ADCIF0

ADCIF 0;

这是在使用中断前要做的事情(突然想起来在main中的第一句不是关闭了所有中断么?所以大胆估计这个中断标志位就算被置位,也不会触发中断响应的函数)


 

接着:

ADCCON3 (HAL_ADC_REF_125V HAL_ADC_DEC_064 HAL_ADC_CHN_VDD3);

看注释是说准备新的转换的值,HAL_ADC_REF_125V HAL_ADC_DEC_064 HAL_ADC_CHN_VDD3的结果为0x0f,查看ADCCON3被置为0x0f时的含义,得知如下设置:

额外转换的参考电压——内部参考电压:根据前面的宏定义可以看到这个参考电压为1.25V

额外转换的抽取率  ——64抽取率:抽取率是用来决定ADC转换时间的,CC2530手册中有公式:

 Tconv=(抽取率+16)x0.25μs,64抽取率对应转换时间为20μs。

单个通道选择      ——VDD/3:这指的是ADC输入的引脚。

这些个概念什么意思嘛!虽然以前写过AD转换的单片机程序,但是接触这些概念还是比较头疼啊!就先把数据手册关于ADC转换的地方看一下吧,大致了解了以下几个概念:

① ADC输入:端口0引脚的信号可以用作ADC输入。

片上温度传感器的输出也可以选择作为ADC的输入,用于温度测量

还可以输入一个对应AVDD5/3的电压作为一个ADC输入。这个输入允许诸如需要在应用中实现一个电池监测器的功能。注意在这种情况下参考电压不能取决于电源电压

② ADC运行模式:ADCCON3寄存器控制单个转换的通道号码、参考电压和抽取率。单个转换在寄存器ADCCON3写入后将立即发生,或如果一个转换序列正在进行,该序列结束之后立即发生。该寄存器位的编码和ADCCON2是完全一样的。

③ ADC参考电压:转换结果的准确性取决于参考电压的稳定性和噪音属性。希望的电压有偏差会导致ADC益误差,与希望电压和实际电压的比例成正比。参考电压的噪音必须低于ADC的量化噪音,以确保达到规定的SNR

④ ADC中断:当通过写ADCCON3触发的一个单个转换完成时,ADC将产生一个中断。当完成一个序列(指ADC的一系列转换)转换时,不产生一个中断(通过DMA方式)。

⑤ ADCDMA触发:每完成一个序列转换,ADC将产生一个DMA触发。当完成一个单个转换,不产生DMA触发。

⑥ ADC转换时间:执行一个转换所需的时间取决于所选的抽取率。总的来说,转换时间由以下公式给定:

 Tconv=(抽取率+16)x0.25μs。

从以上这些概念可以得知,要进行ADC模数转换,就需要有一个ADC输入(需要进行转换的来源),参考电压(决定转换结果的准确性),抽取率(决定转换的时间)。而这里是要对电源进行检测,所以输入通道选择了VDD/3,没次只对一个数据进行采样,那么在采样结束之后就会产生一个中断给ADCIF置位。


 

当产生了中断置位后,就识别出来,然后读出其中的数值,这里我想说一下它查询这个中断位的方式,就我前面说到的,EA被关闭了,就算中断产生了也不会执行中断响应函数了,所以这里采用了while !ADCIF );查询方式。


然后从ADCLADCH中读出转换后的值:

value ADCL;

value |= ((uint16) ADCH) << 8;

ADCL是转换结果的低8位(其中最后两位始终为0),ADCH是高8位,所以需要左移8位。


 

最后将value值与HalAdcVddLimit[4]相比较,也就是与2.0V相比较的。

那为什么和这个电压值比较呢?

查看手册得知2.0VMCU工作的最低电压,这里本身就是要检查电压是否达到是否可以工作的电压值,所以自然要和2.0V进行比较了。

Zigbee学习笔记(四)——zmain_vdd_check();
   如果大于2.0V就返回1,如果小于2.0V就返回0


 

回到zmain_vdd_check中:

(2)如果为1

  vdd_passed_count++;    // Keep track times Vdd passes in row

      MicroWait (10000);     // Wait 10ms to try again

把超过计数值加1,然后延时10ms

顺便看一下延时函数具体是怎么定义的:

#define   MicroWait(t)   Onboard_wait(t)

void Onboard_wait( uint16 timeout )

{

  while (timeout--)

  {

    asm("NOP");

    asm("NOP");

    asm("NOP");

  }

}


 

(3)如果为0

vdd_passed_count 0;  // Reset passed counter

MicroWait (50000);     // Wait 50ms

MicroWait (50000);     // Wait another 50ms to try again

将计数器又重新置位0


 

(4)如果计数器的值被置为0了,就切换LED1灯的状态:

 // toggle LED1 and LED2 

 if (vdd_passed_count == 0)

 {

      if ((toggle !(toggle)))

        HAL_TOGGLE_LED1();

      else

        HAL_TOGGLE_LED2();

 }

虽然注释中说是切换LED1LED2的状态,但是从代码分析可以知道,LED2的状态根本不会被切换,因为条件是toggle !(toggle),而不是!=toggletoggle取非的结果肯定不相同咯,所以这个条件永真,也就执行不到else了。

   看一下HAL_TOGGLE_LED1的定义

   #define   HAL_TOGGLE_LED1() st( if (LED1_SBIT) LED1_SBIT 0; else LED1_SBIT 1;} )

   #define   LED1_SBIT         P1_0

  SFRBIT( P1  0x90, P1_7, P1_6, P1_5, P1_4, P1_3, P1_2, P1_1, P1_0 )

   这里就不解释了,很容易看出来,如果本来LED的引脚是0就置1,如果原来是1就置0

 

(5)然后又回到while条件检查vdd_passed_count是否达到3。是就结束,否则继续循环。

这里就发现一个问题,如果符合的电压始终达不到3次,那就会在这里做死循环了,也就是说如果电压不够,就始终不能进行工作。突然发现做电压检测是十分必要的,以前在做嵌入式开发的时候很多时间会忽略这个,上课的时候老师也一直强调——电源是嵌入式开发中十分重要的一个环节,我想从这里我要意识到了这一点,如果电源不达标,很多工作都是不可靠的。

 

(6)总算最后一句了:

// turn off LED1 

  HAL_TURN_OFF_LED1();

  HAL_TURN_OFF_LED2();

这里的注释又对了,关闭的是LED1

    #defineHAL_TURN_OFF_LED1()      st( LED1_SBIT = LED1_POLARITY (0); )

#defineLED1_POLARITY    ACTIVE_LOW //ACTIVE_HIGH
    #defineACTIVE_LOW       !

这里一个!的值就是0。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值