hoodng
发表于 2007-1-17 22:36:47
结构体里的成员,同样会被优化掉!
个人感觉在结构体里加volatile更好
chutiange_c
发表于 2007-1-25 20:42:06
非常感谢去笨先生的详述:)
AVR_AFA
发表于 2007-1-25 22:54:43
讲的太好了,我以前在用51时遇到过这样的问题,今于终于明白了。
oleon
发表于 2007-1-26 09:48:01
顶了,好久没有来这里看看了。
今天要好好看看
yxs1977
发表于 2007-1-26 13:29:28
顶,以前一直不理解这个关键字的用法,真是获益匪浅,谢谢啦
ChipArt
发表于 2007-1-26 16:07:47
我的理解:
http://www.chipart.cn/
xiao_qi
发表于 2007-1-26 20:57:02
不错不错,收藏了,顶!!
hersey
发表于 2007-2-2 14:11:16
请教处理这样的中断,像这样定义可以么,谢谢
unsigned long int ACU;
unsigned char flag;
volatile unsigned int ACF,BCF;
volatile unsigned long int ACC_BUF;
SIGNAL(SIG_INTERRUPT0)
{
if(!flag)
{
ACC_BUF=ACC_BUF+BCF;
if(ACC_BUF>=ACU)
{
ACC_BUF=0;
SBIT(PORTB,BIT(4));
TCCR0B=0x05;
}
}
else
ACF++;
}
Sidney.MARS
发表于 2007-4-14 21:46:44
精华就是精华……
winter
发表于 2007-4-14 22:20:33
很棒
maigoxx
发表于 2007-4-19 11:04:28
真可惜今天才看到呀!真是太好了!
收藏了!谢谢
sunzongmeng
发表于 2007-5-17 15:37:34
终于明白了,谢谢了.
baishuang0707
发表于 2007-5-28 21:40:13
讲的很明白 谢谢
feng200808
发表于 2007-9-18 19:54:03
hao!顶一个
lucy1211
发表于 2007-9-21 09:07:20
好啊。学习了
zhuzi1441
发表于 2007-9-21 23:08:47
又学到知识了,谢谢!
hmqxj
发表于 2007-9-23 23:45:46
quben 去笨
解释得真好,等我能看懂的时候再次好好体会一下,这一定会让我在以后再这样的问题上少走弯路的,谢谢了!!!
Xianglin
发表于 2007-9-28 17:10:52
讲的不错!
xiaorenren
发表于 2007-9-28 22:05:02
好也,顶下!
cao_zhihong_0
发表于 2007-9-30 10:07:42
顶quben ,好人啊!
sunke9
发表于 2007-10-4 16:35:42
好也,顶下!
chengjia535
发表于 2007-10-5 13:29:12
好,顶下!
sunmeng
发表于 2007-10-9 21:43:59
学习了!
minicatcatcn
发表于 2007-11-1 21:18:01
做个记号,继续学习
niejs
发表于 2007-11-1 23:24:00
向 quben 去笨 致敬。获益匪浅
darlin
发表于 2007-11-2 17:30:42
好!我得去叫我的C语言老师来这里学习才行呀~~
shark
发表于 2007-11-12 13:53:22
如果可以,请armok将此贴置顶吧,每天都有人问这个问题或因为这个问题程序不通.
yyccaa
发表于 2007-11-12 15:42:40
我也觉得阿莫应该整理一下论坛里帖子,做个索引置顶,分个新手入门、资料等类别。
否则像这个问题几乎每个月都有几贴,我们不回,新手会觉得这里太冷漠,但各个都回也麻烦,没那么多耐心。
wenxusun
发表于 2007-11-18 12:36:22
长见识
nick870208
发表于 2007-11-18 14:36:22
不错不错
一直不知道这个VOLATILE的用处,今天清楚了
irerror
发表于 2007-12-25 22:19:19
我刚也遇到此问题了,
加了VOLATILE就OK了!
win2kddk
发表于 2007-12-26 10:22:42
记号,以后备查
fox_wolf
发表于 2007-12-26 11:34:16
学到好东西
liudan_new
发表于 2007-12-26 17:17:47
学到了。
chuanhuibh
发表于 2007-12-27 20:53:35
困惑许久的问题已被楼主道破了,怎一个谢字了得
sdmcu51
发表于 2008-1-27 14:44:39
谢谢,好帖子
glen_cao
发表于 2008-2-14 21:51:13
经典
gao2006good
发表于 2008-2-15 09:18:26
困惑许久的问题已被楼主道破了,怎一个谢字了得
zds_share
发表于 2008-6-10 22:42:46
mark
jamiedu
发表于 2008-6-11 00:21:12
认真看一下。
bear1394
发表于 2008-6-11 03:09:56
作个记号
shhachqi
发表于 2008-6-16 18:53:27
好贴,顶一下!
zsy_zsy
发表于 2008-6-16 21:07:57
记录,收藏,谢谢!
knight_avr
发表于 2008-6-16 23:14:04
顶
非常感谢!!!!!
z_zt
发表于 2008-7-27 16:18:14
volatile!记号,收藏!
bjj9217
发表于 2008-7-27 17:40:37
受益匪浅!
sunshine_ljb
发表于 2008-9-8 17:02:01
谢谢
pally2004
发表于 2008-9-8 17:05:10
收藏~~
gphs
发表于 2008-9-8 19:46:33
我狂用,反正没有副作用
avenbbs
发表于 2008-9-8 20:33:43
这回算是理解个通透,以后可得注意了,不过也不能狂用吧。
caiyu
发表于 2008-9-8 21:04:39
很详细,受益非浅啊
lenyuye
发表于 2008-9-8 23:02:39
典型的例子
for ( int i=0; i<100000; i++);
这个语句用来测试空循环的速度的
但是编译器肯定要把它优化掉,根本就不执行
如果你写成
for ( volatile int i=0; i<100000; i++);
它就会执行了
这个例子还不是很明白噢,for ( int i=0; i<100000; i++); 不是死循环吗?
zlutian
发表于 2008-9-9 08:51:29
谢谢,mark
346675655
发表于 2008-9-9 09:10:27
这样的帖子我喜欢没理由不顶
yxlcarter
发表于 2008-9-9 09:28:38
谢谢,mark
duqinglin
发表于 2008-9-9 09:42:12
biaoji
fengxianjin
发表于 2008-9-9 09:47:55
MARK!
huike
发表于 2008-9-9 10:34:20
典型的例子
for ( int i=0; i<100000; i++);
这个语句用来测试空循环的速度的
但是编译器肯定要把它优化掉,根本就不执行
如果你写成
for ( volatile int i=0; i<100000; i++);
它就会执行了
在KEIL C51上试了这段代码,不管有没有volatile 都是会执行这个循环的。
letyoufly
发表于 2008-12-19 18:40:26
mark
ar3000a
发表于 2009-1-4 13:04:05
仔细学习了大家的讲解。非常感谢。 还有一件疑惑: 象下边这种volatile类型的结构体,在gcc中
到底如何实现的呢? 引用这个变量的时候,编译器会懂得关闭中断吗?
typedef struct _UART_BUF_
{
unsigned char counter;
unsigned char temp_buffer;
unsigned char uart_high;
unsigned char uart_low;
unsigned int uart_data;
}uartbuf;
volatile uartbuf uartdatum;
ar3000a
发表于 2009-1-4 13:35:23
#include <avr/io.h>
#include <avr/interrupt.h>
typedef struct _UART_BUF_
{
unsigned char counter;
unsigned char temp_buffer;
unsigned char uart_high;
unsigned char uart_low;
unsigned int uart_data;
}uartbuf;
volatile uartbuf u1;
int main(void)
{
PORTB|=(1<<PB2);
DDRB|=(1<<PB2);
TIFR|=(1<<OCF2)|(1<<TOV2);//定时器2,800毫秒
TCCR2 = 0x00; //
TCNT2 = 0x01; //
TIMSK = 0x40; //
TCCR2 = 0x03; //
u1.uart_high=u1.uart_low=0;
sei();
while(1)
{
//在下面这个计算过程中,有没有可能出现PB2=0的情况?编译器会不会编译出
//一个附带的cli()?
//上面的volatile能不能保护整个结构呢?怎样实现整个结构的updata同步呢?
u1.temp_buffer=(unsigned char)(u1.uart_low+u1.uart_high);
if(u1.temp_buffer==(u1.uart_low*2))
{
PORTB|=(1<<PB2);
}
else
{
PORTB&=~(1<<PB2);
}
}
}
ISR(TIMER2_OVF_vect)
{
++u1.uart_low;
++u1.uart_high;
}
本贴被 ar3000a 编辑过,最后修改时间:2009-01-04,13:39:48.
ar3000a
发表于 2009-1-4 13:46:18
编译出来了,结果很失望。
结论就是要注意自己添加cli();
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_570883.gif
(原文件名:vol.gif)
本贴被 ar3000a 编辑过,最后修改时间:2009-01-04,13:46:42.
ar3000a
发表于 2009-1-4 13:51:08
最后改成这样:
#include <avr/io.h>
#include <avr/interrupt.h>
typedef struct _UART_BUF_
{
unsigned char counter;
unsigned char temp_buffer;
unsigned char uart_high;
unsigned char uart_low;
unsigned int uart_data;
}uartbuf;
volatile uartbuf u1;
int main(void)
{
unsigned char i,j;
PORTB|=(1<<PB2);
DDRB|=(1<<PB2);
TIFR|=(1<<OCF2)|(1<<TOV2);//定时器2,800毫秒
TCCR2 = 0x00; //
TCNT2 = 0x01; //
TIMSK = 0x40; //
TCCR2 = 0x03; //
u1.uart_high=u1.uart_low=0;
sei();
while(1)
{
//这么做好麻烦那,有什么办法让编译器自动完成?
cli();
i=u1.uart_low; //关闭中断取数,防止意外更改
j=u1.uart_high;
sei();
u1.temp_buffer=(unsigned char)(i+j);
if(u1.temp_buffer==(i*2))
{
PORTB|=(1<<PB2);
}
else
{
PORTB&=~(1<<PB2);
}
}
}
ISR(TIMER2_OVF_vect)
{
++u1.uart_low;
++u1.uart_high;
}
ar3000a
发表于 2009-1-4 14:11:08
前面加了
#include <util/atomic.h>
编译出来就是这样了: 大家看看中断还能影响这个volatile吗?
20 main:
21 .LFB7:
22 .LM1:
23 /* prologue: function */
24 /* frame size = 0 */
25 .LM2:
26 0000 C29A sbi 56-32,2
27 .LM3:
28 0002 BA9A sbi 55-32,2
29 .LM4:
30 0004 88B7 in r24,88-32
31 0006 806C ori r24,lo8(-64)
32 0008 88BF out 88-32,r24
33 .LM5:
34 000a 15BC out 69-32,__zero_reg__
35 .LM6:
36 000c 81E0 ldi r24,lo8(1)
37 000e 84BD out 68-32,r24
38 .LM7:
39 0010 80E4 ldi r24,lo8(64)
40 0012 89BF out 89-32,r24
41 .LM8:
42 0014 83E0 ldi r24,lo8(3)
43 0016 85BD out 69-32,r24
44 .LM9:
45 0018 1092 0000 sts u1+3,__zero_reg__
46 001c 8091 0000 lds r24,u1+3
47 0020 8093 0000 sts u1+2,r24
48 .LM10:
49 /* #APP */
50 ; 27 "vol.c" 1
51 0024 7894 sei
52 ; 0 "" 2
53 .LVL0:
54 /* #NOAPP */
55 .L5:
56 .LBB7:
57 .LBB8:
58 .LBB9:
59 .LM11:
60 /* #APP */
61 ; 50 "d:/winavr/lib/gcc/../../avr/include/util/atomic.h" 1
62 0026 F894 cli
63 ; 0 "" 2
64 /* #NOAPP */
65 .LBE9:
66 .LBE8:
67 .LM12:
68 0028 8091 0000 lds r24,u1+3
69 .LVL1:
70 .LM13:
71 002c 2091 0000 lds r18,u1+2
72 .LVL2:
73 .LBB10:
74 .LBB11:
75 .LM14:
76 /* #APP */
77 ; 56 "d:/winavr/lib/gcc/../../avr/include/util/atomic.h" 1
78 0030 7894 sei
79 ; 0 "" 2
80 .LM15:
81 /* #NOAPP */
82 .LBE11:
83 .LBE10:
84 .LBE7:
85 .LM16:
86 0032 280F add r18,r24
87 0034 2093 0000 sts u1+1,r18
88 .LM17:
89 0038 2091 0000 lds r18,u1+1
90 .LVL3:
91 003c 30E0 ldi r19,lo8(0)
92 003e 90E0 ldi r25,lo8(0)
93 0040 880F lsl r24
94 0042 991F rol r25
95 .LVL4:
96 0044 2817 cp r18,r24
97 0046 3907 cpc r19,r25
98 0048 01F4 brne .L2
99 .LM18:
100 004a C29A sbi 56-32,2
101 004c 00C0 rjmp .L5
102 .L2:
103 .LM19:
104 004e C298 cbi 56-32,2
105 0050 00C0 rjmp .L5
106 .LFE7:
本贴被 ar3000a 编辑过,最后修改时间:2009-01-04,14:14:43.
eduhf_123
发表于 2009-1-4 14:47:26
这不是编译器的错,因为编译器不知道你访问该结构体时中断是打开的还是关闭的,所以如果它不管三七二十一前面加上“关中断”、后面加上“开中断”,就有可能造成误开中断;而如果它不管三七二十一只在前面加上“关中断”却不在完成后开中断,就有可能造成误关中断;最后,如果编译器自作主张使用一个变量保存中断开关状态后关中断,在完成后再恢复保存的中断开关状态,那么它就“犯法”了,因为所有内存单元都是用户(程序员)的而不是编译器的,它没有权力占用任何程序员没有定义成变量的内存单元。所以对长数据访问的完整性应当由程序员来保证。
不只是结构体有这个问题,任何“长数据”(超过CPU字长,无法用单条汇编指令完整访问)都存在这个问题;不只是在主程序和中断服务程序之间存在这个问题,中断服务程序与中断服务程序之间、多任务环境下的任务与任务之间都有这样的问题。
这其实已经涉及到一个新的东西——临界区,论坛中有傻孩子的帖子对此进行了比较详细的论述,感兴趣的坛友可以搜出来看看。
ar3000a
发表于 2009-1-4 15:23:10
eduhf_123 经历 讲得好!终于有了彻底的认识。
我又想到,上面那程序应该尽量做成这样:
#include <avr/io.h>
#include <avr/interrupt.h>
typedef struct _UART_BUF_
{
unsigned char counter;
unsigned char temp_buffer;
unsigned char uart_high;
unsigned char uart_low;
unsigned int uart_data;
}uartbuf;
volatile uartbuf u1;
volatile my_flag; //设定一个标志
int main(void)
{
unsigned char i,j;
PORTB|=(1<<PB2);
DDRB|=(1<<PB2);
TIFR|=(1<<OCF2)|(1<<TOV2);//定时器2,800毫秒
TCCR2 = 0x00; //
TCNT2 = 0x01; //
TIMSK = 0x40; //
TCCR2 = 0x03; //
u1.uart_high=u1.uart_low=0;
sei();
while(1)
{
if(my_flag==1) //把所有运算都放在主程序里
{
my_flag=0;
++u1.uart_low;
++u1.uart_high;
}
u1.temp_buffer=(unsigned char)(u1.uart_low+u1.uart_high);
if(u1.temp_buffer==(u1.uart_low*2))
{
PORTB|=(1<<PB2);
}
else
{
PORTB&=~(1<<PB2);
}
}
}
ISR(TIMER2_OVF_vect)
{
myflag=1;
}
eduhf_123
发表于 2009-1-4 16:27:58
对,不过这个时候u1就不需要声明成“volatile的”了。
而且,即使没有这个问题,通常也都建议把运算等放在主程序中,让中断服务程序尽快结束退出。
tiandinanhai
发表于 2009-1-4 20:59:58
学习了,
dozewolf
发表于 2009-1-9 17:45:12
终于明白我优化就不运行的问题了。。。MARK!!!
xml2028
发表于 2009-1-10 15:04:38
看的帖子越多就越发发现自己的无知
guiltcool
发表于 2009-1-11 16:26:37
又了解了volatile的用法。好好学习!
yanrz
发表于 2009-1-11 16:57:00
我从来就没有这样写过,不过程序也可以运行,不过我从来就没有开过优化!
vincent.r
发表于 2009-1-11 17:35:05
mark
sbsdys
发表于 2009-1-11 19:19:05
当初查过他的用法,记住了一句话:“可变,不优化。”
ts10606
发表于 2009-1-12 10:58:29
收教了!
djl310
发表于 2009-1-14 17:57:39
学习
vtest
发表于 2009-3-1 20:48:55
防优化
中断里修改的全局变量 必须加。。。
lgc-sdu
发表于 2009-4-18 16:42:14
受教了
lysoft
发表于 2009-4-18 18:47:11
C语言特色,呵呵
别的语言没这个的~例如Pascal,由编译器自行识别处理
tb8246
发表于 2009-4-18 22:36:17
好
goink
发表于 2009-4-18 23:24:26
mark
Adrian
发表于 2009-4-19 20:53:30
交流然后知不足学习了
makathy
发表于 2009-4-21 18:10:58
不错,在我解决问题 后才看到啊!!!!!
99zyj
发表于 2009-7-11 20:42:04
顶!!!
99zyj
发表于 2009-7-11 20:42:09
顶!!!
stefgq
发表于 2009-7-11 21:04:58
MARK
chengtina
发表于 2009-7-12 00:04:10
顶个
aohuahua
发表于 2009-7-12 17:30:27
mark!
deepin
发表于 2009-7-13 14:51:49
MARK
teltium
发表于 2009-7-13 16:05:29
很好
sunyouyuan
发表于 2009-7-13 16:49:21
终于知道volatile的用法了 顶!!
fandipeng412
发表于 2009-7-13 16:56:48
看过几次了,还是不能记住
guodong2002
发表于 2009-7-14 09:01:56
的确是不错的帖子,学习了!
mcuyongchao
发表于 2009-7-14 21:41:03
看了,受益匪浅!终于知道了为什么选择最大优化后程序就跑错的原因了
xczxwy
发表于 2009-7-14 21:50:17
看过一次,再看一次
cjbcjb
发表于 2009-7-14 21:55:31
看了,受益匪浅
hiferr
发表于 2009-9-26 11:06:23
学到了 ,要顶啊 !!!quben 去笨 是牛人
abuzhu
发表于 2009-9-26 12:40:04
Orz~
ikvc
发表于 2009-9-28 09:08:42
好贴,去面试嵌入式软件可定问到的问题,呵呵
fool_boy
发表于 2009-9-28 09:42:29
ding