继上次的LPM0模式的官方例程详解,这次是LPM3模式,说实话这次研究LPM3模式就花了上次研究LPM0模式的一半时间都不到,因为大部分代码都很相似,有些细节值得深究。其实我也不是为了研究例程而研究例程。主要是想用过研究例程的过程熟悉MSP430开启低功耗的过程,后面在实际做项目时可以根据需求自行配置各种低功耗模式(因为考虑到可能需要在各个低功耗模式之间自由切换),所以要熟悉每个低功耗模式的配置流程,熟能生巧嘛。
其实LPM3模式有两个官方例程,区别主要在于时钟源的选择上,这次详解的是使用VLOCLK(内部低频时钟源)作为时钟源的02(看文件名就知道)另一个是LFXT1(外部低频时钟源),这里也解释一下VLOCLK和LFXT的区别(源自ChatGPT):
LFXT(Low-Frequency Crystal Oscillator)是一种外部时钟源,它使用晶体振荡器提供稳定的低频时钟信号。LFXT通常具有较高的精度和稳定性,适合需要高精度时钟的应用程序。由于它是一个外部时钟源,因此需要将晶体连接到微控制器的引脚上,并且可能需要占用更多的空间和功耗。LFXT通常用于需要高精度时钟的应用程序,例如实时时钟(RTC)或长时间待机模式下的低功耗时钟运行。
VLOCLK是MSP430微控制器内部的RC振荡器提供的低频时钟信号。它的频率大约在1kHz左右,并且具有较低的精度和稳定性。由于它是内部时钟源,因此可以避免使用外部晶体或振荡器所带来的成本和空间消耗。同时,由于其低功耗特性,VLOCLK也可用于实现长时间待机模式下的时钟运行。VLOCLK通常用于需要低功耗和较低精度时钟的应用程序,例如电量计量、温度监测等。
因此,要根据实际应用需求选择适合的时钟源。如果需要高精度时钟,则应选择外部晶体振荡器(如LFXT);如果需要低功耗和较低精度时钟,则可以选择内部RC振荡器(如VLOCLK)。
废话不多说,代码及释义如下:
//******************************************************************************
// MSP430FR59xx Demo - 进入LPM3模式(设置ACLK = VLO)
//
// 描述: 配置时钟源为VLO的WDT和ACLK并进入LPM3模式
// Note: 在FET板上P1.0驱动一个LED,当打开时可以显示高功率数字
// 测量电流时,LED跳线JP3断开
// LED跳线断开
// ACLK = VLOCLK = ~9.4KHz, MCLK = SMCLK = 1MHz
// 辅助时钟 = 低频时钟源 = 9.4kHz,主时钟 = 子系统时钟 = 1MHz
//
// MSP430FR5969
// ---------------
// /|\| |
// | | |
// --|RST |
// | |
// | |
// | P1.0 |---> Disconnect JP9 for power meas.
//
// Built with IAR Embedded Workbench V5.30 & Code Composer Studio V5.5
//******************************************************************************
#include <msp430.h>
int main(void)
{
/* 参考自《User's Guide》P641 & msp430fr5969.h
* WDTCTL->看门狗定时器控制寄存器的名称
* WDTPW->看门狗定时器控制寄存器WDTCTL的密码
* WDTTMSEL->选择定时器模式或看门狗模式,此处WDTTMSEL被设置为1(msp430fr5969.h->4321行),即选择了定时器模式
* WDTSSEL_1->选择看门狗定时器的时钟源,此处WDTSSEL_2被设置为2,即选择了VLOCLK作为看门狗定时器的时钟源
* WDTIS_5->看门狗定时器的时钟源分频为2^15(1s at 32.768kHz) */
WDTCTL = WDTPW | WDTTMSEL | WDTSSEL_2 | WDTIS_5;
SFRIE1 |= WDTIE;
/* 参考自《User's Guide》P73 & msp430fr5969.h
* SFRIE1->SFR寄存器,用于控制设备的中断使能
* 按位或运算符"|="->可以将一个操作数的特定位设置为1而不影响其他位
* WDTIE->将SFRIE1寄存器的第0位设置为1,以开启看门狗定时器中断 */
// 配置GPIO
/* 参考自《User's Guide》P368
* 配置了所有8个GPIO端口(P1-P4和PJ)的输出模式,使它们都可以用来控制外部设备 */
P1OUT = 0;
P1DIR = 0xFF;
P2OUT = 0;
P2DIR = 0xFF;
P3OUT = 0;
P3DIR = 0xFF;
P4OUT = 0;
P4DIR = 0xFF;
PJOUT = 0;
PJDIR = 0xFFFF;
// 关闭GPIO上电默认高阻抗模式激活->设置高阻抗模式禁用引脚以降低功耗
// 之前配置的端口
/* 参考自《User's Guide》P92 & msp430fr5969.h
* PM5CTL0->控制低功耗模式的寄存器 - PMM寄存器 - 电源管理模块
* LOCKLPM5->(0x0001)->进入/退出LPM5时锁定I/O引脚配置 - PM5CTL0最低位清零*/
PM5CTL0 &= ~LOCKLPM5;
/* CS->Clock System->时钟系统
* 参考自《User's Guide》P104 & msp430fr5969.h */
CSCTL0_H = CSKEY >> 8;// CSCTL0->CS控制寄存器0 - CSCTL0-0_H->CS控制寄存器0的高八位 - CSKEY->CS寄存器解锁密码
CSCTL1 = DCOFSEL_0;// CSCTL1->CS控制寄存器1 - DCOFSEL_0->DCO频率选择:0->1MHz
CSCTL2 = SELM__DCOCLK | SELS__DCOCLK | SELA__VLOCLK;// CSCTL2->CS控制寄存器2 - SELM__DCOCLK | SELS__DCOCLK | SELA__VLOCLK->详情参考《User's Guide》P106
CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;// CSCTL3->CS控制寄存器3 - DIVA__1 | DIVS__1 | DIVM__1->详情参考《User's Guide》P107
CSCTL4 = LFXTOFF | HFXTOFF;// CSCTL4->CS控制寄存器4 - LFXTOFF | HFXTOFF->低/高频振荡器(LFXT)禁用
CSCTL0_H = 0;// CS寄存器上锁
P1DIR |= BIT0;// // 打开LED BIT0->0000 0000 0000 0001
/* SR->Status Register->状态寄存器->参考自《User's Guide》P118
* __bis_SR_register->宏定义,用于设置SR寄存器的值
* LPM3_bits->LPM3低功耗模式
* GIE->general Interrupt Enable->全局中断使能标志位,决定是否允许处理器响应中断请求,GIE=1->正常响应中断;GIE=0->忽略任何中断请求 */
__bis_SR_register(LPM3_bits | GIE);
__no_operation();// 内置的空操作函数,在程序运行时不执行任何操作,但保持CPU处于活动状态,不会进入低功耗模式
}
// 看门狗定时器中断服务程序
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)// 如果是TI或IAR的编译器,则编译下一段代码,否则跳到#else
#pragma vector=WDT_VECTOR// TI和IAR编译器特有的指令,指定了WDT_VECTOR中断向量,表示定义的函数为WDT中断服务程序
__interrupt void WDT_ISR(void)// 中断服务程序的函数声明
#elif defined(__GNUC__)// 如果编译器为GCC,则编译下一段代码
void __attribute__ ((interrupt(WDT_VECTOR))) WDT_ISR (void)
#else
#error Compiler not supported!// 如果编译器不支持TI、IAR和GCC中的任何一种,则产生编译错误
#endif
{
P1OUT ^= BIT0;// P1.0翻转状态(LED1闪烁)
}
还是那句话,要想玩明白一个MCU,一定要认真抱着官方的的《User's Guide》和《Data Sheet》 啃,尤其对于MSP430这种教程资源不太多的(反正我没找到什么系统的教程,我就是按着之前跟野火学STM32那套流程来学MSP430的,基本也能看懂)