【GUI】LVGL无操作系统移植以及移植过程错误处理

news2024/11/27 14:45:35

 目录    

介绍

1. 删除源码

2. 导入lvgl到项目screen_mcu中

3. keil添加分组和头文件

4. 移植显示

5. 移植触摸

6. 添加测试案例

6.1. 测试按钮

6.2. 测试音乐界面

7. 提供时钟

错误处理

L6218E错误

出现花屏

屏幕颜色不对

内存分配


介绍

        本文 主要介绍GD32移植LVGL的过程,以及移植过程中出现的问题以及解决方法,写的非常详细,基本上都截图了。    移植前需要准备下列:

  1. 准备包含触摸功能的屏幕
  2. 实现触摸屏的显示和触摸驱动,确保屏幕没有问题。
  3. 下载lvgl 8.3版本源码下载地址:https://github.com/lvgl/lvgl

本次移植开发板

  • 立创天空星GD32F407VET6
  • 1.69寸电容触摸屏  触摸芯片CS816t,显示:st7789

1. 删除源码

删除源码中不需要的文件夹,仅保留如下内容

  1. demos : lvgl综合案例
  2. examples :单个功能案例
  3. src : 源代码
  4. lv_conf_template.h : 重要的配置文件,里面存在非常多的开关
  5. lvgl.h : 头文件

将上述内容存放到名为lvgl的文件夹中

2. 导入lvgl到项目screen_mcu中

1、在screen_mcu项目中新建third_party文件夹,该文件夹用于存放第三方驱动。

2、将第1个步骤中的lvgl文件夹拷入其中

3、将lvgl文件夹中的lv_conf_tempalate.h修改lv_conf.h

4、把lv_conf.h的条件编译指令#if 0修改成#if 1

3. keil添加分组和头文件

1、使用keil打开screen_mcu项目,添加如下分组

third_party/lvgl/example/porting
third_party/lvgl/src/core
third_party/lvgl/src/draw
third_party/lvgl/src/extra
third_party/lvgl/src/font
third_party/lvgl/src/gpu
third_party/lvgl/src/hal
third_party/lvgl/src/misc
third_party/lvgl/src/widgets

2、添加LVGL相关的.c文件到相应分组,如下:

3、添加头文件路径

4、开启C99模式

4. 移植显示

把lv_port_disp_template.c/h的条件编译指令#if 0修改成#if 1

lv_port_disp_template.h中包含输出设备驱动头文件

#include "st7789.h"

lv_port_disp_template.h中宏定义水平和竖直分辨率(默认横屏)

#define MY_DISP_HOR_RES 240     //水平分辨率
#define MY_DISP_VER_RES 280     //垂直分辨率

修改 lv_port_disp_template.c中 的 lv_port_disp_init 函数

配置图形数据缓冲模式

在lv_port_disp_init函数中选择一种缓冲模式,注释掉其它两种模式

在lv_port_disp_template.c中void disp_init函数添加 屏幕显示驱动初始化函数,这里也就是 ST7789_Init();

/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
    /*You code here*/
  ST7789_Init();
}

在disp_flush函数中配置打点输出

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    if(disp_flush_enabled) {
    	ST7789_Fill(area->x1,area->y1,area->x2,area->y2,(uint16_t*)color_p);
    }
    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

5. 移植触摸

     1、把lv_port_indev_tempalte.c/h的条件编译#if 0修改成# if 1

      2、在lv_port_indev_tempalte.c中裁剪输入设备

  • 只保留touchpad_xxx相关的方法,删除其它方法
  • lv_port_indev_init中只保留touchpad相关的代码
  • 在touchpad_init方法中执行触摸屏初始化CST816T_Init();

(包含驱动)

/*Initialize your touchpad*/
static void touchpad_init(void)
{
    CST816T_Init();            //触摸屏初始化
}

        3、配置触摸检测函数

/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
    /*Your code comes here*/
		return CST816T_is_pressed();
    // return false;
}

        4、配置坐标获取函数

/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
    /*Your code comes here*/
		CST816T_get_xy((uint16_t*)x,(uint16_t*)y);
    //(*x) = 0;
    //(*y) = 0;
}

lv_port_indev_template.c修改之后代码如下:

/**
 * @file lv_port_indev_templ.c
 *
 */

/*Copy this file as "lv_port_indev.c" and set this value to "1" to enable content*/
#if 1

/*********************
 *      INCLUDES
 *********************/
#include "lv_port_indev_template.h"
//#include "../../lvgl.h"
#include "cst816t.h"

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/

static void touchpad_init(void);
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool touchpad_is_pressed(void);
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y);

static void mouse_init(void);
static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool mouse_is_pressed(void);
static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y);

static void keypad_init(void);
static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static uint32_t keypad_get_key(void);

static void encoder_init(void);
static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static void encoder_handler(void);

static void button_init(void);
static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static int8_t button_get_pressed_id(void);
static bool button_is_pressed(uint8_t id);

/**********************
 *  STATIC VARIABLES
 **********************/
lv_indev_t * indev_touchpad;
lv_indev_t * indev_mouse;
lv_indev_t * indev_keypad;
lv_indev_t * indev_encoder;
lv_indev_t * indev_button;

static int32_t encoder_diff;
static lv_indev_state_t encoder_state;

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

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;

    /*------------------
     * Touchpad
     * -----------------*/

    /*Initialize your touchpad if you have*/
    touchpad_init();

    /*Register a touchpad input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touchpad_read;
    indev_touchpad = lv_indev_drv_register(&indev_drv);

 
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

/*------------------
 * Touchpad
 * -----------------*/

/*Initialize your touchpad*/
static void touchpad_init(void)
{
    /*Your code comes here*/
	CST816T_Init();
}

/*Will be called by the library to read the touchpad*/
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static lv_coord_t last_x = 0;
    static lv_coord_t last_y = 0;

    /*Save the pressed coordinates and the state*/
    if(touchpad_is_pressed()) {
        touchpad_get_xy(&last_x, &last_y);
        data->state = LV_INDEV_STATE_PR;
    }
    else {
        data->state = LV_INDEV_STATE_REL;
    }

    /*Set the last pressed coordinates*/
    data->point.x = last_x;
    data->point.y = last_y;
}

/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
    /*Your code comes here*/
		return CST816T_is_pressed();
    // return false;
}

/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
    /*Your code comes here*/
		CST816T_get_xy((uint16_t*)x,(uint16_t*)y);
    //(*x) = 0;
    //(*y) = 0;
}


#else /*Enable this file at the top*/

/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif

6. 添加测试案例

初始化LVGL,包含LVGL相关头文件

6.1. 测试按钮

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "USART.h"
#include "I2C.h"

#include "st7789.h"
#include "cst816t.h"

#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"

// 事件回调
void event_handler(lv_event_t* e) {
  lv_event_code_t code = lv_event_get_code(e);

  if (code == LV_EVENT_VALUE_CHANGED) {
    printf("toggled btn\n");
  }
}
void demo_button_checkable() {
  // 获取显示图层
  lv_obj_t* screen = lv_scr_act();
  // 创建按钮
  lv_obj_t* btn = lv_btn_create(screen);
  // 设置按钮尺寸
  lv_obj_set_size(btn, 120, 50);

  // 4. 在按钮上创建文本并居中显示
  lv_obj_t* label = lv_label_create(btn);
  lv_label_set_text(label, "Toggle");
  // lv_obj_center(label);
  lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
  // 5. 设置按钮可选中
  lv_obj_add_flag(btn, LV_OBJ_FLAG_CHECKABLE);

  // 默认选中
//  lv_obj_add_state(btn, LV_STATE_CHECKED);

  lv_obj_add_event_cb(btn, event_handler, LV_EVENT_VALUE_CHANGED, NULL);
  // 居中
  lv_obj_center(btn);
}

主函数


int main(void) {
  // 配置全局中断分组
  nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
  // 初始化系统嘀嗒定时器
  systick_config();
  // 初始化USART
  USART_init();
  I2C_init();

  // 1. 初始化LVGL
  lv_init();
  // 2.显示屏驱动初始化
  lv_port_disp_init();
  // 3. 触摸屏(输入设备要在屏幕初始化之后再init,否则会失效)
  lv_port_indev_init();

  demo_button_checkable();

  while(1) {
    // 4. 每隔x毫秒调用一次心跳
    lv_tick_inc(1);
    // 5. 执行定时任务(屏幕渲染,事件处理)
    lv_timer_handler();
    // 休眠1ms
    delay_1ms(1);
  }
}

6.2. 测试音乐界面

        音乐界面需要接近1M的内存,天空星内存小了,无法测试,下载进去会报几百个错误,显示内存不足,可以使用梁山派。

        1、keil添加lvgl/demos/music文件夹下所有.c文件

        2、添加相关头文件路径

..\..\third_party\lvgl\demos
..\..\third_party\lvgl\demos\music

        3、修改lv_conf.h中的

#define LV_USE_DEMO_MUSIC 0改为#define LV_USE_DEMO_MUSIC 1

#define LV_FONT_MONTSERRAT_12 0改为#define LV_FONT_MONTSERRAT_12 1

#define LV_FONT_MONTSERRAT_16 0改为#define LV_FONT_MONTSERRAT_16 1

#define LV_USE_DEMO_MUSIC       0
改为
#define LV_USE_DEMO_MUSIC       1

#define LV_FONT_MONTSERRAT_12 0
改为
#define LV_FONT_MONTSERRAT_12 1

#define LV_FONT_MONTSERRAT_16 0
改为
#define LV_FONT_MONTSERRAT_16 1

main.c主函数

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "bsp_basic_timer.h"

#include "lcd.h"
#include "touch.h"

#include "lvgl.h"

#include "lv_demo_music.h"
#include "lv_conf.h"
#include "lv_port_disp_template.h"
#include "lv_port_indev_template.h"

int main(void)
{
    nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);  // 优先级分组
    systick_config();	

    lv_init();
    // 这里必须先初始化disp再初始化indev
    lv_port_disp_init();
    lv_port_indev_init();	

    lv_demo_music();
    while(1)
    {
        lv_tick_inc(1);
		lv_timer_handler();
		delay_1ms(1);
    }
}

7. 提供时钟

        可以不用定时器时钟,直接放在while循环中,后面的定时器就不需要配置

while(1) {
        lv_tick_inc(5);
        lv_timer_handler();
        delay_1ms(5);
}

        在Hardware下创建timer文件夹,文件夹下定义bsp_basic_timer.h和bsp_basic_timer.c文件,内容如下

#ifndef _BSP_BASIC_TIMER_H
#define _BSP_BASIC_TIMER_H

#include "gd32f4xx.h"
#include "systick.h"
#include "stdio.h"
#include "lvgl.h"

#define BSP_TIMER_RCU  				RCU_TIMER5            // 定时器时钟
#define BSP_TIMER      				TIMER5                // 定时器
#define BSP_TIMER_IRQ  				TIMER5_DAC_IRQn       // 定时器中断
#define BSP_TIMER_IRQHANDLER  TIMER5_DAC_IRQHandler // 定时器中断服务函数


//#define BSP_TIMER_RCU  				RCU_TIMER2					// 定时器时钟
//#define BSP_TIMER      				TIMER2							// 定时器
//#define BSP_TIMER_IRQ  			  TIMER2_IRQn					// 定时器中断
//#define BSP_TIMER_IRQHANDLER  TIMER2_IRQHandler		// 定时器中断服务函数


void basic_timer_config(uint16_t pre,uint16_t per); // 基本定时器配置

#endif  /* BSP_BASIC_TIMER_H */

#include "bsp_basic_timer.h"
//#include "bsp_led.h"

/************************************************
函数名称 : basic_timer_config
功    能 : 基本定时器配置
参    数 : pre:时钟预分频值
					  per:周期 
*************************************************/
void basic_timer_config(uint16_t pre,uint16_t per)
{
    /* 一个周期的时间T = 1/f, 定时时间time = T * 周期
    设预分频值位pre,周期位per
    time = (pre + 1) * (per + 1) / psc_clk
	*/
    timer_parameter_struct timere_initpara; 							// 定义定时器结构体
    /* 开启时钟 */
    rcu_periph_clock_enable(BSP_TIMER_RCU); 							// 开启定时器时钟
    /* CK_TIMERx = 4 x CK_APB1  = 4x50M = 200MHZ */
    rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4); // 配置定时器时钟


    timer_deinit(BSP_TIMER);														  // 复位定时器
    /* 配置定时器参数 */
    timere_initpara.prescaler = pre-1;                    //  时钟预分频值 0-65535   psc_clk = CK_TIMER / pre
    timere_initpara.alignedmode = TIMER_COUNTER_EDGE;     // 边缘对齐                  
    timere_initpara.counterdirection = TIMER_COUNTER_UP;  // 向上计数    
    timere_initpara.period = per-1;                       // 周期  
    /* 在输入捕获的时候使用  数字滤波器使用的采样频率之间的分频比例 */
    timere_initpara.clockdivision = TIMER_CKDIV_DIV1;     // 分频因子         
    /* 只有高级定时器才有 配置为x,就重复x+1次进入中断 */    
    timere_initpara.repetitioncounter = 0;							  // 重复计数器 0-255  

    timer_init(BSP_TIMER,&timere_initpara);								// 初始化定时器

    /* 配置中断优先级 */
    nvic_irq_enable(BSP_TIMER_IRQ,3,2); 									// 设置中断优先级为 3,2
    /* 使能中断 */
    timer_interrupt_enable(BSP_TIMER,TIMER_INT_UP);       // 使能更新事件中断 
    /* 使能定时器 */
    timer_enable(BSP_TIMER);
}

/************************************************
函数名称 : BSP_TIMER_IRQHandler
功    能 : 基本定时器中断服务函数 
参    数 : 无
返 回 值 : 无
作    者 : LC
*************************************************/
void BSP_TIMER_IRQHANDLER(void)
{
    /* 这里是定时器中断 */
    if(timer_interrupt_flag_get(BSP_TIMER,TIMER_INT_FLAG_UP) == SET)
    {
        timer_interrupt_flag_clear(BSP_TIMER,TIMER_INT_FLAG_UP);  // 清除中断标志位 
        /* 执行功能 */
        lv_tick_inc(1);
    }
}

定义之后,keil添加.c文件和头文件即可

错误处理

L6218E错误

.\Objects\GD32F450.axf: Error: L6218E: Undefined symbol __aeabi_assert (referred from qrcodegen.o).

解决方案:

添加NDEBUG宏定义

设置如下即可

出现花屏

        出现该现象是由于LVGL相对占用内存较大,需要修改内存问题,在startup_gd32f407_427.s中修改内存大小即可

原始:
Stack_Size      EQU     0x00000400
修改后:
Stack_Size      EQU     0x00000800

屏幕颜色不对

        正常颜色应该和下发模拟器图片一致,按钮是蓝色的,出现该问题的原因:LVGL配置的color depth颜色深度参数和屏幕不一致导致,在配置文件lv_conf.h里面修改LV_COLOR_DEPTH、LV_COLOR_16_SWAP的宏定义。

内存分配

         在LVGL中,除了注释不使用相关业务外,有3个位置可以实现修改内存修改,根据自己情况进行来。

1、startup_gd32f407_427.s中修改内存大小,当移植出现花屏的时候,修改这里即可解决。

2、在配置文件lv_conf.h中:LV_MEM_SIZE定义LVGL内部使用的内存池的大小。该内存池用于LVGL的对象、样式、动画等动态分配的内存需求。决定了LVGL可以使用的总内存量

3、显示缓存(Display Buffer)

在配置文件lv_conf.h中,lv_disp_draw_buf_init函数中指定了显示的缓存大小(即MY_DISP_HOR_RES * MY_DISP_VER_RES)直接决定了一次可以绘制的最大像素数量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1848656.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络编程(TCP协议,UDP协议)

目录 网络编程三要素 IP IPv4 InetAddress类 端口号 协议 UDP协议 UDP协议发送数据 UDP协议接收数据 UDP的三种通信方式(代码实现) TCP协议 TCP通信程序 三次握手和四次挥手 练习 1、客户端:多次发送数据服务器:接收多次接收数据&#xff0c;并打印 2、客户端…

Mysql安装 /lib64/libc.so.6: version `GLIBC_2.28‘ not found 缺少 glibc-2.28.tar.gz

问题&#xff1a;安装Mysql出现 Error mysql/bin/mysqld: /lib64/libm.so.6: version GLIBC_2.27 not found (required by mysql/bin/mysqld) mysql/bin/mysqld: /lib64/libc.so.6: version GLIBC_2.28 not found (required by mysql/bin/mysqld) mysql/bin/mysqld: /lib64/lib…

云计算之CDN

目录 一.什么是CDN&#xff1f; 二.使用CDN的好处&#xff1a; 三.主要特点&#xff1a; 四.关键功能&#xff1a; 一.什么是CDN&#xff1f; 1.CDN的全称是Content Delivery Network&#xff0c;即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和…

LabVIEW电动汽车核心部件检测系统

LabVIEW开发的电动汽车核心部件检测系统&#xff0c;通过硬件接入板和数据采集卡实现信号采集和分析。系统具备智能诊断、模块化设计和用户友好的特点&#xff0c;能够快速、精确地定位故障&#xff0c;提高电动汽车的维护效率和可靠性&#xff0c;支持新能源汽车市场的快速发展…

【教程】PVE下uhd630核显直通HDMI输出 以NUC9为例村雨Murasame

大家好&#xff0c;村雨本雨又来发教程了 最近在搞小主机&#xff0c;之前hp400g3仅仅200多元成功核显直通HDMI&#xff0c;作为简单NAS、解码机、伺服机、中控都非常棒&#xff0c;待机仅9w 村雨Murasame&#xff1a;【教程】7代核显直通HDMI成功输出画面 PVE下7代intel核显…

多路h265监控录放开发-(8)完成摄像机管理的修改和删除功能

xviewer.h public:XViewer(QWidget* parent Q_NULLPTR);//编辑摄像机void SetCam(int index);//121 public slots:void AddCam(); //新增摄像机配置120void SetCam(); //121void DelCam(); //121 private:Ui::XViewerClass ui;QMenu left_menu_; xviewer.cpp void XView…

2024最新1小时零基础编写uniapp和小程序管理后台,基于uniadmin和vue3实现uniapp小程序的网页管理后台

一&#xff0c;创建uniAdmin项目 打开开发者工具Hbuilder,然后点击左上角的文件&#xff0c;点新建&#xff0c;点项目。如下图。 选择uniadmin&#xff0c;编写项目名&#xff0c;然后使用vue3 记得选用阿里云服务器&#xff0c;因为最便宜 点击创建&#xff0c;等待项目创…

Postman 接口测试 安装使用教程

1 下载官网:https://www.postman.com/downloads/ 2 方便下载,特提供百度云网盘: 链接&#xff1a;Postman 3 windows10 安装&#xff0c;点击安装包 #自动安装&#xff0c;并打开 4 举例&#xff0c;比如豆瓣&#xff0c;get 查询时间&#xff0c;图片登 5 举例&#xff0…

Android网络编程之Http通信

//使用HttpURLConnection打开连接 2.HttpURLConnection urlConn (HttpURLConnection) url.openConnection(); //得到读取的内容(流) 4.InputStreamReader in new InputStreamReader(urlConn.getInputStream()); // 为输出创建BufferedReader BufferedReader buffer new …

小米测开二面—80min中核

小米测开二面—80min中核 3.28 无自我介绍直接开问&#xff01;你的第一份实习是一个开发工作你的第二实习为什么又跑到测试了你的第一份实习遇到了哪些挑战你的逆向开发的开发目标是什么&#xff0c;使用了什么工具你最终开发落地是用在了什么方面上&#xff0c;比如机器人路…

【FPGA + Nvidia/算能GPU+AI】自动驾驶多核异构实现 16路车载摄像头实时AI分析解决方案

基于 Xilinx 公司ZYNQ Ultrascale MPSoC系列 FPGA 芯片设计&#xff0c;应用于无人驾驶、慢速特种车及数据采集车、车载仿真测试系统等自动驾驶领域 自动驾驶&#xff1a;16通道车载摄像头PCIE采集卡方案。 16 通道摄像头 最多支持 16 通道 GMSL1/2 摄像头输入 8MP 摄像头 最…

[火灾警报系统]yolov5_7.0-pyside6火焰烟雾识别源码

国内每年都会发生大大小小的火灾&#xff0c;造成生命、财产的损失。但是很多火灾如果能够早期发现&#xff0c;并及时提供灭火措施&#xff0c;将会大大较小损失。本套源码采用yolov5-7.0目标检测算法结合pyside6可视化界面源码&#xff0c;当检测到火灾时&#xff0c;能否发出…

BGP路由反射器实验

实验内容&#xff1a; 通过本实验验证bgp路由反射器的规则 1. 从client收到的路由更新&#xff0c;反射到non-client和client&#xff0c;同时发送给EBGP邻居 2. 从non-client收到的路由更新&#xff0c;只反射到client&#xff0c;同时发送给EBGP邻居 3. 从EBGP邻居收到的路…

多路h265监控录放开发-(8)通过XCameraWIget类拖拽实现指定播放rtsp和窗口

首先修改xviewer的构造函数&#xff0c;把创建QWiget对象改为XCameraWiget对象&#xff0c;执行XCameraWiget类的构造函数 xcamera_widget.h #pragma once #include <QWidget> class XCameraWidget :public QWidget {Q_OBJECTpublic:XCameraWidget(QWidget* p nullptr)…

【六】【QT开发应用】信号和信号槽的五种写法

第一种写法 第二种写法 第三种写法 第四种写法 第五种写法 完整代码 mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow …

【STM32--Cortex-M3】

STM32-Cortex-M3 ■ Cortex-M3 处理器内核到基于Cortex-M3的MCU■ ARM的各种架构版本■ 指令集■ Cortex-M3简介■ Cortex-M3寄存器组■ Cortex-M3■ Cortex-M3■ Cortex-M3 ■ Cortex-M3 处理器内核到基于Cortex-M3的MCU Cortex-M3处理器内核是单片机的中央处理单元&#xff…

Linux系统开机自启动脚本(案例:Raspberry Pi 4B脚本)

前言&#xff1a;本篇博客为手把手教学的 Linux 系统开机自启动脚本教程&#xff0c;且额外包含有 Raspberry Pi 4B 的开机自启动案例。日常工程项目中往往需要 Linux 系统能够自启动一些代码程序&#xff0c;本篇博客利用虚拟机下的 Ubuntu 自启动脚本来进行教学&#xff0c;且…

React的State和setState

如何确地使用 State 不要直接修改 State.修改State应该使用 setState():构造函数是唯一可以给 this.state 赋值的地方 State 与 props 类似&#xff0c;但是 state 是私有的&#xff0c;并且完全受控于当前组件 我们可以在我们的自定义组件中添加私有的State jcode class C…

mac怎么压缩pdf文件,苹果电脑怎么压缩pdf文件大小

在当今数字化时代&#xff0c;PDF文件已成为广泛使用的文档格式之一。然而&#xff0c;PDF 文件可能会因其包含的图像、图形和其他元素而导致文件较大&#xff0c;这可能会影响文件的传输、存储和共享。因此&#xff0c;对 PDF 文件进行压缩以减小其文件大小是很有必要的。今天…

【详细】一步一步实现一个BP神经网络-逐行代码解说

本文来自《老饼讲解-BP神经网络》https://www.bbbdata.com/ ​ 要如何使用代码实现一个BP神经网络呢&#xff1f; 下面跟随笔者&#xff0c;一步一步详细来实现&#xff0c;再对代码进行详细解说。 通过本文可以详细掌握怎么使用matlab来实现一个BP神经网络。 一、一步一步实…