本文原创作者: 少占鱼大神
关于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)
{
//添加传输升级文件和升级用户程序区的代码
return 1;
}
用户程序:
#include
//main函数无特殊要求
void main(void)
{
while(1);
}
//中断函数无特殊需求,可根据需求随意添加
void UART_ISR(void) interrupt 4
{
return;
}
工程配置如下
六,关于升级文件
升级文件的传输可以根据需要使用任何方式,例如串口,网络,USB,存储卡等。升级文件的传输可以做在bootloader里,也可以做在用户程序里,或者两种方式都有。一般来说,bootloader的代码比较简单,不适合做复杂的传输方式。如果传输方式比较复杂,可以在用户程序里传输升级文件,暂存到一个外部存储器,然后跳转到bootloader,让bootloader从外部存储器读出并升级用户程序。升级的时候要注意用户代码的范围。
为了传输的可靠性,升级文件一般还会添加一个文件头,里面包含一些基本的文件信息,例如长度,校验等,这些可以通过编写一些简单的工具来完成。
另外,推荐一些升级文件的传输方式,做bootloader的时候可以考虑
1 ,串口。可以考虑使用XMODEM协议传输升级文件,因为这是一个比较标准的传输协议,很多现成的软件可以支持,例如Windows下自带的超级终端就可以实现(XP以后的系统没有超级终端,但是也有一些别的软件可以代替,例如SecureCRT)
2, USB主机。可以用U盘方式升级。升级文件取一个特定文件名,放在特定位置,主机读取到文件后自动升级
3, USB从机。可以让从机虚拟成一个U盘,PC把文件复制到这个虚拟U盘就完成升级。这样就不需要编写专门的升级软件
4, 以太网。
a)TFTP,这是标准的文件传输命令,Windows自带,而且协议简单
b)Web。用网页的方式,界面有好直观,用网页浏览器就可以实现,也不用单独开发专用的升级软件。
上一篇:P10点阵屏C51单片机程序
下一篇:51单片机lcd1602d电子时钟设计
设计资源 培训 开发板 精华推荐
- 使用 LTC2379CMS-18、18 位、1.6Msps SAR ADC 的典型应用
- SJA1110 100Base-T1多千兆以太网交换机示例板
- AM3G-0515DZ ±15V 3 瓦 DC-DC 转换器的典型应用
- LT6656BIS6-2.048、2.048V 低功率精密高压电源监视器的典型应用
- 使用 Analog Devices 的 LTC1434CGN 的参考设计
- OM17023: BFU520W评估板,用于频率为315、,434和868 MHz的汽车遥控无钥匙进入LNA应用
- LT1086CT 具有自动光控制功能的低压差正稳压器的典型应用
- ADP2450ACPZ-3-EVBZ,用于评估断路器应用的 ADP2450 电源管理 IC 的评估板
- DEMO9S08SE8: SE8演示板
- 基于MP23AB01DH全差分模拟MEMS麦克风的开发板
- AMD推出第二代Versal Premium系列产品:首款PCIe 6.0和CXL 3.1的SoC FPGA
- 红帽宣布达成收购Neural Magic的最终协议
- 5G网速比4G快但感知差!邬贺铨:6G标准制定应重视用户需求
- SEMI报告:2024年第三季度全球硅晶圆出货量增长6%
- OpenAI呼吁建立“北美人工智能联盟” 好与中国竞争
- 传OpenAI即将推出新款智能体 能为用户自动执行任务
- 尼得科智动率先推出两轮车用电动离合器ECU
- ASML在2024 年投资者日会议上就市场机遇提供最新看法
- AMD将裁员4%,以在人工智能芯片领域争取更强的市场地位
- Arm:以高效计算平台为核心,内外协力共筑可持续未来