了解更多关于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='\r';
while (!TRMT);
TXREG='\n';
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("\r\nDone\r\n");
#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
}

  如何使用

  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》

自己用C语言写单片机PIC16 serial bootloader的更多相关文章

  1. 自己用C语言写单片机PIC18 serial bootloader

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

  2. 自己用C语言写dsPIC / PIC24 serial bootloader

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

  3. 自己用C语言写NXP S32K144 serial bootloader

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

  4. 自己用C语言写NXP S32K116 serial bootloader

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

  5. 自己用C语言写RH850 F1KM serial bootloader

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

  6. 自己用C语言写RH850 F1L serial bootloader

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

  7. C语言PIC16 serial bootloader和C#语言bootloader PC端串口通信程序

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

  8. C语言dsPIC / PIC24 serial bootloader和C#语言bootloader PC端串口通信程序

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

  9. C语言PIC18 serial bootloader和C#语言bootloader PC端串口通信程序

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

随机推荐

  1. Quant的笑话

    Q) Why was the FX quant so unlucky with the ladies?A) Because he always kept his dates short. Q) Why ...

  2. Qt开发中的实用笔记三--关于各种类的零碎知识点:

    1,QUuid()创建唯一标识码,在创建数据库实体ID和链接数据库QSqlDatabase时非常方便 2,QScrollArea与QScrollBar,如果是要在widget中添加窗口滑动QScrol ...

  3. winform中固定界面大小的方法

    Step1: MaximizeBox  :  False MinimizeBox   : False Step2: FormBoarderStyle   :  FixedSingle

  4. h5的拖放(drag和drop)

    被拖曳元素发生的事件=== ondragstart:拖拽元素开始被拖拽的时候触发 ondragend:拖拽完成后触发 目标元素发生的事件=== ondragenter:拖曳元素进入目标元素的时候触发 ...

  5. Java中的队列Queue,优先级队列PriorityQueue

    队列Queue 在java5中新增加了java.util.Queue接口,用以支持队列的常见操作.该接口扩展了java.util.Collection接口. Queue使用时要尽量避免Collecti ...

  6. 【学】jQuery的源码思路2——$符号是如何封装的

    jQuery中的$符号功能很强大,原因在于对函数参数的个数以及种类的控制,还有对于面向对象思想的运用 function jQuery(args){ //接受参数,并对其判断 this.elements ...

  7. 基础14_转义字符和特殊字符ASCII

    一.摘要 PSQL转义字符 二.PLSQL转义字符 PLSQL对应的字符和序号关系 二.PLSQL特殊字符 PLSQL对应的字符和序号关系 1. 转义字符为' '; )||'%'; --A&B ...

  8. Sql服务定时重启

    net stop sqlserveragentnet stop mssqlservernet start mssqlservernet start sqlserveragent 保存到记事本中,重命名 ...

  9. volley_缓存介绍

    离线缓存就是在网络畅通的情况下将从服务器收到的数据保存到本地,当网络断开之后直接读取本地文件中的数据.如Json 数据缓存到本地,在断网的状态下启动APP时读取本地缓存数据显示在界面上,常用的APP( ...

  10. CGI

    CGI的工作原理一般是这么定义的: 客户端web浏览器浏览某个主页后,利用一定的方式提交数据,并通过HTTP协议向Web服务器发出请求,服务器端的HTTP Daemon(守护进程)将描述的主页信息通过 ...