MSP430F149——定时器

    科技2022-07-10  225

    前言

    特点

    msp430系列单片机是16位,51单片机为8位,stm32系列为32位。 位数越高代表着该单片机处理数据的能力越快,性能也就越高。32位机器处理性能好,8位机器廉价性价比高,16位机器超低功耗。就是有一个低功耗模式,可以长时间极少耗损地待机,定时唤醒cpu进行工作.

    学习路线

    详细理解时钟初始化配置。 熟悉基本操作IO口。 学习定时器三大功能。 学习中断的原理。 操作各种外设,模块。

    MSP430内部结构

    在接触一款单片机,首先应该了解其总体框架,了解其内部结构,方便后期进行学习理解。

    系统时钟

    在MSP430F149单片机中一共有三个时钟源:

    (1)LFXT1CLK,为低速/高速晶振源,通常接32.768kHz,也可以接(400kHz~16Mhz);

    (2)XT2CLK,可选高频振荡器,外接标准高速晶振,通常是接8Mhz,也可以接(400kHz~16Mhz);

    (3)DCOCLK,数控振荡器,为内部晶振,由RC震荡回路构成;

    在MSP430F149内部一共有三个时钟系统:

    (1)ACLK(Auxiliary Clock)辅助时钟,通常由LFXT1CLK或VLOCLK作为时钟源,可以通过软件控制更改时钟的分频系数;

    (2)MCLK(Master Clock)系统主时钟单元,为系统内核提供时钟,它可以通过软件从四个时钟源选择;

    (3)SMCLK(Sub-Main Clock)系统子时钟,也是可以由软件选择时钟源。

    MSP430F149的时钟设置相关寄存器

    DCOCTL

    DCO控制寄存器,地址为56H,初始值为60H DCO0~DCO2: 定义了8种频率之一,而频率由注入直流发生器的电流定义。

    MOD0~MOD4: Modulation Bit,频率的微调。

    该寄存器在不需要DCO的场合保持默认初始值

    BCSCTL1

    时钟配置寄存器 1,地址为57H,初始值为84H RSEL0~RSEL2: 选择某个内部电阻以决定标称频率.0最低,7最高。

    XT5V: 1.

    DIVA0~DIVA1:选择ACLK的分频系数。DIVA=0,1,2,3,ACLK的分频系数分别是1,2,4,8;

    XTS: 选择LFXT1工作在低频晶体模式(XTS=0)还是高频晶体模式(XTS=1)。

    XT2OFF: 控制XT2振荡器的开启(XT2OFF=0)与关闭(XT2OFF=1)。

    正常情况下把XT2OFF复位.

    BCSCTL2

    时钟配置寄存器2,地址为58H,初始值为00H DCOR: 0,选择内部电阻;1,选择外部电阻

    DIVS0~1: DIVS=0,1,2,3对应SMCLK的分频因子为1,2,4,8

    SELS: 选择SMCLK的时钟源, 0:DCOCLK; 1:XT2CLK/LFXTCLK.

    DIVM0~1: 选择MCLK的分频因子, DIVM=0,1,2,3对应分频因子为1,2,4,8.

    SELM0~1: 选择MCLK的时钟源, 0与1:DCOCLK, 2:XT2CLK, 3:LFXT1CLK

    下面是我自己进行的一段时钟系统初始化配置

    void Clock_Init() { unsigned char i; BCSCTL1 = RSEL0 + RSEL1 + RSEL2; // 采用最高频率7 ACLK = XT2 BCSCTL1&=~XT2OFF; //打开XT2振荡器 do { IFG1 &= ~OFIFG; // 清除振荡器失效标志 for (i = 255; i > 0; i--); // 延时,等待XT2起振 } while ((IFG1 & OFIFG) != 0); // 判断XT2是否起振 BCSCTL2 |= SELS+SELM_2; // SMCLK = MCLK = XT2 }

    接下来开始学习IO口配置

    I/O

    ’|=‘,’&=~‘赋值操作

    P1DIR &= ~BIT1; //P1.1端口设置为输入模式 P1SEL |= BIT1; //P1.1端口设置为功能复用 P1DIR |= BIT0; //P1.0端口设置为输出模式 P1OUT |= BIT0; //P1.0端口输出高电平

    相关函数

    跑马灯(延时函数)

    #include <msp430x14x.h> void Port_Init() { P4DIR |= 0xff; //P4端口配置为输出模式 } void Clock_Init() { unsigned char i; BCSCTL1 = RSEL0 + RSEL1 + RSEL2; // 采用最高频率7 ACLK = XT2 BCSCTL1&=~XT2OFF; //打开XT2振荡器 do { IFG1 &= ~OFIFG; // 清除振荡器失效标志 for (i = 255; i > 0; i--); // 延时,等待XT2起振 } while ((IFG1 & OFIFG) != 0); // 判断XT2是否起振 BCSCTL2 |= SELS+SELM_2; // SMCLK = MCLK = XT2 } void Delay_ms(unsigned int time) { unsigned int i; for(i =0 ;i <1000 ;i++ ) for( ; time >0 ;time--) _NOP(); } void main(void) { unsigned int i; WDTCTL = WDTPW + WDTHOLD; Port_Init(); Clock_Init(); while(1) { for(i = 0;i<8;i++) { P4OUT = ~(0x01<<i); Delay_ms(60000); } } }

    接下来使用定时器来实现跑马灯功能,这时候就要引入定时器这个概念了

    定时器

    内部集成有5种定时器:看门狗定时器WDT,基本定时器BT,定时器TimerA,定时器TimerB,实时时钟RTC.我们主要学习看门狗定时器WDT与定时器TimerA,B。

    看门狗定时器WDT

    作用

    在程序死锁或着系统异常的情况下完成强制复位

    特性

    1.含有定时器与时钟源(定时器计数一定程度产生特定信号) 2.定时器计数过程中,可以通过某些信号清零定时器(简称喂狗) 3.可以禁止看门狗功能

    相关寄存器:

    WDTCTL:

    控制看门狗的工作模式 时钟源 定时器时间间隔选择 WDTPW:看门狗密码设置 WDTHOLD:看门狗定时器挂起 WDTNMIES:看门狗定时器NMI边缘选择 WDTNMI:NMI功能选择位,控制RST/NMI引脚功能。 WDTTMSEL:看门狗功能模式选择。 WDTCNTCL:看门狗定时器清零。 WDTSSEL:看门狗定时器时钟选择。

    IE1(系统中断控制寄存器):

    控制看门狗电路中断信息 NMIIE:NMI中断使能控制位。 1:允许NMI中断; 0∶禁止NMI中断。

    WDTIE:看门狗定时器中断允许位,控制当看门狗电路工作在周期定时模式时WDTIFG的中断使能。 1∶允许EDTIFG中断; 0:禁止WDTIFG中断。

    IFG1(系统中断标志寄存器):

    保留系统中断信息 NMIIFG:NMI中断请求标志位,用户必须软件清除该中断请求。 WDTIFG:看门狗定时器中断请求标志位。需要特别注意,在看门狗模式下该位必须由用户在软件中清除,而在周期定时模式下该位是可以被自动清除的。

    程序中使用模式举例

    1.禁止使用WDT: WDTCTL = WDTPW +WDTHOL;//禁止看门狗定时器的使用 2.使用WDT模式:

    #include <msp430x14x.h> void main()//看门狗定时器产生方波 { WDTCTL = WDT_MDLY_32; //看门狗定时器选用32ms的定时周期 IE1 |= WDTIE; //打开看门狗定时中断允许位 P1DIR |= BIT1; //设置方波输出引脚为输出方向 _EINT(); //打开总中断使能 } #pragma vector=WDT_VECTOR //进入中断服务程序必须添加的语句 __interrupt void Watchdog(void) { P1OUT ^= BIT1; //看门狗定时器中断响应后将方波输出引脚电平取反,达到方波效果 }

    定时器Timer

    特点

    16位定时器、4种工作模式; 多种可选择的计数器时钟源; 多个可配置输入端的捕获/比较寄存器; 8种输出模式的可配置输出单元

    相关寄存器

    TACTL:

    16位计数器中的控制位和状态位;

    TACCTLx

    控制捕获/比较寄存器和比较器;

    TACCRx

    该寄存器使用最简单,可读可写,在PWM输出中CCR0常用作周期,CCR1中用作占空比。

    TAR

    16位计数器的技术执行单元,保存计数器内容

    TAIV

    保存了中断请求的中断源。

    四种工作模式

    停止模式

    默认功能

    增计数模式(产生两个中断标志)

    计数到TACCR0值时,返回0,重新计数。此时计数到TACCR0的同时产生一个中断标志CCIFG,而当计数器溢出返回零的同时又同时产生一个中断标志TAIFG。

    连续计数模式(产生一个中断标志)

    计数器将直接计数到计数器所能计数的最大值0FFFFH之后重新返回零,再次计数。返回零的同时产生一个TAIFG中断标志。 如果相应中断位允许,每当一个定时间隔到来都会产生中断请求,在连续计数模式下,须将下一事件发生的时间在当前中断程序中加到CCRx中。

    增减计数模式(产生两个中断标志)

    当计数器计数到跟TACCR0一样的之后,然后从TACCR0开始又减少,直到为零,然后又开始增。当计数跟TACCR0一样的时候产生一个中断标志CCIFG,当减到为零的时候又产生一个中断标志TAIFG。

    三种功能:

    16位定时计数器

    这是定时器的默认模式,当在比较模式下的时候,与捕获模式相关的硬件停止工作,如果这个时候开启定时器中断,然后设置定时器终值(将终值写入TACCRx),开启定时器,当TAR的值增到TACCRx的时候,中断标志位CCIFGx置1,同时产生中断。若中断允许未开启则只将中断标志位CCIFGx置1。

    例子:能够软件设置定时间隔来产生中断处理一些事情,如键盘扫描,也可以结合信号输出产生时序脉冲发生器,PWM信号发生器。如:不断装载TACCRx,启动定时器,TAR和TACCRx比较产生中断处理。

    //可以用来做跑马灯实验 #include <msp430x14x.h> void Port_Init() { P4DIR |= 0xff; //P4端口设置为输出模式 } void Clock_Init() { unsigned char i; BCSCTL1 = RSEL0 + RSEL1 + RSEL2; // 采用最高频率7 ACLK = XT2 BCSCTL1&=~XT2OFF; //打开XT2振荡器 do { IFG1 &= ~OFIFG; // 清除振荡器失效标志 for (i = 255; i > 0; i--); // 延时,等待XT2起振 } while ((IFG1 & OFIFG) != 0); // 判断XT2是否起振 BCSCTL2 |= SELS+SELM_2; // SMCLK = MCLK = XT2 } void Delay_ms(unsigned int time) { unsigned int i; for(i =0 ;i <1000 ;i++ ) for( ; time >0 ;time--) _NOP(); } void TimerA_Init() { CCTL0 = CCIE; // 捕获/比较中断使能 CCR0 = 6000; // 比较值为8000,即从0计数到8000产生一次中断 TACTL = TASSEL_2 + MC_1+TACLR; // 使用SMCLK时钟,使用增计数模式,清零TACCR寄存器 } void main(void) { WDTCTL = WDTPW + WDTHOLD; //关闭看门狗 Port_Init(); Clock_Init(); TimerA_Init(); _BIS_SR(LPM0_bits + GIE); // _BIS_SR(LPM0_bits + GIE) 具有同时打开全局中断和进入LPM0; 等同于:_EINT(); LPM0; } #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A (void) //定时器A中断服务程序 { unsigned int i; for(i=0;i<8;i++) { P4OUT=~(0x01<<i); Delay_ms(60000); } }

    捕获功能

    捕获模式: 利用外部信号的上升沿、下降沿或上升下降沿触发来测量外部或内部事件,也可以由软件停止。捕获源可以由CCISx选择CCIxA,CCIxB,GND,VCC。完成捕获后相应的捕获标志位CCIFGx置1

    捕获模式的应用: 利用捕获源的来触发捕获TAR的值,并将每次捕获的值都保存到TACCRx中,可以随时读取TACCRx的值,TACCRx是个16位的寄存器,捕获模式用于事件的精确定位。如测量时间、频率、速度等

    例子:利用两次捕获的值来测量脉冲的宽度。或捕获选择任意沿,CCISx=”11“(输入选择VCC),这样即当VCC与GND发生切换时产生

    #include <msp430x14x.h> void Port_Init() { P1DIR &= ~BIT1; //P1.1端口设置为输入模式 P1SEL |= BIT1; //P1.1端口设置为功能复用 P1DIR |= BIT0; //P1.0端口设置为输出模式 P1OUT |= BIT0; } void Clock_Init() { unsigned char i; BCSCTL1 = RSEL0 + RSEL1 + RSEL2; // 采用最高频率7 ACLK = XT2 BCSCTL1&=~XT2OFF; //打开XT2振荡器 do { IFG1 &= ~OFIFG; // 清除振荡器失效标志 for (i = 255; i > 0; i--); // 延时,等待XT2起振 } while ((IFG1 & OFIFG) != 0); // 判断XT2是否起振 BCSCTL2 |= SELS+SELM_2; // SMCLK = MCLK = XT2 } void TimerA_Init() { //定时模式示例 //CCTL0 = CCIE; // 捕获/比较中断使能 //CCR0 = 6000; // 比较值为8000,即从0计数到8000产生一次中断 //TACTL = TASSEL_2 + MC_1+TACLR; // 使用SMCLK时钟,使用增计数模式,清零TACCR寄存器 //捕获模式示例 TACTL = TACLR + TASSEL_2 + ID_2 + MC_3; //清零TACCR寄存器,使用SMCLK时钟,8分频,使用增减计数模式 TACCTL0 = CM_2+ CCIS_0 + SCS + CAP + CCIE; //设置为 上升下降沿捕获,捕获通道0,同步捕获,捕捉模式,捕获/比较中断使能 //TACCTL1 = CM_3 + CCIS_1 + SCS + CAP + CCIE; //设置为 上升下降沿捕获,捕获通道1,同步捕获,捕捉模式,捕获/比较中断使能 } void main(void) { WDTCTL = WDTPW + WDTHOLD; //关闭看门狗 Port_Init(); Clock_Init(); TimerA_Init(); _BIS_SR(LPM0_bits + GIE); // _BIS_SR(LPM0_bits + GIE) 具有同时打开全局中断和进入LPM0; 等同于:_EINT(); LPM0; // 如果只使用定时器之类的功能时,可以使用低功耗模式,而不使用while(1) } #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A (void) //定时器A中断服务程序 { P1OUT ^= BIT0; }

    输出PWM功能

    #include <msp430x14x.h> void Port_Init() { P6DIR = 0XFF; P6OUT = 0Xff; } void Clock_Init() { unsigned char i; BCSCTL1 = RSEL0 + RSEL1 + RSEL2; // 采用最高频率7 ACLK = XT2 BCSCTL1&=~XT2OFF; //打开XT2振荡器 do { IFG1 &= ~OFIFG; // 清除振荡器失效标志 for (i = 255; i > 0; i--); // 延时,等待XT2起振 } while ((IFG1 & OFIFG) != 0); // 判断XT2是否起振 BCSCTL2 |= SELS+SELM_2; // SMCLK = MCLK = XT2 } void Delay_ms(unsigned int time) { unsigned int i; for(i =0 ;i <1000 ;i++ ) for( ; time >0 ;time--) _NOP(); } void TimerA_Init() { //定时模式示例 //CCTL0 = CCIE; // 捕获/比较中断使能 //CCR0 = 6000; // 比较值为8000,即从0计数到8000产生一次中断 //TACTL = TASSEL_2 + MC_1+TACLR; // 使用SMCLK时钟,使用增计数模式,清零TACCR寄存器 //捕获模式示例 //TACTL = TACLR + TASSEL_2 + ID_3 + MC_3; //清零TACCR寄存器,使用SMCLK时钟,8分频,使用增减计数模式 //TACCTL0 = CM_2+ CCIS_0 + SCS + CAP + CCIE; //设置为 下降沿捕获,捕获通道0,同步捕获,捕捉模式,捕获/比较中断使能 //TACCTL1 = CM_3 + CCIS_1 + SCS + CAP + CCIE; //设置为 上升下降沿捕获,捕获通道1,同步捕获,捕捉模式,捕获/比较中断使能 //PWM输出模式示例 TACTL |= TASSEL_2 + ID_3 + MC_2 + TACLR + TAIE; //使用SMCLK时钟,8分频,使用连续计数模式,清零TACCR寄存器,定时器溢出中断 TACCTL0= CCIE; CCR0 = 5000; } void main(void) { WDTCTL = WDTPW + WDTHOLD; //关闭看门狗 Port_Init(); Clock_Init(); TimerA_Init(); _BIS_SR(LPM0_bits + GIE); // _BIS_SR(LPM0_bits + GIE) 具有同时打开全局中断和进入LPM0; 等同于:_EINT(); LPM0; // 如果只使用定时器之类的功能时,可以使用低功耗模式,而不使用while(1) } #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A (void) //定时器A中断服务程序 { P6OUT ^= BIT0; CCR0 = CCR0 + 5000; }
    Processed: 0.009, SQL: 8