ls的乱写
PC = progammer counter //程序计数器
ACC = accumulate //累加器
PSW = progammer status word //程序状态字
SP = stack point //堆栈指针
DPTR = data point register //数据指针 寄存器
IP = interrupt priority //中断优先级
IE = interrupt enable // 中断使能
TMOD = timer mode //定时器 方式 (定时器/计数器 控制寄存器)
ALE = alter (变更,可能是)
PSEN = progammer saving enable //程序存储器使能(选择外部程序存储器的意思)
EA = enable all(允许所有中断)完整应该是 enable all interrupt
PROG = progamme (程序)
SFR = special funtion register //特殊功能寄存器
TCON = timer control //定时器控制
PCON = power control //电源控制
MSB = most significant bit//最高有效位
LSB = last significant bit//最低有效位
CY = carry //进位(标志)
AC = assistant carry //辅助进位
OV = overflow //溢出
ORG = originally //起始来源
DB = define byte //字节定义
EQU = equal //等于
DW = define word //字定义
E = enable //使能
OE = output enable //输出使能
RD = read //读
WR = write //写
中断部分:
INT0 = interrupt 0 //中断0
INT1 = interrupt 1//中断1
T0 = timer 0 //定时器0
T1 = timer 1 //定时器1
TF1 = timer1 flag //定时器1 标志 (其实是定时器1中断标志位)
IE1 = interrupt exterior //(外部中断请求,可能是)
IT1 = interrupt touch //(外部中断触发方式,可能是)
ES = enable serial //串行使能
ET = enable timer //定时器使能
EX = enable exterior //外部使能(中断)
PX = priority exterior //外部中断优先级
PT = priority timer //定时器优先级
PS = priority serial //串口优先级
全局变量与局部变量
c51中如何实现对全局变量的声明,注意项目含有多个文件,要声明一个全局变量,使得各模块都能使用该变量。:定义方法一般,所在模块中象一般全局变量一样定义如int x;其他要使用该变量的模块中,声明如:extern int a;
静态变量只是在第一次使用的时候初始化,如果是全局变量,则加static与否结果相同。如果是局部变量,则其他模块访问不到。
静态函数只有在本编译文件中才能被调用。其他c文件则不能调用。因此在其他文件中可以申明同名函数,而不互相影响。
中断函数在什么模块中使用都可以。只要申明中使用中断函数申明格式即可。
查表就是把数据事先放在程序存储器里,程序运行时从中取出。所以先要放表。
tab:db **
其中tab叫作表的首地址。
51单片机查表指令有两条:movc a,@a+dptr和movc a,@a+pc,前者用得较多。在查表前首先要找到首地址赋给dptr,执行mov dptr,#tab。其后根据表中数据个序号,把序号赋给a,再执行movc a,@a+dptr,则a中即得查表结果
const 表示本数组不可修改 数组为常量数组
code 表示本数组生成后是在ROM区中 同样不可修改
idata 表示数组生成后在在0x00~0xff的256个RAM中,使用指针寻址
具体的参考下面
data,bdata,idata,pdata,xdata,code存储类型与存储区
bit是在内部数据存储空间中 20H .. 2FH 区域中一个位的地址,或者 8051 位可寻址 SFR 的一个位地址。
code是在 0000H .. 0FFFFH 之间的一个代码地址。
data是在 0 到 127 之间的一个数据存储器地址,或者在 128 .. 255 范围内的一个特殊功能寄存器(SFR)地址。
idata是 0 to 255 范围内的一个 idata 存储器地址。
xdata 是 0 to 65535 范围内的一个 xdata 存储器地址。
指针类型和存储区的关系详解
一、存储类型与存储区关系
data ---> 可寻址片内ram
bdata ---> 可位寻址的片内ram
idata ---> 可寻址片内ram,允许访问全部内部ram
pdata ---> 分页寻址片外ram (MOVX @R0) (256 BYTE/页)
xdata ---> 可寻址片外ram (k 地址范围)
code ---> 程序存储区 (k 地址范围),对应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来寻址k空间,但因为使用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 变量地址空间
MOV A, #0x01
MOV @DPTR, A
INC DPTR
MOV DPTR, #0x000A
MOV A, #tmp(0x00)
MOV @DPTR, A
INC DPTR
MOV A, #tmp(0x00)
;0x000A-0x000C是在外ram区分配的pstr指针
MOVX @DPTR, A
这种情况很类似第5种和第3种情况的组合,既把pstr分配在外ram空间了又增加了指针类型的分辨值。
最近做了一块板子,当然考虑到元器件的选型了,由于指标中要求精度比较高,所以对于AD的选型很慎重。
很多人对于精度和分辨率的概念不清楚,这里我做一下总结,希望大家不要混淆。
我们搞电子开发的,经常跟“精度”与“分辨率”打交道,这个问题不是三言两语能搞得清楚的,在这里只作抛砖引玉了。
简单点说,“精度”是用来描述物理量的准确程度的,而“分辨率”是用来描述刻度划分的。从定义上看,这两个量应该是风马牛不相及的。(是不是有朋友感到愕然^_^)。很多卖传感器的JS就是利用这一点来糊弄人的了。简单做个比喻:有这么一把常见的塑料尺(中学生用的那种),它的量程是10厘米,上面有100个刻度,最小能读出1毫米的有效值。那么我们就说这把尺子的分辨率是1毫米,或者量程的1%;而它的实际精度就不得而知了(算是0.1毫米吧)。当我们用火来烤一下它,并且把它拉长一段,然后再考察一下它。我们不难发现,它还有有100个刻度,它的“分辨率”还是1毫米,跟原来一样!然而,您还会认为它的精度还是原来的0.1毫米么?(这个例子是引用网上的,个人觉得比喻的很形象!)
回到电子技术上,我们考察一个常用的数字温度传感器:AD7416。供应商只是大肆宣扬它有10位的AD,分辨率是1/1024。那么,很多人就会这么欣喜:哇塞,如果测量
温度0-100摄氏度,100/1024……约等于0.098摄氏度!这么高的精度,足够用了。但是我们去浏览一下AD7416的数据手册,居然发现里面赫然写着:测量精度0.25摄氏度!所以说分辨率跟精度完全是两回事,在这个温度传感器里,只要你愿意,你甚至可以用一个14位的AD,获得1/16384的分辨率,但是测量值的精度还是0.25摄氏度^_^
所以很多朋友一谈到精度,马上就和分辨率联系起来了,包括有些项目负责人,只会在那里说:这个系统精度要求很高啊,你们AD的位数至少要多少多少啊……
其实,仔细浏览一下AD的数据手册,会发现跟精度有关的有两个很重要的指标:DNL和INL。似乎知道这两个指标的朋友并不多,所以在这里很有必要解释一下。
DNL:Differencial NonLiner——微分非线性度
INL:Interger NonLiner——积分非线性度(精度主要用这个值来表示)
他表示了ADC器件在所有的数值点上对应的模拟值,和真实值之间误差最大的那一点的误差值。也就是,输出数值偏离线性最大的距离。单位是LSB(即最低位所表示的量)。
当然,像有的AD如△—∑系列的AD,也用Linearity error 来表示精度。
为什么有的AD很贵,就是因为INL很低。分辨率同为12bit的两个ADC,一个INL=±3LSB,而一个做到了±1.5LSB,那么他们的价格可能相差一倍。
所以在这里帮大家把这两个概念理一下,以后大家就可以理直气壮的说精度和分辨率了,而不是将精度理解为分辨率。呵呵,希望对大家有用!
分辨率计算:测量电压范围/(2^AD位数-1);
我把充电字节禁止充电,然后重新上电,用万用表量了下2,3脚电压,2脚为0.6V,3脚为0.2V,这两脚的电压应该是表明DS1302起振了,之前不正常时2脚为0V,3脚为2.4V,但是还是不知道为什么一下就起振了,奇怪!难道是在不接电池的情况下一定要把充电字节禁止充电?
大家在用DS1302的时候会碰到调整时间这个问题...因为我们平时用的是十进制比较多,而DS1302则输出和输入都是8421 BCD码.所以特意写了一个转换的小程序,希望对大家有用...
////////////////////////////////////////////////////////////////////////////////////////////////
//函数名:ZH_Data();
//返回参数:有.返回为十进制或十进制BCD码.
//输入参数:State=0 输入为十进制BCD码 输出为十进制.
//输入参数:State=1 输入为十进制,输出为十进制BCD码.
//设计人:wang1jin.
//设计版本:V1.0.
//////////////////////////////////////////////////////////////////////////////////////////////
uint8 ZH_Data(bit State,uint8 Value)
{
if(State==0) //判断工作模式.
{
Value=(Value/16)*10+(Value%16); //把8421BCD码转为十进制
return Value; //返回;
}
else //把十进制转为8421BCD码;
{
Value=(Value/10)*16+Value%10; //把十进制转为8421BCD码.
return Value; //返回;
}
}