STM32-驱动OLED显示屏使用SPI(软件模拟时序)实现

本章概述思维导图:

SPI通信协议

SPI通信协议介绍

SPI通讯:高速的、串行通讯、全双工、同步、总线协议;(通过片选信号选中设备);

注:SPI通讯通过片选信号选中设备,串口通讯通过端口号选中设备;

SPI通讯一般至少配置4根线:SCK时钟线,MOSI主机输出从机输入、MISO主机输入从机输出、CS片选;


SPI中根据时钟极性和时钟相位的不同,可以分为4种模式;

CPOL时钟极性:可以确定时钟线空闲时的电平状态;

CPHA时钟相位:可以确定第一个时钟沿是发送数据还是采样数据的


寻址方式:当主设备要和多个从机进行通信时,主设备需要先向对应从设备的片选线上发送使能信号(高电平或者低电平,根据从机而定)表示选中该从设备;


SPI总线在进行数据传送时,先传送高位,后传送低位;数据线为高电平表示逻辑‘1’,低电平表示逻辑‘0’,一字节传送完成后无需应答即可开始下一字节的传送;SPI总线采用同步方式工作,时钟线在上升沿或下降沿时发送器向数据线上发送数据,在紧接着的下降沿或上升沿接收器从数据线上读取数据,完成一位数据传送,八个时钟周期即可完成一个字节数据的传送;


极性和相位:

PI总线有4种不同的工作模式,取决于时钟极性CPOL和时钟相位CPHL这两个因素;

时钟极性CPOL表示时钟线SCLK空闲时的状态;

        CPOL=0时,空闲时时钟线SCLK为低电平;

        CPOL=1时,空闲时时钟线SCLK为高电平;

时钟相位CPHL表示采样时刻;

        CPHL=0时,每个周期的第一个时钟沿采样数据;

        CPHL=1时,每个周期的第二个时钟沿采样数据;

极性和相位设置

对于一个特定的从设备来说,一般在出厂时就会将其设计为某种特定的工作模式,我们在使用该设备就必须保证主设备的工作模式和该从设备保持一致否则是无法进行通信的,所以一般我们需要对主设备的CPOL极性和CPHA进行配置;


SPI四种工作模式:

注意,在此SPI传输数据采用的时软件模拟时序,跟此前串口采用的是硬件时序控制(寄存器控制)是不一样的;

软件模拟时序:软件模拟时序是通过编程代码(如循环、延时函数、定时器中断等)来控制信号的时序关系。开发者需要手动编写代码来生成特定的时序波形(如SPI、I2C、PWM等),通常依赖CPU的指令执行时间或定时器来控制信号的切换。

硬件时序控制:硬件时序控制是通过直接操作单片机的硬件寄存器(如定时器、PWM模块、SPI/I2C控制器等)来生成时序信号。单片机通常内置了专用的硬件模块,开发者通过配置这些模块的寄存器来实现特定的时序功能。

在以后编程开发中如何选择:

选择软件模拟时序:

1. 需要快速实现简单功能。

2.硬件平台没有专用硬件模块。

3.对时序精度要求不高。

选择硬件时序控制(寄存器操作):

1.需要高速、精确的时序控制。

2.需要节省CPU资源。

3.硬件平台提供专用硬件模块。


SPI模式1(软件模拟时序)

模式1:时钟极性CPOL=0;时钟相位CPHA=0;时钟线SCLK空闲时为低电平,数据线在第一个时钟沿(上升沿)采样数据;

代码示例:

/*SPI模式1软件模拟时序形参:dat-->发送的数据
*/
u8 SPI_WRbyte(u8 dat)
{SCLK=0;//时钟线拉低u8 data_rx=0;//读取数据for(u8 i=0;i<8;i++){SCLK=0;//开始发送数据if(dar & 0x80) MOSI=1;//主机输出从机输入else MOSI=0;//主机输入从机输出SCLK=1;//一位数据发送完成dat<<=1;data_rx<<=1;//接收数据一定要先左移1位,因为先赋值为1的话,循环8次;最前面的1就会丢失if(MISO) data_rx|=0x01;}SCLK=0;//时钟线空闲电平为低电平return data_rx;
}

SPI模式2(软件模拟时序)

模式2:时钟极性CPOL=0;时钟相位CPHA=1;时钟线SCLK空闲时为低电平,数据线在第二个时钟沿(下降沿)采样数据;

代码示例:

/*SPI模式2软件模拟时序形参:dat-->发送的数据
*/
u8 SPI2_WRbyte(u8 dat)
{SCLK=0;//时钟线空闲电平为低电平u8 data_rx=0;//读取数据for(u8 i=0;i<8;i++){SCLK=1;//开始发送数据if(dat & 0x80) MOSI=1;//主机输出,从机输入else MOSI=0;//主机输出,从机输入SCLK=0;//一位数据发送完成dat<<=1;data_rx<<=1;if(MISO) data_rx|=0x01; }SCLK=0;//时钟线空闲电平为低电平return data_rx;
}

SPI模式3(软件模拟时序)

模式3:时钟极性CPOL=1;时钟相位CPHA=0;时钟线SCLK空闲时为高电平,数据线在第一个时钟沿(下降沿)采样数据;

代码示例:

/*SPI模式3软件模拟时序形参:dat-->发送的数据
*/
u8 SPI3_WRbyte(u8 dat)
{SCLK=1;//时钟线空闲电平为高电平u8 data_rx=0;//读取数据for(u8 i=0;i<8;i++){SCLK=1;//开始发送数据if(dat & 0x80) MOSI=1;//主机输出,从机输入else MOSI=0;//主机输出从机输入SCLK=0;//一位数据发送完成dat<<=1;data_rx<<=1;if(MISO) data_rx|=0x01;}SCLK=1;//时钟线空闲电平为高电平return data_rx;
}

SPI模式4(软件模拟时序)

模式4:时钟极性CPOL=1;时钟相位CPHA=1;时钟线SCLK空闲时为高电平,数据线在第二个时钟沿(上升沿)采样数据

代码示例:

/*SPI模式3软件模拟时序形参:dat-->发送的数据
*/
u8 SPI4_WRbyte(u8 dat)
{SCLK=1;//时钟线空闲电平为高电平u8 data_rx=0;//读取数据for(u8 i=0;i<8;i++){SCLK=0;//开始发送数据if(dat & 0x80) MOSI=1;//主机输出,从机输入else MISO=0;//主机输出从机输入SCLK=1;//一位数据发送完成dat<<=1;data_rx<<=1;if(MISO) data_rx|=0x01;}SCLk=1;//时钟线空闲电平为高电平return data_rx;
}

OLED显示屏

OLED显示屏介绍

屏幕类型:OLED(自发光显示屏)

屏幕接口:串行接口(只有一根数据线)、并行通讯(多条数据线);

接口协议:IIC或SPI(4线/3线模式);

屏幕尺寸:0.96寸,分辨率:128(列)*64(行);单色屏幕;

屏幕颜色:单色屏幕、16位(bit)屏幕(RGB565)、26位屏幕;

当前开发板:OLED屏幕,串行通讯方式,通讯接口:SPI

电路原理图:

根据原理图,查看对应引脚

OLED1脚(GND)——接地(低电平)

OLED2脚(VCC)——接3.3V高电压(高电平)

OLED3脚(D0)——PB14时钟线(SCK)

OLED4脚(D1)——PB13数据线(MOSI主机输出从机输入)

OLED5脚(RES)——PB12复位线(低电平复位)

OLED6脚(DC)——PB1数据命令选择脚(低电平0:发送命令;高电平1:发送数据)

OLED7脚(CS)——PA7片选信号线(低电平选中)

OLED显示屏引脚配置

配置步骤:

1.开时钟

2.配置GPIO引脚模式

3.上拉下拉

4.将每个引脚进行宏定义,方便操作;

代码示例:

//宏定义
#define OLED_CS(x) if(x==1){GPIOA->ODR|=1<<7;}\else if(x==0){GPIOA->BRR|=1<<7;}
#define OLED_DC(x)  if(x==1){GPIOB->ODR|=1<<1;}\else if(x==0){GPIOB->BRR|=1<<1;}
#define OLED_RES(x)  if(x==1){GPIOB->ODR|=1<<12;}\else if(x==0){GPIOB->BRR|=1<<12;}
#define OLED_MOSI(x)  if(x==1){GPIOB->ODR|=1<<13;}\else if(x==0){GPIOB->BRR|=1<<13;}   
#define OLED_SCLK(x)  if(x==1){GPIOB->ODR|=1<<14;}\else if(x==0){GPIOB->BRR|=1<<14;}   #include"OLED.h"
/*OLED显示屏引脚配置函数1脚(GND)——接地(低电平)2脚(VCC)——接3.3V高电压(高电平)3脚(D0)——PB14时钟线(SCK)4脚(D1)——PB13数据线(MOSI主机输出从机输入)5脚(RES)——PB12复位线(低电平复位)6脚(DC)——PB1数据命令选择脚(低电平0:发送命令;高电平1:发送数据)7脚(CS)——PA7片选信号线(低电平选中)
*/
void OLED_GPIO_Init(void)
{//开时钟RCC->APB2ENR|=1<<2;//开启PA时钟RCC->APB2ENR|=1<<3;//开启PB时钟//配置GPIO引脚模式GPIOB->CRL&=0xffffff0f;GPIOB->CRL|=0x00000030;//PB1GPIOB->CRH&=0xf000ffff;GPIOB->CRH|=0x03330000;//PB12,13,14;GPIOA->CRL&=0x0fffffff;GPIOA->CRL|=0x30000000;//PA7//上拉下拉GPIOA->ODR|=1<<7;//取消选中设备
}

OLED屏幕实现发送1字节数据函数(软件模拟时序)

分析OLED显示屏时序接口:

CS片选信号是低电平选中设备

SCLK时钟线空闲时既可以为高电平也可以为低电平,上升沿为读取数据,下降沿为发送数据。推断出时钟极性既可以为1也可以为0。

当时钟极性为0时,第一个时钟沿(上升沿)为采样读取数据,相位为0;为SPI工作模式1;

当时钟极性为1时,第二个时钟沿(上升沿)为采样读取数据,相位为1;为SPI工作模式4;

实现发送一字节数据函数(软件模拟时序)代码示例:

/*OLED屏幕SPI模式1发送一字节函数形参:	dat-->发送的数据flag-->DC数据命令选择标志位
当时钟极性为0时,第一个时钟沿(上升沿)为采样读取数据,相位为0;为SPI工作模式1;
*/
void OLED_Wbyte(u8 dat,u8 flag) 
{OLED_CS(0);//片选线低电平选中设备OLED_SCLK(0);//时钟线空闲电平为低电平OLED_DC(flag);//数据命令选择线选择发送命令还是数据for(u8 i=0;i<8;i++){OLED_SCLK(0);//开始发送时间if(dat & 0x80){OLED_MOSI(1);}else OLED_MOSI(0);OLED_SCLK(1);//数据发送完成dat<<=1;}OLED_SCLK(0);//时钟线空闲电平为低电平OLED_CS(1);//取消选中设备
}

清屏函数

清屏本质:将屏幕缓冲区(显存)全部填充为0(黑色)或0xFF(白色);

根据SSD1306驱动芯片OLED屏中文参考手册(第7页)

通过命令B0h到B7h,设置目标显示位置的页起始地址。

通过命令00h到0Fh设置指针的下起始列地址。

通过命令10h到1Fh设置指针的上起始列地址。

寻址方式:页面寻址,把68行分成了8页,列不变,依旧时128列。

在页面寻址下,在显示RAW读/写之后,列地址指针会自动增加1,行地址不会;

代码示例:

/*OLED屏幕清屏函数形参:dat->清屏的数据
*/
#define OLED_cmd 0//写入命令
#define OLED_dat 1//写入数据
void OLED_clear(u8 dat)
{for(u8 i=0;i<8;i++){OLED_Wbyte(0xb0+i,OLED_cmd);//页起始地址OLED_Wbyte(0x00,OLED_cmd);//下列低起始地址OLED_Wbyte(0x10,OLED_cmd);//上列高起始地址for(u8 j=0;j<128;j++){OLED_Wbyte(dat,OLED_dat);}}
}

OLED屏幕初始化函数

OLED屏幕代码序列厂家都会提供好的,我们只用复制粘贴在修改即可(这里将清屏函数写入0xff是起全部点亮效果用来测试OLED屏幕初始化是否有用。正常写入0,即可);

代码示例:

/*OLED显示屏初始化函数
*/
void OLED_Init(void)
{OLED_GPIO_Init();//OLED引脚配置函数OLED_RES(1);//复位Delay_MS(100);OLED_RES(0);Delay_MS(100);OLED_RES(1);//复位OLED_Wbyte(0xAE,OLED_cmd); /*display off*/ OLED_Wbyte(0x00,OLED_cmd); /*set lower column address*/OLED_Wbyte(0x10,OLED_cmd); /*set higher column address*/OLED_Wbyte(0x40,OLED_cmd); /*set display start line*/ OLED_Wbyte(0xB0,OLED_cmd); /*set page address*/ OLED_Wbyte(0x81,OLED_cmd); /*contract control*/ OLED_Wbyte(0xCF,OLED_cmd); /*128*/ OLED_Wbyte(0xA1,OLED_cmd); /*set segment remap*/ OLED_Wbyte(0xA6,OLED_cmd); /*normal / reverse*/ OLED_Wbyte(0xA8,OLED_cmd); /*multiplex ratio*/ OLED_Wbyte(0x3F,OLED_cmd); /*duty = 1/64*/ OLED_Wbyte(0xC8,OLED_cmd); /*Com scan direction*/ OLED_Wbyte(0xD3,OLED_cmd); /*set display offset*/ OLED_Wbyte(0x00,OLED_cmd);OLED_Wbyte(0xD5,OLED_cmd); /*set osc division*/ OLED_Wbyte(0x80,OLED_cmd);OLED_Wbyte(0xD9,OLED_cmd); /*set pre-charge period*/ OLED_Wbyte(0Xf1,OLED_cmd);OLED_Wbyte(0xDA,OLED_cmd); /*set COM pins*/ OLED_Wbyte(0x12,OLED_cmd);OLED_Wbyte(0xdb,OLED_cmd); /*set vcomh*/ OLED_Wbyte(0x30,OLED_cmd);OLED_Wbyte(0x8d,OLED_cmd); /*set charge pump enable*/ OLED_Wbyte(0x14,OLED_cmd);OLED_Wbyte(0xAF,OLED_cmd); /*display ON*/OLED_clear(0xff);//清屏函数写0xff全部点亮
}

主函数代码示例:

#include "stdio.h"
#include "OLED.h"
int main()
{OLED_Init();//显示屏初始化函数printf("各模块初始化完成\n");while(1){}
}

代码运行效果:


设置光标函数

x--列        0列-127列

y--行        0行-7行(页面寻址),每8行为一个页面

代码示例:

/*
设置光标
形参:x --列0~127y --行0~7(页面寻址),每8行为一个页面
*/
void OLED_setpos(u8 x,u8 y)
{OLED_Wbyte(0xb0+(y&0x7),OLED_cmd);//页地址选择OLED_Wbyte(0x00|(x&0x0f),OLED_cmd);//设置列低4位OLED_Wbyte(0x10|((x>>4)&0xf),OLED_cmd);//设置列高4位
}

汉字显示函数

/*显示汉字*/
//形参:size--汉字的大小,y--光标设置的行,X--关闭设置的列
void OLED_DisplayFont(u8 x,u8 y,u8 size,const u8 *font)
{u8 i=0,j=0;for(i=0;i<size/8;i++)//汉字需要占用的页面数量{OLED_setpos(x,y+i);for(j=0;j<size;j++)//要显示的列数{OLED_Wbyte(font[i*size+j],OLED_dat);}    }
}

显示函数首先要在取模软件取模(取模软件设置):

取模代码:

const u8 font1[][16*16/8]=
{{0x00,0xFC,0x04,0x04,0xFC,0x20,0x10,0x4C,0x4B,0x48,0x48,0x48,0xC8,0x08,0x08,0x00,0x00,0x0F,0x04,0x04,0x0F,0x00,0x30,0x48,0x44,0x42,0x42,0x41,0x40,0x40,0x70,0x00},/*"吃",0*/{0x02,0x02,0xE2,0x22,0x22,0xFE,0x22,0x22,0x22,0xFE,0x22,0x22,0xE2,0x02,0x02,0x00,0x00,0x00,0xFF,0x48,0x44,0x43,0x40,0x40,0x40,0x43,0x44,0x44,0xFF,0x00,0x00,0x00},/*"西",1*/{0x00,0x00,0x00,0xFC,0x04,0x04,0xFC,0x04,0x02,0x02,0xFE,0x03,0x02,0x00,0x00,0x00,0x80,0x60,0x18,0x07,0x00,0x00,0x7F,0x20,0x14,0x08,0x31,0x0E,0x30,0x40,0x80,0x00},/*"瓜",2*/{0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",3*/
};

主函数代码示例:


#include "OLED.h"int main()
{OLED_Init();//显示屏初始化函数while(1){OLED_DisplayFont(16+16,3,16,font1[0]);OLED_DisplayFont(16+16*2,3,16,font1[1]);OLED_DisplayFont(16+16*3,3,16,font1[2]);OLED_DisplayFont(16+16*4,3,16,font1[3]);}
}

代码运行结果:


制作不易!喜欢的小伙伴给个小赞赞!喜欢我的小伙伴点个关注!有不懂的地方和需要的资源随时问我哟!

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

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

相关文章

Easy系列PLC相对运动指令实现定长输送(ST源代码)

汇川Easy系列PLC总线伺服转矩控制功能块 Easy系列PLC总线伺服转矩控制功能块(详细PDO配置+完整ST源代码)_pdo中添加目标力矩然后映射到轴中-CSDN博客文章浏览阅读215次。Easy系列PLC如何实现轮廓速度模式PV速度模式Easy系列PLC如何实现轮廓速度模式PV速度控制_汇川easy plc轮廓…

SpringCloud学习第一季-4

目录 16.SpringCloud Alibaba Nacos服务注册和配置中心 SpringCloud Alibaba简介 1. 为什么出现 SpringCloud Alibaba 2. SpringCloud Alibaba带来了什么 2.1 能干什么 2.2 去哪里下载 2.3 怎么玩 3. 学习资料的获取 17.SpringCloud Alibaba Nacos服务注册和配置中心 …

嵌入式开发学习———Linux环境下数据结构学习(五)

折半查找&#xff08;二分查找&#xff09;适用于已排序的数组&#xff0c;通过不断缩小查找范围定位目标值。int binarySearch(int arr[], int size, int target) {int left 0, right size - 1;while (left < right) {int mid left (right - left) / 2;if (arr[mid] t…

(一)React +Ts(vite创建项目/useState/Props/Interface)

文章目录 项目地址 一、React基础 1.1 vite创建 1. 创建项目 2. 安装项目所需环境 1.2 jsx 1. 三元表达式 1.3 基础 1. 创建第一个组件 2. 安装boostrap 3. 插件常用命令 4. map 二、组件 2.1 useState 1. useState 2. 使用 3.更新对象 4. 更新数组(增,删,改) 5. 使用immer…

网关和BFF是如何演化的

BFF&#xff08;Backend For Frontend&#xff09;:对返回的数据结构进行聚合、裁剪、透传等适配逻辑。 适用于API网关之后的数据聚合、裁剪与透传简化客户端逻辑&#xff0c;减少网络开销敏感数据过滤 BFF逻辑层 架构没有最好&#xff0c;要看是否满足当前的业务场景。 业务的…

SQL中的WITH语句(公共表表达式CTE)解释

SQL中的WITH语句&#xff08;公共表表达式CTE&#xff09; WITH语句&#xff0c;也称为公共表表达式&#xff08;Common Table Expression&#xff0c;CTE&#xff09;&#xff0c;是SQL中一种强大的功能&#xff0c;它允许你创建临时结果集&#xff0c;这些结果集可以在后续的…

服务器地域选择指南:深度分析北京/上海/广州节点对网站速度的影响

更多云服务器知识&#xff0c;尽在hostol.com你准备开一个覆盖全国的线上零食店&#xff0c;现在万事俱备&#xff0c;只差一个核心问题没解决&#xff1a;你唯一的那个总仓库&#xff0c;应该建在哪里&#xff1f;是建在哈尔滨&#xff0c;让南方的朋友下单后&#xff0c;一包…

桶排序-Java实现

桶排序是一种分配式排序算法&#xff0c;将元素分到有限数量的桶里&#xff0c;每个桶再单独排序&#xff08;比如用插入排序&#xff09;&#xff0c;最后依次把各个桶中的元素取出来即完成排序。 时间复杂度&#xff1a;最佳 O(n) | 平均 O(n n/k k) | 最差 O(n) 空间复杂…

oracle知识

这里写自定义目录标题Oracle常用的数据类型&#xff1a;Oracle实操&#xff1a;创建数据表Oracle约束建表的时候设置约束&#xff1a;表创建后添加添加约束&#xff1a;Oracle常用的数据类型&#xff1a; Oracle实操&#xff1a;创建数据表 Oracle约束 建表的时候设置约束&…

超级人工智能+无人机操控系统,振兴乡村经济的加速器,(申请专利应用),严禁抄袭!

无人机边缘智能系统&#xff1a;山林珍稀资源探测的完整架构与实战指南本人设计的多模态边缘AI系统已在秦岭山区完成实地验证&#xff0c;对7种高价值食用菌识别准确率达94.3%&#xff0c;定位误差小于0.8米一、前沿技术融合的商业化机遇根据Gartner 2025年技术成熟度曲线分析&…

用腾讯地图写一个逆地址解析(很详细)

首先说明以下代码适合有前端基础知识的同学。以下是css和html部分<!DOCTYPE html><html lang"zh-CN"><!-- lang是用来申明语言类型&#xff0c;这里申明为中文&#xff08;zh&#xff09;中国大陆&#xff08;CN&#xff09;补充中文繁体为zh-TW --&g…

在 Vue3+Vite+TypeScript 项目中使用 svg 文件并支持自定义样式

参考文档&#xff1a;vite-svg-loader 安装与配置 安装插件 pnpm add vite-svg-loader -D配置 // vite.config.ts import svgLoader from vite-svg-loaderexport default defineConfig({plugins: [vue(),svgLoader({defaultImport: component})] })使用 <script setup …

ShimetaPi M4-R1:国产高性能嵌入式平台的异构计算架构与OpenHarmony生态实践

在全球化芯片供应链波动及树莓派等硬件持续涨价的背景下&#xff0c;ShimetaPi M4-R1 作为全栈国产化嵌入式开发平台&#xff0c;以 高性能异构计算架构 和 开源鸿蒙原生支持 为核心突破点&#xff0c;填补了中高端边缘设备开发的国产方案空白。其基于瑞芯微 RK3568B2 的硬件设…

zookeeper分布式锁 -- 读锁和写锁实现方式

读锁和写锁读锁: 是共享锁,读锁与读锁是可以兼容的,所以同时有多个请求都可以持有写锁: 是独占锁,写锁与任何锁都互斥,所以只有一个请求持有,这个请求释放写锁其他请求才能持有一旦持有写锁,说明数据在发送变化就不能读了,自然一个请求就不能出现读锁和写锁共存的情况总结: 读锁…

第二篇:Linux 文件系统操作:从基础到进阶

目录 一、文件与目录管理基础 创建文件 创建目录 目录结构查看 二、链接文件深入理解 创建软链接 创建硬链接 核心区别对比 三、文件压缩与解压缩全攻略 1、压缩命令对比 2、解压缩命令 3、三种压缩方式性能对比 4、通用解压技巧 四、文件查找与搜索 1、按文件名…

哔哩哔哩招游戏内容产品运营

游戏内容产品运营【2026届】&#xff08;岗位信息已获jobleap.cn授权转发到csdn&#xff09;哔哩哔哩集团 上海收录时间&#xff1a; 2025年08月01日职位描述1、负责研究B站游戏创作者的创作过程、动机及遇到的问题&#xff0c;产出研究报告&#xff1b; 2、结合用研分析和相关…

谈谈Flutter中的Key

目录 前言 一、什么是Key 1.StatelessWidget 2.StatefulWidget 3.加入Key后的效果 二、什么时候应该使用 Key&#xff1f; 1.Flutter判断widget的逻辑 1.Flutter判断组件身份的规则 1.Widget的类型&#xff08;runtimeType&#xff09;相同 2. Key相同&#xff08;ke…

重生之我在暑假学习微服务第八天《OpenFeign篇》

个人主页&#xff1a;VON文章所属专栏&#xff1a;微服务 微服务系列文章 重生之我在暑假学习微服务第一天《MybatisPlus-上篇》重生之我在暑假学习微服务第二天《MybatisPlus-下篇》重生之我在暑假学习微服务第三天《Docker-上篇》重生之我在暑假学习微服务第四天《Docker-下篇…

风光储综合能源系统双层优化规划设计【MATLAB模型实现】

本模型基于双层优化框架&#xff0c;利用KKT条件、大M法、对偶理论求解&#xff0c;专注于综合能源系统&#xff08;微电网&#xff09;多电源容量优化配置的模型介绍。代码采用CPLEX求解器&#xff0c;注释详尽&#xff0c;非常适合新手学习该类问题的建模与求解思路。 模型总…

雪花算法重复id问题

原理解析 雪花算法实现简单、适配性强&#xff0c;无论是电商订单、日志追踪还是分布式存储&#xff0c;都能满足 “唯一、有序、高效、可扩展” 的核心需求&#xff0c;因此成为分布式ID主流选择。雪花算法生成的ID是一个64位的整数&#xff0c;由多段不同意义的数字拼接而成&…