×
嵌入式 > 技术百科 > 详情

单片机中断问题30例

发布时间:2020-06-06 发布时间:
|

一、单片机中断问题30例

1、单片机外中断INT0为下降沿触发,当中断被触发后cpu执行中断程序,若本次中断的程序还未执行完INT0又来了一个相同的下降沿中断信号怎么办?cpu会怎么处理?若是定时器中断呢?串口中断呢?求解释

答:再来一个INT0信号不会执行。相同的优先级不会打断正在执行的中断。

一. 如果是高优先级的中断来了,会打断低优先级的正在执行的中断而执行高优先级的中断。

51单片机的默认(此时的IP寄存器不做设置)中断优先级为:

外部中断0 > 定时/计数器0 > 外部中断1 > 定时/计数器1 > 串行中断;

当同时有几种中断到达时,高优先级中断会先得到服务。

例如:当计数器0中断和外部中断1(优先级 计数器0中断>外部中断1)同时到达时,会进入计时器0的中断服务函数;但是在外部中断1的中断服务函数正在服务的情况下,这时候任何中断都是打断不了它的,包括逻辑优先级比它高的外部中断0计数器0中断。

51单片机的中断优先级控制寄存器IP可以把默认的中断优先级设置为高或低级,

例如默认是外部中断0 > 定时/计数器0 > 外部中断1 > 定时/计数器1 > 串行中断;

现在设为定时1 和串行中断为高优先级 其它为低 ,那么中断0执行时会被定时器1 或串行中断打断,如果设定的两个高优先级定时/计数器1 和串行中断同时响应,会再自然排队,先执行定时1中断再执行串行中断。

2、单片机中断问题,中断3为什么不执行,整个程序有什么不对的地方呢?

#include

#define uint unsigned int

#define uchar unsigned char

sbit p1_0=P1^0;

sbit p1_1=P1^1;

sbit p1_2=P1^2;

sbit p1_3=P1^3;

sbit p1_4=P1^4;

sbit p1_5=P1^5;

uchar PWM_T1 = 0;

uchar PWM_T2 = 0;

uint i,m;

void delay(uint z)

{

for(i=z;i>0;i--)

for(m=0;m<110;m++);

}

void PWM_value_left(int pwm_set)

{

PWM_T1=pwm_set;

}

void PWM_value_right(int pwm_set)

{

PWM_T2=pwm_set;

}

void main(void)

{

bit flag = 1;

uint n;

TMOD=0x22;

TH0=241;

TH1=241;

TL0=241;

TL1=241;

TR0=1;

TR1=1;

ET0=1;

ET1=1;

EA=1;

P1=0xf0;

delay(20);

PWM_value_left(7);

PWM_value_right(10);

delay(100);

PWM_value_left(8);

PWM_value_right(9);

delay(100);

PWM_value_left(9);

PWM_value_right(8);

delay(100);

PWM_value_left(10);

PWM_value_right(7);

}

timer0() interrupt 1 using 2

{

static uint t ;

t++;

if(t==10)

{

t=0;

p1_0=1;

p1_1=0;

}

if(PWM_T1==t)

P1=P1&0xfc;

}

timer1() interrupt 3

{

static uint t1 ;

t1++;

if(t1==10)

{

t1=0;

p1_2=1;

p1_3=0;

}

if(PWM_T2==t1)

P1=P1&0xf3;

}

答:没有主循环,

没有等到中断3

程序运行一次就跑飞了!!!

void main(void)

{

//...你的程序

//在这里加 死循环,等待中断

while(1)

{

;

}

}

而且,中断响应函数里必须要清中断标志位(你的没有)!

3、各位大侠帮我看一下我写的51单片机C程序中断有没有问题,执行中断后不能继续执行主程序,注:P3.2口一直接

注:P3.2口一直接地,程序如下:

#include

sbit dula=P2^6;

sbit wela=P2^7;

sbit d0=P1^0;

sbit d1=P1^1;

sbit d2=P1^2;

sbit d3=P1^3;

sbit d4=P1^4;

sbit d5=P1^5;

sbit d6=P1^6;

sbit d7=P1^7;

#define uchar unsigned char

#define uint unsigned int

uchar num;

uchar code table[]={

0x3f,0x06,0x5b,0x4f,

0x66,0x6d,0x7d,0x07,

0x7f,0x6f,0x77,0x7c,

0x39,0x5e,0x79,0x71};

void delay(uint z);

void main()

{

EA=1;

EX0=1;

IT0=0;

wela=1;

P0=0xc0;

wela=0;

while(1)

{

for(num=0;num<16;num++)

{

dula=1;

P0=table[num];

dula=0;

delay(1000);

}

}

}

void delay(uint z)

{

uint a,b;

for(a=z;a>0;a--)

for(b=110;b>0;b--);

}

void exter0() interrupt 0

{

uint c;

for(c=0;c<25000;c++);

d0=0;

for(c=0;c<25000;c++);

d0=1;

for(c=0;c<25000;c++);

d1=0;

for(c=0;c<25000;c++);

d1=1;

for(c=0;c<25000;c++);

d2=0;

for(c=0;c<25000;c++);

d2=1;

for(c=0;c<25000;c++);

d3=0;

for(c=0;c<25000;c++);

d3=1;

for(c=0;c<25000;c++);

d4=0;

for(c=0;c<25000;c++);

d4=1;

for(c=0;c<25000;c++);

d5=0;

for(c=0;c<25000;c++);

d5=1;

for(c=0;c<25000;c++);

d6=0;

for(c=0;c<25000;c++);

d6=1;

for(c=0;c<25000;c++);[page]

d7=0;

for(c=0;c<25000;c++);

d7=1;

}

答:

IT0=0;//低电平触发,只要单片机监测到是低电平,就触发中断

你P3.2一直接地,一直是低电平,那中断就不断的执行,当然回不到主程序中了。

改成IT0=1;//下降沿触发,单片机监测到高电平到电平跳变,就触发中断

就算P3.2一直接地,也只触发一次,中断执行完了,就回到主程序中了。

4、我的单片机这个程序为什么不能完全执行整个程序谁能告诉我!就是没法执行3次亮暗的!

2010-10-20 21:40 提问者:3865203bin3 | 悬赏分:10

ORG 0000H

AG:MOV A,#11111110B

AG1:RL A

MOV P0,A

ACALL DELAY

DJNZ R0,AG1

ACALL DELAY

MOV A,#11111111B

MOV P1,A

ACALL DELAY

MOV P0,#00000000B

ACALL DELAY

MOV P0,#11111111B

ACALL DELAY

MOV P0,#00000000B

ACALL DELAY

MOV P0,#11111111B

ACALL DELAY

SJMP AG

DELAY:MOV R3,#10

D3:MOV R2,#200

D1:MOV R1,#250

D2JNZ R1,D2

DJNZ R2,D1

DJNZ R3,D3

RET

END

我是想执行完流水灯亮.就然后执行全亮全暗3次 !可是就是不会跳到全亮全暗3次~~

答:

R0没有赋初值!另外建议不要使用前2B个地址,因为51中断矢量就在这个空间里。建议从0030H开始。以下程序在keil4中仿真成功。

ORG 0000H

AJMP AG

ORG 0030H

AG:MOV A,#11111110B

MOV R0,#8

AG1:RL A

MOV P0,A

ACALL DELAY

DJNZ R0,AG1

ACALL DELAY

MOV A,#11111111B

MOV P1,A

ACALL DELAY

MOV P0,#00000000B

ACALL DELAY

MOV P0,#11111111B

ACALL DELAY

MOV P0,#00000000B

ACALL DELAY

MOV P0,#11111111B

ACALL DELAY

SJMP AG

DELAY:MOV R3,#10

D3:MOV R2,#200

D1:MOV R1,#250

D2JNZ R1,D2

DJNZ R2,D1

DJNZ R3,D3

RET

END

5、STC89C52通过两个外部中断P3.2和P3.3,来控制P1.0和P1.1的数码管亮和灭,一定keil C

说明:通过外部中断0【P3.2】,P1.0的数码管亮,中断结束后,数码管灭;再由外部中断1【P3.3】,P1.1的数码管亮,次中断结束后,数码管灭;简言之就是一个中断只控制一个数码管,中断之间在功能上没有必然的联系,编程环境keil C51。P1.0和P1.1口上接的都是普通LED小灯,数码管=LED小灯。

以下是我编的程序,就是一个中断控制一个数码管,但是当有两个中断时,我就抓瞎了

#include

sbit D1=P1^0;

void main()

{

D1=1;

EA=1;

EX0=1;

}

void exter() interrupt 0

{

D1=0;

}

求高手帮我改改程序,改成两个中断的那种,功能要求都写在上面了~【希望能有程序注释】3Q,我会去keil里面模拟的~~o()^))o

答:

/*模块低电平有效、外部中断0、1为低电平出发*/

#include "reg52.h"

void delay( char i)

{

unsigned char t;

while(i--)

{

for(t=0;t<108;t++);

}

}

void INT0_ROUTING() interrupt 0//外部中断0子程序

{

P0=0xfe;//LED0点亮

while((P3|0xfb)==0xff);//等待外部中断0口(P3^2松开)

delay(10);//延时去抖动

P0=0xff;//LED0熄灭

}

void INT0_ROUTING() interrupt 2

{

P0=0xfd;//LED1点亮

while((P3|0xf7)==0xff);//等待外部中断1口(P3^3松开)

delay(10);//延时去抖动

P0=0xff;//LED1熄灭

}

void main()

{

EA=1;//中断总开关

EX0=1;//外部中断0开

EX1=1;//外部中断1开

/*默认低电平触发*/

while(1);//死循环 防止跑飞

}

6、单片机中断问题,下面这段程序不知道为什么只进一次中断,就没有反应了呢?

#include // 包含51单片机寄存器定义的头文件

#define uint unsigned int

sbit key1=P1^4;

sbit key2=P1^5;

void delay1ms(uint i)

{

uchar j;

while(i--)

{

for(j=0;j<125;j++) //1ms基准延时程序

{

;

}

}

}

void init()

{

EA=1; //开总中断

ES=1; //开串口中断

TMOD= 0x21; //定时器1定时方式2,定时器1工作于8位自动重载模式, 用于产生波特率

SCON = 0x50; // 设定串行口工作方式1 允许接收

TH0=(65536-50000)/256;

TL0=(65536-50000)%256;

TH1= 0xfd; //11.0592M 波特率9600

TL1= 0xfd;

PCON =0x00; // 波特率不倍增

TR1= 1; //启动定时器T1

TR0=1; //启动定时器T0

ET0=1; //打开T0中断

}

void key()

{

if(key2==0)

P0=0x3f;

delay1ms(5000);

P0=0xf3;

}

void mainxh()

{

while(1)

{

key();

P0=0x32;

}

}

void keybreak()

{

P0=0xf1;

delay1ms(5000);

P0=0x1f;

mainxh();

}

void main(void)

{

init();

mainxh();

}

void Time0(void) interrupt 1

{

TH0=(65536-50000)/256; //定时器T0的高8位重新赋初值

TL0=(65536-50000)%256; //定时器T0的高8位重新赋初值

[page]

if(key1==0)

keybreak();

}

这个程序上电后P0口显示0x32;按下key2显示0x3f;key1用于中断,每20ms检测是否有按下key1键,有的话,P0口显示0xf1。

答 :

ORG 0000H AJMP MAIN ORG 0001H LJMP INT_0 ORG 30H MAIN:MOV SP,#8FH MOV P0,#0FFH MOV P3,#0FFH SETB IT0 SETB EA SETB EX0 LJMP START START: MOV A,#10000000B LOOP: MOV P0,A RLC A LCALL DELAY LCALL DELAY LJMP LOOP LJMP START;

这句是多余的 根本不会执行 INT_0: PUSH ACC ;

由于p中1断中1A被设为10所以5中7断返回后对A移位没有意义,o A一e直为10 ,并不d是只能中断一1次 .

还有,不清楚key1是什么中断,貌似是键盘扫描吧,

while(1)

{

key();

P0=0x32;

}

都进入死循环了,所以跳不出来,就一次中断了。

7、新手学习avr单片机ATmage 128 遇到问题,中断程序被忽略问题,找不到原因。

avr studio 4 软件仿真时,编译通过了,单在编译信息栏却看到中断程序被忽略。在软件仿真时也发现中断程序没有执行。不知道问题出在哪里,我用的是avr studio 4 ATmage 128 单片机.

程序如下

#include

#include

void main() //用的是TC0 溢出中断,来控制八位LED 一秒闪烁

{

PORTE = 0xFF; //LED 关 端口高电平位关

DDRE = 0xFF;

MCUCR |=(1<

sei(); //开启全局中断

TIMSK|=(1<

TCNT0 =155; //定时器赋初值

TCCR0 |= (1 << CS01); //8分频

while (1);

}

volatile unsigned int j =0;

#pragma interrupt_handler timer0_ovf_isr:17

void timer0_ovf_isr(void)

{

TCNT0 = 156; //设初值

j++;

if(j <= 5000) //中断5000次后 执行LED 电平翻转

PORTE ^= 0xFF; //LED 电平翻转

}

../lesson2.c:18: warning: ignoring #pragma interrupt_handler timer0_ovf_isr

上面是写的程序。还有编译信息栏里的话。

答:

不是,你那句#pragma interrupt_handler timer0_ovf_isr:17是ICCAVR编译软件中写中断的方式,而看你的头文件#include 和#include 应该是用avr studio装GCCavr编译软件的写法,你加上把中断成

SIGNAL(SIG_OVERFLOW0)

{

TCNT0 = 156; //设初值

j++;

if(j <= 5000) //中断5000次后 执行LED 电平翻转

PORTE ^= 0xFF; //LED 电平翻转

}

看看,记住,这是GCCAVR 编译软件的写法

8新学的C51单片机,编了个电平触发式中断程序,不知道为什么和跳变沿的一样了,诸位帮忙看看.

#include

#define uchar unsigned char

#define uint unsigned int

sbit d1=P1^0;

sbit dula=P2^6;

sbit wela=P2^7;

void delay(uint z);

uchar code table[]={

0x3f,0x06,0x5b,0x4f,

0x66,0x6d,0x7d,0x07,

0x7f,0x6f,0x77,0x7c,

0x39,0x5e,0x79,0x71};

void main()

{

EA=1;

EX0=1;

IT0=0;

while(1)

{ d1=1;

dula=1;

P0=table[1];

dula=0;

P0=0xff;

wela=1;

P0=0xfe;

wela=0;

delay(500);

dula=1;

P0=table[2];

dula=0;

P0=0xff;

wela=1;

P0=0xfd;

wela=0;

delay(500);

dula=1;

P0=table[3];

dula=0;

P0=0xff;

wela=1;

P0=0xfb;

wela=0;

delay(500);

dula=1;

P0=table[4];

dula=0;

P0=0xff;

wela=1;

P0=0xf7;

wela=0;

delay(500);

dula=1;

P0=table[5];

dula=0;

P0=0xff;

wela=1;

P0=0xef;

wela=0;

delay(500);

dula=1;

P0=table[6];

dula=0;

P0=0xff;

wela=1;

P0=0xdf;

wela=0;

delay(500);

}

}

void delay(uint z)

{

uint x,y;

for(x=100;x>0;x--)

for(y=z;y>0;y--);

}

void enter() interrupt 0

{

d1=0;

}

答: 你这个程序中设置IT0=0,说明是低电平触发,所以只要P3^2口一直是低电平那么主程序停止,所以发光二极管点亮,如果P3^2口变为高电平,主程序继续,发光二极管熄灭。另一种情况是当IT0=1的时候是负跳变触发,就是当P3^2口检测到一个又高电平到低电平的跳变后,触发中断,在中断函数中点亮灯,立即出中断,执行到d1=1时熄灯。看到的现象就是灯闪一下,直到又检测到一个负跳变,灯又闪一下。两种触发方式的现象是不一样的,如果你硬件没问题的话。你可以把中断函数写成d1=!d1试试。

9、在C51单片机中,中断服务程序怎么撤销中断引脚上的低电平?

我用的是,第一个单片机输出低电平到第二个单片机的P3^2,第二个单片机是电平触发方式中断

低电平触发方式:要求低电平保持到CPU实际响应为止,为了避勉CPU再次响应中断,在中断服务程序中应该撤除中断引脚上的低电平。请问,怎么撤销?在中断服务程序中怎么写? 直接写P3^2=1;行吗?

答:

第一个单片机的程序,是谁来编写? 如果也是楼主,那就好办了。

第二个单片机完成了中断的功能,在退出之前,可以向第一个单片机回送一个脉冲;

第一个单片机收到这个脉冲,就应该撤消送到第二个单片机的中断申请信号。

----

另外,如果能算出来完成中断的时间,第一个单片机送来的申请信号,就不要超过这个时间,应该及时、自动的撤消申请信号。

[page]

第一个单片机送来的申请信号,也不可过短,应该能让对方检测到。

10、程序如下,我想要得到的效果是1秒左边的电动机转动,同时黄灯亮,1秒右边转动,蓝灯亮,以此循环下去,但是这个程序用上去后,左边转》右边转》左边转》之后就一直是左边了,不切换了,谁能帮我解决下问题,感激不尽!!

#include

sbit m=P2^0;

sbit b=P2^6;

sbit y=P2^7;

unsigned char count;

void main()

{

TMOD=0x01;

TH0=(65536-50000)/256;

TL0=(65536-50000)%256;

TR0=1;

ET0=1;

EA=1;

count=0;

m=!0;

b=!1;

y=!0;

while(1)

{

if(TF0==1)

{

count++;

if(count==20)

{

m=0;

b=1;

y=0;

}

if(count==40)

{

m=!0;

b=!1;

y=!0;

}

TF0=0;

TH0=(65536-50000)/256;

TL0=(65536-50000)%256;

}

}

}

答案

#include

sbit m=P2^0;

sbit b=P2^6;

sbit y=P2^7;

unsigned char count;

void main()

{

TMOD=0x01;

TH0=(65536-50000)/256;

TL0=(65536-50000)%256;

TR0=1;

count=0;

m=!0;

b=!1;

y=!0;

while(1) {

if(TF0==1) {

TH0=(65536-50000)/256;

TL0=(65536-50000)%256;

TF0=0;

count++;

if(count==20) {

m=0; b=1; y=0;

}

if(count==40) {

count=0; //加上这句.

m=!0; b=!1; y=!0;

}

}

}

}!

用T0定时50ms,溢出20次,溢出40次,分别代表了具体的时间。 溢出40次之后,应该从头开始统计溢出次数,所以,此处应该有count=0;。 楼主原来的程序,缺少count=0;,那么它就会继续增加,直到65536,才自动回到0。 这样,时间,就难以控制了。

11、求助关于51单片机外部中断的问题,小弟最近在学单片机,刚做了一个键盘扫描程序。发现如果外部中断为电平触发,程序能正常运行。但如果改为边沿触发,在将键值送给显示重开中断指令为EX0=1后,中断竟然还会被触发一次,这之后,再按键就不能触发中断了。如果将中断程序中关中断语句去掉,按键能被扫描,但引起中断的次数不好说了。请大侠们看看哪出问题了。谢谢

uchar keynum,//定义全局变量按键时的键值

dpnum,//显示值

time1,//延时计数值

topen,//延时计数控制

keyin;//外部中断0向主程序传递有中断标识,有键按下

keydeal;//按键程序调用标志

uchar keytable[4][4]={7,8,9,'/',4,5,6,'*',1,2,3,'-','c',0,'=','+'};//按实际键盘编值

uchar keyboard();//键盘扫描程序,负责键值扫描,判断键释放由主函数完成

void display(uchar,uchar);// 显示子程序,

sbit keysign=P3^2;//P3.2为中断0入口,此定义用于程序判断是否真有键按下及键是否释放

void main()

{uchar keybiao,keybiao1;//有键按下标志,键放开标志

IE=0x89;//开总中断,外部中断0,定时器中断1

IT0=1;//中断触发方式

PT1=1;//中断优先级

TMOD=0x90;//定时器1工作方式1

TH1=(65536-5000)/256;//定时器初值高8位(定时5ms)

TL1=(65536-5000)%256;

TR1=1;//开始计时

P2=0xf0;//给键盘列高电平,行低电平

keydeal=0x00;//让键处理初值为0,既未处理

while(1)

{if(keyin==1) //可能有键按下

{

if(time1>=2)//已延时10ms;计数2次,

{if(keysign==0&&keydeal==0)

{keynum=keyboard();

keybiao=1;

keydeal=1;

topen=0;//关延时计数

}//判断是否真有键按下,调用键盘扫描程序

else if(keybiao==0&&time1>=2&&keybiao1==0)

{EX0=1;

keyin=0;

topen=0;

}//如果没键按下,重开外部中断0,中断标志清0

}

if(keybiao==1&&keysign!=0)

{keybiao=0;

time1=0;

keybiao1=1;//为防止前一次time1的影响而设的标志

topen=1;

}

if(keybiao1==1&&time1>=2)

{keybiao1=0;

topen=0;

EX0=1;

keyin=0;//重开外部中断0,中断标志清0

keydeal=0;//重开键未处理,让程序可调用处理程序

dpnum=keynum;//将键值传给显示

}

}

}

}

void display(uchar x,uchar i)//中断控制显示,显示一直持续到下次中断到

uchar keyboard()

{uchar con1,con2,i,j;

con1=P2|0x0f;//只保留P2口高四位,便于switch

switch(con1)//通过cp可得到列为0的位

{case 0x7f:j=3;break;//j为列值

case 0xbf:j=2;break;

case 0xdf:j=1;break;

case 0xef:j=0;break;

}

for(i=0;i<=3;i++)

{P2=_crol_(0xfe,i);//依次给行赋0

con2=P2|0x0f;// 只保留P2口高四位,便于比较

if(con2!=0xff) break;

}

P2=0xf0;//给键盘列高电平,行低电平

return(keytable[i][j]);

}

void T1_time()interrupt 3

{TH1=(65536-5000)/256;//定时器初值高8位(定时5ms)

TL1=(65536-5000)%256;

time1++;

if(topen!=1) time1=0;//如果延时标志不为1,不开始计时

display(dpnum,5);

}

void int0()interrupt 0

{EX0=1;

keyin=1;//向主程序传递键按下

[page]

topen=1;//10ms延时计数开始

}

由于字数有限,有部分程序给删了,显示等部分程序应该没问题,我在其它地方能正常运行。

答:

不需要每次在进入中断程序后开一次中断;EX0=1可以去掉。

实际上,外部中断工作在边沿触发方式的时候,第一次电平跳变触发后进入中断程序,然后硬件自动清除IE0中断标志位。但是在执行中断程序的过程中,如果中断引脚再次检测到电平跳变(负到高),那么IE0会被再次置1 。如果在退出中断程序之前没及时清0,那么就会再次引发一次中断。

而按键的过程,不包括按下和松开时的电平抖动,至少会产生两次电平跳转。

因此,只需在你中断程序里适当加一点延迟,再将EX=1, 改成IE0=0 。

12、我用的单片机是8051F的单片机,在程序中我用了两个中断。一个是定时计数器2产生的中断100MS一次的数据采集。另一个是向上位机发送采集来的数据,使用的串口来实现的,用的单片机的UART来实现。也是一个中断。这两个中断在一起工作时需要注意些什么?我的中断程序出了一些问题。

(就是默认情况下,UART的中断级别更高,但是有的时候UART的中断不能及时响应,这是为甚?)

答:

之前和你做的一样就两个中断 UART0加一个定时器 我用的是C8051F040

你向上位机发送数据使用UART0时 要确认定时器工作完毕

T2定时中断后 你加一个完成标志如T2FLAG

if(T2FLAG==1) 将采集的数据放入 UART0的SBUF0 是UART0工作

你100ms的中断时间 C8051这么快速的单片机怎么都该发送完成了吧。

13、MSP430单片机中断嵌套,如何跳出中断?

当进行A中断时,来了一个B中断,我想让B中断程序执行完后不继续

执行A中断而跳出整个中断,去执行主程序,请问这个怎么设置呢?

答:

中断的时候会把SR状态跟中断下来要执行语句的地址放进堆栈中,实现处理完中断以后cpu要执行的语句,注意是地址先进,SR后进,出栈时SR先出,地址后出,当然了在中断里面可以嵌套中断的,对可屏蔽中断来说,主要是CPU响应中断以后,GIE会自动复位,所以不能对可屏蔽中断进行嵌套,如果在中断中要嵌套可屏蔽中断的话可以开GIE,但要注意的是如果此时正在响应的中断标志还是置位的情况下会反复进入此中断,就像死循环一样,这时会引起堆栈的溢出,而在响应可屏蔽中断时,不可屏蔽中断不受此影响,因为他不受GIE的影响,只受自己单独的使能位影响。在堆栈中的操作原理类似。

14、MSP430单片机有几个需要软件清除的中断标志?如何清除?

(1)清除各个端口的外中断用:PxIFG,相应的位置0即可;

(2)清除Timer中断用:TAIFG,TBIFG,相应的位置0即可;

答:

MSP430的16个外中断比如软件清除Flag,在进入外中断后,首先要做的就是把相应的PxIFG清0;

而定时器Timer中断是自动清除Flag;

还有在中断嵌套的时候会用到,在进入中断后,MCU会自动把全局中断位GIE清零,这样在进入本中断后就不会再相应其他中断,若要进行中断嵌套,必须在进入中断后把GIE再置1.

15、MCS-51系列单片机的有几个中断源?各中断标志是如何产生的?如何清除各中断标志?

答:

标准51有5个中断向量(不算复位),分别是外部中断0,定时器0,外部中断1,定时器1,串行口;总共有6个中断标志,串行口的发送和接受共享一个中断向量。

各个终端标志产生情况如下:

外部中断可以设置边沿触发或者电平触发,边沿触发进入中断程序后硬件自动清中断标志,电平触发需要软件清标志位;

定时器T0,T1计数溢出产生中断,进入中断程序硬件自动清标志位;

串行口发送完成或者接收到数据就触发中断,由于是两个中断标志共享一个中断向量,所以需要在中断程序里由软件判断是发送中断还是接受中断,并且只能由软件清标志位;

以上是标准51的中断系统,52由于多了一个T2定时器(T2定时器跟T0,T1功能相差很大,T2要强大很多),因此多了一个中断向量2个中断标志(溢出中断和T2外部中断),T2中断标志必须由软件清除标志位

中断使能位于IE寄存器

各中断标志位于相应的模块控制寄存器里面

模块 位地位 位名称 说明

T1 TCON.7 TF1 T1溢出标志

T0 TCON.5 TF0 T0溢出标志

T2 T2CON.7 TF2 T2溢出中断标志

T2CON.6 EXF2 T2外部中断标志

外部中断1 TCON.3 IE1 外部中断1标志

外部中断0 TCON.1 IE0 外部中断0标志

串行口 SCON.1 TI 发送中断标志

SCON.0 RI 接受中断标志

16、MCS51单片机的汇编语言的中断服务程序最多有几个?

答:一般而言有5个对:2个外中断 ,2个定时器中断, 1个串口中断。

但是单片机的中断服务资源是根据硬件的结构设计,会有不同的数量和类型的中断服务,,,因此中断并不是对语言来讲的,而是对于硬件资源来讲的。比如52有6个中断。

基于语言编译器来讲,我就举例个人感觉最好的开发51大系列的开发环境Keil,其编译器最多支持32个中断服务,,,,因此中断对编译来说,是一个“模拟”的概念。

17、单片机中断改变频率,为什么几个输出频率无法改变? 程序如下?

#include

#define uchar unsigned char

#define uint unsigned int

uchar T,t1;

unsigned char data table[5] = {486,236,151,111,86} ;

sbit CLK=P2^3 ;

sbit EN=P2^0 ;

void init();

void main()

{

init();

}

void init()

{

EN=1;

T=0;

TMOD=0x01;

EA=1;

TR0=1;

ET0=1;

t1=table[T];

TH0=(65536-t1)/256;

TL0=(65536-t1)%256;

}

void timer0() interrupt 1

{

TMOD=0x01;

EA=1;

TR0=1;

ET0=1;

t1=table[T];

TH0=(65536-t1)/256;

TL0=(65536-t1)%256;

CLK=~CLK;

}

[page]

 

答:

T你只付了0值,怎么会变化频率呢?你在主函数里加个T的赋值语句就行了,例如:while(T){T--;delay1s();}

18、单片机中断程序的书写步骤?

答:

标准形式:

void 函数名(void)interrupt n using m

{函数体语句}

n ----中断编号

m-----要使用工作寄存器组号

19、我想知道单片机的蜂鸣器音乐程序中断是如何响应的?从main主程序中如何到中断程序?具体步骤是啥?谢谢!

#include

sbit speaker = P1^5;

unsigned char timer0h, timer0l, time;

//--------------------------------------

//单片机晶振采用11.0592MHz

// 频率-半周期数据表 高八位 本软件共保存了四个八度的28个频率数据

code unsigned char FREQH[] = {

0xF2, 0xF3, 0xF5, 0xF5, 0xF6, 0xF7, 0xF8, //低音1234567

0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFC,//1,2,3,4,5,6,7,i

0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, //高音 234567

0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF}; //超高音 1234567

// 频率-半周期数据表 低八位

code unsigned char FREQL[] = {

0x42, 0xC1, 0x17, 0xB6, 0xD0, 0xD1, 0xB6, //低音1234567

0x21, 0xE1, 0x8C, 0xD8, 0x68, 0xE9, 0x5B, 0x8F, //1,2,3,4,5,6,7,i

0xEE, 0x44, 0x6B, 0xB4, 0xF4, 0x2D, //高音 234567

0x47, 0x77, 0xA2, 0xB6, 0xDA, 0xFA, 0x16}; //超高音 1234567

//--------------------------------------

//世上只有妈妈好数据表 要想演奏不同的乐曲, 只需要修改这个数据表

code unsigned char sszymmh[] = {5,1,1,5,1,1,6,1,2,5,1,2,1,2,2,7,1,4,5,1,1,5,1,1,6,1,2,5,1,2,2,2,2,1,2,4,

5,1,1,5,1,1,5,2,2,3,2,2,1,2,2,7,1,2

};

//--------------------------------------

void t0int() interrupt 1 //T0中断程序,控制发音的音调

{

TR0 = 0; //先关闭T0

speaker = !speaker; //输出方波, 发音

TH0 = timer0h; //下次的中断时间, 这个时间, 控制音调高低

TL0 = timer0l;

TR0 = 1; //启动T0

}

//--------------------------------------

void delay(unsigned char t) //延时程序,控制发音的时间长度

{

unsigned char t1;

unsigned long t2;

for(t1 = 0; t1 < t; t1++) //双重循环, 共延时t个半拍

for(t2 = 0; t2 < 8000; t2++); //延时期间, 可进入T0中断去发音

TR0 = 0; //关闭T0, 停止发音

}

//--------------------------------------

void song() //演奏一个音符

{

TH0 = timer0h; //控制音调

TL0 = timer0l;

TR0 = 1; //启动T0, 由T0输出方波去发音

delay(time); //控制时间长度

}

//--------------------------------------

void main(void)

{

unsigned char k, i;

TMOD = 1; //置T0定时工作方式1

ET0 = 1; //开T0中断 IE=0x82;

EA = 1; //开CPU中断

while(1) {

i = 0;

time = 1;

while(time) {

k = sszymmh[i] + 7 * sszymmh[i + 1] - 1;

//第i个是音符, 第i+1个是第几个八度

timer0h = FREQH[k]; //从数据表中读出频率数值

timer0l = FREQL[k]; //实际上, 是定时的时间长度

time = ssz

ymmh[i + 2]; //读出时间长度数值

i += 3;

song(); //发出一个音符

}

}

}

答:

你看main()函数就行了,首先进行k、i的定义,然后是定义中断的类型(程序中用的是定时器中断),这个定时器有点特殊,它的作用是定义频率的,频率间隔小则声调高,反之声调低。这个频率就是时间的倒数呗,所以TH的值越大,声调越高;TL的值越小,声调越低。接着往下走,while(1) 就是等待中断的意思,这个程序中的定时器中断没有设置初值,所以中断几乎没有等待,时时触发(要是有等待时间,音乐不就连不上了么)。综上:这个定时器中断完成两个任务:1、使单片机时时触发(等待时间几乎为0);2、控制了音符的演奏频率。

再往下 while(time) 的循环就是为演奏的音符赋值的操作了。

20、单片机中断该什么时候进如?

答:

中断看是外部中断、定时器还是串行口中断了。

如果是外部中断,就是p3.2、p3.3检测到这两个口电平变化时(假设这两个口接上按键,那么当按键按下时表明产生中断),然后跳到中断程序执行。

如果是定时器中断的话,有个中断标志位TFx(x表示0或者1),比如说你设置一个1S的定时器程序,你以50ms为基准,20次产生1s的时间,然后当50ms一过,标志位就产生变化,进入定时器中断程序执行!

串行口中断也是一样有一个标志位,接受或者发送数据满了以后,标志位就发生变化,然后进入中断执行!

21、PIC单片机AD中断什么时候开启,对AD中断应该怎样理解。

答:

AD模数转换,是把模拟电压数值采样进来,然后转换成数字信号。这一采样和转换是需要时间的。并不是一开AD就能读到数字信号数据。

一般来说其时间都只有几微秒到几百微秒(根据设置不同而定)。如果单片机没有其他工作的时候,可以用循环等待的方式等AD转换结束(转换结束后DONE位会被置位)。但如果你的单片机还有其他工作,那就没必要在等待它上面花费时间。可以开AD操作后,继续执行其他程序。而转换结束后,AD中断可以暂时断开现有炒作,而把AD数据读进来。这就是AD中断的作用。

2251单片机的五个中断分别在什么时候(什么情况)执行里面的程序!

答:

外部中断0 :P3.2口有低电平(IT0=0)/ 下降沿(IT0=1)。

外部中断1 :P3.3口有低电平(IT1=0)/ 下降沿(IT1=1)。

定时器0中断:当定时器0计数到FFFF溢出时

[page]

定时器1中断:当定时器1计数到FFFF溢出时

串口中断:串口接收到一帧。或发送完一帧数据都会产生中断。

你网上找一下TCON和SCON。什么条件让中断标志位的值改变。 那么就会进入中断服务程序去。

23、51单片机,如果中断函数比较长,执行到一半又触发了这个中断,程序会停止从头执行,还是执行结束后响应中

答:

51单片机中,中断分高低两个优先级,高优先级的中断能打断低优先级的中断。

但同级中断是不能打断同级中断的!无论该中断函数有多长,在执行到一半这个中断又发生了,还是要等到该中断函数执行完毕,并再执行了一条主程序指令后才会再次进入该中断。

不过,若楼主恰好在这个低优先级中断服务程序中修改了该中断为高优先级,那么如果该中断函数比较长,执行到一半又触发了这个中断,则该中断函数就会被重新从头开始执行(中断嵌套)。这是因为除串口中断以外的其他中断,在 CPU 响应该中断,程序转入该中断函数前就已经将该中断的中断标志清零了。

另外,51的串口中断比较特别,因为需要软件清除串口中断标志,所以只要在未清串口中断标志前,是不会发生上述这样的中断嵌套的。

24、求51单片机程序,两个计数器,主要是中断函数的函数名以及初始化设置

答:

void into_into() interrupt 1 定时器0中断入口函数

{

。。。。中断服务程序。。。。

TH0=0;//

TL0=0;// 重新给T0赐值

}

void into_into() interrupt 3 定时器1中断入口函数

{

。。。。中断服务程序。。。。

TH1=0;//

TL1=0;// 重新给T1赐值

}

void to_to()

{

TMOD=0x11; //顶时器T0和T1工作方式1

TH0=0;//

TL0=0;// T0赐初值

TH1=0;//

TL1=0// T1赐初值

TR0=1;// 开始记数

ET0=1;// 允许T0中断

TR1=1;// 开始记数

ET1=1;// 允许T1中断

EA=1; // 打开总中断

}

void main()

{

INIT_T0(); //定时器中断初始化

while(1)

{

...........

}

25、请教一个单片机中断的问题:比如来了一个脉冲,开始中断,但中断里的程序执行到一半时,又来了一个脉冲,请问这时中断里的程序是从头开始呢还是继续呢?

我的意思是程序就一个中断A,来了一个脉冲,A执行,A执行到一半时,又来了一个脉冲,通知A执行。这时A是从头执行还是先不理会呢?

答:

需要具体情况具体分析,因为不同的单片机在中断机制上有细微的差别,需要查他的资料。

一般来说,一个中断源请求中断,对CPU来说,是一次性的做了一个“中断挂号”。假如当时因条件不满足(例如CPU正在“关中断”,即没有打开“中断允许”),而没有响应中断,则挂号信息还在,这样,将来一旦打开了中断允许,仍然会响应,只是晚了一点而已。

而中断响应以后,必须有办法把这个“中断挂号”消除掉。有的CPU的功能是:只要响应了这个中断,挂号就自动消除了。也有的CPU不能自动清除挂号,必须在中断服务程序中编入“清除中断挂号”的操作,否则,一旦打开了中断允许,它又会重复发生中断。

现在的大多数单片机里,中断控制器和CPU是在同一个芯片中,它可以做到自动消除中断挂号。而过去许多种CPU,所配用的中断控制器是另外一个芯片,自然就无法自动消除了。

也有的CPU中有另外一种“不挂号”的中断请求。它必须由外界(发出中断请求的那个设备)来保持一直不停申请,等到响应中断的时候,再设法(例如,在中断服务程序中发出一个输出信号)通知那个设备撤销申请。

大多数的CPU中,一旦响应中断进入了服务程序,就把“中断允许”关掉了。故此时如果又有下一个中断请求来了,不能立即响应,只能挂一个号,等以后“开中断”时才能再响应。如果程序员希望能够“嵌套中断”(即在一次中断服务程序的执行中途又进入了另一个中断服务程序),就需要在服务程序内编入“开中断”的操作。

“嵌套中断”原则上允许“自己嵌套自己”,也就是说,一次中断服务程序的执行中途又被打断并进入了和自己一样的中断服务程序,并从头到尾执行一遍,结束后返回到先前打断的那一点,并继续执行后半截服务程序。这种情况会产生什么效果,是需要程序员自己考虑的。

也有的CPU具有“优先次序”机制,可以在某一级的中断服务程序里禁止优先级不比自己高的其他中断来打断自己。同时,也提供给程序员有“放弃优先权”以及“修改优先级”的灵活性。

而被优先机制暂时“屏蔽”的那些较低优先级的中断申请,同样挂号仍在,以后高优先级的中断结束以后,还能响应。

不过需要注意,大多数的CPU中,“中断挂号”是只能挂一个的。也就是说,在前一次的中断申请所挂的号还没有被清除以前,又来了下一个中断申请,那么,第二个挂号是挂不上的。

不过某些处理器中,中断挂号可能分成几个层次:CPU里面是一层,外围针对各个具体的设备,还有另外一级“预备挂号”,那就比较复杂了。

另外多说几句:上面已经说,程序员可以自己决定你的中断服务程序允许还是不允许“嵌套”。

如果不允许,您可以采用关中断的办法,或者利用优先机制,来屏蔽同一中断源的第二个中断请求。

这样,第二个中断就不会被响应。但它仍可以挂上一个号(只要它发生在上一个中断挂号已经被清除掉以后的时间)。然后,中断服务程序结束时,一般都会开中断并释放优先级屏蔽。然后,第二个中断请求就会被响应,于是再一次执行中断服务程序。

如果允许“嵌套”,那就会如我上面所说:

一次中断服务程序的执行中途又被打断并进入了和自己一样的中断服务程序,并从头到尾执行一遍,结束后返回到先前打断的那一点,并继续执行后半截服务程序。

[page]

26、我用51单片机定时/计数器1计数为什么不计数?想让它记数产生中断让蜂鸣器响。

sbit fengming=P1^6;

void main()

{

TMOD=0x50;

EA=1;

ET1=1;

TH1=0xff;//来一次中断记一次数

TL1=0xff;

TR1=1;

}

void time1(void) interrupt 3

{

fengming=0;

}

答:

不知道是你在网页上打错了,还是怎么回事。

void time1(void) interrupt 3-------》void timer1(void) interrupt 3

主程序最后,要加个死循环:while(1){};

还有,你在这用了方式1,这个方式在你进中断后,TH1和TL1会变成0000H。你不对他重新赋值,你要等FFFFH次计数,才会进中断。

27MCS-51 单片机定时器/计数器1的中断入口地址是: 一共有四个A. 0003H B. 000BH C. 0013H D. 001BH,到底是是哪一个?

答:答案是D.1BH

因为:

外中断0——03h

定时器0——0bh

外中断1——13h

定时器1——1bh

串口———23h

请背熟

28、我看很多程序都是主程序进入while(1),就死在while(1)里了,然后等待外中断。那么现在的问题是我想让它进入外中断完事后,跳过while(1),执行下边的程序,该怎么办?

while里边用break吗?不知道好使不好使,还有标志位我看是硬件自动清零,查询标志应该不能用吧,那该怎么办呢?

答:

结束while(1)语句最好的方法就是使用break来跳出死循环,关键就是选择合适的flag(标志位),如果说中断标志位是硬件自动清零的话,那么楼主不妨在中断服务子程序中自己加入一个标志位:如果用汇编语言的话,PSW中的F0位就可以很好的使用;如果用C的话,就可以随便定义一个位变量,如bit a=0;。也就是说,楼主需要在程序中定义一个位变量a,在中断服务子程序中将a置1,退出中断后查询a是否为1,例如:if(a) {a=0;break;}这样就跳出了while语句了。

比方说,如果楼主想写一个等待按键按下中断的程序,就可以用while(!a);而不用while(1)语句了。

29、我用外部中断1,中断一次显示下一个数,数码管显示没问题。但是我用P3-3口用导线连接,接触一次地线,松开一次,这时候数码管显示会乱跳,有时候加两次数,有时候加好多次数,反正就是不稳定。假如p3-3口通过按键接地的话,按一次按键一般情况会加一次数,但有时候也是不稳定,可能中断好几次。

程序如下:

#include

#define uint unsigned int

#define uchar unsigned char

uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

uchar times;

uchar i=0;

void delay(uint z)

{

uint x,y;

for(x=z;x>0;x--)

for(y=112;y>0;y--);

}

void main()

{

EA=1;

EX1=1;

IT1=1;

while(1)

{

P1=table[i];

P2=0x00;

}

}

void into() interrupt 2

{ delay(1000);

i++;

if(i==10) i=1;

}

答:

是抖动的问题。

应该采取消抖措施,硬件、软件方法皆可。

----

楼主在中断函数中,延时,时间看来很是不短!

但是延时后,并没有检测按键是否还在按下,这就不能算是软件消抖。

30、 (1) 为什么单片机有两个外部中断0允许位?有什么作用?

(2)在51内核单片机中,当允许响应外部中断0的中断请求时,其特殊功能寄存器ie中的位必须为1 es exo ea et0?

答:

(1)两个中断是因为一般的单片机有两个中断源,可以实现两级中断嵌套,在实现复杂功能上两级中断嵌套很有用。

(2)

EA--总中断允许位,必须为1

ES--串行中断允许位,不必开,为0

EX0--外部中断0允许位,应为1

ET0--定时计数溢出中断允许位,不必开,为0

 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
Semtech的LoRa技术携手Chipsafer将牧场连接至云端