STM32 TCP实现OTA

芯片:stm32f407

开发平台:stm32cubeide

上位机开发平台:visual studio 2017

1. FLASH分配

将flash划分为四个部分:

        bootloader:        0x8000000-0x800ffff

        app1:                0x8010000-0x805ffff

        app2:                0x8060000-0x80affff

        parameters:      0x80e0000-0x80fffff

        其中,bootloader程序为启动程序,app1是当前运行程序,app2为准备升级程序,parameters存储程序相关参数。

2. BOOTLOADER

        在app2中用最后一段flash地址0x80dfff0来存储升级标志Upgrade_Flag,比如有新程序下载到app2中,则0x80dfff0中数据为0xaaaaaa,如果为其他则表示没有新程序,开机后bootloader首先运行,启动后检测Upgrade_Flag是否为0xaaaaaa:

        如果是,则将app2中的程序拷贝到app1中,然后重置标志位Upgrade_Flag为0xffffffff且跳转到app1起始地址0x8010000开始执行新的程序;

        如果否,则直接跳转到app1起始地址0x8010000开始运行程序;

        bootloader主要代码如下:

#define IAP_ADDRESS			0x8000000		//
#define APP1_ADDRESS			0x8010000		//
#define APP1_ADDRESS_END		0x805FFFF		//
#define APP2_ADDRESS			0x8060000		//
#define APP2_ADDRESS_END		0x80AFFFF		//
#define PARA_ADDRESS			0x80E0000		//
#define UPGRADE_ADDRESS			0x80DFFF0		//pFunction Jump_To_Application;
uint32_t JumpAddress;pFunction Jump_To_Application;
void Jump_To_APP()
{uint32_t JumpAddress;printf("jump to app: %#x\r\n", APP1_ADDRESS);//HAL_DeInit();__disable_irq();if(((*(__IO uint32_t*)APP1_ADDRESS)&0x2ffe0000)==0x20020000){/* Jump to user application */JumpAddress = *(__IO uint32_t*) (APP1_ADDRESS + 4);Jump_To_Application = (pFunction) JumpAddress;//printf("jump %#x success \r\n",APP1_ADDRESS);/* Initialize user application's Stack Pointer */__set_MSP(*(__IO uint32_t*) APP1_ADDRESS);Jump_To_Application();}else{printf("error [0x%08x]\r\n",(*(volatile uint32_t*)APP1_ADDRESS));}
}
uint8_t u8_Code_Buff[2048];//2k
uint16_t Num=0;
uint8_t NotUpgrade[4]={0xff,0xff,0xff,0xff};
uint8_t Upgrade[4]={0xaa,0xaa,0xaa,0xaa};
uint32_t Upgrade_Flag;void Copy_APP2_to_APP1(void)
{if(((*(__IO uint32_t*)APP2_ADDRESS)&0x2ffe0000)!=0x20020000){printf("invalid app in address [0x%08x]\r\n",APP2_ADDRESS);return;}MEM_IF_IniT();uint32_t APP1_Addr;uint32_t APP2_Addr;APP1_Addr=APP1_ADDRESS;APP2_Addr=APP2_ADDRESS;MEM_If_Erase(APP1_ADDRESS,APP1_ADDRESS_END);printf("Erase app1 flash\r\n");for(int i=0;i<150;i++)//copy 150*2k=300k, max size of app is 300k{printf("APP1_Addr = %x\r\n",APP1_Addr);printf("APP2_Addr = %x\r\n",APP2_Addr);MEM_If_Read(u8_Code_Buff,APP2_Addr,2048);HAL_Delay(10);MEM_If_Write_Byte(u8_Code_Buff,APP1_Addr,2048);HAL_Delay(10);APP1_Addr+=0x800;APP2_Addr+=0x800;memset(u8_Code_Buff,0,sizeof(u8_Code_Buff));Num=i;if(1){printf("Successfully copied page %d\r\n",Num);}else{printf("Copy failed page %d\r\n",Num);}}MEM_If_Erase(UPGRADE_ADDRESS,UPGRADE_ADDRESS);MEM_If_Write_Byte(NotUpgrade,UPGRADE_ADDRESS,sizeof(NotUpgrade));MEM_IF_DeInit();
}int main(void)
{/* USER CODE BEGIN 1 *///SCB->VTOR = FLASH_BASE | 0x40000;/* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */printf("\r\n");printf("*****************************************\r\n");printf("*         luckyzjian's ISP              *\r\n");printf("*                                       *\r\n");printf("*          www.cdxcjc.com               *\r\n");printf("*                                       *\r\n");printf("*       Version: v%d.%d.%d            *\r\n",version_board,version_year,version_no);printf("*                                       *\r\n");printf("*           026-82598116                *\r\n");printf("*****************************************\r\n");printf("************ flash table  ***************\r\n");printf("*bootloader  : %#x -------- %#x******\r\n",IAP_ADDRESS,APP1_ADDRESS-1);printf("*APP1        : %#x -------- %#x******\r\n",APP1_ADDRESS,APP1_ADDRESS_END);printf("*APP2        : %#x -------- %#x******\r\n",APP2_ADDRESS,APP2_ADDRESS_END);printf("*PRIVATE PARA: %#x -------- %#x******\r\n",PARA_ADDRESS,PARA_ADDRESS+0X1FFFF);printf("*****************************************\r\n");TM1629_init();Upgrade_Flag=*(__IO uint32_t*)(UPGRADE_ADDRESS);printf("Upgrade_Flag = 0x%x\r\n",Upgrade_Flag);if(0xaaaaaaaa==Upgrade_Flag){printf("there is new app in address: %x\r\n",APP2_ADDRESS);printf("copy new app in address: %x to address: %x\r\n",APP2_ADDRESS,APP1_ADDRESS);TM1629_printRow1("-----",ShowType_Right);TM1629_printRow2("-ISP-",ShowType_Right);TM1629_DISPLAY();Copy_APP2_to_APP1();printf("copy finished\r\n",APP2_ADDRESS,APP1_ADDRESS);printf("------%#x\r\n",(APP1_ADDRESS+4)&0XFF000000);if(((APP1_ADDRESS+4)&0xff000000)==0x08000000){printf("jump APP1 running");Jump_To_APP(APP1_ADDRESS);}}else{printf("there is no new app in address: %x\r\n",APP2_ADDRESS);printf("------%#x\r\n",(APP1_ADDRESS+4)&0xff000000);if(((APP1_ADDRESS+4)&0xff000000)==0x08000000){printf("jump APP1 running\r\n");Jump_To_APP(APP1_ADDRESS);}}/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

3. APP

APP程序因为是从0x08010000开始运行的,要注意修改如下两个地方

/Core/Src/system_stm32f4xx.c中:#define VECT_TAB_OFFSET         0x00010000U     /*!< Vector Table base offset field.This value must be a multiple of 0x200. */STM32F407ZGTX_FLASH.ld:MEMORY
{CCMRAM    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 64KRAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 128KFLASH    (rx)    : ORIGIN = 0x8010000,   LENGTH = 320K
}

程序通过TCP下载,因为我项目中已经有一套TCP的通讯接口,为了方便,便在原来的自定义接口协议中增加了下载程序的协议

通讯格式定义如下:

发送:
0x02起始码1
ADD地址1控制仪地址 0X80~0X8F 代表0~15号地址
CMD命令字节1
LB数据[DF]长度1
[DF]数据LB
CS校验码1=NOT(0x02+ADD+CMD+LB+[DF])+1
0X03结束码1
响应:
0x06起始码1
ADD地址1控制仪地址 0X80~0X8F 代表0~15号地址
CMD命令字节1
LB数据[DF]长度1
[DF]数据LB
CS校验码1=NOT(0x06+ADD+CMD+LB+[DF])+1
0X03结束码1

涉及下载的命令定义如下:

命令命令代码命令格式响应说明
开始下载固件0x510x02 ADD 0x51 0x02 [分包数量] CS  0x030x06 ADD 0x51  0x01 <STATUS> CS 0x03[分包数量],固件数据包按1000字节一个包进行分包,最后一包不足1000字节时,用0x00填充到1000字节,将总的分包数量在开始升级固件指令时写入
返回STATUS:
0X06 成功;
0x15 失败
写入固件0x520x02 ADD 0x52 [分包顺序][数据长度]{数据} CS 0x030x02 ADD 0x52 0x03 [分包顺序] <STATUS> CS 0x03[分包顺序][数据长度]《数据》三部分固定长度为1004个字节,其中:
[分包顺序]为两字节,代表该帧数据为整个固件包的第几包数据,从0开始计数;
[数据长度]为两字节,代表该包数据字节长度,应固定为1000字节;
《数据》为固件内容,当最后一包不足1000字节时,用0x00填充到1000字节
返回STATUS:
0X06 成功;
0x15 失败;
写入固件结束0x530x02 ADD 0x53 0x02 <CRCH>  <CRCL> CS 0x030x06 ADD 0x53 0x01 <STATUS> CS 0x03CRCH,CHRL组成固件全部数据的CRC16校验,下位机收到结束指令后,对整包数据进行CRC16校验,与该指令CRC校准字比对,如果比对成功,则标记为升级成功(向地址0x80DFFF0写入0xaaaaaa)
返回STATUS:
0X06 升级成功;
0x15 升级失败;
放弃写入固件0x5f0x02 ADD 0x5f 0x00 CS 0x030x06 ADD 0x5f 0x00 CS 0x03

#define CLIENTMAX 5
typedef struct
{struct netconn *conn;uint8_t num;
}tcp_client;
typedef struct{struct netconn *client[CLIENTMAX+2];uint8_t state[CLIENTMAX+2];osThreadId client_taskid[CLIENTMAX+2];Controller_StatusDef realdatastatus[CLIENTMAX+2];
}client_ad;
client_ad clientad;uint8_t isIAPStart=0;
uint16_t IAP_frameTotalCount=0;
uint16_t IAP_frameCount=0;
uint16_t IAP_frameSeq=0;
uint16_t IAP_frameLength=0;
uint16_t IAP_frameCRC=0x0000;
uint8_t isIAPFinish=0;
uint8_t isIAPSuccess=0;uint8_t NotUpgrade[4]={0xff,0xff,0xff,0xff};
uint8_t Upgrade[4]={0xaa,0xaa,0xaa,0xaa};void svr_task(void const *arg);
void processCmd(Controller_AckDataDef frame,Controller_AckDataDef* ackframe,uint8_t clientindex);
osThreadDef(myTaskClient, tcp_server_thread, osPriorityNormal, CLIENTMAX, 1400);void MX_FREERTOS_Init(void) {osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 1024);defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);osThreadDef(tcpmultiTask, svr_task, osPriorityNormal, 0, 1024);osThreadCreate(osThread(tcpmultiTask), NULL);clientad.state[CLIENTMAX]=1;clientad.realdatastatus[CLIENTMAX]=RealPass_Stop;comackframe.originaldata_data=comackdata;	isCOMHasACK=0;}
err_t client_init(void *arg,uint8_t* clientnumindex)
{uint8_t          clientnum;                             //?????? TCP client ????err_t          err;                             //????(UCOSIII)uint8_t ifreceiveclient=0;for(clientnum=0;clientnum<CLIENTMAX;clientnum++)   //???????????(????20????){if(clientad.state[clientnum]==0)                 //???? clientnum ?????????0(???){			ifreceiveclient=1;break;                                         //???? ????  ????????}}		if(ifreceiveclient==0){UsrLog("This no space to accept client");return 1;}*clientnumindex=clientnum;return ERR_OK;                                     //??????
}void svr_task(void const *arg)
{err_t         oserr;                       struct netconn *conn,*newconn;             while(!isLWIPInitSuccess)osDelay(100);for(int i=0;i<CLIENTMAX;i++)   {clientad.state[i]=0;clientad.realdatastatus[i]=RealPass_Stop;//clientad.iapstatus[i]=IAPStatus_app;}	conn = netconn_new(NETCONN_TCP);            netconn_bind(conn,IP_ADDR_ANY,sysParameterStruct._Para_ControlIP_PORT); netconn_listen(conn);  		                sprintf((char*)iptxt, "%d", sysParameterStruct._Para_ControlIP_PORT);  UsrLog("tcp start listen on port: %s",iptxt);while(1){uint8_t clientnumindex=0;//if(get_clientindex(&clientnumindex) != ERR_OK)//	osDelay(100);				if(netconn_accept(conn,&newconn) == ERR_OK) {		if(client_init((void *)newconn,&clientnumindex) != ERR_OK){                                         netconn_close(newconn);                 netconn_delete(newconn);                }else{clientad.client[clientnumindex]=newconn;             			clientad.state[clientnumindex]=1;                       clientad.client_taskid[clientnumindex] = osThreadCreate(osThread(myTaskClient),  (void *)clientnumindex);osDelay(100);if(clientad.client_taskid[clientnumindex]==NULL){UsrLog("Failed to create the recv thread with id: %d",clientnumindex);}else{UsrLog("create the recv thread with id: %x",(int)(clientad.client_taskid[clientnumindex]));}}}osDelay(100);}
}
void tcp_server_thread(void const *arg)
{err_t err;struct netbuf *clientrecvbuf;Controller_AckDataDef recvframe;Controller_AckDataDef ackframe;uint8_t recvdata[40];uint8_t ackdata[80];/*recv tcp data buf*/ackframe.originaldata_head=0x06;ackframe.originaldata_address=sysParameterStruct._Para_ControlEquiAddress;ackframe.originaldata_end=0x03;ackframe.originaldata_data=ackdata;ip_addr_t addr; u16_t port;uint8_t *app_flash_buf;/* get remote IP address and port*/uint8_t clientindex=(uint8_t)arg;	if((err=netconn_getaddr(clientad.client[clientindex],&addr, &port, 0))==ERR_OK){sprintf((char*)iptxt, "%d.%d.%d.%d:%d", (uint8_t)(addr.addr),(uint8_t)(addr.addr>>8),(uint8_t)(addr.addr>>16),(uint8_t)(addr.addr>>24),port);  UsrLog("one client is connected:%s",iptxt);}uint8_t *data;u16_t len;while(1){		if((err=netconn_recv(clientad.client[clientindex],&clientrecvbuf))==ERR_OK){do{netbuf_data(clientrecvbuf,&data,&len);//printf("recevie one frame: length=%d, data=0x%x--0x%x\r\n",len,data[0],data[len-1]);if(len>=6){if(data[0]==0x02&&data[len-1]==0x03){recvframe.originaldata_head=data[0];recvframe.originaldata_address=data[1];recvframe.originaldata_cmd=data[2];if(recvframe.originaldata_cmd==0x52)//app upload data frame:0x02 add 0x52 [frame seq] [frame len] {app data} cs 0x03{IAP_frameSeq=(uint16_t)((data[3]<<8)|data[4]);IAP_frameLength=(uint16_t)((data[5]<<8)|data[6]);app_flash_buf=data+7;printf("recevie one frame data: frame seq=%d, frame data length=%d\r\n",IAP_frameSeq,IAP_frameLength);uint8_t frameRight=1;if(isIAPStart){if(IAP_frameSeq==IAP_frameCount&&IAP_frameSeq<IAP_frameTotalCount){if(IAP_frameLength!=500){printf("wrong frame length(%d), length should be 1000\r\n",IAP_frameLength);frameRight=0;}if(frameRight){printf("valid frame data\r\n");uint32_t flashdestination=APP2_ADDRESS+500*IAP_frameSeq;MEM_IF_IniT();if (MEM_If_Write_Word(app_flash_buf,flashdestination,IAP_frameLength)  == HAL_OK){printf("write frame data seq(%d)(data:0x%x..) to flash(addr:0x%08x) success\r\n",IAP_frameSeq,*app_flash_buf,flashdestination);IAP_frameCount++;}else /* An error occurred while writing to Flash memory */{printf("write frame data seq(%d) to flash fail\r\n",IAP_frameSeq);frameRight=0;}MEM_IF_DeInit();}}else{frameRight=0;}}else{frameRight=0;}if(!frameRight){printf("invalid frame data or process data fail\r\n");}uint8_t realdatalength=0;ackframe.originaldata_head=0x06;ackframe.originaldata_address=sysParameterStruct._Para_ControlEquiAddress;ackframe.originaldata_end=0x03;ackframe.originaldata_cmd=recvframe.originaldata_cmd;*(ackframe.originaldata_data+realdatalength)=IAP_frameSeq>>8;realdatalength++;*(ackframe.originaldata_data+realdatalength)=IAP_frameSeq;realdatalength++;*(ackframe.originaldata_data+realdatalength)=frameRight?0x06:0x15;realdatalength++;ackframe.originaldata_length=realdatalength;netconn_ack(&ackframe,clientad.client[clientindex]);}else{recvframe.originaldata_length=data[3];recvframe.originaldata_cs=data[len-2];recvframe.originaldata_end=data[len-1];if(recvframe.originaldata_length+6==len){for(int i=0;i<recvframe.originaldata_length;i++){recvdata[i]=data[4+i];}recvframe.originaldata_data=recvdata;processCmd(recvframe,&ackframe,clientindex);netconn_ack(&ackframe,clientad.client[clientindex]);continue;}}}}ackframe.originaldata_cmd=0xf3;ackframe.originaldata_length=0;netconn_ack(&ackframe,clientad.client[clientindex]);				}while(netbuf_next(clientrecvbuf)>=0);netbuf_delete(clientrecvbuf);}else if(err==ERR_CLSD||err==ERR_RST)break;	}if(clientad.state[clientindex]==1){if((err=netconn_getaddr(clientad.client[clientindex],&addr, &port, 0))==ERR_OK){sprintf((char*)iptxt, "%d.%d.%d.%d:%d", (uint8_t)(addr.addr),(uint8_t)(addr.addr>>8),(uint8_t)(addr.addr>>16),(uint8_t)(addr.addr>>24),port);  UsrLog("one ramote is closed:%s",iptxt); }clientad.state[clientindex]=0;netconn_close(clientad.client[clientindex]);netconn_delete(clientad.client[clientindex]);			vTaskDelete(clientad.client_taskid[clientindex]);}
}void processCmd(Controller_AckDataDef frame,Controller_AckDataDef* ackframe,uint8_t clientindex)
{//Controller_AckDataDef ackframe;ackframe->originaldata_head=0x06;ackframe->originaldata_address=sysParameterStruct._Para_ControlEquiAddress;ackframe->originaldata_end=0x03;ackframe->originaldata_cmd=frame.originaldata_cmd;ackframe->originaldata_length=0;uint8_t *databuf=ackframe->originaldata_data;uint8_t realdatalength=0;switch(frame.originaldata_cmd){case 0x51://start download appprintf("start download app\r\n");IAP_frameTotalCount=(uint16_t)(frame.originaldata_data[0] << 8 | frame.originaldata_data[1]);printf("app frames total count is %d\r\n",IAP_frameTotalCount);MEM_IF_IniT();if(MEM_If_Erase(APP2_ADDRESS,APP2_ADDRESS_END)!=HAL_OK){printf("erase flash fail, abort app downloading\r\n");isIAPStart=false;*(databuf+realdatalength)=0x15;realdatalength++;ackframe->originaldata_length=realdatalength;}else{printf("erase flash from %#x to %#x, wait for frame transmitting\r\n",APP2_ADDRESS,APP2_ADDRESS_END);IAP_frameCount=0;isIAPStart=true;*(databuf+realdatalength)=0x06;realdatalength++;ackframe->originaldata_length=realdatalength;}MEM_IF_DeInit();break;case 0x53://finish download appprintf("finish download app\r\n");uint16_t IAP_crc16=(uint16_t)(frame.originaldata_data[0] << 8 | frame.originaldata_data[1]);printf("receive app crc16 is %x\r\n",IAP_crc16);if(1)//(IAP_crc16==IAP_frameCRC){printf("pass crc check, finish download app\r\n");MEM_IF_IniT();MEM_If_Erase(UPGRADE_ADDRESS,UPGRADE_ADDRESS);MEM_If_Write_Byte(Upgrade,UPGRADE_ADDRESS,sizeof(Upgrade));MEM_IF_DeInit();*(databuf+realdatalength)=0x06;realdatalength++;ackframe->originaldata_length=realdatalength;isIAPStart=false;}else{printf("crc check fail, finish download app\r\n");*(databuf+realdatalength)=0x15;realdatalength++;ackframe->originaldata_length=realdatalength;isIAPStart=false;}break;case 0x5f:printf("receive abort download app command\r\n");isIAPStart=false;IAP_frameCount=0;break;/*
other cmd process...*/default:break;}
}

3. 上位机实现升级工具(C# winform)

    

 4. 实现效果

升级工具通过TCP与板卡进行通讯,之前版本是V20.2024.3

打开升级程序包bin文件

点击下载

开始下载,显示整片程序被分成399个包

下载完成,提示重启板卡完成升级

重启后,开始将程序从APP2拷贝到APP1

拷贝完成,跳转到APP1运行,程序已经更新成V20.2024.4

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

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

相关文章

一流的财务:搞数据!!!(干货)

“三流财务给数据&#xff0c;二流财务给分析报告&#xff0c;一流财务给....&#xff08;解决方案&#xff09;“这些文章应该很多人都看到过&#xff0c;这个口号粗看好像很有道理&#xff0c;但笔者并不认同&#xff0c;因为大家都忽略了一个重要的概念&#xff1a;数据&…

什么是rouge metric

采用分类任务的指标评估生成任务的问题 举个例子&#xff0c;在一个seq2seq模型中&#xff0c;黄金标签是“police killed the gunman”&#xff0c;模型输出是"the gunman police killed"&#xff0c;两句话的意思是有差别的&#xff0c;但是从unigram的角度&#…

虚 拟 化原理

1 概念&#xff1a; ①通俗理解&#xff1a; 虚拟化是在硬件和操作系统之间的实践 ②通过对计算机的服务层级的理解&#xff0c;理解虚拟化概念 抽离层级之间的依赖关系&#xff08;服务器虚拟化&#xff09; 2 虚拟化分类 ①按架构分类 ◆寄居架构&#xff1a;装在操作系统上…

OSCP靶场--Nickel

OSCP靶场–Nickel 考点(1.POST方法请求信息 2.ftp&#xff0c;ssh密码复用 3.pdf文件密码爆破) 1.nmap扫描 ┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.237.99 -sV -sC -p- --min-rate 5000 Starting Nmap 7.92 ( https://nmap.org ) at 2024-02-22 04:06 EST Nm…

5.1 Ajax数据爬取之初介绍

目录 1. Ajax 数据介绍 2. Ajax 分析 2.1 Ajax 例子 2.2 Ajax 分析方法 &#xff08;1&#xff09;在网页页面右键&#xff0c;检查 &#xff08;2&#xff09;找到network&#xff0c;ctrl R刷新 &#xff08;3&#xff09;找 Ajax 数据包 &#xff08;4&#xff09;…

【前后端的那些事】文件上传组件封装

文章目录 效果前端代码后端代码组件封装 效果 前端代码 /views/file/file.vue <template><el-row><el-uploadv-model:file-list"fileList"class"upload-demo"multiple:auto-upload"false":on-preview"handlePreview"…

Swiper.js:不识这个轮播图js库,说明你的前端还未入门

hello&#xff0c;我是贝格前端工场&#xff0c;本期给大家带来轮播图的s库&#xff1a;Swiper.js&#xff0c;用这个类库处理轮播图、幻灯片、画廊那是得心应手&#xff0c;非常的easy&#xff0c;欢迎老铁们点赞关注&#xff0c;如有前端定制开发需求可以私信我们。 一、Swip…

网络编程、UDP、TCP

计算机网络 就是将地理位置不同的具有独立功能的多台计算及外部设备&#xff0c;通过通信线路连接起来&#xff0c;在网络操作系统、网络管理软件以及网络通信协议的管理和协调下&#xff0c;实现资源共享和信息传递的计算机系统 目的 传播交流信息、数据交换、通信 如何做…

TensorRT及CUDA自学笔记003 CUDA编程模型、CUDA线程模型及其管理、CUDA内存模型及其管理

TensorRT及CUDA自学笔记003 CUDA编程模型、CUDA线程模型及其管理、CUDA内存模型及其管理 各位大佬&#xff0c;这是我的自学笔记&#xff0c;如有错误请指正&#xff0c;也欢迎在评论区学习交流&#xff0c;谢谢&#xff01; CUDA编程模型 我们使用CUDA_C语言进行CUDA编程&am…

【Vue3】‘vite‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

问题 今天拿到别人项目的时候&#xff0c;我平时比较习惯用pnpm&#xff0c;我就使用pnpm i先下载依赖包&#xff0c;下载完成后&#xff0c;启动项目&#xff0c;就开始报以下错误&#xff01; 但是当我执行pnpm i的时候&#xff0c;vite不应该就已经被我下载下来了吗 研究了…

【Java程序设计】【C00307】基于Springboot的基Hadoop的物品租赁管理系统(有论文)

基于Springboot的基Hadoop的物品租赁管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的基于 Hadoop的物品租赁系统的设计与实现&#xff0c;本系统有管理员、用户二种角色权限&#xff1b; 前台首页&#…

day11-项目集成SpringSecurity-今日指数

项目集成SpringSecurity 学习目标 理解自定义认证和授权过滤器流程&#xff1b;理解项目集成SprignSecurity流程&#xff1b; 第一章 自定义认证授权过滤器 1、SpringSecurity内置认证流程 通过研究SpringSecurity内置基于form表单认证的UsernamePasswordAuthenticationFi…

【工程院院士加盟】第四届计算机通信与人工智能国际会议

CCAI 2024 | Xian, Chinahttp://ccai.net/ - IEEE出版&#xff0c;EI核心和Scopus检索 - 工程院院士&#xff0c;IEEE Fellow等学术大咖主题演讲 - 会议时间-地点&#xff1a;2024年5月24-26日&#xff0c;中国西安 会议简介 Brief Introduction 作为人工智能的重要传播技术…

Linux环境下基本指令

今天我们一起来认识一下Linux环境下一些基本的指令&#xff0c;这些指令是我们学习Linux的基础&#xff0c;只有掌握了这些指令&#xff0c;我们才能在Linux环境下进一步学习知识&#xff0c;话不多说&#xff0c;我们开始&#xff08;以下演示操作是在云服务器的环境下&#x…

基于SSM的车位租赁系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的车位租赁系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…

【数据分析之Numpy基础004】数学运算大揭秘:轻松玩转ndarray的强大实力

ndarray的数学运算是一项非常重要的操作&#xff0c;包括不同对象之间的四则运算&#xff0c;三角函数变换、求和、求平均等操作 1、四则运算 如果参与运算的两个对象都是ndarray&#xff0c;并且形状相同&#xff0c;那么就可以进行对位之间的四则&#xff08; - * / &#x…

前后端分离vue.js+nodejs学生考勤请假系统 _fbo36

此系统设计主要采用的是nodejs语言来进行开发&#xff0c;采用vue框架技术&#xff0c;框架分为三层&#xff0c;分别是控制层Controller&#xff0c;业务处理层Service&#xff0c;持久层dao&#xff0c;能够采用多层次管理开发&#xff0c;对于各个模块设计制作有一定的安全性…

UI设计中,2D、2.5D、3D、4D该如何辨别?教会你

hello&#xff0c;我是大千UI工场&#xff0c;从事UI设计8年之久&#xff0c;在日常工作中经常听到一些概念&#xff0c;现在将这些概念图文并茂的呈现给您&#xff0c;欢迎点赞评论&#xff0c;如有设计需求&#xff0c;可以私信我们。 在UI设计中&#xff0c;2D、2.5D、3D和4…

【Pytorch深度学习开发实践学习】B站刘二大人课程笔记整理lecture09 Softmax多分类

代码&#xff1a; import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader import torch.nn as nn import torch.nn.functional as Fbatch_size 64 transform transforms.Compose([transforms.ToTensor(), transforms.Normali…

python:读 Freeplane.mm文件,使用 xml.etree 生成测试案例.csv文件

Freeplane 是一款基于 Java 的开源软件&#xff0c;继承 Freemind 的思维导图工具软件&#xff0c;它扩展了知识管理功能&#xff0c;在 Freemind 上增加了一些额外的功能&#xff0c;比如数学公式、节点属性面板等。 强大的节点功能&#xff0c;不仅仅节点的种类很多&#xf…