版权声明:本文为博主原创文章,转载请附上原文出处链接。
通过今天的学习来掌握:
1、STC8A8K64S4A12系列单片机降低功耗的方式,空闲模式和掉电模式的原理。
2、单片机进入掉电模式和退出掉电模式的寄存器配置及程序设计。
单片机系统电源管理实际上就是控制单片机系统的低功耗,或者说省电。
设计低功耗的单片机系统需要从以下几个方面考虑:
☆注:单片机电源管理,主要针对的就是单片机这个芯片的低功耗。
STC8A8K64S4A12系列单片机为了降低功耗,可使之运行于3种省电模式,即低速模式、空闲模式和掉电模式。如下表所示。
序号 | 工作模式 | 典型功耗 | 控制方式 | 备注 |
---|---|---|---|---|
1 | 正常模式 | 2.7mA ~ 7mA | 不进入省电模式 | 参考STC15W4K32S4 |
2 | 低速模式 | 待定 | CLKDIV寄存器控制 | 设定工作频率大小 |
3 | 空闲模式 | PCON寄存器IDL位控制 | IDL位置1进空闲模式 | |
4 | 掉电模式 | ≤1.5uA | PCON寄存器PD位控制,VOCTRL寄存器SCC位控制 | 选择外部SCC模块时,功耗小于0.15uA |
■ STC8A8K64S4A12系列单片机内部结构图
STC8A8K64S4A12系列单片机中包括:中央处理器(CPU)、程序存储器(Flash)、数据存储器(SRAM)、定时器/计数器、掉电唤醒专用定时器、GPIO口、A/D转换、比较器、看门狗、UART1、UART2、UART3、UART4、CCP/PWM/PCA、高速同步串行通信端口SPI、I2C、片内高精度IRC时钟及高可靠复位等模块。
☆注:CPU(Central Processing Unit)是单片机的核心部件,包括运算器和控制器。
■ STC8A8K64S4A12系列单片机系统时钟与主时钟
1、系统时钟SYSclk是指对主时钟进行分频后给CPU、定时器、串行口、I2C、SPI、CCP/PWM/PCA、A/D转换等功能模块提供的实际工作时钟。
2、主时钟MCLK可以是内部高精度24MHZ的IRC时钟,也可以是内部32KHZ的IRC(误差较大),还可以是外部输入的时钟信号或外部晶体震荡器产生的时钟。
☆注:系统时钟SYSclk默认是不输出到单片机引脚的,当需要输出到P5.4或P1.6口时再设置寄存器MCLKODIV[3:0]位不为0。
3、系统时钟和主时钟不是一码事,系统时钟是由主时钟经过分频得出的。如何对主时钟分频,是通过配置CLKDIV时钟分频寄存器的系统时钟选择控制位实现。
☆注:如果想降低功耗,可适当对主时钟进行分频,实现降低系统时钟频率的目的,但必须以可以实现项目功能为前提。
■ STC8A8K64S4A12系列单片机工作在空闲模式
1、该模式下,除系统不给CPU供时钟,CPU不执行指令外,其余功能部件仍可继续工作。举例:如果定时器已被调用,开启空闲模式,定时器依然在计数。
2、看门狗在空闲模式下是否工作取决于自身有一个“IDLE”模式位。
3、空闲模式下,RAM、堆栈指针(PC)、程序状态字(PSW)、累加器(A)等寄存器都保持原有数据。
4、空闲模式下,GPIO口保持着空闲模式被激活前那一刻的逻辑状态。
5、任何一个中断都会将IDL位清零,从而退出空闲模式。
6、单片机从空闲模式下被唤醒,则程序会从上次设置单片机进入空闲模式语句的下一条语句开始往下执行。
☆注:STC8A8K64S4A12系列单片机工作在空闲模式下,单片机的功耗约1.8mA。
■ STC8A8K64S4A12系列单片机工作在掉电模式
1、该模式下,单片机所使用的时钟(内部系统时钟或外部晶体/时钟)停振,由于无时钟源,CPU、看门狗、定时器、串行口、A/D转换、SPI等功能模块停止工作,但外部中断0~外部中断4、CCP/PWM/PCA、低压检测电路均可继续工作。
2、掉电模式下,所有特殊功能寄存器(SFR)维持进入掉电模式前那一刻的状态不变。
3、掉电模式下,GPIO口保持着掉电模式被激活前那一刻的逻辑状态。
4、特定的外部引脚可唤醒掉电模式下的CPU,这些外部引脚有外部中断引脚、CCP0/CCP1/CCP2/CCP3引脚、串口接收引脚、定时器/计数器外部输入引脚。
5、除特定的外部引脚可唤醒掉电模式下的CPU外,还可通过配置特殊功能寄存器WKTCH和WKTCL唤醒掉电模式下的CPU。
6、单片机从掉电模式下被唤醒,则程序会从上次设置单片机进入掉电模式语句的下一条语句开始往下执行。
7、特别注意:编写C语言程序时,在将进入掉电模式时,一定在设置MCU进入掉电模式语句后加2~4条空语句(即NOP语句)。
☆注:STC8A8K64S4A12系列单片机工作在掉电模式下,单片机的功耗还由电压控制寄存器VOCTRL的SCC位共同决定。
STC8A8K64S4A12系列单片机内部掉电唤醒定时器是一个15位的计数器(由{WKTCH[6:0],WKTCL[7:0]}组成15位),用于唤醒处于掉电模式的单片机。
如果掉电唤醒定时器WKTCH寄存器的WKTEN位置1,则单片机进入掉电模式后,掉电唤醒定时器开始计数,当计数值与用户所设置的值一样时,掉电唤醒定时器将单片机唤醒。
用户所设置的值是通过配置WKTCL寄存器的B0B7位和WKTCH寄存器的B0B6位实现。具体可参考下图。
☆注:15位计数器的范围是:032767,所以写入寄存器{WKTCH[6:0],WKTCL[7:0]}中的数值也是在032767范围内。
STC8A8K64S4A12系列单片机内部掉电唤醒定时器有自己的内部时钟,其中掉电唤醒定时器计数一次的时间就是由该时钟决定。内部掉电唤醒定时器时钟频率约为32768HZ,当然误差较大,所以计算出的掉电唤醒定时器定时时间与实际时间会有较大偏差。
下面给出掉电唤醒定时器定时时间计算公式:
☆注:用户通过读RAM区F8H和F9H的内容(F8H存放频率的高字节,F9H存放频率的低字节)来获取内部掉电唤醒专用定时器出厂时所记录的时钟频率。内部掉电唤醒定时器专用时钟16分频后用于掉电唤醒定时器计数。
举例,配置WKTCH寄存器低7位初始装载值为0x0F,WKTCL寄存器初始装载值为0xFF,计算掉电唤醒定时器定时时间。
STC8A8K64S4A12系列单片机时钟及电源管理所用到的寄存器有11个,如下表所示:
序号 | 寄存器名 | 读/写 | 功能描述 |
---|---|---|---|
1 | CKSEL | 读/写 | 时钟选择寄存器 |
2 | CLKDIV | 读/写 | 时钟分频寄存器 |
3 | IRC24MCR | 读/写 | 内部24M振荡器控制寄存器 |
4 | IRC32KCR | 读/写 | 内部32K振荡器控制寄存器 |
5 | XOSCCR | 读/写 | 外部晶振控制寄存器 |
6 | LIRTRIM | 读/写 | IRC频率微调寄存器 |
7 | IRTRIM | 读/写 | IRC频率调整寄存器 |
8 | PCON | 读/写 | 电源控制寄存器 |
9 | VOCTRL | 读/写 | 电压控制寄存器 |
10 | WKTCH | 读/写 | 掉电唤醒定时器计数寄存器 |
11 | WKTCL | 读/写 | 掉电唤醒定时器计数寄存器 |
☆注:WKTCH寄存器最高位WKTEN是掉电唤醒定时器的使能控制位。
==☆注:本节的实验源码是在“实验2-4-1:外部中断0(下降沿中断方式)”的基础上修改。本节对应的实验源码是:“实验2-6-1:单片机掉电唤醒 - 外部中断0(下降沿方式)”。 ==
本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。
序号 | 文件名 | 后缀 | 功能描述 |
---|---|---|---|
1 | led | .c | 包含与用户led控制有关的用户自定义函数 |
2 | exint | .c | 外部中断有关的用户自定义函数 |
3 | delay | .c | 包含用户自定义延时函数 |
■ 需要引用的头文件
#include "delay.h"
#include "led.h"
#include "exint.h"
■ 需要包含的头文件
本例需要包含的头文件路径如下表:
序号 | 路径 | 描述 |
---|---|---|
1 | …\ Source | led.h、exint.h和delay.h头文件在该路径,所以要包含 |
2 | …\User | STC8.h头文件在该路径,所以要包含 |
MDK中点击魔术棒,打开工程配置窗口,按照下图所示添加头文件包含路径。
首先,在exint.c文件中编写外部中断0初始化函数INT0_Init,代码如下。
程序清单:外部中断0初始化函数
/***********************************************************
功能描述:外部中断0初始化
入口参数:无
返回值:无
************************************************************/
void INT0_Init(void)
{
IE0 = 0; //将INT0中断请求标志位清"0"
EX0 = 1; //使能INT0中断允许位
IT0 = 1; //选择INT0为下降沿触发方式
}
然后,编写外部中断服务函数,中断服务函数中无任务,代码如下。
程序清单:中断服务函数
/***********************************************************
功能描述:外部中断服务程序
入口参数:无
返回值:无
************************************************************/
void INT0_Isr (void) interrupt 0
{
; //无任务
}
最后,在主函数中先控制D4灯亮D3灯灭,约5s后控制D4灯灭D3灯亮、对INT0进行初始化、配置使单片机进入掉电模式。
代码清单:主函数
int main()
{
SleepDelay = 0; //初始清零
EA = 1; //允许总中断
while(1)
{
delay_ms(1); //延时1ms
if(++msecond >= 1000) //约1秒到
{
msecond = 0; //清1000ms计数
led_on(LED_4); //点亮用户指示灯D4
led_off(LED_3); //熄灭用户指示灯D3
if(++SleepDelay >= 5) //约5秒到
{
SleepDelay = 0; //清零延时用时间变量
if(TRUE)
{
SleepDelay = 0; //清零延时用时间变量
led_on(LED_3); //点亮用户指示灯D3
led_off(LED_4); //熄灭用户指示灯D4
INT0_Init(); //外部中断0初始化
PCON |= 0x02; //单片机进入掉电模式
_nop_();
_nop_();
_nop_();
}
}
}
}
}
本实验需要使用P3.2(外部中断0引脚)连接到J26端子TOUCH,因此需要按下图所示连接杜邦线。
==☆注:本节的实验源码是在“实验2-6-1:单片机掉电唤醒 - 外部中断0(下降沿方式)”的基础上修改。本节对应的实验源码是:“实验2-6-2:单片机掉电唤醒 - 外部中断0(上升沿或下降沿方式)”。 ==
本实验需要用到的头文件以及添加头文件包含路径的方法请参考“实验2-6-1:单片机掉电唤醒 - 外部中断0(下降沿方式)”部分。
首先,在exint.c文件中编写外部中断0初始化函数INT0_Init,代码如下。
程序清单:外部中断0初始化函数
/***********************************************************
功能描述:外部中断0初始化
入口参数:无
返回值:无
************************************************************/
void INT0_Init(void)
{
IE0 = 0; //将INT0中断请求标志位清"0"
EX0 = 1; //使能INT0中断允许位
IT0 = 0; //选择INT0为上升沿或下降沿触发方式
}
然后,编写外部中断服务函数,中断服务函数中无任务,代码如下。
程序清单:中断服务函数
/***********************************************************
功能描述:外部中断服务程序
入口参数:无
返回值:无
************************************************************/
void INT0_Isr (void) interrupt 0
{
; //无任务
}
最后,在主函数中先控制D4灯亮D3灯灭,约5s后控制D4灯灭D3灯亮、对INT0进行初始化、配置使单片机进入掉电模式。
代码清单:主函数
int main()
{
SleepDelay = 0; //初始清零
EA = 1; //允许总中断
while(1)
{
delay_ms(1); //延时1ms
if(++msecond >= 1000) //约1秒到
{
msecond = 0; //清1000ms计数
led_on(LED_4); //点亮用户指示灯D4
led_off(LED_3); //熄灭用户指示灯D3
if(++SleepDelay >= 5) //约5秒到
{
SleepDelay = 0; //清零延时用时间变量
if(TRUE)
{
SleepDelay = 0; //清零延时用时间变量
led_on(LED_3); //点亮用户指示灯D3
led_off(LED_4); //熄灭用户指示灯D4
INT0_Init(); //外部中断0初始化
PCON |= 0x02; //单片机进入掉电模式
_nop_();
_nop_();
_nop_();
}
}
}
}
}
本实验需要使用P3.2(外部中断0引脚)连接到J26端子TOUCH,因此需要按下图所示连接杜邦线。
==☆注:本节的实验源码是在“实验2-6-1:单片机掉电唤醒 - 外部中断0(下降沿方式)”的基础上修改。本节对应的实验源码是:“实验2-6-2:单片机掉电唤醒 - 外部中断0(上升沿或下降沿方式)”。 ==
本本实验需要用到的头文件以及添加头文件包含路径的方法请参考“实验2-6-1:单片机掉电唤醒 - 外部中断0(下降沿方式)”部分。
首先,在exint.c文件中编写外部中断1初始化函数INT1_Init,代码如下。
程序清单:外部中断1初始化函数
/***********************************************************
功能描述:外部中断1初始化
入口参数:无
返回值:无
************************************************************/
void INT1_Init(void)
{
IE1 = 0; //将INT1中断请求标志位清"0"
EX1 = 1; //使能INT1中断允许位
IT1 = 1; //选择INT1为下降沿触发方式
}
然后,编写外部中断服务函数,中断服务函数中无任务,代码如下。
程序清单:中断服务函数
/***********************************************************
功能描述:外部中断服务程序
入口参数:无
返回值:无
************************************************************/
void INT1_Isr (void) interrupt 2
{
; //无任务
}
最后,在主函数中先控制D4灯亮D3灯灭,约5s后控制D4灯灭D3灯亮、对INT1进行初始化、配置使单片机进入掉电模式。
代码清单:主函数
int main()
{
SleepDelay = 0; //初始清零
EA = 1; //允许总中断
while(1)
{
delay_ms(1); //延时1ms
if(++msecond >= 1000) //约1秒到
{
msecond = 0; //清1000ms计数
led_on(LED_4); //点亮用户指示灯D4
led_off(LED_3); //熄灭用户指示灯D3
if(++SleepDelay >= 5) //约5秒到
{
SleepDelay = 0; //清零延时用时间变量
if(TRUE)
{
SleepDelay = 0; //清零延时用时间变量
led_on(LED_3); //点亮用户指示灯D3
led_off(LED_4); //熄灭用户指示灯D4
INT1_Init(); //外部中断1初始化
PCON |= 0x02; //单片机进入掉电模式
_nop_();
_nop_();
_nop_();
}
}
}
}
}
本实验需要使用P3.3(外部中断1引脚)连接到J26端子TOUCH,因此需要按下图所示连接杜邦线。
==☆注:本节的实验源码是在“实验2-6-3:单片机掉电唤醒 - 外部中断1(下降沿方式)”的基础上修改。本节对应的实验源码是:“实验2-6-4:单片机掉电唤醒 - 外部中断1(上升沿或下降沿方式)”。 ==
本实验需要用到的头文件以及添加头文件包含路径的方法请参考“实验2-6-1:单片机掉电唤醒 - 外部中断0(下降沿方式)”部分。
首先,在exint.c文件中编写外部中断1初始化函数INT1_Init,代码如下。
程序清单:外部中断1初始化函数
/***********************************************************
功能描述:外部中断1初始化
入口参数:无
返回值:无
************************************************************/
void INT1_Init(void)
{
IE1 = 0; //将INT1中断请求标志位清"0"
EX1 = 1; //使能INT1中断允许位
IT1 = 0; //选择INT1为上升沿或下降沿触发方式
}
然后,编写外部中断服务函数,中断服务函数中无任务,代码如下。
程序清单:中断服务函数
/***********************************************************
功能描述:外部中断服务程序
入口参数:无
返回值:无
************************************************************/
void INT1_Isr (void) interrupt 2
{
; //无任务
}
最后,在主函数中先控制D4灯亮D3灯灭,约5s后控制D4灯灭D3灯亮、对INT1进行初始化、配置使单片机进入掉电模式。
代码清单:主函数
int main()
{
SleepDelay = 0; //初始清零
EA = 1; //允许总中断
while(1)
{
delay_ms(1); //延时1ms
if(++msecond >= 1000) //约1秒到
{
msecond = 0; //清1000ms计数
led_on(LED_4); //点亮用户指示灯D4
led_off(LED_3); //熄灭用户指示灯D3
if(++SleepDelay >= 5) //约5秒到
{
SleepDelay = 0; //清零延时用时间变量
if(TRUE)
{
SleepDelay = 0; //清零延时用时间变量
led_on(LED_3); //点亮用户指示灯D3
led_off(LED_4); //熄灭用户指示灯D4
INT1_Init(); //外部中断1初始化
PCON |= 0x02; //单片机进入掉电模式
_nop_();
_nop_();
_nop_();
}
}
}
}
}
本实验需要使用P3.3(外部中断1引脚)连接到J26端子TOUCH,因此需要按下图所示连接杜邦线。
本实验需要使用P3.3(外部中断1引脚)连接到J26端子TOUCH,因此需要按下图所示连接杜邦线。
==☆注:本节的实验源码是在“实验2-6-1:单片机掉电唤醒 - 外部中断0(下降沿方式)”的基础上修改。本节对应的实验源码是:“实验2-6-5:单片机掉电唤醒 - 外部中断2(下降沿方式)”。 ==
本实验需要用到的头文件以及添加头文件包含路径的方法请参考“实验2-6-1:单片机掉电唤醒 - 外部中断0(下降沿方式)”部分。
首先,在exint.c文件中编写外部中断2初始化函数INT2_Init,代码如下。
程序清单:外部中断2初始化函数
/***********************************************************
功能描述:外部中断2初始化
入口参数:无
返回值:无
************************************************************/
void INT2_Init(void)
{
INTCLKO |= 0x10; //使能INT2中断允许位
}
然后,编写外部中断服务函数,中断服务函数中无任务,代码如下。
程序清单:中断服务函数
/***********************************************************
功能描述:外部中断服务程序
入口参数:无
返回值:无
************************************************************/
void INT2_Isr (void) interrupt 10
{
; //无任务
}
最后,在主函数中先控制D4灯亮D3灯灭,约5s后控制D4灯灭D3灯亮、对INT2进行初始化、配置使单片机进入掉电模式。
代码清单:主函数
int main()
{
SleepDelay = 0; //初始清零
EA = 1; //允许总中断
while(1)
{
delay_ms(1); //延时1ms
if(++msecond >= 1000) //约1秒到
{
msecond = 0; //清1000ms计数
led_on(LED_4); //点亮用户指示灯D4
led_off(LED_3); //熄灭用户指示灯D3
if(++SleepDelay >= 5) //约5秒到
{
SleepDelay = 0; //清零延时用时间变量
if(TRUE)
{
SleepDelay = 0; //清零延时用时间变量
led_on(LED_3); //点亮用户指示灯D3
led_off(LED_4); //熄灭用户指示灯D4
INT2_Init(); //外部中断2初始化
PCON |= 0x02; //单片机进入掉电模式
_nop_();
_nop_();
_nop_();
}
}
}
}
}
本实验需要使用P3.6(外部中断2引脚)连接到J26端子TOUCH,因此需要按下图所示连接杜邦线。
==☆注:本节的实验源码是在“实验2-6-1:单片机掉电唤醒 - 外部中断0(下降沿方式)”的基础上修改。本节对应的实验源码是:“实验2-6-6:单片机掉电唤醒 - 外部中断3(下降沿方式)”。 ==
本实验需要用到的头文件以及添加头文件包含路径的方法请参考“实验2-6-1:单片机掉电唤醒 - 外部中断0(下降沿方式)”部分。
首先,在exint.c文件中编写外部中断3初始化函数INT3_Init,代码如下。
程序清单:外部中断3初始化函数
/***********************************************************
功能描述:外部中断3初始化
入口参数:无
返回值:无
************************************************************/
void INT3_Init(void)
{
INTCLKO |= 0x20; //使能INT3中断允许位
}
然后,编写外部中断服务函数,中断服务函数中无任务,代码如下。
程序清单:中断服务函数
/***********************************************************
功能描述:外部中断服务程序
入口参数:无
返回值:无
************************************************************/
void INT3_Isr (void) interrupt 11
{
; //无任务
}
最后,在主函数中先控制D4灯亮D3灯灭,约5s后控制D4灯灭D3灯亮、对INT3进行初始化、配置使单片机进入掉电模式。
代码清单:主函数
int main()
{
SleepDelay = 0; //初始清零
EA = 1; //允许总中断
while(1)
{
delay_ms(1); //延时1ms
if(++msecond >= 1000) //约1秒到
{
msecond = 0; //清1000ms计数
led_on(LED_4); //点亮用户指示灯D4
led_off(LED_3); //熄灭用户指示灯D3
if(++SleepDelay >= 5) //约5秒到
{
SleepDelay = 0; //清零延时用时间变量
if(TRUE)
{
SleepDelay = 0; //清零延时用时间变量
led_on(LED_3); //点亮用户指示灯D3
led_off(LED_4); //熄灭用户指示灯D4
INT3_Init(); //外部中断3初始化
PCON |= 0x02; //单片机进入掉电模式
_nop_();
_nop_();
_nop_();
}
}
}
}
}
本实验需要使用P3.6(外部中断2引脚)连接到J26端子TOUCH,因此需要按下图所示连接杜邦线。
==☆注:本节的实验源码是在“实验2-6-1:单片机掉电唤醒 - 外部中断0(下降沿方式)”的基础上修改。本节对应的实验源码是:“实验2-6-7:单片机掉电唤醒 - 定时唤醒”。 ==
本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。
序号 | 文件名 | 后缀 | 功能描述 |
---|---|---|---|
1 | led | .c | 包含与用户led控制有关的用户自定义函数 |
2 | wkt | .c | 内部掉电唤醒定时器有关的用户自定义函数 |
3 | delay | .c | 包含用户自定义延时函数 |
首先,在exint.c文件中编写外部中断3初始化函数INT3_Init,代码如下。
■ 需要引用的头文件
#include "delay.h"
#include "led.h"
#include "wkt.h"
■ 需要引用的头文件路径
本例需要包含的头文件路径如下表:
序号 | 路径 | 描述 |
---|---|---|
1 | …\ Source | led.h、wkt.h和delay.h头文件在该路径,所以要包含 |
2 | wkt | stc8.h头文件在该路径,所以要包含 |
MDK中点击魔术棒,打开工程配置窗口,按照下图所示添加头文件包含路径。
首先,在wkt.c文件中编写掉电唤醒定时器计数寄存器配置函数,可以实现将单片机内部掉电唤醒定时器开启并对15位计数器赋初值,代码如下。
程序清单:掉电唤醒定时器计数寄存器配置函数
/**************************************
功能描述:唤醒定时器计数寄存器配置
入口参数:uint16 SetTime: 实际计数值
返回值:无
***************************************/
void SetWakeUpTime(uint16 SetTime)
{
if(SetTime > 0) SetTime=SetTime-1; //待写入WKTCH、WKTCL寄存器值比实际计数值少1
WKTCL = (uint8)SetTime; //赋值WKTCL寄存器
WKTCH = (uint8)(SetTime >> 8) | 0x80; //赋值WKTCH寄存器并使能掉电唤醒定时器
}
然后,在主函数中先控制D4灯亮D3灯灭,约5s后控制D4灯灭D3灯亮、开启掉电唤醒定时器并赋值计数器、配置使单片机进入掉电模式。
代码清单:主函数
int main(void)
{
SleepDelay = 0; //初始清零
while(1)
{
delay_ms(1); //延时1ms
if(++msecond >= 1000) //约1秒到
{
msecond = 0; //清1000ms计数
led_on(LED_4); //点亮用户指示灯D4
led_off(LED_3); //熄灭用户指示灯D3
if(++SleepDelay >= 5) //约5秒到
{
SleepDelay = 0; //清零延时用时间变量
led_on(LED_3); //点亮用户指示灯D3
led_off(LED_4); //熄灭用户指示灯D4
SetWakeUpTime(4096); //约2秒后唤醒
PCON |= 0x02; //单片机进入掉电模式
_nop_();
_nop_();
_nop_();
}
}
}
}