STM32F103——基础篇

目录

1、寄存器基础知识

2、STM32F103系统架构

2.1 Cortex M3 内核&芯片

2.2 STM32F103系统架构

3、存储器映射

4、寄存器映射

4.1 寄存器描述解读

4.2 寄存器映射举例

4.3 寄存器地址计算 

4.4 stm32f103xe.h 寄存器映射


1、寄存器基础知识

概念:寄存器(Register)是单片机内部一种特殊的内存,它可以实现对单片机各个功能的控制。简单的来说可以把寄存器当成一些控制开关,控制包括内核及外设的各种状态。所以无论是51单片机还是 STM32,都需要用寄存器来实现各种控制,以完成不同的功能。

由于寄存器资源非常宝贵,一般都是一个位或者几个位控制一个功能, 对于 STM32 来说,其寄存器是 32 位的,一个 32 位的寄存器,可能会有 32 个控制功能,相当于 32 个开关,由于 STM32 的复杂性,它内部有几百个寄存器,所以整体来说 STM32 的寄存器还是比较复杂的。不过,千万不要被其吓到了,实际上 STM32 是由于内部有很多外设,所以导致寄存器很多,实际上已经把它分好类,每个外设也就那么几个或者几十个寄存器,学起来就不难了。

从大方向来区分,STM32 寄存器分为两类,如下图:

 注意:其中,内核寄存器,我们一般只需要关心中断控制寄存器和 SysTick 寄存器即可,其他三大类,我们一般很少直接接触。而外设寄存器,则是学到哪个外设,就了解哪个外设相关寄存器即可,所以整体来说,需要关心的寄存器并不是很多,而且很多都是有共性的,比如STM32F103ZET6 有 8 个定时器,我们只需要学习了其中一个的相关寄存器,其他 7 个基本都是一样。

经过上面一波了解之后,再给大家举个简单的例子, 我们知道寄存器的本质是一个特殊的内存,对于STM32 来说,以 GPIOB 的 ODR 寄存器为例,其寄存器地址为:0X40010C0C,所以对其赋值可以写成:

(*(unsigned int *))(0X40010C0C) = 0XFFFF;

这样我们就完成了对 GPIOB->ODR 寄存器的赋值,全部 0XFFFF,表示 GPIOB 所有 IO 口(16 个 IO 口)都输出高电平。对于我们来说,0X40010C0C就是一个寄存器的特殊地址。

虽然上面的代码实现了需要的功能,但是从实用的角度来说,这么写肯定是不好的,可读性极差,可维护性也很差,所以一般会使用结构体来访问,比如改写成这样:

GPIOB->ODR = 0XFFFF;

这样可读性就比之前的代码好多了,可维护性也相对好一点。至于 GPIOB 结构体怎么来的,在后续会给大家介绍。

2、STM32F103系统架构

STM32F103 是 ST 公司基于 ARM 授权 Cortex M3 内核而设计的一款芯片,而 Cortex M 内核使用的是 ARM v7-M 架构,是为了替代老旧的单片机而量身定做的一个内核,具有低成本、低功耗、实时性好、中断响应快、处理效率高等特点。

2.1 Cortex M3 内核&芯片

ARM公司提供内核(如Cortex M3,简称CM3,下同)授权,完整的MCU还需要很多其他组件。芯片公司(ST、NXP、TI、GD、华大等)在得到CM3内核授权后,就可以把CM3内核用在自己的硅片设计中,添加:存储器,外设,I/O以及其它功能块。不同厂家设计出的单片机会有不同的配置,包括存储器容量、类型、外设等都各具特色,因此才会有市面上各种不同应用的ARM芯片。Cortex M3内核和芯片的关系如下图:

从上图可以看出,ARM公司提供CM3内核和调试系统,其他的东西(外设(IIC、SPI、UART、TIM等)、存储器(SRAM、FLASH等)、I/O等)由芯片制造商设计开发。这里ST公司就是STM32F103芯片的制造商。

2.2 STM32F103系统架构

STM32F103的系统主要由:四个驱动单元(可以主动发起通信,图中黑色①区域)和四个被动单元(只能被驱动工作,图中黑色②区域)组成。如下图,内部系统结构简图:

总线矩阵为分界线,该分界线的左边的称为主动单元,右边的称为被动单元。四个主动单元分别为红色方框框住的红色字体①②③④;四个被动单元分别为黄色方框框住的黄色字体①②③④;其分类如下表:

 注意:这里的驱动/被动单元都是指连接了总线矩阵的部分,未连接总线矩阵的部分,则不算作驱动/被驱动单元。

接下来我们讲一下这些单元。 

1. I Code总线(I-Bus)

这是Cortex M3内核的指令总线,连接闪存指令接口(如:FLASH),用于获取指令。由于该总线功能单一,并没有直接连接到总线矩阵,因此被排除在驱动单元之外。
2. D Code 总线(D-Bus)
这是Cortex M3内核的数据总线,连接闪存存储器数据接口(如:SRAM、FLASH等),用于各种数据访问,如常量、变量等。
3. 系统总线(S-Bus)
这是Cortex M3内核的系统总线,连接所有外设(如:GPIO、SPI、IIC、TIM等),用于控制各种外设工作,如配置各种外设相关寄存器等。
4. DMA 总线
DMA是直接存储访问控制器,可以实现数据的自动搬运,整个过程不需要CPU处理。如可以实现DMA传输内存数据到DAC,输出任意波形,传输过程不需要CPU参与,可以大大节省CPU支,从而更高效的处理事务。STM32F103ZET6内部有2个DMA控制器,可以实现内存到外设、外设到内存、内存到内存的数据传输。
5. 内部FLASH
内部FLASH即单片机的硬盘,用于代码/数据存储,CPU通过ICode总线经FLASH接口访问内部FLASH,FLASH最高访问速度是24Mhz,因此以72M速度访问时,需要插入2个时钟周期延迟。
6. 内部SRAM
内部SRAM即单片机的内存,用于数据存储,直接挂载在总线矩阵上面,CPU通过D Code总线实现0等待延时访问SRAM,最快总线频率可达72Mhz,从而保证高效高速的访问内存
7. FSMC
FSMC即灵活的静态存储控制器,实际上就是一个外部总线接口,可以用来访问外部SRAM、NAND/NOR FLASH、LCD等。它也是直接挂在总线矩阵上面的,以方便CPU快速访问外挂器件。
8. AHB/APB
AHB总线连接总线矩阵,同时通过2个APB桥连接APB1和APB2,AHB总线速度最大为72Mhz,APB2总线速度最大也是72Mhz,但是APB1总线速度最大只能是36Mhz。这三个总线上面挂载了STM32内部绝大部分外设。
9. 总线矩阵
总线矩阵协调内核系统总线和DMA主控总线之间的访问仲裁,仲裁利用轮换算法,保证各个总线之间的有序访问,从而确保工作正常。

3、存储器映射

STM32是一个32位单片机,他可以很方便的访问4GB以内的存储空间(2^32 = 4GB),因此Cortex M3内核将下图中的所有结构,包括:FLASH、SRAM、外设及相关寄存器等全部组织在同一个4GB的线性地址空间内,我们可以通过C语言来访问这些地址空间,从而操作相关外设(读/写)。数据字节以小端格式(小端模式)存放在存储器中,数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。

存储器本身是没有地址信息的,我们对存储器分配地址的过程就叫存储器映射。这个分配一般由芯片厂商做好了,ST将所有的存储器及外设资源都映射在一个4GB的地址空间上(8个块),从而可以通过访问对应的地址,访问具体的外设。ST将4GB空间分成8个块,每个块512MB,如上图所示,从图中我们可以看出有很多保留区域(Reserved),这是因为一般的芯片制造厂家是不可能把4GB空间用完的,同时,为了方便后续型号升级,会将一些空间预留(Reserved)。映射关系及8个存储块的功能如下表所示:

 这里我们重点挑前面3个存储块介绍。

 第一个块是Block 0,用于存储代码,即FLASH空间;

用户FLASH大小是512KB,这是对于我们使用的STM32F103ZET6来说,如果是其他型号,可能FLASH会更小,当然,如果ST喜欢,也是可以随时推出更大容量的STM32F103单片机的,因为这里保留了一大块地址空间。还有,STM32的出厂固化BootLoader非常精简,整个BootLoder只占了2KB FLASH空间。

第二个块是Block 1,用于存储数据,即SRAM空间。

这 个 块 仅 使 用 了 64KB 大 小 ( 仅 大 容 量 STM32F103 型 号 才 有 这 么 多 SRAM , 比 如STM32F103ZET6等),用于SRAM访问,同时也有大量保留地址用于扩展。

第三个块是Block 2,用于外设访问,STM32内部大部分的外设都是放在这个块里面的,该存储块里面包括了AHB、APB1和APB2三个总线相关的外设,其中AHB和APB2是高速总线(72Mhz max),APB1是低速总线(36M max)。

同样可以看到,各个总线之间,都有预留地址空间,方便后续扩展。关于STM32各个外设具体挂在哪个总线上面,大家可以参考前面的 STM32F103系统结构图 和 STM32F103存储器映射图进行查找对应。 

4、寄存器映射

给存储器分配地址的过程叫存储器映射,寄存器是一类特殊的存储器,它的每个位都有特定的功能,可以实现对外设/功能的控制,给寄存器的地址命名的过程就叫寄存器映射。 

举个简单的例子,大家家里面的纸张就好比通用存储器,用来记录数据是没问题的,但是不会有具体的动作,只能做记录,而你家里面的电灯开关,就好比寄存器了,假设你家有8个灯,就有8个开关(相当于一个8位寄存器),这些开关也可以记录状态,同时还能让电灯点亮/关闭,是会产生具体动作的。为了方便区分和使用,我们会给每个开关命名,比如厨房开关、大厅开关、卧室开关等,给开关命名的过程,就是寄存器映射。

当然STM32内部的寄存器有非常多,远远不止8个开关这么简单,但是原理是差不多的,每个寄存器的每一个位,一般都有特定的作用。

4.1 寄存器描述解读

GPIOODR寄存器为例。

 ① 寄存器名字
每个寄存器都有一个对应的名字,以简单表达其作用,并方便记忆,这里GPIOx_ODR表示寄存器英文名,x可以从A~E,说明有5个这样的寄存器(每个端口有一个,事实上最新的STM32F103型号,可能还有F,G等端口,IO数量更多)。
②寄存器偏移量及复位值
地址偏移量表示相对该外设基地址的偏移,比如GPIOB,通过查询可知其外设基地址是:0x4001 0C00。那么GPIOB_ODR寄存器的地址就是:0x4001 0C0C。知道了外设基地址和地址偏移量,我们就可以知道任何一个寄存器的实际地址。

复位值表示该寄存器在系统复位后的默认值,可以用于分析外设的默认状态。这里全部是0。
③寄存器位表
描述寄存器每一个位的作用(共32bit),这里表示ODR寄存器的第15位(bit),位名字为ODR15,rw表示该寄存器可读写(r,可读取;w,可写入)。
④位功能描述
描述寄存器每个位的功能,这里表示位0~15,对应ODR0~ODR15,每个位控制一个IO口的输出状态。其他寄存器描述,参照以上方法解读接口。

4.2 寄存器映射举例

从前面的学习我们知道 GPIOB_ODR 寄存器的地址为:0x4001 0C0C,假设我们要控制 GPIOB的 16 个 IO 口都输出 1,则可以写成:

*(unsigned int *)(0x40010C0C) = 0XFFFF;

这里我们先要将 0x4001 0C0C 强制转换成 unsigned int 类型指针,然后用*对这个指针的值进行设置,从而完成对 GPIOB_ODR 寄存器的写入。

这样写代码功能是没问题,但是可读性和可维护性都很差,使用起来极其不便,因此我们将代码改为:
#define GPIOB_ODR *(unsigned int *)(0x40010C0C)
GPIOB_ODR = 0XFFFF;

这样,我们就定义了一个 GPIOB_ODR 的宏,来替代数值操作,很明显,GPIOB_ODR 的可读性和可维护性,比直接使用数值操作来的直观和方便。这个宏定义过程就可以称之为寄存器的映射。当然,为了简单,我们只举了一个简单实例,实际上大量寄存器的映射,使用结构体是最方便的方式。

4.3 寄存器地址计算 

STM32F103大部分外设寄存器地址都是在存储块2上面的。具体某个寄存器地址,由三个参数决定:

 1、总线基地址(BUS_BASE_ADDR);

2,外设基于总线基地址的偏移量(PERIPH_OFFSET);

3,寄存器相对外设基地址的偏移量(REG_OFFSET)。

可以表示为:寄存器地址 = BUS_BASE_ADDR(总线基地址)+ PERIPH_OFFSET(外设基于总线基地址的偏移量)+ REG_OFFSET(寄存器相对外设基地址的偏移量);

 总线基地址(BUS_BASE_ADDR),STM32F103内部有三个总线(APB1、APB2和AHB),对应的总线基地址,下表中APB1的基地址,也叫外设基地址,表中的偏移量就是相对于外设基地址的偏移量。如下:

偏移量是怎么偏移得到的那个值呢?

总线APB1基地址相对于自身基地址偏移的偏移量为:0;

总线APB2基地址相对于总线APB1基地址偏移的偏移量为:0x1 0000;

总线AHB基地址相对于总线APB1基地址偏移的偏移量为:0x1 8000;

注意:AHB的总线基地址是0X4001 8000,从该基地址到0X4002 0000,只挂了SDIO一个外设,后续的AHB外设基地址都大于等于0X4002 0000。为了方便计算,我们可以将AHB的总线基地址改成:0X4002 0000,而SDIO则单独定义一个基地址给他即可。

外设基于总线基地址的偏移量(PERIPH_OFFSET),不同外设偏移量不一样,以GPIO为例,GPIO外设基地址及相对总线偏移量如下表所示:

 上表的偏移量,就是外设基于APB2总线基地址的偏移量(PERIPH_OFFSET)。

知道了外设基地址,再查询找到具体某个寄存器相对外设基地址的偏移量就可以知道该寄存器的实际地址了,以GPIOB的相关寄存器为例, GPIOB 寄存器相对外设基地址的偏移量如下表所示:

上表的偏移量,就是寄存器基于外设基地址的偏移量(REG_OFFSET)。

因此,我们根据前面的公式,很容易可以计算出GPIOB_ODR的地址:

GPIOB_ODR地址 = APB2总线基地址 + GPIOB外设偏移量 + 寄存器偏移量

所以得到:GPIOB_ODR 地址 = 0X4001 0000 + 0XC00 + 0X0C = 0X4001 0C0C
举了这个例子之后相信头明白了,其他寄存器的地址大家都应该可以熟练掌握并计算出来。

4.4 stm32f103xe.h 寄存器映射

STM32F103所有寄存器映射都在stm32f103xe.h里面完成,包括各种基地址定义、结构体定义、外设寄存器映射、寄存器位定义(占了绝大部分)等,整个文件有1W多行,非常庞大。我们没有必要对该文件进行全面分析,因为很多内容都是相似的,我们只需要知道寄存器是如何被映射的,就可以了,至于寄存器位定义这些内容,知道是怎么回事就可以了。

我们还是以GPIO为例进行说明,看看stm32f103xe.h是如何对GPIO的寄存器进行映射的,通过对GPIO寄存器映射,了解stm32f103xe.h的映射规则。stm32f103xe.h文件主要包含五个部分内容,如下:

寄存器映射主要涉及到上表中加粗的两个组成部分:外设寄存器结构体类型定义和寄存器映射,总结起来,包括3个步骤:

(1) 外设寄存器结构体类型定义
(2)外设基地址定义
(3)寄存器映射(通过将外设基地址强制转换为外设结构体类型指针即可)

以GPIO为例,其寄存器结构体类型定义如下:

typedef struct
{__IO uint32_t CRL; /* GPIO_CRL 寄存器,相对外设基地址偏移量:0X00 */__IO uint32_t CRH; /* GPIO_CRH 寄存器,相对外设基地址偏移量:0X04 */__IO uint32_t IDR; /* GPIO_IDR 寄存器,相对外设基地址偏移量:0X08 */__IO uint32_t ODR; /* GPIO_ODR 寄存器,相对外设基地址偏移量:0X0C */__IO uint32_t BSRR; /* GPIO_BSRR 寄存器,相对外设基地址偏移量:0X10 */__IO uint32_t BRR; /* GPIO_BRR 寄存器,相对外设基地址偏移量:0X14 */__IO uint32_t LCKR; /* GPIO_LCKR 寄存器,相对外设基地址偏移量:0X18 */
} GPIO_TypeDef;

GPIO外设基地址定义如下:

#define PERIPH_BASE 0x40000000UL /* 外设基地址 */#define APB1PERIPH_BASE PERIPH_BASE /* APB1 总线基地址 */
#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000UL) /* APB2 总线基地址 */
#define AHBPERIPH_BASE (PERIPH_BASE + 0x00020000UL) /* AHB 总线基地址 */#define GPIOA_BASE (APB2PERIPH_BASE + 0x00000800UL) /* GPIOA 基地址 */
#define GPIOB_BASE (APB2PERIPH_BASE + 0x00000C00UL) /* GPIOB 基地址 */
#define GPIOC_BASE (APB2PERIPH_BASE + 0x00001000UL) /* GPIOC 基地址 */
#define GPIOD_BASE (APB2PERIPH_BASE + 0x00001400UL) /* GPIOD 基地址 */
#define GPIOE_BASE (APB2PERIPH_BASE + 0x00001800UL) /* GPIOE 基地址 */
#define GPIOF_BASE (APB2PERIPH_BASE + 0x00001C00UL) /* GPIOF 基地址 */
#define GPIOG_BASE (APB2PERIPH_BASE + 0x00002000UL) /* GPIOG 基地址 */
GPIO外设寄存器映射定义如下:
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE) /* GPIOA 寄存器地址映射 */
#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE) /* GPIOB 寄存器地址映射 */
#define GPIOC ((GPIO_TypeDef *)GPIOC_BASE) /* GPIOC 寄存器地址映射 */
#define GPIOD ((GPIO_TypeDef *)GPIOD_BASE) /* GPIOD 寄存器地址映射 */
#define GPIOE ((GPIO_TypeDef *)GPIOE_BASE) /* GPIOE 寄存器地址映射 */
#define GPIOF ((GPIO_TypeDef *)GPIOF_BASE) /* GPIOF 寄存器地址映射 */
#define GPIOG ((GPIO_TypeDef *)GPIOG_BASE) /* GPIOG 寄存器地址映射 */

以上三部分代码,就完成了STM32F103内部GPIOA~GPIOG的寄存器映射,其原理其实是比较简单的,包括两个核心知识点:1,结构体地址自增;2,地址强制转换;

结构体地址自增:我们第一步就定义了GPIO_TypeDef结构体类型,其成员包括:CRL、CRH、IDR、ODR、BSRR、BRR和LCKR,每个成员是uint32_t类型,也就是4个字节,这样假设:CRL地址是0的话,CRH就是0X04,IDR就是0X08,ODR就是0X0C,以此类推。

地址强制转换:以GPIOB为例,GPIOB外设的基地址为:GPIOB_BASE(0X4001 0C00),我们使用GPIO_TypeDef将该地址强制转换为GPIO结构体类型指针:GPIOB,这样GPIOB->CRL的地址就是:GPIOB_BASE(0X4001 0C00),GPIOB->CRH的地址就是:GPIOB_BASE + 0X04(0X4001 0C04),GPIOB->IDR的地址就是:GPIOB_BASE + 0X08(0X4001 0C08),以此类推。

这样我们就使用结构体方式完成了对GPIO寄存器的映射,其他外设的寄存器映射也都是这个方法,这里就不一一介绍了。

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

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

相关文章

谈谈对Android音视频开发的探究

在日常生活中,视频类应用占据了我们越来越多的时间,各大公司也纷纷杀入这个战场,不管是抖音、快手等短视频类型,虎牙、斗鱼等直播类型,腾讯视频、爱奇艺、优酷等长视频类型,还是Vue、美拍等视频编辑美颜类型…

局域网部署,用WorkPlus视频会议保密又安全

用户采用私有化部署视频会议软件的情况主要有以下几种因素: 1. 针对机密性高的会议:如果有涉及高度机密的商业谈判或敏感信息交流等重要会议,政府、军工、企业等用户会选择局域网内部署视频会议软件,以保证信息安全。 2. 频繁进…

Tailwind CSS:简洁高效的工具,提升前端开发体验

112. Tailwind CSS:简洁高效的工具,提升前端开发体验 1. 什么是Tailwind CSS? Tailwind CSS是由Adam Wathan、Jonathan Reinink、David Hemphill和Steve Schoger等人共同创建的一种现代CSS框架。与传统的CSS框架不同,Tailwind CS…

AtcoderABC228场

A - On and OffA - On and Off 题目大意 一个人每天在指定的时间点打开房间的灯,并在另一个时间点关闭灯。问题是确定在给定的时间点,灯是否亮着。 思路分析 注意时间24小时制,同一天和隔夜两种情况 确定给定的时间点是否在灯亮的时间范围…

C高级【day3】

思维导图: 判断家目录下,普通文件的个数和目录文件的个数: #!/bin/bashvar1(ls -l ~/ | cut -d r -f 1 | grep -i -) var2(ls -l ~/ | cut -d r -f 1 | grep -i d) #echo ${var1[*]} #echo ${var2[*]}echo 普通文件个数:${#var…

Bug的严重等级和优先级别与分类

一、 Bug的严重等级定义: 1、 Blocker 即系统无法执行、崩溃或严重资源不足、应用模块无法启动或异常退出、无法测试、造成系统不稳定。 严重花屏内存泄漏 用户数据丢失或破坏系统崩溃/死机/冻结模块无法启动或异常退出严重的数值计算错误功能设计与需求严重不符其…

激荡十三年,消费金融进入“体验争夺战”的下半场

消费金融行业又开始涌动着变局。 先是一些老玩家悬着的心,终于落地。过去两年,消费金融是蚂蚁集团整改的关键板块。前不久,蚂蚁集团被监管部门开出71.23亿元的“罚单”,市场普遍认为这是利空出尽的信号。 与此同时,竞…

Zebec Payroll :计划推出 WageLink On-Demand Pay,进军薪酬发放领域

“Zebec Protocol 生态旨以 Web3 的方式建立全新的公平秩序,基于其流支付体系构建的薪酬支付板块,就是解决问题的一把利刃” Zebec Protocol 在创立之初就有着一个十分宏大的愿景,其希望通过 Web3 的方式来进一步打破世界上一些不公平现象。 …

【力扣】21. 合并两个有序链表 <链表指针>

【力扣】21. 合并两个有序链表 将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例1 输入:l1 [1,2,4], l2 [1,3,4] 输出:[1,1,2,3,4,4] 示例 2 输入:l1 [], l2 [] 输出:…

华为云低代码平台Astro Canvas 搭建汽车展示大屏——实验指导手册

实验背景 大屏应用Astro Canvas是华为云低代码平台Astro的子服务之一,是以数据可视化为核心,以屏幕轻松编排,多屏适配可视为基础,用户可通过图形化界面轻松搭建专业水准的数据可视化大屏。例如汽车展示大屏、监控大屏、项目开发大…

华为QinQ技术的基本qinq和灵活qinq 2种配置案例

基本qinq配置: 运营商pe设备在收到同一个公司的ce发来的的包,统一打上同样的vlan ,如上图,同一个家公司两边统一打上vlan 2,等于在原内网vlan 10或20过来的包再统一打上vlan 2的标签,这样传输就不会和其它…

Stable Diffusion教程(6) - 图片高清放大

放大后细节 修复图片损坏 显存占用 速度 批量放大 文生图放大 好 是 高 慢 否 附加功能放大 一般 否 中 快 是 图生图放大 好 是 低 慢 是 tile模型放大 非常好 是 高 快 是 通过文生图页面的高清修复 优点:放大时能添加更多细节&am…

道本科技受邀参加建筑产业互联网推动建筑产业现代化体系构建座谈会,以数字化产品为建筑行业注入新动能!

2023年7月底,道本科技作为中国建筑业协会合作伙伴,受邀参加了建筑产业互联网推动建筑产业现代化体系构建座谈会。在这次座谈会上,道本科技旗下产品“合规数”“合同智能审查”和“智合同范本库”被中国建筑(中小企业)产…

HTML5中的data-*属性

介绍&#xff1a; data-*全局属性是一类被称为自定义数据属性的属性&#xff0c;它赋予我们在所有 HTML 元素上嵌入自定义数据属性的能力。 data-*的使用 <div class"child" data-name"小红" data-age"18"></div> 在js里有两种获…

【办公自动化】使用Python一键提取PDF中的表格到Excel(文末送书5本)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

用html+javascript打造公文一键排版系统14:为半角和全角字符相互转换功能增加英文字母、阿拉伯数字、标点符号、空格选项

一、实际工作中需要对转换选项细化内容 在昨天我们实现了最简单的半角字符和全角字符相互转换功能&#xff0c;就是将英文字母、阿拉伯数字、标点符号、空格全部进行转换。 在实际工作中&#xff0c;我们有时只想英文字母、阿拉伯数字、标点符号、空格之中的一两类进行转换&a…

python中计算2的32次方减1,python怎么算2的3次方

大家好&#xff0c;给大家分享一下怎么样用python编写2的n次方,n由键盘输入&#xff0c;很多人还不知道这一点。下面详细解释一下。现在让我们来看看&#xff01; ---恢复内容开始--- 1、内置函数&#xff1a;取绝对值函数abs() 2、内置函数&#xff1a;取最大值max()&#xff…

uniapp 返回上一页并刷新

如要刷新的是mine页面 在/pages/mine/improveInfo页面修改信息&#xff0c;点击保存后跳转到个人中心&#xff08;/pages/mine/index&#xff09;页面并刷新更新数据 点击保存按钮时执行以下代码&#xff1a; wx.switchTab({url: /pages/mine/index }) // 页面重载 let pages …

Socks IP轮换:为什么是数据挖掘和Web爬取的最佳选择?

在数据挖掘和Web爬取的过程中&#xff0c;IP轮换是一个非常重要的概念。数据挖掘和Web爬取需要从多个网站或来源获取数据&#xff0c;而这些网站通常会对来自同一IP地址的请求进行限制或封锁。为了避免这些问题&#xff0c;数据挖掘和Web爬取过程中需要使用Socks IP轮换技术。在…