OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 12893|回复: 25

变量定义前加__IO的疑问

[复制链接]

29

主题

81

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2015-6-10
在线时间
1 小时
发表于 2015-6-24 10:22:39 | 显示全部楼层 |阅读模式
5金钱
在有些程序中,经常会看到这样的变量定义,前面有加__IO,想问一下,这样定义的目的是什么?跟前面不加__IO有什么区别?
__IO   uint16_t TxCnt,RxCnt;  
__IO   FlagStatus  SendFlag,ReceiveFlag;

最佳答案

查看完整内容[请看2#楼]

回复【5楼】enginezhong: --------------------------------- 内存就是你MCU中的RAM MCU操作寄存器的速度比操作内存的速度快,所以编译器优化的时候,会把局部变量的值在使用时放到寄存器中(比如R1),后续需要操作这个临时变量时,就会直接找操作这个R1。但这样做有个问题,就是如果这时这个局部变量的在RAM中的值变了,就是说RAM上的值和寄存器R1的值不一致,这样MCU还操作R1上的值就会出现错误,为了避免这样的情况,这种值容 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2015-6-24 10:22:40 | 显示全部楼层
回复【5楼】enginezhong:
---------------------------------
内存就是你MCU中的RAM

MCU操作寄存器的速度比操作内存的速度快,所以编译器优化的时候,会把局部变量的值在使用时放到寄存器中(比如R1),后续需要操作这个临时变量时,就会直接找操作这个R1。但这样做有个问题,就是如果这时这个局部变量的在RAM中的值变了,就是说RAM上的值和寄存器R1的值不一致,这样MCU还操作R1上的值就会出现错误,为了避免这样的情况,这种值容易发生变话的变量就会用volatile(易变的)来修饰,这样的话,编译器就不会“自作聪明”吧值放到寄存器R1里操作,每次都会访问内存取最新的值进行操作,这样就不会出上述错误。你可以做个小实验,观察汇编语句就知道差别了

像R1这样的寄存器就十几个,只有在需要使用的时候才会被赋值。

如果你的程序需要避免上述情况,那就加volatile,确保操作正确
如果你的程序不会出现上述情况,那就不加volatile,这样编译器会优化变量操作,提供速度,一般情况下都不用volatile

关于volatile的使用可以百度一下,讲的比我详细
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2015-6-24 10:42:43 | 显示全部楼层
表示volatile修饰符,在STM库里__IO宏定义volatile
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复

使用道具 举报

29

主题

81

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2015-6-10
在线时间
1 小时
 楼主| 发表于 2015-6-24 11:02:20 | 显示全部楼层
回复【2楼】ianhom:
---------------------------------
没搞明白,为什么有些要加volatile修饰符,有写不用?
回复

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2015-6-24 11:05:44 | 显示全部楼层
回复【3楼】enginezhong:
---------------------------------
加volatile修饰符的基本作用就是不会被编译器优化,确保变量申请在内存中,每次访问该值的时候都是去内存中访问,而不是去寄存器中(编译器为了优化,会把变量值放到寄存器中并直接访问)
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复

使用道具 举报

29

主题

81

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2015-6-10
在线时间
1 小时
 楼主| 发表于 2015-6-24 16:37:58 | 显示全部楼层
回复【4楼】ianhom:
---------------------------------
回复【4楼】ianhom:
---------------------------------
好像还是没有特别明白,申请变量在内存中?你说的内存是哪个内存?是闪存还是SRAM啊?你说会把变量值放到寄存器中,还可以这样的吗?STM32有多少空间寄存器可以用来存放变量啊?
另外,一般什么情况下要加__IO?什么情况下可以不加啊?
回复

使用道具 举报

29

主题

81

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2015-6-10
在线时间
1 小时
 楼主| 发表于 2015-6-24 17:51:22 | 显示全部楼层
回复【6楼】ianhom:
---------------------------------
ianhom高手啊,看了之后明白很多了。。。
回复

使用道具 举报

10

主题

75

帖子

0

精华

初级会员

Rank: 2

积分
135
金钱
135
注册时间
2015-5-22
在线时间
0 小时
发表于 2015-8-31 18:43:46 | 显示全部楼层
回复【6楼】ianhom:
---------------------------------
厉害!
我建了一个战舰stm32交流群:320350722 新手请教老手,老手大显身手! stm32交流群:320350722 stm32交流群:320350722
回复

使用道具 举报

0

主题

12

帖子

0

精华

新手上路

积分
48
金钱
48
注册时间
2013-8-3
在线时间
4 小时
发表于 2015-9-1 18:30:08 | 显示全部楼层
茅塞顿开啊
回复

使用道具 举报

0

主题

10

帖子

0

精华

新手上路

积分
36
金钱
36
注册时间
2015-12-13
在线时间
2 小时
发表于 2015-12-13 18:02:53 | 显示全部楼层
我们当时老师是这样讲的
a = 1;
a = 0;
这两条语句,如果不加volatile的话,可能会被编译器优化成
a = 0;
于是第一句就没了。第一句在操作变量的时候确实没什么用,但是操作IO口的时候这是一个下降沿。
回复

使用道具 举报

29

主题

81

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2015-6-10
在线时间
1 小时
 楼主| 发表于 2015-12-14 15:48:33 | 显示全部楼层
回复【10楼】非吾愿:
---------------------------------
是的啊,另外我看库函数里面的寄存器变量的定义,也都加了volatile。
回复

使用道具 举报

5

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2016-4-10
在线时间
26 小时
发表于 2016-5-5 21:53:23 | 显示全部楼层
ianhom 发表于 2015-6-24 10:22
回复【5楼】enginezhong:
---------------------------------
内存就是你MCU中的RAM

MCU操作寄存器的速度 ...

那还请问
#define     __O     volatile                  /*!< defines 'write only' permissions     */
#define     __IO    volatile                  /*!< defines 'read / write' permissions   */
这两个有什么区别?定义的不是同一个类型吗
“做技术的不容易,能在技术路上走的很远的都是勇士!”看到一篇帖子这样说
回复

使用道具 举报

5

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2016-4-10
在线时间
26 小时
发表于 2016-5-5 21:53:48 | 显示全部楼层
ianhom 发表于 2015-6-24 10:42
表示volatile修饰符,在STM库里__IO宏定义volatile

那还请问
#define     __O     volatile                  /*!< defines 'write only' permissions     */
#define     __IO    volatile                  /*!< defines 'read / write' permissions   */
这两个有什么区别?定义的不是同一个类型吗
“做技术的不容易,能在技术路上走的很远的都是勇士!”看到一篇帖子这样说
回复

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2016-5-6 10:51:16 | 显示全部楼层
篮板痴汉玩蛋片 发表于 2016-5-5 21:53
那还请问
#define     __O     volatile                  /*!< defines 'write only' permissi ...

两个宏定义在代码预处理完成之后是一样的,都只是用了volatile来修饰。
这里用两个不同的宏名定义同一个volatile,是为了从代码阅读的角度做区别,帮助理解意图,__O表明'write only'权限,__IO表明'read / write'权限
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2016-5-6 11:04:36 | 显示全部楼层
非吾愿 发表于 2015-12-13 18:02
我们当时老师是这样讲的
a&nbsp;=&nbsp;1;
a&nbsp;=&nbsp;0;
这两条语句,如果不加volatile的话,可能会被 ...

恩,一般操作io的时候都是操作具体的寄存器,在定义这些寄存器地址的时候就会像你说的那样增加volatile
QQ截图20160506110155.png
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复

使用道具 举报

5

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2016-4-10
在线时间
26 小时
发表于 2016-5-10 21:07:00 | 显示全部楼层
ianhom 发表于 2016-5-6 10:51
两个宏定义在代码预处理完成之后是一样的,都只是用了volatile来修饰。
这里用两个不同的宏名定义同一个 ...

虽然现在还是不怎么明白 我先留着这个问题 谢谢啦
“做技术的不容易,能在技术路上走的很远的都是勇士!”看到一篇帖子这样说
回复

使用道具 举报

60

主题

409

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2814
金钱
2814
注册时间
2012-10-17
在线时间
653 小时
发表于 2016-9-22 14:05:17 | 显示全部楼层
之前不是有一篇譬喻的很好,好像也在這個論壇

類似是說
一個作業員每隔10分鐘要去查表作一次記錄
忽然主管詢問他"現在"表的值是多少
如果有volatile =>作業員一定要再去查表後才能回報主管 (速度慢)
沒有volatile    =>作業員根據上一次的記錄回報主管 (速度快,但數值可能已經不一樣了)

如果某的位址裡面存放的數據是會被硬體改變的(狀態寄存器之類的...)
那就必須加上volatile修飾的...不然讀取該位址時有可能會拿通用寄存器裡的數值..
回复

使用道具 举报

0

主题

3

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2015-9-19
在线时间
23 小时
发表于 2016-10-15 17:48:46 | 显示全部楼层
学习了.
回复

使用道具 举报

7

主题

90

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
325
金钱
325
注册时间
2016-10-21
在线时间
43 小时
发表于 2016-10-25 12:46:48 | 显示全部楼层
一般中断里用到的变量,中断函数中调用其他函数用到的变量,要用volatile,否则会有意想不到的问题。
回复

使用道具 举报

0

主题

56

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
254
金钱
254
注册时间
2015-10-15
在线时间
39 小时
发表于 2016-11-1 20:18:35 | 显示全部楼层
volatile关键字:说明变量在程序执行中可被隐含地改变。
/*STM32F10x 固件库旧的变量类型 (为了传统目的而维护) /
typedef int32_t  s32;
typedef int16_t s16;
typedef int8_t  s8;

typedef const int32_t sc32;  /*!< Read Only */
typedef const int16_t sc16;  /*!< Read Only */
typedef const int8_t sc8;   /*!< Read Only */

typedef __IO int32_t  vs32;
typedef __IO int16_t  vs16;
typedef __IO int8_t   vs8;

typedef __I int32_t vsc32;  /*!< Read Only */
typedef __I int16_t vsc16;  /*!< Read Only */
typedef __I int8_t vsc8;   /*!< Read Only */

typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;

typedef const uint32_t uc32;  /*!< Read Only */
typedef const uint16_t uc16;  /*!< Read Only */
typedef const uint8_t uc8;   /*!< Read Only */

typedef __IO uint32_t  vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t  vu8;

typedef __I uint32_t vuc32;  /*!< Read Only */
typedef __I uint16_t vuc16;  /*!< Read Only */
typedef __I uint8_t vuc8;   /*!< Read Only */

//#ifndef __cplusplus
typedef enum {FALSE = 0, TRUE = !FALSE} bool;
//#endif
//typedef enum {FALSE = 0, TRUE = !FALSE} BOOL;
typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;

typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))

typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;

/*STM32F10x 固件库旧的宏定义 (为了传统目的而维护) /
#define HSEStartUp_TimeOut   HSE_STARTUP_TIMEOUT
#define HSE_Value            HSE_VALUE
#define HSI_Value            HSI_VALUE
回复

使用道具 举报

0

主题

56

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
254
金钱
254
注册时间
2015-10-15
在线时间
39 小时
发表于 2016-11-1 20:42:35 | 显示全部楼层
本帖最后由 jpaekeo 于 2016-11-1 21:07 编辑

typedef和#define的不同?
typedef命名一个新的数据类型,但实际上这个新的数据类型是已经存在的,只不过是定义了一个新的名字。
#define只是一个标号的定义。
参考:http://blog.csdn.net/zuoquan24/article/details/8617233
回复

使用道具 举报

0

主题

56

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
254
金钱
254
注册时间
2015-10-15
在线时间
39 小时
发表于 2017-3-9 16:03:14 | 显示全部楼层
都是大神!看完之后对于变量类型前加__IO还有__O的问题总于理解了,茅塞顿开呀
回复

使用道具 举报

1

主题

31

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
310
金钱
310
注册时间
2016-7-29
在线时间
58 小时
发表于 2017-3-23 17:30:08 | 显示全部楼层
讲得比较好,现在STM32的库中,大量使用这种方式,值得重视。
回复

使用道具 举报

0

主题

12

帖子

0

精华

高级会员

Rank: 4

积分
920
金钱
920
注册时间
2015-5-12
在线时间
80 小时
发表于 2020-2-17 23:14:22 | 显示全部楼层
厉害厉害  学习了
回复

使用道具 举报

0

主题

12

帖子

0

精华

高级会员

Rank: 4

积分
920
金钱
920
注册时间
2015-5-12
在线时间
80 小时
发表于 2020-2-17 23:15:34 | 显示全部楼层
厉害厉害  学习了
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
12
金钱
12
注册时间
2019-1-1
在线时间
2 小时
发表于 2020-3-29 22:25:26 | 显示全部楼层
学习了!谢谢!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-25 11:53

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表