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》

  • 相关阅读:
    区分.net中的virtual new 与override
    DOM
    两个php函数
    中文字符,全角字符的正则表达式
    CSS实现居中代码大全
    xp纯净版
    A Visit to Two National Parks: Mount Rainier and Valley Forge
    8、检测浏览器和操作系统
    客户
    American History: The Reagan Years
  • 原文地址:https://www.cnblogs.com/geekygeek/p/hyperbootloader_pic16.html
Copyright © 2011-2022 走看看