在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于串口環(huán)形隊(duì)列的IAP實(shí)現(xiàn)

技術(shù)讓夢(mèng)想更偉大 ? 來源:CSDN技術(shù)社區(qū) ? 2023-04-12 09:28 ? 次閱讀

我這里主要是記錄一下我所使用的方法,調(diào)試也花了兩天時(shí)間。 我所用的型號(hào)是STM32F103C8T6,這個(gè)IC有64KFlash和20K的RAM,也有小道說有后置隱藏的64K,也就是說其實(shí)是有128K,我一直也沒有測(cè)試,有空測(cè)測(cè),有大神這樣說,估計(jì)是可以的。 這里重點(diǎn)記錄一下我寫的IAP思路和代碼以及細(xì)節(jié)和遇到坑的地方。先大體的概述一下,最后貼上我認(rèn)為重點(diǎn)的代碼。 在概述之前先要解決一個(gè)問題,那就是sram空間和flash空間的問題,sram只有20K,flash有64k。解決的辦法有很多: 1)最常見的就是自己寫上位機(jī)軟件,通過分包發(fā)送,期間還可以加入加密算法,校驗(yàn)等等。 2)使用環(huán)形隊(duì)列,簡(jiǎn)單點(diǎn)說就是個(gè)環(huán)形數(shù)組,一邊接收上位機(jī)數(shù)據(jù),一邊往flash里面寫。 這里條件限制就采用第二種方法。所以即使是分給A和B的25K空間的flash空間,sram只有20K也是不能一次接收完所有的bin數(shù)據(jù)的,這里我只開辟了一個(gè)1K的BUF,使用尾插法寫入,我的測(cè)試應(yīng)用程序都在5-6K,用這樣的方法可以在9600波特率下測(cè)試穩(wěn)定,也試過57600的勉強(qiáng)可以的,115200就不行了。環(huán)形隊(duì)列代碼如下: C文件:

				#include"fy_looplist.h"  #include"fy_includes.h"   #ifndefNULL #defineNULL0 #endif  #ifndefmin #definemin(a,b)(a)<(b)?(a):(b)?// #endif  #defineDEBUG_LOOP1  staticintCreate(_loopList_s*p,unsignedchar*buf,unsignedintlen); staticvoidDelete(_loopList_s*p); staticintGet_Capacity(_loopList_s*p); staticintGet_CanRead(_loopList_s*p); staticintGet_CanWrite(_loopList_s*p); staticintRead(_loopList_s*p,void*buf,unsignedintlen); staticintWrite(_loopList_s*p,constvoid*buf,unsignedintlen);  struct_typdef_LoopList_list= { Create, Delete, Get_Capacity, Get_CanRead, Get_CanWrite, Read, Write };   //初始化環(huán)形緩沖區(qū) staticintCreate(_loopList_s*p,unsignedchar*buf,unsignedintlen) { if(NULL==p) { #ifDEBUG_LOOP printf("ERROR:inputlistisNULL "); #endif return0; } p->capacity=len; p->buf=buf; p->head=p->buf;//頭指向數(shù)組首地址 p->tail=p->buf;//尾指向數(shù)組首地址  return1; }  //刪除一個(gè)環(huán)形緩沖區(qū) staticvoidDelete(_loopList_s*p) { if(NULL==p) { #ifDEBUG_LOOP printf("ERROR:inputlistisNULL "); #endif return; }  p->buf=NULL;//地址賦值為空 p->head=NULL;//頭地址為空 p->tail=NULL;//尾地址尾空 p->capacity=0;//長(zhǎng)度為空 }  //獲取鏈表的長(zhǎng)度 staticintGet_Capacity(_loopList_s*p) { if(NULL==p) { #ifDEBUG_LOOP printf("ERROR:inputlistisNULL "); #endif return-1; } returnp->capacity; }  //返回能讀的空間 staticintGet_CanRead(_loopList_s*p) { if(NULL==p) { #ifDEBUG_LOOP printf("ERROR:inputlistisNULL "); #endif return-1; }  if(p->head==p->tail)//頭與尾相遇 { return0; }  if(p->headtail)//尾大于頭 { returnp->tail-p->head; }  returnGet_Capacity(p)-(p->head-p->tail);//頭大于尾 }  //返回能寫入的空間 staticintGet_CanWrite(_loopList_s*p) { if(NULL==p) { #ifDEBUG_LOOP printf("ERROR:inputlistisNULL "); #endif return-1; }  returnGet_Capacity(p)-Get_CanRead(p);//總的減去已經(jīng)寫入的空間 }   //p--要讀的環(huán)形鏈表 //buf--讀出的數(shù)據(jù) //count--讀的個(gè)數(shù) staticintRead(_loopList_s*p,void*buf,unsignedintlen) { intcopySz=0;  if(NULL==p) { #ifDEBUG_LOOP printf("ERROR:inputlistisNULL "); #endif return-1; }  if(NULL==buf) { #ifDEBUG_LOOP printf("ERROR:inputbufisNULL "); #endif return-2; }  if(p->headtail)//尾大于頭 { copySz=min(len,Get_CanRead(p));//比較能讀的個(gè)數(shù) memcpy(buf,p->head,copySz);//讀出數(shù)據(jù) p->head+=copySz;//頭指針加上讀取的個(gè)數(shù) returncopySz;//返回讀取的個(gè)數(shù) } else//頭大于等于了尾 { if(lenhead-p->buf))//讀的個(gè)數(shù)小于頭上面的數(shù)據(jù)量 { copySz=len;//讀出的個(gè)數(shù) memcpy(buf,p->head,copySz); p->head+=copySz; returncopySz; } else//讀的個(gè)數(shù)大于頭上面的數(shù)據(jù)量 { copySz=Get_Capacity(p)-(p->head-p->buf);//先讀出來頭上面的數(shù)據(jù) memcpy(buf,p->head,copySz); p->head=p->buf;//頭指針指向數(shù)組的首地址 //還要讀的個(gè)數(shù) copySz+=Read(p,(char*)buf+copySz,len-copySz);//接著讀剩余要讀的個(gè)數(shù) returncopySz; } } } //p--要寫的環(huán)形鏈表 //buf--寫出的數(shù)據(jù) //len--寫的個(gè)數(shù) staticintWrite(_loopList_s*p,constvoid*buf,unsignedintlen) { inttailAvailSz=0;//尾部剩余空間  if(NULL==p) { #ifDEBUG_LOOP printf("ERROR:listisempty "); #endif return-1; }  if(NULL==buf) { #ifDEBUG_LOOP printf("ERROR:bufisempty "); #endif return-2; }  if(len>=Get_CanWrite(p))//如果剩余的空間不夠 { #ifDEBUG_LOOP printf("ERROR:nomemory "); #endif return-3; }  if(p->head<=?p->tail)//頭小于等于尾 { tailAvailSz=Get_Capacity(p)-(p->tail-p->buf);//查看尾上面剩余的空間 if(len<=?tailAvailSz)//個(gè)數(shù)小于等于尾上面剩余的空間 { memcpy(p->tail,buf,len);//拷貝數(shù)據(jù)到環(huán)形數(shù)組 p->tail+=len;//尾指針加上數(shù)據(jù)個(gè)數(shù) if(p->tail==p->buf+Get_Capacity(p))//正好寫到最后 { p->tail=p->buf;//尾指向數(shù)組的首地址 } returnlen;//返回寫入的數(shù)據(jù)個(gè)數(shù) } else { memcpy(p->tail,buf,tailAvailSz);//填入尾上面剩余的空間 p->tail=p->buf;//尾指針指向數(shù)組首地址 //剩余空間剩余數(shù)據(jù)的首地址剩余數(shù)據(jù)的個(gè)數(shù) returntailAvailSz+Write(p,(char*)buf+tailAvailSz,len-tailAvailSz);//接著寫剩余的數(shù)據(jù) } } else//頭大于尾 { memcpy(p->tail,buf,len); p->tail+=len; returnlen; } }   /*********************************************ENDOFFILE********************************************/

1、整體思路

把64K的flash空間分成了4個(gè)部分,第一部分是BootLoader,第二部分是程序A(APP1),第三部分是程序B(APP2),第四部分是用來存儲(chǔ)一些變量和標(biāo)記的。下面是空間的分配情況。BootLoader程序可以用來更新程序A,而程序A又更新程序B,程序B可以更新程序A。 最開始的時(shí)候想的是程序A、B都帶更新了干嘛還多此一舉,其實(shí)這個(gè)Bootloader還是需要的。如果之后程序A、B和FLAG三部分,假設(shè)一種情況,在程序B中更新程序A中遇到問題,復(fù)位后直接成磚,因?yàn)槌绦駻在其實(shí)地址,上電直接運(yùn)行程序A,而程序A現(xiàn)在出問題了,那就沒招了。 所以加上BootLoader情況下,不管怎么樣BootLoader的程序是不會(huì)錯(cuò)的,因?yàn)楦虏粫?huì)更新BootLoader,計(jì)時(shí)更新出錯(cuò)了,還可以進(jìn)入BootLoader重新更新應(yīng)用程序。我見也有另外一種設(shè)計(jì)方法的,就是應(yīng)用程序只有一個(gè)程序A,把程序B區(qū)域的flash當(dāng)作緩存用,重啟的時(shí)候判斷B區(qū)域有沒有更新程序,有的話就把B拷貝到A,然后擦除B,我感覺這樣其實(shí)也一樣,反正不管怎么樣這部分空間是必須要預(yù)留出來的。b8815812-d893-11ed-bfe3-dac502259ad0.png 這里在keil中配置的只有起始地址和大小,并沒有結(jié)束地址,我這里也就不詳細(xì)計(jì)算了。總體就是這樣的。

2、Bootloader部分

BootLoader的任務(wù)有兩個(gè),一是在串口中斷接收BIN的數(shù)據(jù)和主循環(huán)內(nèi)判斷以及更新APP1的程序,二是在在程序開始的時(shí)候判斷有沒有可用的用戶程序進(jìn)而跳轉(zhuǎn)到用戶程序(程序A或者程序B)。 簡(jiǎn)單介紹下執(zhí)行流程: 系統(tǒng)上電首先肯定是執(zhí)行BootLoader程序的,因?yàn)樗钠鹗嫉刂肪褪?x08000000,首先是初始化,然后判斷按鍵是否手動(dòng)升級(jí)程序,按鍵按下了就把FLAG部分的APP標(biāo)記寫成0xFFFF(這里用的宏定義方式),再執(zhí)行執(zhí)行App_Check(),否則就直接執(zhí)行App_Check()。 App_Check函數(shù)是來判斷程序A和程序B的,最開始BootLoader是用swd方式下載的,下載的時(shí)候全片擦除,所以會(huì)執(zhí)行主循環(huán)的Update_Check函數(shù)。此時(shí)串口打印出“等待接收APP1的BIN”,這個(gè)時(shí)候發(fā)送APP1的BIN過去,等接受完了,會(huì)寫在FLAG區(qū)域?qū)憘€(gè)0xAAAA,代表程序A寫入了,下次啟動(dòng)可以執(zhí)行程序A。 主要代碼部分

				#include"fy_includes.h"  /* 晶振使用的是16M其他頻率在system_stm32f10x.c中修改 使用printf需要在fy_includes.h修改串口重定向?yàn)?definePRINTF_USARTUSART1 */   /* Bootloader程序  完成三個(gè)任務(wù)  步驟1.檢查是否有程序更新,如果有就擦寫flash進(jìn)行更新,如果沒有進(jìn)入步驟2 步驟2.判斷app1有沒有可執(zhí)行程序,如果有就執(zhí)行,如果沒有進(jìn)入步驟3 步驟3.串口等待接收程序固件  */  #defineFLAG_UPDATE_APP10xBBAA #defineFLAG_UPDATE_APP20xAABB #defineFLAG_APP10xAAAA #defineFLAG_APP20xBBBB #defineFLAG_NONE0xFFFF  _loopList_slist1; u8rxbuf[1024]; u8temp8[2]; u16temp16; u32rxlen=0; u32applen=0; u32write_addr; u8overflow=0; u32now_tick=0; u8_cnt_10ms=0;  staticvoidApp_Check(void) { //獲取程序標(biāo)號(hào) STMFLASH_Read(FLASH_PARAM_ADDR,&temp16,1);  if(temp16==FLAG_APP1)//執(zhí)行程序A { if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//可執(zhí)行? { printf("執(zhí)行程序A... "); IAP_RunApp(FLASH_APP1_ADDR); } else { printf("程序A不可執(zhí)行,擦除APP1程序所在空間... "); for(u8i=10;i<35;i++) { STMFLASH_Erase(FLASH_BASE+i*STM_SECTOR_SIZE,512); } printf("程序A所在空間擦除完成... "); printf("將執(zhí)行程序B... "); if(((*(vu32*)(FLASH_APP2_ADDR+4))&0xFF000000)==0x08000000)//可執(zhí)行? { printf("執(zhí)行程序B... "); IAP_RunApp(FLASH_APP2_ADDR); } else { printf("程序B不可執(zhí)行,擦除APP2程序所在空間... "); for(u8i=35;i<60;i++) { STMFLASH_Erase(FLASH_BASE+i*STM_SECTOR_SIZE,512); } printf("程序B所在空間擦除完成... "); } } }  if(temp16==FLAG_APP2)//執(zhí)行程序B { if(((*(vu32*)(FLASH_APP2_ADDR+4))&0xFF000000)==0x08000000)//可執(zhí)行? { printf("執(zhí)行程序B... "); IAP_RunApp(FLASH_APP2_ADDR); } else { printf("程序B不可執(zhí)行,擦除APP2程序所在空間... "); for(u8i=35;i<60;i++) { STMFLASH_Erase(FLASH_BASE+i*STM_SECTOR_SIZE,512); } printf("程序B所在空間擦除完成... "); printf("將執(zhí)行程序A... "); if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//可執(zhí)行? { printf("執(zhí)行程序A... "); IAP_RunApp(FLASH_APP1_ADDR); } else { printf("程序A不可執(zhí)行,擦除APP1程序所在空間... "); for(u8i=10;i<35;i++) { STMFLASH_Erase(FLASH_BASE+i*STM_SECTOR_SIZE,512); } printf("程序A所在空間擦除完成... "); } } }  if(temp16==FLAG_NONE) { printf("擦除App1程序所在空間... "); for(u8i=10;i<35;i++) { STMFLASH_Erase(FLASH_BASE+i*STM_SECTOR_SIZE,512); } printf("程序A所在空間擦除完成... "); } }   staticvoidUpdate_Check(void) { if(_list.Get_CanRead(&list1)>1) { _list.Read(&list1,&temp8,2);//讀取兩個(gè)數(shù)據(jù)  temp16=(u16)(temp8[1]<<8)|temp8[0];  STMFLASH_Write(write_addr,&temp16,1); write_addr+=2; }  if(GetSystick_ms()-now_tick>10)//10ms { now_tick=GetSystick_ms(); _cnt_10ms++; if(applen==rxlen&&rxlen)//接收完成 { if(overflow) { printf("接收溢出,無法更新,請(qǐng)重試 "); SoftReset();//軟件復(fù)位 } else { printf(" 接收BIN文件完成,長(zhǎng)度為%d ",applen);  temp16=FLAG_APP1; STMFLASH_Write(FLASH_PARAM_ADDR,&temp16,1);//寫入標(biāo)記 temp16=(u16)(applen>>16); STMFLASH_Write(FLASH_PARAM_ADDR+2,&temp16,1); temp16=(u16)(applen); STMFLASH_Write(FLASH_PARAM_ADDR+4,&temp16,1);  SoftReset();//軟件復(fù)位 } }elseapplen=rxlen;//更新長(zhǎng)度 } if(_cnt_10ms>=50) { _cnt_10ms=0; Led_Tog(); if(!rxlen) { printf("等待接收App1的BIN文件 "); } } } intmain(void) { NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//開啟AFIO時(shí)鐘 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//禁止JTAG保留SWD  Systick_Configuration(); Led_Configuration(); Key_Configuration(); Usart1_Configuration(9600); USART_ITConfig(USART1,USART_IT_IDLE,DISABLE);//關(guān)閉串口空閑中斷  printf("thisisbootloader! "); if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==SET) { Delay_ms(100); if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==SET)//開機(jī)按下keyup進(jìn)行更新 { printf("主動(dòng)更新,"); temp16=FLAG_NONE; STMFLASH_Write(FLASH_PARAM_ADDR,&temp16,1); } else {  } }  App_Check();  printf("執(zhí)行BootLoader程序... "); _list.Create(&list1,rxbuf,sizeof(rxbuf));  write_addr=FLASH_APP1_ADDR;  while(1) { Update_Check(); } }  //USART1串口中斷函數(shù) voidUSART1_IRQHandler(void) { if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) { u8temp=USART1->DR; if(_list.Write(&list1,&temp,1)<=0) { overflow=1; } rxlen++; } }
					其中的宏:

				//FLASH起始地址 #defineSTM32_FLASH_BASE0x08000000//STM32FLASH的起始地址 #defineFLASH_APP1_ADDRSTM32_FLASH_BASE+0x2800//偏移10K #defineFLASH_APP2_ADDRSTM32_FLASH_BASE+0x8c00//偏移35K #defineFLASH_PARAM_ADDRSTM32_FLASH_BASE+0xF000//偏移60K

3、程序A和程序B部分

這兩個(gè)都是用戶程序,這兩個(gè)程序都帶有更新程序功能,我這里用作測(cè)試的A和B程序大體都差不多,不同的地方就是程序A接收的BIN用來更新程序B,程序B接收的BIN用來更新A,還有就是中斷向量表便宜不同以及打印輸出不同。 應(yīng)用程序部分沒什么說的,程序A和B很類似,這里貼上A的代碼

				#include"fy_includes.h"  /* 晶振使用的是16M其他頻率在system_stm32f10x.c中修改 使用printf需要在fy_includes.h修改串口重定向?yàn)?definePRINTF_USARTUSART1 */   /* APP1程序  完成兩個(gè)任務(wù)  1.執(zhí)行本身的app任務(wù),同時(shí)監(jiān)聽程序更新,監(jiān)聽到停止本身的任務(wù)進(jìn)入到狀態(tài)2 2.等待接收完成,完成后復(fù)位重啟  */  #defineFLAG_UPDATE_APP10xBBAA #defineFLAG_UPDATE_APP20xAABB #defineFLAG_APP10xAAAA #defineFLAG_APP20xBBBB #defineFLAG_NONE0xFFFF  _loopList_slist1; u8rxbuf[1024]; u8temp8[2]; u16temp16; u32rxlen=0; u32applen=0; u32write_flsh_addr; u8update=0; u8overflow=0; u32now_tick; u8_cnt_10ms=0;  staticvoidUpdate_Check(void) { if(update)//監(jiān)聽到有更新程序 { write_flsh_addr=FLASH_APP2_ADDR;//App1更新App2的程序 overflow=0; rxlen=0; _list.Create(&list1,rxbuf,sizeof(rxbuf));  printf("擦除APP2程序所在空間... "); for(u8i=35;i<60;i++)//擦除APP2所在空間程序 { STMFLASH_Erase(FLASH_BASE+i*STM_SECTOR_SIZE,512); } printf("程序B所在空間擦除完成... ");  while(1) { if(_list.Get_CanRead(&list1)>1) { _list.Read(&list1,&temp8,2);//讀取兩個(gè)數(shù)據(jù)  temp16=(u16)(temp8[1]<<8)|temp8[0];  STMFLASH_Write(write_flsh_addr,&temp16,1); write_flsh_addr+=2; }  if(GetSystick_ms()-now_tick>10)//10ms { now_tick=GetSystick_ms(); _cnt_10ms++; if(applen==rxlen&&rxlen)//接收完成 { if(overflow) { printf(" 接收溢出,請(qǐng)重新嘗試 "); SoftReset();//軟件復(fù)位 }  printf(" 接收BIN文件完成,長(zhǎng)度為%d ",applen);  temp16=FLAG_APP2; STMFLASH_Write(FLASH_PARAM_ADDR,&temp16,1);//寫入標(biāo)記 temp16=(u16)(applen>>16); STMFLASH_Write(FLASH_PARAM_ADDR+2,&temp16,1); temp16=(u16)(applen); STMFLASH_Write(FLASH_PARAM_ADDR+4,&temp16,1);  printf("系統(tǒng)將重啟.... "); SoftReset();//軟件復(fù)位 }elseapplen=rxlen;//更新長(zhǎng)度 }  if(_cnt_10ms>=50) { _cnt_10ms=0; Led_Tog(); if(!rxlen) { printf("等待接收App2的BIN文件 "); } } }//while(1) } }   staticvoidApp_Task(void) { if(GetSystick_ms()-now_tick>500) { now_tick=GetSystick_ms(); printf("正在運(yùn)行APP1 "); Led_Tog(); } }  intmain(void) { SCB->VTOR=FLASH_APP1_ADDR;  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//開啟AFIO時(shí)鐘 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//禁止JTAG保留SWD  Systick_Configuration(); Led_Configuration(); Usart1_Configuration(9600); printf("thisisAPP1! ");  Delay_ms(500);  while(1) { Update_Check(); App_Task(); } }  //USART1串口中斷函數(shù) voidUSART1_IRQHandler(void) { if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) { u8temp=USART1->DR; if(update) { if(_list.Write(&list1,&temp,1)<=?0) { overflow=1; } } else { rxbuf[rxlen]=temp; } rxlen++; } if(USART_GetITStatus(USART1,USART_IT_IDLE)!=RESET) { u8temp=USART1->DR; temp=USART1->SR;  if(strstr((char*)rxbuf,"AppUpdate")&&rxlen) { update=1; USART_ITConfig(USART1,USART_IT_IDLE,DISABLE);//關(guān)閉串口空閑中斷 } else { Usart1_SendBuf(rxbuf,rxlen); } rxlen=0; }  }
					這里如果要移植需要注意的就是向量表的偏移以及更新擦寫的區(qū)域。

4、剩余的4Kflash空間部分

這里其實(shí)只是用來存儲(chǔ)2個(gè)變量,一個(gè)是程序運(yùn)行標(biāo)記,一個(gè)是接收到的程序長(zhǎng)度,程序標(biāo)記還有點(diǎn)把子用,程序長(zhǎng)度其實(shí)要不要都無所謂。

5、遇到的坑

最值得一說的就是更新部分,最開始程序沒有加入擦除flash,遇到的情況就是下載完BootLoader后發(fā)送app1沒問題,在app1中更新App2也沒問題,然后app2再更新app1就出問題了。直觀的結(jié)果就是循環(huán)隊(duì)列溢出,原因就是app2在更新app1前沒有去擦除app1所在的flash,所以在寫的時(shí)候就要去擦除,這樣就寫的很慢,然而串口接收是不停的收,所以就是寫不過來。
審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • FlaSh
    +關(guān)注

    關(guān)注

    10

    文章

    1656

    瀏覽量

    150597
  • 調(diào)試
    +關(guān)注

    關(guān)注

    7

    文章

    602

    瀏覽量

    34406
  • 串口
    +關(guān)注

    關(guān)注

    14

    文章

    1580

    瀏覽量

    78327
  • IAP
    IAP
    +關(guān)注

    關(guān)注

    2

    文章

    164

    瀏覽量

    24738
  • bootloader
    +關(guān)注

    關(guān)注

    2

    文章

    238

    瀏覽量

    46327

原文標(biāo)題:基于串口環(huán)形隊(duì)列的IAP實(shí)現(xiàn)!

文章出處:【微信號(hào):技術(shù)讓夢(mèng)想更偉大,微信公眾號(hào):技術(shù)讓夢(mèng)想更偉大】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    基于STM32的串口環(huán)形隊(duì)列IAP調(diào)試

    基于STM32的串口環(huán)形隊(duì)列IAP調(diào)試心得
    的頭像 發(fā)表于 09-18 15:33 ?1857次閱讀
    基于STM32的<b class='flag-5'>串口</b><b class='flag-5'>環(huán)形</b><b class='flag-5'>隊(duì)列</b><b class='flag-5'>IAP</b>調(diào)試

    STM32串口環(huán)形緩沖區(qū)的實(shí)現(xiàn)

    試試用代碼實(shí)現(xiàn)吧!從隊(duì)列串口緩沖區(qū)的實(shí)現(xiàn)串口環(huán)形緩沖區(qū)收發(fā):在很多入門級(jí)教程中,我們知道的
    發(fā)表于 10-16 11:40

    請(qǐng)問串口接受用環(huán)形隊(duì)列,發(fā)送也能用嗎?

    串口接受用環(huán)形隊(duì)列,發(fā)送也可以用?發(fā)送用普通的中斷也可以
    發(fā)表于 05-07 07:56

    環(huán)形隊(duì)列串口數(shù)據(jù)接收中的使用

    前言??書接上回,前文主要介紹了環(huán)形隊(duì)列實(shí)現(xiàn)原理以及C語言實(shí)現(xiàn)及測(cè)試過程,本文將回歸到嵌入式平臺(tái)的應(yīng)用中,話不多說,淦,上干貨!實(shí)驗(yàn)?zāi)康腍AL庫(kù)下
    發(fā)表于 12-06 06:27

    如何使用隊(duì)列實(shí)現(xiàn)STM32串口環(huán)形緩沖?

    串口環(huán)形緩沖的好處是什么?如何使用隊(duì)列實(shí)現(xiàn)STM32串口環(huán)形緩沖?
    發(fā)表于 12-07 07:13

    基于stm32串口環(huán)形緩沖隊(duì)列處理機(jī)制是什么

    基于stm32串口環(huán)形緩沖隊(duì)列處理機(jī)制是什么
    發(fā)表于 12-08 07:06

    實(shí)現(xiàn)隊(duì)列環(huán)形緩沖的方法

    串口隊(duì)列環(huán)形緩沖區(qū)隊(duì)列串口環(huán)形緩沖的好處代碼實(shí)現(xiàn)
    發(fā)表于 02-21 07:11

    環(huán)形隊(duì)列的操作如何去實(shí)現(xiàn)

    環(huán)形隊(duì)列結(jié)構(gòu)的定義是什么?環(huán)形隊(duì)列的操作如何去實(shí)現(xiàn)呢?
    發(fā)表于 02-25 06:35

    深度解析數(shù)據(jù)結(jié)構(gòu)與算法篇之隊(duì)列環(huán)形隊(duì)列實(shí)現(xiàn)

    的位置。 02 — 環(huán)形隊(duì)列實(shí)現(xiàn) 要想將元素放入隊(duì)列我們必須知道對(duì)頭和隊(duì)尾,在隊(duì)列長(zhǎng)度不能無限大的條件下我們還要知道
    的頭像 發(fā)表于 06-18 10:07 ?2098次閱讀

    STM32串口環(huán)形緩沖--使用隊(duì)列實(shí)現(xiàn)(開放源碼)

    串口隊(duì)列環(huán)形緩沖區(qū)隊(duì)列串口環(huán)形緩沖的好處代碼實(shí)現(xiàn)
    發(fā)表于 12-24 19:04 ?28次下載
    STM32<b class='flag-5'>串口</b><b class='flag-5'>環(huán)形</b>緩沖--使用<b class='flag-5'>隊(duì)列</b><b class='flag-5'>實(shí)現(xiàn)</b>(開放源碼)

    基于STM32的串口環(huán)形隊(duì)列IAP調(diào)試心得

    使用環(huán)形隊(duì)列,簡(jiǎn)單點(diǎn)說就是個(gè)環(huán)形數(shù)組,一邊接收上位機(jī)數(shù)據(jù),一邊往flash里面寫。
    發(fā)表于 02-08 15:22 ?5次下載
    基于STM32的<b class='flag-5'>串口</b><b class='flag-5'>環(huán)形</b><b class='flag-5'>隊(duì)列</b><b class='flag-5'>IAP</b>調(diào)試心得

    STM32進(jìn)階之串口環(huán)形緩沖區(qū)實(shí)現(xiàn)

    碼代碼的應(yīng)該學(xué)數(shù)據(jù)結(jié)構(gòu)都學(xué)過隊(duì)列環(huán)形隊(duì)列隊(duì)列的一種特殊形式,應(yīng)用挺廣泛的。因?yàn)橛刑辔恼玛P(guān)于這方面的內(nèi)容,理論知識(shí)可以看別人的,下面寫得挺好的:STM32進(jìn)階之
    發(fā)表于 12-06 10:00 ?3273次閱讀

    嵌入式環(huán)形隊(duì)列和消息隊(duì)列實(shí)現(xiàn)

    嵌入式環(huán)形隊(duì)列和消息隊(duì)列實(shí)現(xiàn)數(shù)據(jù)緩存和通信的常見數(shù)據(jù)結(jié)構(gòu),廣泛應(yīng)用于嵌入式系統(tǒng)中的通信協(xié)議和領(lǐng)域。
    的頭像 發(fā)表于 04-14 11:52 ?1837次閱讀

    嵌入式環(huán)形隊(duì)列和消息隊(duì)列是如何去實(shí)現(xiàn)的?

    嵌入式環(huán)形隊(duì)列和消息隊(duì)列實(shí)現(xiàn)數(shù)據(jù)緩存和通信的常見數(shù)據(jù)結(jié)構(gòu),廣泛應(yīng)用于嵌入式系統(tǒng)中的通信協(xié)議和領(lǐng)域。
    發(fā)表于 05-20 14:55 ?1282次閱讀

    嵌入式環(huán)形隊(duì)列與消息隊(duì)列實(shí)現(xiàn)原理

    嵌入式環(huán)形隊(duì)列,也稱為環(huán)形緩沖區(qū)或循環(huán)隊(duì)列,是一種先進(jìn)先出(FIFO)的數(shù)據(jù)結(jié)構(gòu),用于在固定大小的存儲(chǔ)區(qū)域中高效地存儲(chǔ)和訪問數(shù)據(jù)。其主要特點(diǎn)包括固定大小的數(shù)組和兩個(gè)指針(頭指針和尾指針
    的頭像 發(fā)表于 09-02 15:29 ?975次閱讀
    主站蜘蛛池模板: 国产一区美女视频 | 亚洲一区二区三区免费 | 操女人在线| 日本黄色影片在线观看 | 天天做天天爽天天谢 | 亚久久| 久久精品视频国产 | 日本在线不卡一区二区 | 久久婷婷色综合老司机 | 一区不卡视频 | 国内一国产农村妇女一级毛片 | avtom影院永久转四虎入口 | 日本暴力喉深到呕吐hd | 久久综合久久88 | 5x性区m免费毛片视频看看 | 亚洲一区欧美一区 | 日本在线不卡视频 | 天天插天天插天天插 | 国产资源视频 | 国产在线综合网 | 俄罗斯一级特黄黄大片 | 国产三级毛片视频 | 性欧美护士18xxxxhd视频 | 日韩免费一区 | 天天鲁天天爽天天视频 | 欧美综合色 | 77788色淫免费网站视频 | 又黄又湿又爽 | 99久久成人国产精品免费 | 边做饭边被躁欧美三级小说 | 亚洲啪啪网站 | 毛片一级黄色 | 久久就是精品 | 深夜视频在线 | 中文字幕一区二区三区视频在线 | 美女被玩 | 天堂在线视频网站 | 亚洲黄色三级网站 | 亚洲天天在线 | 午夜免费福利视频 | 欧美h网|