读写内部闪存FLASH读取芯片ID

news2024/11/15 11:32:41

读写内部闪存FLASH

右下角是OLED,然后左上角在PB1和PB11两个引脚,插上两个按键用于控制。下一个代码读取芯片ID,这个也是接上一个OLED,能显示测试数据就可以了。
在这里插入图片描述

STM32-STLINK Utility

在这里插入图片描述
本节的代码调试,使用辅助软件STM32-STLINK Utility,在使用之前我们需要用stink把STM32连接好,然后我们点击这个按钮连接,可以看到下面这个窗口里显示的,就是闪存里面存储的数据了。这个软件可以直接修改闪存里的数据,可以修改选项字节数据,不用写任何代码,非常方便。

Address:可以指定想要查看的起始地址,目前是0x0800 0000,也就是整个闪存的起始地址。
Size:就是从起始地址开始,总共查看多少个字节,目前0x10000,就是查看64KB的字节数
Data Width:数据宽度,可以指定以32位/16位/8位的形式显示,分别对应,字/半字/字节。

16位
在这里插入图片描述
8位
在这里插入图片描述
闪存的操作:

第一步,读取数据,直接封装一下uint16_t Data = *((__IO uint16_t *)(0x08000000));
第二步,擦除:全擦除或页擦除,这两个功能分别对应一个库函数。执行之前,手动调用,解锁;执行之后,在加锁。
第三步,编程,有对应库函数直接调用。执行之前,手动调用,解锁;执行之后,在加锁。

选项字节的擦除和编成与主闪存的擦除和编程类似,有对应的函数。

在这里插入图片描述

用代码配置读写保护,容易造成芯片自锁,如把闪存写保护了,但程序里并没有预留解除写保护的代码,这样锁住之后,芯片就没法下载程序。但还可以再软件里自救,在这个选项字节配置里,把读写保护去掉,再Apply就能救活芯片了。

flash.h库函数

在这里插入图片描述

在这里插入图片描述
FLASH_Status返回值,是这个操作的完成状态,函数返回状态功能:返回第一个,表示芯片当前忙;返回第二个,表示编程错误;返回第三个,表示写保护错误;返回第四个,表示返回完成;返回第五个,表示等待超时。

//这三个是内核相关,不用过多了解与调用
void FLASH_SetLatency(uint32_t FLASH_Latency);
void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess);
void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer);
//加锁解锁
void FLASH_Unlock(void);//解锁
void FLASH_Lock(void);//加锁,把CR寄存器LOCK位置1
//主闪存
FLASH_Status FLASH_ErasePage(uint32_t Page_Address); //闪存擦除某一页
FLASH_Status FLASH_EraseAllPages(void);//全擦除
FLASH_Status FLASH_EraseOptionBytes(void);//擦除选项字节

FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);//在指定地址,写入字
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);//在指定地址,写入半字

//选项字节的写入
FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);//自定义的Data0和Data1
FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);//写保护
FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);//读保护
FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY);//用户选项的3个配置位

//获取选项字节当前状态
uint32_t FLASH_GetUserOptionByte(void);//获取用户选项的三个配置位
uint32_t FLASH_GetWriteProtectionOptionByte(void);//获取写保护状态
FlagStatus FLASH_GetReadOutProtectionStatus(void);//获取读保护状态  
............................//获取自定义的Data0和Data1没有给现成函数,直接指针访问就可以了。

FlagStatus FLASH_GetPrefetchBufferStatus(void);//获取预取缓冲区状态 不用了解
void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState);//中断使能
FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG);//获取标志位
void FLASH_ClearFlag(uint32_t FLASH_FLAG);//清除标志位
FLASH_Status FLASH_GetStatus(void);//获取状态
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);//等待上一次操作 等待忙等待BSY为0(上面主闪存这些函数内部已经实现等待忙操作了,此函数不用我们单独调用)

注意:使用完STLINK这个软件,要及时断开连接,要不然设备占用,keil下载出错。

在Store模块,要有SRAM缓存数组来管理FLASH的最后一页,实现参数任意读写和保存

MyFLASH.c

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:FLASH读取一个32位的字
  * 参    数:Address 要读取数据的字地址
  * 返 回 值:指定地址下的数据
  */
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
	return *((__IO uint32_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH读取一个16位的半字
  * 参    数:Address 要读取数据的半字地址
  * 返 回 值:指定地址下的数据
  */
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{
	return *((__IO uint16_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH读取一个8位的字节
  * 参    数:Address 要读取数据的字节地址
  * 返 回 值:指定地址下的数据
  */
uint8_t MyFLASH_ReadByte(uint32_t Address)
{
	return *((__IO uint8_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH全擦除
  * 参    数:无
  * 返 回 值:无
  * 说    明:调用此函数后,FLASH的所有页都会被擦除,包括程序文件本身,擦除后,程序将不复存在
  */
void MyFLASH_EraseAllPages(void)
{
	FLASH_Unlock();					//解锁
	FLASH_EraseAllPages();			//全擦除
	FLASH_Lock();					//加锁
}

/**
  * 函    数:FLASH页擦除
  * 参    数:PageAddress 要擦除页的页地址
  * 返 回 值:无
  */
void MyFLASH_ErasePage(uint32_t PageAddress)
{
	FLASH_Unlock();					//解锁
	FLASH_ErasePage(PageAddress);	//页擦除
	FLASH_Lock();					//加锁
}

/**
  * 函    数:FLASH编程字
  * 参    数:Address 要写入数据的字地址
  * 参    数:Data 要写入的32位数据
  * 返 回 值:无
  */
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
	FLASH_Unlock();							//解锁
	FLASH_ProgramWord(Address, Data);		//编程字
	FLASH_Lock();							//加锁
}

/**
  * 函    数:FLASH编程半字
  * 参    数:Address 要写入数据的半字地址
  * 参    数:Data 要写入的16位数据
  * 返 回 值:无
  */
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
	FLASH_Unlock();							//解锁
	FLASH_ProgramHalfWord(Address, Data);	//编程半字
	FLASH_Lock();							//加锁
}

MyFLASH.h

#ifndef __MYFLASH_H
#define __MYFLASH_H

uint32_t MyFLASH_ReadWord(uint32_t Address);
uint16_t MyFLASH_ReadHalfWord(uint32_t Address);
uint8_t MyFLASH_ReadByte(uint32_t Address);

void MyFLASH_EraseAllPages(void);
void MyFLASH_ErasePage(uint32_t PageAddress);

void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data);
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);

#endif

Store.c

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

#define STORE_START_ADDRESS		0x0800FC00		//宏定义,存储的起始地址  (闪存的最后一页)
#define STORE_COUNT				512				//宏定义,存储数据的个数

uint16_t Store_Data[STORE_COUNT];				//定义SRAM数组

/**
  * 函    数:参数存储模块初始化    
  * 参    数:无
  * 返 回 值:无
  */
  void Store_Init(void)      //第一大步,第一次使用的时候,对闪存进行初始化
{
	/*判断是不是第一次使用*/
	if (MyFLASH_ReadHalfWord(STORE_START_ADDRESS) != 0xA5A5)	//读取第一个半字的标志位,if成立,则执行第一次使用的初始化
	{
		MyFLASH_ErasePage(STORE_START_ADDRESS);					//擦除指定页
		MyFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5);	//在第一个半字写入自己规定的标志位,用于判断是不是第一次使用
		
		//把剩余的存储空间,全都置为默认值0
		for (uint16_t i = 1; i < STORE_COUNT; i ++)				//循环STORE_COUNT次,除了第一个标志位。注意;要从1开始,而不是0,因为第一个半字是标志位,剩下的才是有效数据
		{
			MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, 0x0000);		//除了标志位的有效数据全部清0。注:因为一个半字要占用两个地址,所以i要乘2
		}
	}
	
	/*第2大步,上电时,将闪存数据加载回SRAM数组,就是上电时恢复数据,实现SRAM数组的掉电不丢失*/
	for (uint16_t i = 0; i < STORE_COUNT; i ++)					//循环STORE_COUNT次,包括第一个标志位
	{
		Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i * 2);		//将闪存的数据加载回SRAM数组
	}
}

/**
  * 函    数:参数存储模块保存数据到闪存
  * 参    数:无
  * 返 回 值:无
  */
void Store_Save(void)  //备份保存
{
	MyFLASH_ErasePage(STORE_START_ADDRESS);				//擦除指定页
	for (uint16_t i = 0; i < STORE_COUNT; i ++)			//循环STORE_COUNT次,包括第一个标志位
	{
		MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, Store_Data[i]);	//将SRAM数组的数据,备份保存到闪存
	}
}

/**
  * 函    数:参数存储模块将所有有效数据清0
  * 参    数:无
  * 返 回 值:无
  */
void Store_Clear(void)
{
	for (uint16_t i = 1; i < STORE_COUNT; i ++)			//循环STORE_COUNT次,除了第一个标志位。注:i要从1开始,不用把标志位清0
	{
		Store_Data[i] = 0x0000;							//SRAM数组有效数据清0
	}
	Store_Save();										//更新保存数据到闪存。每次修改完数组后,都要Store_Save();保证数值和闪存数据一样;如果不Save,那下次上电,加载的是以前保存的数据
}

Store.h

#ifndef __STORE_H
#define __STORE_H

extern uint16_t Store_Data[];

void Store_Init(void);
void Store_Save(void);
void Store_Clear(void);

#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Store.h"
#include "Key.h"

uint8_t KeyNum;					//定义用于接收按键键码的变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();				//OLED初始化
	Key_Init();					//按键初始化
	Store_Init();				//参数存储模块初始化,在上电的时候将闪存的数据加载回Store_Data,实现掉电不丢失
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Flag:");
	OLED_ShowString(2, 1, "Data:");
	
	while (1)
	{
		KeyNum = Key_GetNum();		//获取按键键码
		
		if (KeyNum == 1)			//按键1按下
		{
			Store_Data[1] ++;		//变换测试数据
			Store_Data[2] += 2;
			Store_Data[3] += 3;
			Store_Data[4] += 4;
			Store_Save();			//将Store_Data的数据备份保存到闪存,实现掉电不丢失
		}
		
		if (KeyNum == 2)			//按键2按下
		{
			Store_Clear();			//将Store_Data的数据全部清0
		}
		
		OLED_ShowHexNum(1, 6, Store_Data[0], 4);	//显示Store_Data的第一位标志位
		OLED_ShowHexNum(3, 1, Store_Data[1], 4);	//显示Store_Data的有效存储数据
		OLED_ShowHexNum(3, 6, Store_Data[2], 4);    //3行6列显示Store_Data[2],长度为4
		OLED_ShowHexNum(4, 1, Store_Data[3], 4);
		OLED_ShowHexNum(4, 6, Store_Data[4], 4);
	}
}

程序现象
Flag显示标志位:A5A5,这是之前保存的。按下Key2,可以去清0所以参数;按下Key1,可以变换测试数据,之后断定在重新上电,数据保持原样,按复位键,数据也不会丢失。
在这里插入图片描述
按下Key2,可以去清0所以参数
在这里插入图片描述
按下Key1,可以变换测试数据
在这里插入图片描述

前面一部分存储的是程序文件,最后一页存储的是用户数据,目前我们的假设是程序文件比较小,最后一页肯定是没有用到的,所以我们放心的使用最后一页,但是如果程序比较大,触及到了最后一页,那程序和用户数据存储的位置就冲突了,或者说如果你参数非常多,最后10页很大一部分都是留着存储用户数据的,这样如果前面的程序文件长一些,那样非常容易和用户数据冲突,并且这种冲突如果没发现,就会产生非常隐蔽的bug,那如何解决这个问题呢,这时我们可以给程序文件限定一个存储范围,不让它分配到后面我们用户数据的空间来。

在这里插入图片描述

这就是编译器,给各个数据分配的空间地址和范围了。如,片上的ROM,起始地址是0800 0000,注意,最高位的0省略了。它的Size:是0x10000,默认全部的64k闪存,都是程序代码分配的空间 ,

如果你想把闪存的尾部空间留着自己用,那可以把这个程序空间的size改小点,比如我们改成0XFC00,这样编译后的代码,无论如何也不会分配到最后一页了。如果Size过小,那编译的时候也会报错。

所以如果你计划把闪存尾部的很多空间都留着自己用,那就把这个程序代码的空间改小点,以免冲突。然后这个下载程序的起始地址也可以改,比如你想写个BOOTLOADER程序放在闪存尾部,那可以在这里修改下载到闪存的起始位置。

在这里插入图片描述

最右边这里是片上RAM的起始地址和大小,2000开始大小5000对应就是20K。

在这里插入图片描述

这里debug, settings,Flash download,在这里是配置下载选项,其中这个选项我们要选择第二个,擦除扇区,也就是页擦除。
第一个是,每次下载代码都全擦除再下载。
第二个是用到多少页,就擦多少页这个下载速度更快一些,如果你想在闪存尾部存储数据,那也最好选择页擦除的下载,要不然每次下载程序芯片都全擦除了。

在这里插入图片描述

程序编译之后,到底占用了多大的空间,我们可以全部编一下,在下面有一行信息就显示了Program Size,程序大小,其中有四个数,这四个数分别是什么意思,感兴趣的话可以网上搜索。
这里只需要记住,前三个数相加,得到的就是程序占用闪存的大小,后两个数相加,得到的是占用SRAM的大小。

在这里插入图片描述

这个程序大小,也可以在Target1这里(工程目录最上面)双击,会打开一个.map文件,这就是详细的编译信息。这个.map文件看完就删掉,要不然每次编译后,都会弹出窗口问你是不是要重新加载。

我们看最后面这里也有写程序的大小,并且有计算结果:
倒数第二行,是占用SRAM的大小,这里结果是2664字节,2.6kb,最后一行,是占用闪存的大小,这里是4576字节,4.47kb。

在这里插入图片描述

下载到STM32里,验证一下。可以看到,程序在0x0800 11E0地址终止,用计算机转换:16进制 11E0就是10进制的4576。观察的数据和编译的结果相符,没问题。

读取芯片ID

复制OLED的工程。

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"

int main(void)
{
	OLED_Init();						//OLED初始化
	
	OLED_ShowString(1, 1, "F_SIZE:");	//显示静态字符串
	OLED_ShowHexNum(1, 8, *((__IO uint16_t *)(0x1FFFF7E0)), 4);		//使用指针读取指定地址下的闪存容量寄存器
	
	OLED_ShowString(2, 1, "U_ID:");		//显示静态字符串
	OLED_ShowHexNum(2, 6, *((__IO uint16_t *)(0x1FFFF7E8)), 4);		//使用指针读取指定地址下的产品唯一身份标识寄存器
	OLED_ShowHexNum(2, 11, *((__IO uint16_t *)(0x1FFFF7E8 + 0x02)), 4);  //第2次读是,基地址+0x02地址偏移
	OLED_ShowHexNum(3, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x04)), 8);
	OLED_ShowHexNum(4, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x08)), 8);
	
	while (1)
	{
		
	}
}

程序现象
在这里插入图片描述
ID号对不对,可以用软件来验证。

在这里插入图片描述

手册

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

什么是云服务器镜像,如何选择?

云服务器镜像是一种用于业务连续性、灾难恢复和备份的技术手段&#xff0c;其本质是云端创建的服务器数据副本。 这些镜像内容可以涵盖系统、光盘、软件、网站甚至整个服务器&#xff0c;主要用于创建容错和冗余服务器计算基础架构&#xff0c;为用户提供了一个方便且可靠的解…

银河麒麟桌面操作系统V10SP1【FTP服务器】配置手册

简介: FTP是一个文件传输协议,主要是在互联网上提供文件储存和访问服务的计算机,一个FTP服务器可以对多个客户端提供服务。本文主要介绍在银河麒麟桌面操作系统V10SP1上如何搭建FTP服务器以及在客户端如何访问FTP服务器的操作方法。 正文: 一、操作环境 服务端:银河麒…

推荐系统(LLM去偏?) | (WSDM24)预训练推荐系统:因果去偏视角

::: 大家好&#xff01;今天我分享的文章是来自威斯康星大学麦迪逊分校和亚马逊AWS AI实验室的最新工作&#xff0c;文章所属领域是推荐系统和因果推理&#xff0c;作者针对跨域推荐中的偏差问题提出了一种基于因果去偏的预训练推荐系统框架PreRec。 ::: 原文&#xff1a;Pre-t…

logstash配置文件中明文密码加密

1 案例背景 应用配置文件中禁止使用明文密码&#xff0c;需要加密处理 上图中&#xff0c;红框打码位置为es的明文密码&#xff0c;需要对其进行处理 2 创健keystore文件 /rpa/logstash/bin/logstash-keystore --path.settings /rpa/isa/conf/logstash/ create 注&#xff1…

3d渲染软件有哪些(2),渲染100邀请码1a12

3D渲染软件有很多&#xff0c;上次我们介绍了几个&#xff0c;这次我们接着介绍。 1、Arnold Arnold渲染器是一款基于物理算法的电影级渲染引擎&#xff0c;它具有渲染质量高、材质系统丰富、渲染速度快等特点&#xff0c;是3D设计师的极佳选择。2、Octane Render Octane Ren…

一文详解:什么是企业邮箱?最全百科

什么是企业邮箱&#xff1f;企业邮箱即绑定企业自有域名作为邮箱后缀的邮箱&#xff0c;是企业用于内部成员沟通和客户沟通的邮箱系统。 一、企业邮箱概念拆解 1.什么是企业邮箱&#xff1f; 企业邮箱即使用企业域名作为后缀的邮箱系统。它不仅提供专业的电子邮件收发功能&a…

JFreeChart 生成Word图表

文章目录 1 思路1.1 概述1.2 支持的图表类型1.3 特性 2 准备模板3 导入依赖4 图表生成工具类 ChartWithChineseExample步骤 1: 准备字体文件步骤 2: 注册字体到FontFactory步骤 3: 设置图表具体位置的字体柱状图&#xff1a;饼图&#xff1a;折线图&#xff1a;完整代码&#x…

韩顺平0基础学java——第30天

p600-611 坦克大战&#xff01; 艰难推进中 坦克大战-子弹 发射子弹 1.当发射一颗子弹后&#xff0c;就相当于启动一个线程 2.玩家拥有子弹对象&#xff0c;当按下J时&#xff0c;就启动发射行为&#xff08;线程&#xff09;&#xff0c;让子弹不停移动&#xff0c;形成…

Ubuntu20.04安装python2和python3及版本配置

Ubuntu20.04安装python2和python3及版本配置_ubuntu 20.04 python3-CSDN博客https://blog.csdn.net/pangc2014/article/details/117407413 >>>ubuntu 安装源码python2_mob649e8161c39d的技术博客_51CTO博客https://blog.51cto.com/u_16175489/7327966

让python的报错代码只显示第一层

在 Python 中&#xff0c;sys.tracebacklimit 是 sys 模块中的一个属性&#xff0c;它用于控制在错误发生时&#xff0c;Python 解释器显示的堆栈追踪&#xff08;traceback&#xff09;的深度。 具体来说&#xff1a; • 默认行为&#xff1a;当出现未处理的异常时&#xff…

华为OD机试 - 掌握单词个数(Java 2024 D卷 100分)

华为OD机试 2024D卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;D卷C卷A卷B卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测…

Spark运行spark-shell与hive运行时均报错的一种解决方案

环境按照尚硅谷的配置的。 在运行hive的时候&#xff0c;报错代码为30041&#xff0c;无法执行insert语句。 在运行spark-shell的时候&#xff0c;报错&#xff0c;无法进入到shell脚本中。 可能的问题&#xff1a; 对集群设置的域名与集群的主机名称不一致。 例如&#xff1a;…

C#之Delta并联机械手的视觉相机标定与形状匹配

本文导读 上节课程我们讲述了如何建立Delta并联机械手正逆解&#xff0c;本节课程我们主要讲解如何通过C#语言开发正运动Delta并联机械手视觉流水线同步分拣的视觉部分。 VPLC711硬件介绍 VPLC711是正运动推出的一款基于x86平台和Windows操作系统的高性能机器视觉EtherCAT运…

75. UE5 RPG 创建场景摆放部件蓝图

这一篇文章来点简单的内容&#xff0c;相当于我们使用蓝图创建类似于unity的预制体。 创建一个一个柱子蓝图 首先&#xff0c;我们创建一个立柱的蓝图&#xff0c;将我们之前创建的柱子上面含有火焰和灯光的部分合并成一个蓝图&#xff0c;方便往场景内添加。 点击创建一个基…

Docker系列之安全

Docker的安全前言一、Docker 容器与虚拟机的区别 1. 隔离与共享 2. 性能与损耗二、Docker 存在的安全问题 1.Docker 自身漏洞 2.Docker 源码问题三、 Docker 架构缺陷与安全机制 1. 容器之间的局域网攻击 2. DDoS 攻击耗尽资源 3. 有漏…

ACL 2023事件相关(事件抽取、事件关系抽取、事件预测等)论文汇总

ACL 2023事件抽取相关(事件抽取、事件关系抽取、事件预测等)论文汇总&#xff0c;后续会更新全部的论文讲解。 Event Extraction Code4Struct: Code Generation for Few-Shot Event Structure Prediction 数据集&#xff1a;ACE 2005 动机&#xff1a;与自然语言相比&#xf…

利用maven命令往本地仓库添加jar包

一&#xff1a;遇到问题 有些jar包在中央仓库没有&#xff0c;需要手动往本地仓库添加&#xff0c;方便以后打包使用。 比如&#xff1a;添加红框这个依赖&#xff0c;现在爆红 二&#xff1a;解决办法 **第一步&#xff1a;**打开idea&#xff0c;找到运行按钮旁边的框&am…

Android集成高德地图SDK(2)

1.解压下载的压缩包&#xff0c;找到AMap_Android_SDK_All\AMap3DMap_DemoDocs\AMap_Android_API_3DMap_Demo\AMap3DDemo\app\libs&#xff0c;复制libs里的所有文件&#xff0c;将其粘贴到Android工程的libs目录下&#xff0c;如图所示。 2.打开app下的build.gradle&#xff0…

无忧易售升级:一键设置图片分辨率,赋能十大跨境电商平台

在电商领域&#xff0c;产品图片的品质直接影响着顾客的购买决策与品牌形象的塑造。无忧易售ERP特推出图片分辨率修改功能&#xff0c;为电商卖家们提供更专业的图像优化工具&#xff0c;让每一像素都成为吸引客户的秘密武器&#xff01; 一、Allegro、OZON、Coupang、Cdiscou…

数据分析python基础实战分析

数据分析python基础实战分析 安装python&#xff0c;建议安装Anaconda 【Anaconda下载链接】https://repo.anaconda.com/archive/ 记得勾选上这个框框 安装完后&#xff0c;然后把这两个框框给取消掉再点完成 在电脑搜索框输入"Jupyter"&#xff0c;牛马启动&am…