聊聊程序分散加载启动的奥秘

李肖遥 2022-12-08 08:01
    关注、星标公众号,直达精彩内容

素材来源:https://blog.csdn.net/zhengyangliu123/article/details/78788815

整理:技术让梦想更伟大 | 李肖遥


笔者来聊聊分散加载的东西。

1、什么是分散加载

程序是静态的概念,有数据有代码,都是存在不同的区域,但是进程是动态的概念,主进程在运行的时候,会实际修改对应的数据,还有在上电加载的时候将数据段搬到对应的位置,都是属于运行态,由程序执行来保证。

分散加载会把Code与Data放在指定的区域,保证程序在进入main函数后正常运行,如果有多个Code或者Data的时候,会分别加载到对应的区域,不会直接按照起始地址连着一起加载。

比如上图,在可执行的视图里面,分散加载会找到对于的Code、Data地址,然后加载,对于一些其他段,比如bss段会进行初始化为0的操作。

如果全部按照Code和data这种顺序加载,那在执行视图里面则会出现顺序错误,比如Code3加载到bss1,导致程序执行异常

2、分散加载的作用

2.1 ARMCC 编译器分散加载代码

本文以STM32的启动为介绍,在介绍分散加载启动之前,介绍一下STM32的启动方式,总共有三种启动方式。根据选定的启动模式,主闪存存储器、系统存储器或SRAM可以按照以下方式访问:

  • 从主闪存存储器启动:主闪存存储器被映射到启动空间(0x0000 0000),但仍然能够在它原有的地址(0x0800 0000)访问它,即闪存存储器的内容可以在两个地址区域访问, 0x00000000或0x0800 0000。
  • 从系统存储器启动:系统存储器被映射到启动空间(0x0000 0000),但仍然能够在它原有的地址(互联型产品原有地址为0x1FFF B000,其它产品原有地址为0x1FFF F000)访问它。
  • 从内置SRAM启动:只能在0x2000 0000开始的地址区访问SRAM。当从内置SRAM启动,在应用程序的初始化代码中,必须使用NVIC的异常表和偏移寄存器,从新映射向量表到SRAM。

本文中介绍的是:从主闪存启动,也就是内置的主闪存Flash启动。上图为 一个简单的STM32 加载与执行视图的绘制,链接脚本指定Code 从0x0800 0000开始,RW ZI 从0x2000 0000开始放置。

LR_IROM1 0x08000000 0x00010000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00010000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}
12345678910
  • 左边加载视图静态的Code和Data放置方式,比如download的时候 两者把axf 解析成bin文件,然后烧录到nor flash中,可以看到其实静态放置的位置 关系不是很大,主要是执行的时候 位置正确就行 ,因为Code中有绝对地址,不然PC跑飞。
  • 执行视图即程序正常运行的时候 Code或者Data放置的位置。
  • 烧录的位置程序执行的位置不同,分散加载 负责讲其加载到对应位置,保证main 函数执行正常
  • 图中BSS段初始化为0 或者未初始化的全局变量,不占用ImageSIze(bin文件大小),所以加载视图中并没有其,执行视图必须有,上电的时候会将这部分初始化为0。

综述函数的作用

来看看具体的分散加载代码,是如何搬运data 和初始化bss段的。(下文中中断向量表偏移0x10000 偏移64K)

armcc 手册里面介绍:__main__rt_entry 是初始化运行态的环境,以及后面运行APP程序。

通俗点来讲__main函数初始化运行态的环境,主要的功能就是做分散加载将Code位置搬运正确,才能正常运行Code。其作用如下:

  • 将section 拷贝到对应的执行域地址执行,(把RO RW从加载域拷贝到执行域,如果有压缩的Section 会进行解压缩并进行拷贝)
  • 还有bss 段的初始化,将其初始化为0,
  • 之后跳到__rt_entry。
  • 以及堆栈的初始化,
  • lib库的初始化
  • 跳到对应的用户程序(main)。
  • main函数结束后,调用exit函数。

手册内容如下:

__user_setup_stackheap

  • 初始化堆栈地址,以及SP指针位置

__scatterload_copy

  • 主要是RW data的拷贝

__scatterload_zeroinit

  • 主要是ZI data的初始化

__rt_entry如下图armcc 手册所说:

  • 建立堆栈

  • 初始化C库(方便固件使用C库)

  • 调用main函数

  • 关闭C库

  • 离开

  • 启动代码的简单介绍

0x08010188  F000F802  __main:                               bl      0x8010190        ; __scatterload_rt2  
1
0x0801018C  F000F83C                                        bl      0x8010208        ; __rt_entry
1

跳到初始化堆栈区域,执行完成之后,跳到main函数。

1 0x08010190  A00A      __scatterload_rt2:                    adr     r0,0x80101BC    
2 0x08010192  E8900C00                                        ldm     r0,{r10,r11}     
3 0x08010196  4482                                            add     r10,r10,r0                                                                                    
4 0x08010198  4483                                            add     r11,r11,r0                                                                                    
5 0x0801019A  F1AA0701          sub.w   r7,r10,#0x1
12345

第一句adr指令,其作用就是将地址读到寄存器中, 接着,以r0为基地址,读取r0+3464地址的值,将其放到r10,r0+3464+4 的值 ,将其放到r11, 然后,r10+=r0,r11+=r0, r7=r10-1而 0x08013620 ~ 0x08013640 是一个region表,记录着加载域或者执行域的地址信息,从map文件中也可以看到一些信息,根据链接脚本信息,RW的起始地址0x2000 0000, 前三个信息:RW 起始地址,数量size,拷贝的函数 后三个信息:ZI 起始地址,数量size,初始化为0的函数

备注学习:ldm 指令,与stm指令是一对,加载指定地址的数据 LDM{cond} mode Rn{!}, reglist{^} 读取Rn 地址中的数据,放到寄存器,并且之后地址自增,再次读取 STM{cond} mode Rn{!}, reglist{^} 以Rn 地址为基地址,将寄存器的值放到基地址内存,并且之后地址自增,再次写入

1 0x0801019E  45DA      __scatterload_null:                  cmp     r10,r11    
2 0x080101A0  D101                                           bne     0x80101A6    
3 0x080101A2  F000F831                                       bl      0x8010208        ; __rt_entry                                                                                                                                                  
4 0x080101A6  F2AF0E09                                       adr     r14,0x80101A1 
5 0x080101AA  E8BA000F                                       ldm     r10!,{r0-r3}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
6 0x080101AE  F0130F01                                       tst     r3,#0x1                                                                                       
7 0x080101B2  BF18                                           it      ne                                                                                            
8 0x080101B4  1AFB                                           subne   r3,r7,r3                                                                                      
9 0x080101B6  F0430301                                       orr     r3,r3,#0x1                                                                                    
10 0x080101BA  4718                                           bx      r3
11 0x080101BC  00003464                                       dcd     0x3464
12 0x080101C0  00003484                                       dcd     0x3484
123456789101112

第一行:比较r10 r11 r10 是region表的首地址,先读三个,后读三个数据,之后就等于r11,直接跳到__rt_entry 第二行:如果不等,跳转到第三行, 第三行:如果相等,则跳到__rt_entry 第四行:则将地址到r14 ,用于返回。第五行:读取RW的地址信息,size 和拷贝函数地址,r0-r3 可以看到region的信息被读出来了。第六-第十行:将跳转地址转成奇数地址,用于bx指令跳转,080101C4 -> 080101C5,之后跳到拷贝函数。

1 0x080101C4  3A10      __scatterload_copy:                  subs    r2,r2,#0x10
2 0x080101C6  BF24                                           itt     cs                                                                                            
3 0x080101C8  C878                                           ldmcs   r0!,{r3-r6}                                                                                   
4 0x080101CA  C178                                           stmcs   r1!,{r3-r6}                                                                                   
5 0x080101CC  D8FA                                           bhi     0x80101C4        ; __scatterload_copy                                                         
6 0x080101CE  0752                                           lsls    r2,r2,#0x1D                                                                                   
7 0x080101D0  BF24                                           itt     cs                                                                                            
8 0x080101D2  C830                                           ldmcs   r0!,{r4,r5}                                                                                   
9 0x080101D4  C130                                           stmcs   r1!,{r4,r5}                                                                                   
10 0x080101D6  BF44                                           itt     mi                                                                                            
11 0x080101D8  6804                                           ldrmi   r4,[r0]                                                                                       
12 0x080101DA  600C                                           strmi   r4,[r1]                                                                                       
13 0x080101DC  4770                                           bx      r14                                                                                           
14 0x080101DE  0000                                           movs    r0,r0                                                                                         
1234567891011121314

r2 是RW data的size 信息,r0 是 RW的起始地址信息,0x08013640,从map信息也可以看到r0:0801340 r1:20000000地址 第一到第五行:是一个循环语句,每次拷贝16个字节,到RAW区域,即0x2000 0000地址中。对于78个字数据 拷贝70个后,最后八个数字没办法拷贝,不满足CS 第六行:左移29位,将个数清零。r2 = 0-8 = 0xFFFF FFF8 第七行 第八行:拷贝最后八个数据到RAW数据 第十 十一 十二行:不满MI (复数)则直接跳过 如果满足的话,则拷贝最后一个数据, 最后跳转到 cmp r10 r11 ,进行bss 段的初始化。

备注:BHI则表示大于则跳转,看之前文章介绍,ARM学习(2) 寄存器的理解 ===》通用寄存器及状态寄存器IT:if then 分支指令,后面如果满足状态标志位,则执行,否则直接跳过, lsl:左移指令, MI:为负数则执行

1 0x080101E0  2300      __scatterload_zeroinit:              movs    r3,#0x0                                                                                       
2 0x080101E2  2400                                           movs    r4,#0x0                                                                                       
3 0x080101E4  2500                                           movs    r5,#0x0                                                                                       
4 0x080101E6  2600                                           movs    r6,#0x0                                                                                       
5 0x080101E8  3A10                                           subs    r2,r2,#0x10                                                                                   
6 0x080101EA  BF28                                           it      cs                                                                                            
7 0x080101EC  C178                                           stmcs   r1!,{r3-r6}                                                                                   
8 0x080101EE  D8FB                                           bhi     0x80101E8                                                                                     
9 0x080101F0  0752                                           lsls    r2,r2,#0x1D                                                                                   
10 0x080101F2  BF28                                           it      cs                                                                                            
11 0x080101F4  C130                                           stmcs   r1!,{r4,r5}                                                                                   
12 0x080101F6  BF48                                           it      mi
13 0x080101F8  600B                                           strmi   r3,[r1]                                                                                       
14 0x080101FA  4770                                           bx      r14                                                                                           
1234567891011121314

获取到bss段的数据后,可以看到r0-r3更新信息,数据size 为 0x0728个第一到第八行:同样则是循环语句,每次初始化16个字的数据为0, 第九行:同样左移29位,将数据清零 第十行 到 第 十一行:将最后八个字节数据写入0 第十二行 到第十三行:同上面一致(数据拷贝)

数据初始化完成后,同样跳转到 cmp r10 r11,则相等,跳到 __rt_entry

0x080101FC  B51F      __rt_lib_init:                       push    {r0-r4,r14}                                                                                   
0x080101FE  F003FA09  __rt_lib_init_fp_1:                  bl      0x8013614        ; _fp_init                                                                   
0x08010202  BD1F      __rt_lib_init_alloca_1:              pop     {r0-r4,pc}                                                                                    
0x08010204  B510      __rt_lib_shutdown:                   push    {r4,r14}     
0x08010206  BD10      __rt_lib_shutdown_cpp_1:             pop     {r4,pc}
                                                                                      
0x08010208  F003F9BE  __rt_entry:                          bl      0x8013588        ; __user_setup_stackheap                                                     
0x0801020C  4611                                           mov     r1,r2                                                                                         
0x0801020E  F7FFFFF5  __rt_entry_li:                       bl      0x80101FC        ; __rt_lib_init
                                                              
0x08010212  F000F811  __rt_entry_main:                     bl      0x8010238        ; main
                                                                       
0x08010216  F003F9F0                                       bl      0x80135FA        ; exit                                                                       
0x0801021A  B403      __rt_exit:                           push    {r0,r1}                                                                                       
0x0801021C  F7FFFFF2  __rt_exit_ls:                        bl      0x8010204        ; __rt_lib_shutdown                                                          
0x08010220  BC03      __rt_exit_exit:                      pop     {r0,r1} 

0x08010222  F000FAF5                                       bl      0x8010810        ; _sys_exit  
0x08010226  0000                                           movs    r0,r0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
12345678910111213141516171819

__rt_enry:进入到初始化堆栈的地方:初始化堆栈的位置,以及SP指针。

之后初始化 fp_init,需要用到p10 协处理器,之后再研究。__rt_entry_main:进入main函数。则分散加载完成。

0801 360C  4800      __user_libspace:              ldr     r0,0x8013610     ; r0,=__libspace_start                                                           
0801 360E  4770                                    bx      r14
0801 3610  20000140                                dcd     0x20000140       ; __libspace_start                                                                                                                                                              
123

libspace_start:lib库 空间使用 栈空间,在初始化堆栈空间的时候。

1 08013588  4675      __user_setup_stackheap:       mov     r5,r14                                      
2 0801358A  F000F83F                                bl      0x801360C        ; __user_libspace          
3 0801358E  46AE                                    mov     r14,r5                                      
4 08013590  0005                                    movs    r5,r0                                       
5 08013592  4669                                    mov     r1,r13                                      
6 08013594  4653                                    mov     r3,r10                                      
7 08013596  F0200007                                bic     r0,r0,#0x7                                  
8 0801359A  4685                                    mov     r13,r0                                      
9 0801359C  B018                                    add     sp,sp,#0x60 
10 0801359E  B520                                    push    {r5,r14}
11 080135A0  F7FDFA3C                                bl      0x8010A1C        ; __user_initial_stackheap
12 080135A4  E8BD4020                                pop     {r5,r14}
13 080135A8  F04F0600                                mov.w   r6,#0x0                                     
14 080135AC  F04F0700                                mov.w   r7,#0x0
15 080135B0  F04F0800                                mov.w   r8,#0x0
16 080135B4  F04F0B00                                mov.w   r11,#0x0                                    
17 080135B8  F0210107                                bic     r1,r1,#0x7                                  
18 080135BC  46AC                                    mov     r12,r5                                      
19 080135BE  E8AC09C0                                stm     r12!,{r6-r8,r11}                            
20 080135C2  E8AC09C0                                stm     r12!,{r6-r8,r11}                            
21 080135C6  E8AC09C0                                stm     r12!,{r6-r8,r11}                            
22 080135CA  E8AC09C0                                stm     r12!,{r6-r8,r11}                            
23 080135CE  468D                                    mov     r13,r1                                      
24 080135D0  4770                                    bx      r14                                                                  
123456789101112131415161718192021222324

第八行 到 第十二行:r13 = 20000140 加 0x60之后,正好指向 lib库的地址的栈顶。2000 01A0. 第十八行:r12 = 2000 0140,后面初始化 lib 库 后 变成 r12 = 2000 0180 第二十三行:r13 指向栈顶 2000 07A0

可以看到向量表的第一个地址也是 2000 07A0,符合预期。

__user_initial_stackheap                                                                            
                 LDR     R0, =  Heap_Mem
08010A1C  4804      __user_initial_stackheap:       ldr     r0,0x8010A30                                                                                             
                 LDR     R1, =(Stack_Mem + Stack_Size)
08010A1E  4905                                      ldr     r1,0x8010A34                                                                                                                                                                 
                 LDR     R2, = (Heap_Mem +  Heap_Size)
08010A20  4A05                                      ldr     r2,0x8010A38
                 LDR     R3, = Stack_Mem
08010A22  4B06                                      ldr     r3,0x8010A3C
                 BX      LR
08010A24  4770                                      bx      r14                                               
08010A26  0000                                      dcw     0x0                                                                                                                                                                                                                                                                                                                               
08010A28  08010371                                  dcd     0x8010371        ; SystemInit                     
08010A2C  08010189                                  dcd     0x8010189        ; __main                         
08010A30  200001A0                                  dcd     0x200001A0       ; Heap_Mem                       
08010A34  200007A0                                  dcd     0x200007A0       ; __initial_sp                   
08010A38  200003A0                                  dcd     0x200003A0       ; Stack_Mem                      
08010A3C  200003A0                                  dcd     0x200003A0       ; Stack_Mem                      
123456789101112131415161718

初始化堆栈的地址 开始位置,将其存储到 r0- r3中。

  • 可以看到R0、R1和R2 分别存放的是堆的基地址、栈的基地址(栈顶)和堆的极限地址(与arm cc手册说的一致。)来看看armcc 手册上面是怎么介绍堆栈初始化函数的:
  • __user_initial_stackheap 函数将栈基地址(栈顶)值放在r1中,可以从上面寄存器看到,确实寄存器r1存放的是栈顶的地址。
  • __user_setup_stackheap 初始化sp的地址为栈顶地址(上面的代码中第二十三行)
  • __user_initial_stackheap 之所以可以使用C语言来编写,是因为 __user_setup_stackheap 提供了一个 临时的栈,(手册可能比较老,和代码有点出入。)


版权声明:本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

关注我的微信公众号,回复“加群”按规则加入技术交流群。


点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。

李肖遥 公众号“技术让梦想更伟大”,作者:李肖遥,专注嵌入式,只推荐适合你的博文,干货,技术心得,与君共勉。
评论
  • 自动化已成为现代制造业的基石,而驱动隔离器作为关键组件,在提升效率、精度和可靠性方面起到了不可或缺的作用。随着工业技术不断革新,驱动隔离器正助力自动化生产设备适应新兴趋势,并推动行业未来的发展。本文将探讨自动化的核心趋势及驱动隔离器在其中的重要角色。自动化领域的新兴趋势智能工厂的崛起智能工厂已成为自动化生产的新标杆。通过结合物联网(IoT)、人工智能(AI)和机器学习(ML),智能工厂实现了实时监控和动态决策。驱动隔离器在其中至关重要,它确保了传感器、执行器和控制单元之间的信号完整性,同时提供高
    腾恩科技-彭工 2025-01-03 16:28 166浏览
  • 在快速发展的能源领域,发电厂是发电的支柱,效率和安全性至关重要。在这种背景下,国产数字隔离器已成为现代化和优化发电厂运营的重要组成部分。本文探讨了这些设备在提高性能方面的重要性,同时展示了中国在生产可靠且具有成本效益的数字隔离器方面的进步。什么是数字隔离器?数字隔离器充当屏障,在电气上将系统的不同部分隔离开来,同时允许无缝数据传输。在发电厂中,它们保护敏感的控制电路免受高压尖峰的影响,确保准确的信号处理,并在恶劣条件下保持系统完整性。中国国产数字隔离器经历了重大创新,在许多方面达到甚至超过了全球
    克里雅半导体科技 2025-01-03 16:10 122浏览
  • 这篇内容主要讨论三个基本问题,硅电容是什么,为什么要使用硅电容,如何正确使用硅电容?1.  硅电容是什么首先我们需要了解电容是什么?物理学上电容的概念指的是给定电位差下自由电荷的储藏量,记为C,单位是F,指的是容纳电荷的能力,C=εS/d=ε0εrS/4πkd(真空)=Q/U。百度百科上电容器的概念指的是两个相互靠近的导体,中间夹一层不导电的绝缘介质。通过观察电容本身的定义公式中可以看到,在各个变量中比较能够改变的就是εr,S和d,也就是介质的介电常数,金属板有效相对面积以及距离。当前
    知白 2025-01-06 12:04 111浏览
  • 本文介绍Linux系统更换开机logo方法教程,通用RK3566、RK3568、RK3588、RK3576等开发板,触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。制作图片开机logo图片制作注意事项(1)图片必须为bmp格式;(2)图片大小不能大于4MB;(3)BMP位深最大是32,建议设置为8;(4)图片名称为logo.bmp和logo_kernel.bmp;开机
    Industio_触觉智能 2025-01-06 10:43 72浏览
  • 物联网(IoT)的快速发展彻底改变了从智能家居到工业自动化等各个行业。由于物联网系统需要高效、可靠且紧凑的组件来处理众多传感器、执行器和通信设备,国产固态继电器(SSR)已成为满足中国这些需求的关键解决方案。本文探讨了国产SSR如何满足物联网应用的需求,重点介绍了它们的优势、技术能力以及在现实场景中的应用。了解物联网中的固态继电器固态继电器是一种电子开关设备,它使用半导体而不是机械触点来控制负载。与传统的机械继电器不同,固态继电器具有以下优势:快速切换:确保精确快速的响应,这对于实时物联网系统至
    克里雅半导体科技 2025-01-03 16:11 181浏览
  • 彼得·德鲁克被誉为“现代管理学之父”,他的管理思想影响了无数企业和管理者。然而,关于他的书籍分类,一种流行的说法令人感到困惑:德鲁克一生写了39本书,其中15本是关于管理的,而其中“专门写工商企业或为企业管理者写的”只有两本——《为成果而管理》和《创新与企业家精神》。这样的表述广为流传,但深入探讨后却发现并不完全准确。让我们一起重新审视这一说法,解析其中的矛盾与根源,进而重新认识德鲁克的管理思想及其著作的真正价值。从《创新与企业家精神》看德鲁克的视角《创新与企业家精神》通常被认为是一本专为企业管
    优思学院 2025-01-06 12:03 77浏览
  • 每日可见的315MHz和433MHz遥控模块,你能分清楚吗?众所周知,一套遥控设备主要由发射部分和接收部分组成,发射器可以将控制者的控制按键经过编码,调制到射频信号上面,然后经天线发射出无线信号。而接收器是将天线接收到的无线信号进行解码,从而得到与控制按键相对应的信号,然后再去控制相应的设备工作。当前,常见的遥控设备主要分为红外遥控与无线电遥控两大类,其主要区别为所采用的载波频率及其应用场景不一致。红外遥控设备所采用的射频信号频率一般为38kHz,通常应用在电视、投影仪等设备中;而无线电遥控设备
    华普微HOPERF 2025-01-06 15:29 94浏览
  • 光耦合器,也称为光隔离器,是一种利用光在两个隔离电路之间传输电信号的组件。在医疗领域,确保患者安全和设备可靠性至关重要。在众多有助于医疗设备安全性和效率的组件中,光耦合器起着至关重要的作用。这些紧凑型设备经常被忽视,但对于隔离高压和防止敏感医疗设备中的电气危害却是必不可少的。本文深入探讨了光耦合器的功能、其在医疗应用中的重要性以及其实际使用示例。什么是光耦合器?它通常由以下部分组成:LED(发光二极管):将电信号转换为光。光电探测器(例如光电晶体管):检测光并将其转换回电信号。这种布置确保输入和
    腾恩科技-彭工 2025-01-03 16:27 171浏览
  • 在智能家居领域中,Wi-Fi、蓝牙、Zigbee、Thread与Z-Wave等无线通信协议是构建短距物联局域网的关键手段,它们常在实际应用中交叉运用,以满足智能家居生态系统多样化的功能需求。然而,这些协议之间并未遵循统一的互通标准,缺乏直接的互操作性,在进行组网时需要引入额外的网关作为“翻译桥梁”,极大地增加了系统的复杂性。 同时,Apple HomeKit、SamSung SmartThings、Amazon Alexa、Google Home等主流智能家居平台为了提升市占率与消费者
    华普微HOPERF 2025-01-06 17:23 97浏览
  •     为控制片内设备并且查询其工作状态,MCU内部总是有一组特殊功能寄存器(SFR,Special Function Register)。    使用Eclipse环境调试MCU程序时,可以利用 Peripheral Registers Viewer来查看SFR。这个小工具是怎样知道某个型号的MCU有怎样的寄存器定义呢?它使用一种描述性的文本文件——SVD文件。这个文件存储在下面红色字体的路径下。    例:南京沁恒  &n
    电子知识打边炉 2025-01-04 20:04 85浏览
  • PLC组态方式主要有三种,每种都有其独特的特点和适用场景。下面来简单说说: 1. 硬件组态   定义:硬件组态指的是选择适合的PLC型号、I/O模块、通信模块等硬件组件,并按照实际需求进行连接和配置。    灵活性:这种方式允许用户根据项目需求自由搭配硬件组件,具有较高的灵活性。    成本:可能需要额外的硬件购买成本,适用于对系统性能和扩展性有较高要求的场合。 2. 软件组态   定义:软件组态主要是通过PLC
    丙丁先生 2025-01-06 09:23 71浏览
  • 随着市场需求不断的变化,各行各业对CPU的要求越来越高,特别是近几年流行的 AIOT,为了有更好的用户体验,CPU的算力就要求更高了。今天为大家推荐由米尔基于瑞芯微RK3576处理器推出的MYC-LR3576核心板及开发板。关于RK3576处理器国产CPU,是这些年的骄傲,华为手机全国产化,国人一片呼声,再也不用卡脖子了。RK3576处理器,就是一款由国产是厂商瑞芯微,今年第二季推出的全新通用型的高性能SOC芯片,这款CPU到底有多么的高性能,下面看看它的几个特性:8核心6 TOPS超强算力双千
    米尔电子嵌入式 2025-01-03 17:04 48浏览
  • 根据Global Info Research项目团队最新调研,预计2030年全球封闭式电机产值达到1425百万美元,2024-2030年期间年复合增长率CAGR为3.4%。 封闭式电机是一种电动机,其外壳设计为密闭结构,通常用于要求较高的防护等级的应用场合。封闭式电机可以有效防止外部灰尘、水分和其他污染物进入内部,从而保护电机的内部组件,延长其使用寿命。 环洋市场咨询机构出版的调研分析报告【全球封闭式电机行业总体规模、主要厂商及IPO上市调研报告,2025-2031】研究全球封闭式电机总体规
    GIRtina 2025-01-06 11:10 89浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦