天天看點

基于AVR-BootLoader,通過霜蟬遠端式列槽可實作單片機的遠端更新

最近一直利用業餘時間寫自己的“基于AVR-BootLoader”,啟發是由于一次在ourAVR論壇看到了紹子陽的bootloader,聯想到公司在用AVR MCU,但每次更新程式都要花費很大的力氣車馬勞頓的跑到工程現場,而且很多機器還安裝在國外,為了更新一次程式發費了很多的人力物力财力,加上公司的機器目前大部分都配有遠端監控系統,是以本人決定寫一個具有自有産權的“AVR-BootLoader”。

特别說明:本 “AVR-BootLoad” 軟體代碼屬上海霜蟬版權所有,在此貢獻釋出,僅限于個人免費使用不得用于商業用途,本人也不保證代碼的嚴謹性,如在更新中出現任何問題與本人無關,本人已測試過Atmega64A與Atmega128。話不多說了上源代碼,網友們和AVR愛好者可以拷貝到 CodeWizardAVR V2.03.9編譯器下編譯。

需要讨論或有遇到BUG的網友們可以聯系我:QQ:285247488  mail:[email protected] 

上位機截圖:

基于AVR-BootLoader,通過霜蟬遠端式列槽可實作單片機的遠端更新

遠端更新DTU

基于AVR-BootLoader,通過霜蟬遠端式列槽可實作單片機的遠端更新

遠端更新連接配接雲平台虛拟序列槽

基于AVR-BootLoader,通過霜蟬遠端式列槽可實作單片機的遠端更新

//          關于上海霜蟬-AVR_BootLoade_V1.00 // 1、軟體版本V1.00 編譯環境CodeWizardAVR V2.03.9 Standard; // 2、支援本公司常用的三種AVR晶片; // 3、支援标準Xmodem和擴充Xmodem_1K協定; // 4、聯機握手密碼為"00",握手成功手的等待檔案逾時為1分鐘; // 5、預設複位等待3S退出boot到使用者程式或循環運作boot; // 6、支援1分鐘以内的斷網續傳; // 7、支援連續10幀以内資料錯誤的重傳; // 8、支援下載下傳過程中的取消超作; // 9、支援當收到包時,接收過程中每個字元的逾時間隔為 1 秒; // 10、支援所有的逾時及錯誤事件至少重試 10 次; // 11、支援數等待逾時6S的請求; // 12、Boot Loader - Size:1024words; // 13、支援傳輸速度:38.400KB/S~2.400KB/S; // 14、支援公司常用最多的三個型号ATMEGA32,64,128。 // 15、支援開門狗自定義開關,自定義時鐘頻率

#include  "AVR_boot.h"    // 頭檔案包含 //--------------------------------------------------// //同步密碼長度 #define  CONNECTCNT         7 //同步密碼 uchar   KEY_Data [10 ]   =   { "SCICALA" } ; // Declare your global variables here //--------------------------------------------------// // 全局變量定義 uchar      RX_buff [ BUFSIZE ] ;                           // 資料拉收緩存 uchar    Frame_State , SOH_Wait_cnt ;             // 幀狀态,幀頭等待計數 uint     Time_cnt , Error_cnt ;                              // 逾時計數,連續幀錯誤計數 uint     buffptr , buffptr_old , buffptr_New ;             // 資料緩存指針必須大于1024 ulong    FlashAddr ;                                           // Flash位址 uchar    UpdatedSta ;                                         // 更新标志 //-----------------------------------------------// //擦除(code=0x03)和寫入(code=0x05)一個Flash頁 void  boot_page_ew ( ulong  p_address , char  code ) {     # asm       ldd   r26 , y +1        ;  R26  LSB       ldd  r27 , y +2         ;  R27  MSB     # endasm      SPM_REG  =  code ;                  // 寄存器SPMCSR中為操作碼     # asm       mov  r30 , r26       mov  r31 , r27     # endasm      #ifdef   ATMEGA128       RAMPZ = ( p_address >> 16 ) ;      // RAMPZ0 = 1: ELPM/SPM 可以通路程式存儲器位址$8000 - $FFFF ( 高64K 位元組)      #endif     # asm ( "spm" ) ;                 // 對指定Flash頁進行擦操作 } //填充Flash緩沖頁中的一個字 void  boot_page_fill ( uint  A_address , uint  data ) {       # asm          LDD  R30 , Y +2      ;  R30  LSB          LDD  R31 , Y +3      ;  R31  MSB          LD   R26 , Y          LDD  R27 , Y +1          MOV  R0 , R26          MOV  R1 , R27          MOV  R26 , R30          MOV  R27 , R31       # endasm          SPM_REG  = 0x01 ;            //寄存器SPMCSR中為操作碼       # asm          mov  r30 , r26          mov  r31 , r27       # endasm         # asm ( "spm" ) ;             //對指定Flash頁進行擦操作 } //等待一個Flash頁的寫完成 void  wait_page_rw_ok ( void ) {        while ( SPM_REG  &  0x40 )       {            while ( SPM_REG  &  0x01 ) ;            SPM_REG  =  0x11 ;           # asm ( "spm" ) ;            while ( SPM_REG  &  0x01 ) ;       } } //-----------------------------------------------// //更新一個Flash頁的完整處理 void  write_one_page ( uchar  data [ ]) {      uint  i ;      boot_page_ew ( FlashAddr , 0x03 ) ;          //擦除一個Flash頁      wait_page_rw_ok ( ) ;                     //等待擦除完成      for ( i = 0 ; i < SPM_PAGESIZE ; i += 2 )           //将資料填入Flash緩沖頁中  按字填充      {          boot_page_fill ( i , ( uint ) data [ i ] + ( data [ i +1 ] << 8 )) ;          wait_page_rw_ok ( ) ;      }      boot_page_ew ( FlashAddr , 0x05 ) ;          //将緩沖頁資料寫入一個Flash頁      wait_page_rw_ok ( ) ;                     //等待寫入完成 } //--------------------------------------------------// //等待序列槽資料1S逾時自動轉為應答 unsigned  char  Wait1S_UART ( ) { uchar  i = 0 ;    do    {      #if  WDGEn      Watchdog_Reset ( ) ;                        // 喂狗      #endif      if ( TIFR & 0x10 )                            // OCF1A: T/C1 輸出比較 A 比對标志位      {          TIFR| = 0x10 ;                          // 清除Time1定時器比較比對标志          i ++ ;          if ( i >= 4 )                             // 等待1S 250ms*4=1S          {    Frame_State = 0x06 ;  break ;     }    // 幀資料逾時轉為應答請求重發資料幀      }      if ( UCSRAREG ( COMPORTNo )  &  0x80 )      {          UCSRAREG ( COMPORTNo )| = 0x80 ;           // 清除接收完成狀态          #if  Run_LEDEn          Run_LED ;                             // 運作LED閃爍          #endif          i = 100 ;          return  UDRREG ( COMPORTNo ) ;            // 讀取UDR0      }    }    while ( 100 != i ) ;                             // 等待資料||逾時退出 } // //===================================================// void  main ( void ) { uchar    packNO , packNO_old ;   // 包号、包号留存 uint     crc16 ;               // 接收CRC緩存 uint     li ;                  // 幀計數 uchar    ch ,  cl ;              // 包号      PORT_Init ( ) ;             // 端口初始化      UART_Init ( ) ;             // 序列槽初始化      Time1_Init ( ) ;            // 定時器初始化 250ms      #if  WDGEn      WatchDog_Enable ( ) ;       // 打開看門狗(2S)      #else     WatchDog_Disenable();    // 禁止看門狗      #endif      #if  Wait_BootTime      Time_cnt = EEPROM_Read ( EE_TimeAddr ) ;   // 讀取boot運作時間      #endif      #if  SafeUpdated_En      UpdatedSta = EEPROM_Read ( EE_SafeAddr ) ; // 讀取更新成功标志      #endif     # asm ( "cli" )              // 關總中斷      #if  Delay_En             // 是否延時      for ( li = 0 ; li < 5000 ; li ++ )      {   # asm ( "nop" )  }      #endif //-----------------------------------------------// //等待"握手",否則退出Bootloader程式,從0x0000處執行應用程式      Time_cnt  +=  WiteTimeCnt ;      cl  =  0 ;      while ( 1 )      {          if ( TIFR & 0x10 )                    // OCF1A: T/C1 輸出比較 A 比對标志位          {              TIFR| = 0x10 ;                  // 清除Time1定時器比較比對标志               #if  Run_LEDEn              Run_LED ;                     // 運作LED閃爍               #endif               Time_cnt -- ;              if ( Time_cnt == 0 )              // 等待握手逾時              {                   #if  SafeUpdated_En                   if ( UpdatedSta )               // 上次更新失敗                    {    while ( 1 ) ;            }    // 複位boot                    else                    #endif                    {    quit_boot ( ) ;     }        // 跳轉到使用者程式               }               if ( UCSRAREG ( COMPORTNo )  &  0x80 )               {                  ch = Wait_UART ( ) ;                    if ( ch ==  KEY_Data [ cl ])                  {    cl ++ ;    }                  else                  {    cl  =  0 ;  }                    //WriteCom(ch);         // 密碼回傳               }               if ( cl  ==  CONNECTCNT ) break ;          }          #if  WDGEn          Watchdog_Reset ( ) ;                // 喂狗          #endif      } //-----------------------------------------------// //啟動Xmodex CRC傳資料=字元“C”,等待控制字〈soh〉      Time_cnt  =  TimeOutCntC ;      while ( 1 )      {          if ( TIFR & 0x10 )                    // OCF1A: T/C1 輸出比較 A 比對标志位          {              TIFR| = 0x10 ;                  // 清除Time1定時器比較比對标志               #if  Run_LEDEn              Run_LED ;                     // 運作LED閃爍               #endif              Send_UART ( XMODEM_RWC )  ;      //發送 "C"              Time_cnt -- ;              if ( Time_cnt  ==  0 )            // 等待檔案逾時              {                   #if  SafeUpdated_En                   if ( UpdatedSta )                   // 上次更新失敗                    {    while ( 1 ) ;        }    // 複位boot                    else                    #endif                    {    quit_boot ( ) ;     }            // 跳轉到使用者程式               }        // 跳轉到使用者程式          }          if ( UCSRAREG ( COMPORTNo )  &  0x80 )   // 序列槽有資料          {              #ifdef   Xmodem              if (  Wait_UART ( ) ==  XMODEM_SOH )   //XMODEM指令開始  0x01               #else     // Xmodem_1K               if (  Wait_UART ( ) ==  XMODEM_STX )   //XMODEM指令開始  0x02               #endif               break ;          }          #if  WDGEn          Watchdog_Reset ( ) ;                // 喂狗          #endif      } //-----------------------------------------------// // 開始接收資料進入Xmodem協定接收檔案 // 幀的兩個時間很重要:連續出錯10次*最大幀請求間隔6S // 累計請求間隔10*6S=1min      packNO  =  1 ;          // Xmodem 起始為 0x01      packNO_old = 0 ;      buffptr  =  0 ;      buffptr_old = 0 ;      Error_cnt  =  0 ;      FlashAddr  =  0 ;      Frame_State = 0x01 ;    // 第一幀不判斷幀頭      while ( 1 )      {          switch  ( Frame_State )     // 幀狀态          {              case  0x00 :   // 接受狀态 幀頭與停止信号判斷              {                   ch = XMODEM_NUL ;                   // 清除                    if ( UCSRAREG ( COMPORTNo )  &  0x80 )   // 序列槽有資料                    {  ch = Wait_UART ( ) ;    }            // 讀取幀頭或停止信号                    if ( TIFR & 0x10 )                    // OCF1A: T/C1 輸出比較 A 比對标志位                    {                        TIFR| = 0x10 ;                  // 清除Time1定時器比較比對标志                        SOH_Wait_cnt ++ ;              // 等待計時 250ms                         if ( SOH_Wait_cnt >= 24 )         // 等待幀逾時請求資料(6S*10=1min)                         {                             Frame_State = 0x06 ;        // 要求重發資料塊                              SOH_Wait_cnt = 0 ;          // 幀請求計時                              #if  Run_LEDEn                          Run_LED ;                     // 運作LED閃爍                              #endif                         }                    }                    //------------------------------                   if ( ch ==  XMODEM_EOT )  // 發送結束                    {                        for ( li = ( buffptr_New -128 ) ; li < buffptr_New ; )    // 判斷上一幀資料尾16個正确性以決定是否重傳                      {                          if (( RX_buff [ li ++ ]) != 0xff ) break ;          // 填充幀判斷争強EOT抗幹擾能力 FF CF                              {                                  if (( RX_buff [ li ++ ]) != 0xcf ) break ;      // 填充幀判斷争強EOT抗幹擾能力 FF CF                          }                         }                         if ( li == buffptr_New )                         {    Send_UART ( XMODEM_ACK ) ;           // 最後一幀應答完成                             Frame_State = 0x0ff ;               // 轉為退出boot                         }                         else                         {                             Frame_State = 0x06 ;                // 要求重發資料塊                              SOH_Wait_cnt = 0 ;                  // 幀請求計時                         }                    }                    #ifdef   Xmodem                    if ( ch ==  XMODEM_SOH )  // Xmodem幀頭判斷                    #else     // Xmodem_1K                    if ( ch ==  XMODEM_STX )  // Xmodem_1K幀頭判斷                    #endif                    {                        Frame_State = 0x01 ;           // 轉為包号檢查                         SOH_Wait_cnt = 0 ;             // 清除幀頭等待計時                    }              }              break ;              case  0x01 :   //包序号校驗              {                    ch  =   Wait1S_UART ( ) ;              // 擷取包序号                  cl  =  ~ Wait1S_UART ( ) ;                  if ( ch  ==  cl )                      // 包号對比                    {    Frame_State = 0x02 ;                         packNO = ch ;                    // 正確定留包号                    }                    else                    {    Frame_State = 0x06 ;        }    // 重發應答ANK              }              break ;              case  0x02 :   // 進入二級CRC校驗              {                   for ( li  =  0 ;  li  <  BUFFER_SIZE ;  li ++ )              // 接收完整一幀資料 (128位元組)                  {                      RX_buff [ buffptr ++ ]  =  Wait1S_UART ( ) ;      // 接收資料                         // 幀資料接收逾時1S退出for詢環,再接收2個資料或逾時1S+2S轉為應答                         if ( Frame_State == 0x06 ) break ;                  }                  crc16  =  Wait1S_UART ( ) ;                    crc16 = crc16 << 8 ;                  crc16  +=  Wait1S_UART ( ) ;                      // 接收2個位元組的CRC效驗字                  if ( CRC16_Word ( & RX_buff [ buffptr  -  BUFFER_SIZE ] , BUFFER_SIZE ) == crc16 )   // CRC校驗驗證                  {                        if ( packNO == packNO_old )           // 接收相同包不寫flash                        {    Frame_State = 0x05 ;            // 正常應答ACK                              buffptr = buffptr_old ;                        }                         else                         {    Frame_State = 0x03 ;           // 正确應答                              buffptr_New = buffptr ;        // 記錄目前資料指針                         }                    }                    else                    {    Frame_State = 0x06 ;                // 應答NAK                         buffptr = buffptr_old ;             // 去掉錯誤資料的指針                    }              }              break ;              case  0x03 :   // 校驗通過,執行寫入              {                   if ( FlashAddr  <  BootStart )            //避免寫入Boot區                  {                         #if  BUFFER_SIZE < SPM_PAGESIZE   // ---                         if ( buffptr  >=  SPM_PAGESIZE )      //緩沖區滿,寫入資料;否則繼續接收                       {                                //接收多個幀,寫入一頁                           write_one_page ( & RX_buff [ 0 ]) ;     //寫入緩沖區内容到Flash中                           FlashAddr  +=  SPM_PAGESIZE ;   //修改Flash頁位址                           buffptr  =  0 ;                       }                         #else       //----------------------                         while ( buffptr  >  0 )               //接收一幀,寫入多個頁面                       {                           write_one_page ( & RX_buff [ BUFSIZE  -  buffptr ]) ;                           FlashAddr  +=  SPM_PAGESIZE ;    //修改Flash頁位址                           buffptr  -=  SPM_PAGESIZE ;                       }                         #endif    //-----------------------                    }                  else                                 //超過BootStart,忽略寫操作                  {  buffptr  =  0 ;   }                    //重置接收指針                  Frame_State = 0x04 ;              }              break ;              case  0x04 :   //讀取寫入的Flash内容并和下載下傳的緩沖區比較              {                   Frame_State = 0x05 ;                    // 轉為應答狀态                    buffptr_old = buffptr ;                 // 寫入正常才記錄資料指針               }              break ;              case  0x05 :   // 正确應答ACK              {                    packNO_old = packNO ;                   // 接收完整一幀保留本次包号                    Send_UART ( XMODEM_ACK ) ;               // 認可應答                    //WriteCom(packNO);         // 測試                    //WriteCom(FlashAddr);      // 測試                    //WriteCom(FlashAddr>>8);   // 測試                    Error_cnt  =  0 ;                       // 清除連續錯誤計數                    Frame_State = 0x00 ;                    // 轉為幀接收(請求)狀态              }              break ;              case  0x06 :  // 錯誤=重發應答ANK              {                    Send_UART ( XMODEM_NAK ) ;               // 要求重發資料塊                  Error_cnt ++ ;                         // 連續錯誤計數                    Frame_State = 0x00 ;                    // 轉為接收狀态              }              break ;              default :  // 更新完成退出處理              {                   #if  SafeUpdated_En                   EEPROM_Write ( EE_SafeAddr , 0 ) ; // 寫更新成功标志 0                   #endif                   quit_boot ( ) ;                         //退出Bootloader               }              break ;          }  // switch End          if ( Error_cnt > 10 )  // 連續出錯10次退出更新(複位)          {               Send_UART ( XMODEM_CAN ) ;       // 撤銷傳送(無條件停止)               #if  SafeUpdated_En               EEPROM_Write ( EE_SafeAddr , 1 ) ; // 寫更新失敗标志 1               #endif              while ( 1 ) ;                    // 沒有更新完成重新開始          }          #if  WDGEn          Watchdog_Reset ( ) ;                            // 喂狗          #endif      }  // while end //-------------------------------------------------// }    // main end //-----------------------------------------------// #include  "AVR_boot.h"   // 頭檔案包含 //-----------------------------------------------// //----------初始化-------------------------------// // 輸出端口初始化 void  PORT_Init ( ) { // 上電預設全為輸入口 // 輸出口設定      #if  Run_LEDEn      DDRREG ( LEDPORT )| = ( 1  <<  LEDPORTNo ) ;  // 訓示燈      #endif } //-----------------------------------------------// // 序列槽初始化 void  UART_Init ( ) {      #if  RS485_En      DDRREG ( RS485PORT )| = ( 1  <<  RS485TXEn ) ;     // 設定(PC5)RS485方向控制引腳為輸出      RX485DE_RX ;                              // 預設為接收      #endif      UCSRAREG ( COMPORTNo )  =  0x00 ;      UCSRBREG ( COMPORTNo )  =  0x18 ;              // Enable Receiver and Transmitter      UCSRCREG ( COMPORTNo )  =  0x0E ;              // Set frame. format: 8data, 2stop bit      // 通信速率      UBRRHREG ( COMPORTNo )  =  BAUD_H ;             // 0X00      UBRRLREG ( COMPORTNo )  =  BAUD_L ;             // Set baud rate   16M 9600 0x0067 } // 250ms定時器設定Time1 //-----------------------------------------------// //使用定時器1:1024分頻,CTC模式4,産生以毫秒為機關的時間 void  Time1_Init ( ) { // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 16MHz     TCCR1A = 0x00 ;                              // CTC4     TCCR1B = 0x08 ;                              // CTC4     TCCR1B| = 0x03 ;                             // clkI/O/64 ( 來自預分頻器) 16M=4us     OCR1A = T1_TCNT ;                            // 250MS } //-----------------------------------------------// // 看門狗初始化函數 2s void  WatchDog_Enable ( void ) { // Watchdog Timer initialization // Watchdog Timer Prescaler: OSC/2048k     MCUCSR = 0x00 ;                  // 控制與狀态寄存器     WDTCR = 0x1F ;                   // 看門狗使能 500ms(D)1.0S(E) 2.0S(F)     WDTCR = 0x0F ; } // 禁止看門狗 void  WatchDog_Disenable ( void )    // 禁止看門狗 {     MCUCSR = 0x00 ;                  // 控制與狀态寄存器     WDTCR =0 b00011111 ;             // 看門狗 使能位修改 使能(B4=1) 2.0S(F)     WDTCR =0 b00000111 ;             // 禁止看門狗 2.0S(7) } // 喂狗 void  Watchdog_Reset ( void ) {   # asm ( "wdr" )      }            // 喂狗 //-----------------------------------------------// //-------------子函數----------------------------// //寫入資料到序列槽 void  Send_UART ( unsigned  char  dat ) {   uchar  i ; #if  RS485_En    RX485DE_TX ;                                // 使能RS485發送 #endif    UDRREG ( COMPORTNo )  =  dat ;    // UDR0    //等待資料發送完成    while ( ! ( UCSRAREG ( COMPORTNo )  &  0x40 )) ;      // 等待資料發送完成 Bit 6 – TXC: USART 發送結束    UCSRAREG ( COMPORTNo )| = 0x40 ;                 // 清除發送完成狀态 #if  RS485_En    RX485DE_RX ;                                // 使能RS485接收 #endif } //-----------------------------------------------// //等待序列槽資料(注意是”死等“) unsigned  char  Wait_UART ( ) {      while ( ! ( UCSRAREG ( COMPORTNo )  &  0x80 )) ;    // 等等資料到來 Bit 7 – RXC: USART 接收結束      UCSRAREG ( COMPORTNo )| = 0x80 ;               // 清除接收完成狀态      #if  Run_LEDEn      Run_LED ;                                 // 運作LED閃爍      #endif      return  UDRREG ( COMPORTNo ) ; } //-----------------------------------------------// //計算CRC int  CRC16_Word ( char  * ptr ,  int  count ) {      int  crc  =  0 ;      char  i ;      while  ( -- count  >=  0 )      {          crc  =  crc ^  ( int )  * ptr ++  <<  8 ;          i  =  8 ;          do          {          if  ( crc  &  0x8000 )               crc  =  crc  <<  1 ^  0x1021 ;          else               crc  =  crc  <<  1 ;          }  while ( -- i ) ;      }      return  ( crc ) ; } //-----------------------------------------------// //退出Bootloader程式,從0x0000處執行應用程式 void  quit_boot ( void ) {       MCUCR  =  0x00 ;                   //當IVSEL 為"0“ 時,中斷向量位于Flash 存儲器的起始位址;       #ifdef  ATMEGA128       RAMPZ  =  0x00 ;                   //0: ELPM/SPM 可以通路程式存儲器位址$0000 - $7FFF ( 低64K 位元組)       #endif      # asm ( "jmp 0x0000" )              //跳轉到Flash的0x0000處,執行使用者的應用程式 } //-----------------------------------------------// // 讀EEPROM一個位元組 uchar  EEPROM_Read ( uint  Addr )             // EEPROM讀1個位元組操作   0 {      while ( EECR  &  0x02 ) ;                  // 等待上一次寫操作結束      EEAR  =  Addr ;                         // 設定位址寄存器      EECR | =  0x01 ;                        // 設定EERE 以啟動讀操作 b0      return ( EEDR ) ;                        // 自資料寄存器傳回資料 } // 寫EEPROM一個位元組 void  EEPROM_Write ( uint  Addr , char  Data )   // EEPROM 寫1個位元組操作 {      EEAR  =  Addr ;                         // 設定位址寄存器      EEDR  =  Data ;                         // 設定資料寄存器    //    #asm("cli")                     // EEMPE置1,EEPE1,這兩步操作中間不能超過4個時鐘周期      EECR | =  0x04 ;                        // 置位EEMWE            b2      EECR | =  0x02 ;                        // 置位EEWE以啟動寫操作 b1      //#asm("sei") } //-----------------------------------------------// //-------------------------------------------------------// #ifndef  _AVR_BOOT_H_ #define  _AVR_BOOT_H_      1 // 配置檔案包含 #include  "Config.h" //------------------------------------------------------// #ifdef     ATMEGA32 #include  <mega32.h> #endif #ifdef   ATMEGA64 #include  <mega64.h> #endif #ifdef   ATMEGA128 #include  <mega128.h> #endif //---------------------------------------------------// typedef  signed  char      schar ; typedef  signed  int       sin t ; typedef  signed  long      slong ; typedef  unsigned  char    uchar ; typedef  unsigned  int     uint ; typedef  unsigned  long    ulong ; //--------------------------------------------------// // 函數申明 void  UART_Init ( ) ; void  PORT_Init ( ) ; void  Time1_Init ( ) ; void  Send_UART ( unsigned  char  dat ) ; unsigned  char  Wait_UART ( ) ; unsigned  char  Wait1S_UART ( ) ; void  WatchDog_Disenable ( void ) ; void  quit_boot ( void ) ; int  CRC16_Word ( char  * ptr ,  int  count ) ; void  write_one_page ( uchar  data [ ]) ; void  WatchDog_Enable ( void ) ; void  Watchdog_Reset ( void ) ; uchar  EEPROM_Read ( uint  Addr ) ; void  EEPROM_Write ( uint  Addr , char  Data ) ; //--------------------------------------------------// //内部使用的宏定義 #define  CONCAT(a, b)       a ## b #define  CONCAT3(a, b, c)   a ## b ## c //端口以及位定義 #define  PORTREG(No)        CONCAT(PORT, No) #define  PINREG(No)         CONCAT(PIN, No) #define  DDRREG(No)         CONCAT(DDR, No) #define  UDRREG(No)         CONCAT(UDR, No) //序列槽初始化需要寄存器 #define  UCSRAREG(No)       CONCAT3(UCSR, No, A) #define  UCSRBREG(No)       CONCAT3(UCSR, No, B) #define  UCSRCREG(No)       CONCAT3(UCSR, No, C) #define  UBRRHREG(No)       CONCAT3(UBRR, No, H) #define  UBRRLREG(No)       CONCAT3(UBRR, No, L) //---------------------------------------------------// // 端口定義 #define      RX485DE_RX      PORTREG(RS485PORT)&=~(1 << RS485TXEn);   // SCI接收使能 #define      RX485DE_TX      PORTREG(RS485PORT)|=(1 << RS485TXEn);    // SCI發送使能 #define      Run_LED         PORTREG(LEDPORT)^= (1 << LEDPORTNo);     // boot運作LED //---------------------------------------------------// //定義Xmoden控制字元 #define  XMODEM_NUL          0x00         // null #define  XMODEM_SOH          0x01         // Xmodem資料頭 #define  XMODEM_STX          0x02         // Xmodem_1K資料頭 #define  XMODEM_EOT          0x04         // 發送結束 #define  XMODEM_ACK          0x06         // 認可響應 #define  XMODEM_NAK          0x15         // 不認可響應 #define  XMODEM_CAN          0x18         // 撤銷傳送 #define  XMODEM_EOF          0x1A         // 填充資料包 #define  XMODEM_RWC          'C'          // CRC16-128 //-------------------------------------------------------// #ifdef   Xmodem_1K #define  BUFFER_SIZE         1024 #else    // Xmodem #define  BUFFER_SIZE         128 #endif //-----------------------------------------------------// #ifdef   ATMEGA32 #define  SPM_PAGESIZE        128          // SPM 頁大小 #define  BootStart           0x3C00*2     // 按位元組 #define  SPM_REG             SPMCR        // SPM寄存器 #endif #ifdef   ATMEGA64 #define  SPM_PAGESIZE        256          // SPM 頁大小 #define  BootStart           0x7C00*2     // 按位元組 #define  SPM_REG             SPMCSR       // SPM寄存器 #endif #ifdef   ATMEGA128 #define  SPM_PAGESIZE        256          // SPM 頁大小 #define  BootStart           0xFC00*2     // 按位元組 #define  SPM_REG             SPMCSR       // SPM寄存器 #endif //接收緩沖區大小不能小于 SPM_PAGESIZE #if  BUFFER_SIZE < SPM_PAGESIZE #define  BUFSIZE SPM_PAGESIZE             // UART資料緩存 #else #define BUFSIZE BUFFER_SIZE              // UART資料緩存 #endif //計算和定義波特率設定參數 #define  BAUD_SETTING (unsigned char)((unsigned long)CRYSTAL/ ( 16 * ( unsigned  long ) BAUDRATE ) -1 ) #define  BAUD_H ((unsigned char)(BAUD_SETTING>>8)) #define  BAUD_L (unsigned char)BAUD_SETTING //計算T1定時器設定參數 #define  T1_TCNT (unsigned int)((unsigned long)CRYSTAL*250/ ( 64  *  1000 )) ; //--------------------------------------------------------// #endif  // _AVR_BOOT_H_ #ifndef  _CONFIG_H_ #define  _CONFIG_H_      1 // //               關于上海霜蟬-AVR_bootV1.00 // 1、軟體版本V1.00 編譯環境CodeWizardAVR V2.03.9 Standard; // 2、支援本公司常用的三種AVR晶片; // 3、支援标準Xmodem和擴充Xmodem_1K協定; // 4、聯機握手密碼為"00",握手成功手的等待檔案逾時為1分鐘; // 5、預設複位等待3S退出boot到使用者程式或循環運作boot; // 6、支援1分鐘以内的斷網續傳; // 7、支援連續10幀以内資料錯誤的重傳; // 8、支援下載下傳過程中的取消超作; // 9、支援當收到包時,接收過程中每個字元的逾時間隔為 1 秒; // 10、支援所有的逾時及錯誤事件至少重試 10 次; // 11、支援數等待逾時6S的請求; // 12、Boot Loader - Size:1024words; // 13、支援傳輸速度:38.400KB/S~2.400KB/S; // 14、支援上海霜蟬常用最多的三個型号ATMEGA32,64,128。 // 15、支援開門狗自定義開關,自定義時鐘頻率 // // 注意:修改編譯器配置 (char to int;char is unsigned) // 注意:填充資料必須大于兩包(>=256) // 定義晶片型号 // 晶片型号選擇 //#define   ATMEGA32 #define  ATMEGA64                 // 已測試Atmgea64L //#define   ATMEGA128 // 協定類型選擇:Xmodem或Xmodem_1K #define  Xmodem              // Xmodex 128(CRC16) //#define Xmodem_1K            // Xmodem 1024(CRC16) //-----------------------------------------------// // 系統時鐘MHz #ifndef  CRYSTAL #define  CRYSTAL            16000000          // 16M #endif // 波特率 38400~2400 #define  BAUDRATE           9600 // 等待密碼的逾時時間 = WiteTimeCnt * 250ms // 逾時次數 #define  WiteTimeCnt        10                // 10=2.5s // 使用者設定boot駐留等待握手時間(1=250ms)+2.5S(WiteTimeCnt) #define  Wait_BootTime      40                // (1=250ms)+2.5S // 等待檔案的逾時時間 = TimeOutCntC * 250ms // 發送'C'的最大次數 #define  TimeOutCntC        40                // 40=1min // 序列槽号(ATMEA32 序列槽号為空) #define  COMPORTNo          0                 // UART0 // 看門狗使能 #define  WDGEn              1                 // 使用看門狗 // 使用485模式 #define  RS485_En           1                 // 使用485使能腳 // 485控制端口和引腳 #define  RS485PORT          E                 // PORTE #define  RS485TXEn          2                 // PORTE2 // 使用LED訓示狀态 #define  Run_LEDEn          1                 // 使能boot運作LED訓示 // LED控制端口和引腳 #define  LEDPORT            B                 // PORTB #define  LEDPORTNo          6                 // PORTB6 // 延時用于解決序列槽資料出錯 #define  Delay_En           0 // 使用者設定boot駐留等待握手時間(1=250ms)+2.5S(WiteTimeCnt) // 使此功能需要設定EEPROM #define  Wait_BootTime      40                // (40*250ms)+2.5S #define  EE_TimeAddr         0                // 使用EEPROM 占用1個位元組 // 安全更新(更新不成功不進入使用者區) // 使此功能需要設定EEPROM #define  SafeUpdated_En     1 #define  EE_SafeAddr        1                // 使用EEPROM 占用1個位元組 //-----------------------------------------------// #endif   // _CONFIG_H_ //End of file: bootcfg.h

繼續閱讀