6. 驅(qū)動(dòng)可配置化開發(fā) --- LED驅(qū)動(dòng)

本博客中示例代碼下載路徑: https://github.com/maziot-stm32/A1/releases/tag/v0.6

驅(qū)動(dòng)可配置化開發(fā)

前面已經(jīng)提到了代碼要分層, 便于理解和閱讀代碼. 這里針對其中的驅(qū)動(dòng)層引入一個(gè)新的概念, 驅(qū)動(dòng)可配置化開發(fā).

何為可配置化開發(fā), 舉個(gè)最簡單的例子:
原來我的 STM32F103RC 小板子(簡稱A1設(shè)備)上 PA8 和 PD2 接了一個(gè) LED 燈, 現(xiàn)在我重新畫了一個(gè)板子(簡稱C3設(shè)備), 用的依然是 F103RC 主控, 但是 LED 燈的接在 PC13 引腳上. 現(xiàn)在我希望 C3 可以直接復(fù)用 A1 的驅(qū)動(dòng), 驅(qū)動(dòng)代碼中改動(dòng)量控制在僅僅只需要修改硬件上外掛的 LED 燈個(gè)數(shù), 有效電平, 連接的 GPIO 引腳等與硬件電路強(qiáng)相關(guān)的信息, 其余與硬件不相關(guān)的代碼不需要做任何修改.

簡單總結(jié)下:

  • 可配置化開發(fā)目的是為了提高代碼的復(fù)用性
  • 可配置化開發(fā)將與硬件設(shè)計(jì)強(qiáng)相關(guān)的參數(shù)剝離出來, 針對不同的設(shè)備做不同的配置

LED 驅(qū)動(dòng)可配置化抽象

基于上面的概念, 想一下, LED 燈與硬件強(qiáng)相關(guān)的配置有哪些?
目前我想到的有這些:

  • 硬件連接: 接在STM32的哪個(gè)GPIO口上, 包括PORT和PIN.
  • 有效電平: 高電平點(diǎn)亮還是低電平點(diǎn)亮.
  • 默認(rèn)狀態(tài): 上電后默認(rèn)是點(diǎn)亮還是熄滅.

用結(jié)構(gòu)體描述如下:

typedef struct _MAZDRV_LED_CTRL_
{
    MAZDRV_LED_GPIO_PORT port;              // 連接LED的GPIO PORT
    MAZDRV_LED_GPIO_PIN pin;                // 連接LED的GPIO PIN
    MAZDRV_LED_GPIO_LEVEL light;            // 高電平還是低電平點(diǎn)亮
    MAZDRV_LED_STATUS status;               // 默認(rèn)狀態(tài)是點(diǎn)亮還是熄滅
} MAZDRV_LED_CTRL;

每一個(gè)成員分別定義對應(yīng)的枚舉類型, 用于規(guī)范配置項(xiàng), 枚舉定義如下:

typedef enum _MAZDRV_LED_GPIO_PORT_
{
    MAZDRV_LED_GPIO_PORTA = GPIOA_BASE,
    MAZDRV_LED_GPIO_PORTB = GPIOB_BASE,
    MAZDRV_LED_GPIO_PORTC = GPIOC_BASE,
    MAZDRV_LED_GPIO_PORTD = GPIOD_BASE,
    MAZDRV_LED_GPIO_PORTE = GPIOE_BASE,
    MAZDRV_LED_GPIO_PORTF = GPIOF_BASE,
    MAZDRV_LED_GPIO_PORTG = GPIOG_BASE,
} MAZDRV_LED_GPIO_PORT;

typedef enum _MAZDRV_LED_GPIO_PIN_
{
    MAZDRV_LED_GPIO_PIN0 = GPIO_PIN_0,
    MAZDRV_LED_GPIO_PIN1 = GPIO_PIN_1,
    MAZDRV_LED_GPIO_PIN2 = GPIO_PIN_2,
    MAZDRV_LED_GPIO_PIN3 = GPIO_PIN_3,
    MAZDRV_LED_GPIO_PIN4 = GPIO_PIN_4,
    MAZDRV_LED_GPIO_PIN5 = GPIO_PIN_5,
    MAZDRV_LED_GPIO_PIN6 = GPIO_PIN_6,
    MAZDRV_LED_GPIO_PIN7 = GPIO_PIN_7,
    MAZDRV_LED_GPIO_PIN8 = GPIO_PIN_8,
    MAZDRV_LED_GPIO_PIN9 = GPIO_PIN_9,
    MAZDRV_LED_GPIO_PIN10 = GPIO_PIN_10,
    MAZDRV_LED_GPIO_PIN11 = GPIO_PIN_11,
    MAZDRV_LED_GPIO_PIN12 = GPIO_PIN_12,
    MAZDRV_LED_GPIO_PIN13 = GPIO_PIN_13,
    MAZDRV_LED_GPIO_PIN14 = GPIO_PIN_14,
    MAZDRV_LED_GPIO_PIN15 = GPIO_PIN_15,
    MAZDRV_LED_GPIO_PIN_ALL = GPIO_PIN_All,
} MAZDRV_LED_GPIO_PIN;

typedef enum _MAZDRV_LED_GPIO_LEVEL_
{
    MAZDRV_LED_GPIO_LEVEL_HIGH = GPIO_PIN_SET,
    MAZDRV_LED_GPIO_LEVEL_LOW = GPIO_PIN_RESET,
} MAZDRV_LED_GPIO_LEVEL;

typedef enum _MAZDRV_LED_STATUS_
{
    MAZDRV_LED_STATUS_ON = 0,
    MAZDRV_LED_STATUS_OFF,
    MAZDRV_LED_STATUS_TOGGLE,
} MAZDRV_LED_STATUS;

基于上述剝離出來的參數(shù), 硬件上不同的 LED 燈就可以用 MAZDRV_LED_CTRL 對象來描述了. 示例代碼如下:

typedef enum _MAZDRV_LED_
{
    MAZDRV_LED0 = 0,
    MAZDRV_LED1,
    MAZDRV_LED_MAX,
} MAZDRV_LED;

static MAZDRV_LED_CTRL g_mazdrv_led_ctrl[MAZDRV_LED_MAX] =
{
    [MAZDRV_LED0] =
    {
        .port   = MAZDRV_LED_GPIO_PORTA,
        .pin    = MAZDRV_LED_GPIO_PIN8,
        .light  = MAZDRV_LED_GPIO_LEVEL_LOW,
        .status = MAZDRV_LED_STATUS_OFF,
    },
    [MAZDRV_LED1] =
    {
        .port   = MAZDRV_LED_GPIO_PORTD,
        .pin    = MAZDRV_LED_GPIO_PIN2,
        .light  = MAZDRV_LED_GPIO_LEVEL_LOW,
        .status = MAZDRV_LED_STATUS_OFF,
    },
};

LED 可配置化驅(qū)動(dòng)程序

上面通過 MAZDRV_LED_CTRL 對象將硬件上 LED 的信息描述出來了. 現(xiàn)在我們的驅(qū)動(dòng)就必須以這些硬件信息為輸入, 支持各種各樣的配置情況.

LED 初始化:

int MAZ_Drv_led_init(void)
{
    MAZDRV_LED led;
    MAZDRV_LED_CTRL *ctrl = NULL;
    GPIO_InitTypeDef GPIO_InitStruct = { 0 };

    ctrl = g_mazdrv_led_ctrl;

    for (led = MAZDRV_LED0; led < MAZDRV_LED_MAX; led++)
    {
        /* GPIO Ports Clock Enable */
        MAZ_Drv_led_gpio_prot_clk_enable(led);

        /* Configure GPIO pin */
        GPIO_InitStruct.Pin = ctrl[led].pin;
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
        GPIO_InitStruct.Pull = (ctrl[led].light == MAZDRV_LED_GPIO_LEVEL_HIGH) ? GPIO_PULLDOWN : GPIO_PULLUP;
        HAL_GPIO_Init((GPIO_TypeDef*) ctrl[led].port, &GPIO_InitStruct);

        /* Set default status */
        MAZ_Drv_led_set_status(led, ctrl[led].status);
    }

    return MAZRET_NOERR;
}

int MAZ_Drv_led_gpio_prot_clk_enable(MAZDRV_LED led)
{
    MAZDRV_LED_GPIO_PORT port;
    MAZDRV_LED_CTRL *ctrl = NULL;

    if (led < MAZDRV_LED0 || led >= MAZDRV_LED_MAX)
    {
        return MAZRET_EINVAL;
    }

    ctrl = g_mazdrv_led_ctrl;
    port = ctrl[led].port;

    /* GPIO Ports Clock Enable */
    switch (port)
    {
        case MAZDRV_LED_GPIO_PORTA:
            __HAL_RCC_GPIOA_CLK_ENABLE();
            break;
        case MAZDRV_LED_GPIO_PORTB:
            __HAL_RCC_GPIOB_CLK_ENABLE();
            break;
        case MAZDRV_LED_GPIO_PORTC:
            __HAL_RCC_GPIOC_CLK_ENABLE();
            break;
        case MAZDRV_LED_GPIO_PORTD:
            __HAL_RCC_GPIOD_CLK_ENABLE();
            break;
        case MAZDRV_LED_GPIO_PORTE:
            __HAL_RCC_GPIOE_CLK_ENABLE();
            break;
        case MAZDRV_LED_GPIO_PORTF:
            __HAL_RCC_GPIOF_CLK_ENABLE();
            break;
        case MAZDRV_LED_GPIO_PORTG:
            __HAL_RCC_GPIOG_CLK_ENABLE();
            break;
    }

    return MAZRET_NOERR;
}

LED 設(shè)置狀態(tài):

int MAZ_Drv_led_set_status(MAZDRV_LED led, MAZDRV_LED_STATUS status)
{
    MAZDRV_LED_GPIO_LEVEL level;
    MAZDRV_LED_CTRL *ctrl = NULL;

    if (led < MAZDRV_LED0 || led >= MAZDRV_LED_MAX)
    {
        return MAZRET_EINVAL;
    }

    if (status < MAZDRV_LED_STATUS_ON || status > MAZDRV_LED_STATUS_TOGGLE)
    {
        return MAZRET_EINVAL;
    }

    ctrl = g_mazdrv_led_ctrl;

    switch (status)
    {
        case MAZDRV_LED_STATUS_ON:
            level = ctrl[led].light;
            HAL_GPIO_WritePin((GPIO_TypeDef*) ctrl[led].port, ctrl[led].pin, level);
            break;
        case MAZDRV_LED_STATUS_OFF:
            if (MAZDRV_LED_GPIO_LEVEL_HIGH == ctrl[led].light)
                level = MAZDRV_LED_GPIO_LEVEL_LOW;
            else if (MAZDRV_LED_GPIO_LEVEL_LOW == ctrl[led].light)
                level = MAZDRV_LED_GPIO_LEVEL_HIGH;
            HAL_GPIO_WritePin((GPIO_TypeDef*) ctrl[led].port, ctrl[led].pin, level);
            break;
        case MAZDRV_LED_STATUS_TOGGLE:
            HAL_GPIO_TogglePin((GPIO_TypeDef*) ctrl[led].port, ctrl[led].pin);
            break;
    }

    return MAZRET_NOERR;
}

不難發(fā)現(xiàn), 驅(qū)動(dòng)函數(shù)中所有與硬件相關(guān)的部分, 全部由 g_mazdrv_led_ctrl 變量提供. 因此移植代碼時(shí), 僅需要修改 g_mazdrv_led_ctrl 變量即可實(shí)現(xiàn)快速移植.

代碼倉庫

倉庫路徑: https://github.com/maziot-stm32/A1
驅(qū)動(dòng)文件: https://github.com/maziot-stm32/A1/tree/master/MAZ_Drivers/MAZ_Drv_led

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末猛遍,一起剝皮案震驚了整個(gè)濱河市桐汤,隨后出現(xiàn)的幾起案子颜矿,更是在濱河造成了極大的恐慌壮莹,老刑警劉巖变逃,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件街立,死亡現(xiàn)場離奇詭異犯助,居然都是意外死亡住诸,警方通過查閱死者的電腦和手機(jī)猫胁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進(jìn)店門箱亿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人弃秆,你說我怎么就攤上這事届惋∷杳保” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵脑豹,是天一觀的道長郑藏。 經(jīng)常有香客問我,道長瘩欺,這世上最難降的妖魔是什么必盖? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮俱饿,結(jié)果婚禮上歌粥,老公的妹妹穿的比我還像新娘。我一直安慰自己拍埠,他們只是感情好失驶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著枣购,像睡著了一般嬉探。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上棉圈,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天涩堤,我揣著相機(jī)與錄音,去河邊找鬼迄损。 笑死定躏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的芹敌。 我是一名探鬼主播痊远,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼氏捞!你這毒婦竟也來了碧聪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤液茎,失蹤者是張志新(化名)和其女友劉穎逞姿,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捆等,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡滞造,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了栋烤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谒养。...
    茶點(diǎn)故事閱讀 39,769評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖明郭,靈堂內(nèi)的尸體忽然破棺而出买窟,到底是詐尸還是另有隱情丰泊,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布始绍,位于F島的核電站瞳购,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏亏推。R本人自食惡果不足惜学赛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望径簿。 院中可真熱鬧罢屈,春花似錦嘀韧、人聲如沸篇亭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽译蒂。三九已至,卻和暖如春谊却,著一層夾襖步出監(jiān)牢的瞬間柔昼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工炎辨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捕透,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓碴萧,卻偏偏與公主長得像乙嘀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子破喻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內(nèi)容