STM32软件层实现原理

发布者:EtherealLove最新更新时间:2024-07-23 来源: elecfans关键字:STM32 手机看文章 扫描二维码
随时随地手机看文章

一、前言

以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。


使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。

图片

二、实现原理

原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。


三、代码实现

国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread


头文件接口:


本次只实现如下接口,device_open 和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:


/*

    驱动注册

*/

int cola_device_register(cola_device_t *dev);

/*

    驱动查找

*/

cola_device_t *cola_device_find(const char *name);

/*

    驱动读

*/

int cola_device_read(cola_device_t *dev,  int pos, void *buffer, int size);

/*

    驱动写

*/

int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);

/*

    驱动控制

*/

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;

};

 

/*

    驱动注册

*/

int cola_device_register(cola_device_t *dev);

/*

    驱动查找

*/

cola_device_t *cola_device_find(const char *name);

/*

    驱动读

*/

int cola_device_read(cola_device_t *dev,  int pos, void *buffer, int size);

/*

    驱动写

*/

int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);

/*

    驱动控制

*/

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;

 

/*

    查找任务是否存在

*/

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;

}

 

/*

    驱动注册

*/

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);

 

}

/*

    驱动查找

*/

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;

}

/*

    驱动读

*/

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;

}

/*

    驱动写

*/

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;

}

/*

    驱动控制

*/

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),需要在初始化中调用。


#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);

}

应用层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状态改变一次

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文件中就不需要调用led.h头文件了,rtt就是这样实现的。


四、总结

这样就可以实现软硬件分层了,是不是非常好用!


关键字:STM32 引用地址:STM32软件层实现原理

上一篇:stm32型号命名规则 stm32制作工艺多少nm
下一篇:STM32WB55_NUCLEO开发(3)----手机与STM32WB直接配对

推荐阅读最新更新时间:2024-11-13 08:22

stm32时钟设置函数
这里涉及到一个很重要的寄存器,时钟配置寄存器:RCC_CFGR 1 #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) 2 /* #define SYSCLK_FREQ_HSE HSE_VALUE */ 3 #define SYSCLK_FREQ_24MHz 24000000 4 #else 5 /* #define SYSCLK_FREQ_HSE HSE_VALUE */ 6 /* #define SYSCLK_FREQ_24MHz 24000000 */ 7 /* #define SY
[单片机]
STM32直接驱动ov7670 开发笔记
很久没更新技术日志了,最近在调试OV7670摄像头,之中遇见了不少的麻烦。什么花屏啦,彩条不正常呀,等等,很多很多。经过一周的调试可算是调试出来了;期间在网上也查了很多,我想大家都会发现尽然都不能用,网上配置的寄存器表都是有错误的(对于没有fifo的,有fifo的我没试过),我花了一天时间认认真真的把OV7670的英文手册看了一遍,发现中文手册错的的太多了,就算是英文手册里有几个寄存器也没说清楚,实验和手册说的不统一。直接驱动摄像头的话STM32可以做到一帧(网上说用DMA方式,我是没办法实现),虽然做出来意义不大,但是可以学习摄像头这方面很多知识。 经过我的调试发现,要成功的关键:首先是时钟的初始化,直接驱动时时钟设置和寄存器设定
[单片机]
STM32菜鸟成长记录---GPIO的使用
#include stm32f10x_lib.h #include stm32f10x.h GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO宏操作结构体 void Delay(__IO uint32_t nCount)//__IO的宏定义volatile { for(; nCount != 0; nCount--); } /*初始化嵌入式Flash接口,初始化PLL使其达到系统可用频率*/ void RCC_Configuration(void) { /* Setup the microcontroller system. Initialize the Embedd
[单片机]
STM32中断优先级和开关总中断(很老很经典)
一、中断优先级: STM32(Cortex-M3)中的优先级概念 STM32(Cortex-M3)中有两个优先级的概念——抢占式优先级和响应优先级,有人把响应优先级称作'亚优先级'或'副优先级',每个中断源都需要被指定这两种优先级。 具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。 当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决
[单片机]
<font color='red'>STM32</font>中断优先级和开关总中断(很老很经典)
STM32与LPC系列ARM资源比较
由于有周立公开发板的影响,LPC系列的开发板在工程师心目中一般是入门的最好型号之一。这次刚好有STM32的竞赛,正好将两者的资源进行比较一下(LPC系列以LPC213X为例)。 LPC213X包括LPC2131、2132、2138等, 是基于一个支持实时仿真和跟踪的16/32 位ARM7TDMI-STM CPU,并带有32kB、64kB 和512kB 嵌入的高速Flash 存储器。128 位宽度的存储器接口和独特的加速结构使32 位代码能够在最大时钟速率下运行。对代码规模有严格控制的应用可使用16 位Thumb 模式将代码规模降低超过30%,而性能的损失却很小。 而 STM32 则大致分为两类,一种是基本型,一种是增强型。这同51内
[单片机]
学习STM32必须了解的五大嵌入式操作系统
基于STM平台且满足实时控制要求操作系统,有以下5种可供移植选择。分别为μClinux、μC/OS-II、eCos、FreeRTOS和rt-thread。下面分别介绍这五种嵌入式操作系统的特点及不足,通过对比,读者可以根据自己的应用需求选择合适的平台。 TOP1:μClinux μClinux是一种优秀的嵌入式Linux版本,其全称为micro-control Linux,从字面意思看是指微控制Linux。同标准的Linux相比,μClinux的内核非常小,但是它仍然继承了Linux操作系统的主要特性,包括良好的稳定性和移植性、强大的网络功能、出色的文件系统支持、标准丰富的API,以及TCP/IP网络协议等。因为没有MMU内
[单片机]
STM32是怎样进入执行中断函数xxx_IRQHandler(void)的
在STM32单片机的编程当中,中断函数的名称都是xxx_IRQHandler格式的。那当编译程序的时候是怎么知道这是一个中断函数的呢? 每个中断都是有入口地址的。程序在执行过程中遇到中断的时候,会先判断这个中断的类型,根据类型再到中断向量表中查找,找到之后,根据表中指明的地址,程序就跳到该地址开始执行代码。 ST提供的固件库当中,有提供一个stm32f10x_it.c文件,打开之后会发现里面放的都是些空函数,但是名字都是“xxx_Handler()”格式,需要使用某个中断的时候,在代码中使能该中断,并到这个文件中将中断服务函数添加上,就可以了。 而这些名字就是一个个的中断函数入口地址。在启动代码中便有这些定义。如下图所示:
[单片机]
<font color='red'>STM32</font>是怎样进入执行中断函数xxx_IRQHandler(void)的
GD32代码移植STM32(一)
GAIWEI例子:GD32F103移植STM32F103 使用相同FLASH和管脚数量相同的芯片,例如GDF103C8T6移植STM32F103C8T6程序。虽然两个款芯片的寄存器地址以及架构基本相同。但是需要注意的是GD32F10x主频是108兆,但是STM32F10x主频是72兆。所以需要针对以RCC时钟进行修改。 1.先将芯片的选项进行修改:查找对应芯片。 2.将STM32的启动文件替换成GD的启动文件。 3.修改时钟相关配置。 打开stm32f10x.h文件,#define HSE_STARTUP_TIMEOUT ((uint16_t)0x0500) /*! Time out for HSE start up
[单片机]
GD32代码移植<font color='red'>STM32</font>(一)
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved