zoukankan      html  css  js  c++  java
  • 自己用C语言写单片机PIC16 serial bootloader

                         了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序)。

      为什么自己写bootloader

      我的第一款自己的serial bootloader是为Microchip PIC16单片机写的UART bootloader,我命其名为HyperBootloader_PIC16. 为什么取这个名字,下面会讲。很多朋友可能会问为什么要自己写bootloader, 百度上一搜,有不少下载下来直接就可以用。比如ds30_Loader 就很不错,免费,还支持Microchip很多系列的单片机。是没错,但是网上搜到的bootloader用C语言写的少得可怜,或者不能用,或者不是用XC8编译的(Microchip 的C编译器)。它们绝大多数都是用汇编写的,包括ds30_Loader。对于不怎么用汇编的我感觉很头疼,这些bootloader也不太好修改,比如增加个自己需要的功能都比较困难。所以我决定自己用C语言写PIC16 serial bootloader。说干就干,本来以为是小菜一碟,没想到写一个稳定好用又节省空间的bootloader也不简单,这是后话。在讲如何实现自己的PIC16 serial bootloader之前,我先讲下serial bootloader的基础知识。如果不需要了解的,请跳过这部分。

      Serial bootloader之ABC

      Serial bootloader是一种非常方便使用并且低成本的程序烧写的方法。一般情况,每次烧写Microchip单片机我们都需要将烧录器PICKit3或ICD3接上目标板,然后在电脑上使用Microchip IPE或MPLAB X就可以直接烧写Hex文件到目标板中。使用serial bootloader 就可以不需要插拔烧录器,对开发工程师来讲非常的方便。Serial bootloader需要用到单片机的串口,所以单片机端需要如下硬件电路,其中DB9串口是和电脑的串口相连。

      

      Serial bootloader 和应用程序一样也是烧录到程序存储器中,serial bootloader 和应用程序在程序存储器中需要分开放置。所以serial bootloader一般有两种放置方式,一种是放置在程序存储器头部,另一种是放置在程序存储器底部,如下图所示。

     

      Serial bootloader 可以使用烧录器PICkit3或ICD3烧到目标板上,之后更新应用程序就不需要烧录器了。目标板和电脑通过串口相连,电脑上运行一个串口通信程序,将应用程序的Hex文件通过串口传给serial bootloader, serial bootloader 再将接收到的Hex数据烧录到程序存储器的正确的位置上。接下来就是讲今天的主角HyperBootloader_PIC16——我自己写的第一款PIC16单片机C语言 serial bootloader。

      HyperBootloader_PIC16

      HyperBootloader_PIC16我是模仿HI-TECH的PICC bootloader,由于我是用XC8的编译器的,所以有很多改动。上面有提到bootloader在程序存储器中要么是在头部要么是在底部,而HyperBootloader_PIC16 是在程序存储器的底部。与它通信的电脑端的串口通信程序是超级终端——HyperTerminal. 这也是它命名的由来。

      主要代码段

      HyerBootloader_PIC16是一款用C语言写的只占很少空间的serial bootloader。不到0x200程序字空间. 实现逻辑也很简单,主要代码段如下。

    /* receive a hex file via the serial port and write it to program memory */
        for(;;)        // loop until end of file
        {
            typedef union {
                unsigned int word;
                unsigned char byte[2];
            } wordbyte;
            static persistent unsigned char inx;
            static persistent BANKX wordbyte addr;
    
            while (comms_getch()!=':');    // wait for start of hex file line
    
            words2write = cksum = bytecount = getXbyte();    
            words2write >>= 1;           // convert byte count to word count
            addr.byte[1] = getXbyte();    // get the high byte of address
            addr.byte[0] = getXbyte();   // get the low byte of the address
            addr.word >>= 1;   // convert byte address to word address
    
            EEADR = addr.byte[0];
            EEADRH = addr.byte[1];
            if(addr.byte[1] == 0x21)    // unless this case,
                EEPGD = 0;              // when EEPROM should be selected
            else
            {
                EEPGD = 1;        // else destination is flash memory
        // ignore code that overlaps loader or data such as CONF/IDLOC
                #ifdef _BANK_ALIGNED
                if( addr.byte[1] >= (BOOT_START>>8) )
                {
                #else
                if( addr.word >= (BOOT_START) ){
                #endif
                    while (!TRMT);
                    TXREG='
    ';
                    while (!TRMT);
                    TXREG='
    ';
                    continue;
                }
            }
            rectype = getXbyte();    // get the record type
            inx=0;
            while(bytecount--)
            {
                databuff[inx++]=getXbyte();    // read all bytes in this record
            }
            checksum();    // test the checksum of this record
    
            if(rectype==1)
            { // if this was an END record: prepare to run new program
                comms_puts("
    Done
    ");
            #asm
                GOTO run_program
            #endasm
            }
            // else ... INHX8M data record
            ix=0;
            isStartup=0;
    
           // Initiate a write to memory - EEADR has already been loaded
            if (((tmpadrh=addr.byte[1])|(addr.byte[0] & 0xFC)) == 0)
            {    // is this address < 0004h?
                EEADRH = BOOT_START >> 8;    
            #ifndef _BANK_ALIGNED
                tmpadr = EEADR;
                EEADR = ((BOOT_START & 0xFF));
            #endif
                isStartup=1;    // Yes - this is the reset vector code of new app
            }
            #ifdef _WRITE_4_WORDS
            prewrite = EEADR & _FWMASK;
            EEADR &= ~_FWMASK;  // to start of flash-write boundary
            do
            {
            if(prewrite){
                    prewrite--;
                    RD=1;
                    NOP();
                    NOP();
            }else{
                    EEDATA=databuff[ix++];
                    EEDATH=databuff[ix++];
                    if(words2write==0){
                            prewrite=((~EEADR)&_FWMASK);
                    }
            }
            #else
            do
            {
                EEDATA=databuff[ix++];
                EEDATH=databuff[ix++];
            #endif
                while(WR);
                WREN=1;    // commit this word to flash
                EECON2=0x55;
                EECON2=0xAA;
                WR=1;            //initiate the write
                NOP();
                NOP();
                while (WR);
                WREN=0;
            #ifdef _BANK_ALIGNED
                if(isStartup && (EEADR==3)){
            #else
                if(isStartup && ((EEADR&3)==3)){
            #endif
                isStartup = 0;
                EEADRH = tmpadrh;    //swap back the address
            #ifndef _BANK_ALIGNED
                EEADR = (tmpadr|3);
            #endif
                }
                if(++EEADR == 0)
                    EEADRH++;
            #ifdef _WRITE_4_WORDS
            }while((prewrite)||words2write--);
            #else
            }while(words2write--);
            #endif
        }
    View Code

      如何使用

      1. 使用XC8编译HyperBootloader_PIC16, 由于HyperBootloader_PIC16将放在程序存储器底部,占0x200程序字,编译前,需先将Code Offset编译参数设到正确值。例如,某PIC16 单片机的程序存储器空间为0x2000程序字,Code Offset = 0x2000 - 0x200 = 0x1E00, 所以只需设置Code offset为1E00, 然后编译。

      2. 使用pickit3烧录HyperBootloader_PIC16的Hex文件到目标板中。

      3. 拔除pickit3烧录器,连接目标板与PC的串口,打开超级终端,设置如下:9600-8-None-1-None, Line Delay-20ms

      4. 重启目标板,超级终端会出现Booting... 字样。

      5. 6秒内,在超级终端窗口中按下键盘上任何按键,会出现">"(6秒内没按键,会自动跳转到用户的应用程序中去)。

      6. 打开Send Text File对话框,选择期望烧录的应用程序hex文件,点击确认, HyperBootloader会将接收到的数据传回到电脑超级终端上,并将数据烧录到目标板程序存储器的正确位置。

      7. 烧录完毕,再次重启目标板,超级终端显示完Booting ......,就自动跳到应用程序中,目标板开始正常运行应用程序。

      之后每次更新应用程序,只需重复步骤 4 ~ 7 就可以了。

      效果展示

      下面是我使用HyperBootloader_PIC16给PIC16F877A烧录应用程序的效果, HyperBootloader_PIC16会将接收到的数据先发送回电脑,同时再完成烧录。如果有问题,这样非常利于debug.

      Booting.... >
      :100000000A128A1104283FFF0A128A11522EFF1B7E
      :10001000112883137F1883170008840A0319FF0A25
      :1000200008007F087F398A000408840A0319FF0A40
      :1000300082003FFF3FFF3FFF3FFF3FFF3FFF3FFF8C
      :10020000533465347434743469346E346734203450
      :1002100054344D3452343034203474346F342034F8
      :10022000753473346534203469346E347434653411
      :1002300072346E3461346C34203469346E34733407
      :100240007434723475346334743469346F346E3496
      :1002500020346334793463346C346534203463344B
      :100260006C346F3463346B342E342E342E342E348D
      :100270002E342E34203400347534743469346C34A4
      :1002800069347A346134743469346F346E342034B0
      :100290006F346E3420344D346934633472346F34C7
      :1002A0006334683469347034203438342D34623423
      :1002B0006934743420346D34693464342D347234C8
      :1002C00061346E346734653420344D3443345534EE
      :1002D000203450344934433431343634463438349D
      :1002E0003734373441340D340A3400341B345B3432
      :1002F00031343B34343430343B34333431346D3482
      :1003000020344E344F34543445341B345B34313450
      :100310003B34343430343B34333434346D3420346F
      :1003200043344F344C344F3452341B345B34313407
      :100330003B34343430343B34333432346D34203451
      :100340004334483441344E34473445341B345B34F1
      :1003500030346D3420340D340A3400342D342D34CF
      :100360002D342D342D342D342D342D342D342D3485
      :100370002D342D342D342D342D342D342D342D3475
      :100380002D342D342D342D342D342D342D342D3465
      :100390002D342D342D342D342D342D342D342D3455
      :1003A0002D342D342D342D342D342D342D342D3445
      :1003B0002D342D342D342D342D342D342D342D3435
      :1003C0002D342D340D340A340034543468346934F7
      :1003D00073342034703472346F346734723461345F
      :1003E0006D342034693473342034613420347334F0
      :1003F00069346D3470346C34653420346534783449
      :1004000061346D3470346C34653420346F34663448
      :100410002034733465347234693461346C3420347C
          .

          .

          .
      :100CA000FE0A452E8313E830FD000530FE00F930C2
      :100CB000FF00A03084000A128A11452683010A121F
      :100CC0008A115C2D20308316980090308312980092
      :100CD000673083169900181508008C1E00341A0816
      :100CE000F0008C1208003FFF3FFF3FFF3FFF3FFF38
      :02400E
      :00000001FF

      Done

      主要特性

      HyperBootloader_PIC16有以下主要特性

      1. C语言写的,XC8 编译(只有一点汇编在里面)。

      2. 非常容易移植。

      3. 支持FLASH烧写

      4. 可支持EEPROM烧写。

      5. 不支持CONFIG BITS/IDLOC 烧写, 保持应用程序的Configuration Bits和Bootloader的一致。

      如果你有什么疑问,或有兴趣了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966验证信息请填 bootloader 或 cnblogs)

      想了解dsPIC bootloader 请阅读我的随笔《自己用C语言写dsPIC / PIC24 serial bootloader》

      想了解PIC18 bootloader 请阅读我的随笔《自己用C语言写单片机PIC18 serial bootloader》

  • 相关阅读:
    CodeForces 785D Anton and School
    CodeForces 785C Anton and Fairy Tale
    CodeForces 785B Anton and Classes
    CodeForces 785A Anton and Polyhedrons
    爱奇艺全国高校算法大赛初赛C
    爱奇艺全国高校算法大赛初赛B
    爱奇艺全国高校算法大赛初赛A
    EOJ 3265 七巧板
    EOJ 3256 拼音魔法
    EOJ 3262 黑心啤酒厂
  • 原文地址:https://www.cnblogs.com/geekygeek/p/hyperbootloader_pic16.html
Copyright © 2011-2022 走看看