一种8051的bootloader的实现方式

发布时间 : 星期日 文章一种8051的bootloader的实现方式更新完毕开始阅读

一种8051的bootloader的实现方式

一, 基本硬件需求

要实现IAP功能,需要51单片机可以在程序里修改代码空间的Flash,或者至少可以修改用户程序区的Flash,新出的51大部分都能满足这个要求

二, 空间划分

一般bootloader位于单片机代码空间的起始地址,用户程序在后面。这个需要根据实际的需求来决定,bootloader功能简单,就少占用一些,bootloader功能复杂的就多占用一些。除此之外,一般还要根据Flash的页为界线划分。附带的工程模板里,bootloader使用0x0000-0x0fff区间,用户程序使用0x1000以后的空间。

三, 中断的处理

51单片机的中断入口一般位于0地址开始的区间,无法修改,但是根据上面的空间划分方式,这个区间位于bootloader的范围,是不能随意更改的。所以代码里用了一个软件的方式对中断入口做了重映射处理,后面将结合具体的代码介绍实现方式。

四, Bootloader的处理

1, 建立工程的时候,选择把Startup.a51添加到工程 2, 在Startup.a51里添加如下代码:

ORG 0003H

LJMP 2003H ORG 000BH LJMP 200BH ORG 0013H LJMP 2013H ORG 001BH LJMP 201BH

ORG 0023H LJMP 2023H ………………………….

根据具体型号的中断数量和地址,添加中断跳转代码,格式为ORG XXH LJMP 2000+XXH,这样做,是为了将中断映射到用户程序区的0x2000开始的空间,在用户程序里,还要做一些对应的设置,后面将介绍。

3, Bootloader的处理流程。Bootloader的主要作用一般是开机初始化,自检和升级

用户程序,以及引导用户程序。因为上面已经把中断映射到用户程序空间,所以bootloader里最好就不要用中断了。

五, 用户程序的处理。

1, 用户程序的Startup.a51无特殊需求,可以根据需要选择添加到工程,然后自己做

修改,也可以不添加到工程,由编译器连接一个默认的startup.a51

2, 用户程序的所有普通函数和中断函数也没有特殊要求,可以按正常的方式编写 3, 用户程序的工程设置。因为用户程序不再是从0地址开始,所以需要在工程设置

里做定位处理:设置用代码的范围,定位用户代码入口地址。具体设定如下图: 因为用户代码规划到0x1000以后的空间,所以设置code range从0x1000开始 为了让bootloader能准确跳到用户程序入口,所以需要将C_C51STARTUP定位到0x1000位置。(C_STARTUP位于startup.a51里,它才是程序的真正入口,而不是main函数;另外,入口也并不是必须定位在这个位置,只要位于用户代码空间就可以)

4, 中断映射。在bootloader里,将中断入口定位在了0x2000开始的空间,在用户

程序里,也必须做一个对应的设置。方法如下:

这样处理之后,便完成了中断的映射。当中断发生时,会先进入位于bootloader里的硬件中断入口,然后在那里跳转到0x2000开始的一个软件重定义的向量表,再跳转到中断入口函数。和没有bootloader的方式比起来,这样做会多一次LJMP跳转,但是一般情况下影响不大。

关于bootloader存放位置:

备注:其实,最好是将bootloader程序放到最后,这样,应用程序起始地址,中断地址等不用设置,默认程序从0x0000h开始执行,然后用函数指针跳转到bootloader 程序起始地址,让其先执行。通过bootloader内部程序选择是否升级应用程序还是直接跳转回应用程序区执行。

若升级,就读写flash的应用程序部分。若不升级,就跳转回应用程序继续运行。

BOOTLOADER 程序举例: #include

//用户程序起始地址

#define USER_APP_ADDR 0x1000

char power_on_test(void); char check_upgrade_request(void); char upgrade(void);

void main(void) {

//定义一个函数指针,用于跳转到用户程序 void (*boot)() = USER_APP_ADDR; //bootloader里不能开启中断 EA = 0;

//添加系统初始化代码 if(power_on_test()){//开机自检 upgrade(); } else if

(check_upgrade_request()){//检查是否有升级需求 upgrade(); }

//如果不需要升级,或者升级已经完成,执行下面的代码进入用户程序 (*boot)();

//正常情况下不会运行到这里,以防万一 while(1); }

char power_on_test(void) {

//添加开机自检代码,如果自检错误,进入升级模式 return 0; }

char check_upgrade_request(void) {

//添加检查用户是否有升级要求的代码,例如输入命令或按下按键,如果有,则进入升级模式 return 0; }

char upgrade(void)

联系合同范文客服:xxxxx#qq.com(#替换为@)