初识bos框架


了解到一个很棒的裸机代码使用框架,趁现在没什么具体的项目,这几天使用下,准备把之前接触过的框架都总结下,都移植一遍,这样可以增加自己做项目时的选择,另外把之前做过的功能,也尽量模块化,使之适合OS与非OS的使用场景。

大体了解下bos的框架结构

BOS代码分为3部分:
BOS仓库:功能模块和驱动 ,一般情况下用户不需要改动,可以将此仓库作为子模块。
BOS_Config:配置文件和设备注册文件
BOS_Hal:硬件抽象层, 不同分支对应不同硬件平台,选择对应平台下载,没有合适的则选择master分支

移植过程

基于stm32f407来操作。自己开发板上面功能模块比较多,这样好写测试代码,以后的测试框架也尽量以这个芯片来弄!

用cubemx,建立一个空工程,这一步就不说了

克隆bos的代码

BabyOS							//可作git子模块使用
├── bos
│   ├── algorithm               //常用算法,无需添加其中文件
│   ├── core					//核心文件,全部包含至工程
│   ├── drivers					//驱动文件,选择spiflash驱动添加至工程
│   ├── modules					//功能模块,全部添加至工程,由配置文件b_config.h配置
│   ├── thirdparty				//第三方代码,选择SFUD第三方代码添加至工程
│   └── utils					//实用代码,选择delay部分代码添加至工程
├── doc							//相关文档
├── LICENSE						//开源协议
└── README.md
BabyOS_Config					//克隆后放入工程目录,全部添加至工程
BabyOS_Hal						//克隆后放入工程目录,添加hal、gpio、uart、spi部分
进入用户工程目录执行
git submodule add https://gitee.com/notrynohigh/BabyOS.git
git clone https://gitee.com/notrynohigh/BabyOS_Config.git    //克隆配置文件及设备注册文件
git clone https://gitee.com/notrynohigh/BabyOS_Hal.git		 //克隆后切换到对应平台的分支,如果没有则采用master分支作为模板
进入到babyos_hal目录下

执行 git checkout st_hal;切换到st库分支下。
删除掉用户配置及hal子仓库下的git

往空工程里,添加核心文件

新建一个Bos/Conifg文件夹

往里面添加C:\Users\Administrator\Desktop\babyOSTest\BabyOS_Config下,b_config.h和b_device_list.h两个头文件

新建一个Bos/core文件夹

往里面添加C:\Users\Administrator\Desktop\babyOSTest\BabyOS\bos\core下两个.c文件

新建一个Bos/Modules文件夹

往里面添加C:\Users\Administrator\Desktop\babyOSTest\BabyOS\bos\modules下所有功能模块.c文件

新建一个Bos/Drivers文件夹

往里面添加C:\Users\Administrator\Desktop\babyOSTest\BabyOS\bos\drivers需要的驱动。这里只需要spiflash的驱动。

新建一个Bos/Hal文件夹
新建一个Bos/Thirdparty文件夹

往里面添加C:\Users\Administrator\Desktop\babyOSTest\BabyOS\bos\thirdparty\SFUD下,需要的第三方组件

新一个Bos/Utils文件夹

往里面添加C:\Users\Administrator\Desktop\babyOSTest\BabyOS\bos\utils,里所需要的实用功能。

添加头文件

除cubemx需要的头文件外,还需要添加默认加载的头文件如下:
BabyOS/bos/
BabyOS_Hal/inc/
BabyOS_Config/

添加滴答

在stm32f4xx_it.c里,首先加上头文件包含b_hal.h,然后在void SysTick_Handler(void)里加上bHalIncSysTick();//这个函数主要实现了volatile uint32_t bSysTick = 0;这个变量+1操作

us延时

完成b_hal.c里面us级别的延时函数,us延时未采用定时器,依赖于具体平台
注:定时器的周期与b_config.h里_TICK_FRQ_HZ要匹配

用户自定义

在b_config.h和b_device_list.h里添加自定义的功能及注册设备。这里一定要关掉不必要的功能,否则会出现一大堆错误。

修改硬件接口

通过b_hal.h里的#include "b_hal_if.h"头文件来关联,并修改里面的参数

修改硬件抽象层里面的内容

也就是hal文件夹下b_hal_XX.c开头的文件,一般来说只给出最基础的,根据需要添加自己的功能

添加自己逻辑

可以在主函数里,添加应用,具体提供的函数接口,需要更多资料,看了下使用手册,还是太简单了。
不过,在主函数里面写了下面两句话后,确实开始打印了。

		BOS_PERIODIC_TASK(Test,3000);//test 是一个测试程序,里面就打印一段话
		bExec();//轮循函数

移植总结

到这里基本算是移植完了吧,但最后调用的函数还需要再深入研究下,这个其实就是一个框架,没有什么系统。重点是要知道框架提供的调用接口,及内部运行原理。

框架重点

int bExec()轮循函数到底是如何实现的???

此函数在core.c中。里面的内容如下:

    bSECTION_FOR_EACH(bos_polling, pbPoling_t, polling)
    {
        (*polling)();
    }

这个bSECTION_FOR_EACH是在b_section.h中定义的:

#define bSECTION_FOR_EACH(section_name, data_type, variable)                     \//定义了段名  数据类型  变量
    for (data_type *variable = BOS_SECTION_ITEM_GET(section_name, data_type, 0); \  //定义了一个函数指针 ,指向的就是pbPoling_t类型的,后面这个宏是找bos_polling这个段的首地址+0
         (intptr_t)variable != (intptr_t)BOS_SECTION_END_ADDR(section_name); variable++)//后面的宏_END_ADD:就是取段的尾地址

$$Base是什么东西??

环境就是MDK,不同的编译环境,这里的设置是不同的。$$Base表示前面的段的首地址
相应的前面段的尾地址$$Limit
这里还是MDK链接脚本里的语法。

bos_polling, pbPoling_t, polling又是什么??

pbPoling_t,这个是一个指针函数在b_section.h的第60行定义:typedef void (*pbPoling_t)(void);//这个定义谁是谁的别名呢?pbPoling_t 是void(*)(void)的别名
polling,就是一个指针函数名。
bos_polling,是一个段名

intptr_t又是什么??

在 stdint.h中101行定义:typedef signed int intptr_t;

bExec()总结

综合,这个函数的意思就是在程序段bos_polling中,依次执行polling函数。也实现了轮询。因为没有OS调度,所以,这就是代码的调度核心。

int bInit()到底要实现什么???

这个也是在core.c中第300行实现的。

int bInit()
{
    bHalInit();//这个在bhal.c中硬件抽象层里定义,可添加端口初始化等代码,还是空的。

    b_log("HW:%d.%d.%d FW:%d.%d.%d COMPILE:%s-%s\r\n", (HW_VERSION / 10000),
          (HW_VERSION % 10000) / 100, HW_VERSION % 100, (FW_VERSION / 10000),
          (FW_VERSION % 10000) / 100, FW_VERSION % 100, __DATE__, __TIME__);
    b_log("device number:%d\r\n", bDEV_MAX_NUM);//打印过程会再展开
    return bDeviceInit();//猜测,这个就是要实现设备注册
}

bDeviceInit()要实现什么呢???

这个也是在b_device.c中第128行实现.

int bDeviceInit()
{
    memset(&bNullDriver, 0, sizeof(bNullDriver));
    bSECTION_FOR_EACH(driver_init, pbDriverInit_t, pdriver_init)
    {
        (*pdriver_init)();
    }//这个宏定义与轮询宏是一样的,要实现的也是从在driver_init段中,依次执行pdriver_init函数
    return 0;
}
bNullDriver是什么??

实际上这是个设备抽象层定义的结构体。也就是将设备统一操作为打开,关闭,读、写等。

b_log()函数过程的实现???

要启用b_log功能,首先要在b_config.h中启用宏_DEBUG_ENABLE.这样会包含#include "modules/inc/b_mod_log.h"在这个头文件中,才会找到b_log的宏定义。
#define b_log(...) bLogOut(3, B_LOG_PARAM_DEFAULT, __VA_ARGS__)
而这个#define B_LOG_PARAM_DEFAULT __FILE__, __func__, __LINE__

bLogOut函数,还挺复杂???
/**
 * \brief Create and output string
 * \param type b_log_i b_log_w b_log_e b_log >> 0, 1, 2, 3  这几个应该是信息民,警告,错误,日志,共4种类型的日志
 * \param ptr_file file name
 * \param ptr_func function name
 * \param line line number
 * \retval none
 */
void bLogOut(uint8_t type, const char *ptr_file, const char *ptr_func, uint32_t line,
             const char *fmt, ...)
{
    uint32_t buf_len  = 0;
    uint32_t param    = 0;
    uint8_t  name_len = 0;
    int      str_len  = 0;
    char *   p_tmp = NULL, *pbuf = (char *)bLogBuff;//这里指向一个数组
    char     line_number[8];
    va_list  ap;

    if (type >= 4)
    {
        return;
    }

    memset(pbuf, 0, B_LOG_BUF_SIZE);
    param = bLogParamTable[type];//信息类型数组 B_LOG_I_PARAM, B_LOG_W_PARAM, B_LOG_E_PARAM  
//#define B_LOG_I_PARAM (B_LOG_PARAM_NULL)
//#define B_LOG_W_PARAM (B_LOG_PARAM_FUNC | B_LOG_PARAM_LINE)
//#define B_LOG_E_PARAM (B_LOG_PARAM_FILE | B_LOG_PARAM_FUNC | \B_LOG_PARAM_LINE)

    if (type < 3)//前三种类型处理
    {
        pbuf[buf_len++] = bLogPrefix[type];//这个数组存三个字符I、W、E
        pbuf[buf_len++] = ':';
        if (param & B_LOG_PARAM_FILE)
        {
            name_len = strlen(ptr_file);
            p_tmp    = (char *)ptr_file;
            if (name_len > 10)
            {
                p_tmp    = (char *)(ptr_file + name_len - 10);
                name_len = 10;
            }
            memcpy(pbuf + buf_len, p_tmp, name_len);
            buf_len += name_len;
            pbuf[buf_len++] = ' ';
        }
        if (param & B_LOG_PARAM_FUNC)
        {
            p_tmp    = (char *)ptr_func;
            name_len = strlen(ptr_func);
            memcpy(pbuf + buf_len, p_tmp, name_len);
            buf_len += name_len;
            pbuf[buf_len++] = ' ';
        }
        if (param & B_LOG_PARAM_LINE)
        {
            str_len = sprintf(line_number, "%d", line);
            if (str_len < 0)
            {
                return;
            }
            memcpy(pbuf + buf_len, line_number, str_len);
            buf_len += str_len;
            pbuf[buf_len++] = ' ';
        }
    }
    va_start(ap, fmt);//解决变参问题一组宏
    str_len = vsnprintf(pbuf + buf_len, B_LOG_BUF_SIZE - buf_len - 1, fmt, ap);
    va_end(ap);
    if (str_len < 0)
    {
        return;
    }
    bLogOutput(pbuf);//调用hal库的HAL_UART_Transmit(&huart1, pbuf, len, 0xffff);打印内容。这个函数定义在串口驱动层中b_hal_uart.c中
}
va_start宏

详见博客:关于va_start

bInit总结

猜想的不对,设备注册应该还是另有函数实现。这里只是初始化注册中的设备。

另一个重要的函数BOS_PERIODIC_TASK()??

这个函数是在b_os.h中宏定义的,可见,应该是非常频繁的使用的一个。

#define BOS_PERIODIC_TASK(pf, ms)                         \
    {                                                     \
        static uint32_t tick##pf = 0;                     \//定义了一个静态的变量 tick##pf
        if (bHalGetSysTick() - tick##pf > (MS2TICKS(ms))) \//bHalGetSysTick()这个函数只是返回了bSysTick这个全局变量
        {                                                 \
            tick##pf = bHalGetSysTick();                  \
            pf();                                         \//时间到了后执行这个函数。
        }                                                 \
    }

MS2TICKS(ms)又是什么呢??

这个是在b_config.h中宏定义的。#define MS2TICKS(m) (m / (1000 / _TICK_FRQ_HZ))m:定时的时间 1000/系统节拍:这个整体其实表示的是ms的系统节拍数 再被m除的话,就是将定时时间转成系统的节拍数。

系统滴答又是如何定义的呢?

这个其实是stm32 的hal库默认定义的,就是1ms中断一次。在main.c里的HAL_Init()里定义。

BOS_PERIODIC_TASK总结

本篇只是对babyos的调度做一个认识,其核心显然不是这块,而是其驱动框架。这就有点rtt一样的感觉了。具体的如何使用,也在驱动框架里。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guangod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值