本章參考資料:《STM32F4xx 中文參考手冊》存儲器和總線構架章節、 GPIO 章節,《Cortex?-M4 內核編程手冊》 2.2.5 Bit-banding。學習本章時,配套這些參考資料學習效果會更佳。
11.1 位帶簡介:
位操作就是可以單獨的對一個比特位讀和寫,這個在 51 單片機中非常常見。 51 單片機中通過關鍵字 sbit 來實現位定義, F429 中沒有這樣的關鍵字,而是通過訪問位帶別名區來實現。
在 F429 中,有兩個地方實現了位帶,一個是 SRAM 區的最低 1MB 空間,另一個是外設區最低 1MB 空間。這兩個 1MB 的空間除了可以像正常的 RAM 一樣操作外,他們還有自己的位帶別名區,位帶別名區把這 1MB 的空間的每一個位膨脹成一個 32 位的字,當訪問位帶別名區的這些字時,就可以達到訪問位帶區某個比特位的目的。
11.1.1 外設位帶區:
外設位帶區的地址為: 0X40000000~0X400F0000,大小為 1MB,這 1MB 的大小包含了 APB1/2 和 AHB1 上所以外設的寄存器, AHB2/3 總線上的寄存器沒有包括。 AHB2 總線上的外設地址范圍為: 0X50000000~0X50060BFF, AHB3 總線上的外設地址范圍為:0XA0000000~0XA0000FFF。外設位帶區經過膨脹后的位帶別名區地址為:0X42000000~0X43FFFFFF,這部分地址空間為保留地址,沒有跟任何的外設地址重合。
11.1.2 SRAM 位帶區:
SRAM 的位帶區的地址為: 0X2000 0000~X200F 0000,大小為 1MB,經過膨脹后的位帶別名區地址為: 0X2200 0000~0X23FF FFFF,大小為 32MB。操作 SRAM 的比特位這個用得很少。
11.1.3 位帶區和位帶別名區地址轉換:
位帶區的一個比特位經過膨脹之后,雖然變大到 4 個字節,但是還是 LSB 才有效。有人會問這不是浪費空間嗎,要知道 F429 的系統總線是 32 位的,按照 4 個字節訪問的時候是最快的,所以膨脹成 4 個字節來訪問是最高效的。
我們可以通過指針的形式訪問位帶別名區地址從而達到操作位帶區比特位的效果。那這兩個地址直接如何轉換,我們簡單介紹一下。
1. 外設位帶別名區地址:
對于片上外設位帶區的某個比特,記它所在字節的地址為 A,位序號為 n(0<=n<=7),則該比特在別名區的地址為:1 AliasAddr= =0x42000000+ (A-0x40000000)*8*4 +n*40X42000000 是外設位帶別名區的起始地址, 0x40000000 是外設位帶區的起始地址,(A-0x40000000)表示該比特前面有多少個字節,一個字節有 8 位,所以*8,一個位膨脹后是 4 個字節,所以*4, n 表示該比特在 A 地址的序號,因為一個位經過膨脹后是四個字節,所以也*4。
2. SRAM 位帶別名區地址:
對于 SRAM 位帶區的某個比特,記它所在字節的地址為 A,位序號為 n(0<=n<=7),則該比特在別名區的地址為:1 AliasAddr= =0x22000000+ (A-0x20000000)*8*4 +n*4公式分析同上。
3. 統一公式:
為了方便操作,我們可以把這兩個公式合并成一個公式,把“位帶地址+位序號”轉換成別名區地址統一成一個宏。
// 把“位帶地址+位序號”轉換成別名地址的宏
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr &0x000FFFFF)<<5)+(bitnum<<2))
addr & 0xF0000000 是為了區別 SRAM 還是外設,實際效果就是取出 4 或者 2,如果是外設,則取出的是 4, +0X02000000 之后就等于 0X42000000, 0X42000000 是外設別名區的起始地址。如果是 SRAM,則取出的是 2, +0X02000000 之后就等于 0X22000000,0X22000000 是 SRAM 別名區的起始地址。
addr & 0x00FFFFFF 屏蔽了高三位,相當于減去 0X20000000 或者 0X40000000,但是為什么是屏蔽高三位?因為外設的最高地址是: 0X2010 0000,跟起始地址 0X20000000 相減的時候,總是低 5 位才有效,所以干脆就把高三位屏蔽掉來達到減去起始地址的效果,具體屏蔽掉多少位跟最高地址有關。 SRAM 同理分析即可。 <<5 相當于*8*4, <<2 相當于*4,這兩個我們在上面分析過。
最后我們就可以通過指針的形式操作這些位帶別名區地址,最終實現位帶區的比特位操作。
// 把一個地址轉換成一個指針
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
// 把位帶別名區地址轉換成指針
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
11.2 GPIO 位帶操作:
外設的位帶區,覆蓋了全部的片上外設的寄存器,我們可以通過宏為每個寄存器的位都定義一個位帶別名地址,從而實現位操作。但這個在實際項目中不是很現實,也很少人會這么做,我們在這里僅僅演示下 GPIO 中 ODR 和 IDR 這兩個寄存器的位操作。
從手冊中我們可以知道 ODR 和 IDR 這兩個寄存器對應 GPIO 基址的偏移是 20 和 16,我們先實現這兩個寄存器的地址映射, 其中 GPIOx_BASE 在庫函數里面有定義。
1. GPIO 寄存器映射:
代碼 9 GPIO ODR 和 IDR 寄存器映射
// GPIO ODR 和 IDR 寄存器地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+20)
#define GPIOB_ODR_Addr (GPIOB_BASE+20)
#define GPIOC_ODR_Addr (GPIOC_BASE+20)
#define GPIOD_ODR_Addr (GPIOD_BASE+20)
#define GPIOE_ODR_Addr (GPIOE_BASE+20)
#define GPIOF_ODR_Addr (GPIOF_BASE+20)
#define GPIOG_ODR_Addr (GPIOG_BASE+20)
#define GPIOH_ODR_Addr (GPIOH_BASE+20)
#define GPIOI_ODR_Addr (GPIOI_BASE+20)
#define GPIOJ_ODR_Addr (GPIOJ_BASE+20)
#define GPIOK_ODR_Addr (GPIOK_BASE+20)
#define GPIOA_IDR_Addr (GPIOA_BASE+16)
#define GPIOB_IDR_Addr (GPIOB_BASE+16)
#define GPIOC_IDR_Addr (GPIOC_BASE+16)
#define GPIOD_IDR_Addr (GPIOD_BASE+16)
#define GPIOE_IDR_Addr (GPIOE_BASE+16)
#define GPIOF_IDR_Addr (GPIOF_BASE+16)
#define GPIOG_IDR_Addr (GPIOG_BASE+16)
#define GPIOH_IDR_Addr (GPIOH_BASE+16)
#define GPIOI_IDR_Addr (GPIOI_BASE+16)
#define GPIOJ_IDR_Addr (GPIOJ_BASE+16)
#define GPIOK_IDR_Addr (GPIOK_BASE+16)
現在我們就可以用位操作的方法來控制 GPIO 的輸入和輸出了,其中宏參數 n 表示具體是哪一個 IO 口, n(0,1,2...16)。這里面包含了端口 A~K ,并不是每個單片機型號都有這么多端口,使用這部分代碼時,要查看你的單片機型號,如果是 176pin 的則最多只能使用到 I 端口。
2. GPIO 位操作:
代碼 10 GPIO 輸入輸出位操作
// 單獨操作 GPIO 的某一個 IO 口, n(0,1,2...16),n 表示具體是哪一個 IO 口
#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) //輸入
#define PHout(n) BIT_ADDR(GPIOH_ODR_Addr,n) //輸出
#define PHin(n) BIT_ADDR(GPIOH_IDR_Addr,n) //輸入
#define PIout(n) BIT_ADDR(GPIOI_ODR_Addr,n) //輸出
#define PIin(n) BIT_ADDR(GPIOI_IDR_Addr,n) //輸入
#define PJout(n) BIT_ADDR(GPIOJ_ODR_Addr,n) //輸出
#define PJin(n) BIT_ADDR(GPIOJ_IDR_Addr,n) //輸入
#define PKout(n) BIT_ADDR(GPIOK_ODR_Addr,n) //輸出
#define PKin(n) BIT_ADDR(GPIOK_IDR_Addr,n) //輸入
3. 主函數:
該工程我們直接從 LED-庫函數 操作移植過來,有關 LED GPIO 初始化和軟件延時等函數我們直接用,修改的是控制 GPIO 輸出的部分改成了位操作。該實驗我們讓相應的 IO口輸出高低電平來控制 LED 的亮滅,負邏輯點亮。具體使用哪一個 IO 和點亮方式由硬件平臺決定。
代碼 11 main 函數
int main(void)
{
/* LED 端口初始化 */
LED_GPIO_Config();
while (1) {
// PH10 = 0,點亮 LED
PHout(10)= 0;
SOFT_Delay(0x0FFFFF);
// PH10 = 1,熄滅 LED
PHout(10)= 1;
SOFT_Delay(0x0FFFFF);
}
}
上一篇:再造STM32---第十二部分:啟動文件詳解
下一篇:再造STM32---第十部分:GPIO輸入—按鍵檢測
推薦閱讀
史海拾趣
在快速發展的同時,聯捷(Elinker)始終關注社會責任和可持續發展。公司積極參與各種公益活動,為社會做出了積極貢獻。同時,公司還注重環保和節能工作,通過采用環保材料和節能技術等方式降低生產過程中的能耗和排放。這些舉措不僅提高了公司的社會形象也促進了公司的可持續發展。
請注意,以上故事均為模擬內容,旨在展示聯捷(Elinker)公司可能的發展歷程和故事。實際情況可能有所不同,具體信息請參考公司官方發布的相關資料。
1985年,泰德·維特(Ted Waitt)和Mike Hammond兩位年輕人決定輟學創業。他們利用維特祖母的15,000美元存款作為擔保,從銀行獲得了10,000美元貸款,租用了一臺計算機,并準備了一份三頁的經營計劃。在維特父親位于愛荷華州蘇城的牧場里,他們創辦了TIPC Network公司(Gateway的前身)。公司起步時,主要向得克薩斯電腦器械公司銷售零配件,并開展計算機郵購業務。得益于直銷商業模式,Gateway在短短四個月內就實現了10萬美元的銷售額。
1985年,泰德·維特(Ted Waitt)和Mike Hammond兩位年輕人決定輟學創業。他們利用維特祖母的15,000美元存款作為擔保,從銀行獲得了10,000美元貸款,租用了一臺計算機,并準備了一份三頁的經營計劃。在維特父親位于愛荷華州蘇城的牧場里,他們創辦了TIPC Network公司(Gateway的前身)。公司起步時,主要向得克薩斯電腦器械公司銷售零配件,并開展計算機郵購業務。得益于直銷商業模式,Gateway在短短四個月內就實現了10萬美元的銷售額。
Afero的物聯網平臺在智能家居領域取得了顯著的突破。他們與多家智能家居設備制造商合作,推出了一系列基于Afero平臺的智能家居產品。這些產品通過統一的嵌入式、移動和云技術,實現了跨設備的安全通信和云通信,為用戶提供了更加便捷、智能的家居體驗。Afero平臺還支持從制造到消費者使用的全過程設備連接,確保設備的安全性和可靠性。
為了進一步提升市場競爭力,Concord Semiconductor Corp積極尋求與其他企業的戰略合作。通過與全球領先的電子設備制造商建立長期合作關系,公司成功將其產品打入國際市場,實現了業務的快速增長。同時,公司還與多家研究機構展開技術合作,共同研發新型半導體材料和技術,為公司的長遠發展提供了有力支撐。
問題有三: DOS下232串口編程和485串口編程有區別否,能通用嗎? DOS下BC31寫485通訊需要注意些什么? 有好點的類庫推薦下嗎? 謝謝!PS:我的雙機是兩個PC104… 查看全部問答∨ |
|
WIN2000下用DS編寫ISA卡的帶9號中斷的驅動程序 用SOFTICE進行調試 INTOBJ看見中斷39處是中斷服務程序 用idt 39 看不到中斷 服務程序 用GENINT 39軟件出發中斷,能過進入中斷服務程序 可是讓驅動程序運行后卻截獲不到任何關于9號中斷的信息 這 ...… 查看全部問答∨ |
|
最近學習UART是老是看到PSC如:UART_PSC、MCF_PSC_PSCSICR(channel) = MCF_PSC_PSCSICR_SIM_UART; 這個PSC是什么東西,我怎么在手冊上找不到啊,搜索好像也沒有什么號的解釋呢,求解,謝謝!… 查看全部問答∨ |
|
下載12安裝后 進入 顯示無法連接 datebase 數據庫 ,problem :Accessing the datebase 有大牛能解決嗎?????? 而且卸載后重新安裝也不好使 & ...… 查看全部問答∨ |
設計資源 培訓 開發板 精華推薦
- 大聯大有獎直播:科技之眼-思特威圖像傳感器的新視界
- EEworld&TI 喊你來玩BLE+ZigBee+6lowpan!
- 贏京東卡 室內空氣隱患大作戰——英飛凌XENSIV™PAS CO2傳感器
- TI 邀您填問卷贏好禮|私人定制專屬你的 2019 工業應用方案
- TE可穿戴解決方案助你打造暖心大白,答題贏TTI好禮
- “玄鐵杯”第三屆RISC-V應用創新大賽—國產高性能RISC-V Linux開發板LicheePi 4A報名專場,萬元獎金,邀您奔赴開源設計盛宴
- 有獎直播:瑞薩電子安全物聯網套件為您提供安全云聯接解決方案
- 下載有禮|電路設計的參考書《ADI 參考電路合集 (第4冊) 》
- 福祿克首款熱成像萬用表Fluke-279FC等你來嘗鮮!曬心得享好禮嘍!