嵌入式硬件寄存器操作層次

嵌入式硬件寄存器操作層次
寄存器操作—>基於CMSIS-CORE操作—>基於硬件抽象層hal操作—>基於API操作(針對hal api再次作了面向對象的封裝)

1.寄存器操作

這裏寫圖片描述

基於寄存器操作的閃燈程序

int main()
{ 
unsigned int mask_pin18 = 1 << 18;
volatile unsigned int *port1_dir = (unsigned int
*)0x2009C020;
volatile unsigned int *port1_set = (unsigned int
*)0x2009C038;
volatile unsigned int *port1_clr = (unsigned int
*)0x2009C03C;

  *port1_dir |= mask_pin18;
  while (true) 
  {   
      *port1_set |= mask_pin18;
      wait(0.5);
      *port1_clr|= mask_pin18;     
      wait(0.5);
   }
}

將寄存器的地址賦值給指針,通過地址指針操作寄存器的相關功能位

2.基於CMSIS-CORE操作

前面的代碼已經表明,基於MCU寄存器的應用程序其大量代碼是寄存器地址的定義,爲了減少用戶的代碼量,ARM公司已經要求各個廠商把這部分代碼寫成統一的接口格式給用戶使用,這就是CMSIS-CORE的目標.
如在類似kinetis MK64F12.h 和STM32 stm32f103.h 文件中,你可以找到以下相關代碼.

#define PORTA_BASE (0x40049000u)
/* Peripheral PORTA base pointer /
#define PORTA ((PORT_Type *)PORTA_BASE)
#define PORTA_BASE_PTR (PORTA)

/** PORT - Register Layout Typedef */
typedef struct {
  __IO uint32_t PCR[32];                           /**< Pin Control Register n, array offset: 0x0, array step: 0x4 */
  __O  uint32_t GPCLR;                             /**< Global Pin Control Low Register, offset: 0x80 */
  __O  uint32_t GPCHR;                             /**< Global Pin Control High Register, offset: 0x84 */
       uint8_t RESERVED_0[24];
  __IO uint32_t ISFR;                              /**< Interrupt Status Flag Register, offset: 0xA0 */
       uint8_t RESERVED_1[28];
  __IO uint32_t DFER;                              /**< Digital Filter Enable Register, offset: 0xC0 */
  __IO uint32_t DFCR;                              /**< Digital Filter Clock Register, offset: 0xC4 */
  __IO uint32_t DFWR;                              /**< Digital Filter Width Register, offset: 0xC8 */
} PORT_Type, *PORT_MemMapPtr;
這樣一來,我們就可以基於CMSIS-CORE使用以下代碼來完成我們的功能了。

int main()
{
unsigned int mask_pin18 = 1 << 18;
while (true) {
PORTA->FIOSET |= mask_pin18;
wait(0.5);
PORTA->FIOCLR |= mask_pin18;
wait(0.5);
}
}

3.基於硬件抽象層hal操作

雖然從代碼量上來說,基於CMSIS-CORE的閃燈程序已經比原先的改進了不少,但操作方式上並沒有任何變化,用戶依然需要理解寄存器的相關概念,而對於應用程序開發人員來說,他們更能理解的是SDK,即各種各樣得函數調用,於是,mbed在cmsis-core的基礎之上專門設計了一個硬件抽象層,把MCU的所有寄存器操作都整合成hal api函數調用方式,對於應用開發人員來說,他只需要調用hal api即可,而對於底層開發人員來說,他只需要實現hal api即可。

Hal api的所有函數原型都在hal目錄下,與閃燈相關的gpio 函數原型如下:

uint32_t gpio_set(PinNamepin);

void gpio_init (gpio_t *obj,PinName pin, PinDirection direction);

void gpio_mode (gpio_t *obj,
PinMode mode);

void gpio_dir (gpio_t *obj, PinDirection direction);

void gpio_write(gpio_t *obj,int value);

int gpio_read (gpio_t *obj);

這樣一來,我們就可以基於hal api使用以下代碼來完成我們的功能了。

int
main() {
gpio_set(LED1);
gpio_t gpio;
gpio_init(&gpio, LED1, PIN_OUTPUT);
while (true)
{
gpio_write(&gpio,1);
wait(0.5);
gpio_write(&gpio,0);
wait(0.5);
}
}

4.基於API操作(針對hal api再次作了面向對象的封裝)

基於hal api操作的應用程序雖然已經可以做到與具體的mcu無關了,但習慣了java,c#程序設計的程序員來說還是不太習慣,於是,mbed又針對hal api再次作了面向對象的封裝,使得用戶可以更簡單地來編寫上層應用,它對應的函數定義在api目錄下,相應的實現在common目錄下,閃燈程序相關的定義在DigitalOut.h中,其中也包括了對應的實現,代碼如下:

class DigitalOut
{
public:
DigitalOut(PinName pin) {
gpio_init(&gpio, pin, PIN_OUTPUT);
}
void write(int value) {
gpio_write(&gpio, value);
}
int read() {
return gpio_read(&gpio);
}

#ifdef
MBED_OPERATORS
DigitalOut& operator= (int value) {
write(value);
return *this;
}
DigitalOut& operator= (DigitalOut& rhs) {
write(rhs.read());
return *this;
}
operator int() {
return read();
}
#endif
protected:
gpio_t gpio;
};
這樣一來,我們就可以基於mbed api使用以下代碼來完成我們的功能了。


DigitalOut led1(LED1);
int main()
{
while (true)
{
led1 = 1;
wait(0.5);
led1 = 0;
wait(0.5);
}
}

發佈了51 篇原創文章 · 獲贊 26 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章