Windows CE 休眠唤醒全面解析

2024-06-13 03:38

本文主要是介绍Windows CE 休眠唤醒全面解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

欢迎加入Wince技术讨论群QQ#326444254


Windows CE 休眠唤醒全面解析(基于2440平台)

Windows CE 作为一个广泛应用于移动便携设备上的操作系统,提供了完善的电源管理的功能。其中,休眠唤醒便是一个重要的功能。那么,休眠唤醒是什么原理呢,这首先要从硬件说起。这里呢,我就拿用自己得最熟练的三星平台的2440 CPU为例来和大家探讨一下。

首先看2440 Datasheet 里关于休眠部分的描述

SLEEP Mode

The block disconnects the internal power. So, there occurs no power consumption due to CPU and the internal logic except the wake-up logic in this mode. Activating the SLEEP mode requires two independent power sources. One ofthe two power sources supplies the power for the wake-up logic. The other one supplies other internal logics ,including CPU, and should be controlled for power on/off. In the SLEEP mode, the second power supply source forthe CPU and internal logics will be turned off. The wakeup from SLEEP mode can be issued by the EINT[15:0] or by RTC alarm interrupt.

上面这段话大意就是,当CPU进入休眠模式后,整个CPU系统会进入低功耗模式,只有当外部中断0-15中任意一个中断被触发,或者实时时钟中断被触发时,系统才会被唤醒。我们结合2440 wince5.0 BSP中的相关部分来详细分析。

(这里说句题外话,现在市面流传着2种类型的wince5.0BSP,一种是基于三星官方发布的PQOAL结构的,另一种,是从4.2BSP升级上来的,也就是把原来4.2下的 BSP经过修改,使得能够在PB5.0下编译通过。下面我要分析的就是后者,也就是从 wince4.2下升级过来的5.0 BSP.他的结构和4.2下面的基本相同。

按我的观点,这两种BSP 无所谓好坏,只要能实现产品功能的,就是好的BSP.不过从长远来看,微软主推的是PQOAL结构的BSP,以后官方发布的5.06.0BSP,基本都是采用的这种结构。)

使得系统进入休眠的方法有很多,比如在WINCE的桌面上,点左下角的图标,然后选择 “挂起。或者是在应用程序或驱动中调用SetSystemPowerState函数,都可以让系统进入休眠状态。实际上,这两种方法殊途同归,最终都是要去调一个 OEM层的函数 : OEMPowerOff

.

这个函数的具体实现在

WINCE500"PLATFORM"SMDK2410"KERNEL"HAL"power.c

,如下

VOID OEMPowerOff(void)

{

       volatile IOPreg *s2410IOP = (IOPreg *)IOP_BASE;

      volatile INTreg *s2410INT = (INTreg *)INT_BASE;

       volatile LCDreg *s2410LCD = (LCDreg *)LCD_BASE;   

 

    /* Save Current Important CPU Regs...   */

    CPUSaveRegs(CPUBackupRegs);

 

    /* LCD Controller Disable               */

    CPULCDOff();

 

       /* Stop all GPIO */

       ConfigStopGPIO();

 

       /* Set misc register for power off */

       ConfigMiscReg();

 

 

    /* Actual Power-Off Mode Entry          */

    CPUPowerOff();

 

    /* Recover Process, Load CPU Regs       */

    CPULoadRegs(CPUBackupRegs);

 

       /* Clear GSTATUS2 register : Write 1 to clear */

       s2410IOP->rGSTATUS2 = s2410IOP->rGSTATUS2;

 

    /* Interrupt Clear                      */

    s2410IOP->rEINTPEND = s2410IOP->rEINTPEND;

    s2410LCD->rLCDSRCPND = s2410LCD->rLCDSRCPND;

    s2410LCD->rLCDINTPND = s2410LCD->rLCDINTPND;

    s2410INT->rSUBSRCPND = s2410INT->rSUBSRCPND;

    s2410INT->rSRCPND    = s2410INT->rSRCPND;

    s2410INT->rINTPND    = s2410INT->rINTPND;

 

    OEMInitDebugSerial();

    CPUClearCS8900();

 

       RETAILMSG(1,(TEXT("-- Exit OEMPOWER."r"n")));

       RETAILMSG(1,(TEXT("s2410INT->rINTMOD = 0x%x "r"n"), s2410INT->rINTMOD));

       RETAILMSG(1,(TEXT("s2410INT->rINTMSK = 0x%x "r"n"), s2410INT->rINTMSK));

   

}

我们可以看到,这里面依次做了以下工作:

调用 CPULCDOff函数,关闭背光。

调用 ConfigStopGPIO,设置各IO休眠后的状态

调用 ConfigMiscReg,设置 CPU上的 Misc寄存器。

接下来,调用 CPUPowerOff。。。。。。。

注意看程序里的注释:Actual Power-Off Mode Entry

也就是说,在这个函数的内部,才会真正使得CPU进入休眠模式,那么我们接下来看看这个函数都干了什么工作吧。搜索,怎么搜不到函数的实现?????

其实,这个函数的具体实现是用汇编语句来写的,所以在搜索的时候,文件的类型得选择 *.*,而不是 .c,.cpp,*.h等,

我们终于在 WINCE500"PLATFORM"SMDK2410"KERNEL"HAL"ARM"fw.s中找到了这个函数的实现,当然,都是汇编写得 :(           

LEAF_ENTRY CPUPowerOff

 

; 1. Save register state and return address on the stack.

    ;

    stmdb   sp!, {r4-r12}                  

    stmdb   sp!, {lr}

 

 

    ; 2. Save MMU & CPU Registers to RAM.

;。。。。。。。。。。。。。。。。。。。。。。。。。。。。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

这里我就不把代码贴出来了,大家自己去BSP包里看。

这写部分代码的功能就是保存当前系统的状态,把CPU上一些寄存器里的数据保存到RAM里去,然后禁止RAM自刷新的功能。而且当CPU进入Sleep状态时,RAM是不会掉电的,这样RAM里得数据就不会丢失,当CPU被唤醒后再用RAM里的数据来恢复系统。

注意这一句

; 6. Set external wake-up interrupts (EINT0-2: power-button and keyboard).

。。。。。。。。。。。。。

。。。。。。。。。。。。

也就是说在这行话下面,你就得加入设置唤醒中断源的程序了

如果你在这里成功设置了某个IO 作为中断功能的话,那么系统在休眠后就可以通过人为触发这个中断来实现唤醒CPU(注意,是唤醒CPU,而不是唤醒Wince 系统).这里教大家个小窍门,我们完全可以不在这个语句下面来写汇编语句来实现设置外部唤醒中断的功能(谁让咱是汇编菜鸟呢)。而是在之前的 ConfigStopGPIO里,写C的程序来完成同样的功能。当然,你得保证你设置的那个IO的状态在进入休眠前没有被改变 :)

 

接下来,程序走到这里

。。。。。。。。。。。。。。。。。。。。。

。。。。。。。。。。。。。。。。。。。。。

。。。。。。。。。。。。。。。。。。。。。

       ldr     r4, =vCLKCON

       ldr     r5, =0x7fff8            ; Power Off Mode

 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Sometimes it is not working in cache mode. So I modify to jump to ROM area.

 

       ldr          r6, =0x92000000        ; make address to 0x9200 0020

       add        r6, r6, #0x20        ;

       mov     pc, r6                        ; jump to Power off code in ROM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 

       b       SelfRefreshAndPowerOff

 

       ALIGN   32                      ; for I-Cache Line(32Byte, 8 Word)

 

SelfRefreshAndPowerOff          ; run with Instruction Cache's code

       str     r1, [r0]          ; Enable SDRAM self-refresh

       str          r3, [r2]          ; MISCCR Setting

       str     r5, [r4]          ; Power Off !!

       b       .

       LTORG

这段代码的意义,就是把     0x7fff8 这个32位数送到CLKCON寄存器里,这样就使得CPU进入了休眠的模式

不过在实际编译运行过程中,我发现,如果是在4.2bsp中,这样的代码是没问题的,系统能够正常进入休眠,但是在升级到5.0后,在进入休眠之前,系统会发生异常错误,还没执行进入休眠的语句,程序就跑飞了。经过一段排查,发现把

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Sometimes it is not working in cache mode. So I modify to jump to ROM area.

 

       ldr          r6, =0x92000000        ; make address to 0x9200 0020

       add        r6, r6, #0x20        ;

       mov     pc, r6                        ; jump to Power off code in ROM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

这段代码注释掉,就解决了上面的问题(具体原理是什么还在摸索中)

至此,无论是4.2BSP还是5.0BSP,都可以进入休眠状态了。拿仪器测了测,恩,果然这时候系统中消耗的电流大幅度降低。那么接下来,就是另一个艰巨的任务了:系统唤醒。

正如之前我们提到的,必须在系统进入休眠前,正确设置外部唤醒中断,才能够唤醒CPU.一般来说,正确设置唤醒中断源,有三个要点。

把对应的GPIO设置为中断功能

明确外部中断触发条件,比如我们把这个唤醒用的中断源所对应的IO接到一个按键上,希望通过按下按键来实现唤醒。那么就得明确,当按下这个按键时,IO口上的电平会发生什么样的变化。

设置EXTINTn寄存器,按照按键按下时IO电平的变化条件来设置。比如当按下按键时,IO口上的电平会发生从高到低的变化,那么我们就设置对应的EXTINTn,使得中断触发条件为Falling edge trigeerde,即下降沿触发。

这三点都注意了,那么你会发现,当系统休眠后,按下这个按键,CPU就会被唤醒,消耗电流一下子就变大了。。。但是,这仅仅是唤醒了CPU,还没有使得WINCE系统恢复起来,那么要恢复WINCE 系统,要怎么做呢??



首先,通过看CPU Data Sheet

 

 

       

 

 

由上图可以看出,当系统发生由SLEEPNORMAL的切换时,中间要经过一个 RESET的过程,这个过程称之为 Power On Reset,2440 CPU的寄存器中,专门有一个用来判断发生Reset原因的寄存器GSTATUS2

       也就是说,当CPU Reset后,这个寄存器里的值是会保留的。那么,就可以通过读取这个寄存器里的值,来判断究竟是什么原因发生的CPU Reset了。

       说了这么多,无非是为了明确一点,当CPU被外部中断唤醒时,相当于发生了Power Reset的过程。那么唤醒CPU,就类似于给CPU做了一个 硬件复位,不过GSTATUS2里会保存一个数值,来表明Reset的原因。另外,Power On Reset后,在之前Sleep过程中保存下来的RAM里的系统数据是不会丢失的,我们要做的唤醒系统,就是把这些数值恢复到他原来的地址里去。

那么当CPU 唤醒之后,它运行的第一段程序是什么呢?这点很重要,因为唤醒=Power Reset,那么Reset CPU之后,运行第一段程序自然就是Bootloader了,那么我们看看,Bootloader里是怎么处理的。

       这里我以常用的三星提供的Nboot为例。Bootloader的入口点是

       ENTRY

 

    ;1)The code, which converts to Big-endian, should be in little endian code.

    ;2)The following little endian code will be compiled in Big-Endian mode.

    ; The code byte order should be changed as the memory bus width.

    ;3)The pseudo instruction,DCD can't be used here because the linker generates error.

    ASSERT :DEF:ENDIAN_CHANGE

   

    b   ResetHandler    ; 0x00 Reset

    b   .               ; 0x04 Undefined

    b   .               ; 0x08 Supervisor

    b   .               ; 0x0c Prefetch Abort

    b   .               ; 0x10 Data Abort

    b   .               ; 0x14 Reserved

    b   .               ; 0x18 IRQ

b   .               ; 0x1c FIQ

在这里,如果是Reset复位,那么就会跳转到0地址,也就是ResetHandler    去执行。

ResetHandler

      ldr     r0, = GPFCON

      ldr     r1, = 0x55aa     

      str     r1, [r0]

 

    ldr r0,=WTCON       ;watch dog disable

    ldr r1,=0x0        

    str r1,[r0]

 

    ldr r0,=INTMSK

    ldr r1,=0xffffffff ;all interrupt disable

    str r1,[r0]

 

    ldr r0,=INTSUBMSK

    ldr r1,=0x7ff       ;all sub interrupt disable

    str r1,[r0]

 

    ldr     r0, = INTMOD

    mov r1, #0x0        ; set all interrupt as IRQ (not FIQ)

    str     r1, [r0]

 

    ; configure GPIO pins

    bl Port_Init

 

    ; CLKDIVN

    ldr r0,=CLKDIVN

    ldr r1,=0x7     ; 0x0 = 1:1:1 , 0x1 = 1:1:2    , 0x2 = 1:2:2 , 0x3 = 1:2:4, 0x4 = 1:4:4, 0x5 = 1:4:8, 0x6 = 1:3:3, 0x7 = 1:3:6

 

    str r1,[r0]

    ; delay

    mov     r0, #DELAY

5   subs    r0, r0, #1

    bne     %B5

 

    ; MMU_SetAsyncBusMode FCLK:HCLK= 1:2

    ands r1, r1, #0x2

    beq %F1

    mrc p15,0,r0,c1,c0,0

    orr r0,r0,#R1_nF:OR:R1_iA

    mcr p15,0,r0,c1,c0,0

1

 

    ;To reduce PLL lock time, adjust the LOCKTIME register.

    ldr r0,=LOCKTIME

    ldr r1,=0xffffff

    str r1,[r0]

    ; delay

    mov     r0, #DELAY

5   subs    r0, r0, #1

    bne     %B5

 

    ;Configure MPLL

    ldr r0,=MPLLCON         

    ldr r1,=((110<<12)+(3<<4)+1) ;Fin=16MHz,Fout=399MHz

;    ldr r1,=((0xf6<<12)+(0xd<<4)+0x0) ;Fin=12MHz,Fout=200MHz

    str r1,[r0]

    ; delay

    mov     r0, #DELAY

5   subs    r0, r0, #1

    bne     %B5

 

    ;Configure UPLL

    ldr     r0, =UPLLCON         

    ldr     r1, =((60<<12)+(4<<4)+2) ;Fin=16MHz, Fout=48MHz

;  ldr     r1, =((0x48<<12)+(0x3<<4)+0x2) ;Fin=12MHz, Fout=48MHz

    str     r1, [r0]

    ; delay

    mov     r0, #0x200

5   subs    r0, r0, #1

    bne     %B5

 

以上部分无论是HardReset还是PowerReset都要执行,主要是做的初始化CPU时钟的工作,接下来

 

; :::::::::::::::::::::::::::::::::::::::::::::

;           BEGIN: Power Management

; - - - - - - - - - - - - - - - - - - - - - - -

      ldr       r1, =GSTATUS2           ; Determine Booting Mode

      ldr       r10, [r1]

      tst       r10, #0x2

      beq       %F2                     ; if not wakeup from PowerOffmode Skip

                                ;    MISCCR setting

 

 

      LED_ON 0xc

     str r10, [r1]                      ; Clear Test

 

;     B .

 

 

      ldr        r1, =MISCCR         ; MISCCR's Bit 17, 18, 19 -> 0

      ldr       r0, [r1]                ; I don't know why, Just fallow Sample Code.

      bic       r0, r0, #(3 << 17)      ; SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:L->H

      str       r0, [r1]

 

      ; Set memory control registers

      add        r0, pc, #SMRDATA - (. + 8)

      ldr       r1, =BWSCON ; BWSCON Address

      add       r2, r0, #52       ; End address of SMRDATA

loop10

      ldr       r3, [r0], #4

      str r3, [r1], #4

      cmp       r2, r0

      bne loop10

 

      mov r1, #256

loop11

      subs r1, r1, #1              ; wait until the SelfRefresh is released.

      bne loop11

 

 

      ldr          r2, =0x201000                               ; offset into the RAM

      add        r2, r2, #0x30000000                            ; add physical base

      mov     pc, r2                                               ; & jump to StartUp address

      nop

      nop

      nop

      b .

 

      b       %F3                                          ; if wakeup from PowerOff mode

                                                       ;       goto Power-up code.

; Watchdog reset

2

      tst           r10, #0x4                            ; In case of the wake-up from Watchdog reset,

                                                              ;      go to SDRAM start address(0x3000_0000)

      b            %F4                                          ; If not wakeup from Watchdog reset,

;     beq        %F4                                          ; If not wakeup from Watchdog reset,

                                                              ;      goto Normal Mode.

 

      mov       r0, #4

      str       r0, [r1]                               ; Clear the GSTATUS2. Because same code is located in memory address.

 

      ; Set memory control registers

      ldr       r0, =SMRDATA

      ldr       r1, =BWSCON ; BWSCON Address

      add       r2, r0, #52       ; End address of SMRDATA

loop0

      ldr       r3, [r0], #4

      str r3, [r1], #4

      cmp       r2, r0

      bne loop0

 

      mov r1, #256

loop1

      subs r1, r1, #1              ; wait until the SelfRefresh is released.

      bne loop1

 

      ldr          r2, =0x201000                               ; offset into the RAM

      add        r2, r2, #0x30000000                            ; add physical base

      mov     pc, r2                                               ; & jump to StartUp address

      b .

 

; Case of Power off reset

3

      ldr        r1, =MISCCR         ; MISCCR's Bit 17, 18, 19 -> 0

      ldr       r0, [r1]                ; I don't know why, Just fallow Sample Code.

      bic       r0, r0, #(3 << 17)      ; SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:L->H

      str       r0, [r1]

; - - - - - - - - - - - - - - - - - - - - - - -

;           END: Power Management

; :::::::::::::::::::::::::::::::::::::::::::::

4

 

    ; Configure memory controller

    ;ldr    r0,=SMRDATA

    add     r0, pc, #SMRDATA - (. + 8)

    ldr r1,=BWSCON ;BWSCON Address

    add r2, r0, #52 ;End address of SMRDATA

0      

    ldr r3, [r0], #4   

    str r3, [r1], #4   

    cmp r2, r0     

    bne %B0

 

BringUpWinCE   

……..

……..

……..

…….

这段代码,首先通过读取 GSTATUS2 寄存器里的数值,来判断Reset的原因,我们之前提到过,如果这个值是0x2,那么就是唤醒引起的PowerReset.

ldr r1, =GSTATUS2           ; Determine Booting Mode

      ldr       r10, [r1]

      tst       r10, #0x2

      beq       %F2                     ; if not wakeup from PowerOffmode Skip

                                ;    MISCCR setting

判断GSTATUS2 里的数值是否为0x2,如果是的话,继续向下执行唤醒的恢复操作,否则就跳转到标签为2的程序段去执行。

标签2的程序中,判断GSTATUS2里的数值是否为0x4,如果是的话,说明发生了看门狗reset,那么要执行看门狗reset的恢复过程。

如果二者都不是的话,那么就认为是发生了Hard Reset,那么就按照正常的步骤,去加载Wince系统。

好,我们接着看看,假如GSTATUS2里的数值为2的话。那么就不会跳转到标签2的程序段中,而是向下执行这段程序。

LED_ON 0xc

     str r10, [r1]                      ; Clear Test

 

;     B .

 

 

      ldr        r1, =MISCCR         ; MISCCR's Bit 17, 18, 19 -> 0

      ldr       r0, [r1]                ; I don't know why, Just fallow Sample Code.

      bic       r0, r0, #(3 << 17)      ; SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:L->H

      str       r0, [r1]

 

      ; Set memory control registers

      add        r0, pc, #SMRDATA - (. + 8)

      ldr       r1, =BWSCON ; BWSCON Address

      add       r2, r0, #52       ; End address of SMRDATA

loop10

      ldr       r3, [r0], #4

      str r3, [r1], #4

      cmp       r2, r0

      bne loop10

 

      mov r1, #256

loop11

      subs r1, r1, #1              ; wait until the SelfRefresh is released.

      bne loop11

 

 

      ldr          r2, =0x201000                               ; offset into the RAM

      add        r2, r2, #0x30000000                            ; add physical base

      mov     pc, r2                                               ; & jump to StartUp address

      nop

      nop

      nop

      b .

这段程序的意义,就是恢复CPU的时钟,开启RAM的自刷新然后跳转到 RAM中的一个地址去执行,这个地址是0x32001000。那么熟悉2440 WINCE启动的朋友们应该明白了,这个地址就是BootloaderNandFlash里的数据装载完毕后,跳转执行的地址。那么在这里,跳转到0x30201000这个地址后,WINCE系统就会被装载了,也就是说WINCE的操作系统被唤醒了。(全文完)

这篇关于Windows CE 休眠唤醒全面解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1056176

相关文章

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

Python 中的异步与同步深度解析(实践记录)

《Python中的异步与同步深度解析(实践记录)》在Python编程世界里,异步和同步的概念是理解程序执行流程和性能优化的关键,这篇文章将带你深入了解它们的差异,以及阻塞和非阻塞的特性,同时通过实际... 目录python中的异步与同步:深度解析与实践异步与同步的定义异步同步阻塞与非阻塞的概念阻塞非阻塞同步

Redis中高并发读写性能的深度解析与优化

《Redis中高并发读写性能的深度解析与优化》Redis作为一款高性能的内存数据库,广泛应用于缓存、消息队列、实时统计等场景,本文将深入探讨Redis的读写并发能力,感兴趣的小伙伴可以了解下... 目录引言一、Redis 并发能力概述1.1 Redis 的读写性能1.2 影响 Redis 并发能力的因素二、

Spring MVC使用视图解析的问题解读

《SpringMVC使用视图解析的问题解读》:本文主要介绍SpringMVC使用视图解析的问题解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring MVC使用视图解析1. 会使用视图解析的情况2. 不会使用视图解析的情况总结Spring MVC使用视图

Windows Server服务器上配置FileZilla后,FTP连接不上?

《WindowsServer服务器上配置FileZilla后,FTP连接不上?》WindowsServer服务器上配置FileZilla后,FTP连接错误和操作超时的问题,应该如何解决?首先,通过... 目录在Windohttp://www.chinasem.cnws防火墙开启的情况下,遇到的错误如下:无法与

利用Python和C++解析gltf文件的示例详解

《利用Python和C++解析gltf文件的示例详解》gltf,全称是GLTransmissionFormat,是一种开放的3D文件格式,Python和C++是两个非常强大的工具,下面我们就来看看如何... 目录什么是gltf文件选择语言的原因安装必要的库解析gltf文件的步骤1. 读取gltf文件2. 提

Python解析器安装指南分享(Mac/Windows/Linux)

《Python解析器安装指南分享(Mac/Windows/Linux)》:本文主要介绍Python解析器安装指南(Mac/Windows/Linux),具有很好的参考价值,希望对大家有所帮助,如有... 目NMNkN录1js. 安装包下载1.1 python 下载官网2.核心安装方式3. MACOS 系统安

Java中的runnable 和 callable 区别解析

《Java中的runnable和callable区别解析》Runnable接口用于定义不需要返回结果的任务,而Callable接口可以返回结果并抛出异常,通常与Future结合使用,Runnab... 目录1. Runnable接口1.1 Runnable的定义1.2 Runnable的特点1.3 使用Ru

使用EasyExcel实现简单的Excel表格解析操作

《使用EasyExcel实现简单的Excel表格解析操作》:本文主要介绍如何使用EasyExcel完成简单的表格解析操作,同时实现了大量数据情况下数据的分次批量入库,并记录每条数据入库的状态,感兴... 目录前言固定模板及表数据格式的解析实现Excel模板内容对应的实体类实现AnalysisEventLis