实验名称:中断技术、基本时钟和低功耗模式(实验
5、实验6) 姓名: 学号: 实验目的
1.了解中断原理,包括对中断源、中断向量、中断类型号、中断程序以及中断响应过程的理解;
2.掌握单片机C语言中断程序设计方法;
3.了解 MSP430Gxxx 基本时钟模块的工作原理,掌握其控制方法; 4.掌握利用时钟信号和中断技术实现定时功能的方法; 5.掌握低功耗模式控制方法。 实验基本任务 实验 5中断技术: 1.中断响应过程的理解
阅读下面 C 语言中断程序 L5_int.C,说明程序执行的流程和实现功能。上机实践,回答下面问题,掌握用 C 语言编写中断程序的方法。
程序L5_int如下:
#include \"io430.h\" #include \"in430.h\" void delay( )
//延时函数 { unsigned int j; for (j=0;j
//LED闪 { P2OUT &=~BIT3; delay(); P2OUT |= BIT3; delay(); } void Buzz( )
//蜂鸣响 { unsigned int i; for (i=0;i
//设置引脚P2.4、P2.3输出,P2.3连接LED,P2.4连接蜂鸣器 P2SEL &=~(BIT3+BIT4); P2SEL2 &=~(BIT3+BIT4); P2OUT|=(BIT3+BIT4); P2DIR|=(BIT3+BIT4); //设置端口P1.5允许中断 P1SEL &= BIT5; P1SEL2 &= BIT5; P1OUT |=BIT5; P1REN |=BIT5; P1DIR &=~BIT5; P1IES |= BIT5; P1IFG &=~BIT5; P1IE |= BIT5; _EINT(); //总中断允许 for (;;) //主循环 { Blink(); }; } #pragma vector=PORT1_VECTOR __interrupt void port_ISR( ) { Buzz(); P1IFG &=~BIT5; }
1) 从程序如何判断用的是哪个中断源?其中断类型号是多少?将实验板上某一按键与该中断源对应的引脚相连,运行程序,操作按键,观察现象。
答:程序是通过判断中断标志位来确定是哪个中断源,P1.5为中断源,中断类型号是2; 现象:运行程序时P2.3控制的LED4灯不断闪烁,当P1.5控制的开关发出中断申请时即按下按键后闪烁暂停,控制P2.4连接的蜂鸣器响3声,然后继续LED4灯闪烁。
2) main函数中无调用函数 Buzz的语句函数 Buzz 如何能被执行?何时会被执行? 据此描述中断响应过程。
答: 函数Buzz是在函数名为port_ISR的中断程序中,因此当P1.5发出中断申请时即当按下按键时,函数port_ISR就会被执行,执行完毕后再返回main函数中继续执行main函数。
中断响应的过程:P1.5处发出中断请求→判断是否满足响应条件→若满足,则CPU在执行完当前指令后,硬件自动完成保护现场的操作→从中断向量表中取中断向量至PC→转去执行中断服务子程序;
3)如果 port_int 函数中不清分中断标志P1IFG的后果是什么? 答: 如果不清分中断标志P1IFG的话就会一直响应中断,然后port_ISR函数就会一直被执行,蜂鸣器不断的响。
4) 如果L5_int.c中的PORT1_VECTOR改为PORT2_VECTOR,其他不变,程序执行的后果是什么?为什么?(可在 main 函数入口处加一断点,运行程序,看现象,分析原因)
答: PORT1_VECTOR改为PORT2_VECTOR,其他不变,程序将会无法进入中断。因为程序中的中断属于P1引脚的中断,中断向量与P2引脚的中断向量不同,所进行的改动则是把中断程序写入到了P2引脚的中断向量对应的地址中,而P1引脚的中断向量对应的地址上没有程序,因此无法执行原先的中断子程。
当在主程序入口处加一断点时可以发现,由于已经设置了中断的端口,因此当有中断信号发出时,程序仍然会去执行中断子程,但由于中断向量没有正确设置,PC指针会跑飞,然后机器会自动复位,重新执行程序。
5)如果中断源采用的是P2.1,按键用 K7,请设计连线,修改 L5_int.c程序完成以中断方式响应 K7 的操作。
答:将P2.1引脚连线与K7相连,其他连线不变,连线图如下:
修改后的程序如下:
#include \"io430.h\" #include \"in430.h\" void delay( )
//延时函数 { unsigned int j; for (j=0;j
//LED闪 { P2OUT &=~BIT3; delay(); P2OUT |= BIT3; delay(); } void Buzz( )
//蜂鸣响 { unsigned int i; for (i=0;i
//设置引脚P2.4、P2.3输出,P2.3连接LED,P2.4连接蜂鸣器 P2SEL &=~(BIT3+BIT4); P2SEL2 &=~(BIT3+BIT4); P2OUT|=(BIT3+BIT4); P2DIR|=(BIT3+BIT4); //设置端口 P2.1 允许中断 P2SEL &=~ BIT1; P2SEL2 &=~ BIT1; P2OUT |=BIT1; P2REN |=BIT1; P2DIR &=~BIT1; P2IES |= BIT1; P2IFG &=~BIT1; P2IE |= BIT1; _EINT(); //总中断允许 for (;;) //主循环 { Blink(); }; } #pragma vector=PORT2_VECTOR __interrupt void port_ISR( ) { Buzz(); P2IFG &=~BIT1; }
6)(选做)分析L5_int.c 程序 1)有主循环;2)无主无限循环两种情况有何不同? 注意: 1) 查看io430G2553.h 文件末尾处有关中断向量偏址的符号定义。
2)为便于了解程序执行流程,可在中断子程入口处设置一断点,然后连续运行程序(F5),观察操作按键和不操作按键两种情况下程序执行的现象有何不同。
答:无主无限循环程序很快运行结束,无法响应中断,因此不可去掉无限循环语句。
2.中断程序编程练习
在实验板上用跳线将按键 K
3、K7 分别与单片机的 P1.1 和 P1.6 相连,编程以中断方式 响应按键 K3 和 K7 的请求:当按下一次 K3 键,实验板上的蜂鸣器发出一警报声;当按下一次 K7 键,实验板上的发光二极管 L2 闪 3 次。主循环中控制 L5 循环闪亮。
答:用跳线将按键 K
3、K7 分别与单片机的 P1.1 和 P1.6 相连,P2.1、P2.4分别连接 L2和L5,P2.3 连接蜂鸣器,接线图如下:
程序如下: #include \"io430.h\" #include \"in430.h\" void delay( ) //延时函数 { unsigned int j; for (j=0;j
//设置引脚 P2.1、P2.3、P2.4输出,P2.
1、P2.4分别连接 L2和L5,P2.3 连接蜂鸣器 P2SEL &=~(BIT1+BIT3+BIT4); P2SEL2 &=~(BIT1+BIT3+BIT4); P2OUT|=(BIT1+BIT3+BIT4); P2DIR|=(BIT1+BIT3+BIT4); //设置端口 P1.1、P1.6 允许中断K
3、K7 分别与单P1.1 和 P1.6 相连 P1SEL &=~ (BIT1+BIT6); P1SEL2 &=~ (BIT1+BIT6); P1OUT |=(BIT1+BIT6); P1REN |=(BIT1+BIT6); P1DIR &=~(BIT1+BIT6); P1IES |= (BIT1+BIT6); P1IFG &=~(BIT1+BIT6); P1IE |= (BIT1+BIT6); _EINT(); //总中断允许 for (;;) //主循环
{ L5Blink(); }; } #pragma vector=PORT1_VECTOR __interrupt void port_ISR( ) { if ((P1IFG&BIT1)!=0) {Buzz(); P1IFG &=~BIT1; }; if ((P1IFG&BIT6)!=0) { L2Blink(); P1IFG&=~BIT6;}; }
实验思考和研究:
1)如果按键K
3、K7分别连接在P2.0和 P2.4上,如何修改程序以实现任务2功能? 答: P2.1、P2.5分别连接 L2和L5,P2.3 连接蜂鸣器,P2.0、P2.4分别连接按键K
3、K7,接线图如下:
程序如下: #include \"io430.h\" #include \"in430.h\" void delay( ) //延时函数 { unsigned int j; for (j=0;j
//设置引脚 P2.1、P2.3、P2.5输出,P2.
1、P2.5分别连接 L2和L5,P2.3 连接蜂鸣器 P2SEL &=~(BIT1+BIT3+BIT5); P2SEL2 &=~(BIT1+BIT3+BIT5); P2OUT|=(BIT1+BIT3+BIT5); P2DIR|=(BIT1+BIT3+BIT5); //设置端口 P2.0、P2.4 允许中断,P2.0、P2.4分别连接按键K
3、K7 P2SEL &=~ (BIT0+BIT4); P2SEL2 &=~ (BIT0+BIT4); P2OUT |=(BIT0+BIT4); P2REN |=(BIT0+BIT4); P2DIR &=~(BIT0+BIT4); P2IES |= (BIT0+BIT4); P2IFG &=~(BIT0+BIT4); P2IE |= (BIT0+BIT4); _EINT(); //总中断允许 for (;;) //主循环
{ L5Blink(); }; } #pragma vector=PORT2_VECTOR __interrupt void port_ISR( ) { if ((P2IFG&BIT0)!=0) {Buzz(); P2IFG &=~BIT0; }; if ((P2IFG&BIT4)!=0) { L2Blink(); P2IFG&=~BIT4;}; } 2)如果按键 K
3、K7 分别连接在 P1.3 和 P2.7 上,如何修改程序以实现任务 2 功能? 答: P2.1、P2.5分别连接 L2和L5,P2.3 连接蜂鸣器,P1.
3、P2.7分别连接按键K
3、K7,接线图如下:
程序如下: #include \"io430.h\" #include \"in430.h\" void delay( ) //延时函数 { unsigned int j; for (j=0;j
//设置引脚 P2.1、P2.3、P2.4输出,P2.
1、P2.4分别连接 L2和L5,P2.3 连接蜂鸣器 P2SEL &=~(BIT1+BIT3+BIT4); P2SEL2 &=~(BIT1+BIT3+BIT4); P2OUT|=(BIT1+BIT3+BIT4); P2DIR|=(BIT1+BIT3+BIT4); //设置端口 P1.3、P2.7 允许中断分别连接按键K
3、K7 P1SEL &= BIT3; P1SEL2 &= BIT3; P1OUT |=BIT3; P1REN |=BIT3; P1DIR &=~BIT3; P1IES |= BIT3; P1IFG &=~BIT3; P1IE |= BIT3; P2SEL &=~ BIT7; P2SEL2 &=~ BIT7; P2OUT |=BIT7; P2REN |=BIT7; P2DIR &=~BIT7; P2IES |= BIT7; P2IFG &=~BIT7; P2IE |= BIT7; _EINT(); //总中断允许 for (;;) //主循环
{ L5Blink(); }; } #pragma vector=PORT1_VECTOR #pragma vector=PORT2_VECTOR __interrupt void port_ISR( ) { if ((P1IFG&BIT3)!=0) {Buzz(); P2IFG &=~BIT3; }; if ((P2IFG&BIT7)!=0) { L2Blink(); P2IFG&=~BIT1;}; }
3.采用事件标志处理中断
阅读程序 L5_intA.c 和 L5_intB.c(见后页),描述其实现功能。在实验板上将 P1.0 与 一个按键的控制端相连, P1.7 与蜂鸣器的控制端相连。 比较 L5_intA.c 和 L5_intB.c 二者在编程实现上有何不同。注意各自中断子程执行时间的长短。 用 L5_intB.c 的方法,改写任务2的编程。
答: 程序A和程序B实现的功能相同:用P1.0作为中断源,当P1.0接收到中断信号时,控制蜂鸣器响一声。不同的是程序A把控制蜂鸣器鸣叫的过程放在中断程序中,而程序B仅仅在中断程序中设置了一个事件标志,而把控制蜂鸣器鸣叫放在了while循环中,这样每当事件标志被响应时,蜂鸣器就会鸣一声。因此程序A的中断子程执行时间长于程序B。
接线图如下: P2.1、P2.4分别连接 L2和L5,P2.3 连接蜂鸣器,P1.1连K
3、P1.6连K7。
修改的程序如下: #include \"io430.h\" #include \"in430.h\" int flag=0; void delay( ) //延时函数 { unsigned int j; for (j=0;j
//设置引脚 P2.1、P2.3、P2.4输出,P2.
1、P2.4分别连接 L2和L5,P2.3 连接蜂鸣器 P2SEL &=~(BIT1+BIT3+BIT4); P2SEL2 &=~(BIT1+BIT3+BIT4); P2OUT|=(BIT1+BIT3+BIT4); P2DIR|=(BIT1+BIT3+BIT4); //设置端口 P1.1连K
3、P1.6连K7 允许中断 P1SEL &=~ (BIT1+BIT6); P1SEL2 &=~ (BIT1+BIT6); P1OUT |=(BIT1+BIT6); P1REN |=(BIT1+BIT6); P1DIR &=~(BIT1+BIT6); P1IES |= (BIT1+BIT6); P1IFG &=~(BIT1+BIT6); P1IE |= (BIT1+BIT6); _EINT(); //总中断允许 for (;;) //主循环 { L5Blink(); if (flag==1) { Buzz(); flag=0; } if (flag==2) { L2Blink(); flag=0; } } } #pragma vector=PORT1_VECTOR __interrupt void port_ISR( ) { if ((P1IFG&BIT1)!=0) {flag=1; P1IFG &=~BIT1; }; if ((P1IFG&BIT6)!=0) { flag=2; P1IFG&=~BIT6;}; }
4.(选做)按键抖动处理
程序 L5_Key.C 见后页, 其功能是用中断方式相应与 P1.2 连接的按键,计数按键的次数,并将所计的次数用8 个发光二极管显示出来。运行该程序,并操作按键,观察实际操作的次数与显示值之间的关系。编程改进L5_Key.C 程序,用软件方式去除按键抖动的影响。
说明:通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。
答:根据分析,需要在响应了第一次下降沿后,加入一定的延时,躲过其它电压毛刺的产生时间。通过实验观察可以发现,改进之前,二进制显示的数值明显大于实际按键数,而改进之后,两者数值大致相等。
具体程序如下:
#include \"io430.h\" #include \"in430.h\"
unsigned int number=0;
//记录响应按键次数
void delay( )
//延时函数
{
unsigned int j;
for (j=0; j
}
int main( void )
{
WDTCTL = WDTPW + WDTHOLD;
//关闭看门狗
__disable_interrupt(); //_DINT(); 禁止总中断
P2SEL=0;
//置P2为基本I/O功能
P2SEL2=0;
P2OUT=0xFF;
//置P2输出的初值
P2DIR=0xFF;
//置P2为输出方向
P1SEL &= BIT2; //置P1.2允许中断连K3
P1SEL2 &= BIT2;
P1OUT |=BIT2;;
P1REN |=BIT2;
P1DIR &=~BIT2;
P1IES |= BIT2;
P1IFG &=~BIT2;
P1IE |= BIT2;
__enable_interrupt(); //_EINT(); 总中断运行
while(1){ }; }
#pragma vector=PORT1_VECTOR
__interrupt void port_int(void) {
if( (P1IFG&BIT2)!=0 ) { delay(); //增加延时函数,避开毛刺
if ( (P1IFG&BIT2)!=0 )
{
number++;
P2OUT=~number;
}
P1IFG &=~BIT2; } }
实验6 基本时钟和低功耗模式: 1.数字示波器的使用
1) 将信号源的波形在示波器上显示出来,掌握测量周期、频率、峰峰值的方法;
答:用示波器测得信号源的周期T=20us、频率f=1.000KHZ、峰峰值V=3.18V。 2) 用孔孔导线将实验板的地信号与示波器的地信号相连,测量实验板上的 Vcc 电源信号是否正常。
答: 测得实验板上Vcc信号正常,Vccmax=3.76V,Vccmin=3.52V,Vccavg=3.66V。 2.测试上电复位系统的 ACLK、和 SMCLK 时钟频率
编程输出单片机上电复位后的 ACLK、和 SMCLK 时钟,用示波器测量其频率,并记录下来。
答:本程序需要置引脚P1.0、P1.4分别输出ACLK、SMCLK,需要确认外部晶振连上,输出的ACLK频率为F(ACLK)=32.7KHZ,SMCLK的频率为F(SMCLK)=1.031MHZ。
程序如下:
#include \"io430.h\" int main( void ) { //关闭看门狗
WDTCTL = WDTPW + WDTHOLD; //设置P2.6、P2.7连接外部晶振 P2SEL|=(BIT6+BIT7); P2SEL2&=~(BIT6+BIT7); P2DIR&=~BIT6; P2DIR|=BIT7; //设置P1.0、P1.4输出ACLK、SMCLK P1SEL|=BIT0; P1SEL2&=~BIT0; P1DIR|=BIT0; P1SEL|=BIT4; P1SEL2&=~BIT4; P1DIR|=BIT4; while(1); }
实验思考和研究
思考:1)上电复位后,CPU 工作的时钟信号 MCLK 频率值是多少?
答:上电复位后,通过查看基本时钟模块相关寄存器,发现BCSCTL2寄存器上SELM位为00,SELS位为则0,可知MCLK的时钟源为DCO,SMCLK的时钟源也为DCO,因此通过测量上面复位后的SMCLK频率可知MCLK的频率,由上述可知F(MCLK)=1.031MHZ。
2) 实验板上 JP8 中间的两个插针接到 32.768KHz 侧和接到 P2.6/P2.7 侧结果有何不同? 为什么?
答:是由32.768KHZ低频振荡器控制的,因此比较精确,示波器测量的精确值和理论值相差不大,接到 P2.6/P2.7 侧是由片内低功耗低频振荡器控制的,受环境温度和工作电压影响较大,因此测量值和理论值相差较大。 3.掌握基本时钟模块的编程控制
参看附录 A 实验板原理图,用跳线将 JP8 中的插针信号接到晶振 32.768Khz 侧,使晶振 与单片机的 P2.6 和 P2.7 相连。编程控制基本时钟模块,设置 ACLK 分别为下面时钟频率,并通过 P1.0 输出 ACLK,用示波器观察:
1) ACLK=8192Hz;(时钟源外部晶振四分频,即 32768Hz/4)
答:P2.6、P2.7连接外部晶振引脚,通过 P1.0 输出 ACLK,观察的F(ACLK)=8.1kHZ。
具体程序代码如下:
#include \"io430.h\" int main( void ) { // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD; P1SEL|=BIT0; //设置P1.0输出ACLK P1SEL2&=~BIT0; P1DIR|=BIT0; P2SEL|=BIT6; //设置P2.6、P2.7连接外部晶振引脚 P2SEL2&=~BIT6; P2DIR&=~BIT6; //P2.6 XIN输入 P2SEL|=BIT7; P2SEL2&=~BIT7; P2DIR|=BIT7; //P2.7 XOU输出
BCSCTL1|=DIVA_2; //设置ACLK为4分频 while(1); }
2) ACLK=1.5KHz;(时钟源 VLOCLK 八分频,即 12KHz/8) 答:通过 P1.0 输出 ACLK,观察的F(ACLK)=1.2KHZ。
具体程序代码如下:
#include \"io430.h\" int main( void ) { // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD; P1SEL|=BIT0; //设置P1.0输出ACLK P1SEL2&=~BIT0; P1DIR|=BIT0; BCSCTL1|=DIVA_3; //设置ACLK时钟源为VLOCLK,并为8分频 BCSCTL3|=LFXT1S_2; while(1); }
实验思考和研究
思考:可否编程在引脚 P2.4 上输出 ACLK? 为什么?
答:不可以,因为根据说明指导书MSP430G2553的辅助时钟ACLK是由P1.0输出的,内部硬件电路设计结构决定了不能用P2.4输出ACLK。
4.DCO 出厂校验值的频率检测
1) 利用出厂校验值,编程使DCO 分别为1MHz、8MHz、12MHz、16MHz,通过P1.4输出,用示波器测量实际值。
答: 出厂校验值为1MHZ时,F实际=0.991MHZ。出厂校验值为8MHZ时,F实际=8.157MHZ。出厂校验值为12MHZ时,F实际=12.03MHZ。出厂校验值为16MHZ时,F实际=16.17MHZ。
以上测试数据说明:DCOCLK是由片内数字可控RC振荡器控制的,受环境温度和工作电压的影响较大,因此出厂校验值和实际测量值也存在不小的误差。
具体程序代码如下:
#include \"io430.h\" int main( void ) { // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD; //关闭看门狗
P1SEL|=BIT4; //设置P1.4输出SMCLK P1SEL2&=~BIT4; P1DIR|=BIT4; BCSCTL1=CALBC1_1MHZ; //利用出厂校验值设置DCO的振荡频率为1MHZ, //其他情况改变1MHz就可以了 DCOCTL=CALDCO_1MHZ; while(1); }
2)(选做)控制发光二级管通过延时闪亮,分别编程使主系统时钟工作在(1) MCLK=复位频率/8 约100KHz;(2) MCLK=DCO=16MHz 两种不同MCLK 频率下,观察灯的亮灭速度有何不同,掌握主系统时钟的变化对程序执行速度的影响。
答: 经实验观察可知,MCLK设置为100KHZ时LED1灯的闪烁频率比设置为16MHZ慢了非常多,由此可知主系统时钟是主要提供给CPU工作的时钟,MCLK频率越高,CPU工作速度越快。
MCLK=复位频率/8具体程序代码如下:
#include \"io430.h\" void delay( ) //延时函数 { unsigned int j; for (j=0;j
MCLK=DCO=16MHz具体程序代码如下:
#include \"io430.h\" void delay( ) //延时函数 { unsigned int j; for (j=0;j
5.低功耗模式学习
程序 L6_LPM.c 见下,用跳线将P2.3 与L4 短接,将P2.4 用长杜邦线与buzz 短接,P1.1与K2 短接,并用示波器分别观察P1.0、P1.4 输出的ACLK 和SMCLK,了解低功耗模式的进入和退出。
程序L6_LPM.c 清单(提供电子版): #include \"io430.h\" #include \"in430.h\" void delay( ) //延时函数 { unsigned int j; for (j=0;j
//设置端口P2.3输出,连接L4,控制LED,P2.4输出,控制蜂鸣器 P2SEL &=~(BIT3+BIT4); P2SEL2&=~(BIT3+BIT4); P2OUT |= BIT3+BIT4; P2DIR |= BIT3+BIT4; //设置端口P1.1允许中断 P1.1连接K2 P1SEL &=~BIT1; P1SEL2 &=~BIT1; P1REN |=BIT1; P1OUT |=BIT1; P1DIR &=~BIT1; P1IES |=BIT1; P1IFG &=~BIT1; P1IE |=BIT1; _EINT(); //P1.0输出时钟ACLK, P1.4输出时钟SMCLK P1SEL |=BIT0+BIT4; P1SEL2 &=~(BIT0+BIT4); P1DIR |=BIT0+BIT4; Blink(); Buzz(); for (;;) //主循环 { LPM4; //进入低功耗模式 Blink(); } } #pragma vector=PORT1_VECTOR __interrupt void port_ISR( ) { Buzz(); P1IFG&=~(BIT1); //清中断标志 LPM4_EXIT; }
1) 运行程序,观察现象,并记录进入低功耗前、进入低功耗后、响应中断后、退出中断后的时钟、发光二极管和蜂鸣器状态,并做分析。
答:程序开始运行时,P2.3控制的LED4先闪烁,然后蜂鸣器鸣叫,接着进入低功耗模式,实验板无现象产生,若此时按下K2键向P1.1发出中断信号后蜂鸣器开始鸣叫,接着LED4又开始闪烁,然后进入低功耗模式,实验板无现象产生。
进入低功耗LPM4前F(ACLK)=32.89KHZ,F(SMCLK)=1.033MHZ,进入后F(ACLK)=0,F(SMCLK)=0,响应中断后F(ACLK)=32.89KHZ,F(SMCLK)=1.033MHZ,退出中断后刚开始F(ACLK)= 32.89KHZ,F(SMCLK)=1.033MHZ,退出中断LED灯闪烁后F(ACLK)=0,F(SMCLK)=0。
分析:程序顺着流程执行,先是LED闪烁,然后蜂鸣器响,接着进入循环,然后进入低功耗模式LPM4,此时PC指针停止不动,程序停止执行。若此时按下K2键发出中断,则程序会立刻停止低功耗模式,将当前状态储存入堆栈中,然后跳转执行中断子程,蜂鸣器响,退出低功耗模式,然后程序返回断点,返回到主函数中执行Blink()后再次进入低功耗模式。 2) 如果程序中没有 LPM4_EXIT 语句,运行的结果会有什么不同?请分析。
答:如果程序中没有LPM4_EXIT,则不同之处在于按下K2发出中断信号后只有蜂鸣器鸣叫然后进入低功耗模式,而LED4不会闪烁。
分析:程序在主函数中进入低功耗模式后停止执行,若此时按下K2键发出中断,则程序会立刻停止低功耗模式,将当前状态储存入堆栈中,然后跳转执行中断子程,蜂鸣器响,与1不同的是,中断子程中没有退出LPM4语句,因此程序在执行完中断后立刻返回中断之前的低功耗状态,而不会跳转返回到主函数中执行Blink(),因此LED灯不会闪烁。 3) (选做) 将 LPM4 改为LPM0,LPM4_EXIT 改为LPM0_EXIT,重新完成任务1。
答:程序开始运行时,P2.3控制的LED4先闪烁,然后蜂鸣器鸣叫,接着进入低功耗模式,实验板无现象产生,若此时按下K2键向P1.1发出中断信号后蜂鸣器开始鸣叫,接着LED4又开始闪烁,然后进入低功耗模式,实验板无现象产生。
进入低功耗LPM0前F(ACLK)=32.89KHZ,F(SMCLK)=1.033MHZ,进入后F(ACLK)=32.89KHZ,F(SMCLK)=1.033MHZ,响应中断后F(ACLK)=32.89KHZ,F(SMCLK)=1.033MHZ,退出中断后刚开始F(ACLK)=32.89KHZ,F(SMCLK)=1.033MHZ,退出中断LED灯闪烁后F(ACLK)=32.89KHZ,F(SMCLK)=1.033MHZ。
分析:程序顺着流程执行,先是LED闪烁,然后蜂鸣器响,接着进入循环,然后进入低功耗模式LPM4,此时PC指针停止不动,程序停止执行。若此时按下K2键发出中断,则程序会立刻停止低功耗模式,将当前状态储存入堆栈中,然后跳转执行中断子程,蜂鸣器响,退出低功耗模式,然后程序返回断点,返回到主函数中执行Blink()后再次进入低功耗模式。
原因分析:在低功耗LPM4模式下,CPU、MCLK、SMCLK、ACLK均被禁止,因此进入低功耗LPM4模式后P1.0和P1.4均不输出信号;而在低功耗LPM0模式下,CPU、MCLK被禁止,而SMCLK和ACLK均在活动,因此进入低功耗模式前后P1.0和P1.4输出的信号不变。虽然表面实验现象和LPM4一样,但是用示波器测得的引脚输出信号不一样。 6.利用输出的时钟信号做中断源,实现定时功能
将任务 3 中P1.0 输出的1.5KHz ACLK 时钟信号,作为P1.6 的中断申请信号,用导线将P1.6 与P1.0 相连即可,在中断子程中设置一个计数变量,计数中断子程被执行的次数,中断子程每被执行1500 次表示一秒时间到。利用该定时功能,将8个发光二级管设计成一个秒表,显示秒值,每秒改变一次8 个发光二级管的显示。
答:将P2.0~P2.7与LED1~LED8连接起来,通过设置基本时钟控制寄存器将ACLK的时钟源选为12KHz的VLOCK,然后再设置ACLK为8分频,这样就可以使P1.0输出1.5KHz的ACLK信号。将P1.6与P1.0再连接起来,将P1.6设置为允许中断,在中断程序中加入计数因子,每隔1500次计数则可以视为1s,这时令8个LED灯变化一次。即可实现要求功能。
具体程序代码1如下: #include \"io430.h\" #include \"in430.h\" unsigned char time=0; unsigned int i=0; int main( void ) { WDTCTL = WDTPW + WDTHOLD; //关闭看门狗 //设置端口P1.0输出1.5KHzACLK时钟信号 P1SEL|=BIT0; P1SEL2&=~BIT0; P1DIR|=BIT0; BCSCTL3&=~LFXT1S0; BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO 低频时钟选择为VLO ACLK选为VLO __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 //设置P2.0~P2.7为输出状态 与LED连接分别接L1~L7 P2SEL&=0; P2SEL2&=0; P2DIR|=0Xff; P2OUT|=0Xff; //设置端口P1.6允许中断 将P1.6与P1.0连接 P1SEL&=~BIT6; P1SEL2&=~BIT6; P1REN|=BIT6; P1OUT&=~BIT6; P1DIR&=~BIT6; P1IES&=~BIT6; P1IFG&=~BIT6; P1IE|=BIT6; _EINT(); while(1) { if (i>=1500) { time+=1; i=0; } P2OUT=~time; //LED灯显示输出秒表的值 } } #pragma vector=PORT1_VECTOR __interrupt void port_ISR() { i++; P1IFG&=~(BIT6); //清中断标志 }
或者具体程序代码2如下:
#include \"io430.h\" #include \"in430.h\" unsigned char time=0; unsigned int i=0; int main( void ) { //关闭看门狗
WDTCTL = WDTPW + WDTHOLD; //设置端口P1.0输出1.5KHzACLK时钟信号 P1SEL|=BIT0; P1SEL2&=~BIT0; P1DIR|=BIT0; BCSCTL3&=~LFXT1S0; BCSCTL3|=LFXT1S1; BCSCTL1&=~DIVA1; BCSCTL1|=DIVA0; //设置P2.0~P2.7为输出状态 P2SEL&=0; P2SEL2&=0; P2DIR|=0Xff; P2OUT|=0Xff; //设置端口P1.6允许中断 P1SEL&=~BIT6; P1SEL2&=~BIT6; P1REN|=BIT6; P1OUT&=~BIT6; P1DIR&=~BIT6; P1IES&=~BIT6; P1IFG&=~BIT6; P1IE|=BIT6; _EINT(); while(1){ if (i>=1500) { time+=1; i=0;} P2OUT=~time; //LED灯显示输出秒表的值 } } #pragma vector=PORT1_VECTOR __interrupt void port_ISR(){ i++; P1IFG&=~(BIT6); //清中断标志 }
(选做) 如果要每隔5 秒蜂鸣器响一声,如何在任务6 的基础上编程实现? 答:将P1.7与蜂鸣器相连,然后在中断程序在加入一个计时因子来控制蜂鸣器。
具体代码如下: #include \"io430.h\" #include \"in430.h\" unsigned char time=0; unsigned int i=0; void delay(); int main( void ) {
WDTCTL = WDTPW + WDTHOLD; //关闭看门狗
//设置端口P1.0输出1.5KHzACLK时钟信号 P1SEL|=BIT0; P1SEL2&=~BIT0; P1DIR|=BIT0; BCSCTL3&=~LFXT1S0; // LFXT1 = VLO 低频时钟选择为VLO ACLK选为VLO BCSCTL3 |= LFXT1S_2; BCSCTL1&=~DIVA1; BCSCTL1|=DIVA0; //设置P2.0~P2.7为输出状态 P2SEL&=~0; P2SEL2&=~0; P2DIR|=0Xff; P2OUT|=0Xff;
//设置P1.7为输出状态
P1SEL&=~BIT7; P1SEL2&=~BIT7; P1OUT|=BIT7; P1DIR|=BIT7;
//设置端口P1.6允许中断
P1SEL&=~BIT6;
P1SEL2&=~BIT6;
P1REN|=BIT6;
P1OUT&=~BIT6;
P1DIR&=~BIT6;
P1IES&=~BIT6;
P1IFG&=~BIT6;
P1IE|=BIT6; _EINT();
while(1) {
if (i>=1500) {
time+=1;
if((time%5)==0)
P1OUT&=~BIT7;
delay();
P1OUT|=BIT7;
i=0; }
P2OUT=~time; //LED灯显示输出秒表的值
} }
void delay() //延时函数
{
unsigned int j;
for (j=0;j
}
#pragma vector=PORT1_VECTOR
__interrupt void port_ISR() {
i++; P1IFG&=~(BIT6); //清中断标志
}
7.(选做)改用4 个数码管显示秒值,重新完成任务6。
(选做)改用4 个数码管显示秒值无蜂鸣器
答:将P2.0~P2.7依次与Sa ~Sh相连, P1.1~P1.4与S1~S4相连,P1.6与P1.0连接, P1.6设置允许中断,P2.6.0连P2.6,P2.7.0连P2.7。
具体代码如下: #include \"io430.h\" #include \"in430.h\" void delay(); unsigned char time=0; unsigned int i=0; const char LEDtab[10]={~0x3F,~0x06,~0x5B,~0x4F,~0x66,~0x6D,~0x7D,~0x07,~0x7F,~0x6F}; unsigned char a=0,b=0,c=0,d=0; unsigned char flag=0; int main( void ) { //关闭看门狗
WDTCTL = WDTPW + WDTHOLD; //设置端口P1.0输出1.5KHzACLK时钟信号 P1SEL|=BIT0; P1SEL2&=~BIT0; P1DIR|=BIT0; BCSCTL3&=~LFXT1S1; BCSCTL3|=LFXT1S1; BCSCTL1&=~DIVA1; BCSCTL1|=DIVA0;
//设置P2.0~P2.7为输出状态 P2SEL=0; P2SEL2=0; P2DIR=0XFF; P2OUT=0XFF;
//设置P1.1~P1.4为输出状态; P1SEL&=~(BIT1+BIT2+BIT3+BIT4); P1SEL2&=~(BIT1+BIT2+BIT3+BIT4); P1DIR|=BIT1+BIT2+BIT3+BIT4; P1OUT&=~(BIT1+BIT2+BIT3+BIT4); //设置端口P1.6允许中断 P1SEL&=~BIT6; P1SEL2&=~BIT6; P1REN|=BIT6; P1OUT&=~BIT6; P1DIR&=~BIT6; P1IES&=~BIT6; P1IFG&=~BIT6; P1IE|=BIT6; _EINT(); while(1) { if (i>1500) { time+=1; i=0; } time=time%5000; d=time/500; c=(time%500)/50; b=(time%50)/5; a=time%5; if (a==0) { delay(); } } } void delay() //延时函数 { unsigned int j; for (j=0;j
__interrupt void port_ISR() { i++;
//显示输出数码管 if (flag==0)
{P2OUT=LEDtab[a]; P1OUT&=~(BIT1+BIT2+BIT3+BIT4); P1OUT|=BIT1; flag=1;} else if (flag==1)
{P2OUT=LEDtab[b]; P1OUT&=~(BIT1+BIT2+BIT3+BIT4); P1OUT|=BIT2; flag=2;} else if (flag==2)
{P2OUT=LEDtab[c]; P1OUT&=~(BIT1+BIT2+BIT3+BIT4); P1OUT|=BIT3; flag=3;} else if (flag==3)
{P2OUT=LEDtab[d]; P1OUT&=~(BIT1+BIT2+BIT3+BIT4); P1OUT|=BIT4; flag=0;} P1IFG&=~(BIT6);
//清中断标志 }
(选做)改用4 个数码管显示秒值蜂鸣器响一声
答:将P2.0~P2.7依次与Sa ~Sh相连, P1.1~P1.4与S1~S4相连,P1.6与P1.0连接, P1.6设置允许中断,P2.6.0连P2.6,P2.7.0连P2.7, P1.7与BUZZ相连增加蜂鸣器延时程序。
具体代码如下: #include \"io430.h\" #include \"in430.h\" void delay(); unsigned char time=0; unsigned int i=0; const char LEDtab[10]={~0x3F,~0x06,~0x5B,~0x4F,~0x66,~0x6D,~0x7D,~0x07,~0x7F,~0x6F}; unsigned char a=0,b=0,c=0,d=0; unsigned char flag=0; int main( void ) { //关闭看门狗
WDTCTL = WDTPW + WDTHOLD; //设置端口P1.0输出1.5KHzACLK时钟信号 P1SEL|=BIT0; P1SEL2&=~BIT0; P1DIR|=BIT0; BCSCTL3&=~LFXT1S1; BCSCTL3|=LFXT1S1; BCSCTL1&=~DIVA1; BCSCTL1|=DIVA0;
//设置P2.0~P2.7为输出状态 P2SEL=0; P2SEL2=0; P2DIR=0XFF; P2OUT=0XFF;
//设置P1.1~P1.4、P1.7为输出状态; P1SEL&=~(BIT1+BIT2+BIT3+BIT4+BIT7); P1SEL2&=~(BIT1+BIT2+BIT3+BIT4+BIT7); P1DIR|=BIT1+BIT2+BIT3+BIT4+BIT7; P1OUT|=BIT7; P1OUT&=~(BIT1+BIT2+BIT3+BIT4); //设置端口P1.6允许中断 P1SEL&=~BIT6; P1SEL2&=~BIT6; P1REN|=BIT6; P1OUT&=~BIT6; P1DIR&=~BIT6; P1IES&=~BIT6; P1IFG&=~BIT6; P1IE|=BIT6; _EINT();
while(1) { if (i>1500) { time+=1; i=0; } time=time%5000; d=time/500; c=(time%500)/50; b=(time%50)/5; a=time%5; if (a==0) { P1OUT&=~BIT7; //蜂鸣器响 delay();
P1OUT|=BIT7; } } } void delay() //延时函数 { unsigned int j; for (j=0;j
__interrupt void port_ISR() { i++; //显示输出数码管 if (flag==0)
{P2OUT=LEDtab[a]; P1OUT&=~(BIT1+BIT2+BIT3+BIT4); P1OUT|=BIT1; flag=1; } else if (flag==1)
{P2OUT=LEDtab[b]; P1OUT&=~(BIT1+BIT2+BIT3+BIT4); P1OUT|=BIT2; flag=2;} else if (flag==2)
{P2OUT=LEDtab[c]; P1OUT&=~(BIT1+BIT2+BIT3+BIT4); P1OUT|=BIT3; flag=3;} else if (flag==3)
{P2OUT=LEDtab[d]; P1OUT&=~(BIT1+BIT2+BIT3+BIT4); P1OUT|=BIT4; flag=0;} P1IFG&=~(BIT6);
//清中断标志 }
实验思考和研究
总体来说,觉得实验
5、6内容很多,学到了很多知识;实验过程中遇到了很多问题重温了课本和课件后解决了一些难题,加深了对课本上抽象的内容的理解,比如说实验前对于时钟,我的理解一直很模糊,似是而非,经过实验,发现其实它不过是三个寄存器,三个时钟信号,四个时钟源之间的问题,虽然过程比较繁琐,脉络却是清晰的;而且关于中断,我也有了进一步的理解,特别是最后几个选作实验和必做实验是对这两节知识的综合应用,难度有点大,但是写出来之后特别是程序问题解决达到实验效果后还是很有成就感的。