Keil C51 Code Banking

发布者:数字冒险最新更新时间:2021-10-28 来源: eefocus关键字:Keil  C51  Code 手机看文章 扫描二维码
随时随地手机看文章

1. 简介

MCS-51是8根数据线,16根地址线,所以MCS-51最大只能访问64KB(216)的地址。很多较复杂的C51代码,其整个代码生成Bin文件可能大小64KB。针对这种情况,Keil C51提出了Code Banking机制来解决这个问题。


2. 基本原理

MCS-51内核的代码执行机制已经固定死了,代码运行的地址范围只能在0-64KB之间。一般情况下,我们编译生成的Bin文件,其代码执行地址和代码存储地址是一致。MCU执行到哪个地址,直接去ROM上取相应地址的内容然后执行即可。


MCU要访问超过64KB的地址范围,肯定需要增加地址线。增加4根地址线,则能够访问到2MB的地址范围。由于MCS-51只能执行64K范围的代码,Keil C51编译器相应也只会生成64K地址范围内的代码。


C51是采用分离编译,即单个文件独立编译,最后再链接成一个Bin文件。在链接的过程中,会有一个地址重定位的过程,会将每个obj文件中的代码映射成64K中的一个绝对地址。Keil链接器在链接时,可以将指定的多个Obj文件中的代码地址重定位到相同同地址空间去。如ObjA和ObB指定地址重定位到相同的地址范围内,并且各自的CodeSize为40KB。这样A.c和B.c的代码不能同时在MCU上执行,但是分两次加载,就可以在分别MCU上执行了。


MCS-51默认ROM片外存储器为64KB,存放A.bin。MCS-51再外接1个64KB的外置存储器ROM存放B.bin。什么时候读取ROMA,什么时候读取ROMB呢?还需要1个Pin用来选择。执行A.C中的函数时,选择读取ROMA,执行B.C中的函数时,选择读取ROMB。那么如何知道A.C中的函数会读取ROMA,B.C中的函数会读取ROMB呢?这是因为编译器会将A.C中的函数全部标记0,将B.C中的函数全部标记1。这个标记正好对应上面选择ROM的Pin。


3. Keil的实现

像Reset Vector、Interrupt Vectors、Interrupt Service Routines以及负责几个相同地址模块切换的代码,都是必须固定位置,不能随意变动,可能导致系统出问题。所以Keil C51提出了一个Common Area的概念,存放上述代码。然后针对重定位到相同地址的代码,则被称为Bank Area。


3.1. 具体设置

Bank Area,选择指定有多少个相同地址范围的代码。

在这里插入图片描述

指定文件所属Bank号。

可以将多个文件指定为相同Bank号,未指定Bank号的文件默认为Common Area。BX51链接器最多支持32个Bank号,LX51链接器最多支持64个Bank号。

在这里插入图片描述

Bank分配基本原则。

Common Bank因为是不需要重复加载的,所以效率最高。那些追求效率的代码,都可骗我在Common Bank中。如:Reset Vector、Interrupt Vector、Interruption Service Routines、String constants、Bank Switching Routines、Inter-Bank Jump Tables等等。

Bank0放置一上电就需要调用,并且调用不是非常频率的代码。

其他调用不频繁的代码放在其他Bank。


添加Bank调用代码,默认使用系统提供的(在KeilC51LIBL51_BANK.A51)。

B_NBANKS与前面配置的Bank数相同,B_MODE是Bank_Switching的方式。


;                          For BL51 the maximum value for ?B_NBANKS is 32

;                          For LX51 the maximum value for ?B_NBANKS is 64

?B_NBANKS       EQU  4    ; Define maximum Number of Banks

;                         ; following values are allowed: 2, 4, 8, 16, 32, 64

;                         ; for BL51 the maximum value for ?B_NBANKS is 32

;                         ; for LX51 the maximum value for ?B_NBANKS is 64

;

; ?B_MODE: Bank Switching via

;                    <0=> 8051 Port

;                    <1=> XDATA Port

;                    <4=> User-provided bank switch code

?B_MODE         EQU  0    ; 0 for Bank-Switching via 8051 Port

;                         ; 1 for Bank-Switching via XDATA Port

;                         ; 4 for user-provided bank switch code


3.2. 链接器

Keil C51支持2种链接器,分别为BL51和LX51。

在这里插入图片描述

3.2.1. BL51链接器

BL51默认生成的Hex文件为Hex80,并且当前工程设置多少个Bank,则生成多少个Hex文件,每个Bank和相同的Common组成一个文件,如下图。每个Hex文件可以用Hex2Bin.exe转换成Bin文件。

在这里插入图片描述

3.2.2. LX51链接器

BL51是较早的链接器,LX51是在BL51基础上进行扩展的链接器,功能更强大,优化性能更好。一般情况下建议使用LX51。LX51会将多个Bank合并生成一个Hex文件。这个Hex文件中的代码地址空间是超过64KB的,Hex80格式不支持超过64KB的地址空间。针对这种情况,一种新的Hex描述格式产生了——Hex386。Hex386不仅支持多超过64KB地址范围,还支持指定偏移存储。

BL51链接器生成的Bin文件,如果Bank Area有多余空间,会以0填充。而LX51生成的Bin文件,如果Bank Rrea有多余空间,则会优先以Common代码填充。Offset默认为0,如果指定了,则将生成的代码放在Bin文件相应的偏移。下图为偏移为0。

在这里插入图片描述

在这里插入图片描述

3.3. Bank Switching方式

3.3.1. 8051Port

MSC-51操作64KROM的结构如下:

我们完全可以依据上述接口,连接多个ROM。然后通过P口来选通。

L51_BANK.A51中有下述代码,即指定P1口用来控制选择哪个ROM,也即代码执行到Bank1时,P1=1;执行到Bank2时,P1=2,依次类推。更详细的切换流程,可以查看汇编代码。


IF  ?B_MODE = 0;

;-----------------------------------------------------------------------------

; if ?BANK?MODE is 0 define the following values

; For Bank-Switching via 8051 Port define Port Address / Bits

;

; Bank Switching via 8051 Port

;    This is only used if ?B_MODE is 0

; P1: 8051 Port address <0x0-0xFF>

P1              DATA    90H      ; I/O Port Address

;

?B_PORT         EQU     P1       ; default is P1

; ?B_FIRSTBIT: Starting with Bit <0-7>

;      Default is Bit 2

?B_FIRSTBIT     EQU     2        ; default is Bit 2

;

;-----------------------------------------------------------------------------

ENDIF;


3.3.2. XData Port

查看L51_BANK.A51代码,变量B_XDATAPORT是参与切换的标识,默认设置为0xFFFF,可以根据需要修改。


IF  ?B_MODE = 1;

;-----------------------------------------------------------------------------

; if ?BANK?MODE is 1 define the following values

; For Bank-Switching via XDATA Port define XDATA Port Address / Bits

;

; Bank Switching via XDATA Port Address

;    This is only used if ?B_MODE is 1

; P1: XDATA port address <0x0-0xFFFF>

?B_XDATAPORT    EQU     0FFFFH   ; default is XDATA Port Address 0FFFFH

; ?B_FIRSTBIT: Starting with Bit <0-7>

;      Default is Bit 0

?B_FIRSTBIT     EQU     0        ; default is Bit 0

;

;-----------------------------------------------------------------------------

ENDIF;


配合分布外部存储器,如下图。PSD813F2可以0FFFFH地址为控制位,来分别切换不同的Bank对应不同的存储空间,达到和8051Port类似的效果。标准的ROM成本较高,使用此种方式,可以更方便地支持更多的Bank,成本也低。PSD813F2更详细的配置可以参考PSD813F2的DataSheet。

3.3.3. user-provided

以上两种方式,明显是8051Port更容易。所以用户定义也是基于这种方式。很多基于MSC-51内核的MCU,并未完整引出P1口,不能正确的使用方法1,此时可以自定义。见L51_BANK.A51代码。


P1              DATA    90H      ; I/O Port Addresses

P3              DATA    0B0H

;

SWITCH0         MACRO            ; Switch to Memory Bank #0

                CLR     P1.5     ; Clear Port 1 Bit 5

                CLR     P3.3     ; Clear Port 3 Bit 3

                ENDM

;

SWITCH1         MACRO            ; Switch to Memory Bank #1

                SETB    P1.5     ; Set   Port 1 Bit 5

                CLR     P3.3     ; Clear Port 3 Bit 3

                ENDM

;

SWITCH2         MACRO            ; Switch to Memory Bank #2

                CLR     P1.5     ; Clear Port 1 Bit 5

                SETB    P3.3     ; Set   Port 3 Bit 3

                ENDM

;

SWITCH3         MACRO            ; Switch to Memory Bank #3

                SETB    P1.5     ; Set   Port 1 Bit 5

                SETB    P3.3     ; Set   Port 3 Bit 3

                ENDM


默认是以P1.5和P3.3两个Pin为例。需要匹配相应的外置电路,见下图。编译器编译Bank1的函数,会在前面插入SWITCH1指令,相当于Bank1对应的EPROM。编译器编译Bank2的函数,会在前面插入SWITCH2指令,相当于Bank2对应的EPROM。更多详细信息,可以在Keil中仿真调试查看。

3.3.4. 注意

使用user-provided时,因为复位时,系统保持之前的状态,不会自动切换到Bank0,需要修改切换代码,见STARTUP.A51代码的最后,将if 0改为if 1。


; This code is required if you use L51_BANK.A51 with Banking Mode 4

; Code Banking

; Select Bank 0 for L51_BANK.A51 Mode 4

#if 0   

;      Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4.

EXTRN CODE (?B_SWITCH0)

                CALL    ?B_SWITCH0      ; init bank mechanism to code bank 0

#endif


3.4. 自定义外部存储器

除了MSC-51直接总线支持的的ROM外部存储器外,还有一些设备可以作为外部存储器存储bin文件。如EEPROM、NorFlash,这两种设置,MSC-51一般没有直接提供总线访问,也就是说直接连接到MSC-51上,然后直接利用Keil提供的Bank Switching方法。那么针对这种情况,我们有办法吗?可以的。我们可以完全不用Keil提供的Switch方法,完全自己构建Switch方法。如在执行Bank0中的FunA时,接下来需要执行Bank1中的函数B,那么在执行FunB之前,先让代码运行至Common Bank中的SwitchFun。SwitchFun负责将Bank1中的Bin文件加载SRAM中覆盖原有的Bank0的代码。详见下面的伪代码。


// Common.c

void SwitchFun(int nOldBankNo, int nNewBankNo, PFun pFun)

{

LoadBinToSRAM(nNewBankNo);

pFun();

LoadBinToSRAM(nNewBankNo);

}


// Bank0.c

void FunA()

{

// Call FunB of bank1

SwitchFun(0, 1, FunB);

// Do some stuff

}


// Bank1.c

void FunB()

{

// Do some stuff

}


LoadBinToSRAM完成加载指定Bank的Bin覆盖到指定的SRAM。

此种方法主要是利用Keil的Code Banking功能将指定文件生成相同的执行代码地址,加载切换的过程换成自己实现。这里依然要利用L51_BANK.A51文件,否则无法使用Bank功能。然后用user-provided模式,为了防止触发Keil提供的切换功能自动设置了相应的Pin,我们可以修改L51_BANK.A51中B_MODE = 4时时的代码,注释对相关Pin的设置。当我们调用Bank0的函数时,系统可能会调用SWITCHO函数,然后会设置对应的2个Pin,这会带来不可控影响。


P1              DATA    90H      ; I/O Port Addresses

P3              DATA    0B0H

;

SWITCH0         MACRO            ; Switch to Memory Bank #0

;                CLR     P1.5     ; Clear Port 1 Bit 5

;                CLR     P3.3     ; Clear Port 3 Bit 3

                ENDM

;

SWITCH1         MACRO            ; Switch to Memory Bank #1

;                SETB    P1.5     ; Set   Port 1 Bit 5

;                CLR     P3.3     ; Clear Port 3 Bit 3

[1] [2]
关键字:Keil  C51  Code 引用地址:Keil C51 Code Banking

上一篇:C51中的函数指针
下一篇:C51和MDK的ROM大小及变量绝对地址初始化

推荐阅读最新更新时间:2024-11-09 10:31

Microchip发布面向VS Code® 的MPLAB® 扩展早期访问版本
赋能设计人员在流行集成开发环境中使用Microchip开发工具 此次发布是公司长期计划的第一步,旨在扩大产品组合、更好地服务VS Code 生态系统开发人员 为充分利用Microsoft® Visual Studio® Code (VS Code®) 的多功能性,Microchip Technology(微芯科技公司)今日发布面向VS Code 的 MPLAB® 扩展(MPLAB® Extensions)早期访问版本。 此次发布为嵌入式设计人员提供了将项目从MPLAB X集成开发环境(IDE) 导入VS Code的工具,同时仍可使用Microchip的调试和编程支持。这一举措是Microchip长期战略的一部分,旨在扩展其
[嵌入式]
Microchip发布面向VS <font color='red'>Code</font>® 的MPLAB® 扩展早期访问版本
C51单片机对共阳极数码管的控制设计
这是共阳极数码管的电路图,其中JP3接到P0口,JP3的8-1对应数码管的a-dp引脚。 共阳极数码管的编码表如下,注意a---最低位,dp---最高位: 【0---3】0xco,0xf9,0xa4,0xb0, 【4---7】0x99,0x92,0x82,0xf8, 【8---B】0x80,0x90,0x88,0x83, 【C---F】0xc6,0xa1,0x86,0x8e。 C51程序显示数字0-9: #include #define uchar unsigned char void delay(); uchar smg[10] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,
[单片机]
<font color='red'>C51</font>单片机对共阳极数码管的控制设计
基于Keil MDK-ARM 和 IAR EWARM进行仿真打印的配置
1写在前面 很多初学者习惯使用软件仿真,应该是很多人都知道的一款仿真软件。 以前开发板相对较贵,且快递不方便,使用仿真软件可以理解。现在便宜的STM32开发板就十几块,还用仿真软件,我不是很理解。 有经验的人都知道,仿真和实际运行情况很多时候都不一样,相信不用我说,大家都明白。 因此,我个人不是很推荐大家仿真,本文内容可能存在纰漏,仅限个人学习。 下面讲述基于Keil MDK-ARM 和 IAR EWARM进行仿真打印的配置。 2Keil仿真打印配置 Keil MDK-ARM不能仿真,原因出在仿真参数出现了问题: 修改这两处参数为:DARMSTM.DLL -pSTM32F103ZE 基于前面使用STM32CubeMX生成工
[单片机]
基于<font color='red'>Keil</font> MDK-ARM 和 IAR EWARM进行仿真打印的配置
单片机c语言教程第三章--C51数据类型
每写一个程序,总离不开数据的应用,在学习 c51 语言的过程中掌握理解数据类型也是 很关键的。先看表 3-1,表中列出了 KEIL uVision2 单片机c语言编译器所支持的数据类型。在标准C语言中基本的数据类型为 char,int,short,long,float 和 double,而在c51编译器中int 和 short 相同,float 和 double 相同,这里就不列出说明了。下面来看看它们的具体定 义 数据类型 长 度 值 域 unsigned char 单字节 0~255 signed char 单字节 -128~+127 unsigned int 双字节 0~65535
[单片机]
干货,三分钟教你Keil C51软件的使用方法
KEIL C51标准C编译器为8051微控制器的软件开发提供了C语言环境,但是界面是英文的好多初学者看很多教程都是一头雾水,本站特地制作了一个相对简单的教程。他能能嵌入汇编语言保留了汇编代码高效,快速的特点。KEIL C51编译器的功能不断增强,使你可以更加贴近CPU本身,及其它的衍生产品,其效率已经达到了相当搞的程度。C51已被完全集成到uVision2的集成开发环境中,这个集成开发环境包含:编译器,汇编器,实时操作系统,项目管理器,调试器。uVision2 IDE可为它们提供单一而灵活的开发环境。 Keil C51 软件是众多单片机应用开发的优秀软件之一,它集编辑,编译,仿真于一体,支持汇编,PLM 语言和 C 语言的程序
[单片机]
干货,三分钟教你<font color='red'>Keil</font> <font color='red'>C51</font>软件的使用方法
Mendix公司首届“Low-Code for Good”全球黑客马拉松成功举办
Mendix公司首届“Low-Code for Good”全球黑客马拉松成功举办,汇集来自64个国家超过1,200名开发者 ● 低代码黑客马拉松“MxHacks 2022”于 9月23日至24日 在全球四个国家地区(波士顿、伦敦、鹿特丹、新加坡)及线上举行 ● 1,200多名开发者线上线下齐聚一堂,共同为推动公益事业发展搭建数字化解决方案 中国北京 - 2022年10月21日 - 企业级低代码应用开发全球领导者Mendix公司, a Siemens business于近日举办了首届 “MxHacks 2022:Low-Code for Good”全球低代码黑客马拉松。 来自64个国家的1,200多名开发者通过线下及
[工业控制]
C51 DS1302芯片+lcd12864 显示时间
1.原理图 1302芯片部分 lcd12864部分 2.代码部分 config.h #ifndef __CONFIG_H #define __CONFIG_H #include reg51.h #include lcd12864.h #include intrins.h #define uchar unsigned char #define uint unsigned int #endif lcd12864.c #include lcd12864.h void lcdinit(void) //初始化LCD { write(0,0x30); //功能设定 write(0,0x0c); //显示开
[单片机]
<font color='red'>C51</font> DS1302芯片+lcd12864 显示时间
KEIL C51代码优化详细分析:局部参数放寄存器变量,数据覆盖技术
阅读了《单片机与嵌入式系统应用》2005年第10期杂志《经验交流》栏目的一篇文章《Keil C51对同一端口的连续读取方法》(原文)后,笔者认为该文并未就此问题进行深入准确的分析 文章中提到的两种解决方法并不直接和简单。笔者认为这并非是Keil C51中不能处理对一个端口进行连续读写的问题,而是对Kei1 C51的使用不够熟悉和设计不够细致的问题,因此特撰写本文。 本文中对原文提到的问题,提出了三种不同于原文的解决方法。每种方法都比原文中提到的方法更直接和简单,设计也更规范。(无意批评,请原文作者见谅) 1 问题回顾和分析 原文中提到:在实际工作中遇到对同一端口反复连续读取,Keil C51编译并未达到预期的结果。原文作者
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved