【蓝桥杯嵌入式】第十三届省赛(第二场)

目录

0 前言

1 展示

1.1 源码

1.2 演示视频

1.3 题目展示

2 CubeMX配置(第十三届省赛第二场真题)

2.1 设置下载线

2.2 HSE时钟设置

2.3 时钟树配置

2.4 生成代码设置

2.5 USART1

2.5.1 基本配置

2.5.2 NVIC

2.5.3 DMA 

2.6 TIM

2.6.1 TIM2

2.6.2 TIM4

2.6.3 TIM6

3 引脚配置

4 代码相关定义、声明

4.1 变量声明

4.2 函数声明

5 主要函数

5.1 LCD

5.2 KEY

5.3 EEPROM

5.4 LED

5.5 PWM

5.6 定时器回调函数

5.7 串口回调函数

 5.8 串口

5.9 上电初始化

6 测试

7 做题感受


菜狗上线~~~


0 前言

  • 开发板:CT117E-M4(STM32G431RBT6)
  • 软件环境:CubeMX + Keil5
  • 涉及题目:第十三届蓝桥杯嵌入式省赛第二场真题

1 展示

1.1 源码

Gitee链接:

1.2 演示视频

B站链接:

1.3 题目展示


2 CubeMX配置(第十三届省赛第二场真题)

2.1 设置下载线

2.2 HSE时钟设置

2.3 时钟树配置

晶振一定要改成24M,晶振一定要改成24M,晶振一定要改成24M,主频80M

2.4 生成代码设置

2.5 USART1

2.5.1 基本配置

题目要求串口1波特率9600

2.5.2 NVIC

串口一定要使能NVIC

2.5.3 DMA 

添加两个DMA即可

2.6 TIM

2.6.1 TIM2

TIM2用作PWM输出功能,通过引脚PA1输出

配置成2KHz的PWM

定时器2也要使能NVIC

2.6.2 TIM4

TIM4做基准定时器,10ms定时,专门用来按键扫描

预分频系数80-1

重装载值10000-1

定时器4也要使能NVIC

2.6.3 TIM6

定时器65用来实现倒计时5S,不开定时器6也可以用定时器4实现,这里我不想让倒计时和按键有联系,就多开了一个定时器,配置如下

定时器6也要使能NVIC


3 引脚配置

  • 配置8个LED         PD2  outpp    PC8~PC15   outpp
  • 配置4个按键         PA0、PB0、PB1、PB2    配置为上拉输入模式
  • 配置串口1            PA9  PA10
  • PWM                   PA1(TIM2-CH2)


4 代码相关定义、声明

4.1 变量声明

主要的变量定义如下所示,用了两个结构体,一个是写参数的,一个是写标志位的

/* 定义结构体 */
struct Param_TypeDef
{
	u32 LED_Tick; // LED定时 函数减速
	u32 LCD_Tick; // LCD定时 函数减速
	u32 RX_Tick;  // RX 定时 函数减速
	u32 PWM_Tick; // PWM定时 函数减速
	u32 EEP_Tick; // EEPROM 定时
	u8 LED_State; // LED状态变量

	u16 Set_PA1_Freq; //
	u8 Set_PA1_Duty;

	u8 Shop_Num_X; // 购买数量X
	u8 Shop_Num_Y; // 购买数量Y
	float Price_X; // 单价X
	float Price_Y; // 单价Y
	u8 REP_X;	   // 库存X
	u8 REP_Y;	   // 库存Y

	float All_Price; // 总价

	u8 last_rep_X; // 上次的X
	u8 last_rep_Y; // 上次的Y
	float Last_Price_X; // 单价X
	float Last_Price_Y; // 单价Y
};

struct Flag_TypeDef
{
	bool LCD_Dir;
	u8 LCD_View;		 // LCD界面
	u8 Current_Platform; // 当前平台
	bool Key4_Press;	 // KEY4按下
	bool led2_state;
};

extern struct Param_TypeDef param;
extern struct Flag_TypeDef flag;

/* 定义结构体 */

// 定义状态机状态
#define SHOP 0
#define PRICE 1
#define REP 2

4.2 函数声明

/* 函数声明 */
void LED_proc(void);
void LCD_Disp_proc(void);
void Key_proc_Loop(void);
void Power_Init(void); // 上电初始化
void RX_Proc(void); // 串口接收函数
void PWM_Set_Proc(void);
void EEPROM_Proc(void);

5 主要函数

5.1 LCD

LCD一共有三个界面,分别是购买界面、单价界面、库存界面,分别题目要求到的标题和内容~

这里的MYLCD_printf()函数是我自己封装的

// LCD显示
void LCD_Disp_proc(void)
{
	// 函数减速
	if (uwTick - param.LCD_Tick < 50)
		return;
	param.LCD_Tick = uwTick;

	// 执行任务
	if (flag.LCD_View == SHOP)
	{ // 购买界面
		MYLCD_printf(Line1, "        SHOP         ");
		MYLCD_printf(Line3, "     X:%2d           ", param.Shop_Num_X);
		MYLCD_printf(Line4, "     Y:%2d           ", param.Shop_Num_Y);
	}
	else if (flag.LCD_View == PRICE)
	{ // 单价界面
		MYLCD_printf(Line1, "        PRICE        ");
		MYLCD_printf(Line3, "     X:%.1f           ", param.Price_X);
		MYLCD_printf(Line4, "     Y:%.1f           ", param.Price_Y);
	}
	else if (flag.LCD_View == REP)
	{ // 库存界面
		MYLCD_printf(Line1, "        REP          ");
		MYLCD_printf(Line3, "     X:%2d           ", param.REP_X);
		MYLCD_printf(Line4, "     Y:%2d           ", param.REP_Y);
	}
}

正常的LCD显示语句,每次都要使用之前清零,再用sprint函数拼接字符串再调用LCD的显示函数,为了显示的更加简洁我用可变参数列表封装了这三行代码~代码如下

// // 使用之前先清除显示数组,再填写内容
// memset(LCD_Show_text, '\0', sizeof(LCD_Show_text));
// sprintf(LCD_Show_text, "    LED:OFF     ");
// LCD_DisplayStringLine(Line5, (uint8_t *)LCD_Show_text);
void MYLCD_printf(unsigned char linex, char *format, ...)
{
    char LCD_Show_text[30];

    memset(LCD_Show_text, '\0', sizeof(LCD_Show_text));

    va_list arg;                          // 定义可变参数列表数据类型的变量arg
    va_start(arg, format);                // 从format开始,接收参数列表到arg变量
    vsprintf(LCD_Show_text, format, arg); // 使用vsprintf打印格式化字符串和参数列表到字符数组中
    LCD_DisplayStringLine(linex, (uint8_t *)LCD_Show_text);
    va_end(arg); // 结束变量arg

    //	sprintf((char *)LCD_Show_text, str);
}

思路如下: 

  1. //先清除数组的内容
  2. // 定义可变参数列表数据类型的变量arg
  3. // 从format开始,接收参数列表到arg变量
  4. // 使用vsprintf打印格式化字符串和参数列表到字符数组中
  5. //LCD显示
  6. // 结束变量arg

5.2 KEY

按键处理函数,使用01Stdio的按键扫描函数,放在定时器4里10ms扫描一次

按键1是切换界面

按键2是购买数量,注意越界回滚

按键3是购买单价,注意越界回滚,这个但是是浮点数,这里就有说到了,浮点数的2.0f其实不准确,如果判断当前价格>2.0了就参数回滚,会出现1.9直接跳变到2.0,所以我们把比较的数值改成2.01f就完美解决了~~~

按键4 计算总计,串口上传数据,发送完成,单价清零

void Key_proc_Loop(void)
{
	if (bkey[1].short_flag == 1)
	{
		flag.LCD_View++;
		if (flag.LCD_View >= 3)
			flag.LCD_View = 0; // 三个界面
		bkey[1].short_flag = 0;
	}
	if (bkey[2].short_flag == 1)
	{
		if (flag.LCD_View == SHOP)
		{ // 购买界面
			param.Shop_Num_X++;
			if (param.Shop_Num_X > param.REP_X) // 超过库存,越界回滚成0
				param.Shop_Num_X = 0;
		}
		else if (flag.LCD_View == PRICE)
		{ // 单价界面
			param.Price_X += 0.1f;
			if (param.Price_X > 2.01f) // 注意浮点数
				param.Price_X = 1.0f;  // 越界回滚
		}
		else if (flag.LCD_View == REP)
		{ // 库存界面
			param.REP_X++;
		}
		bkey[2].short_flag = 0;
	}
	if (bkey[3].short_flag == 1) //
	{
		if (flag.LCD_View == SHOP)
		{ // 购买界面
			param.Shop_Num_Y++;
			if (param.Shop_Num_Y > param.REP_Y) // 超过库存,越界回滚成0
				param.Shop_Num_Y = 0;
		}
		else if (flag.LCD_View == PRICE)
		{ // 单价界面
			param.Price_Y += 0.1f;
			if (param.Price_Y > 2.01f) // 注意浮点数
				param.Price_Y = 1.0f;  // 越界回滚
		}
		else if (flag.LCD_View == REP)
		{ // 库存界面
			param.REP_Y++;
		}
		bkey[3].short_flag = 0;
	}
	if (bkey[4].short_flag == 1) //
	{
		if (flag.LCD_View == SHOP)
		{ // 购买界面
			flag.Key4_Press = 1;
			param.REP_X -= param.Shop_Num_X;
			param.REP_Y -= param.Shop_Num_Y;
			param.All_Price = param.Shop_Num_X * param.Price_X + param.Shop_Num_Y * param.Price_Y;

			memset(USART_tx_string, '\0', sizeof(USART_tx_string)); // 变量清零
			sprintf(USART_tx_string, "X:%d,Y:%d,Z:%.1f", param.Shop_Num_X, param.Shop_Num_Y, param.All_Price);
			HAL_UART_Transmit_DMA(&huart1, (uint8_t *)USART_tx_string, strlen(USART_tx_string));

			// 发送完成,单价清零
			param.Shop_Num_X = 0;
			param.Shop_Num_Y = 0;
		}
		bkey[4].short_flag = 0;
	}
}

5.3 EEPROM

这个函数100ms调用一次,在函数里判断当前值和100ms以前的值是否相等,如果不相等,就说明数据变化了,就需要存储到EEPROM中,存到对应的地址里

要存储的单价是一位浮点数,乘以10变成整数存进去,读取的时候不要忘记除以10即可

这里的逻辑是先判断,后赋值,如果先赋值后判断,永远检测不出来数据跳变,这里要细细品味一下,有之前写的按键扫描的味道~

void EEPROM_Proc(void)
{
	if (uwTick - param.EEP_Tick < 100)
		return;
	param.EEP_Tick = uwTick;

	if (param.last_rep_X != param.REP_X)
	{
		EEPROM_WriteByte(0, param.REP_X); // 剩余数量X
		HAL_Delay(10);
	}

	if (param.last_rep_Y != param.REP_Y)
	{
		EEPROM_WriteByte(1, param.REP_Y); // 剩余数量Y
		HAL_Delay(10);
	}

	if (param.Last_Price_X != param.Price_X)
	{
		EEPROM_WriteByte(2, (param.Price_X * 10)); // 单价X
		HAL_Delay(10);
	}

	if (param.Last_Price_Y != param.Price_Y)
	{
		EEPROM_WriteByte(3, (param.Price_Y * 10)); // 单价Y
		HAL_Delay(10);
	}
	param.last_rep_X = param.REP_X;
	param.last_rep_Y = param.REP_Y;
	param.Last_Price_X = param.Price_X;
	param.Last_Price_Y = param.Price_Y; // 延迟赋值
}

5.4 LED

LED显示函数,只需要写一次即可,我们只需要修改param.LED_State这个变量,就能达到控制哪一位LED亮灭的状态

LED显示多用位运算,非常巧妙~

//LED驱动函数
void LED_Disp(unsigned char state)
{
	HAL_GPIO_WritePin(GPIOC, 0xFF00, GPIO_PIN_SET);		  // 先全部熄灭 1
	HAL_GPIO_WritePin(GPIOC, state << 8, GPIO_PIN_RESET); // 点亮 0
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);	  // 锁存器置高,使能
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); // 锁存器置低,失能
}
// LED处理函数
void LED_proc(void)
{
	static u8 led1, led2;
	// 函数减速
	if (uwTick - param.LED_Tick < 20)
		return;
	param.LED_Tick = uwTick;

	led1 = flag.Key4_Press << 0; // 5S内是1
	led2 = flag.led2_state << 1;

	param.LED_State = led1 | led2;
	LED_Disp(param.LED_State);
}

5.5 PWM

  • 设置频率,设置占空比,只修改变量即可
  • __HAL_TIM_SetAutoreload设置重装载值,80分频之后是1MHz = 1e6,用1e6/要设置的频率就是重装载值
  • __HAL_TIM_SetCompare设置比较值,设置高电平时间,即设置占空比,比较值=重装载值*占空比
void PWM_Set_Proc(void)
{
	if (uwTick - param.PWM_Tick < 100)
		return;
	param.PWM_Tick = uwTick;

	// 设置频率
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
	param.Set_PA1_Freq = 2000;    //2000Hz
	__HAL_TIM_SetAutoreload(&htim2, 1e6 / param.Set_PA1_Freq - 1);

	// 设置占空比
	if (flag.Key4_Press == 1) // 5S内
		param.Set_PA1_Duty = 30;    //30%占空比
	else
		param.Set_PA1_Duty = 5;    //5%占空比
	__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, (1e6 / param.Set_PA1_Freq - 1) * param.Set_PA1_Duty / 100 + 1);    //设置占空比函数
}

5.6 定时器回调函数

定时器4专门用来10ms扫描一次按键

定时器6用来处理LED的5S点亮,和0.1S闪烁,使用标志位判断即可,这些都是常规操作~

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	static uint16_t LED_cnt, LED_cnt2;

	if (htim->Instance == TIM4)
	{
		key_serv_double(); // 10ms按键处理
	}

	if (htim->Instance == TIM6) // 10ms进入一次 处理倒计时
	{
		if (flag.Key4_Press == 1)
		{
			if (++LED_cnt >= 500)
			{
				LED_cnt = 0;
				flag.Key4_Press = 0;
			}
		}
		if ((param.REP_X == 0) && (param.REP_Y == 0)) // 如果XY的库存都等于0
		{
			if (++LED_cnt2 >= 10)
			{
				LED_cnt2 = 0; // 100ms
				flag.led2_state = !flag.led2_state;
			}
		}
		else
			flag.led2_state = 0;
	}
}

5.7 串口回调函数

// 串口的接收 回调函数
char USART_tx_string[50];
char rxdata[100];
uint8_t RX_Str_Data;
unsigned char rx_pointer; // 自己定义的指针,判断接收到哪了

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if (huart->Instance == USART1) // 如果是USART1
	{
		param.RX_Tick = uwTick;

		rxdata[rx_pointer++] = RX_Str_Data;				// 接收到的字符串存放在这里
		HAL_UART_Receive_DMA(&huart1, &RX_Str_Data, 1); // 最后这个参数只能写1
	}
}

 5.8 串口

void RX_Proc(void)
{
	if (uwTick - param.RX_Tick < 50)
		return;
	param.RX_Tick = uwTick;

	// 执行任务

	if (rx_pointer == 1 && rxdata[0] == '?') // 如果收到一个数据,并且是#
	{
		memset(USART_tx_string, '\0', sizeof(USART_tx_string)); // 变量清零
		sprintf(USART_tx_string, "X:%.1f,Y:%.1f", param.Price_X, param.Price_Y);
		HAL_UART_Transmit_DMA(&huart1, (uint8_t *)USART_tx_string, strlen(USART_tx_string));
	}
	else if (rx_pointer > 0)
    {
	}

	rx_pointer = 0;						  // 指针归位
	memset(rxdata, '\0', sizeof(rxdata)); // 变量清零
}

5.9 上电初始化

  1. LCD初始化
  2. 按键初始化
  3. 定时器初始化
  4. PWM初始化
  5. 串口DMA发送初始化
  6. 串口DMA接收初始化
  7. 检测是否第一次上电,如果是第一次上电,就初始化库存和单价
// 上电初始化
void Power_Init(void)
{
	LED_Disp(0x00); // 关掉所有LED

	LCD_Init(); // LCD初始化
	LCD_Clear(Black);
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);
	LCD_DrawLine(120, 0, 320, Horizontal);
	LCD_DrawLine(0, 160, 240, Vertical);
	HAL_Delay(150);
	LCD_Clear(Blue);
	LCD_DrawRect(70, 210, 100, 100);
	HAL_Delay(150);
	LCD_Clear(Blue);
	LCD_DrawCircle(120, 160, 50);
	HAL_Delay(150);

	LCD_Clear(Black);
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);

	KEY_GPIO_Init(); // 手动初始化,防止忘记配置CubeMX
	// 定时器初始化
	HAL_TIM_Base_Start_IT(&htim4);
	HAL_TIM_Base_Start_IT(&htim6); // 用于倒计时

	//	// PWM初始化
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); // 打开定时器2 通道2

	HAL_UART_Transmit_DMA(&huart1, (uint8_t *)USART_tx_string, strlen(USART_tx_string));
	HAL_UART_Receive_DMA(&huart1, &RX_Str_Data, 1); // IT改为DMA
	// 参数初始化
	if (EEPROM_ReadByte(111) != 11) // 第一次进入是不等于的
	{
		// 先执行这里的代码
		// 第一次就先初始化
		param.REP_X = 10; // 库存默认10
		param.REP_Y = 10; // 库存默认10
		param.Price_X = 1.0;
		param.Price_Y = 1.0f;

		EEPROM_WriteByte(111, 11); // 在111写111
	}
	else // 不是第一次上电
	{
		// 上电先读取EEPROM
		param.REP_X = EEPROM_ReadByte(0);
		HAL_Delay(1);
		param.REP_Y = EEPROM_ReadByte(1);
		HAL_Delay(1);
		param.Price_X = EEPROM_ReadByte(2) / 10.0;
		HAL_Delay(1);
		param.Price_Y = EEPROM_ReadByte(3) / 10.0;
		HAL_Delay(1);
	}
}

6 测试

按键可以自行测试,这里我只展示串口部分的效果


7 做题感受

  • 注意浮点数的比较 2.0f与2.01f的区别,看上面5.2 KEY 按键3的解释
  • 串口收发不到数据,没使用rx_proc函数,然后重新配置了一下TX和RX的DMA就可以使用了
  • PWM没有输出,使用定时器2通道2,我写成了通道1,所以没有输出...
  • EEPROM存储的数据不能是小数;
  • 试题中比较难的部分是如何判定设备是否是第一次启动以及EEPROM连续读取需要一定的时间间隔
  • 总的来说,该试题还是比较简单的,就剩一些常见的解题模式框架,🚀🚀🚀!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ICP配准算法

配准算法 问题定义ICP(point to point)算法思想步骤分解point to point和point to plane的区别ICP配准算法的标准流程NDT 本篇将介绍配准算法&#xff0c;将介绍ICP(point to point)、ICP(point to plane)和NDT算法。其中ICP有两种&#xff0c;point to point表示通过构建点与点…

达梦备份与恢复

达梦备份与恢复 基础环境 操作系统&#xff1a;Red Hat Enterprise Linux Server release 7.9 (Maipo) 数据库版本&#xff1a;DM Database Server 64 V8 架构&#xff1a;单实例1 设置bak_path路径 --创建备份文件存放目录 su - dmdba mkdir -p /dm8/backup--修改dm.ini 文件…

NzN的数据结构--二叉树part1

你叉叉&#xff0c;让你学数据结构你不学&#xff1b;你叉叉&#xff0c;让你看二叉树你不看。 今天我们来一起学习二叉树部分&#xff0c;先赞后看是好习惯。 一、树的概念及结构 1. 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有…

阿里云服务器可以干什么?阿里云服务器主要用途是干嘛的?

阿里云服务器可以干嘛&#xff1f;能干啥你还不知道么&#xff01;简单来讲可用来搭建网站、个人博客、企业官网、论坛、电子商务、AI、LLM大语言模型、测试环境等&#xff0c;阿里云百科aliyunbaike.com整理阿里云服务器的用途&#xff1a; 阿里云服务器活动 aliyunbaike.com…

SpringCloud Alibaba Sentinel 规则持久化

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第十七篇&#xff0c;即使用 Sentinel 实现规则持久化。 二、概述 从前面我们做的实验可知&#xff0c;…

4/7 QT_day1

#include "mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) {//窗口设置this->setWindowTitle("小黑子(little black son)");this->setWindowIcon(QIcon("D:\\qq文件\\Pitrue\\pictrue\\black.jpg"));this-&g…

【数据结构与算法】:快速排序和冒泡排序

一&#xff0c;快速排序 快速排序是一种比较复杂的排序算法&#xff0c;它总共有4种实现方式&#xff0c;分别是挖坑法&#xff0c;左右"指针"法&#xff0c;前后"指针"法&#xff0c;以及非递归的快速排序&#xff0c;并且这些算法中也会涉及多种优化措施…

Tokenize Anything via Prompting

SAM的延续&#xff0c;把SAM输出的token序列用来进行分类&#xff0c;分割和一个自然语言的decoder处理&#xff0c;但其实现在多模态的图像的tokenizer也几乎都是用VIT来实现的。一开始认为这篇文章可能是关于tokenize的&#xff0c;tokenize还是很重要的&#xff0c;后来看完…

若依框架学习——分页查询列表

条件查询【多条件】列表展示【分页】SaCheckPermissionTableName TableId NotBlank Page分页 响应数据封装类

JMeter+Ant+Jenkins构建接口报告(无人驾驶版)

展示结果&#xff1a; uc浏览器打开测试报告&#xff0c;绿色显示脚本结果 搭建操作步骤如下 1.jemter写好脚本 2.下载并配置ant环境变量&#xff1a;加上activation.jar、commons-lang3-3.8.1.jar、mail.jar 这3个包 mail.jar需要引用到jmeter 3.下载安装Jenkins 并进行构建…

CKA 基础操作教程(六)

Kubernetes Deployments 理论学习 在 Kubernetes 中&#xff0c;Deployments 是一种资源对象&#xff0c;用于定义和管理容器化应用程序的部署过程&#xff0c; 容器化应用的声明式定义&#xff1a;使用 Deployments &#xff0c;可以声明性地定义应用程序的部署配置&#x…

Vue使用高德地图

1.在高德平台注册账号 2.我的 > 管理管理中添加Key 3.安装依赖 npm i amap/amap-jsapi-loader --save 或 yarn add amap/amap-jsapi-loader --save 4.导入 AMapLoade import AMapLoader from amap/amap-jsapi-loader; 5.直接上代码&#xff0c;做好了注释&#xff08;初始化…

初识ES(ES的基本概念、倒排索引、索引和文档的CRUD)

1、ES是什么&#xff1f; 一个开源的分布式搜索引擎&#xff0c;可以用来实现搜索、日志统计、分析、系统监控等功能。ES的底层是基于Lucene实现的。 Lucene是一个Java语言的搜索引擎类库。 什么是elastic stack&#xff08;ELK&#xff09;&#xff1f; elasticsearch。存储、…

实验室用进口高纯聚四氟乙烯材质PFA方盘抗酸碱耐高温PFA托盘

PFA方盘又称托盘&#xff1a;耐高温、耐腐蚀。 进口透明可溶性聚四氟乙烯方盘。可应用于成膜实验&#xff0c;样品液体脱漏等。能放在电热板上直接加热使用&#xff0c;也可以用于烘箱烘干&#xff0c;实验室腐蚀性样品的转移和搬运&#xff0c;防止腐蚀性液体洒落。 产品特性…

Python常用算法--解决数据结构问题【附源码】

一、约瑟夫环问题 解释:约瑟夫环(Josephus Problem)是一个著名的数学问题,它描述了一个关于围坐一圈的人进行游戏的场景。游戏规则是从一个人开始,顺序报数,每报到特定数目的人将会被排除出圈子,然后从被排除的下一人开始继续报数,游戏继续进行直到最后剩下一个人。 …

ETL工具-nifi干货系列 第九讲 处理器EvaluateJsonPath,根据JsonPath提取字段

1、其实这一节课本来按照计划一起学习RouteOnAttribute处理器&#xff08;相当于java中的ifelse&#xff0c;switch case 控制语句&#xff09;&#xff0c;但是在学习的过程中遇到了一些问题。RouteOnAttribute 需要依赖处理器EvaluateJsonPath&#xff0c;所以本节课我们一起…

如何确定螺栓的载荷和扭矩——SunTorque智能扭矩系统

智能扭矩系统-智能拧紧系统-扭矩自动控制系统-SunTorque 螺栓作为一种常见的紧固件&#xff0c;广泛应用于各种机械和设备中。正确确定螺栓的载荷及其扭矩对于确保设备的安全运行和延长其使用寿命至关重要。本文将探讨如何确定螺栓的载荷及其扭矩&#xff0c;帮助读者更好地理…

将excel,csv中合并块中某条记录的值应用到整个块(使用多行的值,来填充新列数据)。

背景描述 在excel中使用其它列的值&#xff0c;根据某种计算规则来填充另一列&#xff08;或新列&#xff09;很容易实现。但是如果需要根据合并块中的多行来填充列时&#xff0c;就不容易实现&#xff0c;由于对excel不是太常用&#xff0c;因此这里使用的命令行工具实现的。…

K8s学习三(Pod与探针)

深入学习Pod Pod配置文件 写一个自己的配置文件,nginx-po.yaml apiVersion: v1 #api文档版本 kind: Pod #资源类型对象&#xff0c;也可以配置为像Development&#xff0c;StatefulSet这一类的对象 metadata: # Pod相关的元数据&#xff0c;用于描述Pod的数据name: nginx-po…

4月7号总结

java学习 一.正则表达式 定义&#xff1a;正则表达式是一种用于描述字符串模式的表达式&#xff0c;通常被用于文本搜索、匹配和替换。它是一种强大的工具&#xff0c;可以在文本处理和文本分析中进行复杂的匹配和操作。 通过字符串引用里面的方法matches&#xff0c;然后执行…