【LVGL】学习笔记--(1)Keil中嵌入式系统移植LVGL

这篇具有很好参考价值的文章主要介绍了【LVGL】学习笔记--(1)Keil中嵌入式系统移植LVGL。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档

一 LVGL简介

最近emwin用的比较烦躁,同时被LVGL酷炫的界面吸引到了,所以准备换用LVGL试试水。

LVGL(轻量级和通用图形库)是一个免费和开源的图形库,它提供了创建嵌入式GUI所需的一切,具有易于使用的图形元素,美丽的视觉效果和低内存占用。

【1】主要特性

  1. 丰富且强大的模块化图形组件:按钮 (buttons)、图表 (charts)、列表 (lists)、滑动条 (sliders)、图片 (images) 等

  1. 高级的图形引擎:动画、抗锯齿、透明度、平滑滚动、图层混合等效果

  1. 支持多种输入设备:触摸屏、 键盘、编码器、按键等

  1. 支持多显示设备

  1. 不依赖特定的硬件平台,可以在任何显示屏上运行

  1. 配置可裁剪(最低资源占用:64 kB Flash,16 kB RAM)

  1. 基于UTF-8的多语种支持,例如中文、日文、韩文、阿拉伯文等

  1. 可以通过类CSS的方式来设计、布局图形界面(例如:Flexbox、Grid)

  1. 支持操作系统、外置内存、以及硬件加速(LVGL已内建支持STM32 DMA2D、NXP PXP和VGLite)

  1. 即便仅有单缓冲区(frame buffer)的情况下,也可保证渲染如丝般顺滑

  1. 全部由C编写完成,并支持C++调用

  1. 支持Micropython编程,参见:LVGL API in Micropython

  1. 支持模拟器仿真,可以无硬件依托进行开发

  1. 丰富详实的例程

  1. 详尽的文档以及API参考手册,可线上查阅或可下载为PDF格式

  1. 在 MIT 许可下免费和开源

【2】配置要求

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档

【3】与其他显示工具的对比

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档

二 LVGL移植前准备

【1】参考资料

  1. LVGL官网:https://lvgl.io/

  1. LVGL源码:https://gitee.com/my_lvgl/lvgl

  1. 百问网LVGL中文开发手册:http://lvgl.100ask.net/8.2/index.html

  1. 一些关于移植的经验资料:

LITTLEVGL (LVGL)入门之移植到STM32芯片

LVGL学习笔记 | 02 - 移植LVGL 8.2到STM32F407开发板(MCU屏)

STM32移植LVGL(LittleVGL)

在STM32F4上移植LVGL8.2

【2】硬件资源

硬件资源包括:

  1. 嵌入式平台(我用的MCU是华大的HC32F460芯片)

  1. 实现了屏幕驱动的液晶屏(我用的是3.2寸320*240的8080并口屏,屏幕驱动可以移步【嵌入式】MCU(HC32F460)+并口LCD液晶屏ILI9341 移植emWin记录)

  1. 输入设备(非必要,包括触摸屏、鼠标、键盘、编码器、按键,我自己使用的是磁控旋钮编码器)

【3】其他(GUI Guider)

推荐一款不错的LVGL设计工具GUI Guider,是由恩智浦开发的,通过NXP官网(https://www.nxp.com.cn/design/software/development-software/gui-guider:GUI-GUIDER)即可下载。

具体用法参考我的另一篇文章《【LVGL】学习笔记--(2)GUI Guider的使用》。

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档

准备好了以上的内容,接下来就可以进行移植了。

三 LVGL移植

【1】源码下载

首先下载LVGL源码,链接见上一章的参考资料。有很多版本,我这边没有选择最新的版本,而是用了V1.5.0-GA版本GUI Guider支持的V8.3.2版本:

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档
lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档

下载完解压后是这样的:

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档

【2】源码添加工程

  1. 将上面解压完成的lvgl-v8.3.2文件夹中的下列文件复制到自己keil工程自建文件夹GUI_LVGL中:

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档
  1. 复制进来后,删除proting文件夹以及lv_conf_template文件中_template后缀:

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档
  1. 在keil中建立管理目录:

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档

其中:

  • GUI/LVGL用来存放src及其子目录中所有.c文件。这一步比较考验耐心和细致,每一个子目录下都有不少源文件。(要是不想自己keil工程中有许多看起来凌乱的源文件,可以参考STM32/keil把多个c文件编译为静态库lib中的方法,预先将这许许多多的.c文件编译为lib库,那么GUI/LVGL中放一个lib文件即可。但是这种方法要注意创建lib的工程和使用lib的工程芯片型号要一致才可以)。我是使用的lib库的形式。

  • GUI/LVGL/PORT用来存放porting下的三个源文件,分别是lv_port_disp.c(显示接口文件)、lv_port_indev(输入设备接口文件)、lv_port_fs(文件系统接口文件)

  • GUI/LVGL用来存放GUI Guider生成的图形界面文件,这边暂时还没有用到,可以不用管。

  1. 包含头文件路径:

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档
  1. 最后还有两个重要的小操作,一个是要选用C99 Mode:

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档

另一个是加大栈空间,方法是打开.s启动文件,修改其中的Stack_Size值,我这边配置的是8KB(根据上面LVGL运行配置要求的推荐值确定)

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档

至此,可以编译一下,由于还没有使用显示接口等,所以这边应该是编译无误的。

【3】添加心跳接口

在timer.c中包含头文件"lvgl.h",并在1ms定时器中调用lv_tick_inc(1)启用心跳:

/**************************************************************************
* 函数名称: TimeraUnit2_IrqCallback
* 功能描述: 定时器A 单元2初始化
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 其它说明: 1ms定时器中断
**************************************************************************/
static void TimeraUnit2_IrqCallback(void)
{
    lv_tick_inc(1);
    TIMERA_ClearFlag(TIMERA_UNIT2, TimeraFlagOverflow);
}

当然还有其他方式让LVGL开始心跳,这个可以自行选用,控制心跳周期为1ms即可。

【4】显示接口对接屏幕驱动

  1. 修改lv_conf.h头文件中的#if 0为#if 1,同时根据适配的显示设备设置颜色格式:

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档

补充,如果想屏幕刷新快一点,可以将FPS做如下调整(30ms-->10ms,即FPS由30-->100):

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档
  1. 把lv_port_disp.c、lv_port_disp.h、lv_port_indev.c、lv_port_indev.h四个文件的#if 0 都改成#if 1 ,这四个文件包含的头文件名字还需根据编译报错信息修改。:

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档
lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档

注意,若头文件#include "lvgl/lvgl.h"包含报错,可以添加宏定义LV_CONF_INCLUDE_SIMPLE

  1. 修改lv_port_disp.c中适配底层屏幕驱动分辨率(我用的就是320*240):

/*********************
 *      DEFINES
 *********************/
#ifndef MY_DISP_HOR_RES
    #warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen width, default value 320 is used for now.
    #define MY_DISP_HOR_RES    320
#endif

#ifndef MY_DISP_VER_RES
    #warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen height, default value 240 is used for now.
    #define MY_DISP_VER_RES    240
#endif
  1. 修改lv_port_disp.c中lv_port_disp_init函数,该函数包含两个部分,一个是初始化disp_init(),一个是绘制缓冲区

其中初始化函数disp_init()中加入自己的屏幕初始化程序:

void LCD_AllInit(void)
{
    LCD_InitGPIO();  //初始化几个GPIO口,包括CS\RS\WR\RD\RES\DB0-15
    
    LCD_HardwareReset();  //LCD复位

    LCD_ConfigureREG();   //RGB配置初始化
    
    LCD_Clear(WHITE);  //清屏白色

    LCD_DisplayDir(data_inter.showDirect);  //默认为横屏
}

static void disp_init(void)
{
    /*You code here*/
    LCD_AllInit();
}
  1. 修改lv_port_disp.c中lv_port_disp_init函数绘制缓冲区的部分,删除不用的Example for 2/3,只留Example for 1即可:

void lv_port_disp_init(void)
{
    /*-------------------------
     * Initialize your display
     * -----------------------*/
    disp_init();

    /*-----------------------------
     * Create a buffer for drawing
     *----------------------------*/

    /**
     * LVGL requires a buffer where it internally draws the widgets.
     * Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display.
     * The buffer has to be greater than 1 display row
     *
     * There are 3 buffering configurations:
     * 1. Create ONE buffer:
     *      LVGL will draw the display's content here and writes it to your display
     *
     * 2. Create TWO buffer:
     *      LVGL will draw the display's content to a buffer and writes it your display.
     *      You should use DMA to write the buffer's content to the display.
     *      It will enable LVGL to draw the next part of the screen to the other buffer while
     *      the data is being sent form the first buffer. It makes rendering and flushing parallel.
     *
     * 3. Double buffering
     *      Set 2 screens sized buffers and set disp_drv.full_refresh = 1.
     *      This way LVGL will always provide the whole rendered screen in `flush_cb`
     *      and you only need to change the frame buffer's address.
     */

    /* Example for 1) */
    static lv_disp_draw_buf_t draw_buf_dsc_1;
    static lv_color_t buf_1[MY_DISP_HOR_RES * 10];                          /*A buffer for 10 rows*/
    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10);   /*Initialize the display buffer*/

    /*-----------------------------------
     * Register the display in LVGL
     *----------------------------------*/

    static lv_disp_drv_t disp_drv;                         /*Descriptor of a display driver*/
    lv_disp_drv_init(&disp_drv);                    /*Basic initialization*/

    /*Set up the functions to access to your display*/

    /*Set the resolution of the display*/
    disp_drv.hor_res = MY_DISP_HOR_RES;
    disp_drv.ver_res = MY_DISP_VER_RES;

    /*Used to copy the buffer's content to the display*/
    disp_drv.flush_cb = disp_flush;

    /*Set a display buffer*/
    disp_drv.draw_buf = &draw_buf_dsc_1;

    /*Required for Example 3)*/
    //disp_drv.full_refresh = 1;

    /* Fill a memory array with a color if you have GPU.
     * Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.
     * But if you have a different GPU you can use with this callback.*/
    //disp_drv.gpu_fill_cb = gpu_fill;

    /*Finally register the driver*/
    lv_disp_drv_register(&disp_drv);
}

补充,如果想屏幕刷新快一点,在SRAM足够的条件下,可以修改默认的buf_1[MY_DISP_HOR_RES * 10]为buf_1[MY_DISP_HOR_RES * MY_DISP_VER_RES / 4]:

static lv_disp_draw_buf_t draw_buf_dsc_1;
    static lv_color_t buf_1[MY_DISP_HOR_RES * MY_DISP_VER_RES / 4];                          /*A buffer for 10 rows*/
    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * MY_DISP_VER_RES / 4);   /*Initialize the display buffer*/
  1. 修改lv_port_disp.c中的刷屏函数disp_flush,默认的刷屏用打点的方式速度太慢,改用刷块的方式:

void LCD_Fill_LVGL(U16 sx,U16 sy,U16 ex,U16 ey,U16 *color)
{
    uint16_t height, width;
    uint16_t i, j;

    width = ex - sx + 1;            /* 得到填充的宽度 */
    height = ey - sy + 1;           /* 高度 */

    for (i = 0; i < height; i++)
    {
        LCD_SetCursor(sx, sy + i); /* 设置光标位置 */
        LCD_WriteRAM_Prepare();    /* 开始写入GRAM */

        for (j = 0; j < width; j++)
            LCD_WriteRAM(color[i * width + j]); /* 写入数据 */
    }
} 

/*Flush the content of the internal buffer the specific area on the display
 *You can use DMA or any hardware acceleration to do this operation in the background but
 *'lv_disp_flush_ready()' has to be called when finished.*/
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    LCD_Fill_LVGL(area->x1,area->y1,area->x2,area->y2,(U16 *)color_p);

    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

至此,显示接口对接屏幕驱动完成。

【5】输入设备接口对接编码器

如果没有使用到诸如触摸屏、鼠标、键盘、编码器、按键这几类的外部设备,只要显示界面不用操作的话,可以跳过这一节,直接到LVGL测试章节继续。

我这边用到的是磁控旋钮编码器外设

  1. 修改lv_port_indev.c中lv_port_indev_init函数,包含两个部分,一个是初始化encoder_init(),一个是注册编码器外部设备

其中初始化函数encoder_init()中加入自己的屏幕初始化程序:

/*Initialize your keypad*/
extern STRU_KNOB knob_old;
extern char knob_state_now;
static void encoder_init(void)
{
    /*Your code comes here*/
    MLX_InitGPIO();
    MLX_InitSPI();
    knob_old = knobPosInit();  //旋钮位置初始化
}
  1. 删除不用的外部设备,只留下编码器作为唯一外部输入:

void lv_port_indev_init(void)
{
    /**
     * Here you will find example implementation of input devices supported by LittelvGL:
     *  - Touchpad
     *  - Mouse (with cursor support)
     *  - Keypad (supports GUI usage only with key)
     *  - Encoder (supports GUI usage only with: left, right, push)
     *  - Button (external buttons to press points on the screen)
     *
     *  The `..._read()` function are only examples.
     *  You should shape them according to your hardware
     */

    static lv_indev_drv_t indev_drv;
    
    /*------------------
     * Encoder
     * -----------------*/

    /*Initialize your encoder if you have*/
    encoder_init();

    /*Register a encoder input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_ENCODER;
    indev_drv.read_cb = encoder_read;
    indev_encoder = lv_indev_drv_register(&indev_drv);

    /*Later you should create group(s) with `lv_group_t * group = lv_group_create()`,
     *add objects to the group with `lv_group_add_obj(group, obj)`
     *and assign this input device to group to navigate in it:
     *`lv_indev_set_group(indev_encoder, group);`*/
}
  1. 注册外部设备,修改encoder_read函数,encoder_handler可以不用管,encoder_diff的加减表示左旋和右旋,encoder_state赋值LV_INDEV_STATE_PR或者LV_INDEV_STATE_REL表示按下或松开

/*Will be called by the library to read the encoder*/
static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    if(knob_state_now == 9 || knob_state_now == 15)  //按下动作和按下状态都算按下
        encoder_state = LV_INDEV_STATE_PR;   //按下
    else
        encoder_state = LV_INDEV_STATE_REL;  //松开
    
    if(knob_state_now == 19)
        encoder_diff ++;
    else if(knob_state_now == 17)
        encoder_diff --;

    data->enc_diff = encoder_diff;
    data->state = encoder_state;
    encoder_diff = 0;
}

knob_state_now表示当前旋钮的状态,其状态的获得在主循环中获取,将其映射到encoder_diff和encoder_state这两个变量

#define KNOB_ESCAPE         8   //旋钮抬起状态,xy不变
#define KNOB_UP             17  //z不变,正向旋转
#define KNOB_DOWN           19  //z不变,反向旋转
#define KNOB_ENTER_BEF      15  //按下动作
  1. 创建、挂载Group

旋钮、键盘这种外部设备比较特殊,在初始化完成之后,如果想使用,必须先创建、挂载到Group才行,这一点,初始化函数 lv_port_indev_init 的注释中也明确地提到了:

/*Later you should create group(s) with `lv_group_t * group = lv_group_create()`,
     *add objects to the group with `lv_group_add_obj(group, obj)`
     *and assign this input device to group to navigate in it:
     *`lv_indev_set_group(indev_encoder, group);`*/

上面的意思就是说,使用编码器作为外部输入设备,需要使用“组”来配合,步骤如下:

  • 首先使用lv_group_create来创建组;

  • 其次将需要外部设备控制的控件,通过lv_group_add_obj挂载到组中;

  • 最后使用lv_indev_set_group将该组与输入设备绑定;

使用例程如下:

lv_group_t *groupRect;  //定义组名
//1.创建组
groupRect = lv_group_create();
//2.挂载控件到组
lv_group_add_obj(groupRect,guider_ui.screen_plus);
lv_group_add_obj(groupRect,guider_ui.screen_minus);
lv_group_add_obj(groupRect,guider_ui.screen_next);
//3.将输入设备与该组绑定
lv_indev_set_group(indev_encoder,groupRect);

注1:上面有三个不同的控件加入到组中,加入"组"中的先后顺序,就对应着你使用编码器在各个对象之间进行切换的先后顺序。最先加入的会先被选择,后加入的就会排在后面,就是这样的选择顺序;

注2:并不是所有的控件都能绑定组,诸如Label就不行;

注3:一个输入设备最好只绑定一个组,否则可能会出问题。如果需要界面进行切换,并在每个界面操作不同的控件组,那么输入设备需要绑定的组也要随着界面的切换而重新绑定。

四 LVGL测试

至此便完成了LVGL的显示接口以及输入设备接口的移植。

在主任务中添加上面的初始化,这边简单做了一个小界面方便展示(这个展示不包含上面的输入设备操作,带输入设备的例程可以看后面一篇文章):

#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
static void lv_ex_label_1(void)
{
    lv_obj_t * label2 = lv_label_create(lv_scr_act());
    lv_label_set_recolor(label2, true);
    lv_label_set_long_mode(label2, LV_LABEL_LONG_SCROLL_CIRCULAR); /*Circular scroll*/
    lv_obj_set_width(label2, 120);
    // Hello world ! Trisuborn.
    lv_label_set_text(label2, "#ff0000 Hello# #00ff00 world ! Trisuborn.#");
    lv_obj_align(label2, LV_ALIGN_CENTER, 0, 0);
}

void GUI_Task(void)
{
    //LVGL初始化
    lv_init();
    //显示器初始化
    lv_port_disp_init();
    //外部输入初始化
    lv_port_indev_init();
    //界面生成
    lv_ex_label_1();

    while(1)
    {
        knob_now = knobPosNow();  //确定旋钮当前位置
        knob_state_now = Knob_State_Entry(&knob_old, &knob_now, knob_state_old);  //确定旋钮当前状态
        if(KNOB_ESCAPE == knob_state_now)
        {
            knob_state_old = knob_state_now;
        }
        else
        {
            knob_old = knob_now;
            knob_state_old = knob_state_now;
        }
        lv_task_handler();
        os_dly_wait(5);
    }
}

效果如下:文章来源地址https://www.toymoban.com/news/detail-781033.html

lvgl+keil,嵌入式,C语言,嵌入式硬件,LVGL,stm32,HC32,Powered by 金山文档

到了这里,关于【LVGL】学习笔记--(1)Keil中嵌入式系统移植LVGL的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 《嵌入式系统设计师教程 (第2版)》学习笔记

    《嵌入式系统设计师教程 (第2版).pdf》链接:https://download.csdn.net/download/AnChenliang_1002/87864728 该资源在上传时涉及到版权问题无法上传,所以保留该资源仅为了日后查看时博主自己可以下载; 本文用来记录在学习《嵌入式系统设计师教程 (第2版)》过程中的个人笔记。 图书简介

    2024年02月09日
    浏览(39)
  • 【嵌入式系统开发】Keil 实现十次作业详细代码

          🔥《嵌入式系统开发》系列专栏主要以LPC1100系列微控制器为硬件平台,详细介绍Cortex—-M0微控制器的原理与开发技术,基于keil仿真软件平台设计最小应用系统板和具有在板仿真器的口袋开发板以及相关例程。       🔥本文已收录于嵌入式系统开发系列专栏:嵌入式

    2024年02月08日
    浏览(41)
  • 正点原子STM32嵌入式学习-keil5安装教程

    前言:本人没有什么嵌入式的经验,但是看到硬件的同事做开发板比较好玩,比较感兴趣。刚好有这样一个机会,可以跟随《原子教你玩STM32(库函数版)》课程线下学习,在此,将本次课程的学习做一个记录。相信对我这样一个小白来说,帮助还是会非常大的。 目录 一.下

    2024年03月10日
    浏览(57)
  • 基于RK3588的嵌入式linux系统开发(二)——uboot源码移植及编译

            由于官方的SDK占用空间较大(大约20GB左右),需要联系相关供应商提供,且官方的SDK通过各种脚本文件进行集成编译,难以理解系统开发的详细过程。本章介绍直接从官方Github网站下载源码进行移植,进行uboot移植及编译,具体内容如下所述: 1.进入官方的github网

    2024年01月16日
    浏览(48)
  • 【嵌入式Linux学习笔记】platform设备驱动和input子系统

    对于Linux这种庞大的操作系统,代码重用性非常重要,所以需要有相关的机制来提升效率,去除重复无意义的代码,尤其是对于驱动程序,所以就有了platform和INPUT子系统这两种工作机制。 学习视频地址:【正点原子】STM32MP157开发板 platform 驱动框架分为总线、设备和驱动。总

    2024年02月07日
    浏览(48)
  • 【嵌入式学习笔记】嵌入式入门2——中断(外部中断)

    打断CPU执行正常的程序,转而处理紧急程序,然后返回原暂停的程序继续运行,就叫中断 作用1: 实时控制在确定时间内对相应事件作出响应 ——定时器中断 作用2: 故障处理检测到故障,需要第一时间处理 ——外部中断 作用3: 数据传输不确定数据何时会来 ——串口中断

    2024年02月08日
    浏览(67)
  • 软考-嵌入式系统设计师:[嵌入式系统基础:笔记(一)]

    大家不要只收藏不关注呀,哪怕只是点个赞也可以呀!🤣 粉丝私信发邮箱,免费发你PDF!!! 因为准备备考中级嵌入式设计师证书,所以买了一些资料回来准备复习,本书为倪奕文老师编制的书,如果大家有时间和精力还是很建议大家去买一本的,这本书反而是能够让小白很快

    2023年04月08日
    浏览(51)
  • 带你了解LVGL:一个开源的嵌入式图形库

    嵌入式系统是一种将计算机硬件和软件集成在一个特定的应用中的系统,例如智能手机、智能手表、汽车仪表盘等。嵌入式系统通常需要与用户进行交互,因此需要一个友好和易用的图形用户界面(GUI)。然而,开发一个高质量的GUI并不容易,因为嵌入式系统通常有限的资源

    2024年02月09日
    浏览(58)
  • 【嵌入式学习笔记】嵌入式基础9——STM32启动过程

    程序段交叉引用关系(Section Cross References):描述各文件之间函数调用关系 删除映像未使用的程序段(Removing Unused input sections from the image):描述工程中未用到被删除的冗余程序段(函数/数据) 映像符号表(Image Symbol Table):描述各符号(程序段/数据)在存储器中的地址、类

    2024年02月15日
    浏览(75)
  • 嵌入式学习笔记汇总

    本文整理STM32、STM8和uCOS-III的所有文章链接。 源码:mySTM32-learn STM32学习笔记(1)——LED和蜂鸣器 STM32学习笔记(2)——按键输入实验 STM32学习笔记(3)——时钟系统 STM32学习笔记(4)——NVIC中断优先级管理和外部中断EXTI STM32学习笔记(5)——系统定时器SysTick STM32学习笔

    2023年04月20日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包