一篇帶你了解C語言訪問存儲(chǔ)器的方法
在單片機(jī)中我們經(jīng)常需要訪問某個(gè)指定的寄存器或者到指定的RAM地址,在本文為簡(jiǎn)單描述,下文所說的存儲(chǔ)器可指:寄存器,RAM等。
01宏定義:
定義一個(gè)宏,將地址值轉(zhuǎn)化為C指針,然后取這個(gè)指針指向的內(nèi)容,這樣就可以訪問存儲(chǔ)了,代碼如下:
- #define SDA_DIR_REG *(__IO uint32_t *)SDA_MOD_OFFSET
分析:
(__IOuint32_t *)SDA_MOD_OFFSE 是強(qiáng)制類型轉(zhuǎn)換強(qiáng)制轉(zhuǎn)換為指針*(__IOuint32_t *)SDA_MOD_OFFSET 取這個(gè)指針里內(nèi)容。這是一種很簡(jiǎn)單實(shí)用的方法,對(duì)于訪問某個(gè)寄存器是很長(zhǎng)好用的。舉例:
- *(__IOuint16_t *) (((uint32_t)0x60020000) )
(((uint32_t)0x60020000))是32位的IO地址(物理地址,硬件上設(shè)定的,不可修改) *(__IO uint16_t*)是讀取該地址的參數(shù)值,其值為16位參數(shù)。
實(shí)際上是讀取0x60020000寄存器的參數(shù),或者可以說是這個(gè)IO口現(xiàn)在的狀態(tài)。
02結(jié)構(gòu)體:
將存儲(chǔ)器定義為一種數(shù)據(jù)結(jié)構(gòu),然后定義一個(gè)指向結(jié)構(gòu)體的指針。
符合CMSIS的設(shè)備驅(qū)動(dòng)庫(kù)就是這樣做的
- typedef struct
- {
- __IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
- __IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
- __IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
- __IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
- __IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
- __IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
- __IO uint16_t BSRRL; /*!< GPIO port bit set/reset low register, Address offset: 0x18 */
- __IO uint16_t BSRRH; /*!< GPIO port bit set/reset high register, Address offset: 0x1A */
- __IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
- __IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
- } GPIO_TypeDef;
- #define PERIPH_BASE ((uint32_t)0x40000000)
- #define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000)
- #define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800)
- #define GPIOC ((GPIO_TypeDef *)GPIOC_BASE)
大家看著上面的代碼應(yīng)該很熟悉,這就是我在ST給的標(biāo)準(zhǔn)外設(shè)庫(kù)中復(fù)制的,這也是CMSIS標(biāo)準(zhǔn)的驅(qū)動(dòng)發(fā)方式。
我在《STM32驅(qū)動(dòng)LCD實(shí)戰(zhàn)》文中就是使用這種方式驅(qū)動(dòng)操作LCD。代碼如下。
- typedef struct
- {
- uint8 LCD_CMD;//用于LCD命令操作
- uint8 LCD_DATA;//用于LCD數(shù)據(jù)操作
- } LCD_TypeDef;
- #define LCD_BASE ((uint32_t)(0x60000000 | 0x0000FFFF))
- #define LCD ((LCD_TypeDef *) LCD_BASE)
詳解如下:
LCD->LCD_CMD :是地址((uint32_t)(0x60000000| 0x0000FFFF))上的數(shù)據(jù)LCD->LCD_DATA:是地址((uint32_t)(0x60000000| 0x00010000))上的數(shù)據(jù)這種驅(qū)動(dòng)方式更加簡(jiǎn)潔,代碼結(jié)構(gòu)化。個(gè)人也更喜歡這種方式。03對(duì)比
方法1:簡(jiǎn)單,但是生成代碼效率低,因?yàn)榧拇嫫鞯牡刂分刀紩?huì)被存儲(chǔ)為常量,代碼體積會(huì)變大。由于需要訪問的更多寄存器來設(shè)置地址值,運(yùn)行速度會(huì)更低。不過,若外設(shè)控制代碼值操作1個(gè)寄存器,效率就和方法2相同了方法2:允許外設(shè)中的多個(gè)寄存器共用一個(gè)常量作為基地址。訪問每個(gè)寄存器時(shí)可以用立即數(shù)偏移尋址模式。
本文轉(zhuǎn)載自微信公眾號(hào)「知曉編程」