最近在论坛、QQ群里好多人都在讨论低功耗设计,想到之前遇到的一个客户也有这方面的一个要求,顺着他的想法做了一个在低功耗模式下使用ADC的例子。客户要做的是一个恒温控制,在设定温度范围内让MCU进入休眠状态,只有在超过温度范围后才唤醒MCU进行温度调节。话不多说,让我们开始例程介绍。
运行平台:
FRDM-25Z
IARv7.3
在KL25_SC代码包中platinum工程上修改
Low Power Mode 简介
飞思卡尔Kinetis系列MCU基于90纳米TFS技术,使得MCU在低功耗模式下,拥有良好的性能和功耗表现,KL系列更是被评为业内最低功耗的MCU。KL25Z 功耗模式总共有 11 种,分别是:Run、VLPR、Wait、VLPW、Stop、VLPS、LLS、VLLS3、VLLS2、VLLS1、VLLS0,能够满足客户对MCU各种低功耗的配置要求,在深度睡眠模式下智能外设能够处理相应数据而不需要唤醒内核。
图1
在本设计中需要在低功耗模式下监控温度,热电偶的电信号需要用到ADC进行采样,查手册可知ADC能够运行的最低功耗模式是VLPS模式。VLPS模式下大部分外设仍然可以使用,但需要注意的是在VLPS模式下总线时钟是禁止的,因此在进入VLPS模式前应该将ADC的时钟设为ADACK,不然它进入VLPS模式后就嗝屁了。VLPS模式下只能采用硬件触发来触发ADC采样,本例采用的是LPMR定时器来触发ADC采样。VLPS模式下可以采用中断唤醒方式,本例采用ADC中断唤醒。当然也可以采用异步DMA通道来搬运ADC转换结果,搬运完成后自动回到VLPS模式下,感兴趣的话也可以试一下这种方式哈。
图2
代码介绍:
int main (void)
{
#ifdef CMSIS // If we are conforming to CMSIS, we need to call start here
start();
#endif
lptmr_init(1000,LPTMR_USE_LPOCLK); //trigger ADC per 1000ms // 初始化代码中设置LPO作为lptmr的时钟源,保证lptmr在VLPS下能够正常工作;
init_ADC16(); //初始化ADC,设置ADC硬件触发源为lptmr,使能ADC范围比较模式,即当转换结果小于C1V,大于C2V时保存结果;
enable_irq(ADC0_irq_no); //在进入低功耗模式前使能ADC中断。
printf("Enter VLPS mode...\r\n");
clockMonitor(OFF);
enter_vlps();
while(1)
{
if(flag_wakeup == 1)
{
flag_wakeup = 0;
ADC0_SC2 &= ~ADC_SC2_ACFE_MASK;
disable_irq(ADC0_irq_no); //退出后,为调节温度需关闭范围比较模式,同时关闭ADC中断,采用查询模式;
printf("Wake up from VLPS..\n");
printf("adcresult = %d\n",adcresult);
}
if((ADC0_SC1(0) & ADC_SC1_COCO_MASK) == ADC_SC1_COCO_MASK) //查询转换结果
{
adcresult = ADC0_R(0);
printf("wake up adcresult = %d\n",adcresult);
if((adcresult>= 4000) && (adcresult<= 5000)) //当调节到ADC结果再次进入调节范围时,准备进入低功耗模式;
{
ADC0_SC2 |= ADC_SC2_ACFE_MASK; //为实现监控,重新使能范围比较模式和ADC中断。
enable_irq(ADC0_irq_no);
printf("Enter VLPS mode...\n");
clockMonitor(OFF);
enter_vlps();
}
}
}
}
实验结果:
设置比较值为4000~5000,打印结果如下:
图3
好了,就这些了,第一次写技术文章,很浅显的东西说了一大堆,比较乱,望批评指正哈。
附件为参考代码。
Hi FanXi,非常感谢!实测电流是多少呢?