新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > STM32 _I _0 _IO volatile const

        STM32 _I _0 _IO volatile const

        作者: 時間:2016-12-03 來源:網絡 收藏
        __I、 __O 、__IO是什么意思?
        這是ST庫里面的宏定義,定義如下:
        #define __I volatile const /*!< defines read only permissions */
        #define __O volatile /*!< defines write only permissions */
        #define __IO volatile /*!< defines read / write permissions */


        顯然,這三個宏定義都是用來替換成 volatile 和 const 的,所以我們先要了解 這兩個關鍵字的作用:

        volatile
        簡單的說,就是不讓編譯器進行優化,即每次讀取或者修改值的時候,都必須重新從內存或者寄存器中讀取或者修改。

        一般說來,volatile用在如下的幾個地方:
        1、中斷服務程序中修改的供其它程序檢測的變量需要加volatile;
        2、多任務環境下各任務間共享的標志應該加volatile;
        3、存儲器映射的硬件寄存器通常也要加volatile說明,因為每次對它的讀寫都可能由不同意義;

        我認為這是區分C程序員和嵌入式系統程序員的最基本的問題。搞嵌入式的家伙們經常同硬件、中斷、RTOS等等打交道,所有這些都要求用到 volatile變量。不懂得volatile的內容將會帶來災難。假設被面試者正確地回答了這是問題(嗯,懷疑是否會是這樣),我將稍微深究一下,看一下這家伙是不是直正懂得volatile完全的重要性。
        1)一個參數既可以是const還可以是volatile嗎?解釋為什么。
        2); 一個指針可以是volatile 嗎?解釋為什么。
        3); 下面的函數有什么錯誤:
        int square(volatile int *ptr)
        {
        return *ptr * *ptr;
        }

        1)是的。一個例子是只讀的狀態寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應該試圖去修改它。
        2); 是的。盡管這并不很常見。一個例子是當一個中服務子程序修該一個指向一個buffer的指針時。
        3) 這段代碼有點變態。這段代碼的目的是用來返指針*ptr指向值的平方,但是,由于*ptr指向一個volatile型參數,編譯器將產生類似下面的代碼:
        int square(volatile int *ptr)
        {
        int a,b;
        a = *ptr;
        b = *ptr;
        return a * b;
        }
        由于*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:
        long square(volatile int *ptr)
        {
        int a;
        a = *ptr;
        return a * a;
        }



        const
        只讀變量,即變量保存在只讀靜態存儲區。編譯時,如何嘗試修改只讀變量,則編譯器提示出錯,就能防止誤修改。
        const與define
        兩者都可以用來定義常量,但是const定義時,定義了常量的類型,所以更精確一些(其實const定義的是只讀變量,而不是常量)。#define只是簡單的文本替換,除了可以定義常量外,還可以用來定義一些簡單的函數,有點類似內置函數。const和define定義的常量可以放在頭文件里面。(小注:可以多次聲明,但只能定義一次)

        const與指針
        int me;
        const int * p1=&me; //p1可變,*p1不可變 const 修飾的是 *p1,即*p1不可變
        int * const p2=&me; //p2不可變,*p2可變 const 修飾的是 p2,即p2不可變
        const int *const p3=&me; //p3不可變,*p3也不可變 前一個const 修飾的是 *p3,后一個const 修飾的是p3,兩者都不可變


        前面介紹了 volatile 和 const 的用法,不知道大家了解了沒?了解了后,下面的講解就更加容易了:
        __I :輸入口。既然是輸入,那么寄存器的值就隨時會外部修改,那就不能進行優化,每次都要重新從寄存器中讀取。也不能寫,即只讀,不然就不是輸入而是輸出了。
        __O :輸出口,也不能進行優化,不然你連續兩次輸出相同值,編譯器認為沒改變,就忽略了后面那一次輸出,假如外部在兩次輸出中間修改了值,那就影響輸出
        __IO:輸入輸出口,同上


        為什么加下劃線?

        原因是:避免命名沖突
        一般宏定義都是大寫,但因為這里的字母比較少,所以再添加下劃線來區分。這樣一般都可以避免命名沖突問題,因為很少人這樣命名,這樣命名的人肯定知道這些是有什么用的。
        經常寫大工程時,都會發現老是命名沖突,要不是全局變量沖突,要不就是宏定義沖突,所以我們要盡量避免這些問題,不然出問題了都不知道問題在哪里。


        volatile一般用在以下三個方面:

        1、中斷標志位

        2、多線程共享的變量

        3、狀態寄存器
        來自ouravr野火M3


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 南郑县| 中超| 彭山县| 泽普县| 屯留县| 资中县| 来宾市| 巴彦县| 漳浦县| 秀山| 清河县| 平邑县| 镇雄县| 北辰区| 额尔古纳市| 三门县| 保亭| 合作市| 常德市| 政和县| 五寨县| 眉山市| 北宁市| 台东县| 防城港市| 龙岩市| 青铜峡市| 宜州市| 河北省| 商水县| 阿克陶县| 北碚区| 九龙城区| 富阳市| 大悟县| 美姑县| 台江县| 淳化县| 凤翔县| 禄丰县| 通江县|