avr单片机 在中断函数了改变全局变变量的值,发生很奇怪的事情,在这里向各位高手请教了,谢谢,源程序如
#include<iom16v.h>#include<macros.h>#include<delay.h>#include<UseAVRPortBit.h>volatil...
#include <iom16v.h>
#include <macros.h>
#include <delay.h>
#include <UseAVRPortBit.h>
volatile unsigned int i=0;
void port_init(void)
{PORTA=0XF0;
DDRA = 0xFF;
PORTB = 0x00;
DDRB = 0x00;
PORTC = 0x00; //m103 output only
DDRC = 0x00;
PORTD = 0x04;
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;
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();
}
}
我觉得问题出现在,中断函数里面,具体状况:未发生中断,1-4号灯亮,当第一次发生中断时,本应该是5——8号灯亮,但不知为什么,会出现,等全灭,或全亮的怪现象,希望各位高手能够指点一下,问题解决了,我一定加分!
很抱歉,break; 是我后面忘加了,加了CLI();SEI();问题有了好转,但还是不能解决,只有中断发生的一瞬间,才会有5-8号灯亮,之后又变为1-4号灯亮,延时函数无效,且为什么有变回去了,希望高手能够详细解释一下,保证一定加分! 请问一下,会不会是按键中断无法去抖,i的值混乱造成的?
楼下的修改方法挺好的,可是如果我原本是想通过i的设置,实现根据按键次数实现不同功能,本来想实现三次分别代表不同的功能,上面的其实是出错后简化了的,因为觉得错误出现在i的值上,用楼下建议的intr_flag 标志只能实习2次的区别,不具有有一般性,希望高手能够在多多指教一下
为了感谢大家,我把分数提高到50,谢谢了,其实我最想知道的是出错的原因,非常感谢
谢谢, 展开
#include <macros.h>
#include <delay.h>
#include <UseAVRPortBit.h>
volatile unsigned int i=0;
void port_init(void)
{PORTA=0XF0;
DDRA = 0xFF;
PORTB = 0x00;
DDRB = 0x00;
PORTC = 0x00; //m103 output only
DDRC = 0x00;
PORTD = 0x04;
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;
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();
}
}
我觉得问题出现在,中断函数里面,具体状况:未发生中断,1-4号灯亮,当第一次发生中断时,本应该是5——8号灯亮,但不知为什么,会出现,等全灭,或全亮的怪现象,希望各位高手能够指点一下,问题解决了,我一定加分!
很抱歉,break; 是我后面忘加了,加了CLI();SEI();问题有了好转,但还是不能解决,只有中断发生的一瞬间,才会有5-8号灯亮,之后又变为1-4号灯亮,延时函数无效,且为什么有变回去了,希望高手能够详细解释一下,保证一定加分! 请问一下,会不会是按键中断无法去抖,i的值混乱造成的?
楼下的修改方法挺好的,可是如果我原本是想通过i的设置,实现根据按键次数实现不同功能,本来想实现三次分别代表不同的功能,上面的其实是出错后简化了的,因为觉得错误出现在i的值上,用楼下建议的intr_flag 标志只能实习2次的区别,不具有有一般性,希望高手能够在多多指教一下
为了感谢大家,我把分数提高到50,谢谢了,其实我最想知道的是出错的原因,非常感谢
谢谢, 展开
6个回答
展开全部
可能有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
}
}
}
展开全部
以下是我使用WINAVR+AVR Studio编译,程序如下:
#include <avr/io.h>
#include <avr/iom16.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
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 <iom16v.h>
#include <macros.h>
//#include <delay.h>
//#include <UseAVRPortBit.h>
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 <avr/io.h>
#include <avr/iom16.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
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 <iom16v.h>
#include <macros.h>
//#include <delay.h>
//#include <UseAVRPortBit.h>
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;
}
可实现更多的功能。
如果还是有问题,可以将你的硬件情况和整个软件发上来。
本回答被提问者采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
一个变量如果要在中断中改变它,且在主函数中用到,在它的定义前加个volatile
void port_init(void)的函数中,一定要先DDRA = 0xFF;后PORTA=0XF0;。
再就是中断函数中尽量不要写占用cpu的语句。delay函数就更别提了。
void port_init(void)的函数中,一定要先DDRA = 0xFF;后PORTA=0XF0;。
再就是中断函数中尽量不要写占用cpu的语句。delay函数就更别提了。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
你只要改下面的就行了。
#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);
}
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
switch(i%2)
{
case 1:PORTA=0X0F;
case 0:PORTA=0XF0;
}
这里面应该加上break语句,加上去再试试!
{
case 1:PORTA=0X0F;
case 0:PORTA=0XF0;
}
这里面应该加上break语句,加上去再试试!
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询