概述
关于NIOS中断服务函数中的变量在main函数中没有变化的问题
关键词:SOPC NIOS 中断
前段时间做NIOS的PIO中断时遇到一个问题,在中断处理函数中对一个全局变量进行赋值,然后在main函数中的whlie(1)循环中利用该全局变量进行条件判断,再执行其他指令。当main函数执行时遇到中断触发,进入中断服务函数中,对该全局变量进行赋值,接着退出中断,继续执行main函数中的while(1)的指令,但是该全局变量的值并未发生改变。
#include <stdio.h>
#include <altera_avalon_pio_regs.h>
#include <alt_types.h>
#include <unistd.h>
#include <system.h>
#include "sys/alt_irq.h"
alt_u8 led_en;
void key_isr()
{
alt_u8 data;
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(KEY_BASE, 0); //关闭按键中断
data = IORD_ALTERA_AVALON_PIO_EDGE_CAP(KEY_BASE) ;
if(data == 0x3)
{
}
else if(data & 0x1)
{
led_en = 1;
}
else if(data & 0x2)
{
led_en = 0;
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, 0);
}
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_BASE, 0x3); //清零所有捕获位
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(KEY_BASE, 0X3); //打开按键中断
}
int main(void)
{
alt_ic_isr_register(KEY_IRQ_INTERRUPT_CONTROLLER_ID,
KEY_IRQ,
key_isr,
0,
0);
IOWR_ALTERA_AVALON_PIO_DIRECTION(LED_BASE, 0xf); //设置方向为输出
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_BASE, 0x3); //清零所有捕获位
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(KEY_BASE, 0X3); //打开按键中断
while(1)
{
if(led_en == 1)
{
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, 0xf);
usleep(1000000);
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, 0);
usleep(1000000);
}
}
return 0;
}
如上述代码中,led_en为该全局变量,while(1)中为led闪烁的代码,当程序进入中断时,中断服务函数key_isr会将led_en的值变为1,退出中断后,执行main函数中的循环。但在实际执行中,中断服务函数已将led_en赋值为1,但在main函数中led_en的值并未被读取到。因此在while循环中的if判断语句一直为false。
经过分析后发现导致该问题发生的原因是在Eclipse中编译程序时,会对程序进行一定程度的优化。例如如下代码:XBYTE[2]=0x55; XBYTE[2]=0x56; XBYTE[2]=0x57; XBYTE[2]=0x58;
。
对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器却会对上述四条语句进行优化,认为只有XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。在本次线程内,当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中;以后再取变量值时,就直接从寄存器中取值;当变量值在本线程里改变时,会同时把变量的新值copy到该寄存器中,以便保持一致;当变量在因别的线程而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致。
因此针对该问题,解决方法有两种:一:关闭程序优化;二:不对该全局变量进行优化。
方法二比较简单,只需要在定义变量时在前面加上volatile,例如:volatile int led_en;使用volatile定义后的变量,系统在使用时总是重新从它所在的内存读取数据,而不是寄存器中,这样就可以避免变量的读取值与实际值不一致。
方法一需要在Eclipse中关闭代码优化选项,右键工程,选择properties,打开如下所示
在列出的选项中选中Nios Application Properties,将Optimization level 选择为off,点击apply,然后ok保存,接着再编译程序下载就不会出现上述问题。
总结
一个函数用了一个外部的变量,但这个变量在此函数中没有改变,只是引用,这时候编译器会去做优化,把它的值暂放在内部寄存器中,用的时候读取的是寄存器的值,而不是去访问它的地址取值,这样的话,当这个变量在外部发生了变化的时候,比如中断,或者另外的进程等等。但在这个函数里面就不能起作用,因为被优化后使用的是寄存器的值,还是原来的值,导致错误发生。这种情况下,就要加上这个volatile定义,就不会被优化了。
最后
以上就是稳重枫叶为你收集整理的关于NIOS中断服务函数中的变量在main函数中没有变化的问题关于NIOS中断服务函数中的变量在main函数中没有变化的问题的全部内容,希望文章能够帮你解决关于NIOS中断服务函数中的变量在main函数中没有变化的问题关于NIOS中断服务函数中的变量在main函数中没有变化的问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复