嵌入式IDE(2):KEIL中SCF分散加载链接文件详解和实例分析

news2025/2/27 8:13:26

在上一篇文章IAR中ICF链接文件详解和实例分析中,我通过I.MX RT1170的SDK中的内存映射关系,分析了IAR中的ICF链接文件的语法。对于MCU编程所使用的IDE来说,IAR和Keil用得比较多,所以这一篇文章就来分析一下Keil的分散文件.scf(scatter file)。

文章目录

  • 1 内存映射
  • 2 SCF语法分析
    • 2.1 工程的SCF文件
    • 2.2 define
    • 2.3 加载区域和执行区域

1 内存映射

和上一篇文章一样,同样使用I.MX RT1170的SDK中的链接文件进行分析,通过实际的分散文件来学习里面的语法。和上一节也是同一个例程,除了芯片自带的RAM外,还有NOR Flash和SDRAM。首先来看一下整个工程的内存映射表格:

类型名称起始地址大小
FlashNOR Flash0x300000000x1000000
RAMSDRAM0x800000000x3000000
RAMNCACHE_REGION0x830000000x1000000
RAMSRAM_DTC_cm70x200000000x40000
RAMSRAM_ITC_cm70x00x40000
RAMSRAM_OC10x202400000x80000
RAMSRAM_OC20x202c00000x80000
RAMSRAM_OC_ECC10x203400000x10000
RAMSRAM_OC_ECC20x203500000x10000

对于我们的工程来说,有以下几个内存:

  1. 两个256KB的紧耦合内存DTCMITCM
  2. 两个带ECC的片内RAM:OC1OC2
  3. 在映射的起始地址为0x30000000的FlexSPI1接口上接了一个16MB的NOR Flash
  4. 在映射的起始地址为0x80000000的FlexSPI2接口上接了一个64MB的SDRAM。其中,前48MB用于可缓存的区域,后16MB(NCACHE_REGION)用于不可缓存区域,通常直接与硬件进行交互的buffer需要设置为不可缓存。

2 SCF语法分析

2.1 工程的SCF文件

针对上面的内存映射,官方的SDK中提供的SCF文件如下:

#if (defined(__ram_vector_table__))
  #define __ram_vector_table_size__    0x00000400
#else
  #define __ram_vector_table_size__    0x00000000
#endif

#define m_flash_config_start           0x30000400
#define m_flash_config_size            0x00000C00

#define m_ivt_start                    0x30001000
#define m_ivt_size                     0x00000020

#define m_boot_data_start              0x30001020
#define m_boot_data_size               0x00000010

#define m_dcd_data_start               0x30001030
#define m_dcd_data_size                0x000006E8

#define m_xmcd_data_start              0x30001040
#define m_xmcd_data_size               0x00000204

#define m_interrupts_start             0x30002000
#define m_interrupts_size              0x00000400

#define m_text_start                   0x30002400
#if (defined(__use_flash64MB__))
#define m_text_size                    0x03FFDC00
#else
#define m_text_size                    0x00FFDC00
#endif

#define m_qacode_start                 0x00000000
#define m_qacode_size                  0x00040000

#define m_interrupts_ram_start         0x80000000
#define m_interrupts_ram_size          __ram_vector_table_size__

#define  m_data_start                  (m_interrupts_ram_start + m_interrupts_ram_size)
#define  m_data_size                   (0x03000000 - m_interrupts_ram_size)

#define m_data2_start                  0x20000000
#define m_data2_size                   0x00040000

#define m_data3_start                  0x202C0000
#define m_data3_size                   0x00080000

#define m_ncache_start                 0x83000000
#define m_ncache_size                  0x01000000

/* Sizes */
#if (defined(__stack_size__))
  #define Stack_Size                   __stack_size__
#else
  #define Stack_Size                   0x0400
#endif

#if (defined(__heap_size__))
  #define Heap_Size                    __heap_size__
#else
  #define Heap_Size                    0x0400
#endif

#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
LR_m_text m_flash_config_start m_text_start+m_text_size-m_flash_config_start {   ; load region size_region
  RW_m_config_text m_flash_config_start FIXED m_flash_config_size { ; load address = execution address
    * (.boot_hdr.conf, +FIRST)
  }

  RW_m_ivt_text m_ivt_start FIXED m_ivt_size { ; load address = execution address
    * (.boot_hdr.ivt, +FIRST)
  }

  RW_m_boot_data_text m_boot_data_start FIXED m_boot_data_size { ; load address = execution address
    * (.boot_hdr.boot_data, +FIRST)
  }

#if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1)
  RW_m_dcd_data_text m_dcd_data_start FIXED m_dcd_data_size { ; load address = execution address
    * (.boot_hdr.dcd_data, +FIRST)
  }
#elif defined(XIP_BOOT_HEADER_XMCD_ENABLE) && (XIP_BOOT_HEADER_XMCD_ENABLE == 1)
  RW_m_xmcd_data_text m_xmcd_data_start FIXED m_xmcd_data_size { ; load address = execution address
    * (.boot_hdr.xmcd_data, +FIRST)
  }
#endif
#else
LR_m_text m_interrupts_start m_text_start+m_text_size-m_interrupts_start {   ; load region size_region
#endif
  VECTOR_ROM m_interrupts_start FIXED m_interrupts_size { ; load address = execution address
    * (.isr_vector,+FIRST)
  }
  ER_m_text m_text_start FIXED m_text_size { ; load address = execution address
    * (InRoot$$Sections)
    .ANY (+RO)
  }
#if (defined(__ram_vector_table__))
  VECTOR_RAM m_interrupts_ram_start EMPTY m_interrupts_ram_size {
  }
#else
  VECTOR_RAM m_interrupts_start EMPTY 0 {
  }
#endif
  RW_m_data2 m_data2_start m_data2_size {
    * (RamFunction)
    * (DataQuickAccess)
  }
#if (defined(__heap_noncacheable__))
  RW_m_data m_data_start m_data_size-Stack_Size { ; RW data
#else
  RW_m_data m_data_start m_data_size-Stack_Size-Heap_Size { ; RW data
#endif
    .ANY (+RW +ZI)
    *(*m_usb_dma_init_data)
    *(*m_usb_dma_noninit_data)
  }
#if (!defined(__heap_noncacheable__))
  ARM_LIB_HEAP +0 EMPTY Heap_Size {    ; Heap region growing up
  }
#endif
  ARM_LIB_STACK m_data_start+m_data_size EMPTY -Stack_Size { ; Stack region growing down
  }
  RW_m_ram_text m_qacode_start m_qacode_size { ;
    * (CodeQuickAccess)
  }
#if (defined(__heap_noncacheable__))
  RW_m_ncache m_ncache_start m_ncache_size - Heap_Size { ; ncache data
#else
  RW_m_ncache m_ncache_start m_ncache_size { ; ncache data
#endif
    * (NonCacheable.init)
    * (*NonCacheable)
  }
#if (defined(__heap_noncacheable__))
  ARM_LIB_HEAP +0 EMPTY Heap_Size {    ; Heap region growing up
  }
  RW_m_ncache_unused +0 EMPTY m_ncache_size-ImageLength(RW_m_ncache)-Heap_Size { ; Empty region added for MPU configuration
#else
  RW_m_ncache_unused +0 EMPTY m_ncache_size-ImageLength(RW_m_ncache) { ; Empty region added for MPU configuration
#endif
  }
}

2.2 define

先来分析第一段分散文件,KEIL的分散文件的语法define#if defined语句与C语言一致,所以下面这一段还是很好理解的:

#if (defined(__ram_vector_table__))
  #define __ram_vector_table_size__    0x00000400
#else
  #define __ram_vector_table_size__    0x00000000
#endif

#define m_flash_config_start           0x30000400
#define m_flash_config_size            0x00000C00

#define m_ivt_start                    0x30001000
#define m_ivt_size                     0x00000020

#define m_boot_data_start              0x30001020
#define m_boot_data_size               0x00000010

#define m_dcd_data_start               0x30001030
#define m_dcd_data_size                0x000006E8

#define m_xmcd_data_start              0x30001040
#define m_xmcd_data_size               0x00000204

#define m_interrupts_start             0x30002000
#define m_interrupts_size              0x00000400

#define m_text_start                   0x30002400
#if (defined(__use_flash64MB__))
#define m_text_size                    0x03FFDC00
#else
#define m_text_size                    0x00FFDC00
#endif

#define m_qacode_start                 0x00000000
#define m_qacode_size                  0x00040000

#define m_interrupts_ram_start         0x80000000
#define m_interrupts_ram_size          __ram_vector_table_size__

#define  m_data_start                  (m_interrupts_ram_start + m_interrupts_ram_size)
#define  m_data_size                   (0x03000000 - m_interrupts_ram_size)

#define m_data2_start                  0x20000000
#define m_data2_size                   0x00040000

#define m_data3_start                  0x202C0000
#define m_data3_size                   0x00080000

#define m_ncache_start                 0x83000000
#define m_ncache_size                  0x01000000

/* Sizes */
#if (defined(__stack_size__))
  #define Stack_Size                   __stack_size__
#else
  #define Stack_Size                   0x0400
#endif

#if (defined(__heap_size__))
  #define Heap_Size                    __heap_size__
#else
  #define Heap_Size                    0x0400
#endif

先说明一下,I.MX系列单片机上电会进入L1 BootLoader,它用来引导程序如何启动,比如说是否加密、加密密钥、是XIP还是non-XIP(就要拷贝到RAM)、是否要初始化时钟。在NOR Flash启动的情况下,程序镜像的前0x2000字节就是用来给L1 BootLoader提供一些启动信息的,这里不必过分关注这些字段的意义,若想详细理解可以参考我的这篇文章I.MX RT1170启动详解:Boot配置、Bootable image头的组成。
(1)__ram_vector_table__没有在别的地方定义,所以__ram_vector_table_size__为0。这也很好理解,因为这里有NOR Flash,向量表就不放到RAM中了,而是放在NOR Flash的最前面。
(2)m_flash_config_startm_flash_config_size:用来给L1 BootLoader提供NOR Flash的配置信息,因为上电后L1 BootLoader用最慢的最保险的配置来初始化NOR Flash,如果用户希望自行配置一些参数,比如时钟变快一些,就可以在这个字段填充配置信息,起始地址为0x30000400(NOR Flash的基地址为0x30000000),长度为0xC00
(3)m_ivt_startm_ivt_size:IVT(Image Vector Table)字段,用来保存程序入口地址等参数
(4)m_boot_data_startm_boot_data_size:用来保存镜像的绝对起始地址和大小
(5)m_dcd_data_startm_dcd_data_sizeDCD字段,一般用来初始化SDRAM,特别是希望程序在SDRAM运行的时候需要配置此字段
(6)m_xmcd_data_startm_xmcd_data_size:可以看到这里的起始地址和大小与上面的DCD字段重合了,实际上二者的功能类似,只不过DCD的配置是一个个寄存器配置的指令,比较复杂,而XMCD简化了这些配置操作,这两个字段是二选一的。
(7)m_interrupts_startm_interrupts_size:前面说了,L1 BootLoader的头信息的大小为0x2000,所以从0x2000开始就是程序的开始,最前面放置向量表,长度为0x400
(8)m_text_startm_text_size:代码段紧接着向量表后面,起始地址为0x30002400,这里__use_flash64MB__为假,我们假设用的是16MB(0x1000000)的NOR Flash,剩下的大小就是0x1000000-0x2400=0x00FFDC00
(9)m_qacode_startm_qacode_size:即前面内存映射中芯片内部的SRAM_ITC_cm7
(10)m_interrupts_ram_startm_interrupts_ram_size:如果向量表没有放在NOR Flash,就放在SDRAM的起始,这里由于放在NOR Flash,这两个字段没有用到
(11)m_data_startm_data_size:data数据段,这里将data段放在了SDRAM。这里SDRAM的大小为64M,这个字段占了前48M。
(12)m_data2_startm_data2_sizem_data3_startm_data3_size:同样是data数据段,分别为SRAM_ITC_cm7SRAM_OC2,即片内的RAM都可以作为data段放置变量

  • SRAM_OC1没有用到,我们可以自行声明。因为L1 BootLoader运行时用到了这块SRAM,所以使用时需要考虑使用这块SRAM的时间。

(13)m_ncache_startm_ncache_size:即SDRAM最后的16M用来做non-cacheable区域,比如GUI绘制的Buffer、摄像头的Buffer和DMA的数据,这种直接与硬件交互的内存,需要定义在不可缓存的区域。这与MPU配置有关,可以参考我的MPU系列的文章MPU内存保护单元详解及例子和L1 Cache之I-Cache和D-cache详解。
(14)Stack_SizeHeap_Size:分别为栈和堆的大小,由于程序中使用了FreeRTOS,所以只要保证这里的栈和堆的大小能够成功初始化FreeRTOS即可,初始化FreeRTOS过程应该没有内存分配,所以Heap Size可以设置为0。

2.3 加载区域和执行区域

接下来开始涉及到一些分散文件的语法,参考文档:<DUI0377G_02_mdk_armlink_user_guide.pdf>(可以在KEIL安装目录下找到)。
相比IAR,KEIL的分散文件的语法简单地多,和Linux的ld文件差不多,分散文件就由一个或多个加载区域(Load Region)构成,如下图所示:
在这里插入图片描述
加载区域的语法如下:

load_region_name (base_address | ("+" offset)) [attribute_list] [max_size]
"{"
execution_region_description+
"}"
  • load_region_name(名称): 用于由链接器识别不同加载区域的独特标签,每个加载区域必须具有唯一的名称
  • base_address(基地址):加载区域内的代码和数据在内存中放置的起始内存地址
  • attribute_list(属性): 定义加载区域的特性和行为,包括只读、读写、仅执行或其他内存保护属性
  • max_size(最大大小): 可选,用于限制加载区域的大小,防止内存溢出
  • execution_region_description(执行区域): 加载区域可以包含一个或多个执行区域。执行区域表示连续的代码和数据块,作为一个单独的单元加载到内存中

如果要把所有语法都总结到文章中就太耗时了,所以还是继续分析分散文件,出现了什么语法或关键字,我们再来去找它的意思。由于后面的分散文件中的宏定义太多而影响阅读,这里假设XIP_BOOT_HEADER_ENABLE=1XIP_BOOT_HEADER_DCD_ENABLE=1XIP_BOOT_HEADER_XMCD_ENABLE=0__heap_noncacheable__(表示将堆放置在non-cacheable区域,保证堆内存不会收到缓存的影响)。

剩下的分散文件实际上就是定义了一个加载区域LR_m_text,它的起始地址为m_flash_config_start(0x30000400),最大的大小为m_text_start+m_text_size-m_flash_config_start(16M-0x400=0xFFFC00),即从0x30000400处开始链接,大小为0xFFFC00,这个大小仅限制加载区域的大小(下面属性为FIXED的执行区域)。0~0x400与NXP RT系列单片机的加密启动有关,这些字段编译器无法进行填充,所以这里就没有考虑。

LR_m_text m_flash_config_start m_text_start+m_text_size-m_flash_config_start {   ; load region size_region
	......
}
  • 在分散文件中,;后面为注释

在加载区域LR_m_text下有非常多个执行区域,下面来一个个分析一下:

1、RW_m_config_text:起始地址0x30000400,大小0xC00

RW_m_config_text m_flash_config_start FIXED m_flash_config_size { ; load address = execution address
	* (.boot_hdr.conf, +FIRST)
}
  • FIXED:执行区域的属性,表示让执行区域的执行地址与加载地址尽量保持相等。这意味着,分配给这个执行区域的代码和数据在加载到内存时会尽量放置在指定的执行地址上。如果因为内存冲突或空间不足等原因无法满足,则链接器会报错。
  • +FIRST:表示把该section放在该执行区域的最开始的地方

所以这里就是从0x30000400开始处开始放置boot_hdr.conf段,因为放置的位置必须固定才能被L1 BootLoader正确识别,所以执行区域需要用FIXED属性。

2、RW_m_ivt_text:起始地址0x30001000,大小0x00000020

RW_m_ivt_text m_ivt_start FIXED m_ivt_size { ; load address = execution address
	* (.boot_hdr.ivt, +FIRST)
}

同上,放置L1 BootLoader的引导头。

3、RW_m_boot_data_text:起始地址0x30001020,大小0x00000010

RW_m_boot_data_text m_boot_data_start FIXED m_boot_data_size { ; load address = execution address
	* (.boot_hdr.boot_data, +FIRST)
}

同上,放置L1 BootLoader的引导头。

4、RW_m_dcd_data_text:起始地址0x30001030,大小0x000006E8

RW_m_dcd_data_text m_dcd_data_start FIXED m_dcd_data_size { ; load address = execution address
	* (.boot_hdr.dcd_data, +FIRST)
}

同上,放置L1 BootLoader的引导头。

5、VECTOR_ROM:起始地址0x30002000,大小0x00000400

VECTOR_ROM m_interrupts_start FIXED m_interrupts_size { ; load address = execution address
	* (.isr_vector,+FIRST)
}

放置中断向量表。在启动文件startup_MIMXRT1176_cm7.S文件中定义了该段:.section .isr_vector, "a",这里的a表示将该段标记为可分配(allocatable)的,意味着它在链接时可以被分配到内存中的某个位置。

6、ER_m_text:起始地址0x30002400,大小0x00FFDC00

ER_m_text m_text_start FIXED m_text_size { ; load address = execution address
	* (InRoot$$Sections)
	.ANY (+RO)
}
  • InRoot$$Sections是在分散文件中使用的特殊标记,用来将压缩数据段放置该执行区域中,以确保这些数据段在运行时能够被自动解压缩并提供给程序使用。该特性是ARM为了减少存储空间占用设计的,上电后ARM库会根据此段来进行解压。
    • 参考文章:Example of placing code in a root region
  • .ANY:可以理解为*,表示所有段,但.ANY可以用在多个执行区域中,而*一般只用在一个执行区域中,所以.ANY会更灵活一些。具体参考手册7.4章节<Placement of unassigned sections with the .ANY module selector>
  • (+RO):只读数据段

这里表示将所有的只读数据段放置在这个执行区域。

7、VECTOR_RAM :这里将中断向量表放置在NOR Flash了,这个执行区域没有用到

VECTOR_RAM m_interrupts_start EMPTY 0 {
}
  • EMPTY表示保留一个空区域,但这里区域的大小设为0,所以这段执行区域没有任何作用

8、RW_m_data2:起始地址0x20000000,大小0x00040000

RW_m_data2 m_data2_start m_data2_size {
	* (RamFunction)
	* (DataQuickAccess)
}

这里定义了两个Section:RamFunctionDataQuickAccess,在程序中都可以用__attribute__((section("")))来定义函数或变量到内部的SRAM_DTCM中,可以加快函数的执行速度和数据的访问速度。

9、RW_m_data:起始地址0x80000000,大小0x03000000-0x400

RW_m_data m_data_start m_data_size-Stack_Size { ; RW data
	.ANY (+RW +ZI)
	*(*m_usb_dma_init_data)
	*(*m_usb_dma_noninit_data)
}

这个执行区域就是SDRAM的前48M,将所有的读写数据段和bss段放置在此,同时声明两个usb段,用于SDK中对于USB相关功能的实现。实际上USB段放在non-cacheable区域肯定是可以运行的,但是同时也意味着没有用到缓存,速度就会降低很多。所以就可以将USB相关变量声明到cacheable的区域,然后在代码中必要的地方手动缓存更新相关函数,如SCB_CleanInvalidateDCacheSCB_CleanDCache

10、ARM_LIB_STACK:起始地址0x83000000,大小0x400

ARM_LIB_STACK m_data_start+m_data_size EMPTY -Stack_Size { ; Stack region growing down
}
  • ARM_LIB_STACK:栈的执行区域的固定名称

这里的Stack_Size的前面有一个-,表示栈是向下生长的。

11、RW_m_ram_text:起始地址0x00000000,大小0x00040000

RW_m_ram_text m_qacode_start m_qacode_size { ;
	* (CodeQuickAccess)
}

与上面的7类似,声明一个CodeQuickAccess段,用于将函数链接到内部的SRAM_ITCM中,因为内部的SRAM的速度比NOR Flash或SDRAM的访问速度都快得多。

12、RW_m_ncache:起始地址0x83000000,大小0x01000000-0x400

RW_m_ncache m_ncache_start m_ncache_size - Heap_Size { ; ncache data
	* (NonCacheable.init)
	* (*NonCacheable)
}

定义non-cacheable区域的两个段NonCacheable.initNonCacheable,同时预留堆的空间,因为这里我们假设堆空间也为non-cacheable

13、ARM_LIB_HEAP:大小0x400

ARM_LIB_HEAP +0 EMPTY Heap_Size {    ; Heap region growing up
}
  • +0:表示为上一个执行区域的结束地址,根据用户放置到RW_m_ncache执行区域的变量的多少和大小来决定这个地址
  • ARM_LIB_HEAP:堆的执行区域的固定名称

定义堆空间的内存。

14、RW_m_ncache_unused

RW_m_ncache_unused +0 EMPTY m_ncache_size-ImageLength(RW_m_ncache)-Heap_Size { ; Empty region added for MPU configuration
}

同样放置在上一个执行区域的结束地址处,用来给MPU进行配置,大小m_ncache_size-ImageLength(RW_m_ncache)-Heap_Size即除去变量和堆外的剩下的non-cacheable区域。

  • ImageLength可以取某个执行区域占的大小

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

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

相关文章

geopandas 笔记:geometry上的操作汇总

如无特殊说明&#xff0c;数据主要来自&#xff1a;GeoDataFrame 应用&#xff1a;公园分布映射至subzone_UQI-LIUWJ的博客-CSDN博客 0 读入数据 subzone gpd.read_file(ura-mp19-subzone-no-sea-pl.geojson) subzone subzone_tstsubzone[0:5] subzone_tst subzone_tst.plot…

几十行C++代码生成自己的图片

背景&#xff1a;Kyle McCormick 在 StackExchange 上启动了一个名为 “Tweetable Mathematical Art” 的创意比赛。在这个挑战中&#xff0c;参与者必须在三条推文的长度内编写代码以创造一幅艺术图像。具体来说&#xff0c;每位参赛者需用 C 设计三个函数&#xff1a;RD、GR …

哪种股票可以T+0交易?

股票市场T&#xff0b;0交易制度是实现市场公平&#xff0c;解决市场多空方失衡的重要市场机制。随着中国证券市场的发展&#xff0c;机构投资者占比大幅提升&#xff0c;市场投资者理性程度不断增加&#xff0c;监管机制也日渐完善&#xff0c;恢复T&#xff0b;0交易制度将是…

专业的批量剪辑软件推荐,在哪可以免费下载?免费吗?

今天推荐一款适合广大短视频创作者使用的专业的批量剪辑软件&#xff0c;它叫做超级编导批量剪辑软件&#xff0c;进入超级编导官网就可以立即免费下载&#xff0c;同时该软件支持免费试用。 不管你是做电商带货种草视频、本地生活推广视频&#xff0c;还是企业拓客类的获客视频…

SpotBugs代码检查:instanceof总是返回true(BC_VACUOUS_INSTANCEOF)

https://spotbugs.readthedocs.io/en/latest/bugDescriptions.html#bc-instanceof-will-always-return-true-bc-vacuous-instanceof 使用instanceof判断的时候&#xff0c;总是返回true&#xff0c;除非被检测的结果是null。遇到这种告警&#xff0c;可能是写代码的人理解错误…

无涯教程-JavaScript - IMCSC函数

描述 IMCSC函数以x yi或x yj文本格式返回复数的余割。 复数的余割定义为正弦的倒数。即 余割(z) 1 /正弦(z) 语法 IMCSC (inumber)争论 Argument描述Required/OptionalInumberA complex number for which you want the cosecant.Required Notes Excel中的复数只是简单…

过滤和分页源码、接口文档、jwt介绍和构成、base64编码、drf-jwt使用

过滤和分页源码 补充 #### 为什么在视图类中配置一个过滤类&#xff0c;就能走-filter_backends [SearchFilter,MyFilter]-GenericAPIView&#xff1a;继承APIVIew的视图类&#xff0c;是不能这样配置的----》自己过滤-filter_backends api_settings.DEFAULT_FILTER_BACKEN…

TVjar生成踩坑记录

近期TVBox及其衍生品很火&#xff0c;其中&#xff0c;jar更是主力军 github上有相关源码。 因为github总是被墙&#xff0c;想着能不能自己生成呢 于是开始折腾。 1、下载仓库 以这个为例 仓库下载地址 2、尝试在电脑生成jar 直接运行 buildAndGenJar.bat 3、报错 各…

使用Spring Gateway为对象存储系统MinIo和kkFileView文档预览增加登录验证

文章目录 1、kkfileview下载部署1.1、安装包部署运行1.1.1、物理机或虚拟机上运行1.1.2、Docker容器环境环境运行 1.2、接入说明 2、使用Spring Gateway增加登录认证2.1、网关实现代码2.2、文件服务实现代码2.3、Demo运行效果 官网介绍&#xff1a;kkFileView为文件文档在线预览…

浅谈安科瑞智能操控装置在上海特斯拉工厂配电工程的应用

0.背景 Background 2018年10月17日&#xff0c;上海市临港管委会表示&#xff0c;特斯拉&#xff08;上海&#xff09;有限公司已成功摘得上海临港装备产业区Q01-05地块864885平方米&#xff08;合计1297.32亩&#xff09;的工业用地。2019年1月7日&#xff0c;位于上海东南一…

C动态分配

动态分布与静态发布&#xff1a; 静态分配 1、 在程序编译或运行过程中&#xff0c;按事先规定大小分配内存空间的分配方式。int a [10] 2、 必须事先知道所需空间的大小。 3、 分配在栈区或全局变量区&#xff0c;一般以数组的形式。 4、 按计划分配。 动态分配 1、在程序运…

Alins - 化繁为简、极致优雅的WebUI框架

最近造了个js框架 Alins&#xff0c;分享一下&#xff1a; &#x1f680; Alins: 最纯粹优雅的WebUI框架 English | 文档 | 演练场 | 更新日志 | 反馈错误/缺漏 | Gitee | 留言板 0 简介 0.1 前言 Alins是一款极致纯粹、简洁、优雅的Web UI框架。秉持0-API、Less is More 的…

替换滚珠螺杆需要了解哪些参数?

滚珠螺杆具有定位精度高、高寿命、低污染和可做高速正逆向的传动及变换传动等特性&#xff0c;因具上述特性&#xff0c;滚珠螺杆已成为近来精密科技产业及精密机械产业的定位及测量系统上的重要零组件之一。 众所周知&#xff0c;滚珠螺杆是可以替换的&#xff0c;不仅同品牌之…

概率论与数理统计学习笔记(7)——全概率公式与贝叶斯公式

目录 1. 背景2. 全概率公式3. 贝叶斯公式 1. 背景 下图是本文的背景内容&#xff0c;小B休闲时间有80%的概率玩手机游戏&#xff0c;有20%的概率玩电脑游戏。这两个游戏都有抽卡环节&#xff0c;其中手游抽到金卡的概率为5%&#xff0c;端游抽到金卡的概率为15%。已知小B这天抽…

步进电机基本结构原理了解一下

工作原理 步进电机驱动器根据外来的控制脉冲和方向信号&#xff0c; 通过其内部的逻辑电路&#xff0c;控制步进电机的绕组以一定的时序正向或反向通电&#xff0c;使得电机正向/反向旋转&#xff0c;或者锁定。 以1.8度两相步进电机为例&#xff1a;当两相绕组都通电励磁时&…

喜马拉雅 Redis 与 Pika 缓存使用军规

作者&#xff1a;喜马拉雅 董道光 宣言&#xff1a;缓存不是万金油&#xff0c;更不是垃圾桶&#xff01;&#xff01;&#xff01; 缓存作为喜马拉雅至关重要的基础组件之一&#xff0c;每天承载着巨大的业务请求量。一旦缓存出现故障&#xff0c;对业务的影响将非常严重。因…

经销商沟通难题怎么破?破解之道看这里!

01 经销商&#xff1a;生产商的得力帮手&#xff0c;消费者的贴心管家 经销商是指在市场经济中&#xff0c;负责将生产商生产的产品或提供的服务转售给最终消费者的中间商。在现代商业环境中&#xff0c;经销商在产品分销链条中扮演着重要的角色&#xff0c;他们促进了产品的快…

Python 自然语言处理 文本分类 地铁方面留言文本

将关于地铁的留言文本进行自动分类。 不要着急&#xff0c;一步步来。 导入需要的库。 import numpy as np import pandas as pd import jieba # 分词 import re # 正则 from fnmatch import fnmatch # 通配符 from sklearn.preprocessing import LabelEncoder from sklearn…

数据分析面试题(2023.09.08)

数据分析流程 总体分为四层&#xff1a;需求层、数据层、分析层和结论层 一、统计学问题 1、贝叶斯公式复述并解释应用场景 公式&#xff1a;P(A|B) P(B|A)*P(A) / P(B)应用场景&#xff1a;如搜索query纠错&#xff0c;设A为正确的词&#xff0c;B为输入的词&#xff0c;那…

世和基因亮相2023服贸会,中国精准检测技术走向世界

9月6日&#xff0c;2023中国国际服务贸易交易会在北京圆满收官&#xff0c;本届服贸会围绕“开放引领发展&#xff0c;合作共赢未来”年度主题&#xff0c;吸引了全球领先的创新技术和科研成果亮相盛会&#xff0c;累计入场近28万人。 作为国内肿瘤精准医学头部企业&#xff0…