计硬基础实验报告3
实验名称:
中断技术 、 基本时钟和低功耗模式 (实验 5 5 、实验 6 6 )
姓名:
学号:
实验班号:
机器号:D D- - 100
实验目的
1. 了解中断原理,包括对中断源、中断向量、中断类型号、中断程序以及中断响应过程的理解; 2. 掌握单片机 C 语言中断程序设计方法。
3. 了解 MSP430Gxxx 基本时钟模块的工作原理,掌握其控制方法; 4. 掌握利用时钟信号和中断技术实现定时功能的方法; 5.掌握低功耗模式控制方法。
实验 基本 任务
实验 5 中断技术 :
1. 中断响应过程的理解
阅读下面 C 语言中断程序L5_int.C(见后页),说明程序执行的流程和实现功能。上机实践,回答下面问题,掌握用C 语言编写中断程序的方法。
注意: 1) 查看io430G2553.h 文件末尾处有关中断向量偏址的符号定义。
2)为便于了解程序执行流程,可在中断函数入口处设置一断点,然后连续运行程序(F5),观察操作按键和不操作按键两种情况下程序执行的现象有何不同。
程序见 Lab_5 项目,程序 L5_int.C 如下:
#include "io430.h" #include "in430.h"
void delay( )
//延时函数 {
unsigned int j;
for (j=0;j<0xffff;j++);
}
void Blink( )
//LED闪 {
P2OUT &=~BIT3;
delay();
P2OUT |= BIT3;
delay();
}
void Buzz( )
//蜂鸣响 { unsigned int i;
for (i=0;i<3;i++)
{
P2OUT &=~BIT4;
delay();
P2OUT|= BIT4;
delay();
}; }
void main ( void ) {
WDTCTL = WDTPW + WDTHOLD;
//关闭看门狗
//设置引脚P2.4、P2.3输出,P2.3连接LED,P2.4连接蜂鸣器
P2SEL &=~(BIT3+BIT4);
P2SEL2 &=~(BIT3+BIT4);
P2OUT|=(BIT3+BIT4);
P2DIR|=(BIT3+BIT4);
//中断相关设置即设置端口P1.3允许中断
P1SEL &= ~BIT3;
P1SEL2 &= ~BIT3;
P1OUT |=BIT3;
P1REN |=BIT3;
P1DIR &=~BIT3;
P1IES |= BIT3;
P1IFG &=~BIT3;
P1IE |= BIT3;
_EINT();
//总中断允许
for (;;)
//主循环
{
Blink();
};
}
#pragma
vector=PORT1_VECTOR
__interrupt
void port_ISR( ) {
Buzz();
P1IFG &=~BIT3;
}
1) 从程序如何判断用的是哪个中断源?中断类型号是多少?将实验板上某一按键与该中断源对应的引脚相连,运行程序,操作按键,观察现象。
答:程序是通过判断中断标志位来确定是哪个中断源,P1.3 为中断源,中断类型号是 2; 现象:运行程序时P2.3控制的LED4灯不断闪烁,当P1.3控制的开关发出中断申请时即按下按键K4后闪烁暂停,控制P2.4连接的蜂鸣器响3声,然后继续LED4灯闪烁。
2)main 函数中无调用函数port_ISR 的语句,函数port_ISR 如何能被执行?何时会被执行? 据此描述中断响应过程。
答:当 P1.3 发出中断申请时即当按下按键时,函数 port_ISR 就会被执行,执行完毕后再返回 main 函数中继续执行 main 函数。
中断响应的过程:P1.3处发出中断请求→判断是否满足响应条件→若满足,则CPU在执行完当前指令后,硬件自动完成保护现场的操作→从中断向量表中取中断向量至PC→转去执行中断服务子程序; 3) 如果函数port_ISR 中不清分中断标志P1IFG 的后果是什么?
答:如果不清分中断标志P1IFG的话就会一直响应中断,然后port_ISR函数就会一直被执行,蜂鸣器不断的响。
4) 如果L5_int.c 中的PORT1_VECTOR 改为PORT2_VECTOR, 其他不变,程序执行的后果是什么?为什么?(可在main 函数入口处加一断点,运行程序,看现象,分析原因)
答:PORT1_VECTOR 改为 PORT2_VECTOR,其他不变,程序将会无法进入中断。因为程序中的中断属于 P1 引脚的中断,中断向量与 P2 引脚的中断向量不同,所进行的改动则是把中断程序写入到了 P2 引脚的中断向量对应的地址中,而 P1 引脚的中断向量对应的地址上没有程序,因此无法执行原先的中断子程。
当在主程序入口处加一断点时可以发现,由于已经设置了中断的端口,因此当有中断信号发出时,程序仍然会去执行中断子程,但由于中断向量没有正确设置,PC指针会跑飞,然后机器会自动复位,重新执行程序。
5)如果中断源采用的是P2.5, 按键用K6,请设计连线,修改L5_int.c 程序完成以中断方式响 应K6 的操作。
答:将 P2.5 引脚连线与 K6 相连,其他连线不变,连线图如下:
修改后见 程序见 Lab_5 项目,程序 L5_int-1.c 如下:
#include "io430.h" #include "in430.h" void delay( )
//延时函数 {
unsigned int j;
for (j=0;j<0xffff;j++); } void Blink( )
//LED 闪 {
P2OUT &=~BIT3;
delay();
P2OUT |= BIT3;
delay();
} void Buzz( )
//蜂鸣响 { unsigned int i;
for (i=0;i<3;i++)
{
P2OUT &=~BIT4;
delay();
P2OUT|= BIT4;
delay();
}; } void main ( void ) {
WDTCTL = WDTPW + WDTHOLD;
//关闭看门狗 //设置引脚 P2.4、P2.3 输出,P2.3 连接 LED,P2.4 连接蜂鸣器
P2SEL &=~(BIT3+BIT4);
P2SEL2 &=~(BIT3+BIT4);
P2OUT|=(BIT3+BIT4);
P2DIR|=(BIT3+BIT4);
//设置端口 P2.5 允许中断
P2SEL &=~ BIT5;
P2SEL2 &=~ BIT5;
P2OUT |=BIT5;
P2REN |=BIT5;
P2DIR &=~BIT5;
P2IES |= BIT5;
P2IFG &=~BIT5;
P2IE |= BIT5;
_EINT();
//总中断允许
for (;;)
//主循环
{
Blink();
};
} #pragma
vector=PORT2_VECTOR
__interrupt
void port_ISR( ) {
Buzz();
P2IFG &=~BIT5;
}
2. 中断程序编程练习
在实验板上用跳线将按键 K2、K7 分别与单片机的P1.2 和P1.7 相连,编程以中断方式响应按键K2 和K7 的请求:当按下一次K2 键,实验板上的蜂鸣器发出一警报声;当按下一次K7 键,实验板上的发光二极管L2 闪2 次。主循环中控制L5 循环闪亮。
:
答:用跳线将按键 K2、K7 分别与单片机的 P1.2 和 P1.7 相连,P2.1、P2.4 分别连接 L2和 L5,P2.3 连接蜂鸣器, 接线图如下: :
修改后见 程序见 Lab_5 项目,程序 L5_int-2.c 如下:
#include "io430.h"
#include "in430.h"
void delay( )
//延时函数
{
unsigned int j;
for (j=0;j<0xffff;j++);
}
void L2Blink( )
//L2 闪 2 次
{ unsigned int i;
for (i=0;i<2;i++)
{
P2OUT &=~BIT1;
delay();
P2OUT|= BIT1;
delay();
};
}
void L5Blink( )
//L5 闪
{
P2OUT &=~BIT4;
delay();
P2OUT |= BIT4;
delay();
}
void Buzz( )
//蜂鸣响
{ P2OUT &=~BIT3;
delay();
P2OUT|= BIT3;
delay();
}
void main ( void )
{
WDTCTL = WDTPW + WDTHOLD;
//关闭看门狗
//设置引脚 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.2、P1.7 允许中断 K2、K7 分别与单 P1.2 和 P1.7 相连
P1SEL &=~ (BIT2+BIT7);
P1SEL2 &=~ (BIT2+BIT7);
P1OUT |=(BIT2+BIT7);
P1REN |=(BIT2+BIT7);
P1DIR &=~(BIT2+BIT7);
P1IES |= (BIT2+BIT7);
P1IFG &=~(BIT2+BIT7);
P1IE |= (BIT2+BIT7);
_EINT();
//总中断允许
for (;;)
//主循环
{
L5Blink();
};
}
#pragma
vector=PORT1_VECTOR
__interrupt
void
port_ISR( )
{
if ((P1IFG&BIT2)!=0)
{Buzz();
P1IFG &=~BIT2; }; if ((P1IFG&BIT7)!=0) { L2Blink(); P1IFG&=~BIT7;};
}
思考:
1) 如果按键 K2、K7 分别连接在P2.1 和P2.6 上,如何修改程序以实现任务2 功能? 答: :
P2.0、P2.4 分别连接 L2 和 L5,P2.3 连接蜂鸣器,P2.1、P2.6 分别连接按键 K2、K7,接线图如下:
修改后见 程序见 Lab_5 项目,程序 L5_int-3.c 如下:
#include "io430.h"
#include "in430.h"
void delay( )
//延时函数
{
unsigned int j;
for (j=0;j<0xffff;j++);
}
void L2Blink( )
//L2 闪 2 次
{ unsigned int i;
for (i=0;i<2;i++)
{
P2OUT &=~BIT0;
delay();
P2OUT|= BIT0;
delay();
};
}
void L5Blink( )
//L5 闪
{
P2OUT &=~BIT4;
delay();
P2OUT |= BIT4;
delay();
}
void Buzz( )
//蜂鸣响
{ P2OUT &=~BIT3;
delay();
P2OUT|= BIT3;
delay();
}
void main ( void )
{
WDTCTL = WDTPW + WDTHOLD;
//关闭看门狗
//设置引脚 P2.0、P2.3 、P2.4 输出,P2.0、P2.4 分别连接 L2 和 L5,P2.3 连接蜂鸣器
P2SEL &=~(BIT0+BIT3+BIT4);
P2SEL2 &=~(BIT0+BIT3+BIT4);
P2OUT|=(BIT0+BIT3+BIT4);
P2DIR|=(BIT0+BIT3+BIT4);
//设置端口 P2.1、P2.6 允许中断,P2.1、P2.6 分别连接按键 K2、K7
P2SEL &=~ (BIT1+BIT6);
P2SEL2 &=~ (BIT1+BIT6);
P2OUT |=(BIT1+BIT6);
P2REN |=(BIT1+BIT6);
P2DIR &=~(BIT1+BIT6);
P2IES |= (BIT1+BIT6);
P2IFG &=~(BIT1+BIT6);
P2IE |= (BIT1+BIT6);
_EINT();
//总中断允许
for (;;)
//主循环
{
L5Blink();
};
}
#pragma
vector=PORT2_VECTOR
__interrupt
void
port_ISR( )
{
if ((P2IFG&BIT1)!=0)
{Buzz();
P2IFG &=~BIT1; }; if ((P2IFG&BIT6)!=0) { L2Blink(); P2IFG&=~BIT6;};
}
2) 如果按键 K2、K7 分别连接在 P1.0 和 P2.4 上,如何修改程序以实现任务 2 功能?
答: :
P2.1、P2.5 分别连接 L2 和 L5,P2.3 连接蜂鸣器,P1.0、P2.4 分别连接按键 K2、K7,接线图如下:
修改后见 程序见 Lab_5 项目,程序 L5_int-4.c 如下:
#include "io430.h"
#include "in430.h"
void delay( )
//延时函数
{
unsigned int j;
for (j=0;j<0xffff;j++);
}
void L2Blink( )
//L2 闪 2 次
{ unsigned int i;
for (i=0;i<2;i++)
{
P2OUT &=~BIT1;
delay();
P2OUT|= BIT1;
delay();
};
}
void L5Blink( )
//L5 闪
{
P2OUT &=~BIT5;
delay();
P2OUT |= BIT5;
delay();
}
void Buzz( )
//蜂鸣响
{ P2OUT &=~BIT3;
delay();
P2OUT|= BIT3;
delay();
}
void main ( void )
{
WDTCTL = WDTPW + WDTHOLD;
//关闭看门狗
//设置引脚 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);
//设置端口 P1.0、P2.4 允许中断,P1.0、P2.4 分别连接按键 K2、K7
P1SEL &=~ BIT0;
P1SEL2 &=~ BIT0;
P1OUT |=BIT0;
P1REN |=BIT0;
P1DIR &=~BIT0;
P1IES |= BIT0;
P1IFG &=~BIT0;
P1IE |= BIT0;
P2SEL &=~ BIT4;
P2SEL2 &=~ BIT4;
P2OUT |=BIT4;
P2REN |=BIT4;
P2DIR &=~BIT4;
P2IES |= BIT4;
P2IFG &=~BIT4;
P2IE |= BIT4;
_EINT();
//总中断允许
for (;;)
//主循环
{
L5Blink();
};
}
#pragma
vector=PORT1_VECTOR #pragma
vector=PORT2_VECTOR __interrupt
void
port_ISR( )
{
if ((P1IFG&BIT0)!=0)
{Buzz();
P2IFG &=~BIT3; }; if ((P2IFG&BIT4)!=0) { L2Blink(); P2IFG&=~BIT4;};
}
3. 采用事件标志处理中断
阅读程序 L5_intA.c 和L5_intB.c(见后页),描述其实现功能。在实验板上将P1.4 与一个按键的控制端相连, P1.6 与蜂鸣器的控制端相连。
比较L5_intA.c 和L5_intB.c 二者在编程实现上有何不同。注意各自中断函数执行时间的长短。
用L5_intB.c 的方法,改写任务2 的编程。
答:
程序见Lab_5 项目下程序L5_intA.c与 程序见Lab_5 项目下程序L5_intB.c在实验板上进行比较情况如下:
程序A和程序B实现的功能相同:用P1.4作为中断源,当P1.4接收到中断信号时,控制蜂鸣器响一声。不同的是程序A把控制蜂鸣器鸣叫的过程放在中断程序中,而程序B仅仅在中断程序中设置了一个事件标志,而把控制蜂鸣器鸣叫放在了while循环中,这样每当事件标志被响应时,蜂鸣器就会鸣一声。因此程序A的中断子程执行时间长于程序B。
用 用 L5_intB.c 的方法 任务 2 2 修改编程:用跳线将按键 K2、K7 分别与单片机的 P1.2 和 P1.7 相连,P2.1、P2.4 分别连接 L2 和 L5,P2.3 连接蜂鸣器, 接线图如下: :
修改后见 程序见 Lab_5 项目,程序 L5_intB- -1 1c .c 如下:
#include "io430.h"
#include "in430.h"
int flag=0; void delay( )
//延时函数
{
unsigned int j;
for (j=0;j<0xffff;j++);
}
void L2Blink( )
//L2 闪 2 次
{ unsigned int i;
for (i=0;i<2;i++)
{
P2OUT &=~BIT1;
delay();
P2OUT|= BIT1;
delay();
};
}
void L5Blink( )
//L5 闪
{
P2OUT &=~BIT4;
delay();
P2OUT |= BIT4;
delay();
}
void Buzz( )
//蜂鸣响连 P2.3
{ P2OUT &=~BIT3;
delay();
P2OUT|= BIT3;
delay();
}
void main ( void )
{
WDTCTL = WDTPW + WDTHOLD;
//关闭看门狗
//设置引脚 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.2 连 K2、P1.7 连 K7 允许中断
P1SEL &=~ (BIT2+BIT7);
P1SEL2 &=~ (BIT2+BIT7);
P1OUT |=(BIT2+BIT7);
P1REN |=(BIT2+BIT7);
P1DIR &=~(BIT2+BIT7);
P1IES |= (BIT2+BIT7);
P1IFG &=~(BIT2+BIT7);
P1IE |= (BIT2+BIT7);
_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&BIT2)!=0)
{flag=1;
P1IFG &=~BIT2; }; if ((P1IFG&BIT7)!=0) { flag=2; P1IFG&=~BIT7;};
}
4 .(提高)按键抖动处理
程序 L5_Key.C 见后页, 其功能是用中断方式相应与 P1.2 连接的按键,计数按键的次数,并将所计的次数用8 个发光二极管显示出来。运行该程序,并操作按键,观察实际操作的次数与显示值之间的关系。编程改进L5_Key.C 程序,用软件方式去除按键抖动的影响。
说明:
通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合(按下)及断开(释放)的瞬间均伴随有一连串的抖动,产生电压毛刺,见图5-1机械按键的电压变化图。
在一次按键过程中,因为电压毛刺的产生,会有若干次下降沿和上升沿。采用下降沿判断时,只有第一次下降沿是真正的按键事件,其它是由于按键抖动带来的毛刺,不是按键事件。去除这些毛刺带来的影响,称为按键消抖或去抖。软件编程处理比较简单的方法是,在响应了第一次下降沿后,在中断函数中加入一定的延时,躲过其它电压毛刺的产生时间。
答:
通过在实验板测试见 程序见 Lab_5 项目 下程序 L5_Key.c ,显示按键次数大于实际数。
改进在按键中断程序增加延时函数,调整延时长短,使实际按键数与显示数值大致相等。
修改后见 程序见 Lab_5 项 项 目,程序 L5_Key- -1 1c .c 如下:
#include "io430.h"
#include "in430.h"
unsigned int number=0;
//记录响应按键次数
void delay( )
//延时函数
{
unsigned int j;
for (j=0; j<0xffff; 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;
}
}
思考: :
1.延时函数加在按键中断程序的什么位置? 为什么? 答:延时函数在按键中断程序接收到信号之前,根据分析,需要在响应了第一次下降沿后,加入一定的延时,躲过其它电压毛刺的产生时间。
2.延时函数的延时长短如何控制? 答:通过实验观察可以发现,改进之前,二进制显示的数值明显大于实际按键数,而改进之后,两者数值大致相等以此来调整延时长短。
3.除延时方法去抖外,有没有其他的方法可去抖?可上网查找相关资料了解。
答:在键数较少时可用硬件方法消除键抖动,如:RS 触发器为常用的硬件去抖。
实验 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 时钟频率
新创建的一个MSP430G2553 项目,在给出的main.c 基础上,编程输出单片机上电复位后的ACLK、和SMCLK 时钟,用示波器测量其频率值,记录下来。
答:程序需要置引脚 P1.0、P1.4 分别输出 ACLK、SMCLK,需要确认外部晶振连上,输出的 ACLK 频率为 F(ACLK)=32.7KHZ,SMCLK 的频率为 F(SMCLK)=1.031MHZ。接线如下:
见 程序见 Lab_6 项目,程序 L6_pin.c 如下:
#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) 实验板上JP8 中间的两个插针接到32.768KH 晶振侧和接到P2.6/P2.7 侧,测得ACLK 的结果有何不同? 为什么? 答:是由 32.768KHZ 低频振荡器控制的,因此比较精确,示波器测量的精确值和理论值相差不大,接到 P2.6/P2.7 侧是由片内低功耗低频振荡器控制的,受环境温度和工作电压影响较大,因此测量值和理论值相差较大。
2) 在debug 下如图6-1,通过View/Register 更改System Clock 模块控制寄存器值,分别置DIVA1、DIVA0=01、11;DIVS1、DIVS0=10、11;置LFXT1S0、LFXT1S0=00、10,记录示波器测量得到的ACLK(P1.0 输出)和SMCLK(P1.4 输出)的频率值,填写在表6-1、6-2、6-3 中,掌握时钟模块各控制寄存器相关位的作用。
表 6-1
DIVAxx 与 ACLK 关系 DIVA1 DIVA0 ACLK 频率值 作用 0 1
1 1
表 6-2
DIVSxx 与 SMCLK 关系 DIVS1 DIVS0 SMCLK 频率值 作用 1 0
1 1
表 6-3
LFXT1Sxx 与 ACLK 关系 LFXT1S1 LFXT1S0 ACLK 频率值 时钟来源 0 0
1 0
3) 上电复位后,CPU 工作的时钟信号 MCLK 频率值是多少?
答:上电复位后,通过查看基本时钟模块相关寄存器,发现 BCSCTL2 寄存器上 SELM 位为00,SELS 位为则 0,可知 MCLK 的时钟源为 DCO,SMCLK 的时钟源也为 DCO,因此通过测量上面复位后的 SMCLK 频率可知 MCLK 的频率,由上述可知 F(MCLK)=1.031MHZ。
3. 掌握基本时钟模块的编程控制
参看附录A 实验板原理图,用跳线将JP8 中的插针信号接到晶振32.768Khz 侧,使晶振与单片机的P2.6 和P2.7 相连。编程控制基本时钟模块,设置ACLK 分别为下面时钟频率,并通过P1.0输出ACLK,用示波器观察:
1)
ACLK=16.384kHz;(时钟源外部晶振二分频,即32768Hz/2)
答:P2.6、P2.7 连接外部晶振引脚,通过 P1.0 输出 ACLK,观察的 F(ACLK)=16.3kHZ。接线如下图:
见 程序见 Lab_6 项目,程序 L6_pin - 1.c 如下:
#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_1;
//设置 ACLK 为 2 分频 while(1); }
2)
ACLK=1.5KHz;(时钟源VLOCLK 八分频,即12KHz/8) 答:通过 P1.0 输出 ACLK,观察的 F(ACLK)=1.4KHZ。
见 程序见 Lab_6 项目,程序 L6_pin - 2.c 如下:
#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、16MHz,通过P1.4 输出,并用示波器测量实际值。
答: :
出厂校验值为 1MHZ 时,F 实际=0.991MHZ,出厂校验值为 16MHZ 时,F 实际=16.17MHZ。
以上测试数据说明:DCOCLK 是由片内数字可控 RC 振荡器控制的,受环境温度和工作电压的影响较大,因此出厂校验值和实际测量值也存在不小的误差。
见 程序见 Lab_6 项目,程序 L6_pin - 3.c 如下:
#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 例程test_2553.c 基础上,分别编程使主系统时钟工作在(1) MCLK = 复位频率/8 约100KHz;(2) MCLK=DCO=16MHz; 两种不同MCLK 频率下,观察灯的亮灭速度有何不同,掌握主系统时钟的变化对程序执行速度的影响。
答: :
经实验观察可知,MCLK 设置为 100KHZ 时 LED1 灯的闪烁频率比设置为 16MHZ 慢了非常多,由此可知主系统时钟是主要提供给 CPU 工作的时钟,MCLK 频率越高,CPU 工作速度越快。
(1) MCLK = 复位频率/8 约 100KHz,程 程见 序见 Lab_6 项目,程序 L6_pin - 4.c 如下:
#include "io430.h"
void delay( )
//延时函数
{
unsigned int j;
for (j=0;j<0xffff;j++);
}
int main( void )
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
P2SEL&=~BIT0;
//设置 P2.0 连接 L1 控制 LED1 闪烁
P2SEL2&=~BIT0;
P2DIR|=BIT0;
BCSCTL2|=DIVM_3;
//设置 MCLK=复位频率/8 约 100KHz; unsigned int i; while(1)
{
for (i=0;i<5;i++)
{P2OUT &=~BIT0;
delay();
P2OUT|=BIT0;
delay();
} } }
(2) MCLK=DCO=16MHz,程 程见 序见 Lab_6 项目,程序 L6_pin - 5.c 如下:
#include "io430.h"
void delay( )
//延时函数
{
unsigned int j;
for (j=0;j<0xffff;j++);
}
int main( void )
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
P2SEL&=~BIT0;
//设置 P2.0 连接 L1 控制 LED1 闪烁
P2SEL2&=~BIT0;
P2DIR|=BIT0;
BCSCTL1=CALBC1_16MHZ;
//利用出厂校验值设置 DCO 的振荡频率为 16MHZ
DCOCTL=CALDCO_16MHZ;
unsigned int i;
while(1) {
for (i=0;i<5;i++)
{P2OUT &= ~BIT0;
delay();
P2OUT |=BIT0;
delay();
} } }
5. 低功耗模式学习 程序 L6_LPM.c 见下,用跳线将P2.3 与L4 短接,将P2.4 用长杜邦线与buzz 短接,P1.1 与
K2短接,并用示波器分别观察P1.0、P1.4 输出的ACLK 和SMCLK,了解低功耗模式的进入和退出。
答:接线如下图:
程 序见Lab_6 项目,程序L6_LPM.c 清单(提供电子版):
#include "io430.h" #include "in430.h" void delay( )
//延时函数 {
unsigned int j;
for (j=0;j<0xffff;j++);
} void Blink( )
//LED闪 {
unsigned int i;
for (i=0;i<5;i++)
{ P2OUT &= ~BIT3;
delay();
P2OUT |=BIT3;
delay();
}; } void Buzz( )
//蜂鸣响 {
unsigned int i;
for (i=0;i<3;i++)
{ P2OUT &= ~BIT4;
delay();
P2OUT |=BIT4;
delay();
};
} int
main ( void ) {
WDTCTL = WDTPW + WDTHOLD;
//关闭看门狗 //设置端口P2.3输出,控制LED,P2.4输出,控制蜂鸣器
P2SEL &=~(BIT3+BIT4);
P2SEL2&=~(BIT3+BIT4);
P2OUT |= BIT3+BIT4;
P2DIR |= BIT3+BIT4;
//设置端口P1.1允许中断
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一样,但是用示波器测得的引脚输出信号不一样。
程 序见Lab_6 项目,程序L6_LPM-1.c:
#include "io430.h" #include "in430.h" void delay( )
//延时函数 {
unsigned int j;
for (j=0;j<0xffff;j++);
} void Blink( )
//LED 闪 {
unsigned int i;
for (i=0;i<5;i++)
{ P2OUT &= ~BIT3;
delay();
P2OUT |=BIT3;
delay();
}; } void Buzz( )
//蜂鸣响 {
unsigned int i;
for (i=0;i<3;i++)
{ P2OUT &= ~BIT4;
delay();
P2OUT |=BIT4;
delay();
}; } int
main ( void ) {
WDTCTL = WDTPW + WDTHOLD;
//关闭看门狗 //设置端口 P2.3 输出,控制 LED,P2.4 输出,控制蜂鸣器
P2SEL &=~(BIT3+BIT4);
P2SEL2&=~(BIT3+BIT4);
P2OUT |= BIT3+BIT4;
P2DIR |= BIT3+BIT4;
//设置端口 P1.1 允许中断
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 (;;)
//主循环
{
LPM0; //
Blink();
}
}
#pragma
vector=PORT1_VECTOR
__interrupt
void
port_ISR( ) { Buzz();
P1IFG&=~(BIT1);
//清中断标志
LPM0_EXIT; }
6. (提高)利用输出的时钟信号做中断源,实现定时功能
将任务 3 中P1.0 输出的1.5KHz ACLK 时钟信号,作为P1.5 的中断申请信号,用导线将P1.5与P1.0 相连即可,在中断函数中设置一个计数变量,计数中断函数被执行的次数,中断函数每被执行1500 次表示一秒时间到。利用该定时功能,将8 个发光二级管设计成一个秒表,显示秒值,每秒改变一次8 个发光二级管的显示。
答:将P2.0~P2.7与LED1~LED8连接起来,通过设置基本时钟控制寄存器将ACLK的时钟源选为12KHz的VLOCK,然后再设置ACLK为8分频,这样就可以使P1.0输出1.5KHz的ACLK信号。将P1.5与P1.0再连接起来,将P1.5设置为允许中断,在中断程序中加入计数因子,每隔1500次计数则可以视为1s,这时令8个LED灯变化一次。即可实现要求功能。
程 序见Lab_6 项目,程序L6_LPM-2.c:
#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.5允许中断
P1SEL&=~BIT5;
P1SEL2&=~BIT5;
P1REN|=BIT5;
P1OUT&=~BIT5;
P1DIR&=~BIT5;
P1IES&=~BIT5;
P1IFG&=~BIT5;
P1IE|=BIT5;
_EINT();
while(1){
if (i>=1500) {
time+=1;
i=0;}
P2OUT=~time;
//LED灯显示输出秒表的值
}
}
#pragma
vector=PORT1_VECTOR
__interrupt
void
port_ISR(){ i++;
P1IFG&=~(BIT5);
//清中断标志
}
思考:如果要每隔5 秒蜂鸣器响一声,如何在任务6 的基础上编程实现? 答:将P1.7与蜂鸣器相连,然后在中断程序在加入一个计时因子来控制蜂鸣器。
接线图如下:
程 序见Lab_6 项目,程序L6_LPM-3.c:
#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.5 允许中断
P1SEL&=~BIT5;
P1SEL2&=~BIT5;
P1REN|=BIT5;
P1OUT&=~BIT5;
P1DIR&=~BIT5;
P1IES&=~BIT5;
P1IFG&=~BIT6;
P1IE|=BIT5; _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<0xffff;j++);
}
#pragma
vector=PORT1_VECTOR
__interrupt
void
port_ISR() {
i++; P1IFG&=~(BIT5); //清中断标志
}
觉得实验 5、6 内容很多,学到了很多知识;实验过程中遇到了很多问题重温了课本和课件后解决了一些难题,加深了对课本上抽象的内容的理解,比如说实验前对于时钟,我的理解一直很模糊,似是而非,经过实验,发现其实它不过是三个寄存器,三个时钟信号,四个时钟源之间的问题,虽然过程比较繁琐,脉络却是清晰的;而且关于中断,我也有了进一步的理解,特别是最后几个选作实验和必做实验是对这两节知识的综合应用,难度有点大,但是写出来之后特别是程序问题解决达到实验效果后还是很有成就感的。
上一篇:执业药师“挂证”行为自查报告
下一篇:心理学实验报告