avr单片机 在中断函数了改变全局变变量的值,发生很奇怪的事情,在这里向各位高手请教了,谢谢,源程序如
答案:6 悬赏:70
解决时间 2021-02-21 04:49
- 提问者网友:謫仙
- 2021-02-20 13:48
avr单片机 在中断函数了改变全局变变量的值,发生很奇怪的事情,在这里向各位高手请教了,谢谢,源程序如
最佳答案
- 二级知识专家网友:舍身薄凉客
- 2021-02-20 14:00
以下是我使用WINAVR+AVR Studio编译,程序如下:
#include
#include
#include
#defineF_CPU 16000000UL
#include
volatile unsigned int i=0;
void port_init(void)
{
PORTA = 0xF0;
DDRA= 0xFF;
PORTB = 0x00;
DDRB= 0x00;
PORTC = 0x00;
DDRC= 0x00;
PORTD = 0x04;
DDRD= 0x00;
}
SIGNAL(SIG_INTERRUPT0)
{
i++;
switch(i%2)
{
case 1:PORTA=0x0F;break;
case 0:PORTA=0xF0;break;
}
_delay_ms(200);
}
void init_devices(void)
{
//stop errant interrupts until set up
cli(); //disable all interrupts
port_init();
MCUCR = 0x00;
GICR= 0x40;
TIMSK = 0x00; //timer interrupt sources
sei(); //re-enable interrupts
//all peripherals are now initialized
}
int main()
{
init_devices();
while(1)
{
sei();
}
return 0;
}
我使用这个程序没有你所说的问题。
1.INT0引脚一起接地:1-4和5-8是交替亮的。改变延时时间,则交替的频率也改变。说明延时是有效的。
2.手动触发中断,1-4和5-8是也交替亮。
3.不会的,因为在中断中有200ms的延时,这个时间足够去除抖动。
补充:
这个是我使用ICCV7.14版本的软件,由于没有delay.h和UseAVRPortBit.h,这里将其注释了,自己写了个延时函数,但时间不是很准,不影响测试。
#include
#include
//#include
//#include
volatile unsigned int i=0;
void Delay_ms(unsigned char ucData)
{
unsigned int j;
while(--ucData)
{
for(j = 0;j < 3000; j++);
}
}
void port_init(void)
{PORTA=0xF0;
DDRA= 0xFF;
PORTB = 0x00;
DDRB= 0x00;
PORTC = 0x00; //m103 output only
DDRC= 0x00;
PORTD = 0x00;
DDRD= 0x00;
}
#pragma interrupt_handler int0_isr:iv_INT0
void int0_isr(void)
{
//external interupt on INT0
i++;
switch(i%2)
{
case 1:PORTA=0x0F;break;
case 0:PORTA=0xF0;
}
Delay_ms(200);
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
MCUCR = 0x00;
GICR= 0x40;
TIMSK = 0x00; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
void main(void)
{
init_devices();
while(1)
{
SEI();
}
}
我使用以上软件进行测试,还是没有发现楼主所说的问题,楼主把delay.h和UseAVRPortBit.h也帖出来。
测试过程如下:
1.采用按键触发外部中断,都是交替变化的。
2.通过改变for(j = 0;j < 3000; j++);中的值,交替变化速度也随着变化,说明中断中使用延时函数还是有效的。
3.中断是不会发生重入的,对于AVR单片机,进入中断后,系统已经将全局中断屏蔽了,即使再次发生中断,也不会响应,除非在中断函数中将全局中断打开。这里还要说明的是,中断嵌套也只能嵌套优先级高的中断,除非进行特殊处理。
如果改成如下:
i++;
switch(i%8)
{
case 7:PORTA=0xFE;break;
case 6:PORTA=0xFD;break;
case 5:PORTA=0xFB;break;
case 4:PORTA=0xF7;break;
case 3:PORTA=0xEF;break;
case 2:PORTA=0xDF;break;
case 1:PORTA=0xBF;break;
case 0:PORTA=0x7F;break;
}
可实现更多的功能。
如果还是有问题,可以将你的硬件情况和整个软件发上来。
#include
#include
#include
#defineF_CPU 16000000UL
#include
volatile unsigned int i=0;
void port_init(void)
{
PORTA = 0xF0;
DDRA= 0xFF;
PORTB = 0x00;
DDRB= 0x00;
PORTC = 0x00;
DDRC= 0x00;
PORTD = 0x04;
DDRD= 0x00;
}
SIGNAL(SIG_INTERRUPT0)
{
i++;
switch(i%2)
{
case 1:PORTA=0x0F;break;
case 0:PORTA=0xF0;break;
}
_delay_ms(200);
}
void init_devices(void)
{
//stop errant interrupts until set up
cli(); //disable all interrupts
port_init();
MCUCR = 0x00;
GICR= 0x40;
TIMSK = 0x00; //timer interrupt sources
sei(); //re-enable interrupts
//all peripherals are now initialized
}
int main()
{
init_devices();
while(1)
{
sei();
}
return 0;
}
我使用这个程序没有你所说的问题。
1.INT0引脚一起接地:1-4和5-8是交替亮的。改变延时时间,则交替的频率也改变。说明延时是有效的。
2.手动触发中断,1-4和5-8是也交替亮。
3.不会的,因为在中断中有200ms的延时,这个时间足够去除抖动。
补充:
这个是我使用ICCV7.14版本的软件,由于没有delay.h和UseAVRPortBit.h,这里将其注释了,自己写了个延时函数,但时间不是很准,不影响测试。
#include
#include
//#include
//#include
volatile unsigned int i=0;
void Delay_ms(unsigned char ucData)
{
unsigned int j;
while(--ucData)
{
for(j = 0;j < 3000; j++);
}
}
void port_init(void)
{PORTA=0xF0;
DDRA= 0xFF;
PORTB = 0x00;
DDRB= 0x00;
PORTC = 0x00; //m103 output only
DDRC= 0x00;
PORTD = 0x00;
DDRD= 0x00;
}
#pragma interrupt_handler int0_isr:iv_INT0
void int0_isr(void)
{
//external interupt on INT0
i++;
switch(i%2)
{
case 1:PORTA=0x0F;break;
case 0:PORTA=0xF0;
}
Delay_ms(200);
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
MCUCR = 0x00;
GICR= 0x40;
TIMSK = 0x00; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
void main(void)
{
init_devices();
while(1)
{
SEI();
}
}
我使用以上软件进行测试,还是没有发现楼主所说的问题,楼主把delay.h和UseAVRPortBit.h也帖出来。
测试过程如下:
1.采用按键触发外部中断,都是交替变化的。
2.通过改变for(j = 0;j < 3000; j++);中的值,交替变化速度也随着变化,说明中断中使用延时函数还是有效的。
3.中断是不会发生重入的,对于AVR单片机,进入中断后,系统已经将全局中断屏蔽了,即使再次发生中断,也不会响应,除非在中断函数中将全局中断打开。这里还要说明的是,中断嵌套也只能嵌套优先级高的中断,除非进行特殊处理。
如果改成如下:
i++;
switch(i%8)
{
case 7:PORTA=0xFE;break;
case 6:PORTA=0xFD;break;
case 5:PORTA=0xFB;break;
case 4:PORTA=0xF7;break;
case 3:PORTA=0xEF;break;
case 2:PORTA=0xDF;break;
case 1:PORTA=0xBF;break;
case 0:PORTA=0x7F;break;
}
可实现更多的功能。
如果还是有问题,可以将你的硬件情况和整个软件发上来。
全部回答
- 1楼网友:傲气稳了全场
- 2021-02-20 19:33
在中断的全局变量前须加volatile
- 2楼网友:一秋
- 2021-02-20 18:18
你只要改下面的就行了。
#pragma interrupt_handler int0_isr:iv_INT0
void int0_isr(void)
{
//external interupt on INT0
多定义char k;
i++;
k=i%2;
switch(i)
{
case 1:PORTA=0x0F;
case 0:PORTA=0xF0;
}
Delay_ms(200);
}
#pragma interrupt_handler int0_isr:iv_INT0
void int0_isr(void)
{
//external interupt on INT0
多定义char k;
i++;
k=i%2;
switch(i)
{
case 1:PORTA=0x0F;
case 0:PORTA=0xF0;
}
Delay_ms(200);
}
- 3楼网友:蓝房子
- 2021-02-20 17:08
switch(i%2)
{
case 1:PORTA=0x0F;
case 0:PORTA=0xF0;
}
这里面应该加上break语句,加上去再试试!
{
case 1:PORTA=0x0F;
case 0:PORTA=0xF0;
}
这里面应该加上break语句,加上去再试试!
- 4楼网友:长青诗
- 2021-02-20 16:23
一个变量如果要在中断中改变它,且在主函数中用到,在它的定义前加个volatile
void port_init(void)的函数中,一定要先DDRA= 0xFF;后PORTA=0xF0;。
再就是中断函数中尽量不要写占用cpu的语句。delay函数就更别提了。
void port_init(void)的函数中,一定要先DDRA= 0xFF;后PORTA=0xF0;。
再就是中断函数中尽量不要写占用cpu的语句。delay函数就更别提了。
- 5楼网友:一袍清酒付
- 2021-02-20 14:51
可能有2点原因:
1. 中断服务中switch语句中没有break语句, 导致PORTA=0x0F;接着设定了PORTA=0xF0; 可能case 1时会出现闪或看不到效果.
2. 中断产生了重入. 导致中断服务再次打断,后果无法预知,建议修改如下(含第1点)
#pragma interrupt_handler int0_isr:iv_INT0
void int0_isr(void)
{
//external interupt on INT0
//stop errant interrupts
CLI(); //disable all interrupts
i++;
switch(i%2)
{
case 1:PORTA=0x0F;break;
case 0:PORTA=0xF0;break;
}
SEI(); //re-enable interrupts
Delay_ms(200);
}
另外还有1点最好检查下: 在中断中使用Delay_ms好用么?
补充:
因为在中断中延时函数是无效的.建议你修改下整个代码的机制:
中断中设定全局变量或发送消息,并禁止中断,在main()判断全局变量或接收消息,判断中断产生后设定PORTA,并延时200ms,延时时间到后再中断使能.
volatile BOOL intr_flag = FALSE;
void int0_isr(void)
{
//external interupt on INT0
//stop errant interrupts
CLI(); //disable all interrupts
intr_flag = TRUE;
}
...
void main(void)
{
init_devices();
while(1)
{
if (intr_flag == TRUE) {
i++;
switch(i%2)
{
case 1:PORTA=0x0F;break;
case 0:PORTA=0xF0;break;
}
Delay_ms(200);
intr_flag = FALSE;
SEI(); //re-enable interrupts
}
}
}
1. 中断服务中switch语句中没有break语句, 导致PORTA=0x0F;接着设定了PORTA=0xF0; 可能case 1时会出现闪或看不到效果.
2. 中断产生了重入. 导致中断服务再次打断,后果无法预知,建议修改如下(含第1点)
#pragma interrupt_handler int0_isr:iv_INT0
void int0_isr(void)
{
//external interupt on INT0
//stop errant interrupts
CLI(); //disable all interrupts
i++;
switch(i%2)
{
case 1:PORTA=0x0F;break;
case 0:PORTA=0xF0;break;
}
SEI(); //re-enable interrupts
Delay_ms(200);
}
另外还有1点最好检查下: 在中断中使用Delay_ms好用么?
补充:
因为在中断中延时函数是无效的.建议你修改下整个代码的机制:
中断中设定全局变量或发送消息,并禁止中断,在main()判断全局变量或接收消息,判断中断产生后设定PORTA,并延时200ms,延时时间到后再中断使能.
volatile BOOL intr_flag = FALSE;
void int0_isr(void)
{
//external interupt on INT0
//stop errant interrupts
CLI(); //disable all interrupts
intr_flag = TRUE;
}
...
void main(void)
{
init_devices();
while(1)
{
if (intr_flag == TRUE) {
i++;
switch(i%2)
{
case 1:PORTA=0x0F;break;
case 0:PORTA=0xF0;break;
}
Delay_ms(200);
intr_flag = FALSE;
SEI(); //re-enable interrupts
}
}
}
我要举报
如以上问答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
推荐资讯