嵌入式开发之bootloader_嵌入式bootloader

    addu    t1,4

_init_check:
bltu t1,t2,_init_data
nop

    ##################################################################
    # If there are no RAM functions, skip the next two sections --
    # copying RAM functions from program flash to data memory and
    # initializing bus matrix registers.
    ##################################################################
    la      t1,_ramfunc_length
    beqz    t1,_ramfunc_done
    nop

    ##################################################################
    # Copy RAM functions from program flash to data memory
    #   src=_ramfunc_image_begin dst=_ramfunc_begin stop=_ramfunc_end
    ##################################################################
    la      t0,_ramfunc_image_begin
    la      t1,_ramfunc_begin
    la      t2,_ramfunc_end

_init_ramfunc:
lw t3,(t0)
sw t3,(t1)
addu t0,4
addu t1,4
_ramfunc_check:
bltu t1,t2,_init_ramfunc
nop

    ##################################################################
    # Initialize bus matrix registers if RAM functions exist in the
    # application
    ##################################################################
    la      t1,_bmxdkpba_address
    la      t2,BMXDKPBA
    sw      t1,0(t2)
    la      t1,_bmxdudba_address
    la      t2,BMXDUDBA
    sw      t1,0(t2)
    la      t1,_bmxdupba_address
    la      t2,BMXDUPBA
    sw      t1,0(t2)

_ramfunc_done:

    ##################################################################
    # Initialize CP0 registers
    ##################################################################
    # Initialize Count register
    ##################################################################
    mtc0    zero,_CP0_COUNT

    ##################################################################
    # Initialize Compare register
    ##################################################################
    li      t2,-1
    mtc0    t2,_CP0_COMPARE

    ##################################################################
    # Initialize EBase register
    ##################################################################
    la      t1,_ebase_address
    mtc0    t1,_CP0_EBASE

    ##################################################################
    # Initialize IntCtl register
    ##################################################################
    la      t1,_vector_spacing
    li      t2,0                    # Clear t2 and
    ins     t2,t1,5,5               # shift value to VS field
    mtc0    t2,_CP0_INTCTL

    ##################################################################
    # Initialize CAUSE registers
    # - Enable counting of Count register <DC = 0>
    # - Use special exception vector <IV = 1>
    # - Clear pending software interrupts <IP1:IP0 = 0>
    ##################################################################
    li      t1,0x00800000
    mtc0    t1,_CP0_CAUSE

    ##################################################################
    # Initialize STATUS register
    # - Access to Coprocessor 0 not allowed in user mode <CU0 = 0>
    # - User mode uses configured endianness <RE = 0>
    # - Preserve Bootstrap Exception vectors <BEV>
    # - Preserve soft reset <SR> and non-maskable interrupt <NMI>
    # - CorExtend enabled based on whether CorExtend User Defined
    #   Instructions have been implemented <CEE = Config<UDI>>
    # - Disable any pending interrups <IM7..IM2 = 0, IM1..IM0 = 0>
    # - Disable hardware interrupts <IPL7:IPL2 = 0>
    # - Base mode is Kernel mode <UM = 0>
    # - Error level is normal <ERL = 0>
    # - Exception level is normal <EXL = 0>
    # - Interrupts are disabled <IE = 0>
    ##################################################################
    mfc0    t0,_CP0_CONFIG
    ext     t1,t0,22,1              # Extract UDI from Config register
    sll     t1,t1,17                # Move UDI to Status.CEE location
    mfc0    t0,_CP0_STATUS
    and     t0,t0,0x00580000        # Preserve SR, NMI, and BEV
    or      t0,t1,t0                # Include Status.CEE (from UDI)
    mtc0    t0,_CP0_STATUS

    ##################################################################
    # Call the "on bootstrap" procedure
    ##################################################################
    la      t0,_on_bootstrap
    jalr    t0
    nop

    ##################################################################
    # Initialize Status<BEV> for normal exception vectors
    ##################################################################
    mfc0    t0,_CP0_STATUS
    and     t0,t0,0xffbfffff        # Clear BEV
    mtc0    t0,_CP0_STATUS

    ##################################################################
    # Call main. We do this via a thunk in the text section so that
    # a normal jump and link can be used, enabling the startup code
    # to work properly whether main is written in MIPS16 or MIPS32
    # code. I.e., the linker will correctly adjust the JAL to JALX if
    # necessary
    ##################################################################
    and     a0,a0,0
    and     a1,a1,0
    la      t0,_main_entry
    jr      t0
    nop

    
    .end _startup

    ##################################################################
    # Boot Exception Vector Handler
    # Jumps to _bootstrap_exception_handler
    ##################################################################
    .section .bev_handler,"ax",@progbits
    .set noreorder
    .ent _bev_exception

_bev_exception:
la k0,_bootstrap_exception_handler
jr k0
nop

    .end _bev_exception
                    
    ##################################################################
    # General Exception Vector Handler
    # Jumps to _general_exception_handler
    ##################################################################
    .section .gen_handler,"ax",@progbits
    .set noreorder
    .ent _gen_exception

_gen_exception:
la k0,_general_exception_context
jr k0
nop

    .end _gen_exception


    .text
    .ent _main_entry

_main_entry:
##################################################################
# Call main
##################################################################
jal main
nop

    ##################################################################
    # Call exit
    ##################################################################
    jal    exit
    nop

    ##################################################################
    # Just in case, go into infinite loop
    ##################################################################

1:
b 1b
nop
.end _main_entry


 下面是bootlaoder的main主场了,这是你可能就顺眼多了,因为c里面你可以自己用拼音表达你的意思,当然你是英语学习委员也可以用英语,但我反对用123来表示,那是霸权行为,只有当时的你可以明白,我一直觉得代码没必要自己从头开始,快速掌握一门语言或者一款mcu从她自带的demo开始,一通ctl c v后你的kpi就完成了,所以人生苦短,不要太在意那么多,知识层出不穷,只有掌握了快速学习的要义你在能在有限的生命里,畅想无限的事情,当然,买块板子自己亲自跑一跑,那跑板子后面吃灰也是很有必要的,最后祝你顺利毕业找到好工作!



/*********************************************************************
*

  •              PIC32 Boot Loader
    

  • FileName: main.c
  • Dependencies:
  • Processor: PIC32
  • Complier: MPLAB C32
  •              MPLAB IDE
    
  • Company: Microchip Technology, Inc.
  • Software License Agreement
  • The software supplied herewith by Microchip Technology Incorporated
  • (the 揅ompany? for its PIC32 Microcontroller is intended
  • and supplied to you, the Company抯 customer, for use solely and
  • exclusively on Microchip PIC32 Microcontroller products.
  • The software is owned by the Company and/or its supplier, and is
  • protected under applicable copyright laws. All rights are reserved.
  • Any use in violation of the foregoing restrictions may subject the
  • user to criminal sanctions under applicable laws, as well as to
  • civil liability for the breach of the terms and conditions of this
  • license.
  • THIS SOFTWARE IS PROVIDED IN AN 揂S IS?CONDITION. NO WARRANTIES,
  • WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
  • TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  • PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
  • IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
  • CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
  • $Id: $
  • $Name: $

//片内flash为512k bytes 4k*128page
//0x9D07FFFF–0x9D000000 Program Flash
//
// PFM KERNEL AND USER MODE MAPPING
// Virtual Address Physical Address
// --------------- ----------------
// 0xBFC0_2FEF or ***************** 0x1FC0_2FEF
// 0X9FC0_2FEF * *
// * *
// * Boot Flash *
// 0xBFC0_0000 or * *
// 0x9FC0_0000 ***************** 0x1FC0_0000

// 0xBD07_FFFF or ***************** 0x1D07_FFFF
// 0x9D07_FFFF * * BL_CSUM_ADDR 0x1D07_FFF4
// * * BL_PROGSZ_ADDR 0x1D07_FFF0
// 0xBD07_E000 or ***************** 0x1D07_E000
// 0x9D07_E000 * *
// * User App * 500k User app
// * *
// * Program *
// * Flash *
// * *
// 0x9D00_1000 ***************** 0x1D00_1000//4k bootloader
// * BootLoader *
// 0xBD00_0000 or * *
// 0x9D00_0000 ***************** 0x1D00_0000
**********************************************************************/
#include <stdlib.h>
#include <plib.h>
#include “GenericTypeDefs.h”
#include “msg_cmd.h”
//#include “utils.h”
#include <stdarg.h>
// 80Mhz Core/Periph, Pri Osc w/PLL, Write protect Boot Flash
//#pragma config FPLLODIV = DIV_1, FPLLMUL = MUL_20, FPLLIDIV = DIV_2, FWDTEN = OFF, FPBDIV = DIV_1, POSCMOD = XT, FNOSC = PRIPLL, CP = OFF
//#pragma config FPLLMUL = MUL_20, FPLLIDIV = DIV_2, FPLLODIV = DIV_1, FWDTEN = OFF
//#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPBDIV = DIV_1
//#pragma config ICESEL = ICS_PGx2, BWP = ON
#pragma config FPLLMUL = MUL_20, FPLLIDIV = DIV_2, FPLLODIV = DIV_1, FWDTEN = OFF
#pragma config POSCMOD = XT, FNOSC = PRIPLL, FPBDIV = DIV_1
#pragma config ICESEL = ICS_PGx2, BWP = ON,CP = OFF

#define SHELL_CMD 0

#define BL_CSUM_ADDR 0x9D07FFF4
#define BL_PROGSZ_ADDR 0x9D07FFF0
#define FLASH_PROG_BASE 0x9D000000
#define USER_APP_ADDR 0x9D001000
#define FLASH_PAGE_SIZE 4096
#define __ROM_SIZE BL_PROGSZ_ADDR-FLASH_PROG_BASE
#define BIOS_LOAD USER_APP_ADDR
#define BL_MINOR_VERSION 1
#define BL_MAJOR_VERSION 0

#define MAX_CMD_LEN 30
#define MAX_ARGS MAX_CMD_LEN/4

#define UART1_RXREG_IS_NOTNULL (U1ASTAbits.URXDA==1)

#define ENTER_KEY 0x0d
#define BACK_KEY 0x08
#define ESC_KEY 0x1b

#define dog()
#define SYS_FREQ (80000000L)

#define mLED_1 LATBbits.LATB0
#define mLED_2 LATBbits.LATB1
#define mLED_3 LATBbits.LATB2

#define SECONDS (SYS_FREQ/2)
#define MILLI_SECONDS (SECONDS/1000)

#define MAX_DATA_BFR 4096

unsigned char gBuffer[MAX_DATA_BFR];
//unsigned int pagebuff[1024];

#define DFT_DOWNLOAD_ADDR ((int)&gBuffer[0])
void PutChar(BYTE txChar);
void HandleCommand();
BYTE gRxData;
void PutResponse(WORD responseLen);
void VerifyFlashOK(int filesize,WORD csum);
int SectorProg(unsigned int begin, unsigned short *data, unsigned int size);
unsigned char read_byte(unsigned char *recchar);
void Puts(char *s);
void Printf(char *fmt, …);
#define next_line() Puts(“\r\n”)
#define prompt() Puts(“\>”)
//#define DFT_DOWNLOAD_ADDR
#if SHELL_CMD==1
int LoadFromUart(int argc, char *argv[])
#else
int LoadFromUart()
#endif
{
unsigned int start, fileSize;
unsigned int write_addr,writedsize=0;
unsigned int load_addr =(int) DFT_DOWNLOAD_ADDR;
WORD checksum=0,mychecksum=0;
int bValue=0;

#if SHELL_CMD==1
if(argc>1)
{
start = strtoul(argv[1],0,10);
if(load_addr>0)
load_addr = start;
}
#endif
start = load_addr;

while(!kbhit());*((unsigned char *)load_addr++) = getkey();
while(!kbhit());*((unsigned char *)load_addr++) = getkey();
while(!kbhit());*((unsigned char *)load_addr++) = getkey();
while(!kbhit());*((unsigned char *)load_addr++) = getkey();
		 
fileSize=	
(*((unsigned char *)DFT_DOWNLOAD_ADDR+0)<<0)+
(*((unsigned char *)DFT_DOWNLOAD_ADDR+1)<<8)+
(*((unsigned char *)DFT_DOWNLOAD_ADDR+2)<<16)+
(*((unsigned char *)DFT_DOWNLOAD_ADDR+3)<<24);

fileSize=fileSize-6;
if(fileSize>=__ROM_SIZE) 
{//Puts("Flash size overflow!!!\r\n");
return -1;
}

load_addr  = (int)DFT_DOWNLOAD_ADDR;	
write_addr = (int)FLASH_PROG_BASE;
writedsize=0;
while(writedsize <fileSize)
{
    if(kbhit())
	{
        bValue=1-bValue;
        mLED_1=bValue;                    
    	mychecksum+=*((unsigned char *)load_addr++) = getkey();
		writedsize++;dog();
		if( writedsize%0x1000==0 )
		{

		  SectorProg(write_addr,(unsigned short*)DFT_DOWNLOAD_ADDR,0x1000);
		  write_addr=write_addr+0x1000;
     	  load_addr  = (int)DFT_DOWNLOAD_ADDR;	
	      PutChar('.');dog();
	    }
   }
}

if(load_addr%0x1000!=0)
{
  SectorProg(write_addr,(unsigned short*)DFT_DOWNLOAD_ADDR,fileSize - (write_addr-BIOS_LOAD));
  PutChar('.');dog();
}
load_addr  = (int)DFT_DOWNLOAD_ADDR;
//check sum

while(!kbhit());*((unsigned char *)load_addr++) = getkey();
while(!kbhit());*((unsigned char *)load_addr++) = getkey();
//while(!kbhit());*((unsigned char *)load_addr++) = getkey();
//while(!kbhit());*((unsigned char *)load_addr++) = getkey();
checksum=
(*((unsigned char *)DFT_DOWNLOAD_ADDR+0)<<0)+
(*((unsigned char *)DFT_DOWNLOAD_ADDR+1)<<8);
//(*((unsigned char *)DFT_DOWNLOAD_ADDR+1)<<16)+
//(*((unsigned char *)DFT_DOWNLOAD_ADDR+1)<<24);
if(checksum==mychecksum)
 VerifyFlashOK(fileSize,checksum);

//FILESIZE1 = fileSize;

return 0;

}

void VerifyFlashOK(int filesize,WORD csum)
{
//gBuffer[1] contains the prog size in bytes. must be on DWORD boundry
int temp;
//DWORD* fptr;

        NVMErasePage( (void*)(BL_CSUM_ADDR&0xFFFFF000));
		if( !((*(DWORD*)BL_CSUM_ADDR) == 0xFFFFFFFF && 
			(*(DWORD*)BL_PROGSZ_ADDR) == 0xFFFFFFFF) )
		{
			//send the error response
			Puts("Flash not Erase\r\n");
			return;
		}	
		
		//fptr = (DWORD*)FLASH_PROG_BASE;
    
		NVMWriteWord((DWORD*)(BL_PROGSZ_ADDR), filesize); //write flash prog size in bytes


		NVMWriteWord((WORD*)(BL_CSUM_ADDR), csum); //write checksum


		if( !((*(WORD*)BL_CSUM_ADDR) == csum && 
			(*(DWORD*)BL_PROGSZ_ADDR) ==filesize ) )
		{
            Puts("Flash Check sum Erro\r\n");
		}	

}

int SectorProg(unsigned int begin, unsigned short data, unsigned int size)
{
/

unsigned int tmp = 0x200;//0x1000-(begin&0xfff);

//if(tmp>size)
//	tmp = size;
//SectorErase(begin&0xfffff000);
for(; size;)
{	
    mLED_3=0;
    if((begin&0xFFF)==0)
      NVMErasePage((void*)(begin&0xfffff000));
	//FlashProg(begin, data, tmp/2);
    // Write the pagebuff data to NVM_PROGRAM_PAGE + NVM_PAGE_SIZE
    //NVMProgram((void *)begin, (const void *)data, size, (void*) pagebuff);
    NVMWriteRow((DWORD*)begin, (DWORD*)data);

	//Puts("Program ok\r\n");
	size  -= tmp;
	begin += tmp;
	data  += tmp/2;
	tmp = (size>0x1000)?0x1000:size;				
}

/
int RowCount, nRow;
unsigned char
ptr=(unsigned char*)data;
RowCount = size / 512;

		if( size % 512 )
			RowCount++;
			
		nRow = 0;
		
		while(nRow < RowCount)
		{
			int RowAddr;
			
			RowAddr = nRow*512;
			
			if( ((begin+RowAddr) & 0xFFF) == 0 )
				NVMErasePage( (void*)(begin+RowAddr) );
			
			// Write 128 words 
			NVMWriteRow((void*)(begin+RowAddr), (void*)&ptr[RowAddr]);
			nRow++;
		}	

return 0;			

}

void JumpToApp()
{
void (fptr)(void);
fptr = (void (
)(void))USER_APP_ADDR;
fptr();
}

BOOL VerifyFlash()
{
DWORD temp, ProgSz;
DWORD* fptr;
BYTE* fbptr;
WORD csum = 0,mycsum=0;

fptr = (DWORD*)BL_PROGSZ_ADDR;

ProgSz = *fptr;
mycsum = *(WORD*)BL_CSUM_ADDR; 

if( ProgSz > BMXPFMSZ )
	return FALSE;

fbptr = (BYTE*)FLASH_PROG_BASE;

for( temp = 0; temp < ProgSz; temp++ )
	csum += fbptr[temp];
	
//csum = ~csum + 1;

return (csum == mycsum);

}

/*********************************************************/
#if SHELL_CMD==1

int Help(int argc, char *argv[]);
int Auto(int argc, char *argv[]);

typedef int (*cmdproc)(int argc, char *argv[]);
typedef struct {
char *cmd;
char *hlp;
cmdproc proc;
}CMD_STRUC;

CMD_STRUC CMD_INNER[] =
{ {“?”, “help”, Help},
{“load”, “load bin file from console”, LoadFromUart},
// {“prog”, “program from sdram to flash”, ProgFlash},
// {“boot”, “boot from flash”, BootLoader},
// {“copy”, “copy from flash to flash”, CopyFlash},
// {“run”, “run from sdram”, RunProgram},
{“auto”, “auto download and program”,Auto},
{NULL, NULL, NULL}
};
/*
int Help(int argc, char *argv[])
{
int i;

for(i=0; CMD_INNER[i].cmd!=NULL; i++)
{
	if(CMD_INNER[i].hlp!=NULL)
	{
		Puts(CMD_INNER[i].cmd);
		Puts(" -----> ");
		Puts(CMD_INNER[i].hlp);
		Puts("\r\n");
	}
}

return 0;

}
*/
//int Auto(void);
int Auto(int argc, char *argv[])
{

//1.download to sdram
char *para_ptr[4];
//char temp[10];
argc=argc;

LoadFromUart(0, para_ptr);

//2.program to flash
/*
para_ptr[1]=“8000”;
para_ptr[2]=“44000000”;
para_ptr[3]=temp;
ultostr(temp,FILESIZE1);

ProgFlash1(4, para_ptr);
*/
//3.boot

JumpToApp();

return 0;

}
/*********************************************************/

static void ParseArgs(char *cmdline, int *argc, char **argv)
{
#define STATE_WHITESPACE 0
#define STATE_WORD 1

char *c;
int state = STATE_WHITESPACE;
int i;
    
*argc = 0;

if(strlen(cmdline) == 0)
	return;

// convert all tabs into single spaces 
c = cmdline;
while(*c != '\0')
{
	if(*c == '\t')
		*c = ' ';
	c++;
}

c = cmdline;
i = 0;

// now find all words on the command line 
while(*c != '\0')
{
	if(state == STATE_WHITESPACE)
	{
		if(*c != ' ')
		{
			argv[i] = c;		//将argv[i]指向c
			i++;
			state = STATE_WORD;
		}
	}
	else
	{ // state == STATE_WORD 
		if(*c == ' ')
		{
			*c = '\0';
			state = STATE_WHITESPACE;
		}
	}
	c++;
}

*argc = i;

#undef STATE_WHITESPACE
#undef STATE_WORD
}

static int GetCmdMatche(char *cmdline)
{
int i;

for(i=0; CMD_INNER[i].cmd!=NULL; i++)
{
	if(strncmp(CMD_INNER[i].cmd, cmdline, strlen(CMD_INNER[i].cmd))==0)
		return i;
}

return -1;

}

static int ParseCmd(char *cmdline, int cmd_len)
{
int argc, num_commands;
char *argv[MAX_ARGS];

ParseArgs(cmdline, &argc, argv);

// only whitespace
if(argc == 0)
return -1;

num_commands = GetCmdMatche(argv[0]);
	
if(num_commands<0)
	return -1;
	
if(CMD_INNER[num_commands].proc!=NULL)	
    {
    CMD_INNER[num_commands].proc(argc, argv);
	}		
return 0;			

}
#endif
/*********************************************************/

#define BlinkLED() {mLED_1 = ((ReadCoreTimer() & 0x0200000) != 0);}
#define BlinkLED2() {mLED_2 = ((ReadCoreTimer() & 0x0200000) != 0);}
#define BlinkLED3() {mLED_1 = ((ReadCoreTimer() & 0x2000000) != 0);}

BOOL PutMyDLChar()
{
if(ReadCoreTimer()>=SECONDS )
{
PutChar(‘>’);

WriteCoreTimer(0);
return TRUE;
}
else return FALSE;
}

/*********************************************************/

int main (void)
{
//int s = DFT_DOWNLOAD_ADDR;
int i, key;
int time_out0;
char command[MAX_CMD_LEN];
unsigned int pb_clock;

SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

mCTClearIntFlag();
OpenCoreTimer(SECONDS);

//setup LED ports
TRISBbits.TRISB0 = 0;
TRISBbits.TRISB1 = 0;
TRISBbits.TRISB2 = 0;

BOOL FlashGood = FALSE;

// SETUP UART COMMS: No parity, one stop bit, autobaud, polled

// OpenUART1(UART_EN|UART_EN_ABAUD|UART_BRGH_FOUR, UART_RX_ENABLE | UART_TX_ENABLE, 0 );
//OpenUART1(UART_EN|UART_EN_ABAUD|UART_BRGH_FOUR, UART_RX_ENABLE | UART_TX_ENABLE, 0 );
// OpenUART1(UART_EN | UART_BRGH_FOUR, UART_RX_ENABLE | UART_TX_ENABLE, mUARTBRG(80000000, 115200));

UARTConfigure(UART1, UART_ENABLE_PINS_TX_RX_ONLY);
UARTSetFifoMode(UART1, UART_INTERRUPT_ON_TX_NOT_FULL | UART_INTERRUPT_ON_RX_NOT_EMPTY);
UARTSetLineControl(UART1,UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
UARTSetDataRate(UART1, 80000000, 115200);//UART1_BAUDRATE);
UARTEnable(UART1, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));

//U1MODEbits.ABAUD = 1;		//set autobaud mode

mLED_3=0;mLED_2=0;

/*
while(U1MODEbits.ABAUD ) //wait for sync character U
{
if( FlashGood && mCTGetIntFlag() )
{
//timeout while waiting for sync from pc - jump to user app
JumpToApp();
}

	BlinkLED();		
} 		

/
/
**********************************/
/

PutChar(0x0c);PutChar(0x0c);
next_line();
Puts(“********************************************\r\n”);
Puts("
VDC300 BIOS BOOT \r\n");
Puts("
GT-BIOS GT-SS1-V1.0 *\r\n");

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

1.0 *\r\n");

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-46gANxhH-1715715036973)]

[外链图片转存中…(img-TM54omjI-1715715036974)]

[外链图片转存中…(img-CXtAtGxC-1715715036974)]

[外链图片转存中…(img-fUWKCqAJ-1715715036975)]

[外链图片转存中…(img-wiIIE7y1-1715715036976)]

[外链图片转存中…(img-bHkrMxZj-1715715036976)]

[外链图片转存中…(img-MkLSgOou-1715715036977)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

  • 26
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值