0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

STM32軟件層實現(xiàn)原理

科技綠洲 ? 來源:工程師進階筆記 ? 作者:工程師進階筆記 ? 2023-06-22 10:29 ? 次閱讀

一、前言

STM32為例,打開網(wǎng)絡(luò)上下載的例程或者是購買開發(fā)板自帶的例程,都會發(fā)現(xiàn)應(yīng)用層中會有stm32f10x.h或者stm32f10x_gpio.h,這些文件嚴格來時屬于硬件層的,如果軟件層出現(xiàn)這些文件會顯得很亂。

使用過Linux的童鞋們肯定知道linux系統(tǒng)無法直接操作硬件層,打開linux或者rt_thread代碼會發(fā)現(xiàn)代碼中都會有device的源文件,沒錯,這就是驅(qū)動層。

圖片

二、實現(xiàn)原理

原理就是將硬件操作的接口全都放到驅(qū)動鏈表上,在驅(qū)動層實現(xiàn)device的open、read、write等操作。當(dāng)然這樣做也有弊端,就是驅(qū)動find的時候需要遍歷一遍驅(qū)動鏈表,這樣會增加代碼運行時間。

三、代碼實現(xiàn)

國際慣例,寫代碼先寫頭文件。rt_thread中使用的是雙向鏈表,為了簡單在這我只用單向鏈表。有興趣的可以自行研究rt_thread

頭文件接口:

本次只實現(xiàn)如下接口,device_open 和device_close等剩下的接口可以自行研究。這樣就可以在應(yīng)用層中只調(diào)用如下接口可實現(xiàn):

/*
    驅(qū)動注冊
*/
int cola_device_register(cola_device_t *dev);
/*
    驅(qū)動查找
*/
cola_device_t *cola_device_find(const char *name);
/*
    驅(qū)動讀
*/
int cola_device_read(cola_device_t *dev,  int pos, void *buffer, int size);
/*
    驅(qū)動寫
*/
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
/*
    驅(qū)動控制
*/
int cola_device_ctrl(cola_device_t *dev,  int cmd, void *arg);;

頭文件cola_device.h:

#ifndef _COLA_DEVICE_H_
#define _COLA_DEVICE_H_
 
 
enum LED_state
{
    LED_OFF,
    LED_ON,
    LED_TOGGLE,
 
};
 
typedef struct cola_device  cola_device_t;
 
struct cola_device_ops
{
    int  (*init)   (cola_device_t *dev);
    int  (*open)   (cola_device_t *dev, int oflag);
    int  (*close)  (cola_device_t *dev);
    int  (*read)   (cola_device_t *dev, int pos, void *buffer, int size);
    int  (*write)  (cola_device_t *dev, int pos, const void *buffer, int size);
    int  (*control)(cola_device_t *dev, int cmd, void *args);
 
};
 
struct cola_device
{
    const char * name;
    struct cola_device_ops *dops;
    struct cola_device *next;
};
 
/*
    驅(qū)動注冊
*/
int cola_device_register(cola_device_t *dev);
/*
    驅(qū)動查找
*/
cola_device_t *cola_device_find(const char *name);
/*
    驅(qū)動讀
*/
int cola_device_read(cola_device_t *dev,  int pos, void *buffer, int size);
/*
    驅(qū)動寫
*/
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
/*
    驅(qū)動控制
*/
int cola_device_ctrl(cola_device_t *dev,  int cmd, void *arg);
 
#endif

源文件cola_device.c:

#include "cola_device.h"
#include < string.h >
#include < stdbool.h >
 
 
struct cola_device *device_list = NULL;
 
/*
    查找任務(wù)是否存在
*/
static bool cola_device_is_exists( cola_device_t *dev )
{
    cola_device_t* cur = device_list;
    while( cur != NULL )
    {
        if( strcmp(cur- >name,dev- >name)==0)
        {
            return true;
        }
        cur = cur- >next;
    }
    return false;
}
 
 
static int device_list_inster(cola_device_t *dev)
{
    cola_device_t *cur = device_list;
    if(NULL == device_list)
    {
        device_list = dev;
        dev- >next   = NULL;
    }
    else
    {
        while(NULL != cur- >next)
        {
            cur = cur- >next;
        }
        cur- >next = dev;
        dev- >next = NULL;
    }
    return 1;
}
 
/*
    驅(qū)動注冊
*/
int cola_device_register(cola_device_t *dev)
{
    if((NULL == dev) || (cola_device_is_exists(dev)))
    {
        return 0;
    }
 
    if((NULL == dev- >name) ||  (NULL == dev- >dops))
    {
        return 0;
    }
    return device_list_inster(dev);
 
}
/*
    驅(qū)動查找
*/
cola_device_t *cola_device_find(const char *name)
{
    cola_device_t* cur = device_list;
    while( cur != NULL )
    {
        if( strcmp(cur- >name,name)==0)
        {
            return cur;
        }
        cur = cur- >next;
    }
    return NULL;
}
/*
    驅(qū)動讀
*/
int cola_device_read(cola_device_t *dev,  int pos, void *buffer, int size)
{
    if(dev)
    {
        if(dev- >dops- >read)
        {
            return dev- >dops- >read(dev, pos, buffer, size);
        }
    }
    return 0;
}
/*
    驅(qū)動寫
*/
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)
{
    if(dev)
    {
        if(dev- >dops- >write)
        {
            return dev- >dops- >write(dev, pos, buffer, size);
        }
    }
    return 0;
}
/*
    驅(qū)動控制
*/
int cola_device_ctrl(cola_device_t *dev,  int cmd, void *arg)
{
    if(dev)
    {
        if(dev- >dops- >control)
        {
            return dev- >dops- >control(dev, cmd, arg);
        }
    }
    return 0;
}

硬件注冊方式:以LED為例,初始化接口void led_register(void),需要在初始化中調(diào)用。

#include "stm32f0xx.h"
#include "led.h"
#include "cola_device.h"
 
 
#define PORT_GREEN_LED                 GPIOC                   
#define PIN_GREENLED                   GPIO_Pin_13              
 
/* LED亮、滅、變化 */
#define LED_GREEN_OFF                  (PORT_GREEN_LED- >BSRR = PIN_GREENLED)
#define LED_GREEN_ON                   (PORT_GREEN_LED- >BRR  = PIN_GREENLED)
#define LED_GREEN_TOGGLE               (PORT_GREEN_LED- >ODR ^= PIN_GREENLED)
 
 
static cola_device_t led_dev;
 
static void led_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
    GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;                            
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                     
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                  
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                     
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;                  
    GPIO_Init(PORT_GREEN_LED, &GPIO_InitStructure);
    LED_GREEN_OFF;
}
 
static int led_ctrl(cola_device_t *dev, int cmd, void *args)
{
    if(LED_TOGGLE == cmd)
    {
        LED_GREEN_TOGGLE;
    }
    else 
    {
        
    }
    return 1;
}
 
 
static struct cola_device_ops ops =
{
    .control = led_ctrl,
};
 
void led_register(void)
{
    led_gpio_init();
    led_dev.dops = &ops;
    led_dev.name = "led";
    cola_device_register(&led_dev);
}

應(yīng)用層app代碼:

#include < string.h >
#include "app.h"
#include "config.h"
#include "cola_device.h"
#include "cola_os.h"
 
static task_t timer_500ms;
static cola_device_t *app_led_dev;
 
//led每500ms狀態(tài)改變一次
static void timer_500ms_cb(uint32_t event)
{
    cola_device_ctrl(app_led_dev,LED_TOGGLE,0);
}
 
void app_init(void)
{
    app_led_dev = cola_device_find("led");
    assert(app_led_dev);
    cola_timer_create(&timer_500ms,timer_500ms_cb);
    cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);
}

這樣app.c文件中就不需要調(diào)用led.h頭文件了,rtt就是這樣實現(xiàn)的。

四、總結(jié)

這樣就可以實現(xiàn)軟硬件分層了,是不是非常好用!

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • STM32
    +關(guān)注

    關(guān)注

    2262

    文章

    10846

    瀏覽量

    353677
  • 軟件
    +關(guān)注

    關(guān)注

    69

    文章

    4611

    瀏覽量

    86984
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4694

    瀏覽量

    68075
收藏 人收藏

    評論

    相關(guān)推薦

    STM32CubeIDE軟件實現(xiàn)STM32外部中斷實例

    本文用STM32CubeIDE軟件實現(xiàn)STM32外部中斷實例。
    的頭像 發(fā)表于 08-24 09:09 ?4255次閱讀

    STM32是怎樣去實現(xiàn)軟件時間片調(diào)度的

    STM32 實現(xiàn)軟件時間片調(diào)度前言:在有些時候嵌入式系統(tǒng)不需要上RTOS的情況下,使用一個while大循環(huán),有可能會造成一while套一
    發(fā)表于 08-24 07:33

    AUTOSAR基礎(chǔ)軟件是由哪些部分組成的

    AUTOSAR基礎(chǔ)軟件即BSW(Basic Software),與應(yīng)用、運行環(huán)境共同搭建了AUTOSAR的
    發(fā)表于 02-17 08:00

    stm32軟件如何驅(qū)動LCD?

    LCD的接口模式有哪些?stm32軟件如何驅(qū)動LCD?
    發(fā)表于 02-23 06:12

    基于STM32、FreeRTOS 實現(xiàn)硬件看門狗+軟件看門狗監(jiān)測多任務(wù)的方法

    基于STM32、FreeRTOS實現(xiàn)硬件看門狗+軟件看門狗監(jiān)測多任務(wù)的方法
    的頭像 發(fā)表于 03-12 10:11 ?9186次閱讀

    stm32用什么軟件寫程序

    stm32用什么軟件寫程序?STM32單片機在編程時可以使用庫函數(shù)和使用配置寄存器的方式來進行程序的實現(xiàn)。
    發(fā)表于 09-21 16:00 ?1.5w次閱讀

    STM32軟件架構(gòu)設(shè)計

    STM32軟件架構(gòu)1、架構(gòu)設(shè)計的意義(1)應(yīng)用代碼邏輯清晰,且避免代碼冗余;(2)代碼通用性,方便軟件高速、有效的移植;(3)各功能獨立,低耦合高內(nèi)聚;2、總體架構(gòu)圖3、結(jié)構(gòu)說明4、
    發(fā)表于 11-06 09:05 ?34次下載
    <b class='flag-5'>STM32</b><b class='flag-5'>軟件</b>架構(gòu)設(shè)計

    STM32軟件模擬串口的實現(xiàn)-基于CrubeMX

    STM32軟件模擬串口的實現(xiàn)-基于CrubeMX
    發(fā)表于 11-30 10:36 ?10次下載
    <b class='flag-5'>STM32</b><b class='flag-5'>軟件</b>模擬串口的<b class='flag-5'>實現(xiàn)</b>-基于CrubeMX

    STM32CubeMX實戰(zhàn)教程(一)——軟件入門

    STM32Cube 是一個全面的軟件平臺,包括了ST產(chǎn)品的每個系列。平臺包括了STM32Cube 硬件抽象(一個STM32抽象
    發(fā)表于 12-07 17:36 ?2次下載
    <b class='flag-5'>STM32</b>CubeMX實戰(zhàn)教程(一)——<b class='flag-5'>軟件</b>入門

    STM32 硬件抽象(Hardware Abstraction la

    STM32 硬件抽象(Hardware Abstraction la
    發(fā)表于 12-09 12:06 ?1次下載
    <b class='flag-5'>STM32</b> 硬件抽象<b class='flag-5'>層</b>(Hardware Abstraction la

    AUTOSAR 基礎(chǔ)軟件

    AUTOSAR基礎(chǔ)軟件即BSW(Basic Software),與應(yīng)用、運行環(huán)境共同搭建了AUTOSAR的
    發(fā)表于 12-22 19:03 ?26次下載
    AUTOSAR 基礎(chǔ)<b class='flag-5'>軟件</b><b class='flag-5'>層</b>

    一個通用嵌入式驅(qū)動的代碼實現(xiàn)

    STM32為例,打開網(wǎng)絡(luò)上下載的例程或者是購買開發(fā)板自帶的例程,都會發(fā)現(xiàn)應(yīng)用中會有stm32f10x.h或者stm32f10x_gpio.h,這些文件嚴格來時屬于硬件
    的頭像 發(fā)表于 11-16 11:31 ?784次閱讀

    AN4457_基于STM32F4xx系列單片機軟件模擬UART的設(shè)計實現(xiàn)

    AN4457_基于STM32F4xx系列單片機軟件模擬UART的設(shè)計實現(xiàn)
    發(fā)表于 11-21 08:11 ?0次下載
    AN4457_基于<b class='flag-5'>STM32</b>F4xx系列單片機<b class='flag-5'>軟件</b>模擬UART的設(shè)計<b class='flag-5'>實現(xiàn)</b>

    UM1725_STM32F4的HAL和LL用戶手冊

    UM1725_STM32F4的HAL和LL用戶手冊
    發(fā)表于 11-22 08:21 ?21次下載
    UM1725_<b class='flag-5'>STM32</b>F4的HAL<b class='flag-5'>層</b>和LL<b class='flag-5'>層</b>用戶手冊

    在嵌入式中如何實現(xiàn)應(yīng)用和硬件分層管理呢

    STM32為例,打開網(wǎng)絡(luò)上下載的例程或者是購買開發(fā)板自帶的例程,都會發(fā)現(xiàn)應(yīng)用中會有stm32f10x.h或者stm32f10x_gpio.h,這些文件嚴格來時屬于硬件
    發(fā)表于 06-14 17:55 ?687次閱讀
    在嵌入式中如何<b class='flag-5'>實現(xiàn)</b>應(yīng)用<b class='flag-5'>層</b>和硬件<b class='flag-5'>層</b>分層管理呢