关于NIOS中断服务函数中的变量在main函数中没有变化的问题

关于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定义,就不会被优化了。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值