?? ref.c~
字號:
????????}?while(--i);
????}
????return?(crc);
}
//退出Bootloader程序,從0x0000處執(zhí)行應(yīng)用程序
void?quit(void)
{
??????uart_putchar('O');uart_putchar('K');
uart_putchar(0x0d);uart_putchar(0x0a);
?????while(!(UCSR0A?&?0x20));????????????//等待結(jié)束提示信息回送完成
??MCUCR?=?0x01;
?????MCUCR?=?0x00;????????????????????//將中斷向量表遷移到應(yīng)用程序區(qū)頭部
?????RAMPZ?=?0x00;????????????????????//RAMPZ清零初始化
?????asm("jmp?0x0000\n");????????????????//跳轉(zhuǎn)到Flash的0x0000處,執(zhí)行用戶的應(yīng)用程序
}
//主程序
void?main(void)
{
????int?i?=?0;
????unsigned?char?timercount?=?0;
????unsigned?char?packNO?=?1;
????int?bufferPoint?=?0;
????unsigned?int?crc;
//初始化M128的USART0
????UBRR0H?=?BAUD_H;????
????UBRR0L?=?BAUD_L;????????????//Set?baud?rate
????UCSR0B?=?0x18;????????????//Enable?Receiver?and?Transmitter
????UCSR0C?=?0x0E;????????????//Set?frame?format:?8data,?2stop?bit
//初始化M128的T/C0,15ms自動重載
??OCR0?=?0xEA;
??TCCR0?=?0x0F;????
//向PC機發(fā)送開始提示信息
????while(startupString[i]!='\0')
????{
????????uart_putchar(startupString[i]);
????????i++;
????}
//3秒種等待PC下發(fā)“d”,否則退出Bootloader程序,從0x0000處執(zhí)行應(yīng)用程序
????while(1)
????{
????????if(uart_getchar()==?'d')?break;
????????if?(TIFR?&?0x02)????????????????????????//timer0?over?flow
????????{
???????????????if?(++timercount?>?200)?quit();????????//200*15ms?=?3s
????????????TIFR?=?TIFR|0x02;
????????}
????}
????//每秒向PC機發(fā)送一個控制字符“C”,等待控制字〈soh〉
????while(uart_getchar()!=XMODEM_SOH)????????//receive?the?start?of?Xmodem
????{
?????????if(TIFR?&?0x02)????????????????????//timer0?over?flow
????????{
????????????if(++timercount?>?67)????????????????????????//wait?about?1?second
????????????{
????????????????uart_putchar(XMODEM_RECIEVING_WAIT_CHAR);????//send?a?"C"
????????????????timercount=0;
????????????}
????????????TIFR=TIFR?|?0x02;
????????}
????}
????//開始接收數(shù)據(jù)塊
????do
????{
????????if?((packNO?==?uart_waitchar())?&&?(packNO?==(~uart_waitchar())))
????????{????//核對數(shù)據(jù)塊編號正確
????????????for(i=0;i<128;i++)????????????????//接收128個字節(jié)數(shù)據(jù)
????????????{
????????????????data[bufferPoint]=?uart_waitchar();
????????????????bufferPoint++;????
????????????}
????????????crc?=?(uart_waitchar()<<8);
????????????crc?+=?uart_waitchar();????????????//接收2個字節(jié)的CRC效驗字
????????????if(calcrc(&data[bufferPoint-128],128)==crc)????//CRC校驗驗證
????????????{????//正確接收128個字節(jié)數(shù)據(jù)
????????????????while(bufferPoint?>=?SPM_PAGESIZE)
????????????????{????//正確接受256個字節(jié)的數(shù)據(jù)
????????????????????write_one_page();????????????//收到256字節(jié)寫入一頁Flash中
????????????????????address?+=?SPM_PAGESIZE;????//Flash頁加1
????????????????????bufferPoint?=?0;
????????????????}????
????????????????uart_putchar(XMODEM_ACK);????????//正確收到一個數(shù)據(jù)塊
????????????????packNO++;????????????????????????//數(shù)據(jù)塊編號加1
????????????}
????????????else
????????????{
????????????????uart_putchar(XMODEM_NAK);????????//要求重發(fā)數(shù)據(jù)塊
????????????}
????????}
????????else
????????{
????????????uart_putchar(XMODEM_NAK);????????????????//要求重發(fā)數(shù)據(jù)塊
????????}
????}while(uart_waitchar()!=XMODEM_EOT);????????????????//循環(huán)接收,直到全部發(fā)完
????uart_putchar(XMODEM_ACK);????????????????????????//通知PC機全部收到
????
????if(bufferPoint)?write_one_page();????????????????//把剩余的數(shù)據(jù)寫入Flash中
????quit();????????????????//退出Bootloader程序,從0x0000處執(zhí)行應(yīng)用程序
}
????程序的主體部分采用C高級編寫,結(jié)構(gòu)性好,程序的相應(yīng)部分都給出了比較詳細的注釋說明,讀者非常容易讀懂和理解。下面再對程序做進一步的說明。
l????函數(shù)“void??write_one_page(void)”?實現(xiàn)了對ATmega128一個Flash頁的完整編程處理。當(dāng)程序從串口正確接收到256個字節(jié)后,(ATmega128一個Flash頁為128個字),便調(diào)用該函數(shù)將其寫入ATmega128一個Flash頁中。函數(shù)先將一個指定的Flash頁進行擦除;然后將數(shù)據(jù)填入Flash????的緩沖頁中,最后將Flash????緩沖頁的數(shù)據(jù)寫入到該指定的Flash頁中(詳細技術(shù)細節(jié)見第二章相關(guān)內(nèi)容的介紹)。
l????一個Flash頁的擦除、寫入,以及填充Flash緩沖頁的函數(shù)采用內(nèi)嵌AVR匯編完成,在ICCAVR中,寄存器R16、R17、R18、R19用于傳遞一個C函數(shù)的第1、2個參數(shù)(int類型)或第1個乘數(shù)(long類型),具體參考ICCAVR應(yīng)用說明。
l????函數(shù)“void?quit(void)”的用途是退出Bootloader程序,從Flash的0x0000處執(zhí)行用戶的應(yīng)用程序。在執(zhí)行強行跳轉(zhuǎn)指令“jmp?0x0000”前,對寄存器MCUCR的操作是將中斷向量地址遷移回應(yīng)用程序區(qū)的頭部,因為在ICCAVR環(huán)境中編譯Bootloader程序時,其自動把中斷向量地址遷移到了Bootloader區(qū)的頭部。為了保證能正確執(zhí)行用戶的程序,在跳轉(zhuǎn)前需要把中斷向量地址遷再移回應(yīng)用程序區(qū)的頭部。
l????在這段Bootloader程序中使用的硬件資源為T/C0和USART0,用戶在編寫其應(yīng)用程序時,應(yīng)首先對這兩個硬件資源相關(guān)的寄存器重新做初始化。
l????Bootloader程序占具并住留在Flash的最高1K字空間內(nèi),因此實際的應(yīng)用程序空間為63K字(126K字節(jié)),所以用戶編寫的應(yīng)用程序不得超出126K字節(jié)。同時應(yīng)將ATmega128的熔絲位BLB12、BLB11的狀態(tài)設(shè)置為“00”,禁止SPM和LPM指令對Bootloader區(qū)的讀寫操作,已確保Bootloader程序不被改寫和擦除。
5.2.3?IAP的實現(xiàn)與應(yīng)用
1.????Bootloader程序的編譯與下載
首先在ICCAVR中新建一個工程項目,并按照生成Bootloader程序代碼的要求進行正確的設(shè)置。打開Project?–>?Options的Compiler?Options設(shè)置選項窗口,見圖5.1:
l????在Device?Configration欄中選定器件ATMega128;
l????選定Use?RAMPZ/ELPM項(ATMega128的Flash?>?64K字節(jié));
l????Program?Type選定為Boot?Loader;
l????Boot?Size選擇1K?Words。
圖5.1?在ICCAVR中編寫B(tài)ootloader程序的編譯屬性設(shè)置
正確設(shè)置好編譯選項后輸入C的源代碼,然后編譯生成.HEX的下載代碼程序。
在下載HEX文件前還要對ATmega128芯片的熔絲位進行正確的配置:
l????配置M103C熔絲位,使芯片工作于ATmega128方式;
l????配置BOOTSZ1和BOOTSZ0熔絲位,設(shè)定BOOTLOADER區(qū)的大小為1024個字,起始首地址為0xFC00;
l????配置BOOTRST熔絲位,設(shè)定芯片上電起動從BOOTLOADER區(qū)的起始地址處開始,既每次RESET復(fù)位后從0xFC00處執(zhí)行Bootloader程序;
l????下載Bootloader程序的HEX文件;
l????配置LB2和LB1熔絲位,加密程序;
l????配置BLB12和BLB11熔絲位,對BOOTLOADER區(qū)進行安全鎖定。
特別注意的是,以上對芯片熔絲位的配置以及Bootloader程序的下載,需要由ISP、或JTAG、或并行方式實現(xiàn),既要實現(xiàn)IAP,首先還需要使用一次非IAP的編程方式來建立IAP的應(yīng)用環(huán)境。
2.????IAP應(yīng)用
當(dāng)你按照上面的方法將Bootloader程序下載完成后,就可以使用它來下載你的應(yīng)用程序了。具體操作如下。
l????編寫你的應(yīng)用程序,編譯生成HEX文件;
l????使用HEX2BIN.EXE轉(zhuǎn)換程序,將HEX文件轉(zhuǎn)換成BIN文件;
l????使用普通的RS232電纜將PC機的串口與ATmega128的串口連接;
l????打開WINDOWS中的超級終端軟件,正確設(shè)置COM口的參數(shù):38400,1,8,無,2,無(使用2位停止位提高通信可靠性);
l????ATmega128上電,在PC超級終端收到“Type?'d'?download,?Others?run?app.”的Bootloader程序啟動的提示詳細;
l????3秒鐘內(nèi)在PC上按下“d”鍵,通知Bootloader程序轉(zhuǎn)入接收數(shù)據(jù)并更新應(yīng)用程序的處理。3秒鐘內(nèi)沒有按“d”鍵,PC超級終端收到“OK”提示,Bootloader程序退出,自動轉(zhuǎn)入執(zhí)行芯片內(nèi)原有的用戶應(yīng)用程序(如果有的話,否則再次啟動Bootloader程序);
l????當(dāng)PC超級終端收到“C”(一秒鐘一個),說明Bootloader程序轉(zhuǎn)入接收數(shù)據(jù)和更新應(yīng)用程序的處理流程,正在等待PC下發(fā)數(shù)據(jù);
l????在PC超級終端上的工具欄中選擇“傳送->發(fā)送文件”,在發(fā)送文件窗口選擇協(xié)議“Xmodem”,文件欄中選定要下載應(yīng)用程序的BIN文件,單擊發(fā)送按鈕;
l????此時出現(xiàn)文件發(fā)送窗口,顯示文件發(fā)送的過程和進度,以及是否出錯;
l????當(dāng)文件全部正確發(fā)送完成后,PC超級終端收到“OK”提示,Bootloader程序退出,自動轉(zhuǎn)入執(zhí)行剛更新的用戶應(yīng)用程序。
在ATmega128中燒入這樣一個Bootloader程序,建立了IAP后,最基本的開發(fā)AVR的環(huán)境就簡化成“PC+RS232電纜+目標板”。讀者在掌握了Bootloader程序編寫的原理后,可以編寫自己的Bootloader程序,實現(xiàn)系統(tǒng)程序的自動遠程網(wǎng)絡(luò)更新等應(yīng)用。
AVR的BOOTLOADER功能同其它一些芯片不同,它的BOOTLOADER程序沒有固化(固定)在芯片內(nèi)部(出廠為空),而是需要由用戶設(shè)計實現(xiàn)(實際上,你第一次下載BOOTLOADER程序還必須使用其它的方式編程,如ISP、JTAG等),因此對一般的用戶掌握起來有一定的困難,不如一些其它芯片的固化IAP使用方便。但對高手來講,可以根據(jù)實際需要編寫高級、高效、專用的BOOTLOADER程序,如從一個U盤讀取數(shù)據(jù),更新用戶的應(yīng)用程序;編寫一個時間炸彈,或?qū)τ脩舻拿艽a進行驗證,10次不對則將系統(tǒng)程序銷毀等等。簡單意味著使用方便,但靈活和適應(yīng)性差,而靈活性需要你具備更高的能力去駕馭它。可能會有一天,在單片機的系統(tǒng)上也出現(xiàn)了“病毒”程序,其原因就是使用了固化的BOOTLOADER程序。由于固化(固定)的程序采用規(guī)定公開(開放)的接口,那么用一個帶“病毒”的應(yīng)用程序更新原來的應(yīng)用程序也就輕而易舉了。
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -