打印
[STM32F1]

冒昧再次出现请教WHILE语句的问题

[复制链接]
楼主: gdszzyq
手机看帖
扫描二维码
随时随地手机跟帖
21
gdszzyq|  楼主 | 2015-5-12 10:31 | 只看该作者 回帖奖励 |倒序浏览
Xflyan 发表于 2015-5-12 10:24
可能在中断里被改变的全局变量,循环判断操作里没有动作的变量,建议都是 volatile 的
你的应用里 if 是 ...

你的意思是if每次都去读test这个变量,而while就只读第一次然后就吊死在哪了?那请问到底哪些变量要定义成volatile,哪些不用,比如IO需要吗

使用特权

评论回复
22
diweo| | 2015-5-12 10:57 | 只看该作者
本帖最后由 diweo 于 2015-5-12 11:01 编辑
gdszzyq 发表于 2015-5-12 10:31
你的意思是if每次都去读test这个变量,而while就只读第一次然后就吊死在哪了?那请问到底哪些变量要定义 ...

建议你再仔细琢磨琢磨16楼的话。
你设想的条件是(test<2000),但是编译器看到前面你刚刚test=0,因为0<2000,所以把条件变成(1)了。while还是不停执行,只不过每次都是while(1),而不是你写的while(test<2000).。
你说换if可以的,请你仔细比较一下你10楼贴的代码。

至于volatile,网上一大堆,自己看吧。


使用特权

评论回复
评论
gdszzyq 2015-5-12 11:32 回复TA
你的意思是因为while语句前面有test=0存在,因编译器优化原因就把"while(test<2000);"当成"while(1)"编译了?但我试过将test=0放到while(test<2000);语句后面也一样  
Xflyan 2015-5-12 11:16 回复TA
结果是这样的,编译器优化问题,就看楼主能不能理解什么是 编译器优化 了.... 
23
lvyunhua| | 2015-5-12 11:03 | 只看该作者
楼上正解!

使用特权

评论回复
24
Xflyan| | 2015-5-12 11:09 | 只看该作者
gdszzyq 发表于 2015-5-12 10:31
你的意思是if每次都去读test这个变量,而while就只读第一次然后就吊死在哪了?那请问到底哪些变量要定义 ...

volatile 易变的,也就是 容易被改变的变量都最好加上while 把 test 缓存到寄存器了,没有重新读内存

使用特权

评论回复
25
lei129210| | 2015-5-12 11:44 | 只看该作者
16楼正解。

使用特权

评论回复
26
294479435| | 2015-5-12 12:21 | 只看该作者
少一个test++吧

使用特权

评论回复
27
294479435| | 2015-5-12 12:23 | 只看该作者
test=0不能放while(1)里面

使用特权

评论回复
28
949155525| | 2015-5-12 12:23 | 只看该作者
加入volatile      编译原理不熟

使用特权

评论回复
29
949155525| | 2015-5-12 12:24 | 只看该作者
看下中断和非终端数据处理机制

使用特权

评论回复
30
gdszzyq|  楼主 | 2015-5-12 12:44 | 只看该作者
我曾经把程序改成这样,结果还是一样吊在while(flag);,我看还是Xflyan说的那样,是因为test这个变量没有定义成volatile类型,导致while一直读取的都是原来的初始值。
int main(void)
{
  SystemInit ();
  LED_Init();
  TIM6_Int_Init(10,7200);//10Khz的计数频率,计数到5000为500ms
  uart_init(9600);
  LED1=1;
  while (1)
  {
     LED1=!LED1;
     while(flag);
  }
}

void TIM6_IRQHandler(void)   //TIM3中断
{
        if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
        {
        TIM_ClearITPendingBit(TIM6, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源                
        test++;
        if(test>2000)flag=0;
                else flag=1;
        }
}

使用特权

评论回复
31
gdszzyq|  楼主 | 2015-5-12 12:45 | 只看该作者
以下是网上找来的:
由于cpu优化,有时候读取变量值并不是到内存去读,而是读寄存器。这个值在其他中断或者任务中被改变了,但是cpu又读取了缓存的值就不正确了。使用volatile修饰后不使用寄存器缓存值,每次都重新读取。

使用特权

评论回复
评论
Xflyan 2015-5-12 13:01 回复TA
就是这个意思 
32
springvirus| | 2015-5-12 13:01 | 只看该作者
如8楼所述,你大可以试试,因为本人就吃过volatile的亏了~~
中断中修改变量,外部判断变量值,怎么都不改变,加上volatile,一切OK!!

使用特权

评论回复
33
dtmcp| | 2015-5-12 13:08 | 只看该作者
看芯片有没有TIME6

使用特权

评论回复
34
Xflyan| | 2015-5-12 13:10 | 只看该作者
gdszzyq 发表于 2015-5-12 12:45
以下是网上找来的:
由于cpu优化,有时候读取变量值并不是到内存去读,而是读寄存器。这个值在其他中断或者 ...

编译器根据上下文的关系,来判断是否要做优化;如果没有告诉编译器这个变量是可能会被其它地方改变的(未加 volatile),编译器就会把当前内存的值缓存到寄存器(R0 ~ R12)中,然后直接判断寄存器里的值,这样可能增加执行速度;volatile 就是告诉编译器这个变量随时可能被改变,所以每次都要去读原始内存值
16楼的意思就是,编译器根据上下文关系(当前函数内,你没有告诉编译器变量会被中断改变),判断出 test < 2000 始终成立,直接当 while (1) 执行了....

使用特权

评论回复
35
gdszzyq|  楼主 | 2015-5-12 14:06 | 只看该作者
从来没用过这个变量类型,出了问题还不知道怎么回事,看来以后要将会变化的变量都定义成volatile类型得了。

使用特权

评论回复
36
awficel1| | 2015-5-12 15:24 | 只看该作者
gdszzyq 发表于 2015-5-12 09:22
真是这个原因造成的,改成volatile 类型就好了,我真是不明白了,为什么我用IF语句时就可以正常运行呢, ...

你这个问题我在430里也遇过。有时候就是要volatile。有时候也不用这样。真是怪啊。中断函数是不是跟main函数不在一个文件里?

使用特权

评论回复
37
gdszzyq|  楼主 | 2015-5-12 15:46 | 只看该作者
不在一个文件里

使用特权

评论回复
38
加油吧小鱼儿| | 2015-5-12 19:48 | 只看该作者
非常感谢大家,学习了!

使用特权

评论回复
39
mmuuss586| | 2015-5-12 20:14 | 只看该作者
程序跟踪下,看TEST有没有加;

使用特权

评论回复
40
wangliuliu566| | 2015-5-12 21:15 | 只看该作者
gdszzyq 发表于 2015-5-12 10:31
你的意思是if每次都去读test这个变量,而while就只读第一次然后就吊死在哪了?那请问到底哪些变量要定义 ...

其实养成良好的编程习惯,这类问题根本不是问题,既在中断中使用又在其他地方查询的变量,几乎都会加上
volatile修饰的,不加volatile修饰的话,开了优化时,大多会有问题,我自己遇到过一次,客户曾经也遇到过
一次,所以**犹新。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则