1、电设工作小结之MSP430G2553 学习笔记1把这几天的工作做一个小结:第一版MSP430G2553 学习笔记 Created on: 2012-8-18Author: zhang bin学习笔记for msp430g2553redesigned by zhang bin2012-08-18versions:12_08_01一,MSP430G2553 单片机的各个功能模块(一) ,IO 口模块,1,我们所用的 MSP430G2553 有两组 IO 口,P1 和 P2。2,IO 口的寄存器有:方向选择寄存器 PxDIR,输出寄存器 PxOUT,输入寄存器PxIN,IO 口内部上拉或下拉电阻使能
2、寄存器 PxREN, IO 口功能选择寄存器 PxSEL 和PxSEL2,IO 口中断使能寄存器 PxIE,中断沿选择寄存器 PxIES,IO 口中断标志寄存器PxIFG。3,所有的 IO 都带有中断,其中所有的 P1 口公用一个中断向量,所有的 P2 口公用一个中断向量。所以在使用中断时,当进入中断后,还要判断到底是哪一个 IO 口产生的中断,判断方法可以是判断各个 IO 口的电平。4,中断标志 PxIFG 需要软件清除,也可以用软件置位,从而用软件触发一个中断。注意:在设置 PxIESx 时根据 PxINx 有可能会引起相应的 PxIFGx 置位(具体的情况见用户指南) ,所以在初始化完
3、IO 口中断以后,正式使用 IO 中断前要先将对应的 PxIFGx 清零。程序如下:void IO_interrupt_init() /IO 中断初始化函数P1REN |= BIT4+BIT5+BIT6+BIT7; / pullup 内部上拉电阻使能/使用中断时,使能内部的上拉电阻这样当该脚悬空是,电平不会跳变,防止悬空时电平跳变不停的触发中断P1OUT = BIT4+BIT5+BIT6+BIT7; / 当引脚上的上拉或下拉电阻使能时,PxOUT 选择是上拉还是下来/0:下拉,1:上拉P1IE |= BIT4+BIT5+BIT6+BIT7; / interrupt enabled P13 中断
4、使能P1IES |= BIT4+BIT5+BIT6+BIT7; / Hi/lo edge 下降沿中断/P1IES /上升沿触发中断P1IFG /中断标志位清零5,PxOUT:如果引脚选择了内部的上拉或下拉电阻使能,则 PxOUT 设定电阻是上拉还是下拉,0:下拉,1:上拉6,当 IO 口不用时,最好不要设为输入,且为浮动状态(这是 IO 口的默认状态) ,因为当输入为浮动时,输入电压有可能会在 VIL 和 VIH 之间,这样会产生击穿电流。所以不用的IO 口可以设为输出状态,或设为输入状态但通过外围电路接至 VCC 或 GND,或接一个上拉/下拉电阻。7,当使用 msp430g2553 的 I
5、O 口时要注意,因为 g2553 的 IO 口寄存器的操作,不像 51,它不能单独针对某一位进行操作,必须对整个寄存器进行操作。所以就不像 51,g2553 不可以定义 bit 型的数据。所以在使用 msp 的 IO 口时要注意对需要位的操作,而不要影响其他无关的位,可以 用 | /RS = P2.0#define SET_RS P2OUT|=BIT0;#define CLR_RW P2OUT /RW = P2.1#define SET_RW P2OUT|=BIT1;#define CLR_EN P2OUT /EN = P2.2#define SET_EN P2OUT|=BIT2;#defin
6、e DataPort P1OUT8,g2553 的 P27 和 P26 脚分别接外部晶体的输出和输入脚 XOUT 和 XIN,默认是自动设为了晶振管脚功能,但是当想把它们用为普通的 IO 时,也可以,设置对应的 SEL 设为普通的 IO 即可,如下:P2DIR |= BIT6+BIT7; /把 P26 和 P27 配置为普通 IO 并为输出脚 默认为晶振的输入和输出引脚 作为 dac0832 的P2SEL /cs 和 wr 控制端P2SEL2 (二) ,时钟系统1,msp430 能做到超低功耗,合理的时钟模块是功不可没的。但是功能强大的时钟模块设置起来也相对复杂一些。2,msp430 的时钟源
7、有:(1) ,外接低频晶振 LFXT1CLK:低频模式接手表晶体 32768Hz,高频模式450KHz8MHz;(2) ,外接高速晶振 XT2CLK:8MHz ;(3) ,内部数字控制振荡器 DCO:是一个可控的 RC 振荡器,频率在 016MHz;(4) ,超低功耗低频振荡器 VLO:不可控,420KHz 典型值为 12KHz;3,时钟模块:430 的时钟模块有 MCLK SMCLK ACLK :(1) ,主系统时钟 MCLK:提供给 MSP430 的 CPU 时钟。可以来自 LFXT1CLK XT2CLK DCO VLO 可选,默认为 DCO。(2) ,子系统时钟 SMCLK: 提供给高速
8、外设。可以来自 LFXT1CLK XT2CLK DCO VLO 可选,默认为 DCO。(3) ,辅助系统时钟 ACLK:提供给低速外设。可来自 LFXT1CLK VLO。 4,内部的振荡器 DCO 和 VLO 提供的时钟频率不是很精确,随外部环境变化较大。DCO 默认的频率大概为 800KHz,但我用示波器观察的为 1.086MHz 左右,当 DCO 设置的过高时,用示波器可以看到波形不再是方波,而是类似于正弦波。DCO 可以用 CCS 提供的宏定义进行相对比较精确的设置,如下:DCOCTL = CALDCO_12MHZ; /DCO 设为 12MHz 这种方法设 DCO 频率比较精确,实际测得
9、为 12.08MHz 左右 正弦波BCSCTL1 = CALBC1_12MHZ;用这种方法可以设置 1,8,12,16MHz宏定义如下:#ifndef _DisableCalDataSFR_8BIT(CALDCO_16MHZ); SFR_8BIT(CALBC1_16MHZ); SFR_8BIT(CALDCO_12MHZ); SFR_8BIT(CALBC1_12MHZ); SFR_8BIT(CALDCO_8MHZ); SFR_8BIT(CALBC1_8MHZ); SFR_8BIT(CALDCO_1MHZ); SFR_8BIT(CALBC1_1MHZ); #endif 5,使用超低功耗低频振荡器
10、VLO 可以很大程度地降低系统功耗,下面的例子是设置ACLK 为 VLO,MCLK 为 VLO 的 8 分频:#include /1 延时/#define CPU_F (double)16000000)/cpu frequency16000000#define CPU_F (double)1630)/cpu frequency1630 /CPU 的实际 MCLK 大约为13.05/8=1.63KHz#define delay_us(x) _delay_cycles(long)(CPU_F*(double)x/1000000.0)#define delay_ms(x) _delay_cycles
11、(long)(CPU_F*(double)x/1000.0)void main(void)volatile unsigned int i; / Volatile to prevent removalWDTCTL = WDTPW + WDTHOLD; / Stop watchdog timerBCSCTL3 |= LFXT1S_2; / LFXT1 = VLO 低频时钟选择为VLO ACLK 选为 VLOIFG1 / Clear OSCFault flag 清除振荡器错误中断标志_bis_SR_register(SCG1 + SCG0); / Stop DCO SCG1 禁止 SMCLK SCG
12、0禁止 DCOBCSCTL2 |= SELM_3 + DIVM_3; / MCLK = LFXT1/8/因为前面已经选择了 LFXT1 = VLO 所以 MCLK 选为 VLO 8 分频 所以 CPU 的MCLK 大约为 1.5KHzP1DIR = 0xFF; / All P1.x outputsP1OUT = 0; / All P1.x resetP2DIR = 0xFF; / All P2.x outputsP2OUT = 0; / All P2.x resetP1SEL |= BIT0+BIT4; / P10 P14options 功能选择为外围模块/p10 输出 ACLK,来自 VLO
13、,p14 输出 SMCLK, 因为禁止了 SMCLK,所以 P14 脚无波形输出/VLO 典型值为 12KHz 实际用示波器测得为: 13.05KHz 左右波动/所以 CPU 的实际 MCLK 大约为 13.05/8=1.63KHzfor (;)P1OUT = BIT6; / P1.6 闪烁delay_ms(1000);6,如上面的程序所示,其中的延迟函数用那种方法,使用系统的延迟周期函数_delay_cycles(int n); 可以达到比较精确的延迟,如下:/more_/1 延时/#define CPU_F (double)16000000)/cpu frequency16000000#d
14、efine CPU_F (double)12000000)/cpu frequency12000000#define delay_us(x) _delay_cycles(long)(CPU_F*(double)x/1000000.0)#define delay_ms(x) _delay_cycles(long)(CPU_F*(double)x/1000.0)/2 空函数#define nop() _NOP();7,系统上电后默认使用的是 DCO 时钟,DCO 默认的频率大概为 800KHz,但我用示波器观察的为 1.086MHz 左右,当 DCO 设置的过高时,用示波器可以看到波形不再是方波,
15、而是类似于正弦波。(三) ,定时器 Timer_A1,MSP430g2553 具有两个 16 位的定时器:Timer0_A Timer1_A。分别具有三个捕捉/比较寄存器,具有输入捕捉,输出比较功能。可以产生定时中断,也可以产生 PWM。2,产生 PWM,例子如下:#include void Timer_A0_1_init() /TA0.1 输出 PWMTACTL|= TASSEL_1+MC_1;/ACLK,增计数CCTL1=OUTMOD_7;/输出模式为复位 /置位CCR0=328;/时钟频率为 32768HZ,100HZ/CCR1=164;/时钟频率为 32768HZ,占空比 CCR1/C
16、CR0=50%CCR1=109;/占空比 CCR1/CCR0=1/3 TA0.1 由 P1.2 P1.6输出void Timer_A1_2_init() /TA1.2 输出 PWMTA1CTL|= TASSEL_1+MC_1;/ACLK,增计数TA1CCTL2=OUTMOD_7;/输出模式为复位 /置位,注意 CCTL2 要写为 TA1CCTL2TA1CCR0=164;/时钟频率为 32768HZ,波形 32768/CCR0=199HZTA1CCR2=41;/占空比 CCR2/CCR0=1/4,注意 CCR2 要写成 TA1CCR2 TA1.2 由P2.4 P2.5 输出void Timer_
17、A1_1_init() /TA1.1 输出 PWMTA1CCTL1=OUTMOD_7;TA1CCR1=123; /占空比 CCR1/CCR0=3/4,注意 CCR1 要写成 TA1CCR1 TA1.1 由P2.1 P2.2 输出void IO_init()P1SEL|=BIT2+BIT6;P1DIR|=BIT2+BIT6;/P1.2 P1.6 输出 TA0.1 OUT1P2SEL|=BIT4+BIT5;P2DIR|=BIT4+BIT5;/P2.4 P2.5 输出 TA1.2 OUT2P2SEL|=BIT1+BIT2;P2DIR|=BIT1+BIT2; /P2.1 P2.2 输出 TA1.1 O
18、UT1void main(void) WDTCTL=WDTPW+WDTHOLD;IO_init();Timer_A0_1_init();Timer_A1_2_init();Timer_A1_1_init();_BIS_SR(CPUOFF); / Enter LPM0 进入低功耗模式 0 SMCLK ON,ACLK ON3,Timer_A 的捕获/比较寄存器TAR 寄存器是 Timer_A 的 16 位的计数寄存器。TACCRx 是 Timer_A 的捕获/比较寄存器,当为捕获模式时:当捕获发生时,把 TAR 的值装载到 TACCRx 中。当为比较模式时:TACCRx 中装的是要与 TAR 寄存
19、器相比较的值。4,捕获模式捕获外部输入的信号的上升沿或下降沿或上升沿下降沿都捕捉,当捕捉发生时,把 TAR 的值装载到 TACCRx 中,同时也可以进入中断,执行相应的操作。这样利用捕捉上升沿或下降沿就可以计算外部输入信号的周期,得出频率。利用捕捉上升沿和下降沿可以得出输入信号的高电平或低电平的持续时间。也可以算出占空比。下面是一个例子,是 Timer_A 捕获初始化的程序:void timer_init() /使用 Timer1_A 时要特别注意各个寄存器的写法,因为 Timer0_A 的寄存器都简写了,所以在写/Timer1_A 的寄存器时,要特别注意与 Timer0_A 的不同P1SEL
20、 |= BIT2; /选择 P12 作为捕捉的输入端子 Timer0_A/TACCTL1 |=CM_3+SCS+CAP+CCIE; /上下沿都触发捕捉,用于测脉宽,同步模式、时能中断 CCI1ATACCTL1 |=CM_1+SCS+CAP+CCIE; /上升沿触发捕捉,同步模式、时能中断 CCI1ATACTL |= TASSEL1+MC_2; /选择 SMCLK 时钟作为计数时钟源,不分频 增计数模式不行,必须连续计数模式P2SEL |= BIT1; /选择 P21 作为捕捉的输入端子 Timer1_A/TA1CCTL1 |=CM_3+SCS+CAP+CCIE; /上下沿都触发捕捉,用于测脉宽
21、,同步模式、时能中断 CCI1ATA1CCTL1 |=CM_1+SCS+CAP+CCIE; /上升沿触发捕捉,同步模式、时能中断 CCI1ATA1CTL |= TASSEL1+MC_2; /选择 SMCLK 时钟作为计数时钟源,不分频 增计数模式不行,必须连续计数模式相对应的中断函数如下:#pragma vector=TIMER0_A1_VECTOR /Timer0_A CC1 的中断向量_interrupt void Timer_A(void)/ CCI0A 使用的捕捉比较寄存器是 TA0CCR0,TA0CCR0 单独分配给一个/中断向量 TIMER1_A0_VECTOR,所以进入中断后直接
22、就是 Timer0_A CC0 产生的中断,不用经过类似/下面的方法判断中断源了 。/Timer0_A CC1-4, TA0 公用一个中断向量 TIMER0_A1_VECTOR,所以进入了中断后还要用下面/的方法进行判断是哪一个中断源产生的中断switch(TAIV) /如果是 Timer0_A CC1 产生的中断case 2:flag=1;LPM1_EXIT; /退出低功耗模式/ _BIC_SR_IRQ(LPM1_bits);/_bic_SR_register_on_exit(LPM1_bits);break;case 4: break;case 10:break;#pragma vecto
23、r=TIMER1_A1_VECTOR /Timer1_A CC1 的中断向量_interrupt void Timer_A1(void)/ P1OUT|=BIT0; /led 调试用的/ LPM1_EXIT; /退出低功耗模式 因为使用的是 CCI0A 使用的捕捉比较寄存器是TA1CCR0,TA1CCR0 单独分配给一个/中断向量 TIMER1_A0_VECTOR,所以进入中断后直接就是 Timer1_A CC0 产生的中断,不用经过类似/下面注释掉的方法判断 。/而 Timer1_A CC1-4, TA1 则公用一个中断向量 TIMER1_A1_VECTOR,所以进入了中断后还要用下面/的方
24、法进行判断是哪一个中断源产生的中断switch(TA1IV) /如果是 Timer1_A CC1 产生的中断case 2:flag=2;LPM1_EXIT; /退出低功耗模式/ _BIC_SR_IRQ(LPM1_bits);/_bic_SR_register_on_exit(LPM1_bits);break;case 4:break;case 10:break;/如果要测量更低频率的信号的话,可以在中断中判断溢出中断发生的次数,这样就可以得到溢出的次数,从而可以测量更/低频率的信号5,Timer_A 的计数模式计数模式有:增计数模式,连续计数模式和增减计数模式。具体的各个模式的详解,参见用户指
25、南。6,定时器的定时中断在使用定时器的定时中断时,要注意定时器计数模式的选择。在使用中断时,要注意中断向量的使用和中断源的判断,下面就举一个例子,注释的也较详细:#include unsigned int t=0;void main(void)WDTCTL = WDTPW + WDTHOLD; / Stop WDTP1DIR |= 0x01; / P1.0 outputCCTL0 = CCIE; / CCTLx 是捕获/ 比较控制寄存器 interrupt enabled CCIE=0x0010 时能定时器 A 中断CCR0 = 50000; /捕获/比较寄存器 设置计数器 CCR0 的初值
26、16 位寄存器,最大值为 65535/默认 SMCLK 使用的是 DCO,默认的 DCO 大约为 800KHz,而CCR0=50000,所以中断产生的频率大约为 16HzTACTL = TASSEL_2 + MC_2; / SMCLK, contmode 连续计数模式从0 计到 0FFFFh/TACTL = TASSEL_2 + MC_1; / SMCLK, upmode 增计数模式从 0计到 CCR0_BIS_SR(LPM0_bits + GIE); / Enter LPM0 w/ interrupt 进入低功耗模式 0,允许中断/ Timer A0 interrupt service ro
27、utine#pragma vector=TIMER0_A0_VECTOR_interrupt void Timer_A (void) /CCIFG 中断被响应后,该标志位自动清零/P1OUT = 0x01; / Toggle P1.0t+;if(t=5)P1OUT = BIT0; / Toggle P1.0t=0;CCR0 += 50000; / Add Offset to CCR0 增加 CCR0 偏移/定时器总是从 0 开始往上计数,一直到计满再从 0 开始,在连续计数模式下,当定时器的值等于 CCR0 时,产生中断/在中断中对 CCR0 增加 50000,这样的话定时器从当前值到下一时刻
28、再次等于 CCR0 时的间隔为 50000,恒定/这样产生中断的时间间隔就相等了/所以在连续计数模式下,要想使中断的时间间隔一定,就要有 CCR0 += n;这句话/在中断中 CCR0 不需要从新赋值,区别于 51中断的使用注意情况:还是把举个例子吧:#include void main(void)WDTCTL = WDTPW + WDTHOLD; / Stop WDTP1DIR |= 0x01; / P1.0 outputTACTL = TASSEL_2 + MC_2 + TAIE; / SMCLK, contmode, interrupt TAIE允许定时器溢出中断_BIS_SR(LPM0
29、_bits + GIE); / Enter LPM0 w/ interrupt GIE 允许中断/ Timer_A3 Interrupt Vector (TA0IV) handler#pragma vector=TIMER0_A1_VECTOR_interrupt void Timer_A(void)switch( TA0IV ) /TAIV 中断向量寄存器 用于case 2: break; / CCR1 not used 捕获/ 比较器 1case 4: break; / CCR2 not used 捕获/ 比较器 2case 10: P1OUT = 0x01; / overflow 定时器
30、溢出break;7,注意:定时器 Timer0_A 的时钟可以选择为外接时钟输入 TACLK(P10 ) ,这样当外接一个信号时,定时器 Timer0_A 就相当于一个计数器使用。这样就可以用 Timer0_A 接外接信号,Timer1_A 接标准的时钟如 32768Hz 的晶振,就可以实现等精度测频了。其实Timer1_A 的时钟也可以外接的,但是在 g2553 中没有这个外接管脚(P37) ,所以就只能选择正常的时钟了。Timer0_A 的外接时钟输入 TACLK(P10)的设置如下:下面是我实现等精度测频时,两个定时器的初始化程序:void timer0_init()TACTL |= TASSEL_0+MC_2+TACLR; /选择 TACLK 时钟作为计数时钟源,不分频 必须连续计数模式P1SEL |= BIT0; /P10 为 Timer0_A 的时钟 TACLK 输入,接外部待测信号,这样Timer0_A 就当作计数器用/Timer1_A 采用 ACLK 作为时钟源计数,这样 ACLK 就相当于是标准信号,这样两个定时