找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

拋磚引玉之位段操作

[復(fù)制鏈接]
ID:64689 發(fā)表于 2014-8-20 16:24 | 顯示全部樓層 |閱讀模式
拋磚引玉之位段操作
回復(fù)

使用道具 舉報

ID:51088 發(fā)表于 2014-8-20 17:00 | 顯示全部樓層
Cortex?-M3存儲器映像包括兩個位段(bit-band)區(qū)。這兩個位段區(qū)將別名存儲器區(qū)中的每個字映射到位段存儲器區(qū)的一個位,在別名存儲區(qū)寫入一個字具有對位段區(qū)的目標位執(zhí)行讀-改-寫操作的相同效果。
在STM32F10xxx里,外設(shè)寄存器和SRAM都被映射到一個位段區(qū)里,這允許執(zhí)行單一的位段的寫和讀操作。
下面的映射公式給出了別名區(qū)中的每個字是如何對應(yīng)位帶區(qū)的相應(yīng)位的:
bit_word_addr = bit_band_base + (byte_offset x 32) + (bit_number × 4)
其中:
bit_word_addr是別名存儲器區(qū)中字的地址,它映射到某個目標位。
bit_band_base是別名區(qū)的起始地址。
byte_offset是包含目標位的字節(jié)在位段里的序號
bit_number是目標位所在位置(0-31)

在 CM3  支持的位段中,有兩個區(qū)中實現(xiàn)了位段。

其中一個是 SRAM 區(qū)的最低 1MB 范圍, 0x20000000 ‐ 0x200FFFFF(SRAM 區(qū)中的最低 1MB);

第二個則是片內(nèi)外設(shè)區(qū)的最低 1MB范圍, 0x40000000 ‐ 0x400FFFFF(片上外設(shè)區(qū)中的最低 1MB)。

在 C 語言中使用位段操作

在 C編譯器中并沒有直接支持位段操作。比如,C 編譯器并不知道對于同一塊內(nèi)存,能夠使用不同的地址來訪問,也不知道對位段別名區(qū)的訪問只對 LSB 有效。欲在 C中使用位段操作,最簡單的做法就是#define 一個位段別名區(qū)的地址。例如:

#define DEVICE_REG0 ((volatile unsigned long *) (0x40000000))

#define DEVICE_REG0_BIT0 ((volatile unsigned long *) (0x42000000))

#define DEVICE_REG0_BIT1 ((volatile unsigned long *) (0x42000004))

...

*DEVICE_REG0 = 0xab;        //使用正常地址訪問寄存器

*DEVICE_REG0_BIT1 = 0x1;  

還可以更簡化:

//把“位帶地址+位序號” 轉(zhuǎn)換成別名地址的宏

#define BITBAND(addr, bitnum)((addr & 0xF0000000)+0x2000000+((addr & 0xFFFFF)<<5)+(bitnum<<2))  
  //把該地址轉(zhuǎn)換成一個指針

#define MEM_ADDR(addr)  *((volatile unsigned long *) (addr))

于是:

MEM_ADDR(DEVICE_REG0) = 0xAB;     //使用正常地址訪問寄存器  

MEM_ADDR(BITBAND(DEVICE_REG0,1)) = 0x1;  //使用位段別名地址

注意:當(dāng)你使用位段功能時,要訪問的變量必須用 volatile 來定義。因為 C 編譯器并不知道同一個比特可以有兩個地址。所以就要通過 volatile,使得編譯器每次都如實地把新數(shù)值寫入存儲器,而不再會出于優(yōu)化的考慮 ,在中途使用寄存器來操作數(shù)據(jù)的復(fù)本,直到最后才把復(fù)本寫回。

實際上,在寫程序是都有這樣的定義:

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))

#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))

#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))

然后定義:#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C

最后操作:#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //輸出 ODR保存要輸出的數(shù)據(jù);IDR保存讀入的數(shù)據(jù)
回復(fù)

使用道具 舉報

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

本版積分規(guī)則

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

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

快速回復(fù) 返回頂部 返回列表