當(dāng)前位置:首頁 > 單片機(jī) > 單片機(jī)
[導(dǎo)讀]支持了位帶操作后,便可以使用普通的加載/儲(chǔ)存指令來對(duì)單一的比特進(jìn)行讀寫操作了。簡單而言,就是可以單獨(dú)的對(duì)一個(gè)比特位讀和寫。在F103中,有兩個(gè)地方實(shí)現(xiàn)了位帶操作,其中一個(gè)是SRAM區(qū)的最低1MB范圍,第二個(gè)則是片

支持了位帶操作后,便可以使用普通的加載/儲(chǔ)存指令來對(duì)單一的比特進(jìn)行讀寫操作了。簡單而言,就是可以單獨(dú)的對(duì)一個(gè)比特位讀和寫。在F103中,有兩個(gè)地方實(shí)現(xiàn)了位帶操作,其中一個(gè)是SRAM區(qū)的最低1MB范圍,第二個(gè)則是片內(nèi)外設(shè)區(qū)的最低1MB范圍。這兩個(gè)區(qū)中的地址除了可以像普通的RAM一樣使用外,它們還都有自己的“位帶別名區(qū)”,位帶別名區(qū)把每個(gè)比特膨脹成一個(gè)32位的字。當(dāng)你通過位帶別名區(qū)訪問這些字時(shí),就可以達(dá)到訪問原始比特的目的。


圖1.1位帶區(qū)與位帶別名區(qū)的膨脹對(duì)應(yīng)關(guān)系圖

支持位帶操作的兩個(gè)內(nèi)存區(qū)的范圍是:0x2000_0000‐0x200F_FFFF(SRAM區(qū)中的最低1MB);0x4000_0000‐0x400F_FFFF(片上外設(shè)區(qū)中的最低1MB)。外設(shè)位帶區(qū)經(jīng)過膨脹后的位帶別名區(qū)地址為:0X42000000~0X43FFFFFC,這部分地址空間為保留地址,沒有跟任何的外設(shè)地址重合。SRAM區(qū)經(jīng)過膨脹后的位帶別名區(qū)地址為:0X2200 0000~0X23FF FFFC,大小為32MB。

位帶區(qū)的一個(gè)比特位經(jīng)過膨脹之后,雖然變大到4個(gè)字節(jié),但是還是LSB才有效。有人會(huì)問這不是浪費(fèi)空間嗎,要知道F103的系統(tǒng)總線是32位的,按照4個(gè)字節(jié)訪問的時(shí)候是最快的,所以膨脹成4個(gè)字節(jié)來訪問是最高效的。我們可以通過指針的形式訪問位帶別名區(qū)地址從而達(dá)到操作位帶區(qū)比特位的效果。那這兩個(gè)地址直接如何轉(zhuǎn)換,下面簡單地介紹一下。

一、對(duì)于片上外設(shè)位帶區(qū)的某個(gè)比特,記它所在字節(jié)的地址為A,位序號(hào)為n(0<=n<=7),則該比特在別名區(qū)的地址為:

1.AliasAddr==0x42000000+ (A-0x40000000)*8*4 +n*4

0X42000000是外設(shè)位帶別名區(qū)的起始地址,0x40000000是外設(shè)位帶區(qū)的起始地址,(A-0x40000000)表示該比特位前面有多少個(gè)字節(jié),一個(gè)字節(jié)有8位,所以*8,一個(gè)位膨脹后是4個(gè)字節(jié),所以*4,n表示該比特在A地址的序號(hào),因?yàn)橐粋€(gè)位經(jīng)過膨脹后是四個(gè)字節(jié),所以也*4。

二、對(duì)于SRAM位帶區(qū)的某個(gè)比特,記它所在字節(jié)的地址為A,位序號(hào)為n(0<=n<=7),則該比特在別名區(qū)的地址為:

1.AliasAddr==0x22000000+ (A-0x20000000)*8*4 +n*4

公式的分析同上所示

三、上面公式的統(tǒng)一:

為了方便操作,我們可以把這兩個(gè)公式合并成一個(gè)公式,把"位帶地址+位序號(hào)"轉(zhuǎn)換成別名區(qū)地址統(tǒng)一成一個(gè)宏。

//把"位帶地址+位序號(hào)"轉(zhuǎn)換成別名地址的宏

2 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr &

0x000FFFFF)<<5)+(bitnum<<2))
addr&0xF0000000是為了區(qū)別SRAM還是外設(shè),實(shí)際效果就是取出4或者2,如果是外設(shè),則取出的是4,+0X02000000之后就等于0X42000000,0X42000000是外設(shè)別名區(qū)的起始地址。如果是SRAM,則取出的是2,+0X02000000之后就等于0X22000000,0X22000000是SRAM別名區(qū)的起始地址。

addr & 0x00FFFFFF屏蔽了高三位,相當(dāng)于減去0X20000000或者0X40000000,但是為什么是屏蔽高三位?因?yàn)橥庠O(shè)的最高地址是:0X2010 0000,跟起始地址0X20000000相減的時(shí)候,總是低5位才有效,所以干脆就把高三位屏蔽掉來達(dá)到減去起始地址的效果,具體屏蔽掉多少位跟最高地址有關(guān)。SRAM同理分析即可。<<5相當(dāng)于前面公式中的*8*4,<<2相當(dāng)于*4。

最后我們就可以通過指針的形式操作這些位帶別名區(qū)地址,最終實(shí)現(xiàn)位帶區(qū)的比特位操作。

//把一個(gè)地址轉(zhuǎn)換成一個(gè)指針
#defineMEM_ADDR(addr)*((volatileunsignedlong*)(addr))
//把位帶別名區(qū)地址轉(zhuǎn)換成指針
#defineBIT_ADDR(addr,bitnum)MEM_ADDR(BITBAND(addr,bitnum))
(后文有附上對(duì)*((volatileunsignedlong*)的理解)。

從手冊(cè)中我們可以知道ODR和IDR這兩個(gè)寄存器對(duì)應(yīng)GPIO基址的偏移是20和16,我們先實(shí)現(xiàn)這兩個(gè)寄存器的地址映射,其中GPIOx_BASE在庫函數(shù)里面有定義。接著根據(jù)下圖便可理解GPIO ODR和IDR寄存器映射代碼。



圖1.2寄存器起始地址

//IO口地址映射

#define GPIOA_ODR_Addr(GPIOA_BASE+12) //0x4001080C

#define GPIOB_ODR_Addr(GPIOB_BASE+12) //0x40010C0C

#define GPIOC_ODR_Addr(GPIOC_BASE+12) //0x4001100C

#define GPIOD_ODR_Addr(GPIOD_BASE+12) //0x4001140C

#define GPIOE_ODR_Addr(GPIOE_BASE+12) //0x4001180C

#define GPIOF_ODR_Addr(GPIOF_BASE+12) //0x40011A0C

#define GPIOG_ODR_Addr(GPIOG_BASE+12) //0x40011E0C

#define GPIOA_IDR_Addr(GPIOA_BASE+8) //0x40010808

#define GPIOB_IDR_Addr(GPIOB_BASE+8) //0x40010C08

#define GPIOC_IDR_Addr(GPIOC_BASE+8) //0x40011008

#define GPIOD_IDR_Addr(GPIOD_BASE+8) //0x40011408

#define GPIOE_IDR_Addr(GPIOE_BASE+8) //0x40011808

#define GPIOF_IDR_Addr(GPIOF_BASE+8) //0x40011A08

#define GPIOG_IDR_Addr(GPIOG_BASE+8) //0x40011E08

其中:

#define GPIOA_BASE(APB2PERIPH_BASE + 0x0800)

#define GPIOB_BASE(APB2PERIPH_BASE + 0x0C00)

#define GPIOC_BASE(APB2PERIPH_BASE + 0x1000)

#define GPIOD_BASE(APB2PERIPH_BASE + 0x1400)

#define GPIOE_BASE(APB2PERIPH_BASE + 0x1800)

#define GPIOF_BASE(APB2PERIPH_BASE + 0x1C00)

#define GPIOG_BASE(APB2PERIPH_BASE + 0x2000)

#define APB2PERIPH_BASE(PERIPH_BASE + 0x10000)

#define PERIPH_BASE((uint32_t)0x40000000)

//GPIO輸入輸出位操作

#define PAout(n)BIT_ADDR(GPIOA_ODR_Addr,n)//輸出

#define PAin(n)BIT_ADDR(GPIOA_IDR_Addr,n)//輸入

#define PBout(n)BIT_ADDR(GPIOB_ODR_Addr,n)//輸出

#define PBin(n)BIT_ADDR(GPIOB_IDR_Addr,n)//輸入

#define PCout(n)BIT_ADDR(GPIOC_ODR_Addr,n)//輸出

#define PCin(n)BIT_ADDR(GPIOC_IDR_Addr,n)//輸入

#define PDout(n)BIT_ADDR(GPIOD_ODR_Addr,n)//輸出

#define PDin(n)BIT_ADDR(GPIOD_IDR_Addr,n)//輸入

#define PEout(n)BIT_ADDR(GPIOE_ODR_Addr,n)//輸出

#define PEin(n)BIT_ADDR(GPIOE_IDR_Addr,n)//輸入

#define PFout(n)BIT_ADDR(GPIOF_ODR_Addr,n)//輸出

#define PFin(n)BIT_ADDR(GPIOF_IDR_Addr,n)//輸入

#define PGout(n)BIT_ADDR(GPIOG_ODR_Addr,n)//輸出

#define PGin(n)BIT_ADDR(GPIOG_IDR_Addr,n)//輸入

附:對(duì)*((volatile unsigned long*)的理解:

對(duì)于不同的計(jì)算機(jī)體系結(jié)構(gòu),設(shè)備可能是端口映射,也可能是內(nèi)存映射的。如果系統(tǒng)結(jié)構(gòu)支持獨(dú)立的IO地址空間,并且是端口映射,就必須使用匯編語言完成實(shí)際對(duì)設(shè)備的控制,因?yàn)镃語言并沒有提供真正的“端口”的概念。如果是內(nèi)存映射,那就方便的多了。

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

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

1. volatile變量可變?cè)试S除了程序之外的比如硬件來修改他的內(nèi)容2.訪問該數(shù)據(jù)任何時(shí)候都會(huì)直接訪問該地址處內(nèi)容,即通過cache提高訪問速度的優(yōu)化被取消。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉