data: 固定指前面0x00-0x7f的128个RAM,可以用acc直接读写的,速度最快,生成的代码也最小。 idata: 固定指前面0x00-0xff的256个RAM,其中前128和dATa的128完全相同,只是因为访问的方式不同。idATa是用类似C中的指针方式 访问的。汇编中的语句为:mox ACC,@Rx.(不重要的补充:c中idATa做指针式的访问效果很好) xdata: 外部扩展RAM,一般指外部0x0000-0xffff空间,用DPTR访问。 pdata: 外部扩展RAM的低256个字节,地址出现在A0-A7的上时读写,用movx ACC,@Rx读写。这个比较特殊,而且C51好象有对此BUG, 建议少用。但也有他的优点,具体用法属于中级问题,这里不提。 startup.a51 的作用,和汇编一样,在C中定义的那些变量和数组的初始化就在startup.a51中进行,如果你在定义全局变量时带有数值,如unsigned char dATa xxx="100";,那startup.a51中就会有相关的赋值。如果没有=100,startup.a51就会把他清 0。(startup.a51==变量的初始化)。 这些初始化完毕后,还会设置SP指针。对非变量区域,如堆栈区,将不会有赋值或清零动作。 有 人喜欢改startup.a51,为了满足自己一些想当然的爱好,这是不必要的,有可能错误的。比如掉电保护的时候想保存一些变量, 但改startup.a51来实现是很笨的方法,实际只要利用非变量区域的特性,定义一个指针变量指向堆栈低部:0xff处就可实现。, 为什么还要去改? 可以这么说:任何时候都可以不需要改startup.a51,如果你明白它的特性。 bit 是在内部数据存储空间中 20H .. 2FH 区域中一个位的地址,这在DATA的20H以后以字节形式出现,可互相参照。另外加上8051 可寻址 的SFR,但刚刚试过,只是00H--7FH起作用,也就是说当数据有变化时颜色变红,以后的从80H到--FFH就不是位寻址区了,是位寻址的特殊寄存器,如涉及到了可位寻址的那11个当然会有反应。 复位后,程序计数器PC的内容为0000H,内部RAM各单元的值不确定。各功能寄存器的复位值如下:堆栈指针SP的复位值为07H,累加器ACC、寄存器B的复位值为00H,数据指针DPTR的复位值为0000H,而p0、p1、p2、p3四个口的复位值为0FFH。其他SFR如PSW、TCON、TMOD、TL0、TH0、TL1、TH1的复位值也为00H。 wave中是低128字节和高128字节(0-7FH),低128字节是片内RAM区,高128字节(80-FFH)是SFR(特殊功能寄存器)bit则是位于低128字节的20H .. 2FH 区域,即data的20H .. 2FH 区域 code 是在 0000H .. 0FFFFH 之间的一个代码地址。 我用 ORG 5000H TAB: DB 22H,3BH,43H,66H,5H,6DH,88H后, CODE从5000H开始以后变成DB各位 data 是在 0 到 127 之间的一个数据存储器地址,或者加 128 .. 255 范围内的一个特殊功能寄存器(SFR)地址。两者访问的方式不同。实际上由于PSW的复位设置PSW.3=RS0和PSW.4=RS1皆为0,所以通用工作寄存器区就是第0区,所以data的00--07H部分是与REG栏中的R0--R7对应的。以后的则仅代表低128字节的内部RAM。 idata 是 0 to 255 范围内的一个 idata 存储器地址。 idata与data重合低128字节,有的地方只有DATA表示256字节的片内RAM, xdata 是 0 to 65535 范围内的一个 xdata 存储器地址。 指针类型和存储区的关系详解 一、存储类型与存储区关系 data ---> 可寻址片内ram bdata ---> 可位寻址的片内ram idata ---> 可寻址片内ram,允许访问全部内部ram pdata ---> 分页寻址片外ram (MOVX @R0) (256 BYTE/页) xdata ---> 可寻址片外ram (64k 地址范围FFFFH) 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的0x0000-0x0009 ...... 第1种情况: uchar data * data pstr; pstr="tmp"; 首先要提醒大家这样的代码是有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 * data pstr; pstr = tmp; 这种情况是没问题的,这样的使用方法是指在内ram分配一个指针变量("*"号后的data关键字的作用),而且这个指针本身指向 xdata区("*"前xdata关键字的作用)。编译后的汇编代码如下。 MOV 0x08,#tmp(0x00) ;0x08和0x09是在内ram区分配的pstr指针变量地址空间 MOV 0x09,#tmp(0x00) 这种情况应该是在这里所有介绍各种情况中效率最高的访问外ram的方法了,请大家记住他。 第3种情况: uchar xdata * xdata pstr; pstr="tmp"; 这中情况也是对的,但效率不如第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 * xdata pstr; pstr="tmp"; 如果详细看了第1种情况的读者发现这种写法和第1种很相似,是的,同第1 种情况一样这样也是有bug的,但是这次是把pstr分 配到了外ram区了。编译后的汇编代码如下。 MOV DPTR, #0x000A ;0x000A是在外ram区分配的pstr指针变量的地址空间 MOV A, #tmp(0x00) MOVX @DPTR, A 第5种情况: uchar * data pstr; pstr="tmp"; 大家注意到"*"前的关键字声明没有了,是的这样会发生什么事呢?下面这么写呢!对了用齐豫的一首老歌名来说就是 “请跟我 来”,请跟我来看看编译后的汇编代码,有人问这不是在讲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空间,对于没有声明指针指向存储空间类型的指针, 系统编译代码时都强制加载一个字节的指针类型分辩值。具体的对应关系可以参考KeilC的help中C51 User's Guide。 第6种情况: uchar * pstr; pstr="tmp"; 这是最直接最简单的指针变量声明,但他的效率也最低。还是那句话,大家一起说好吗!编译后的汇编代码如下。 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 这种情况很类似第5种和第3种情况的组合,既把pstr分配在外ram空间了又增加了指针类型的分辨值。 |
电解电容在电路中的作用 |
1,滤波作用,在电源电路中,整流电路将交流变成脉动的直流,而在整流电路之后接入一个较大容量的电解电容,利用其充放电特性,使整流后的脉动直流电压变成相对比较稳定的直流电压。在实际中,为了防止电路各部分供电电压因负载变化而产生变化,所以在电源的输出端及负载的电源输入端一般接有数十至数百微法的电解电容.由于大容量的电解电容一般具有一定的电感,对高频及脉冲干扰信号不能有效地滤除,故在其两端并联了一只容量为0.001--0.lpF的电容,以滤除高频及脉冲干扰. 2,耦合作用:在低频信号的传递与放大过程中,为防止前后两级电路的静态工作点相互影响,常采用电容藕合.为了防止信号中韵低频分量损失过大,一般总采用容量较大的电解电容。 二、电解电容的判断方法 电解电容常见的故障有,容量减少,容量消失、击穿短路及漏电,其中容量变化是因电解电容在使用或放置过程中其内部的电解液逐渐干涸引起,而击穿与漏电一般为所加的电压过高或本身质量不佳引起。判断电源电容的好坏一般采用万用表的电阻档进行测量.具体方法为:将电容两管脚短路进行放电,用万用表的黑表笔接电解电容的正极。红表笔接负极(对指针式万用表,用数字式万用表测量时表笔互调),正常时表 针应先向电阻小的方向摆动,然后逐渐返回直至无穷大处。表针的摆动幅度越大或返回的速度越慢,说明电容的容量越大,反之则说明电容的容量越小.如表针指在中间某处不再变化,说明此电容漏电,如电阻指示值很小或为零,则表明此电容已击穿短路.因万用表使用的电池电压一般很低,所以在测量低耐压的电容时比较准确,而当电容的耐压较高时,打时尽管测量正常,但加上高压时则有可能发生漏电或击穿现象. 三、电解电容的使用注意事项 1、电解电容由于有正负极性,因此在电路中使用时不能颠倒联接。在电源电路中,输出正电压时电解电容的正极接电源输出端,负极接地,输出负电压时则负极接输出端,正极接地.当电源电路中的滤波电容极性接反时,因电容的滤波作用大大降低,一方面引起电源输出电压波动,另一方面又因反向通电使此时相当于一个电阻的电解电容发热.当反向电压超过某值时,电容的反向漏电电阻将变得很小,这样通电工作不久,即可使电容因过热而炸裂损坏. 2.加在电解电容两端的电压不能超过其允许工作电压,在设计实际电路时应根据具体情况留有一定的余量,在设计稳压电源的滤波电容时,如果交流电源电压为220~时变压器次级的整流电压可达22V,此时选择耐压为25V的电解电容一般可以满足要求.但是,假如交流电源电压波动很大且有可能上升到250V以上时,最好选择耐压30V以上的电解电容。 3,电解电容在电路中不应靠近大功率发热元件,以防因受热而使电解液加速干涸. 4、对于有正负极性的信号的滤波,可采取两个电解电容同极性串联的方法,当作一个无极性的电容。 |
电容器在电子电路中几乎是不可缺少的储能元件,它具有隔断直流、连通交流、阻止低频的特性。广泛应用在耦合、隔直、旁路、滤波、调谐、能量转换和自动控制等电路中。熟悉电容器在不同电路中的名称意义,有助于我们读懂电子电路图。
1.滤波电容 它接在直流电源的正、负极之间,以滤除直流电源中不需要的交流成分,使直流电平滑。一般常采用大容量的电解电容器,也可以在电路中同时并接其他类型的小容量电容以滤除高频交流电。
2.退耦电容 并接于放大电路的电源正、负极之间,防止由电源内阻形成的正反馈而引起的寄生振荡。
3.旁路电容 在交、直流信号的电路中,将电容并接在电阻两端或由电路的某点跨接到公共电位上,为交流信号或脉冲信号设置一条通路,避免交流信号成分因通过电阻产生压降衰减。
4.耦合电容 在交流信号处理电路中,用于连接信号源和信号处理电路或者作两放大器的级间连接,用以隔断直流,让交流信号或脉冲信号通过,使前后级放大电路的直流工作点互不影响。
5.调谐电容 连接在谐振电路的振荡线圈两端,起到选择振荡频率的作用。
6.衬垫电容 与谐振电路主电容串联的辅助性电容,调整它可使振荡信号频率范围变小,并能显著地提高低频端的振荡频率。适当地选定衬垫电容的容量,可以将低端频率曲线向上提升,接近于理想频率跟踪曲线。
7.补偿电容 它是与谐振电路主电容并联的辅助性电容,调整该电容能使振荡信号频率范围扩大。
8.中和电容 并接在三极管放大器的基极与发射极之间,构成负反馈网络,以抑制三极管极间电容造成的自激振荡。
9.稳频电容 在振荡电路中,起稳定振荡频率的作用。
10.定时电容 在RC时间常数电路中与电阻R串联,共同决定充放电时间长短的电容。
11.加速电容 接在振荡器反馈电路中,使正反馈过程加速,提高振荡信号的幅度。
12.缩短电容 在UHF高频头电路中,为了缩短振荡电感器长度而串接的电容。
13.克拉泼电容 在电容三点式振荡电路中,与电感振荡线圈串联的电容,起到消除晶体管结电容对频率稳定性影响的作用。
14.锡拉电容 在电容三点式振荡电路中,与电感振荡线圈两端并联的电容,起到消除晶体管结电容的影响,使振荡器在高频端容易起振。
15.稳幅电容 在鉴频器中,用于稳定输出信号的幅度。
16.预加重电容 为了避免音频调制信号在处理过程中造成对分频量衰减和丢失,而设置的RC高频分量提升网络电容。
17.去加重电容 为恢复原伴音信号,要求对音频信号中经预加重所提升的高频分量和噪声一起衰减掉,设置在RC网络中的电容。
18.移相电容 用于改变交流信号相位的电容。
19.反馈电容 跨接于放大器的输入与输出端之间,使输出信号回输到输入端的电容。
20.降压限流电容 串联在交流电回路中,利用电容对交流电的容抗特性,对交流电进行限流,从而构成分压电路。
21.逆程电容 用于行扫描输出电路,并接在行输出管的集电极与发射极之间,以产生高压行扫描锯齿波逆程脉冲,其耐压一般在1500V以上。
22.校正电容 串接在偏转线圈回路中,用于校正显像管边缘的延伸线性失真。
23.自举升压电容 利用电容器的充、放电储能特性提升电路某点的电位,使该点电位达到供电端电压值的2倍。
24.消亮点电容 设置在视放电路中,用于关机时消除显像管上残余亮点的电容。
25.软启动电容 一般接在开关电源的开关管基极上,防止在开启电源时,过大的浪涌电流或过高的峰值电压加到开关管基极上,导致开关管损坏。
26.启动电容 串接在单相电动机的副绕组上,为电动机提供启动移相交流电压。在电动机正常运转后与副绕组断开。
27.运转电容 与单相电动机的副绕组串联,为电动机副绕组提供移相交流电流。在电动机正常运行时,与副绕组保持串接。
指针就是指变量或数据所在的存储区地址。如一个字符型的变量 STR 存放在内存单元DATA 区的 51H 这个地址中,那么 DATA 区的 51H 地址就是变量 STR 的指针。在 C 语言中 指针是一个很重要的概念,正确有效的使用指针类型的数据,能更有效的表达复杂的数据 结构,能更有效的使用数组或变量,能方便直接的处理内存或其它存储区。指针之所以 能这么有效的操作数据,是因为无论程序的指令、常量、变量或特殊寄存器都要存放在内 存单元或相应的存储区中,这些存储区是按字节来划分的,每一个存储单元都能用唯一的 编号去读或写数据,这个编号就是常说的存储单元的地址,而读写这个编号的动作就叫做寻 址,通过寻址就能访问到存储区中的任一个能访问的单元,而这个功能是变量或数组等 是不可能代替的。C 语言也因此引入了指针类型的数据类型,专门用来确定其他类型数据的 地址。用一个变量来存放另一个变量的地址,那么用来存放变量地址的变量称为“指针变量”。 如用变量 STRIP 来存放文章开头的 STR 变量的地址 51H,变量 STRIP 就是指针变量。下面 用一个图表来说明变量的指针和指针变量两个不一样的概念。 file:///Z:\TEMP\msohtmlclip1\01\clip_image001.png 变量的指针就是变量的地址,用取地址运算符‘&’取得赋给指针变量。&STR 就是把 变量 STR 的地址取得。用语句 STRIP = &STR 就能把所取得的 STR 指针存放在 STRIP 指 针变量中。STRIP 的值就变为 51H。可见指针变量的内容是另一个变量的地址,地址所属的 变量称为指针变量所指向的变量。 要访问变量 STR 除了能用‘STR’这个变量名来访问之外,还能用变量地址来访 问。方法是先用&STR 取变量地址并赋于 STRIP 指针变量,然后就能用*STRIP 来对 STR 进行访问了。‘*’是指针运算符,用它能取得指针变量所指向的地址的值。在上图中指针 变量 STRIP 所指向的地址是 51H,而 51H 中的值是 40H,那么*STRIP 所得的值就是 40H。 使用指针变量之前也和使用其它类型的变量那样要求先定义变量,而且形式也相类似, 一般的形式如下: 数据类型 [存储器类型] * 变量名; unsigned char xdata *pi //指针会占用二字节,指针自身存放在编译器默认存储区,指 向 xdata 存储区的 char 类型 unsigned char xdata * data pi; //除指针自身指定在 data 区,其它同上 int * pi; //定义为一般指针,指针自身存放在编译器默认存储区,占三个字节 在定义形式中“数据类型”是指所定义的指针变量所指向的变量的类型。“存储器类型” 是编译器编译时的一种扩展标识,它是可选的。在没有“存储器类型”选项时,则定义为一 般指针,如有“存储器类型”选项时则定义为基于存储器的指针。限于 51 芯片的寻址范围, 指针变量最大的值为 0xFFFF,这样就决定了一般指针在内存会占用 3 个字节,第一字节存 放该指针存储器类型编码,后两个则存放该指针的高低位址。而基于存储器的指针因为不用 识别存储器类型所以会占一或二个字节,idata,data,pdata 存储器指针占一个字节,code,xdata 则会占二个字节。由上可知,明确的定义指针,能节省存储器的开销,这在严格要求程序 体积的项目中很有用处。 指针的使用方法很多,限于篇幅以上只能对它做一些基础的介绍。下面用在讲述常量时 的例程改动一下,用以说明指针的基本使用方法。 #include //预处理文件里面定义了特殊寄存器的名称如 P1 口定义为 P1 void main(void) { //定义花样数据,数据存放在片内 CODE 区中 unsigned char code design[]={0xFF,0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F, 0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0xFE,0xFF, 0xFF,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80,0x0, 0xE7,0xDB,0xBD,0x7E,0xFF}; unsigned int a; //定义循环用的变量 unsigned char b; unsigned char code * dsi; //定义基于 CODE 区的指针 do{ dsi = &design[0]; //取得数组第一个单元的地址 for (b=0; b<32; b++) { } }while(1); } for(a=0; a<30000; a++); //延时一段时间 P1 = *dsi; //从指针指向的地址取数据到 P1 口 dsi++; //指针加一, 为了能清楚的了解指针的工作原理,能使用 keil uv2 的软件仿真器查看各变量和存储器的 值。编译程序并执行,然后打开变量窗口,如图。用单步执行,就能查到到指针的变量。 如图中所示的是程序中循环执行到第二次,这个时候指针 dsi 指向 c:0x0004 这个地址,这个地址 的值是 0xFE。在存储器窗口则能察看各地址单元的值。使用这种方法不但在学习时能 帮助更好的了解语法或程序的工作,而且在实际使用中更能让你更快更准确的编写程序或解 决程序中的问题。 |
|
| file:///Z:\TEMP\msohtmlclip1\01\clip_image003.png |
file:///Z:\TEMP\msohtmlclip1\01\clip_image004.png | file:///Z:\TEMP\msohtmlclip1\01\clip_image002.png | file:///Z:\TEMP\msohtmlclip1\01\clip_image005.png | |
| |||
欢迎光临 (http://www.51hei.com/bbs/) | Powered by Discuz! X3.1 |