STM32内置Flash

news2025/1/9 10:09:20

一、原理

 利用flash存储用户数据需要注意查看,用户数据是否会覆盖芯片运行程序。

IAP(在程序中编程)利用程序修改程序本身,和OTA是一个原理。IAP在程序中编程支持任意一种通信下载。

ICP(在电路中编程,通过外接引脚下载),每次下载会将程序完全更新。JTAG和SWD为仿真器下载程序,例如JLINK-JTAG和STLNIK-SWD。串口下载(手册中系统Bootload硬件有说明)使用的时系统存储器的Bootload。

 1、STM32的存储器映像

2、个人理解的Bootload原理

 3、STM32中容量产品闪存容量分布情况

可以看到的主存储器和信息块属于flash,闪存存储器不属于flash,相当于单独的外设。闪存存储器相当于上面信息块和主存储器的管理员,用于管理擦除和编程(读取flash直接进行指针读取即可,无需借用存储器)。

  1. STM32内部的flash只分成了页,起始地址为0x0800 0000,直到0x0801 FFFF,一共128K,每K一页,可以看到,以000、400、800、C00结尾的都是页起始地址。
  2. 系统存储区容量为2K,起始地址,存储系统Bootload内容。容量2K。
  3. 用户选项字节为16Byte,起始地址为0x1FFF F800 ,容量16Byte
  4. 用户选项字节和启动程序代码(系统存储区)也是flash,但是不计算在闪存容量中,闪存容量一般指程序存储区flash。
  5. 闪存存储器接口寄存器起始地址为0x4002 2000,属于外设,在外设存储区内

 

4、flash基本结构

5、flash擦除和编程详细内容

5.1、flash解锁

通过键寄存器写入指定的键值实现。RDPRT是解除读保护的密钥。将flash_cr重新置lock=1可锁住flash_cr。

5.2、使用指针访问存储器

volatile:

  1. 在c语言中表示易变的数据,防止编译器优化(编译器自动去除无用的繁杂代码)。
  2. STM32中有工作组寄存器,类似cache,工作速度快,但是使用的变量可能是程序中变量的映射。若程序为多线程或者中断,改变了此变量,会造成工作组寄存器和源变量值不一致,导致程序异常。通过volatile可以高速编译器变量需要实时注意是否更改。

通过*((__IO uint16_t *)(0x0800 0000))通过程序取出地址0x0800 0000地址的寄存器的数据,并通过uint16_t类型(可根据具体需求)返还。也可通过此形式直接指定指定地址的值。flash安全程度较高,需要提前解锁。若写入SRAM则不需要。

5.3、程序存储区编程

写入只能通过地址防止,进行半字的写入,一次2byte。写入32bit需要分两次,写入8bit可以先进行读出在使用读改写的方式写入。

5.4、程序存储区页擦除,flash写入前必须全擦除为1,只能写入0,不能写入1,根据手册的擦除最小单位进行。

5.5、全擦除

6、选项字节的组织和用途

可以看到表中,有数据和n数据,表示写入正常数据时要在对应的n位写入反码,这样才能够正常有效写入。 写入反码的过程,硬件会自动计算并写入。

WRP:配置flash程序存储区写保护,每位对应保护4个存储页,4*8*4 = 128页,刚好对应中容量的最大字节128K。

 

6.1 、选项字节编程

解锁flash锁后还需要解锁选项字节的锁(也需要先写入Key1,再写入Key2),之后才能操作选项字节。

6.2、选项字节擦除

 7、期间的电子签名

可以通过指定签名运行指定程序来限制程序被盗。 

8、手册

在SystemInit已经打开了HSI。

 

 

 

因为flash的原因,默认写保护使能为0,不使能写保护为1。

 

9、编程

在库文件.c的头部有说明,库中后期增加了XL加大容量的芯片,部分函数只能使用于加大容量的芯片。

9.1存储格式

  •  Intel存储格式为小端存储:即低字节在低地址,高字节在高地址。即L_Byte(低地址) +H_Byte(高地址) ,例如0x482A = 18594。小端存储为 0x48 0x2A。
intel格式(小端存储)bit
Byte10x2A(L_Byte)
76543210
20x48(H_Byte)
15141312111098
  • Motorola存储格式为大端存储:即高字节在低地址,低字节在高地址。即H_Byte(低地址) +L_Byte(高地址) ,例如0x482A = 18594。大端存储为 0x2A 0x48。
Motorola格式(大端存储)bit
Byte10x48(H_Byte)
15141312111098
20x2A(L_Byte)
76543210
  • 字节内部相同高bit在左,低bit在右。例如大端存储和小端字节内存储格式相同。
大端小端相同(bit位相同)
1514131211109876543210
0x48(H_Byte)0x2A(L_Byte)

 9.2为了区分程序存储空间和使用flash存储用户数据的空间大小,限制程序flash。

如果想写一个自定义的Bootload程序在尾部,也可以通过此处更改烧写程序的起始位置,但是要计算Bootload程序的大小、正式程序的大小,防止空间不足 。

右边是片上ram的内存。

9.3 下载配置,根据需要配置下载时如何擦除程序。使用IAP选择页擦除(STM32为扇区擦除选项)

前三个数为程序占用闪存的大小,后面两个相加为占用SRAM的大小。

目前可以看到我这个程序占用flash的大小为5.03KB=5150.72B,flash地址为0x0800 0000,偏移5148B,实际存储空间到0x0800 141C左右。

使用软件核实程序的确存储到了0x0800141C左右。

二、程序实例,STM32 ST-LINK Utility使用见主页文章

1、测试程序中的Flash基本操作单元的功能,flash页写入、flash读取、页擦除、全部擦除。(按键1用PB11、按键2用PB10)

1.1 测试1  (程序中#if (1))

1、程序烧写完成上电,查看OLED显示内容,是否为flash首地址的32bit、16bit、8bit(小端存储,低字节在低地址)

 

2、按下按键PB11可以看到和程序中相同flash程序存储区全部擦除,注意再次烧写程序时需要关闭STM32 ST-LINK Utility,防止冲突

3、重新烧写程序,按下按键PB12可以看到程序存储区中flash中0x0800 0400的页被删除,直到0x0800 0800(每个扇区1K),擦除后为FF

1.2、测试2 (程序中改#if (0))

可以看到0x0800FC00页地址原来的数据。

按下按键PB11或PB10,0x0800FC00和0x0800FC10所在地址的数据写为0x00000000(32bit)和0x0F0F(16bit)。

程序

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Button.h"
#include "MyFlash.h"
int main(void){
	OLED_Init();
	ButtonPB11PB10_Init();
	
	//测试程序存储区flash数据读取
	OLED_ShowString(1,1,"Flash:");//
	OLED_ShowHexNum(2,1,MyFlash_ReadWord(0x08000000),8);
	OLED_ShowHexNum(3,1,MyFlash_ReadHalfWord(0x08000000),4);
	OLED_ShowHexNum(4,1,MyFlash_ReadByte(0x08000000),2);
	
	
	while(1){
		#if (0)  //为真运行
		//测试程序存储区flash全部擦除和页擦除
		if(GetButtonPB11PB10() == 1){
			MyFlash_EraseAll();
		}else if(GetButtonPB11PB10() == 2){
			MyFlash_ErasePage(0x08000400);//擦除第二页数据
		}
		#else  //测试程序存储区flash写入字和半字
		if((GetButtonPB11PB10() == 1) || (GetButtonPB11PB10() == 2)){
			MyFlash_ErasePage(0x0800FC00);
			MyFlash_ProgramWord(0x0800FC00,0x00000000);//地址0x0800FC00写入半字0x00000000
			MyFlash_ProgramHalfWord(0x0800FC10,0x0F0F);//地址0x0800FC00写入半字0x0F0F
			OLED_ShowString(4,4,"W");
			Delay_ms(500);
			OLED_ShowString(4,4," ");
		}
		#endif
	}
	
	return 0;
}

MyFlash.c

#include "stm32f10x.h"                  // Device header
/*选项字节配置可通过外部的STM32 ST-Link Utility,用户自行使用选项字节容易出现问题*/

/**
  * @brief 读取Flash指定地址的字
  * @param  Address:32位地址
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
uint32_t MyFlash_ReadWord(uint32_t Address){
	//对于Address,通过(__IO uint32_t *)变为uint32_t类型数据的指针,通过*取该地址的值
	return *((__IO uint32_t *)(Address)) ;
}

/**
  * @brief 读取Flash指定地址的半字
  * @param  Address:32位地址
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
uint16_t MyFlash_ReadHalfWord(uint32_t Address){
	//对于Address,通过(__IO uint16_t *)变为uint16_t类型数据的指针,通过*取该地址的值返回
	return *((__IO uint16_t *)(Address)) ;//uint16_t *表示指向uint16_t数据的指针
}

/**
  * @brief 读取Flash指定地址的字
  * @param  Address:32位地址
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
uint8_t MyFlash_ReadByte(uint32_t Address){
	//对于Address,通过(__IO uint32_t *)变为uint32_t的指针,通过*取该地址的值
	return *((__IO uint8_t *)(Address)) ;
}

/**
  * @brief 程序存储区flash全部擦除
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void MyFlash_EraseAll(void){
	FLASH_Unlock();//程序存储区flash页编程解锁
	FLASH_EraseAllPages();//全部擦除
	FLASH_Lock();//程序存储区flash页编程关锁
}

/**
  * @brief 程序存储区flash页擦除
  * @param  Address:需要擦除的页地址
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void MyFlash_ErasePage(uint32_t PageAddress){
	FLASH_Unlock();//程序存储区flash页编程解锁
	FLASH_ErasePage(PageAddress);//全部擦除
	FLASH_Lock();//程序存储区flash页编程关锁
}


/**
  * @brief 程序存储区flash指定地址写字
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void MyFlash_ProgramWord(uint32_t Address,uint32_t WriteWord){
	FLASH_Unlock();//程序存储区flash页编程解锁
	FLASH_ProgramWord(Address,WriteWord);//指定地址写字
	FLASH_Lock();//程序存储区flash页编程关锁
}


/**
  * @brief 程序存储区flash指定地址写半字
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void MyFlash_ProgramHalfWord(uint32_t Address,uint16_t WriteWord){
	FLASH_Unlock();//程序存储区flash页编程解锁
	FLASH_ProgramHalfWord(Address,WriteWord);//指定地址写半字,写入32bit地址的低地址,STM32flash小端存储,低字节在低位
	FLASH_Lock();//程序存储区flash页编程关锁
}


MyFlash.h

#ifndef __MYFLASH_H
#define __MYFLASH_H
#include "stm32f10x.h"                  // Device header
uint32_t MyFlash_ReadWord(uint32_t Address);
uint16_t MyFlash_ReadHalfWord(uint32_t Address);
uint8_t MyFlash_ReadByte(uint32_t Address);
void MyFlash_EraseAll(void);
void MyFlash_ErasePage(uint32_t PageAddress);
void MyFlash_ProgramWord(uint32_t Address,uint32_t WriteWord);
void MyFlash_ProgramHalfWord(uint32_t Address,uint16_t WriteWord);

#endif

 Button.c

/**
  * @brief 初始化引脚PB11地开信号接收Button,用于辅助测试看门狗
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void ButtonPB11PB10_Init(void){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef  GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}


/**
  * @brief 获取PB11的Button是否按下
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
uint8_t GetButtonPB11PB10(void){
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == RESET){
		Delay_ms(10);
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == RESET);
		Delay_ms(10);
		return 1;
	}
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10) == RESET){
		Delay_ms(10);
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10) == RESET);
		Delay_ms(10);
		return 2;
	}
	return 0;
}

Button.h

#ifndef __BUTTON_H
#define __BUTTON_H
#include "stm32f10x.h"                  // Device header



uint8_t GetButtonPB11PB10(void);
void ButtonPB11PB10_Init(void);
#endif

2、 读写内部Flash,通过Flash最后一页内存进行数据存储(上电读取内容、按键更新并写入内容)(按键1用PB11、按键2用PB10)

测试方法:

1、烧写程序后可以看到程序持续运行,此时、OLED显示程序存储区flash的最后一页存储的8Byte数据,第一次使用为0x00000000,可以看到指定的flash第一次读写标志位0xA5A5和0x00等数据已写入。

2、按键PB10可以看到程序存储区flash最后一页存储的前5字节当前数据变为0x1111;0x2222;0x3333;0x4444;按键PB11可以看到数据会自增。

程序

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Button.h"
#include "Store.h"
int main(void){
	OLED_Init();
	ButtonPB11PB10_Init();
	Store_Init();
	
	//显示当前Flash最后一页的数据
	OLED_ShowString(1,1,"Flash:");//
	
	while(1){
		uint8_t Key_Num = GetButtonPB11PB10();
		//测试按键控制Flash数据更新
		if(Key_Num == 1){//PB11
			for(uint8_t i=1;i<5;i++){
				Store_Data[i]++;
			}
			Store_Write();
			Store_Read();
			OLED_ShowString(4,1,"PB11");
		}else if(Key_Num == 2){//PB10
			Store_Data[1] = 0x1111;
			Store_Data[2] = 0x2222;
			Store_Data[3] = 0x3333;
			Store_Data[4] = 0x4444;
			Store_Write();
			Store_Read();
			OLED_ShowString(4,1,"PB10");
		}
		
		//显示Flash数据
		OLED_ShowHexNum(2,1,Store_Data[1],4);
		OLED_ShowHexNum(2,6,Store_Data[2],4);
		OLED_ShowHexNum(3,1,Store_Data[3],4);
		OLED_ShowHexNum(3,6,Store_Data[4],4);
		
		
	}
	
	return 0;
}

Store.c

#include "stm32f10x.h"                  // Device header
#include "MyFlash.h"

#define STORE_START_ADDRESS 0x0800FC00 //写入页的起始地址
#define STORE_COUNT 512
#define STORE_FLAG  0xA5A5
uint16_t Store_Data[STORE_COUNT] = {STORE_FLAG,0};//用RAM对应存储Flash最后一页的数据

/**
	* @brief flash最后一页数据初始化,第一次使用的话默认为0x00
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void Store_Init(void){
	//对于存储过数据的Flash我们默认使用最后一页的起始地址16bit作为标志
	if(MyFlash_ReadHalfWord(STORE_START_ADDRESS) == STORE_FLAG){//若不是第一次使用,读出数据
		for(uint16_t i=0;i<STORE_COUNT;i++){
			Store_Data[i] = MyFlash_ReadHalfWord(STORE_START_ADDRESS+i*2);
		}
	}else{//若是第一次使用,写入0xA5A5标志位和剩余的0x00
		MyFlash_ErasePage(STORE_START_ADDRESS);//擦除最后一页
		for(uint16_t i=0;i<STORE_COUNT;i++){
			MyFlash_ProgramHalfWord(STORE_START_ADDRESS+i*2,Store_Data[i]);//写入
		}
	}
}

/**
  * @brief 将SAM的数据(Store_Data)写入flash最后一页
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void Store_Write(void){
	MyFlash_ErasePage(STORE_START_ADDRESS);//擦除最后一页
	for(uint16_t i=0;i<STORE_COUNT;i++){
		MyFlash_ProgramHalfWord(STORE_START_ADDRESS+i*2,Store_Data[i]);//写入
	}
}

/**
  * @brief 将Flash的数据读出到将SAM的数据(Store_Data)
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void Store_Read(void){
	for(uint16_t i=0;i<STORE_COUNT;i++){
		Store_Data[i] = MyFlash_ReadHalfWord(STORE_START_ADDRESS+i*2);
	}
}





Store.h

#ifndef __STORE_H
#define __STORE_H
#include "stm32f10x.h"                  // Device header

extern uint16_t Store_Data[];
void Store_Init(void);
void Store_Write(void);
void Store_Read(void);

#endif

Button.c

/**
  * @brief 初始化引脚PB11地开信号接收Button,用于辅助测试看门狗
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void ButtonPB11PB10_Init(void){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef  GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}


/**
  * @brief 获取PB11的Button是否按下
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
uint8_t GetButtonPB11PB10(void){
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == RESET){
		Delay_ms(10);
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == RESET);
		Delay_ms(10);
		return 1;
	}
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10) == RESET){
		Delay_ms(10);
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10) == RESET);
		Delay_ms(10);
		return 2;
	}
	return 0;
}

Button.h

#ifndef __BUTTON_H
#define __BUTTON_H
#include "stm32f10x.h"                  // Device header



uint8_t GetButtonPB11PB10(void);
void ButtonPB11PB10_Init(void);
#endif

 MyFlash.c

#include "stm32f10x.h"                  // Device header
/*选项字节配置可通过外部的STM32 ST-Link Utility,用户自行使用选项字节容易出现问题*/

/**
  * @brief 读取Flash指定地址的字
  * @param  Address:32位地址
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
uint32_t MyFlash_ReadWord(uint32_t Address){
	//对于Address,通过(__IO uint32_t *)变为uint32_t类型数据的指针,通过*取该地址的值
	return *((__IO uint32_t *)(Address)) ;
}

/**
  * @brief 读取Flash指定地址的半字
  * @param  Address:32位地址
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
uint16_t MyFlash_ReadHalfWord(uint32_t Address){
	//对于Address,通过(__IO uint16_t *)变为uint16_t类型数据的指针,通过*取该地址的值返回
	return *((__IO uint16_t *)(Address)) ;//uint16_t *表示指向uint16_t数据的指针
}

/**
  * @brief 读取Flash指定地址的字
  * @param  Address:32位地址
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
uint8_t MyFlash_ReadByte(uint32_t Address){
	//对于Address,通过(__IO uint32_t *)变为uint32_t的指针,通过*取该地址的值
	return *((__IO uint8_t *)(Address)) ;
}

/**
  * @brief 程序存储区flash全部擦除
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void MyFlash_EraseAll(void){
	FLASH_Unlock();//程序存储区flash页编程解锁
	FLASH_EraseAllPages();//全部擦除
	FLASH_Lock();//程序存储区flash页编程关锁
}

/**
  * @brief 程序存储区flash页擦除
  * @param  Address:需要擦除的页地址
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void MyFlash_ErasePage(uint32_t PageAddress){
	FLASH_Unlock();//程序存储区flash页编程解锁
	FLASH_ErasePage(PageAddress);//全部擦除
	FLASH_Lock();//程序存储区flash页编程关锁
}


/**
  * @brief 程序存储区flash指定地址写字
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void MyFlash_ProgramWord(uint32_t Address,uint32_t WriteWord){
	FLASH_Unlock();//程序存储区flash页编程解锁
	FLASH_ProgramWord(Address,WriteWord);//指定地址写字
	FLASH_Lock();//程序存储区flash页编程关锁
}


/**
  * @brief 程序存储区flash指定地址写半字
  * @param  
  *     @arg 
  * @param  
  *     @arg 
  * @retval None
  */
void MyFlash_ProgramHalfWord(uint32_t Address,uint16_t WriteWord){
	FLASH_Unlock();//程序存储区flash页编程解锁
	FLASH_ProgramHalfWord(Address,WriteWord);//指定地址写半字,写入32bit地址的低地址,STM32flash小端存储,低字节在低位
	FLASH_Lock();//程序存储区flash页编程关锁
}


 MyFlash.h

#ifndef __MYFLASH_H
#define __MYFLASH_H
#include "stm32f10x.h"                  // Device header
uint32_t MyFlash_ReadWord(uint32_t Address);
uint16_t MyFlash_ReadHalfWord(uint32_t Address);
uint8_t MyFlash_ReadByte(uint32_t Address);
void MyFlash_EraseAll(void);
void MyFlash_ErasePage(uint32_t PageAddress);
void MyFlash_ProgramWord(uint32_t Address,uint32_t WriteWord);
void MyFlash_ProgramHalfWord(uint32_t Address,uint16_t WriteWord);

#endif

3、读写芯片ID

读取STM32指定地址下的原厂id号,和容量。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
int main(void){
	OLED_Init();
	
	//显示当前Flash最后一页的数据
	OLED_ShowString(1,1,"F_Size:");//
	OLED_ShowHexNum(1,8,*((__IO uint16_t *)(0x1FFFF7E0)),4);//我的芯片显示0x80-Flash容量128kB
	
	
	OLED_ShowString(2,1,"UID:");//
	OLED_ShowHexNum(2,5,*((__IO uint16_t *)(0x1FFFF7E8+0x02)),4);
	OLED_ShowHexNum(2,9,*((__IO uint16_t *)(0x1FFFF7E8)),4);

	OLED_ShowHexNum(3,1,*((__IO uint32_t *)(0x1FFFF7E8+0x04)),8);
	OLED_ShowHexNum(4,1,*((__IO uint32_t *)(0x1FFFF7E8+0x08)),8);
	while(1){
		
		
	}
	
	return 0;
}

感谢江协科技!!!

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

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

相关文章

两种方式实现Kepware与PLC之间的心跳检测

两种方式实现Kepware与PLC之间的心跳检测 实现Kepware与PLC之间的心跳检测1.OPCUA 外挂程序2.Kepware Advanced Tag 实现Kepware与PLC之间的心跳检测 1.OPCUA 外挂程序 这是通过上位程序来触发心跳的一种机制&#xff0c;在C#中&#xff0c;可以利用OPC UAOPCAutodll的方式…

英伟达Project Digits赋能医疗大模型:创新应用与未来展望

英伟达Project Digits赋能医疗大模型&#xff1a;创新应用与未来展望 一、引言 1.1 研究背景与意义 在当今数字化时代&#xff0c;医疗行业作为关乎国计民生的关键领域&#xff0c;正面临着前所未有的挑战与机遇。一方面&#xff0c;传统医疗模式在应对海量医疗数据的处理、复…

中国省级产业结构高级化及合理化数据测算(2000-2023年)

一、数据介绍 数据名称&#xff1a;中国省级产业结构高级化、泰尔指数 数据年份&#xff1a;2000-2023年 数据范围&#xff1a;31个省份 数据来源&#xff1a;中国统计年鉴、国家统计局 数据整理&#xff1a;内含原始版本、线性插值版本、ARIMA填补版本 数据说明&#xf…

关于Mac使用VSCode连接虚拟机

1. 下载插件 输入Remote - SSH下载下图两个插件。 2. 配置虚拟机信息 按图示步骤点击完成后&#xff0c;进入到虚拟主机的配置页面。 其中Host可以自定义主机名&#xff0c;HostName是虚拟机ip&#xff0c;可以通过ifconfig eth0查看ip&#xff0c;User是虚拟机的用户名。…

GOGOGO 接口

低高耦合?【程序中追求低耦合,所以接口广用】 低耦合:关联依赖性弱(你走了我还在) 高耦合:关联依赖性强(牵一发而动全身) 接口 概念:多个抽象方法的集合,只有结构无具体实现,并交给实现类完成功能操作【接口写功能,实现类写具体实现】 语法结构: 定义接口的关…

nginx反向代理+缓存

1、nginx-LB配置页面缓存 [rootOldboy conf]# vi nginx.conf http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;include proxy.conf; …

React中的合成事件

合成事件与原生事件 区别&#xff1a; 1. 命名不一样&#xff0c;原生用纯小写方式&#xff0c;react用小驼峰的方式 原生&#xff1a;onclick React的&#xff1a;onClick 2. 事件处理函数的写法不一样 原生的是传入一个字符串&#xff0c;react写法传入一个回调函数 3.…

智能安全帽_4G/5G智能安全帽主板方案定制开发

智能安全帽是一种先进的安全防护设备&#xff0c;主要以视频和语音通话为功能&#xff0c;能够全面记录施工现场的作业情况&#xff0c;并支持管理人员与现场工作人员之间的双向语音通话。这一创新设计使得项目管理人员能够实时、有效地掌握施工过程中的安全和质量情况。 这款智…

uni-app图文列表到详情页面切换

需求&#xff1a;参考若依框架后&#xff0c;想实现首页浏览文章列表&#xff0c;没有合适的样式参考&#xff0c;所以需要有效果做到“图文列表到详情页面切换”&#xff0c;查阅了一下案例 发现有相应的案例&#xff0c;在导航栏“模板”中找到了 DCloud 插件市场 PC电脑端访…

MySQL安装,配置教程

一、Linux在线yum仓库安装 打开MySQL官方首页&#xff0c;链接为&#xff1a;https://www.mysql.com/ 界面如下&#xff1a; 在该页面中找到【DOWNOADS】选项卡&#xff0c;点击进入下载页面。 在下载界面中&#xff0c;可以看到不同版本的下载链接&#xff0c;这里选择【My…

【项目】修改远程仓库地址、报错jdk

一、修改远程仓库地址 进入你刚刚克隆到本地的仓库目录&#xff0c;执行以下命令来修改远程仓库的 URL&#xff0c;将其指向你自己的新仓库&#xff1a; cd 原仓库名 git remote set-url origin <你自己的新仓库的 Git 地址>补充&#xff1a; 错误分析&#xff1a; wa…

进阶篇-Day17:JAVA的日志、枚举、类加载器、反射等介绍】

目录 1、日志1.1 日志概念1.2 日志框架&#xff08;1&#xff09; Logback框架&#xff1a;&#xff08;2&#xff09;配置文件介绍&#xff1a; 2、枚举3、类加载器3.1 类加载器的介绍3.2 类加载器的加载过程&#xff1a;加载、链接、初始化3.3 类加载器的分类3.4 双亲委派模式…

GPU算力平台的应用之任意门:任意穿搭匹配模型的应用教程

大家好&#xff0c;今天给大家介绍一下&#xff1a;GPU算力平台的应用之任意门:任意穿搭匹配模型的应用教程。 文章目录 一、GPU算力平台概述人工智能智能发展为什么需要GPU算力平台 二、注册与登录账号注册流程 三、平台的应用之Anydoor应用启动器选择Anydoor的应用场景Anydoo…

阿里云代理商热销产品推荐

在数字化浪潮的推动下&#xff0c;企业对于云计算的依赖日益加深。阿里云&#xff0c;作为中国领先的云计算服务提供商&#xff0c;为企业提供了丰富多样的云产品和服务。本文将聚焦于阿里云代理商热销产品推荐&#xff0c;探讨其如何帮助企业高效利用云资源&#xff0c;加速数…

漏洞扫描工具

完整源码项目包获取→点击文章末尾名片&#xff01; 漏洞检测 该模块主要是对目标Web系统进行安全漏洞扫描&#xff0c;包括SQL注入、跨站脚本攻击&#xff08;XSS&#xff09;、弱密码、中间件漏洞。中间件漏洞扫描包括对Weblogic、Struts2、Tomcat 、Jboss、Drupal、Nexus的已…

SAP 销售确认收入的科目确定是由什么确定的?以及如何后台配置

财务同事问我&#xff0c;对销售单进行销售收入时确定收入科目是否是关联公司科目&#xff0c;我想当然的认为是由于客户主数据的贸易伙伴来决定的。后来查了一下配置&#xff0c;发现我搞错了。原来是通过客户的账号组来确定的。 然后我查了一下资料。分享如下&#xff1a; …

Kafka运维指南

一、Kafka架构概述 Kafka是一种分布式消息队列系统&#xff0c;采用发布 - 订阅模式&#xff0c;主要由生产者&#xff08;Producer&#xff09;、消费者&#xff08;Consumer&#xff09;、代理&#xff08;Broker&#xff09;和Zookeeper组成。 生产者&#xff1a;负责向Kaf…

Hadoop 实战笔记(一) -- Windows 安装 Hadoop 3.x

环境准备 安装 JAVA 1.8 Java环境搭建之JDK下载及安装下载 Hadoop 3.3.5 安装包 Hadoop 下载&#xff1a;https://archive.apache.org/dist/hadoop/common/ 一、JAVA JDK 环境检查 二、Hadoop(HDFS)环境搭建 1. 解压安装文件 hadoop-3.3.5.tar 2. 配置环境变量 HADOOP_HO…

Vscode辅助编码AI神器continue插件

案例效果 1、安装或者更新vscode 有些版本的vscode不支持continue,最好更新到最新版,也可以直接官网下载 https://code.visualstudio.com/Download 2、安装continue插件 搜索continue,还未安装的,右下脚有个Install,点击安装即可 <

rabbitmq——岁月云实战笔记

1 rabbitmq设计 生产者并不是直接将消息投递到queue,而是发送给exchange,由exchange根据type的规则来选定投递的queue,这样消息设计在生产者和消费者就实现解耦。 rabbitmq会给没有type预定义一些exchage,而实际我们却应该使用自己定义的。 1.1 用户注册设计 用户在…