日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

串口IAP实验

發(fā)布時(shí)間:2023/12/16 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 串口IAP实验 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

IAP,即在應(yīng)用編程。很多單片機(jī)都支持這個(gè)功能,STM32也不例外。在之前的FLASH模擬EEPROM實(shí)驗(yàn)里面,我們學(xué)習(xí)了STM32的FLASH自編程,本章我們將結(jié)合FLASH自編程的知識(shí),通過(guò)STM32的串口實(shí)現(xiàn)一個(gè)簡(jiǎn)單的IAP功能。fficeffice" />

48.1 IAP簡(jiǎn)介???

IAP(In Application Programming)即在應(yīng)用編程,IAP是用戶自己的程序在運(yùn)行過(guò)程中對(duì)User Flash的部分區(qū)域進(jìn)行燒寫(xiě),目的是為了在產(chǎn)品發(fā)布后可以方便地通過(guò)預(yù)留的通信口對(duì)產(chǎn)品中的固件程序進(jìn)行更新升級(jí)。 通常實(shí)現(xiàn)IAP功能時(shí),即用戶程序運(yùn)行中作自身的更新操作,需要在設(shè)計(jì)固件程序時(shí)編寫(xiě)兩個(gè)項(xiàng)目代碼,
第一個(gè)項(xiàng)目程序不執(zhí)行正常的功能操作,而只是通過(guò)某種通信方式(如USB、USART)接收程序或數(shù)據(jù),執(zhí)行對(duì)第二部分代碼的更新;第二個(gè)項(xiàng)目代碼才是真正的功能代碼。這兩部分項(xiàng)目代碼都同時(shí)燒錄在User Flash中,當(dāng)芯片上電后,首先是第一個(gè)項(xiàng)目代碼開(kāi)始運(yùn)行,它作如下操作:   

1)檢查是否需要對(duì)第二部分代碼進(jìn)行更新   

2)如果不需要更新則轉(zhuǎn)到4)   

3)執(zhí)行更新操作   

4)跳轉(zhuǎn)到第二部分代碼執(zhí)行   

第一部分代碼必須通過(guò)其它手段,如JTAG或ISP燒入;第二部分代碼可以使用第一部分代碼IAP功能燒入,也可以和第一部分代碼一起燒入,以后需要程序更新是再通過(guò)第一部分IAP代碼更新。  

我們將第一個(gè)項(xiàng)目代碼稱之為Bootloader程序,第二個(gè)項(xiàng)目代碼稱之為APP程序,他們存放在STM32 FLASH的不同地址范圍,一般從最低地址區(qū)開(kāi)始存放Bootloader,
緊跟其后的就是APP程序(注意,如果FLASH容量足夠,是可以設(shè)計(jì)很多APP程序的,本章我們只討論一個(gè)APP程序的情況)。這樣我們就是要實(shí)現(xiàn)2個(gè)程序:Bootloader和APP。 

STM32的APP程序不僅可以放到FLASH里面運(yùn)行,也可以放到SRAM里面運(yùn)行,本章,我們將制作兩個(gè)APP,一個(gè)用于FLASH運(yùn)行,一個(gè)用于SRAM運(yùn)行。

我們先來(lái)看看STM32正常的程序運(yùn)行流程,如圖48.1.1所示:

?



圖48.1.1 STM32正常運(yùn)行流程圖

?????? STM32的內(nèi)部閃存(FLASH)地址起始于0x08000000,一般情況下,程序文件就從此地址開(kāi)始寫(xiě)入。此外STM32是基于Cortex-M3內(nèi)核的微控制器,其內(nèi)部通過(guò)一張“中斷向量表”
來(lái)響應(yīng)中斷,程序啟動(dòng)后,將首先從“中斷向量表”取出復(fù)位中斷向量執(zhí)行復(fù)位中斷程序完成啟動(dòng),而這張“中斷向量表”的起始地址是0x08000004,當(dāng)中斷來(lái)臨,STM32的內(nèi)部硬
件機(jī)制亦會(huì)自動(dòng)將PC指針定位到“中斷向量表”處,并根據(jù)中斷源取出對(duì)應(yīng)的中斷向量執(zhí)行中斷服務(wù)程序。

?????? 在圖48.1.1中,STM32在復(fù)位后,先從0X08000004地址取出復(fù)位中斷向量的地址,并跳轉(zhuǎn)到復(fù)位中斷服務(wù)程序,如圖標(biāo)號(hào)①所示;在復(fù)位中斷服務(wù)程序執(zhí)行完之后,會(huì)跳轉(zhuǎn)到我們
的main函數(shù),如圖標(biāo)號(hào)②所示;而我們的main函數(shù)一般都是一個(gè)死循環(huán),在main函數(shù)執(zhí)行過(guò)程中,如果收到中斷請(qǐng)求(發(fā)生重中斷),此時(shí)STM32強(qiáng)制將PC指針指回中斷向量表處,如圖標(biāo)號(hào)③所示;然后,根據(jù)中斷源進(jìn)入相應(yīng)的中斷服務(wù)程序,如圖標(biāo)號(hào)④所示;在執(zhí)行完中斷服務(wù)程序以后,程序再次返回main函數(shù)執(zhí)行,如圖標(biāo)號(hào)⑤所示。

?????? 當(dāng)加入IAP程序之后,程序運(yùn)行流程如圖48.1.2所示:

?

?????? 在圖48.1.2所示流程中,STM32復(fù)位后,還是從0X08000004地址取出復(fù)位中斷向量的地址,并跳轉(zhuǎn)到復(fù)位中斷服務(wù)程序,在運(yùn)行完復(fù)位中斷服務(wù)程序之后跳轉(zhuǎn)到IAP的main函數(shù),
如圖標(biāo)號(hào)①所示,此部分同圖48.1.1一樣;在執(zhí)行完IAP以后(即將新的APP代碼寫(xiě)入STM32的FLASH,灰底部分。新程序的復(fù)位中斷向量起始地址為0X08000004+N+M),跳轉(zhuǎn)至
新寫(xiě)入程序的復(fù)位向量表,取出新程序的復(fù)位中斷向量的地址,并跳轉(zhuǎn)執(zhí)行新程序的復(fù)位中斷服務(wù)程序,隨后跳轉(zhuǎn)至新程序的main函數(shù),如圖標(biāo)號(hào)②和③所示,同樣main函數(shù)為一個(gè)
死循環(huán),并且注意到此時(shí)STM32的FLASH,在不同位置上,共有兩個(gè)中斷向量表。

?????? 在main函數(shù)執(zhí)行過(guò)程中,如果CPU得到一個(gè)中斷請(qǐng)求,PC指針仍強(qiáng)制跳轉(zhuǎn)到地址0X08000004中斷向量表處,而不是新程序的中斷向量表,如圖標(biāo)號(hào)④所示;程序再根據(jù)我們?cè)O(shè)置
的中斷向量表偏移量,跳轉(zhuǎn)到對(duì)應(yīng)中斷源新的中斷服務(wù)程序中,如圖標(biāo)號(hào)⑤所示;在執(zhí)行完中斷服務(wù)程序后,程序返回main函數(shù)繼續(xù)運(yùn)行,如圖標(biāo)號(hào)⑥所示。

?????? 通過(guò)以上兩個(gè)過(guò)程的分析,我們知道IAP程序必須滿足兩個(gè)要求:

  • 新程序必須在IAP程序之后的某個(gè)偏移量為x的地址開(kāi)始;
  • 必須將新程序的中斷向量表相應(yīng)的移動(dòng),移動(dòng)的偏移量為x;
  • 本章,我們有2個(gè)APP程序,一個(gè)為FLASH的APP,程序在FLASH中運(yùn)行,另外一個(gè)位SRAM的APP,程序運(yùn)行在SRAM中,圖48.1.2雖然是針對(duì)FLASH APP來(lái)說(shuō)的,但是在

    SRAM里面運(yùn)行的過(guò)程和FLASH基本一致,只是需要設(shè)置向量表的地址為SRAM的地址。

    1.APP程序起始地址設(shè)置方法

    隨便打開(kāi)一個(gè)之前的實(shí)例工程,點(diǎn)擊Options for TargetàTarget選項(xiàng)卡,如圖48.1.3所示:

    圖48.1.3 FLASH APP Target選項(xiàng)卡設(shè)置

    ?????? 默認(rèn)的條件下,圖中IROM1的起始地址(Start)一般為0X08000000,大小(Size)為0X80000,即從0X08000000開(kāi)始的512K空間為我們的程序存儲(chǔ)(因?yàn)槲覀兊腟TM32F103ZET6的
    FLASH大小是512K)。而圖中,我們?cè)O(shè)置起始地址(Start)為0X08010000,即偏移量為0X10000(64K字節(jié)),因而,留給APP用的FLASH空間(Size)只有0X80000-0X10000=0X70000
    (448K字節(jié))大小了。設(shè)置好Start和Szie,就完成APP程序的起始地址設(shè)置。

    ?????? 這里的64K字節(jié),需要大家根據(jù)Bootloader程序大小進(jìn)行選擇,比如我們本章的Bootloader程序?yàn)?2K左右,理論上我們只需要確保APP起始地址在Bootloader之后,
    并且偏移量為0X200的倍數(shù)即可(相關(guān)知識(shí),請(qǐng)參考:http://www.openedv.com/posts/list/392.htm)。這里我們選擇64K(0X10000)字節(jié),留了一些余量,方便Bootloader以后的升級(jí)修改。

    ?????? 這是針對(duì)FLASH APP的起始地址設(shè)置,如果是SRAM APP,那么起始地址設(shè)置如圖48.1.4所示:

    ?

    圖48.1.4 SRAM APP Target選項(xiàng)卡設(shè)置

    ?????? 這里我們將IROM1的起始地址(Start)定義為:0X20001000,大小為0XA000(40K字節(jié)),即從地址0X20000000偏移0X1000開(kāi)始,存放APP代碼。因?yàn)檎麄€(gè)STM32F103ZET6的
    SRAM大小為64K字節(jié),所以IRAM1(SRAM)的起始地址變?yōu)?X2000B000(0x20001000+0xA000=0X2000B000),大小只有0X5000(20K字節(jié))。這樣,整個(gè)STM32F103ZET6的SRAM
    分配情況為:最開(kāi)始的4K給Bootloader程序使用,隨后的40K存放APP程序,最后20K,用作APP程序的內(nèi)存。這個(gè)分配關(guān)系大家可以根據(jù)自己的實(shí)際情況修改,不一定和我們這里的設(shè)
    置一模一樣,不過(guò)也需要注意,保證偏移量為0X200的倍數(shù)(我們這里為0X1000)。

    ?????? 2.中斷向量表的偏移量設(shè)置方法

    ?????? 之前我們講解過(guò),在系統(tǒng)啟動(dòng)的時(shí)候,會(huì)首先調(diào)用systemInit函數(shù)初始化時(shí)鐘系統(tǒng),同時(shí)systemInit還完成了中斷向量表的設(shè)置,我們可以打開(kāi)systemInit函數(shù),看看函數(shù)體的結(jié)尾處有這樣幾行代碼:

    #ifdef VECT_TAB_SRAM

    SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;

    ?/* Vector Table Relocation in Internal SRAM. */

    #else

    SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;

    /* Vector Table Relocation in Internal FLASH. */

    #endif

    從代碼可以理解,VTOR寄存器存放的是中斷向量表的起始地址。默認(rèn)的情況VECT_TAB_SRAM是沒(méi)有定義,所以執(zhí)行SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; ?

    對(duì)于FLASH APP,我們?cè)O(shè)置為FLASH_BASE+偏移量0x10000,所以我們可以在FLASH APP的main函數(shù)最開(kāi)頭處添加如下代碼實(shí)現(xiàn)中斷向量表的起始地址的重設(shè):

    SCB->VTOR = FLASH_BASE | 0x10000;

    ?????? 以上是FLASH APP的情況,當(dāng)使用SRAM APP的時(shí)候,我們?cè)O(shè)置起始地址為:SRAM_bASE+0x1000,同樣的方法,我們?cè)赟RAM APP的main函數(shù)最開(kāi)始處,添加下面代碼:

    SCB->VTOR = SRAM_BASE | 0x1000;

    ?????? 這樣,我們就完成了中斷向量表偏移量的設(shè)置。

    通過(guò)以上兩個(gè)步驟的設(shè)置,我們就可以生成APP程序了,只要APP程序的FLASH和SRAM大小不超過(guò)我們的設(shè)置即可。不過(guò)MDK默認(rèn)生成的文件是.hex文件,并不方便我
    們用作IAP更新,我們希望生成的文件是.bin文件,這樣可以方便進(jìn)行IAP升級(jí)(至于為什么,請(qǐng)大家自行百度HEX和BIN文件的區(qū)別!)。這里我們通過(guò)MDK自帶的格式轉(zhuǎn)換
    工具fromelf.exe,來(lái)實(shí)現(xiàn).axf文件到.bin文件的轉(zhuǎn)換。該工具在MDK的安裝目錄\ARM\BIN40文件夾里面。

    fromelf.exe轉(zhuǎn)換工具的語(yǔ)法格式為:fromelf [options] input_file。其中options有很多選項(xiàng)可以設(shè)置,詳細(xì)使用請(qǐng)參考光盤(pán)《mdk如何生成bin文件.pdf》.

    本章,我們通過(guò)在MDK點(diǎn)擊Options for TargetàUser選項(xiàng)卡,在Run User Programs After Build/Rebuild 欄,勾選Run#1和DOS16,并寫(xiě)入:D:\Keil3.80a\ARM\BIN40\fromelf.exe? --bin -o? ..\OBJ\TEST.bin ..\OBJ\TEST.axf ,如圖48.1.6所示:

    ?

    ?????? 通過(guò)這一步設(shè)置,我們就可以在MDK編譯成功之后,調(diào)用fromelf.exe(注意,我的MDK是安裝在D:\Keil3.80A文件夾下,如果你是安裝在其他目錄,請(qǐng)根據(jù)你
    自己的目錄修改fromelf.exe的路徑),根據(jù)當(dāng)前工程的TEST.axf(如果是其他的名字,請(qǐng)記住修改,這個(gè)文件存放在OBJ目錄下面,格式為xxx.axf),生成一個(gè)

    TEST.bin的文件。并存放在axf文件相同的目錄下,即工程的OBJ文件夾里面。在得到.bin文件之后,我們只需要將這個(gè)bin文件傳送給單片機(jī),即可執(zhí)行IAP升級(jí)。

    ?????? 最后再來(lái)APP程序的生成步驟:

  • 設(shè)置APP程序的起始地址和存儲(chǔ)空間大小
  • 對(duì)于在FLASH里面運(yùn)行的APP程序,我們可以按照?qǐng)D48.1.3的設(shè)置。對(duì)于SRAM里面運(yùn)行的APP程序,我們可以參考圖48.1.4的設(shè)置。

  • 設(shè)置中斷向量表偏移量
  • 這一步按照上面講解,重新設(shè)置SCB->VTOR的值即可。

  • 設(shè)置編譯后運(yùn)行fromelf.exe,生成.bin文件.
  • 通過(guò)在User選項(xiàng)卡,設(shè)置編譯后調(diào)用fromelf.exe,根據(jù).axf文件生成.bin文件,用于IAP更新。?

    以上3個(gè)步驟,我們就可以得到一個(gè).bin的APP程序,通過(guò)Bootlader程序即可實(shí)現(xiàn)更新。

    大家可以打開(kāi)我們光盤(pán)的兩個(gè)APP工程,熟悉這些設(shè)置。

    48.2 硬件設(shè)計(jì)

    本章實(shí)驗(yàn)(Bootloader部分)功能簡(jiǎn)介:開(kāi)機(jī)的時(shí)候先顯示提示信息,然后等待串口輸入接收APP程序(無(wú)校驗(yàn),一次性接收),在串口接收到APP程序
    之后,即可執(zhí)行IAP。如果是SRAM APP,通過(guò)按下KEY0即可執(zhí)行這個(gè)收到的SRAM APP程序。如果是FLASH APP,則需要先按下WK_UP按鍵,將串口接
    收到的APP程序存放到STM32的FLASH,之后再按KEY2既可以執(zhí)行這個(gè)FLASH APP程序。通過(guò)KEY1按鍵,可以手動(dòng)清除串口接收到的APP程序。DS0用于指示程序運(yùn)行狀態(tài)。

    本實(shí)驗(yàn)用到的資源如下:

  • 指示燈DS0
  • 四個(gè)按鍵(KEY0/KEY1/KEY2/WK_UP)
  • 串口
  • TFTLCD模塊
  • 這些用到的硬件,我們?cè)谥岸家呀?jīng)介紹過(guò),這里就不再介紹了。

    48.3 軟件設(shè)計(jì)

    本章,我們總共需要3個(gè)程序:1,Bootloader;2,FLASH APP;3)SRAM APP;其中,我們選擇之前做過(guò)的RTC實(shí)驗(yàn)(在第二十章介紹)來(lái)做為FLASH APP程序
    (起始地址為0X08010000),選擇觸摸屏實(shí)驗(yàn)(在第三十一章介紹)來(lái)做SRAM APP程序(起始地址為0X20001000)。Bootloader則是通過(guò)TFTLCD顯示實(shí)驗(yàn)(在第
    十八章介紹)修改得來(lái)。本章,關(guān)于SRAM APP和FLASH APP的生成比較簡(jiǎn)單,我們就不細(xì)說(shuō),請(qǐng)大家結(jié)合光盤(pán)源碼,以及48.1節(jié)的介紹,自行理解。本章軟件設(shè)計(jì)僅針對(duì)Bootloader程序。

    打開(kāi)本實(shí)驗(yàn)工程,可以看到我們?cè)黾恿薎AP組,在組下面添加了iap.c文件以及其頭文件isp.h。打開(kāi)iap.c, 代碼如下:

    #include "sys.h"

    #include "delay.h"

    #include "usart.h"

    #include "stmflash.h"

    #include "iap.h"???? ?

    iapfun jump2app;

    u16 iapbuf[1024];

    //appxaddr:應(yīng)用程序的起始地址

    //appbuf:應(yīng)用程序CODE.

    //appsize:應(yīng)用程序大小(字節(jié)).

    void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)

    {

    ?????? u16 t;

    ?????? u16 i=0;

    ?????? u16 temp;

    ?????? u32 fwaddr=appxaddr;//當(dāng)前寫(xiě)入的地址

    ?????? u8 *dfu=appbuf;

    ?????? for(t=0;t<appsize;t+=2)

    ?????? {??????????????????????????????????????? ???

    ????????????? temp=(u16)dfu[1]<<8;

    ????????????? temp+=(u16)dfu[0];????? ?

    ????????????? dfu+=2;//偏移2個(gè)字節(jié)

    ????????????? iapbuf[i++]=temp;? ???

    ????????????? if(i==1024)

    ????????????? {

    ???????????????????? i=0;

    ???????????????????? STMFLASH_Write(fwaddr,iapbuf,1024);???

    ???????????????????? fwaddr+=2048;//偏移2048? 16=2*8.所以要乘以2.

    ????????????? }

    ?????? }

    ?????? if(i)STMFLASH_Write(fwaddr,iapbuf,i);//將最后的一些內(nèi)容字節(jié)寫(xiě)進(jìn)去.?

    }

    //跳轉(zhuǎn)到應(yīng)用程序段

    //appxaddr:用戶代碼起始地址.

    void iap_load_app(u32 appxaddr)

    {

    ?????? if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)????? //檢查棧頂?shù)刂肥欠窈戏?

    ?????? {

    ????????????? jump2app=(iapfun)*(vu32*)(appxaddr+4);????????

    //用戶代碼區(qū)第二個(gè)字為程序開(kāi)始地址(復(fù)位地址)?????????

    ????????????? MSR_MSP(*(vu32*)appxaddr);???????????????????????????????

    //初始化APP堆棧指針(用戶代碼區(qū)的第一個(gè)字用于存放棧頂?shù)刂?

    ????????????? jump2app();??? //跳轉(zhuǎn)到APP.

    ?????? }

    }

    ?????? 該文件總共只有2個(gè)函數(shù),其中,iap_write_appbin函數(shù)用于將存放在串口接收buf里面的APP程序?qū)懭氲紽LASH。iap_load_app函數(shù),則用于跳轉(zhuǎn)到APP程序運(yùn)行,
    其參數(shù)appxaddr為APP程序的起始地址,程序先判斷棧頂?shù)刂肥欠窈戏?#xff0c;在得到合法的棧頂?shù)刂泛?#xff0c;通過(guò)MSR_MSP函數(shù)(該函數(shù)在sys.c文件)設(shè)置棧頂?shù)刂?#xff0c;
    最后通過(guò)一個(gè)虛擬的函數(shù)(jump2app)跳轉(zhuǎn)到APP程序執(zhí)行代碼,實(shí)現(xiàn)IAPàAPP的跳轉(zhuǎn)。

    ?????? 打開(kāi)iap.h代碼如下:

    #ifndef __IAP_H__

    #define __IAP_H__

    #include "sys.h"???

    typedef? void (*iapfun)(void);???? //定義一個(gè)函數(shù)類型的參數(shù).??

    #define FLASH_APP1_ADDR??????????? 0x080010000? ????

    //第一個(gè)應(yīng)用程序起始地址(存放在FLASH)

    //保留0X08000000~0X0800FFFF的空間為Bootloader使用?? ??

    void iap_load_app(u32 appxaddr);???????????????????????????????????????????????? //跳轉(zhuǎn)到APP程序執(zhí)行

    void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 applen);?? //在指定地址開(kāi)始,寫(xiě)入bin

    #endif

    ?????? 這部分代碼比較簡(jiǎn)單,。本章,我們是通過(guò)串口接收APP程序的,我們將usart.c和usart.h做了稍微修改,在usart.h中,我們定義USART_REC_LEN為55K字節(jié),
    也就是串口最大一次可以接收55K字節(jié)的數(shù)據(jù),這也是本Bootloader程序所能接收的最大APP程序大小。然后新增一個(gè)USART_RX_CNT的變量,用于記錄接收到
    的文件大小,而USART_RX_STA不再使用。打開(kāi)usart.c,可以看到我們修改USART1_IRQHandler部分代碼如下:

    //串口1中斷服務(wù)程序

    //注意,讀取USARTx->SR能避免莫名其妙的錯(cuò)誤?? ????

    u8 USART_RX_BUF[USART_REC_LEN] __attribute__ ((at(0X20001000)));

    //接收緩沖,最大USART_REC_LEN個(gè)字節(jié),起始地址為0X20001000.???

    //接收狀態(tài)

    //bit15, 接收完成標(biāo)志

    //bit14, 接收到0x0d

    //bit13~0,???? 接收到的有效字節(jié)數(shù)目

    u16 USART_RX_STA=0;?????? ?????? //接收狀態(tài)標(biāo)記???? ?

    u16 USART_RX_CNT=0;?????????????????? //接收的字節(jié)數(shù)???? ?

    void USART1_IRQHandler(void)

    {

    ?????? u8 res;????

    #ifdef OS_CRITICAL_METHOD

    //如果OS_CRITICAL_METHOD定義了,說(shuō)明使用ucosII了.

    ?????? OSIntEnter();???

    #endif

    ?????? if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//接收到數(shù)據(jù)

    ?????? {????

    ????????????? res=USART_ReceiveData(USART1);

    ????????????? if(USART_RX_CNT<USART_REC_LEN)

    ????????????? {

    ???????????????????? USART_RX_BUF[USART_RX_CNT]=res;

    ???????????????????? USART_RX_CNT++;????????????????? ???????????????????????????????????????????????????????????? ?????

    ????????????? }

    ?????? }

    #ifdef OS_CRITICAL_METHOD ?????

    //如果OS_CRITICAL_METHOD定義了,說(shuō)明使用ucosII了.

    ?????? OSIntExit();? ???????????????????????????????????????????????????????????????????????????? ?

    #endif

    }

    ?????? 這里,我們指定USART_RX_BUF的地址是從0X20001000開(kāi)始,該地址也就是SRAM APP程序的起始地址!然后在USART1_IRQHandler函數(shù)里面,將串口發(fā)
    送過(guò)來(lái)的數(shù)據(jù),全部接收到USART_RX_BUF,并通過(guò)USART_RX_CNT計(jì)數(shù)。代碼比較簡(jiǎn)單,我們就不多說(shuō)了。

    最后我們看看main函數(shù)如下:

    int main(void)

    {???????????

    ?????? u8 t,key;

    ?????? u16 oldcount=0;???? //老的串口接收數(shù)據(jù)值

    ?????? u16 applenth=0;???? //接收到的app代碼長(zhǎng)度

    ?????? u8 clearflag=0;

    ?????? uart_init(256000);? ??? //串口初始化為256000

    ?????? delay_init();??? ?? ? ????? //延時(shí)初始化

    ?????? LCD_Init();??? ??????? //液晶初始化

    ?????? LED_Init();?????????? ? ??? //初始化與LED連接的硬件接口

    ????? KEY_Init();????????????????? //按鍵初始化 ??????

    POINT_COLOR=RED;//設(shè)置字體為紅色

    ?????? LCD_ShowString(60,50,200,16,16,"Warship STM32");????

    ?????? LCD_ShowString(60,70,200,16,16,"IAP TEST");?????

    ?????? LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");

    ?????? LCD_ShowString(60,110,200,16,16,"2012/9/24");?

    ?????? LCD_ShowString(60,130,200,16,16,"WK_UP:Copy APP2FLASH");

    ?????? LCD_ShowString(60,150,200,16,16,"KEY1:Erase SRAM APP");

    ?????? LCD_ShowString(60,170,200,16,16,"KEY0:Run SRAM APP");

    ?????? LCD_ShowString(60,190,200,16,16,"KEY2:Run FLASH APP");

    ?????? POINT_COLOR=BLUE;

    ?????? //顯示提示信息

    ?????? POINT_COLOR=BLUE;//設(shè)置字體為藍(lán)色 ?

    ?????? while(1)

    ?????? {

    ?????? ????? if(USART_RX_CNT)

    ????????????? {

    ???????????????????? if(oldcount==USART_RX_CNT)

    //新周期內(nèi),沒(méi)有收到任何數(shù)據(jù),認(rèn)為本次數(shù)據(jù)接收完成.

    ???????????????????? {

    ??????????????????????????? applenth=USART_RX_CNT;

    ??????????????????????????? oldcount=0;

    ??????????????????????????? USART_RX_CNT=0;

    ??????????????????????????? printf("用戶程序接收完成!\r\n");

    ??????????????????????????? printf("代碼長(zhǎng)度:%dBytes\r\n",applenth);

    ???????????????????? }else oldcount=USART_RX_CNT;????????????????????

    ????????????? }

    ????????????? t++; delay_ms(10);

    ????????????? if(t==30)

    ????????????? {

    ???????????????????? LED0=!LED0; t=0;

    ???????????????????? if(clearflag)

    ???????????????????? {

    ??????????????????????????? clearflag--;

    ??????????????????????????? if(clearflag==0)LCD_Fill(60,210,240,210+16,WHITE);//清除顯示

    ???????????????????? }

    ????????????? }???? ? ??? ?

    ????????????? key=KEY_Scan(0);

    ????????????? if(key==KEY_UP)

    ????????????? {

    ???????????????????? if(applenth)

    ???????????????????? {

    ??????????????????????????? printf("開(kāi)始更新固件...\r\n");?????

    ??????????????????????????? LCD_ShowString(60,210,200,16,16,"Copying APP2FLASH...");

    ?????????????????????????? if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)

    //判斷是否為0X08XXXXXX.

    ??????????????????????????? {???? ??????

    iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,

    applenth); //更新FLASH代碼??

    ?????????????????????????????????? LCD_ShowString(60,210,200,16,16,"Copy APP Successed!!");

    ?????????????????????????????????? printf("固件更新完成!\r\n");??????

    ??????????????????????????? }else

    ??????????????????????????? {

    ?????????????????????????????????? LCD_ShowString(60,210,200,16,16,"Illegal FLASH APP!? ");?????? ??

    ?????????????????????????????????? printf("非FLASH應(yīng)用程序!\r\n");

    ??????????????????????????? }

    ??????????????????? }else

    ???????????????????? {

    ??????????????????????????? printf("沒(méi)有可以更新的固件!\r\n");

    ??????????????????????????? LCD_ShowString(60,210,200,16,16,"No APP!");

    ???????????????????? }

    ???????????????????? clearflag=7;//標(biāo)志更新了顯示,并且設(shè)置7*300ms后清除顯示??????? ?

    ????????????? }

    ????????????? if(key==KEY_DOWN)

    ????????????? {

    ???????????????????? if(applenth)

    ???????????????????? {?????????????????????????????????????????????????????????????????????????????????????????????????????????????

    ??????????????????????????? printf("固件清除完成!\r\n");???

    ??????????????????????????? LCD_ShowString(60,210,200,16,16,"APP Erase Successed!");

    ??????????????????????????? applenth=0;

    ???????????????????? }else

    ???????????????????? {

    ??????????????????????????? printf("沒(méi)有可以清除的固件!\r\n");

    ??????????????????????????? LCD_ShowString(60,210,200,16,16,"No APP!");

    ???????????????????? }

    ???????????????????? clearflag=7;//標(biāo)志更新了顯示,并且設(shè)置7*300ms后清除顯示????????????????????????????????????????????????????????

    ????????????? }

    ????????????? if(key==KEY_LEFT)

    ????????????? {

    ???????????????????? printf("開(kāi)始執(zhí)行FLASH用戶代碼!!\r\n");

    ???????????????????? if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)

    //判斷是否為0X08XXXXXX.

    ???????????????????? {????

    ??????????????????????????? iap_load_app(FLASH_APP1_ADDR);//執(zhí)行FLASH APP代碼

    ???????????????????? }else

    ???????????????????? {

    ??????????????????????????? printf("非FLASH應(yīng)用程序,無(wú)法執(zhí)行!\r\n");

    ??????????????????????????? LCD_ShowString(60,210,200,16,16,"Illegal FLASH APP!");??? ??

    ???????????????????? }????????????????????????????????????????????????????????????

    ???????????????????? clearflag=7;//標(biāo)志更新了顯示,并且設(shè)置7*300ms后清除顯示 ?

    ????????????? }

    ????????????? if(key==KEY_RIGHT)

    ????????????? {

    ???????????????????? printf("開(kāi)始執(zhí)行SRAM用戶代碼!!\r\n");

    ???????????????????? if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x20000000)

    //判斷是否為0X20XXXXXX.

    ???????????????????? {????

    ??????????????????????????? iap_load_app(0X20001000);//SRAM地址

    ???????????????????? }else

    ???????????????????? {

    ??????????????????????????? printf("非SRAM應(yīng)用程序,無(wú)法執(zhí)行!\r\n");

    ??????????????????????????? LCD_ShowString(60,210,200,16,16,"Illegal SRAM APP!");???? ??

    ???????????????????? }????????????????????????????????????????????????????????????

    ???????????????????? clearflag=7;//標(biāo)志更新了顯示,并且設(shè)置7*300ms后清除顯示

    ????????????? }????????????????????????? ??

    ????????????? ?

    ?????? }?? ?????? ???

    }

    ?????? 該段代碼,實(shí)現(xiàn)了串口數(shù)據(jù)處理,以及IAP更新和跳轉(zhuǎn)等各項(xiàng)操作。Bootloader程序就設(shè)計(jì)完成了,但是一般要求bootloader程序越小越好(給APP省空間嘛),
    所以,本章我們把一些不需要用到的.c文件全部去掉,最后得到工程截圖如圖48.3.1所示:

    ?

    ?

    圖48.3.1 Bootloader 工程截圖

    ?????? 從上圖可以看出,雖然去掉了一些不用的.c文件,但是Bootloader大小還是有22K左右,比較大,主要原因是液晶驅(qū)動(dòng)和printf占用了比較多的flash,如果大家
    想進(jìn)一步刪減,可以去掉LCD顯示和printf等,不過(guò)我們?cè)诒菊聻榱搜菔拘Ч?#xff0c;所以保留了這些代碼。

    ????? 至此,本實(shí)驗(yàn)的軟件設(shè)計(jì)部分結(jié)束。

    ?????? FLASH APP和SRAM APP兩部分代碼,我們?cè)趯?shí)驗(yàn)?zāi)夸浵绿峁┝藘蓚€(gè)實(shí)驗(yàn)供大家參考,不過(guò)要提醒大家,根據(jù)我們的設(shè)置,FLASH APP的起始地址必須是0X08010000,而SRAM APP的起始地址必須是0X20001000。

    48.4 下載驗(yàn)證

    在代碼編譯成功之后,我們下載代碼到ALIENTEK戰(zhàn)艦STM32開(kāi)發(fā)板上,得到,如圖48.4.1所示:

    ?

    圖48.4.1 IAP程序界面

    此時(shí),我們可以通過(guò)串口,發(fā)送FLASH APP或者SRAM APP到戰(zhàn)艦STM32開(kāi)發(fā)板,如圖48.4.2所示:

    圖48.4.2 串口發(fā)送APP程序界面

    ?????? 先用串口調(diào)試助手的打開(kāi)文件按鈕(如圖標(biāo)號(hào)1所示),找到APP程序生成的.bin文件,然后設(shè)置波特率為256000(為了提高速度,Bootloader程序?qū)⒉ㄌ芈时辉O(shè)置為256000了),
    最后點(diǎn)擊發(fā)送文件(圖中標(biāo)號(hào)3所示),將.bin文件發(fā)送給戰(zhàn)艦STM32開(kāi)發(fā)板。

    ?????? 在收到APP程序之后,我們就可以通過(guò)KEY0/KEY2運(yùn)行這個(gè)APP程序了(如果是FLASH APP,則先需要通過(guò)WK_UP將其存入對(duì)應(yīng)

    總結(jié)

    以上是生活随笔為你收集整理的串口IAP实验的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。