1. 程式人生 > 其它 >RISC-V MCU 應用筆記之最易變的關鍵詞 - volatile

RISC-V MCU 應用筆記之最易變的關鍵詞 - volatile

1、volatile關鍵字

volatile 是易變的、不穩定的意思。和const一樣是一種型別修飾符,volatile關鍵字修飾的變數,編譯器對訪問該變數的程式碼不再進行優化,從而可以提供對特殊地址的穩定訪問。
以前只是聽過這個關鍵詞,知道它的存在,但從來沒用過。用此文記錄下在開發RISC-V MCU過程中,未用volatile修飾標誌位變數,編譯器進行優化,導致程式執行異常。

2、Demo

開發中,常見的需求,主迴圈中根據中斷中修改的標誌位,執行不同的功能,

 1 #include "debug.h"
 2  
 3 uint8_t flag_interrupt = 0;
 4  
 5 int
main(void) 6 { 7 USART_Printf_Init(115200); 8 printf("SystemClk:%d\r\n",SystemCoreClock); 9 10 EXTI0_INT_INIT(); 11 12 while(1) 13 { 14 if(flag_interrupt == 1) 15 { 16 flag_interrupt = 0; 17 printf("do something\r\n"); 18 } 19 }
20 } 21 22 /* 外部中斷服務函式*/ 23 __attribute__((interrupt("WCH-Interrupt-fast"))) 24 void EXTI0_IRQHandler(void) 25 { 26 if(EXTI_GetITStatus(EXTI_Line0)==SET) //EXTI_GetITStatus用來獲取中斷標誌位狀態 27 { 28 flag_interrupt = 1; 29 printf("Run at EXTI\r\n"); 30 EXTI_ClearITPendingBit(EXTI_Line0); //
清除中斷標誌位 31 } 32 }

將程式下載至MCU後,給P1.0引腳下降沿觸發訊號,執行現象如下

進入中斷服務函式,改變了flag_interrupt的值,但是主函式仍然沒有執行相應的程式,很是奇怪,檢查反彙編程式碼,才發現是編譯器對flag_interrupt變數的訪問進行了優化,如圖,

1 278:    01271063              bne    a4,s2,278 <main+0x34>  # 不相等就跳轉至0x278的位置,即還是本條語句的位置,

可以看到,編譯器對flag_interrupt變數的訪問進行了優化,沒有重新去0x20000080的位置進行取值,而是每次都用a4暫存器的值與s2暫存器(值為1)比較,不相等還是跳回本條語句的位置,重複執行,導致即使在中斷中改變了其值,主迴圈中也不能執行對應的功能。這時候就需要使用volatile關鍵字對flag_interrupt進行修飾。

1 volatile uint8_t flag_interrupt = 0;

加了volatile關鍵字修飾flag_interrupt後,程式按照設定的預期執行,如下圖所示:

檢視反彙編程式碼,編譯器未對flag_interrupt變數進行優化,老老實實的每次去源地址0x20000080處取值訪問。