[GUI]stm32搭载3.5寸SPI-TFT屏移植LittleVGL

2023-11-12

唠几句,记录下移植笔记
新项目用到LVGL,也是首次接触GUI库,所以Emmmm,,,学呗!!!
之前都是直接在LCD屏上画点、画线、画圆、画个矩形、画个多边形、显示个字符串、显示张图片而已,没有用过GUI库,在网上找了点学习资料,然后把LVGL库的用法整体过了一遍。
寻思着搞个屏练习一下,然后趁着周末把SPI屏(IFI9488/ 480*320)驱动起来,甚至还优化了绘图部分的程序,下面是部分优化记录

方式一:移植淘宝卖家提供的Demo
串口日志:刷整屏用时3s
system Init complate!
RUNNING time: 3032

方式二:优化1(库函数)
串口日志:刷整屏用时1.2s
system Init complate!
RUNNING time: 1221

方式三:优化2(寄存器:spi写)
串口日志:刷整屏用时0.33s
system Init complate!
RUNNING time: 333

最终版
串口日志:刷整屏用时0.24s
system Init complate!
RUNNING time: 239

还有优化的空间,据说用ESP32的SPI能达到80M,那肯定很爽,但是不折腾了,重点还是LVGL部分。
把画点部分代码贴出来吧,这里没有上DMA哦

#define RGB_R(n)	(n>>8)&0xF8
#define RGB_G(n)	(n>>3)&0xFC
#define RGB_B(n)	n<<3

#define LCD_PUSH_GRAM(n)								\
do{														\
	*((__IO uint8_t*)&hspi2.Instance->DR) = RGB_R(n);	\
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));	\
	*((__IO uint8_t*)&hspi2.Instance->DR) = RGB_G(n);	\
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));	\
	*((__IO uint8_t*)&hspi2.Instance->DR) = RGB_B(n);	\
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));	\
}while(0U)


//在指定位置写入一个指定像素的点数据
static inline void _LCD_send_pixel(uint16_t x, uint16_t y, uint16_t color){
	//制定位置
	LCD_CS_L;
	LCD_DC_L;
	*((__IO uint8_t*)&hspi2.Instance->DR) = 0x2A;	//setx-cmd
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));

	LCD_DC_H;
	*((__IO uint8_t*)&hspi2.Instance->DR) = x>>8;	//x-start
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));
	*((__IO uint8_t*)&hspi2.Instance->DR) = x&0x00FF;
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));
	*((__IO uint8_t*)&hspi2.Instance->DR) = x>>8;	//x-end
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));
	*((__IO uint8_t*)&hspi2.Instance->DR) = x&0x00FF;
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));

	LCD_DC_L;
	*((__IO uint8_t*)&hspi2.Instance->DR) = 0x2B;	//sety-cmd
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));

	LCD_DC_H;
	*((__IO uint8_t*)&hspi2.Instance->DR) = y>>8;	//y-start
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));
	*((__IO uint8_t*)&hspi2.Instance->DR) = y&0x00FF;
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));
	*((__IO uint8_t*)&hspi2.Instance->DR) = y>>8;	//y-end
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));
	*((__IO uint8_t*)&hspi2.Instance->DR) = y&0x00FF;
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));

	LCD_DC_L;
	*((__IO uint8_t*)&hspi2.Instance->DR) = 0x2C;	//start write gram
	while(!__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE));

	LCD_DC_H;
	LCD_PUSH_GRAM(color);
	LCD_CS_H;
}
void LCD_send_pixel(uint16_t x, uint16_t y, uint16_t color){
	_LCD_send_pixel(x, y, color);
}

//清屏
void LCD_Clear(uint16_t Color){
	uint32_t i,m;  
	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);

	uint32_t tickstart = HAL_GetTick();

	LCD_CS_L;
	LCD_DC_H;
	for(i=0;i<lcddev.height;i++){
		for(m=0;m<lcddev.width;m++){	
			//Lcd_WriteData_16Bit(Color);
			LCD_PUSH_GRAM(Color);
		}
	}
	LCD_CS_H;
	printf("RUNNING time: %d\n\n",(HAL_GetTick() - tickstart));
}

下载 LVGL 库

这种事情最好是找 LVGL官网LVGL GitHub库,不过最好用的还是国内源 LVGL Gitee库
git checkout v7.8.0这里用的V7.8.0版本,V8.1.0版本把握不住哈哈哈

将LVGL移植到你的工程中

重点关注这几个文件或文件夹即可
在这里插入图片描述将 lvgl 库添加到 keil 中,记得添加路径哦

port 为接口文件,其中lv_port_disp/lv_port_indev/lv_port_fs 分别对应 LCD 屏绘制,触摸、鼠标、编码器等输入设备,还有文件系统,这里只使能lv_port_disp

在这里插入图片描述
将画点函数,放到对应的接口函数中
在这里插入图片描述可将LCD 初始化放到 lvgl 控件初始化函数中
在这里插入图片描述

在 main 函数中,初始化LVGL和 lvgl 的心跳程序

#define USE_LVGL	1

// main函数
int main(void){
	HAL_Init();
	SystemClock_Config();
	MX_GPIO_Init();
	MX_DMA_Init();
	MX_TIM6_Init();
	MX_TIM7_Init();
	MX_USART1_UART_Init();
	MX_IWDG_Init();
	MX_SPI1_Init();
	MX_SPI2_Init();
	MX_SPI3_Init();
#if USE_LVGL
	lv_init();
    lv_port_disp_init();        // 显示器初始化
//    lv_port_indev_init();       // 输入设备初始化(如果没有实现就注释掉)
//    lv_port_fs_init();          // 文件系统设备初始化(如果没有实现就注释掉)

	slim_index();		//小控件测试
//	slim_index2();		//仪表盘控件测试
#else
	LCD_Init();
#endif
	printf("system Init complate!\n");
	while (1) {
#if USE_LVGL
			lv_tick_inc(50);
			lv_task_handler();
#else
			for(uint16_t i=0;i<320;i++){
			LCD_send_pixel(i, i, RED);
			}
			for(uint16_t i=0;i<320;i++){
			LCD_send_pixel(i, 320-i, RED);
			}
			HAL_Delay(1000);
			HAL_IWDG_Refresh(&hiwdg);
#endif  
		}
}

测试函数

lv_obj_t *bar1;
lv_obj_t *btn2;
lv_obj_t *label_bar1;
lv_obj_t *slider1;
lv_obj_t *led1;
static void slim_index(void){
	lv_obj_t *scr = lv_scr_act(); //获取屏幕对象
	
	//彩色标签
#if 1
	lv_obj_t * label1 = lv_label_create(scr, NULL);
    lv_label_set_recolor(label1, true);
    lv_label_set_long_mode(label1, LV_LABEL_LONG_SROLL_CIRC); /*Circular scroll*/
    lv_obj_set_width(label1, 120);
    lv_label_set_text(label1, "#ff0000 Hello# #00ff00 world ! slim su.#");
    lv_obj_align(label1, NULL, LV_ALIGN_IN_TOP_LEFT, 20, 5);
	lv_label_set_anim_speed(label1, 80);
#endif
	
	//圆弧
#if 1
	static lv_style_t style_arc1_bg, style_arc1_indic;
	lv_style_init(&style_arc1_bg);
	lv_style_set_line_width(&style_arc1_bg, LV_STATE_DEFAULT, 10);
	lv_style_set_line_color(&style_arc1_bg, LV_STATE_DEFAULT, LV_COLOR_MAKE(0, 255, 0));
	lv_style_init(&style_arc1_indic);
	lv_style_set_line_width(&style_arc1_indic, LV_STATE_DEFAULT, 10);
	lv_style_set_line_color(&style_arc1_indic, LV_STATE_DEFAULT, LV_COLOR_MAKE(255, 0, 0));
	
	lv_obj_t *arc1 = lv_arc_create(scr, NULL);
	lv_obj_set_size(arc1, 100, 100);
	lv_obj_set_pos(arc1, 5, 50);
	lv_arc_set_bg_angles(arc1, 0, 360);
	lv_arc_set_angles(arc1, 0, 90);
	lv_obj_add_style(arc1, LV_ARC_PART_BG, &style_arc1_bg);
	lv_obj_add_style(arc1, LV_ARC_PART_INDIC, &style_arc1_indic);
	
	static lv_style_t style_arc2_bg, style_arc2_indic;
	lv_style_init(&style_arc2_bg);
	lv_style_set_bg_opa(&style_arc2_bg, LV_STATE_DEFAULT, 0);		//设置透明度
	lv_style_set_border_width(&style_arc2_bg, LV_STATE_DEFAULT, 0);	//边框线宽
	lv_style_set_line_width(&style_arc2_bg, LV_STATE_DEFAULT, 15);
	lv_style_set_line_color(&style_arc2_bg, LV_STATE_DEFAULT, LV_COLOR_SILVER);
	lv_style_init(&style_arc2_indic);
	lv_style_set_line_width(&style_arc2_indic, LV_STATE_DEFAULT, 15);
	lv_style_set_line_color(&style_arc2_indic, LV_STATE_DEFAULT, LV_COLOR_PURPLE);
	
	lv_obj_t *arc2 = lv_arc_create(scr, NULL);
	lv_obj_set_size(arc2, 100, 100);
	lv_obj_set_pos(arc2, 120, 50);
	lv_arc_set_bg_angles(arc2, 0, 360);
	lv_arc_set_angles(arc2, 90, 270);
	lv_obj_add_style(arc2, LV_ARC_PART_BG, &style_arc2_bg);
	lv_obj_add_style(arc2, LV_ARC_PART_INDIC, &style_arc2_indic);
	lv_obj_t *label2 = lv_label_create(arc2, NULL);	 // 在Arc控件上创建一个标签
	lv_obj_align(label2, arc2, LV_ALIGN_CENTER, 20, 0); // 对齐到Arc控件中心
	lv_label_set_text(label2, "2");				 // 设置标签文本
//	lv_obj_set_event_cb(arc2, arc_event_handler);
#endif

	//进度条
#if 1
	static lv_style_t style_bar_label1;
	lv_style_init(&style_bar_label1);
	lv_style_set_text_font(&style_bar_label1, LV_STATE_DEFAULT, &lv_font_montserrat_18);
	
	bar1 = lv_bar_create(scr, NULL);
	lv_obj_set_size(bar1, 100, 15);
	lv_bar_set_range(bar1, 0, 100);
	lv_obj_set_style_local_bg_color(bar1, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
    lv_obj_set_style_local_bg_color(bar1, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_GREEN);
	lv_bar_set_anim_time(bar1, 200);
	lv_bar_set_value(bar1, 80, LV_ANIM_ON);
	lv_obj_align(bar1, scr, LV_ALIGN_IN_TOP_MID, 40, 20);
	
	label_bar1 = lv_label_create(scr, NULL);
	lv_obj_add_style(label_bar1, LV_LABEL_PART_MAIN, &style_bar_label1);
	lv_obj_align(label_bar1, bar1, LV_ALIGN_OUT_RIGHT_MID, 10, 0); 
	lv_label_set_text(label_bar1, "80%");
#endif

	//复选框
#if 1
	static lv_style_t style_checkbox1;
	lv_style_init(&style_checkbox1);
	lv_style_set_text_font(&style_checkbox1, LV_STATE_DEFAULT, &lv_font_montserrat_18);
	lv_style_set_bg_opa(&style_checkbox1, LV_STATE_DEFAULT, LV_OPA_100);
	lv_style_set_bg_color(&style_checkbox1, LV_STATE_DEFAULT, LV_COLOR_YELLOW);

	lv_obj_t *checkbox1 = lv_checkbox_create(scr, NULL);
	lv_obj_set_width(checkbox1, 120);
	lv_obj_set_pos(checkbox1, 240, 150);
	lv_obj_add_style(checkbox1, LV_CHECKBOX_PART_BG, &style_checkbox1);
	lv_checkbox_set_text(checkbox1, "CheckBox");
#endif

	//滑块
#if 0
	slider1 = lv_slider_create(scr, NULL);
	lv_obj_set_size(slider1, 100, 10);
	lv_slider_set_range(slider1, 0, 100);
	lv_slider_set_anim_time(slider1, 200);
	lv_bar_set_value(slider1, 20, LV_ANIM_ON);
	lv_obj_align(slider1, scr, LV_ALIGN_IN_TOP_RIGHT, -20, 20); 
//	lv_obj_set_event_cb(slider1, arc_event_handler);
#endif

	//按钮
#if 1
	lv_obj_t *btn1 = lv_btn_create(scr, NULL);
	lv_obj_set_pos(btn1, 240, 80);
	lv_obj_set_size(btn1, 100, 40);
	lv_obj_t *label_btn1 = lv_label_create(scr, NULL);
	lv_obj_align(label_btn1, btn1, LV_ALIGN_CENTER, 0, 0); 
	lv_label_set_text(label_btn1, "key1");
//	lv_obj_set_event_cb(btn1, arc_event_handler);
	
	btn2 = lv_btn_create(scr, NULL);
	lv_obj_set_pos(btn2, 220, 220);
	lv_obj_set_size(btn2, 100, 40);
	lv_btn_set_checkable(btn2, true);
	lv_btn_set_state(btn2, true);
	lv_obj_t *label_btn2 = lv_label_create(scr, NULL);
	lv_obj_align(label_btn2, btn2, LV_ALIGN_CENTER, 0, 0); 
	lv_label_set_text(label_btn2, "key2");
//	lv_obj_set_event_cb(btn2, arc_event_handler);
#endif 

	//预加载
#if 1
	static lv_style_t style_spinner1_bg, style_spinner1_indic;
	lv_style_init(&style_spinner1_bg);
	lv_style_set_line_width(&style_spinner1_bg, LV_STATE_DEFAULT, 15);
	lv_style_set_line_color(&style_spinner1_bg, LV_STATE_DEFAULT, LV_COLOR_MAGENTA);
	lv_style_init(&style_spinner1_indic);
	lv_style_set_line_width(&style_spinner1_indic, LV_STATE_DEFAULT, 15);
	lv_style_set_line_color(&style_spinner1_indic, LV_STATE_DEFAULT, LV_COLOR_NAVY);
	
	lv_obj_t *spinner1 = lv_spinner_create(scr, NULL);
	lv_obj_set_size(spinner1, 80, 80);
	lv_obj_set_pos(spinner1, 10, 180);
	lv_obj_add_style(spinner1, LV_SPINNER_PART_BG, &style_spinner1_bg);
	lv_obj_add_style(spinner1, LV_SPINNER_PART_INDIC, &style_spinner1_indic);
	
	static lv_style_t style_spinner2_bg, style_spinner2_indic;
	lv_style_init(&style_spinner2_bg);
	lv_style_set_line_width(&style_spinner2_bg, LV_STATE_DEFAULT, 0);
	lv_style_init(&style_spinner2_indic);
	lv_style_set_line_width(&style_spinner2_indic, LV_STATE_DEFAULT, 8);
	lv_style_set_line_color(&style_spinner2_indic, LV_STATE_DEFAULT, LV_COLOR_MAROON);
	
	lv_obj_t *spinner2 = lv_spinner_create(scr, NULL);
	lv_obj_set_size(spinner2, 60, 60);
	lv_obj_set_pos(spinner2, 120, 180);
	lv_spinner_set_type(spinner2, LV_SPINNER_TYPE_FILLSPIN_ARC);
	lv_obj_add_style(spinner2, LV_SPINNER_PART_BG, &style_spinner2_bg);
	lv_obj_add_style(spinner2, LV_SPINNER_PART_INDIC, &style_spinner2_indic);
#endif	
	
	//线条
#if 1
	static lv_style_t style_line1;
	lv_style_init(&style_line1);
	lv_style_set_line_width(&style_line1, LV_STATE_DEFAULT, 10);
	lv_style_set_line_color(&style_line1, LV_STATE_DEFAULT, LV_COLOR_MAKE(255, 100, 100));
	lv_style_set_line_rounded(&style_line1, LV_STATE_DEFAULT, true); //圆角
		
	static lv_point_t line_points[] = {{360, 60},{450,300}};
	lv_obj_t *line1 = lv_line_create(scr, NULL);
	lv_obj_add_style(line1, LV_LINE_PART_MAIN, &style_line1);
	lv_line_set_points(line1, line_points, 2);
	lv_obj_set_pos(line1, 0, 0);	//点的坐标以此为原点
#endif
	
	//led
#if 1
	static lv_style_t style_led1;
	lv_style_init(&style_led1);
	lv_style_set_bg_color(&style_led1, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
	
	led1 = lv_led_create(scr, NULL);
	lv_obj_set_pos(led1, 330, 215);
	lv_obj_set_size(led1, 50, 50);
	lv_led_off(led1);
	lv_obj_add_style(led1, LV_LED_PART_MAIN, &style_led1);
#endif
}
static void slim_index2(void){
	lv_obj_t *scr = lv_scr_act(); //获取屏幕对象
	
	//仪表盘,这里就不再过多的设置样式了,反正样式设计函数调用都差不多
	lv_obj_t *gauge1 = lv_gauge_create(scr, NULL);
	lv_gauge_set_range(gauge1, 0, 80);
	lv_obj_set_size(gauge1, 220, 220);
	lv_gauge_set_scale(gauge1, 270, 21, 5);
	lv_obj_align(gauge1, scr, LV_ALIGN_CENTER, 0, 0); 
}

//没用调试触摸,所以一些控件用定时器做设置咯
extern lv_obj_t *arc;
extern lv_obj_t *bar1;
extern lv_obj_t *btn2;
extern lv_obj_t *label_bar1;
extern lv_obj_t *led1;
extern TIM_HandleTypeDef htim6;
extern TIM_HandleTypeDef htim7;
extern IWDG_HandleTypeDef hiwdg;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
	static uint8_t i = 0;
	char str[10] = {0};
    if (htim == (&htim6)){	//5s
		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
		i += 10;
		i = (i>100)?0:i;
		if((bar1 != NULL) && (btn2 != NULL)){
			lv_bar_set_value(bar1, i, LV_ANIM_ON);
			lv_btn_toggle(btn2);
			lv_led_toggle(led1);
			sprintf(str, "%d%%",i);
			lv_label_set_text(label_bar1, str);
		}
    }
	if (htim == (&htim7)){	//1s
        HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_3);
		HAL_IWDG_Refresh(&hiwdg);
    }
}

测试一下咯

PS:单个控件动画还是挺流畅的,多个控件同时动画的时候确实有些卡顿,但是没有展示的这么严重,应该是视频转GIF,丢帧有些严重。不过功能倒是实现了,嗨森!!!下一步移植触摸驱动,然后搞到ESP32上试试能不能跑个80M的spi
在这里插入图片描述

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[GUI]stm32搭载3.5寸SPI-TFT屏移植LittleVGL 的相关文章

  • STM32与Python上位机通过USB虚拟串口通信

    文章目录 前言 1 查看原理图 2 新建工程 3 添加代码与烧录 4 python代码编写 总结 问题解决思路 前言 在详细阅读广大网友的教程之后 我对STM32和Python通过USB通信的流程烂熟于心 尝试用ST公司的NUCLEO L4
  • 优化VMware提高虚拟机运行速度的技巧

    vmware虚拟机如何设置不当的话会造成运行速度慢 并影响主机运行 甚至会出现死机 一下是提高vmware虚拟机运行速度的几个技巧 希望我的博客对您有用 阿里云最高1888通用代金券 送给你 文章来自 http blog csdn net
  • FM33G0X之上电过程引脚配置

    八 FM33G0X之上电过程引脚配置 使用官方例程的代码初始化 在实际测试中会出现 配置成输出的引脚在上电过程中会将电平拉高 12v的输入电压 引脚可能会拉到3v 并持续一段时间 这对于实际应用中 是不应该出现的 比如一开始在io口配置中配
  • 基于DS18B20和HS1101的仓库自动报警系统

    基于DS18B20和HS1101的仓库自动报警系统 背景介绍 效果展示 完整版的项目代码 仿真文件 下面是项目原理图 具体管脚定义如下图 18B20温度原理 HS1101湿度传感器 红外测距报警模块我用到的是GP2D12 通过数模转化器AD
  • Qt creator4.8.0 以上使用SqLite数据库进行数据操作

    文章目录 前言 一 在 pro工程文件中添加sql模块 二 使用步骤 1 添加头文件 2 链接并打开数据库 3 创建用户信息表management info 4 插入数据操作 5 修改数据库操作 6 查询数据库 总结 前言 Qt creat
  • AD采样出来的数值与实际值之间的关系

    当刚接触AD采样时 一直对于AD采集出来的数值与实际的值之间的关系有些模糊 现在闲暇下来打算记录一下 这里以采集量为电压量来记录 当采集温度 电流等模拟量时 都是通过一个电路把模拟量转化为一个电压量输入进AD采样引脚 就不一一叙述 AD采样
  • stm32USB之模拟U盘

    STMF0 W25Q32模拟U盘 1 第一次写博客 如有错误 请及时指正 如有表达不通顺的地方 敬请谅解 2 本篇文章主要描述如何使用STM32cube配置USB 使用的主控为STM32F072 Flash为W25Q32 使用的主控RAM只
  • connect函数的用法

    作者 曾宏安 华清远见嵌入式学院讲师 在网络编程中 connect函数经常用来在套接字上初始化连接 无论是流式套接字还是数据报套接字都可以使用connect函数 但含义却不一样 下面我们分别来讨论一下 一 流式套接字 流式套接字通常使用的是
  • 按键的短按和长按检测

    方法一 常用的加延时函数 在中断服务函数中加一个比如10ms的延时函数 延时时间的长短取决于实际所用的按键特性 只要延时时间比抖动时间略大即可 原理很简单 加了延时就避开了抖动的这段时间 在延时之后判断引脚电平 如果为低电平就表示是按下 v
  • U-Boot启动过程完全分析

    1 1 U Boot工作过程 U Boot启动内核的过程可以分为两个阶段 两个阶段的功能如下 1 第一阶段的功能 硬件设备初始化 加载U Boot第二阶段代码到RAM空间 设置好栈 跳转到第二阶段代码入口 2 第二阶段的功能 初始化本阶段使
  • LVGL V8应用——实现互斥

    按键互斥 void language setup lv obj t cont lv obj create page lv obj set size cont 320 160 lv obj t ch cb lv checkbox create
  • 在vmware里面看不到已经设置的共享文件夹

    查看你是否设置了共享文件夹 vmware hgfsclient 在上图的虚拟机点击安装vmware tools 之后会在vmware tools文件里面有一个压缩的文件 把它复制到自己创的文件夹并解压 自己创建文件夹使用mkdir p mo
  • 为何在新建STM工程中全局声明两个宏

    在uVision中新建STM32工程后 需要从STM32标准库中拷贝标准外设驱动到自己的工程目录中 此时需要在工程设置 gt C C 选项卡下的Define文本框中键入这两个全局宏定义 STM32F40 41xxx USE STDPERIP
  • 属性,服务,事件

    属性 即设备支持的可读和 或可设置的参数功能 以一个灯为例 灯的开关就可以定义为一个属性 用户可以读取该属性的当前数值来得知灯的开关状态 也可以通过对该属性进行设置来打开或者关闭这个灯 服务 如果设备的某个功能只能设置 不能获取 那么可以将
  • 物联锁项目失败原因分析

    一 背景 2022年3月份接手IM024物联锁项目救火 此项目主要用于医院共享轮椅 共享病床 此项目是从2021年初开始立项开发 投入了大量的人力物力 但是在2022年3月份时产品工作仍然不稳定 此项目基本上可以判定为一个失败的典型 为了吸
  • FreeRTOS中断管理

    目录 说明 一 中断基础 1 1 中断理解 1 2 中断执行步骤 1 3 中断寄存器选择位 1 4 中断优先级分类 二 中断优先级分组设置 2 1 分类 2 2 特点 三 中断有关寄存器 3 1 SHPR1寄存器 3 2 SHPR2寄存器
  • PyQt 布局:创建具有专业外观的 GUI 应用程序

    目录 在 GUI 上布置图形元素 储备 PyQt 布局库 Using General Purpose Layout Managers 构建水平布局 QHBoxLayout 构建垂直布局 QVBoxLayout 在网格中排列小部件 QGrid
  • 计算机基础:一颗芯片是怎样诞生的?

    一颗芯片是怎样诞生的 芯片属于半导体 半导体是介于导体和绝缘体之间的一类物质 元素周期表中硅 锗 硒 硼的单质都属于半导体 这些单质通过掺杂其他元素生成的一些化合物 也属于半导体的范畴 这些化合物在常温下可激发载流子的能力大增 导电能力大大
  • Linux值得学习吗?打工人利用业务时间学习Linux需要多长时间?

    nbsp Linux值得学习吗 打工人利用业务时间学习Linux需要多长时间 在开始前我有一些资料 是我根据自己从业十年经验 熬夜搞了几个通宵 精心整理了一份 Linux的资料从专业入门到高级教程 工具包 点个关注 全部无偿共享给大家 在评
  • 锂电池管理系统(BMS)

    引言 在现代科技的推动下 锂电池已经成为各种电动设备和能源存储系统的首选能源媒介 然而 锂电池在充电和放电过程中存在一系列潜在的安全隐患 同时其性能和寿命也受到一些限制 为了解决这些问题 锂电池管理系统 BMS 应运而生 BMS不仅仅是一个

随机推荐

  • @excel注解_EasyPOI 详细教程以及注解的使用

    因为项目的原因需要用到POI来操作Excel 文档 以前都是直接使用POI来操作的 但是最近听到easypoi的存在 所以自己简单的尝试了下 别说 他还真的挺好用的 Easypoi介绍 Easypoi 为谁而开发 不太熟悉poi的 不想写太
  • LocalDate的用法与String互转

    一 LocalDate常用用法 1 1 申明定义 LocalDate formatDate LocalDate of 2020 2 5 自定义 LocalDate today LocalDate now 获取当前日期 1 2 getX 获取
  • WebRTC实时音视频技术的整体架构介绍

    WebRTC 简介 WebRTC 名称源自网页实时通信 Web Real Time Communication 的缩写 是一个支持网页浏览器进行实时语音通话或视频聊天的技术 是谷歌2010年以6820万美元收购Global IP Solut
  • Echarts 无数据时显示“暂无数据”

    当我们的图表遇到接口数据为空或者筛选之后无数据的情况 会显示成这样 就比较丑 所以需要更换成指定的某些文字做提示 通过配置title 曲线救国 title show true text 暂无数据 left center top center
  • JAVA小练习149——需求: 一家三口都要工作, 儿子工作负责绘画, 妈妈可以在儿子的工作上进行增强---上涂料, 爸爸的工作就是在妈妈的基础上增强---上画框

    interface Work public void work class Son implements Work Override public void work System out println 在画画 class Mother
  • python实践:让所有奇数都在偶数前面,而且奇数升序排列,偶数降序排序

    给定一个任意长度数组 实现一个函数 让所有奇数都在偶数前面 而且奇数升序排列 偶数降序排序 如字符串 1982376455 变成 1355798642 class Solution def SortNum self num list par
  • js查找数组重复元素

    方法一 利用sort方法 先使用sort方法将数组排序 再来判断找出重复元素 function res arr var temp arr sort sort function a b if a b temp indexOf a 1 temp
  • 数值分析复习笔记-第七章-非线性方程求根

    Chapter7 非线性方程求根 7 1 前言 本质 对一些n次代数多项式or超越方程 它们的根是难以通过解析方法求得 因此需采取数值方法 主要有 二分法 不动点迭代法 迭代加速 牛顿迭代法 牛顿法 割线法 7 2 二分法 数学基础 零点定
  • 多边形等分算法

    多边形等分
  • Python基础-- 9函数(中)

    一 函数的返回值 返回值就是函数执行以后返回的结果 通过return来指定函数的返回值 return后面可以跟任意对象 返回值甚至可以是 个函数 二 文档字符串 在定义函数时 可以在函数内部编写文档字符串 文档字符串就是对函数的 说明 he
  • Linux中TAB补全显示设备空间不足问题

    今天在使用linux中习惯性的使用tab键进行补全信息 发现无论在何处按下tab都会显示这样报错 图中因为我用了xshell工具 这里报错是中文的 这个时候要检查下自己的空间是否充足 可使用df查看设备目录使用空间大小 可以将一下不用的目录
  • 概率论的几种常考分布总结

    两点分布 0 1分布 X b 1 p 二项分布 X b n p k 0 1 2 n 指数分布 参数为 线性分布 参数为a b 泊松分布 X k 0 1 2 n
  • 程序员常犯的5个非技术性错误

    一个好的软件开发人员需要培养两种技能 技术技能和非技术技能 不幸的是一些开发者只注重技术的部分 以致养成一些陋习 下面是最常犯的5个非技术性错误 0 缺乏自律 Jim Rohn曾经说过 自律是目标和成果之间的桥梁 我一直认为 不论是成为一名
  • 半导体芯片测试介绍:CP、FT、STL

    CP测试 Chip Probing 对Wafer进行电性能测试 挑选出好的Die 可以减少封装和测试的成本 也可以透过Wafer的良率 检查fab厂制造的工艺水平 FT测试 Final Test 芯片封装完成之后 通过分选机和测试机的配合使
  • Android 兼容8.0 App全局字体调节、禁止App字体随系统字体大小而更改

    在APP中 字体的大小单位一般会用sp 然而在改变系统字体大小时 App字体就会随着系统字体大小改变而改变 这就可能造成APP布局的错位 造成这种情况的原因是 sp单位除了受屏幕密度影响外 还受到用户的字体大小影响 通常情况下 建议使用sp
  • 【周末闲谈】什么是云计算?

    个人主页 个人主页 系列专栏 周末闲谈 第一周 二进制VS三进制 第二周 文心一言 模仿还是超越 第二周 畅想AR 文章目录 前言 什么是云计算 大数据 云计算是分布式计算的一种 云计算为我们提供的三种服务 基础设置即服务 laaS 软件运
  • Unicode汉字编码表

    1 Unicode编码表 Unicode只有一个字符集 中 日 韩的三种文字占用了Unicode中0x3000到0x9FFF的部分 Unicode目前普遍采用的是UCS 2 它用两个字节来编码一个字符 比如汉字 经 的编码是0x7ECF 注
  • 几种任务调度的 Java 实现方法与比较

    I 几种任务调度的 Java 实现方法与比较 综观目前的 Web 应用 多数应用都具备任务调度的功能 本文由浅入深介绍了几种任务调度的 Java 实现方法 包括 Timer Scheduler Quartz 以及 JCron Tab 并对其
  • project facets java转成web项目

    前言 用Eclipse开发项目的时候 把一个Web项目导入到Eclipse里会变成了一个Java工程 将无法在Tomcat中进行部署运行 方法 1 找到 project文件 找到里面的
  • [GUI]stm32搭载3.5寸SPI-TFT屏移植LittleVGL

    唠几句 记录下移植笔记 新项目用到LVGL 也是首次接触GUI库 所以Emmmm 学呗 之前都是直接在LCD屏上画点 画线 画圆 画个矩形 画个多边形 显示个字符串 显示张图片而已 没有用过GUI库 在网上找了点学习资料 然后把LVGL库的