嵌入式计算器模块实现

嵌入式计算器模块规划

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

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

大致流程如下:

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.mzph.cn/web/36288.shtml

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

相关文章

读AI新生:破解人机共存密码笔记15辅助博弈

1. 辅助博弈 1.1. assistance game 1.2. 逆强化学习如今已经是构建有效的人工智能系统的重要工具&#xff0c;但它做了一些简化的假设 1.2.1. 机器人一旦通过观察人类学会了奖励函数&#xff0c;它就会采用奖励函数&#xff0c;这样它就可以执行相同的任务 1.2.1.1. 解决这…

Dominate_一个用于生成和操作 HTML 文档的 Python 库

目录 01初识 Dominate 什么是 Dominate&#xff1f; 为什么选择 Dominate&#xff1f; 安装与配置 02Dominate 的基本使用 创建简单的 HTML 文档 添加表格 嵌套结构 03Dominate 的高级功能 动态内容生成 使用…

CSF视频文件格式转换WMV格式

如果大家看过一些高校教学讲解视频的话&#xff0c;很可能见过这样一个难得的格式&#xff0c;".csf "&#xff0c;非常漂亮 。 用暴风影音都可以打开观看&#xff0c;会自动下载解码。 但是一旦我们想要利用或者上传视频的时候就麻烦了&#xff0c;一般网站不认这…

下载旧版本vscode及扩展,离线下载远程linux服务器插件

背景 工作的内网没有网络&#xff0c;无法使用网络来下载插件和vscode软件&#xff0c;且有远程linux服务器需求&#xff0c;linux服务器中lib相关库比较旧且无法更新&#xff0c;所以需要选择一个旧版本的vscode&#xff0c;相应插件也需要选择旧版本的 旧版本vscode下载 没…

Windows下activemq集群配置(broker-network)

1.activemq版本信息 activemq&#xff1a;apache-activemq-5.18.4 2.activemq架构 3.activemq集群配置 activemq集群配置基于Networks of Brokers 这种HA方案的优点&#xff1a;是占用的节点数更少(只需要2个节点),而且2个broker都可以响应消息的接收与发送。不足&#xff…

Docker 部署 MariaDB 数据库 与 Adminer 数据库管理工具

文章目录 MariaDBmariadb.cnf开启 binlog Adminerdocker-compose.ymlAdminer 连接 MariaDB MariaDB MariaDB是一个流行的开源关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是MySQL的一个分支和替代品。 官网&#xff1a;https://mariadb.com/镜像&#xff…

SpringBoot控制反转和依赖注入

目录 一、内聚和耦合 二、分层解耦 三、具体实现 四、bean的组件扫描 五、bean注入 一、内聚和耦合 在了解分层解耦的概念之前我们我们要去先了解一下内聚和耦合。内聚&#xff1a;通常将的是软件中各个模块之间的功能联系。耦合衡量软件各个模块之间的依赖、关联的程度。一…

ONLYOFFICE 8.1 版本桌面编辑器测评

在现代办公环境中&#xff0c;办公软件的重要性不言而喻。从文档处理到电子表格分析&#xff0c;再到演示文稿制作&#xff0c;强大且高效的办公软件工具能够极大提升工作效率。ONLYOFFICE 作为一个功能全面且开源的办公软件套件&#xff0c;一直以来都受到广大用户的关注与喜爱…

OpenAI推出自我改进AI- CriticGPT

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

如何进行黄金期货日内波段交易-EE trade

日内波段交易是一种在单个交易日内抓取较大波段趋势的方法&#xff0c;旨在利用市场的短期波动获取利润。黄金期货市场由于其高波动性和高杠杆性&#xff0c;成为日内波段交易的理想选择。以下是黄金期货日内波段交易的详细策略和方法。 一、日内波段交易整体设计思想 1. 顺应…

【Linux】生物信息学常用基本命令

wget网址用于直接从网上下载某个文件到服务器&#xff0c;当然也可以直接从网上先把东西下到本地然后用filezilla这个软件来传输到服务器上。 当遇到不会的命令时候&#xff0c;可以使用man “不会的命令”来查看这个命令的详细信息。比如我想要看看ls这个命令的详细用法&…

独立开发者系列(12)——下单与支付

做业务有个绕不开的业务逻辑&#xff0c;就是支付。这里总结一个基础的支付电商逻辑闭环流程&#xff0c;完成支付基础体系的实现。这里假定我们要实现的是一个独立的电商平台上允许用户在平台充值&#xff0c;其他的类似多多购物或者淘宝购物的流程逻辑。 数据表结构的逻辑设…

使用uniapp编写微信小程序

使用uniapp编写微信小程序 文章目录 使用uniapp编写微信小程序前言一、项目搭建1.1 创建项目方式1.1.1 HBuilderX工具创建1.1.2 命令行下载1.1.3 直接Gitee下载 1.2 项目文件解构1.2.1 安装依赖1.2.2 项目启动1.2.3 文件结构释义 1.2 引入uni-ui介绍 二、拓展2.1 uni-app使用uc…

【高考】人生规划指南

作为一个正处在这个选择的十字路口的高考考生&#xff0c;我认为在选择专业和学校时&#xff0c;要根据自己的具体情况和个人目标来权衡。首先&#xff0c;我认为专业是首要考虑因素。因为专业是直接决定未来职业发展方向的&#xff0c;如果不喜欢或者不适合的专业选择&#xf…

数字时代的文化革命:Facebook的社会影响

随着数字技术的飞速发展和互联网的普及&#xff0c;社交网络如今已成为人们日常生活中不可或缺的一部分。在众多社交平台中&#xff0c;Facebook作为最大的社交网络之一&#xff0c;不仅连接了全球数十亿用户&#xff0c;更深刻影响了人们的社会互动方式、文化认同和信息传播模…

前端面试题(基础篇十二)

一、link标签定义、与import的区别 link 标签定义文档与外部资源的关系。 link 元素是空元素&#xff0c;它仅包含属性。 此元素只能存在于 head 部分&#xff0c;不过它可出现任意数。 link 标签中的 rel 属性定义了当前文档与被链接文档之间的关系。常见的 stylesheet 指的是…

Python酷库之旅-第三方库openpyxl(15)

目录 一、 openpyxl库的由来 1、背景 2、起源 3、发展 4、特点 4-1、支持.xlsx格式 4-2、读写Excel文件 4-3、操作单元格 4-4、创建和修改工作表 4-5、样式设置 4-6、图表和公式 4-7、支持数字和日期格式 二、openpyxl库的优缺点 1、优点 1-1、支持现代Excel格式…

pdf已加密如何解除?解密密码的两个方法【可加密】

电脑文件加密的目的就是保护重要信息&#xff0c;防止数据泄露。如果需要解除密码&#xff0c;应该如何操作呢&#xff1f;pdf已加密如何解除&#xff1f;本文整理了以下两种解除文件方法&#xff0c;希望能够帮到有需要的朋友们&#xff01; 方法一、使用金舟文件夹加密大师解…

vue3+vite+nodejs,通过接口的形式请求后端打包(可打包全部或指定打包组件)

项目地址https://gitee.com/sybb011016/test_build 打包通过按钮的形式请求接口&#xff0c;让后端进行打包&#xff0c;后端使用express-generator搭建模版。前端项目就在npm init vuelatest基础上添加了路由 如果只想打包AboutView组件&#xff0c;首先修改后端接口。 //打…

Open3D (C++) 点云旋转至主成分空间

目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 首先使用主成分分析法计算出点云的特征值与特征向量,然后根据点云的特征向量计算出点云与主成分空间之间的…