Myn*_*cks 5 c embedded volatile
我想要一些帮助,以便更好地理解以下段落的一部分:
"volatile关键字限定符表示变量可以在程序之外进行更改.例如,外部设备可能会将数据写入端口.编译器有时会暂时使用缓存或寄存器将值保存在内存位置以进行优化.如果外部写入修改了内存位置,则此更改不会反映在缓存或寄存器值中." (它出自本书:理解和使用c指针,第178-179页)
歧义我已经是这些词组之间:"持有的价值一个内存位置"和"如果外部写入修改内存位置".
我的问题是:我得到的印象是,如果外部设备将数据写入端口,该数据将存储到某个位置(???),然后它们将被存储到寄存器/缓存(??)然后在内部c语言源代码的变量.有些东西被我误解了.据我所知,正常的工作流程应该是:外部设备 - >小型临时缓冲区 - > RAM内存中的变量,(当数据从小工具传输到MCU的RAM时)
#define PORT 0xB0000000
unsigned int volatile * const port = (unsigned int*) PORT;
*port = 0x0BF4; // write to port
value = *port; // read from port
Run Code Online (Sandbox Code Playgroud)
内存映射的I/O设备不通过CPU内核的寄存器(或通常是高速缓存).这就是为什么他们是外部的,他们只是挂在内存总线上的某个地方,假装是内存.
因此,来自这种设备的值将直接出现在(对CPU)看起来像内存的内容中.
在你给出的例子中,这个:
*port = 0x0BF4; // write to port
Run Code Online (Sandbox Code Playgroud)
可能会导致A/D转换器开始转换,这个
value = *port; // read from port
Run Code Online (Sandbox Code Playgroud)
可以读取结果值.这不是一个非常典型的设计(A/D转换器往往比这更复杂,等等),但它是可能的.
如果编译器认为"嘿,只有从写入该值的位置读取",它可能会替换这两个语句
value = 0x0BF4; // "optimized", but broken since no more I/O occurs
Run Code Online (Sandbox Code Playgroud)
如果您试图从该A/D转换器读取值,这将毁了您的一天.
声明位置volatile告诉编译器不要对访问该位置的副作用做出任何假设.
如果你看看像STM32F4基于ARM的微控制器,它有大量的内存映射I/O(串行端口,USB控制器,以太网,定时器,A/D和D/A转换器,......他们都是那里加上一堆内部(对核心,但仍然是内存映射)的东西.