P1OUT|=BIT1; //P1.1置1
P1OUT|=BIT0+BIT2+BIT6+BIT7; //P1.0、 P1.2、 P1.6、 P1.7置1
P1OUT&=~BIT7; //P1.7清0
P1OUT&=~(BIT1+BIT3); //P1.3、 P1.1清0
P1OUT^=BIT0; //P1.0取反
P1OUT^= BIT0+BIT2+BIT4+BIT6; //P1.0、 P1.2、 P1.4、 P1.6取反
__bis_SR_register(SCG0); // Disable the FLL control loop
UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx
UCSCTL1 = DCORSEL_3; // Set RSELx for DCO = 4.9 MHz
UCSCTL2 = FLLD_1 + 74; // Set DCO Multiplier for 2.45MHz
// (FLL_N + 1) * FLLRef = FdcoCLKDIV
// (74 + 1) * 32768 = 2.45MHz
// Set FLL Div = fDCOCLK/2
__bic_SR_register(SCG0); // Enable the FLL control loop
//其中__bis_SR_register()函数是将SR寄存器中的相应位置1
//__bic_SR_register()函数是将SR寄存器中的相应位置0
中断名称(不规范) | 宏定义 |
---|---|
port1口中断 | PORT1_VECTOR |
port2口中断 | PORT2_VECTOR |
振荡器失效中断 | 0xFFFA |
WDT间隔定时器模式中断 | WDT_VECTOR |
WDT看门狗模式中断 | 0xFFFE |
TAxCCR0中断中断 | TIMER0_A0_VECTOR |
TAIFG中断 | TIMER0_A1_VECTOR |
ADC12中断 | ADC12_VECTOR |
串口中断 | USCI_A1_VECTOR |
__bis_SR_register(GIE); // 开启总中断
__bic_SR_register(GIE); // 关闭总中断
//其中__bis_SR_register()函数是将SR寄存器中的相应位置1
//__bic_SR_register()函数是将SR寄存器中的相应位置0
// Timer_A1 Interrupt Vector (TAIV) handler
#pragma vector=TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR(void)
{
switch(__even_in_range(TA0IV,14))// __even_in_range()本征函数,用于多源中断的查询。
{
case 0: break; // No interrupt
case 2: break; // CCR1 not used
case 4: break; // CCR2 not used
case 6: break; // reserved
case 8: break; // reserved
case 10: break; // reserved
case 12: break; // reserved
case 14: P4OUT ^= BIT1; // TAIFG
break;
default: break;
}
}
name | function |
---|---|
XT1 CLK | 外部低频,一般接32768Hz |
VLOCLK | 内部,10K振荡器 |
REFOCLK | 内部,32768Hz |
DCOCLK | 内部,数控振荡器,借助参考时钟 |
XT2 CLK | 外部高频,4~32MHZ |
name | function | 默认 | 默认频率 | 输出方法 |
---|---|---|---|---|
ACLK | 用于低速外设,可由P1.0输出 | XT1CLK | 32768Hz | P1.0 |
MCLK | 用于CPU和系统 | DCOCLKDIV | 1048576Hz | 使用__delay_cycles();和LED查看 |
SMCLK | 用于高速外设,可由P3.4输出 | DCOCLKDIV | 1048576Hz | P3.4 |
//稳定XT1CLK和XT2CLK的程序
//1. 解锁XT1的引脚,这是f66xx设备独有的
while(BAKCTL & LOCKBAK)// Unlock XT1 pins
{
BAKCTL &= ~(LOCKBAK);
}
//2. 设置XT2的引脚
P7SEL |= BIT2 + BIT3; // Port select XT2
//3. 开启XT1, XT2
UCSCTL6 &= ~(XT1OFF + XT2OFF); // Set XT1, XT2 On
//4. 稳定XT1CLK、XT2CLK、DCOCLK
do
{
UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags
SFRIFG1 &= ~OFIFG; // Clear fault flags
}while (SFRIFG1&OFIFG); // Test oscillator fault flag
//5. ACLK选择XT1CLK、SMCLK选择XT2CLK
UCSCTL4 |= SELA__XT1CLK + SELS__XT2CLK; // Select SMCLK, ACLK source
模式 | 作用 |
---|---|
Active | 都可用FLL开 |
LPM0 | ACLK、SMCLK可用 FLL开 |
LPM3 | 仅ACLK可用(我发现这个和LPM2差不多) |
LPM4 | 都不可用(软件关机) |
__bis_SR_register(LPM3_bits);//开启低功耗模式3
__bic_SR_register(LPM3_bits);//关闭低功耗模式3
//也可以这样:
LPM3;//开启
LPM3_EXIT;//关闭
寄存器 | 名称 | 0 | 1 | 复位值 |
---|---|---|---|---|
PxIN | 输入寄存器 | 输入低 | 输入高 | 不确定 |
PxOUT | 输出寄存器 | 输出低 | 输出高 | 不确定 |
决定上下拉输入 | 下拉 | 上拉 | 不确定 | |
PxDIR | 方向寄存器 | 输入(默认) | 输出 | 0 |
PxREN | 上下拉寄存器 | 不使能 | 使能 | 0 |
PxSEL | 引脚功能选择 | I/O功能 | 片内外设 | 0 |
PxDIR | PxREN | PxOUT | I / O配置 |
---|---|---|---|
0 | 0 | x | 输入,无上下拉 |
0 | 1 | 0 | 下拉输入 |
0 | 1 | 1 | 上拉输入 |
1 | x | 0/1 | 输出0/1 |
寄存器 | 名称 | 0 | 1 | 复位 |
---|---|---|---|---|
PxIFG | 中断标志位 | 无中断 | 有中断在等待 | 0 |
PxIE | 中断使能位 | 不使能 | 使能 | 0 |
PxIES | 中断边沿选择 | 上升沿 | 下降沿 | 不确定 |
对于在中断服务函数中手动清零中断标志位IFG,其实有一种更方便的方法老师没讲——PxIV,这个东西会在后边讲Timer_A中看到类似的寄存器——TAxIV
看门狗(Watchdog Timer-WDT)分硬件看门狗和软件看门狗,用于程序跑飞时的系统复位。
程序跑飞不是一种硬件故障,但它会引起死机。
简单的说是一个定时器,从程序开始运行的时候就开始计数,当计数满的时候就会使程序复位。所以要在计满之前让看门狗定时器的数值清零,俗称喂狗。如果在计满之前看门狗没有收到喂狗信号,则认为程序已经跑飞。
WDTIFG
可以自动清零)
WDTIS默认为4h,其时钟信号默认为SMCLK,而SMCLK的时钟源默认为DCOCLKDIV,DCOCLKDIV的频率默认为1048576Hz,所以时间间隔默认为
1 1048576 H z ÷ 2 15 = 1 32 s = 32 m s \frac{1}{1048576Hz\div 2^{15}}=\frac{1}{32}s=32ms 1048576Hz÷2151=321s=32ms
用程序的要求和使用的时钟类型决定了WDT_A的配置方式。 例如,如果用户想要使用LPM3,则WDT_A不应配置为看门狗模式,其时钟源最初来自DCO,XT1为高频模式,XT2为SMCLK或ACLK。 在这种情况下,SMCLK或ACLK将保持启用状态,从而增加LPM3的当前消耗。
//1. 正确的方法
WDTCTL = (WDTPW + WDTHOLD);
WDTCTL = WDTPW | WDTHOLD;
//2. 错误的方法
WDTCTL |= (WDTPW + WDTHOLD);//错误
MC | Mode | 中文 | Description |
---|---|---|---|
00 | Stop | 停止计数 | 定时器停止 |
01 | Up | 增计数 | 定时器重复从零计数到TAxCCR0的值 |
10 | Continuous | 连续计数 | 定时器重复从零到0FFFFh。 |
11 | Up/down | 增减计数 | 定时器重复从零开始计数到TAxCCR0的值并返回到零。 |
捕获比较模块一共7个,n=(0~6)
放数的
下面程序采用增计数模式,那么增加到TA0CCR0 就会产生TA0CCR0 中断,然后计数器自动清零,重新计数
#include
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P4DIR |= BIT1; // P4.1 output
TA0CCTL0 = CCIE; // 开启TA0CCR0 的中断
TA0CCR0 = 50000;
TA0CTL = TASSEL__SMCLK + MC__UP + TACLR; // 时钟源选SMCLK,增计数模式,清零计数器
_BIS_SR(LPM0_bits + GIE); // Enter LPM0, enable interrupts
_NOP(); // For debugger
}
// Timer_A0 ISR
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void) // 注意这个中断向量
{
P4OUT
}
下面程序,由于是连续计数模式,计数器会从0到FFFF重复计数,但是又未设置TA0CCRn的值,所以只在0FFFFh的时候才产生TAIFG这个中断,这个中断的查询在TAxIV=14的位置
#include
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P4DIR |= BIT1; // P4.1 output
TA0CTL = TASSEL__ACLK + MC__CONTINUOUS + TACLR + TAIE; // 时钟源为ACLK,连续计数模式,清空计数器,是能中断
__bis_SR_register(LPM3_bits + GIE);
//【区分】:__bic_SR_register()这个函数是和上面的作用相反,
//比如__bic_SR_register(LPM0_bits + GIE);是关闭低功耗并且关闭总中断
_NOP();
}
#pragma vector=TIMER0_A1_VECTOR // 这个中断向量和上面的程序不一样
__interrupt void TIMER0_A1_ISR(void)
{
switch(__even_in_range(TA0IV,14))// __even_in_range()本征函数,用于多源中断的查询。
{
case 0: break; // No interrupt
case 2: break; // CCR1 not used
case 4: break; // CCR2 not used
case 6: break; // reserved
case 8: break; // reserved
case 10: break; // reserved
case 12: break; // reserved
case 14: P4OUT ^= BIT1; // TAIFG
break;
default: break;
}
}
是ADC的有限位数对模拟量进行量化而引起的误差,有两种计算方法:
在REFCTL这个寄存器中有一个神奇的位叫做REFMSTR,可以通过它来设定由谁控制ADC12的参考电压。
N A D C = 4095 × V I N − V R − V R + − V R − N_{ADC}=4095\times \frac{V_{IN}-V_{R-}}{V_{R+}-V_{R-}} NADC=4095×VR+−VR−VIN−VR−
转换出来的值存放在这里,一般在终端服务函数中查看这个寄存器。当转换结果写入选定的ADC12MEMx, ADC12IFGx中对应标志位置位;当这个寄存器的值被读取之后,IFG自动复位。
这里的x是由ADC12CTL1寄存器中的ADC12CSTARTADDx位确定的
中断使能寄存器,使能哪一位也是由ADC12CTL1寄存器中的ADC12CSTARTADDx位确定的
这个寄存器可以查看是哪个中断标志位置位,具体的代码是:
switch(__even_in_range(ADC12IV,34))// 注意这个内置函数,用于查看是哪个中断到来
{
case 0: break; // Vector 0: No interrupt
case 2: break; // Vector 2: ADC overflow
case 4: break; // Vector 4: ADC timing overflow
case 6: break;// Vector 6: ADC12IFG0
case 8: break; // Vector 8: ADC12IFG1
case 10: break; // Vector 10: ADC12IFG2
case 12: break; // Vector 12: ADC12IFG3
case 14: break; // Vector 14: ADC12IFG4
case 16: break; // Vector 16: ADC12IFG5
case 18: break; // Vector 18: ADC12IFG6
case 20: break; // Vector 20: ADC12IFG7
case 22: break; // Vector 22: ADC12IFG8
case 24: break; // Vector 24: ADC12IFG9
case 26: break; // Vector 26: ADC12IFG10
case 28: break; // Vector 28: ADC12IFG11
case 30: break; // Vector 30: ADC12IFG12
case 32: break; // Vector 32: ADC12IFG13
case 34: break; // Vector 34: ADC12IFG14
default: break;
}
注释都在例程里,仔细看哦~
#include
void main(void)
{
//1. 关闭看门狗
WDTCTL = WDTPW | WDTHOLD;
//2. 使用ADC12_A参考电压控制寄存器
REFCTL0 &= ~REFMSTR;
//3.1 ADC12ENC置零来设置ADC12
ADC12CTL0 &=~ ADC12ENC;
ADC12CTL0 = ADC12SHT12 + ADC12ON + ADC12REFON + ADC12REF2_5V;
// 采样时间Tsample = 64个ADC12CLK,打开ADC12,开参考电压,参考电压VREF+=2.5V。
//这里注意ADC12SHT12 和ADC12SHT02 的区别
//ADC12SHT02 用于设置MEM0~MEN7的采样周期是64个ADC12CLK
//ADC12SHT12 用于设置MEM8~MEN15的采样周期是64个ADC12CLK
ADC12CTL1 = ADC12CSTARTADD_8 + ADC12SHP + ADC12SSEL_2 + ADC12CONSEQ_0;
// ADC12MEMO8作为转换存储寄存器,脉冲采样模式, ADC时钟MCLK,单通道单次转换(缺省)
ADC12MCTL8 = ADC12SREF_1 + ADC12INCH_4;
// VR+ = VREF+, VR- = AVss,采样通道CH4
ADC12IE = BIT8; // 使能ADC12MEM8的中断
ADC12CTL0 |= ADC12ENC; //ADC12ENC置1,开启转换
P6SEL |= BIT4; // P6.4 作为ADC输入
while (1)
{
ADC12CTL0 |= ADC12SC; // 不断置位ADC12SC来实现ADC12一直转换
_BIS_SR(GIE); // 开总中断
__no_operation(); // For debugger
}
}
#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
{
switch(__even_in_range(ADC12IV,34))
{
// 这边分了很多种情况,来区分这个多源中断的不同中断源,
// 可以通过设置case的顺序来实现配置中断的优先级
case 0: break; // Vector 0: No interrupt
case 2: break; // Vector 2: ADC overflow
case 4: break; // Vector 4: ADC timing overflow
case 6: break; // Vector 6: ADC12IFG0
case 8: break; // Vector 8: ADC12IFG1
case 10: break; // Vector 10: ADC12IFG2
case 12: break; // Vector 12: ADC12IFG3
case 14: break; // Vector 14: ADC12IFG4
case 16: break; // Vector 16: ADC12IFG5
case 18: break; // Vector 18: ADC12IFG6
case 20: break; // Vector 20: ADC12IFG7
case 22: // Vector 22: ADC12IFG8
// 在这里配置要干啥
break;
case 24: break; // Vector 24: ADC12IFG9
case 26: break; // Vector 26: ADC12IFG10
case 28: break; // Vector 28: ADC12IFG11
case 30: break; // Vector 30: ADC12IFG12
case 32: break; // Vector 32: ADC12IFG13
case 34: break; // Vector 34: ADC12IFG14
default: break;
}
}
最后一章了!!!加油!!
发送设备、接收设备使用各自的时钟控制数据的发送和接收过程。为使双方的收发协调,要求发送和接收设备的时钟尽可能一致。
USCI_Ax 模块通过UCAxRXD、UCAxTXD两个引脚连接外部系统。 UCSYNC位清0时,USCI模块配置为UART模式。
产生波特率有两种模式,低频波特率产生模式和过采样波特率产生模式,通过设置UCOS16位进行选择。
若N <16,设置UCOS16=0选择低频波特率产生模式。
若N ≥16,设置UCOS16=1选择过采样波特率产生模式。
//时钟源32768Hz,波特率2400,低频模式
UCA1CTL1 |= UCSWRST; // Put state machine in reset
UCA1CTL1 |= UCSSEL_1; // CLK = ACLK = 32768Hz
UCA1BR0 = 0x0D; // (32768/2400=13.65)
UCA1BR1 = 0x00; //
UCA1MCTL |= UCBRS_5; // (0.65*8=5.2)
UCA1CTL1 &= ~UCSWRST; // Initialize USCI state machine
//时钟源1048576Hz,波特率9600,过采样模式
UCA1CTL1 |= UCSWRST; // **Put state machine in reset**
UCA1CTL1 |= UCSSEL_SMCK; // BRCLK = SMCLK
UCA1BR0 = 6; // 1048576/9600=109.23;109.23/16=6.83
UCA1BR1 = 0; //
UCA1MCTL = UCBRF_13 + UCOS16; //UCBRFx=0.83*16=13.28,并置位UCOS16
UCA1CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
预分频寄存器。UCAxBR0 是低八位,一般只需要配置这个就可以了
接收数据的缓冲寄存器
发送数据的缓冲寄存器
中断使能寄存器
USCI中断向量寄存器
00h = 无中断待处理
02h =中断源:数据已经接收;中断标志位:UCRXIFG;中断优先级:最高
04h =中断源:传送缓冲区空; 中断标志位: UCTXIFG;中断优先级:最低
采用查询方式,低频模式波特率,时钟源ACLK=32768Hz,波特率2400.
#include
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
//以下部分为TS3A5017芯片控制代码,直接复制使用即可
P3DIR = 0x30;//P3.4~P3.5设置为输出0011 0000
P3OUT = 0x20;//接入S3(IN1(P3.4)=0 IN2(P3.5)=1)
P4DIR = 0x30;//方向设置为输出0011 0000
P4OUT = 0x10;//建立到9针串口的连接
P8SEL |= BIT2+BIT3; // UCA1RXD(P8.3) UCA1TXD(P8.2) 1100
UCA1CTL1 |= UCSWRST; // **Put state machine in reset**
//【注意】老师给的例程中这里写错了,ACLK前面应该是两个下划线
UCA1CTL1 |= UCSSEL__ACLK; // CLK = ACLK
UCA1BR0 = 13; // 32768/2400=13.65 (see User's Guide)
UCA1BR1 = 0x00;
UCA1MCTL |= UCBRS_5; // Modulation UCBRSx = 0.65*8 = 5
UCA1CTL1 &= ~UCSWRST; // Initialize USCI state machine
UCA1TXBUF =0x55; //发送0x55
while (!(UCA1IFG&UCTXIFG)); //等待该字节发完
}
采用中断方式,过采样,时钟源SMCLK=1048576Hz,波特率9600
这里省略了很多代码。
#include
void main(void)
{
//这里省略了关闭看门狗、配置TS3A5017芯片和稳定XT1CLK的代码
P8SEL |= BIT2+BIT3; // UCA1TXD(P8.2) UCA1RXD(P8.3) 1100
UCA1CTL1 |= UCSWRST; // **Put state machine in reset**
UCA1CTL1 |= UCSSEL_SMCK; // BRCLK = SMCLK
UCA1BR0 = 6; // 1048576/9600=109.23;109.23/16=6.83
UCA1BR1 = 0; //
UCA1MCTL = UCBRF_13 + UCOS16; //UCBRFx=0.83*16=13.28
UCA1CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCA1IE |= UCRXIE; // Enable USCI_A0 RX interrupt
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled
__no_operation(); // For debugger
}
#pragma vector=USCI_A1_VECTOR
__interrupt void USCI_A1_ISR(void)
{
switch(__even_in_range(UCA1IV,4))
{
case 0: break; // Vector 0 - no interrupt
case 2: // Vector 2 - RXIFG
while (!(UCA1IFG&UCTXIFG));
//这里,只用当UCTXIFG为1,即UCA1TXBUF空的时候,才向UCA1TXBUF中传入数据
UCA1TXBUF = UCA1RXBUF; // TX -> RXed character
break;
case 4: break; // Vector 4 - TXIFG
default: break;
}
}
结束!祝大家考个好成绩