单片机地址指定物理地址为什么用@

如何通过xcode编程使MAC机器和HID的USB单片机设备进行通讯
#import &Foundation/Foundation.h&
#include &IOKit/hid/IOHIDLib.h&
#include &IOKit/hid/IOHIDKeys.h&
@protocol UsbHIDDelegate &NSObject&
- (void)usbhidDidRecvData:(uint8_t*)recvData length:(CFIndex)reportL
- (void)usbhidDidM
- (void)usbhidDidR
@interface UsbHID : NSObject {
IOHIDManagerRef managerR
IOHIDDeviceRef deviceR
@property(nonatomic,strong)id&UsbHIDDelegate&
+ (UsbHID *)sharedM
- (void)connectHID;
- (void)senddata:(char*)
- (IOHIDManagerRef)getManageR
- (void)setManageRef:(IOHIDManagerRef)
- (IOHIDDeviceRef)getDeviceR
- (void)setDeviceRef:(IOHIDDeviceRef)
#import &UsbHID.h&
@implementation UsbHID
static UsbHID *_sharedManager =
static void MyInputCallback(void* context, IOReturn result, void* sender, IOHIDReportType type, uint32_t reportID, uint8_t *report,CFIndex reportLength) {
[[[UsbHID sharedManager] delegate] usbhidDidRecvData:report length:reportLength];
static void Handle_DeviceMatchingCallback(void *inContext,IOReturn inResult,void *inSender,IOHIDDeviceRef inIOHIDDeviceRef) {
[[UsbHID sharedManager] setDeviceRef:inIOHIDDeviceRef];
char *inputbuffer = malloc(64);
IOHIDDeviceRegisterInputReportCallback([[UsbHID sharedManager]getDeviceRef], (uint8_t*)inputbuffer, 64, MyInputCallback, NULL);
NSLog(@&%p设备插入,现在usb设备数量:%ld&,(void *)inIOHIDDeviceRef,USBDeviceCount(inSender));
[[[UsbHID sharedManager] delegate] usbhidDidMatch];
static void Handle_DeviceRemovalCallback(void *inContext,IOReturn inResult,void *inSender,IOHIDDeviceRef inIOHIDDeviceRef) {
[[UsbHID sharedManager] setDeviceRef:nil];
NSLog(@&%p设备拔出,现在usb设备数量:%ld&,(void *)inIOHIDDeviceRef,USBDeviceCount(inSender));
[[[UsbHID sharedManager] delegate] usbhidDidRemove];
static long USBDeviceCount(IOHIDManagerRef HIDManager){
CFSetRef devSet = IOHIDManagerCopyDevices(HIDManager);
if(devSet)
return CFSetGetCount(devSet);
+(UsbHID *)sharedManager {
@synchronized( [UsbHID class] ){
if(!_sharedManager)
_sharedManager = [[self alloc] init];
return _sharedM
+(id)alloc {
@synchronized ([UsbHID class]){
NSAssert(_sharedManager == nil,
@&Attempted to allocated a second instance&);
_sharedManager = [super alloc];
return _sharedM
- (id)init {
self = [super init];
if (self) {
managerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
IOHIDManagerScheduleWithRunLoop(managerRef, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
IOReturn ret = IOHIDManagerOpen(managerRef, 0L);
if (ret != kIOReturnSuccess) {
NSAlert* alert = [NSAlert alertWithMessageText:@&error& defaultButton:@&OK& alternateButton:nil otherButton:nil informativeTextWithFormat:@&打开设备失败!&];
[alert runModal];
const long vendorID = 0x1391;
const long productID = 0x2111;
NSMutableDictionary* dict= [NSMutableDictionary dictionary];
[dict setValue:[NSNumber numberWithLong:productID] forKey:[NSString stringWithCString:kIOHIDProductIDKey encoding:NSUTF8StringEncoding]];
[dict setValue:[NSNumber numberWithLong:vendorID] forKey:[NSString stringWithCString:kIOHIDVendorIDKey encoding:NSUTF8StringEncoding]];
IOHIDManagerSetDeviceMatching(managerRef, (__bridge CFMutableDictionaryRef)dict);
IOHIDManagerRegisterDeviceMatchingCallback(managerRef, &Handle_DeviceMatchingCallback, NULL);
IOHIDManagerRegisterDeviceRemovalCallback(managerRef, &Handle_DeviceRemovalCallback, NULL);
NSSet* allDevices = (__bridge NSSet*)(IOHIDManagerCopyDevices(managerRef));
NSArray* deviceRefs = [allDevices allObjects];
if (deviceRefs.count==0) {
- (void)dealloc {
IOReturn ret = IOHIDDeviceClose(deviceRef, 0L);
if (ret == kIOReturnSuccess) {
deviceRef =
ret = IOHIDManagerClose(managerRef, 0L);
if (ret == kIOReturnSuccess) {
managerRef =
- (void)connectHID {
NSSet* allDevices = (__bridge NSSet*)(IOHIDManagerCopyDevices(managerRef));
NSArray* deviceRefs = [allDevices allObjects];
deviceRef = (deviceRefs.count)?(__bridge IOHIDDeviceRef)[deviceRefs objectAtIndex:0]:
- (void)senddata:(char*)outbuffer {
if (!deviceRef) {
IOReturn ret = IOHIDDeviceSetReport(deviceRef, kIOHIDReportTypeOutput, 0, (uint8_t*)outbuffer, sizeof(outbuffer));
if (ret != kIOReturnSuccess) {
NSAlert* alert = [NSAlert alertWithMessageText:@&error& defaultButton:@&OK& alternateButton:nil otherButton:nil informativeTextWithFormat:@&发送数据失败!&];
[alert runModal];
- (IOHIDManagerRef)getManageRef {
return managerR
- (void)setManageRef:(IOHIDManagerRef)ref {
managerRef =
- (IOHIDDeviceRef)getDeviceRef {
return deviceR
- (void)setDeviceRef:(IOHIDDeviceRef)ref {
deviceRef =
> 本站内容系网友提交或本网编辑转载,其目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请及时与本网联系,我们将在第一时间删除内容!
本人是奇葩,最近鼓捣了一套在mac上coding远程ubuntu上的theano代码的东东,记之以期造福后人. Overview: 下图是我的编程环境和网络环境
我期望能在本地mac机器上对远程的ubuntu theano server进行write.run.debug.view matplotlib图片.
mac设置(参考这里) 考虑到在Mac本地 ...
(1)使用XCode建立一个MAC OS X应用: 第一步:打开XCode,新建一个OSX应用-&Cocoa Application 第二步:点击*.xib文件,出现一个窗口,然后从左边拖一个按钮在窗口里,然后按 Ctrl+鼠标右键+拖动按钮到*.m文件最后一行前,增加这个函数. 第三步:拖一个标签到窗口,然后同样Ctrl+鼠标左键+拖动到*h里面,然 ...
路由器绑定IP设置(通过单IP使多机器能同时上网) 网线布局: 将公司局域网中的一个网头接到新的路由器上,将多个计算机接入到路由器的其它任一端口上.
第一步:获取本机IP地址信息 设置本机IP地址为自动获取,然后使用ipconfig/all命令查看当前信息,并记录下来.
第二步:进入新的路由器 默认为192.168.2.1,与公司现有主路由器192. ...
虽然看不太懂,目前也用不上,由于此文章太酷了,我还是先留下来,方便日后用上搞了几天,终于搞定iPhone动态库的了,包括破(po)解(jie)Xcode创建和编译iPhone Dynamic工程如题,最近几天项目要求把以前的静态库换成动态库,在网上搜了很多帖子,也自己摸索了两天,还在命令行敲了很多,累啊,其实完全不用. 首先得破(po)解(jie)Xcode ...
在很多办公室甚至家中都有无线路由器以方便通过WIFI信号上网.如果没有无线路由器,如何让多个移动智能终端同时上网呢?如果你是Windows用户那么可以选择wifi共享精灵来解决,如果你拥有MAC机器,那么在MAC系统里有个&互联网共享&功能,稍加设置就能让你的MAC机器成为WIFI发射热点,这和在Iphone手机上的热点功能类似. 在系统 ...
.cn/showtopic-7791.aspx FPGA的“可编程”使你迷惑吗?
任何一个硬件工程师对FPGA都不会陌生,就好比C语言对于软件工程师来说是必修课程一样,只要是电子相关专业的学生,都要学习可编程逻辑这门课程.FPGA的英文全称是Field Programmable GateArray,即现 ...
在很多办公室甚至家中都有无线路由器以方便通过WIFI信号上网.如果没有无线路由器,如何让多个移动智能终端同时上网呢?如果你是Windows用户那么可以选择wifi共享精灵来解决,如果你拥有MAC机器,那么在MAC系统里有个&互联网共享&功能,稍加设置就能让你的MAC机器成为WIFI发射热点,这和在Iphone手机上的热点功能类似.在系统偏 ...
用纯JAVA语言编程读取MAC地址的实现
作者:Ackarlix
本文介绍如何在WindowXP/NT/2000环境中,编写纯Java程序,执行外部命令IPCONFIG,并通过分析该命令的输入流而获得本机的MAC地址的编程方法. 1 引言 用Java编写的程序,可以很方便地运行在各种平台的环境.但在实际的开发过程中,有时不得不涉及一些底层的编程.比如 ...&&&&海思2108改MAC工具,用于海思2108机顶盒修改MAC地址之用,可以用U盘拷贝后插机顶盒上操作。
海思2108改MAC工具,用于海思2108机顶盒修改MAC地址之用,可以用U盘拷贝后插机顶盒上操作。
海思2108改MAC工具,用于海思2108机顶盒修改MAC地址之用,可以用U盘拷贝后插机顶盒上操作。
若举报审核通过,可奖励20下载分
被举报人:
举报的资源分:
请选择类型
资源无法下载
资源无法使用
标题与实际内容不符
含有危害国家安全内容
含有反动色情等内容
含广告内容
版权问题,侵犯个人或公司的版权
*详细原因:
VIP下载&&免积分60元/年(1200次)
您可能还需要
开发技术下载排行[转载]Freescale 16位单片机的地址映射
[转载]Freescale 16位单片机的地址映射
转载自中电网-毛毛的博客,三篇文章重新编辑合为一篇,内容未作任何改动。
原来一直不太明白单片机的地址映射,也没有仔细的研究过,我想这就是我不是牛人的原因吧。通常开始学单片机,都是写一些比较小的程序,如果不做项目开发之类的,以飞思卡尔16位单片机的资源配置来说也足够了。但是前一阵子遇到了一个问题,需要在RAM中存一个比较大的常数数组,但是单单存在RAM中的话,肯定是存不下,考虑到数组是常数,所以只能存在ROM里,但是当时时间较短,没有研究明白,还得到了非常惨痛的教训,觉得不甘心,打算再花时间研究了一下。在以后的文章中我会把我的研究心得记录下来,希望大家提出意见。
飞思卡尔16位单片机的资源配置
&以MC9S12XS128MAL为例,其实DG128之类的类似。如图一,128代表的是单片机中的FLASH大小为128K
Byte,同理64代表的是单片机中的FLASH大小为64 K Byte,256代表的是单片机中的FLASH大小为256 K
Byte。但是S12(X)所使用的内核CPU12(X)的地址总线为16位,寻址范围最大为2^16 =64K Byte,而这64K
Byte的寻址空间还包括寄存器、EEPROM(利用Data Flash模拟)、RAM等,因此不是所有的64K
Byte都是用来寻址FLASH。所以在S12(X)系列单片机中,很多资源是以分页的形式出现的,其中包括EEPROM、RAM、FLASH。EEPROM的每页大小为1K
Byte,RAM的每页大小为4K Byte,FLASH的每页大小为16K Byte。因此XS128中EEPROM的页数为8K/1K =
8页,RAM的页数为8K/4K = 2页,Flash的页数为128K/16K = 8页。
<img style="WiDTH: 541 height: 210px" src="/DownloadImg/9/.jpg" real_src="/DownloadImg/9/.jpg" alt="[转载]Freescale&16位单片机的地址映射" title="[转载]Freescale&16位单片机的地址映射" action-data="http%3A%2F%%2Fattachment%2FF15%2Fhk.jpg" action-type="show-slide" height="246" width="667">
<img src="/DownloadImg/9/.jpg" real_src="/DownloadImg/9/.jpg" alt="[转载]Freescale&16位单片机的地址映射" title="[转载]Freescale&16位单片机的地址映射" action-data="http%3A%2F%%2Fattachment%2FF15%2F.jpg" action-type="show-slide" height="857" width="367">
在单片普通模式中,复位后,所有内存资源的映射如图二所示,其中从0xFF的2K范围内映射为寄存器区,如I/O端口寄存器等,当然寄存器没有那么多,后面的一部分其实没有使用;
从0xBFF,共1K的空间,映射为EEPROM区,由上面的分析,XS128中共有8页的共8K的EEPROM,所以这8页的EEPROM都是以分页的形式出现的,可以通过设置寄存器EPAGE选择不同的页并进行访问;
从0x0C00到0x0FFF的1K空间为保留区(其实这里面也有学问,以后探讨);
从0xFFF的12K空间为RAM区,分为三页,但是和前面所说的EEPROM不同,这三页中有2页(对于XS128和XS256)或一页(对于XS64)为固定页,位于12K空间的后一部分,以XS128为例,其内部的RAM资源为8K,所以其三页中的最后两页(0xFFF)为固定页,第一页(0xFFF)为窗口区,通过设置寄存器RPAGE来映射其他分页的RAM,当然在单片普通模式下,XS128内部已经没有其他的RAM了,所以这一页其实也没有用。但是对于XS256,这一页是有用的,因为它总共有12K的RAM。但是,在单片普通模式下,即没有外扩RAM的情况下,用户是不用刻意的去配置RPAGE的,因为复位的时候,已经默认指向那一页的RAM。
从0x4000-0xFFFF的总共48K的空间为Flash区,分为三页。其中第一页和第三页为固定的Flash页,中间的一页(0x8000-0xBFFF)为窗口区,通过设置PPAGE寄存器,可以映射到其他的分页Flash。
在最后的一页固定的Flash区域中的最后256字节中,保存的是中断向量。
对于RAM和Flash来说,其实固定页和其他的分页资源是统一编址的,不同的是固定页不可以通过寄存器(RPAGE、PPAGE)改变映射,而其他的页必须通过寄存器的设置来选择映射不同的页。
codewarrior中的prm文件
网上广泛流传的一篇文章讲述的是8位飞思卡尔单片机的内存映射,这几天,研究了一下Codewarrior 5.0
prm文件,基于16位单片机MC9S12XS128,一点心得,和大家分享。有什么错误请指正。
关于Codewarrior 中的
要讨论单片机的地址映射,就必须要接触.prm文件,本篇的讨论基于
Codewarrior 5.0
编译器,单片机采用MC9S12XS128。
通过项目模板建立的新项目中都有一个名字为“project.prm”的文件,位于Project
Settings-&Linker Files文件夹下。一个标准的基于XS128的.prm文件起始内容如下:
.prm文件范例:
RAM = READ_WRITE DATA_NEAR 0x2000 TO 0x3FFF;
ROM_4000 = READ_ONLY DATA_NEAR IBCC_NEAR 0x4000 TO 0x7FFF;
ROM_C000 = READ_ONLY DATA_NEAR IBCC_NEAR 0xC000 TO 0xFEFF;
//OSVECTORS = READ_ONLY 0xFF10 TO
EEPROM_00 = READ_ONLY DATA_FAR IBCC_FAR 0x000800 TO 0x000BFF;
EEPROM_01 = READ_ONLY DATA_FAR IBCC_FAR 0x010800 TO 0x010BFF;
EEPROM_02 = READ_ONLY DATA_FAR IBCC_FAR 0x020800 TO 0x020BFF;
EEPROM_03 = READ_ONLY DATA_FAR IBCC_FAR 0x030800 TO 0x030BFF;
EEPROM_04 = READ_ONLY DATA_FAR IBCC_FAR 0x040800 TO 0x040BFF;
EEPROM_05 = READ_ONLY DATA_FAR IBCC_FAR 0x050800 TO 0x050BFF;
EEPROM_06 = READ_ONLY DATA_FAR IBCC_FAR 0x060800 TO 0x060BFF;
EEPROM_07 = READ_ONLY DATA_FAR IBCC_FAR 0x070800 TO 0x070BFF;
PAGE_F8 = READ_ONLY DATA_FAR IBCC_FAR 0xF88000 TO 0xF8BFFF;
PAGE_F9 = READ_ONLY DATA_FAR IBCC_FAR 0xF98000 TO 0xF9BFFF;
PAGE_FA = READ_ONLY DATA_FAR IBCC_FAR 0xFA8000 TO 0xFABFFF;
PAGE_FB = READ_ONLY DATA_FAR IBCC_FAR 0xFB8000 TO 0xFBBFFF;
PAGE_FC = READ_ONLY DATA_FAR IBCC_FAR 0xFC8000 TO 0xFCBFFF;
PAGE_FE = READ_ONLY DATA_FAR IBCC_FAR 0xFE8000 TO 0xFEBFFF;
_PRESTART,
VIRTUAL_TABLE_SEGMENT,
//.ostext,
DEFAULT_ROM, NON_BANKED,
INTO ROM_C000 ;
OTHER_ROM INTO PAGE_FE, PAGE_FC, PAGE_FB, PAGE_FA,
PAGE_F9, PAGE_F8;
//.stackstart,
//.stackend,
PAGED_RAM,
DEFAULT_RAM
DISTRIBUTE DISTRIBUTE_INTO
ROM_4000, PAGE_FE, PAGE_FC, PAGE_FB,
PAGE_FA, PAGE_F9, PAGE_F8;
CONST_DISTRIBUTE DISTRIBUTE_INTO
ROM_4000, PAGE_FE, PAGE_FC, PAGE_FB,
PAGE_FA, PAGE_F9, PAGE_F8;
DATA_DISTRIBUTE DISTRIBUTE_INTO
//.vectors INTO OSVECTORS;
//_vectab OsBuildNumber
_OsOrtiStackStart _OsOrtiStart
STACKSIZE 0x100
VECTOR 0 _Startup
//VECTOR 0 Entry
//INIT Entry
文件组成结构
按所含的信息的不同.prm文件有六个组成部分构成,这里仅讨论和内存空间映射关系紧密的三个部分,其他的不做讨论。
· SEGMENTS
定义和划分芯片所有可用的内存资源,包括程序空间和数据空间。一般我们将程序空间定义成ROM,把数据空间定义成RAM,但这些名字都不是系统保留的关键词,可以由用户随意修改。用户也可以把内存空间按地址和属性随意分割成大小不同的块,每块可以自由命名。例如同样是RAM,可以使用不同的属性,使其有复位后变量清零和不清零之分。
关于内存划分的具体方法在后面详解。
· PLACEMENT
将指派源程序中所定义的各种段,如数据段DATA_SEG、CONST_SEG和代码段CODE_SEG
被具体放置到哪一个内存块中。它是将源程序中的定义描述和实际物理内存挂钩的桥梁。
· STACKSIZE
定义系统堆栈长度,其后给出的长度字节数可以根据实际应用需要进行修改。堆栈的实际定位取决于RAM内存的划分和使用情况。默认的情况下,堆栈放在RAM区域的起始部分。当然,堆栈的定义不只有这种方式,还可以使用STACKTOP关键字。后面将详细讨论。
内存划分的具体方式
由SEGMENTS开始到END为止,中间可以添加任意多行内存划分的定义,每一行用分号结尾。定义行的语法型式为:
块名属性1属性2
,属性n起始地址 TO 结束地址
“块名”的定义和C语言变量定义相同,是以英文字母开头的一个字符串,用户可以自己任意定义块名。
“属性”用户是不能自己定义的,因为属性名指定了上面所说的“块名”所对应的不同的内存类型和访问方式,而不同物理内存的类型和访问方式是一定的。
对于“属性1”,Codewarrior 5.0中可以有三种不同的类型,对于只读的Flash-ROM区属性一定是READ_ONLY,对于可读写的RAM区属性可以是READ_WRITE,也可以是NO_INIT。它们两者的关键区别是ANSI-C的初始化代码会把定位在READ_WRITE块中的所有全局和静态变量自动清零,而NO_INIT块中的变量将不会被自动清零。当然只是复位时不清零,掉电时还是清零的,但是对于单片机系统,变量在复位时不被自动清零这一特性有时是很关键的,在某些应用中有特殊的用途。
对于“属性2
属性n”,根据上面给出的.prm的范例文件可以看出来,可能的形式有“DATA_FAR”、“DATA_NEAR”、“IBCC_FAR”、“IBCC_NEAR”四种类型。其中,“DATA_FAR”和“DATA_NEAR”相对应,当内存区域包含变量或者是常量时(通常是RAM、Flash和EEPROM),必须指明上面两种属性中的一种,由于涉及到内存的分页,可以这样理解:“DATA_FAR”属性指定的内存块为可以保存数据的非固定页,而“DATA_NEAR”属性指定的内存块为可以保存数据的固定页;同理“IBCC_FAR”和“IBCC_NEAR”相对应,当内存区域包含代码时(Flash和EEPROM),必须指明上面两种属性中的一种,“IBCC_FAR”属性指定的内存块为可以保存代码的非固定页,而“IBCC_NEAR”属性指定的内存块为可以保存代码的固定页
讨论到这里,细心的读者已经发现,在上面的.prm文件范例中,RAM的属性有“DATA_FAR”和“DATA_NEAR”两种,Flash的属性中也是四种都有,但是EEPROM中却只有“DATA_FAR”和“IBCC_FAR”两种,这正好验证了上一篇文章()中所提到的,RAM、Flash中都有固定页,但是EEPROM中全部是非固定页。
起始地址和结束地址决定了一内存块的物理位置,对于固定页,用4位16进制数表示,而对于非固定页,则用6位16进制表示,多出来的两位其实是寄存器EPAGE、RPAGE或PPAGE的值,可见,对于分页的资源,是通过寄存器(EPAGE、RPAGE或PPAGE)和16位的地址总线的组合来进行寻址的。
“TO”是系统保留的关键字,必须大写。
下面,根据上面范例提供的内容,举几个例子:
RAM = READ_WRITE DATA_NEAR 0x2000 TO 0x3FFF;
上面这句话的意思是:分配0xFFF的区域的块名为“RAM”(当然可以定义别的名称),由上一篇文章而知,这一区域的物理内存的性质为RAM,属性应该为“READ_WRITE”,并且这一区域中的两页都为固定页,所以为“DATA_NEAR”。
将8K字节RAM的后面4K字节定义成非自动清零的数据保留区,则应如下定义:
RAM = READ_WRITE DATA_NEAR 0x2000 TO 0x2FFF;
RAM_NO_INIT = NO_INIT DATA_NEAR 0x3000 TO 0x3FFF;
注意,各部分RAM的分配地址不应该存在重叠的部分,否则会发生错误。
EEPROM_00 = READ_ONLY DATA_FAR IBCC_FAR 0x000800 TO 0x000BFF;
XS128单片机中的EEPROM由Data-Flash模拟,所以属性为READ_ONLY。EEPROM全部为非固定页,所以用“DATA_FAR”、“IBCC_FAR”。后面的起始地址和结束地址分别为6位的16进制数,前两位的“00”实质指的是EEPROM分页寄存器EPAGE的值为0x00。
用SEGMENTS只是从单片机的物理内存这一角度对其进行空间划分。源程序本身并不知道物理内存被分割和属性定义的这些细节。它们两者之间必须通过下面的PLACEMENT建立联系。
程序段和数据段的放置
PLACEMENT-END内所描述的信息是告诉连接器源程序中所定义的各类段应该被具体放置到哪一个内存块中去。其语法型式为:
段名2,...
, 段名n INTO 内存块名1,内存块名2,
,内存块名n
段名2,...
, 段名n DISTRIBUTE_INTO 内存块名1,内存块名2,
,内存块名n
段名就是在源程序中用“#pragma”声明的数据段、常数段或代码段的名字。如果用缺省名“DEFAULT”,
则默认的数据段名为DEFAULT_RAM,代码段和常数段名为DEFAULT_ROM。若程序中定义的段名没有在PLACEMENT中提及,则将被视同为DEFAULT。几个相同性质但不同名字的段可以被放置到同一个内存块中,相互之间用逗号分隔。
是系统保留的关键词,在这里为“放入”的意思。
· DISTRIBUTE_INTO
也是系统的保留关键字。Codewarrior
具有内存自动优化的功能,但是在“Small memory”模式中,这种功能不会被启用,只有当16-bit的地址空间不能存放下所有的变量和代码时,才会启用这种功能。
在SEGMENTS-END区域中,当在内存模块的属性中加上“DATA_FAR”、“DATA_NEAR”、“IBCC_FAR”、“IBCC_NEAR”四种属性中的任何一种时,那么在PLACEMENT-END区域中,就需要指定段名“
内存块名就是前面介绍的用SEGMENTS划分好的不同的内存块名字。
利用这样直观的定位描述文本可以方便灵活的将数据或代码定位到芯片内存任意可能的位置,实现某些特殊目的的应用。
下面的例子,说明了各种段名、PLACEMENT
和SEGMENTS之间的对应关系。
定义非自动清零的数据段
RAM = READ_WRITE DATA_NEAR 0x2000 TO 0x2FFF;
RAM_NO_INIT = NO_INIT DATA_NEAR 0x3000 TO 0x3FFF;
DATA_PERSISTENT INTO RAM_NO_INIT;
//源程序编写:
#pragma DATA_SEG
DATA_PERSISTENT //定义复位时非自定清零数据段
#pragma DATA_SEG DEFAULT
堆栈的设置
关于堆栈的设置,Codewarrior提供了两种方式:“STACKSIZE”命令方式和“STACKTOP”命令方式。这两种方式在同一个.prm文件中,不能同时存在。当用户只关心堆栈的大小而不关心堆栈的存放位置时,推荐使用STACKSIZE方式。
系统默认的方式为使用STACKSIZE方式。
STACKSIZE命令方式:
当使用STACKSIZE命令方式时,如果在PLACEMENT-END部分声明了“SSTACK INTO RAM”,这样的话,堆栈区就被放在RAM区域的起始部分,下面的例子说明了这种方式:
RAM = READ_WRITE DATA_NEAR 0x2000 TO 0x3FFF;
SSTACK, PAGED_RAM, DEFAULT_RAM
STACKSIZE 0x100
上面的例子将堆栈区域存放的地址为0x20FF-0x2000,初始的堆栈指针指向栈顶地址0x20FF。
相反,如果在PLACEMENT-END部分没有声明“SSTACK INTO RAM”,则堆栈被分配在RAM区域中已分配空间的后面。请参见例6。
RAM = READ_WRITE DATA_NEAR 0x2000 TO 0x3FFF;
PAGED_RAM, DEFAULT_RAM
STACKSIZE 0x100
在这个例子中,如果RAM区域中已经分配的变量占用了4个字节(从0x2000到0x2003),则堆栈放在这四个字节的后面,从0x2103到0x2004,初始的堆栈指针指向0x2103。
STACKYOP命令方式:
当使用STACKTOP命令方式时,如果在PLACEMENT-END部分声明了“SSTACK INTO RAM”,同样,堆栈区就被放在RAM区域的起始部分,初始的栈顶则由STACKTOP指定。若没有相应的声明,则初始的栈顶由STACKTOP指定,而堆栈的大小则根据处理器的不同由编译器自行设定,其大小足够装下处理器的PC寄存器的值。
发表评论:
TA的最新馆藏[转]&[转]&2122人阅读
单片机(27)
1、& data区空间小,所以只有频繁用到或对运算速度要求很高的变量才放到data区内,比如for循环中的计数&#20540;。
2、& data区内最好放局部变量。
因为局部变量的空间是可以覆盖的(某个函数的局部变量空间在退出该函数是就释放,由别的函数的局部变量覆盖),可以提高内存利用率。当然静态局部变量除外,其内存使用方式与全局变量相同;
3、& 确保你的程序中没有未调用的函数。
在Keil C里遇到未调用函数,编译器就将其认为可能是中断函数。函数里用的局部变量的空间是不释放,也就是同全局变量一样处理。这一点Keil C做得很愚蠢,但也没办法。
4、& 程序中遇到的逻辑标志变量可以定义到bdata中,可以大大降低内存占用空间。
在51系列芯片中有16个字节位寻址区bdata,其中可以定义8*16=128个逻辑变量。定义方法是: bdata bit LedS但位类型不能用在数组和结构体中。
5、& 其他不频繁用到和对运算速度要求不高的变量都放到xdata区。
6、& 如果想节省data空间就必须用large模式,将未定义内存位置的变量全放到xdata区。当然最好对所有变量都要指定内存类型。
7、& 当使用到指针时,要指定指针指向的内存类型。在C51中未定义指向内存类型的通用指针占用3个字节;而指定指向data区的指针只占1个字节;指定指向xdata区的指针占2个字节。如指针p是指向data区,则应定义为:& char data *p;。还可指定指针本身的存放内存类型,如:char data *。其含义是指针p指向data区变量,而其本身存放在xdata区。
是在内部数据存储空间中 20H .. 2FH 区域中一个位的地址,或者 8051 位可寻址 SFR 的一个位地址。
是在 0000H .. 0FFFFH 之间的一个代码地址。
是在 0 到 127 之间的一个数据存储器地址,或者在 128 .. 255 范围内的一个特殊功能寄存器(SFR)地址。
是 0 to 255 范围内的一个 idata 存储器地址。
xdata 是 0 to 65535 范围内的一个 xdata 存储器地址。
指针类型和存储区的关系详解
一、存储类型与存储区关系
&&&&data&&&& ---&&&&&可寻址片内ram
&&&&bdata&&&&---&&&&&可位寻址的片内ram
&&&&idata&&&&---&&&&&可寻址片内ram,允许访问全部内部ram
&&&&pdata&&&&---&&&&&分页寻址片外ram (MOVX @R0) (256 BYTE/页)
&&&&xdata&&&&---&&&&&可寻址片外ram (64k 地址范围)
&&&&code&&&& ---&&&&&程序存储区 (64k 地址范围),对应MOVC @DPTR
二、指针类型和存储区的关系
&&&&对变量进行声明时可以指定变量的存储类型如:
&&&&uchar data x和data uchar x相等价都是在内ram区分配一个字节的变量。
&&&&同样对于指针变量的声明,因涉及到指针变量本身的存储位置和指针所指向的存储区位置不同而进行相应的存储区类型关键字的
&&&&uchar xdata * data pstr
&&&&是指在内ram区分配一个指针变量(&*&号后的data关键字的作用),而且这个指针本身指向xdata区(&*&前xdata关键字的作用),
可能初学C51时有点不好懂也不好记。没关系,我们马上就可以看到对应“*”前后不同的关键字的使用在编译时出现什么情况。
&&&&......
&&&&uchar xdata tmp[10];&&&&//在外ram区开辟10个字节的内存空间,地址是外ram的0x9
&&&&......
&&&&第1种情况:
&&&&uchar data *
&&&&首先要提醒大家这样的代码是有bug的, 他不能通过这种方式正确的访问到tmp空间。 为什么?我们把编译后看到下面的汇编
&&&&MOV 0x08,#tmp(0x00)&&&&&&&&;0x08是指针pstr的存储地址
&&&&看到了吗!本来访问外ram需要2 byte来寻址64k空间,但因为使用data关键字(在&*&号前的那个),所以按KeilC编译环境来说
就把他编译成指向内ram的指针变量了,这也是初学C51的朋友们不理解各个存储类型的关键字定义而造成的bug。特别是当工程中的
默认的存储区类为large时,又把tmp[10] 声明为uchar tmp[10] 时,这样的bug是很隐秘的不容易被发现。
&&&&第2种情况:
&&&&uchar xdata *
&&&&pstr =
&&&&这种情况是没问题的,这样的使用方法是指在内ram分配一个指针变量(&*&号后的data关键字的作用),而且这个指针本身指向
xdata区(&*&前xdata关键字的作用)。编译后的汇编代码如下。
&&&&MOV 0x08,#tmp(0x00)&&&&&&&&;0x08和0x09是在内ram区分配的pstr指针变量地址空间
&&&&MOV 0x09,#tmp(0x00)
&&&&这种情况应该是在这里所有介绍各种情况中效率最高的访问外ram的方法了,请大家记住他。
&&&&第3种情况:
&&&&uchar xdata *
&&&&这中情况也是对的,但效率不如第2种情况。编译后的汇编代码如下。
&&&&MOV DPTR, #0x000A&&&&&&&&;0x000A,0x000B是在外ram区分配的pstr指针变量地址空间
&&&&MOV A, #tmp(0x00)
&&&&MOV @DPTR, A
&&&&INC DPTR
&&&&MOV A, #tmp(0x00)
&&&&MOVX @DPTR, A
&&&&这种方式一般用在内ram资源相对紧张而且对效率要求不高的项目中。
&&&&第4种情况:
&&&&uchar data *
&&&&如果详细看了第1种情况的读者发现这种写法和第1种很相&#20284;,是的,同第1 种情况一样这样也是有bug的,但是这次是把pstr分
配到了外ram区了。编译后的汇编代码如下。
&&&&MOV DPTR, #0x000A&&&&&&&&;0x000A是在外ram区分配的pstr指针变量的地址空间
&&&&MOV A, #tmp(0x00)
&&&&MOVX @DPTR, A
&&&&第5种情况:
&&&&uchar *
&&&&大家注意到&*&前的关键字声明没有了,是的这样会发生什么事呢?下面这么写呢!对了用齐豫的一首老歌名来说就是 “请跟我
来”,请跟我来看看编译后的汇编代码,有人问这不是在讲C51吗? 为什么还要给我们看汇编代码。C51要想用好就要尽可能提升C51
编译后的效率,看看编译后的汇编会帮助大家尽快成为生产高效C51代码的高手的。还是看代码吧!
&&&&MOV 0x08, #0X01&&&&&&&&&&&&;0x08-0x0A是在内ram区分配的pstr指针变量的地址空间
&&&&MOV 0x09, #tmp(0x00)
&&&&MOV 0x0A, #tmp(0x00)
&&&&注意:这是新介绍给大家的,大家会疑问为什么在前面的几种情况的pstr指针变量都用2 byte空间而到这里就用3 byte空间了
呢?这是KeilC的一个系统内部处理,在KeilC中一个指针变量最多占用 3 byte空间,对于没有声明指针指向存储空间类型的指针,
系统编译代码时都强制加载一个字节的指针类型分辩&#20540;。具体的对应关系可以参考KeilC的help中C51 User's Guide。
&&&&第6种情况:
&&&&uchar *
&&&&这是最直接最简单的指针变量声明,但他的效率也最低。还是那句话,大家一起说好吗!编译后的汇编代码如下。
&&&&MOV DPTR, #0x000A&&&&&&&&;0x000A-0x000C是在外ram区分配的pstr指针变量地址空间
&&&&MOV A, #0x01
&&&&MOV @DPTR, A
&&&&INC DPTR
&&&&MOV DPTR, #0x000A
&&&&MOV A, #tmp(0x00)
&&&&MOV @DPTR, A
&&&&INC DPTR
&&&&MOV A, #tmp(0x00)
&&&&MOVX @DPTR, A
&&&&这种情况很类&#20284;第5种和第3种情况的组合,既把pstr分配在外ram空间了又增加了指针类型的分辨&#20540;。
&&&&小结一下:大家看到了以上的6种情况,其中效率最高的是第2种情况,既可以正确访问ram区又节约了代码,效率最差的是第 6
种,但不是说大家只使用第2种方式就可以了,还要因情况而定,一般说来应用51系列的系统架构的内部ram资源都很紧张,最好大家
在定义函数内部或程序段内部的局部变量使用内ram,而尽量不要把全局变量声明为内ram区中。所以对于全局指针变量我建议使用第
3 种情况,而对于局部的指针变量使用第2种方式。
keil C51存储区域分为程序存储区和数据存储区2大类型。
&&& 一.程序存储区(Pragram Area):
&&& 欲将声明的数据存放在程序存储区域,可以使用关键字“code”说明。
&&& 例 unsigned char code i=10;则表示 i为无符号字符型数据存放区域为程序存储区。
&&& 二.数据存储区(Data Memory):
&&& 数据存储区域分为内部数据存储区、外部数据存储区域和特殊功能寄存器寻址区。
&&& 1.内部数据存储区域(Internal Data Memory):可以使关键字&data、iadta、bdata&做相应说明。
&&& data:直接寻址区,声明的数据存储范围为内部RAM低128字节 0X00~0X7F。
&&& 例 unsigned char data i=10;则表示 i为无符号字符型数据存放区域为数据存储区域(RAM)的低128字节范围内。
&&& idata:间接寻址区,声明的数据存储范围为整个内部RAM区 0X00~0XFF。
&&& 例 unsigned char idata i=10;则表示 i为无符号字符型数据存放区域为数据存储区域(RAM)内。
&&& bdata:可位寻址区,寻址范围为0X20~0X2F。
&&& 2.外部数据存储区(External Data Memory):可以使用关键字&pdata、xdata&进行说明。
&&& pdata:主要用于紧凑模式,能访问1页(256字节)的外部RAM,即在访问使用,pdata定义的数据时,不会影响P2口的输出电平(在访问某些自身内部扩展的外部RAM时本身就不会影响I/O端口)。
&&& 例 u则表示 i为无符号字符型数据存放区域为外部数据存储区域(RAM)内(只能在一页范围内)具体操作哪一页,可由其他i/o口设定。
&&& xdata:可访问64k的外部数据存储区,地址范围0X0000~0XFFFF,同pdata一样在访问芯片自身内部扩展的RAM时也不会影响I/O端口。
&&& 例 u则表示 i为无符号字符型数据存放区域为外部数据存储区(RAM)。
&&& 3.特殊功能寄存器寻址区域(Speciac Function Register Memory)-SFR:8051提供128字节的SFR寻址区,该区域可以字节寻址,字寻址,能被8整除的地址单元还可以位寻址。该区域用于控制定时器、计数器、串口等外围接口。使用时可用关键字“sfr、sfr16、sbit”做相应的声明。
&&& 例 字节寻址 sfr P0=0x80;为P0 口地址为80H,“=”后0X00~0XFF 之间的常数。
&&&&&&&&&& 字寻址&&& sfr16 T2=0XCC;指定Timer2 口地址T2L=0XCC T2H=0XCD。
&&&&&&&&&&& 位寻址&&& sbit EA=0xAF;指定第0xAF 位为EA,即中断允许
&&& 在使用C51时有时我们并没有明确指定所定义的数据的存储类型,然而依然正确。 这是由于存储模式决定了没有明确指定存储类型的变量,函数参数等的缺省存储区域。
&&& 供有3种存储模式(存储模式在 C51 编译器选项中选择):
&& 1.Small模式
&&&& 所有缺省变量参数均装入内部 RAM,优点是访问速度快,缺点是空间有限,只适用于小程序。
&&&& 2. Compact 模式
&&& 所有缺省变量均位于外部RAM区的一页(256Byte)。
&&& 3. Large 模式
&&& 所有缺省变量可放在多达 64KB 的外部RAM 区,优点是空间大,可存变量多,缺点是速度较慢。
C51存储器类型有bit
code等,可能不全面有遗漏
对应的物理存储器是:
bit,即位数据:数据存储器位寻址区,即20H~2FH的范围,共16个字节,16*8=128个位,位地址00h~7fh,连续的。
sbit:特殊功能寄存器中的位数据:只有能够被8整除的那些特殊功能寄存器中的各个位才能被称为sbit,位地址80H~FFH,不连续的,间断的。
data:数据区,对51为00H~7FH共128个字节,对52为00H~FFH,共256个字节,用MOV寻址,前128用直接寻址或寄存器(R0~R7)寻址,后128用R0、R1间接寻址。
xdata:外部数据区,0000H~FFFFH连续,用DPTR间接寻址(MOVX指令)
bdata:位寻址去的字节,20H~2FH
sfr:特殊功能寄存器(80H~FFH),直接寻址
pdata:外部数据区,P2口保持数据,用R0R1间接寻址(MOVX指令)
code:程序存储器,用MOVC指令只读
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:426496次
积分:5413
积分:5413
排名:第3284名
原创:88篇
转载:165篇
评论:74条
(1)(1)(1)(1)(1)(4)(7)(11)(8)(2)(3)(2)(2)(2)(2)(2)(4)(4)(6)(11)(8)(2)(58)(8)(10)(8)(22)(17)(3)(16)(29)(3)}

我要回帖

更多关于 单片机地址线 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信