« 上一篇下一篇 »

STM32几种库空间占用与执行效率对比及C语言枚举的特别用例

1、STM32标准库与Cube、LL及直接写寄存器的对比

如上图示为STM32标准库与Cube库、LL库及直接写寄存器在ROM、RAM的空间占用以及执行效率上的对比,可以看出,不管是在空间占用还是执行效率上,直接写寄存器永远都是性能最好的方式,不过一般开发中不会用这种方式,因为不便于移植,所以用的最多的还是几种库。

SPL(标准库),是我从大学以来到工作,前后经历两家公司都一直在用的库,标准库支持所有的外设,而且无论在空间占用还是执行效率上,都不失为一个优秀的库,这个库的存在对ST迅速占领MCU的市场有着不小的功劳,毕竟很大程度上节省了开发人员的时间。不过遗憾的是,现在ST官方已经不再更新标准库,就是说后续有bug,或者是出了新的器件,新的外设,都不会在标准库上做支持了。

Cube HAL库,这个库我没实际用过,但是配合Cube MX的软件,的确是开发利器,可以直接在图形化界面上对外设进行配置,然后自动生成代码,包括一些比较复杂的驱动,如USB、以太网+LwIP等,都可以很简单的完成。但是从图中可以看到,Cube HAL的空间占用是标准库的2倍还多,执行效率大概只有标准库的3/5,根据这个对比,如果从我的角度来看,我是尽可能的不会用这个库的,毕竟空间和执行效率算是程序中最重要的两个东西了,这两个东西都不太行,光是开发快有啥用,那我也得有这么多空间用才行不是。

Cube LL库,从上图可以看到,这个库在空间占用与执行效率上比标准库还要低,就只比直接写寄存器差一点了,所以说这个库还是很值得用的,但是美中不足的是,相比起Cube HAL,Cube LL还很不完善,只支持部分的外设,有一些复杂的外设如USB目前都不支持,后续也不知道会不会支持,如果说后面LL库也会全面覆盖所有功能的话,这个库还是很值得使用的。

根据上述分析,我个人觉得目前最好的库还是标准库,像Cube HAL,能不用就不用吧,空间占用大,效率低,而且,使用这个库出了问题,找起来比标准库会麻烦的多。当然,虽然工作中不用,但是业余学习可以多熟悉下这两个库的使用,包括Cube Mx的软件。


2、枚举与宏结合使用的特别用例

#define LV_STYLE_PROP_INIT(name, group, id, attr)  name = (((group << 4) + id) | ((attr) << 8))

#define LV_STYLE_ATTR_NONE          0
#define LV_STYLE_ATTR_INHERIT       (1 << 7)

#define LV_STYLE_ID_VALUE 0x0   /*max 9 pcs*/
#define LV_STYLE_ID_COLOR 0x9   /*max 3 pcs*/
#define LV_STYLE_ID_OPA   0xC   /*max 2 pcs*/
#define LV_STYLE_ID_PTR   0xE   /*max 2 pcs*/

enum {
    /*Skip 0th property*/
    LV_STYLE_PROP_INIT(LV_STYLE_RADIUS,             0x0, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE),
    LV_STYLE_PROP_INIT(LV_STYLE_CLIP_CORNER,        0x0, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE),
    LV_STYLE_PROP_INIT(LV_STYLE_SIZE,               0x0, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE),
    LV_STYLE_PROP_INIT(LV_STYLE_TRANSFORM_WIDTH,    0x0, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE),
    LV_STYLE_PROP_INIT(LV_STYLE_TRANSFORM_HEIGHT,   0x0, LV_STYLE_ID_VALUE + 5, LV_STYLE_ATTR_NONE),
    LV_STYLE_PROP_INIT(LV_STYLE_TRANSFORM_ANGLE,    0x0, LV_STYLE_ID_VALUE + 6, LV_STYLE_ATTR_NONE),
    LV_STYLE_PROP_INIT(LV_STYLE_TRANSFORM_ZOOM,     0x0, LV_STYLE_ID_VALUE + 7, LV_STYLE_ATTR_NONE),
    LV_STYLE_PROP_INIT(LV_STYLE_OPA_SCALE,          0x0, LV_STYLE_ID_OPA + 0,   LV_STYLE_ATTR_INHERIT),
};

int main(void)
{
 printf("LV_STYLE_RADIUS = %d\r\n", LV_STYLE_RADIUS);
 printf("LV_STYLE_CLIP_CORNER = %d\r\n", LV_STYLE_CLIP_CORNER);
 printf("LV_STYLE_SIZE = %d\r\n", LV_STYLE_SIZE);
 printf("LV_STYLE_TRANSFORM_WIDTH = %d\r\n", LV_STYLE_TRANSFORM_WIDTH);
 printf("LV_STYLE_TRANSFORM_HEIGHT = %d\r\n", LV_STYLE_TRANSFORM_HEIGHT);
 printf("LV_STYLE_TRANSFORM_ANGLE = %d\r\n", LV_STYLE_TRANSFORM_ANGLE);
 printf("LV_STYLE_TRANSFORM_ZOOM = %d\r\n", LV_STYLE_TRANSFORM_ZOOM);
 printf("LV_STYLE_OPA_SCALE = %d\r\n", LV_STYLE_OPA_SCALE);
 getchar();
 system("pause");
}

上述代码中先是定义了一个带参数的宏LV_STYLE_PROP_INIT,它有4个参数,对后面3个参数进行运算赋值给第1个参数,然后在枚举中使用这个宏, 同时定义了几个成员,就这样,把宏和枚举结合起来,枚举中定义的成员的值由宏运算得来。从printf()打印出来的结果来看, 枚举中几个成员的赋值都是正确的,说明这种用法是没错的。说实话,我也是第一次看到这种用法,按理来说,通常的,我们定义一个枚举,里面的成员的值就是直接用‘=’赋值,或者就是默认,这里的用法却是没有这样做,而是每一个成员都是一个宏,然后宏的第1个参数就是枚举中定义的成员。这操作感觉有点高级。

时间过得很快,又特么一个周过去了,刚刚老妈又来问我找对象的事情了,头痛哦!


2020年11月29日 于广州花都