久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4798|回復(fù): 0
收起左側(cè)

嵌入式的C程序中(*(volatile unsigned long *)的理解

[復(fù)制鏈接]
ID:90762 發(fā)表于 2018-10-22 13:41 | 顯示全部樓層 |閱讀模式
嵌入式的C程序中(*(volatile unsigned long *)的理解
  (*(volatile unsigned long *)
  
    對于不同的計算機體系結(jié)構(gòu),設(shè)備可能是端口映射,也可能是內(nèi)存映射的。如果系統(tǒng)結(jié)構(gòu)支持獨立的IO地址空間,并且是端口映射,就必須使用匯編語言完成實際對設(shè)備的控制,因為C語言并沒有提供真正的“端口”的概念。如果是內(nèi)存映射,那就方便的多了。
       
    Volatile    表示可隨硬件端口變化。
   
   

以 #define    IOPIN (*((volatile unsigned long *) 0xE0028000)) 為例:作為一個宏定義語句,define是定義一個變量或常量的偽指令。首先( volatile unsigned long * )的意思是將后面的那個地址強制轉(zhuǎn)換成 volatile unsigned long * ,unsigned long    * 是無符號長整形,volatile 是一個類型限定符,如const一樣,當(dāng)使用volatile限定時,表示這個變量是依賴系統(tǒng)實現(xiàn)的,以為著這個變量會被其他程序或者計算機硬件修改,由于地址依賴于硬件,volatile就表示他的值會依賴于硬件。

   
    volatile 類型是這樣的,其數(shù)據(jù)確實可能在未知的情況下發(fā)生變化。比如,硬件設(shè)備的終端更改了它,現(xiàn)在硬件設(shè)備往往也有自己的私有內(nèi)存地址,比如顯存,他們一般是通過映象的方式,反映到一段特定的內(nèi)存地址當(dāng)中,這樣,在某些條件下,程序就可以直接訪問這些私有內(nèi)存了。另外,比如共享的內(nèi)存地址,多個程序都對它操作的時候。你的程序并不知道,這個內(nèi)存何時被改變了。如果不加這個voliatile修飾,程序是利用catch當(dāng)中的數(shù)據(jù),那個可能是過時的了,加了 voliatile,就在需要用的時候,程序重新去那個地址去提取,保證是最新的。歸納起來如下:
    1.    volatile變量可變允許除了程序之外的比如硬件來修改他的內(nèi)容
    2. 訪問該數(shù)據(jù)任何時候都會直接訪問該地址處內(nèi)容,即通過cache提高訪問速度的優(yōu)化被取消

   
   

對于((volatile unsigned long *) 0xE0028000)為隨硬件需要定義的一種地址,前面加上“*”指針,為直接指向該地址,整個定義約定符號IOPIN代替,調(diào)用的時候直接對指向的地址寄存器寫內(nèi)容既可。這實際上就是內(nèi)存映射機制的方便性了。其中volatile關(guān)鍵字是嵌入式系統(tǒng)開發(fā)的一個重要特點。上述表達(dá)式拆開來分析,首先(volatile    unsigned long *) 0xE0028000的意思是把0xE0028000強制轉(zhuǎn)換成volatile unsigned long類型的指針,暫記為p,那么就是#define A *p,即A為P指針指向位置的內(nèi)容了。這里就是通過內(nèi)存尋址訪問到寄存器A,可以讀/寫操作。

   
   

對于(volatile unsigned char *)0x20我們再分析一下,它是由兩部分組成:
    1)(unsigned char *)0x20,0x20只是個值,前面加(unsigned char *)表示0x20是個地址,(等效#define A *p  )而且這個地址類型是unsigned    char ,意思是說讀寫這個地址時,要寫進(jìn)unsigned char 的值,讀出也是unsigned char 。
   
   

   
   
   

2)volatile,關(guān)鍵字volatile 確保本條指令不會因C 編譯器的優(yōu)化而被省略,且要求每次直接讀值。例如用while((unsigned char *)0x20)時,有時系統(tǒng)可能不真正去讀0x20的值,而是用第一次讀出的值,如果這樣,那這個循環(huán)可能是個死循環(huán)。用了volatile    則要求每次都去讀0x20的實際值。
   
      那么(volatile unsigned char *)0x20是一個固定的指針,是不可變的,不是變量。而char *u則是個指針變量。
      

   

再在前面加"*":*(volatile    unsigned char *)0x20則變成了變量(普通的unsigned char變量,不是指針變量),如果#define i (*(volatile unsigned char *)0x20),那么與(等效unsigned char i)  是一樣了,只不過前面的i的地址是固定的。
   
   

    那么如何對這條語句進(jìn)行理解呢?
   
    首先,我們來分析define語句后面的內(nèi)容: (*(volatile unsigned char *)0x20),首先看到里面使用了關(guān)鍵字volatile和數(shù)據(jù)類型unsigned char以及C語言中的地址引用符號“*”,將這段代碼拆開來看, (unsigned char *)0x20中0x20是一個地址,其存儲數(shù)據(jù)的類型為unsigned char型,即一個8位的二進(jìn)制數(shù)據(jù),如一個8位的寄存器。利用關(guān)鍵字volatile對其進(jìn)行修飾(volatile unsigned char *)0x20則表示這個地址中存放的數(shù)據(jù)容易被外部所軟件/硬件改變,告訴編譯器不要去優(yōu)化該條語句,每次執(zhí)行時均從該地址中去讀取這個值。再在(volatile unsigned char *)0x20的前面加上地址引用符號"*"則表示一個指針對應(yīng)的變量,則這條語句就成為了一個可操作的指針?biāo)赶虻牡刂穬?nèi)容,相當(dāng)于*p,只不過這兒p的地址固定為了0x20,*p所指向的數(shù)據(jù)類型定義為了unsigned char,最后將define后面的內(nèi)容用括號括起來,這是一個良好的編程習(xí)慣!最終就形成了我們所看到的 (*(volatile unsigned char *)0x20)形式。
    ---------------------
    實例
   

以前看到#define SREG    (*(volatile    unsigned char *)0x5F)這樣的定義,總是感覺很奇怪,不知道為什么,今天終于有了一點點心得,請大蝦們多多批磚~~~
         嵌入式系統(tǒng)編程,要求程序員能夠利用C語言訪問固定的內(nèi)存地址。既然是個地址,那么按照C語言的語法規(guī)則,這個表示地址的量應(yīng)該是指針類型。所以,知道要訪問的內(nèi)存地址后,比如0x5F,
         第一步是要把它強制轉(zhuǎn)換為指針類型
    (unsigned    char *)0x5F,AVR的SREG是八位寄存器,所以0x5F強制轉(zhuǎn)換為指向unsigned char類型。
       volatile(可變的)這個關(guān)鍵字說明這變量可能會被意想不到地改變,這樣編譯器就不會去假設(shè)這個變量的值了。這種“意想不到地改變”,不是由程序去改變,而是由硬件去改變

   
   


       第二步,對指針變量解引用,就能操作指針?biāo)赶虻牡刂返膬?nèi)容了
       *(volatile unsigned char *)0x5F
       第三步,小心地把#define宏中的參數(shù)用括號括起來,這是一個很好的習(xí)慣,所以#define SREG    (*(volatile    unsigned char *)0x5F)
        類似的,如果使用一個32位處理器,要對一個32位的內(nèi)存地址進(jìn)行訪問,可以這樣定義:
        #define RAM_ADDR     (*(volatile    unsigned long  *)0x0000555F)
        然后就可以用C語言對這個內(nèi)存地址進(jìn)行讀寫操作了
        以下與普通操作一樣

   

讀:tmp =    RAM_ADDR;
         寫:RAM_ADDR = 0x55

   
   
      
結(jié)論:那么你的問題就可解答了,(*(volatile unsigned char *)0x20)可看作是一個普通變量,這個變量有固定的地址,指向0x20。而0x20只是個常量,不是指針更不是變量。
   
  
用法
在嵌入式的C程序中,我們經(jīng)常看到類似如下的定義:
#define AAA  (*(volatile unsigned char *)0x20)  取內(nèi)容等效(X=5
#define BBB  (*(volatile unsigned char *)0x4B000020)
讀temp=AAA;

寫AAA=X22;

完整的Word格式文檔51黑下載地址:
volatile unsigned long.zip (16.96 KB, 下載次數(shù): 14)


評分

參與人數(shù) 2黑幣 +55 收起 理由
sad520ljh + 5 共享資料的黑幣獎勵!
admin + 50 共享資料的黑幣獎勵!

查看全部評分

回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 国产91久久久久蜜臀青青天草二 | 久久久免费在线观看 | 亚洲人成人一区二区在线观看 | 国产乱码久久久 | 成人毛片视频免费 | 日韩欧美三级在线 | 美女视频网站久久 | 国产中文原创 | 在线观看的av | 久久精品国产精品青草 | 日韩欧美在线观看视频 | 国产成人一区二区三区 | 狠狠干网| 国产综合精品一区二区三区 | 91欧美精品成人综合在线观看 | 成人一级片在线观看 | 国产精品v| 国产精品九九九 | 成人免费视频 | 9色网站 | 91久久精品一区二区二区 | 精品视频在线播放 | 精品在线观看一区二区 | 九九热免费看 | 精品国产一区二区三区久久影院 | 亚洲欧美中文日韩在线 | 毛片免费视频 | 国产精品一区二区不卡 | 欧美日韩国产一区二区 | 欧美一区二区三区日韩 | 免费成人在线网站 | 久久精品99 | 国产成人一区二区三区久久久 | 日韩黄| 久久最新 | 91久久精品日日躁夜夜躁国产 | 国产三级日本三级 | 一级做受毛片免费大片 | 婷婷桃色网 | 中文字幕av免费 | 久久国产三级 |