单片机经验总结2---学习笔记

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

单片机经验总结2一,C51内存结构深度剖析在编写应用程序时,定义一个变量,一个数组,或是说一个固定表格,到底存储在什么地方;当定义变量大小超过MCU的内存范围时怎么办;如何控制变量定义不超过存储范围;以及如何定义变量才能使得变量访问速度最快,写出的程序运行效率最高。以下将一一解答。1六类关键字(六类存储类型)dataidataxdatapdatacodebdatacode:codememory(程序存储器也即只读存储器)用来保存常量或是程序。codememory采用16位地址线编码,可以是在片内,或是片外,大小被限制在64KB作用:定义常量,如八段数码表或是编程使用的常,在定义时加上code或明确指明定义的常量保存到codememory(只读)使用方法:charcodetable[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};此关键字的使用方法等同于constdatadatamemory(数据存储区)只能用于声明变量,不能用来声明函数,该区域位于片内,采用8位地址线编码,具有最快的存储速度,但是数量被限制在128byte或更少。使用方法:unsignedchardatafast_variable=0;idataidatamemory(数据存储区)只能用于声明变量,不能用来声明函数.该区域位于片内,采用8位地址线编码,内存大小被限制在256byte或更少。该区域的低地址区与datamemory地址一致;高地址区域是52系列在51系列基础上扩展的并与特殊功能寄存器具有相同地址编码的区域。即:datamemory是idatamemory的一个子集。xdataxdatamemory只能用于声明变量,不能用来声明函数,该区域位于MCU外部,采用16位地址线进行编码,存储大小被限制在64KB以内。使用方法:unsignedcharxdatacount=0;pdatapdatamemory只能用于声明变量,不能用来声明函数,该区域位于MCU外部,采用8位地址线进行编码。存储大小限制在256byte.是xdatamemory的低256byte。为其子集。使用方法unsignedcharpdatacount=0;bdatabdatamemory只能用于声明变量,不能用来声明函数。该区域位于8051内部位数据地址。定义的量保存在内部位地址空间,可用位指令直接读写。使用方法:unsignedcharbdatavarab=0注:有些资料讲,定义字符型变量时,在缺省unsigned时,字符型变量,默认为无符号,与标准C不同,但我在KeiluVision3中测试的时候发现并非如此。在缺省的情况下默认为有符号。或许在以前的编译器是默认为无符号。所以看到有的资料上面这样讲的时候,要注意一下,不同的编译器或许不同。所以我们在写程序的时候,还是乖乖的把unsignedsigned加上,咱也别偷这个懒。2函数的参数和局部变量的存储模式C51编译器允许采用三种存储器模式:SMALL,COMPACT和LARGE。一个函数的存储器模式确定了函数的参数的局部变量在内存中的地址空间。处于SMALL模式下的函数参数和局部变量位于8051单片机内部RAM中,处于COMPACT和LARGE模式下的函数参数和局部变量则使用单片机外部RAM。在定义一个函数时可以明确指定该函数的存储器模式。方法是在形参表列的后面加上一存储模式。示例如下:#pragmalarge//此预编译必须放在所有头文前面intfunc0(charx,y)small;charfunc1(intx)large;intfunc2(charx);注:上面例子在第一行用了一个预编译命令#pragma它的意思是告诉c51编译器在对程序进行编译时,按该预编译命令后面给出的编译控制指令LARGE进行编译,即本例程序编译时的默认存储模式为LARGE.随后定义了三个函数,第一个定义为SMALL存储模式,第二个函数定义为LARGE第三个函数未指定,在用C51进行编译时,只有最后一个函数按LARGE存储器模式处理,其它则分别按它们各自指定的存储器模式处理。本例说明,C51编译器允许采用所谓的存储器混合模式,即允许在一个程序中将一些函数使用一种存储模式,而其它一些则按另一种存储器模式,采用存储器混合模式编程,可以充分利用8051系列单片机中有限的存储器空间,同时还可以加快程序的执行速度。3绝对地址访问absacc.h(相当重要)#defineCBYTE((unsignedcharvolatilecode*)0)#defineDBYTE((unsignedcharvolatiledata*)0)#definePBYTE((unsignedcharvolatilepdata*)0)#defineXBYTE((unsignedcharvolatilexdata*)0)功能:CBYTE寻址CODE区DBYTE寻址DATA区PBYTE寻址XDATA(低256)区XBYTE寻址XDATA区例:如下指令在对外部存储器区域访问地址0x1000xvar=XBYTE[0x1000];XBYTE[0x1000]=20;#defineCWORD((unsignedintvolatilecode*)0)#defineDWORD((unsignedintvolatiledata*)0)#definePWORD((unsignedintvolatilepdata*)0)#defineXWORD((unsignedintvolatilexdata*)0)功能:与前面的一个宏相似,只是它们指定的数据类型为unsignedint.。通过灵活运用不同的数据类型,所有的8051地址空间都是可以进行访问。如DWORD[0x0004]=0x12F8;即内部数据存储器中(0x08)=0x12;(0x09)=0xF8注:用以上八个函数,可以完成对单片机内部任意ROM和RAM进行访问,非常方便。还有一种方法,那就是用指钟,后面会对C51的指针有详细的介绍。4寄存器变量(register)为了提高程序的执行效率,C语言允许将一些频率最高的那些变量,定义为能够直接使用硬件寄存器的所谓的寄存器变量。定义一个变量时,在变量类型名前冠以“register”即将该变量定义成为了寄存器变量。寄存器变量可以认为是一自动变量的一种。有效作用范围也自动变量相同。由于计算机寄存器中寄存器是有限的。不能将所有变量都定义成为寄存器变量,通常在程序中定义寄存器变量时,只是给编译器一个建议,该变量是否真正成为寄存器变量,要由编译器根据实际情况来确定。另一方面,C51编译器能够识别程序中使用频率最高的变量,在可能的情况下,即使程序中并未将该变量定义为寄存器变量,编译器也会自动将其作为寄存器变量处理。被定义的变量是否真正能成为寄存器变量,最终是由编译器决定的。5内存访问杂谈1指钟指钟本身是一个变量,其中存放的内容是变量的地址,也即特定的数据。8051的地址是16位的,所以指针变量本身占用两个存储单元。指针的说明与变量的说明类似,仅在指针名前加上“*”即可。如int*int_point;声明一个整型指针char*char_point;声明一个字符型指针利用指针可以间接存取变量。实现这一点要用到两个特殊运算符&取变量地址*取指针指向单元的数据示例一:inta,b;int*int_point;//定义一个指向整型变量的指针a=15;int_point=&a;//int_point指向a*int_point=5;//给int_point指向的变量a赋值5等同于a=5;示例二:chari,table[6],*char_point;char_point=table;for(i=0;i6;i++){char_point=i;char_point++;}注:指针可以进行运算,它可以与整数进行加减运算(移动指针)。但要注意,移动指针后,其地址的增减量是随指针类型而异的,如,浮点指针进行自增后,其内部将在原有的基础上加4,而字符指针当进生自增的时候,其内容将加1。原因是浮点数,占4个内存单元,而字符占一个字节。宏晶科技最新一代STC12C5A360S2系列,每一个单片机出厂时都有全球唯一身份证号码(ID号),用户可以在单片机上电后读取内部RAM单元F1H~F7H的数值,来获取此单片机的唯一身份证号码。使用MOV@Ri指令来读取。下面介绍C51获取方法:charid[7]={0};chari;charidata*point;for(i=0;i7;i++){id[i]=*point;point++;}(此处只是对指针做一个小的介绍,达到访问内部任何空间的方式,后述有对指针使用的详细介绍)2对SFR,RAM,ROM的直接存取C51提供了一组可以直接对其操作的扩展函数若源程序中,用#include包含头文件,io51.h后,就可以在扩展函数中使用特殊功能寄存器的地址名,以增强程序的可读性:注此方法对SFR,RAM,ROM的直接存取不建议使用.因为,淡io51.h这个头文件在KEIL中无法打开,可用指针,或是采用absacc.h头文件,3PWM与PCASTC12系列有两路PWM/PCAPWM:(PulseWidthModulation)脉宽调制,是一种使用程序来控制波形占空比,周期,相位波形的技术。PCA:(ProgrammableCounterArray)可编程计数阵列,它比通常的定时/计数器的定时能力强,需要CPU的干预少。其优势一是软件简单,二是精度大有提高。二,reg51.头文件剖析我们平时写单片机应用程序的时候,所使用的头文件大多都是用的的reg51.h或是用reg52.h。会写C51的人都会用,但对其头文件内部的定义有所了解的人确并不多。下面对其内部做详细解释,方便读者作进一步的了解,并能运用各类型号的单片机。因为增强型号的单片机的增强功能都是通过特殊功能寄存器控制。打开reg52.h头文件,会发现是由大量的sfr,sbit的声明组成,甚至于还有sfr16.其实这样的声明都是与单片机内部功能寄存器(特殊功能寄存器)联系起来的,下面对其做出详细解释sfr:声明变量SFR声明一个变量,它的声明与其它的C变量声明基本相同,唯一的区别,SFR在声明的同时为其指定特殊功能寄存器作为存储地址,而不同于C变量声明的整型,字符型等等由编译器自动分配存储空间。如reg52.h头文件,第一条声明就是sfrP0=0x80;此处声明一个变量P0,并指定其存储地址为特殊功能寄存器0x80;,在加入reg52.h头文件后。编写应用程序时P0就可以直接使用而无需定义,对P0的操作就是,对内部特殊功能寄存器(0x80对应用MCU的P0口)的操作,可进行读写操作。如果将第一条声明改为sfrK0=0x80;那么,如果要把单片机的P0口全部拉低,则不能写P0=0x00;而应保存后再在应用程序中写成K0=0x00;否则编译器会提示“P0为未定义标识符”使用方法:sfr[variable]=[address]//为变量分配一个特殊功能寄存器。1等号右边,只能是十进制,十六进制整型的数据常量,,不允许带操作符的表达式经典的8051内核支持的SFR地址从0x80H~0xFF飞利浦80C51MX系列0x180H~0x1FF2SFR不能声明于任何函数内部,包括main函数。只能声明于函数外。3用SFR声明一个变量后,不能用取地址运算符&获取其地址,编译无法通过,编译器会提示非法操作。4有一点须特别注意,51内核0x80~0xff,为特殊功能寄存器地址区间,但并不是所有的地址都有定义,如果说你所用的MCU芯片上对于某个地址没有定义,那么用sfr在定义变量的时候,不要把变量的地址分配到未定义的特殊功能寄存器上,虽然编译时能通过,用KEIL仿真时貌似是没有问题,但下载到芯片里运行时,是会出问题的。比如说,向一个未定义的特殊功能寄存器执行读操作,读出来的就是一个未知的数。(读者可自行测试,先把串口通信调通,然后做

1 / 34
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功