清华大学计算机硬件技术基础实验报告

更新时间:2024-06-10 20:27:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

实验名称:实验6:中断技术

姓名:袁鹏 学号:2013011780 实验班号:33 机器号:42

一.实验目的

1. 了解中断原理,包括对中断源、中断向量、中断类型号、中断程序以及中断响应过程的 理解;

2. 掌握单片机 C 语言中断程序设计方法 二.实验任务

1. 中断响应过程的理解 代码: #include \#include \ 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.1允许中断 P1SEL &= BIT1; P1SEL2 &= BIT1; P1OUT |=BIT1;; P1REN |=BIT1; P1DIR &=~BIT1; P1IES |= BIT1; P1IFG &=~BIT1; P1IE |= BIT1; _EINT(); //总中断允许 for (;;) //主循环 { Blink(); }; } #pragma vector=PORT1_VECTOR __interrupt void port_ISR( ) { Buzz(); P1IFG &=~BIT1; } 该程序的功能是让P2.3控制的LED灯不断闪烁,当P1.1控制的开关发出中断申请时,控制P2.4控制的蜂鸣器响三声,然后继续让LED灯闪烁。

1) 从程序如何判断用的是哪个中断源?其中断类型号是多少?将实验板上某一按键与 该中断源对应的引脚相连,运行程序,操作按键,观察现象。

程序是通过判断中断标志位来确定是哪个中断源,P1.1的中断类型号是2。运程序时P2.3控制的LED4灯不断闪烁,当P1.1控制的开关发出中断申请时,控制P2.4控制的蜂鸣器响三声,然后继续让LED4灯闪烁。

2)main 函数中无调用函数Buzz 的语句,函数Buzz 如何能被执行?何时会被执行? 据 此描述中断响应过程。

函数Buzz是在函数名为port_ISR的中断程序中,因此当P1.1发出中断申请时,函数port_ISR就会被执行,执行完毕后再返回main函数中继续执行main函数。 3) 如果port_int 函数中不清分中断标志P1IFG 的后果是什么?

如果不清分中断标志P1IFG的话就会一直相应中断,然后port_ISR函数就会一直被执行,蜂鸣器不断的响。

4) 如果L6_int.c 中的PORT1_VECTOR 改为PORT2_VECTOR, 其他不变,程序执行

的后果是什么?为什么?(可在主程序入口处加一断点,运行程序,看现象,分析原因) 将PORT1_VECTOR 改为PORT2_VECTOR后当按下K2键给P1.1发出中断申请后蜂鸣器不会鸣叫,因为没有正确的设置中断向量,未能将中断程序的入口地址放入FFE0+偏址的中断向量表中,因此程序不能正确的进行中断响应。

思考:当在主程序入口处加一断点时可以发现,由于已经设置了中断的端口,因此当有中断信号发出时,程序仍然会去执行中断子程,但由于中断向量没有正确设置,PC指针会跑飞,然后机器会自动复位,重新执行程序。

5)如果中断源采用的是P1.5, 按键用K7,请设计连线,修改L6_int.c 程序完成以中断

方式响应K7 的操作。

只需要将P1.1允许中断改为P1.5允许中断即可,同时将P1.5用跳线块与K7相连,具体代码如下: #include \#include \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.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; } 6)(选做)去掉L6_int.c 程序最后的那条无限循环语句,看看有什么现象?可以去掉吗? 去掉程序最后的无限循环语句后LED4灯不在闪烁,但当P1.1发出中断申请后蜂鸣器还是会响三下,因此如果仅仅实现中断功能,则可以去掉无限循环语句。 2. 中断程序编程练习

将P1.4、P1.5与K5、K6相连,作为中断源,将P1.7、P2.0、P2.6与BUZZ、LED1、LED7相连,每当K5键按下,使蜂鸣器鸣叫,每当K6键按下,控制二极管闪烁,实现功能。具体代码如下:

#include \#include \ void delay( ) //延时函数 { unsigned int j; for (j=0;j<0xffff;j++); } void Blink( ) //LED闪 { P2OUT &=~BIT6; delay(); P2OUT |= BIT6; delay(); } void Blink2( ) //LED闪 { unsigned int i; for(i=0;i<3;i++) { P2OUT &=~BIT0; delay(); P2OUT |= BIT0; delay(); } } void Buzz( ) //蜂鸣响 { P1OUT &=~BIT7; delay(); P1OUT|= BIT7; delay(); } void main ( void ) { WDTCTL = WDTPW + WDTHOLD; //关闭看门狗 _DINT(); //关闭总中断允许 P1IE &=~(BIT4+BIT5); //关闭分中断允许 //设置引脚P2.0、P2.6、P1.7输出,P2.0连接LED1,P2.6连接LED7,P1.7连接蜂鸣器 P2SEL &=~(BIT0+BIT6); P2SEL2 &=~(BIT0+BIT6); P1SEL &=~BIT7; P2SEL2 &=~BIT7; P2OUT|=(BIT0+BIT6); P2DIR|=(BIT0+BIT6); P1OUT|=BIT7; P1DIR|=BIT7; //设置端口P1.4、P1.5允许中断 P1SEL &=~(BIT4+BIT5); P1SEL2 &=~(BIT4+BIT5); P1OUT |=(BIT4+BIT5);; P1REN |=(BIT4+BIT5); P1DIR &=~(BIT4+BIT5); P1IES |=(BIT4+BIT5); P1IFG &=~(BIT4+BIT5); P1IE |=(BIT4+BIT5); _EINT(); //总中断允许 for (;;) //主循环 { Blink(); }; } #pragma vector=PORT1_VECTOR __interrupt void port_ISR( ) { if((P1IFG&BIT4)!=0) {

Buzz(); P1IFG &=~BIT4; } if((P1IFG&BIT5)!=0) { Blink2(); P1IFG &=~BIT5; } } 思考:如果用长导线将按键K5、K6 分别连接在P2.2 和P2.5 上,如何修改程序以实现 任务2 功能?

若用长导线将按键K5、K6 分别连接在P2.2 和P2.5 上,则只需将P2.2与P2.5设置为允许中断即可,具体代码如下: #include \#include \void delay( ) //延时函数 { unsigned int j; for (j=0;j<0xffff;j++); } void Blink( ) //LED闪 { P2OUT &=~BIT6; delay(); P2OUT |= BIT6; delay(); } void Blink2( ) //LED闪 { unsigned int i; for(i=0;i<3;i++) { P2OUT &=~BIT0; delay(); P2OUT |= BIT0; delay(); } } void Buzz( ) //蜂鸣响 { P1OUT &=~BIT7; delay(); P1OUT|= BIT7; delay(); } void main ( void ) { WDTCTL = WDTPW + WDTHOLD; //关闭看门狗 _DINT(); //关闭总中断允许 P2IE &=~(BIT2+BIT5); //关闭分中断允许 //设置引脚P2.0、P2.6、P1.7输出,P2.0连接LED1,P2.6连接LED7,P1.7连接蜂鸣器 P2SEL &=~(BIT0+BIT6); P2SEL2 &=~(BIT0+BIT6); P1SEL &=~BIT7; P2SEL2 &=~BIT7; P2OUT|=(BIT0+BIT6); P2DIR|=(BIT0+BIT6); P1OUT|=BIT7; P1DIR|=BIT7; //设置端口P2.2、P2.5允许中断 P2SEL &=~(BIT2+BIT5); P2SEL2 &=~(BIT2+BIT5); P2OUT |=(BIT2+BIT5);; P2REN |=(BIT2+BIT5); P2DIR &=~(BIT2+BIT5); P2IES |=(BIT2+BIT5); P2IFG &=~(BIT2+BIT5); P2IE |=(BIT2+BIT5); _EINT(); //总中断允许 for (;;) //主循环 { Blink(); }; } #pragma vector=PORT2_VECTOR __interrupt void port_ISR( ) { if((P2IFG&BIT2)!=0) { Buzz(); P2IFG &=~BIT2; } if((P2IFG&BIT5)!=0) { Blink2(); P2IFG &=~BIT5; } } 思考:K5键连接的P1.4与K6键连接的P1.6均属于同一级优先级,因此当执行P1.4发出的中断子程时若按下K6再次发出中断申请,则程序会先处理完P1.4控制的中断程序,然后在执行完后执行P1.5控制的子程。若想要实现实时反馈,则可以将K6连接的端口改为P2.X,由于P2端口的中断优先级高于P1,因此程序会优先执行P2控制的中断程序。 3. 采用事件标志处理中断

阅读程序 L6_intA.c 和L6_intB.c(见后页),描述其实现功能。比较L6_intA.c 和L6_intB.c二者在编程实现上有何不同。

程序A和程序B实现的功能相同:用P1.0作为中断源,当P1.0接收到中断信号时,控制蜂鸣器响一声。不同的是程序A把控制蜂鸣器鸣叫的过程放在中断程序中,而程序B仅仅在中断程序中设置了一个事件标志,而把控制蜂鸣器鸣叫放在了while循环中,这样每当事件标志被响应时,蜂鸣器就会鸣一声。因此程序A的中断子程执行时间长于程序B。 用L6_intB.c 的方法,改写任务2 的编程。 具体代码如下: #include \#include \int flag=0; void delay( ) //延时函数 { unsigned int j; for (j=0;j<0xffff;j++); } void Blink( ) //LED闪 { P2OUT &=~BIT6; delay(); P2OUT |= BIT6; delay(); } void Blink2( ) //LED闪 { unsigned int i; for(i=0;i<3;i++) { P2OUT &=~BIT0; delay(); P2OUT |= BIT0; delay(); } } void Buzz( ) //蜂鸣响 { P1OUT &=~BIT7; delay(); P1OUT|= BIT7; delay(); } void main ( void ) { WDTCTL = WDTPW + WDTHOLD; //关闭看门狗 _DINT(); //关闭总中断允许 P1IE &=~(BIT4+BIT5); //关闭分中断允许 //设置引脚P2.0、P2.6、P1.7输出,P2.0连接LED1,P2.6连接LED7,P1.7连接蜂鸣器 P2SEL &=~(BIT0+BIT6); P2SEL2 &=~(BIT0+BIT6); P1SEL &=~BIT7; P2SEL2 &=~BIT7; P2OUT|=(BIT0+BIT6); P2DIR|=(BIT0+BIT6); P1OUT|=BIT7; P1DIR|=BIT7; //设置端口P1.4、P1.5允许中断 P1SEL &=~(BIT4+BIT5); P1SEL2 &=~(BIT4+BIT5); P1OUT |=(BIT4+BIT5);; P1REN |=(BIT4+BIT5); P1DIR &=~(BIT4+BIT5); P1IES |=(BIT4+BIT5); P1IFG &=~(BIT4+BIT5); P1IE |=(BIT4+BIT5); _EINT(); //总中断允许 for (;;) //主循环 { Blink(); if(flag==1) { Buzz(); flag=0; } else if(flag==2) { Blink2(); flag=0; } } } #pragma vector=PORT1_VECTOR __interrupt void port_ISR( ) { if((P1IFG&BIT4)!=0) { flag=1; P1IFG &=~BIT4; } if((P1IFG&BIT5)!=0) { flag=2; P1IFG &=~BIT5; } } 4.(选做)按键抖动处理

为了去除这些毛刺带来的影响,进行按键消抖,需要在响应了第一次下降沿后,加入一定的延时,躲过其它电压毛刺的产生时间。具体代码如下: #include \#include %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; P1SEL2 &= BIT2; P1OUT |=BIT2;; P1REN |=BIT2; P1DIR &=~BIT2; P1IES |= BIT2; P1IFG &=~BIT2; P1IE |= BIT2; __enable_interrupt(); while(1){ }; } //_EINT(); 总中断运行

#pragma vector=PORT1_VECTOR __interrupt void port_int(void) { unsigned int i; for(i=0;i<3;i++) { delay(); } if ( (P1IFG&BIT2)!=0 ) { number++; P2OUT=~number; } P1IFG &=~BIT2; }

实验名称:实验7:基本时钟和低功耗模式 姓名:袁鹏 学号:2013011780 实验班号:33 机器号:42

一.实验目的

1. 了解MSP430Gxxx 基本时钟模块的工作原理,掌握其控制方法; 2. 掌握利用时钟信号和中断技术实现定时功能的方法; 3.掌握低功耗模式控制方法 二. 实验任务

1. 数字示波器的使用

(1).用示波器测得信号源的周期T=20us、频率f=1.000KHZ、峰峰值V=3.12V。 (2).测得实验板上Vcc信号正常,Vccmax=3.76V,Vccmin=3.52V,Vccavg=3.66V。 2. 测试上电复位系统的 ACLK、和SMCLK 时钟频率

输出的ACLK频率为F(ACLK)=32.79KHZ,SMCLK的频率为F(SMCLK)=1.031MHZ。 代码如下: #include \int main( void ) { // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD; P1SEL|=BIT0; //P1.0输出ACLK P1SEL2&=~BIT0; P1DIR|=BIT0; P1SEL|=BIT4; //P1.4输出SMCLK P1SEL2&=~BIT4; P1DIR|=BIT4; while(1); } 思考:上电复位后,CPU 工作的时钟信号MCLK 频率值是多少?

上电复位后,通过查看基本时钟模块相关寄存器,可知MCLK的时钟源为DCO,SMCLK的时钟源也为DCO,因此通过测量上面复位后的SMCLK频率可知MCLK的频率,由上述可知F(MCLK)=1.031.MHZ。

3. 掌握基本时钟模块的编程控制

参看附录A 实验板原理图,用跳线将JP8 中的插针信号接到晶振32.768Khz 侧,使晶振 与单片机的P2.6 和P2.7 相连。编程控制基本时钟模块,设置ACLK 分别为下面时钟频 率,并通过P1.0 输出ACLK,用示波器观察:

(1). ACLK=4096Hz;(时钟源外部晶振,32768Hz/8) 观察的F(ACLK)= 4.098KHZ。 具体代码如下:

#include \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_3; //设置ACLK为8分频 while(1); } (2). ACLK=3KHz;(时钟源VLOCLK, 12KHz/4) 观察的F(ACLK)= 3.165KHZ。 具体代码如下:

#include \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_2; //设置ACLK时钟源为VLOCLK,并为4分频 BCSCTL3|=LFXT1S_2; while(1); } 思考:可否编程在引脚P2.0 上输出ACLK? 为什么? 不可以,因为根据说明指导书MSP430G2553的辅助时钟ACLK是由P1.0输出的,内部硬件电路设计结构决定了不能用P2.0输出ACLK。

反思:LFXT1CLK是由32.768KHZ低频振荡器控制的,因此比较精确,示波器测量的精确值和理论值相差不大。而VLOCLK是由片内低功耗低频振荡器控制的,受环境温度和工作电压影响较大,因此测量值和理论值相差较大。 4. DCO 出厂校验值的频率检测

(1)利用出厂校验值,编程使DCO 分别为1MHz、8MHz、12MHz、16MHz,通过P1.4 输出,用示波器测量实际值。

出厂校验值为1MHZ时,F实际= 0.992MHZ。出厂校验值为8MHZ时,F实际= 8.197MHZ。 出厂校验值为12MHZ时,F实际= 12.05MHZ。出厂校验值为16MHZ时,F实际= 16.39MHZ。 具体代码如下: #include \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 DCOCTL=CALDCO_1MHZ; /*BCSCTL1=CALBC1_8MHZ; //利用出厂校验值设置DCO的振荡频率为8MHZ DCOCTL=CALDCO_8MHZ; BCSCTL1=CALBC1_12MHZ; //利用出厂校验值设置DCO的振荡频率为12MHZ DCOCTL=CALDCO_12MHZ; BCSCTL1=CALBC1_16MHZ; //利用出厂校验值设置DCO的振荡频率为16MHZ DCOCTL=CALDCO_16MHZ;*/ while(1); } 思考:DCOCLK是由片内数字可控RC振荡器控制的,受环境温度和工作电压的影响较大,因此出厂校验值和实际测量值也存在不小的误差。

(2)(选做)控制发光二级管通过延时闪亮,编程分别使主系统时钟工作在 (1) MCLK=复位频率/8 约100KHz; (2) MCLK=DCO=16MHz;

两种不同频率下,观察灯的亮灭速度有何不同,掌握主系统时钟的变化对程序执行速度的影响:

经实验观察可知,MCLK设置为100KHZ时LED1灯的闪烁频率比设置为16MHZ慢了非常多,由此可知主系统时钟是主要提供给CPU工作的时钟,MCLK频率越高,CPU工作速度越快。 代码(1):

#include \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控制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): #include \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控制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. 低功耗模式学习

(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 输出的3KHz ACLK 时钟信号,作为P1.5 的中断申请信号,用导线将 P1.5 与P1.0 相连即可,在中断子程中设置一个计数变量,计数中断子程被执行的次数, 中断子程每被执行3000 次表示一秒时间到。利用该定时功能,将8 个发光二级管设计 成一个秒表,显示秒值,每秒改变一次8 个发光二级管的显示。

实现方法:将P2.0~P2.7与LED1~LED8连接起来,通过设置基本时钟控制寄存器将ACLK的时钟源选为12KHz的VLOCK,然后再设置ACLK为4分频,这样就可以使P1.0输出3KHz的ACLK信号。将P1.5与P1.0再连接起来,将P1.5设置为允许中断,在中断程序中加入计数因子,每隔3000次计数则可以视为1s,这时令8个LED灯变化一次。即可实现要求功能。具体代码如下:

#include \#include %unsigned int i=0,c=0; int main ( void ) { WDTCTL = WDTPW + WDTHOLD; //关闭看门狗 _DINT(); //关闭中断允许 P1IE &=~BIT5; //设置端口P2.0~P2.7为输出 P2SEL=0; P2SEL2=0; P2OUT=0xff; P2DIR=0xff; //设置端口P1.5允许中断 P1SEL &=~BIT5; P1SEL2 &=~BIT5; P1REN |=BIT5; P1OUT |=BIT5; P1DIR &=~BIT5; P1IES |=BIT5; P1IFG &=~BIT5; P1IE |=BIT5; _EINT(); //P1.0输出时钟3KHzACLK P1SEL|=BIT0; P1SEL2&=~BIT0; P1DIR|=BIT0; BCSCTL1|=DIVA_2; //设置ACLK时钟源为VLOCLK,并为4分频 BCSCTL3|=LFXT1S_2; while(1); } #pragma vector=PORT1_VECTOR __interrupt void port_ISR( ) { i++; //计时因子自增 if(i==3000) //1s改变发光二极管状态一次 { c++; P2OUT=~c; i=0; } } P1IFG&=~(BIT5); //清中断标志 (选做) 如果要每隔10 秒蜂鸣器响一声,如何在任务6 的基础上编程实现?

实现方法:只需将P1.7与蜂鸣器相连,然后在中断程序在加入一个计时因子来控制蜂鸣器即可,具体代码如下: #include \#include %unsigned int i=0,c=0,k=0; void delay() //延时函数 { unsigned int d; for(d=0;d<0xffff;d++); } void buzz() //蜂鸣器响一声 { P1OUT&=~BIT7; delay(); P1OUT|=BIT7; } int main ( void ) { WDTCTL = WDTPW + WDTHOLD; //关闭看门狗 _DINT(); //关闭中断允许 P1IE &=~BIT5; //设置P1.7为输出 P1SEL&=~BIT7; P1SEL2&=~BIT7; P1OUT|=BIT7; P1DIR|=BIT7; //设置端口P2.0~P2.7为输出 P2SEL=0; P2SEL2=0; P2OUT=0xff; P2DIR=0xff; //设置端口P1.5允许中断 P1SEL &=~BIT5; P1SEL2 &=~BIT5; P1REN |=BIT5; P1OUT |=BIT5; P1DIR &=~BIT5; P1IES |=BIT5; P1IFG &=~BIT5; P1IE |=BIT5; _EINT(); //P1.0输出时钟3KHzACLK P1SEL|=BIT0; P1SEL2&=~BIT0; P1DIR|=BIT0; BCSCTL1|=DIVA_2; //设置ACLK时钟源为VLOCLK,并为4分频 BCSCTL3|=LFXT1S_2; while(1); } #pragma vector=PORT1_VECTOR __interrupt void port_ISR( ) { i++; //计时因子自增 k++; //计时因子自增 if(i==3000) //1s改变发光二极管状态一次 { c++; P2OUT=~c; i=0; } if(k==30000) //10s蜂鸣器响一声 { buzz(); k=0; } P1IFG&=~(BIT5); //清中断标志 } 7.(选做)改用4 个数码管显示秒值,重新完成任务6

实现方法:将P2.0~P2.7与Sa~Sh相连来控制数码管,将P1.4、P1.1、P1.2、P1.3与S1、S2、S3、S4相连来实现串行显示,其余P1.0与P1.5和任务六一样相连接。将计数因子代表的秒表值转化为分钟和秒输出到数码管上。具体代码如下: #include \#include \void delay1() { unsigned int q; for(q=0;q<0xff;q++); } unsigned int i=0,c=0,a1,a2,a3,a4; unsigned char LED[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //LED灯 int main ( void ) { WDTCTL = WDTPW + WDTHOLD; //关闭看门狗 _DINT(); //关闭中断允许 P1IE &=~BIT5; P1SEL&=~(BIT1+BIT2+BIT3+BIT4); //设置P1.1~P1.4为输出 P1SEL2&=~(BIT1+BIT2+BIT3+BIT4); P1DIR|=BIT1+BIT2+BIT3+BIT4; P1OUT&=~(BIT1+BIT2+BIT3+BIT4); //设置端口P2.0~P2.7为输出 P2SEL=0; P2SEL2=0; P2OUT=0xff; P2DIR=0xff; //设置端口P1.5允许中断 P1SEL &=~BIT5; P1SEL2 &=~BIT5; P1REN |=BIT5; P1OUT |=BIT5; P1DIR &=~BIT5; P1IES |=BIT5; P1IFG &=~BIT5; P1IE |=BIT5; _EINT(); //P1.0输出时钟3KHzACLK P1SEL|=BIT0; P1SEL2&=~BIT0; P1DIR|=BIT0; BCSCTL1|=DIVA_2; //设置ACLK时钟源为VLOCLK,并为4分频 BCSCTL3|=LFXT1S_2; while(1) { a1=c/600; a2=(c-600*a1)/60; a3=(c-600*a1-60*a2)/10; a4=c-600*a1-60*a2-10*a3; P2OUT=LED[a4]; //控制第一个数码管显示的数字 P1OUT=0x10; delay1(); P2OUT=LED[a3]; //控制第二个数码管显示的数字 P1OUT=0x02; delay1(); P2OUT=LED[a2]; //控制第三个数码管显示的数字 P1OUT=0x04; delay1(); P2OUT=LED[a1]; //控制第四个数码管显示的数字 P1OUT=0x08; delay1(); } } #pragma vector=PORT1_VECTOR

__interrupt void port_ISR( ) { i++; //计时因子自增 if(i==3000) //1s改变发光二极管状态一次 { c++; i=0; } P1IFG&=~(BIT5); //清中断标志 } (选做) 如果要每隔10 秒蜂鸣器响一声,如何在任务6 的基础上编程实现?

实现方法:和任务六的第二个选作任务一样,再增加一个计时因子即可。具体代码如下: #include \#include \void delay1() { unsigned int q; for(q=0;q<0xff;q++); } void delay2() //延时函数 { unsigned int d; for(d=0;d<0xffff;d++); } void buzz() //蜂鸣器响一声 { P1OUT&=~BIT7; delay2(); P1OUT|=BIT7; } unsigned int i=0,c=0,k=0,a1,a2,a3,a4; unsigned char LED[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //LED灯 int main ( void ) { WDTCTL = WDTPW + WDTHOLD; //关闭看门狗 _DINT(); //关闭中断允许 P1IE &=~BIT5; P1SEL&=~(BIT1+BIT2+BIT3+BIT4); P1SEL2&=~(BIT1+BIT2+BIT3+BIT4); P1DIR|=BIT1+BIT2+BIT3+BIT4; P1OUT&=~(BIT1+BIT2+BIT3+BIT4); //设置端口P2.0~P2.7为输出 P2SEL=0; P2SEL2=0; P2OUT=0xff; P2DIR=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 &=~BIT5; P1IE |=BIT5; _EINT(); //P1.0输出时钟3KHzACLK P1SEL|=BIT0; P1SEL2&=~BIT0; P1DIR|=BIT0; BCSCTL1|=DIVA_2; //设置ACLK时钟源为VLOCLK,并为4分频 BCSCTL3|=LFXT1S_2; while(1) { a1=c/600; a2=(c-600*a1)/60; a3=(c-600*a1-60*a2)/10; a4=c-600*a1-60*a2-10*a3; P2OUT=LED[a4]; //控制第一个数码管显示的数字 P1OUT|=BIT4; P1OUT&=~(BIT1+BIT2+BIT3); delay1(); P2OUT=LED[a3]; //控制第二个数码管显示的数字 P1OUT|=BIT1; P1OUT&=~(BIT2+BIT3+BIT4); delay1(); P2OUT=LED[a2]; //控制第三个数码管显示的数字 P1OUT|=BIT2; P1OUT&=~(BIT1+BIT3+BIT4); delay1(); P2OUT=LED[a1]; //控制第四个数码管显示的数字 P1OUT|=BIT3; P1OUT&=~(BIT1+BIT2+BIT4); delay1(); } } #pragma vector=PORT1_VECTOR __interrupt void port_ISR( ) { i++; //计时因子自增 k++; //计时因子自增 if(i==3000) //1s改变发光二极管状态一次 { c++; i=0; } if(k==30000) //10s蜂鸣器响一声 { buzz(); k=0; } P1IFG&=~(BIT5); //清中断标志 } 思考:中断程序要尽可能的简洁,最好能只处理一些关键程序,如果此题中将控制数码管显示的程序放在中断程序中,则可能导致中断程序执行时间超出预期,秒表将会产生严重误差。 思考2:经过与标准秒表对比,此种方式设置的秒表仍存在一定误差,原因猜测是VLOCLK是由片内低功耗低频振荡器控制的,受环境温度和工作电压影响较大,因此测量值和理论值相差较大。

本文来源:https://www.bwwdw.com/article/nta6.html

Top