嵌入式 C - 易失性限定符在我的中断例程中无关紧要
EMBEDDED C - Volatile qualifier does not matter in my interrupt routine
我是嵌入式 C 的新手,最近看了一些有关 volatile 限定符的视频。他们都提到了同样的事情。 volatile限定符的使用场景:
- 在 ISR(中断服务例程)中读取或写入变量时
- RTOS 应用程序或多线程(这不是我的情况)
- 内存映射 IO(这也不是我的情况)
我的问题是我的代码没有卡在下面的 whiletest();
函数中
当我的UART接收到数据然后触发void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
中断函数
int test;
int main(void)
{
test = 0;
MX_GPIO_Init();
MX_USART1_UART_Init();
HAL_UART_Receive_IT(&huart1, (uint8_t *)&ch, 1);
while (1)
{
Delay(500);
printf("the main is runing\r\n");
whiletest();
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
test = 1;
HAL_UART_Receive_IT(&huart1, (uint8_t *)&ch, 1);
}
}
void whiletest(void)
{
int count =0;
while(!test){
count++;
printf("%d\r\n",count);
Delay(2000);
}
}
我用的是keilIDE和stm32cubeIDE。我了解到,如果您选择 o2 或 o3 优化级别,编译器会优化一些指令。因此,我为构建选项选择了 o2 级别,但它似乎对我的代码没有影响。编译器不会优化 while 循环中的加载指令,并在 main 函数中缓存测试值 0
,正如 youtube 上的视频所教的那样。这很混乱。在什么情况下我应该使用 volatile 限定符同时保持我的代码优化(o2 或 o3 级别)。
注意:我用的是stm32h743zi (M7)
volatile
通知编译器对象容易产生副作用。这意味着它可以被不在程序执行路径中的东西改变。
因为您从不直接调用中断例程,编译器假定 test
变量永远不会是 1
。你需要告诉他(volatile
做到了)无论如何它都可能改变。
示例:
volatile int test;
void interruptHandler(void)
{
test = 1;
}
void foo(void)
{
while(!test);
LED_On();
}
编译器知道 test
可以以某种方式改变并且 总是 在 while
循环中读取它
foo:
push {r4, lr}
ldr r2, .L10
.L6:
ldr r3, [r2] //compiler reads the value of the test from the memory as it knows that it can change.
cmp r3, #0
beq .L6
bl LED_On
pop {r4, lr}
bx lr
.L10:
.word .LANCHOR0
test:
没有 volatile
编译器将假定 test
始终为零。
foo:
ldr r3, .L10
ldr r3, [r3]
cmp r3, #0
bne .L6
.L7:
b .L7 //dead loop here
.L6:
push {r4, lr}
bl LED_On
pop {r4, lr}
bx lr
.L10:
.word .LANCHOR0
test:
在您的代码中,如果对象被不在程序路径中的东西更改,您必须使用 volatile。
如果优化后的代码表现得好像优化器什么也没做,编译器可能只会优化(更改)代码。
在您的例子中,您在 while 循环中调用了两个函数(Delay 和 printf)。编译器看不到这些函数的作用,因为它们出现在单独的编译器单元中。因此,编译器必须假定它们可能会更改全局变量 test 的值,因此无法优化对 test 中值的检查。删除函数调用,编译器可能会优化测试值的检查。
我是嵌入式 C 的新手,最近看了一些有关 volatile 限定符的视频。他们都提到了同样的事情。 volatile限定符的使用场景:
- 在 ISR(中断服务例程)中读取或写入变量时
- RTOS 应用程序或多线程(这不是我的情况)
- 内存映射 IO(这也不是我的情况)
我的问题是我的代码没有卡在下面的 whiletest();
函数中
当我的UART接收到数据然后触发void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
中断函数
int test;
int main(void)
{
test = 0;
MX_GPIO_Init();
MX_USART1_UART_Init();
HAL_UART_Receive_IT(&huart1, (uint8_t *)&ch, 1);
while (1)
{
Delay(500);
printf("the main is runing\r\n");
whiletest();
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
test = 1;
HAL_UART_Receive_IT(&huart1, (uint8_t *)&ch, 1);
}
}
void whiletest(void)
{
int count =0;
while(!test){
count++;
printf("%d\r\n",count);
Delay(2000);
}
}
我用的是keilIDE和stm32cubeIDE。我了解到,如果您选择 o2 或 o3 优化级别,编译器会优化一些指令。因此,我为构建选项选择了 o2 级别,但它似乎对我的代码没有影响。编译器不会优化 while 循环中的加载指令,并在 main 函数中缓存测试值 0
,正如 youtube 上的视频所教的那样。这很混乱。在什么情况下我应该使用 volatile 限定符同时保持我的代码优化(o2 或 o3 级别)。
注意:我用的是stm32h743zi (M7)
volatile
通知编译器对象容易产生副作用。这意味着它可以被不在程序执行路径中的东西改变。
因为您从不直接调用中断例程,编译器假定 test
变量永远不会是 1
。你需要告诉他(volatile
做到了)无论如何它都可能改变。
示例:
volatile int test;
void interruptHandler(void)
{
test = 1;
}
void foo(void)
{
while(!test);
LED_On();
}
编译器知道 test
可以以某种方式改变并且 总是 在 while
循环中读取它
foo:
push {r4, lr}
ldr r2, .L10
.L6:
ldr r3, [r2] //compiler reads the value of the test from the memory as it knows that it can change.
cmp r3, #0
beq .L6
bl LED_On
pop {r4, lr}
bx lr
.L10:
.word .LANCHOR0
test:
没有 volatile
编译器将假定 test
始终为零。
foo:
ldr r3, .L10
ldr r3, [r3]
cmp r3, #0
bne .L6
.L7:
b .L7 //dead loop here
.L6:
push {r4, lr}
bl LED_On
pop {r4, lr}
bx lr
.L10:
.word .LANCHOR0
test:
在您的代码中,如果对象被不在程序路径中的东西更改,您必须使用 volatile。
如果优化后的代码表现得好像优化器什么也没做,编译器可能只会优化(更改)代码。
在您的例子中,您在 while 循环中调用了两个函数(Delay 和 printf)。编译器看不到这些函数的作用,因为它们出现在单独的编译器单元中。因此,编译器必须假定它们可能会更改全局变量 test 的值,因此无法优化对 test 中值的检查。删除函数调用,编译器可能会优化测试值的检查。