This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430G2553:实现时钟(hh:mm:ss)并使用__delay_cycles()

Guru**** 2539500 points
Other Parts Discussed in Thread: MSP430G2553

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/574132/msp430g2553-implementing-a-clock-hh-mm-ss-and-use-of-__delay_cycles

部件号:MSP430G2553

您好,

我正在设计一个需要在显示屏上显示时钟的设备,我的意思是要显示一天中的时间(小时,分钟)。 MCU是MSP430G2553,其3.2768万KHz xtal连接到相关引脚。 我的代码(简化)如下所示:

#define sleep_Time_1S 3.2767万L

void main (void)
{
	WDTCTL = WDTPW | WDTHOLD; //停止看门狗

	初始化();//各种初始化,例如GPIO,同时显示

	(1){
	
		START_LPM_Timer(SLEEGE_1S);
		
		DO_SOME_AND_DISPLAY_CLOCK ();		//执行一些任务		
		
		LPM3I();		
	}
}

void START_LPM_Timer(unsigned long Time)
{
TA0CCR0 =时间;
TA0CTL = TIME_CLARK_ACLK+TIMER MODE_UG+TALCLR;
TA0CCTL0 &=~CCIFG;
TA0CCTL0 |= CCIE;
}

作废LPM3I(void)
{
__bis_sr_register (LPM3_bits+GIE);
__NO_OPERATION();
}

#pragma vector=TIMER0_A0_vector
__interrupt void ISR_Timer0_A0(void)//从休眠函数
{
TA0CTL &=~(MC_1);
TA0CCTL0 &=~(CCIE);
_low_power模式_off_on_exit();
} 

//启用中断的LPM3

作废LPM3I (作废)

    __bis_sr_register (LPM3_bits+GIE);
    __no_operation();
}

ACLK由外部32kHz晶体计时。

其目的是启动一个计时器,在while (1)内精确计数1。  启动计时器后,代码执行一些任务(包括更新显示屏上的时间),然后进入低功耗模式3。 计时器到期时(即1秒后),MCU将唤醒并开始新的循环。

我希望,不管执行 DO-something_and_display_clock ()需要什么,只要它远少于1,系统就应该实施精确的时钟; 相反,我注意到,大约一天之后,显示屏显示的时间(hh:mm)比我使用的挂钟晚了大约3分钟(这应该非常精确)。 如需进一步的详细信息,do_somethe_and_display_clock()函数执行 几个__delay_cycles(day)的调用,其中delay =4000 (这是通过驱动显示器的代码完成的,它需要驱动一些具有指定定时的引脚)。

MCU的时钟频率为1MHz DCO (因此,delay_cycles每次应达到4ms)。

有没有什么理由让我错过了为什么在24小时后时钟会出现问题? 每天3秒意味着一个月后1个半小时,绝对不可接受。

谢谢,致以诚挚的问候

Fabio

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好Fabio,

    我认为您需要的是以下应用说明。 在MSP430上实施实时时钟

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好,Jace:

    感谢您向我指出文档。 timer_a示例在概念上与我的代码没有太大区别。 我还有几个问题:

    1)使用 __delay_cycles()是否影响计时精度,即计时器A的计数过程? 从我到目前为止读到的关于这种功能的信息来看,我不认为是这样的,因为它只是执行一些代码,它完全采用所需的时钟周期,而不在MCU外设上执行任何特定操作;只是将它排除在可能的问题原因之外。

    2)在 RTC中,使用TIME_A示例代码:

    设置TA MOV #TASEL0+TALCLR,&TACTL;Timer_A的ACLK
    BIS #CCIE,&CCTL0;启用CCR0中断。
    MOV #07FFFh,&CCR0;使用3.2767万 加载CCR0。
    BIS #MC0,&TACTL;以“最高CCR0”模式启动TA 

    MSP430用户指南(slau144)指出,“最高CCR0”模式是MC1 (MC0是“停止计时器”)

    12.3 1 TACTL,Timer_A控制寄存器

    Mcx Bits 5-4 Mode控件。 Timer_A未使用时设置Mcx = 00h可节省电量。

    00停止模式:计时器停止。

    01向上模式:计时器计数到TCCR0。

    10连续模式:计时器最多计数0FFFFh。

    11升/降模式:计时器计数至TCCR0,然后降至0000h。

    不应该是最后一行:BIS #MC1,&TACTL  ?

    谢谢,致以诚挚的问候

    Fabio

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    已编辑帖子以反映更正的信息。 -JH

    您好Fabio,

    __delay_cycles()不应影响TimerA计数,除非它在中断关闭的时间段内使用,从而延迟您可以为TimerA中断提供服务的时间, 或者,它在TimerA中断期间使用,并且足够长的延迟足以阻止以下中断的服务。 如果你看一下__delay_cycles(),它只是一个NOP循环。

    在汇编示例中,MC0被定义为Timer A寄存器Mcx部分的位0。 MC1是位1。 通过设置MC0 (BIS指令),您可以将定时器A更改为UP模式,因为Mcx将读数为'01',即模式"MC1"。 通常,在我们的示例中,我们用两种方式定义寄存器值,首先通过精确位位置(本例中为#MC0和#MC1),然后通过其最终效果(通过标签中的下划线进行区分)。 (对于计时器模式,其外观如下所示:MC_0,MC_1,MC_2等。)  这似乎有点令人困惑,这就是为什么我更喜欢使用下划线方法来提高代码可读性的原因。 请参阅以下标题文件摘录中如何定义计时器模式和位。

    #定义TASSSEL1 (0x0200) /*计时器时钟源选择1*/
    #define TASSEL0 (0x0100) /*计时器时钟源选择0*/
    #define ID1 (0x0080) /*定时器A时钟输入分频器1*/
    #define ID0 (0x0040) /*定时器A时钟输入分频器0*/
    #define MC1 (0x0020) /*定时器A模式控制1*/
    #define MC0 (0x0010) /*定时器A模式控制0 */
    #定义TALCLR (0x0004) /*计时器A计数器清除*/
    #define TAIE (0x0002) /*定时器A计数器中断启用*/
    #define TAIFG (0x0001) /*计时器A计数器中断标志*/
    
    #define mc_0 (0*0x10u) /*定时器A模式控制:0-停止*/
    #define MC_1 (1*0x10u) /*定时器A模式控制:1-至CCR0 */
    #define MC_2 (2*0x10u) /*定时器A模式控制:2-继续*/
    #define MC_3 (3*0x10u) /*定时器A模式控件:3-上/下*/
    #define ID_0 (0*0x40u) /*定时器A输入分隔符:0-/1 */
    #define ID_1 (1*0x40u) /*定时器A输入分隔符:1-/2 */
    #define ID_2 (2*0x40u) /*定时器A输入分隔符:2 -/4 */
    #define ID_3 (3*0x40u) /*定时器A输入分隔符:3-/8 */
    #define tassel_0 (0*0x100u) /*定时器A时钟源选择:0- TCLK */
    #define tassel_1 (1*0x100u) /*定时器A时钟源选择:1- ACLK */
    #define tassel_2 (2*0x100u) /*定时器A时钟源选择:2- SMCLK */
    #define tassel_3 (3*0x100u) /*定时器A时钟源选择:3- INCLK */ 


    此外,从应用手册中可以掌握的一点是,您需要通过ACLK从LFXtal运行TimerA或Watchdog (LFXTAL -> Aclck -> TimerA/ Watchdog Timer)。 通过使用DCO,您将在时间测量中引入DCO的自然误差/漂移。 LFxtal将更准确地满足您的需求。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好,Jace:

    我会仔细检查我的_delay_cycles()调用,但根据您的建议,它们应该不是问题。

    关于最后一句,您说 :“您将希望通过ACLK从LFXtal运行TimerA或Watchdog”。 我刚刚注意到我的代码和AppNote之间的差异:

    AppNote:

           设置TA       MOV #TASEL0+TALCLR,&TACTL;Timer_A的ACLK

    我的代码:

           TA0CTL = TIME_CLARK_ACLK+TIMER MODE_UG+TALCLR;

    其中timer_clock_aclk定义为tassel_1

    谈到DCO,我意味着主MCU时钟是DCO 1MHz,但我不知道上述计时器设置(tassel_0和tassel_1)是否是您所说的“从LFXtal运行定时器A”,这就是我从一开始就想做的。 但可能是因为它未正确实施,而是问题的根本原因。 我有32KHz xtal连接到XIN/XOUT。 要将其用作ACLK的源,我应该将tassel多路复用器设置为TCLK (tassel_0) 还是ACLK (tassel_1)? 请参阅 图12-1。 Timer_A slau144j的方框图。

    12.2 .1.1 时钟源选择和除法器

    计时器时钟可以来自ACLK,SMCLK,也可以通过TACLK或INCLK从外部获取。 时钟源
    使用TASSELx位选择。

    “通过TALCK外部”是指“从连接到XIN/XOUT的xtal”?

    关于MC0和MC_0我理解您的意思,AppNote程序集代码设置了单位0,这与整个寄存器部分的设置模式MC_1相同。 是的,这有点令人困惑,但严格来说是正确的。

    谢谢,致以诚挚的问候

    Fabio

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好Fabio,

    您需要将TASSELx设置为ACLK,以便通过ACLK为计时器计时。 选择TALCK可让您选择外部时钟以选择要使用的GPIO。 您还需要通过检查时钟模块寄存器来确保XTAL提供了ACLK。 默认情况下,应将其设置为使用LF XTAL;但是,您必须确保xtal正确振荡,否则如果模块检测到振荡器故障,它将返回到用于ACLK的VLOCLK上。 只是需要记住的一些东西。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    好的,感谢TCLK的澄清,顺便说一句,我刚刚意识到TSSEL0和Tassel_1与以上MC0和MC_1相同,因此实际上我的计时器已正确设置为从XTAL运行。

    非常感谢。
    Fabio