msp430g2553内部资源总结.docx
《msp430g2553内部资源总结.docx》由会员分享,可在线阅读,更多相关《msp430g2553内部资源总结.docx(48页珍藏版)》请在冰点文库上搜索。
![msp430g2553内部资源总结.docx](https://file1.bingdoc.com/fileroot1/2023-5/14/e2f7c9d5-0b90-47fc-88e0-414d515a350b/e2f7c9d5-0b90-47fc-88e0-414d515a350b1.gif)
msp430g2553内部资源总结
电设工作小结之——MSP430G2553学习笔记——1
一,MSP430G2553单片机的各个功能模块
(一),IO口模块,
1,咱们所用的MSP430G2553有两组IO口,P1和P2。
2,IO口的寄放器有:
方向选择寄放器PxDIR,输出寄放器PxOUT,输入寄放器PxIN,IO口内部上拉或下拉电阻使能寄放器PxREN, IO口功能选择寄放器PxSEL和PxSEL2,IO口中断使能寄放器PxIE,中断沿选择寄放器PxIES,IO口中断标志寄放器PxIFG。
3,所有的IO都带有中断,其中所有的P1口公用一个中断向量,所有的P2口公用一个中断向量。
因此在利用中断时,当进入中断后,还要判定究竟是哪个IO口产生的中断,判定方式能够是判定各个IO口的电平。
4,中断标志PxIFG需要软件清除,也能够用软件置位,从而用软件触发一个中断。
注意:
在设置PxIESx时依照PxINx有可能会引发相应的PxIFGx置位(具体的情形见用户指南),因此在初始化完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中断使能
P1IES |= BIT4+BIT5+BIT6+BIT7; // Hi/lo edge 下降沿中断
//P1IES &= ~BIT3; //上升沿触发中断
P1IFG &= ~(BIT4+BIT5+BIT6+BIT7); //中断标志位清零
}
5,PxOUT:
若是引脚选择了内部的上拉或下拉电阻使能,那么PxOUT设定电阻是上拉仍是下拉,0:
下拉,1:
上拉
6,当IO口不历时,最好不要设为输入,且为浮动状态(这是IO口的默许状态),因为当输入为浮动时,输入电压有可能会在VIL和VIH之间,如此会产生击穿电流。
因此不用的IO口能够设为输出状态,或设为输入状态但通过外围电路接至VCC或GND,或接一个上拉/下拉电阻。
7,当利用msp430g2553的IO口时要注意,因为g2553的IO口寄放器的操作,不像51,它不能单独针对某一名进行操作,必需对整个寄放器进行操作。
因此就不像51,g2553不能够概念bit型的数据。
因此在利用msp的IO口时要注意对需要位的操作,而不要阻碍其他无关的位,能够 用 | & ^等按位操作的符号。
在利用IO都操纵其他外围模块时也要注意要利用的IO口的概念,能够用如下的概念方式:
#define CLR_RS P2OUT&=~BIT0; //RS = P2.0
#define SET_RS P2OUT|=BIT0;
#define CLR_RW P2OUT&=~BIT1; //RW = P2.1
#define SET_RW P2OUT|=BIT1;
#define CLR_EN P2OUT&=~BIT2; //EN = P2.2
#define SET_EN P2OUT|=BIT2;
#define DataPort P1OUT
8,g2553的P27和P26脚别离接外部晶体的输出和输入脚XOUT和XIN,默许是自动设为了晶振管脚功能,可是当想把它们用为一般的IO时,也能够,设置对应的SEL设为一般的IO即可,如下:
P2DIR |= BIT6+BIT7; //把P26和P27配置为一般IO 并为输出脚 默以为晶振的输入和输出引脚 作为dac0832的
P2SEL &= ~(BIT6+BIT7); //cs和wr操纵端
P2SEL2 &= ~(BIT6+BIT7);
(二),时钟系统
1,msp430能做到超低功耗,合理的时钟模块是功不可没的。
可是功能壮大的时钟模块设置起来也相对复杂一些。
2,msp430的时钟源有:
(1),外接低频晶振LFXT1CLK:
低频模式接腕表晶体32768Hz,高频模式450KHz~8MHz;
(2),外接高速晶振XT2CLK:
8MHz;
(3),内部数字操纵振荡器DCO:
是一个可控的RC振荡器,频率在0~16MHz;
(4),超低功耗低频振荡器VLO:
不可控,4~20KHz 典型值为12KHz;
3,时钟模块:
430的时钟模块有MCLK SMCLK ACLK :
(1),主系统时钟MCLK:
提供给MSP430的CPU时钟。
能够来自LFXT1CLK XT2CLK DCO VLO可选,默以为DCO。
(2),子系统时钟SMCLK:
提供给高速外设。
能够来自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频率比较精准,实际测得为12.08MHz左右 正弦波
BCSCTL1 = CALBC1_12MHZ;
用这种方式能够设置1,8,12,16MHz
宏概念如下:
#ifndef __DisableCalData
SFR_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,利用超低功耗低频振荡器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((long)(CPU_F*(double)x/1000.0))
void main(void)
{
volatile unsigned int i; // Volatile to prevent removal
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO 低频时钟选择为VLO ACLK选为VLO
IFG1 &= ~OFIFG; // Clear OSCFault flag 清除振荡器错误中断标志
__bis_SR_register(SCG1 + SCG0); // Stop DCO SCG1禁止SMCLK SCG0禁止DCO
BCSCTL2 |= SELM_3 + DIVM_3; // MCLK = LFXT1/8
//因为前面已经选择了LFXT1 = VLO 因此MCLK选为VLO 8分频 因此CPU的MCLK大约为1.5KHz
P1DIR = 0xFF; // All P1.x outputs
P1OUT = 0; // All P1.x reset
P2DIR = 0xFF; // All P2.x outputs
P2OUT = 0; // All P2.x reset
P1SEL |= BIT0+BIT4; // P10 P14options 功能选择为外围模块
//p10输出ACLK,来自VLO,p14输出SMCLK, 因为禁止了SMCLK,因此P14脚无波形输出
//VLO典型值为12KHz 实际用示波器测得为:
13.05KHz 左右波动
//因此CPU的实际MCLK大约为13.05/8=1.63KHz
for (;;)
{
P1OUT ^= BIT6; // P1.6 闪烁
delay_ms(1000);
}
}
6,如上面的程序所示,其中的延迟函数用那种方式,利用系统的延迟周期函数__delay_cycles(int n); 能够达到比较精准的延迟,如下:
//more_
//1延时
//#define CPU_F ((double)16000000)//cpu frequency16000000
#define 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设置的太高时,用示波器能够看到波形再也不是方波,而是类似于正弦波。
(三),按时器Timer_A
1,MSP430g2553具有两个16位的按时器:
Timer0_A Timer1_A。
别离具有三个捕捉/比较寄放器,具有输入捕捉,输出比较功能。
能够产生按时中断,也能够产生PWM。
2,产生PWM,例子如下:
#include
void Timer_A0_1_init() //TA0.1输出PWM
{
TACTL|= TASSEL_1+MC_1;//ACLK,增计数
CCTL1=OUTMOD_7;//输出模式为复位/置位
CCR0=328;//时钟频率为32768HZ,100HZ
//CCR1=164;//时钟频率为32768HZ,占空比CCR1/CCR0=50%
CCR1=109;//占空比CCR1/CCR0=1/3 TA0.1由P1.2 P1.6输出
}
void Timer_A1_2_init() //TA1.2输出PWM
{
TA1CTL|= TASSEL_1+MC_1;//ACLK,增计数
TA1CCTL2=OUTMOD_7;//输出模式为复位/置位,注意CCTL2要写为TA1CCTL2
TA1CCR0=164;//时钟频率为32768HZ,波形32768/CCR0=199HZ
TA1CCR2=41;//占空比CCR2/CCR0=1/4,注意CCR2要写成TA1CCR2 TA1.2由P2.4 P2.5输出
}
void Timer_A1_1_init() //TA1.1输出PWM
{
TA1CCTL1=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 OUT1
P2SEL|=BIT4+BIT5;
P2DIR|=BIT4+BIT5;//P2.4 P2.5输出 TA1.2 OUT2
P2SEL|=BIT1+BIT2;
P2DIR|=BIT1+BIT2; //P2.1 P2.2输出 TA1.1 OUT1
}
void 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 ON
}
3,Timer_A的捕捉/比较寄放器
TAR寄放器是Timer_A的16位的计数寄放器。
TACCRx是Timer_A的捕捉/比较寄放器,当为捕捉模式时:
当捕捉发生时,把TAR的值装载到TACCRx中。
当为比较模式时:
TACCRx中装的是要与TAR寄放器相较较的值。
4,捕捉模式
捕捉外部输入的信号的上升沿或下降沿或上升沿下降沿都捕捉,当捕捉发生时,把TAR的值装载到TACCRx中,同时也能够进入中断,执行相应的操作。
如此利用捕捉上升沿或下降沿就能够够计算外部输入信号的周期,得出频率。
利用捕捉上升沿和下降沿能够得出输入信号的高电平或低电平的持续时刻。
也能够算出占空比。
下面是一个例子,是Timer_A捕捉初始化的程序:
void timer_init() //利用Timer1_A时要专门注意各个寄放器的写法,因为Timer0_A的寄放器都简写了,因此在写
//Timer1_A的寄放器时,要专门注意与Timer0_A的不同
{
P1SEL |= BIT2; //选择P12作为捕捉的输入端子 Timer0_A
//TACCTL1 |=CM_3+SCS+CAP+CCIE; //上下沿都触发捕捉,用于测脉宽,同步模式、时能中断 CCI1A
TACCTL1 |=CM_1+SCS+CAP+CCIE; //上升沿触发捕捉,同步模式、时能中断 CCI1A
TACTL |= TASSEL1+MC_2; //选择SMCLK时钟作为计数时钟源,不分频 增计数模式不行,必需持续计数模式
P2SEL |= BIT1; //选择P21作为捕捉的输入端子 Timer1_A
//TA1CCTL1 |=CM_3+SCS+CAP+CCIE; //上下沿都触发捕捉,用于测脉宽,同步模式、时能中断 CCI1A
TA1CCTL1 |=CM_1+SCS+CAP+CCIE; //上升沿触发捕捉,同步模式、时能中断 CCI1A
TA1CTL |= TASSEL1+MC_2; //选择SMCLK时钟作为计数时钟源,不分频 增计数模式不行,必需持续计数模式
}
相对应的中断函数如下:
#pragma vector=TIMER0_A1_VECTOR //Timer0_A CC1 的中断向量
__interrupt void Timer_A(void)
{
// CCI0A 利用的捕捉比较寄放器是TA0CCR0,TA0CCR0单独分派给一个
//中断向量TIMER1_A0_VECTOR,因此进入中断后直接确实是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 vector=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,因此进入了中断后还要用下面
//的方式进行判定是哪个中断源产生的中断
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的计数模式
计数模式有:
增计数模式,持续计数模式和增减计数模式。
具体的各个模式的详解,参见用户指南。
6,按时器的按时中断
在利用按时器的按时中断时,要注意按时器计数模式的选择。
在利用中断时,要注意中断向量的利用和中断源的判定,下面就举一个例子,注释的也较详细:
#include
unsigned int t=0;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P1DIR |= 0x01; // P1.0 output
CCTL0 = CCIE; // CCTLx是捕捉/比较操纵寄放器 interrupt enabled CCIE=0x0010 时能按时器A中断
CCR0 = 50000; //捕捉/比较寄放器 设置计数器CCR0的初值 16位寄放器,最大值为65535
//默许SMCLK利用的是DCO,默许的DCO大约为800KHz,而CCR0=50000,因其中断产生的频率大约为16Hz
TACTL = 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 routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void) //CCIFG中断被响应后,该标志位自动清零
{
//P1OUT ^= 0x01; // Toggle P1.0
t++;
if(t==5)
{
P1OUT ^= BIT0; // Toggle P1.0
t=0;
}
CCR0 += 50000; // Add Offset to CCR0 增加CCR0偏移
//按时器老是从0开始往上计数,一直到计满再从0开始,在持续计数模式下,当按时器的值等于CCR0时,产生中断
//在中断中对CCR0增加50000,如此的话按时器从当前值到下一时刻再次等于CCR0时的距离为50000,恒定
//如此产生中断的时刻距离就相等了
//因此在持续计数模式下,要想使中断的时刻距离必然,就要有CCR0 += n;这句话