嵌入式计算器模块实现

嵌入式计算器模块规划

计算器混合算法解析
上面我们的算法理论已经完善, 我们只用给一个混合运算式, 计算器就可以帮助我们计算出结果.

但是存在一个痛点, 每次计算算式,都要重新编译程序, 所以我们想到了, 利用单片机, 读取用户输入的按键, 组成算式, 输入给机器, 这样我们就可以利用上面的算法, 再次计算出结果了.

大致流程如下:

image-20240624100125749

所以, 我们第一步做的,就是stm32利用矩阵按键识别键值

第二步,就是单片机把读取到的键值, 组合成算式

第三步,就是把算式传给算法,计算出结果

第四步, 就是把结果清零

拓展:第五步,可以把结果转换成语音播报

第一步: 矩阵按键,读取键值

(1)读取原理

首先我们要了解矩阵按键, 是干什么的, 顾名思义,矩阵按键,就是几行几列,依次排开的,按钮, 我们如果知道行,知道列,就可以锁定那个按键,所以我们只需要让单片机知道,我们按下的是哪一行,哪一列,那么单片机通过提前布局好的按键键值,就可以知道我们按下的是哪个按键了.

image-20240624101158298

(2)按键布局

如下图, 即为我们矩阵按键的键盘布局:

第一行 ( ) / *

第二行 1 2 3 +

第三行 4 5 6 -

第四行 7 8 9 Esc

第五行 ← 0 → =

image-20240624102450597

(3)按键原理图

矩阵按键原理图:

image-20240624103255572

(4)单片机io口识别原理

我们锁定行列, 此矩阵按键有五行,四列, 我们就先识别按下哪一列吧,然后后面再锁定行,这样就可以得到坐标了.

单说, 按下按键, 怎么io口怎么识别出按下按键呢?

举一个例子, 单片机io口,相当于装满水的水杯, 单片机会检测io口水杯, 是满的,还是空的. 用户按下按键,就相当于, 把水倒掉,那么我们就可以让单片机检测到按键.

image-20240624122114389

所以, 单片机检测io口,端口被称作输入口,顾名思义就是读取io口状态, 并把io口状态,反馈给单片机,那么水倒哪里了呢? 我们按下按键, 水就倒到了地下. 所以我们按键另一端按键接地是持续输出低电平的输出口.

<1>识别列

我们把上述的步骤, 复制四份, 我们就可以判断按下是哪一列了

image-20240624122801579

此时,四个列检测io口, 链接四个按键,按键另一端连接的是地, 这个地可以用io口输出低电平代替,方便后续矩阵键盘拓展.

image-20240624131512384

但是我们有四列, 五行, 所以, 每列都有,五个按钮, 我们紧接着, 再把他们排列起来.

image-20240624131141800

<2>识别行

此时, 我们通过判断 PA1,PA2,PA3,PA4那个io口变化了,就可以识别到是哪列按键按下了,

但是我们是矩阵按键,还要进行行的识别.

其实,识别方法同理,我们只需要把, io口类型进行反转,把列控制端口全反转成输出低电平, 现在检测io口状态的变成每行的端口,当按下第一行按钮时候,对应的端口就会变成低电平, 单片机检测到,就可以识别到行 如下图所示

image-20240624132339632

进行拓展后,就变成了矩阵按键,

image-20240624132534304

<3> 识别原理总结

我们识别原理就是,先赋予列检测io口,高电平,设置其端口类型为输入口,读取按键状态,按键另一端,是输出口,持续输出低电平.

当我们按下按键的时候, 输入口io口的高电平会通过按键,送到低电平,此时单片机检测到低电平, 就判定是哪一列的按键按下了.

此时列已经锁定了, 下面开始锁定行,此时按下仍然处于按下状态.

我们此时设置控制行的io口,为输入口,检测按键状态, 控制列的io口,设置为输出低电平,那么此时按键是按下状态, 对应的行io口,电平就会从高电平->低电平, 那么单片机就会检测到io口状态变化, 我们就可以锁定对应的行.

行和列已经锁定,那么我们通过计算就可以得到我们按下的是矩阵按键的哪一个按键了.

<4>代码实现

我们使用线性反转法的核心思想,就是锁定行和列的坐标, 通过反转io口类型,检测io口状态,根据按键按下的状态,进而锁定坐标.

为了更快的进入列的选择,我们把四列io口,全部设置成中断形式,对应的行io口,全部设置为推挽输出低电平, 四列io口的中断触发方式,设置成下降沿触发.

①锁定列

这样我们就可以很快的进行, 锁定列了;

配置 PA1 ,PA2, PA3, PA4 为下降沿触发中断

1.中断初始化
void Exti_key_config(void)
{//定义官方文档结构体EXTI_InitTypeDef   EXTI_InitStructure;GPIO_InitTypeDef   GPIO_InitStructure;NVIC_InitTypeDef   NVIC_InitStructure;//初始化//使能时钟 PA  AFIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);	//io口初始化, 设置//使能内部上拉GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	GPIO_Init(GPIOA, &GPIO_InitStructure);/* Connect EXTI1 line to PA1 pin */GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);/* Connect EXTI2 line to PA2 pin */GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2);/* Connect EXTI3 line to PA3 pin */GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);/* Connect EXTI4 line to PA4 pin */GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4);//中断端口的设置(外部中断线 1,2,3和4,  端口模式, 什么触发: 下降沿 , 开启等)/* Configure EXTI0 line */EXTI_InitStructure.EXTI_Line = EXTI_Line1 | EXTI_Line2 | EXTI_Line3 | EXTI_Line4;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);//下面配置中断优先级/* Configure EXTI1 interrupt */NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);/* Configure EXTI2 interrupt */NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;NVIC_Init(&NVIC_InitStructure);/* Configure EXTI3 interrupt */NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;NVIC_Init(&NVIC_InitStructure);/* Configure EXTI4 interrupt */NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;NVIC_Init(&NVIC_InitStructure);
}	
2.触发中断

char key_number; // 1–4 (代表一到四列)

_Bool key_button_down; //代表按键按下

void EXTI1_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line1) != RESET){delay(0x20000);	//中断服务函数当中 , 是不能用大延时的,快进		快出/* Your code goes here */key_number = 1;key_button_down = 1;//中断服务函数当中 , 是不能用大延时的,快进		快出delay(0x20000);	EXTI_ClearITPendingBit(EXTI_Line1);}
}void EXTI2_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line2) != RESET){//中断服务函数当中 是不能用大延时的,快进		快出delay(0x20000);	/* Your code goes here */key_number = 2;key_button_down = 1;//中断服务函数当中 , 是不能用大延时的,快进快出delay(0x20000);	EXTI_ClearITPendingBit(EXTI_Line2);}
}void EXTI3_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line3) != RESET){//中断服务函数当中 , 是不能用大延时的,快进快出delay(0x20000);	/* Your code goes here */key_number = 3;key_button_down = 1;//中断服务函数当中 , 是不能用大延时的,快进快出delay(0x20000);	EXTI_ClearITPendingBit(EXTI_Line3);}
}void EXTI4_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line4) != RESET){//中断服务函数当中 , 是不能用大延时的,快进快出delay(0x20000);	/* Your code goes here */key_number = 4;key_button_down = 1;//中断服务函数当中 , 是不能用大延时的,快进快出delay(0x20000);	EXTI_ClearITPendingBit(EXTI_Line4);}
}
3.锁定列数值
extern char key_number;
extern char chose_column;//选中的列
void find_column(void)
{if(key_number == 1){chose_column = 1;}elseif(key_number == 2){chose_column = 2;}		elseif(key_number == 3){chose_column = 3;}elseif(key_number == 4){chose_column = 4;}	else{}		
}
②锁定行

此时列已经锁定, 我们把列io口,全变成输出低电平, 控制行的io口,变成输入口,高电平, 此时单片机检测io的变化,就可以检测到哪行按下了.

1.端口类型转换
/* 切换为推挽输出模式 GPIO_Mode_Out_PP*/
//下面进行判断是哪个行(对调模式)
//GPIOA, GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4
void exchange_Mode(void)
{GPIO_InitTypeDef   GPIO_InitStructure;//初始化//使能时钟 PA  AFIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);	//io口初始化, 设置//使能内部上拉GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	GPIO_Init(GPIOA, &GPIO_InitStructure);	/* 切换为下拉输入输入模式  GPIO_Mode_IPD *///GPIOA, GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7//GPIOB, GPIO_Pin_0 | GPIO_Pin_10	//io口初始化, 设置//使能内部上拉GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;	GPIO_Init(GPIOA, &GPIO_InitStructure);	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;	GPIO_Init(GPIOB, &GPIO_InitStructure);		}	

2.锁定行

电平反转, 类型反转,当检测到行io口电平变成低电平,就可以锁定行了

extern char chose_line;//选中的行
void find_line(void)	//行
{GPIO_SetBits(GPIOA, GPIO_Pin_1);GPIO_SetBits(GPIOA, GPIO_Pin_2);GPIO_SetBits(GPIOA, GPIO_Pin_3);GPIO_SetBits(GPIOA, GPIO_Pin_4);GPIO_ResetBits(GPIOA, GPIO_Pin_5);GPIO_ResetBits(GPIOA, GPIO_Pin_6);GPIO_ResetBits(GPIOA, GPIO_Pin_7);GPIO_ResetBits(GPIOB, GPIO_Pin_0);GPIO_ResetBits(GPIOB, GPIO_Pin_10);delay(0x20000);if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5) == SET){delay(0x20000);while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5) == SET);chose_line = 1;}elseif(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) == SET){delay(0x20000);while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) == SET);chose_line = 2;}elseif(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_7) == SET){delay(0x20000);while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_7) == SET);chose_line = 3;}elseif(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == SET){delay(0x20000);while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == SET);chose_line = 4;}elseif(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == SET){delay(0x20000);while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == SET);chose_line = 5;}	
}
③ 计算键值

//根据所在行列 ,计算出特定符号

char compute_sign(char lines,char columns)
{//算出特定需要char counter;char sign;counter = (lines-1)*4 + columns;
/* 行  1	2	3	4 (列)
1   (	)	/	*
2	1	2	3	+
3	4	5	6	-
4	7	8	9	Esc
5	<-	0	->	=*/	switch(counter){case 1:	sign = '(';break;case 2:sign = ')';break;case 3:sign = '/';break;case 4:sign = '*';break;case 5:sign = '1';break;case 6:sign = '2';break;case 7:sign = '3';break;case 8:sign = '+';break;case 9:sign = '4';break;case 10:sign = '5';break;case 11:sign = '6';break;case 12:sign = '-';break;		case 13:sign = '7';break;		case 14:sign = '8';break;		case 15:sign = '9';break;		case 16:sign = 'x';break;		case 17:sign = '<';break;		case 18:sign = '0';break;		case 19:sign = '>';break;		case 20:sign = '=';break;		default:sign = 0;break;		}return sign;
}
④ main函数调用展示键值
<1>软件初始化
void Software_Init(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	//中断控制器分组设置OLED_Init();Delay_Init();
//	uart_init();//波特率115200uart1_init(115200);//线性反转第一波(等待按键按下)button_key_config();Exti_key_config();init_collect_data();//按键收集中缀式初始化
}
<2>按键展示在OLED上
//按键展示
void show_keyboard(void)
{int counter;//展示选中的数字OLED_ShowChar(80, 0, show_sign, OLED_8X16);if(collect_space.counter == collect_space.insert_locate && (show_sign != '<') && (show_sign != '>')){OLED_ClearArea(0, 40, 128, 16);//for循环输出字符for(counter = 0; counter < collect_space.counter ;counter++){OLED_ShowChar(5+(counter)*14, 40, collect_space.data_symbol[counter], OLED_8X16);}		}elseif(collect_space.counter != collect_space.insert_locate){OLED_ClearArea(0, 40, 128, 16);//for循环输出字符for(counter = 0; counter < collect_space.counter ;counter++){OLED_ShowChar(5+(counter)*14, 40, 			collect_space.data_symbol[counter], OLED_8X16);}}OLED_Update();	
}
<3>循环检测按键按下
	while(1){//按键按下if(key_button_down == 1){//识别按键scan_keyboard();	//注意,此时按键应该抬起//拾取按键到中缀式collect_Key_information(show_sign);//按键展示show_keyboard();//擦屁股, 恢复读取模式 线性反转第一波(等待按键按下)button_key_config();Exti_key_config();	key_button_down = 0;}}

第二步: 单片机键值, 组合成算式字符串

(1)收集框架

我们收集的算式, 包括,加减乘除,‘0’-‘9’,还有左右括号,至于等于号,就不需要了,因为按完算式后,按下等于号, 相当于计算结果,等计算出结果后, 我们再按下等于,相当于清零,所以我们要做一下区分.

image-20240624170617115

(2)中缀式数据结构

所以, 我们定义一个中缀算式的数据结构

#define data_MaxSize   100
//中缀式处理结构体
struct CollectSpace
{char data_symbol[data_MaxSize];	//存储中缀式符号的数组int counter;					//最后一个字符的数组位置int insert_locate;					//当前需要插入的位置_Bool Start_Mode;				//是否开始计算_Bool clear;					//是否清零		
};	

(3)读取开始运算标志,计算结果

如果第一次按下等于号 ,就开始计算

if(collect_space.Start_Mode == 1)	//判断中缀式处理结构,是否进入计算模式
{//中缀式结构数组 --> 后缀式
Conversion_expression(collect_space.data_symbol,Suffix_expression);//转换后缀式//计算数值Calculate_result = Calculate_value(Suffix_expression);OLED_Clear();//结果OLED_Printf(0,0, OLED_8X16,"%.2f", Calculate_result);//总算式OLED_ShowString(0,20, collect_space.data_symbol,OLED_8X16);OLED_Update();collect_space.Start_Mode = 0;	//停止计算
}

(4)收集按键信息

①分按键类型,进入不同模式

收集的信息, 分为数字,运算符和等于号,

我们分别根据类型, 进入不同的模式进行处理:

image-20240624180928671

判断对应类型,进入不同处理模式

void collect_Key_information(char collect_key)
{//获得按键//查询功能if(collect_key >= '0' && collect_key <= '9'){char_input.character_Mode = 1;	//数字模式}elseif(collect_key == '+' || collect_key == '-' || collect_key == '*' || collect_key == '/' || collect_key == '(' || collect_key == ')'	)		{char_input.character_Mode = 2;	//运算符模式}elseif(collect_key == '<'||collect_key == '>'){char_input.character_Mode = 3;	//移动编辑模式}elseif(collect_key == 'x'){char_input.character_Mode = 4;	//编辑删除模式}elseif(collect_key == '='){char_input.character_Mode = 5;	//运算结果模式}deal_mode(collect_key);
}
② 根据不同模式,进入不同的处理
<1>数字模式

数字可以插入第一个位置和 第字符个数+1的位置

处理方法: 先腾出要插入的位置,然后把对应位置插入

if(char_input.character_Mode == 1)
{//合法性判断(可以插入第一个位置, 和 第(字符个数 + 1)的位置)直接使用物理序号if(collect_space.insert_locate >= 0 && collect_space.insert_locate <= collect_space.counter){for(j = collect_space.counter; j > collect_space.insert_locate; j--){collect_space.data_symbol[j] = collect_space.data_symbol[j-1];}collect_space.data_symbol[collect_space.insert_locate] = deal_key;//合法后 , 字符数量加1collect_space.counter++;//默认下次光标插入位置++collect_space.insert_locate++;}
}
<2>运算符模式

(可以插入第一个位置, 和 第(字符个数 + 1)的位置)直接使用物理序号

if(char_input.character_Mode == 2)	//加入合法性判断
{//合法性判断(可以插入第一个位置, 和 第(字符个数 + 1)的位置)直接使用物理序号if(collect_space.insert_locate >= 0 && collect_space.insert_locate <= collect_space.counter){for(j = collect_space.counter; j > collect_space.insert_locate; j--){collect_space.data_symbol[j] = collect_space.data_symbol[j-1];}collect_space.data_symbol[collect_space.insert_locate] = deal_key;//合法后 , 字符数量加1collect_space.counter++;//默认下次光标插入位置++collect_space.insert_locate++;}}
<3>移动编辑模式

这里, 我们只是切换了光标序号,所以我们下次插入字符的时候,就不能直接覆盖了,而是腾出位置,然后插入了

if(char_input.character_Mode == 3)	//移动编辑插入字符模式
{//光标跟踪if(deal_key == '<'){if(collect_space.insert_locate > 0){collect_space.insert_locate--;		}}else if(deal_key == '>'){if(collect_space.insert_locate < collect_space.counter){collect_space.insert_locate++;}}
}
<4>删除字符模式

我们删除字符前, 要做删除位置合法性判断(删除位置 = 插入位置的前一个字符)

//合法性判断(可以删除的位置 0 ~ 数组的collect_space.counter-1)

if(char_input.character_Mode == 4)	//删除字符模式
{//删除位置合法性判断(删除位置 = 插入位置的前一个字符)deletesapce.now_delete = collect_space.insert_locate-1;//合法性判断(可以删除的位置 0 ~ 数组的collect_space.counter-1)if(deletesapce.now_delete >= 0 && deletesapce.now_delete < collect_space.counter){//删除光标处的前一个字符 === //把光标后的字符移动到此为止(覆盖)//临界 data[collect_space.counter-2 ] = data[collect_space.counter-1 ];//==> j = collect_space.counter-2 =得出范围=> j < collect_space.counter-1for(j = deletesapce.now_delete; j < collect_space.counter-1; j++){collect_space.data_symbol[j] = collect_space.data_symbol[j+1];}//数组个数减去1collect_space.counter--;//光标位序减去1collect_space.insert_locate--;}
}
<5>运算模式

当我们第一次按下按键,我们就进入运算模式, 并且加一个自锁变量,下次等于就是清零变量,collect_space.clear ^= 1;

if(char_input.character_Mode == 5)	//运算模式
{//开启计算结果,并将计算数值装入中缀式if(collect_space.clear == 0){collect_space.data_symbol[collect_space.counter] = '\0';collect_space.Start_Mode = 1;	//中缀式结构 进入下次计算的待计算模式(擦屁股)//分情况collect_space.counter = 0;collect_space.insert_locate = 0;//初始的时候, 是数组, 0collect_space.clear ^= 1;}elseif(collect_space.clear == 1)	//将计算清零(归零):擦屁股{//清空屏幕OLED_Clear();OLED_Update();collect_space.clear ^= 1;}}

第三步,计算结果

我们通过观看博客原理,即可

https://blog.csdn.net/qq_57484399/article/details/138288148

第四步,屏幕显示

我们可以直接调用OLED显示函数,显示结果

但是如果我们需要使用语音,读出结果的话,就要对每一位进行分个进行读取,然后结合个十百千万以及汉语的语言习惯了,我会单独出一个博客,讲解,如果把自然数小数进行语音播报.

第五步, 清零

再次按下等于号,即可清零

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

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

相关文章

输入系统和应用编程

目录 一、输入设备和输入系统 1.什么是输入设备&#xff1f; 2.什么是输入系统&#xff1f; 二、输入系统框架及调试 1.框架概述 2.编写 APP 需要掌握的知识 &#xff08;1&#xff09;内核中怎么表示一个输入设备&#xff1f; &#xff08;2&#xff09;APP 可以得到什…

Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!

代码仓库 会同步代码到 GitHub https://github.com/turbo-duck/flink-demo 当前章节 继续上一节的内容&#xff1a;https://blog.csdn.net/w776341482/article/details/139875037 上一节中&#xff0c;我们需要使用 nc 或者 telnet 等工具来模拟 Socket 流。这节我们写一个 …

SAPUI5基础知识9 - JSON Module与数据绑定

1. 背景 在前面的博客中&#xff0c;我们已经学习了SAPUI5中视图和控制器的使用&#xff0c;在本篇博客中&#xff0c;让我们学习下MVC架构中的M-模型了。 SAPUI5中的JSON Model是一个客户端模型&#xff0c;可以用于在SAPUI5应用程序中处理和操作JSON数据。SAPUI5提供了绑定…

IPv6知识点整理

IPv6&#xff1a;是英文“Internet Protocol Version 6”&#xff08;互联网协议第6版&#xff09;的缩写&#xff0c;是互联网工程任务组&#xff08;IETF&#xff09;设计的用于替代IPv4的下一代IP协议&#xff0c;其地址数量号称可以为全世界的每一粒沙子编上一个地址 。 国…

React的生命周期函数详解

import React,{Component} from "react";import SonApp from ./sonAppclass App extends Component{state{hobby:爱吃很多好吃的}// 是否要更新数据&#xff0c;这里返回true才会更新数据shouldComponentUpdate(nextProps,nextState){console.log("app.js第一步…

创建和探索VGG16模型

PyTorch在torchvision库中提供了一组训练好的模型。这些模型大多数接受一个称为 pretrained 的参数&#xff0c;当这个参数为True 时&#xff0c;它会下载为ImageNet 分类问题调整好的权重。让我们看一下创建 VGG16模型的代码片段&#xff1a; from torchvision import models…

视图(views)

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 下面通过一个例子讲解在Django项目中定义视图&#xff0c;代码如下&#xff1a; from django.http import HttpResponse # 导入响应对象 impo…

Flutter【组件】点击类型表单项

简介 flutter 点击表单项组件&#xff0c;适合用户输入表单的场景。 点击表单项组件是一个用户界面元素&#xff0c;通常用于表单或设置界面中&#xff0c;以便用户可以点击它们来选择或更改某些设置或输入内容。这类组件通常由一个标签和一个可点击区域组成&#xff0c;并且…

Redis-数据类型-zset

文章目录 1、查看redis是否启动2、通过客户端连接redis3、切换到db4数据库4、将一个或多个member元素及其score值加入到有序集key当中5、升序返回有序集key6、升序返回有序集key&#xff0c;让分数一起和值返回的结果集7、降序返回有序集key&#xff0c;让分数一起和值返回到结…

Charles抓包工具系列文章(一)-- Compose 拼接http请求

一、背景 众所周知&#xff0c;Charles是一款抓包工具&#xff0c;当然是http协议&#xff0c;不支持tcp。&#xff08;如果你想要抓tcp包&#xff0c;请转而使用wireshark&#xff0c;在讲述websocket的相关技术有梳理过wireshark抓包&#xff09; 话说回来&#xff0c;char…

浏览器自带的IndexDB的简单使用示例--小型学生管理系统

浏览器自带的IndexDB的简单使用示例--小型学生管理系统 文章说明代码效果展示 文章说明 本文主要为了简单学习IndexDB数据库的使用&#xff0c;写了一个简单的增删改查功能 代码 App.vue&#xff08;界面的源码&#xff09; <template><div style"padding: 30px&…

红队内网攻防渗透:内网渗透之内网对抗:横向移动篇域控系统提权NetLogonADCSPACKDC永恒之蓝CVE漏洞

红队内网攻防渗透 1. 内网横向移动1.1 横向移动-域控提权-CVE-2020-1472 NetLogon1.2 横向移动-域控提权-CVE-2021-422871.3 横向移动-域控提权-CVE-2022-269231.4 横向移动-系统漏洞-CVE-2017-01461.5 横向移动-域控提权-CVE-2014-63241. 内网横向移动 1、横向移动-域控提权-…

elementui组件库实现电影选座面板demo

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Cinema Seat Selection</title><!-- 引入E…

【学一点儿前端】单页面点击前进或后退按钮导致的内存泄露问题(history.listen监听器清除)

今天测试分配了一个比较奇怪的问题&#xff0c;在单页面应用中&#xff0c;反复点击“上一步”和“下一步”按钮时&#xff0c;界面表现出逐渐变得卡顿。为分析这一问题&#xff0c;我用Chrome的性能监控工具进行了浏览器性能录制。结果显示&#xff0c;每次点击“上一步”按钮…

区间预测 | Matlab实现CNN-ABKDE卷积神经网络自适应带宽核密度估计多变量回归区间预测

区间预测 | Matlab实现CNN-ABKDE卷积神经网络自适应带宽核密度估计多变量回归区间预测 目录 区间预测 | Matlab实现CNN-ABKDE卷积神经网络自适应带宽核密度估计多变量回归区间预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现CNN-ABKDE卷积神经网络自适应…

思考题:相交的几何图形

给定不超过 26 个几何图形&#xff0c;每个图形都有一个唯一大写字母作为其编号。 每个图形在平面中的具体位置已知&#xff0c;请你判断&#xff0c;对于每个图形&#xff0c;有多少个其他图形与其存在交点。 在判断交点时&#xff0c;只考虑边与边相交的情况&#xff0c;如…

Java 8 Date and Time API

Java 8引入了新的日期和时间API&#xff0c;位于java.time包下&#xff0c;旨在替代旧的java.util.Date和java.util.Calendar类。新API更为简洁&#xff0c;易于使用&#xff0c;并且与Joda-Time库的一些理念相吻合。以下是Java 8 Date and Time API中几个核心类的简要概述&…

AIGC-CVPR2024best paper-Rich Human Feedback for Text-to-Image Generation-论文精读

Rich Human Feedback for Text-to-Image Generation斩获CVPR2024最佳论文&#xff01;受大模型中的RLHF技术启发&#xff0c;团队用人类反馈来改进Stable Diffusion等文生图模型。这项研究来自UCSD、谷歌等。 在本文中&#xff0c;作者通过标记不可信或与文本不对齐的图像区域&…

【网络协议】精讲ARP协议工作原理!图解超赞超详细!!!

亲爱的用户&#xff0c;打开微信&#xff0c;搜索公众号&#xff1a;“风云说通信”&#xff0c;即可免费阅读该文章~~ 目录 前言 1. ARP协议介绍 1.1 ARP协议功能 1.2 ARP请求报文 1.3 ARP工作原理 2. ARP 缓存超时 2.1 RARP 3. ARP 攻击 3.1 ARP 攻击分类 前言 首先…

HTML(16)——边距问题

清楚默认样式 很多标签都有默认的样式&#xff0c;往往我们不需要这些样式&#xff0c;就需要清楚默认样式 写法&#xff1a; 用通配符选择器&#xff0c;选择所有标签&#xff0c;清除所有内外边距选中所有的选择器清楚 *{ margin:0; padding:0; } 盒子模型——元素溢出 作…