RISC-V MCU 應用筆記之最易變的關鍵詞 - volatile
阿新 • • 發佈:2022-05-27
1、volatile關鍵字
volatile 是易變的、不穩定的意思。和const一樣是一種型別修飾符,volatile關鍵字修飾的變數,編譯器對訪問該變數的程式碼不再進行優化,從而可以提供對特殊地址的穩定訪問。
以前只是聽過這個關鍵詞,知道它的存在,但從來沒用過。用此文記錄下在開發RISC-V MCU過程中,未用volatile修飾標誌位變數,編譯器進行優化,導致程式執行異常。
2、Demo
開發中,常見的需求,主迴圈中根據中斷中修改的標誌位,執行不同的功能,
1 #include "debug.h" 2 3 uint8_t flag_interrupt = 0; 4 5 intmain(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處取值訪問。